sidekick-shared 0.29.0 → 0.30.0
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/CHANGELOG.md +48 -0
- package/README.md +198 -56
- package/dist/aggregation/EventAggregator.d.ts +96 -2
- package/dist/aggregation/EventAggregator.js +535 -42
- package/dist/aggregation/snapshot.d.ts +37 -8
- package/dist/aggregation/snapshot.js +31 -9
- package/dist/aggregation/types.d.ts +38 -1
- package/dist/browser.d.ts +9 -1
- package/dist/browser.js +29 -3
- package/dist/context/sessionContext.js +8 -0
- package/dist/esm/aggregation/EventAggregator.js +535 -42
- package/dist/esm/aggregation/snapshot.js +31 -9
- package/dist/esm/browser.js +3 -0
- package/dist/esm/context/sessionContext.js +8 -0
- package/dist/esm/fileContinuity.js +149 -0
- package/dist/esm/formatters/toolSummary.js +4 -1
- package/dist/esm/index.js +7 -2
- package/dist/esm/modelCatalog.js +5 -4
- package/dist/esm/modelContext.js +4 -3
- package/dist/esm/modelInfo.js +4 -3
- package/dist/esm/node.js +3 -1
- package/dist/esm/observedContextWindows.js +2 -1
- package/dist/esm/ownKey.js +26 -0
- package/dist/esm/parsers/codexParser.js +372 -7
- package/dist/esm/parsers/openCodeParser.js +2 -1
- package/dist/esm/parsers/subagentEndState.js +61 -0
- package/dist/esm/parsers/subagentScanner.js +37 -12
- package/dist/esm/parsers/subagentTraceParser.js +103 -37
- package/dist/esm/pricingCatalog.js +3 -2
- package/dist/esm/promptHistory.js +22 -11
- package/dist/esm/providers/claudeCode.js +60 -29
- package/dist/esm/providers/codex.js +235 -201
- package/dist/esm/providers/codexCompressedReader.js +184 -0
- package/dist/esm/providers/codexDatabase.js +47 -2
- package/dist/esm/providers/codexRollouts.js +20 -2
- package/dist/esm/providers/codexSubagents.js +456 -0
- package/dist/esm/providers/compressedRollouts.js +330 -0
- package/dist/esm/providers/factory.js +4 -1
- package/dist/esm/providers/rolloutWalker.js +32 -4
- package/dist/esm/schemas/sessionEvent.js +63 -14
- package/dist/esm/sessionMonitor.js +7 -1
- package/dist/esm/sessionPreviews.js +9 -0
- package/dist/esm/sessionPromptHistory.js +5 -3
- package/dist/esm/subagentActivity.js +125 -0
- package/dist/esm/subagentDisplayState.js +81 -0
- package/dist/esm/subagentSpawn.js +363 -0
- package/dist/esm/testing/codexSubagentFixtures.js +336 -0
- package/dist/esm/toolCallOrigins.js +17 -10
- package/dist/esm/toolCategory.js +6 -2
- package/dist/esm/transcript.js +8 -0
- package/dist/esm/turns/assistantTurn.js +6 -2
- package/dist/esm/usage/claudeUsageDedupe.js +68 -0
- package/dist/esm/usage/usageEvents.js +4 -1
- package/dist/esm/watchers/eventBridge.js +45 -0
- package/dist/esm/watchers/factory.js +5 -3
- package/dist/esm/watchers/jsonlTail.js +82 -48
- package/dist/esm/watchers/jsonlWatcher.js +61 -4
- package/dist/esm/watchers/providerReaderWatcher.js +18 -4
- package/dist/esm/zaiQuota.js +2 -1
- package/dist/fileContinuity.d.ts +95 -0
- package/dist/fileContinuity.js +187 -0
- package/dist/formatters/toolSummary.js +4 -1
- package/dist/index.d.ts +19 -7
- package/dist/index.js +48 -10
- package/dist/modelCatalog.js +5 -4
- package/dist/modelContext.js +4 -3
- package/dist/modelInfo.js +4 -3
- package/dist/node.d.ts +5 -1
- package/dist/node.js +18 -2
- package/dist/observedContextWindows.js +2 -1
- package/dist/ownKey.d.ts +16 -0
- package/dist/ownKey.js +30 -0
- package/dist/parsers/codexParser.d.ts +107 -0
- package/dist/parsers/codexParser.js +373 -7
- package/dist/parsers/openCodeParser.js +2 -1
- package/dist/parsers/subagentEndState.d.ts +20 -0
- package/dist/parsers/subagentEndState.js +65 -0
- package/dist/parsers/subagentScanner.d.ts +19 -6
- package/dist/parsers/subagentScanner.js +37 -12
- package/dist/parsers/subagentTraceParser.d.ts +33 -5
- package/dist/parsers/subagentTraceParser.js +103 -37
- package/dist/pricingCatalog.js +3 -2
- package/dist/promptHistory.d.ts +13 -3
- package/dist/promptHistory.js +22 -11
- package/dist/providers/claudeCode.js +59 -28
- package/dist/providers/codex.d.ts +35 -5
- package/dist/providers/codex.js +232 -198
- package/dist/providers/codexCompressedReader.d.ts +58 -0
- package/dist/providers/codexCompressedReader.js +221 -0
- package/dist/providers/codexDatabase.d.ts +25 -0
- package/dist/providers/codexDatabase.js +48 -2
- package/dist/providers/codexRollouts.d.ts +16 -2
- package/dist/providers/codexRollouts.js +20 -2
- package/dist/providers/codexSubagents.d.ts +66 -0
- package/dist/providers/codexSubagents.js +495 -0
- package/dist/providers/compressedRollouts.d.ts +114 -0
- package/dist/providers/compressedRollouts.js +380 -0
- package/dist/providers/factory.d.ts +5 -0
- package/dist/providers/factory.js +4 -1
- package/dist/providers/rolloutWalker.d.ts +15 -2
- package/dist/providers/rolloutWalker.js +33 -4
- package/dist/providers/types.d.ts +36 -1
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/sessionEvent.d.ts +51 -10
- package/dist/schemas/sessionEvent.js +63 -14
- package/dist/sessionMonitor.d.ts +6 -0
- package/dist/sessionMonitor.js +7 -1
- package/dist/sessionPreviews.js +9 -0
- package/dist/sessionPromptHistory.d.ts +5 -0
- package/dist/sessionPromptHistory.js +5 -36
- package/dist/subagentActivity.d.ts +91 -0
- package/dist/subagentActivity.js +132 -0
- package/dist/subagentDisplayState.d.ts +81 -0
- package/dist/subagentDisplayState.js +86 -0
- package/dist/subagentSpawn.d.ts +175 -0
- package/dist/subagentSpawn.js +385 -0
- package/dist/testing/codexSubagentFixtures.d.ts +48 -0
- package/dist/testing/codexSubagentFixtures.js +344 -0
- package/dist/toolCallOrigins.d.ts +5 -0
- package/dist/toolCallOrigins.js +17 -10
- package/dist/toolCategory.js +6 -2
- package/dist/transcript.js +8 -0
- package/dist/turns/assistantTurn.d.ts +4 -0
- package/dist/turns/assistantTurn.js +6 -2
- package/dist/types/codex.d.ts +71 -2
- package/dist/types/sessionEvent.d.ts +38 -3
- package/dist/usage/claudeUsageDedupe.d.ts +31 -0
- package/dist/usage/claudeUsageDedupe.js +68 -0
- package/dist/usage/usageEvents.d.ts +4 -1
- package/dist/usage/usageEvents.js +4 -1
- package/dist/watchers/eventBridge.js +45 -0
- package/dist/watchers/factory.d.ts +6 -0
- package/dist/watchers/factory.js +5 -3
- package/dist/watchers/jsonlTail.d.ts +27 -4
- package/dist/watchers/jsonlTail.js +84 -48
- package/dist/watchers/jsonlWatcher.d.ts +22 -1
- package/dist/watchers/jsonlWatcher.js +60 -3
- package/dist/watchers/providerReaderWatcher.d.ts +7 -0
- package/dist/watchers/providerReaderWatcher.js +18 -4
- package/dist/watchers/types.d.ts +12 -0
- package/dist/zaiQuota.js +2 -1
- package/package.json +1 -1
|
@@ -13,6 +13,21 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import type { SessionEvent } from '../types/sessionEvent';
|
|
15
15
|
import type { CodexRolloutLine, CodexSessionMeta, CodexTokenUsage, CodexRateLimits } from '../types/codex';
|
|
16
|
+
/** Pending exec command awaiting its end event. */
|
|
17
|
+
interface PendingExecCommand {
|
|
18
|
+
call_id: string;
|
|
19
|
+
command: string[];
|
|
20
|
+
workdir?: string;
|
|
21
|
+
timestamp: string;
|
|
22
|
+
}
|
|
23
|
+
/** Pending MCP tool call awaiting its end event. */
|
|
24
|
+
interface PendingMcpToolCall {
|
|
25
|
+
call_id: string;
|
|
26
|
+
server_name?: string;
|
|
27
|
+
tool_name: string;
|
|
28
|
+
arguments?: Record<string, unknown>;
|
|
29
|
+
timestamp: string;
|
|
30
|
+
}
|
|
16
31
|
/**
|
|
17
32
|
* Resolve the usage of the single call a Codex `token_count` event reports.
|
|
18
33
|
*
|
|
@@ -73,6 +88,15 @@ export interface CodexRolloutParserOptions {
|
|
|
73
88
|
* unchanged. For cheap passes over large rollouts; default false.
|
|
74
89
|
*/
|
|
75
90
|
metadataOnly?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Emit the multi-agent lifecycle as `system` events with `origin: { kind:
|
|
93
|
+
* 'subagent-activity' }` (read them with `subagentActivityFromEvent()`):
|
|
94
|
+
* `SubAgentActivity` items (`started`, `completed`, `interacted`,
|
|
95
|
+
* `interrupted`) and each `FINAL_ANSWER` agent message. Transcripts,
|
|
96
|
+
* context attribution, and the aggregator's message counts skip them.
|
|
97
|
+
* Default false: those records produce no events.
|
|
98
|
+
*/
|
|
99
|
+
includeSubagentActivity?: boolean;
|
|
76
100
|
}
|
|
77
101
|
/** Pending tool-call state counters from {@link CodexRolloutParser.getPendingStats}. */
|
|
78
102
|
export interface CodexPendingStats {
|
|
@@ -85,6 +109,47 @@ export interface CodexPendingStats {
|
|
|
85
109
|
/** Pending calls forgotten because `maxPendingBytes` was exceeded. */
|
|
86
110
|
evictedByBytes: number;
|
|
87
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* JSON-serializable continuation state of a {@link CodexRolloutParser}, from
|
|
114
|
+
* `exportResumeState()`, for `importResumeState()` in a parser that resumes
|
|
115
|
+
* at the same rollout position (for example from a persisted session
|
|
116
|
+
* snapshot). Every table lists its entries oldest first.
|
|
117
|
+
*/
|
|
118
|
+
export interface CodexRolloutResumeState {
|
|
119
|
+
version: 1;
|
|
120
|
+
sessionMeta: CodexSessionMeta | null;
|
|
121
|
+
/** Model from the latest `turn_context`, attributed to later events. */
|
|
122
|
+
currentModel: string | null;
|
|
123
|
+
/** Cumulative total of the previous token_count event, to skip its duplicates. */
|
|
124
|
+
prevTotalUsage: CodexTokenUsage | null;
|
|
125
|
+
lastTokenUsage: CodexTokenUsage | null;
|
|
126
|
+
modelContextWindow: number | null;
|
|
127
|
+
lastRateLimits: CodexRateLimits | null;
|
|
128
|
+
hasAggregateRateLimits: boolean;
|
|
129
|
+
inPlanMode: boolean;
|
|
130
|
+
/** Call ids whose tool use was already emitted, so their end event does not emit another. */
|
|
131
|
+
emittedToolUseIds: string[];
|
|
132
|
+
/** `apply_patch` calls awaiting output: call id and its per-file tool-use ids. */
|
|
133
|
+
patchExpandedToolUseIds: Array<[string, string[]]>;
|
|
134
|
+
/** `exec_command_begin` events awaiting their end. */
|
|
135
|
+
pendingExecCommands: PendingExecCommand[];
|
|
136
|
+
/** `mcp_tool_call_begin` events awaiting their end. */
|
|
137
|
+
pendingMcpToolCalls: PendingMcpToolCall[];
|
|
138
|
+
/**
|
|
139
|
+
* Multi-agent tool calls by call id with their raw tool names, so a later
|
|
140
|
+
* `SubAgentActivity` record names its tool. Optional: absent in states
|
|
141
|
+
* from earlier versions (and when `includeSubagentActivity` is off).
|
|
142
|
+
*/
|
|
143
|
+
collaborationCalls?: Array<[string, string]>;
|
|
144
|
+
/**
|
|
145
|
+
* Forked subagent rollouts: the ordinal below which records are the
|
|
146
|
+
* embedded parent history (see `getInheritedHistoryEnd()`). Optional:
|
|
147
|
+
* absent (nothing skipped) in states from earlier versions.
|
|
148
|
+
*/
|
|
149
|
+
inheritedHistoryEnd?: number | null;
|
|
150
|
+
}
|
|
151
|
+
/** A valid `CodexTokenUsage` (copied), `null` for `null`, or `undefined` when invalid. Internal. */
|
|
152
|
+
export declare function codexTokenUsageFrom(value: unknown): CodexTokenUsage | null | undefined;
|
|
88
153
|
/**
|
|
89
154
|
* Stateful parser for Codex JSONL rollout lines.
|
|
90
155
|
*
|
|
@@ -112,6 +177,15 @@ export declare class CodexRolloutParser {
|
|
|
112
177
|
/** Byte budget for pending calls; `null` = unlimited (no accounting). */
|
|
113
178
|
private readonly maxPendingBytes;
|
|
114
179
|
private readonly metadataOnly;
|
|
180
|
+
private readonly includeSubagentActivity;
|
|
181
|
+
/**
|
|
182
|
+
* Set once a forked child's rollout embeds an ancestor's session_meta: its
|
|
183
|
+
* own `subagent_history_start_ordinal`, below which records are the
|
|
184
|
+
* parent's history and are skipped. `null` while nothing is skipped.
|
|
185
|
+
*/
|
|
186
|
+
private historyStartOrdinal;
|
|
187
|
+
/** Multi-agent tool calls (call id → raw name), only with `includeSubagentActivity`. */
|
|
188
|
+
private collaborationCalls;
|
|
115
189
|
/** Pending calls in insertion order, for the byte budget. */
|
|
116
190
|
private pendingLedger;
|
|
117
191
|
private pendingBytes;
|
|
@@ -130,6 +204,29 @@ export declare class CodexRolloutParser {
|
|
|
130
204
|
getModelContextWindow(): number | null;
|
|
131
205
|
/** Get the last observed rate limits from token_count events. */
|
|
132
206
|
getLastRateLimits(): CodexRateLimits | null;
|
|
207
|
+
/**
|
|
208
|
+
* In a forked subagent's rollout, the ordinal of its first own record:
|
|
209
|
+
* records with a lower `ordinal` are the parent history the fork embeds
|
|
210
|
+
* and produce no events. Known once the rollout's second line (an embedded
|
|
211
|
+
* ancestor `session_meta`) was parsed; `null` otherwise, and for every
|
|
212
|
+
* rollout that is not such a fork.
|
|
213
|
+
*/
|
|
214
|
+
getInheritedHistoryEnd(): number | null;
|
|
215
|
+
/**
|
|
216
|
+
* The state later lines depend on — session metadata, current model,
|
|
217
|
+
* previous cumulative token total, context window, rate limits, plan mode,
|
|
218
|
+
* and the tool-call correlation tables (newest `limit` entries each) — as
|
|
219
|
+
* JSON-serializable data. Eviction counters are not included.
|
|
220
|
+
*/
|
|
221
|
+
exportResumeState(limit?: number): CodexRolloutResumeState;
|
|
222
|
+
/**
|
|
223
|
+
* Replaces this parser's state with one from {@link exportResumeState}, as
|
|
224
|
+
* if it had parsed the rollout up to where that state was taken. Returns
|
|
225
|
+
* false, changing nothing, when `state` is not a valid version-1 state.
|
|
226
|
+
* This parser's own `maxTrackedToolCalls`, `maxPendingBytes`, and
|
|
227
|
+
* `metadataOnly` options apply to the imported tables.
|
|
228
|
+
*/
|
|
229
|
+
importResumeState(state: unknown): boolean;
|
|
133
230
|
/**
|
|
134
231
|
* Converts a single rollout line to zero or more session events.
|
|
135
232
|
*/
|
|
@@ -142,6 +239,9 @@ export declare class CodexRolloutParser {
|
|
|
142
239
|
* first.
|
|
143
240
|
*/
|
|
144
241
|
private putPending;
|
|
242
|
+
private putPendingExec;
|
|
243
|
+
private putPendingMcp;
|
|
244
|
+
private putPendingPatch;
|
|
145
245
|
/** Removes and returns a pending call. */
|
|
146
246
|
private takePending;
|
|
147
247
|
private forgetPendingBytes;
|
|
@@ -152,6 +252,12 @@ export declare class CodexRolloutParser {
|
|
|
152
252
|
private toolOutput;
|
|
153
253
|
private handleSessionMeta;
|
|
154
254
|
private handleResponseItem;
|
|
255
|
+
private rememberCollaborationCall;
|
|
256
|
+
private subagentActivityEvent;
|
|
257
|
+
/** A child's `FINAL_ANSWER` message to its parent (opt-in). */
|
|
258
|
+
private handleAgentMessage;
|
|
259
|
+
/** A `SubAgentActivity` turn item (opt-in). */
|
|
260
|
+
private handleItemCompleted;
|
|
155
261
|
private handleMessage;
|
|
156
262
|
private handleReasoning;
|
|
157
263
|
private handleFunctionCall;
|
|
@@ -164,3 +270,4 @@ export declare class CodexRolloutParser {
|
|
|
164
270
|
private handleEventMsg;
|
|
165
271
|
private handleTokenCount;
|
|
166
272
|
}
|
|
273
|
+
export {};
|
|
@@ -18,9 +18,11 @@ exports.resolveCodexCallUsage = resolveCodexCallUsage;
|
|
|
18
18
|
exports.normalizeCodexToolName = normalizeCodexToolName;
|
|
19
19
|
exports.normalizeCodexToolInput = normalizeCodexToolInput;
|
|
20
20
|
exports.extractPatchFilePaths = extractPatchFilePaths;
|
|
21
|
+
exports.codexTokenUsageFrom = codexTokenUsageFrom;
|
|
21
22
|
const codex_1 = require("../types/codex");
|
|
22
23
|
const openCodeParser_1 = require("./openCodeParser");
|
|
23
24
|
const usageNormalization_1 = require("../usageNormalization");
|
|
25
|
+
const subagentActivity_1 = require("../subagentActivity");
|
|
24
26
|
function reportedCompaction(tokensBefore, tokensAfter) {
|
|
25
27
|
if (typeof tokensBefore !== 'number' ||
|
|
26
28
|
typeof tokensAfter !== 'number' ||
|
|
@@ -178,6 +180,84 @@ function extractPatchFilePaths(input) {
|
|
|
178
180
|
}
|
|
179
181
|
/** Default cap on each piece of per-call correlation state the parser keeps. */
|
|
180
182
|
exports.DEFAULT_MAX_TRACKED_TOOL_CALLS = 4096;
|
|
183
|
+
/** Entries per table {@link CodexRolloutParser.exportResumeState} keeps by default. */
|
|
184
|
+
const DEFAULT_RESUME_STATE_LIMIT = 256;
|
|
185
|
+
/** Raw names of Codex's multi-agent tools (namespace `collaboration`). */
|
|
186
|
+
const COLLABORATION_TOOL_NAMES = new Set([
|
|
187
|
+
'spawn_agent',
|
|
188
|
+
'followup_task',
|
|
189
|
+
'send_message',
|
|
190
|
+
'interrupt_agent',
|
|
191
|
+
'wait_agent',
|
|
192
|
+
'list_agents',
|
|
193
|
+
]);
|
|
194
|
+
const SUBAGENT_ACTIVITY_KINDS = new Set([
|
|
195
|
+
'started',
|
|
196
|
+
'completed',
|
|
197
|
+
'interacted',
|
|
198
|
+
'interrupted',
|
|
199
|
+
]);
|
|
200
|
+
function nonEmptyString(value) {
|
|
201
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
202
|
+
}
|
|
203
|
+
/** `subagent_history_start_ordinal` of a session_meta payload, when valid. */
|
|
204
|
+
function historyStartOrdinalOf(meta) {
|
|
205
|
+
const value = meta?.subagent_history_start_ordinal;
|
|
206
|
+
return typeof value === 'number' && Number.isInteger(value) && value > 0 ? value : null;
|
|
207
|
+
}
|
|
208
|
+
function isPlainObject(value) {
|
|
209
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
210
|
+
}
|
|
211
|
+
function cloneJson(value) {
|
|
212
|
+
return JSON.parse(JSON.stringify(value));
|
|
213
|
+
}
|
|
214
|
+
function isOptionalString(value) {
|
|
215
|
+
return value === undefined || typeof value === 'string';
|
|
216
|
+
}
|
|
217
|
+
function isStringArray(value) {
|
|
218
|
+
return Array.isArray(value) && value.every((item) => typeof item === 'string');
|
|
219
|
+
}
|
|
220
|
+
function isTokenCount(value) {
|
|
221
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0;
|
|
222
|
+
}
|
|
223
|
+
/** A valid `CodexTokenUsage` (copied), `null` for `null`, or `undefined` when invalid. Internal. */
|
|
224
|
+
function codexTokenUsageFrom(value) {
|
|
225
|
+
if (value === null)
|
|
226
|
+
return null;
|
|
227
|
+
if (!isPlainObject(value))
|
|
228
|
+
return undefined;
|
|
229
|
+
if (!isTokenCount(value.input_tokens) || !isTokenCount(value.output_tokens))
|
|
230
|
+
return undefined;
|
|
231
|
+
const usage = {
|
|
232
|
+
input_tokens: value.input_tokens,
|
|
233
|
+
output_tokens: value.output_tokens,
|
|
234
|
+
};
|
|
235
|
+
for (const field of ['cached_input_tokens', 'reasoning_output_tokens', 'total_tokens']) {
|
|
236
|
+
const count = value[field];
|
|
237
|
+
if (count === undefined)
|
|
238
|
+
continue;
|
|
239
|
+
if (!isTokenCount(count))
|
|
240
|
+
return undefined;
|
|
241
|
+
usage[field] = count;
|
|
242
|
+
}
|
|
243
|
+
return usage;
|
|
244
|
+
}
|
|
245
|
+
/** Last `limit` items of an insertion-ordered collection, oldest first. */
|
|
246
|
+
function newest(items, size, limit) {
|
|
247
|
+
const count = limit >= 0 ? Math.min(size, Math.floor(limit)) : 0;
|
|
248
|
+
const kept = [];
|
|
249
|
+
let skip = size - count;
|
|
250
|
+
for (const item of items) {
|
|
251
|
+
if (kept.length >= count)
|
|
252
|
+
break;
|
|
253
|
+
if (skip > 0) {
|
|
254
|
+
skip -= 1;
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
kept.push(item);
|
|
258
|
+
}
|
|
259
|
+
return kept;
|
|
260
|
+
}
|
|
181
261
|
/** Fixed per-entry cost added to each pending call's byte estimate. */
|
|
182
262
|
const PENDING_ENTRY_OVERHEAD_BYTES = 64;
|
|
183
263
|
/** Prefix of the bookkeeping keys the parser stashes inside tool inputs. */
|
|
@@ -242,6 +322,15 @@ class CodexRolloutParser {
|
|
|
242
322
|
/** Byte budget for pending calls; `null` = unlimited (no accounting). */
|
|
243
323
|
maxPendingBytes;
|
|
244
324
|
metadataOnly;
|
|
325
|
+
includeSubagentActivity;
|
|
326
|
+
/**
|
|
327
|
+
* Set once a forked child's rollout embeds an ancestor's session_meta: its
|
|
328
|
+
* own `subagent_history_start_ordinal`, below which records are the
|
|
329
|
+
* parent's history and are skipped. `null` while nothing is skipped.
|
|
330
|
+
*/
|
|
331
|
+
historyStartOrdinal = null;
|
|
332
|
+
/** Multi-agent tool calls (call id → raw name), only with `includeSubagentActivity`. */
|
|
333
|
+
collaborationCalls = new Map();
|
|
245
334
|
/** Pending calls in insertion order, for the byte budget. */
|
|
246
335
|
pendingLedger = new Map();
|
|
247
336
|
pendingBytes = 0;
|
|
@@ -257,6 +346,7 @@ class CodexRolloutParser {
|
|
|
257
346
|
? Math.floor(maxBytes)
|
|
258
347
|
: null;
|
|
259
348
|
this.metadataOnly = options.metadataOnly === true;
|
|
349
|
+
this.includeSubagentActivity = options.includeSubagentActivity === true;
|
|
260
350
|
}
|
|
261
351
|
/** Counters for the pending tool-call state and what the caps evicted. */
|
|
262
352
|
getPendingStats() {
|
|
@@ -289,13 +379,172 @@ class CodexRolloutParser {
|
|
|
289
379
|
getLastRateLimits() {
|
|
290
380
|
return this.lastRateLimits;
|
|
291
381
|
}
|
|
382
|
+
/**
|
|
383
|
+
* In a forked subagent's rollout, the ordinal of its first own record:
|
|
384
|
+
* records with a lower `ordinal` are the parent history the fork embeds
|
|
385
|
+
* and produce no events. Known once the rollout's second line (an embedded
|
|
386
|
+
* ancestor `session_meta`) was parsed; `null` otherwise, and for every
|
|
387
|
+
* rollout that is not such a fork.
|
|
388
|
+
*/
|
|
389
|
+
getInheritedHistoryEnd() {
|
|
390
|
+
return this.historyStartOrdinal;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* The state later lines depend on — session metadata, current model,
|
|
394
|
+
* previous cumulative token total, context window, rate limits, plan mode,
|
|
395
|
+
* and the tool-call correlation tables (newest `limit` entries each) — as
|
|
396
|
+
* JSON-serializable data. Eviction counters are not included.
|
|
397
|
+
*/
|
|
398
|
+
exportResumeState(limit = DEFAULT_RESUME_STATE_LIMIT) {
|
|
399
|
+
return cloneJson({
|
|
400
|
+
version: 1,
|
|
401
|
+
sessionMeta: this.sessionMeta,
|
|
402
|
+
currentModel: this.currentModel,
|
|
403
|
+
prevTotalUsage: this.prevTotalUsage,
|
|
404
|
+
lastTokenUsage: this.lastTokenUsage,
|
|
405
|
+
modelContextWindow: this.modelContextWindow,
|
|
406
|
+
lastRateLimits: this.lastRateLimits,
|
|
407
|
+
hasAggregateRateLimits: this.hasAggregateRateLimits,
|
|
408
|
+
inPlanMode: this.inPlanMode,
|
|
409
|
+
emittedToolUseIds: newest(this.emittedToolUseIds, this.emittedToolUseIds.size, limit),
|
|
410
|
+
patchExpandedToolUseIds: newest(this.patchExpandedToolUseIds, this.patchExpandedToolUseIds.size, limit),
|
|
411
|
+
pendingExecCommands: newest(this.pendingExecCommands.values(), this.pendingExecCommands.size, limit),
|
|
412
|
+
pendingMcpToolCalls: newest(this.pendingMcpToolCalls.values(), this.pendingMcpToolCalls.size, limit),
|
|
413
|
+
...(this.historyStartOrdinal !== null
|
|
414
|
+
? { inheritedHistoryEnd: this.historyStartOrdinal }
|
|
415
|
+
: {}),
|
|
416
|
+
...(this.collaborationCalls.size > 0
|
|
417
|
+
? {
|
|
418
|
+
collaborationCalls: newest(this.collaborationCalls, this.collaborationCalls.size, limit),
|
|
419
|
+
}
|
|
420
|
+
: {}),
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Replaces this parser's state with one from {@link exportResumeState}, as
|
|
425
|
+
* if it had parsed the rollout up to where that state was taken. Returns
|
|
426
|
+
* false, changing nothing, when `state` is not a valid version-1 state.
|
|
427
|
+
* This parser's own `maxTrackedToolCalls`, `maxPendingBytes`, and
|
|
428
|
+
* `metadataOnly` options apply to the imported tables.
|
|
429
|
+
*/
|
|
430
|
+
importResumeState(state) {
|
|
431
|
+
if (!isPlainObject(state) || state.version !== 1)
|
|
432
|
+
return false;
|
|
433
|
+
const s = state;
|
|
434
|
+
const prevTotalUsage = codexTokenUsageFrom(s.prevTotalUsage);
|
|
435
|
+
const lastTokenUsage = codexTokenUsageFrom(s.lastTokenUsage);
|
|
436
|
+
if (prevTotalUsage === undefined || lastTokenUsage === undefined)
|
|
437
|
+
return false;
|
|
438
|
+
if (s.sessionMeta !== null && !isPlainObject(s.sessionMeta))
|
|
439
|
+
return false;
|
|
440
|
+
if (s.lastRateLimits !== null && !isPlainObject(s.lastRateLimits))
|
|
441
|
+
return false;
|
|
442
|
+
if (s.currentModel !== null && typeof s.currentModel !== 'string')
|
|
443
|
+
return false;
|
|
444
|
+
const contextWindow = s.modelContextWindow;
|
|
445
|
+
if (contextWindow !== null &&
|
|
446
|
+
!(typeof contextWindow === 'number' && Number.isFinite(contextWindow) && contextWindow > 0)) {
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
if (typeof s.hasAggregateRateLimits !== 'boolean' || typeof s.inPlanMode !== 'boolean') {
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
if (!isStringArray(s.emittedToolUseIds))
|
|
453
|
+
return false;
|
|
454
|
+
const patches = s.patchExpandedToolUseIds;
|
|
455
|
+
if (!Array.isArray(patches) ||
|
|
456
|
+
!patches.every((entry) => Array.isArray(entry) &&
|
|
457
|
+
entry.length === 2 &&
|
|
458
|
+
typeof entry[0] === 'string' &&
|
|
459
|
+
isStringArray(entry[1]))) {
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
const execs = s.pendingExecCommands;
|
|
463
|
+
if (!Array.isArray(execs) ||
|
|
464
|
+
!execs.every((entry) => isPlainObject(entry) &&
|
|
465
|
+
typeof entry.call_id === 'string' &&
|
|
466
|
+
isStringArray(entry.command) &&
|
|
467
|
+
isOptionalString(entry.workdir) &&
|
|
468
|
+
typeof entry.timestamp === 'string')) {
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
const mcps = s.pendingMcpToolCalls;
|
|
472
|
+
if (!Array.isArray(mcps) ||
|
|
473
|
+
!mcps.every((entry) => isPlainObject(entry) &&
|
|
474
|
+
typeof entry.call_id === 'string' &&
|
|
475
|
+
typeof entry.tool_name === 'string' &&
|
|
476
|
+
isOptionalString(entry.server_name) &&
|
|
477
|
+
(entry.arguments === undefined || isPlainObject(entry.arguments)) &&
|
|
478
|
+
typeof entry.timestamp === 'string')) {
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
const inheritedEnd = s.inheritedHistoryEnd;
|
|
482
|
+
if (inheritedEnd !== undefined &&
|
|
483
|
+
inheritedEnd !== null &&
|
|
484
|
+
!(typeof inheritedEnd === 'number' && Number.isInteger(inheritedEnd) && inheritedEnd > 0)) {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
const collaborationCalls = s.collaborationCalls;
|
|
488
|
+
if (collaborationCalls !== undefined &&
|
|
489
|
+
!(Array.isArray(collaborationCalls) &&
|
|
490
|
+
collaborationCalls.every((entry) => Array.isArray(entry) &&
|
|
491
|
+
entry.length === 2 &&
|
|
492
|
+
typeof entry[0] === 'string' &&
|
|
493
|
+
typeof entry[1] === 'string'))) {
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
const copy = cloneJson({
|
|
497
|
+
sessionMeta: s.sessionMeta,
|
|
498
|
+
lastRateLimits: s.lastRateLimits,
|
|
499
|
+
patches: patches,
|
|
500
|
+
execs: execs,
|
|
501
|
+
mcps: mcps,
|
|
502
|
+
});
|
|
503
|
+
this.reset();
|
|
504
|
+
this.sessionMeta = copy.sessionMeta;
|
|
505
|
+
this.historyStartOrdinal = typeof inheritedEnd === 'number' ? inheritedEnd : null;
|
|
506
|
+
this.currentModel = s.currentModel;
|
|
507
|
+
this.prevTotalUsage = prevTotalUsage;
|
|
508
|
+
this.lastTokenUsage = lastTokenUsage;
|
|
509
|
+
this.modelContextWindow = contextWindow;
|
|
510
|
+
this.lastRateLimits = copy.lastRateLimits;
|
|
511
|
+
this.hasAggregateRateLimits = s.hasAggregateRateLimits;
|
|
512
|
+
this.inPlanMode = s.inPlanMode;
|
|
513
|
+
for (const id of s.emittedToolUseIds) {
|
|
514
|
+
rememberBounded(this.emittedToolUseIds, id, this.maxTrackedToolCalls);
|
|
515
|
+
}
|
|
516
|
+
for (const [callId, toolUseIds] of copy.patches)
|
|
517
|
+
this.putPendingPatch(callId, toolUseIds);
|
|
518
|
+
for (const pending of copy.execs) {
|
|
519
|
+
this.putPendingExec(this.metadataOnly
|
|
520
|
+
? { call_id: pending.call_id, command: [], timestamp: pending.timestamp }
|
|
521
|
+
: pending);
|
|
522
|
+
}
|
|
523
|
+
for (const pending of copy.mcps) {
|
|
524
|
+
this.putPendingMcp(this.metadataOnly ? { ...pending, arguments: undefined } : pending);
|
|
525
|
+
}
|
|
526
|
+
if (this.includeSubagentActivity && Array.isArray(collaborationCalls)) {
|
|
527
|
+
for (const [callId, name] of collaborationCalls) {
|
|
528
|
+
this.rememberCollaborationCall(callId, name);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return true;
|
|
532
|
+
}
|
|
292
533
|
/**
|
|
293
534
|
* Converts a single rollout line to zero or more session events.
|
|
294
535
|
*/
|
|
295
536
|
convertLine(line) {
|
|
537
|
+
if (line.type === 'session_meta') {
|
|
538
|
+
return this.handleSessionMeta(line.timestamp, line.payload, line.ordinal);
|
|
539
|
+
}
|
|
540
|
+
// A forked subagent rollout embeds the parent's history before its own
|
|
541
|
+
// records; that history is the parent's, not the child's.
|
|
542
|
+
if (this.historyStartOrdinal !== null &&
|
|
543
|
+
typeof line.ordinal === 'number' &&
|
|
544
|
+
line.ordinal < this.historyStartOrdinal) {
|
|
545
|
+
return [];
|
|
546
|
+
}
|
|
296
547
|
switch (line.type) {
|
|
297
|
-
case 'session_meta':
|
|
298
|
-
return this.handleSessionMeta(line.timestamp, line.payload);
|
|
299
548
|
case 'response_item':
|
|
300
549
|
return this.handleResponseItem(line.timestamp, line.payload);
|
|
301
550
|
case 'compacted':
|
|
@@ -311,6 +560,8 @@ class CodexRolloutParser {
|
|
|
311
560
|
/** Reset all parser state. */
|
|
312
561
|
reset() {
|
|
313
562
|
this.sessionMeta = null;
|
|
563
|
+
this.historyStartOrdinal = null;
|
|
564
|
+
this.collaborationCalls.clear();
|
|
314
565
|
this.currentModel = null;
|
|
315
566
|
this.pendingExecCommands.clear();
|
|
316
567
|
this.pendingMcpToolCalls.clear();
|
|
@@ -360,6 +611,16 @@ class CodexRolloutParser {
|
|
|
360
611
|
this.evictedByBytes += 1;
|
|
361
612
|
}
|
|
362
613
|
}
|
|
614
|
+
putPendingExec(pending) {
|
|
615
|
+
this.putPending(this.pendingExecCommands, pending.call_id, pending, () => stringBytes(pending.call_id, pending.workdir, pending.timestamp, ...(Array.isArray(pending.command) ? pending.command : [])));
|
|
616
|
+
}
|
|
617
|
+
putPendingMcp(pending) {
|
|
618
|
+
this.putPending(this.pendingMcpToolCalls, pending.call_id, pending, () => stringBytes(pending.call_id, pending.server_name, pending.tool_name, pending.timestamp) +
|
|
619
|
+
approxJsonBytes(pending.arguments));
|
|
620
|
+
}
|
|
621
|
+
putPendingPatch(callId, toolUseIds) {
|
|
622
|
+
this.putPending(this.patchExpandedToolUseIds, callId, toolUseIds, () => stringBytes(callId, ...toolUseIds));
|
|
623
|
+
}
|
|
363
624
|
/** Removes and returns a pending call. */
|
|
364
625
|
takePending(table, callId) {
|
|
365
626
|
const value = table.get(callId);
|
|
@@ -390,7 +651,25 @@ class CodexRolloutParser {
|
|
|
390
651
|
return this.metadataOnly ? '' : content;
|
|
391
652
|
}
|
|
392
653
|
// --- Handlers ---
|
|
393
|
-
handleSessionMeta(timestamp, payload) {
|
|
654
|
+
handleSessionMeta(timestamp, payload, ordinal) {
|
|
655
|
+
if (this.sessionMeta) {
|
|
656
|
+
// Only the rollout's own (first) session_meta counts. A forked child
|
|
657
|
+
// embeds its parent's right after its own, followed by the parent's
|
|
658
|
+
// history up to the child's `subagent_history_start_ordinal`; from
|
|
659
|
+
// here on, records below that ordinal are skipped. (Children whose
|
|
660
|
+
// rollout has no embedded meta keep every record: in some, Codex
|
|
661
|
+
// recorded a start ordinal past their own records.)
|
|
662
|
+
const start = historyStartOrdinalOf(this.sessionMeta);
|
|
663
|
+
if (this.historyStartOrdinal === null &&
|
|
664
|
+
start !== null &&
|
|
665
|
+
typeof ordinal === 'number' &&
|
|
666
|
+
ordinal < start) {
|
|
667
|
+
this.historyStartOrdinal = start;
|
|
668
|
+
}
|
|
669
|
+
return [];
|
|
670
|
+
}
|
|
671
|
+
if (!payload || typeof payload !== 'object')
|
|
672
|
+
return [];
|
|
394
673
|
this.sessionMeta = payload;
|
|
395
674
|
const text = payload.base_instructions?.text?.trim();
|
|
396
675
|
return [
|
|
@@ -430,10 +709,91 @@ class CodexRolloutParser {
|
|
|
430
709
|
return this.handleCustomToolCall(timestamp, payload);
|
|
431
710
|
case 'custom_tool_call_output':
|
|
432
711
|
return this.handleCustomToolCallOutput(timestamp, payload);
|
|
712
|
+
case 'agent_message':
|
|
713
|
+
return this.handleAgentMessage(timestamp, payload);
|
|
433
714
|
default:
|
|
434
715
|
return [];
|
|
435
716
|
}
|
|
436
717
|
}
|
|
718
|
+
// --- Subagent activity ---
|
|
719
|
+
rememberCollaborationCall(callId, name) {
|
|
720
|
+
this.collaborationCalls.delete(callId);
|
|
721
|
+
this.collaborationCalls.set(callId, name);
|
|
722
|
+
while (this.collaborationCalls.size > this.maxTrackedToolCalls) {
|
|
723
|
+
this.collaborationCalls.delete(this.collaborationCalls.keys().next().value);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
subagentActivityEvent(timestamp, id, activity) {
|
|
727
|
+
return {
|
|
728
|
+
type: 'system',
|
|
729
|
+
timestamp,
|
|
730
|
+
origin: { kind: subagentActivity_1.SUBAGENT_ACTIVITY_ORIGIN_KIND },
|
|
731
|
+
message: {
|
|
732
|
+
role: 'system',
|
|
733
|
+
id: `subagent-activity:${id}`,
|
|
734
|
+
sourceLabel: 'subagent activity',
|
|
735
|
+
content: [{ type: subagentActivity_1.SUBAGENT_ACTIVITY_BLOCK_TYPE, ...activity }],
|
|
736
|
+
},
|
|
737
|
+
providerMetadata: { providerId: 'codex', source: 'codex-rollout' },
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
/** A child's `FINAL_ANSWER` message to its parent (opt-in). */
|
|
741
|
+
handleAgentMessage(timestamp, item) {
|
|
742
|
+
if (!this.includeSubagentActivity || !Array.isArray(item.content))
|
|
743
|
+
return [];
|
|
744
|
+
const first = item.content.find((part) => !!part && typeof part === 'object' && typeof part.text === 'string');
|
|
745
|
+
const parsed = (0, subagentActivity_1.parseCodexAgentMessageText)(first?.text);
|
|
746
|
+
if (!parsed || parsed.messageType !== 'FINAL_ANSWER')
|
|
747
|
+
return [];
|
|
748
|
+
const agentPath = nonEmptyString(item.author) ?? parsed.sender;
|
|
749
|
+
const recipient = nonEmptyString(item.recipient) ?? parsed.taskName;
|
|
750
|
+
const text = this.metadataOnly ? undefined : nonEmptyString(parsed.payload.trim());
|
|
751
|
+
const activity = {
|
|
752
|
+
kind: 'final-answer',
|
|
753
|
+
...(agentPath ? { agentPath } : {}),
|
|
754
|
+
...(recipient ? { recipient } : {}),
|
|
755
|
+
...(text ? { text } : {}),
|
|
756
|
+
};
|
|
757
|
+
return [
|
|
758
|
+
this.subagentActivityEvent(timestamp, nonEmptyString(item.id) ?? `final-answer-${timestamp}-${agentPath ?? ''}`, activity),
|
|
759
|
+
];
|
|
760
|
+
}
|
|
761
|
+
/** A `SubAgentActivity` turn item (opt-in). */
|
|
762
|
+
handleItemCompleted(timestamp, event) {
|
|
763
|
+
if (!this.includeSubagentActivity)
|
|
764
|
+
return [];
|
|
765
|
+
const item = event.item;
|
|
766
|
+
if (!item || item.type !== 'SubAgentActivity')
|
|
767
|
+
return [];
|
|
768
|
+
const kind = typeof item.kind === 'string' ? item.kind : '';
|
|
769
|
+
if (!SUBAGENT_ACTIVITY_KINDS.has(kind))
|
|
770
|
+
return [];
|
|
771
|
+
const itemId = nonEmptyString(item.id);
|
|
772
|
+
const completedTurn = kind === 'completed' && itemId?.startsWith('subagent-completed-')
|
|
773
|
+
? nonEmptyString(itemId.slice('subagent-completed-'.length))
|
|
774
|
+
: undefined;
|
|
775
|
+
const callId = kind === 'completed' ? undefined : itemId;
|
|
776
|
+
const tool = callId ? this.collaborationCalls.get(callId) : undefined;
|
|
777
|
+
const fields = {
|
|
778
|
+
callId,
|
|
779
|
+
tool,
|
|
780
|
+
turnId: completedTurn,
|
|
781
|
+
agentThreadId: nonEmptyString(item.agent_thread_id),
|
|
782
|
+
agentPath: nonEmptyString(item.agent_path),
|
|
783
|
+
model: nonEmptyString(item.model),
|
|
784
|
+
reasoningEffort: nonEmptyString(item.reasoning_effort),
|
|
785
|
+
parentThreadId: nonEmptyString(event.thread_id),
|
|
786
|
+
parentTurnId: nonEmptyString(event.turn_id),
|
|
787
|
+
};
|
|
788
|
+
const activity = { kind: kind };
|
|
789
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
790
|
+
if (value !== undefined)
|
|
791
|
+
activity[key] = value;
|
|
792
|
+
}
|
|
793
|
+
return [
|
|
794
|
+
this.subagentActivityEvent(timestamp, itemId ?? `${kind}-${timestamp}-${activity.agentThreadId ?? ''}`, activity),
|
|
795
|
+
];
|
|
796
|
+
}
|
|
437
797
|
handleMessage(timestamp, item) {
|
|
438
798
|
const text = extractTextFromContent(item.content);
|
|
439
799
|
if (!text)
|
|
@@ -515,6 +875,11 @@ class CodexRolloutParser {
|
|
|
515
875
|
const canonicalName = normalizeCodexToolName(item.name);
|
|
516
876
|
const normalizedInput = normalizeCodexToolInput(canonicalName, item.name, parsedArgs);
|
|
517
877
|
rememberBounded(this.emittedToolUseIds, item.call_id, this.maxTrackedToolCalls);
|
|
878
|
+
if (this.includeSubagentActivity &&
|
|
879
|
+
typeof item.call_id === 'string' &&
|
|
880
|
+
(item.namespace === 'collaboration' || COLLABORATION_TOOL_NAMES.has(item.name))) {
|
|
881
|
+
this.rememberCollaborationCall(item.call_id, item.name);
|
|
882
|
+
}
|
|
518
883
|
return [
|
|
519
884
|
{
|
|
520
885
|
type: 'assistant',
|
|
@@ -589,7 +954,7 @@ class CodexRolloutParser {
|
|
|
589
954
|
if (filePaths.length === 0)
|
|
590
955
|
return [];
|
|
591
956
|
const toolUseIds = filePaths.map((fp) => `${item.call_id}-${fp}`);
|
|
592
|
-
this.
|
|
957
|
+
this.putPendingPatch(item.call_id, toolUseIds);
|
|
593
958
|
for (const id of toolUseIds) {
|
|
594
959
|
rememberBounded(this.emittedToolUseIds, id, this.maxTrackedToolCalls);
|
|
595
960
|
}
|
|
@@ -739,7 +1104,7 @@ class CodexRolloutParser {
|
|
|
739
1104
|
const pending = this.metadataOnly
|
|
740
1105
|
? { call_id: e.call_id, command: [], timestamp }
|
|
741
1106
|
: { call_id: e.call_id, command: e.command, workdir: e.workdir, timestamp };
|
|
742
|
-
this.
|
|
1107
|
+
this.putPendingExec(pending);
|
|
743
1108
|
return [];
|
|
744
1109
|
}
|
|
745
1110
|
case 'exec_command_end': {
|
|
@@ -802,8 +1167,7 @@ class CodexRolloutParser {
|
|
|
802
1167
|
arguments: this.metadataOnly ? undefined : e.arguments,
|
|
803
1168
|
timestamp,
|
|
804
1169
|
};
|
|
805
|
-
this.
|
|
806
|
-
approxJsonBytes(pending.arguments));
|
|
1170
|
+
this.putPendingMcp(pending);
|
|
807
1171
|
return [];
|
|
808
1172
|
}
|
|
809
1173
|
case 'mcp_tool_call_end': {
|
|
@@ -972,6 +1336,8 @@ class CodexRolloutParser {
|
|
|
972
1336
|
timestamp,
|
|
973
1337
|
},
|
|
974
1338
|
];
|
|
1339
|
+
case 'item_completed':
|
|
1340
|
+
return this.handleItemCompleted(timestamp, event);
|
|
975
1341
|
case 'turn_aborted':
|
|
976
1342
|
case 'agent_reasoning':
|
|
977
1343
|
case 'agent_message':
|
|
@@ -22,6 +22,7 @@ exports.convertOpenCodeMessage = convertOpenCodeMessage;
|
|
|
22
22
|
exports.parseDbMessageData = parseDbMessageData;
|
|
23
23
|
exports.parseDbPartData = parseDbPartData;
|
|
24
24
|
const usageNormalization_1 = require("../usageNormalization");
|
|
25
|
+
const ownKey_1 = require("../ownKey");
|
|
25
26
|
/**
|
|
26
27
|
* OpenCode → Claude Code tool name mapping.
|
|
27
28
|
* OpenCode uses lowercase names; downstream code expects PascalCase.
|
|
@@ -57,7 +58,7 @@ function normalizeToolName(name) {
|
|
|
57
58
|
if (!name)
|
|
58
59
|
return name;
|
|
59
60
|
// Check mapping (case-insensitive lookup via lowercase key)
|
|
60
|
-
const mapped = TOOL_NAME_MAP
|
|
61
|
+
const mapped = (0, ownKey_1.ownValue)(TOOL_NAME_MAP, name.toLowerCase());
|
|
61
62
|
if (mapped)
|
|
62
63
|
return mapped;
|
|
63
64
|
// Already PascalCase (starts with uppercase)? Pass through.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a Claude Code subagent transcript ended cleanly, read line by line.
|
|
3
|
+
*
|
|
4
|
+
* Clean means: the last user or assistant line is an assistant line that
|
|
5
|
+
* stopped with `end_turn` or `stop_sequence`, and every `tool_use` in the
|
|
6
|
+
* transcript has its `tool_result`. A user line after that (a resumed agent's
|
|
7
|
+
* new prompt) makes it unfinished again.
|
|
8
|
+
*
|
|
9
|
+
* Pure. Internal to the subagent parsers.
|
|
10
|
+
*
|
|
11
|
+
* @module parsers/subagentEndState
|
|
12
|
+
*/
|
|
13
|
+
export declare class SubagentEndTracker {
|
|
14
|
+
private readonly unanswered;
|
|
15
|
+
private lastWasCleanAssistant;
|
|
16
|
+
/** Feeds one parsed JSONL line, in file order. */
|
|
17
|
+
observe(raw: unknown): void;
|
|
18
|
+
/** Whether the lines so far end cleanly. */
|
|
19
|
+
endedCleanly(): boolean;
|
|
20
|
+
}
|