@agent-native/core 0.84.1 → 0.84.3
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +15 -0
- package/corpus/core/docs/design/durable-agent-runs.md +34 -35
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/engine/builder-engine.ts +81 -9
- package/corpus/core/src/agent/production-agent.ts +9 -2
- package/corpus/core/src/agent/run-loop-with-resume.ts +38 -8
- package/corpus/core/src/agent/run-manager.ts +8 -7
- package/corpus/core/src/agent/thread-data-builder.ts +6 -0
- package/corpus/core/src/cli/design-connect.ts +175 -0
- package/corpus/core/src/cli/skills.ts +5 -7
- package/corpus/core/src/client/AgentPanel.tsx +8 -0
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +4 -1
- package/corpus/core/src/client/agent-chat-adapter.ts +253 -24
- package/corpus/core/src/client/sharing/ShareButton.tsx +70 -21
- package/corpus/core/src/client/sse-event-processor.ts +46 -4
- package/corpus/core/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +15 -17
- package/corpus/templates/analytics/AGENTS.md +1 -1
- package/corpus/templates/design/actions/apply-motion-edit.ts +50 -18
- package/corpus/templates/design/actions/get-motion-timeline.ts +4 -14
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +156 -12
- package/corpus/templates/design/app/components/design/MotionDock.tsx +2 -3
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +217 -75
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +39 -39
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +558 -37
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +75 -3
- package/corpus/templates/design/app/components/design/types.ts +13 -0
- package/corpus/templates/design/app/components/layout/Layout.tsx +1 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +17 -0
- package/corpus/templates/design/app/i18n-data.ts +245 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +890 -252
- package/corpus/templates/design/changelog/2026-06-30-agent-chat-now-reports-saved-design-generations-clearly-when.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-apply-styles-now-appears-only-for-localhost-visual-edit-scre.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-copying-or-dragging-screen-elements-onto-the-infinite-canvas.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-questions-now-use-tighter-editor-typography-and-contr.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-element-drags-can-be-cancelled-with-escape-before-they-commi.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-pending-visual-style-edits-now-warn-before-you-leave-the-edi.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-share-options-now-make-export-and-agent-handoff-easier-to-no.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-visual-style-drags-stay-live-while-pending-edits-can-be-appl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-01-design-chat-no-longer-shows-a-redundant-context-tab-above-the-composer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-01-motion-track-creation-no-longer-fails-in-local-editors.md +6 -0
- package/corpus/templates/design/changelog/2026-07-01-share-general-access-menu-stays-open-when-choosing-organization.md +6 -0
- package/corpus/templates/design/server/plugins/db.ts +10 -0
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +61 -10
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +9 -2
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts +2 -2
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +31 -8
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/agent/run-manager.d.ts +8 -7
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +8 -7
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts +2 -0
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +5 -0
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/cli/design-connect.d.ts +2 -0
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +140 -0
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +5 -7
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +5 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +4 -4
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts +3 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +2 -2
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +216 -22
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts +6 -0
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +25 -11
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +18 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +34 -5
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +2 -2
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +7 -7
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +15 -17
- package/docs/design/durable-agent-runs.md +34 -35
- package/package.json +1 -1
- package/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +15 -17
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-chat-adapter.d.ts","sourceRoot":"","sources":["../../src/client/agent-chat-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAsB,MAAM,qBAAqB,CAAC;AAMhF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-chat-adapter.d.ts","sourceRoot":"","sources":["../../src/client/agent-chat-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAsB,MAAM,qBAAqB,CAAC;AAMhF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAkBrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,MAAM,MAAM,oBAAoB;AAC9B;;;;GAIG;AACD,KAAK;AACP,0EAA0E;GACxE,WAAW,CAAC;AA0oChB;;;;GAIG;AACH;;;GAGG;AACH,MAAM,WAAW,6BAA6B;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC3C,SAAS,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC5C,SAAS,CAAC,EAAE;QAAE,OAAO,EAAE,eAAe,GAAG,SAAS,CAAA;KAAE,CAAC;IACrD,WAAW,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IACxD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,CAAA;KAAE,CAAC;IAC3D,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC;AAED,wBAAgB,sBAAsB,CACpC,OAAO,CAAC,EAAE,6BAA6B,GACtC,gBAAgB,CAs6ClB"}
|
|
@@ -529,6 +529,34 @@ function hasContinuationProgress(content) {
|
|
|
529
529
|
? part.text.trim().length > 0
|
|
530
530
|
: part.result !== undefined);
|
|
531
531
|
}
|
|
532
|
+
function lastCompletedSideEffectTool(content) {
|
|
533
|
+
for (let i = content.length - 1; i >= 0; i--) {
|
|
534
|
+
const part = content[i];
|
|
535
|
+
if (part.type === "tool-call" &&
|
|
536
|
+
part.activity !== true &&
|
|
537
|
+
part.result !== undefined &&
|
|
538
|
+
part.isError !== true &&
|
|
539
|
+
part.completedSideEffect === true) {
|
|
540
|
+
return part;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return undefined;
|
|
544
|
+
}
|
|
545
|
+
function humanizeActionName(toolName) {
|
|
546
|
+
return toolName
|
|
547
|
+
.replace(/^agent:/, "")
|
|
548
|
+
.replace(/[-_]+/g, " ")
|
|
549
|
+
.trim();
|
|
550
|
+
}
|
|
551
|
+
function completedToolTimeoutMessage(toolName) {
|
|
552
|
+
if (toolName === "generate-design" || toolName === "update-design") {
|
|
553
|
+
return "The design was saved, but the assistant timed out before sending its final note. You can open the generated design from the completed tool card above.";
|
|
554
|
+
}
|
|
555
|
+
if (toolName === "present-design-variants") {
|
|
556
|
+
return "The design variants were saved, but the assistant timed out before sending its final note. You can review the completed variants from the tool card above.";
|
|
557
|
+
}
|
|
558
|
+
return `The ${humanizeActionName(toolName)} action completed, but the assistant timed out before sending its final response. The saved result is in the completed tool card above.`;
|
|
559
|
+
}
|
|
532
560
|
/**
|
|
533
561
|
* Signature of the *unique* sentence-like segments in a continuation's newly
|
|
534
562
|
* streamed text, used to detect a degenerate repetition loop. A stuck model
|
|
@@ -603,6 +631,8 @@ function toolContinuationKey(part) {
|
|
|
603
631
|
stableJson(part.args),
|
|
604
632
|
part.result === undefined ? "pending" : "done",
|
|
605
633
|
part.result ?? "",
|
|
634
|
+
part.isError === true ? "error" : "",
|
|
635
|
+
part.completedSideEffect === true ? "side-effect" : "",
|
|
606
636
|
part.activity === true ? "activity" : "tool",
|
|
607
637
|
part.mcpApp ? "mcp-app" : "",
|
|
608
638
|
].join("\u0000");
|
|
@@ -657,6 +687,8 @@ function incrementalActionGuidance(tool) {
|
|
|
657
687
|
case "generate-design":
|
|
658
688
|
case "update-design":
|
|
659
689
|
return "persist a minimal first version (fewer files) with `generate-design`, then refine individual files with `edit-design` search/replace instead of resending everything";
|
|
690
|
+
case "present-design-variants":
|
|
691
|
+
return "save compact but complete variant screens with `present-design-variants` first, keeping each HTML direction focused enough to finish, then refine the chosen direction with `generate-design` or `edit-design`";
|
|
660
692
|
case "create-visual-plan":
|
|
661
693
|
case "create-ui-plan":
|
|
662
694
|
case "create-plan-design":
|
|
@@ -1039,11 +1071,13 @@ export function createAgentChatAdapter(options) {
|
|
|
1039
1071
|
// its own budget rather than inheriting the prior payload's.
|
|
1040
1072
|
let lastInFlightToolSignature;
|
|
1041
1073
|
let repeatedInFlightToolCount = 0;
|
|
1074
|
+
let recoveryGaveUpOnInFlightTool = false;
|
|
1042
1075
|
const MAX_REPEATED_INFLIGHT_TOOL_STALLS = 3;
|
|
1043
1076
|
const continuationHistoryFragments = [];
|
|
1044
1077
|
const structuredContinuationFragments = [];
|
|
1045
1078
|
let visibleContinuationPrefix = [];
|
|
1046
1079
|
let lastAutoContinueReason = null;
|
|
1080
|
+
let lastRecoverableRunError = null;
|
|
1047
1081
|
const attemptedRunIds = [];
|
|
1048
1082
|
let authRecoveryAttempted = false;
|
|
1049
1083
|
let continuationToolCallCounter = 0;
|
|
@@ -1053,6 +1087,12 @@ export function createAgentChatAdapter(options) {
|
|
|
1053
1087
|
lastAutoContinueReason
|
|
1054
1088
|
? `last_auto_continue_reason: ${lastAutoContinueReason}`
|
|
1055
1089
|
: "",
|
|
1090
|
+
lastRecoverableRunError?.errorCode
|
|
1091
|
+
? `last_recoverable_error_code: ${lastRecoverableRunError.errorCode}`
|
|
1092
|
+
: "",
|
|
1093
|
+
lastRecoverableRunError?.message
|
|
1094
|
+
? `last_recoverable_error: ${lastRecoverableRunError.message}`
|
|
1095
|
+
: "",
|
|
1056
1096
|
`stale_run_continuations: ${staleRunContinuationAttempts}`,
|
|
1057
1097
|
`stalled_transient_continuations: ${stalledTransientContinuationAttempts}`,
|
|
1058
1098
|
`empty_transient_continuations: ${emptyTransientContinuationAttempts}`,
|
|
@@ -1070,6 +1110,9 @@ export function createAgentChatAdapter(options) {
|
|
|
1070
1110
|
.join("\n");
|
|
1071
1111
|
};
|
|
1072
1112
|
const exhaustedRecoveryMessage = (reason) => {
|
|
1113
|
+
if (recoveryGaveUpOnInFlightTool) {
|
|
1114
|
+
return "The agent got stuck waiting for the same tool to finish, so I stopped the automatic retries. The tool did not report a completed result.";
|
|
1115
|
+
}
|
|
1073
1116
|
if (recoveryGaveUpOnRepetition) {
|
|
1074
1117
|
return "The agent got stuck repeating the same response without finishing, so I stopped the automatic retries. This often happens when it tries to re-type a large pasted file into one action — starting a new chat, or asking for a smaller first step, usually gets it unstuck.";
|
|
1075
1118
|
}
|
|
@@ -1302,11 +1345,81 @@ export function createAgentChatAdapter(options) {
|
|
|
1302
1345
|
}
|
|
1303
1346
|
return false;
|
|
1304
1347
|
};
|
|
1348
|
+
const reconnectBackgroundContinuationForRunTimeout = async function* () {
|
|
1349
|
+
if (!threadId || !runId)
|
|
1350
|
+
return false;
|
|
1351
|
+
const interruptedRunId = runId;
|
|
1352
|
+
const interruptedLastSeq = lastSeq;
|
|
1353
|
+
let lastActiveRunError = null;
|
|
1354
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
1355
|
+
if (attempt > 0) {
|
|
1356
|
+
await delay(500, abortSignal);
|
|
1357
|
+
}
|
|
1358
|
+
if (abortSignal.aborted)
|
|
1359
|
+
return true;
|
|
1360
|
+
try {
|
|
1361
|
+
const activeRes = await fetch(`${apiUrl}/runs/active?threadId=${encodeURIComponent(threadId)}`, { signal: abortSignal });
|
|
1362
|
+
if (!activeRes.ok) {
|
|
1363
|
+
if (activeRes.status === 404)
|
|
1364
|
+
return false;
|
|
1365
|
+
lastActiveRunError = new Error(`Active run lookup failed: ${activeRes.status}`);
|
|
1366
|
+
continue;
|
|
1367
|
+
}
|
|
1368
|
+
const active = await activeRes.json();
|
|
1369
|
+
if (!active?.active || !active.runId)
|
|
1370
|
+
return false;
|
|
1371
|
+
const activeRunId = String(active.runId);
|
|
1372
|
+
const dispatchMode = typeof active.dispatchMode === "string"
|
|
1373
|
+
? active.dispatchMode
|
|
1374
|
+
: "";
|
|
1375
|
+
if (activeRunId === interruptedRunId) {
|
|
1376
|
+
if (dispatchMode.startsWith("background"))
|
|
1377
|
+
continue;
|
|
1378
|
+
return false;
|
|
1379
|
+
}
|
|
1380
|
+
const activeTurnId = typeof active.turnId === "string" ? active.turnId : "";
|
|
1381
|
+
const activeStatus = typeof active.status === "string" ? active.status : "";
|
|
1382
|
+
if (!dispatchMode.startsWith("background"))
|
|
1383
|
+
return false;
|
|
1384
|
+
if (activeTurnId && activeTurnId !== turnId)
|
|
1385
|
+
return false;
|
|
1386
|
+
if (activeStatus !== "running" && activeStatus !== "starting") {
|
|
1387
|
+
return false;
|
|
1388
|
+
}
|
|
1389
|
+
runId = activeRunId;
|
|
1390
|
+
if (!attemptedRunIds.includes(activeRunId)) {
|
|
1391
|
+
attemptedRunIds.push(activeRunId);
|
|
1392
|
+
}
|
|
1393
|
+
lastSeq = -1;
|
|
1394
|
+
setActiveRun({ threadId, runId: activeRunId, lastSeq: -1 });
|
|
1395
|
+
const reconnected = yield* reconnectCurrentRun();
|
|
1396
|
+
if (reconnected)
|
|
1397
|
+
return true;
|
|
1398
|
+
}
|
|
1399
|
+
catch (activeErr) {
|
|
1400
|
+
if (activeErr instanceof Error &&
|
|
1401
|
+
activeErr.name === "AbortError") {
|
|
1402
|
+
clearActiveRun();
|
|
1403
|
+
return true;
|
|
1404
|
+
}
|
|
1405
|
+
lastActiveRunError = activeErr;
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
if (lastActiveRunError) {
|
|
1409
|
+
captureChatClientError(lastActiveRunError, "reconnect-background-continuation-failed");
|
|
1410
|
+
}
|
|
1411
|
+
runId = interruptedRunId;
|
|
1412
|
+
lastSeq = interruptedLastSeq;
|
|
1413
|
+
return false;
|
|
1414
|
+
};
|
|
1305
1415
|
const visibleContentForContinuation = () => {
|
|
1306
1416
|
return contentAfterContinuationPrefix(content, visibleContinuationPrefix);
|
|
1307
1417
|
};
|
|
1308
1418
|
const prepareAutoContinuation = (signal) => {
|
|
1309
1419
|
lastAutoContinueReason = signal.reason;
|
|
1420
|
+
if (signal.errorInfo) {
|
|
1421
|
+
lastRecoverableRunError = signal.errorInfo;
|
|
1422
|
+
}
|
|
1310
1423
|
const isTransient = signal.reason !== "loop_limit";
|
|
1311
1424
|
const visibleContent = visibleContentForContinuation();
|
|
1312
1425
|
const currentPartialHistory = contentToContinuationHistory(visibleContent);
|
|
@@ -1315,13 +1428,13 @@ export function createAgentChatAdapter(options) {
|
|
|
1315
1428
|
// whitespace-only output cannot keep the run alive indefinitely.
|
|
1316
1429
|
const madeContentProgress = hasContinuationProgress(visibleContent);
|
|
1317
1430
|
// An action was streamed but has not returned yet (a tool_start with
|
|
1318
|
-
// no tool_done)
|
|
1319
|
-
//
|
|
1320
|
-
//
|
|
1321
|
-
//
|
|
1322
|
-
//
|
|
1323
|
-
const hasInFlightTool = hasInFlightToolCall(visibleContent)
|
|
1324
|
-
|
|
1431
|
+
// no tool_done). This is durable enough to survive continuation: the
|
|
1432
|
+
// server already emitted a real tool call. A tool-scoped activity
|
|
1433
|
+
// card ("Preparing generate-design") is useful UI, but it happens
|
|
1434
|
+
// before tool_start; treating it as progress caused silent retry
|
|
1435
|
+
// loops when the LLM timed out while assembling a large tool input.
|
|
1436
|
+
const hasInFlightTool = hasInFlightToolCall(visibleContent);
|
|
1437
|
+
const completedSideEffectTool = lastCompletedSideEffectTool(content);
|
|
1325
1438
|
// Either real output or an actively-running tool counts as progress
|
|
1326
1439
|
// for the stalled/empty caps.
|
|
1327
1440
|
const madeProgress = madeContentProgress || hasInFlightTool;
|
|
@@ -1334,11 +1447,11 @@ export function createAgentChatAdapter(options) {
|
|
|
1334
1447
|
// MAX_REPEATED_INFLIGHT_TOOL_STALLS consecutive stream_ended events,
|
|
1335
1448
|
// bail with a clear message.
|
|
1336
1449
|
//
|
|
1337
|
-
//
|
|
1338
|
-
//
|
|
1339
|
-
//
|
|
1340
|
-
//
|
|
1341
|
-
//
|
|
1450
|
+
// Count broken streams (connection drop / reconnect failed) and
|
|
1451
|
+
// no_progress stalls (the client aborts a stream that stayed open but
|
|
1452
|
+
// stopped producing events). Do NOT count run_timeout: with an
|
|
1453
|
+
// in-flight tool that means the server is still actively executing a
|
|
1454
|
+
// slow action and reconnection may recover the result.
|
|
1342
1455
|
const currentInFlightToolPart = visibleContent.find((p) => p.type === "tool-call" &&
|
|
1343
1456
|
p.result === undefined &&
|
|
1344
1457
|
p.activity !== true);
|
|
@@ -1346,8 +1459,8 @@ export function createAgentChatAdapter(options) {
|
|
|
1346
1459
|
const currentInFlightToolSignature = currentInFlightToolPart
|
|
1347
1460
|
? inFlightToolInputSignature(currentInFlightToolPart)
|
|
1348
1461
|
: undefined;
|
|
1349
|
-
const
|
|
1350
|
-
if (currentInFlightToolName &&
|
|
1462
|
+
const isBrokenInFlightTool = signal.reason === "stream_ended" || signal.reason === "no_progress";
|
|
1463
|
+
if (currentInFlightToolName && isBrokenInFlightTool) {
|
|
1351
1464
|
if (currentInFlightToolName === lastInFlightToolName &&
|
|
1352
1465
|
currentInFlightToolSignature === lastInFlightToolSignature) {
|
|
1353
1466
|
repeatedInFlightToolCount += 1;
|
|
@@ -1384,11 +1497,27 @@ export function createAgentChatAdapter(options) {
|
|
|
1384
1497
|
}
|
|
1385
1498
|
else {
|
|
1386
1499
|
totalTransientContinuationAttempts += 1;
|
|
1500
|
+
// If a mutating action already completed, do not turn a missing
|
|
1501
|
+
// closing sentence into a scary connection failure. Give the model
|
|
1502
|
+
// one continuation opportunity (the completed tool itself counts
|
|
1503
|
+
// as progress on the first timeout); if the follow-up produces no
|
|
1504
|
+
// new content, stop locally with a clear "saved, final note timed
|
|
1505
|
+
// out" message.
|
|
1506
|
+
if (completedSideEffectTool &&
|
|
1507
|
+
!hasInFlightToolCall(content) &&
|
|
1508
|
+
!madeContentProgress &&
|
|
1509
|
+
!hasInFlightTool) {
|
|
1510
|
+
return {
|
|
1511
|
+
ok: false,
|
|
1512
|
+
resetVisibleContent: false,
|
|
1513
|
+
completedToolName: completedSideEffectTool.toolName,
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1387
1516
|
// Bail when the same write tool is stuck in-flight across too many
|
|
1388
1517
|
// consecutive continuations. Checked before the text-repeat guard
|
|
1389
1518
|
// because hasInFlightTool=true would mask the repeat as progress.
|
|
1390
1519
|
if (repeatedInFlightToolCount >= MAX_REPEATED_INFLIGHT_TOOL_STALLS) {
|
|
1391
|
-
|
|
1520
|
+
recoveryGaveUpOnInFlightTool = true;
|
|
1392
1521
|
return { ok: false, resetVisibleContent: false };
|
|
1393
1522
|
}
|
|
1394
1523
|
// Bail fast on a non-advancing repetition loop, well before the
|
|
@@ -1751,6 +1880,11 @@ export function createAgentChatAdapter(options) {
|
|
|
1751
1880
|
if (err.reason === "no_progress") {
|
|
1752
1881
|
await abortCurrentRun();
|
|
1753
1882
|
}
|
|
1883
|
+
if (err.reason === "run_timeout" && !err.errorInfo) {
|
|
1884
|
+
const reconnected = yield* reconnectBackgroundContinuationForRunTimeout();
|
|
1885
|
+
if (reconnected)
|
|
1886
|
+
return;
|
|
1887
|
+
}
|
|
1754
1888
|
if (err.reason === "stream_ended") {
|
|
1755
1889
|
const reconnected = yield* reconnectCurrentRun();
|
|
1756
1890
|
if (reconnected)
|
|
@@ -1761,15 +1895,48 @@ export function createAgentChatAdapter(options) {
|
|
|
1761
1895
|
}
|
|
1762
1896
|
const continuation = prepareAutoContinuation(err);
|
|
1763
1897
|
if (!continuation.ok) {
|
|
1764
|
-
|
|
1898
|
+
if (continuation.completedToolName) {
|
|
1899
|
+
const message = completedToolTimeoutMessage(continuation.completedToolName);
|
|
1900
|
+
content.push({ type: "text", text: message });
|
|
1901
|
+
yield {
|
|
1902
|
+
content: [...content],
|
|
1903
|
+
status: {
|
|
1904
|
+
type: "complete",
|
|
1905
|
+
reason: "stop",
|
|
1906
|
+
},
|
|
1907
|
+
metadata: {
|
|
1908
|
+
custom: {
|
|
1909
|
+
...(runId ? { runId } : {}),
|
|
1910
|
+
runWarning: {
|
|
1911
|
+
message,
|
|
1912
|
+
errorCode: "final_response_timeout_after_tool",
|
|
1913
|
+
recoverable: true,
|
|
1914
|
+
},
|
|
1915
|
+
},
|
|
1916
|
+
},
|
|
1917
|
+
};
|
|
1918
|
+
clearActiveRun();
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
const preservedError = err.errorInfo ?? lastRecoverableRunError ?? null;
|
|
1922
|
+
const message = preservedError?.message ??
|
|
1923
|
+
exhaustedRecoveryMessage(err.reason);
|
|
1924
|
+
const details = [
|
|
1925
|
+
preservedError?.details,
|
|
1926
|
+
connectionRecoveryDetails(),
|
|
1927
|
+
]
|
|
1928
|
+
.filter(Boolean)
|
|
1929
|
+
.join("\n\n");
|
|
1930
|
+
const errorCode = preservedError?.errorCode ?? "connection_error";
|
|
1765
1931
|
captureChatClientError(err, "auto-continuation-exhausted", {
|
|
1766
1932
|
autoContinueReason: err.reason,
|
|
1933
|
+
...(errorCode ? { errorCode } : {}),
|
|
1767
1934
|
});
|
|
1768
1935
|
const runError = {
|
|
1769
1936
|
message,
|
|
1770
|
-
details:
|
|
1771
|
-
errorCode
|
|
1772
|
-
recoverable: true,
|
|
1937
|
+
...(details ? { details } : {}),
|
|
1938
|
+
errorCode,
|
|
1939
|
+
recoverable: preservedError?.recoverable ?? true,
|
|
1773
1940
|
...(runId ? { runId } : {}),
|
|
1774
1941
|
};
|
|
1775
1942
|
if (typeof window !== "undefined") {
|
|
@@ -1777,10 +1944,12 @@ export function createAgentChatAdapter(options) {
|
|
|
1777
1944
|
detail: { ...runError, tabId },
|
|
1778
1945
|
}));
|
|
1779
1946
|
}
|
|
1780
|
-
settleInterruptedToolCalls(content
|
|
1947
|
+
settleInterruptedToolCalls(content, undefined, {
|
|
1948
|
+
includeActivity: true,
|
|
1949
|
+
});
|
|
1781
1950
|
content.push({
|
|
1782
1951
|
type: "text",
|
|
1783
|
-
text:
|
|
1952
|
+
text: formatChatErrorText(message, preservedError?.upgradeUrl, errorCode),
|
|
1784
1953
|
});
|
|
1785
1954
|
yield {
|
|
1786
1955
|
content: [...content],
|
|
@@ -1899,6 +2068,29 @@ export function createAgentChatAdapter(options) {
|
|
|
1899
2068
|
if (content.length > 0) {
|
|
1900
2069
|
const continuation = prepareAutoContinuation(new AgentAutoContinueSignal({ reason: "stream_ended" }));
|
|
1901
2070
|
if (!continuation.ok) {
|
|
2071
|
+
if (continuation.completedToolName) {
|
|
2072
|
+
const message = completedToolTimeoutMessage(continuation.completedToolName);
|
|
2073
|
+
content.push({ type: "text", text: message });
|
|
2074
|
+
yield {
|
|
2075
|
+
content: [...content],
|
|
2076
|
+
status: {
|
|
2077
|
+
type: "complete",
|
|
2078
|
+
reason: "stop",
|
|
2079
|
+
},
|
|
2080
|
+
metadata: {
|
|
2081
|
+
custom: {
|
|
2082
|
+
...(runId ? { runId } : {}),
|
|
2083
|
+
runWarning: {
|
|
2084
|
+
message,
|
|
2085
|
+
errorCode: "final_response_timeout_after_tool",
|
|
2086
|
+
recoverable: true,
|
|
2087
|
+
},
|
|
2088
|
+
},
|
|
2089
|
+
},
|
|
2090
|
+
};
|
|
2091
|
+
clearActiveRun();
|
|
2092
|
+
return;
|
|
2093
|
+
}
|
|
1902
2094
|
const message = exhaustedRecoveryMessage("stream_ended");
|
|
1903
2095
|
captureChatClientError(err, "recovery-exhausted");
|
|
1904
2096
|
const runError = {
|
|
@@ -1913,7 +2105,9 @@ export function createAgentChatAdapter(options) {
|
|
|
1913
2105
|
detail: { ...runError, tabId },
|
|
1914
2106
|
}));
|
|
1915
2107
|
}
|
|
1916
|
-
settleInterruptedToolCalls(content
|
|
2108
|
+
settleInterruptedToolCalls(content, undefined, {
|
|
2109
|
+
includeActivity: true,
|
|
2110
|
+
});
|
|
1917
2111
|
content.push({
|
|
1918
2112
|
type: "text",
|
|
1919
2113
|
text: `Something went wrong: ${message}`,
|