session

package
v0.64.2 Latest Latest
Warning

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

Go to latest
Published: May 7, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Index

Constants

View Source
const CurrentVersion = 3

CurrentVersion is the session format version for JSONL tree sessions.

Variables

This section is empty.

Functions

func DefaultSessionDir

func DefaultSessionDir(cwd string) string

DefaultSessionDir returns the default session storage directory for a cwd. Convention: ~/.kit/sessions/<encoded-cwd>, where path separators are encoded as "--" with no leading or trailing dashes — e.g. /home/user/proj becomes home--user--proj. See encodeCwdForDir for the full encoding rules (including Windows path handling).

func DeleteSession

func DeleteSession(path string) error

DeleteSession removes a session file from disk.

func GenerateEntryID

func GenerateEntryID() string

GenerateEntryID creates a unique entry identifier (16 hex chars).

func GenerateSessionID

func GenerateSessionID() string

GenerateSessionID creates a unique session identifier (32 hex chars).

func MarshalEntry

func MarshalEntry(entry any) ([]byte, error)

MarshalEntry serializes any entry to a JSON line (no trailing newline).

func UnmarshalEntry

func UnmarshalEntry(data []byte) (any, error)

UnmarshalEntry deserializes a JSON line into the appropriate entry type. Returns one of: *SessionHeader, *MessageEntry, *ModelChangeEntry, *BranchSummaryEntry, *LabelEntry, *SessionInfoEntry.

Types

type BranchSummaryEntry

type BranchSummaryEntry struct {
	Entry
	FromID  string `json:"from_id"` // leaf of the summarized branch
	Summary string `json:"summary"`
}

BranchSummaryEntry provides LLM-generated context from an abandoned branch. When the user navigates away from a branch, a summary of that branch's conversation is stored so the LLM retains context about what was explored.

func NewBranchSummaryEntry

func NewBranchSummaryEntry(parentID, fromID, summary string) *BranchSummaryEntry

NewBranchSummaryEntry creates a BranchSummaryEntry.

type CompactionEntry added in v0.19.0

type CompactionEntry struct {
	Entry
	Summary          string   `json:"summary"`
	FirstKeptEntryID string   `json:"first_kept_entry_id"`
	TokensBefore     int      `json:"tokens_before"`
	TokensAfter      int      `json:"tokens_after"`
	MessagesRemoved  int      `json:"messages_removed"`
	ReadFiles        []string `json:"read_files,omitempty"`
	ModifiedFiles    []string `json:"modified_files,omitempty"`
}

CompactionEntry records an LLM-generated summary of older messages. Instead of deleting old messages, the tree manager skips entries before FirstKeptEntryID when building the LLM context, preserving full history.

func NewCompactionEntry added in v0.19.0

func NewCompactionEntry(parentID, summary, firstKeptEntryID string, tokensBefore, tokensAfter, messagesRemoved int, readFiles, modifiedFiles []string) *CompactionEntry

NewCompactionEntry creates a CompactionEntry.

type Entry

type Entry struct {
	Type      EntryType `json:"type"`
	ID        string    `json:"id"`
	ParentID  string    `json:"parent_id,omitempty"`
	Timestamp time.Time `json:"timestamp"`
}

Entry is the common structure shared by all tree entries (everything except the session header). Every entry has an ID, an optional ParentID (empty for root entries), a type tag, and a timestamp.

func NewEntry

func NewEntry(entryType EntryType, parentID string) Entry

NewEntry creates a base Entry with a generated ID and current timestamp.

type EntryType

type EntryType string

EntryType identifies the kind of entry stored in a JSONL session file. Sessions are append-only JSONL files where each line is a typed entry linked by id/parent_id to form a tree structure.

const (
	EntryTypeSession       EntryType = "session"
	EntryTypeMessage       EntryType = "message"
	EntryTypeModelChange   EntryType = "model_change"
	EntryTypeBranchSummary EntryType = "branch_summary"
	EntryTypeLabel         EntryType = "label"
	EntryTypeSessionInfo   EntryType = "session_info"
	EntryTypeExtensionData EntryType = "extension_data"
	EntryTypeCompaction    EntryType = "compaction"
	EntryTypeSystemPrompt  EntryType = "system_prompt"
)

