Documentation
¶
Overview ¶
Package session ties together the message history, usage totals, and identity for one continuous conversation with the model.
Each Session is created with a UUID v4 identifier that also names its log file, making it straightforward to correlate terminal output with the structured log on disk.
A production session also owns the per-conversation runtime stack — sandbox, client, executor, agent runner, logger, model config — all scoped to the session's working directory. The Manager type in this package builds those wirings; the bare New constructor remains for tests that don't need the full stack.
Index ¶
- type ApprovalResponseMsg
- type CacheCompactionTriggerMsg
- type ChannelMessageMsg
- type ClientFactory
- type Deps
- type EventStream
- type ExecOutcome
- type Manager
- func (m *Manager) Active() *Session
- func (m *Manager) All() []*Session
- func (m *Manager) Clear(id string) (*Session, error)
- func (m *Manager) CloseAll() error
- func (m *Manager) Compact(id string) (*Session, error)
- func (m *Manager) CredentialAvailable() bool
- func (m *Manager) Delete(id string) error
- func (m *Manager) Find(id string) *Session
- func (m *Manager) New(workDir string) (*Session, error)
- func (m *Manager) RefreshCredentials() error
- func (m *Manager) SetActive(id string) bool
- func (m *Manager) SetProgram(p interface{ ... })
- type ModelSelection
- type OrchStream
- type Session
- func (s *Session) AddUsage(r usage.RequestUsage)
- func (s *Session) AgentRunner() *agentreg.Runner
- func (s *Session) Append(msg message.Message)
- func (s *Session) ApplyCompaction(summary string)
- func (s *Session) AutoApprove() bool
- func (s *Session) AutoApproveAPIKey() string
- func (s *Session) AutoApproveModel() model.ID
- func (s *Session) AutoCompact() bool
- func (s *Session) CancelExec()
- func (s *Session) Client() client.Client
- func (s *Session) Close() error
- func (s *Session) CompactAPIKey() string
- func (s *Session) CompactIdleTimeout() time.Duration
- func (s *Session) CompactModel() model.ID
- func (s *Session) CompactSelection() ModelSelection
- func (s *Session) Control() controlpkg.Client
- func (s *Session) DequeueInbound() (string, bool)
- func (s *Session) Effort() string
- func (s *Session) EnqueueInbound(content string)
- func (s *Session) ExecuteSelection() ModelSelection
- func (s *Session) Executor() *toolexec.Executor
- func (s *Session) Features() settings.FeatureSet
- func (s *Session) FoldLiveUsage()
- func (s *Session) HasIdleTimer() bool
- func (s *Session) HooksRegistry() *hooksreg.Registry
- func (s *Session) ID() string
- func (s *Session) LiveFoldedCount() int
- func (s *Session) LoadedSkills() [][2]string
- func (s *Session) Logger() *logger.Logger
- func (s *Session) Messages() []message.Message
- func (s *Session) ModelConfig() model.Config
- func (s *Session) ModelName() string
- func (s *Session) PlanSelection() ModelSelection
- func (s *Session) PlanStore() *planengine.Store
- func (s *Session) Prompts() *promptreg.Registry
- func (s *Session) Reasoning() bool
- func (s *Session) RecordSkill(name, body string)
- func (s *Session) ResetLiveFoldedCount()
- func (s *Session) RestoreTools()
- func (s *Session) ReviewSelection() ModelSelection
- func (s *Session) ReviewerSubagentModel() model.ID
- func (s *Session) Sandbox() sandbox.Sandbox
- func (s *Session) SessionTitle() bool
- func (s *Session) SessionTitleAPIKey() string
- func (s *Session) SessionTitleEffort() string
- func (s *Session) SessionTitleModel() model.ID
- func (s *Session) SetAutoApprove(v bool)
- func (s *Session) SetAutoCompact(v bool)
- func (s *Session) SetGenerationOptions(opts model.GenerationOptions)
- func (s *Session) SetModel(m model.ID) error
- func (s *Session) SetProgram(p interface{ ... })
- func (s *Session) SetSessionTitle(v bool)
- func (s *Session) SetTitle(title string)
- func (s *Session) SetWaiting(v bool)
- func (s *Session) SourceWorkDir() string
- func (s *Session) StartCompaction(ctx context.Context) EventStream
- func (s *Session) StartExec(ctx context.Context, messages []message.Message) EventStream
- func (s *Session) StartIdleTimer(d time.Duration)
- func (s *Session) StartOrchestration(ctx context.Context, orch *orchestrator.Orchestrator, ...) OrchStream
- func (s *Session) StopIdleTimer()
- func (s *Session) Title() string
- func (s *Session) Waiting() bool
- func (s *Session) WorkDir() string
- func (s *Session) Worktree() *worktree.Handle
- type SessionCreatedEvent
- type SessionDeletedEvent
- type SubagentProgressMsg
- type WorktreeCreatedEvent
- type WorktreePrunedEvent
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ApprovalResponseMsg ¶
ApprovalResponseMsg is sent to the Bubble Tea program when the jungi control websocket connection receives a remote decision on a forwarded tool approval request, so the TUI can resolve the matching pending approval and dismiss its overlay. Modelled on ChannelMessageMsg — async injection through the session's program handle.
TODO: Behavior carries the remote service's legacy "permission" wire vocabulary ("allow"/"deny"); realign with jungi's "approval" terminology once the remote server does.
type CacheCompactionTriggerMsg ¶
type CacheCompactionTriggerMsg struct {
SessionID string
}
CacheCompactionTriggerMsg is sent to the Bubble Tea program when the idle timer fires, signalling that the session's cached tokens are approaching expiry and in-place compaction should begin.
type ChannelMessageMsg ¶
ChannelMessageMsg is sent to the Bubble Tea program when the jungi control websocket connection receives an inbound message, so the TUI can route it into the target session as a new user turn (or enqueue it if the session is currently busy). Modelled on CacheCompactionTriggerMsg — async injection through the session's program handle.
type ClientFactory ¶
type ClientFactory func(log *logger.Logger, systemPrompt string, m model.ID, tools []tooldef.Definition, opts model.GenerationOptions, transportOpts ...client.Option) client.Client
ClientFactory is the constructor signature used to build a session's API client. Production wires this to defaultClientFactory, which resolves the per-provider credential from the auth store and dispatches to the right SDK client constructor based on the model's provider; tests inject a fake to avoid hitting the network. opts carries the provider-neutral generation settings (reasoning effort); see model.GenerationOptions.
type Deps ¶
type Deps struct {
LogDir string
ConfigDir string
Skills *skillreg.Registry
UserSkills *skillreg.Registry
Prompts *promptreg.Registry
UserPrompts *promptreg.Registry
Agents *agentreg.Registry
UserAgents *agentreg.Registry
Settings settings.Settings
NewClient ClientFactory
// JungiControlToken is the bearer token used to authenticate with the
// jungi control service. Empty means no credential has been
// configured; sessions skip connecting in that case regardless of
// the [jungi_control] enabled setting.
JungiControlToken string
// NewControl is a factory hook so tests can substitute a fake control
// client instead of dialing a real service. A nil value defaults to
// control.New.
NewControl func(cfg control.Config) control.Client
}
Deps carries the process-scoped dependencies a Manager needs to wire up each new session. LogDir and the skill registries are loaded once at startup; Settings holds the full user-level configuration loaded from ~/.config/jungi/settings.toml (with any CLI flag overrides already applied); NewClient is a factory hook so tests can substitute a fake client. Credentials themselves are never carried on Deps: each session resolves them per-provider from the auth store at build time (see defaultClientFactory), so a submitted credential for any provider takes effect without touching Deps.
ConfigDir is the resolved user-level configuration directory (~/.config/jungi/), used to locate GUIDANCE.md for injection into the system prompt. An empty value simply omits the <user-guidance> block.
Skills holds the built-in (embedded) skills and UserSkills holds the user-level skills loaded from ~/.config/jungi/skills/. They are kept separate so the session builder can interleave project-level skills (<repo>/.jungi/skills/) between them at the correct precedence: built-in > project > user.
Prompts holds the built-in (embedded) prompts and UserPrompts holds the user-level prompts loaded from ~/.config/jungi/prompts/. They are kept separate so the session builder can interleave project-level prompts (<repo>/.jungi/prompts/) between them at the correct precedence: built-in > project > user.
Agents is the registry of agent definitions available for subagent execution (orient, plan/research, etc.). A nil value falls back to an empty registry so callers that don't need agents can omit it safely.
UserAgents holds the user-level agents loaded from ~/.config/jungi/agents/. It is kept separate from Agents so the session builder can interleave project-level agents (<repo>/.jungi/agents/) between them at the correct precedence: built-in > project > user.
Settings is the user-level configuration. Per-session, the session builder also loads and merges any <repo>/.jungi/settings.toml project file on top, so the effective settings may differ from what is stored here. The project file is loaded fresh for every new/compacted/cleared session so project overrides always reflect the on-disk state at session build time.
type EventStream ¶
type EventStream struct {
Events <-chan toolexec.ToolEvent
Approvals <-chan approval.Request
Usage <-chan usage.RequestUsage
Text <-chan string
Outcome <-chan ExecOutcome
}
EventStream is the receive-side view of an in-flight executor Run. Events emits each tool invocation as it completes; Approvals emits approval requests when the model invokes unsafe_shell; Usage emits each round-trip's RequestUsage live as it arrives, for progressive cost/context display; Text emits each non-empty assistant-text block as that response arrives, before any tools from the same response; Outcome emits the final result (or error) once the loop ends. Events, Approvals, Usage, and Text are all closed before Outcome is written.
Usage sends are best-effort: StartExec uses a buffered channel with a non-blocking send, so a slow or non-draining reader (e.g. compaction, which reuses StartExec but never selects on Usage) simply misses events rather than stalling the executor. Callers that need a definitive accounting should reconcile against the Outcome's Result.Usages.
Text sends are unbuffered and blocking: the executor will not emit that response's tool events until a reader has received the text. Callers (including compaction waiters) MUST drain Text, even if they discard it.
type ExecOutcome ¶
ExecOutcome bundles the result of a tool-use loop with its terminal error. The TUI translates this into either a model-response message or an error message; modelling both in one struct keeps the result channel a single buffered slot and avoids two parallel channels per Run.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager owns the collection of sessions and knows how to build new ones bound to a working directory. The active session is the one whose messages currently appear in the TUI viewport; the others may still be running tool loops in the background.
Sessions can be added via New and replaced in-place via Clear. CloseAll is invoked at process exit to release log file descriptors.
func NewManager ¶
NewManager constructs an empty Manager. No sessions exist until New is called. The caller is responsible for invoking CloseAll on shutdown.
func (*Manager) Active ¶
Active returns the currently-active session, or nil if none exists yet. The TUI must guard against nil before dereferencing — at startup, before the user has run /new, there is no active session.
func (*Manager) All ¶
All returns the sessions in insertion order. The returned slice shares backing memory with the manager's; callers must not mutate it.
func (*Manager) Clear ¶
Clear replaces the session identified by id with a brand-new session bound to the same working directory. Any in-flight tool-use loop or orchestration on the old session is cancelled before it is closed so that background goroutines exit promptly. The new session has a fresh UUID, an empty message history, zeroed usage totals, and its own log file — it is otherwise identical to what Manager.New would produce for the same workDir.
The new session occupies the same position in the session list as the old one, so the ordering visible in /sessions is preserved. If the cleared session was active, the new session becomes active.
Returns an error if id is not found or if the new session cannot be wired (e.g. log file cannot be created).
func (*Manager) CloseAll ¶
CloseAll releases every session's log file descriptor. Errors from individual closes are joined so callers see all failures, not just the first.
func (*Manager) Compact ¶
Compact replaces the session identified by id with a fresh session that inherits the old session's git worktree (when present), keeping the same branch checked out and the same on-disk files. It is the /compact lifecycle path: the user wants to keep working on the same feature, just with a fresh conversation context.
The old session is closed, but its worktree is detached first so that closing does not prune it. The new session takes ownership of the worktree handle; from the user's perspective the agent's branch and uncommitted changes carry over verbatim.
Returns an error if id is not found or if the new session cannot be wired.
func (*Manager) CredentialAvailable ¶ added in v0.2.0
CredentialAvailable reports whether an OpenRouter credential is stored. The TUI uses this to decide which session-creating commands are available and which idle-screen message to show.
func (*Manager) Delete ¶
Delete closes the session identified by id, removes it from the session list, and sets the active session to nil unconditionally — the caller is expected to return to the empty-state view rather than fall back to another session. Returns an error if id is not found.
func (*Manager) Find ¶
Find returns the session with the given ID, or nil if not present. Used by the TUI to route async messages tagged with their originating session ID to the correct session, even when that session is not active.
func (*Manager) New ¶
New builds a fully wired session bound to workDir. workDir must exist and be a readable directory; the picker UI is responsible for offering only valid paths, but Manager validates again as a safety net so that a fat-fingered programmatic caller cannot create a broken session.
When workDir is inside a git repository, the session is hosted in a freshly-created git worktree at <repo>/.jungi/state/worktrees/<id>/ on branch jungi/<id>, isolating its work from any other session in the same repo. When workDir is not in a git repository, the session runs against the directory directly (graceful fallback for scratch dirs and projects that aren't version-controlled).
On success the new session becomes the active one, on the assumption that the user just asked for it; the previous active session keeps running its tool loop in the background.
func (*Manager) RefreshCredentials ¶ added in v0.2.0
RefreshCredentials replaces every existing session with a fresh one so they re-resolve their provider credentials from the auth store. Callers invoke this after a credential is saved via /credentials: credentials are never cached on Deps, so this exists solely to rebuild in-flight sessions (whose clients were constructed once, at build time) rather than to record which provider changed.
Lifecycle events (worktree.pruned, worktree.created, session.created) are suppressed during this operation to avoid spurious hook firings.
func (*Manager) SetActive ¶
SetActive promotes the session with the given ID to active. Returns false if no such session exists; the previous active session is unchanged in that case.
func (*Manager) SetProgram ¶
func (m *Manager) SetProgram(p interface{ Send(msg interface{}) })
SetProgram wires the Bubble Tea program into the manager so that every session — both existing and future ones — can send CacheCompactionTriggerMsg events into the TUI event loop when their idle timers fire. Called once by main after the program is created but before p.Run().
type ModelSelection ¶ added in v0.2.0
type ModelSelection struct {
// Model is the resolved model identifier for the command's session.
// Empty means no model is configured for this command.
Model model.ID
// GenerationOptions is the resolved provider-neutral generation
// settings (reasoning effort) for the command's session. A zero value
// means no reasoning override.
GenerationOptions model.GenerationOptions
}
ModelSelection is a fully-resolved set of model and generation-option values for a slash command (/new, /plan, /execute, or /review). Unlike settings.CommandConfig — which carries the raw, possibly-empty TOML values — every field here is concrete: GenerationOptions has already been reconciled against what the resolved model supports (an unsupported effort level is silently disabled). Model may be empty when the command's section carries no configured model, meaning the command is disabled.
type OrchStream ¶
type OrchStream struct {
Result <-chan orchestrator.Result
}
OrchStream is the receive-side view of an in-flight orchestration. Result emits the aggregated final result once every agent finishes. Per-agent progress is not exposed here — StartOrchestration forwards it directly to the TUI as SubagentProgressMsg via async injection (see drainProgress), so there is nothing for the caller to drain.
type Session ¶
type Session struct {
Usage usage.SessionUsage
// LastMessageAt records the time the most recent API call completed
// successfully. It is used by the idle-timer logic to determine when
// cached tokens are approaching expiry and in-place compaction should
// be triggered.
LastMessageAt time.Time
// contains filtered or unexported fields
}
Session groups message history and usage tracking under a unique identifier.
Usage is exported so the TUI can read running totals directly without an accessor. All other state is private; callers mutate it through the methods below so the slice is never replaced out from under concurrent readers.
The runtime fields (sandbox, client, executor, agentRunner, logger, closeLog, modelConfig, workDir) are populated only when the session was built through Manager.New. Sessions created via the bare New constructor have nil runtime fields and are intended for unit tests that operate only on message history and usage accumulation.
func New ¶
func New() *Session
New creates a session with a fresh UUID v4 identifier and no runtime wiring. Use Manager.New for production sessions; this constructor is retained for tests that exercise message history and usage in isolation.
func (*Session) AddUsage ¶
func (s *Session) AddUsage(r usage.RequestUsage)
AddUsage folds a single request's token counts and reported cost into the running session totals.
func (*Session) AgentRunner ¶
AgentRunner returns the session's subagent runner. Nil for bare sessions.
func (*Session) Append ¶
Append adds a message to the end of the conversation history.
func (*Session) ApplyCompaction ¶
ApplyCompaction replaces the session's full message history with a single hidden carry-over user message built from summary, and resets the API client's server-side conversation state so the next request starts fresh with only the compact context. Active skill bodies are re-injected as hidden user messages before the carry-over so they survive the reseed. The session's LastMessageAt is stamped so the next idle timer starts from the compaction time rather than the original last-message time.
func (*Session) AutoApprove ¶
AutoApprove reports whether the AI auto-approver is enabled for this session. When true, run_unsafe_shell approval requests are delegated to a Haiku-class model rather than the manual overlay.
func (*Session) AutoApproveAPIKey ¶ added in v0.2.0
AutoApproveAPIKey returns the credential for the provider that owns the session's auto-approve evaluator model, resolved at session build time. Used by the auto-approver to make its own single-turn evaluation call. Empty when auto-approval is unconfigured.
func (*Session) AutoApproveModel ¶
AutoApproveModel returns the resolved model used to evaluate run_unsafe_shell auto-approval decisions. Empty when [auto_approve].model is unconfigured, meaning auto-approval is disabled.
func (*Session) AutoCompact ¶ added in v0.3.0
AutoCompact reports whether idle autocompaction is enabled for this session.
func (*Session) CancelExec ¶
func (s *Session) CancelExec()
CancelExec cancels the context of any in-flight tool-use loop or orchestration on this session. It is safe to call when no work is in flight — the cancel function is nil in that case and the call is a no-op. After cancellation the goroutine will exit and drain its channels; the TUI will receive a ModelErrorMsg (context cancelled) which it silently drops because the session ID will no longer be found in the manager after a /clear.
func (*Session) Client ¶
Client returns the session's API client. Nil for bare sessions.
func (*Session) Close ¶
Close releases resources owned by the session: any in-flight work is cancelled first so the goroutine can exit promptly, then any LSP servers are shut down, then the worktree (if any) is pruned, then the log file descriptor is released. Safe to call on bare sessions; returns nil.
Worktree pruning is force=true so process exit and TUI-initiated close paths both work uniformly: the TUI gates dirty closes through the confirmation overlay before invoking Close, so reaching this point means the caller has already accepted any loss; on process exit there is no UI to consult and orphaned worktrees are recoverable via `git worktree prune`, so forcing through is the better default.
Worktree prune errors are joined with the log close error rather than short-circuiting — failing to remove a worktree must not stop log files from being released.
func (*Session) CompactAPIKey ¶ added in v0.3.0
CompactAPIKey returns the credential for the provider that owns the compact model, resolved at session build time. Used by the compact summarizer. Empty when compact.model is unconfigured.
func (*Session) CompactIdleTimeout ¶ added in v0.3.0
CompactIdleTimeout returns the idle duration after which autocompaction fires. Zero means unset.
func (*Session) CompactModel ¶ added in v0.3.0
CompactModel returns the resolved compact model identifier. Empty when compact.model is unconfigured, meaning /compact and autocompact are disabled.
func (*Session) CompactSelection ¶ added in v0.3.0
func (s *Session) CompactSelection() ModelSelection
CompactSelection returns the resolved model and generation options for /compact and idle autocompaction. Zero value (empty Model) for bare sessions or when compact.model is unconfigured.
func (*Session) Control ¶
func (s *Session) Control() controlpkg.Client
Control returns the session's jungi control client, or nil when the feature is disabled, misconfigured, or the session was built via the bare New constructor.
func (*Session) DequeueInbound ¶
DequeueInbound pops the oldest queued inbound channel message, if any. The second return value reports whether a message was present.
func (*Session) Effort ¶
Effort returns the current output-config effort level for this session. An empty string means no effort override is active.
func (*Session) EnqueueInbound ¶
EnqueueInbound appends a channel message's content to the session's inbound queue. Used to hold jungi control messages that arrive while the session is Waiting so they are not dropped; DequeueInbound drains them once the session becomes idle again.
func (*Session) ExecuteSelection ¶ added in v0.2.0
func (s *Session) ExecuteSelection() ModelSelection
ExecuteSelection returns the resolved per-command model selection for the /execute slash command. Zero value (empty Model) for bare sessions or when [execute].model is unconfigured.
func (*Session) Executor ¶
Executor returns the session's tool-use executor. Nil for bare sessions.
func (*Session) Features ¶ added in v0.2.0
func (s *Session) Features() settings.FeatureSet
Features returns the FeatureSet describing which model-backed features the session's effective settings configured. Zero value (all false) for bare sessions.
func (*Session) FoldLiveUsage ¶
func (s *Session) FoldLiveUsage()
FoldLiveUsage records that one more round-trip's usage has been folded into Usage live (via the usage channel), so handleModelResponse's end-of-turn reconciliation knows which prefix of Result.Usages to skip.
func (*Session) HasIdleTimer ¶
HasIdleTimer reports whether an idle timer is currently pending. Exposed for tests that need to assert whether a timer was started or cleared.
func (*Session) HooksRegistry ¶
HooksRegistry returns the session's lifecycle hook registry. Non-nil for sessions built via Manager; nil for bare test sessions. Callers may invoke Emit directly; nil is handled gracefully in hooksreg.Registry.Emit.
func (*Session) ID ¶
ID returns the session's unique identifier, which also serves as the base name for the session log file.
func (*Session) LiveFoldedCount ¶
LiveFoldedCount reports how many round-trips have already been folded live for the current turn.
func (*Session) LoadedSkills ¶
LoadedSkills returns a snapshot of the currently active skills as an ordered slice of (name, body) pairs. Safe to call from any goroutine.
func (*Session) Logger ¶
Logger returns the session's structured event logger. Nil for bare sessions.
func (*Session) Messages ¶
Messages returns the full conversation history in chronological order.
func (*Session) ModelConfig ¶
ModelConfig returns the pricing and context-limit metadata for the model the session targets. Zero value for bare sessions.
func (*Session) ModelName ¶
ModelName returns the model identifier string for the model the session targets (e.g. "anthropic/claude-sonnet-5"). Empty for bare sessions.
func (*Session) PlanSelection ¶ added in v0.2.0
func (s *Session) PlanSelection() ModelSelection
PlanSelection returns the resolved per-command model selection for the /plan slash command. Zero value (empty Model) for bare sessions or when [plan].model is unconfigured.
func (*Session) PlanStore ¶
func (s *Session) PlanStore() *planengine.Store
PlanStore returns the session's plan store, or nil when the session is not hosted in a git repo. Used by tests and any future code that needs direct access; the routine tool-call path goes through the executor, which is wired during build.
func (*Session) Prompts ¶
Prompts returns the per-session merged prompt registry (built-in > project > user precedence). When s.prompts is nil the session is a bare or test session — not an error condition — and an empty registry is returned so callers never need nil guards. Do not conflate nil with a load failure.
func (*Session) Reasoning ¶ added in v0.2.0
Reasoning returns whether reasoning is enabled for this session.
func (*Session) RecordSkill ¶
RecordSkill stores the rendered body for the named skill so it can be re-injected by ApplyCompaction. If the skill was already recorded its body is updated to the new value; insertion order is preserved on first record. Safe to call from any goroutine.
func (*Session) ResetLiveFoldedCount ¶
func (s *Session) ResetLiveFoldedCount()
ResetLiveFoldedCount is the exported form of resetLiveFoldedCount, for callers outside the package (the TUI, after end-of-turn reconciliation).
func (*Session) RestoreTools ¶ added in v0.2.0
func (s *Session) RestoreTools()
RestoreTools re-advertises the session's full tool set and lifts any executor dispatch restriction. Idempotent: safe when tools were never restricted.
func (*Session) ReviewSelection ¶ added in v0.2.0
func (s *Session) ReviewSelection() ModelSelection
ReviewSelection returns the resolved per-command model selection for the /review slash command. Zero value (empty Model) for bare sessions or when review.model is unconfigured.
func (*Session) ReviewerSubagentModel ¶
ReviewerSubagentModel returns the resolved model used for the reviewer subagent spawned by /review and review_ticket. Empty when [review.reviewer_subagent].model is unconfigured, meaning the reviewer subagent is disabled.
func (*Session) Sandbox ¶
Sandbox returns the session's sandbox. Nil for bare sessions.
func (*Session) SessionTitle ¶ added in v0.3.0
SessionTitle reports whether automatic session title generation is enabled for this session.
func (*Session) SessionTitleAPIKey ¶ added in v0.3.0
SessionTitleAPIKey returns the credential for the provider that owns the session's title generation model, resolved at session build time. Empty when session titles are unconfigured.
func (*Session) SessionTitleEffort ¶ added in v0.3.0
SessionTitleEffort returns the reasoning effort level configured for session title generation. Empty when unconfigured or disabled.
func (*Session) SessionTitleModel ¶ added in v0.3.0
SessionTitleModel returns the resolved model used to generate session titles. Empty when [session_title].model is unconfigured, meaning title generation is disabled.
func (*Session) SetAutoApprove ¶
SetAutoApprove enables or disables the AI auto-approver for this session. Enabling is a no-op when no auto-approve model is configured — there is nothing to evaluate approval requests with, so the toggle stays off regardless of v.
func (*Session) SetAutoCompact ¶ added in v0.3.0
SetAutoCompact enables or disables idle autocompaction for this session. Enabling is a no-op when no compact model is configured — there is nothing to summarise with, so the toggle stays off regardless of v.
func (*Session) SetGenerationOptions ¶
func (s *Session) SetGenerationOptions(opts model.GenerationOptions)
SetGenerationOptions updates the provider-neutral generation options (reasoning effort) for the current model and rebuilds the client in-place.
Safe to call on bare sessions (no factory, no executor); in that case it is a no-op. Callers must not call this while a tool-use loop is in flight.
func (*Session) SetModel ¶
SetModel swaps the session's API client to target a different model. It builds a fresh client via the factory that was stored at construction time, wires it into the executor, and updates modelName and modelConfig so that context-limit and pricing calculations immediately reflect the new model. Accumulated TotalCost from prior requests is preserved; only future requests price at the new model's rate.
SetModel resets the new client's prompt-cache state (it starts empty by construction) so the next request is sent as a fresh conversation from the server's perspective. This is intentional: the previous server-side betaMessages were keyed to the old model's context and cannot be replayed against a different model endpoint.
Safe to call on bare sessions (no factory, no executor); in that case it is a no-op. Callers must not call SetModel while a tool-use loop is in flight on this session.
SetModel returns an error, without changing any session state, if m is not a registered model. Callers (the /model command and the OpenRouter search flow) are expected to register or already know m is registered before calling SetModel, so this should not fail in practice; it exists to avoid silently falling back to another model's pricing/context-limit config.
func (*Session) SetProgram ¶
func (s *Session) SetProgram(p interface{ Send(msg interface{}) })
SetProgram wires the Bubble Tea program into the session so the idle timer can inject CacheCompactionTriggerMsg events into the TUI event loop. Called once by the TUI after the program is created.
func (*Session) SetSessionTitle ¶ added in v0.3.0
SetSessionTitle enables or disables automatic session title generation for this session. Enabling is a no-op when no session-title model is configured — there is nothing to generate titles with, so the toggle stays off regardless of v.
func (*Session) SetTitle ¶ added in v0.3.0
SetTitle sets the generated human-readable title slug for this session.
func (*Session) SetWaiting ¶
SetWaiting sets the in-flight flag. Called by the goroutine spawn site when a request begins, and by the result handlers when it ends.
func (*Session) SourceWorkDir ¶
SourceWorkDir returns the directory the user originally selected when the session was created. Equal to WorkDir when no worktree is in play; differs when WorkDir points at a worktree-relative path. Manager.Clear and Manager.Compact use this to build the successor session from the user-chosen directory rather than the disposable worktree path.
func (*Session) StartCompaction ¶
func (s *Session) StartCompaction(ctx context.Context) EventStream
StartCompaction obtains a conversation summary from the compact model via a throwaway client (see compact.Summarize). It does not append the summary prompt onto session history and does not use the session client. The returned EventStream follows the same contract as StartExec so the TUI waitForCompactionEvent path stays unchanged: unused event/approval/text channels close, then Outcome carries the summary (or error).
On an empty compact model this is a no-op: WAITING is not set and a zero EventStream is returned. Callers must not drain a zero stream.
func (*Session) StartExec ¶
StartExec spawns a goroutine that runs the session's tool-use loop and returns channels carrying the per-tool events, approval requests, and the final outcome. Channels are owned by the goroutine: it writes events and approval requests as they happen, closes those channels on exit, then writes the outcome. Callers read the channels through tea.Cmds without ever closing them, so a session-switch in the TUI cannot panic the writer.
A cancellable child context is derived from ctx and stored on the session so that CancelExec can abort an in-flight loop (e.g. when the user runs /clear). The cancel is also called on goroutine exit so the context is always released promptly.
The session is marked WAITING synchronously here, before the goroutine spawns, so the next View render observes the busy state without any race against the goroutine starting. Clearing waiting is the caller's responsibility (terminal-message handlers in the TUI clear it; cancel paths flip it off as part of CancelExec's contract). This start-side ownership keeps long-running work visible regardless of which TUI handler launched it, without making the goroutine fight the existing drain-message filter that depends on waiting=true at message time.
Panics if the session has no executor wired (i.e. it was built via the bare New() constructor); production callers always go through Manager.
func (*Session) StartIdleTimer ¶
StartIdleTimer starts (or resets) the idle timer for duration d. When the timer fires it sends a CacheCompactionTriggerMsg to the Bubble Tea program so the TUI can initiate in-place history compaction before the cached tokens expire. Safe to call when program is nil — the timer is still created but its callback is a no-op.
func (*Session) StartOrchestration ¶
func (s *Session) StartOrchestration(ctx context.Context, orch *orchestrator.Orchestrator, tasks []orchestrator.Task) OrchStream
StartOrchestration spawns a goroutine that runs the given orchestrator against tasks and returns a channel carrying the final aggregated result. Per-agent progress is forwarded to the TUI as it happens via drainProgress + async injection (SubagentProgressMsg), the same mechanism planAgentRunner.ReviewDiff uses for the plan-driven review_ticket path — so ad-hoc /review and review_ticket display subagent progress identically.
A cancellable child context is derived and stored on the session, consistent with StartExec, so that CancelExec can abort an in-flight orchestration.
As with StartExec, the session is marked WAITING synchronously here so the next View render reflects the busy state without racing the goroutine. End-of-work clears are the TUI's responsibility.
func (*Session) StopIdleTimer ¶
func (s *Session) StopIdleTimer()
StopIdleTimer cancels the pending idle timer if one is running. Safe to call when no timer is active.
func (*Session) Title ¶ added in v0.3.0
Title returns the generated human-readable title slug for this session, or an empty string if no title has been generated yet.
func (*Session) Waiting ¶
Waiting reports whether a tool-use loop is currently in flight on this session. The TUI uses this to gate new submissions and to render the WAITING tag in the divider when this session is the active one.
func (*Session) WorkDir ¶
WorkDir returns the working directory the session is bound to. Empty for sessions built via the bare New constructor. When the session is hosted in a git worktree, this is the worktree-relative path; the sandbox, LSP manager, and system prompt all see the worktree as the canonical project root.
func (*Session) Worktree ¶
Worktree returns the worktree handle this session owns, or nil when the session is not hosted in a worktree. The TUI uses this to query dirty-state before /close and /clear so the user can be warned about uncommitted or unpushed work that would be discarded.
type SessionCreatedEvent ¶
SessionCreatedEvent implements hooksreg.Payload for session.created. Its fields are exactly the keys hooksreg's catalog declares for that event: the session ID and the working directory.
func (SessionCreatedEvent) Env ¶
func (e SessionCreatedEvent) Env() map[string]string
Env implements hooksreg.Payload.
func (SessionCreatedEvent) Event ¶
func (SessionCreatedEvent) Event() hooksreg.Event
Event implements hooksreg.Payload.
func (SessionCreatedEvent) WorkDir ¶
func (e SessionCreatedEvent) WorkDir() string
WorkDir implements hooksreg.Payload.
type SessionDeletedEvent ¶
SessionDeletedEvent implements hooksreg.Payload for session.deleted. Its fields are exactly the keys hooksreg's catalog declares for that event: the session ID and the working directory.
WorkDirEnv is the value reported via the WORK_DIR env var; Dir is the actual working directory the hook process runs in. These differ for session.deleted: the hook process runs in the session's source directory after the worktree has already been pruned, but WORK_DIR keeps reporting the original (possibly worktree-relative) workDir value so consumers see the path the session operated against throughout its life.
func (SessionDeletedEvent) Env ¶
func (e SessionDeletedEvent) Env() map[string]string
Env implements hooksreg.Payload.
func (SessionDeletedEvent) Event ¶
func (SessionDeletedEvent) Event() hooksreg.Event
Event implements hooksreg.Payload.
func (SessionDeletedEvent) WorkDir ¶
func (e SessionDeletedEvent) WorkDir() string
WorkDir implements hooksreg.Payload.
type SubagentProgressMsg ¶
type SubagentProgressMsg struct {
SessionID string
Event agentreg.ProgressEvent
}
SubagentProgressMsg is sent to the Bubble Tea program when a reviewer or research subagent starts, finishes, or errors, so the TUI can append a harness message to the session history. It is the single progress path for both producers: StartOrchestration (ad-hoc /review) and planAgentRunner.ReviewDiff (plan-driven review_ticket) both drain their progress channel through drainProgress and forward each event here via async injection through the session's program handle — the same mechanism the idle timer uses for CacheCompactionTriggerMsg — rather than a channel the TUI itself drains via a chained tea.Cmd.
type WorktreeCreatedEvent ¶
WorktreeCreatedEvent implements hooksreg.Payload for worktree.created. Its fields are exactly the keys hooksreg's catalog declares for that event: the worktree path, the repo root, and the session ID.
func (WorktreeCreatedEvent) Env ¶
func (e WorktreeCreatedEvent) Env() map[string]string
Env implements hooksreg.Payload.
func (WorktreeCreatedEvent) Event ¶
func (WorktreeCreatedEvent) Event() hooksreg.Event
Event implements hooksreg.Payload.
func (WorktreeCreatedEvent) WorkDir ¶
func (e WorktreeCreatedEvent) WorkDir() string
WorkDir implements hooksreg.Payload.
type WorktreePrunedEvent ¶
WorktreePrunedEvent implements hooksreg.Payload for worktree.pruned. Its fields are exactly the keys hooksreg's catalog declares for that event: the worktree path, the repo root, and the session ID.
func (WorktreePrunedEvent) Env ¶
func (e WorktreePrunedEvent) Env() map[string]string
Env implements hooksreg.Payload.
func (WorktreePrunedEvent) Event ¶
func (WorktreePrunedEvent) Event() hooksreg.Event
Event implements hooksreg.Payload.
func (WorktreePrunedEvent) WorkDir ¶
func (e WorktreePrunedEvent) WorkDir() string
WorkDir implements hooksreg.Payload.
Source Files
¶
- hookevents.go
- manager.go
- plan_agent_runner.go
- session.go