mixdog 0.9.38 → 0.9.39
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/package.json +9 -4
- package/scripts/abort-recovery-test.mjs +43 -2
- package/scripts/agent-tag-reuse-smoke.mjs +146 -6
- package/scripts/agent-terminal-reap-test.mjs +127 -0
- package/scripts/agent-trace-io-test.mjs +69 -0
- package/scripts/code-graph-disk-hit-test.mjs +224 -0
- package/scripts/execution-completion-dedup-test.mjs +157 -0
- package/scripts/execution-pending-resume-kick-test.mjs +57 -2
- package/scripts/execution-resume-esc-integration-test.mjs +174 -0
- package/scripts/explore-bench.mjs +38 -2
- package/scripts/explore-prompt-policy-test.mjs +152 -11
- package/scripts/find-fuzzy-hidden-test.mjs +122 -0
- package/scripts/internal-comms-bench-test.mjs +226 -0
- package/scripts/internal-comms-bench.mjs +185 -58
- package/scripts/internal-comms-smoke.mjs +171 -23
- package/scripts/live-worker-smoke.mjs +38 -2
- package/scripts/memory-cycle-routing-test.mjs +111 -0
- package/scripts/memory-rule-contract-test.mjs +93 -0
- package/scripts/output-style-smoke.mjs +2 -2
- package/scripts/rg-runner-test.mjs +240 -0
- package/scripts/routing-corpus-test.mjs +349 -0
- package/scripts/routing-corpus.mjs +211 -32
- package/scripts/session-orphan-sweep-test.mjs +83 -0
- package/scripts/steering-drain-buckets-test.mjs +179 -0
- package/scripts/tool-smoke.mjs +21 -13
- package/scripts/tool-tui-presentation-test.mjs +202 -0
- package/src/agents/heavy-worker/AGENT.md +10 -7
- package/src/agents/reviewer/AGENT.md +6 -4
- package/src/agents/worker/AGENT.md +7 -5
- package/src/rules/agent/00-common.md +4 -4
- package/src/rules/agent/00-core.md +11 -14
- package/src/rules/agent/20-skip-protocol.md +3 -3
- package/src/rules/agent/30-explorer.md +50 -60
- package/src/rules/agent/40-cycle1-agent.md +15 -24
- package/src/rules/agent/41-cycle2-agent.md +33 -57
- package/src/rules/agent/42-cycle3-agent.md +28 -42
- package/src/rules/lead/01-general.md +7 -10
- package/src/rules/lead/lead-brief.md +11 -14
- package/src/rules/lead/lead-tool.md +6 -5
- package/src/rules/shared/01-tool.md +44 -45
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +37 -1
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +20 -5
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +21 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +17 -38
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +17 -8
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +270 -78
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/delivered-completions.mjs +123 -0
- package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +15 -2
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +41 -2
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store.mjs +223 -42
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +25 -20
- package/src/runtime/agent/orchestrator/tools/builtin/fs-reachability.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +118 -53
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +106 -29
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +8 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +33 -2
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +151 -64
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +37 -13
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +84 -49
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +172 -23
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +3 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +68 -5
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +17 -3
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +24 -10
- package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +4 -7
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +1 -0
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +4 -4
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +4 -3
- package/src/runtime/memory/lib/memory-cycle3.mjs +12 -2
- package/src/runtime/shared/tool-primitives.mjs +4 -1
- package/src/runtime/shared/tool-status.mjs +27 -0
- package/src/runtime/shared/tool-surface.mjs +6 -3
- package/src/session-runtime/config-helpers.mjs +14 -0
- package/src/session-runtime/context-status.mjs +1 -0
- package/src/session-runtime/effort.mjs +6 -2
- package/src/session-runtime/model-recency.mjs +5 -2
- package/src/session-runtime/runtime-core.mjs +35 -2
- package/src/session-runtime/tool-catalog.mjs +34 -0
- package/src/standalone/agent-tool/notify.mjs +13 -0
- package/src/standalone/agent-tool.mjs +45 -69
- package/src/standalone/explore-tool.mjs +6 -7
- package/src/tui/App.jsx +31 -0
- package/src/tui/app/model-options.mjs +5 -3
- package/src/tui/app/model-picker.mjs +12 -24
- package/src/tui/app/transcript-window.mjs +1 -0
- package/src/tui/components/ToolExecution.jsx +11 -6
- package/src/tui/components/TranscriptItem.jsx +1 -1
- package/src/tui/components/tool-execution/surface-detail.mjs +24 -10
- package/src/tui/components/tool-execution/text-format.mjs +10 -19
- package/src/tui/dist/index.mjs +517 -142
- package/src/tui/engine/agent-job-feed.mjs +144 -17
- package/src/tui/engine/agent-response-tail.mjs +68 -0
- package/src/tui/engine/notification-plan.mjs +16 -0
- package/src/tui/engine/session-api.mjs +8 -2
- package/src/tui/engine/session-flow.mjs +19 -1
- package/src/tui/engine/tool-card-results.mjs +54 -32
- package/src/tui/engine/tool-result-status.mjs +75 -21
- package/src/tui/engine/turn.mjs +77 -42
- package/src/tui/engine.mjs +63 -2
- package/src/workflows/bench/WORKFLOW.md +25 -35
- package/src/workflows/default/WORKFLOW.md +38 -32
- package/src/workflows/solo/WORKFLOW.md +19 -22
- package/scripts/_jitter-fuzz.mjs +0 -44410
- package/scripts/_jitter-fuzz2.mjs +0 -44400
- package/scripts/_jitter-probe.mjs +0 -44397
- package/scripts/_jp2.mjs +0 -45614
package/src/tui/dist/index.mjs
CHANGED
|
@@ -1976,10 +1976,11 @@ function bridgeAgentModelSummary(args) {
|
|
|
1976
1976
|
]);
|
|
1977
1977
|
}
|
|
1978
1978
|
function summarizeLineWindow(a) {
|
|
1979
|
+
const hasOffset = a.offset != null;
|
|
1979
1980
|
const offset = a.offset ?? a.start_line ?? a.startLine ?? a.line;
|
|
1980
1981
|
const limit = a.limit ?? a.line_count ?? a.lineCount ?? a.lines;
|
|
1981
1982
|
if (offset == null && limit == null) return "";
|
|
1982
|
-
const start = Number(offset);
|
|
1983
|
+
const start = Number(offset) + (hasOffset ? 1 : 0);
|
|
1983
1984
|
const count = Number(limit);
|
|
1984
1985
|
if (Number.isFinite(start) && Number.isFinite(count) && count > 0) {
|
|
1985
1986
|
return `lines ${start}-${Math.max(start, start + count - 1)}`;
|
|
@@ -2839,7 +2840,9 @@ function toolWorkUnit(name, args = {}, category = "") {
|
|
|
2839
2840
|
case "read_mcp_resource":
|
|
2840
2841
|
return unitDescriptor("Read", { count: queryCount(a, "uri", "uris") || 1, noun: "resource" });
|
|
2841
2842
|
case "apply_patch": {
|
|
2842
|
-
const
|
|
2843
|
+
const patchText = String(a.patch ?? "");
|
|
2844
|
+
const creating = a.old_string === "" || /^\*\*\*\s+Add File:/mi.test(patchText);
|
|
2845
|
+
const deleting = !creating && a.new_string === "" && a.old_string != null || /^\*\*\*\s+Delete File:/mi.test(patchText);
|
|
2843
2846
|
if (a.dry_run === true) {
|
|
2844
2847
|
return unitDescriptor("Patch", {
|
|
2845
2848
|
count: patchFileCount(a) || 1,
|
|
@@ -2850,8 +2853,8 @@ function toolWorkUnit(name, args = {}, category = "") {
|
|
|
2850
2853
|
}
|
|
2851
2854
|
return unitDescriptor("Patch", {
|
|
2852
2855
|
count: patchFileCount(a) || 1,
|
|
2853
|
-
active: creating ? "Creating" : "Editing",
|
|
2854
|
-
done: creating ? "Created" : "Edited",
|
|
2856
|
+
active: creating ? "Creating" : deleting ? "Deleting" : "Editing",
|
|
2857
|
+
done: creating ? "Created" : deleting ? "Deleted" : "Edited",
|
|
2855
2858
|
noun: "file"
|
|
2856
2859
|
});
|
|
2857
2860
|
}
|
|
@@ -10233,6 +10236,7 @@ function toolHasDisplayResultForRows(item) {
|
|
|
10233
10236
|
}
|
|
10234
10237
|
function toolExpandedRawTextForRows(item, rawRt) {
|
|
10235
10238
|
if (item?.aggregate) return rawRt;
|
|
10239
|
+
if (item?.agentResponseAggregate) return rawRt;
|
|
10236
10240
|
const hasDisplayResult = toolHasDisplayResultForRows(item);
|
|
10237
10241
|
if (hasDisplayResult) return toolDisplayedResultTextForRows(item);
|
|
10238
10242
|
return stripLeadingStatusMarkerFromTextForRows(rawRt || "");
|
|
@@ -12383,10 +12387,11 @@ var compareModelRecency = (a, b) => {
|
|
|
12383
12387
|
}
|
|
12384
12388
|
const ta = releaseTime(a);
|
|
12385
12389
|
const tb = releaseTime(b);
|
|
12386
|
-
if (ta !== tb) return tb - ta;
|
|
12387
|
-
if (!!a?.latest !== !!b?.latest) return a?.latest ? -1 : 1;
|
|
12388
12390
|
const versionDelta = compareModelVersion(a, b);
|
|
12391
|
+
if (ta > 0 && tb > 0 && ta !== tb) return tb - ta;
|
|
12389
12392
|
if (versionDelta) return versionDelta;
|
|
12393
|
+
if (!!a?.latest !== !!b?.latest) return a?.latest ? -1 : 1;
|
|
12394
|
+
if (ta !== tb) return tb - ta;
|
|
12390
12395
|
return String(a?.display || a?.id || "").localeCompare(String(b?.display || b?.id || ""));
|
|
12391
12396
|
};
|
|
12392
12397
|
var modelFamily = (m) => {
|
|
@@ -15835,11 +15840,9 @@ function createModelPicker({
|
|
|
15835
15840
|
setChannelPrompt(null);
|
|
15836
15841
|
setHookPrompt(null);
|
|
15837
15842
|
setSettingsPrompt(null);
|
|
15838
|
-
|
|
15843
|
+
modelPickerRequestRef.current += 1;
|
|
15839
15844
|
let modelPickerClosed = false;
|
|
15840
|
-
let activeModelProvider = null;
|
|
15841
15845
|
let providerListHighlightProvider = null;
|
|
15842
|
-
const isActiveModelPicker = () => !modelPickerClosed && modelPickerRequestRef.current === modelPickerRequest;
|
|
15843
15846
|
const returnTo = typeof options.returnTo === "function" ? options.returnTo : null;
|
|
15844
15847
|
const returnLabel = String(options.returnLabel || "Agents");
|
|
15845
15848
|
const returnOnNestedCancel = options.returnOnNestedCancel === true;
|
|
@@ -15853,7 +15856,6 @@ function createModelPicker({
|
|
|
15853
15856
|
let providerModels = Array.isArray(cacheRef.current.models) ? cacheRef.current.models : [];
|
|
15854
15857
|
let refreshModelsPromise = null;
|
|
15855
15858
|
let renderedQuickModels = false;
|
|
15856
|
-
let renderActiveProviderModels = null;
|
|
15857
15859
|
if (!providerModels.length || options.refreshModels === true) {
|
|
15858
15860
|
setPicker({
|
|
15859
15861
|
title: options.title || "Model",
|
|
@@ -15904,16 +15906,12 @@ function createModelPicker({
|
|
|
15904
15906
|
providerListHighlightProvider = renderOptions.highlightProvider;
|
|
15905
15907
|
}
|
|
15906
15908
|
const highlightProvider = renderOptions.highlightProvider || providerListHighlightProvider || null;
|
|
15907
|
-
activeModelProvider = null;
|
|
15908
|
-
renderActiveProviderModels = null;
|
|
15909
15909
|
const openProviderModelsPicker = (provider) => {
|
|
15910
15910
|
if (!provider) return;
|
|
15911
|
-
activeModelProvider = provider;
|
|
15912
|
-
renderActiveProviderModels = () => openProviderModelsPicker(provider);
|
|
15913
15911
|
const providerModels2 = models.filter((model) => model.provider === provider);
|
|
15914
15912
|
const preferredEffort = (values = []) => {
|
|
15915
15913
|
const allowed = values.filter(Boolean);
|
|
15916
|
-
for (const value of ["high", "medium", "low", "none", "xhigh", "max"]) {
|
|
15914
|
+
for (const value of ["high", "medium", "low", "none", "xhigh", "max", "ultra"]) {
|
|
15917
15915
|
if (allowed.includes(value)) return value;
|
|
15918
15916
|
}
|
|
15919
15917
|
return allowed[0] || null;
|
|
@@ -15986,6 +15984,7 @@ ${model?.id || ""}`;
|
|
|
15986
15984
|
if (value === "medium") return "\u25D1";
|
|
15987
15985
|
if (value === "high") return "\u25D5";
|
|
15988
15986
|
if (value === "max") return "\u25C6";
|
|
15987
|
+
if (value === "ultra") return "\u2726";
|
|
15989
15988
|
return "\u25CF";
|
|
15990
15989
|
};
|
|
15991
15990
|
const effortColor = (value) => {
|
|
@@ -15994,6 +15993,7 @@ ${model?.id || ""}`;
|
|
|
15994
15993
|
if (value === "medium") return theme.claude;
|
|
15995
15994
|
if (value === "high") return theme.error;
|
|
15996
15995
|
if (value === "max") return theme.permission;
|
|
15996
|
+
if (value === "ultra") return theme.permission;
|
|
15997
15997
|
return theme.error;
|
|
15998
15998
|
};
|
|
15999
15999
|
const modelFooter = (model = null) => {
|
|
@@ -16128,33 +16128,23 @@ ${model?.id || ""}`;
|
|
|
16128
16128
|
});
|
|
16129
16129
|
};
|
|
16130
16130
|
renderModelPicker();
|
|
16131
|
-
const
|
|
16132
|
-
if (!isActiveModelPicker()) return;
|
|
16131
|
+
const adoptFreshModels = (freshModels) => {
|
|
16133
16132
|
if (!Array.isArray(freshModels) || freshModels.length === 0) return;
|
|
16134
|
-
|
|
16135
|
-
models = normalizeModelOptions(providerModels);
|
|
16136
|
-
cacheRef.current = { models: providerModels, at: Date.now() };
|
|
16137
|
-
if (activeModelProvider === null) {
|
|
16138
|
-
renderModelPicker();
|
|
16139
|
-
} else if (typeof renderActiveProviderModels === "function") {
|
|
16140
|
-
renderActiveProviderModels();
|
|
16141
|
-
}
|
|
16133
|
+
cacheRef.current = { models: freshModels, at: Date.now() };
|
|
16142
16134
|
};
|
|
16143
16135
|
if (renderedQuickModels && refreshModelsPromise) {
|
|
16144
|
-
void refreshModelsPromise.then(
|
|
16136
|
+
void refreshModelsPromise.then(adoptFreshModels).catch(() => {
|
|
16145
16137
|
});
|
|
16146
16138
|
} else if (cacheIsStale) {
|
|
16147
16139
|
if (!providerModelsTtlRefreshPromise) {
|
|
16148
16140
|
providerModelsTtlRefreshPromise = Promise.resolve(loadModels({ force: true })).then((freshModels) => {
|
|
16149
|
-
|
|
16150
|
-
cacheRef.current = { models: freshModels, at: Date.now() };
|
|
16151
|
-
}
|
|
16141
|
+
adoptFreshModels(freshModels);
|
|
16152
16142
|
return freshModels;
|
|
16153
16143
|
}).finally(() => {
|
|
16154
16144
|
providerModelsTtlRefreshPromise = null;
|
|
16155
16145
|
});
|
|
16156
16146
|
}
|
|
16157
|
-
void providerModelsTtlRefreshPromise.
|
|
16147
|
+
void providerModelsTtlRefreshPromise.catch(() => {
|
|
16158
16148
|
});
|
|
16159
16149
|
}
|
|
16160
16150
|
};
|
|
@@ -18531,6 +18521,29 @@ import stringWidth9 from "string-width";
|
|
|
18531
18521
|
|
|
18532
18522
|
// src/tui/components/tool-execution/text-format.mjs
|
|
18533
18523
|
import stripAnsi6 from "strip-ansi";
|
|
18524
|
+
|
|
18525
|
+
// src/runtime/shared/tool-status.mjs
|
|
18526
|
+
function normalizeToolTerminalStatus(value) {
|
|
18527
|
+
const raw = String(value || "").trim().toLowerCase();
|
|
18528
|
+
if (!raw) return "";
|
|
18529
|
+
if (/^(running|pending|queued|in_progress|in-progress)$/.test(raw)) return "running";
|
|
18530
|
+
if (/^(completed|complete|done|success|succeeded|ok)$/.test(raw)) return "completed";
|
|
18531
|
+
if (/^(failed|fail|error|errored|timeout|timed_out|killed)$/.test(raw)) return "failed";
|
|
18532
|
+
if (/^(cancelled|canceled|cancel)$/.test(raw)) return "cancelled";
|
|
18533
|
+
if (/^(denied|deny|refused|rejected)$/.test(raw)) return "denied";
|
|
18534
|
+
return "";
|
|
18535
|
+
}
|
|
18536
|
+
function toolResultTerminalStatus(text) {
|
|
18537
|
+
const body = String(text || "");
|
|
18538
|
+
const tagged = body.match(/<status[^>]*>([\s\S]*?)<\/status>/i)?.[1]?.trim();
|
|
18539
|
+
if (tagged) return normalizeToolTerminalStatus(tagged);
|
|
18540
|
+
const bracketed = body.match(/^\[status:\s*([^\]]*)\]/mi)?.[1]?.trim();
|
|
18541
|
+
if (bracketed) return normalizeToolTerminalStatus(bracketed);
|
|
18542
|
+
const inline = body.match(/^(?:status|state):\s*([^\s·,;]+)/mi)?.[1]?.trim();
|
|
18543
|
+
return normalizeToolTerminalStatus(inline);
|
|
18544
|
+
}
|
|
18545
|
+
|
|
18546
|
+
// src/tui/components/tool-execution/text-format.mjs
|
|
18534
18547
|
var MIN_RESULT_LINE_CHARS = 24;
|
|
18535
18548
|
var RESULT_LINE_HARD_MAX = 80;
|
|
18536
18549
|
var SUMMARY_MAX_CHARS = 48;
|
|
@@ -18600,30 +18613,20 @@ function shellResultStatus(value) {
|
|
|
18600
18613
|
return match ? String(match[1] || "").toLowerCase() : "";
|
|
18601
18614
|
}
|
|
18602
18615
|
function normalizeTerminalStatus(value) {
|
|
18603
|
-
|
|
18604
|
-
if (!raw) return "";
|
|
18605
|
-
if (/^(running|pending|queued|in_progress|in-progress)$/.test(raw)) return "running";
|
|
18606
|
-
if (/^(completed|complete|done|success|succeeded|ok)$/.test(raw)) return "completed";
|
|
18607
|
-
if (/^(failed|fail|error|errored|timeout|timed_out|killed)$/.test(raw)) return "failed";
|
|
18608
|
-
if (/^(cancelled|canceled|cancel)$/.test(raw)) return "cancelled";
|
|
18609
|
-
return "";
|
|
18616
|
+
return normalizeToolTerminalStatus(value);
|
|
18610
18617
|
}
|
|
18611
18618
|
function displayTerminalStatus(value) {
|
|
18619
|
+
if (String(value || "").trim().toLowerCase() === "exit") return "Exit";
|
|
18612
18620
|
const status = normalizeTerminalStatus(value);
|
|
18613
18621
|
if (status === "running") return "Running";
|
|
18614
18622
|
if (status === "completed") return "Finished";
|
|
18615
18623
|
if (status === "failed") return "Failed";
|
|
18616
18624
|
if (status === "cancelled") return "Cancelled";
|
|
18625
|
+
if (status === "denied") return "Denied";
|
|
18617
18626
|
return "";
|
|
18618
18627
|
}
|
|
18619
18628
|
function resultTerminalStatus(value) {
|
|
18620
|
-
|
|
18621
|
-
const tagged = text.match(/<status[^>]*>([\s\S]*?)<\/status>/i)?.[1]?.trim();
|
|
18622
|
-
if (tagged) return normalizeTerminalStatus(tagged);
|
|
18623
|
-
const bracketed = text.match(/^\[status:\s*([^\]]*)\]/mi)?.[1]?.trim();
|
|
18624
|
-
if (bracketed) return normalizeTerminalStatus(bracketed);
|
|
18625
|
-
const inline = text.match(/^(?:status|state):\s*([^\s·,;]+)/mi)?.[1]?.trim();
|
|
18626
|
-
return normalizeTerminalStatus(inline);
|
|
18629
|
+
return toolResultTerminalStatus(value);
|
|
18627
18630
|
}
|
|
18628
18631
|
var LEADING_STATUS_MARKER_LINE_RE2 = /^\[status:\s*[^\]]*\]\s*$/i;
|
|
18629
18632
|
function stripLeadingStatusMarkerLines(lines) {
|
|
@@ -18647,11 +18650,15 @@ function isShellTool(normalizedName, label = "") {
|
|
|
18647
18650
|
const l = String(label || "").toLowerCase();
|
|
18648
18651
|
return n === "shell" || n === "bash" || n === "bash_session" || n === "shell_command" || n === "job_wait" || l === "run";
|
|
18649
18652
|
}
|
|
18650
|
-
function shellDisplayStatus({ pending = false, failedCount = 0, isError = false, result = "" } = {}) {
|
|
18653
|
+
function shellDisplayStatus({ pending = false, failedCount = 0, exitFailedCount = 0, isError = false, result = "" } = {}) {
|
|
18651
18654
|
const status = shellResultStatus(result);
|
|
18652
18655
|
if (pending || /^(running|pending|queued)$/.test(status)) return "running";
|
|
18653
18656
|
if (/^cancel/.test(status)) return "cancelled";
|
|
18654
|
-
if (/^(failed|error|killed|timeout)$/.test(status)
|
|
18657
|
+
if (/^(failed|error|killed|timeout)$/.test(status)) return "failed";
|
|
18658
|
+
const realFailed = Math.max(0, Number(failedCount) - Number(exitFailedCount));
|
|
18659
|
+
if (realFailed > 0) return "failed";
|
|
18660
|
+
if (Number(exitFailedCount) > 0) return "exit";
|
|
18661
|
+
if (isError || failedCount > 0) return "failed";
|
|
18655
18662
|
return "completed";
|
|
18656
18663
|
}
|
|
18657
18664
|
function shellHeader(status, count = 1) {
|
|
@@ -18707,7 +18714,9 @@ function withModelAndTag(label, args) {
|
|
|
18707
18714
|
function joinActionAgent(action, agent) {
|
|
18708
18715
|
return agent ? `${action} ${agent}` : action;
|
|
18709
18716
|
}
|
|
18710
|
-
function agentResponseTitle(args) {
|
|
18717
|
+
function agentResponseTitle(args, count = 1) {
|
|
18718
|
+
const total = Math.max(1, Number(count) || 1);
|
|
18719
|
+
if (total > 1) return `Responses ${total} agents`;
|
|
18711
18720
|
const name = titleizeAgentName(args?.agent || args?.subagent_type || args?.name || "");
|
|
18712
18721
|
return withModelAndTag(joinActionAgent("Response", name), args);
|
|
18713
18722
|
}
|
|
@@ -18962,13 +18971,17 @@ function clampFailureCount(errorCount, groupCount, isError) {
|
|
|
18962
18971
|
if (Number.isFinite(explicit)) return Math.max(0, Math.min(groupCount, Math.floor(explicit)));
|
|
18963
18972
|
return isError ? groupCount : 0;
|
|
18964
18973
|
}
|
|
18965
|
-
function toolStatusColor({ pending, groupCount, callFailedCount = 0, terminalStatus = "" }) {
|
|
18974
|
+
function toolStatusColor({ pending, groupCount, callFailedCount = 0, exitFailedCount = 0, terminalStatus = "" }) {
|
|
18966
18975
|
if (pending) return theme.text;
|
|
18967
18976
|
const status = normalizeTerminalStatus(terminalStatus);
|
|
18968
18977
|
if (status === "cancelled") return theme.warning;
|
|
18969
|
-
if (
|
|
18970
|
-
if (
|
|
18971
|
-
|
|
18978
|
+
if (status === "denied") return theme.warning;
|
|
18979
|
+
if (callFailedCount > 0) {
|
|
18980
|
+
if (groupCount > 1 && callFailedCount < groupCount) return theme.mixdogOrange || theme.warning;
|
|
18981
|
+
return theme.error;
|
|
18982
|
+
}
|
|
18983
|
+
if (exitFailedCount > 0) return theme.warning;
|
|
18984
|
+
return theme.success;
|
|
18972
18985
|
}
|
|
18973
18986
|
|
|
18974
18987
|
// src/tui/components/tool-execution/ResultBody.jsx
|
|
@@ -18999,7 +19012,7 @@ var TOOL_ANIM_TICK_MS = TOOL_BLINK_MS;
|
|
|
18999
19012
|
function statusCopy(name, label, count, doneCount, pending, isError, args = {}) {
|
|
19000
19013
|
return formatToolActionHeader(name, args, { pending, count });
|
|
19001
19014
|
}
|
|
19002
|
-
function ToolExecution({ name, args, result, rawResult, isError, errorCount, callErrorCount, expanded, columns = 80, attached = false, count = 1, completedCount = 0, startedAt = 0, completedAt = 0, aggregate = false, categories = {}, doneCategories = null, headerFinalized = true, deferredDisplayReady = false }) {
|
|
19015
|
+
function ToolExecution({ name, args, result, rawResult, isError, errorCount, callErrorCount, exitErrorCount, expanded, columns = 80, attached = false, count = 1, completedCount = 0, startedAt = 0, completedAt = 0, aggregate = false, categories = {}, doneCategories = null, headerFinalized = true, deferredDisplayReady = false, agentResponseAggregate = false }) {
|
|
19003
19016
|
const rowWidth = Math.max(1, Number(columns || 80));
|
|
19004
19017
|
const groupCount = Math.max(1, Number(count || 1));
|
|
19005
19018
|
const doneCount = Math.max(0, Math.min(groupCount, Number(completedCount || (result == null ? 0 : groupCount))));
|
|
@@ -19023,6 +19036,7 @@ function ToolExecution({ name, args, result, rawResult, isError, errorCount, cal
|
|
|
19023
19036
|
const elapsed = elapsedMs >= 1e3 ? formatElapsed(elapsedMs) : "";
|
|
19024
19037
|
const failedCount = clampFailureCount(errorCount, groupCount, isError);
|
|
19025
19038
|
const callFailedCount = clampFailureCount(callErrorCount, groupCount, false);
|
|
19039
|
+
const exitFailedCount = clampFailureCount(exitErrorCount, groupCount, false);
|
|
19026
19040
|
const displayGroupCount = groupCount;
|
|
19027
19041
|
const displayCategories = normalizeCountMap(categories || {});
|
|
19028
19042
|
const normalizedDoneCategories = doneCategories ? normalizeCountMap(doneCategories) : displayCategories;
|
|
@@ -19048,7 +19062,7 @@ function ToolExecution({ name, args, result, rawResult, isError, errorCount, cal
|
|
|
19048
19062
|
detailText = "";
|
|
19049
19063
|
}
|
|
19050
19064
|
const aggregateTerminalStatus = pending ? "running" : resultTerminalStatus(rt) || (isError || failedCount > 0 ? "failed" : "completed");
|
|
19051
|
-
const dotColor2 = toolStatusColor({ pending, groupCount, callFailedCount, terminalStatus: aggregateTerminalStatus });
|
|
19065
|
+
const dotColor2 = toolStatusColor({ pending, groupCount, callFailedCount, exitFailedCount, terminalStatus: aggregateTerminalStatus });
|
|
19052
19066
|
const dotText2 = pending && !blinkOn ? " " : TURN_MARKER;
|
|
19053
19067
|
const gutter2 = 2;
|
|
19054
19068
|
const showHeaderExpandHint2 = hasRawResult;
|
|
@@ -19103,7 +19117,7 @@ function ToolExecution({ name, args, result, rawResult, isError, errorCount, cal
|
|
|
19103
19117
|
const firstResultLine = hasDisplayResult ? String(lines[0] ?? "") : "";
|
|
19104
19118
|
const firstResultLineClipped = hasDisplayBody && stringWidth9(firstResultLine) > maxResultChars;
|
|
19105
19119
|
const hasHiddenDetail = !pending && hasDisplayBody && (totalLines > 1 || firstResultLineClipped || Boolean(resultSummary));
|
|
19106
|
-
const shellStatus = isShellSurface ? shellDisplayStatus({ pending, failedCount, isError, result: displayedResultText }) : "";
|
|
19120
|
+
const shellStatus = isShellSurface ? shellDisplayStatus({ pending, failedCount, exitFailedCount, isError, result: displayedResultText }) : "";
|
|
19107
19121
|
const shellElapsed = isShellSurface ? shellResultElapsed(displayedResultText) || elapsed : "";
|
|
19108
19122
|
const backgroundElapsed = backgroundMeta ? backgroundTaskElapsed(backgroundMeta, elapsed) : isBackgroundTaskTool(normalizedName) ? backgroundTaskElapsed(parsedArgs, elapsed) : "";
|
|
19109
19123
|
const toolArgPath = parsedArgs?.path ?? parsedArgs?.file_path ?? parsedArgs?.file ?? "";
|
|
@@ -19128,7 +19142,7 @@ function ToolExecution({ name, args, result, rawResult, isError, errorCount, cal
|
|
|
19128
19142
|
const collapsedDetail = pending ? pendingDetailPlaceholder : isShellSurface ? prefixElapsed(mergeTerminalDetail(shellStatus, shellCollapsedSummary), shellElapsed) : mergeTerminalDetail(terminalStatus, nonShellDetail);
|
|
19129
19143
|
const backgroundMetadataExpandable = isBackgroundMetadataResult && hasRawResult && !pending;
|
|
19130
19144
|
const showRawResult = expanded && (hasDisplayBody || hasRawResult) && (!isBackgroundMetadataResult || hasRawResult);
|
|
19131
|
-
const detailLines = showRawResult ? hasDisplayBody ? lines : rawRt ? stripLeadingStatusMarkerLines(rawRt.split("\n")) : [] : collapsedDetail ? [collapsedDetail] : [];
|
|
19145
|
+
const detailLines = showRawResult ? agentResponseAggregate && hasRawResult ? stripLeadingStatusMarkerLines(rawRt.split("\n")) : hasDisplayBody ? lines : rawRt ? stripLeadingStatusMarkerLines(rawRt.split("\n")) : [] : collapsedDetail ? [collapsedDetail] : [];
|
|
19132
19146
|
const isPendingPlaceholderDetail = !showRawResult && Boolean(pendingDetailPlaceholder);
|
|
19133
19147
|
const detailColor = isPendingPlaceholderDetail ? theme.subtle : theme.text;
|
|
19134
19148
|
const isAgentResult = !isBackgroundResult && !pending && isAgentTool(normalizedName) && hasDisplayResult;
|
|
@@ -19148,14 +19162,14 @@ function ToolExecution({ name, args, result, rawResult, isError, errorCount, cal
|
|
|
19148
19162
|
const keepAgentDetail = (isError || agentFailureText) && !(agentHeaderFailure && !agentSurfaceBrief);
|
|
19149
19163
|
visibleDetailLines = keepAgentDetail ? [agentDetailLine] : [];
|
|
19150
19164
|
}
|
|
19151
|
-
const finalStatusColor = toolStatusColor({ pending, groupCount, callFailedCount, terminalStatus });
|
|
19165
|
+
const finalStatusColor = toolStatusColor({ pending, groupCount, callFailedCount, exitFailedCount, terminalStatus });
|
|
19152
19166
|
const dotColor = finalStatusColor;
|
|
19153
19167
|
const markerGlyph = isAgentResponse ? AGENT_RESPONSE_MARKER : isAgentSurfaceCard ? AGENT_CALL_MARKER : TURN_MARKER;
|
|
19154
19168
|
const isDirectionalMarker = isAgentResponse || isAgentSurfaceCard;
|
|
19155
19169
|
const markerText = isDirectionalMarker ? `${markerGlyph} ` : markerGlyph;
|
|
19156
19170
|
const dotText = pending && !blinkOn ? " " : markerText;
|
|
19157
19171
|
let labelText;
|
|
19158
|
-
if (isAgentResponse) labelText = agentResponseTitle(parsedArgs);
|
|
19172
|
+
if (isAgentResponse) labelText = agentResponseTitle(parsedArgs, displayGroupCount);
|
|
19159
19173
|
else if (isBackgroundResponse) labelText = backgroundTaskResultTitle(normalizedName, backgroundMeta || parsedArgs);
|
|
19160
19174
|
else if (isBackgroundMetadataResult) labelText = backgroundTaskActionTitle(normalizedName, backgroundMeta);
|
|
19161
19175
|
else if (isShellSurface) labelText = shellHeader(shellStatus, displayGroupCount);
|
|
@@ -19364,7 +19378,7 @@ var Item = React19.memo(function Item2({ item, prevKind, columns, toolOutputExpa
|
|
|
19364
19378
|
node = /* @__PURE__ */ jsx19(ToolHookDenialCard, { item, columns });
|
|
19365
19379
|
break;
|
|
19366
19380
|
}
|
|
19367
|
-
node = /* @__PURE__ */ jsx19(ToolExecution, { name: item.name, args: item.args, result: item.result, rawResult: item.rawResult, isError: item.isError, errorCount: item.errorCount, callErrorCount: item.callErrorCount, expanded: toolOutputExpanded || item.expanded, columns, attached: false, count: item.count, completedCount: item.completedCount, startedAt: item.startedAt, completedAt: item.completedAt, aggregate: item.aggregate, categories: item.categories, doneCategories: item.doneCategories, headerFinalized: item.headerFinalized, deferredDisplayReady: item.deferredDisplayReady });
|
|
19381
|
+
node = /* @__PURE__ */ jsx19(ToolExecution, { name: item.name, args: item.args, result: item.result, rawResult: item.rawResult, isError: item.isError, errorCount: item.errorCount, callErrorCount: item.callErrorCount, exitErrorCount: item.exitErrorCount, expanded: toolOutputExpanded || item.expanded, columns, attached: false, count: item.count, completedCount: item.completedCount, startedAt: item.startedAt, completedAt: item.completedAt, aggregate: item.aggregate, categories: item.categories, doneCategories: item.doneCategories, headerFinalized: item.headerFinalized, deferredDisplayReady: item.deferredDisplayReady, agentResponseAggregate: item.agentResponseAggregate });
|
|
19368
19382
|
break;
|
|
19369
19383
|
}
|
|
19370
19384
|
case "notice":
|
|
@@ -19672,6 +19686,32 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
|
|
|
19672
19686
|
searchModelsCacheRef.current = { models: null, at: 0 };
|
|
19673
19687
|
}
|
|
19674
19688
|
}, []);
|
|
19689
|
+
useEffect10(() => {
|
|
19690
|
+
let alive = true;
|
|
19691
|
+
const timer2 = setTimeout(async () => {
|
|
19692
|
+
const seq = onboardingPrefetchSeqRef.current;
|
|
19693
|
+
try {
|
|
19694
|
+
const models = await Promise.resolve(store.listProviderModels?.() || []);
|
|
19695
|
+
if (alive && seq === onboardingPrefetchSeqRef.current && Array.isArray(models) && models.length > 0 && !Array.isArray(providerModelsCacheRef.current.models)) {
|
|
19696
|
+
providerModelsCacheRef.current = { models, at: Date.now() };
|
|
19697
|
+
}
|
|
19698
|
+
} catch {
|
|
19699
|
+
}
|
|
19700
|
+
if (!alive) return;
|
|
19701
|
+
try {
|
|
19702
|
+
const searchModels = await Promise.resolve(store.listSearchModels?.() || []);
|
|
19703
|
+
if (alive && Array.isArray(searchModels) && searchModels.length > 0 && !Array.isArray(searchModelsCacheRef.current.models)) {
|
|
19704
|
+
searchModelsCacheRef.current = { models: searchModels, at: Date.now() };
|
|
19705
|
+
}
|
|
19706
|
+
} catch {
|
|
19707
|
+
}
|
|
19708
|
+
}, 1500);
|
|
19709
|
+
timer2.unref?.();
|
|
19710
|
+
return () => {
|
|
19711
|
+
alive = false;
|
|
19712
|
+
clearTimeout(timer2);
|
|
19713
|
+
};
|
|
19714
|
+
}, [store]);
|
|
19675
19715
|
const { onboardingWarnReopen, openOnboardingAuthStep } = createOnboardingSteps({
|
|
19676
19716
|
store,
|
|
19677
19717
|
setPicker,
|
|
@@ -22507,18 +22547,6 @@ function bracketField(text, name) {
|
|
|
22507
22547
|
const re = new RegExp(`^\\[${name}:\\s*([^\\]]*)\\]`, "mi");
|
|
22508
22548
|
return re.exec(String(text ?? ""))?.[1]?.trim() || "";
|
|
22509
22549
|
}
|
|
22510
|
-
function toolResultStatus(text) {
|
|
22511
|
-
const value = String(text ?? "");
|
|
22512
|
-
const tagged = textBetweenTag2(value, "status");
|
|
22513
|
-
if (tagged) return tagged.trim();
|
|
22514
|
-
const bracketed = bracketField(value, "status");
|
|
22515
|
-
if (bracketed) return bracketed.trim();
|
|
22516
|
-
const inline = /^(?:status|state):\s*([^\s·,;]+)/mi.exec(value);
|
|
22517
|
-
return inline ? inline[1].trim() : "";
|
|
22518
|
-
}
|
|
22519
|
-
function isErrorToolStatus(status) {
|
|
22520
|
-
return /^(failed|error|timeout|cancelled|canceled|killed)$/i.test(String(status || "").trim());
|
|
22521
|
-
}
|
|
22522
22550
|
function parseSyntheticAgentMessage(text) {
|
|
22523
22551
|
const value = String(text ?? "").trim();
|
|
22524
22552
|
if (!value) return null;
|
|
@@ -22771,6 +22799,13 @@ function notificationQueueKey(event, text, parsed) {
|
|
|
22771
22799
|
const hasBody = /\n\s*\n[\s\S]*\S/.test(String(text || "")) ? "b1" : "b0";
|
|
22772
22800
|
return [id, type || fallbackKind, status, hasBody].filter(Boolean).join(":");
|
|
22773
22801
|
}
|
|
22802
|
+
function executionCardKey(event, text, parsed) {
|
|
22803
|
+
const meta = event?.meta && typeof event.meta === "object" ? event.meta : {};
|
|
22804
|
+
const executionId = String(meta.execution_id || "").trim();
|
|
22805
|
+
if (!executionId) return notificationQueueKey(event, text, parsed);
|
|
22806
|
+
const hasBody = /\n\s*\n[\s\S]*\S/.test(String(text || "")) ? "b1" : "b0";
|
|
22807
|
+
return `card:${executionId}:${hasBody}`;
|
|
22808
|
+
}
|
|
22774
22809
|
function isExecutionNotification(event, text, parsed) {
|
|
22775
22810
|
const meta = event?.meta && typeof event.meta === "object" ? event.meta : {};
|
|
22776
22811
|
if (meta.execution_id || meta.execution_surface) return true;
|
|
@@ -22869,23 +22904,43 @@ var yieldToRenderer = ({ frames = 1 } = {}) => new Promise((resolve5) => {
|
|
|
22869
22904
|
|
|
22870
22905
|
// src/tui/engine/tool-result-status.mjs
|
|
22871
22906
|
var CANCELLED_RESULT_STATUS_LINE = "[status: cancelled]";
|
|
22907
|
+
function shellCommandExitCode(text) {
|
|
22908
|
+
const body = String(text || "");
|
|
22909
|
+
if (!/^\s*(?:Error:\s*)?\[shell-run-failed\]/i.test(body)) return null;
|
|
22910
|
+
const header = body.split("\n", 1)[0] || "";
|
|
22911
|
+
if (/\[timeout:|\[signal:|timed out|aborted|interrupted/i.test(header)) return null;
|
|
22912
|
+
const m = header.match(/\[exit code:\s*(\d+)\]/i);
|
|
22913
|
+
if (!m) return null;
|
|
22914
|
+
const code = Number(m[1]);
|
|
22915
|
+
return Number.isFinite(code) ? code : null;
|
|
22916
|
+
}
|
|
22917
|
+
function toolCallOutcome(message, rawText) {
|
|
22918
|
+
const exitCode = shellCommandExitCode(rawText);
|
|
22919
|
+
if (exitCode != null) {
|
|
22920
|
+
return { isCallError: false, isExitError: true, exitCode };
|
|
22921
|
+
}
|
|
22922
|
+
const isCallError = message?.isError === true || message?.toolKind === "error";
|
|
22923
|
+
return {
|
|
22924
|
+
isCallError,
|
|
22925
|
+
isExitError: false,
|
|
22926
|
+
exitCode
|
|
22927
|
+
};
|
|
22928
|
+
}
|
|
22929
|
+
function failureDetailText({ succeeded = 0, realErrors = 0, exitErrors = 0, exitCode } = {}) {
|
|
22930
|
+
const parts = [];
|
|
22931
|
+
if (succeeded > 0) parts.push(`${succeeded} Ok`);
|
|
22932
|
+
if (realErrors > 0) parts.push(`${realErrors} Failed`);
|
|
22933
|
+
if (exitErrors > 0) {
|
|
22934
|
+
const solo = exitErrors === 1 && realErrors === 0 && succeeded === 0;
|
|
22935
|
+
parts.push(solo && Number.isFinite(exitCode) ? `Exit ${exitCode}` : `${exitErrors} Exit`);
|
|
22936
|
+
}
|
|
22937
|
+
return parts.join(" \xB7 ");
|
|
22938
|
+
}
|
|
22872
22939
|
function normalizedResultStatusToken(value) {
|
|
22873
|
-
|
|
22874
|
-
if (!raw) return "";
|
|
22875
|
-
if (/^(running|pending|queued|in_progress|in-progress)$/.test(raw)) return "running";
|
|
22876
|
-
if (/^(completed|complete|done|success|succeeded|ok)$/.test(raw)) return "completed";
|
|
22877
|
-
if (/^(failed|fail|error|errored|timeout|timed_out|killed)$/.test(raw)) return "failed";
|
|
22878
|
-
if (/^(cancelled|canceled|cancel)$/.test(raw)) return "cancelled";
|
|
22879
|
-
return "";
|
|
22940
|
+
return normalizeToolTerminalStatus(value);
|
|
22880
22941
|
}
|
|
22881
22942
|
function resultTextTerminalStatus(text) {
|
|
22882
|
-
|
|
22883
|
-
const tagged = body.match(/<status[^>]*>([\s\S]*?)<\/status>/i)?.[1]?.trim();
|
|
22884
|
-
if (tagged) return normalizedResultStatusToken(tagged);
|
|
22885
|
-
const bracketed = body.match(/^\[status:\s*([^\]]*)\]/mi)?.[1]?.trim();
|
|
22886
|
-
if (bracketed) return normalizedResultStatusToken(bracketed);
|
|
22887
|
-
const inline = body.match(/^(?:status|state):\s*([^\s·,;]+)/mi)?.[1]?.trim();
|
|
22888
|
-
return normalizedResultStatusToken(inline);
|
|
22943
|
+
return toolResultTerminalStatus(text);
|
|
22889
22944
|
}
|
|
22890
22945
|
function itemHasKnownTerminalStatus(item, texts = []) {
|
|
22891
22946
|
const settled = (token) => token === "completed" || token === "failed" || token === "cancelled";
|
|
@@ -22907,11 +22962,14 @@ ${body}`;
|
|
|
22907
22962
|
function groupedToolResultText(group) {
|
|
22908
22963
|
const completed = Math.min(group.count, group.completed);
|
|
22909
22964
|
if (group.count <= 1) return group.results.at(-1)?.text ?? "";
|
|
22910
|
-
|
|
22911
|
-
|
|
22912
|
-
const
|
|
22965
|
+
const exitErrors = Number(group.exitErrors || 0);
|
|
22966
|
+
if (group.errors > 0 || exitErrors > 0) {
|
|
22967
|
+
const realErrors = Math.max(0, Number(group.callErrors || group.errors || 0));
|
|
22968
|
+
const succeeded = Math.max(0, completed - group.errors - exitErrors);
|
|
22969
|
+
const exitCode = group.results.find((result) => result?.isExitError)?.exitCode;
|
|
22970
|
+
const reasons = group.results.filter((result) => result?.isError && !result?.isExitError).map((result) => firstErrorLine(result?.text)).filter(Boolean);
|
|
22913
22971
|
const uniqueReasons = [...new Set(reasons)].slice(0, 2);
|
|
22914
|
-
const base =
|
|
22972
|
+
const base = failureDetailText({ succeeded, realErrors, exitErrors, exitCode });
|
|
22915
22973
|
return [
|
|
22916
22974
|
`${base}${uniqueReasons[0] ? ` \xB7 ${uniqueReasons[0]}` : ""}`,
|
|
22917
22975
|
...uniqueReasons.slice(1)
|
|
@@ -22945,9 +23003,10 @@ ${text}`);
|
|
|
22945
23003
|
}
|
|
22946
23004
|
return chunks.join("\n\n");
|
|
22947
23005
|
}
|
|
22948
|
-
function aggregateBucketForCategory(category) {
|
|
23006
|
+
function aggregateBucketForCategory(category, { agentBatch = "" } = {}) {
|
|
22949
23007
|
const key = String(category || "").trim();
|
|
22950
23008
|
if (key === "Read" || key === "Search") return "category:Read+Search";
|
|
23009
|
+
if (key === "Agent") return agentBatch ? `category:Agent:${agentBatch}` : "category:Agent";
|
|
22951
23010
|
return key ? `category:${key}` : "default";
|
|
22952
23011
|
}
|
|
22953
23012
|
function aggregateSummaries(aggregate) {
|
|
@@ -23066,6 +23125,12 @@ function createToolCardResults({
|
|
|
23066
23125
|
buildAgentJobCardPatch,
|
|
23067
23126
|
agentStatusState
|
|
23068
23127
|
}) {
|
|
23128
|
+
function finalizedErrorFallbackBody(body, text, exitCode) {
|
|
23129
|
+
if (String(body || "").trim()) return body;
|
|
23130
|
+
if (String(text || "").trim()) return text;
|
|
23131
|
+
if (exitCode != null) return `Exit ${exitCode}`;
|
|
23132
|
+
return "Failed";
|
|
23133
|
+
}
|
|
23069
23134
|
function patchToolItem(id, patch) {
|
|
23070
23135
|
const prev = getState().items.find((it) => it.id === id);
|
|
23071
23136
|
const ok = patchItem(id, patch);
|
|
@@ -23083,10 +23148,8 @@ function createToolCardResults({
|
|
|
23083
23148
|
const rawText = toolResultText(message?.content);
|
|
23084
23149
|
const aggregate = card.aggregate;
|
|
23085
23150
|
const callRec = aggregate && callId ? aggregate.calls.get(callId) : null;
|
|
23086
|
-
const
|
|
23087
|
-
const
|
|
23088
|
-
const isResultError = /^\s*\[?error/i.test(rawText) || isErrorToolStatus(toolResultStatus(rawText)) || isMemoryCall && memoryCoreResultErrorText(rawText) != null;
|
|
23089
|
-
const isError = isCallError || isResultError;
|
|
23151
|
+
const { exitCode, isExitError, isCallError } = toolCallOutcome(message, rawText);
|
|
23152
|
+
const isError = isCallError;
|
|
23090
23153
|
const text = isError ? toolErrorDisplay(rawText, card?.name || "tool") : rawText;
|
|
23091
23154
|
if (aggregate && card.itemId === aggregate.itemId) {
|
|
23092
23155
|
if (!callRec) return false;
|
|
@@ -23099,14 +23162,17 @@ function createToolCardResults({
|
|
|
23099
23162
|
assignAggregateSummaryOrder(aggregate, callRec);
|
|
23100
23163
|
callRec.isError = isError;
|
|
23101
23164
|
callRec.isCallError = isCallError;
|
|
23165
|
+
callRec.isExitError = isExitError;
|
|
23166
|
+
callRec.exitCode = exitCode;
|
|
23102
23167
|
callRec.resultText = text;
|
|
23103
23168
|
callRec.resolved = true;
|
|
23104
23169
|
const allCalls = [...aggregate.calls.values()];
|
|
23105
23170
|
const completed = allCalls.filter((r) => r.resolved).length;
|
|
23106
23171
|
const errors = allCalls.filter((r) => r.isError).length;
|
|
23107
23172
|
const callErrors = allCalls.filter((r) => r.isCallError).length;
|
|
23108
|
-
const
|
|
23109
|
-
const
|
|
23173
|
+
const exitErrors = allCalls.filter((r) => r.isExitError).length;
|
|
23174
|
+
const succeeded = Math.max(0, completed - errors - exitErrors);
|
|
23175
|
+
const detailText = errors > 0 || exitErrors > 0 ? failureDetailText({ succeeded, realErrors: callErrors, exitErrors, exitCode: allCalls.find((r) => r.isExitError)?.exitCode }) : formatAggregateDetail(aggregateSummaries(aggregate));
|
|
23110
23176
|
const currentItem = getState().items.find((it) => it.id === card.itemId);
|
|
23111
23177
|
const earlyCompleted = allCalls.filter((r) => r.resolved || r.completedEarly).length;
|
|
23112
23178
|
const visualCompleted = Math.max(completed, earlyCompleted, Math.min(allCalls.length, Number(currentItem?.completedCount || 0)));
|
|
@@ -23119,6 +23185,7 @@ function createToolCardResults({
|
|
|
23119
23185
|
isError: errors > 0,
|
|
23120
23186
|
errorCount: errors,
|
|
23121
23187
|
callErrorCount: callErrors,
|
|
23188
|
+
exitErrorCount: exitErrors,
|
|
23122
23189
|
count: allCalls.length,
|
|
23123
23190
|
completedCount: visualCompleted,
|
|
23124
23191
|
doneCategories: aggregateDoneCategories(allCalls),
|
|
@@ -23128,20 +23195,25 @@ function createToolCardResults({
|
|
|
23128
23195
|
if (callId) done.add(callId);
|
|
23129
23196
|
return true;
|
|
23130
23197
|
}
|
|
23131
|
-
const group = toolGroups.get(card.itemId) || { count: 1, completed: 0, errors: 0, callErrors: 0, results: [] };
|
|
23198
|
+
const group = toolGroups.get(card.itemId) || { count: 1, completed: 0, errors: 0, callErrors: 0, exitErrors: 0, results: [] };
|
|
23132
23199
|
group.completed = Math.min(group.count, group.completed + 1);
|
|
23133
23200
|
group.errors += isError ? 1 : 0;
|
|
23134
23201
|
group.callErrors = (group.callErrors || 0) + (isCallError ? 1 : 0);
|
|
23135
|
-
group.
|
|
23202
|
+
group.exitErrors = (group.exitErrors || 0) + (isExitError ? 1 : 0);
|
|
23203
|
+
group.results.push({ text, isError, isExitError, exitCode });
|
|
23136
23204
|
toolGroups.set(card.itemId, group);
|
|
23137
23205
|
const resultText = groupedToolResultText(group);
|
|
23138
|
-
|
|
23206
|
+
let displayResult = toolGroupedDisplayFallback(resultText, text, rawText);
|
|
23207
|
+
if (group.errors > 0 && !String(displayResult || "").trim()) {
|
|
23208
|
+
displayResult = finalizedErrorFallbackBody(displayResult, text, exitCode);
|
|
23209
|
+
}
|
|
23139
23210
|
const patch = {
|
|
23140
23211
|
result: displayResult,
|
|
23141
23212
|
text: displayResult,
|
|
23142
23213
|
isError: group.errors > 0,
|
|
23143
23214
|
errorCount: group.errors,
|
|
23144
23215
|
callErrorCount: group.callErrors || 0,
|
|
23216
|
+
exitErrorCount: group.exitErrors || 0,
|
|
23145
23217
|
count: group.count,
|
|
23146
23218
|
completedCount: group.completed,
|
|
23147
23219
|
completedAt: Date.now()
|
|
@@ -23154,6 +23226,9 @@ function createToolCardResults({
|
|
|
23154
23226
|
set(agentStatusState({ force: true }));
|
|
23155
23227
|
}
|
|
23156
23228
|
Object.assign(patch, buildAgentJobCardPatch(card.itemId, rawText, isError));
|
|
23229
|
+
if (group.errors > 0 && !String(patch.result || "").trim()) {
|
|
23230
|
+
patch.result = patch.text = finalizedErrorFallbackBody(patch.result, text, exitCode);
|
|
23231
|
+
}
|
|
23157
23232
|
}
|
|
23158
23233
|
patchToolItem(card.itemId, patch);
|
|
23159
23234
|
card.done = true;
|
|
@@ -23204,9 +23279,10 @@ function createToolCardResults({
|
|
|
23204
23279
|
const totalCompleted = completed;
|
|
23205
23280
|
const errors = allCalls.filter((r) => r.isError).length;
|
|
23206
23281
|
const callErrors = allCalls.filter((r) => r.isCallError).length;
|
|
23207
|
-
const
|
|
23282
|
+
const exitErrors = allCalls.filter((r) => r.isExitError).length;
|
|
23283
|
+
const succeeded = Math.max(0, completed - errors - exitErrors);
|
|
23208
23284
|
const rawResult = aggregateRawResult(allCalls);
|
|
23209
|
-
let displayDetail = errors > 0
|
|
23285
|
+
let displayDetail = errors > 0 || exitErrors > 0 ? failureDetailText({ succeeded, realErrors: callErrors, exitErrors, exitCode: allCalls.find((r) => r.isExitError)?.exitCode }) : formatAggregateDetail(aggregateSummaries(aggregate));
|
|
23210
23286
|
if (cancelled) {
|
|
23211
23287
|
const currentItem = getState().items.find((it) => it.id === card.itemId);
|
|
23212
23288
|
displayDetail = withCancelledResultMarker(displayDetail, currentItem);
|
|
@@ -23218,6 +23294,7 @@ function createToolCardResults({
|
|
|
23218
23294
|
isError: errors > 0,
|
|
23219
23295
|
errorCount: errors,
|
|
23220
23296
|
callErrorCount: callErrors,
|
|
23297
|
+
exitErrorCount: exitErrors,
|
|
23221
23298
|
count: allCalls.length,
|
|
23222
23299
|
completedCount: totalCompleted,
|
|
23223
23300
|
doneCategories: aggregateDoneCategories(allCalls),
|
|
@@ -23230,15 +23307,19 @@ function createToolCardResults({
|
|
|
23230
23307
|
}
|
|
23231
23308
|
continue;
|
|
23232
23309
|
}
|
|
23233
|
-
const group = toolGroups.get(card.itemId) || { count: 1, completed: 0, errors: 0, results: [] };
|
|
23310
|
+
const group = toolGroups.get(card.itemId) || { count: 1, completed: 0, errors: 0, exitErrors: 0, results: [] };
|
|
23234
23311
|
group.completed = Math.min(group.count, group.completed + 1);
|
|
23235
23312
|
toolGroups.set(card.itemId, group);
|
|
23236
23313
|
let resultText = groupedToolResultText(group);
|
|
23314
|
+
if (group.errors > 0 && !String(resultText || "").trim()) {
|
|
23315
|
+
const exitRec = (group.results || []).find((r) => r && r.isExitError);
|
|
23316
|
+
resultText = finalizedErrorFallbackBody(resultText, exitRec?.text, exitRec?.exitCode);
|
|
23317
|
+
}
|
|
23237
23318
|
if (cancelled) {
|
|
23238
23319
|
const currentItem = getState().items.find((it) => it.id === card.itemId);
|
|
23239
23320
|
resultText = withCancelledResultMarker(resultText, currentItem);
|
|
23240
23321
|
}
|
|
23241
|
-
patchToolItem(card.itemId, { result: resultText, text: resultText, isError: group.errors > 0, errorCount: group.errors, callErrorCount: group.callErrors || 0, count: group.count, completedCount: group.completed, completedAt: Date.now() });
|
|
23322
|
+
patchToolItem(card.itemId, { result: resultText, text: resultText, isError: group.errors > 0, errorCount: group.errors, callErrorCount: group.callErrors || 0, exitErrorCount: group.exitErrors || 0, count: group.count, completedCount: group.completed, completedAt: Date.now() });
|
|
23242
23323
|
card.done = true;
|
|
23243
23324
|
if (card.callId) done.add(card.callId);
|
|
23244
23325
|
}
|
|
@@ -23246,6 +23327,73 @@ function createToolCardResults({
|
|
|
23246
23327
|
return { patchToolCardResult, flushToolResults };
|
|
23247
23328
|
}
|
|
23248
23329
|
|
|
23330
|
+
// src/runtime/agent/orchestrator/session/manager/delivered-completions.mjs
|
|
23331
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
23332
|
+
var DELIVERED_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
23333
|
+
var DELIVERED_MAX_ENTRIES = 512;
|
|
23334
|
+
var _delivered = /* @__PURE__ */ new Map();
|
|
23335
|
+
function hashCompletionText(text) {
|
|
23336
|
+
const value = String(text ?? "").trim();
|
|
23337
|
+
if (!value) return null;
|
|
23338
|
+
return createHash3("sha1").update(value).digest("hex");
|
|
23339
|
+
}
|
|
23340
|
+
function execKey(executionId) {
|
|
23341
|
+
const id = executionId == null ? "" : String(executionId).trim();
|
|
23342
|
+
return id ? `id:${id}` : null;
|
|
23343
|
+
}
|
|
23344
|
+
function textKey(text) {
|
|
23345
|
+
const h = hashCompletionText(text);
|
|
23346
|
+
return h ? `tx:${h}` : null;
|
|
23347
|
+
}
|
|
23348
|
+
function pruneExpired(now) {
|
|
23349
|
+
for (const [key, expiresAt] of _delivered) {
|
|
23350
|
+
if (expiresAt <= now) _delivered.delete(key);
|
|
23351
|
+
}
|
|
23352
|
+
}
|
|
23353
|
+
function enforceBound() {
|
|
23354
|
+
while (_delivered.size > DELIVERED_MAX_ENTRIES) {
|
|
23355
|
+
const oldest = _delivered.keys().next().value;
|
|
23356
|
+
if (oldest === void 0) break;
|
|
23357
|
+
_delivered.delete(oldest);
|
|
23358
|
+
}
|
|
23359
|
+
}
|
|
23360
|
+
function recordDeliveredCompletion({ executionId, text } = {}) {
|
|
23361
|
+
const now = Date.now();
|
|
23362
|
+
pruneExpired(now);
|
|
23363
|
+
const expiresAt = now + DELIVERED_TTL_MS;
|
|
23364
|
+
let recorded = false;
|
|
23365
|
+
for (const key of [execKey(executionId), textKey(text)]) {
|
|
23366
|
+
if (!key) continue;
|
|
23367
|
+
_delivered.delete(key);
|
|
23368
|
+
_delivered.set(key, expiresAt);
|
|
23369
|
+
recorded = true;
|
|
23370
|
+
}
|
|
23371
|
+
if (recorded) enforceBound();
|
|
23372
|
+
return recorded;
|
|
23373
|
+
}
|
|
23374
|
+
function isDeliveredCompletion({ executionId, text } = {}) {
|
|
23375
|
+
const now = Date.now();
|
|
23376
|
+
const keys = [execKey(executionId), textKey(text)].filter(Boolean);
|
|
23377
|
+
let hit = false;
|
|
23378
|
+
for (const key of keys) {
|
|
23379
|
+
const expiresAt2 = _delivered.get(key);
|
|
23380
|
+
if (expiresAt2 === void 0) continue;
|
|
23381
|
+
if (expiresAt2 <= now) {
|
|
23382
|
+
_delivered.delete(key);
|
|
23383
|
+
continue;
|
|
23384
|
+
}
|
|
23385
|
+
hit = true;
|
|
23386
|
+
}
|
|
23387
|
+
if (!hit) return false;
|
|
23388
|
+
const expiresAt = now + DELIVERED_TTL_MS;
|
|
23389
|
+
for (const key of keys) {
|
|
23390
|
+
if (!_delivered.has(key)) continue;
|
|
23391
|
+
_delivered.delete(key);
|
|
23392
|
+
_delivered.set(key, expiresAt);
|
|
23393
|
+
}
|
|
23394
|
+
return true;
|
|
23395
|
+
}
|
|
23396
|
+
|
|
23249
23397
|
// src/tui/engine/agent-job-feed.mjs
|
|
23250
23398
|
function parseInboundImagePaths(raw) {
|
|
23251
23399
|
if (typeof raw !== "string" || !raw) return [];
|
|
@@ -23266,16 +23414,58 @@ function createAgentJobFeed({
|
|
|
23266
23414
|
enqueue,
|
|
23267
23415
|
drain,
|
|
23268
23416
|
pushUserOrSyntheticItem,
|
|
23417
|
+
pushAsyncAgentResponse,
|
|
23269
23418
|
makeQueueEntry,
|
|
23270
23419
|
getPending,
|
|
23271
23420
|
agentStatusState,
|
|
23272
23421
|
displayedExecutionNotificationKeys,
|
|
23273
|
-
pushNotice
|
|
23422
|
+
pushNotice,
|
|
23423
|
+
now = () => Date.now(),
|
|
23424
|
+
executionResumeTombstoneTtlMs = 3e4,
|
|
23425
|
+
executionResumeTombstoneLimit = 128
|
|
23274
23426
|
}) {
|
|
23275
23427
|
let executionResumeKickDeferred = false;
|
|
23428
|
+
const discardedExecutionResumeKeys = /* @__PURE__ */ new Map();
|
|
23429
|
+
const displayedExecutionResponseStates = /* @__PURE__ */ new Map();
|
|
23276
23430
|
const executionResumeKickBodies = [];
|
|
23277
|
-
function
|
|
23278
|
-
if (
|
|
23431
|
+
function executionResumeKey(body, completionKey = "") {
|
|
23432
|
+
if (completionKey && typeof completionKey === "object") {
|
|
23433
|
+
completionKey = completionKey.executionId || completionKey.key || "";
|
|
23434
|
+
}
|
|
23435
|
+
const explicitKey = String(completionKey || "").trim();
|
|
23436
|
+
if (explicitKey.startsWith("execution:") || explicitKey.startsWith("body:")) return explicitKey;
|
|
23437
|
+
if (explicitKey) return `execution:${explicitKey}`;
|
|
23438
|
+
const value = String(body || "").trim();
|
|
23439
|
+
return value ? `body:${shortTextFingerprint(value)}` : "";
|
|
23440
|
+
}
|
|
23441
|
+
function pruneDiscardedExecutionResumeKeys() {
|
|
23442
|
+
const nowMs = Number(now()) || Date.now();
|
|
23443
|
+
for (const [key, expiresAt] of discardedExecutionResumeKeys) {
|
|
23444
|
+
if (expiresAt <= nowMs) discardedExecutionResumeKeys.delete(key);
|
|
23445
|
+
}
|
|
23446
|
+
}
|
|
23447
|
+
function isDiscardedExecutionResumeKey(key) {
|
|
23448
|
+
if (!key) return false;
|
|
23449
|
+
pruneDiscardedExecutionResumeKeys();
|
|
23450
|
+
return discardedExecutionResumeKeys.has(key);
|
|
23451
|
+
}
|
|
23452
|
+
function rememberDiscardedExecutionResumeKey(key) {
|
|
23453
|
+
if (!key) return;
|
|
23454
|
+
pruneDiscardedExecutionResumeKeys();
|
|
23455
|
+
const limit = Math.max(1, Number(executionResumeTombstoneLimit) || 128);
|
|
23456
|
+
while (!discardedExecutionResumeKeys.has(key) && discardedExecutionResumeKeys.size >= limit) {
|
|
23457
|
+
const oldest = discardedExecutionResumeKeys.keys().next().value;
|
|
23458
|
+
if (oldest == null) break;
|
|
23459
|
+
discardedExecutionResumeKeys.delete(oldest);
|
|
23460
|
+
}
|
|
23461
|
+
const ttlMs = Math.max(1, Number(executionResumeTombstoneTtlMs) || 3e4);
|
|
23462
|
+
discardedExecutionResumeKeys.delete(key);
|
|
23463
|
+
discardedExecutionResumeKeys.set(key, (Number(now()) || Date.now()) + ttlMs);
|
|
23464
|
+
}
|
|
23465
|
+
function kickExecutionPendingResume(body = "", completionKey = "") {
|
|
23466
|
+
const key = executionResumeKey(body, completionKey);
|
|
23467
|
+
if (body && isDiscardedExecutionResumeKey(key)) return;
|
|
23468
|
+
if (body) executionResumeKickBodies.push({ body, key });
|
|
23279
23469
|
if (getDisposed()) return;
|
|
23280
23470
|
if (getState().busy) {
|
|
23281
23471
|
executionResumeKickDeferred = true;
|
|
@@ -23287,16 +23477,34 @@ function createAgentJobFeed({
|
|
|
23287
23477
|
return;
|
|
23288
23478
|
}
|
|
23289
23479
|
executionResumeKickDeferred = false;
|
|
23290
|
-
const
|
|
23291
|
-
|
|
23480
|
+
const resumeBodies = executionResumeKickBodies.splice(0);
|
|
23481
|
+
const resumeBody = resumeBodies.map(({ body: value }) => value).filter(Boolean).join("\n\n");
|
|
23482
|
+
const resumeCompletionKeys = resumeBodies.map(({ key: key2 }) => key2).filter(Boolean);
|
|
23483
|
+
pending.push(makeQueueEntry(resumeBody, {
|
|
23484
|
+
mode: "pending-resume",
|
|
23485
|
+
priority: "next",
|
|
23486
|
+
abortDiscardOnAbort: true,
|
|
23487
|
+
resumeCompletionKeys
|
|
23488
|
+
}));
|
|
23292
23489
|
void drain();
|
|
23293
23490
|
}
|
|
23294
23491
|
function flushDeferredExecutionPendingResumeKick() {
|
|
23295
23492
|
if (!executionResumeKickDeferred || getDisposed() || getState().busy) return;
|
|
23296
23493
|
kickExecutionPendingResume();
|
|
23297
23494
|
}
|
|
23298
|
-
function scheduleExecutionPendingResumeKick(body = "") {
|
|
23299
|
-
queueMicrotask(() => kickExecutionPendingResume(body));
|
|
23495
|
+
function scheduleExecutionPendingResumeKick(body = "", completionKey = "") {
|
|
23496
|
+
queueMicrotask(() => kickExecutionPendingResume(body, completionKey));
|
|
23497
|
+
}
|
|
23498
|
+
function discardExecutionPendingResume(completionKeys = []) {
|
|
23499
|
+
const keys = (Array.isArray(completionKeys) ? completionKeys : [completionKeys]).map((key) => executionResumeKey("", key)).filter(Boolean);
|
|
23500
|
+
if (keys.length === 0) return;
|
|
23501
|
+
for (const key of keys) rememberDiscardedExecutionResumeKey(key);
|
|
23502
|
+
for (let i = executionResumeKickBodies.length - 1; i >= 0; i -= 1) {
|
|
23503
|
+
if (isDiscardedExecutionResumeKey(executionResumeKickBodies[i].key)) {
|
|
23504
|
+
executionResumeKickBodies.splice(i, 1);
|
|
23505
|
+
}
|
|
23506
|
+
}
|
|
23507
|
+
executionResumeKickDeferred = executionResumeKickBodies.length > 0;
|
|
23300
23508
|
}
|
|
23301
23509
|
function buildAgentJobCardPatch(itemId, text, isError = false) {
|
|
23302
23510
|
const parsed = parseAgentJob(text);
|
|
@@ -23314,6 +23522,12 @@ function createAgentJobFeed({
|
|
|
23314
23522
|
function updateAgentJobCard(itemId, text, isError = false) {
|
|
23315
23523
|
patchItem(itemId, buildAgentJobCardPatch(itemId, text, isError));
|
|
23316
23524
|
}
|
|
23525
|
+
function refreshAgentStatus(parsed) {
|
|
23526
|
+
if (!parsed?.taskId) return;
|
|
23527
|
+
const status = String(parsed.status || "").toLowerCase();
|
|
23528
|
+
const terminal = /^(completed|complete|done|success|succeeded|ok|failed|error|timeout|killed|cancelled|canceled|denied)$/.test(status);
|
|
23529
|
+
set(agentStatusState(terminal ? { force: true } : void 0));
|
|
23530
|
+
}
|
|
23317
23531
|
function subscribeRuntimeNotifications() {
|
|
23318
23532
|
if (typeof runtime.onNotification !== "function") return null;
|
|
23319
23533
|
return runtime.onNotification((event) => {
|
|
@@ -23329,38 +23543,53 @@ function createAgentJobFeed({
|
|
|
23329
23543
|
return true;
|
|
23330
23544
|
}
|
|
23331
23545
|
if (delivery.action === "status-only") {
|
|
23332
|
-
|
|
23546
|
+
refreshAgentStatus(parsed);
|
|
23333
23547
|
return true;
|
|
23334
23548
|
}
|
|
23335
23549
|
if (delivery.action === "execution-ui") {
|
|
23336
|
-
const
|
|
23337
|
-
|
|
23338
|
-
|
|
23339
|
-
|
|
23550
|
+
const cardKey = executionCardKey(event, text, parsed);
|
|
23551
|
+
const firstDelivery = !cardKey || !displayedExecutionNotificationKeys.has(cardKey);
|
|
23552
|
+
const executionId = String(event?.meta?.execution_id || parsed?.taskId || "").trim();
|
|
23553
|
+
const status = String(event?.meta?.status || parsed?.status || "").toLowerCase();
|
|
23554
|
+
const hasBody = /\n\s*\n[\s\S]*\S/.test(text);
|
|
23555
|
+
const isFailure = /^(failed|error|timeout|killed|cancelled|canceled|denied)$/.test(status);
|
|
23556
|
+
const successfulPreview = !hasBody && !isFailure && /^(completed|complete|done|success|succeeded|ok)$/.test(status);
|
|
23557
|
+
const responseState = executionId ? displayedExecutionResponseStates.get(executionId) : "";
|
|
23558
|
+
const bodyAlreadyDisplayed = responseState === "body";
|
|
23559
|
+
if (firstDelivery && !successfulPreview && !bodyAlreadyDisplayed) {
|
|
23560
|
+
if (cardKey) displayedExecutionNotificationKeys.add(cardKey);
|
|
23561
|
+
if (executionId) displayedExecutionResponseStates.set(executionId, hasBody ? "body" : "preview");
|
|
23562
|
+
(pushAsyncAgentResponse || pushUserOrSyntheticItem)(delivery.displayText, nextId2(), "injected", { responseKey: executionId });
|
|
23340
23563
|
}
|
|
23341
|
-
|
|
23564
|
+
refreshAgentStatus(parsed);
|
|
23342
23565
|
const resumeBody = String(delivery.modelContent || "").trim();
|
|
23343
23566
|
if (resumeBody) {
|
|
23344
|
-
|
|
23567
|
+
const completionKey = executionResumeKey(resumeBody, executionId);
|
|
23568
|
+
if (isDiscardedExecutionResumeKey(completionKey) || isDeliveredCompletion({ executionId, text: resumeBody })) {
|
|
23569
|
+
if (event && typeof event === "object") event.modelVisibleDelivered = true;
|
|
23570
|
+
return true;
|
|
23571
|
+
}
|
|
23572
|
+
const enqueued = enqueue(resumeBody, {
|
|
23345
23573
|
mode: "task-notification",
|
|
23346
23574
|
// Claude Code parity: live execution completions are queued as
|
|
23347
23575
|
// task notifications so the active loop can attach them after the
|
|
23348
23576
|
// next tool batch; no special pending-resume bypass.
|
|
23349
23577
|
priority: "next",
|
|
23350
23578
|
key: notificationKey || void 0,
|
|
23579
|
+
abortDiscardOnAbort: true,
|
|
23580
|
+
resumeCompletionKeys: completionKey ? [completionKey] : [],
|
|
23351
23581
|
displayText: delivery.displayText || text,
|
|
23352
23582
|
// The immediate Response card was already pushed above
|
|
23353
23583
|
// (pushUserOrSyntheticItem). Keep this queued twin model-visible
|
|
23354
23584
|
// but suppress its drain-time transcript card to avoid a duplicate.
|
|
23355
23585
|
suppressDisplay: true
|
|
23356
23586
|
});
|
|
23587
|
+
if (enqueued) recordDeliveredCompletion({ executionId, text: resumeBody });
|
|
23357
23588
|
if (event && typeof event === "object") event.modelVisibleDelivered = true;
|
|
23358
23589
|
}
|
|
23359
23590
|
return true;
|
|
23360
23591
|
}
|
|
23361
|
-
|
|
23362
|
-
set(agentStatusState({ force: true }));
|
|
23363
|
-
}
|
|
23592
|
+
refreshAgentStatus(parsed);
|
|
23364
23593
|
const modelContent = String(delivery.modelContent ?? delivery.displayText ?? text).trim();
|
|
23365
23594
|
const imagePaths = parseInboundImagePaths(event?.meta?.image_paths);
|
|
23366
23595
|
if (!modelContent && imagePaths.length === 0) return true;
|
|
@@ -23403,12 +23632,68 @@ function createAgentJobFeed({
|
|
|
23403
23632
|
kickExecutionPendingResume,
|
|
23404
23633
|
flushDeferredExecutionPendingResumeKick,
|
|
23405
23634
|
scheduleExecutionPendingResumeKick,
|
|
23635
|
+
discardExecutionPendingResume,
|
|
23406
23636
|
updateAgentJobCard,
|
|
23407
23637
|
buildAgentJobCardPatch,
|
|
23408
23638
|
subscribeRuntimeNotifications
|
|
23409
23639
|
};
|
|
23410
23640
|
}
|
|
23411
23641
|
|
|
23642
|
+
// src/tui/engine/agent-response-tail.mjs
|
|
23643
|
+
function responseEntry(response = {}) {
|
|
23644
|
+
return {
|
|
23645
|
+
key: String(response.key || ""),
|
|
23646
|
+
raw: String(response.rawResult ?? response.raw ?? "").trim(),
|
|
23647
|
+
result: response.result,
|
|
23648
|
+
hasBody: response.hasBody === true,
|
|
23649
|
+
isError: response.isError === true
|
|
23650
|
+
};
|
|
23651
|
+
}
|
|
23652
|
+
function formatAgentResponseRaw(entries = []) {
|
|
23653
|
+
return entries.map((entry, index) => {
|
|
23654
|
+
const raw = String(entry?.raw || "").trim();
|
|
23655
|
+
return raw ? `${index + 1}. agent
|
|
23656
|
+
${raw}` : "";
|
|
23657
|
+
}).filter(Boolean).join("\n\n");
|
|
23658
|
+
}
|
|
23659
|
+
function priorEntries(previous) {
|
|
23660
|
+
if (Array.isArray(previous?.agentResponseEntries) && previous.agentResponseEntries.length) {
|
|
23661
|
+
return previous.agentResponseEntries.map(responseEntry);
|
|
23662
|
+
}
|
|
23663
|
+
return [responseEntry({
|
|
23664
|
+
key: previous?.agentResponseKey,
|
|
23665
|
+
rawResult: previous?.rawResult ?? previous?.result,
|
|
23666
|
+
result: previous?.result,
|
|
23667
|
+
hasBody: previous?.agentResponseHasBody,
|
|
23668
|
+
isError: previous?.isError
|
|
23669
|
+
})];
|
|
23670
|
+
}
|
|
23671
|
+
function appendAgentResponseTail(previous, response, now = Date.now()) {
|
|
23672
|
+
if (previous?.kind !== "tool" || previous.agentDirection !== "inbound") return null;
|
|
23673
|
+
const next = responseEntry(response);
|
|
23674
|
+
const entries = priorEntries(previous);
|
|
23675
|
+
const existingIndex = next.key ? entries.findIndex((entry) => entry.key === next.key) : -1;
|
|
23676
|
+
if (existingIndex >= 0) {
|
|
23677
|
+
entries[existingIndex] = next;
|
|
23678
|
+
} else {
|
|
23679
|
+
if (previous.agentResponseHasBody !== next.hasBody) return null;
|
|
23680
|
+
entries.push(next);
|
|
23681
|
+
}
|
|
23682
|
+
return {
|
|
23683
|
+
args: response.args,
|
|
23684
|
+
result: response.result,
|
|
23685
|
+
rawResult: formatAgentResponseRaw(entries) || null,
|
|
23686
|
+
isError: entries.some((entry) => entry.isError),
|
|
23687
|
+
count: entries.length,
|
|
23688
|
+
completedCount: entries.length,
|
|
23689
|
+
completedAt: now,
|
|
23690
|
+
agentResponseEntries: entries,
|
|
23691
|
+
agentResponseKeys: entries.map((entry) => entry.key).filter(Boolean),
|
|
23692
|
+
agentResponseHasBody: entries.every((entry) => entry.hasBody),
|
|
23693
|
+
agentResponseAggregate: entries.length > 1
|
|
23694
|
+
};
|
|
23695
|
+
}
|
|
23696
|
+
|
|
23412
23697
|
// src/tui/engine/tui-steering-persist.mjs
|
|
23413
23698
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
23414
23699
|
import { join as join8 } from "path";
|
|
@@ -23778,6 +24063,10 @@ function createSessionFlow(bag) {
|
|
|
23778
24063
|
skipSlashCommands: options.skipSlashCommands === true,
|
|
23779
24064
|
displayText: mode === "task-notification" ? notificationDisplayText(displayText) : String(displayText || ""),
|
|
23780
24065
|
suppressDisplay: options.suppressDisplay === true,
|
|
24066
|
+
// Completion resumes are consumed exactly once: Esc abandons their
|
|
24067
|
+
// uncommitted body instead of putting it back at the queue front.
|
|
24068
|
+
abortDiscardOnAbort: options.abortDiscardOnAbort === true,
|
|
24069
|
+
resumeCompletionKeys: Array.isArray(options.resumeCompletionKeys) ? options.resumeCompletionKeys.filter((key) => key != null && String(key).trim()) : [],
|
|
23781
24070
|
steeringPersistId: options.steeringPersistId || null,
|
|
23782
24071
|
steeringPersistRestored: options.steeringPersistRestored === true
|
|
23783
24072
|
};
|
|
@@ -23893,6 +24182,13 @@ function createSessionFlow(bag) {
|
|
|
23893
24182
|
pushUserOrSyntheticItem(entry.text, entry.id, isQueuedEntryEditable(entry) ? "user" : "injected");
|
|
23894
24183
|
}
|
|
23895
24184
|
const nonEditable = batch.filter((entry) => !isQueuedEntryEditable(entry));
|
|
24185
|
+
const discardOnAbort = nonEditable.filter(
|
|
24186
|
+
(entry) => entry?.abortDiscardOnAbort === true || entry?.mode === "pending-resume"
|
|
24187
|
+
);
|
|
24188
|
+
const requeueOnAbort = nonEditable.filter((entry) => !discardOnAbort.includes(entry));
|
|
24189
|
+
const discardExecutionPendingResumeKeys = discardOnAbort.flatMap(
|
|
24190
|
+
(entry) => Array.isArray(entry?.resumeCompletionKeys) ? entry.resumeCompletionKeys : []
|
|
24191
|
+
);
|
|
23896
24192
|
const batchPastedImages = mergePastedImages(batch);
|
|
23897
24193
|
const batchPastedTexts = mergePastedTexts(batch);
|
|
23898
24194
|
const turnStatus = await bag.runTurn(merged, {
|
|
@@ -23902,7 +24198,8 @@ function createSessionFlow(bag) {
|
|
|
23902
24198
|
onCommitted: () => commitSteeringQueueEntries(batch),
|
|
23903
24199
|
submittedIds: [...ids],
|
|
23904
24200
|
restorable: nonEditable.length === 0,
|
|
23905
|
-
requeueOnAbort
|
|
24201
|
+
requeueOnAbort,
|
|
24202
|
+
discardExecutionPendingResumeKeys
|
|
23906
24203
|
});
|
|
23907
24204
|
if (flags.drainEpoch !== drainEpoch) return;
|
|
23908
24205
|
flushDeferredClearedSessionUi();
|
|
@@ -24250,7 +24547,8 @@ function createRunTurn(bag) {
|
|
|
24250
24547
|
submittedIds,
|
|
24251
24548
|
reclaimed: false,
|
|
24252
24549
|
committed: false,
|
|
24253
|
-
requeueEntries: Array.isArray(options.requeueOnAbort) ? options.requeueOnAbort.slice() : []
|
|
24550
|
+
requeueEntries: Array.isArray(options.requeueOnAbort) ? options.requeueOnAbort.slice() : [],
|
|
24551
|
+
discardExecutionPendingResumeKeys: Array.isArray(options.discardExecutionPendingResumeKeys) ? options.discardExecutionPendingResumeKeys.slice() : []
|
|
24254
24552
|
};
|
|
24255
24553
|
set({ busy: true, lastTurn: null, spinner: { active: true, verb: pickVerb(turnIndex), startedAt, responseLength: 0, inputTokens: 0, outputTokens: 0, mode: "requesting" } });
|
|
24256
24554
|
let assistantText = "";
|
|
@@ -24333,6 +24631,7 @@ function createRunTurn(bag) {
|
|
|
24333
24631
|
};
|
|
24334
24632
|
armWatchdog();
|
|
24335
24633
|
let currentAssistantText = "";
|
|
24634
|
+
const committedSegments = [];
|
|
24336
24635
|
let thinkingText = "";
|
|
24337
24636
|
let thinkingStartedAt = 0;
|
|
24338
24637
|
let thinkingSegmentStartedAt = 0;
|
|
@@ -24348,7 +24647,8 @@ function createRunTurn(bag) {
|
|
|
24348
24647
|
const earlyResultBuffer = /* @__PURE__ */ new Map();
|
|
24349
24648
|
const aggregateCards = [];
|
|
24350
24649
|
let tailAggregate = null;
|
|
24351
|
-
|
|
24650
|
+
let providerToolBatch = 0;
|
|
24651
|
+
const TOOL_CARD_PUSH_DELAY_MS = 1e3;
|
|
24352
24652
|
let deferredSeqCounter = 0;
|
|
24353
24653
|
const deferredEntries = [];
|
|
24354
24654
|
const flushDeferredUpTo = (entry) => {
|
|
@@ -24515,10 +24815,11 @@ function createRunTurn(bag) {
|
|
|
24515
24815
|
aggregate.ensureVisible?.();
|
|
24516
24816
|
const errors = allCalls.filter((r) => r.isError).length;
|
|
24517
24817
|
const callErrors = allCalls.filter((r) => r.isCallError).length;
|
|
24818
|
+
const exitErrors = allCalls.filter((r) => r.isExitError).length;
|
|
24518
24819
|
const completed = allCalls.filter((r) => r.resolved).length;
|
|
24519
|
-
const succeeded = completed - errors;
|
|
24820
|
+
const succeeded = Math.max(0, completed - errors - exitErrors);
|
|
24520
24821
|
const rawResult = aggregateRawResult(allCalls);
|
|
24521
|
-
const displayDetail = errors > 0
|
|
24822
|
+
const displayDetail = errors > 0 || exitErrors > 0 ? failureDetailText({ succeeded, realErrors: callErrors, exitErrors, exitCode: allCalls.find((r) => r.isExitError)?.exitCode }) : formatAggregateDetail(aggregateSummaries(aggregate));
|
|
24522
24823
|
patchItem(aggregate.itemId, {
|
|
24523
24824
|
result: displayDetail,
|
|
24524
24825
|
text: displayDetail,
|
|
@@ -24526,6 +24827,7 @@ function createRunTurn(bag) {
|
|
|
24526
24827
|
isError: errors > 0,
|
|
24527
24828
|
errorCount: errors,
|
|
24528
24829
|
callErrorCount: callErrors,
|
|
24830
|
+
exitErrorCount: exitErrors,
|
|
24529
24831
|
count: allCalls.length,
|
|
24530
24832
|
completedCount: allCalls.length,
|
|
24531
24833
|
doneCategories: aggregateDoneCategories(allCalls),
|
|
@@ -24616,6 +24918,7 @@ function createRunTurn(bag) {
|
|
|
24616
24918
|
if (sealToolBlock) clearAggregateContinuation();
|
|
24617
24919
|
const id = currentAssistantId || ensureAssistant(text);
|
|
24618
24920
|
patchItem(id, { text, streaming: false });
|
|
24921
|
+
committedSegments.push(text);
|
|
24619
24922
|
closeAssistantSegment();
|
|
24620
24923
|
return true;
|
|
24621
24924
|
};
|
|
@@ -24732,24 +25035,25 @@ function createRunTurn(bag) {
|
|
|
24732
25035
|
if (!callRec || callRec.resolved || callRec.completedEarly) return;
|
|
24733
25036
|
aggregate.ensureVisible?.();
|
|
24734
25037
|
const rawText = toolResultText(message?.content);
|
|
24735
|
-
const
|
|
24736
|
-
const
|
|
24737
|
-
const isResultError = /^\s*\[?error/i.test(rawText) || isErrorToolStatus(toolResultStatus(rawText)) || isMemoryCall && memoryCoreResultErrorText(rawText) != null;
|
|
24738
|
-
const isError = isCallError || isResultError;
|
|
25038
|
+
const { exitCode, isExitError, isCallError } = toolCallOutcome(message, rawText);
|
|
25039
|
+
const isError = isCallError;
|
|
24739
25040
|
const text = isError ? toolErrorDisplay(rawText, callRec.name || "tool") : rawText;
|
|
24740
25041
|
callRec.summary = !isError ? summarizeToolResult(callRec.name, callRec.args, rawText, isError) : null;
|
|
24741
25042
|
assignAggregateSummaryOrder(aggregate, callRec);
|
|
24742
25043
|
callRec.isError = isError;
|
|
24743
25044
|
callRec.isCallError = isCallError;
|
|
25045
|
+
callRec.isExitError = isExitError;
|
|
25046
|
+
callRec.exitCode = exitCode;
|
|
24744
25047
|
callRec.resultText = text;
|
|
24745
25048
|
callRec.completedEarly = true;
|
|
24746
25049
|
const allCalls = [...aggregate.calls.values()];
|
|
24747
25050
|
const completedCount = allCalls.filter((r) => r.resolved || r.completedEarly).length;
|
|
24748
25051
|
const errors = allCalls.filter((r) => r.isError).length;
|
|
24749
25052
|
const callErrors = allCalls.filter((r) => r.isCallError).length;
|
|
24750
|
-
const
|
|
25053
|
+
const exitErrors = allCalls.filter((r) => r.isExitError).length;
|
|
25054
|
+
const succeeded = Math.max(0, completedCount - errors - exitErrors);
|
|
24751
25055
|
const rawResult = aggregateRawResult(allCalls);
|
|
24752
|
-
const displayDetail = errors > 0
|
|
25056
|
+
const displayDetail = errors > 0 || exitErrors > 0 ? failureDetailText({ succeeded, realErrors: callErrors, exitErrors, exitCode: allCalls.find((r) => r.isExitError)?.exitCode }) : formatAggregateDetail(aggregateSummaries(aggregate));
|
|
24753
25057
|
const currentItem = getState().items.find((it) => it.id === card.itemId);
|
|
24754
25058
|
const visualCompleted = Math.max(
|
|
24755
25059
|
completedCount,
|
|
@@ -24761,6 +25065,7 @@ function createRunTurn(bag) {
|
|
|
24761
25065
|
isError: errors > 0,
|
|
24762
25066
|
errorCount: errors,
|
|
24763
25067
|
callErrorCount: callErrors,
|
|
25068
|
+
exitErrorCount: exitErrors,
|
|
24764
25069
|
count: allCalls.length,
|
|
24765
25070
|
completedCount: visualCompleted
|
|
24766
25071
|
};
|
|
@@ -24786,10 +25091,7 @@ function createRunTurn(bag) {
|
|
|
24786
25091
|
if (!markTurnProgress("steer-message")) return;
|
|
24787
25092
|
if (text === STEERING_SUPPRESSED_DISPLAY) return;
|
|
24788
25093
|
flushStreamBatch();
|
|
24789
|
-
|
|
24790
|
-
patchItem(currentAssistantId, { text: currentAssistantText || assistantText, streaming: false });
|
|
24791
|
-
closeAssistantSegment();
|
|
24792
|
-
}
|
|
25094
|
+
commitAssistantSegment({ sealToolBlock: true });
|
|
24793
25095
|
assistantText = "";
|
|
24794
25096
|
const value = String(text || "").trim();
|
|
24795
25097
|
if (value) {
|
|
@@ -24810,6 +25112,7 @@ function createRunTurn(bag) {
|
|
|
24810
25112
|
}
|
|
24811
25113
|
const batchCalls = (calls || []).filter(Boolean);
|
|
24812
25114
|
if (batchCalls.length === 0) return;
|
|
25115
|
+
const agentBatch = ++providerToolBatch;
|
|
24813
25116
|
const committedAssistantSegment = commitAssistantSegment({ sealToolBlock: true });
|
|
24814
25117
|
if (committedAssistantSegment) {
|
|
24815
25118
|
await yieldToRenderer({ frames: 2 });
|
|
@@ -24822,7 +25125,7 @@ function createRunTurn(bag) {
|
|
|
24822
25125
|
const name = toolCallName(c);
|
|
24823
25126
|
const args = toolCallArgs(c);
|
|
24824
25127
|
const category = classifyToolCategory(name, args);
|
|
24825
|
-
const bucket = category
|
|
25128
|
+
const bucket = aggregateBucketForCategory(category, { agentBatch });
|
|
24826
25129
|
const callId = toolCallId(c);
|
|
24827
25130
|
const callKey = callId || `__tool_${toolCards.length}_${i}`;
|
|
24828
25131
|
const activeCount = Number(aggregateToolCategoryEntry(name, args, category)?.count || 1);
|
|
@@ -24865,7 +25168,7 @@ function createRunTurn(bag) {
|
|
|
24865
25168
|
...categoryEntry,
|
|
24866
25169
|
count: Number(prevCategory?.count || 0) + Number(categoryEntry.count || 1)
|
|
24867
25170
|
});
|
|
24868
|
-
aggregateCard.calls.set(callKey, { name, args, category, summary: null, summarySeq: null, isError: false, isCallError: false, resultText: null, resolved: false, completedEarly: false });
|
|
25171
|
+
aggregateCard.calls.set(callKey, { name, args, category, summary: null, summarySeq: null, isError: false, isCallError: false, isExitError: false, exitCode: null, resultText: null, resolved: false, completedEarly: false });
|
|
24869
25172
|
touchedAggregates.add(aggregateCard);
|
|
24870
25173
|
const card = { itemId: aggregateCard.itemId, callId: callKey, done: false, aggregate: aggregateCard };
|
|
24871
25174
|
if (callId) {
|
|
@@ -25013,10 +25316,18 @@ function createRunTurn(bag) {
|
|
|
25013
25316
|
flushStreamBatch();
|
|
25014
25317
|
syncContextStats({ allowEstimated: true });
|
|
25015
25318
|
const finalText = result?.content != null ? String(result.content) : "";
|
|
25016
|
-
|
|
25017
|
-
|
|
25018
|
-
|
|
25019
|
-
|
|
25319
|
+
let finalRemainder = finalText;
|
|
25320
|
+
for (const seg of committedSegments) {
|
|
25321
|
+
const skipped = finalRemainder.replace(/^\s+/, "");
|
|
25322
|
+
const trimmedSeg = seg ? seg.replace(/^\s+/, "") : "";
|
|
25323
|
+
if (trimmedSeg && skipped.startsWith(trimmedSeg)) {
|
|
25324
|
+
finalRemainder = skipped.slice(trimmedSeg.length);
|
|
25325
|
+
}
|
|
25326
|
+
}
|
|
25327
|
+
if (finalRemainder.trim()) {
|
|
25328
|
+
const id = currentAssistantId || ensureAssistant(finalRemainder);
|
|
25329
|
+
currentAssistantText = finalRemainder;
|
|
25330
|
+
patchItem(id, { text: finalRemainder, streaming: false });
|
|
25020
25331
|
} else if (currentAssistantId && (currentAssistantText.trim() || assistantText.trim())) {
|
|
25021
25332
|
const streamedText = currentAssistantText || assistantText;
|
|
25022
25333
|
patchItem(currentAssistantId, { text: streamedText, streaming: false });
|
|
@@ -25807,7 +26118,8 @@ function createEngineApiA(bag) {
|
|
|
25807
26118
|
restoreQueued,
|
|
25808
26119
|
resetStatsAndSyncContext,
|
|
25809
26120
|
drain,
|
|
25810
|
-
flushDeferredExecutionPendingResumeKick
|
|
26121
|
+
flushDeferredExecutionPendingResumeKick,
|
|
26122
|
+
discardExecutionPendingResume
|
|
25811
26123
|
} = bag;
|
|
25812
26124
|
return {
|
|
25813
26125
|
getState: () => getState(),
|
|
@@ -26301,9 +26613,14 @@ function createEngineApiA(bag) {
|
|
|
26301
26613
|
const restorePastedTexts = canRestore && restoreState?.pastedTexts ? restoreState.pastedTexts : null;
|
|
26302
26614
|
const discardPastedImages = restoreState?.restorable && hasPendingSteering && restoreState?.pastedImages ? restoreState.pastedImages : null;
|
|
26303
26615
|
const discardPastedTexts = restoreState?.restorable && hasPendingSteering && restoreState?.pastedTexts ? restoreState.pastedTexts : null;
|
|
26304
|
-
const requeueEntries = restoreState && !restoreState.committed && Array.isArray(restoreState.requeueEntries) ? restoreState.requeueEntries.
|
|
26616
|
+
const requeueEntries = restoreState && !restoreState.committed && Array.isArray(restoreState.requeueEntries) ? restoreState.requeueEntries.filter(
|
|
26617
|
+
(entry) => entry?.abortDiscardOnAbort !== true && entry?.mode !== "pending-resume"
|
|
26618
|
+
) : [];
|
|
26305
26619
|
const aborted = runtime.abort("cli-react-abort");
|
|
26306
26620
|
if (restoreState) {
|
|
26621
|
+
if (aborted !== false && Array.isArray(restoreState.discardExecutionPendingResumeKeys)) {
|
|
26622
|
+
discardExecutionPendingResume?.(restoreState.discardExecutionPendingResumeKeys);
|
|
26623
|
+
}
|
|
26307
26624
|
if ((restoreText || requeueEntries.length > 0) && aborted !== false) {
|
|
26308
26625
|
restoreState.reclaimed = true;
|
|
26309
26626
|
const idSet = new Set((restoreState.submittedIds || []).filter((id) => id != null));
|
|
@@ -26319,6 +26636,7 @@ function createEngineApiA(bag) {
|
|
|
26319
26636
|
}
|
|
26320
26637
|
restoreState.restorable = false;
|
|
26321
26638
|
restoreState.requeueEntries = [];
|
|
26639
|
+
restoreState.discardExecutionPendingResumeKeys = [];
|
|
26322
26640
|
}
|
|
26323
26641
|
const abortEpoch = flags.leadTurnEpoch;
|
|
26324
26642
|
const recoveryMs = Number(flags.manualAbortRecoveryMs) > 0 ? Number(flags.manualAbortRecoveryMs) : MANUAL_ABORT_RECOVERY_MS;
|
|
@@ -26579,6 +26897,59 @@ async function createEngineSession({
|
|
|
26579
26897
|
if (origin === "user") appendPromptHistory(state.cwd, text);
|
|
26580
26898
|
pushItem({ kind: "user", id, text });
|
|
26581
26899
|
};
|
|
26900
|
+
const pushAsyncAgentResponse = (text, id = nextId(), origin = "injected", metadata = {}) => {
|
|
26901
|
+
const synthetic = parseSyntheticAgentMessage(text);
|
|
26902
|
+
const isAgent = synthetic?.name === "agent";
|
|
26903
|
+
if (!isAgent) return pushUserOrSyntheticItem(text, id, origin);
|
|
26904
|
+
const responseHasBody = /\n\s*\n[\s\S]*\S/.test(String(text || ""));
|
|
26905
|
+
const rawResult = synthetic.rawResult ?? text;
|
|
26906
|
+
const args = {
|
|
26907
|
+
...synthetic.args && typeof synthetic.args === "object" ? synthetic.args : {},
|
|
26908
|
+
type: "result"
|
|
26909
|
+
};
|
|
26910
|
+
const responseKey = String(metadata.responseKey || metadata.executionId || args.task_id || "").trim();
|
|
26911
|
+
const previous = state.items.at(-1);
|
|
26912
|
+
if (previous?.kind === "tool" && previous.agentDirection === "inbound") {
|
|
26913
|
+
const patch = appendAgentResponseTail(previous, {
|
|
26914
|
+
key: responseKey,
|
|
26915
|
+
args,
|
|
26916
|
+
result: synthetic.result,
|
|
26917
|
+
rawResult,
|
|
26918
|
+
hasBody: responseHasBody,
|
|
26919
|
+
isError: synthetic.isError === true
|
|
26920
|
+
});
|
|
26921
|
+
if (patch) {
|
|
26922
|
+
patchItem(previous.id, patch);
|
|
26923
|
+
return true;
|
|
26924
|
+
}
|
|
26925
|
+
}
|
|
26926
|
+
pushItem({
|
|
26927
|
+
kind: "tool",
|
|
26928
|
+
id,
|
|
26929
|
+
name: "agent",
|
|
26930
|
+
args,
|
|
26931
|
+
result: synthetic.result,
|
|
26932
|
+
rawResult,
|
|
26933
|
+
isError: synthetic.isError === true,
|
|
26934
|
+
expanded: false,
|
|
26935
|
+
count: 1,
|
|
26936
|
+
completedCount: 1,
|
|
26937
|
+
startedAt: Date.now(),
|
|
26938
|
+
completedAt: Date.now(),
|
|
26939
|
+
agentDirection: "inbound",
|
|
26940
|
+
agentResponseKey: responseKey,
|
|
26941
|
+
agentResponseHasBody: responseHasBody,
|
|
26942
|
+
agentResponseAggregate: false,
|
|
26943
|
+
agentResponseEntries: [{
|
|
26944
|
+
key: responseKey,
|
|
26945
|
+
raw: String(rawResult ?? "").trim(),
|
|
26946
|
+
result: synthetic.result,
|
|
26947
|
+
hasBody: responseHasBody,
|
|
26948
|
+
isError: synthetic.isError === true
|
|
26949
|
+
}]
|
|
26950
|
+
});
|
|
26951
|
+
return true;
|
|
26952
|
+
};
|
|
26582
26953
|
const pushToast = (text, tone = "info", ttlMs = 3e3) => {
|
|
26583
26954
|
const id = nextId();
|
|
26584
26955
|
const value = String(text ?? "").trim();
|
|
@@ -26668,6 +27039,7 @@ async function createEngineSession({
|
|
|
26668
27039
|
kickExecutionPendingResume,
|
|
26669
27040
|
flushDeferredExecutionPendingResumeKick,
|
|
26670
27041
|
scheduleExecutionPendingResumeKick,
|
|
27042
|
+
discardExecutionPendingResume,
|
|
26671
27043
|
updateAgentJobCard,
|
|
26672
27044
|
buildAgentJobCardPatch,
|
|
26673
27045
|
subscribeRuntimeNotifications
|
|
@@ -26681,6 +27053,7 @@ async function createEngineSession({
|
|
|
26681
27053
|
enqueue: (...args) => bag.enqueue(...args),
|
|
26682
27054
|
drain: (...args) => bag.drain(...args),
|
|
26683
27055
|
pushUserOrSyntheticItem,
|
|
27056
|
+
pushAsyncAgentResponse,
|
|
26684
27057
|
makeQueueEntry: (...args) => bag.makeQueueEntry(...args),
|
|
26685
27058
|
getPending: () => pending,
|
|
26686
27059
|
agentStatusState,
|
|
@@ -26728,6 +27101,7 @@ async function createEngineSession({
|
|
|
26728
27101
|
removeNotice,
|
|
26729
27102
|
setProgressHint,
|
|
26730
27103
|
pushUserOrSyntheticItem,
|
|
27104
|
+
pushAsyncAgentResponse,
|
|
26731
27105
|
upsertSyntheticToolItem,
|
|
26732
27106
|
markToolCallActive,
|
|
26733
27107
|
markToolCallDone,
|
|
@@ -26747,6 +27121,7 @@ async function createEngineSession({
|
|
|
26747
27121
|
kickExecutionPendingResume,
|
|
26748
27122
|
flushDeferredExecutionPendingResumeKick,
|
|
26749
27123
|
scheduleExecutionPendingResumeKick,
|
|
27124
|
+
discardExecutionPendingResume,
|
|
26750
27125
|
updateAgentJobCard,
|
|
26751
27126
|
subscribeRuntimeNotifications
|
|
26752
27127
|
});
|