type ExtensionDataEntry added in v0.3.0

type ExtensionDataEntry struct {
	Entry
	ExtType string `json:"ext_type"` // Extension-defined type string (e.g. "plan-mode:state")
	Data    string `json:"data"`     // Extension-defined data (JSON or plain text)
}

ExtensionDataEntry stores custom extension data in the session tree. Extensions use this to persist state that survives across session restarts.

func NewExtensionDataEntry added in v0.3.0

func NewExtensionDataEntry(parentID, extType, data string) *ExtensionDataEntry

NewExtensionDataEntry creates an ExtensionDataEntry.

type LabelEntry

type LabelEntry struct {
	Entry
	TargetID string `json:"target_id"`
	Label    string `json:"label"`
}

LabelEntry bookmarks a specific entry with a user-defined label.

func NewLabelEntry

func NewLabelEntry(parentID, targetID, label string) *LabelEntry

NewLabelEntry creates a LabelEntry.

type MessageEntry

type MessageEntry struct {
	Entry
	Role     string          `json:"role"`
	Parts    json.RawMessage `json:"parts"` // type-tagged parts array
	Model    string          `json:"model,omitempty"`
	Provider string          `json:"provider,omitempty"`
}

MessageEntry stores a conversation message as a tree entry. The message content uses the same type-tagged parts format as the existing session persistence layer, enabling reuse of MarshalParts/UnmarshalParts.

func NewMessageEntry

func NewMessageEntry(parentID string, msg message.Message) (*MessageEntry, error)

NewMessageEntry creates a MessageEntry from a message.Message, linking it to the given parent entry in the tree.

func (*MessageEntry) ToMessage

func (e *MessageEntry) ToMessage() (message.Message, error)

ToMessage converts a MessageEntry back to a message.Message by unmarshaling the type-tagged parts.

type ModelChangeEntry

type ModelChangeEntry struct {
	Entry
	Provider string `json:"provider"`
	ModelID  string `json:"model_id"`
}

ModelChangeEntry records a provider/model switch in the session tree.

func NewModelChangeEntry

func NewModelChangeEntry(parentID, provider, modelID string) *ModelChangeEntry

NewModelChangeEntry creates a ModelChangeEntry.

type SessionHeader

type SessionHeader struct {
	Type          EntryType `json:"type"`                     // always "session"
	Version       int       `json:"version"`                  // format version (3)
	ID            string    `json:"id"`                       // session UUID
	Timestamp     time.Time `json:"timestamp"`                // creation time
	Cwd           string    `json:"cwd"`                      // working directory
	ParentSession string    `json:"parent_session,omitempty"` // path to parent if forked

	// Subagent fields (set when session is created by a subagent)
	ParentSessionID string `json:"parent_session_id,omitempty"` // UUID of parent session
	SubagentTask    string `json:"subagent_task,omitempty"`     // original task prompt
}

SessionHeader is the first line in a JSONL session file. It carries metadata about the session and does NOT participate in the tree structure (it has no ID or ParentID).

type SessionInfo

type SessionInfo struct {
	// Path is the absolute path to the JSONL session file.
	Path string

	// ID is the session UUID from the header.
	ID string

	// Cwd is the working directory the session was created in.
	Cwd string

	// Name is the user-defined display name (from session_info entries).
	Name string

	// ParentSessionPath is the parent session path if this session was forked.
	ParentSessionPath string

	// ParentSessionID is the UUID of the parent session (for subagent sessions).
	ParentSessionID string

	// SubagentTask is the original task prompt (for subagent sessions).
	SubagentTask string

	// Created is when the session was first created.
	Created time.Time

	// Modified is the timestamp of the last activity (latest message).
	Modified time.Time

	// MessageCount is the number of message entries in the session.
	MessageCount int

	// FirstMessage is a preview of the first user message.
	FirstMessage string
}

