@gajae-code/coding-agent 0.12.0 → 0.12.1
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 +82 -1
- package/dist/types/async/job-manager.d.ts +17 -3
- package/dist/types/config/settings-schema.d.ts +54 -0
- package/dist/types/exa/mcp-client.d.ts +10 -1
- package/dist/types/exec/bash-executor.d.ts +45 -12
- package/dist/types/extensibility/extensions/types.d.ts +16 -2
- package/dist/types/extensibility/gjc-plugins/index.d.ts +12 -2
- package/dist/types/extensibility/gjc-plugins/installer.d.ts +63 -7
- package/dist/types/extensibility/gjc-plugins/lifecycle-reconciliation.d.ts +55 -0
- package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +64 -0
- package/dist/types/extensibility/gjc-plugins/runtime-quarantine.d.ts +67 -0
- package/dist/types/extensibility/gjc-plugins/session-validation.d.ts +3 -1
- package/dist/types/extensibility/gjc-plugins/types.d.ts +124 -0
- package/dist/types/gjc-runtime/launch-tmux.d.ts +1 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +18 -0
- package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
- package/dist/types/gjc-runtime/team-runtime.d.ts +25 -0
- package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +43 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +10 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +31 -80
- package/dist/types/modes/acp/acp-agent.d.ts +2 -19
- package/dist/types/modes/components/gjc-bundle-settings.d.ts +34 -0
- package/dist/types/modes/components/notifications-settings-editor.d.ts +1 -0
- package/dist/types/modes/components/session-observer-overlay.d.ts +18 -0
- package/dist/types/modes/components/settings-selector.d.ts +9 -0
- package/dist/types/modes/components/status-line/gh.d.ts +5 -0
- package/dist/types/modes/components/transcript-viewer-overlay.d.ts +18 -1
- package/dist/types/reminders/star-reminder.d.ts +3 -13
- package/dist/types/runtime-mcp/manager.d.ts +1 -0
- package/dist/types/sdk/acp/adapter.d.ts +3 -1
- package/dist/types/sdk/broker/transport.d.ts +2 -0
- package/dist/types/sdk/bus/attachment-registry.d.ts +1 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +4 -1
- package/dist/types/sdk/bus/config.d.ts +6 -2
- package/dist/types/sdk/bus/index.d.ts +29 -0
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +8 -1
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/reconciliation-store.d.ts +7 -3
- package/dist/types/sdk/bus/rich-draft.d.ts +1 -0
- package/dist/types/sdk/bus/rich-render.d.ts +2 -0
- package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +165 -0
- package/dist/types/sdk/bus/telegram-cli.d.ts +12 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +11 -4
- package/dist/types/sdk/bus/telegram-daemon.d.ts +25 -1
- package/dist/types/sdk/bus/telegram-reference.d.ts +11 -1
- package/dist/types/sdk/bus/threaded-render.d.ts +3 -2
- package/dist/types/sdk/bus/topic-registry.d.ts +11 -1
- package/dist/types/sdk/host/query/revision-store.d.ts +2 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
- package/dist/types/sdk/prompt-status.d.ts +23 -3
- package/dist/types/sdk/session.d.ts +6 -0
- package/dist/types/session/agent-session.d.ts +38 -2
- package/dist/types/session/artifacts.d.ts +8 -0
- package/dist/types/session/blob-store.d.ts +57 -4
- package/dist/types/session/internal/managed-session-storage.d.ts +8 -1
- package/dist/types/session/session-manager.d.ts +23 -6
- package/dist/types/session/session-storage.d.ts +4 -0
- package/dist/types/session/streaming-output.d.ts +36 -7
- package/dist/types/setup/credential-import.d.ts +12 -0
- package/dist/types/skill-state/active-state.d.ts +12 -0
- package/dist/types/skill-state/workflow-hud.d.ts +6 -0
- package/dist/types/task/executor.d.ts +3 -2
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/task/provider-retry-status.d.ts +8 -0
- package/dist/types/task/receipt.d.ts +7 -1
- package/dist/types/task/types.d.ts +23 -0
- package/dist/types/tools/ask-answer-registry.d.ts +2 -2
- package/dist/types/tools/bash-interactive.d.ts +4 -1
- package/dist/types/tools/bash.d.ts +3 -1
- package/dist/types/tools/image-gen.d.ts +4 -0
- package/dist/types/tools/index.d.ts +4 -0
- package/dist/types/tools/output-meta.d.ts +23 -2
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/read.d.ts +0 -6
- package/dist/types/tools/review.d.ts +5 -7
- package/dist/types/tools/subagent.d.ts +2 -0
- package/dist/types/utils/gh.d.ts +13 -0
- package/dist/types/utils/image-resize.d.ts +1 -0
- package/dist/types/web/search/providers/kimi.d.ts +2 -0
- package/dist/types/web/search/providers/searxng.d.ts +7 -0
- package/dist/types/web/search/providers/xai.d.ts +2 -0
- package/package.json +10 -8
- package/scripts/acp-conformance-agent.ts +218 -0
- package/scripts/capture-gjc-bundle-settings.ts +306 -0
- package/scripts/generate-sdk-operation-inventory.ts +3 -0
- package/scripts/resident-memory-bench.ts +1341 -0
- package/scripts/run-acp-conformance.ts +285 -0
- package/src/async/job-manager.ts +78 -20
- package/src/cli/fast-help.ts +1 -1
- package/src/cli/plugin-cli.ts +176 -18
- package/src/commands/team.ts +19 -1
- package/src/config/file-lock.ts +11 -2
- package/src/config/settings-schema.ts +51 -0
- package/src/coordinator-mcp/question-gate-codec.ts +1 -1
- package/src/coordinator-mcp/server.ts +5 -12
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -0
- package/src/defaults/gjc/skills/ralplan/SKILL.md +19 -16
- package/src/defaults/gjc/skills/team/SKILL.md +2 -0
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +37 -24
- package/src/defaults/gjc/skills/ultragoal/validation-batch-contracts.md +12 -0
- package/src/defaults/gjc-defaults.ts +4 -4
- package/src/exa/mcp-client.ts +12 -3
- package/src/exec/bash-executor.ts +144 -27
- package/src/extensibility/extensions/runner.ts +15 -0
- package/src/extensibility/extensions/types.ts +18 -1
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +8 -2
- package/src/extensibility/gjc-plugins/index.ts +19 -2
- package/src/extensibility/gjc-plugins/installer.ts +189 -50
- package/src/extensibility/gjc-plugins/lifecycle-reconciliation.ts +199 -0
- package/src/extensibility/gjc-plugins/lifecycle.ts +626 -0
- package/src/extensibility/gjc-plugins/observability.ts +3 -3
- package/src/extensibility/gjc-plugins/prompt-appendix.ts +5 -1
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +12 -2
- package/src/extensibility/gjc-plugins/runtime-quarantine.ts +121 -0
- package/src/extensibility/gjc-plugins/schema.ts +84 -12
- package/src/extensibility/gjc-plugins/session-validation.ts +9 -3
- package/src/extensibility/gjc-plugins/types.ts +141 -0
- package/src/extensibility/gjc-plugins/validation.ts +9 -0
- package/src/gjc-runtime/launch-tmux.ts +25 -6
- package/src/gjc-runtime/managed-owner-admission.ts +1 -1
- package/src/gjc-runtime/ralplan-runtime.ts +411 -17
- package/src/gjc-runtime/team-launch.ts +8 -0
- package/src/gjc-runtime/team-runtime.ts +140 -32
- package/src/gjc-runtime/team-worker-heartbeat.ts +149 -0
- package/src/gjc-runtime/tmux-owner-isolation.ts +10 -0
- package/src/gjc-runtime/tmux-sessions.ts +58 -13
- package/src/gjc-runtime/ultragoal-runtime.ts +401 -611
- package/src/gjc-runtime/workflow-manifest.generated.json +8 -99
- package/src/gjc-runtime/workflow-manifest.ts +4 -68
- package/src/internal-urls/docs-index.generated.ts +15 -15
- package/src/modes/DESIGN.md +51 -0
- package/src/modes/acp/acp-agent.ts +298 -186
- package/src/modes/components/gjc-bundle-settings.ts +508 -0
- package/src/modes/components/notifications-settings-editor.ts +12 -1
- package/src/modes/components/oauth-selector.ts +68 -30
- package/src/modes/components/session-observer-overlay.ts +305 -86
- package/src/modes/components/settings-selector.ts +56 -5
- package/src/modes/components/status-line/gh.ts +16 -0
- package/src/modes/components/tool-status-header.ts +3 -14
- package/src/modes/components/transcript-viewer-overlay.ts +99 -24
- package/src/modes/controllers/command-controller.ts +4 -0
- package/src/modes/controllers/extension-ui-controller.ts +7 -0
- package/src/modes/controllers/selector-controller.ts +45 -0
- package/src/modes/runtime-init.ts +3 -0
- package/src/prompts/agent-fragments/ralplan-persistence.md +4 -3
- package/src/prompts/system/eager-todo.md +8 -4
- package/src/prompts/system/system-prompt.md +11 -4
- package/src/prompts/tools/bash.md +5 -5
- package/src/prompts/tools/search-tool-bm25.md +5 -0
- package/src/prompts/tools/task.md +1 -1
- package/src/reminders/star-reminder.ts +4 -42
- package/src/runtime-mcp/manager.ts +19 -4
- package/src/sdk/acp/adapter.ts +22 -6
- package/src/sdk/broker/transport.ts +35 -3
- package/src/sdk/bus/attachment-registry.ts +5 -1
- package/src/sdk/bus/chat-daemon-cli.ts +4 -39
- package/src/sdk/bus/chat-daemon-control.ts +6 -3
- package/src/sdk/bus/config.ts +18 -2
- package/src/sdk/bus/index.ts +661 -126
- package/src/sdk/bus/kind-aware-reconciliation.ts +148 -73
- package/src/sdk/bus/lifecycle-commands.ts +4 -1
- package/src/sdk/bus/lifecycle-control-runtime.ts +403 -88
- package/src/sdk/bus/reconciliation-store.ts +95 -16
- package/src/sdk/bus/rich-draft.ts +1 -1
- package/src/sdk/bus/rich-render.ts +2 -2
- package/src/sdk/bus/telegram-adoption-intent.ts +574 -0
- package/src/sdk/bus/telegram-cli.ts +33 -8
- package/src/sdk/bus/telegram-daemon-cli.ts +1 -0
- package/src/sdk/bus/telegram-daemon-contract.ts +11 -4
- package/src/sdk/bus/telegram-daemon.ts +916 -23
- package/src/sdk/bus/telegram-reference.ts +40 -3
- package/src/sdk/bus/threaded-render.ts +48 -3
- package/src/sdk/bus/topic-registry.ts +20 -0
- package/src/sdk/host/query/revision-store.ts +36 -2
- package/src/sdk/host/reverse-leases.ts +44 -7
- package/src/sdk/prompt-status.ts +16 -3
- package/src/sdk/protocol/operation-inventory.generated.json +22 -0
- package/src/sdk/session.ts +88 -9
- package/src/session/agent-session.ts +822 -172
- package/src/session/artifacts.ts +22 -0
- package/src/session/auth-broker-config.ts +10 -3
- package/src/session/blob-store.ts +915 -24
- package/src/session/internal/managed-session-scope.ts +44 -6
- package/src/session/internal/managed-session-storage.ts +48 -6
- package/src/session/session-manager.ts +1614 -435
- package/src/session/session-storage.ts +9 -1
- package/src/session/streaming-output.ts +238 -68
- package/src/setup/credential-import.ts +75 -13
- package/src/skill-state/active-state.ts +32 -0
- package/src/skill-state/workflow-hud.ts +17 -0
- package/src/skill-state/workflow-mutation-guard.ts +496 -2
- package/src/task/executor.ts +122 -39
- package/src/task/index.ts +23 -14
- package/src/task/provider-retry-status.ts +16 -0
- package/src/task/receipt.ts +23 -7
- package/src/task/render.ts +6 -2
- package/src/task/types.ts +108 -0
- package/src/tools/ask-answer-registry.ts +12 -6
- package/src/tools/ask.ts +86 -55
- package/src/tools/ast-edit.ts +1 -0
- package/src/tools/ast-grep.ts +1 -0
- package/src/tools/bash-interactive.ts +8 -3
- package/src/tools/bash.ts +503 -60
- package/src/tools/find.ts +1 -0
- package/src/tools/image-gen.ts +29 -5
- package/src/tools/index.ts +4 -0
- package/src/tools/output-meta.ts +108 -14
- package/src/tools/path-utils.ts +3 -2
- package/src/tools/read.ts +18 -0
- package/src/tools/review.ts +5 -7
- package/src/tools/search.ts +1 -0
- package/src/tools/subagent-render.ts +6 -2
- package/src/tools/subagent.ts +6 -0
- package/src/tools/telegram-send.ts +6 -3
- package/src/utils/gh.ts +39 -0
- package/src/utils/image-resize.ts +3 -0
- package/src/web/search/providers/anthropic.ts +4 -4
- package/src/web/search/providers/kimi.ts +15 -5
- package/src/web/search/providers/searxng.ts +47 -4
- package/src/web/search/providers/xai.ts +7 -2
- package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +0 -23
- package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +0 -30
- package/src/gjc-runtime/ultragoal-pipeline.ts +0 -306
package/src/task/executor.ts
CHANGED
|
@@ -44,23 +44,25 @@ import { SessionManager } from "../session/session-manager";
|
|
|
44
44
|
import { truncateTail } from "../session/streaming-output";
|
|
45
45
|
import type { ContextFileEntry } from "../tools";
|
|
46
46
|
import { jtdToJsonSchema, normalizeSchema } from "../tools/jtd-to-json-schema";
|
|
47
|
-
import {
|
|
47
|
+
import type { ReportFindingDetails } from "../tools/review";
|
|
48
48
|
import { ToolAbortError } from "../tools/tool-errors";
|
|
49
49
|
import type { EventBus } from "../utils/event-bus";
|
|
50
50
|
import { buildNamedToolChoiceResult } from "../utils/tool-choice";
|
|
51
51
|
import type { WorkspaceTree } from "../workspace-tree";
|
|
52
52
|
import { validateAllocatedTaskId } from "./id";
|
|
53
|
-
import {
|
|
53
|
+
import { classifyProviderRetryFromTransport, providerNameFromModel } from "./provider-retry-status";
|
|
54
54
|
import { subprocessToolRegistry } from "./subprocess-tool-registry";
|
|
55
55
|
import { persistTaskTokenLog, taskTokenLogFromUsage } from "./token-log";
|
|
56
56
|
import {
|
|
57
57
|
type AgentDefinition,
|
|
58
58
|
type AgentProgress,
|
|
59
|
+
createSetupFailureSummary,
|
|
59
60
|
hasCompleteUsageCostBreakdown,
|
|
60
61
|
MAX_OUTPUT_BYTES,
|
|
61
62
|
MAX_OUTPUT_LINES,
|
|
62
63
|
type ModelSubstitutionWarning,
|
|
63
|
-
type
|
|
64
|
+
type ReviewFindingsArtifactRef,
|
|
65
|
+
type SetupFailureSummary,
|
|
64
66
|
type SingleResult,
|
|
65
67
|
TASK_SUBAGENT_EVENT_CHANNEL,
|
|
66
68
|
TASK_SUBAGENT_LIFECYCLE_CHANNEL,
|
|
@@ -241,6 +243,8 @@ export interface ExecutorOptions {
|
|
|
241
243
|
* subagents, and a main-model fast-mode auto-disable does not clobber it.
|
|
242
244
|
*/
|
|
243
245
|
inheritedServiceTier?: ServiceTier;
|
|
246
|
+
/** Resolve whether the effective subagent tier grants fast mode for the selected provider. */
|
|
247
|
+
isFastForSubagentProvider?: (provider?: string) => boolean;
|
|
244
248
|
/** Override local:// protocol options so subagent shares parent's local:// root */
|
|
245
249
|
localProtocolOptions?: LocalProtocolOptions;
|
|
246
250
|
/**
|
|
@@ -291,11 +295,13 @@ export class ManagedTaskPersistence {
|
|
|
291
295
|
}
|
|
292
296
|
|
|
293
297
|
async publishOutput(rawOutput: string, metadata: Uint8Array): Promise<void> {
|
|
294
|
-
await this.#artifacts
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
298
|
+
await withArtifactManagerFinalizationTurn(this.#artifacts, () =>
|
|
299
|
+
this.#artifacts.publishManagedOutputGeneration(
|
|
300
|
+
`${this.#taskId}.md.selector.json`,
|
|
301
|
+
`${this.#taskId}.md`,
|
|
302
|
+
Buffer.from(rawOutput, "utf8"),
|
|
303
|
+
metadata,
|
|
304
|
+
),
|
|
299
305
|
);
|
|
300
306
|
}
|
|
301
307
|
}
|
|
@@ -304,6 +310,59 @@ export function createManagedTaskPersistence(artifacts: ArtifactManager, taskId:
|
|
|
304
310
|
return new ManagedTaskPersistence(artifacts, taskId);
|
|
305
311
|
}
|
|
306
312
|
|
|
313
|
+
const MAX_REVIEW_FINDINGS_ARTIFACT_BYTES = 16 * 1024 * 1024;
|
|
314
|
+
const REVIEW_FINDINGS_ARTIFACT_FAILURE = "Review findings artifact publication failed.";
|
|
315
|
+
const artifactManagerFinalizationTails = new WeakMap<ArtifactManager, Promise<void>>();
|
|
316
|
+
|
|
317
|
+
interface ReviewFindingsArtifactPayload {
|
|
318
|
+
version: 1;
|
|
319
|
+
kind: "review-findings";
|
|
320
|
+
taskId: string;
|
|
321
|
+
findingCount: number;
|
|
322
|
+
findings: ReportFindingDetails[];
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async function withArtifactManagerFinalizationTurn<T>(
|
|
326
|
+
manager: ArtifactManager,
|
|
327
|
+
operation: () => Promise<T>,
|
|
328
|
+
): Promise<T> {
|
|
329
|
+
const priorTail = artifactManagerFinalizationTails.get(manager);
|
|
330
|
+
const turn = Promise.withResolvers<void>();
|
|
331
|
+
artifactManagerFinalizationTails.set(manager, turn.promise);
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
await priorTail?.catch(() => undefined);
|
|
335
|
+
return await operation();
|
|
336
|
+
} finally {
|
|
337
|
+
turn.resolve();
|
|
338
|
+
if (artifactManagerFinalizationTails.get(manager) === turn.promise) {
|
|
339
|
+
artifactManagerFinalizationTails.delete(manager);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
async function publishReviewFindingsArtifact(
|
|
345
|
+
manager: ArtifactManager,
|
|
346
|
+
taskId: string,
|
|
347
|
+
findings: ReportFindingDetails[],
|
|
348
|
+
): Promise<ReviewFindingsArtifactRef> {
|
|
349
|
+
const payload: ReviewFindingsArtifactPayload = {
|
|
350
|
+
version: 1,
|
|
351
|
+
kind: "review-findings",
|
|
352
|
+
taskId,
|
|
353
|
+
findingCount: findings.length,
|
|
354
|
+
findings,
|
|
355
|
+
};
|
|
356
|
+
const serialized = JSON.stringify(payload, null, 2);
|
|
357
|
+
const sizeBytes = Buffer.byteLength(serialized, "utf8");
|
|
358
|
+
if (sizeBytes > MAX_REVIEW_FINDINGS_ARTIFACT_BYTES) throw new Error("review findings artifact exceeds limit");
|
|
359
|
+
const sha256 = createHash("sha256").update(serialized).digest("hex");
|
|
360
|
+
const artifactId = await withArtifactManagerFinalizationTurn(manager, () =>
|
|
361
|
+
manager.save(serialized, "review-findings", { maxBytes: sizeBytes }),
|
|
362
|
+
);
|
|
363
|
+
return { uri: `artifact://${artifactId}`, sizeBytes, sha256, findingCount: findings.length };
|
|
364
|
+
}
|
|
365
|
+
|
|
307
366
|
export function renderSubagentUserPrompt(assignment: string, independentMode: boolean): string {
|
|
308
367
|
return prompt.render(subagentUserPromptTemplate, { assignment: assignment.trim(), independentMode });
|
|
309
368
|
}
|
|
@@ -439,21 +498,8 @@ function extractCompletionData(parsed: unknown): unknown {
|
|
|
439
498
|
return parsed;
|
|
440
499
|
}
|
|
441
500
|
|
|
442
|
-
function normalizeCompleteData(data: unknown
|
|
443
|
-
|
|
444
|
-
if (
|
|
445
|
-
Array.isArray(reportFindings) &&
|
|
446
|
-
reportFindings.length > 0 &&
|
|
447
|
-
normalized &&
|
|
448
|
-
typeof normalized === "object" &&
|
|
449
|
-
!Array.isArray(normalized)
|
|
450
|
-
) {
|
|
451
|
-
const record = normalized as Record<string, unknown>;
|
|
452
|
-
if (!("findings" in record)) {
|
|
453
|
-
normalized = { ...record, findings: reportFindings };
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
return normalized;
|
|
501
|
+
function normalizeCompleteData(data: unknown): unknown {
|
|
502
|
+
return parseStringifiedJson(data ?? null);
|
|
457
503
|
}
|
|
458
504
|
|
|
459
505
|
function resolveFallbackCompletion(rawOutput: string, outputSchema: unknown): { data: unknown } | null {
|
|
@@ -480,7 +526,6 @@ interface FinalizeSubprocessOutputArgs {
|
|
|
480
526
|
doneAborted: boolean;
|
|
481
527
|
signalAborted: boolean;
|
|
482
528
|
yieldItems?: YieldItem[];
|
|
483
|
-
reportFindings?: ReviewFinding[];
|
|
484
529
|
outputSchema: unknown;
|
|
485
530
|
}
|
|
486
531
|
|
|
@@ -541,7 +586,7 @@ function buildPlaceholderYieldOutcome(
|
|
|
541
586
|
|
|
542
587
|
export function finalizeSubprocessOutput(args: FinalizeSubprocessOutputArgs): FinalizeSubprocessOutputResult {
|
|
543
588
|
let { rawOutput, exitCode, stderr } = args;
|
|
544
|
-
const { yieldItems,
|
|
589
|
+
const { yieldItems, doneAborted, signalAborted, outputSchema } = args;
|
|
545
590
|
let abortedViaYield = false;
|
|
546
591
|
const hasYield = Array.isArray(yieldItems) && yieldItems.length > 0;
|
|
547
592
|
|
|
@@ -561,7 +606,7 @@ export function finalizeSubprocessOutput(args: FinalizeSubprocessOutputArgs): Fi
|
|
|
561
606
|
if (submitData === null || submitData === undefined) {
|
|
562
607
|
rawOutput = rawOutput ? `${SUBAGENT_WARNING_NULL_YIELD}\n\n${rawOutput}` : SUBAGENT_WARNING_NULL_YIELD;
|
|
563
608
|
} else {
|
|
564
|
-
const completeData = normalizeCompleteData(submitData
|
|
609
|
+
const completeData = normalizeCompleteData(submitData);
|
|
565
610
|
const { validator, error: schemaError } = buildOutputValidator(outputSchema);
|
|
566
611
|
if (schemaError) {
|
|
567
612
|
const outcome = buildSchemaViolationOutcome(
|
|
@@ -608,7 +653,7 @@ export function finalizeSubprocessOutput(args: FinalizeSubprocessOutputArgs): Fi
|
|
|
608
653
|
const hasOutputSchema = normalizedSchema !== undefined && !schemaError;
|
|
609
654
|
const fallback = allowFallback ? resolveFallbackCompletion(rawOutput, outputSchema) : null;
|
|
610
655
|
if (fallback) {
|
|
611
|
-
const completeData = normalizeCompleteData(fallback.data
|
|
656
|
+
const completeData = normalizeCompleteData(fallback.data);
|
|
612
657
|
const { validator } = buildOutputValidator(outputSchema);
|
|
613
658
|
const placeholderPath = findPlaceholderYieldPath(completeData);
|
|
614
659
|
if (placeholderPath) {
|
|
@@ -873,6 +918,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
873
918
|
let sessionEventOrdinal = 0;
|
|
874
919
|
let retryStartOrdinal = 0;
|
|
875
920
|
const seenAssistantMessages = new WeakSet<AgentMessage>();
|
|
921
|
+
let llmRequestStarted = false;
|
|
876
922
|
const seenAssistantMessageIdentities = new Set<string>();
|
|
877
923
|
|
|
878
924
|
// Accumulate usage incrementally from message_end events (no memory for streaming events)
|
|
@@ -965,7 +1011,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
965
1011
|
task,
|
|
966
1012
|
assignment,
|
|
967
1013
|
progress: progressSnapshot,
|
|
968
|
-
sessionFile:
|
|
1014
|
+
sessionFile: sessionFile ?? undefined,
|
|
969
1015
|
});
|
|
970
1016
|
}
|
|
971
1017
|
lastProgressEmitMs = Date.now();
|
|
@@ -1380,6 +1426,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
1380
1426
|
error?: string;
|
|
1381
1427
|
aborted?: boolean;
|
|
1382
1428
|
abortReason?: string;
|
|
1429
|
+
setupFailure?: SetupFailureSummary;
|
|
1383
1430
|
durationMs: number;
|
|
1384
1431
|
}> => {
|
|
1385
1432
|
const sessionAbortController = new AbortController();
|
|
@@ -1387,6 +1434,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
1387
1434
|
let error: string | undefined;
|
|
1388
1435
|
let aborted = false;
|
|
1389
1436
|
let abortReasonText: string | undefined;
|
|
1437
|
+
let setupFailure: SetupFailureSummary | undefined;
|
|
1390
1438
|
const checkAbort = () => {
|
|
1391
1439
|
if (abortSignal.aborted) {
|
|
1392
1440
|
aborted = abortReason === "signal" || runtimeLimitExceeded || abortReason === undefined;
|
|
@@ -1463,6 +1511,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
1463
1511
|
resolvedModelString = formatModelString(model);
|
|
1464
1512
|
activeProviderModelString = resolvedModelString;
|
|
1465
1513
|
}
|
|
1514
|
+
progress.fastMode = model ? (options.isFastForSubagentProvider?.(model.provider) ?? false) : false;
|
|
1466
1515
|
if (authFallbackUsed && model && requestedModel) {
|
|
1467
1516
|
modelSubstitutionWarning = {
|
|
1468
1517
|
requested: formatModelString(requestedModel),
|
|
@@ -1706,7 +1755,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
1706
1755
|
agentSource: agent.source,
|
|
1707
1756
|
description: options.description,
|
|
1708
1757
|
status: "started",
|
|
1709
|
-
sessionFile:
|
|
1758
|
+
sessionFile: sessionFile ?? undefined,
|
|
1710
1759
|
index,
|
|
1711
1760
|
});
|
|
1712
1761
|
}
|
|
@@ -1801,7 +1850,9 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
1801
1850
|
{
|
|
1802
1851
|
getModel: () => session.model,
|
|
1803
1852
|
isIdle: () => !session.isStreaming,
|
|
1853
|
+
getActivePromptHandle: () => session.activePromptHandle,
|
|
1804
1854
|
abort: () => session.abort(),
|
|
1855
|
+
abortPromptAndWait: (handle, options) => session.abortPromptAndWait(handle, options),
|
|
1805
1856
|
hasPendingMessages: () => session.queuedMessageCount > 0,
|
|
1806
1857
|
getPendingMessageCounts: () => session.pendingMessageCounts,
|
|
1807
1858
|
getTranscript: () => session.getTranscript(),
|
|
@@ -1842,11 +1893,15 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
1842
1893
|
for (const message of session.messages) {
|
|
1843
1894
|
if (message.role === "assistant") rememberAssistantMessage(message);
|
|
1844
1895
|
}
|
|
1896
|
+
const failedAssistant = session.getLastAssistantMessage();
|
|
1845
1897
|
progress.retryState = {
|
|
1846
1898
|
attempt: event.attempt,
|
|
1847
1899
|
maxAttempts: event.maxAttempts,
|
|
1848
1900
|
unbounded: event.unbounded,
|
|
1849
|
-
kind:
|
|
1901
|
+
kind: classifyProviderRetryFromTransport({
|
|
1902
|
+
providerCode: failedAssistant?.transportFailure?.providerCode,
|
|
1903
|
+
errorMessage: event.errorMessage,
|
|
1904
|
+
}),
|
|
1850
1905
|
provider: providerNameFromModel(
|
|
1851
1906
|
activeProviderModelString ?? lastAssistantModelString ?? resolvedModelString,
|
|
1852
1907
|
),
|
|
@@ -1905,16 +1960,24 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
1905
1960
|
}
|
|
1906
1961
|
}
|
|
1907
1962
|
const runMode = options.runMode ?? "initial";
|
|
1963
|
+
const markLlmRequestStarted = () => {
|
|
1964
|
+
llmRequestStarted = true;
|
|
1965
|
+
};
|
|
1966
|
+
const promptOptions = {
|
|
1967
|
+
attribution: "agent" as const,
|
|
1968
|
+
// A prompt is an LLM request only after AgentSession accepts its
|
|
1969
|
+
// preflight fence. Rejections remain setup failures.
|
|
1970
|
+
onPreflightAccepted: markLlmRequestStarted,
|
|
1971
|
+
onPreflightAcceptCommit: markLlmRequestStarted,
|
|
1972
|
+
};
|
|
1908
1973
|
if (runMode === "message") {
|
|
1909
|
-
await awaitAbortable(session.prompt(options.resumeMessage ?? "",
|
|
1974
|
+
await awaitAbortable(session.prompt(options.resumeMessage ?? "", promptOptions));
|
|
1910
1975
|
await awaitAbortable(session.waitForIdle());
|
|
1911
1976
|
} else if (runMode === "resume") {
|
|
1912
|
-
await awaitAbortable(
|
|
1913
|
-
session.prompt("Continue from the paused subagent session state.", { attribution: "agent" }),
|
|
1914
|
-
);
|
|
1977
|
+
await awaitAbortable(session.prompt("Continue from the paused subagent session state.", promptOptions));
|
|
1915
1978
|
await awaitAbortable(session.waitForIdle());
|
|
1916
1979
|
} else {
|
|
1917
|
-
await awaitAbortable(session.prompt(task,
|
|
1980
|
+
await awaitAbortable(session.prompt(task, promptOptions));
|
|
1918
1981
|
await awaitAbortable(session.waitForIdle());
|
|
1919
1982
|
}
|
|
1920
1983
|
|
|
@@ -1991,6 +2054,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
1991
2054
|
exitCode = 1;
|
|
1992
2055
|
if (!abortSignal.aborted) {
|
|
1993
2056
|
error = err instanceof Error ? err.stack || err.message : String(err);
|
|
2057
|
+
if (!llmRequestStarted) setupFailure = createSetupFailureSummary(err);
|
|
1994
2058
|
}
|
|
1995
2059
|
} finally {
|
|
1996
2060
|
if (abortSignal.aborted) {
|
|
@@ -2026,6 +2090,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2026
2090
|
error,
|
|
2027
2091
|
aborted,
|
|
2028
2092
|
abortReason: aborted ? abortReasonText : undefined,
|
|
2093
|
+
setupFailure,
|
|
2029
2094
|
durationMs: Date.now() - startTime,
|
|
2030
2095
|
};
|
|
2031
2096
|
};
|
|
@@ -2052,7 +2117,6 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2052
2117
|
let rawOutput = finalOutputChunks.length > 0 ? finalOutputChunks.join("") : outputChunks.join("");
|
|
2053
2118
|
const yieldItems = progress.extractedToolData?.yield as YieldItem[] | undefined;
|
|
2054
2119
|
const reportFindingDetails = progress.extractedToolData?.report_finding as ReportFindingDetails[] | undefined;
|
|
2055
|
-
const reportFindings: ReviewFinding[] | undefined = reportFindingDetails?.map(toReviewFinding);
|
|
2056
2120
|
const finalized = finalizeSubprocessOutput({
|
|
2057
2121
|
rawOutput,
|
|
2058
2122
|
exitCode,
|
|
@@ -2060,12 +2124,25 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2060
2124
|
doneAborted: Boolean(done.aborted),
|
|
2061
2125
|
signalAborted: Boolean(signal?.aborted),
|
|
2062
2126
|
yieldItems,
|
|
2063
|
-
reportFindings,
|
|
2064
2127
|
outputSchema,
|
|
2065
2128
|
});
|
|
2066
2129
|
rawOutput = finalized.rawOutput;
|
|
2067
2130
|
exitCode = finalized.exitCode;
|
|
2068
2131
|
stderr = finalized.stderr;
|
|
2132
|
+
let reviewFindingsRef: ReviewFindingsArtifactRef | undefined;
|
|
2133
|
+
let reviewFindingsPublicationFailed = false;
|
|
2134
|
+
if (reportFindingDetails && reportFindingDetails.length > 0) {
|
|
2135
|
+
try {
|
|
2136
|
+
const manager = options.parentArtifactManager;
|
|
2137
|
+
if (!manager) throw new Error("review findings artifact authority unavailable");
|
|
2138
|
+
reviewFindingsRef = await publishReviewFindingsArtifact(manager, id, reportFindingDetails);
|
|
2139
|
+
} catch {
|
|
2140
|
+
reviewFindingsPublicationFailed = true;
|
|
2141
|
+
exitCode = 1;
|
|
2142
|
+
stderr = REVIEW_FINDINGS_ARTIFACT_FAILURE;
|
|
2143
|
+
paused = false;
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2069
2146
|
const lastYield = yieldItems?.[yieldItems.length - 1];
|
|
2070
2147
|
const yieldAbortReason = lastYield?.status === "aborted" ? lastYield.error || "Subagent aborted task" : undefined;
|
|
2071
2148
|
const { abortedViaYield, hasYield } = finalized;
|
|
@@ -2122,7 +2199,9 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2122
2199
|
exitCode = 1;
|
|
2123
2200
|
}
|
|
2124
2201
|
const wasAborted =
|
|
2125
|
-
runtimeLimitExceeded ||
|
|
2202
|
+
runtimeLimitExceeded ||
|
|
2203
|
+
(!reviewFindingsPublicationFailed &&
|
|
2204
|
+
(abortedViaYield || (!hasYield && (done.aborted || signal?.aborted || false))));
|
|
2126
2205
|
const finalAbortReason = wasAborted
|
|
2127
2206
|
? runtimeLimitExceeded
|
|
2128
2207
|
? resolveAbortReasonText()
|
|
@@ -2130,6 +2209,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2130
2209
|
? yieldAbortReason
|
|
2131
2210
|
: (done.abortReason ?? (signal?.aborted ? resolveSignalAbortReason() : resolveAbortReasonText()))
|
|
2132
2211
|
: undefined;
|
|
2212
|
+
progress.setupFailure = done.setupFailure;
|
|
2133
2213
|
progress.status = paused ? "paused" : wasAborted ? "aborted" : exitCode === 0 ? "completed" : "failed";
|
|
2134
2214
|
scheduleProgress(true);
|
|
2135
2215
|
|
|
@@ -2141,7 +2221,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2141
2221
|
agentSource: agent.source,
|
|
2142
2222
|
description: options.description,
|
|
2143
2223
|
status: progress.status as "completed" | "failed" | "aborted" | "paused",
|
|
2144
|
-
sessionFile:
|
|
2224
|
+
sessionFile: sessionFile ?? undefined,
|
|
2145
2225
|
index,
|
|
2146
2226
|
});
|
|
2147
2227
|
}
|
|
@@ -2165,7 +2245,9 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2165
2245
|
contextWindow: progress.contextWindow,
|
|
2166
2246
|
modelOverride,
|
|
2167
2247
|
modelSubstitutionWarning,
|
|
2248
|
+
fastMode: progress.fastMode,
|
|
2168
2249
|
error: exitCode !== 0 && stderr ? stderr : undefined,
|
|
2250
|
+
setupFailure: done.setupFailure,
|
|
2169
2251
|
aborted: wasAborted,
|
|
2170
2252
|
abortReason: finalAbortReason,
|
|
2171
2253
|
paused,
|
|
@@ -2175,5 +2257,6 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2175
2257
|
extractedToolData: progress.extractedToolData,
|
|
2176
2258
|
retryFailure: progress.retryFailure,
|
|
2177
2259
|
outputMeta,
|
|
2260
|
+
reviewFindingsRef,
|
|
2178
2261
|
};
|
|
2179
2262
|
}
|
package/src/task/index.ts
CHANGED
|
@@ -19,7 +19,7 @@ import type { AgentTool, AgentToolResult, AgentToolUpdateCallback } from "@gajae
|
|
|
19
19
|
import type { Model, Usage } from "@gajae-code/ai";
|
|
20
20
|
import { $pickenv, prompt, Snowflake } from "@gajae-code/utils";
|
|
21
21
|
import type { ToolSession } from "..";
|
|
22
|
-
import { AsyncJobManager, OwnerSubagentShutdownError, type ResumeRunner } from "../async";
|
|
22
|
+
import { AsyncJobManager, OwnerSubagentShutdownError, type ResumeRunner, type SubagentRunOutcome } from "../async";
|
|
23
23
|
import { resolveAgentModelPatterns } from "../config/model-resolver";
|
|
24
24
|
import type { Theme } from "../modes/theme/theme";
|
|
25
25
|
import planModeSubagentPrompt from "../prompts/system/plan-mode-subagent.md" with { type: "text" };
|
|
@@ -98,6 +98,23 @@ function isTaskResumeDescriptor(value: unknown): value is TaskResumeDescriptor {
|
|
|
98
98
|
function renderTaskAssignment(assignment: string, simpleMode: TaskSimpleMode): string {
|
|
99
99
|
return renderSubagentUserPrompt(assignment, simpleMode === "independent");
|
|
100
100
|
}
|
|
101
|
+
|
|
102
|
+
export function subagentRunOutcomeFromSingleResult(
|
|
103
|
+
finalText: string,
|
|
104
|
+
singleResult: Pick<SingleResult, "aborted" | "exitCode" | "paused" | "setupFailure"> | undefined,
|
|
105
|
+
): string | SubagentRunOutcome {
|
|
106
|
+
if (singleResult?.paused) return { kind: "paused" };
|
|
107
|
+
if (singleResult && ((singleResult.aborted ?? false) || singleResult.exitCode !== 0)) {
|
|
108
|
+
return {
|
|
109
|
+
kind: "failed",
|
|
110
|
+
text: finalText,
|
|
111
|
+
...(singleResult.setupFailure && !singleResult.aborted
|
|
112
|
+
? { setupFailureSummary: singleResult.setupFailure.summary }
|
|
113
|
+
: {}),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return finalText;
|
|
117
|
+
}
|
|
101
118
|
function createUsageTotals(): Usage {
|
|
102
119
|
return {
|
|
103
120
|
input: 0,
|
|
@@ -655,15 +672,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
655
672
|
);
|
|
656
673
|
const finalText = result.content.find(part => part.type === "text")?.text ?? "(no output)";
|
|
657
674
|
const singleResult = result.details?.results[0];
|
|
658
|
-
|
|
659
|
-
// A resumed subprocess that aborted or exited non-zero is a failed
|
|
660
|
-
// resume, not a completed one. Throw the rendered failure summary
|
|
661
|
-
// (finalText) so the leg is reported failed instead of being
|
|
662
|
-
// returned as successful continuation.
|
|
663
|
-
if (singleResult && ((singleResult.aborted ?? false) || singleResult.exitCode !== 0)) {
|
|
664
|
-
throw new Error(finalText);
|
|
665
|
-
}
|
|
666
|
-
return finalText;
|
|
675
|
+
return subagentRunOutcomeFromSingleResult(finalText, singleResult);
|
|
667
676
|
},
|
|
668
677
|
{
|
|
669
678
|
id: `${descriptor.task.id}-resume-${Snowflake.next()}`,
|
|
@@ -809,6 +818,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
809
818
|
}
|
|
810
819
|
: undefined;
|
|
811
820
|
progress.retryState = undefined;
|
|
821
|
+
progress.setupFailure = singleResult?.setupFailure;
|
|
812
822
|
}
|
|
813
823
|
completedJobs += 1;
|
|
814
824
|
if (singleResult && ((singleResult.aborted ?? false) || singleResult.exitCode !== 0)) {
|
|
@@ -831,10 +841,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
831
841
|
`Background task batch complete: ${completedJobs}/${taskItems.length} finished.`,
|
|
832
842
|
);
|
|
833
843
|
}
|
|
834
|
-
|
|
835
|
-
return { kind: "paused" };
|
|
836
|
-
}
|
|
837
|
-
return finalText;
|
|
844
|
+
return subagentRunOutcomeFromSingleResult(finalText, singleResult);
|
|
838
845
|
} catch (error) {
|
|
839
846
|
if (progress) {
|
|
840
847
|
progress.status = "failed";
|
|
@@ -1481,6 +1488,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1481
1488
|
agentRegistry: this.session.agentRegistry,
|
|
1482
1489
|
settings: this.session.settings,
|
|
1483
1490
|
inheritedServiceTier: this.session.serviceTier,
|
|
1491
|
+
isFastForSubagentProvider: provider => this.session.isFastForSubagentProvider?.(provider) ?? false,
|
|
1484
1492
|
contextFiles,
|
|
1485
1493
|
skills: availableSkills,
|
|
1486
1494
|
autoloadSkills: resolvedAutoloadSkills,
|
|
@@ -1554,6 +1562,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1554
1562
|
agentRegistry: this.session.agentRegistry,
|
|
1555
1563
|
settings: this.session.settings,
|
|
1556
1564
|
inheritedServiceTier: this.session.serviceTier,
|
|
1565
|
+
isFastForSubagentProvider: provider => this.session.isFastForSubagentProvider?.(provider) ?? false,
|
|
1557
1566
|
contextFiles,
|
|
1558
1567
|
skills: availableSkills,
|
|
1559
1568
|
autoloadSkills: resolvedAutoloadSkills,
|
|
@@ -4,8 +4,24 @@ export type ProviderRetryKind = NonNullable<AgentProgress["retryState"]>["kind"]
|
|
|
4
4
|
|
|
5
5
|
const FIRST_EVENT_TIMEOUT_PATTERN = /stream timed out while waiting for the first event/i;
|
|
6
6
|
const IDLE_STREAM_STALL_PATTERN = /stream stalled while waiting for the next event/i;
|
|
7
|
+
const STREAM_FIRST_EVENT_TIMEOUT_PROVIDER_CODE = "stream_first_event_timeout";
|
|
7
8
|
|
|
8
9
|
export function classifyProviderRetry(errorMessage: string): ProviderRetryKind {
|
|
10
|
+
return classifyProviderRetryFromTransport({ errorMessage });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Prefer typed transport facts when present; fall back to message regex for
|
|
15
|
+
* message-only callers that never received `transportFailure.providerCode`.
|
|
16
|
+
*/
|
|
17
|
+
export function classifyProviderRetryFromTransport(facts: {
|
|
18
|
+
providerCode?: string;
|
|
19
|
+
errorMessage?: string;
|
|
20
|
+
}): ProviderRetryKind {
|
|
21
|
+
if (facts.providerCode?.toLowerCase() === STREAM_FIRST_EVENT_TIMEOUT_PROVIDER_CODE) {
|
|
22
|
+
return "first_event_timeout";
|
|
23
|
+
}
|
|
24
|
+
const errorMessage = facts.errorMessage ?? "";
|
|
9
25
|
if (FIRST_EVENT_TIMEOUT_PATTERN.test(errorMessage)) return "first_event_timeout";
|
|
10
26
|
if (IDLE_STREAM_STALL_PATTERN.test(errorMessage)) return "idle_stream_stall";
|
|
11
27
|
return "provider_error";
|
package/src/task/receipt.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
hasCompleteUsageCostBreakdown,
|
|
3
|
+
type ReviewFindingsArtifactRef,
|
|
4
|
+
type SingleResult,
|
|
5
|
+
type TaskToolDetails,
|
|
6
|
+
} from "./types";
|
|
2
7
|
export interface TaskRoi {
|
|
3
8
|
tokens: number;
|
|
4
9
|
contextTokens?: number;
|
|
@@ -29,11 +34,13 @@ export interface TaskResultReceipt {
|
|
|
29
34
|
contextWindow?: number;
|
|
30
35
|
modelOverride?: string | string[];
|
|
31
36
|
modelSubstitutionWarning?: SingleResult["modelSubstitutionWarning"];
|
|
37
|
+
fastMode?: boolean;
|
|
32
38
|
usage?: SingleResult["usage"];
|
|
33
39
|
cost?: number;
|
|
34
40
|
usageCostBreakdownComplete?: true;
|
|
35
41
|
branchName?: string;
|
|
36
42
|
retryFailure?: { attempt: number; errorSummary: string };
|
|
43
|
+
setupFailure?: { summary: string };
|
|
37
44
|
errorSummary?: string;
|
|
38
45
|
abortSummary?: string;
|
|
39
46
|
preview: string;
|
|
@@ -44,6 +51,8 @@ export interface TaskResultReceipt {
|
|
|
44
51
|
overallCorrectness?: string;
|
|
45
52
|
findingCount: number;
|
|
46
53
|
findings?: Array<{ severity?: string; summary: string }>;
|
|
54
|
+
/** Canonical full-fidelity findings; inline summaries are display-only. */
|
|
55
|
+
findingsRef?: ReviewFindingsArtifactRef;
|
|
47
56
|
};
|
|
48
57
|
extractedToolCounts?: Record<string, number>;
|
|
49
58
|
forkContext?: SingleResult["forkContext"];
|
|
@@ -103,6 +112,9 @@ function normalizeReviewFindingSeverity(severity: unknown, priority: unknown): s
|
|
|
103
112
|
|
|
104
113
|
function buildSafeSynopsis(raw: SingleResult, outputRef: TaskResultReceipt["outputRef"]): string {
|
|
105
114
|
const status = getStatus(raw);
|
|
115
|
+
if (raw.setupFailure) {
|
|
116
|
+
return `Task ${status} during setup: ${raw.setupFailure.summary}`;
|
|
117
|
+
}
|
|
106
118
|
if (raw.modelSubstitutionWarning) {
|
|
107
119
|
return `Task ${status}; requested model substituted from ${raw.modelSubstitutionWarning.requested} to ${raw.modelSubstitutionWarning.effective}.`;
|
|
108
120
|
}
|
|
@@ -131,32 +143,34 @@ function getStatus(raw: SingleResult): TaskResultReceipt["status"] {
|
|
|
131
143
|
|
|
132
144
|
function buildReview(raw: SingleResult): TaskResultReceipt["review"] | undefined {
|
|
133
145
|
const data = raw.extractedToolData;
|
|
134
|
-
|
|
135
|
-
const yields = Array.isArray(data
|
|
146
|
+
const findingsRef = raw.reviewFindingsRef;
|
|
147
|
+
const yields = Array.isArray(data?.yield) ? data.yield : [];
|
|
136
148
|
const reviewYield = yields
|
|
137
149
|
.map(item => (item && typeof item === "object" ? (item as { data?: unknown }).data : undefined))
|
|
138
150
|
.findLast(item => item && typeof item === "object" && "overall_correctness" in item) as
|
|
139
151
|
| { overall_correctness?: unknown }
|
|
140
152
|
| undefined;
|
|
141
|
-
const rawFindings = Array.isArray(data
|
|
153
|
+
const rawFindings = Array.isArray(data?.report_finding) ? data.report_finding : [];
|
|
142
154
|
const findings = rawFindings.slice(0, 20).map(item => {
|
|
143
155
|
const value = item && typeof item === "object" ? (item as Record<string, unknown>) : {};
|
|
144
156
|
const severity = normalizeReviewFindingSeverity(value.severity, value.priority);
|
|
145
157
|
const summaryValue = value.summary ?? value.title ?? value.message ?? value.body ?? "finding";
|
|
146
158
|
return { severity, summary: truncateText(String(summaryValue), 200) ?? "finding" };
|
|
147
159
|
});
|
|
148
|
-
if (!reviewYield && findings.length === 0) return undefined;
|
|
160
|
+
if (!reviewYield && findings.length === 0 && !findingsRef) return undefined;
|
|
149
161
|
return {
|
|
150
162
|
overallCorrectness: truncateText(
|
|
151
163
|
typeof reviewYield?.overall_correctness === "string" ? reviewYield.overall_correctness : undefined,
|
|
152
164
|
200,
|
|
153
165
|
),
|
|
154
|
-
findingCount: rawFindings.length,
|
|
166
|
+
findingCount: findingsRef?.findingCount ?? rawFindings.length,
|
|
155
167
|
findings: findings.length > 0 ? findings : undefined,
|
|
168
|
+
findingsRef,
|
|
156
169
|
};
|
|
157
170
|
}
|
|
158
171
|
|
|
159
172
|
function hasReviewFindings(raw: SingleResult): boolean {
|
|
173
|
+
if (raw.reviewFindingsRef) return true;
|
|
160
174
|
const findings = raw.extractedToolData?.report_finding;
|
|
161
175
|
return Array.isArray(findings) && findings.length > 0;
|
|
162
176
|
}
|
|
@@ -251,10 +265,12 @@ export function buildTaskReceipt(raw: SingleResult): TaskResultReceipt {
|
|
|
251
265
|
usageCostBreakdownComplete:
|
|
252
266
|
raw.usageCostBreakdownComplete === true && hasCompleteUsageCostBreakdown(raw.usage) ? true : undefined,
|
|
253
267
|
branchName: raw.branchName,
|
|
268
|
+
fastMode: raw.fastMode,
|
|
254
269
|
retryFailure: raw.retryFailure
|
|
255
270
|
? { attempt: raw.retryFailure.attempt, errorSummary: "Retry failure recorded." }
|
|
256
271
|
: undefined,
|
|
257
|
-
errorSummary: raw.error ? "Error recorded." : undefined,
|
|
272
|
+
errorSummary: raw.setupFailure?.summary ?? (raw.error ? "Error recorded." : undefined),
|
|
273
|
+
setupFailure: raw.setupFailure ? { summary: raw.setupFailure.summary } : undefined,
|
|
258
274
|
abortSummary: raw.abortReason ? "Abort reason recorded." : undefined,
|
|
259
275
|
preview,
|
|
260
276
|
previewTruncated: false,
|
package/src/task/render.ts
CHANGED
|
@@ -561,7 +561,7 @@ function renderAgentProgress(
|
|
|
561
561
|
const description = progress.description?.trim();
|
|
562
562
|
const displayId = formatTaskId(progress.id);
|
|
563
563
|
const titlePart = description ? `${theme.bold(displayId)}: ${description}` : displayId;
|
|
564
|
-
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)}`;
|
|
564
|
+
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)}${progress.fastMode && theme.icon.fast ? ` ${theme.icon.fast}` : ""}`;
|
|
565
565
|
|
|
566
566
|
// A provider recovery loop is operationally distinct from normal agent work.
|
|
567
567
|
if (progress.retryState && progress.status === "running") {
|
|
@@ -594,6 +594,10 @@ function renderAgentProgress(
|
|
|
594
594
|
)}`,
|
|
595
595
|
);
|
|
596
596
|
}
|
|
597
|
+
if (progress.setupFailure && progress.status !== "running") {
|
|
598
|
+
const summary = `Setup failure: ${truncateToWidth(replaceTabs(progress.setupFailure.summary), 80)}`;
|
|
599
|
+
lines.push(`${continuePrefix}${theme.tree.hook} ${theme.fg("error", summary)}`);
|
|
600
|
+
}
|
|
597
601
|
|
|
598
602
|
// Current tool (if running) or most recent completed tool
|
|
599
603
|
if (progress.status === "running") {
|
|
@@ -862,7 +866,7 @@ function renderAgentResult(result: TaskResultReceipt, isLast: boolean, expanded:
|
|
|
862
866
|
const description = result.description?.trim();
|
|
863
867
|
const displayId = formatTaskId(result.id);
|
|
864
868
|
const titlePart = description ? `${theme.bold(displayId)}: ${description}` : displayId;
|
|
865
|
-
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)} ${formatBadge(
|
|
869
|
+
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)}${result.fastMode && theme.icon.fast ? ` ${theme.icon.fast}` : ""} ${formatBadge(
|
|
866
870
|
statusText,
|
|
867
871
|
iconColor,
|
|
868
872
|
theme,
|