@gajae-code/coding-agent 0.11.11 → 0.12.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 +49 -3
- package/dist/types/cli/read-cli.d.ts +1 -0
- package/dist/types/commands/deep-interview.d.ts +9 -0
- package/dist/types/commands/harness.d.ts +22 -0
- package/dist/types/commands/read.d.ts +6 -0
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/provider-auth-health.d.ts +14 -0
- package/dist/types/config/provider-ranking.d.ts +59 -0
- package/dist/types/config/settings-schema.d.ts +29 -1
- package/dist/types/config/settings.d.ts +2 -0
- package/dist/types/extensibility/extensions/types.d.ts +22 -2
- package/dist/types/extensibility/shared-events.d.ts +6 -0
- package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +5 -12
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +17 -32
- package/dist/types/gjc-runtime/deep-interview-stage.d.ts +37 -0
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +4 -135
- package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
- package/dist/types/gjc-runtime/memory-guard-owner-claims.d.ts +47 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +52 -1
- package/dist/types/gjc-runtime/state-writer.d.ts +5 -46
- package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
- package/dist/types/gjc-runtime/team-runtime.d.ts +2 -1
- package/dist/types/gjc-runtime/team-store.d.ts +12 -0
- package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +92 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +7 -0
- package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +8 -0
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -5
- package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
- package/dist/types/main.d.ts +1 -1
- package/dist/types/memories/index.d.ts +2 -0
- package/dist/types/modes/acp/acp-agent.d.ts +8 -0
- package/dist/types/modes/components/assistant-message.d.ts +3 -1
- package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
- package/dist/types/modes/components/read-tool-group.d.ts +4 -4
- package/dist/types/modes/components/session-observer-overlay.d.ts +4 -0
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +8 -0
- package/dist/types/modes/controllers/event-controller.d.ts +3 -0
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
- package/dist/types/modes/types.d.ts +2 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
- package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +5 -0
- package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
- package/dist/types/sdk/bus/index.d.ts +15 -1
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +37 -0
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +2 -1
- package/dist/types/sdk/bus/reconciliation-store.d.ts +65 -0
- package/dist/types/sdk/host/control/operations.d.ts +1 -1
- package/dist/types/sdk/host/host.d.ts +2 -0
- package/dist/types/sdk/host/query/handlers.d.ts +5 -0
- package/dist/types/session/agent-session.d.ts +44 -10
- package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
- package/dist/types/session/session-manager.d.ts +25 -13
- package/dist/types/session/streaming-output.d.ts +60 -5
- package/dist/types/skill-state/active-state.d.ts +0 -4
- package/dist/types/skill-state/workflow-hud.d.ts +3 -0
- package/dist/types/tools/browser/launch.d.ts +7 -0
- package/dist/types/tools/fetch.d.ts +17 -1
- package/dist/types/tools/output-meta.d.ts +21 -1
- package/dist/types/tools/read-internals.d.ts +12 -0
- package/dist/types/tools/read.d.ts +45 -1
- package/dist/types/tools/resource-gc.d.ts +4 -0
- package/dist/types/tools/tool-result.d.ts +7 -1
- package/package.json +9 -13
- package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
- package/scripts/capture-sticky-viewport-showcase.ts +292 -0
- package/scripts/generate-sdk-operation-inventory.ts +2 -0
- package/scripts/verify-gjc-sdk-canonicalization.ts +122 -18
- package/scripts/verify-sticky-viewport-showcase.ts +611 -0
- package/src/capability/index.ts +8 -0
- package/src/cli/read-cli.ts +2 -1
- package/src/cli.ts +1 -0
- package/src/commands/deep-interview.ts +29 -9
- package/src/commands/harness.ts +35 -12
- package/src/commands/read.ts +11 -2
- package/src/commands/team.ts +1 -1
- package/src/config/model-registry.ts +21 -2
- package/src/config/provider-auth-health.ts +42 -0
- package/src/config/provider-ranking.ts +119 -0
- package/src/config/settings-schema.ts +23 -1
- package/src/config/settings.ts +246 -108
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +229 -82
- package/src/defaults/gjc/skills/ralplan/SKILL.md +58 -25
- package/src/defaults/gjc/skills/team/SKILL.md +1 -1
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +25 -15
- package/src/eval/py/executor.ts +7 -2
- package/src/extensibility/extensions/types.ts +28 -4
- package/src/extensibility/shared-events.ts +5 -0
- package/src/gjc-runtime/deep-interview-ambiguity.ts +47 -82
- package/src/gjc-runtime/deep-interview-recorder.ts +227 -310
- package/src/gjc-runtime/deep-interview-runtime.ts +109 -270
- package/src/gjc-runtime/deep-interview-stage.ts +1016 -0
- package/src/gjc-runtime/deep-interview-state.ts +12 -943
- package/src/gjc-runtime/gc-render.ts +1 -0
- package/src/gjc-runtime/gc-runtime.ts +11 -1
- package/src/gjc-runtime/memory-guard-owner-claims.ts +389 -0
- package/src/gjc-runtime/ralplan-runtime.ts +742 -85
- package/src/gjc-runtime/state-runtime.ts +2 -1
- package/src/gjc-runtime/state-writer.ts +70 -222
- package/src/gjc-runtime/team-launch.ts +34 -5
- package/src/gjc-runtime/team-runtime.ts +970 -33
- package/src/gjc-runtime/team-store.ts +32 -0
- package/src/gjc-runtime/team-worker-memory-guard.ts +363 -0
- package/src/gjc-runtime/team-workers.ts +1 -0
- package/src/gjc-runtime/tmux-owner-isolation.ts +18 -0
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +20 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +13 -7
- package/src/gjc-runtime/workflow-manifest.generated.json +97 -350
- package/src/gjc-runtime/workflow-manifest.ts +34 -179
- package/src/hooks/native-skill-hook.ts +17 -4
- package/src/hooks/skill-state.ts +1 -23
- package/src/internal-urls/docs-index.generated.ts +8 -9
- package/src/internal-urls/local-root-gc.ts +127 -0
- package/src/main.ts +9 -5
- package/src/memories/index.ts +10 -0
- package/src/modes/DESIGN.md +47 -0
- package/src/modes/acp/acp-agent.ts +43 -7
- package/src/modes/acp/acp-event-mapper.ts +14 -7
- package/src/modes/acp/acp-mode.ts +39 -3
- package/src/modes/components/assistant-message.ts +123 -22
- package/src/modes/components/irc-sidebar.ts +176 -62
- package/src/modes/components/model-selector.ts +61 -4
- package/src/modes/components/oauth-selector.ts +42 -12
- package/src/modes/components/read-tool-group.ts +82 -14
- package/src/modes/components/session-observer-overlay.ts +187 -32
- package/src/modes/components/settings-selector.ts +60 -18
- package/src/modes/components/tool-execution.ts +138 -27
- package/src/modes/controllers/event-controller.ts +109 -27
- package/src/modes/controllers/extension-ui-controller.ts +19 -2
- package/src/modes/controllers/input-controller.ts +18 -3
- package/src/modes/controllers/selector-controller.ts +83 -37
- package/src/modes/interactive-mode.ts +62 -3
- package/src/modes/irc-observation-ledger.ts +71 -15
- package/src/modes/runtime-init.ts +19 -2
- package/src/modes/types.ts +2 -0
- package/src/modes/utils/ui-helpers.ts +94 -1
- package/src/prompts/agents/architect.md +9 -1
- package/src/prompts/agents/critic.md +9 -0
- package/src/prompts/system/system-prompt.md +0 -1
- package/src/prompts/tools/read.md +4 -2
- package/src/runtime-mcp/smithery-auth.ts +17 -2
- package/src/runtime-mcp/smithery-connect.ts +11 -1
- package/src/sdk/broker/lifecycle.ts +25 -6
- package/src/sdk/bus/control-drain-lease.ts +104 -0
- package/src/sdk/bus/index.ts +341 -38
- package/src/sdk/bus/kind-aware-reconciliation.ts +242 -0
- package/src/sdk/bus/prompt-reconciliation.ts +2 -1
- package/src/sdk/bus/reconciliation-store.ts +224 -0
- package/src/sdk/host/control/dispatch.ts +5 -1
- package/src/sdk/host/control/operations.ts +1 -1
- package/src/sdk/host/host.ts +23 -1
- package/src/sdk/host/query/handlers.ts +55 -0
- package/src/sdk/mcp/server.ts +46 -18
- package/src/sdk/protocol/operation-inventory.generated.json +29 -0
- package/src/sdk/protocol/operation-registry.ts +7 -2
- package/src/sdk/session.ts +13 -1
- package/src/session/agent-session.ts +466 -50
- package/src/session/memory-guard-checkpoint-participant.ts +131 -0
- package/src/session/session-manager.ts +764 -17
- package/src/session/streaming-output.ts +262 -43
- package/src/setup/provider-onboarding.ts +19 -4
- package/src/skill-state/active-state.ts +0 -10
- package/src/skill-state/workflow-hud.ts +25 -2
- package/src/skill-state/workflow-mutation-guard.ts +65 -7
- package/src/tools/ask.ts +89 -69
- package/src/tools/browser/launch.ts +41 -6
- package/src/tools/fetch.ts +114 -23
- package/src/tools/output-meta.ts +176 -9
- package/src/tools/path-utils.ts +5 -1
- package/src/tools/read-internals.ts +44 -0
- package/src/tools/read.ts +1542 -310
- package/src/tools/resource-gc.ts +182 -18
- package/src/tools/tool-result.ts +14 -1
- package/src/web/search/providers/codex.ts +1 -1
- package/dist/types/gjc-runtime/deep-interview-draft.d.ts +0 -8
- package/dist/types/gjc-runtime/deep-interview-payload.d.ts +0 -41
- package/dist/types/gjc-runtime/deep-interview-repair.d.ts +0 -17
- package/src/gjc-runtime/deep-interview-draft.ts +0 -843
- package/src/gjc-runtime/deep-interview-payload.ts +0 -262
- package/src/gjc-runtime/deep-interview-repair.ts +0 -1674
|
@@ -129,6 +129,21 @@ function stabilizeStreamingPreviews(previews: PerFileDiffPreview[]): PerFileDiff
|
|
|
129
129
|
return changed ? next : previews;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
function previewsAreEqual(a: PerFileDiffPreview[] | undefined, b: PerFileDiffPreview[]): boolean {
|
|
133
|
+
return (
|
|
134
|
+
a?.length === b.length &&
|
|
135
|
+
a.every((preview, index) => {
|
|
136
|
+
const next = b[index];
|
|
137
|
+
return (
|
|
138
|
+
preview.path === next?.path &&
|
|
139
|
+
preview.diff === next.diff &&
|
|
140
|
+
preview.error === next.error &&
|
|
141
|
+
preview.firstChangedLine === next.firstChangedLine
|
|
142
|
+
);
|
|
143
|
+
})
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
132
147
|
function isEditLikeToolName(toolName: string): boolean {
|
|
133
148
|
return toolName === "edit" || toolName === "apply_patch";
|
|
134
149
|
}
|
|
@@ -144,6 +159,8 @@ export interface ToolExecutionOptions {
|
|
|
144
159
|
editFuzzyThreshold?: number;
|
|
145
160
|
editAllowFuzzy?: boolean;
|
|
146
161
|
hashlineAutoDropPureInsertDuplicates?: boolean;
|
|
162
|
+
/** Internal observer for visible asynchronous renderer mutations. */
|
|
163
|
+
onVisibleTranscriptMutation?: () => void;
|
|
147
164
|
}
|
|
148
165
|
|
|
149
166
|
export interface ToolExecutionHandle {
|
|
@@ -168,6 +185,11 @@ export interface ToolExecutionHandle {
|
|
|
168
185
|
* back to {@link setExpanded}.
|
|
169
186
|
*/
|
|
170
187
|
setManuallyExpanded?(expanded: boolean): void;
|
|
188
|
+
/**
|
|
189
|
+
* Internal capability for dispatchers that need exact synchronous visible-output
|
|
190
|
+
* detection. Optional so existing structural handles remain source compatible.
|
|
191
|
+
*/
|
|
192
|
+
consumeVisibleTranscriptChange?(): boolean;
|
|
171
193
|
}
|
|
172
194
|
|
|
173
195
|
/**
|
|
@@ -213,8 +235,11 @@ export class ToolExecutionComponent extends Container {
|
|
|
213
235
|
#argsIdentityVersion = 0;
|
|
214
236
|
#lastArgsReference: any;
|
|
215
237
|
#shareArgsWithRenderer = false;
|
|
216
|
-
// Cached converted images for Kitty protocol (which requires PNG), keyed by index
|
|
217
|
-
#convertedImages: Map<number, { data: string; mimeType: string }> = new Map();
|
|
238
|
+
// Cached converted images for Kitty protocol (which requires PNG), keyed by index and source.
|
|
239
|
+
#convertedImages: Map<number, { data: string; mimeType: string; source: string }> = new Map();
|
|
240
|
+
#imageConversionGenerations = new Map<number, number>();
|
|
241
|
+
#imageConversionsInFlight = new Map<number, string>();
|
|
242
|
+
|
|
218
243
|
// Spinner animation for partial task results
|
|
219
244
|
#spinnerFrame?: number;
|
|
220
245
|
#spinnerAnimation?: AnimationRegistration;
|
|
@@ -229,6 +254,10 @@ export class ToolExecutionComponent extends Container {
|
|
|
229
254
|
expanded: false,
|
|
230
255
|
isPartial: true,
|
|
231
256
|
};
|
|
257
|
+
#onVisibleTranscriptMutation?: () => void;
|
|
258
|
+
#visibleTranscriptChanged = false;
|
|
259
|
+
#visibleProjection = "";
|
|
260
|
+
#disposed = false;
|
|
232
261
|
|
|
233
262
|
constructor(
|
|
234
263
|
toolName: string,
|
|
@@ -246,6 +275,8 @@ export class ToolExecutionComponent extends Container {
|
|
|
246
275
|
this.#editFuzzyThreshold = options.editFuzzyThreshold;
|
|
247
276
|
this.#editAllowFuzzy = options.editAllowFuzzy;
|
|
248
277
|
this.#hashlineAutoDropPureInsertDuplicates = options.hashlineAutoDropPureInsertDuplicates;
|
|
278
|
+
this.#onVisibleTranscriptMutation = options.onVisibleTranscriptMutation;
|
|
279
|
+
|
|
249
280
|
this.#tool = tool;
|
|
250
281
|
this.#ui = ui;
|
|
251
282
|
this.#cwd = cwd;
|
|
@@ -273,18 +304,23 @@ export class ToolExecutionComponent extends Container {
|
|
|
273
304
|
this.#editMode = resolveEditModeForTool(toolName, tool);
|
|
274
305
|
|
|
275
306
|
this.#updateDisplay();
|
|
307
|
+
this.#visibleProjection = this.#captureLogicalVisibleProjection();
|
|
308
|
+
|
|
276
309
|
void this.#runPreviewDiff();
|
|
277
310
|
}
|
|
278
311
|
|
|
279
312
|
updateArgs(args: any, _toolCallId?: string): void {
|
|
313
|
+
const argsChanged = !Bun.deepEquals(this.#args, args);
|
|
314
|
+
if (!argsChanged && !this.#editMode) return;
|
|
280
315
|
if (args !== this.#lastArgsReference) {
|
|
281
316
|
this.#lastArgsReference = args;
|
|
282
317
|
this.#argsIdentityVersion += 1;
|
|
283
318
|
}
|
|
284
|
-
this.#args = this.#shareArgsWithRenderer ? args : cloneToolArgs(args);
|
|
319
|
+
this.#args = argsChanged ? (this.#shareArgsWithRenderer ? args : cloneToolArgs(args)) : this.#args;
|
|
285
320
|
this.#updateSpinnerAnimation();
|
|
286
321
|
void this.#runPreviewDiff();
|
|
287
322
|
this.#updateDisplay();
|
|
323
|
+
this.#markVisibleMutationIfChanged();
|
|
288
324
|
}
|
|
289
325
|
|
|
290
326
|
/**
|
|
@@ -295,6 +331,8 @@ export class ToolExecutionComponent extends Container {
|
|
|
295
331
|
this.#argsComplete = true;
|
|
296
332
|
this.#updateSpinnerAnimation();
|
|
297
333
|
void this.#runPreviewDiff();
|
|
334
|
+
this.#updateDisplay();
|
|
335
|
+
this.#markVisibleMutationIfChanged();
|
|
298
336
|
}
|
|
299
337
|
|
|
300
338
|
async #runPreviewDiff(): Promise<void> {
|
|
@@ -338,14 +376,17 @@ export class ToolExecutionComponent extends Container {
|
|
|
338
376
|
hashlineAutoDropPureInsertDuplicates: this.#hashlineAutoDropPureInsertDuplicates,
|
|
339
377
|
isStreaming,
|
|
340
378
|
});
|
|
341
|
-
if (controller.signal.aborted) return;
|
|
379
|
+
if (this.#disposed || controller.signal.aborted) return;
|
|
342
380
|
if (previews) {
|
|
343
|
-
|
|
381
|
+
const nextPreview = isStreaming ? stabilizeStreamingPreviews(previews) : previews;
|
|
382
|
+
const changed = !previewsAreEqual(this.#editDiffPreview, nextPreview);
|
|
383
|
+
this.#editDiffPreview = nextPreview;
|
|
344
384
|
this.#updateDisplay();
|
|
345
385
|
this.#ui.requestRender();
|
|
386
|
+
if (changed) this.#markVisibleMutationIfChanged(true);
|
|
346
387
|
}
|
|
347
388
|
} catch (err) {
|
|
348
|
-
if (controller.signal.aborted) return;
|
|
389
|
+
if (this.#disposed || controller.signal.aborted) return;
|
|
349
390
|
logger.warn("Edit preview diff failed", { tool: this.#toolName, error: String(err) });
|
|
350
391
|
}
|
|
351
392
|
}
|
|
@@ -359,8 +400,10 @@ export class ToolExecutionComponent extends Container {
|
|
|
359
400
|
isPartial = false,
|
|
360
401
|
_toolCallId?: string,
|
|
361
402
|
): void {
|
|
403
|
+
if (this.#isPartial === isPartial && Bun.deepEquals(this.#result, result)) return;
|
|
362
404
|
this.#textOutputCache = undefined;
|
|
363
405
|
this.#result = result;
|
|
406
|
+
this.#invalidateStaleKittyConversions();
|
|
364
407
|
this.#isPartial = isPartial;
|
|
365
408
|
// When tool is complete, ensure args are marked complete so spinner stops
|
|
366
409
|
if (!isPartial) {
|
|
@@ -370,6 +413,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
370
413
|
this.#updateDisplay();
|
|
371
414
|
// Convert non-PNG images to PNG for Kitty protocol (async)
|
|
372
415
|
this.#maybeConvertImagesForKitty();
|
|
416
|
+
this.#markVisibleMutationIfChanged();
|
|
373
417
|
}
|
|
374
418
|
|
|
375
419
|
/**
|
|
@@ -383,40 +427,101 @@ export class ToolExecutionComponent extends Container {
|
|
|
383
427
|
return [...contentImages, ...detailImages];
|
|
384
428
|
}
|
|
385
429
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
*/
|
|
390
|
-
#maybeConvertImagesForKitty(): void {
|
|
391
|
-
// Only needed for Kitty protocol
|
|
392
|
-
if (TERMINAL.imageProtocol !== ImageProtocol.Kitty) return;
|
|
393
|
-
if (!this.#result) return;
|
|
394
|
-
|
|
395
|
-
const imageBlocks = this.#getAllImageBlocks();
|
|
430
|
+
#imageSource(image: { data?: string; mimeType?: string }): string | undefined {
|
|
431
|
+
return image.data && image.mimeType ? `${image.mimeType}\u0000${image.data}` : undefined;
|
|
432
|
+
}
|
|
396
433
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
if (
|
|
434
|
+
#invalidateStaleKittyConversions(): void {
|
|
435
|
+
const images = this.#getAllImageBlocks();
|
|
436
|
+
const indices = new Set<number>();
|
|
437
|
+
for (let index = 0; index < images.length; index++) {
|
|
438
|
+
const source = this.#imageSource(images[index]);
|
|
439
|
+
if (!source) continue;
|
|
440
|
+
indices.add(index);
|
|
441
|
+
if (this.#convertedImages.get(index)?.source !== source) this.#convertedImages.delete(index);
|
|
442
|
+
if (this.#imageConversionsInFlight.get(index) !== source) {
|
|
443
|
+
this.#imageConversionsInFlight.delete(index);
|
|
444
|
+
this.#imageConversionGenerations.set(index, (this.#imageConversionGenerations.get(index) ?? 0) + 1);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
for (const index of this.#convertedImages.keys()) {
|
|
448
|
+
if (!indices.has(index)) this.#convertedImages.delete(index);
|
|
449
|
+
}
|
|
450
|
+
for (const index of this.#imageConversionsInFlight.keys()) {
|
|
451
|
+
if (!indices.has(index)) {
|
|
452
|
+
this.#imageConversionsInFlight.delete(index);
|
|
453
|
+
this.#imageConversionGenerations.set(index, (this.#imageConversionGenerations.get(index) ?? 0) + 1);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
403
457
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
458
|
+
/** Convert non-PNG images to PNG for Kitty graphics protocol. */
|
|
459
|
+
#maybeConvertImagesForKitty(): void {
|
|
460
|
+
if (TERMINAL.imageProtocol !== ImageProtocol.Kitty) return;
|
|
461
|
+
for (const [index, image] of this.#getAllImageBlocks().entries()) {
|
|
462
|
+
const source = this.#imageSource(image);
|
|
463
|
+
if (!source || image.mimeType === "image/png") continue;
|
|
464
|
+
if (
|
|
465
|
+
this.#convertedImages.get(index)?.source === source ||
|
|
466
|
+
this.#imageConversionsInFlight.get(index) === source
|
|
467
|
+
)
|
|
468
|
+
continue;
|
|
469
|
+
const generation = this.#imageConversionGenerations.get(index) ?? 0;
|
|
470
|
+
this.#imageConversionsInFlight.set(index, source);
|
|
471
|
+
new Bun.Image(Buffer.from(image.data!, "base64"))
|
|
407
472
|
.png()
|
|
408
473
|
.toBase64()
|
|
409
474
|
.then(data => {
|
|
410
|
-
|
|
475
|
+
if (
|
|
476
|
+
this.#disposed ||
|
|
477
|
+
this.#imageConversionGenerations.get(index) !== generation ||
|
|
478
|
+
this.#imageConversionsInFlight.get(index) !== source ||
|
|
479
|
+
this.#imageSource(this.#getAllImageBlocks()[index] ?? {}) !== source
|
|
480
|
+
)
|
|
481
|
+
return;
|
|
482
|
+
this.#imageConversionsInFlight.delete(index);
|
|
483
|
+
this.#convertedImages.set(index, { data, mimeType: "image/png", source });
|
|
411
484
|
this.#updateDisplay();
|
|
412
485
|
this.#ui.requestRender();
|
|
486
|
+
this.#markVisibleMutationIfChanged(true);
|
|
413
487
|
})
|
|
414
488
|
.catch(() => {
|
|
415
|
-
|
|
489
|
+
if (
|
|
490
|
+
this.#disposed ||
|
|
491
|
+
this.#imageConversionGenerations.get(index) !== generation ||
|
|
492
|
+
this.#imageConversionsInFlight.get(index) !== source
|
|
493
|
+
)
|
|
494
|
+
return;
|
|
495
|
+
this.#imageConversionsInFlight.delete(index);
|
|
416
496
|
});
|
|
417
497
|
}
|
|
418
498
|
}
|
|
419
499
|
|
|
500
|
+
#captureLogicalVisibleProjection(): string {
|
|
501
|
+
return this.render(10_000).join("\n");
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
#markVisibleMutationIfChanged(notify = false): void {
|
|
505
|
+
const projection = this.#captureLogicalVisibleProjection();
|
|
506
|
+
if (projection === this.#visibleProjection) return;
|
|
507
|
+
this.#visibleProjection = projection;
|
|
508
|
+
this.#markVisibleMutation(notify);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
#markVisibleMutation(notify = false): void {
|
|
512
|
+
if (notify) {
|
|
513
|
+
this.#onVisibleTranscriptMutation?.();
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
this.#visibleTranscriptChanged = true;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
consumeVisibleTranscriptChange(): boolean {
|
|
520
|
+
const changed = this.#visibleTranscriptChanged;
|
|
521
|
+
this.#visibleTranscriptChanged = false;
|
|
522
|
+
return changed;
|
|
523
|
+
}
|
|
524
|
+
|
|
420
525
|
/**
|
|
421
526
|
* Start or stop spinner animation based on whether this is a partial task result.
|
|
422
527
|
*/
|
|
@@ -430,6 +535,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
430
535
|
const needsSpinner = isStreamingArgs || isPartialTask;
|
|
431
536
|
if (needsSpinner && !this.#spinnerAnimation) {
|
|
432
537
|
this.#spinnerAnimation = registerAnimationCallback(() => {
|
|
538
|
+
if (this.#disposed) return;
|
|
433
539
|
const frameCount = theme.spinnerFrames.length;
|
|
434
540
|
if (frameCount === 0) return;
|
|
435
541
|
this.#spinnerFrame = ((this.#spinnerFrame ?? -1) + 1) % frameCount;
|
|
@@ -456,6 +562,11 @@ export class ToolExecutionComponent extends Container {
|
|
|
456
562
|
}
|
|
457
563
|
|
|
458
564
|
override dispose(): void {
|
|
565
|
+
if (this.#disposed) return;
|
|
566
|
+
this.#disposed = true;
|
|
567
|
+
this.#imageConversionGenerations.clear();
|
|
568
|
+
this.#imageConversionsInFlight.clear();
|
|
569
|
+
this.#convertedImages.clear();
|
|
459
570
|
this.stopAnimation();
|
|
460
571
|
super.dispose();
|
|
461
572
|
}
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
readArgsTargetInternalUrl,
|
|
13
13
|
} from "../../modes/components/read-tool-group";
|
|
14
14
|
import { TodoReminderComponent } from "../../modes/components/todo-reminder";
|
|
15
|
-
import { ToolExecutionComponent } from "../../modes/components/tool-execution";
|
|
15
|
+
import { ToolExecutionComponent, type ToolExecutionHandle } from "../../modes/components/tool-execution";
|
|
16
16
|
import { TtsrNotificationComponent } from "../../modes/components/ttsr-notification";
|
|
17
17
|
import { getSymbolTheme, theme } from "../../modes/theme/theme";
|
|
18
18
|
import type { InteractiveModeContext, TodoPhase } from "../../modes/types";
|
|
@@ -23,6 +23,7 @@ import type { AgentSessionEvent } from "../../session/agent-session";
|
|
|
23
23
|
import { type CustomMessage, isSilentAbort, readPendingDisplayTag } from "../../session/messages";
|
|
24
24
|
import { transferSessionMessageIdentity } from "../../session/session-manager";
|
|
25
25
|
import type { ResolveToolDetails } from "../../tools/resolve";
|
|
26
|
+
import { computeIrcSplitWidths, getIrcSidebarSemanticToken } from "../components/irc-sidebar";
|
|
26
27
|
import type { IrcObservationRecord } from "../irc-observation-ledger";
|
|
27
28
|
import { interruptHint } from "../shared";
|
|
28
29
|
import { buildAbortDisplayMessage } from "../utils/abort-message";
|
|
@@ -36,7 +37,14 @@ type AgentSessionEventKind = AgentSessionEvent["type"];
|
|
|
36
37
|
|
|
37
38
|
/** Test-only performance counters for advisory baseline tests. */
|
|
38
39
|
export const __eventControllerPerfCounters = {
|
|
40
|
+
enabled: false,
|
|
39
41
|
messageUpdateContentVisits: 0,
|
|
42
|
+
enable(): void {
|
|
43
|
+
this.enabled = true;
|
|
44
|
+
},
|
|
45
|
+
disable(): void {
|
|
46
|
+
this.enabled = false;
|
|
47
|
+
},
|
|
40
48
|
reset(): void {
|
|
41
49
|
this.messageUpdateContentVisits = 0;
|
|
42
50
|
},
|
|
@@ -118,6 +126,9 @@ export class EventController {
|
|
|
118
126
|
#toolIntentCache = new Map<string, { args: unknown; intent: string | undefined }>();
|
|
119
127
|
#thinkingContentIndices = new Set<number>();
|
|
120
128
|
#handlers: AgentSessionEventHandlers;
|
|
129
|
+
#visibleTranscriptChanged = false;
|
|
130
|
+
#handlingEvent = false;
|
|
131
|
+
#eventQueue: Promise<void> = Promise.resolve();
|
|
121
132
|
|
|
122
133
|
constructor(private ctx: InteractiveModeContext) {
|
|
123
134
|
this.#handlers = {
|
|
@@ -162,6 +173,26 @@ export class EventController {
|
|
|
162
173
|
this.clearIrcExpiryTimers();
|
|
163
174
|
}
|
|
164
175
|
|
|
176
|
+
#recordVisibleTranscriptMutation(): void {
|
|
177
|
+
this.#visibleTranscriptChanged = true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
#observeVisibleTranscriptMutation(): void {
|
|
181
|
+
if (this.#handlingEvent) {
|
|
182
|
+
this.#recordVisibleTranscriptMutation();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
this.ctx.recordVisibleTranscriptMutation?.();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
#consumeToolVisibleChange(handle: ToolExecutionHandle): void {
|
|
189
|
+
// Structural third-party renderers may not implement the optional exact-consume
|
|
190
|
+
// capability; preserve revision correctness conservatively until they opt in.
|
|
191
|
+
if (typeof handle.consumeVisibleTranscriptChange !== "function" || handle.consumeVisibleTranscriptChange()) {
|
|
192
|
+
this.#recordVisibleTranscriptMutation();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
165
196
|
#resetReadGroup(): void {
|
|
166
197
|
this.#lastReadGroup = undefined;
|
|
167
198
|
}
|
|
@@ -228,17 +259,26 @@ export class EventController {
|
|
|
228
259
|
});
|
|
229
260
|
}
|
|
230
261
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
this.ctx.statusLine.invalidate();
|
|
237
|
-
this.ctx.updateEditorTopBorder();
|
|
262
|
+
handleEvent(event: AgentSessionEvent): Promise<void> {
|
|
263
|
+
const dispatch = this.#eventQueue.then(() => this.#dispatchEvent(event));
|
|
264
|
+
this.#eventQueue = dispatch.catch(() => {});
|
|
265
|
+
return dispatch;
|
|
266
|
+
}
|
|
238
267
|
|
|
239
|
-
|
|
240
|
-
await
|
|
241
|
-
|
|
268
|
+
async #dispatchEvent(event: AgentSessionEvent): Promise<void> {
|
|
269
|
+
if (!this.ctx.isInitialized) await this.ctx.init();
|
|
270
|
+
this.#visibleTranscriptChanged = false;
|
|
271
|
+
this.#handlingEvent = true;
|
|
272
|
+
try {
|
|
273
|
+
this.ctx.statusLine.invalidate();
|
|
274
|
+
this.ctx.updateEditorTopBorder();
|
|
275
|
+
const run = this.#handlers[event.type] as (e: AgentSessionEvent) => Promise<void>;
|
|
276
|
+
await run(event);
|
|
277
|
+
if (this.#visibleTranscriptChanged) this.ctx.recordVisibleTranscriptMutation?.();
|
|
278
|
+
if (this.ctx.isTranscriptViewerOpen?.()) this.ctx.refreshTranscriptViewer?.();
|
|
279
|
+
} finally {
|
|
280
|
+
this.#handlingEvent = false;
|
|
281
|
+
}
|
|
242
282
|
}
|
|
243
283
|
|
|
244
284
|
async #handleAgentStart(_event: Extract<AgentSessionEvent, { type: "agent_start" }>): Promise<void> {
|
|
@@ -268,8 +308,12 @@ export class EventController {
|
|
|
268
308
|
const parsed = parseIrcMessage(message);
|
|
269
309
|
if (!parsed) return;
|
|
270
310
|
const arrival = this.ctx.captureIrcArrivalSnapshot();
|
|
311
|
+
const rightWidth = arrival.panelVisible
|
|
312
|
+
? computeIrcSplitWidths(this.ctx.ui.terminal?.columns ?? 0).rightWidth
|
|
313
|
+
: 0;
|
|
314
|
+
const beforeToken = rightWidth > 0 ? getIrcSidebarSemanticToken(this.ctx.ircLedger, rightWidth) : "";
|
|
271
315
|
const record = this.ctx.ircLedger.observe(parsed, arrival.panelVisible);
|
|
272
|
-
this.#
|
|
316
|
+
const evictedInlineRemoved = this.#cleanupIrcObservationIds(this.ctx.ircLedger.drainEvictedObservationIds());
|
|
273
317
|
if (!record) return;
|
|
274
318
|
const signature = `irc:${record.observationId}`;
|
|
275
319
|
if (this.#renderedCustomMessages.has(signature)) return;
|
|
@@ -279,9 +323,13 @@ export class EventController {
|
|
|
279
323
|
this.#renderedIrcComponents.set(record.observationId, components);
|
|
280
324
|
this.#scheduleIrcExpiry(record, components);
|
|
281
325
|
this.ctx.ui.requestRender();
|
|
326
|
+
const afterToken = rightWidth > 0 ? getIrcSidebarSemanticToken(this.ctx.ircLedger, rightWidth) : "";
|
|
327
|
+
if (components.length > 0 || evictedInlineRemoved || (rightWidth > 0 && beforeToken !== afterToken)) {
|
|
328
|
+
this.#recordVisibleTranscriptMutation();
|
|
329
|
+
}
|
|
282
330
|
}
|
|
283
331
|
|
|
284
|
-
#cleanupIrcObservationIds(observationIds: readonly string[]):
|
|
332
|
+
#cleanupIrcObservationIds(observationIds: readonly string[]): boolean {
|
|
285
333
|
const removedComponents = new Set<Component>();
|
|
286
334
|
for (const observationId of observationIds) {
|
|
287
335
|
const timer = this.#ircExpiryTimers.get(observationId);
|
|
@@ -294,23 +342,26 @@ export class EventController {
|
|
|
294
342
|
for (const component of this.ctx.removeRenderedIrcInlineComponents(observationId) ?? []) {
|
|
295
343
|
removedComponents.add(component);
|
|
296
344
|
}
|
|
297
|
-
|
|
298
345
|
this.#renderedCustomMessages.delete(`irc:${observationId}`);
|
|
299
346
|
}
|
|
300
347
|
for (const component of removedComponents) this.ctx.chatContainer.removeChild(component);
|
|
348
|
+
return removedComponents.size > 0;
|
|
301
349
|
}
|
|
302
350
|
|
|
303
351
|
#cleanupEvictedIrcObservations(): void {
|
|
304
|
-
this.#cleanupIrcObservationIds(this.ctx.ircLedger.drainEvictedObservationIds())
|
|
352
|
+
if (this.#cleanupIrcObservationIds(this.ctx.ircLedger.drainEvictedObservationIds())) {
|
|
353
|
+
this.#recordVisibleTranscriptMutation();
|
|
354
|
+
}
|
|
305
355
|
}
|
|
306
356
|
|
|
307
|
-
#cleanupExpiredIrcInlineComponents(observationId: string):
|
|
357
|
+
#cleanupExpiredIrcInlineComponents(observationId: string): boolean {
|
|
308
358
|
const removedComponents = new Set<Component>(this.#renderedIrcComponents.get(observationId));
|
|
309
359
|
this.#renderedIrcComponents.delete(observationId);
|
|
310
360
|
for (const component of this.ctx.removeRenderedIrcInlineComponents(observationId) ?? []) {
|
|
311
361
|
removedComponents.add(component);
|
|
312
362
|
}
|
|
313
363
|
for (const component of removedComponents) this.ctx.chatContainer.removeChild(component);
|
|
364
|
+
return removedComponents.size > 0;
|
|
314
365
|
}
|
|
315
366
|
|
|
316
367
|
async #handleMessageStart(event: Extract<AgentSessionEvent, { type: "message_start" }>): Promise<void> {
|
|
@@ -326,6 +377,7 @@ export class EventController {
|
|
|
326
377
|
this.#renderedCustomMessages.add(signature);
|
|
327
378
|
this.#resetReadGroup();
|
|
328
379
|
this.ctx.addMessageToChat(event.message);
|
|
380
|
+
if (event.message.display) this.#recordVisibleTranscriptMutation();
|
|
329
381
|
// Tag-keyed pending-bar refresh: when AgentSession.#handleAgentEvent
|
|
330
382
|
// spliced this dequeued custom message out of #steeringMessages /
|
|
331
383
|
// #followUpMessages (it ran before this emit), the array state is
|
|
@@ -373,10 +425,12 @@ export class EventController {
|
|
|
373
425
|
this.ctx.updatePendingMessagesDisplay();
|
|
374
426
|
}
|
|
375
427
|
this.ctx.ui.requestRender();
|
|
428
|
+
if (!wasOptimistic) this.#recordVisibleTranscriptMutation();
|
|
376
429
|
} else if (event.message.role === "fileMention") {
|
|
377
430
|
this.#resetReadGroup();
|
|
378
431
|
this.ctx.addMessageToChat(event.message);
|
|
379
432
|
this.ctx.ui.requestRender();
|
|
433
|
+
this.#recordVisibleTranscriptMutation();
|
|
380
434
|
} else if (event.message.role === "assistant") {
|
|
381
435
|
this.#lastThinkingCount = 0;
|
|
382
436
|
this.#resetReadGroup();
|
|
@@ -387,6 +441,7 @@ export class EventController {
|
|
|
387
441
|
this.ctx.hideThinkingBlock,
|
|
388
442
|
() => this.ctx.ui.requestRender(),
|
|
389
443
|
this.ctx.getAssistantViewportAnchorId?.(event.message),
|
|
444
|
+
() => this.#observeVisibleTranscriptMutation(),
|
|
390
445
|
);
|
|
391
446
|
this.ctx.streamingMessage = event.message;
|
|
392
447
|
addChatChild(this.ctx, this.ctx.streamingComponent);
|
|
@@ -429,15 +484,10 @@ export class EventController {
|
|
|
429
484
|
this.#cleanupEvictedIrcObservations();
|
|
430
485
|
const projectedObservationIds = new Set(inlineProjection.map(record => record.observationId));
|
|
431
486
|
for (const [observationId, components] of componentsByObservationId) {
|
|
432
|
-
|
|
433
|
-
if (
|
|
434
|
-
!projectedObservationIds.has(observationId) ||
|
|
435
|
-
(record?.mode === "ephemeral" && record.expiresAt! - now <= 0)
|
|
436
|
-
) {
|
|
487
|
+
if (!projectedObservationIds.has(observationId)) {
|
|
437
488
|
for (const component of components) {
|
|
438
489
|
this.ctx.chatContainer.removeChild(component);
|
|
439
490
|
}
|
|
440
|
-
this.#renderedIrcComponents.delete(observationId);
|
|
441
491
|
componentsByObservationId.delete(observationId);
|
|
442
492
|
}
|
|
443
493
|
}
|
|
@@ -468,12 +518,12 @@ export class EventController {
|
|
|
468
518
|
}
|
|
469
519
|
const remainingMs = record.expiresAt! - Date.now();
|
|
470
520
|
if (remainingMs <= 0) {
|
|
471
|
-
this.#cleanupExpiredIrcInlineComponents(record.observationId);
|
|
521
|
+
if (this.#cleanupExpiredIrcInlineComponents(record.observationId)) this.#observeVisibleTranscriptMutation();
|
|
472
522
|
return false;
|
|
473
523
|
}
|
|
474
524
|
const timer = setTimeout(() => {
|
|
475
525
|
this.#ircExpiryTimers.delete(record.observationId);
|
|
476
|
-
this.#cleanupExpiredIrcInlineComponents(record.observationId);
|
|
526
|
+
if (this.#cleanupExpiredIrcInlineComponents(record.observationId)) this.#observeVisibleTranscriptMutation();
|
|
477
527
|
this.ctx.ui.requestRender();
|
|
478
528
|
}, remainingMs);
|
|
479
529
|
timer.unref?.();
|
|
@@ -496,6 +546,7 @@ export class EventController {
|
|
|
496
546
|
this.#resetReadGroup();
|
|
497
547
|
this.ctx.addMessageToChat(event.message);
|
|
498
548
|
this.ctx.ui.requestRender();
|
|
549
|
+
this.#recordVisibleTranscriptMutation();
|
|
499
550
|
}
|
|
500
551
|
|
|
501
552
|
async #handleModelFallbackSwitched(
|
|
@@ -549,19 +600,24 @@ export class EventController {
|
|
|
549
600
|
}
|
|
550
601
|
|
|
551
602
|
for (const content of contentsToProcess) {
|
|
552
|
-
__eventControllerPerfCounters.messageUpdateContentVisits += 1;
|
|
603
|
+
if (__eventControllerPerfCounters.enabled) __eventControllerPerfCounters.messageUpdateContentVisits += 1;
|
|
553
604
|
if (content.type !== "toolCall") continue;
|
|
554
605
|
if (content.name === "read") {
|
|
555
606
|
if (!readArgsHaveTarget(content.arguments)) continue;
|
|
556
607
|
if (!readArgsTargetInternalUrl(content.arguments)) {
|
|
557
608
|
this.#trackReadToolCall(content.id, content.arguments);
|
|
558
609
|
const component = this.ctx.pendingTools.get(content.id);
|
|
559
|
-
if (component)
|
|
560
|
-
|
|
610
|
+
if (component) {
|
|
611
|
+
component.updateArgs(content.arguments, content.id);
|
|
612
|
+
this.#consumeToolVisibleChange(component);
|
|
613
|
+
} else {
|
|
561
614
|
const group = this.#getReadGroup();
|
|
562
615
|
group.updateArgs(content.arguments, content.id);
|
|
563
616
|
this.ctx.pendingTools.set(content.id, group);
|
|
617
|
+
this.#recordVisibleTranscriptMutation();
|
|
618
|
+
group.consumeVisibleTranscriptChange();
|
|
564
619
|
}
|
|
620
|
+
|
|
565
621
|
continue;
|
|
566
622
|
}
|
|
567
623
|
}
|
|
@@ -582,6 +638,7 @@ export class EventController {
|
|
|
582
638
|
editFuzzyThreshold: settings.get("edit.fuzzyThreshold"),
|
|
583
639
|
editAllowFuzzy: settings.get("edit.fuzzyMatch"),
|
|
584
640
|
hashlineAutoDropPureInsertDuplicates: settings.get("edit.hashlineAutoDropPureInsertDuplicates"),
|
|
641
|
+
onVisibleTranscriptMutation: () => this.#observeVisibleTranscriptMutation(),
|
|
585
642
|
},
|
|
586
643
|
tool,
|
|
587
644
|
this.ctx.ui,
|
|
@@ -591,8 +648,10 @@ export class EventController {
|
|
|
591
648
|
component.setExpanded(this.ctx.toolOutputExpanded);
|
|
592
649
|
this.ctx.pendingTools.set(content.id, component);
|
|
593
650
|
addChatChild(this.ctx, component);
|
|
651
|
+
this.#recordVisibleTranscriptMutation();
|
|
594
652
|
} else {
|
|
595
653
|
this.ctx.pendingTools.get(content.id)?.updateArgs(renderArgs, content.id);
|
|
654
|
+
this.#consumeToolVisibleChange(this.ctx.pendingTools.get(content.id)!);
|
|
596
655
|
}
|
|
597
656
|
|
|
598
657
|
const args = content.arguments;
|
|
@@ -659,6 +718,7 @@ export class EventController {
|
|
|
659
718
|
if (this.ctx.streamingMessage.stopReason !== "aborted" && this.ctx.streamingMessage.stopReason !== "error") {
|
|
660
719
|
for (const [toolCallId, component] of this.ctx.pendingTools.entries()) {
|
|
661
720
|
component.setArgsComplete(toolCallId);
|
|
721
|
+
this.#consumeToolVisibleChange(component);
|
|
662
722
|
}
|
|
663
723
|
}
|
|
664
724
|
this.#lastAssistantComponent = this.ctx.streamingComponent;
|
|
@@ -685,6 +745,8 @@ export class EventController {
|
|
|
685
745
|
this.ctx.pendingTools.set(event.toolCallId, group);
|
|
686
746
|
}
|
|
687
747
|
this.ctx.ui.requestRender();
|
|
748
|
+
this.#consumeToolVisibleChange(this.ctx.pendingTools.get(event.toolCallId)!);
|
|
749
|
+
|
|
688
750
|
return;
|
|
689
751
|
}
|
|
690
752
|
|
|
@@ -698,6 +760,7 @@ export class EventController {
|
|
|
698
760
|
editFuzzyThreshold: settings.get("edit.fuzzyThreshold"),
|
|
699
761
|
editAllowFuzzy: settings.get("edit.fuzzyMatch"),
|
|
700
762
|
hashlineAutoDropPureInsertDuplicates: settings.get("edit.hashlineAutoDropPureInsertDuplicates"),
|
|
763
|
+
onVisibleTranscriptMutation: () => this.#observeVisibleTranscriptMutation(),
|
|
701
764
|
},
|
|
702
765
|
tool,
|
|
703
766
|
this.ctx.ui,
|
|
@@ -707,6 +770,8 @@ export class EventController {
|
|
|
707
770
|
component.setExpanded(this.ctx.toolOutputExpanded);
|
|
708
771
|
this.ctx.pendingTools.set(event.toolCallId, component);
|
|
709
772
|
addChatChild(this.ctx, component);
|
|
773
|
+
this.#recordVisibleTranscriptMutation();
|
|
774
|
+
|
|
710
775
|
this.ctx.ui.requestRender();
|
|
711
776
|
}
|
|
712
777
|
}
|
|
@@ -723,6 +788,8 @@ export class EventController {
|
|
|
723
788
|
!isFinalAsyncState,
|
|
724
789
|
event.toolCallId,
|
|
725
790
|
);
|
|
791
|
+
this.#consumeToolVisibleChange(component);
|
|
792
|
+
|
|
726
793
|
if (isFinalAsyncState) {
|
|
727
794
|
this.ctx.pendingTools.delete(event.toolCallId);
|
|
728
795
|
this.#backgroundToolCallIds.delete(event.toolCallId);
|
|
@@ -737,6 +804,8 @@ export class EventController {
|
|
|
737
804
|
const component = this.ctx.pendingTools.get(event.toolCallId);
|
|
738
805
|
if (component) {
|
|
739
806
|
component.updateResult({ ...event.result, isError: event.isError }, false, event.toolCallId);
|
|
807
|
+
this.#consumeToolVisibleChange(component);
|
|
808
|
+
|
|
740
809
|
this.ctx.pendingTools.delete(event.toolCallId);
|
|
741
810
|
}
|
|
742
811
|
const asyncState = (event.result.details as { async?: { state?: string } } | undefined)?.async?.state;
|
|
@@ -761,6 +830,8 @@ export class EventController {
|
|
|
761
830
|
const asyncState = (event.result.details as { async?: { state?: string } } | undefined)?.async?.state;
|
|
762
831
|
const isBackgroundRunning = asyncState === "running";
|
|
763
832
|
component.updateResult({ ...event.result, isError: event.isError }, isBackgroundRunning, event.toolCallId);
|
|
833
|
+
this.#consumeToolVisibleChange(component);
|
|
834
|
+
|
|
764
835
|
if (isBackgroundRunning) {
|
|
765
836
|
this.#backgroundToolCallIds.add(event.toolCallId);
|
|
766
837
|
} else {
|
|
@@ -776,6 +847,8 @@ export class EventController {
|
|
|
776
847
|
const asyncState = (event.result.details as { async?: { state?: string } } | undefined)?.async?.state;
|
|
777
848
|
const isBackgroundRunning = asyncState === "running";
|
|
778
849
|
component.updateResult({ ...event.result, isError: event.isError }, isBackgroundRunning, event.toolCallId);
|
|
850
|
+
this.#consumeToolVisibleChange(component);
|
|
851
|
+
|
|
779
852
|
if (isBackgroundRunning) {
|
|
780
853
|
this.#backgroundToolCallIds.add(event.toolCallId);
|
|
781
854
|
} else {
|
|
@@ -893,6 +966,12 @@ export class EventController {
|
|
|
893
966
|
} else if (event.willRetry && !isHandoffAction) {
|
|
894
967
|
this.ctx.showStatus("Context overflow maintenance completed");
|
|
895
968
|
}
|
|
969
|
+
} else if (
|
|
970
|
+
event.skipped &&
|
|
971
|
+
event.errorMessage?.startsWith("Context overflow recovery skipped: nothing eligible to compact.") &&
|
|
972
|
+
!isHandoffAction
|
|
973
|
+
) {
|
|
974
|
+
this.ctx.showStatus(event.errorMessage);
|
|
896
975
|
} else if (event.errorMessage) {
|
|
897
976
|
this.ctx.showWarning(event.errorMessage);
|
|
898
977
|
} else if (isHandoffAction) {
|
|
@@ -999,12 +1078,15 @@ export class EventController {
|
|
|
999
1078
|
const component = new TtsrNotificationComponent(event.rules);
|
|
1000
1079
|
component.setExpanded(this.ctx.toolOutputExpanded);
|
|
1001
1080
|
addChatChild(this.ctx, component);
|
|
1081
|
+
this.#recordVisibleTranscriptMutation();
|
|
1082
|
+
|
|
1002
1083
|
this.ctx.ui.requestRender();
|
|
1003
1084
|
}
|
|
1004
1085
|
|
|
1005
1086
|
async #handleTodoReminder(event: Extract<AgentSessionEvent, { type: "todo_reminder" }>): Promise<void> {
|
|
1006
1087
|
const component = new TodoReminderComponent(event.todos, event.attempt, event.maxAttempts);
|
|
1007
1088
|
addChatChild(this.ctx, component);
|
|
1089
|
+
this.#recordVisibleTranscriptMutation();
|
|
1008
1090
|
this.ctx.ui.requestRender();
|
|
1009
1091
|
}
|
|
1010
1092
|
|