SessionInfo contains metadata about a discovered session, used for listing and session picker display.

func ListAllSessions

func ListAllSessions() ([]SessionInfo, error)

ListAllSessions finds all sessions across all working directories, sorted by modification time (newest first).

func ListSessions

func ListSessions(cwd string) ([]SessionInfo, error)

ListSessions finds all sessions for a given working directory, sorted by modification time (newest first).

type SessionInfoEntry

type SessionInfoEntry struct {
	Entry
	Name string `json:"name"`
}

SessionInfoEntry stores a user-defined display name for the session.

func NewSessionInfoEntry

func NewSessionInfoEntry(parentID, name string) *SessionInfoEntry

NewSessionInfoEntry creates a SessionInfoEntry.

type SystemPromptEntry added in v0.40.0

type SystemPromptEntry struct {
	Type      EntryType `json:"type"`      // always "system_prompt"
	ID        string    `json:"id"`        // unique entry ID
	Timestamp time.Time `json:"timestamp"` // when captured
	Content   string    `json:"content"`   // the system prompt text
	Model     string    `json:"model"`     // the model used (e.g., "claude-sonnet-4-5")
	Provider  string    `json:"provider"`  // the provider used (e.g., "anthropic")
}

SystemPromptEntry records the system prompt and model used for the session. This is primarily for sharing/debugging to see what instructions were active during the conversation. It does NOT participate in the tree structure (no ParentID) and is not used when building LLM context.

func NewSystemPromptEntry added in v0.40.0

func NewSystemPromptEntry(content, model, provider string) *SystemPromptEntry

NewSystemPromptEntry creates a SystemPromptEntry.

type TreeManager

type TreeManager struct {
	// contains filtered or unexported fields
}

TreeManager manages a tree-structured JSONL session. It is the replacement for the linear session.Manager:

  • JSONL append-only format (one JSON object per line)
  • Tree structure via id/parent_id on every entry
  • Leaf pointer tracking current position
  • Context building walks from leaf to root
  • Auto-discovery by working directory

func ContinueRecent

func ContinueRecent(cwd string) (*TreeManager, error)

ContinueRecent finds the most recently modified session for the given cwd, or creates a new one if none exists.

func CreateTreeSession

func CreateTreeSession(cwd string) (*TreeManager, error)

CreateTreeSession creates a new tree session persisted at the default location for the given working directory.

func InMemoryTreeSession

func InMemoryTreeSession(cwd string) *TreeManager

InMemoryTreeSession creates a tree session that is not persisted to disk.

func OpenTreeSession

func OpenTreeSession(path string) (*TreeManager, error)

OpenTreeSession opens an existing JSONL session file.

func (*TreeManager) AddFantasyMessages deprecated

func (tm *TreeManager) AddFantasyMessages(msgs []fantasy.Message) error

Deprecated: Use AddLLMMessages instead.

func (*TreeManager) AddLLMMessages added in v0.30.0

func (tm *TreeManager) AddLLMMessages(msgs []fantasy.Message) error

AddLLMMessages appends multiple LLM messages as entries. This is used when syncing from the agent's ConversationMessages after a step. All entries are buffered and flushed to disk in a single batch.

func (*TreeManager) AppendBranchSummary

func (tm *TreeManager) AppendBranchSummary(fromID, summary string) (string, error)

AppendBranchSummary adds a summary of an abandoned branch.

func (*TreeManager) AppendCompaction added in v0.19.0

func (tm *TreeManager) AppendCompaction(summary, firstKeptEntryID string, tokensBefore, tokensAfter, messagesRemoved int, readFiles, modifiedFiles []string) (string, error)

AppendCompaction adds a compaction entry to the tree. The entry records the summary and the ID of the first entry that should be preserved in the LLM context. Messages before that entry are replaced by the summary.

The compaction entry becomes a new "root" for the post-compaction branch with no parent (empty ParentID). This breaks the parent chain so that old compacted messages are no longer traversed when building context. The kept messages are explicitly collected via FirstKeptEntryID in BuildContext.

