@agent-native/core 0.92.2 → 0.92.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 +2 -2
- package/corpus/core/CHANGELOG.md +26 -0
- package/corpus/core/docs/content/locales/ar-SA/server.mdx +35 -0
- package/corpus/core/docs/content/locales/de-DE/server.mdx +35 -0
- package/corpus/core/docs/content/locales/es-ES/server.mdx +35 -0
- package/corpus/core/docs/content/locales/fr-FR/server.mdx +35 -0
- package/corpus/core/docs/content/locales/hi-IN/server.mdx +35 -0
- package/corpus/core/docs/content/locales/ja-JP/server.mdx +35 -0
- package/corpus/core/docs/content/locales/ko-KR/server.mdx +35 -0
- package/corpus/core/docs/content/locales/pt-BR/server.mdx +35 -0
- package/corpus/core/docs/content/locales/zh-CN/server.mdx +35 -0
- package/corpus/core/docs/content/locales/zh-TW/server.mdx +35 -0
- package/corpus/core/docs/content/server.mdx +35 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/engine/ai-sdk-engine.ts +14 -4
- package/corpus/core/src/agent/engine/anthropic-engine.ts +15 -3
- package/corpus/core/src/agent/engine/builder-engine.ts +30 -4
- package/corpus/core/src/agent/engine/registry.ts +63 -2
- package/corpus/core/src/agent/model-config.ts +0 -2
- package/corpus/core/src/agent/production-agent.ts +12 -1
- package/corpus/core/src/agent/run-manager.ts +57 -36
- package/corpus/core/src/agent/run-store.ts +81 -2
- package/corpus/core/src/agent/thread-data-builder.ts +33 -2
- package/corpus/core/src/client/AssistantChat.tsx +314 -96
- package/corpus/core/src/client/agent-chat-adapter.ts +17 -1
- package/corpus/core/src/client/chat/repo-helpers.ts +45 -0
- package/corpus/core/src/client/chat/tool-call-display.tsx +36 -27
- package/corpus/core/src/client/chat-model-groups.ts +1 -5
- package/corpus/core/src/client/composer/TiptapComposer.tsx +0 -2
- package/corpus/core/src/client/embed-auth.ts +20 -0
- package/corpus/core/src/client/settings/SettingsSection.tsx +66 -5
- package/corpus/core/src/client/sse-event-processor.ts +49 -17
- package/corpus/core/src/client/use-db-sync.ts +31 -9
- package/corpus/core/src/collab/agent-presence.ts +6 -1
- package/corpus/core/src/collab/awareness-store.ts +185 -0
- package/corpus/core/src/collab/awareness.ts +58 -2
- package/corpus/core/src/scripts/agent-engines/manage-agent-engine.ts +7 -8
- package/corpus/core/src/scripts/agent-engines/set-agent-engine.ts +7 -18
- package/corpus/core/src/server/core-routes-plugin.ts +21 -2
- package/corpus/core/src/server/embed-session.ts +20 -4
- package/corpus/core/src/styles/agent-native.css +51 -0
- package/corpus/core/src/tracking/providers.ts +33 -2
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +8 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +9 -1
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorDetail.tsx +41 -11
- package/corpus/templates/analytics/app/pages/monitoring/uptime/types.ts +44 -0
- package/corpus/templates/analytics/changelog/2026-07-09-dashboard-action-menus-now-close-cleanly-before-opening-hist.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-09-dashboard-email-reports-still-send-when-the-screenshot-captu.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-09-uptime-alerts-now-suppress-recovery-noise-during-flapping-an.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-09-uptime-check-history-now-shows-timing-diagnostics-so-slow-or.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-09-uptime-recovery-alerts-now-send-when-the-original-outage-not.md +6 -0
- package/corpus/templates/analytics/docs/uptime-monitoring.md +29 -16
- package/corpus/templates/analytics/netlify.toml +3 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +126 -0
- package/corpus/templates/analytics/server/db/schema-monitoring.ts +5 -0
- package/corpus/templates/analytics/server/jobs/uptime-monitors.ts +5 -1
- package/corpus/templates/analytics/server/lib/uptime-monitors.ts +305 -31
- package/corpus/templates/analytics/server/plugins/db.ts +15 -0
- package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +1 -1
- package/corpus/templates/analytics/server/routes/api/uptime-monitors/run.post.ts +57 -0
- package/corpus/templates/clips/actions/list-meetings.ts +12 -0
- package/corpus/templates/clips/changelog/2026-07-09-meeting-reminders-now-ignore-obvious-solo-personal-calendar-.md +6 -0
- package/corpus/templates/clips/desktop/src-tauri/src/meetings_watcher.rs +1 -0
- package/corpus/templates/clips/server/lib/calendar-event-classification.ts +79 -0
- package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.js +13 -4
- package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
- package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
- package/dist/agent/engine/anthropic-engine.js +14 -3
- package/dist/agent/engine/anthropic-engine.js.map +1 -1
- package/dist/agent/engine/builder-engine.d.ts +1 -1
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +26 -4
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +47 -2
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/agent/model-config.d.ts +2 -2
- package/dist/agent/model-config.d.ts.map +1 -1
- package/dist/agent/model-config.js +0 -2
- package/dist/agent/model-config.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +12 -1
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +52 -33
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +24 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +64 -2
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +28 -2
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +6 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +243 -36
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +15 -1
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/chat/repo-helpers.d.ts.map +1 -1
- package/dist/client/chat/repo-helpers.js +43 -0
- package/dist/client/chat/repo-helpers.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +4 -4
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat-model-groups.d.ts.map +1 -1
- package/dist/client/chat-model-groups.js +1 -3
- package/dist/client/chat-model-groups.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +0 -2
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/embed-auth.d.ts.map +1 -1
- package/dist/client/embed-auth.js +14 -0
- package/dist/client/embed-auth.js.map +1 -1
- package/dist/client/settings/SettingsSection.d.ts.map +1 -1
- package/dist/client/settings/SettingsSection.js +32 -3
- package/dist/client/settings/SettingsSection.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +44 -17
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +29 -9
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/collab/agent-presence.d.ts.map +1 -1
- package/dist/collab/agent-presence.js +5 -2
- package/dist/collab/agent-presence.js.map +1 -1
- package/dist/collab/awareness-store.d.ts +1 -1
- package/dist/collab/awareness-store.d.ts.map +1 -1
- package/dist/collab/awareness-store.js +0 -0
- package/dist/collab/awareness-store.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -0
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/awareness.js +46 -2
- package/dist/collab/awareness.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.js +6 -6
- package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.js +5 -13
- package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/core-routes-plugin.d.ts +5 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +10 -3
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/embed-session.d.ts.map +1 -1
- package/dist/server/embed-session.js +17 -4
- package/dist/server/embed-session.js.map +1 -1
- package/dist/styles/agent-native.css +51 -0
- package/dist/tracking/providers.d.ts.map +1 -1
- package/dist/tracking/providers.js +23 -5
- package/dist/tracking/providers.js.map +1 -1
- package/docs/content/locales/ar-SA/server.mdx +35 -0
- package/docs/content/locales/de-DE/server.mdx +35 -0
- package/docs/content/locales/es-ES/server.mdx +35 -0
- package/docs/content/locales/fr-FR/server.mdx +35 -0
- package/docs/content/locales/hi-IN/server.mdx +35 -0
- package/docs/content/locales/ja-JP/server.mdx +35 -0
- package/docs/content/locales/ko-KR/server.mdx +35 -0
- package/docs/content/locales/pt-BR/server.mdx +35 -0
- package/docs/content/locales/zh-CN/server.mdx +35 -0
- package/docs/content/locales/zh-TW/server.mdx +35 -0
- package/docs/content/server.mdx +35 -0
- package/package.json +1 -1
|
@@ -135,6 +135,36 @@ function cloneContentParts(content) {
|
|
|
135
135
|
...(part.chatUI ? { chatUI: { ...part.chatUI } } : {}),
|
|
136
136
|
});
|
|
137
137
|
}
|
|
138
|
+
export function settleInterruptedAssistantToolCallsInRepo(repo) {
|
|
139
|
+
if (!Array.isArray(repo.messages))
|
|
140
|
+
return { repo, changed: false };
|
|
141
|
+
let changed = false;
|
|
142
|
+
const nextMessages = repo.messages.map((entry) => {
|
|
143
|
+
const wrapper = entry && typeof entry === "object" && "message" in entry
|
|
144
|
+
? entry
|
|
145
|
+
: null;
|
|
146
|
+
const message = (wrapper?.message ?? entry);
|
|
147
|
+
if (message?.role !== "assistant" || !Array.isArray(message.content)) {
|
|
148
|
+
return entry;
|
|
149
|
+
}
|
|
150
|
+
const content = cloneContentParts(message.content);
|
|
151
|
+
if (!settleInterruptedToolCalls(content, undefined, { includeActivity: true })) {
|
|
152
|
+
return entry;
|
|
153
|
+
}
|
|
154
|
+
changed = true;
|
|
155
|
+
const nextMessage = {
|
|
156
|
+
...message,
|
|
157
|
+
content,
|
|
158
|
+
status: { type: "incomplete", reason: "error" },
|
|
159
|
+
};
|
|
160
|
+
return wrapper
|
|
161
|
+
? { ...entry, message: nextMessage }
|
|
162
|
+
: nextMessage;
|
|
163
|
+
});
|
|
164
|
+
return changed
|
|
165
|
+
? { repo: { ...repo, messages: nextMessages }, changed }
|
|
166
|
+
: { repo, changed };
|
|
167
|
+
}
|
|
138
168
|
function clearPendingSelection() {
|
|
139
169
|
fetch(agentNativePath(`/_agent-native/application-state/${PENDING_SELECTION_KEY}`), {
|
|
140
170
|
method: "DELETE",
|
|
@@ -259,6 +289,26 @@ function toolCallPartHasResult(part) {
|
|
|
259
289
|
const candidate = part;
|
|
260
290
|
return candidate.type === "tool-call" && "result" in candidate;
|
|
261
291
|
}
|
|
292
|
+
/**
|
|
293
|
+
* Monotonic progress rank for a tool-call part. Higher means the UI should
|
|
294
|
+
* prefer this copy over a lower-ranked duplicate of the same logical call.
|
|
295
|
+
* Used so reconnect overlays that are ahead of lagging thread messages stay
|
|
296
|
+
* visible instead of flickering back to an older pending spinner.
|
|
297
|
+
*/
|
|
298
|
+
function toolCallProgressRank(part) {
|
|
299
|
+
if (!part || typeof part !== "object")
|
|
300
|
+
return 0;
|
|
301
|
+
const candidate = part;
|
|
302
|
+
if (candidate.type !== "tool-call")
|
|
303
|
+
return 0;
|
|
304
|
+
if ("result" in candidate)
|
|
305
|
+
return 4;
|
|
306
|
+
if (candidate.activity === true)
|
|
307
|
+
return 1;
|
|
308
|
+
return typeof candidate.argsText === "string" && candidate.argsText.length > 0
|
|
309
|
+
? 2
|
|
310
|
+
: 1;
|
|
311
|
+
}
|
|
262
312
|
/**
|
|
263
313
|
* Identity fingerprint for a tool-call part that survives across readers: two
|
|
264
314
|
* readers of the same run assign unrelated synthetic toolCallIds until both
|
|
@@ -294,10 +344,10 @@ function collectRenderedToolCallStates(messages) {
|
|
|
294
344
|
const id = toolCallIdFromContentPart(part);
|
|
295
345
|
if (!id)
|
|
296
346
|
continue;
|
|
297
|
-
const
|
|
347
|
+
const rank = toolCallProgressRank(part);
|
|
298
348
|
const existing = byId.get(id);
|
|
299
349
|
byId.set(id, {
|
|
300
|
-
|
|
350
|
+
rank: Math.max(existing?.rank ?? 0, rank),
|
|
301
351
|
});
|
|
302
352
|
}
|
|
303
353
|
}
|
|
@@ -310,10 +360,10 @@ function collectRenderedToolCallStates(messages) {
|
|
|
310
360
|
const fingerprint = toolCallFingerprintFromContentPart(part);
|
|
311
361
|
if (!fingerprint)
|
|
312
362
|
continue;
|
|
313
|
-
const
|
|
363
|
+
const rank = toolCallProgressRank(part);
|
|
314
364
|
const existing = latestAssistantByFingerprint.get(fingerprint);
|
|
315
365
|
latestAssistantByFingerprint.set(fingerprint, {
|
|
316
|
-
|
|
366
|
+
rank: Math.max(existing?.rank ?? 0, rank),
|
|
317
367
|
});
|
|
318
368
|
}
|
|
319
369
|
}
|
|
@@ -402,24 +452,33 @@ export function dedupeReconnectContentAgainstMessages(content, messages) {
|
|
|
402
452
|
}
|
|
403
453
|
const filtered = byId.size > 0 || latestAssistantByFingerprint.size > 0
|
|
404
454
|
? snapshotDeduped.filter((part) => {
|
|
455
|
+
const reconnectRank = toolCallProgressRank(part);
|
|
405
456
|
const id = toolCallIdFromContentPart(part);
|
|
406
457
|
const existing = id ? byId.get(id) : undefined;
|
|
407
458
|
if (existing) {
|
|
408
|
-
|
|
409
|
-
|
|
459
|
+
// Keep reconnect copies that are strictly ahead of the rendered
|
|
460
|
+
// message (e.g. completed overlay vs lagging pending thread data).
|
|
461
|
+
// Same-or-behind ranks are duplicates and should stay hidden.
|
|
462
|
+
if (reconnectRank <= existing.rank) {
|
|
463
|
+
changed = true;
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
return true;
|
|
410
467
|
}
|
|
411
468
|
// Fingerprint fallback for the id-convergence window: two readers of
|
|
412
469
|
// the same active run can assign unrelated ids to the same logical tool
|
|
413
470
|
// call before the server id converges. Suppress the reconnect overlay
|
|
414
|
-
//
|
|
415
|
-
//
|
|
416
|
-
//
|
|
471
|
+
// only when the rendered message is at least as far along; completed
|
|
472
|
+
// reconnect copies stay visible over pending message copies so the UI
|
|
473
|
+
// does not pop back to an older spinner.
|
|
417
474
|
const fingerprint = toolCallFingerprintFromContentPart(part);
|
|
418
475
|
const latestByFingerprint = fingerprint
|
|
419
476
|
? latestAssistantByFingerprint.get(fingerprint)
|
|
420
477
|
: undefined;
|
|
478
|
+
const isCompletedRepeat = reconnectRank >= 4 && latestByFingerprint?.rank === 4;
|
|
421
479
|
if (latestByFingerprint &&
|
|
422
|
-
|
|
480
|
+
!isCompletedRepeat &&
|
|
481
|
+
reconnectRank <= latestByFingerprint.rank) {
|
|
423
482
|
changed = true;
|
|
424
483
|
return false;
|
|
425
484
|
}
|
|
@@ -834,6 +893,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
834
893
|
const queueDirtyRef = useRef(false);
|
|
835
894
|
const queueMutationVersionRef = useRef(0);
|
|
836
895
|
const dequeueInFlightRef = useRef(false);
|
|
896
|
+
const queueStopVersionRef = useRef(0);
|
|
837
897
|
const [composerContextItems, setComposerContextItems] = useState([]);
|
|
838
898
|
const composerContextItemsRef = useRef([]);
|
|
839
899
|
const isActiveComposerRef = useRef(isActiveComposer);
|
|
@@ -975,6 +1035,9 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
975
1035
|
const [reconnectContent, setReconnectContent] = useState([]);
|
|
976
1036
|
// When stop is clicked during reconnect, keep content visible (don't wipe it)
|
|
977
1037
|
const [reconnectFrozen, setReconnectFrozen] = useState(false);
|
|
1038
|
+
// Adapter took over while reconnect still had visible tool cards — keep the
|
|
1039
|
+
// overlay until the adapter message catches up so we don't flash an empty gap.
|
|
1040
|
+
const [adapterHandoffPending, setAdapterHandoffPending] = useState(false);
|
|
978
1041
|
const reconnectRunIdRef = useRef(null);
|
|
979
1042
|
const reconnectTailOnlyRef = useRef(false);
|
|
980
1043
|
const reconnectCanMaterializeRef = useRef(false);
|
|
@@ -1026,9 +1089,14 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1026
1089
|
isReconnecting,
|
|
1027
1090
|
hasReconnectContent: reconnectContent.length > 0,
|
|
1028
1091
|
});
|
|
1029
|
-
const reconnectActivityContent = useMemo(() => isReconnecting || reconnectFrozen
|
|
1092
|
+
const reconnectActivityContent = useMemo(() => isReconnecting || reconnectFrozen || adapterHandoffPending
|
|
1030
1093
|
? reconnectActivityFallbackContent(runningActivityTool)
|
|
1031
|
-
: [], [
|
|
1094
|
+
: [], [
|
|
1095
|
+
adapterHandoffPending,
|
|
1096
|
+
isReconnecting,
|
|
1097
|
+
reconnectFrozen,
|
|
1098
|
+
runningActivityTool,
|
|
1099
|
+
]);
|
|
1032
1100
|
const lastBroadcastRunningRef = useRef(isRunning);
|
|
1033
1101
|
const tiptapRef = useRef(null);
|
|
1034
1102
|
// Stable ref to the "stop active run" action so addToQueue can abort
|
|
@@ -1113,14 +1181,21 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1113
1181
|
let settledRepo = repo;
|
|
1114
1182
|
if (repo?.messages?.length > 0) {
|
|
1115
1183
|
let shouldImport = true;
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
catch {
|
|
1120
|
-
// If the runtime/export comparison itself fails, do not fail open by
|
|
1121
|
-
// importing a server snapshot that may be stale relative to local UI.
|
|
1184
|
+
// Adapter owns the live turn (including auto-continuation gaps). Do not
|
|
1185
|
+
// let a lagging server thread snapshot clobber in-flight tool cards.
|
|
1186
|
+
if (isRuntimeRunningRef.current || isAutoResumingRef.current) {
|
|
1122
1187
|
shouldImport = false;
|
|
1123
1188
|
}
|
|
1189
|
+
else {
|
|
1190
|
+
try {
|
|
1191
|
+
shouldImport = shouldImportServerThreadData(normalizeThreadRepository(threadRuntime.export()), repo);
|
|
1192
|
+
}
|
|
1193
|
+
catch {
|
|
1194
|
+
// If the runtime/export comparison itself fails, do not fail open by
|
|
1195
|
+
// importing a server snapshot that may be stale relative to local UI.
|
|
1196
|
+
shouldImport = false;
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1124
1199
|
if (shouldImport) {
|
|
1125
1200
|
if (options?.markTitleGenerated) {
|
|
1126
1201
|
titleGeneratedRef.current = true;
|
|
@@ -1264,6 +1339,25 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1264
1339
|
if (isRuntimeRunningRef.current || isAutoResumingRef.current) {
|
|
1265
1340
|
return false;
|
|
1266
1341
|
}
|
|
1342
|
+
// SUPERSEDE THE PREVIOUS RECONNECT GENERATION. A turn that keeps failing
|
|
1343
|
+
// (e.g. repeated stale_run at "Contacting model") produces a new runId
|
|
1344
|
+
// every few seconds; each call here used to OVERWRITE the single-slot
|
|
1345
|
+
// refs below without tearing down the prior closure, leaving its
|
|
1346
|
+
// watchdog (1s) + idleCheck (1s) + thread poll (2s) + SSE retry loop all
|
|
1347
|
+
// running. 4-5 stacked generations = a ~20 req/s request storm that
|
|
1348
|
+
// hammers the same Neon pool the server needs for heartbeats, deepening
|
|
1349
|
+
// the DB saturation that causes the failures in the first place. Abort
|
|
1350
|
+
// the prior generation's AbortController so its stream loop exits and its
|
|
1351
|
+
// `finally` clears every interval before we start a fresh one.
|
|
1352
|
+
if (reconnectAbortRef.current) {
|
|
1353
|
+
try {
|
|
1354
|
+
reconnectAbortRef.current.abort();
|
|
1355
|
+
}
|
|
1356
|
+
catch {
|
|
1357
|
+
// Already aborted / detached — nothing to unwind.
|
|
1358
|
+
}
|
|
1359
|
+
reconnectAbortRef.current = null;
|
|
1360
|
+
}
|
|
1267
1361
|
reconnectRunIdRef.current = runId;
|
|
1268
1362
|
const afterSeq = resolveReconnectAfterSeq(threadId, runId);
|
|
1269
1363
|
reconnectTailOnlyRef.current = afterSeq > 0;
|
|
@@ -1278,6 +1372,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1278
1372
|
});
|
|
1279
1373
|
setIsReconnecting(true);
|
|
1280
1374
|
setReconnectFrozen(false);
|
|
1375
|
+
setAdapterHandoffPending(false);
|
|
1281
1376
|
setReconnectContent([]);
|
|
1282
1377
|
window.dispatchEvent(new CustomEvent("agentNative.chatRunning", {
|
|
1283
1378
|
detail: { isRunning: true, tabId: tabId || threadId },
|
|
@@ -1349,6 +1444,19 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1349
1444
|
let noProgressDuringReconnect = false;
|
|
1350
1445
|
let latestContent = [];
|
|
1351
1446
|
const preparingActionState = {};
|
|
1447
|
+
// Exponential backoff for the reattach retry loop. A run that is
|
|
1448
|
+
// "active" server-side but producing no stream (the exact stuck state
|
|
1449
|
+
// that triggers a reconnect) would otherwise re-fetch /runs/:id/events
|
|
1450
|
+
// every ~250ms — several req/s per generation. Back off 250ms → 5s so a
|
|
1451
|
+
// genuinely stuck run stops hammering the server; reset the moment real
|
|
1452
|
+
// progress streams in (see the onSeq callback) so a recovering run
|
|
1453
|
+
// re-tightens immediately.
|
|
1454
|
+
let reconnectRetryCount = 0;
|
|
1455
|
+
const backoffRetryDelay = () => {
|
|
1456
|
+
const ms = Math.min(250 * 2 ** reconnectRetryCount, 5000);
|
|
1457
|
+
reconnectRetryCount += 1;
|
|
1458
|
+
return new Promise((resolve) => window.setTimeout(resolve, ms));
|
|
1459
|
+
};
|
|
1352
1460
|
const sameRunStillActive = async () => {
|
|
1353
1461
|
try {
|
|
1354
1462
|
const res = await fetch(`${apiUrl}/runs/active?threadId=${encodeURIComponent(threadId)}`, { signal: abortCtrl.signal });
|
|
@@ -1370,6 +1478,11 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1370
1478
|
? window.setInterval(() => {
|
|
1371
1479
|
if (reconnectRunIdRef.current !== runId)
|
|
1372
1480
|
return;
|
|
1481
|
+
// Adapter took over mid-poll — skip imports that would race the
|
|
1482
|
+
// live stream and flicker tool cards back to older snapshots.
|
|
1483
|
+
if (isRuntimeRunningRef.current || isAutoResumingRef.current) {
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1373
1486
|
void refreshThreadFromServer();
|
|
1374
1487
|
}, 2000)
|
|
1375
1488
|
: undefined;
|
|
@@ -1385,7 +1498,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1385
1498
|
if (!sseRes.ok || !sseRes.body) {
|
|
1386
1499
|
const activeState = await sameRunStillActive();
|
|
1387
1500
|
if (activeState !== "inactive") {
|
|
1388
|
-
await
|
|
1501
|
+
await backoffRetryDelay();
|
|
1389
1502
|
continue;
|
|
1390
1503
|
}
|
|
1391
1504
|
break;
|
|
@@ -1405,6 +1518,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1405
1518
|
try {
|
|
1406
1519
|
await readSSEStreamRaw(sseRes.body, content, toolCallCounter, tabId, scheduleUpdate, (seq) => {
|
|
1407
1520
|
markReconnectProgress();
|
|
1521
|
+
reconnectRetryCount = 0;
|
|
1408
1522
|
updateActiveRunSeq(seq);
|
|
1409
1523
|
}, { preparingActionState });
|
|
1410
1524
|
if (reconnectAfterSeq === 0) {
|
|
@@ -1420,7 +1534,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1420
1534
|
}
|
|
1421
1535
|
const activeState = await sameRunStillActive();
|
|
1422
1536
|
if (activeState !== "inactive") {
|
|
1423
|
-
await
|
|
1537
|
+
await backoffRetryDelay();
|
|
1424
1538
|
continue;
|
|
1425
1539
|
}
|
|
1426
1540
|
}
|
|
@@ -1768,7 +1882,8 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1768
1882
|
if (!loadHistoryRepository ||
|
|
1769
1883
|
!hasRestoredRef.current ||
|
|
1770
1884
|
isRestoring ||
|
|
1771
|
-
isRunning
|
|
1885
|
+
isRunning ||
|
|
1886
|
+
isAutoResuming) {
|
|
1772
1887
|
return;
|
|
1773
1888
|
}
|
|
1774
1889
|
let cancelled = false;
|
|
@@ -1785,6 +1900,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1785
1900
|
}, [
|
|
1786
1901
|
historyReloadKey,
|
|
1787
1902
|
importThreadData,
|
|
1903
|
+
isAutoResuming,
|
|
1788
1904
|
isRestoring,
|
|
1789
1905
|
isRunning,
|
|
1790
1906
|
loadHistoryRepository,
|
|
@@ -2187,6 +2303,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2187
2303
|
const next = queuedMessages[0];
|
|
2188
2304
|
if (!next)
|
|
2189
2305
|
return;
|
|
2306
|
+
const stopVersion = queueStopVersionRef.current;
|
|
2190
2307
|
dequeueInFlightRef.current = true;
|
|
2191
2308
|
let cancelled = false;
|
|
2192
2309
|
let started = false;
|
|
@@ -2203,7 +2320,8 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2203
2320
|
await waitForThreadRunToClear(apiUrl, threadId);
|
|
2204
2321
|
if (cancelled)
|
|
2205
2322
|
return;
|
|
2206
|
-
if (
|
|
2323
|
+
if (queueStopVersionRef.current !== stopVersion ||
|
|
2324
|
+
queuedMessagesRef.current[0]?.id !== next.id) {
|
|
2207
2325
|
return;
|
|
2208
2326
|
}
|
|
2209
2327
|
// Keep the placeholder visible while waiting. Remove it only when the
|
|
@@ -2227,6 +2345,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2227
2345
|
}
|
|
2228
2346
|
catch (err) {
|
|
2229
2347
|
if (removedForAppend &&
|
|
2348
|
+
queueStopVersionRef.current === stopVersion &&
|
|
2230
2349
|
!queuedMessagesRef.current.some((message) => message.id === next.id)) {
|
|
2231
2350
|
applyLocalQueuedMessages((prev) => [next, ...prev]);
|
|
2232
2351
|
}
|
|
@@ -2280,30 +2399,66 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2280
2399
|
prevIsRuntimeRunningRef.current = isRuntimeRunning;
|
|
2281
2400
|
if (isRuntimeRunning && !wasRunning) {
|
|
2282
2401
|
// SINGLE-READER OWNERSHIP: the adapter runtime just took over (a new run
|
|
2283
|
-
// started or an adopted run resumed).
|
|
2284
|
-
//
|
|
2285
|
-
//
|
|
2286
|
-
// reader's own cleanup paths (which all check reconnectRunIdRef) no-op.
|
|
2402
|
+
// started or an adopted run resumed). Abort the reconnect reader, but keep
|
|
2403
|
+
// its visible content until the adapter message has tool/text parts so the
|
|
2404
|
+
// UI does not flash an empty gap between readers.
|
|
2287
2405
|
if (reconnectRunIdRef.current !== null) {
|
|
2406
|
+
const keepOverlay = reconnectContent.length > 0;
|
|
2288
2407
|
reconnectRunIdRef.current = null;
|
|
2289
2408
|
reconnectAbortRef.current?.abort();
|
|
2290
2409
|
reconnectAbortRef.current = null;
|
|
2291
2410
|
setIsReconnecting(false);
|
|
2292
|
-
setReconnectContent([]);
|
|
2293
2411
|
setReconnectFrozen(false);
|
|
2294
2412
|
reconnectCanMaterializeRef.current = false;
|
|
2295
2413
|
reconnectTailOnlyRef.current = false;
|
|
2414
|
+
if (keepOverlay) {
|
|
2415
|
+
setAdapterHandoffPending(true);
|
|
2416
|
+
}
|
|
2417
|
+
else {
|
|
2418
|
+
setReconnectContent([]);
|
|
2419
|
+
setAdapterHandoffPending(false);
|
|
2420
|
+
}
|
|
2296
2421
|
}
|
|
2297
2422
|
else if (reconnectFrozen) {
|
|
2298
2423
|
setReconnectFrozen(false);
|
|
2299
2424
|
setReconnectContent([]);
|
|
2425
|
+
setAdapterHandoffPending(false);
|
|
2300
2426
|
reconnectCanMaterializeRef.current = false;
|
|
2301
2427
|
}
|
|
2302
2428
|
if (forceStopped) {
|
|
2303
2429
|
setForceStopped(false);
|
|
2304
2430
|
}
|
|
2305
2431
|
}
|
|
2306
|
-
}, [
|
|
2432
|
+
}, [
|
|
2433
|
+
isRuntimeRunning,
|
|
2434
|
+
reconnectFrozen,
|
|
2435
|
+
forceStopped,
|
|
2436
|
+
reconnectContent.length,
|
|
2437
|
+
]);
|
|
2438
|
+
// Release the deferred reconnect overlay once thread messages have caught
|
|
2439
|
+
// up enough that dedupe would hide the overlay, or after a short timeout so
|
|
2440
|
+
// a stuck handoff cannot leave duplicate tool cards forever.
|
|
2441
|
+
useEffect(() => {
|
|
2442
|
+
if (!adapterHandoffPending)
|
|
2443
|
+
return;
|
|
2444
|
+
if (!isRuntimeRunning) {
|
|
2445
|
+
setReconnectContent([]);
|
|
2446
|
+
setAdapterHandoffPending(false);
|
|
2447
|
+
return;
|
|
2448
|
+
}
|
|
2449
|
+
const stillNeeded = dedupeReconnectContentAgainstMessages(reconnectContent, messages).length >
|
|
2450
|
+
0;
|
|
2451
|
+
if (!stillNeeded) {
|
|
2452
|
+
setReconnectContent([]);
|
|
2453
|
+
setAdapterHandoffPending(false);
|
|
2454
|
+
return;
|
|
2455
|
+
}
|
|
2456
|
+
const timer = window.setTimeout(() => {
|
|
2457
|
+
setReconnectContent([]);
|
|
2458
|
+
setAdapterHandoffPending(false);
|
|
2459
|
+
}, 2500);
|
|
2460
|
+
return () => window.clearTimeout(timer);
|
|
2461
|
+
}, [adapterHandoffPending, isRuntimeRunning, messages, reconnectContent]);
|
|
2307
2462
|
// Same transition guard for isReconnecting: only clear forceStopped on
|
|
2308
2463
|
// the false→true edge (a new reconnect starting on page load).
|
|
2309
2464
|
const prevIsReconnectingRef = useRef(isReconnecting);
|
|
@@ -2320,6 +2475,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2320
2475
|
if (!reconnectCanMaterializeRef.current) {
|
|
2321
2476
|
setReconnectFrozen(false);
|
|
2322
2477
|
setReconnectContent([]);
|
|
2478
|
+
setAdapterHandoffPending(false);
|
|
2323
2479
|
return;
|
|
2324
2480
|
}
|
|
2325
2481
|
try {
|
|
@@ -2359,6 +2515,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2359
2515
|
threadRuntime.import(ensureMessageMetadata(repo));
|
|
2360
2516
|
setReconnectFrozen(false);
|
|
2361
2517
|
setReconnectContent([]);
|
|
2518
|
+
setAdapterHandoffPending(false);
|
|
2362
2519
|
reconnectCanMaterializeRef.current = false;
|
|
2363
2520
|
}
|
|
2364
2521
|
catch (err) {
|
|
@@ -2382,13 +2539,47 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2382
2539
|
threadId,
|
|
2383
2540
|
threadRuntime,
|
|
2384
2541
|
]);
|
|
2542
|
+
const settleVisibleInterruptedTools = useCallback(() => {
|
|
2543
|
+
try {
|
|
2544
|
+
const repo = normalizeThreadRepository(threadRuntime.export());
|
|
2545
|
+
const settled = settleInterruptedAssistantToolCallsInRepo(repo);
|
|
2546
|
+
if (settled.changed) {
|
|
2547
|
+
threadRuntime.import(ensureMessageMetadata(settled.repo));
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
catch (err) {
|
|
2551
|
+
captureError(err, {
|
|
2552
|
+
tags: {
|
|
2553
|
+
source: "agent-chat-client",
|
|
2554
|
+
phase: "settle-stopped-tool-calls",
|
|
2555
|
+
},
|
|
2556
|
+
extra: {
|
|
2557
|
+
threadId: threadId ?? null,
|
|
2558
|
+
tabId: tabId ?? null,
|
|
2559
|
+
},
|
|
2560
|
+
});
|
|
2561
|
+
}
|
|
2562
|
+
}, [tabId, threadId, threadRuntime]);
|
|
2385
2563
|
// Abort the active server run (identical to what the Stop button does) so
|
|
2386
2564
|
// an immediate-while-running send can proceed cleanly without a 409 race.
|
|
2387
2565
|
// Captured in a stable ref so addToQueue can call it without listing
|
|
2388
2566
|
// all the stop-related state in its own dep array.
|
|
2389
|
-
const stopActiveRun = useCallback(() => {
|
|
2567
|
+
const stopActiveRun = useCallback((options) => {
|
|
2390
2568
|
setForceStopped(true);
|
|
2391
2569
|
setOptimisticRunning(false);
|
|
2570
|
+
setHasActiveServerRun(false);
|
|
2571
|
+
setPendingReconnectRecovery(null);
|
|
2572
|
+
setIsAutoResuming(false);
|
|
2573
|
+
if (autoResumeTimerRef.current !== null) {
|
|
2574
|
+
window.clearTimeout(autoResumeTimerRef.current);
|
|
2575
|
+
autoResumeTimerRef.current = null;
|
|
2576
|
+
}
|
|
2577
|
+
resetRunningActivity();
|
|
2578
|
+
if (!options?.preserveQueuedMessages) {
|
|
2579
|
+
queueStopVersionRef.current += 1;
|
|
2580
|
+
dequeueInFlightRef.current = false;
|
|
2581
|
+
applyLocalQueuedMessages(() => []);
|
|
2582
|
+
}
|
|
2392
2583
|
const activeRun = getActiveRun();
|
|
2393
2584
|
const runIdToAbort = reconnectRunIdRef.current ?? activeRun?.runId;
|
|
2394
2585
|
userStoppedRunRef.current = {
|
|
@@ -2409,10 +2600,16 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2409
2600
|
reconnectAbortRef.current = null;
|
|
2410
2601
|
reconnectRunIdRef.current = null;
|
|
2411
2602
|
setIsReconnecting(false);
|
|
2603
|
+
setAdapterHandoffPending(false);
|
|
2412
2604
|
const shouldFreezeReconnectContent = !reconnectTailOnlyRef.current &&
|
|
2413
2605
|
reconnectCanMaterializeRef.current &&
|
|
2414
2606
|
reconnectContent.length > 0;
|
|
2415
2607
|
if (shouldFreezeReconnectContent) {
|
|
2608
|
+
const frozenContent = cloneContentParts(reconnectContent);
|
|
2609
|
+
settleInterruptedToolCalls(frozenContent, undefined, {
|
|
2610
|
+
includeActivity: true,
|
|
2611
|
+
});
|
|
2612
|
+
setReconnectContent(frozenContent);
|
|
2416
2613
|
setReconnectFrozen(true);
|
|
2417
2614
|
}
|
|
2418
2615
|
else {
|
|
@@ -2423,6 +2620,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2423
2620
|
reconnectTailOnlyRef.current = false;
|
|
2424
2621
|
}
|
|
2425
2622
|
threadRuntime.cancelRun();
|
|
2623
|
+
settleVisibleInterruptedTools();
|
|
2426
2624
|
if (typeof window !== "undefined") {
|
|
2427
2625
|
window.dispatchEvent(new CustomEvent("agentNative.chatRunning", {
|
|
2428
2626
|
detail: { isRunning: false, tabId: tabId || threadId },
|
|
@@ -2430,8 +2628,11 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2430
2628
|
}
|
|
2431
2629
|
}, [
|
|
2432
2630
|
apiUrl,
|
|
2631
|
+
applyLocalQueuedMessages,
|
|
2433
2632
|
isReconnecting,
|
|
2434
|
-
|
|
2633
|
+
resetRunningActivity,
|
|
2634
|
+
reconnectContent,
|
|
2635
|
+
settleVisibleInterruptedTools,
|
|
2435
2636
|
tabId,
|
|
2436
2637
|
threadId,
|
|
2437
2638
|
threadRuntime,
|
|
@@ -2439,7 +2640,8 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2439
2640
|
// Keep the ref current so addToQueue can call it without a stale closure.
|
|
2440
2641
|
stopActiveRunRef.current = stopActiveRun;
|
|
2441
2642
|
const addToQueue = useCallback(async (text, images, references, attachments, requestMode, intent = "queued", recoveryAction, includeComposerContext = false, trackInRunsTray = false, preserveReconnectAutoRecoveryBudget = false, hideUserMessage = false) => {
|
|
2442
|
-
if (
|
|
2643
|
+
if (agentEngineConfigured.state === "missing") {
|
|
2644
|
+
void ensureAgentEngineReadyForSubmit();
|
|
2443
2645
|
return;
|
|
2444
2646
|
}
|
|
2445
2647
|
if (!preserveReconnectAutoRecoveryBudget) {
|
|
@@ -2578,7 +2780,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2578
2780
|
hideUserMessage,
|
|
2579
2781
|
},
|
|
2580
2782
|
]);
|
|
2581
|
-
stopActiveRunRef.current();
|
|
2783
|
+
stopActiveRunRef.current({ preserveQueuedMessages: true });
|
|
2582
2784
|
}
|
|
2583
2785
|
else if (isRunning && intent === "queued") {
|
|
2584
2786
|
applyLocalQueuedMessages((prev) => [
|
|
@@ -2620,6 +2822,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2620
2822
|
}
|
|
2621
2823
|
}, [
|
|
2622
2824
|
applyLocalQueuedMessages,
|
|
2825
|
+
agentEngineConfigured.state,
|
|
2623
2826
|
buildComposerContextSubmission,
|
|
2624
2827
|
ensureAgentEngineReadyForSubmit,
|
|
2625
2828
|
execMode,
|
|
@@ -2883,8 +3086,12 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2883
3086
|
setDismissedRunErrorKey(visibleRunErrorKey);
|
|
2884
3087
|
}
|
|
2885
3088
|
setRunErrorInfo(null);
|
|
2886
|
-
} }) })), (isReconnecting ||
|
|
2887
|
-
|
|
3089
|
+
} }) })), (isReconnecting ||
|
|
3090
|
+
reconnectFrozen ||
|
|
3091
|
+
adapterHandoffPending) &&
|
|
3092
|
+
visibleReconnectContent.length > 0 && (_jsx(MessageScrollerItem, { children: _jsx(ReconnectStreamMessage, { content: visibleReconnectContent }) })), (isReconnecting ||
|
|
3093
|
+
reconnectFrozen ||
|
|
3094
|
+
adapterHandoffPending) &&
|
|
2888
3095
|
visibleReconnectContent.length === 0 &&
|
|
2889
3096
|
reconnectContent.length === 0 &&
|
|
2890
3097
|
reconnectActivityContent.length > 0 && (_jsx(MessageScrollerItem, { children: _jsx(ReconnectStreamMessage, { content: reconnectActivityContent }) })), showRunningInUI && (_jsx(MessageScrollerItem, { children: _jsx(RunningActivityStatus, { label: runningStatusLabel }) })), queuedMessages
|
|
@@ -2920,9 +3127,9 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2920
3127
|
isRunning,
|
|
2921
3128
|
requestedIntent: options?.intent,
|
|
2922
3129
|
}), undefined, true)
|
|
2923
|
-
: undefined, onSlashCommand: onSlashCommand,
|
|
3130
|
+
: undefined, onSlashCommand: onSlashCommand, execMode: execMode, onExecModeChange: onExecModeChange, planModeDisabled: planModeDisabled, planModeDisabledReason: planModeDisabledReason, selectedModel: selectedModel ?? defaultModel, selectedEffort: selectedEffort, availableModels: availableModels, onModelChange: onModelChange, onEffortChange: onEffortChange, imageModelMenu: imageModelMenu, onConnectProvider: onConnectProvider, toolbarSlot: composerToolbarSlot, contextItems: composerContextItems, onRemoveContextItem: removeComposerContextItem, plusMenuMode: plusMenuMode, layoutVariant: composerLayoutVariant, providerConnectStatusEnabled: providerStatusChecksEnabled, draftScope: threadId || tabId, interceptBuildRequestsForBuilder: true, onAttachmentError: setComposerError, extraActionButton: contextXRayEnabled ||
|
|
2924
3131
|
composerExtraActionButton ||
|
|
2925
|
-
showRunningInUI ? (_jsxs(_Fragment, { children: [contextXRayEnabled && (_jsx(ContextMeter, { threadId: threadId })), composerExtraActionButton, showRunningInUI && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: stopActiveRun, className: "shrink-0 flex h-7 w-7 items-center justify-center rounded-md bg-muted text-foreground hover:bg-muted/80", children: _jsx(IconPlayerStop, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Stop generating" })] }))] })) : undefined })] }), missingApiKey &&
|
|
3132
|
+
showRunningInUI ? (_jsxs(_Fragment, { children: [contextXRayEnabled && (_jsx(ContextMeter, { threadId: threadId })), composerExtraActionButton, showRunningInUI && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => stopActiveRun(), className: "shrink-0 flex h-7 w-7 items-center justify-center rounded-md bg-muted text-foreground hover:bg-muted/80", children: _jsx(IconPlayerStop, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Stop generating" })] }))] })) : undefined })] }), missingApiKey &&
|
|
2926
3133
|
!authError &&
|
|
2927
3134
|
!missingApiKeySetupAboveComposer ? (_jsx("div", { className: "agent-composer-setup-card", "data-agent-composer-setup-position": "below", children: _jsx(BuilderSetupCard, { onConnected: handleBuilderConnected, bouncePulse: missingKeyBouncePulse, layout: missingApiKeySetupLayout }) })) : null] })] }) }) }) }) }) }));
|
|
2928
3135
|
});
|