session

package
v0.22.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 20, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package session manages on-disk session entries at `<BaseDir>/sessions/<id>/`. A session is one Slack thread or one UI conversation: routing key, status, agent registry, log files, and an optional reference to a project whose folder is the agent cwd.

Sessions own no project files of their own — a project is a shared bundle (see internal/agents/project) whose folder the pool resolves to a cwd at spawn time. See agents-design.md §0.2 for the refactor that removed the per-session git worktree, and the project design (internal/planning/archive/project/design.md) for the Workspace→Project rename.

Files in this package:

  • session.go — Meta + lifecycle (Create/Load/Save/Delete/SetProject)
  • agents.go — per-session AgentEntry + Add/SetActive

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddAgent

func AddAgent(layout config.Layout, id, name, provider string) error

AddAgent appends a new agent entry. Errors on duplicate name within the same session.

func Delete

func Delete(_ context.Context, layout config.Layout, id string) error

Delete removes the session folder. The project it points at is left untouched — projects are shared, so deleting a session must not delete its files.

func List

func List(layout config.Layout) ([]string, error)

List returns every session ID, sorted.

func SaveAgents

func SaveAgents(layout config.Layout, id string, agents []AgentEntry) error

SaveAgents atomically rewrites sessions/<id>/agents.json. nil becomes an empty array on disk so consumers don't have to handle `null`.

func SaveMeta

func SaveMeta(layout config.Layout, id string, meta Meta) error

SaveMeta atomically rewrites sessions/<id>/meta.json.

func SetActiveAgent

func SetActiveAgent(layout config.Layout, id, name string) error

SetActiveAgent updates meta.json's active_agent field. The named agent must already exist in agents.json.

func SetCLISessionID added in v0.15.5

func SetCLISessionID(layout config.Layout, id, name, cliID string) error

SetCLISessionID writes (or clears, with "") the CLI resume id on the agent entry. No-op when the entry doesn't exist.

func SetMaxTurns added in v0.15.5

func SetMaxTurns(layout config.Layout, id, name string, maxTurns int) error

SetMaxTurns persists the per-spawn turn cap on the agent entry, creating it if missing. 0 = unlimited (provider default).

func SetProject added in v0.14.21

func SetProject(_ context.Context, layout config.Layout, id, newProjectID string) error

SetProject changes the project a session points at. No filesystem work — the next agent spawn will resolve the new project's folder as cwd. Conversation, agent registry, and logs are preserved. Empty newProjectID unscopes the session.

func SetThinkingTokens added in v0.18.7

func SetThinkingTokens(layout config.Layout, id, name, v string) error

SetThinkingTokens persists the resolved MAX_THINKING_TOKENS env value on the agent entry, creating it if missing. Empty = unset (provider default, thinking on); "0" = disabled; "<n>" = budget. Always persisted (including "") so switching a reused session back to full thinking clears a prior value.

Types

type AgentEntry

type AgentEntry struct {
	Name             string            `json:"name"`
	Provider         string            `json:"provider"`
	CLISessionID     string            `json:"cli_session_id,omitempty"`
	Status           string            `json:"status"`
	CreatedAt        time.Time         `json:"created_at"`
	LastActive       time.Time         `json:"last_active,omitempty"`
	ProviderSessions map[string]string `json:"provider_sessions,omitempty"`
	// MaxTurns caps agentic turns on the next spawn (--max-turns).
	// 0 = unlimited (provider default). Set per workflow agent node.
	MaxTurns int `json:"max_turns,omitempty"`
	// ThinkingTokens is the resolved MAX_THINKING_TOKENS env value applied on
	// the next spawn (claude). Empty = unset (provider default, thinking on);
	// "0" = disabled; "<n>" = budget. Set per workflow agent node from its
	// thinking + max_thinking_tokens inputs.
	ThinkingTokens string `json:"thinking_tokens,omitempty"`
}

AgentEntry is one row in sessions/<id>/agents.json. CLISessionID is the resume key — wick captures it from the first stream-json event emitted by the CLI and persists it so subsequent spawns can pass `--resume <id>`. See agents-design.md §5.2.

ProviderSessions maps "type/name" provider keys to their last-known CLI session ID. When switching providers, the outgoing resume ID is saved here so switching back can resume the old conversation.

type CreateOptions

type CreateOptions struct {
	ID        string
	ProjectID string
	Origin    Origin
	ChannelID string
	// Preset is the preset name to associate with this session.
	// Stored in meta.json; factory loads content from presets/<name>/agent.md on spawn.
	Preset string
	// UserID is the wick user who is creating this session. Stored in
	// meta.json for ownership checks in MCP handlers.
	UserID string
}