func (*TreeManager) AppendExtensionData added in v0.3.0

func (tm *TreeManager) AppendExtensionData(extType, data string) (string, error)

AppendExtensionData adds an extension data entry to the tree and persists it. Extensions use this to store custom state that survives across session restarts.

func (*TreeManager) AppendFantasyMessage deprecated

func (tm *TreeManager) AppendFantasyMessage(msg fantasy.Message) (string, error)

Deprecated: Use AppendLLMMessage instead.

func (*TreeManager) AppendLLMMessage added in v0.30.0

func (tm *TreeManager) AppendLLMMessage(msg fantasy.Message) (string, error)

AppendLLMMessage converts an LLM message and appends it.

func (*TreeManager) AppendLabel

func (tm *TreeManager) AppendLabel(targetID, label string) (string, error)

AppendLabel sets a label on a target entry.

func (*TreeManager) AppendMessage

func (tm *TreeManager) AppendMessage(msg message.Message) (string, error)

AppendMessage adds a message entry to the tree and persists it.

func (*TreeManager) AppendModelChange

func (tm *TreeManager) AppendModelChange(provider, modelID string) (string, error)

AppendModelChange records a model/provider change.

func (*TreeManager) AppendSessionInfo

func (tm *TreeManager) AppendSessionInfo(name string) (string, error)

AppendSessionInfo sets a display name for the session.

func (*TreeManager) Branch

func (tm *TreeManager) Branch(entryID string) error

Branch moves the leaf pointer to the given entry ID, creating a branch point. Subsequent appends will extend from this new position.

func (*TreeManager) BuildContext

func (tm *TreeManager) BuildContext() (messages []fantasy.Message, provider string, modelID string)

BuildContext walks from the current leaf to the root and returns the conversation messages suitable for sending to the LLM. Compaction entries cause older messages to be replaced by the summary. Branch summaries are converted to user messages to provide context from abandoned branches. Also returns the latest model/provider settings encountered on the path.

func (*TreeManager) Close

func (tm *TreeManager) Close() error

Close flushes any buffered writes and closes the underlying file handle.

func (*TreeManager) DetectCycle added in v0.57.0

func (tm *TreeManager) DetectCycle(fromID string) (cycleDetected bool, cycleEntry string)

DetectCycle walks the parent chain from the given entry ID and returns true if a cycle is detected. This is used for diagnostics.

func (*TreeManager) EntryCount

func (tm *TreeManager) EntryCount() int

EntryCount returns the number of entries (excluding header).

func (*TreeManager) EntryID added in v0.30.0

func (tm *TreeManager) EntryID(entry any) string

EntryID extracts the ID from any entry type.

func (*TreeManager) Flush added in v0.59.0

func (tm *TreeManager) Flush() error

Flush writes any buffered data to the underlying file.

func (*TreeManager) ForkToNewSession added in v0.34.0

func (tm *TreeManager) ForkToNewSession(cwd string, targetID string) (*TreeManager, error)

ForkToNewSession creates a new session file containing the history up to and including the target entry ID. This matches Pi's /fork behavior: it creates a completely new session file with a parent_session reference, copying all entries from the root to the target point.

func (*TreeManager) GetBranch

func (tm *TreeManager) GetBranch(fromID string) []any

GetBranch returns the path of entries from the given entry to the root, ordered from root to the entry. If fromID is empty, uses the current leaf.

func (*TreeManager) GetChildren

func (tm *TreeManager) GetChildren(parentID string) []string

GetChildren returns direct child entry IDs for a given parent.

func (*TreeManager) GetContextEntryIDs added in v0.19.0

func (tm *TreeManager) GetContextEntryIDs() []string

GetContextEntryIDs returns the entry IDs corresponding to the fantasy messages returned by BuildContext, in the same order. Each entry ID maps to the session entry that produced the fantasy message at the same index. This is used by compaction to map a cut point index back to an entry ID.

