cogpit-memory 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -5
- package/dist/cli.d.ts +30 -0
- package/dist/cli.js +1114 -178
- package/dist/commands/context.d.ts +20 -0
- package/dist/commands/index-cmd.d.ts +15 -0
- package/dist/commands/install-skill.d.ts +4 -0
- package/dist/commands/search.d.ts +39 -0
- package/dist/commands/sessions.d.ts +41 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +1117 -180
- package/dist/lib/codex-patches.d.ts +9 -0
- package/dist/lib/codex-tool-normalization.d.ts +8 -0
- package/dist/lib/codex.d.ts +30 -0
- package/dist/lib/dirs.d.ts +8 -0
- package/dist/lib/helpers.d.ts +11 -0
- package/dist/lib/interactiveState.d.ts +35 -0
- package/dist/lib/messageTypeGuards.d.ts +17 -0
- package/dist/lib/metadata.d.ts +31 -0
- package/dist/lib/parser.d.ts +14 -0
- package/dist/lib/pricingTiers.d.ts +30 -0
- package/dist/lib/response.d.ts +2 -0
- package/dist/lib/search-index.d.ts +154 -0
- package/dist/lib/sessionStats.d.ts +6 -0
- package/dist/lib/sessionStatus.d.ts +36 -0
- package/dist/lib/token-costs.d.ts +48 -0
- package/dist/lib/turnBuilder.d.ts +5 -0
- package/dist/lib/types.d.ts +401 -0
- package/package.json +13 -7
- package/skill/SKILL.md +4 -4
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ToolCall } from "./types";
|
|
2
|
+
/** Extract patch payloads passed to nested `tools.apply_patch(...)` calls in Codex exec scripts. */
|
|
3
|
+
export declare function extractApplyPatchInputs(execSource: string): string[];
|
|
4
|
+
/** Parse a Codex apply_patch string into per-file Edit/Write tool calls. */
|
|
5
|
+
export declare function parseApplyPatch(patchText: string, callId: string, timestamp: string, cwd?: string): ToolCall[];
|
|
6
|
+
/** Normalize direct and exec-wrapped Codex apply_patch calls into file tool calls. */
|
|
7
|
+
export declare function parseCodexToolPatches(toolName: string, rawInput: string, callId: string, timestamp: string, cwd?: string): ToolCall[];
|
|
8
|
+
/** Attribute an exec-wrapper patch failure without tainting earlier successful patch calls. */
|
|
9
|
+
export declare function findFailedNestedPatchCallIds(output: string, wrapperIsError: boolean, calls: readonly ToolCall[]): Set<string>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function inferToolError(output: string | null): boolean;
|
|
2
|
+
/** Normalize Codex update_plan input to TodoWrite format. */
|
|
3
|
+
export declare function normalizePlanToTodos(input: Record<string, unknown>): Record<string, unknown>;
|
|
4
|
+
/** Parse Codex custom_tool_call output JSON or structured content blocks. */
|
|
5
|
+
export declare function parseCustomToolOutput(output: unknown): {
|
|
6
|
+
text: string;
|
|
7
|
+
isError: boolean;
|
|
8
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ParseSessionOptions, ParsedSession } from "./types";
|
|
2
|
+
export { extractApplyPatchInputs, findFailedNestedPatchCallIds, parseApplyPatch, parseCodexToolPatches, } from "./codex-patches";
|
|
3
|
+
export { parseCustomToolOutput } from "./codex-tool-normalization";
|
|
4
|
+
interface CodexMetadata {
|
|
5
|
+
sessionId: string;
|
|
6
|
+
version: string;
|
|
7
|
+
gitBranch: string;
|
|
8
|
+
cwd: string;
|
|
9
|
+
model: string;
|
|
10
|
+
slug: string;
|
|
11
|
+
name: string;
|
|
12
|
+
branchedFrom?: {
|
|
13
|
+
sessionId: string;
|
|
14
|
+
turnIndex?: number | null;
|
|
15
|
+
};
|
|
16
|
+
firstUserMessage: string;
|
|
17
|
+
lastUserMessage: string;
|
|
18
|
+
timestamp: string;
|
|
19
|
+
lastTimestamp: string;
|
|
20
|
+
turnCount: number;
|
|
21
|
+
/** True when this session is a Codex sub-agent (spawned by spawn_agent) */
|
|
22
|
+
isSubagent: boolean;
|
|
23
|
+
/** Parent session ID for sub-agent sessions */
|
|
24
|
+
parentSessionId: string | null;
|
|
25
|
+
/** Canonical collaboration path for the agent that owns this rollout. */
|
|
26
|
+
agentPath: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function isCodexSessionText(jsonlText: string): boolean;
|
|
29
|
+
export declare function extractCodexMetadataFromLines(lines: string[]): CodexMetadata;
|
|
30
|
+
export declare function parseCodexSession(jsonlText: string, options?: ParseSessionOptions): ParsedSession;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Find the JSONL file path for a session by searching all project directories. */
|
|
2
|
+
export declare function findJsonlPath(sessionId: string): Promise<string | null>;
|
|
3
|
+
export declare function matchSubagentToMember(leadSessionId: string, subagentFileName: string, members: Array<{
|
|
4
|
+
name: string;
|
|
5
|
+
agentType: string;
|
|
6
|
+
prompt?: string;
|
|
7
|
+
}>): Promise<string | null>;
|
|
8
|
+
export declare function projectDirToReadableName(dirName: string): {
|
|
9
|
+
path: string;
|
|
10
|
+
shortName: string;
|
|
11
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive prompt detection — plan approval and user question states.
|
|
3
|
+
*/
|
|
4
|
+
import type { ParsedSession, Turn } from "./types";
|
|
5
|
+
export interface PlanApprovalState {
|
|
6
|
+
type: "plan";
|
|
7
|
+
allowedPrompts?: Array<{
|
|
8
|
+
tool: string;
|
|
9
|
+
prompt: string;
|
|
10
|
+
}>;
|
|
11
|
+
}
|
|
12
|
+
export interface UserQuestionState {
|
|
13
|
+
type: "question";
|
|
14
|
+
toolUseId: string;
|
|
15
|
+
questions: Array<{
|
|
16
|
+
question: string;
|
|
17
|
+
header?: string;
|
|
18
|
+
options: Array<{
|
|
19
|
+
label: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
}>;
|
|
22
|
+
multiSelect?: boolean;
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
25
|
+
export type PendingInteraction = PlanApprovalState | UserQuestionState | null;
|
|
26
|
+
/**
|
|
27
|
+
* Check if the previous turn's last tool call is the same interactive tool
|
|
28
|
+
* with a pending/error result -- indicates a stuck loop we should suppress.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isStuckInteractiveLoop(turns: Turn[], toolName: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Detect if the session is waiting for user interaction (plan approval or
|
|
33
|
+
* AskUserQuestion). Returns the interaction state or null.
|
|
34
|
+
*/
|
|
35
|
+
export declare function detectPendingInteraction(session: ParsedSession): PendingInteraction;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared message type guards for RawMessage discrimination.
|
|
3
|
+
*
|
|
4
|
+
* Previously duplicated between turnBuilder.ts and parser.ts to avoid circular
|
|
5
|
+
* dependencies. Extracted here as a dependency-free leaf module (imports only
|
|
6
|
+
* from ./types) so both files can share a single source of truth.
|
|
7
|
+
*/
|
|
8
|
+
import type { RawMessage, UserMessage, AssistantMessage, ProgressMessage, SystemMessage, SummaryMessage, QueueOperationMessage } from "./types";
|
|
9
|
+
export declare function isUserMessage(msg: RawMessage): msg is UserMessage;
|
|
10
|
+
export declare function isAssistantMessage(msg: RawMessage): msg is AssistantMessage;
|
|
11
|
+
export declare function isProgressMessage(msg: RawMessage): msg is ProgressMessage;
|
|
12
|
+
export declare function isSystemMessage(msg: RawMessage): msg is SystemMessage;
|
|
13
|
+
export declare function isSummaryMessage(msg: RawMessage): msg is SummaryMessage;
|
|
14
|
+
export declare function isQueueOperationMessage(msg: RawMessage): msg is QueueOperationMessage;
|
|
15
|
+
export declare function isCompactBoundary(msg: RawMessage): msg is SystemMessage & {
|
|
16
|
+
subtype: "compact_boundary";
|
|
17
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type SessionStatusInfo } from "./sessionStatus";
|
|
2
|
+
export declare function getSessionMeta(filePath: string): Promise<{
|
|
3
|
+
sessionId: string;
|
|
4
|
+
version: string;
|
|
5
|
+
gitBranch: string;
|
|
6
|
+
model: string;
|
|
7
|
+
slug: string;
|
|
8
|
+
cwd: string;
|
|
9
|
+
firstUserMessage: string;
|
|
10
|
+
lastUserMessage: string;
|
|
11
|
+
timestamp: string;
|
|
12
|
+
turnCount: number;
|
|
13
|
+
lineCount: number;
|
|
14
|
+
branchedFrom: {
|
|
15
|
+
sessionId: string;
|
|
16
|
+
turnIndex?: number | null;
|
|
17
|
+
} | undefined;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Read backward through a session JSONL to derive agent status.
|
|
21
|
+
* Scans in 4KB chunks from the tail, parsing one line at a time until it
|
|
22
|
+
* finds a meaningful message (assistant or non-meta user). This reads only
|
|
23
|
+
* as far as needed — typically one chunk — and uses the same
|
|
24
|
+
* deriveSessionStatus() function as the client side.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getSessionStatus(filePath: string): Promise<SessionStatusInfo>;
|
|
27
|
+
/**
|
|
28
|
+
* Search all user messages in a session file for a query string.
|
|
29
|
+
* Returns the first matching message snippet, or null if no match.
|
|
30
|
+
*/
|
|
31
|
+
export declare function searchSessionMessages(filePath: string, query: string): Promise<string | null>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ParsedSession, ImageBlock, ParseSessionOptions, UserContent } from "./types";
|
|
2
|
+
export type { PendingInteraction } from "./interactiveState";
|
|
3
|
+
export type { ParseSessionOptions } from "./types";
|
|
4
|
+
export { detectPendingInteraction } from "./interactiveState";
|
|
5
|
+
export declare function parseSession(jsonlText: string, options?: ParseSessionOptions): ParsedSession;
|
|
6
|
+
/**
|
|
7
|
+
* Incrementally append new JSONL lines to an existing parsed session.
|
|
8
|
+
* Avoids re-parsing all turns from scratch — only re-processes the last
|
|
9
|
+
* (potentially incomplete) turn and any new messages.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseSessionAppend(existing: ParsedSession, newJsonlText: string): ParsedSession;
|
|
12
|
+
export declare function getUserMessageText(content: UserContent | null): string;
|
|
13
|
+
export declare function getUserMessageImages(content: UserContent | null): ImageBlock[];
|
|
14
|
+
export declare function getToolColor(toolName: string): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pricing tier constants and model-to-tier resolution.
|
|
3
|
+
*
|
|
4
|
+
* Sources: Claude Code v2.1.172 binary (decompiled JS bundle) for Anthropic
|
|
5
|
+
* models, and the official OpenAI model pricing pages for GPT models.
|
|
6
|
+
* Each model maps to a tier with five price points.
|
|
7
|
+
*
|
|
8
|
+
* Changes vs the old v2.1.53 table:
|
|
9
|
+
* - Extended-context (>200k input) pricing is gone — flat pricing per model.
|
|
10
|
+
* - New frontier tier for Fable 5 / Mythos 5 / Opus 4.8 ($10/$50).
|
|
11
|
+
* - Sonnet 4.5/4.6 dropped to the $3/$15 tier (was $5/$25).
|
|
12
|
+
* - Fast mode (usage.speed === "fast" on Opus 4.6/4.7) bills $30/$150;
|
|
13
|
+
* Opus 4.8 fast bills the same as standard.
|
|
14
|
+
*/
|
|
15
|
+
export interface PricingTier {
|
|
16
|
+
input: number;
|
|
17
|
+
output: number;
|
|
18
|
+
cacheWrite: number;
|
|
19
|
+
cacheRead: number;
|
|
20
|
+
webSearch: number;
|
|
21
|
+
}
|
|
22
|
+
export declare function resolveTier(model: string, speed?: string): PricingTier;
|
|
23
|
+
/**
|
|
24
|
+
* Whether Cogpit has a published USD price for this model.
|
|
25
|
+
*
|
|
26
|
+
* Keep the historical Claude-family fallback for old rollouts whose model is
|
|
27
|
+
* absent or abbreviated, but never price a future/unknown GPT model as if it
|
|
28
|
+
* were Claude. That would create a precise-looking but invented dollar value.
|
|
29
|
+
*/
|
|
30
|
+
export declare function hasKnownPricing(model: string | null | undefined): boolean;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
export interface IndexStats {
|
|
2
|
+
dbPath: string;
|
|
3
|
+
dbSizeBytes: number;
|
|
4
|
+
dbSizeMB: number;
|
|
5
|
+
indexedFiles: number;
|
|
6
|
+
indexedSessions: number;
|
|
7
|
+
indexedSubagents: number;
|
|
8
|
+
totalRows: number;
|
|
9
|
+
watcherRunning: boolean;
|
|
10
|
+
lastFullBuild: string | null;
|
|
11
|
+
lastUpdate: string | null;
|
|
12
|
+
}
|
|
13
|
+
export interface SearchHit {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
filePath: string;
|
|
16
|
+
location: string;
|
|
17
|
+
snippet: string;
|
|
18
|
+
matchCount: number;
|
|
19
|
+
}
|
|
20
|
+
export declare class SearchIndex {
|
|
21
|
+
private db;
|
|
22
|
+
private dbPath;
|
|
23
|
+
projectsDir: string | null;
|
|
24
|
+
private _watcherRunning;
|
|
25
|
+
private _lastFullBuild;
|
|
26
|
+
private _lastUpdate;
|
|
27
|
+
private watcher;
|
|
28
|
+
private debounceTimers;
|
|
29
|
+
constructor(dbPath: string);
|
|
30
|
+
private initSchema;
|
|
31
|
+
getStats(): IndexStats;
|
|
32
|
+
/** Index tool call inputs and results under the given location prefix. */
|
|
33
|
+
private insertToolCalls;
|
|
34
|
+
/**
|
|
35
|
+
* Insert all searchable content from a parsed session into the FTS5 index.
|
|
36
|
+
* Shared by both `indexFile` (single-file) and `buildFull` (batch).
|
|
37
|
+
*/
|
|
38
|
+
private insertSessionContent;
|
|
39
|
+
/**
|
|
40
|
+
* Parse a JSONL file and insert all searchable content into the FTS5 index.
|
|
41
|
+
* Idempotent: deletes old data for the file before re-indexing.
|
|
42
|
+
* All inserts run in a single transaction for performance.
|
|
43
|
+
*/
|
|
44
|
+
indexFile(filePath: string, sessionId?: string, mtimeMs?: number, opts?: {
|
|
45
|
+
isSubagent?: boolean;
|
|
46
|
+
parentSessionId?: string | null;
|
|
47
|
+
}): void;
|
|
48
|
+
/**
|
|
49
|
+
* Query the FTS5 index and return structured search results.
|
|
50
|
+
*
|
|
51
|
+
* - FTS5 unicode61 tokenizer is case-insensitive by default.
|
|
52
|
+
* - When `caseSensitive` is true, a post-filter checks the original query
|
|
53
|
+
* against the snippet text (exact case match).
|
|
54
|
+
* - When `maxAgeMs` is provided, only files whose mtime in `indexed_files`
|
|
55
|
+
* falls within the window are included (join on source_file).
|
|
56
|
+
* - `sessionId` restricts results to a single session.
|
|
57
|
+
* - `limit` defaults to 200 and is clamped to a max of 200.
|
|
58
|
+
*/
|
|
59
|
+
search(query: string, opts?: {
|
|
60
|
+
limit?: number;
|
|
61
|
+
sessionId?: string;
|
|
62
|
+
maxAgeMs?: number;
|
|
63
|
+
caseSensitive?: boolean;
|
|
64
|
+
}): SearchHit[];
|
|
65
|
+
/**
|
|
66
|
+
* Count total matching rows and distinct sessions for a query (without LIMIT).
|
|
67
|
+
* Used by the route to report accurate totalHits and sessionsSearched.
|
|
68
|
+
*/
|
|
69
|
+
countMatches(query: string, opts?: {
|
|
70
|
+
sessionId?: string;
|
|
71
|
+
maxAgeMs?: number;
|
|
72
|
+
}): {
|
|
73
|
+
totalHits: number;
|
|
74
|
+
sessionsSearched: number;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Clear all indexed data and re-index every JSONL file under `projectsDir`.
|
|
78
|
+
* Structure: projectsDir/{projectName}/{sessionId}.jsonl
|
|
79
|
+
* Subagents: projectsDir/{projectName}/{sessionId}/subagents/agent-{id}.jsonl
|
|
80
|
+
*
|
|
81
|
+
* Optimized: discovers all files first, then processes them in a single
|
|
82
|
+
* SQLite transaction with pre-prepared statements. This avoids the overhead
|
|
83
|
+
* of 3000+ individual transactions (each forcing a disk sync).
|
|
84
|
+
*
|
|
85
|
+
* Stores `projectsDir` as a class field so `rebuild()` can reuse it.
|
|
86
|
+
*/
|
|
87
|
+
buildFull(projectsDir: string): void;
|
|
88
|
+
/**
|
|
89
|
+
* Incrementally re-index only files whose mtime has changed since last index.
|
|
90
|
+
* New files (not in indexed_files) are always indexed.
|
|
91
|
+
*
|
|
92
|
+
* WARNING: This walks ALL files under projectsDir and stats each one.
|
|
93
|
+
* On large session stores (3000+ files) this can take minutes.
|
|
94
|
+
* Prefer `updateRecent()` for CLI search paths.
|
|
95
|
+
*/
|
|
96
|
+
updateStale(projectsDir: string): void;
|
|
97
|
+
/**
|
|
98
|
+
* Lightweight incremental update for CLI search paths.
|
|
99
|
+
*
|
|
100
|
+
* Still walks and stats all files via `discoverFiles`, but skips DB lookups
|
|
101
|
+
* for files with mtime <= the high-water mark that are already indexed.
|
|
102
|
+
* Caps re-indexing to `maxFiles` to prevent blocking on large backlogs
|
|
103
|
+
* (run `index rebuild` for a full catch-up).
|
|
104
|
+
*/
|
|
105
|
+
updateRecent(projectsDir: string, maxFiles?: number): void;
|
|
106
|
+
/**
|
|
107
|
+
* Re-run buildFull using the previously stored projectsDir.
|
|
108
|
+
* No-op if projectsDir was never set.
|
|
109
|
+
*/
|
|
110
|
+
rebuild(): void;
|
|
111
|
+
/**
|
|
112
|
+
* Walk the projects directory tree and invoke `callback` for every JSONL file.
|
|
113
|
+
*
|
|
114
|
+
* Directory structure:
|
|
115
|
+
* projectsDir/
|
|
116
|
+
* {projectName}/
|
|
117
|
+
* {sessionId}.jsonl <- session file
|
|
118
|
+
* {sessionId}/subagents/
|
|
119
|
+
* agent-{agentId}.jsonl <- subagent file (recursive)
|
|
120
|
+
*
|
|
121
|
+
* Skips the "memory" directory.
|
|
122
|
+
*/
|
|
123
|
+
private discoverFiles;
|
|
124
|
+
/**
|
|
125
|
+
* Recursively discover subagent JSONL files under the subagents directory
|
|
126
|
+
* that corresponds to `parentPath`.
|
|
127
|
+
*
|
|
128
|
+
* For a parent at `/path/to/session-1.jsonl`, looks for subagents at
|
|
129
|
+
* `/path/to/session-1/subagents/agent-*.jsonl`.
|
|
130
|
+
*
|
|
131
|
+
* Recurses up to `maxDepth` levels (default 4).
|
|
132
|
+
*/
|
|
133
|
+
private discoverSubagents;
|
|
134
|
+
/**
|
|
135
|
+
* Start watching `projectsDir` for JSONL file changes.
|
|
136
|
+
* Runs `updateStale()` immediately for an initial sync, then sets up
|
|
137
|
+
* `fs.watch` with `{ recursive: true }` (macOS-compatible) to detect
|
|
138
|
+
* subsequent file changes and trigger debounced re-indexing.
|
|
139
|
+
*/
|
|
140
|
+
startWatching(projectsDir: string): void;
|
|
141
|
+
/**
|
|
142
|
+
* Stop the file watcher and clear any pending debounce timers.
|
|
143
|
+
* Safe to call even when not watching (no-op).
|
|
144
|
+
*/
|
|
145
|
+
stopWatching(): void;
|
|
146
|
+
/**
|
|
147
|
+
* Private helper: debounce re-indexing of a single file.
|
|
148
|
+
* Waits 2 seconds after the last change event for a given file path
|
|
149
|
+
* before actually calling `indexFile()`. This coalesces rapid writes
|
|
150
|
+
* (e.g. streaming JSONL appends) into a single index operation.
|
|
151
|
+
*/
|
|
152
|
+
private debouncedReindex;
|
|
153
|
+
close(): void;
|
|
154
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session statistics computation — token usage aggregation and tool call tallying.
|
|
3
|
+
*/
|
|
4
|
+
import type { Turn, SessionStats } from "./types";
|
|
5
|
+
export declare function createEmptySessionStats(turnCount: number): SessionStats;
|
|
6
|
+
export declare function computeStats(turns: Turn[]): SessionStats;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derives the current session status from raw JSONL messages.
|
|
3
|
+
* Walks backward from the last message to determine if the agent
|
|
4
|
+
* is idle, thinking, calling tools, etc.
|
|
5
|
+
*
|
|
6
|
+
* This is a pure function — status is always derived from data,
|
|
7
|
+
* never stored as app state.
|
|
8
|
+
*/
|
|
9
|
+
export type SessionStatus = "idle" | "thinking" | "tool_use" | "processing" | "completed" | "compacting" | "deferred";
|
|
10
|
+
export interface SessionStatusInfo {
|
|
11
|
+
status: SessionStatus;
|
|
12
|
+
/** Name of the tool currently being used (if status is tool_use) */
|
|
13
|
+
toolName?: string;
|
|
14
|
+
/** Number of pending queue items (user messages waiting to be processed) */
|
|
15
|
+
pendingQueue?: number;
|
|
16
|
+
/** Why the session terminated (from Claude Code's terminal_reason). Only set for non-normal endings. */
|
|
17
|
+
terminalReason?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Derive session status from raw JSONL message objects.
|
|
21
|
+
*
|
|
22
|
+
* **Provider dispatch:** The function auto-detects the session format by
|
|
23
|
+
* inspecting `rawMessages[0].type`. Codex sessions start with one of
|
|
24
|
+
* `session_meta | turn_context | event_msg | response_item` and are routed
|
|
25
|
+
* to `deriveCodexSessionStatus`. All other sessions are treated as Claude Code
|
|
26
|
+
* format. If a third provider is added, add a detection branch here and in
|
|
27
|
+
* `src/lib/providers/registry.ts`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function deriveSessionStatus(rawMessages: Array<{
|
|
30
|
+
type: string;
|
|
31
|
+
[key: string]: unknown;
|
|
32
|
+
}>): SessionStatusInfo;
|
|
33
|
+
/** Human-readable label for terminal_reason values from Claude Code. */
|
|
34
|
+
export declare function getTerminalReasonLabel(reason: string): string;
|
|
35
|
+
/** Human-readable label for a session status. Returns null for "idle". */
|
|
36
|
+
export declare function getStatusLabel(status: SessionStatus | undefined, toolName?: string, terminalReason?: string): string | null;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token cost calculation library — single source of truth.
|
|
3
|
+
*
|
|
4
|
+
* Pricing is reverse-engineered from the Claude Code binary (v2.1.53) to match
|
|
5
|
+
* exactly what CC reports. CC calculates cost per API call in the message_delta
|
|
6
|
+
* handler using final usage from the streaming response — but the JSONL only
|
|
7
|
+
* records the message_start placeholder usage (output_tokens is severely
|
|
8
|
+
* undercounted, thinking tokens are omitted entirely). We compensate by
|
|
9
|
+
* estimating output from actual content (≈4 chars/token).
|
|
10
|
+
*/
|
|
11
|
+
import type { Turn, SubAgentMessage } from "./types";
|
|
12
|
+
/** Approximate characters per token for content-based estimation. */
|
|
13
|
+
export declare const CHARS_PER_TOKEN = 4;
|
|
14
|
+
export interface CostInput {
|
|
15
|
+
model: string | null;
|
|
16
|
+
inputTokens: number;
|
|
17
|
+
outputTokens: number;
|
|
18
|
+
cacheWriteTokens: number;
|
|
19
|
+
cacheReadTokens: number;
|
|
20
|
+
webSearchRequests?: number;
|
|
21
|
+
/** Fast-mode flag from usage.speed — "fast" bills a higher tier on Opus 4.6/4.7 */
|
|
22
|
+
speed?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Calculate the cost of a single API call / turn.
|
|
26
|
+
*
|
|
27
|
+
* This is the single entry point for all cost calculations. All other
|
|
28
|
+
* functions in the codebase should use this instead of computing cost
|
|
29
|
+
* themselves.
|
|
30
|
+
*/
|
|
31
|
+
export declare function calculateCost(c: CostInput): number;
|
|
32
|
+
/**
|
|
33
|
+
* Backward-compatible wrapper. Prefer `calculateCost()` for new code.
|
|
34
|
+
*/
|
|
35
|
+
export declare function calculateTurnCost(model: string | null, inputTokens: number, outputTokens: number, cacheCreationTokens: number, cacheReadTokens: number): number;
|
|
36
|
+
/** Estimate thinking tokens from a turn's thinking blocks. */
|
|
37
|
+
export declare function estimateThinkingTokens(turn: Turn): number;
|
|
38
|
+
/** Estimate non-thinking output tokens (text + tool use JSON). */
|
|
39
|
+
export declare function estimateVisibleOutputTokens(turn: Turn): number;
|
|
40
|
+
/** Estimate total output tokens (thinking + visible). Uses max(estimated, reported). */
|
|
41
|
+
export declare function estimateTotalOutputTokens(turn: Turn): number;
|
|
42
|
+
/** Estimate output tokens for a sub-agent message. */
|
|
43
|
+
export declare function estimateSubAgentOutput(sa: SubAgentMessage): number;
|
|
44
|
+
/** Calculate cost for a turn using estimated output tokens. */
|
|
45
|
+
export declare function calculateTurnCostEstimated(turn: Turn): number;
|
|
46
|
+
/** Calculate cost for a sub-agent message using estimated output tokens. */
|
|
47
|
+
export declare function calculateSubAgentCostEstimated(sa: SubAgentMessage): number;
|
|
48
|
+
export declare function formatCost(usd: number): string;
|