@agent-native/core 0.85.3 → 0.85.5
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 +12 -0
- package/corpus/core/docs/content/tracking.mdx +1 -1
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/run-manager.ts +30 -10
- package/corpus/core/src/client/AssistantChat.tsx +87 -2
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +1 -1
- package/corpus/templates/design/AGENTS.md +6 -4
- package/corpus/templates/design/actions/present-design-variants.ts +10 -5
- package/corpus/templates/design/changelog/2026-07-03-variant-picks-build-the-selected-app.md +5 -0
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +27 -11
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +60 -3
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/docs/content/tracking.mdx +1 -1
- package/package.json +1 -1
|
@@ -67,8 +67,11 @@ function createUserMessageRunConfig(references, requestMode, recoveryAction, tra
|
|
|
67
67
|
const PENDING_SELECTION_KEY = "pending-selection-context";
|
|
68
68
|
const ACTIVE_RUN_CLEAR_TIMEOUT_MS = 5_000;
|
|
69
69
|
const ACTIVE_RUN_STUCK_THRESHOLD_MS = 90_000;
|
|
70
|
+
const BACKGROUND_ACTIVE_RUN_STUCK_THRESHOLD_MS = 13 * 60_000;
|
|
70
71
|
const ACTIVE_RUN_POLL_INTERVAL_MS = 150;
|
|
71
72
|
const AUTO_RESUME_STATUS_TIMEOUT_MS = 30_000;
|
|
73
|
+
const MAX_RECONNECT_AUTO_RECOVERIES = 3;
|
|
74
|
+
const RECONNECT_NO_PROGRESS_CONTINUE_MESSAGE = "Continue from where you stopped. Use the partial work above, verify what succeeded, and finish the original request. Do not rerun the exact same failed tool input unless the failure was transient or the user explicitly asked for an exact rerun. Prefer dedicated app actions over raw database edits when they exist.";
|
|
72
75
|
// How long a single activity (model call, tool prep, long tool) must stay
|
|
73
76
|
// in-flight before its label is surfaced in the running indicator. Below this
|
|
74
77
|
// the indicator stays a steady "Thinking" so normal fast turns don't flicker
|
|
@@ -82,12 +85,19 @@ function isReplayableTerminalRun(runInfo) {
|
|
|
82
85
|
dispatchMode.startsWith("background") &&
|
|
83
86
|
runInfo.terminalReason === "run_timeout");
|
|
84
87
|
}
|
|
88
|
+
function activeRunStuckThresholdMs(runInfo) {
|
|
89
|
+
const dispatchMode = typeof runInfo.dispatchMode === "string" ? runInfo.dispatchMode : "";
|
|
90
|
+
return dispatchMode.startsWith("background")
|
|
91
|
+
? BACKGROUND_ACTIVE_RUN_STUCK_THRESHOLD_MS
|
|
92
|
+
: ACTIVE_RUN_STUCK_THRESHOLD_MS;
|
|
93
|
+
}
|
|
85
94
|
function activeRunLooksStale(runInfo) {
|
|
86
95
|
const lastProgressAt = typeof runInfo.lastProgressAt === "number" ? runInfo.lastProgressAt : null;
|
|
87
96
|
const nowMs = typeof runInfo.serverNow === "number" ? runInfo.serverNow : Date.now();
|
|
97
|
+
const thresholdMs = activeRunStuckThresholdMs(runInfo);
|
|
88
98
|
return (runInfo.status === "running" &&
|
|
89
99
|
lastProgressAt != null &&
|
|
90
|
-
nowMs - lastProgressAt >
|
|
100
|
+
nowMs - lastProgressAt > thresholdMs);
|
|
91
101
|
}
|
|
92
102
|
/**
|
|
93
103
|
* Decide whether a reconnect should give up with "no progress". The signal is
|
|
@@ -856,6 +866,8 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
856
866
|
const reconnectTailOnlyRef = useRef(false);
|
|
857
867
|
const reconnectCanMaterializeRef = useRef(false);
|
|
858
868
|
const reconnectAbortRef = useRef(null);
|
|
869
|
+
const reconnectAutoRecoveryCountRef = useRef(0);
|
|
870
|
+
const [pendingReconnectRecovery, setPendingReconnectRecovery] = useState(null);
|
|
859
871
|
// Nuclear stop: user clicked stop. Clears the stop button/indicator AND
|
|
860
872
|
// lets new submissions go through immediately — prevents the "stuck
|
|
861
873
|
// queueing forever" state where isReconnecting or isRuntimeRunning gets
|
|
@@ -1148,6 +1160,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1148
1160
|
const abortCtrl = new AbortController();
|
|
1149
1161
|
reconnectAbortRef.current = abortCtrl;
|
|
1150
1162
|
let reconnectTerminalReason = null;
|
|
1163
|
+
const reconnectStuckThresholdMs = activeRunStuckThresholdMs(runInfo);
|
|
1151
1164
|
const watchdog = setInterval(async () => {
|
|
1152
1165
|
try {
|
|
1153
1166
|
const res = await fetch(`${apiUrl}/runs/active?threadId=${encodeURIComponent(threadId)}`);
|
|
@@ -1188,6 +1201,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1188
1201
|
if (!reconnectProgressTimedOut({
|
|
1189
1202
|
lastProgressAt: lastReconnectProgressAt,
|
|
1190
1203
|
now: Date.now(),
|
|
1204
|
+
thresholdMs: reconnectStuckThresholdMs,
|
|
1191
1205
|
})) {
|
|
1192
1206
|
return;
|
|
1193
1207
|
}
|
|
@@ -1351,6 +1365,33 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1351
1365
|
setReconnectFrozen(latestContent.length > 0);
|
|
1352
1366
|
reconnectCanMaterializeRef.current = latestContent.length > 0;
|
|
1353
1367
|
}
|
|
1368
|
+
const canAutoRecoverReconnect = reconnectTerminalReason !== "run_timeout" &&
|
|
1369
|
+
reconnectAutoRecoveryCountRef.current <
|
|
1370
|
+
MAX_RECONNECT_AUTO_RECOVERIES;
|
|
1371
|
+
if (canAutoRecoverReconnect) {
|
|
1372
|
+
reconnectAutoRecoveryCountRef.current += 1;
|
|
1373
|
+
setRunErrorInfo(null);
|
|
1374
|
+
setDismissedRunErrorKey(null);
|
|
1375
|
+
clearActiveRunIfMatches(threadId, runId);
|
|
1376
|
+
reconnectAbortRef.current = null;
|
|
1377
|
+
setIsReconnecting(false);
|
|
1378
|
+
reconnectRunIdRef.current = null;
|
|
1379
|
+
reconnectTailOnlyRef.current = false;
|
|
1380
|
+
if (afterSeq > 0) {
|
|
1381
|
+
reconnectCanMaterializeRef.current = false;
|
|
1382
|
+
}
|
|
1383
|
+
window.dispatchEvent(new CustomEvent("agent-chat:auto-continue", {
|
|
1384
|
+
detail: { tabId: tabId || threadId },
|
|
1385
|
+
}));
|
|
1386
|
+
setPendingReconnectRecovery({
|
|
1387
|
+
id: Date.now(),
|
|
1388
|
+
message: RECONNECT_NO_PROGRESS_CONTINUE_MESSAGE,
|
|
1389
|
+
});
|
|
1390
|
+
window.dispatchEvent(new CustomEvent("agentNative.chatRunning", {
|
|
1391
|
+
detail: { isRunning: false, tabId: tabId || threadId },
|
|
1392
|
+
}));
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1354
1395
|
setRunErrorInfo({
|
|
1355
1396
|
message: reconnectTerminalReason === "run_timeout"
|
|
1356
1397
|
? "The previous background agent run reached its time limit before finishing. The partial work was preserved; continue or retry to pick up from here."
|
|
@@ -1401,6 +1442,9 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1401
1442
|
if (loaded || afterSeq > 0 || latestContent.length === 0) {
|
|
1402
1443
|
reconnectCanMaterializeRef.current = false;
|
|
1403
1444
|
}
|
|
1445
|
+
if (loaded) {
|
|
1446
|
+
reconnectAutoRecoveryCountRef.current = 0;
|
|
1447
|
+
}
|
|
1404
1448
|
window.dispatchEvent(new CustomEvent("agentNative.chatRunning", {
|
|
1405
1449
|
detail: { isRunning: false, tabId: tabId || threadId },
|
|
1406
1450
|
}));
|
|
@@ -2227,10 +2271,13 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2227
2271
|
]);
|
|
2228
2272
|
// Keep the ref current so addToQueue can call it without a stale closure.
|
|
2229
2273
|
stopActiveRunRef.current = stopActiveRun;
|
|
2230
|
-
const addToQueue = useCallback(async (text, images, references, attachments, requestMode, intent = "queued", recoveryAction, includeComposerContext = false, trackInRunsTray = false) => {
|
|
2274
|
+
const addToQueue = useCallback(async (text, images, references, attachments, requestMode, intent = "queued", recoveryAction, includeComposerContext = false, trackInRunsTray = false, preserveReconnectAutoRecoveryBudget = false) => {
|
|
2231
2275
|
if (!(await ensureAgentEngineReadyForSubmit())) {
|
|
2232
2276
|
return;
|
|
2233
2277
|
}
|
|
2278
|
+
if (!preserveReconnectAutoRecoveryBudget) {
|
|
2279
|
+
reconnectAutoRecoveryCountRef.current = 0;
|
|
2280
|
+
}
|
|
2234
2281
|
materializeFrozenReconnectContent();
|
|
2235
2282
|
setShowContinue(false);
|
|
2236
2283
|
setLoopLimitInfo(null);
|
|
@@ -2416,6 +2463,16 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2416
2463
|
appendThreadMessage,
|
|
2417
2464
|
updateComposerContextItems,
|
|
2418
2465
|
]);
|
|
2466
|
+
useEffect(() => {
|
|
2467
|
+
if (!pendingReconnectRecovery)
|
|
2468
|
+
return;
|
|
2469
|
+
const recovery = pendingReconnectRecovery;
|
|
2470
|
+
const timer = window.setTimeout(() => {
|
|
2471
|
+
setPendingReconnectRecovery((current) => current?.id === recovery.id ? null : current);
|
|
2472
|
+
addToQueue(recovery.message, undefined, undefined, undefined, undefined, "queued", "continue", false, false, true);
|
|
2473
|
+
}, 0);
|
|
2474
|
+
return () => window.clearTimeout(timer);
|
|
2475
|
+
}, [addToQueue, pendingReconnectRecovery]);
|
|
2419
2476
|
// Expose imperative handle
|
|
2420
2477
|
useImperativeHandle(ref, () => ({
|
|
2421
2478
|
sendMessage(text, images, options) {
|
|
@@ -2696,7 +2753,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2696
2753
|
addToQueue("Continue from where you left off.", undefined, undefined, undefined, undefined, "queued", "continue");
|
|
2697
2754
|
} })), shouldShowRunError && visibleRunError && (_jsx(RunErrorRecoveryCard, { info: visibleRunError, onContinue: () => {
|
|
2698
2755
|
setRunErrorInfo(null);
|
|
2699
|
-
addToQueue(
|
|
2756
|
+
addToQueue(RECONNECT_NO_PROGRESS_CONTINUE_MESSAGE, undefined, undefined, undefined, undefined, "queued", "continue");
|
|
2700
2757
|
}, onRetry: () => {
|
|
2701
2758
|
setRunErrorInfo(null);
|
|
2702
2759
|
addToQueue(lastUserText
|