// ─── Core Types ─────────────────────────────────────────── export interface ModelCost { input: number; output: number; cacheRead: number; cacheWrite: number; } export interface ThinkingLevelMap { off?: string | null; minimal?: string | null; low?: string | null; medium?: string | null; high?: string | null; xhigh?: string | null; max?: string | null; } export interface ModelCompat { supportsStore?: boolean; supportsDeveloperRole?: boolean; supportsFinishReason?: boolean; supportsReasoningEffort?: boolean; supportsUsageInStreaming?: boolean; maxTokensField?: "max_completion_tokens" | "max_tokens"; requiresToolResultName?: boolean; requiresAssistantAfterToolResult?: boolean; requiresThinkingAsText?: boolean; requiresReasoningContentOnAssistantMessages?: boolean; thinkingFormat?: string; cacheControlFormat?: "anthropic"; supportsEagerToolInputStreaming?: boolean; supportsLongCacheRetention?: boolean; sendSessionAffinityHeaders?: boolean; supportsCacheControlOnTools?: boolean; forceAdaptiveThinking?: boolean; allowEmptySignature?: boolean; openRouterRouting?: Record; } export interface Model { id: string; name?: string; api?: ApiType; baseUrl?: string; reasoning?: boolean; thinkingLevelMap?: ThinkingLevelMap; input?: ("text" | "image" | "audio")[]; cost?: ModelCost; contextWindow?: number; maxTokens?: number; compat?: ModelCompat; headers?: Record; enabled?: boolean; } export type ApiType = | "openai-completions" | "openai-responses" | "anthropic-messages" // Still valid values because pi's builtin catalog uses them, but no longer // offered in the provider picker. | "google-generative-ai" | "google-vertex" | "bedrock-converse-stream" | "mistral-conversations" | "azure-openai-responses" | "openai-codex-responses"; export interface ProviderAuth { type: "api_key" | "oauth"; key?: string; env?: Record; } export interface ProviderOAuth { name: string; } /** * One entry in a custom provider's API key pool. Only the key referenced by * `activeKeyId` is mirrored into `apiKey`, which is the field pi itself reads. */ export interface ProviderApiKey { id: string; label?: string; key: string; } export interface Provider { id: string; name: string; type: "builtin" | "custom"; baseUrl?: string; api?: ApiType; apiKey?: string; apiKeys?: ProviderApiKey[]; activeKeyId?: string; /** Legacy config field; automatic key failover is no longer registered. */ autoFailover?: boolean; authHeader?: boolean; headers?: Record; models: Model[]; oauth?: ProviderOAuth; compat?: ModelCompat; disabled?: boolean; // Auth state hasAuth: boolean; authMethod?: "env" | "file" | "cli" | "none"; } // ─── Pi Config Structure ────────────────────────────────── // Pi stores package references as strings in older settings files and as // objects when package-specific skills are configured. export type PiPackage = string | { source: string; skills?: string[] }; export function packageSource(pkg: PiPackage): string { return typeof pkg === "string" ? pkg : pkg.source; } export interface PiSettings { lastChangelogVersion?: string; defaultProvider?: string; defaultModel?: string; defaultThinkingLevel?: PiThinkingLevel; modelThinkingLevels?: Record; defaultProjectTrust?: "ask" | "always" | "never"; theme?: "light" | "dark" | "light/dark"; hideThinkingBlock?: boolean; expandRunSteps?: boolean; showCacheMissNotices?: boolean; quietStartup?: boolean; collapseChangelog?: boolean; /** Legacy master switch for the native macOS usage menu bar features. */ showNative?: boolean; /** Show the Pi usage menu bar app. */ showPiNative?: boolean; /** Show the ChatGPT/Codex usage menu bar app. */ showChatGPTNative?: boolean; enableInstallTelemetry?: boolean; enableSkillCommands?: boolean; steeringMode?: "one-at-a-time" | "all"; followUpMode?: "one-at-a-time" | "all"; transport?: "sse" | "websocket" | "websocket-cached" | "auto"; httpIdleTimeoutMs?: number; showHardwareCursor?: boolean; editorPaddingX?: 0 | 1 | 2 | 3; outputPad?: 0 | 1; autocompleteMaxVisible?: 3 | 5 | 7 | 10 | 15 | 20; tuiMode?: "regular" | "fullscreen"; fullscreenExitOutput?: "transcript" | "resume-hint"; fullscreenScrollbar?: "auto" | "always" | "hidden"; fullscreenCopyOnSelect?: boolean; compaction?: { enabled?: boolean; reserveTokens?: number; keepRecentTokens?: number; }; retry?: { enabled?: boolean; maxRetries?: number; baseDelayMs?: number; provider?: { timeoutMs?: number; maxRetries?: number; maxRetryDelayMs?: number; }; }; packages?: PiPackage[]; terminal?: { showImages?: boolean; imageWidthCells?: number; clearOnShrink?: boolean; showTerminalProgress?: boolean; images?: "kitty" | "iterm2" | false; trueColor?: boolean; hyperlinks?: boolean; }; images?: { autoResize?: boolean; blockImages?: boolean; }; markdown?: { mermaid?: "off" | "final" | "streaming"; codeBlockIndent?: string; }; warnings?: { anthropicExtraUsage?: boolean; [key: string]: boolean | undefined; }; treeFilterMode?: "default" | "no-tools" | "user-only" | "labeled-only" | "all"; doubleEscapeAction?: "tree" | "fork" | "none"; enabledModels?: string[]; } export type PiThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"; export interface PiAuth { [providerId: string]: ProviderAuth; } export interface CustomProviderConfig { name?: string; baseUrl?: string; api?: ApiType; apiKey?: string; apiKeys?: ProviderApiKey[]; activeKeyId?: string; /** Legacy config field; retained for upgrades but ignored at runtime. */ autoFailover?: boolean; authHeader?: boolean; headers?: Record; models?: Model[]; compat?: ModelCompat; modelOverrides?: Record>; } export interface PiModelsJson { providers: Record; _disabledProviders?: Record; } export interface PiConfig { settings: PiSettings; auth: PiAuth; modelsJson: PiModelsJson | null; } // pi core / extension update check (server queries the npm registry) export interface UpdateItem { name: string; installed: string; latest: string | null; // null → registry lookup failed hasUpdate: boolean; } export interface UpdateCheckResult { pi: UpdateItem | null; // null → pi version unknown extensions: UpdateItem[]; checkedAt: number; } // ─── Usage / Dashboard Types ────────────────────────────── export interface UsageRecord { date: string; // ISO date YYYY-MM-DD providerId: string; modelId: string; inputTokens: number; outputTokens: number; cacheReadTokens: number; cacheWriteTokens: number; requests: number; cost: number; } export interface DailyAggregate { date: string; totalTokens: number; totalCost: number; totalRequests: number; inputTokens: number; outputTokens: number; } export interface ModelUsageSummary { modelId: string; providerId: string; modelName: string; totalTokens: number; totalCost: number; totalRequests: number; avgTokensPerRequest: number; } export interface ProviderUsageSummary { providerId: string; providerName: string; totalTokens: number; totalCost: number; totalRequests: number; modelCount: number; } // ─── Subagents ─────────────────────────────────────────── export interface AgentDef { name: string; fileName: string; filePath: string; package: string; description: string; model?: string; tools?: string[]; thinking?: string; systemPromptMode?: string; inheritProjectContext?: boolean; inheritSkills?: boolean; input?: string[]; body: string; } export interface ChainStep { agent: string; phase?: string; label?: string; output?: string; as?: string; task?: string; } export interface ChainDef { name: string; fileName: string; filePath: string; description: string; steps: ChainStep[]; body: string; } export interface RunRecord { agent: string; ts: number; status: string; duration?: number; exit?: number; taskHash?: string; } export interface SubagentsData { agents: AgentDef[]; chains: ChainDef[]; runHistory: RunRecord[]; } // ─── Config Import/Export ───────────────────────────────── export interface ExportPayload { version: string; exportedAt: string; config: PiConfig; }