@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
|
@@ -854,6 +854,21 @@ function lastActivityTool(
|
|
|
854
854
|
return undefined;
|
|
855
855
|
}
|
|
856
856
|
|
|
857
|
+
function lastPreparingActionTool(
|
|
858
|
+
trail: readonly AgentActivityTrailEntry[],
|
|
859
|
+
): string | undefined {
|
|
860
|
+
for (let i = trail.length - 1; i >= 0; i--) {
|
|
861
|
+
const entry = trail[i];
|
|
862
|
+
const tool = entry?.tool?.trim();
|
|
863
|
+
if (!tool) continue;
|
|
864
|
+
const label = entry.label.trim().toLowerCase();
|
|
865
|
+
if (label.startsWith("preparing ") && label.includes(" action")) {
|
|
866
|
+
return tool;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
return undefined;
|
|
870
|
+
}
|
|
871
|
+
|
|
857
872
|
function formatActivityTrail(
|
|
858
873
|
trail: readonly AgentActivityTrailEntry[],
|
|
859
874
|
): string | undefined {
|
|
@@ -2484,7 +2499,8 @@ export function createAgentChatAdapter(
|
|
|
2484
2499
|
part.result !== undefined,
|
|
2485
2500
|
);
|
|
2486
2501
|
const currentPreparingToolName =
|
|
2487
|
-
lastUnresolvedToolActivity(visibleContent)
|
|
2502
|
+
lastUnresolvedToolActivity(visibleContent) ??
|
|
2503
|
+
lastPreparingActionTool(signal.activityTrail);
|
|
2488
2504
|
// In-flight tool stall guard. When the same write tool is stuck
|
|
2489
2505
|
// in-flight because the connection keeps dropping (stream_ended),
|
|
2490
2506
|
// hasInFlightTool=true keeps madeProgress=true and completely
|
|
@@ -207,6 +207,41 @@ function repoTerminalAssistantCount(
|
|
|
207
207
|
}).length;
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
function toolCallProgressScore(part: RepoMessageContent): number {
|
|
211
|
+
if (part.type !== "tool-call") return 0;
|
|
212
|
+
let score = 1;
|
|
213
|
+
if (part.activity !== true) score += 1;
|
|
214
|
+
if ("result" in part) score += 4;
|
|
215
|
+
return score;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function repoToolCallProgress(repo: NormalizedRepo | null | undefined): {
|
|
219
|
+
total: number;
|
|
220
|
+
materialized: number;
|
|
221
|
+
completed: number;
|
|
222
|
+
score: number;
|
|
223
|
+
} {
|
|
224
|
+
const progress = {
|
|
225
|
+
total: 0,
|
|
226
|
+
materialized: 0,
|
|
227
|
+
completed: 0,
|
|
228
|
+
score: 0,
|
|
229
|
+
};
|
|
230
|
+
for (const entry of getRepoMessages(repo)) {
|
|
231
|
+
const message = getRepoMessage(entry);
|
|
232
|
+
const content = message?.content;
|
|
233
|
+
if (!Array.isArray(content)) continue;
|
|
234
|
+
for (const part of content) {
|
|
235
|
+
if (part?.type !== "tool-call") continue;
|
|
236
|
+
progress.total += 1;
|
|
237
|
+
if (part.activity !== true) progress.materialized += 1;
|
|
238
|
+
if ("result" in part) progress.completed += 1;
|
|
239
|
+
progress.score += toolCallProgressScore(part);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return progress;
|
|
243
|
+
}
|
|
244
|
+
|
|
210
245
|
export function shouldImportServerThreadData(
|
|
211
246
|
currentRepo: NormalizedRepo | null | undefined,
|
|
212
247
|
incomingRepo: NormalizedRepo | null | undefined,
|
|
@@ -230,6 +265,16 @@ export function shouldImportServerThreadData(
|
|
|
230
265
|
) {
|
|
231
266
|
return false;
|
|
232
267
|
}
|
|
268
|
+
const currentTools = repoToolCallProgress(currentRepo);
|
|
269
|
+
const incomingTools = repoToolCallProgress(incomingRepo);
|
|
270
|
+
if (
|
|
271
|
+
incomingTools.total < currentTools.total ||
|
|
272
|
+
incomingTools.materialized < currentTools.materialized ||
|
|
273
|
+
incomingTools.completed < currentTools.completed ||
|
|
274
|
+
incomingTools.score < currentTools.score
|
|
275
|
+
) {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
233
278
|
}
|
|
234
279
|
|
|
235
280
|
return true;
|
|
@@ -29,7 +29,11 @@ import type { ActionChatUIConfig } from "../../action-ui.js";
|
|
|
29
29
|
import type { AgentMcpAppPayload } from "../../mcp-client/app-result.js";
|
|
30
30
|
import { AgentTaskCard } from "../AgentTaskCard.js";
|
|
31
31
|
import { writeClipboardText } from "../clipboard.js";
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
Popover,
|
|
34
|
+
PopoverContent,
|
|
35
|
+
PopoverTrigger,
|
|
36
|
+
} from "../components/ui/popover.js";
|
|
33
37
|
import { ConnectBuilderCard } from "../ConnectBuilderCard.js";
|
|
34
38
|
import { McpAppRenderer } from "../mcp-apps/McpAppRenderer.js";
|
|
35
39
|
import type { ContentPart } from "../sse-event-processor.js";
|
|
@@ -306,16 +310,18 @@ function SimpleCodeViewer({
|
|
|
306
310
|
);
|
|
307
311
|
}
|
|
308
312
|
|
|
309
|
-
function
|
|
313
|
+
function ToolOutputPopover({
|
|
310
314
|
open,
|
|
311
315
|
onOpenChange,
|
|
312
316
|
title,
|
|
313
317
|
payload,
|
|
318
|
+
children,
|
|
314
319
|
}: {
|
|
315
320
|
open: boolean;
|
|
316
321
|
onOpenChange: (open: boolean) => void;
|
|
317
322
|
title: string;
|
|
318
323
|
payload: ToolDetailPayload;
|
|
324
|
+
children: React.ReactNode;
|
|
319
325
|
}) {
|
|
320
326
|
const [copied, setCopied] = useState(false);
|
|
321
327
|
const copyResetRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
@@ -339,12 +345,17 @@ function ToolOutputModal({
|
|
|
339
345
|
}, [payload.copyText]);
|
|
340
346
|
|
|
341
347
|
return (
|
|
342
|
-
<
|
|
343
|
-
<
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
+
<Popover open={open} onOpenChange={onOpenChange}>
|
|
349
|
+
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
|
350
|
+
<PopoverContent
|
|
351
|
+
align="start"
|
|
352
|
+
side="bottom"
|
|
353
|
+
sideOffset={6}
|
|
354
|
+
collisionPadding={12}
|
|
355
|
+
className="flex w-[min(calc(100vw-2rem),760px)] flex-col gap-0 overflow-hidden p-0"
|
|
356
|
+
>
|
|
357
|
+
<div className="flex shrink-0 items-center justify-between gap-3 border-b border-border px-4 py-3">
|
|
358
|
+
<div className="truncate text-sm font-medium">{title}</div>
|
|
348
359
|
<button
|
|
349
360
|
type="button"
|
|
350
361
|
onClick={copyValue}
|
|
@@ -354,15 +365,15 @@ function ToolOutputModal({
|
|
|
354
365
|
{copied ? "Copied" : "Copy"}
|
|
355
366
|
</button>
|
|
356
367
|
</div>
|
|
357
|
-
<div className="
|
|
368
|
+
<div className="p-3">
|
|
358
369
|
<SimpleCodeViewer
|
|
359
370
|
text={payload.text}
|
|
360
371
|
lang={payload.lang}
|
|
361
|
-
maxHeightClass="max-h-
|
|
372
|
+
maxHeightClass="max-h-[75vh]"
|
|
362
373
|
/>
|
|
363
374
|
</div>
|
|
364
|
-
</
|
|
365
|
-
</
|
|
375
|
+
</PopoverContent>
|
|
376
|
+
</Popover>
|
|
366
377
|
);
|
|
367
378
|
}
|
|
368
379
|
|
|
@@ -800,25 +811,23 @@ function ToolCallDisplayGeneric({
|
|
|
800
811
|
/>
|
|
801
812
|
)}
|
|
802
813
|
{resultPayload && (
|
|
803
|
-
<
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
814
|
+
<ToolOutputPopover
|
|
815
|
+
open={outputOpen}
|
|
816
|
+
onOpenChange={setOutputOpen}
|
|
817
|
+
title={outputTitle}
|
|
818
|
+
payload={resultPayload}
|
|
808
819
|
>
|
|
809
|
-
<
|
|
810
|
-
|
|
820
|
+
<button
|
|
821
|
+
type="button"
|
|
822
|
+
aria-label={`View ${toolName} output`}
|
|
823
|
+
className="inline-flex size-6 items-center justify-center rounded-md text-muted-foreground/70 transition-colors hover:bg-accent hover:text-foreground"
|
|
824
|
+
>
|
|
825
|
+
<IconCode className="size-3.5" />
|
|
826
|
+
</button>
|
|
827
|
+
</ToolOutputPopover>
|
|
811
828
|
)}
|
|
812
829
|
</div>
|
|
813
830
|
</AnimatedCollapse>
|
|
814
|
-
{resultPayload && (
|
|
815
|
-
<ToolOutputModal
|
|
816
|
-
open={outputOpen}
|
|
817
|
-
onOpenChange={setOutputOpen}
|
|
818
|
-
title={outputTitle}
|
|
819
|
-
payload={resultPayload}
|
|
820
|
-
/>
|
|
821
|
-
)}
|
|
822
831
|
{approval && (
|
|
823
832
|
<ApprovalAffordance toolName={toolName} approval={approval} />
|
|
824
833
|
)}
|
|
@@ -28,11 +28,7 @@ function addCurrentModel(
|
|
|
28
28
|
currentModel?: string,
|
|
29
29
|
): string[] {
|
|
30
30
|
const next = [...models];
|
|
31
|
-
if (
|
|
32
|
-
engineName === currentEngineName &&
|
|
33
|
-
currentModel &&
|
|
34
|
-
!next.includes(currentModel)
|
|
35
|
-
) {
|
|
31
|
+
if (engineName === currentEngineName && currentModel && next.length === 0) {
|
|
36
32
|
next.unshift(currentModel);
|
|
37
33
|
}
|
|
38
34
|
return next;
|
|
@@ -761,8 +761,6 @@ function ModeSelector({
|
|
|
761
761
|
const FRIENDLY_MODEL_NAMES: Record<string, string> = {
|
|
762
762
|
auto: "Default model",
|
|
763
763
|
"claude-fable-5": "Fable 5",
|
|
764
|
-
"grok-code-fast": "Grok Code Fast",
|
|
765
|
-
"qwen3-coder": "Qwen3 Coder",
|
|
766
764
|
"kimi-k2-5": "Kimi K2.5",
|
|
767
765
|
"deepseek-v3-1": "DeepSeek v3.1",
|
|
768
766
|
"z-ai/glm-5.2": "GLM 5.2",
|
|
@@ -335,6 +335,14 @@ function sameOrigin(input: RequestInfo | URL, win: Window): boolean {
|
|
|
335
335
|
return !!url && !!origin && url.origin === origin;
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
+
function isAgentNativeRuntimePath(pathname: string): boolean {
|
|
339
|
+
return (
|
|
340
|
+
pathname === "/_agent-native" ||
|
|
341
|
+
pathname.endsWith("/_agent-native") ||
|
|
342
|
+
pathname.includes("/_agent-native/")
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
338
346
|
function requestMethod(input: RequestInfo | URL, init?: RequestInit): string {
|
|
339
347
|
return (
|
|
340
348
|
init?.method ??
|
|
@@ -444,6 +452,18 @@ function withEmbedAuthHeaders(
|
|
|
444
452
|
token: string,
|
|
445
453
|
win: Window,
|
|
446
454
|
): [RequestInfo | URL, RequestInit | undefined] {
|
|
455
|
+
const method = requestMethod(input, init);
|
|
456
|
+
const url = inputUrl(input, win);
|
|
457
|
+
if (
|
|
458
|
+
url &&
|
|
459
|
+
sameOrigin(input, win) &&
|
|
460
|
+
GUARDED_METHODS.has(method) &&
|
|
461
|
+
isAgentNativeRuntimePath(url.pathname)
|
|
462
|
+
) {
|
|
463
|
+
url.searchParams.set(EMBED_TOKEN_QUERY_PARAM, token);
|
|
464
|
+
return [url.toString(), init];
|
|
465
|
+
}
|
|
466
|
+
|
|
447
467
|
const headers = new Headers(
|
|
448
468
|
init?.headers ?? (input instanceof Request ? input.headers : undefined),
|
|
449
469
|
);
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { IconChevronDown, IconCheck } from "@tabler/icons-react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
createContext,
|
|
4
|
+
useCallback,
|
|
5
|
+
useContext,
|
|
6
|
+
useEffect,
|
|
7
|
+
useState,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
type TransitionEvent,
|
|
10
|
+
} from "react";
|
|
3
11
|
|
|
4
12
|
import { cn } from "../utils.js";
|
|
5
13
|
|
|
@@ -100,6 +108,58 @@ function StatusBadge({
|
|
|
100
108
|
);
|
|
101
109
|
}
|
|
102
110
|
|
|
111
|
+
function SettingsSectionBody({
|
|
112
|
+
open,
|
|
113
|
+
children,
|
|
114
|
+
}: {
|
|
115
|
+
open: boolean;
|
|
116
|
+
children: ReactNode;
|
|
117
|
+
}) {
|
|
118
|
+
const [present, setPresent] = useState(open);
|
|
119
|
+
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (open) {
|
|
122
|
+
setPresent(true);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (!present) return;
|
|
126
|
+
|
|
127
|
+
// Fallback for reduced-motion and older transition engines that may not
|
|
128
|
+
// emit a height transitionend event.
|
|
129
|
+
const timeout = window.setTimeout(() => setPresent(false), 260);
|
|
130
|
+
return () => window.clearTimeout(timeout);
|
|
131
|
+
}, [open, present]);
|
|
132
|
+
|
|
133
|
+
const handleTransitionEnd = useCallback(
|
|
134
|
+
(event: TransitionEvent<HTMLDivElement>) => {
|
|
135
|
+
if (event.target !== event.currentTarget) return;
|
|
136
|
+
if (open) return;
|
|
137
|
+
if (
|
|
138
|
+
event.propertyName !== "height" &&
|
|
139
|
+
event.propertyName !== "max-height"
|
|
140
|
+
) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
setPresent(false);
|
|
144
|
+
},
|
|
145
|
+
[open],
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
if (!present) return null;
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<div
|
|
152
|
+
data-state={open ? "open" : "closed"}
|
|
153
|
+
aria-hidden={open ? undefined : true}
|
|
154
|
+
inert={open ? undefined : true}
|
|
155
|
+
className="agent-native-settings-section-body"
|
|
156
|
+
onTransitionEnd={handleTransitionEnd}
|
|
157
|
+
>
|
|
158
|
+
{children}
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
103
163
|
function PageSettingsSection({
|
|
104
164
|
id,
|
|
105
165
|
icon,
|
|
@@ -156,7 +216,7 @@ function PageSettingsSection({
|
|
|
156
216
|
)}
|
|
157
217
|
/>
|
|
158
218
|
</button>
|
|
159
|
-
{open
|
|
219
|
+
<SettingsSectionBody open={open}>
|
|
160
220
|
<div
|
|
161
221
|
// `data-agent-native-settings-page` lets the shared stylesheet nudge
|
|
162
222
|
// the smallest fixed type (authored dense for the compact sidebar) up
|
|
@@ -167,7 +227,7 @@ function PageSettingsSection({
|
|
|
167
227
|
>
|
|
168
228
|
{children}
|
|
169
229
|
</div>
|
|
170
|
-
|
|
230
|
+
</SettingsSectionBody>
|
|
171
231
|
</div>
|
|
172
232
|
);
|
|
173
233
|
}
|
|
@@ -189,6 +249,7 @@ function SidebarSettingsSection({
|
|
|
189
249
|
<button
|
|
190
250
|
type="button"
|
|
191
251
|
onClick={onToggle}
|
|
252
|
+
aria-expanded={open}
|
|
192
253
|
className="flex w-full cursor-pointer items-center justify-between px-3 py-2.5 text-start rounded-lg hover:bg-accent/40 transition-colors"
|
|
193
254
|
>
|
|
194
255
|
<div className="flex items-center gap-2 min-w-0">
|
|
@@ -207,7 +268,7 @@ function SidebarSettingsSection({
|
|
|
207
268
|
className={`shrink-0 text-muted-foreground transition-transform ${open ? "rotate-180" : ""}`}
|
|
208
269
|
/>
|
|
209
270
|
</button>
|
|
210
|
-
{open
|
|
271
|
+
<SettingsSectionBody open={open}>
|
|
211
272
|
<div className="border-t border-border px-3 pb-3 pt-2.5">
|
|
212
273
|
{subtitle && (
|
|
213
274
|
<p className="text-[10px] text-muted-foreground mb-2.5">
|
|
@@ -216,7 +277,7 @@ function SidebarSettingsSection({
|
|
|
216
277
|
)}
|
|
217
278
|
{children}
|
|
218
279
|
</div>
|
|
219
|
-
|
|
280
|
+
</SettingsSectionBody>
|
|
220
281
|
</div>
|
|
221
282
|
);
|
|
222
283
|
}
|
|
@@ -577,6 +577,7 @@ function isAutoRecoverableError(ev: SSEEvent, errMsg: string): boolean {
|
|
|
577
577
|
if (
|
|
578
578
|
code === "builder_gateway_network_error" ||
|
|
579
579
|
code === "builder_gateway_timeout" ||
|
|
580
|
+
code === "provider_network_error" ||
|
|
580
581
|
code === "stale_run" ||
|
|
581
582
|
code === "timeout" ||
|
|
582
583
|
code === "timeout_error" ||
|
|
@@ -962,7 +963,7 @@ export function processEvent(
|
|
|
962
963
|
};
|
|
963
964
|
}
|
|
964
965
|
|
|
965
|
-
if (ev.type === "thinking") {
|
|
966
|
+
if (ev.type === "thinking" || ev.type === "reasoning") {
|
|
966
967
|
// Model chain-of-thought. Coalesce consecutive deltas into one reasoning
|
|
967
968
|
// part so the UI can render a single collapsible "Thinking" cell.
|
|
968
969
|
const delta = ev.text ?? "";
|
|
@@ -1001,14 +1002,27 @@ export function processEvent(
|
|
|
1001
1002
|
|
|
1002
1003
|
const pendingToolCallIndex = findPendingToolCallIndex(content, tool);
|
|
1003
1004
|
if (pendingToolCallIndex === -1) {
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1005
|
+
// Only surface a placeholder spinner when this tool has no card yet. A
|
|
1006
|
+
// trailing activity heartbeat that arrives after the matching tool_done
|
|
1007
|
+
// (e.g. reordered reconnect replay) must NOT resurrect a spinner for an
|
|
1008
|
+
// already-completed call — that is the "pop back to an older state"
|
|
1009
|
+
// flicker. The real card reappears on the next tool_start regardless.
|
|
1010
|
+
const hasCompletedSameTool = content.some(
|
|
1011
|
+
(part) =>
|
|
1012
|
+
part.type === "tool-call" &&
|
|
1013
|
+
part.toolName === tool &&
|
|
1014
|
+
part.result !== undefined,
|
|
1015
|
+
);
|
|
1016
|
+
if (!hasCompletedSameTool) {
|
|
1017
|
+
content.push({
|
|
1018
|
+
type: "tool-call",
|
|
1019
|
+
toolCallId: `tc_${++toolCallCounter.value}`,
|
|
1020
|
+
toolName: tool,
|
|
1021
|
+
argsText: "",
|
|
1022
|
+
args: {},
|
|
1023
|
+
activity: true,
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1012
1026
|
}
|
|
1013
1027
|
return {
|
|
1014
1028
|
action: "yield",
|
|
@@ -1043,17 +1057,28 @@ export function processEvent(
|
|
|
1043
1057
|
const pendingToolCallIndex = findPendingToolCallIndex(content, tool, ev.id);
|
|
1044
1058
|
const pendingToolCall =
|
|
1045
1059
|
pendingToolCallIndex >= 0 ? content[pendingToolCallIndex] : undefined;
|
|
1060
|
+
const pendingIsActivityPlaceholder =
|
|
1061
|
+
pendingToolCall?.type === "tool-call" &&
|
|
1062
|
+
pendingToolCall.activity === true &&
|
|
1063
|
+
pendingToolCall.argsText === "" &&
|
|
1064
|
+
Object.keys(pendingToolCall.args).length === 0;
|
|
1065
|
+
// A re-emitted start for the SAME id — a retry/auto-continue clear that
|
|
1066
|
+
// keeps the in-flight card mounted, or a reconnect replay — must update the
|
|
1067
|
+
// existing card in place instead of pushing a duplicate. Matching on id
|
|
1068
|
+
// keeps genuinely parallel same-name calls, which carry distinct ids,
|
|
1069
|
+
// separate.
|
|
1070
|
+
const pendingIsSameIdReplay =
|
|
1071
|
+
pendingToolCall?.type === "tool-call" &&
|
|
1072
|
+
ev.id !== undefined &&
|
|
1073
|
+
pendingToolCall.toolCallId === ev.id;
|
|
1046
1074
|
if (
|
|
1047
1075
|
pendingToolCall &&
|
|
1048
1076
|
pendingToolCall.type === "tool-call" &&
|
|
1049
|
-
|
|
1050
|
-
pendingToolCall.argsText === "" &&
|
|
1051
|
-
Object.keys(pendingToolCall.args).length === 0
|
|
1077
|
+
(pendingIsActivityPlaceholder || pendingIsSameIdReplay)
|
|
1052
1078
|
) {
|
|
1053
|
-
// Upgrade the pending
|
|
1054
|
-
//
|
|
1055
|
-
//
|
|
1056
|
-
// locally-generated id already on the card.
|
|
1079
|
+
// Upgrade the pending card in place. Prefer the server-assigned id so the
|
|
1080
|
+
// subsequent tool_done can match it precisely (parallel same-name calls
|
|
1081
|
+
// each carry their own id). Fall back to the locally-generated id.
|
|
1057
1082
|
content[pendingToolCallIndex] = {
|
|
1058
1083
|
type: "tool-call",
|
|
1059
1084
|
toolCallId: ev.id ?? pendingToolCall.toolCallId,
|
|
@@ -1432,7 +1457,14 @@ function clearAssistantDraftContent(content: ContentPart[]): void {
|
|
|
1432
1457
|
continue;
|
|
1433
1458
|
}
|
|
1434
1459
|
if (part.type === "tool-call" && part.result === undefined) {
|
|
1435
|
-
|
|
1460
|
+
// Only drop ephemeral placeholders. Materialized in-flight tool cards
|
|
1461
|
+
// (real args from tool_start) stay mounted so a retry/auto-continue clear
|
|
1462
|
+
// does not hide→show the same call when the next chunk re-emits it.
|
|
1463
|
+
const isEphemeral =
|
|
1464
|
+
part.activity === true ||
|
|
1465
|
+
part.argsText === "" ||
|
|
1466
|
+
Object.keys(part.args ?? {}).length === 0;
|
|
1467
|
+
if (isEphemeral) content.splice(index, 1);
|
|
1436
1468
|
}
|
|
1437
1469
|
}
|
|
1438
1470
|
}
|
|
@@ -777,16 +777,38 @@ export function useDbSync(
|
|
|
777
777
|
// Suppressed-action-only batches skip this whole list (their
|
|
778
778
|
// mutations perform their own narrow invalidation) — but events must
|
|
779
779
|
// STILL reach the onEvent forwarding below, so guard, don't return.
|
|
780
|
+
//
|
|
781
|
+
// Invalidation is scoped by source. Data-query prefixes (action,
|
|
782
|
+
// extension, tool) refetch only when the batch carries an event that
|
|
783
|
+
// can actually change action/extension-backed data — action
|
|
784
|
+
// mutations, settings, extension, collab, screen-refresh, etc.
|
|
785
|
+
// `app-state` events (agent/UI navigation, selection, and the
|
|
786
|
+
// set-url/questions command channel) drive their OWN keys below and
|
|
787
|
+
// must NEVER fan out into "refetch every action query": an active
|
|
788
|
+
// agent session mirrors navigation + selection into application_state
|
|
789
|
+
// continuously, and the serverless poll path replays those writes
|
|
790
|
+
// back to the originating tab (the DB-scan fallback cannot preserve
|
|
791
|
+
// `requestSource`, so `ignoreSource` can't filter them). Fanning each
|
|
792
|
+
// one into a full `["action"]` refetch turned a normal session into a
|
|
793
|
+
// client fetch storm that exhausted the DB connection pool — which in
|
|
794
|
+
// turn starved run heartbeat writes and surfaced as `stale_run`.
|
|
780
795
|
if (!suppressesWholeBatch) {
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
796
|
+
const hasDataChangingEvent = invalidating.some(
|
|
797
|
+
(evt) => evt.source !== "app-state",
|
|
798
|
+
);
|
|
799
|
+
if (hasDataChangingEvent) {
|
|
800
|
+
queryClient.invalidateQueries({ queryKey: ["action"] });
|
|
801
|
+
queryClient.invalidateQueries({ queryKey: ["extension"] });
|
|
802
|
+
queryClient.invalidateQueries({ queryKey: ["extensions"] });
|
|
803
|
+
queryClient.invalidateQueries({ queryKey: ["extension-slots"] });
|
|
804
|
+
queryClient.invalidateQueries({ queryKey: ["slot-installs"] });
|
|
805
|
+
queryClient.invalidateQueries({ queryKey: ["slot-available"] });
|
|
806
|
+
queryClient.invalidateQueries({ queryKey: ["tool"] });
|
|
807
|
+
queryClient.invalidateQueries({ queryKey: ["tools"] });
|
|
808
|
+
}
|
|
809
|
+
if (invalidating.some((evt) => evt.source === "app-state")) {
|
|
810
|
+
queryClient.invalidateQueries({ queryKey: ["app-state"] });
|
|
811
|
+
}
|
|
790
812
|
if (hasAppStateEvent(invalidating, "navigate")) {
|
|
791
813
|
queryClient.invalidateQueries({ queryKey: ["navigate-command"] });
|
|
792
814
|
}
|
|
@@ -21,7 +21,9 @@ import { AGENT_CLIENT_ID, DEFAULT_AGENT_IDENTITY } from "./agent-identity.js";
|
|
|
21
21
|
import { deleteAwarenessRow, upsertAwarenessRow } from "./awareness-store.js";
|
|
22
22
|
import {
|
|
23
23
|
emitAwarenessChange,
|
|
24
|
+
forgetAwarenessClear,
|
|
24
25
|
getDocAwareness,
|
|
26
|
+
rememberAwarenessClear,
|
|
25
27
|
type AwarenessEntry,
|
|
26
28
|
} from "./awareness.js";
|
|
27
29
|
import { appendRecentEdit, type RecentEdit } from "./recent-edits.js";
|
|
@@ -49,11 +51,13 @@ function cancelLinger(docId: string): void {
|
|
|
49
51
|
|
|
50
52
|
function removeAgentPresence(docId: string): void {
|
|
51
53
|
cancelLinger(docId);
|
|
54
|
+
const clearedAt = Date.now();
|
|
55
|
+
rememberAwarenessClear(docId, AGENT_CLIENT_ID, clearedAt);
|
|
52
56
|
const map = getDocAwareness(docId);
|
|
53
57
|
map.delete(AGENT_CLIENT_ID);
|
|
54
58
|
emitAwarenessChange(docId, currentAwarenessStates(map));
|
|
55
59
|
// Cross-instance removal (serverless) — best-effort, never blocks.
|
|
56
|
-
void deleteAwarenessRow(docId, AGENT_CLIENT_ID);
|
|
60
|
+
void deleteAwarenessRow(docId, AGENT_CLIENT_ID, clearedAt);
|
|
57
61
|
|
|
58
62
|
const interval = _heartbeats.get(docId);
|
|
59
63
|
if (interval) {
|
|
@@ -133,6 +137,7 @@ function readAgentState(docId: string): Record<string, unknown> {
|
|
|
133
137
|
}
|
|
134
138
|
|
|
135
139
|
function writeAgentState(docId: string, state: Record<string, unknown>): void {
|
|
140
|
+
forgetAwarenessClear(docId, AGENT_CLIENT_ID);
|
|
136
141
|
const entry: AwarenessEntry = {
|
|
137
142
|
clientId: AGENT_CLIENT_ID,
|
|
138
143
|
state: JSON.stringify(state),
|