Note: A single MessageEntry produces at most one fantasy message. Branch summary entries also produce one message each. The returned slice has the same length as the messages slice from BuildContext (excluding the compaction summary system message, which has no entry ID — it gets the empty string "").

func (*TreeManager) GetCwd

func (tm *TreeManager) GetCwd() string

GetCwd returns the working directory this session was created in.

func (*TreeManager) GetEntries

func (tm *TreeManager) GetEntries() []any

GetEntries returns all entries (excluding the session header).

func (*TreeManager) GetEntry

func (tm *TreeManager) GetEntry(id string) any

GetEntry returns the entry with the given ID, or nil if not found.

func (*TreeManager) GetExtensionData added in v0.3.0

func (tm *TreeManager) GetExtensionData(extType string) []*ExtensionDataEntry

GetExtensionData returns all extension data entries matching the given type, walking the current branch from root to leaf. If extType is empty, all extension data entries on the branch are returned.

func (*TreeManager) GetFantasyMessages deprecated

func (tm *TreeManager) GetFantasyMessages() []fantasy.Message

Deprecated: Use GetLLMMessages instead.

func (*TreeManager) GetFilePath

func (tm *TreeManager) GetFilePath() string

GetFilePath returns the JSONL file path, or empty for in-memory sessions.

func (*TreeManager) GetHeader

func (tm *TreeManager) GetHeader() SessionHeader

GetHeader returns a copy of the session header.

func (*TreeManager) GetLLMMessages added in v0.30.0

func (tm *TreeManager) GetLLMMessages() []fantasy.Message

GetLLMMessages builds the context and returns just the messages. This satisfies the same conceptual role as the old Manager.GetMessages().

func (*TreeManager) GetLabel

func (tm *TreeManager) GetLabel(id string) string

GetLabel returns the label for an entry, or empty string if none.

func (*TreeManager) GetLastCompaction added in v0.19.0

func (tm *TreeManager) GetLastCompaction() *CompactionEntry

GetLastCompaction returns the most recent CompactionEntry on the current branch, or nil if none exists. Used to carry forward file tracking.

func (*TreeManager) GetLeafID

func (tm *TreeManager) GetLeafID() string

GetLeafID returns the current leaf position.

func (*TreeManager) GetSessionID

func (tm *TreeManager) GetSessionID() string

GetSessionID returns the session UUID.

func (*TreeManager) GetSessionName

func (tm *TreeManager) GetSessionName() string

GetSessionName returns the user-defined display name, or empty string.

func (*TreeManager) GetTree

func (tm *TreeManager) GetTree() []*TreeNode

GetTree builds the full tree structure from root entries.

func (*TreeManager) IsEmpty added in v0.25.0

func (tm *TreeManager) IsEmpty() bool

IsEmpty returns true if the session has no messages (only header).

func (*TreeManager) IsPersisted

func (tm *TreeManager) IsPersisted() bool

IsPersisted returns true if this session writes to disk.

func (*TreeManager) LogTreeDiagnostics added in v0.57.0

func (tm *TreeManager) LogTreeDiagnostics()

LogTreeDiagnostics logs information about the tree structure for debugging. Call this after OpenTreeSession or when anomalies are detected.

func (*TreeManager) MessageCount

func (tm *TreeManager) MessageCount() int

MessageCount returns the number of message entries.

func (*TreeManager) ResetLeaf

func (tm *TreeManager) ResetLeaf()

ResetLeaf moves the leaf pointer to before the first entry (empty conversation).

func (*TreeManager) ValidateParentChain added in v0.57.0

func (tm *TreeManager) ValidateParentChain(parentID string, newEntryID string) error

ValidateParentChain checks that the parent ID points to an existing entry and that appending this entry would not create a cycle. This should be called before appending any entry to the tree. Returns an error if the parent is invalid or would create a cycle.

type TreeNode

type TreeNode struct {
	Entry    any         // the underlying entry (*MessageEntry, *ModelChangeEntry, etc.)
	ID       string      // entry ID
	ParentID string      // parent entry ID
	Children []*TreeNode // child nodes
}

Jump to

Keyboard shortcuts

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