ef5e5fd27c
- Fixed cold revival flow so parked subagents are restored from persisted sessions at startup. - Fixed session-init persistence to include spawns and readSummarize fields for replay accuracy. - Fixed latest-session lookup by adding peekSessionInit for lock-free persisted contract access. - Added lifecycle and session tests for cold-revive success, decline, and retry paths.
199 lines
6.0 KiB
TypeScript
199 lines
6.0 KiB
TypeScript
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
import type { ImageContent, MessageAttribution, ServiceTier, TextContent } from "@oh-my-pi/pi-ai";
|
|
|
|
export const CURRENT_SESSION_VERSION = 3;
|
|
|
|
export const EPHEMERAL_MODEL_CHANGE_ROLE = "fallback";
|
|
|
|
export interface SessionHeader {
|
|
type: "session";
|
|
version?: number; // v1 sessions don't have this
|
|
id: string;
|
|
title?: string; // Auto-generated title from first message
|
|
titleSource?: "auto" | "user";
|
|
timestamp: string;
|
|
cwd: string;
|
|
parentSession?: string;
|
|
}
|
|
|
|
export interface NewSessionOptions {
|
|
parentSession?: string;
|
|
/** Skip flushing the current session and delete it instead of saving. */
|
|
drop?: boolean;
|
|
}
|
|
|
|
export interface SessionEntryBase {
|
|
type: string;
|
|
id: string;
|
|
parentId: string | null;
|
|
timestamp: string;
|
|
}
|
|
|
|
export interface SessionMessageEntry extends SessionEntryBase {
|
|
type: "message";
|
|
message: AgentMessage;
|
|
}
|
|
|
|
export interface ThinkingLevelChangeEntry extends SessionEntryBase {
|
|
type: "thinking_level_change";
|
|
thinkingLevel?: string | null;
|
|
}
|
|
|
|
export interface ModelChangeEntry extends SessionEntryBase {
|
|
type: "model_change";
|
|
/** Model in "provider/modelId" format */
|
|
model: string;
|
|
/** Role: "default", "smol", "slow", etc. Undefined treated as "default" */
|
|
role?: string;
|
|
}
|
|
|
|
export interface ServiceTierChangeEntry extends SessionEntryBase {
|
|
type: "service_tier_change";
|
|
serviceTier: ServiceTier | null;
|
|
}
|
|
|
|
export interface CompactionEntry<T = unknown> extends SessionEntryBase {
|
|
type: "compaction";
|
|
summary: string;
|
|
shortSummary?: string;
|
|
firstKeptEntryId: string;
|
|
tokensBefore: number;
|
|
/** Extension-specific data (e.g., ArtifactIndex, version markers for structured compaction) */
|
|
details?: T;
|
|
/** Hook-provided data to persist across compaction */
|
|
preserveData?: Record<string, unknown>;
|
|
/** True if generated by an extension, undefined/false if pi-generated (backward compatible) */
|
|
fromExtension?: boolean;
|
|
}
|
|
|
|
export interface BranchSummaryEntry<T = unknown> extends SessionEntryBase {
|
|
type: "branch_summary";
|
|
fromId: string;
|
|
summary: string;
|
|
/** Extension-specific data (not sent to LLM) */
|
|
details?: T;
|
|
/** True if generated by an extension, false if pi-generated */
|
|
fromExtension?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Custom entry for extensions to store extension-specific data in the session.
|
|
* Use customType to identify your extension's entries.
|
|
*
|
|
* Purpose: Persist extension state across session reloads. On reload, extensions can
|
|
* scan entries for their customType and reconstruct internal state.
|
|
*
|
|
* Does NOT participate in LLM context (ignored by buildSessionContext).
|
|
* For injecting content into context, see CustomMessageEntry.
|
|
*/
|
|
export interface CustomEntry<T = unknown> extends SessionEntryBase {
|
|
type: "custom";
|
|
customType: string;
|
|
data?: T;
|
|
}
|
|
|
|
/** Label entry for user-defined bookmarks/markers on entries. */
|
|
export interface LabelEntry extends SessionEntryBase {
|
|
type: "label";
|
|
targetId: string;
|
|
label: string | undefined;
|
|
}
|
|
|
|
/** TTSR injection entry - tracks which time-traveling rules have been injected this session. */
|
|
export interface TtsrInjectionEntry extends SessionEntryBase {
|
|
type: "ttsr_injection";
|
|
/** Names of rules that were injected */
|
|
injectedRules: string[];
|
|
}
|
|
|
|
/** Persisted MCP discovery selection state for a session branch. */
|
|
export interface MCPToolSelectionEntry extends SessionEntryBase {
|
|
type: "mcp_tool_selection";
|
|
/** MCP tool names selected for visibility in discovery mode. */
|
|
selectedToolNames: string[];
|
|
}
|
|
|
|
/** Session init entry - captures initial context for subagent sessions (debugging/replay). */
|
|
export interface SessionInitEntry extends SessionEntryBase {
|
|
type: "session_init";
|
|
/** Full system prompt sent to the model */
|
|
systemPrompt: string;
|
|
/** Initial task/user message */
|
|
task: string;
|
|
/** Tools available to the agent */
|
|
tools: string[];
|
|
/** Output schema if structured output was requested */
|
|
outputSchema?: unknown;
|
|
/** Spawn allowlist the subagent ran with ("" = none, "*" = any, else CSV); absent on pre-spawns files. */
|
|
spawns?: string;
|
|
/** The agent's `readSummarize` setting (`false` = read summarization disabled); absent uses the session default. */
|
|
readSummarize?: boolean;
|
|
}
|
|
|
|
/** Mode change entry - tracks agent mode transitions (e.g. plan mode). */
|
|
export interface ModeChangeEntry extends SessionEntryBase {
|
|
type: "mode_change";
|
|
/** Current mode name, or "none" when exiting a mode */
|
|
mode: string;
|
|
/** Optional mode-specific data (e.g. plan file path) */
|
|
data?: Record<string, unknown>;
|
|
}
|
|
|
|
/**
|
|
* Custom message entry for extensions to inject messages into LLM context.
|
|
* Use customType to identify your extension's entries.
|
|
*
|
|
* Unlike CustomEntry, this DOES participate in LLM context.
|
|
* The content participates in LLM context through convertToLlm().
|
|
* Use details for extension-specific metadata (not sent to LLM).
|
|
*
|
|
* display controls TUI rendering:
|
|
* - false: hidden entirely
|
|
* - true: rendered with distinct styling (different from user messages)
|
|
*/
|
|
export interface CustomMessageEntry<T = unknown> extends SessionEntryBase {
|
|
type: "custom_message";
|
|
customType: string;
|
|
content: string | (TextContent | ImageContent)[];
|
|
details?: T;
|
|
display: boolean;
|
|
/** Who initiated this message for billing/attribution semantics. */
|
|
attribution?: MessageAttribution;
|
|
}
|
|
|
|
/** Session entry - has id/parentId for tree structure (returned by "read" methods in SessionManager) */
|
|
export type SessionEntry =
|
|
| SessionMessageEntry
|
|
| ThinkingLevelChangeEntry
|
|
| ModelChangeEntry
|
|
| ServiceTierChangeEntry
|
|
| CompactionEntry
|
|
| BranchSummaryEntry
|
|
| CustomEntry
|
|
| CustomMessageEntry
|
|
| LabelEntry
|
|
| TtsrInjectionEntry
|
|
| MCPToolSelectionEntry
|
|
| SessionInitEntry
|
|
| ModeChangeEntry;
|
|
|
|
/** Raw file entry (includes header) */
|
|
export type FileEntry = SessionHeader | SessionEntry;
|
|
|
|
/** Tree node for getTree() - defensive copy of session structure */
|
|
export interface SessionTreeNode {
|
|
entry: SessionEntry;
|
|
children: SessionTreeNode[];
|
|
/** Resolved label for this entry, if any */
|
|
label?: string;
|
|
}
|
|
|
|
export interface UsageStatistics {
|
|
input: number;
|
|
output: number;
|
|
cacheRead: number;
|
|
cacheWrite: number;
|
|
premiumRequests: number;
|
|
cost: number;
|
|
}
|