sidekick-shared 0.29.1 → 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 +26 -0
- package/README.md +171 -60
- package/dist/aggregation/EventAggregator.d.ts +79 -4
- package/dist/aggregation/EventAggregator.js +391 -37
- package/dist/aggregation/types.d.ts +27 -3
- package/dist/browser.d.ts +7 -3
- package/dist/browser.js +23 -3
- package/dist/context/sessionContext.js +5 -1
- package/dist/esm/aggregation/EventAggregator.js +392 -38
- package/dist/esm/browser.js +3 -1
- package/dist/esm/context/sessionContext.js +6 -2
- package/dist/esm/fileContinuity.js +149 -0
- package/dist/esm/index.js +5 -2
- package/dist/esm/node.js +2 -0
- package/dist/esm/parsers/codexParser.js +192 -3
- package/dist/esm/parsers/subagentEndState.js +61 -0
- package/dist/esm/parsers/subagentScanner.js +4 -0
- package/dist/esm/parsers/subagentTraceParser.js +6 -0
- package/dist/esm/promptHistory.js +22 -11
- package/dist/esm/providers/claudeCode.js +50 -27
- package/dist/esm/providers/codex.js +153 -163
- 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 +32 -4
- 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 +206 -6
- 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 +6 -2
- package/dist/esm/turns/assistantTurn.js +6 -3
- package/dist/esm/usage/usageEvents.js +4 -1
- package/dist/esm/watchers/eventBridge.js +31 -1
- package/dist/esm/watchers/jsonlTail.js +11 -42
- package/dist/esm/watchers/jsonlWatcher.js +19 -9
- package/dist/esm/watchers/providerReaderWatcher.js +5 -4
- package/dist/fileContinuity.d.ts +95 -0
- package/dist/fileContinuity.js +187 -0
- package/dist/index.d.ts +14 -7
- package/dist/index.js +39 -10
- package/dist/node.d.ts +4 -0
- package/dist/node.js +16 -2
- package/dist/parsers/codexParser.d.ts +44 -0
- package/dist/parsers/codexParser.js +192 -3
- package/dist/parsers/subagentEndState.d.ts +20 -0
- package/dist/parsers/subagentEndState.js +65 -0
- package/dist/parsers/subagentScanner.js +4 -0
- package/dist/parsers/subagentTraceParser.d.ts +8 -0
- package/dist/parsers/subagentTraceParser.js +6 -0
- package/dist/promptHistory.d.ts +13 -3
- package/dist/promptHistory.js +22 -11
- package/dist/providers/claudeCode.js +50 -27
- package/dist/providers/codex.d.ts +35 -5
- package/dist/providers/codex.js +150 -160
- 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 +22 -1
- package/dist/schemas/sessionEvent.d.ts +26 -2
- package/dist/schemas/sessionEvent.js +31 -3
- 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 +100 -5
- package/dist/subagentSpawn.js +218 -7
- 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 +5 -1
- package/dist/turns/assistantTurn.d.ts +4 -1
- package/dist/turns/assistantTurn.js +5 -2
- package/dist/types/codex.d.ts +71 -2
- package/dist/types/sessionEvent.d.ts +38 -3
- package/dist/usage/usageEvents.d.ts +4 -1
- package/dist/usage/usageEvents.js +4 -1
- package/dist/watchers/eventBridge.js +30 -0
- package/dist/watchers/jsonlTail.js +11 -42
- package/dist/watchers/jsonlWatcher.d.ts +5 -1
- package/dist/watchers/jsonlWatcher.js +18 -8
- package/dist/watchers/providerReaderWatcher.js +5 -4
- package/package.json +1 -1
|
@@ -18,7 +18,8 @@ import { HeatmapTracker } from './HeatmapTracker';
|
|
|
18
18
|
import { PatternExtractor } from './PatternExtractor';
|
|
19
19
|
import { categorizeError } from '../extractors/errorTaxonomy';
|
|
20
20
|
import { estimateTextTokens } from '../tokenEstimation';
|
|
21
|
-
import {
|
|
21
|
+
import { describeSubagentActivity, isSubagentActivitySystemEvent, subagentActivityFromEvent, } from '../subagentActivity';
|
|
22
|
+
import { agentsStoppedNoticeFromEvent, describeAgentsStopped, describeTaskStatus, isAgentsKilledSystemEvent, isCodexSubagentSpawnTool, isFinalTaskStatus, isSubagentSpawnTool, isTaskNotificationSystemEvent, isTaskStatusSystemEvent, parseAgentsStoppedNotice, parseAsyncAgentLaunch, parseCodexSpawnLaunch, parseTaskNotification, taskNotificationFromEvent, taskNotificationOutcome, taskNotificationPromptFromAttachment, taskStatusFromAttachment, taskStatusFromEvent, } from '../subagentSpawn';
|
|
22
23
|
import { calculateNormalizedUsageCost, extractNormalizedUsage, normalizeProviderUsage, } from '../usageNormalization';
|
|
23
24
|
// ── Defaults ──
|
|
24
25
|
const DEFAULT_TIMELINE_CAP = 200;
|
|
@@ -27,8 +28,26 @@ const DEFAULT_CONTEXT_TIMELINE_CAP = 2_000;
|
|
|
27
28
|
const DEFAULT_BURN_WINDOW_MS = 5 * 60_000;
|
|
28
29
|
const DEFAULT_BURN_SAMPLE_MS = 10_000;
|
|
29
30
|
const COMPACTION_DROP_THRESHOLD = 0.8; // >20% drop
|
|
30
|
-
/**
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Schema version for serialized snapshots. v6: token totals count each Claude
|
|
33
|
+
* response and Codex call once. v7: subagent lifecycles track Codex spawns and
|
|
34
|
+
* record what settled a background agent (`settledBy`).
|
|
35
|
+
*/
|
|
36
|
+
export const SNAPSHOT_SCHEMA_VERSION = 7;
|
|
37
|
+
// Checked without the schema module so this file stays free of Zod.
|
|
38
|
+
const PERMISSION_MODES = new Set([
|
|
39
|
+
'default',
|
|
40
|
+
'acceptEdits',
|
|
41
|
+
'bypassPermissions',
|
|
42
|
+
'plan',
|
|
43
|
+
'auto',
|
|
44
|
+
'dontAsk',
|
|
45
|
+
]);
|
|
46
|
+
function asPermissionMode(value) {
|
|
47
|
+
return typeof value === 'string' && PERMISSION_MODES.has(value)
|
|
48
|
+
? value
|
|
49
|
+
: null;
|
|
50
|
+
}
|
|
32
51
|
// ── Goal gate detection regex ──
|
|
33
52
|
const GOAL_GATE_REGEX = /\b(CRITICAL|MUST|blocker|required|must.?complete|goal.?gate|essential|do.?not.?skip|blocking)\b/i;
|
|
34
53
|
// ── Task notifications delivered as attachments ──
|
|
@@ -47,6 +66,62 @@ function taskNotificationFromAttachmentFollowEvent(event) {
|
|
|
47
66
|
const asEvent = raw;
|
|
48
67
|
return isTaskNotificationSystemEvent(asEvent) ? taskNotificationFromEvent(asEvent) : null;
|
|
49
68
|
}
|
|
69
|
+
function subagentRecordFromFollowEvent(event) {
|
|
70
|
+
const raw = event.raw;
|
|
71
|
+
if (!raw || typeof raw !== 'object')
|
|
72
|
+
return null;
|
|
73
|
+
const notification = taskNotificationFromAttachmentFollowEvent(event);
|
|
74
|
+
if (notification)
|
|
75
|
+
return { kind: 'notification', notification };
|
|
76
|
+
const asEvent = raw;
|
|
77
|
+
const prompt = taskNotificationPromptFromAttachment(raw);
|
|
78
|
+
const notice = prompt !== null ? parseAgentsStoppedNotice(prompt) : agentsStoppedNoticeFromEvent(asEvent);
|
|
79
|
+
if (notice)
|
|
80
|
+
return { kind: 'stopped', notice };
|
|
81
|
+
if (prompt !== null || isTaskNotificationSystemEvent(asEvent)) {
|
|
82
|
+
// A notification this release cannot read: still bookkeeping.
|
|
83
|
+
return { kind: 'unreadable' };
|
|
84
|
+
}
|
|
85
|
+
const status = taskStatusFromAttachment(raw) ?? taskStatusFromEvent(asEvent);
|
|
86
|
+
if (status)
|
|
87
|
+
return { kind: 'task-status', status };
|
|
88
|
+
if (isSubagentActivitySystemEvent(asEvent)) {
|
|
89
|
+
const activity = subagentActivityFromEvent(asEvent);
|
|
90
|
+
return activity ? { kind: 'activity', activity } : { kind: 'unreadable' };
|
|
91
|
+
}
|
|
92
|
+
if (isAgentsKilledSystemEvent(raw))
|
|
93
|
+
return { kind: 'agents-killed' };
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
// ── Subagent spawn input ──
|
|
97
|
+
/**
|
|
98
|
+
* Description and type of a spawn: Claude Code's `description` /
|
|
99
|
+
* `subagent_type`, or Codex `spawn_agent`'s `task_name` / `agent_type`.
|
|
100
|
+
*/
|
|
101
|
+
function spawnFields(input) {
|
|
102
|
+
const text = (value) => typeof value === 'string' && value ? value : undefined;
|
|
103
|
+
const description = text(input.description) ?? text(input.task_name);
|
|
104
|
+
const subagentType = text(input.subagent_type) ?? text(input.subagentType) ?? text(input.agent_type);
|
|
105
|
+
return {
|
|
106
|
+
...(description ? { description } : {}),
|
|
107
|
+
...(subagentType ? { subagentType } : {}),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Whether a spawn's tool result launched the agent in the background or
|
|
112
|
+
* ended it. A Codex `spawn_agent` result is always a launch unless it failed
|
|
113
|
+
* ("collab spawn failed: …"); its `{"task_name": …}` output is a launch even
|
|
114
|
+
* when the output's text looked like an error to the parser (an agent path
|
|
115
|
+
* such as `/root/fix_failed_tests`).
|
|
116
|
+
*/
|
|
117
|
+
function spawnResultKind(codex, content, isError) {
|
|
118
|
+
// Read first: the `codex` hint does not survive a snapshot boundary.
|
|
119
|
+
if (parseCodexSpawnLaunch(content))
|
|
120
|
+
return 'launch';
|
|
121
|
+
if (codex)
|
|
122
|
+
return isError ? 'end' : 'launch';
|
|
123
|
+
return !isError && parseAsyncAgentLaunch(content) ? 'launch' : 'end';
|
|
124
|
+
}
|
|
50
125
|
// ── Todo dependency parsing ──
|
|
51
126
|
/**
|
|
52
127
|
* Parses dependency references from a todo item's content text.
|
|
@@ -132,6 +207,8 @@ export class EventAggregator {
|
|
|
132
207
|
// Subagent lifecycle
|
|
133
208
|
subagents = [];
|
|
134
209
|
pendingSubagents = new Map(); // toolUseId -> index
|
|
210
|
+
/** Codex `spawn_agent` calls still waiting for their result (always a background launch). */
|
|
211
|
+
pendingCodexSpawns = new Set();
|
|
135
212
|
// Plan state
|
|
136
213
|
planExtractor;
|
|
137
214
|
planState = null;
|
|
@@ -194,8 +271,32 @@ export class EventAggregator {
|
|
|
194
271
|
this.applyTaskNotification(notification, event.timestamp);
|
|
195
272
|
this.addTaskNotificationTimeline(event.timestamp, notification);
|
|
196
273
|
}
|
|
274
|
+
else {
|
|
275
|
+
// The plain-text "background agents were stopped by the user" notice.
|
|
276
|
+
const notice = agentsStoppedNoticeFromEvent(event);
|
|
277
|
+
if (notice)
|
|
278
|
+
this.applyAgentsStopped(notice, event.timestamp);
|
|
279
|
+
}
|
|
197
280
|
return;
|
|
198
281
|
}
|
|
282
|
+
// So are a background agent's final `task_status` (same opt-in) and the
|
|
283
|
+
// opt-in Codex subagent lifecycle records (`subagentActivityFromEvent`).
|
|
284
|
+
if (isTaskStatusSystemEvent(event)) {
|
|
285
|
+
const status = taskStatusFromEvent(event);
|
|
286
|
+
if (status)
|
|
287
|
+
this.applyTaskStatus(status, event.timestamp);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (isSubagentActivitySystemEvent(event)) {
|
|
291
|
+
const activity = subagentActivityFromEvent(event);
|
|
292
|
+
if (activity)
|
|
293
|
+
this.applySubagentActivity(activity, event.timestamp);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
// The user killed every running background agent. The line itself is
|
|
297
|
+
// counted below as before.
|
|
298
|
+
if (isAgentsKilledSystemEvent(event))
|
|
299
|
+
this.applyAgentsKilled(event.timestamp);
|
|
199
300
|
// 1. Increment counters, capture timestamps
|
|
200
301
|
this.eventCount++;
|
|
201
302
|
if (!this.sessionStartTime) {
|
|
@@ -261,12 +362,13 @@ export class EventAggregator {
|
|
|
261
362
|
// processFollowEvent — adapter for CLI FollowEvent format
|
|
262
363
|
// ═══════════════════════════════════════════════════════════════════════
|
|
263
364
|
processFollowEvent(event) {
|
|
264
|
-
//
|
|
365
|
+
// Subagent bookkeeping (a mid-turn task-notification or task-status
|
|
366
|
+
// attachment, a stop notice or `agents_killed` line, a Codex lifecycle
|
|
367
|
+
// record), like its SessionEvent form above: not counted as activity.
|
|
265
368
|
if (event.type === 'system') {
|
|
266
|
-
const
|
|
267
|
-
if (
|
|
268
|
-
this.
|
|
269
|
-
this.addTaskNotificationTimeline(event.timestamp, notification);
|
|
369
|
+
const record = subagentRecordFromFollowEvent(event);
|
|
370
|
+
if (record) {
|
|
371
|
+
this.applySubagentFollowRecord(record, event.timestamp);
|
|
270
372
|
return;
|
|
271
373
|
}
|
|
272
374
|
}
|
|
@@ -276,6 +378,8 @@ export class EventAggregator {
|
|
|
276
378
|
this.sessionStartTime = event.timestamp;
|
|
277
379
|
}
|
|
278
380
|
this.lastEventTime = event.timestamp;
|
|
381
|
+
// Followed events carry the mode as a plain string.
|
|
382
|
+
this.trackPermissionMode(event);
|
|
279
383
|
// Provider
|
|
280
384
|
if (!this._providerId && event.providerId) {
|
|
281
385
|
this._providerId = event.providerId;
|
|
@@ -407,6 +511,10 @@ export class EventAggregator {
|
|
|
407
511
|
getSubagents() {
|
|
408
512
|
return [...this.subagents];
|
|
409
513
|
}
|
|
514
|
+
/** Timestamp of the last counted event (`getMetrics().lastEventTime`), without building the metrics. */
|
|
515
|
+
getLastEventTime() {
|
|
516
|
+
return this.lastEventTime;
|
|
517
|
+
}
|
|
410
518
|
getPlan() {
|
|
411
519
|
return this.planState
|
|
412
520
|
? { ...this.planState, steps: this.planState.steps.map((step) => ({ ...step })) }
|
|
@@ -503,6 +611,7 @@ export class EventAggregator {
|
|
|
503
611
|
this.activeTaskId = null;
|
|
504
612
|
this.subagents = [];
|
|
505
613
|
this.pendingSubagents.clear();
|
|
614
|
+
this.pendingCodexSpawns.clear();
|
|
506
615
|
this.planExtractor.reset();
|
|
507
616
|
this.planState = null;
|
|
508
617
|
this.planEnteredAt = undefined;
|
|
@@ -636,7 +745,7 @@ export class EventAggregator {
|
|
|
636
745
|
this.tasks = new Map(state.tasks);
|
|
637
746
|
this.activeTaskId = state.activeTaskId;
|
|
638
747
|
this.subagents = [...state.subagents];
|
|
639
|
-
this.currentPermissionMode = state.permissionMode ?? null;
|
|
748
|
+
this.currentPermissionMode = asPermissionMode(state.permissionMode) ?? null;
|
|
640
749
|
this.permissionModeHistory = state.permissionModeHistory
|
|
641
750
|
? [...state.permissionModeHistory]
|
|
642
751
|
: [];
|
|
@@ -663,6 +772,7 @@ export class EventAggregator {
|
|
|
663
772
|
this.pendingToolCalls.clear();
|
|
664
773
|
this.pendingTaskCreates.clear();
|
|
665
774
|
this.pendingSubagents.clear();
|
|
775
|
+
this.pendingCodexSpawns.clear();
|
|
666
776
|
// A spawn still waiting for its tool_result is resolved by that result,
|
|
667
777
|
// which can land after the snapshot boundary. Background agents need no
|
|
668
778
|
// entry: their notifications are matched against every subagent.
|
|
@@ -1149,7 +1259,7 @@ export class EventAggregator {
|
|
|
1149
1259
|
else if (name === 'UpdatePlan') {
|
|
1150
1260
|
this.handleUpdatePlan(input, new Date(event.timestamp));
|
|
1151
1261
|
}
|
|
1152
|
-
else if (isSubagentSpawnTool(name) && toolUseId) {
|
|
1262
|
+
else if (isSubagentSpawnTool(name, input) && toolUseId) {
|
|
1153
1263
|
this.handleAgentSpawn(toolUseId, input, new Date(event.timestamp));
|
|
1154
1264
|
}
|
|
1155
1265
|
}
|
|
@@ -1193,7 +1303,7 @@ export class EventAggregator {
|
|
|
1193
1303
|
else if (event.toolName === 'UpdatePlan') {
|
|
1194
1304
|
this.handleUpdatePlan(input, new Date(event.timestamp));
|
|
1195
1305
|
}
|
|
1196
|
-
else if (isSubagentSpawnTool(event.toolName) && toolUseId) {
|
|
1306
|
+
else if (isSubagentSpawnTool(event.toolName, input) && toolUseId) {
|
|
1197
1307
|
this.handleAgentSpawn(toolUseId, input, new Date(event.timestamp));
|
|
1198
1308
|
}
|
|
1199
1309
|
}
|
|
@@ -1492,8 +1602,9 @@ export class EventAggregator {
|
|
|
1492
1602
|
// ═══════════════════════════════════════════════════════════════════════
|
|
1493
1603
|
handleAgentSpawn(toolUseId, input, now) {
|
|
1494
1604
|
const agentTaskId = `agent-${toolUseId}`;
|
|
1495
|
-
const
|
|
1496
|
-
const
|
|
1605
|
+
const spawn = spawnFields(input);
|
|
1606
|
+
const description = spawn.description ?? 'Subagent';
|
|
1607
|
+
const subagentType = spawn.subagentType;
|
|
1497
1608
|
const task = {
|
|
1498
1609
|
taskId: agentTaskId,
|
|
1499
1610
|
subject: description,
|
|
@@ -1516,8 +1627,9 @@ export class EventAggregator {
|
|
|
1516
1627
|
if (!agentTask)
|
|
1517
1628
|
return;
|
|
1518
1629
|
// A background launch returns at once; its task notification finishes it.
|
|
1519
|
-
if (
|
|
1630
|
+
if (spawnResultKind(this.pendingCodexSpawns.has(toolUseId), content, isError) === 'launch') {
|
|
1520
1631
|
return;
|
|
1632
|
+
}
|
|
1521
1633
|
agentTask.status = isError ? 'deleted' : 'completed';
|
|
1522
1634
|
agentTask.updatedAt = new Date(timestamp);
|
|
1523
1635
|
}
|
|
@@ -1544,12 +1656,12 @@ export class EventAggregator {
|
|
|
1544
1656
|
if (!Array.isArray(content))
|
|
1545
1657
|
return;
|
|
1546
1658
|
for (const block of content) {
|
|
1547
|
-
if (block.type === 'tool_use' && isSubagentSpawnTool(block.name)) {
|
|
1659
|
+
if (block.type === 'tool_use' && isSubagentSpawnTool(block.name, block.input)) {
|
|
1548
1660
|
const input = block.input;
|
|
1549
1661
|
const toolUseId = block.id;
|
|
1550
1662
|
if (!input || !toolUseId)
|
|
1551
1663
|
continue;
|
|
1552
|
-
this.trackSubagentSpawn(toolUseId, input, event.timestamp);
|
|
1664
|
+
this.trackSubagentSpawn(toolUseId, input, event.timestamp, isCodexSubagentSpawnTool(block.name, input));
|
|
1553
1665
|
}
|
|
1554
1666
|
else if (block.type === 'tool_result') {
|
|
1555
1667
|
const toolUseId = block.tool_use_id;
|
|
@@ -1564,10 +1676,10 @@ export class EventAggregator {
|
|
|
1564
1676
|
// ═══════════════════════════════════════════════════════════════════════
|
|
1565
1677
|
extractSubagentFromFollowEvent(event) {
|
|
1566
1678
|
const raw = event.raw;
|
|
1567
|
-
if (event.type === 'tool_use' && isSubagentSpawnTool(event.toolName)) {
|
|
1679
|
+
if (event.type === 'tool_use' && isSubagentSpawnTool(event.toolName, raw?.input)) {
|
|
1568
1680
|
if (!raw?.input)
|
|
1569
1681
|
return;
|
|
1570
|
-
this.trackSubagentSpawn(raw.id || '', raw.input, event.timestamp);
|
|
1682
|
+
this.trackSubagentSpawn(raw.id || '', raw.input, event.timestamp, isCodexSubagentSpawnTool(event.toolName, raw.input));
|
|
1571
1683
|
}
|
|
1572
1684
|
else if (event.type === 'tool_result') {
|
|
1573
1685
|
if (!raw)
|
|
@@ -1584,11 +1696,12 @@ export class EventAggregator {
|
|
|
1584
1696
|
this.applyTaskNotification(notification, event.timestamp);
|
|
1585
1697
|
}
|
|
1586
1698
|
}
|
|
1587
|
-
trackSubagentSpawn(toolUseId, input, timestamp) {
|
|
1699
|
+
trackSubagentSpawn(toolUseId, input, timestamp, codex = false) {
|
|
1700
|
+
const spawn = spawnFields(input);
|
|
1588
1701
|
const info = {
|
|
1589
1702
|
id: toolUseId,
|
|
1590
|
-
description:
|
|
1591
|
-
subagentType:
|
|
1703
|
+
description: spawn.description ?? 'Unknown task',
|
|
1704
|
+
subagentType: spawn.subagentType ?? (codex ? 'default' : 'general'),
|
|
1592
1705
|
spawnTime: timestamp,
|
|
1593
1706
|
status: 'running',
|
|
1594
1707
|
};
|
|
@@ -1596,19 +1709,23 @@ export class EventAggregator {
|
|
|
1596
1709
|
this.subagents.push(info);
|
|
1597
1710
|
if (toolUseId) {
|
|
1598
1711
|
this.pendingSubagents.set(toolUseId, idx);
|
|
1712
|
+
if (codex)
|
|
1713
|
+
this.pendingCodexSpawns.add(toolUseId);
|
|
1599
1714
|
}
|
|
1600
1715
|
}
|
|
1601
1716
|
/**
|
|
1602
1717
|
* The spawning tool call's result. A foreground agent ends here; a
|
|
1603
|
-
* background launch only reports the agent id
|
|
1604
|
-
* until
|
|
1718
|
+
* background launch only reports the agent id (a Codex spawn, its agent
|
|
1719
|
+
* path), and the agent keeps running until a notification or another
|
|
1720
|
+
* record says it ended.
|
|
1605
1721
|
*/
|
|
1606
1722
|
resolveSubagentResult(toolUseId, content, isError, timestamp) {
|
|
1607
1723
|
const idx = this.pendingSubagents.get(toolUseId);
|
|
1608
1724
|
if (idx === undefined)
|
|
1609
1725
|
return;
|
|
1610
|
-
const
|
|
1611
|
-
if (launch) {
|
|
1726
|
+
const codex = this.pendingCodexSpawns.delete(toolUseId);
|
|
1727
|
+
if (spawnResultKind(codex, content, isError) === 'launch') {
|
|
1728
|
+
const launch = parseCodexSpawnLaunch(content) ?? parseAsyncAgentLaunch(content) ?? {};
|
|
1612
1729
|
this.markBackgroundLaunch(idx, launch);
|
|
1613
1730
|
return;
|
|
1614
1731
|
}
|
|
@@ -1620,6 +1737,8 @@ export class EventAggregator {
|
|
|
1620
1737
|
agent.background = true;
|
|
1621
1738
|
if (launch.agentId)
|
|
1622
1739
|
agent.agentId = launch.agentId;
|
|
1740
|
+
if (launch.agentPath && !agent.agentPath)
|
|
1741
|
+
agent.agentPath = launch.agentPath;
|
|
1623
1742
|
}
|
|
1624
1743
|
completeSubagent(toolUseId, timestamp, outcome = 'completed') {
|
|
1625
1744
|
const idx = this.pendingSubagents.get(toolUseId);
|
|
@@ -1627,16 +1746,58 @@ export class EventAggregator {
|
|
|
1627
1746
|
return;
|
|
1628
1747
|
this.finishSubagent(this.subagents[idx], timestamp, outcome);
|
|
1629
1748
|
}
|
|
1630
|
-
finishSubagent(agent, timestamp, outcome) {
|
|
1749
|
+
finishSubagent(agent, timestamp, outcome, settledBy) {
|
|
1631
1750
|
this.pendingSubagents.delete(agent.id);
|
|
1751
|
+
this.pendingCodexSpawns.delete(agent.id);
|
|
1632
1752
|
agent.status = 'completed';
|
|
1633
1753
|
agent.completionTime = timestamp;
|
|
1634
1754
|
agent.outcome = outcome;
|
|
1755
|
+
if (settledBy)
|
|
1756
|
+
agent.settledBy = settledBy;
|
|
1757
|
+
else
|
|
1758
|
+
delete agent.settledBy;
|
|
1635
1759
|
const start = new Date(agent.spawnTime).getTime();
|
|
1636
1760
|
const end = new Date(timestamp).getTime();
|
|
1637
1761
|
if (!isNaN(start) && !isNaN(end) && end >= start) {
|
|
1638
1762
|
agent.durationMs = end - start;
|
|
1639
1763
|
}
|
|
1764
|
+
else {
|
|
1765
|
+
delete agent.durationMs;
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
/** Puts a settled agent back to running (it resumed). */
|
|
1769
|
+
reopenSubagent(agent, timestamp) {
|
|
1770
|
+
this.pendingSubagents.delete(agent.id);
|
|
1771
|
+
agent.status = 'running';
|
|
1772
|
+
delete agent.completionTime;
|
|
1773
|
+
delete agent.durationMs;
|
|
1774
|
+
delete agent.outcome;
|
|
1775
|
+
delete agent.settledBy;
|
|
1776
|
+
this.settleAgentTask(agent.id, null, timestamp);
|
|
1777
|
+
}
|
|
1778
|
+
/**
|
|
1779
|
+
* Settles a lifecycle that is still running (and its task card). Agents
|
|
1780
|
+
* already settled are left alone: a stop notice or status can name agents
|
|
1781
|
+
* that finished earlier.
|
|
1782
|
+
*/
|
|
1783
|
+
settleRunningSubagent(agent, timestamp, outcome, settledBy) {
|
|
1784
|
+
if (agent.status !== 'running')
|
|
1785
|
+
return false;
|
|
1786
|
+
this.finishSubagent(agent, timestamp, outcome, settledBy);
|
|
1787
|
+
this.settleAgentTask(agent.id, outcome, timestamp);
|
|
1788
|
+
return true;
|
|
1789
|
+
}
|
|
1790
|
+
/**
|
|
1791
|
+
* Moves an agent's task card with its lifecycle: `null` back to in
|
|
1792
|
+
* progress, a failure to deleted, any other outcome to completed.
|
|
1793
|
+
*/
|
|
1794
|
+
settleAgentTask(toolUseId, outcome, timestamp) {
|
|
1795
|
+
const agentTask = toolUseId ? this.tasks.get(`agent-${toolUseId}`) : undefined;
|
|
1796
|
+
if (!agentTask?.isSubagent)
|
|
1797
|
+
return;
|
|
1798
|
+
agentTask.status =
|
|
1799
|
+
outcome === null ? 'in_progress' : outcome === 'failed' ? 'deleted' : 'completed';
|
|
1800
|
+
agentTask.updatedAt = new Date(timestamp);
|
|
1640
1801
|
}
|
|
1641
1802
|
/**
|
|
1642
1803
|
* Applies a background task's notification to the subagent it reports on,
|
|
@@ -1659,20 +1820,13 @@ export class EventAggregator {
|
|
|
1659
1820
|
delete agent.completionTime;
|
|
1660
1821
|
delete agent.durationMs;
|
|
1661
1822
|
delete agent.outcome;
|
|
1823
|
+
delete agent.settledBy;
|
|
1662
1824
|
}
|
|
1663
1825
|
else {
|
|
1664
|
-
this.finishSubagent(agent, timestamp, outcome);
|
|
1826
|
+
this.finishSubagent(agent, timestamp, outcome, 'notification');
|
|
1665
1827
|
}
|
|
1666
1828
|
}
|
|
1667
|
-
|
|
1668
|
-
if (agentTask?.isSubagent) {
|
|
1669
|
-
agentTask.status = notification.interim
|
|
1670
|
-
? 'in_progress'
|
|
1671
|
-
: outcome === 'failed'
|
|
1672
|
-
? 'deleted'
|
|
1673
|
-
: 'completed';
|
|
1674
|
-
agentTask.updatedAt = new Date(timestamp);
|
|
1675
|
-
}
|
|
1829
|
+
this.settleAgentTask(toolUseId, notification.interim ? null : outcome, timestamp);
|
|
1676
1830
|
}
|
|
1677
1831
|
findNotifiedSubagent(notification) {
|
|
1678
1832
|
const { toolUseId, taskId } = notification;
|
|
@@ -1686,6 +1840,206 @@ export class EventAggregator {
|
|
|
1686
1840
|
}
|
|
1687
1841
|
return undefined;
|
|
1688
1842
|
}
|
|
1843
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1844
|
+
// Subagent settling: evidence, stop markers, task statuses, Codex records
|
|
1845
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1846
|
+
/**
|
|
1847
|
+
* Applies host evidence about a subagent (Claude Code's meta flags):
|
|
1848
|
+
* `stoppedByUser` settles a running agent as `stopped`, `finished` as
|
|
1849
|
+
* `completed` (`settledBy: 'meta'`). Agents already settled some other way
|
|
1850
|
+
* keep their outcome; `finished: false` reopens an agent that only meta
|
|
1851
|
+
* settled. Matches by `toolUseId`, then `agentId` (the newest such agent),
|
|
1852
|
+
* and records the agent id when matched by tool_use id.
|
|
1853
|
+
*
|
|
1854
|
+
* @param timestamp ISO time to record as the completion (the agent's last
|
|
1855
|
+
* activity, when the host knows it)
|
|
1856
|
+
* @returns Whether a lifecycle changed
|
|
1857
|
+
*/
|
|
1858
|
+
applySubagentEvidence(evidence, timestamp) {
|
|
1859
|
+
const agent = this.findSubagent(evidence.toolUseId, evidence.agentId);
|
|
1860
|
+
if (!agent)
|
|
1861
|
+
return false;
|
|
1862
|
+
let changed = false;
|
|
1863
|
+
if (evidence.agentId && !agent.agentId) {
|
|
1864
|
+
agent.agentId = evidence.agentId;
|
|
1865
|
+
changed = true;
|
|
1866
|
+
}
|
|
1867
|
+
if (agent.status === 'running') {
|
|
1868
|
+
const outcome = evidence.stoppedByUser
|
|
1869
|
+
? 'stopped'
|
|
1870
|
+
: evidence.finished
|
|
1871
|
+
? 'completed'
|
|
1872
|
+
: null;
|
|
1873
|
+
if (outcome)
|
|
1874
|
+
changed = this.settleRunningSubagent(agent, timestamp, outcome, 'meta') || changed;
|
|
1875
|
+
}
|
|
1876
|
+
else if (agent.settledBy === 'meta' &&
|
|
1877
|
+
evidence.finished === false &&
|
|
1878
|
+
evidence.stoppedByUser !== true) {
|
|
1879
|
+
this.reopenSubagent(agent, timestamp);
|
|
1880
|
+
changed = true;
|
|
1881
|
+
}
|
|
1882
|
+
return changed;
|
|
1883
|
+
}
|
|
1884
|
+
/** The newest lifecycle with this spawning tool_use id, else with this agent id. */
|
|
1885
|
+
findSubagent(toolUseId, agentId) {
|
|
1886
|
+
if (toolUseId) {
|
|
1887
|
+
for (let i = this.subagents.length - 1; i >= 0; i--) {
|
|
1888
|
+
if (this.subagents[i].id === toolUseId)
|
|
1889
|
+
return this.subagents[i];
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
if (agentId) {
|
|
1893
|
+
for (let i = this.subagents.length - 1; i >= 0; i--) {
|
|
1894
|
+
if (this.subagents[i].agentId === agentId)
|
|
1895
|
+
return this.subagents[i];
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
return undefined;
|
|
1899
|
+
}
|
|
1900
|
+
/** `agents_killed`: the user killed every running background agent. */
|
|
1901
|
+
applyAgentsKilled(timestamp) {
|
|
1902
|
+
let settled = 0;
|
|
1903
|
+
for (const agent of this.subagents) {
|
|
1904
|
+
if (!agent.background)
|
|
1905
|
+
continue;
|
|
1906
|
+
if (this.settleRunningSubagent(agent, timestamp, 'stopped', 'stop-marker'))
|
|
1907
|
+
settled++;
|
|
1908
|
+
}
|
|
1909
|
+
if (settled > 0)
|
|
1910
|
+
this.addSubagentTimeline(timestamp, describeAgentsStopped(null));
|
|
1911
|
+
}
|
|
1912
|
+
/**
|
|
1913
|
+
* "N background agents were stopped by the user: "A", "B"": settles the
|
|
1914
|
+
* running agents with those descriptions, the newest first for repeats.
|
|
1915
|
+
*/
|
|
1916
|
+
applyAgentsStopped(notice, timestamp) {
|
|
1917
|
+
const taken = new Set();
|
|
1918
|
+
for (const description of notice.descriptions) {
|
|
1919
|
+
for (let i = this.subagents.length - 1; i >= 0; i--) {
|
|
1920
|
+
const agent = this.subagents[i];
|
|
1921
|
+
if (taken.has(agent) || agent.status !== 'running')
|
|
1922
|
+
continue;
|
|
1923
|
+
if (agent.description.trim() !== description)
|
|
1924
|
+
continue;
|
|
1925
|
+
taken.add(agent);
|
|
1926
|
+
this.settleRunningSubagent(agent, timestamp, 'stopped', 'stop-marker');
|
|
1927
|
+
break;
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
this.addSubagentTimeline(timestamp, describeAgentsStopped(notice));
|
|
1931
|
+
}
|
|
1932
|
+
/** A background agent's final `task_status` attachment, matched by agent id. */
|
|
1933
|
+
applyTaskStatus(status, timestamp) {
|
|
1934
|
+
if (!isFinalTaskStatus(status.status))
|
|
1935
|
+
return;
|
|
1936
|
+
const agent = this.findSubagent(undefined, status.taskId);
|
|
1937
|
+
if (!agent)
|
|
1938
|
+
return;
|
|
1939
|
+
if (this.settleRunningSubagent(agent, timestamp, taskNotificationOutcome(status.status), 'task-status')) {
|
|
1940
|
+
this.addSubagentTimeline(timestamp, describeTaskStatus(status), agent.id);
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
/**
|
|
1944
|
+
* A Codex subagent lifecycle record: `started` links the spawn to its child
|
|
1945
|
+
* thread; `completed` (a child turn finished) and `final-answer` (the
|
|
1946
|
+
* child's report, matched by its agent path) complete it; `interacted`
|
|
1947
|
+
* after `followup_task` puts it back to running (a `send_message` does
|
|
1948
|
+
* not: it does not start a turn); `interrupted` (`interrupt_agent`) settles
|
|
1949
|
+
* it as `stopped`, since the child keeps its thread and a follow-up can
|
|
1950
|
+
* run it again, like a user stop rather than a kill.
|
|
1951
|
+
*/
|
|
1952
|
+
applySubagentActivity(activity, timestamp) {
|
|
1953
|
+
const byThread = () => this.findSubagent(undefined, activity.agentThreadId) ??
|
|
1954
|
+
this.findSubagentByPath(activity.agentPath);
|
|
1955
|
+
let agent;
|
|
1956
|
+
switch (activity.kind) {
|
|
1957
|
+
case 'started': {
|
|
1958
|
+
agent = this.findSubagent(activity.callId, undefined);
|
|
1959
|
+
if (!agent)
|
|
1960
|
+
break;
|
|
1961
|
+
agent.background = true;
|
|
1962
|
+
if (activity.agentThreadId)
|
|
1963
|
+
agent.agentId = activity.agentThreadId;
|
|
1964
|
+
if (activity.agentPath)
|
|
1965
|
+
agent.agentPath = activity.agentPath;
|
|
1966
|
+
break;
|
|
1967
|
+
}
|
|
1968
|
+
case 'completed':
|
|
1969
|
+
agent = byThread();
|
|
1970
|
+
if (agent)
|
|
1971
|
+
this.settleRunningSubagent(agent, timestamp, 'completed', 'notification');
|
|
1972
|
+
break;
|
|
1973
|
+
case 'final-answer':
|
|
1974
|
+
agent = this.findSubagentByPath(activity.agentPath, true);
|
|
1975
|
+
if (agent)
|
|
1976
|
+
this.settleRunningSubagent(agent, timestamp, 'completed', 'notification');
|
|
1977
|
+
break;
|
|
1978
|
+
case 'interacted':
|
|
1979
|
+
agent = byThread();
|
|
1980
|
+
if (agent && activity.tool === 'followup_task' && agent.status === 'completed') {
|
|
1981
|
+
this.reopenSubagent(agent, timestamp);
|
|
1982
|
+
}
|
|
1983
|
+
break;
|
|
1984
|
+
case 'interrupted':
|
|
1985
|
+
agent = byThread();
|
|
1986
|
+
if (agent)
|
|
1987
|
+
this.settleRunningSubagent(agent, timestamp, 'stopped', 'stop-marker');
|
|
1988
|
+
break;
|
|
1989
|
+
}
|
|
1990
|
+
this.addSubagentTimeline(timestamp, describeSubagentActivity(activity), agent?.id);
|
|
1991
|
+
}
|
|
1992
|
+
/** The newest lifecycle with this Codex agent path (with `runningFirst`, a running one first). */
|
|
1993
|
+
findSubagentByPath(agentPath, runningFirst = false) {
|
|
1994
|
+
if (!agentPath)
|
|
1995
|
+
return undefined;
|
|
1996
|
+
let fallback;
|
|
1997
|
+
for (let i = this.subagents.length - 1; i >= 0; i--) {
|
|
1998
|
+
const agent = this.subagents[i];
|
|
1999
|
+
if (agent.agentPath !== agentPath)
|
|
2000
|
+
continue;
|
|
2001
|
+
if (!runningFirst || agent.status === 'running')
|
|
2002
|
+
return agent;
|
|
2003
|
+
fallback ??= agent;
|
|
2004
|
+
}
|
|
2005
|
+
return fallback;
|
|
2006
|
+
}
|
|
2007
|
+
applySubagentFollowRecord(record, timestamp) {
|
|
2008
|
+
switch (record.kind) {
|
|
2009
|
+
case 'notification':
|
|
2010
|
+
this.applyTaskNotification(record.notification, timestamp);
|
|
2011
|
+
this.addTaskNotificationTimeline(timestamp, record.notification);
|
|
2012
|
+
break;
|
|
2013
|
+
case 'stopped':
|
|
2014
|
+
this.applyAgentsStopped(record.notice, timestamp);
|
|
2015
|
+
break;
|
|
2016
|
+
case 'task-status':
|
|
2017
|
+
this.applyTaskStatus(record.status, timestamp);
|
|
2018
|
+
break;
|
|
2019
|
+
case 'activity':
|
|
2020
|
+
this.applySubagentActivity(record.activity, timestamp);
|
|
2021
|
+
break;
|
|
2022
|
+
case 'agents-killed':
|
|
2023
|
+
this.applyAgentsKilled(timestamp);
|
|
2024
|
+
break;
|
|
2025
|
+
case 'unreadable':
|
|
2026
|
+
break;
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
addSubagentTimeline(timestamp, description, toolUseId) {
|
|
2030
|
+
const text = description.length > 200 ? description.substring(0, 197) + '...' : description;
|
|
2031
|
+
this.timeline.push({
|
|
2032
|
+
type: 'tool_result',
|
|
2033
|
+
timestamp,
|
|
2034
|
+
description: text,
|
|
2035
|
+
noiseLevel: 'system',
|
|
2036
|
+
messageClassification: 'system',
|
|
2037
|
+
...(toolUseId ? { metadata: { toolUseId } } : {}),
|
|
2038
|
+
});
|
|
2039
|
+
if (this.timeline.length > this.timelineCap) {
|
|
2040
|
+
this.timeline.shift();
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
1689
2043
|
addTaskNotificationTimeline(timestamp, notification) {
|
|
1690
2044
|
let description = notification.summary ?? `Background task ${notification.status ?? 'finished'}`;
|
|
1691
2045
|
if (description.length > 200)
|
|
@@ -1936,9 +2290,9 @@ export class EventAggregator {
|
|
|
1936
2290
|
// Private: Permission Mode
|
|
1937
2291
|
// ═══════════════════════════════════════════════════════════════════════
|
|
1938
2292
|
trackPermissionMode(event) {
|
|
1939
|
-
|
|
2293
|
+
const mode = asPermissionMode(event.permissionMode);
|
|
2294
|
+
if (!mode)
|
|
1940
2295
|
return;
|
|
1941
|
-
const mode = event.permissionMode;
|
|
1942
2296
|
if (mode !== this.currentPermissionMode) {
|
|
1943
2297
|
this.permissionModeHistory.push({
|
|
1944
2298
|
timestamp: event.timestamp,
|
package/dist/esm/browser.js
CHANGED
|
@@ -17,7 +17,8 @@ export { addLocalDays, formatDurationMs, formatLocalDateKey, formatTokenCount, p
|
|
|
17
17
|
export { parseMcpToolName } from './parsers/mcpToolName';
|
|
18
18
|
export { buildSessionContextSnapshot, calculateSessionContextPressure, createSessionContextProjector, } from './context/sessionContext';
|
|
19
19
|
export { ACCOUNT_PROVIDER_IDS, MODEL_PROVIDER_IDS, QUOTA_PROVIDER_IDS, RUNTIME_QUOTA_PROVIDER_IDS, SESSION_PROVIDER_IDS, } from './providerIds';
|
|
20
|
-
export { SUBAGENT_SPAWN_TOOL_NAMES, isSubagentSpawnTool, isTaskNotificationSystemEvent, parseTaskNotification, taskNotificationFromEvent, } from './subagentSpawn';
|
|
20
|
+
export { SUBAGENT_SPAWN_TOOL_NAMES, agentsStoppedNoticeFromEvent, isAgentsKilledSystemEvent, isCodexSubagentSpawnTool, isSubagentSpawnTool, isTaskNotificationSystemEvent, isTaskStatusSystemEvent, parseAgentsStoppedNotice, parseCodexSpawnLaunch, parseTaskNotification, taskNotificationFromEvent, taskStatusFromAttachment, taskStatusFromEvent, } from './subagentSpawn';
|
|
21
|
+
export { SUBAGENT_PARENT_IDLE_ENDED_MS, SUBAGENT_UNREPORTED_QUIET_MS, resolveSubagentDisplayState, subagentDisplayLabel, } from './subagentDisplayState';
|
|
21
22
|
export { assistantTurnEventsFromSessionEvents, extractTurnSubagents, isAssistantTurnSubagentTool, reasoningSummary, segmentAssistantTurn, } from './turns/assistantTurn';
|
|
22
23
|
export { parseModelId, getModelPricing, resolveModelPricing, getModelInfo, calculateCost, calculateCostWithPricing, calculateCostWithProvenance, mergeCostSources, shortModelName, getModelDisplayInfo, compareModelIds, sortModelIds, formatCost, canonicalModelId, isMovingModelAlias, registerModelPricing, clearRegisteredModelPricing, getPricingCatalogInfo, costSourceFromPricingProvenance, mergeCostComponents, } from './modelInfo';
|
|
23
24
|
export { exportResolvedModelCatalog, importResolvedModelCatalog, registerModelAlias, resolveModelAlias, RESOLVED_MODEL_CATALOG_SCHEMA_VERSION, } from './modelCatalog';
|
|
@@ -31,6 +32,7 @@ export { isAggregateCodexLimit } from './types/codex';
|
|
|
31
32
|
// Codex rollout parsing (pure: no filesystem access)
|
|
32
33
|
export { CodexRolloutParser, DEFAULT_MAX_TRACKED_TOOL_CALLS, extractPatchFilePaths, normalizeCodexToolName, normalizeCodexToolInput, resolveCodexCallUsage, } from './parsers/codexParser';
|
|
33
34
|
export { codexRolloutOrigin, codexSpawnParentFromSource } from './parsers/codexRolloutOrigin';
|
|
35
|
+
export { SUBAGENT_ACTIVITY_BLOCK_TYPE, SUBAGENT_ACTIVITY_ORIGIN_KIND, describeSubagentActivity, isSubagentActivitySystemEvent, parseCodexAgentMessageText, subagentActivityFromEvent, } from './subagentActivity';
|
|
34
36
|
export { HUMAN_CLAUDE_ENTRYPOINTS, HUMAN_CODEX_SOURCES, humanPromptText, isHumanPrompt, } from './humanPrompt';
|
|
35
37
|
export { renderHandoffUrlTemplate } from './handoffUrl';
|
|
36
38
|
// Tool categories across providers
|
|
@@ -8,7 +8,8 @@ import { EventAggregator } from '../aggregation/EventAggregator';
|
|
|
8
8
|
import { getModelContextWindowSize } from '../modelContext';
|
|
9
9
|
import { parseMcpToolName } from '../parsers/mcpToolName';
|
|
10
10
|
import { estimateTextTokens } from '../tokenEstimation';
|
|
11
|
-
import { isTaskNotificationSystemEvent } from '../subagentSpawn';
|
|
11
|
+
import { isTaskNotificationSystemEvent, isTaskStatusSystemEvent } from '../subagentSpawn';
|
|
12
|
+
import { isSubagentActivitySystemEvent } from '../subagentActivity';
|
|
12
13
|
const DEFAULT_CONTEXT_SOURCE_LIMIT = 200;
|
|
13
14
|
const DEFAULT_SNIPPET_MAX_CHARS = 240;
|
|
14
15
|
const DEFAULT_BODY_MAX_CHARS = 5000;
|
|
@@ -207,7 +208,10 @@ function extractSourcesFromEvent(event, state) {
|
|
|
207
208
|
}
|
|
208
209
|
function extractSystemSource(event, state) {
|
|
209
210
|
// Background-task notices only update subagent lifecycles (like the aggregator).
|
|
210
|
-
if (isTaskNotificationSystemEvent(event))
|
|
211
|
+
if (isTaskNotificationSystemEvent(event) || isTaskStatusSystemEvent(event))
|
|
212
|
+
return;
|
|
213
|
+
// So are subagent lifecycle records (opt-in Codex parser events).
|
|
214
|
+
if (isSubagentActivitySystemEvent(event))
|
|
211
215
|
return;
|
|
212
216
|
const message = event.message;
|
|
213
217
|
const text = extractText(message?.content);
|