/** * Everything this tool knows about Pi's session file layout. * * Verified against the installed Pi 0.83.0 (`dist/core/session-manager.js`, * `dist/config.js`), not assumed: * * - the home is Pi's agent directory: `$PI_CODING_AGENT_DIR`, else `~/.pi/agent`; * - sessions live in `/sessions//_.jsonl`; * - a file is JSONL: one `session` header, then entries with `id`/`parentId`/`timestamp`; * - an assistant message without a numeric `usage` object crashes Pi (C-11). * * When Pi changes, this file changes. Nothing outside this folder holds these facts. */ import type { ToolEffect } from "./contract.js"; /** Pi's current session file version (`CURRENT_SESSION_VERSION`). */ export declare const PI_SESSION_VERSION = 3; export declare const SESSIONS_DIR_NAME = "sessions"; /** * The customType of the provenance entry. It is written as a `custom` entry, which Pi's * `buildSessionContext` drops on the floor: the marker is stored and shown, never sent to * the model (FR-47, FR-48). `src/host/pi-extension/` registers the renderer that shows it. */ export declare const MARKER_CUSTOM_TYPE = "resume-from-provenance"; /** Prefix of the title of a session file that cannot be read (T-PI-13). */ export declare const UNREADABLE_TITLE_PREFIX = "(unreadable) "; /** What replaces a tool result body (FR-24, FR-25). */ export declare const DROPPED_BODY_NOTE = "(content dropped: imported session, may be stale)"; /** Context window assumed for Pi when configuration overrides none (FR-18). */ export declare const DEFAULT_WINDOW_TOKENS = 200000; /** What an imported assistant turn declares about itself. It cost nothing to import. */ export declare const IMPORTED_API = "resume-from"; export declare const IMPORTED_PROVIDER = "resume-from"; export declare const IMPORTED_MODEL = "imported-session"; /** Pi's default agent directory. Mirrors Pi's own `getAgentDir()`. */ export declare function defaultPiHome(): string; /** Pi's encoding of a working directory into one directory name. */ export declare function encodeCwd(cwd: string): string; export declare function sessionsRoot(home: string): string; export declare function sessionDirFor(home: string, cwd: string): string; /** Pi's own file naming: the ISO timestamp with `:` and `.` replaced, then the id. */ export declare function sessionFileName(isoTimestamp: string, sessionId: string): string; /** The session id Pi would read out of a session file name, or null. */ export declare function sessionIdFromFileName(fileName: string): string | null; export interface PiSessionHeader { type: "session"; version?: number; id: string; timestamp: string; cwd: string; } export interface PiEntryBase { type: string; id: string; parentId: string | null; timestamp: string; } export type PiEntry = PiEntryBase & Record; export interface PiTextBlock { type: "text"; text: string; textSignature?: string; } export interface PiThinkingBlock { type: "thinking"; thinking: string; thinkingSignature?: string; } export interface PiImageBlock { type: "image"; data: string; mimeType: string; } export interface PiToolCallBlock { type: "toolCall"; id: string; name: string; arguments: Record; } export type PiContentBlock = PiTextBlock | PiThinkingBlock | PiToolCallBlock | PiImageBlock; /** The six numbers Pi dereferences without a guard. Missing any of them is C-11. */ export interface PiUsage { input: number; output: number; cacheRead: number; cacheWrite: number; reasoning?: number; totalTokens: number; cost: { input: number; output: number; cacheRead: number; cacheWrite: number; total: number; }; } export interface PiUserMessage { role: "user"; content: string | PiContentBlock[]; timestamp: number; } export interface PiAssistantMessage { role: "assistant"; content: PiContentBlock[]; api: string; provider: string; model: string; usage: PiUsage; stopReason: string; timestamp: number; } export interface PiToolResultMessage { role: "toolResult"; toolCallId: string; toolName: string; content: PiContentBlock[]; isError: boolean; timestamp: number; } export type PiMessage = PiUserMessage | PiAssistantMessage | PiToolResultMessage; export interface PiMessageEntry extends PiEntryBase { type: "message"; message: PiMessage; } export interface PiCompactionEntry extends PiEntryBase { type: "compaction"; summary: string; firstKeptEntryId?: string; retainedTail?: PiMessage[]; tokensBefore: number; } export interface PiCustomEntry extends PiEntryBase { type: "custom"; customType: string; data?: unknown; } /** * Entry types Pi writes that carry no turn: settings, bookmarks, and extension state. * They are known, so they are not reported as skipped. * * `custom_message` is deliberately absent. Pi's `sessionEntryToContextMessages` turns it * into a real context message, so an extension can put conversation content there. This * adapter does not know that content's shape, so it is skipped — and counted, so the skip * is visible rather than a silent shortening of the session. */ export declare const NON_TURN_ENTRY_TYPES: ReadonlySet; export declare function isRecord(value: unknown): value is Record; export declare function asHeader(value: unknown): PiSessionHeader | null; export declare function asEntry(value: unknown): PiEntry | null; export declare function entryMessage(entry: PiEntry): Record | null; /** The visible text of a message content, hidden reasoning excluded (FR-28). */ export declare function visibleText(content: unknown): string; export declare function toolCallBlocks(content: unknown): PiToolCallBlock[]; /** Did the call change the repository? (FR-26) A shell is never assumed either way. */ export declare function toolEffectFor(toolName: string): ToolEffect; /** One line, whatever the input contained. */ export declare function oneLine(text: string): string; export declare function truncate(text: string, limit: number): string; export declare function shortArguments(argumentsText: string): string; export declare function shortTitle(text: string): string; /** ISO-8601 UTC, or null when the source recorded nothing usable. */ export declare function toIsoUtc(value: unknown): string | null; export declare function emptyUsage(): PiUsage;