CreateOptions describes a new session. ProjectID is optional — a session may be created without one, in which case the pool falls back to the tools-config default project (or a per-session temp dir if no default is set).

type Meta

type Meta struct {
	// ProjectID references the project this session belongs to. Empty =
	// unscoped (pool falls back to the tools-config default project).
	ProjectID    string    `json:"project_id,omitempty"`
	Origin       Origin    `json:"origin"`
	ChannelID    string    `json:"channel_id,omitempty"`
	ActiveAgent  string    `json:"active_agent,omitempty"`
	Status       Status    `json:"status"`
	CreatedAt    time.Time `json:"created_at"`
	LastActive   time.Time `json:"last_active"`
	PendingInput []string  `json:"pending_input,omitempty"`
	// Label is the session title shown in the sidebar. By default it is
	// the first user message truncated to 60 runes (see
	// pool.setLabelIfEmpty), cached here so sidebar rendering never needs
	// to open conversation.jsonl. Once a human or the agent sets an
	// explicit title (TitleCustom=true) the auto-derived label no longer
	// overwrites it.
	Label string `json:"label,omitempty"`
	// TitleCustom marks Label as an explicit title set by a human or the
	// agent (via the wick_set_title MCP tool), as opposed to the
	// auto-derived first-message label. When true, the first-user-message
	// auto-label is skipped so it never clobbers the chosen title.
	TitleCustom bool `json:"title_custom,omitempty"`
	// Preset is the name of the preset active for this session.
	// Factory reads the preset content from presets/<name>/agent.md on
	// every spawn so edits to the preset take effect on next respawn.
	Preset string `json:"preset,omitempty"`
	// Subscribers is the list of user IDs that opted in to receive
	// browser push notifications for this session's lifecycle
	// transitions (queue → working → idle). Persisted in meta.json so
	// the subscription survives wick restart. Sessions are shared
	// across users (anyone can open them) but pushes target only the
	// IDs in this list — no auto-subscribe on session create.
	Subscribers []string `json:"subscribers,omitempty"`
	// UserID is the wick user ID that created this session. Empty for
	// legacy sessions created before ownership tracking was added.
	// When non-empty, only the owning user (or app owner) may access it.
	UserID string `json:"user_id,omitempty"`
}

Meta is the persisted-on-disk shape of a session. PendingInput is the message buffer that survives wick restart so a session that was queued at shutdown gets its messages drained on next boot.

func (*Meta) AddSubscriber added in v0.15.0

func (m *Meta) AddSubscriber(userID string) bool

AddSubscriber appends userID to Subscribers if not already present. Returns true if the list changed (i.e. caller should persist Meta).

func (*Meta) IsSubscribed added in v0.15.0

func (m *Meta) IsSubscribed(userID string) bool

IsSubscribed returns true when userID has opted in to receive lifecycle push notifications for this session.

func (*Meta) RemoveSubscriber added in v0.15.0

func (m *Meta) RemoveSubscriber(userID string) bool

RemoveSubscriber drops userID from Subscribers. Returns true if the list changed.

type Origin

type Origin string

Origin identifies where the session was first created from. Slack threads use thread_ts as the session ID; UI/API sessions use a UUID generated by wick.

const (
	OriginSlack    Origin = "slack"
	OriginTelegram Origin = "telegram"
	OriginREST     Origin = "rest"
	OriginUI       Origin = "ui"
)

type Session

type Session struct {
	ID     string       `json:"id"`
	Meta   Meta         `json:"meta"`
	Agents []AgentEntry `json:"agents"`
}

Session is the in-memory view: ID + meta + agent registry. Mirrors the trio of files at sessions/<id>/.

func Create

func Create(_ context.Context, layout config.Layout, opt CreateOptions) (Session, error)

Create materializes sessions/<id>/: meta.json, agents.json (empty array), agent.md snapshot. No filesystem work touches the project folder — project folders live under projects/<id>/ and are shared across sessions; the session simply stores the project id as a reference.

func Load

func Load(layout config.Layout, id string) (Session, error)

Load reads meta.json + agents.json. Missing agents.json is treated as an empty list.

type Status

type Status string

Status is the high-level pool view: idle (no subprocess), queued (waiting for a slot), running (subprocess alive).

const (
	StatusIdle    Status = "idle"
	StatusQueued  Status = "queued"
	StatusRunning Status = "running"
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL