33e1857a1d
- Add additionalDirectories to NewSessionOptions - #resetToNewSession now seeds #additionalDirectories from options, so all new-session transitions (handoff, branch, /new) get the roots - AgentSession.newSession passes settings dirs via options instead of calling setAdditionalDirectories after the fact Co-authored-by: oh-my-pi <https://omp.sh>
261 lines
8.3 KiB
TypeScript
261 lines
8.3 KiB
TypeScript
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
import type { ImageContent, MessageAttribution, ServiceTierByFamily, TextContent } from "@oh-my-pi/pi-ai";
|
|
import type { StructuredSubagentSchemaMode } from "../task/types";
|
|
|
|
export const CURRENT_SESSION_VERSION = 3;
|
|
|
|
export const SESSION_TITLE_SLOT_BYTES = 256;
|
|
|
|
export const SESSION_TITLE_SLOT_ENTRY_TYPE = "title";
|
|
|
|
export const TITLE_CHANGE_ENTRY_TYPE = "title_change";
|
|
|
|
export type SessionTitleSource = "auto" | "user";
|
|
|
|
/** Fixed-width first-line slot carrying the mutable current session title. */
|
|
export interface SessionTitleSlotEntry {
|
|
type: typeof SESSION_TITLE_SLOT_ENTRY_TYPE;
|
|
v: 1;
|
|
title: string;
|
|
source?: SessionTitleSource;
|
|
updatedAt: string;
|
|
pad: string;
|
|
}
|
|
|
|
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?: SessionTitleSource;
|
|
timestamp: string;
|
|
cwd: string;
|
|
/**
|
|
* Additional workspace directories beyond `cwd` (multi-root workspace).
|
|
* Absolute, normalized, deduplicated. Absent on legacy single-cwd sessions.
|
|
* See {@link SessionWorkspace} in `./session-workspace`.
|
|
*/
|
|
additionalDirectories?: string[];
|
|
parentSession?: string;
|
|
/** Provider prompt-cache identity inherited by exact-route full forks. */
|
|
providerPromptCacheKey?: string;
|
|
}
|
|
|
|
export interface NewSessionOptions {
|
|
parentSession?: string;
|
|
/** Provider prompt-cache identity to seed on the new session header. */
|
|
providerPromptCacheKey?: string;
|
|
/** Skip flushing the current session and delete it instead of saving. */
|
|
drop?: boolean;
|
|
/** Additional workspace directories to seed on the new session. */
|
|
additionalDirectories?: string[];
|
|
}
|
|
|
|
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;
|
|
/**
|
|
* The user-configured selector at the time of this change: `"auto"` when auto
|
|
* mode was active, otherwise the concrete level. Absent on entries written
|
|
* before auto-mode persistence existed; readers fall back to `thinkingLevel`.
|
|
*/
|
|
configured?: 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: ServiceTierByFamily | 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;
|
|
/**
|
|
* Dead-end warning from the post-pass progress guard: the pass completed
|
|
* but freed too little for maintenance to continue. Rendered on the
|
|
* compaction divider.
|
|
*/
|
|
warning?: string;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/** Append-only audit entry recording a session title change. */
|
|
export interface TitleChangeEntry extends SessionEntryBase {
|
|
type: typeof TITLE_CHANGE_ENTRY_TYPE;
|
|
title: string;
|
|
previousTitle?: string;
|
|
source: SessionTitleSource;
|
|
trigger?: string;
|
|
}
|
|
|
|
declare module "@oh-my-pi/pi-agent-core/compaction/entries" {
|
|
interface CustomCompactionSessionEntries {
|
|
titleChange: TitleChangeEntry;
|
|
}
|
|
}
|
|
|
|
/** 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[];
|
|
}
|
|
|
|
/** 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;
|
|
/** Enforcement policy recorded with the output schema for faithful revival. */
|
|
outputSchemaMode?: StructuredSubagentSchemaMode;
|
|
/** Whether revival must retain only the explicitly persisted tool names. */
|
|
restrictToolNames?: boolean;
|
|
/** 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
|
|
| TitleChangeEntry
|
|
| TtsrInjectionEntry
|
|
| SessionInitEntry
|
|
| ModeChangeEntry;
|
|
|
|
/** Raw logical file entry after loaders strip any fixed-width title slot. */
|
|
export type FileEntry = SessionHeader | SessionEntry;
|
|
|
|
/** Physical JSONL entry before slot-aware loaders fold the title slot. */
|
|
export type RawFileEntry = SessionTitleSlotEntry | FileEntry;
|
|
|
|
/** 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;
|
|
totalTokens: number;
|
|
orchestrationInput: number;
|
|
orchestrationOutput: number;
|
|
orchestrationCacheRead: number;
|
|
premiumRequests: number;
|
|
cost: number;
|
|
}
|