@agent-native/core 0.119.2 → 0.119.4
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 +19 -0
- package/corpus/core/package.json +3 -3
- package/corpus/core/src/agent/production-agent.ts +107 -125
- package/corpus/core/src/agent/run-manager.ts +45 -2
- package/corpus/core/src/agent/thread-data-builder.ts +85 -8
- package/corpus/core/src/cli/create.ts +44 -5
- package/corpus/core/src/client/AssistantChat.tsx +37 -9
- package/corpus/core/src/client/chat/message-components.tsx +9 -1
- package/corpus/core/src/client/chat/repo-helpers.ts +77 -0
- package/corpus/core/src/client/chat/tool-call-display.tsx +51 -15
- package/corpus/core/src/server/agent-chat/framework-prompts.ts +3 -1
- package/corpus/core/src/server/agent-chat/plugin-options.ts +9 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +12 -3
- package/corpus/core/src/templates/chat/.agents/skills/actions/SKILL.md +512 -0
- package/corpus/core/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +189 -0
- package/corpus/core/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/core/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +177 -0
- package/corpus/core/src/templates/chat/.agents/skills/capture-learnings/SKILL.md +89 -0
- package/corpus/core/src/templates/chat/.agents/skills/create-skill/SKILL.md +221 -0
- package/corpus/core/src/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +220 -0
- package/corpus/core/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +263 -0
- package/corpus/core/src/templates/chat/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/core/src/templates/chat/.agents/skills/frontend-design/SKILL.md +160 -0
- package/corpus/core/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +232 -0
- package/corpus/core/src/templates/chat/.agents/skills/security/SKILL.md +280 -0
- package/corpus/core/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +118 -0
- package/corpus/core/src/templates/chat/.agents/skills/shadcn-ui/SKILL.md +119 -0
- package/corpus/core/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +100 -0
- package/corpus/core/src/templates/chat/.env.example +5 -0
- package/corpus/core/src/templates/chat/.ignore +0 -0
- package/corpus/core/src/templates/chat/.oxfmtrc.json +8 -0
- package/corpus/core/src/templates/chat/AGENTS.md +69 -0
- package/corpus/core/src/templates/chat/CHANGELOG.md +10 -0
- package/corpus/core/src/templates/chat/DEVELOPING.md +185 -0
- package/corpus/core/src/templates/chat/README.md +32 -0
- package/corpus/core/src/templates/chat/_gitignore +43 -0
- package/corpus/core/src/templates/chat/actions/hello.ts +13 -0
- package/corpus/core/src/templates/chat/actions/navigate.ts +41 -0
- package/corpus/core/src/templates/chat/actions/run.ts +2 -0
- package/corpus/core/src/templates/chat/actions/view-screen.ts +31 -0
- package/corpus/core/src/templates/chat/app/components/layout/Header.tsx +60 -0
- package/corpus/core/src/templates/chat/app/components/layout/Layout.tsx +185 -0
- package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +450 -0
- package/corpus/core/src/templates/chat/app/components/ui/button.tsx +1 -0
- package/corpus/core/src/templates/chat/app/components/ui/card.tsx +1 -0
- package/corpus/core/src/templates/chat/app/components/ui/dropdown-menu.tsx +1 -0
- package/corpus/core/src/templates/chat/app/components/ui/input.tsx +1 -0
- package/corpus/core/src/templates/chat/app/components/ui/label.tsx +1 -0
- package/corpus/core/src/templates/chat/app/components/ui/sheet.tsx +1 -0
- package/corpus/core/src/templates/chat/app/components/ui/toolkit-provider.tsx +17 -0
- package/corpus/core/src/templates/chat/app/components/ui/tooltip.tsx +1 -0
- package/corpus/core/src/templates/chat/app/design-system.ts +3 -0
- package/corpus/core/src/templates/chat/app/entry.client.tsx +19 -0
- package/corpus/core/src/templates/chat/app/entry.server.tsx +10 -0
- package/corpus/core/src/templates/chat/app/global.css +93 -0
- package/corpus/core/src/templates/chat/app/hooks/use-navigation-state.ts +93 -0
- package/corpus/core/src/templates/chat/app/i18n/ar-SA.ts +68 -0
- package/corpus/core/src/templates/chat/app/i18n/de-DE.ts +71 -0
- package/corpus/core/src/templates/chat/app/i18n/en-US.ts +70 -0
- package/corpus/core/src/templates/chat/app/i18n/es-ES.ts +71 -0
- package/corpus/core/src/templates/chat/app/i18n/fr-FR.ts +71 -0
- package/corpus/core/src/templates/chat/app/i18n/hi-IN.ts +69 -0
- package/corpus/core/src/templates/chat/app/i18n/index.ts +34 -0
- package/corpus/core/src/templates/chat/app/i18n/ja-JP.ts +70 -0
- package/corpus/core/src/templates/chat/app/i18n/ko-KR.ts +70 -0
- package/corpus/core/src/templates/chat/app/i18n/pt-BR.ts +71 -0
- package/corpus/core/src/templates/chat/app/i18n/zh-CN.ts +66 -0
- package/corpus/core/src/templates/chat/app/i18n/zh-TW.ts +66 -0
- package/corpus/core/src/templates/chat/app/i18n-data.ts +556 -0
- package/corpus/core/src/templates/chat/app/lib/agent-page.tsx +49 -0
- package/corpus/core/src/templates/chat/app/lib/app-config.ts +11 -0
- package/corpus/core/src/templates/chat/app/lib/tab-id.ts +1 -0
- package/corpus/core/src/templates/chat/app/lib/utils.ts +1 -0
- package/corpus/core/src/templates/chat/app/root.tsx +173 -0
- package/corpus/core/src/templates/chat/app/routes/_index.tsx +94 -0
- package/corpus/core/src/templates/chat/app/routes/agent.tsx +24 -0
- package/corpus/core/src/templates/chat/app/routes/chat.$threadId.tsx +1 -0
- package/corpus/core/src/templates/chat/app/routes/database.tsx +17 -0
- package/corpus/core/src/templates/chat/app/routes/extensions.$id.$slug.tsx +2 -0
- package/corpus/core/src/templates/chat/app/routes/extensions.$id.tsx +11 -0
- package/corpus/core/src/templates/chat/app/routes/extensions._index.tsx +11 -0
- package/corpus/core/src/templates/chat/app/routes/extensions.tsx +5 -0
- package/corpus/core/src/templates/chat/app/routes/observability.tsx +19 -0
- package/corpus/core/src/templates/chat/app/routes/settings.tsx +89 -0
- package/corpus/core/src/templates/chat/app/routes/team.tsx +11 -0
- package/corpus/core/src/templates/chat/app/routes.ts +4 -0
- package/corpus/core/src/templates/chat/app/vite-env.d.ts +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-14-chat-opens-reliably-on-hosted-deployments-instead-of-failing.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
- package/corpus/core/src/templates/chat/changelog/2026-07-23-full-page-chat-is-better-centered-with-quieter-chat-history-.md +6 -0
- package/corpus/core/src/templates/chat/components.json +20 -0
- package/corpus/core/src/templates/chat/learnings.defaults.md +5 -0
- package/corpus/core/src/templates/chat/netlify.toml +10 -0
- package/corpus/core/src/templates/chat/package.json +92 -0
- package/corpus/core/src/templates/chat/public/agent-native-icon-dark.svg +10 -0
- package/corpus/core/src/templates/chat/public/agent-native-icon-light.svg +10 -0
- package/corpus/core/src/templates/chat/public/agent-native-logo-dark.svg +21 -0
- package/corpus/core/src/templates/chat/public/agent-native-logo-light.svg +21 -0
- package/corpus/core/src/templates/chat/public/favicon.svg +1 -0
- package/corpus/core/src/templates/chat/public/icon-180.svg +1 -0
- package/corpus/core/src/templates/chat/public/icon-192.svg +1 -0
- package/corpus/core/src/templates/chat/public/icon-512.svg +1 -0
- package/corpus/core/src/templates/chat/public/manifest.json +21 -0
- package/corpus/core/src/templates/chat/react-router.config.ts +7 -0
- package/corpus/core/src/templates/chat/server/middleware/auth.ts +15 -0
- package/corpus/core/src/templates/chat/server/plugins/agent-chat.ts +21 -0
- package/corpus/core/src/templates/chat/server/plugins/auth.ts +17 -0
- package/corpus/core/src/templates/chat/server/routes/[...page].get.ts +5 -0
- package/corpus/core/src/templates/chat/ssr-entry.ts +15 -0
- package/corpus/core/src/templates/chat/tsconfig.json +21 -0
- package/corpus/core/src/templates/chat/vite.config.ts +19 -0
- package/corpus/templates/analytics/AGENTS.md +19 -11
- package/corpus/templates/analytics/actions/list-data-dictionary.ts +3 -1
- package/corpus/templates/analytics/actions/save-data-dictionary-entry.ts +14 -0
- package/corpus/templates/analytics/actions/search-analytics-query-catalog.ts +41 -0
- package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +13 -0
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +12 -11
- package/corpus/templates/analytics/app/pages/adhoc/DashboardSkeleton.tsx +3 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +7 -1
- package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +8 -1
- package/corpus/templates/analytics/changelog/2026-07-22-fixed-dashboards-and-analyses-missing-a-copyable-share-link.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-23-dashboard-chart-loading-placeholders-are-easier-to-see-in-da.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-23-routine-analytics-lookups-reuse-existing-query-definitions.md +6 -0
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +1 -12
- package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +405 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +11 -16
- package/corpus/templates/content/changelog/2026-07-23-database-toolbar-sort-and-filter-controls-open-reliably.md +6 -0
- package/corpus/templates/forms/app/lib/public-form-link.ts +14 -0
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +6 -14
- package/corpus/templates/forms/changelog/2026-07-23-published-form-links-can-be-copied-without-being-asked-to-re.md +6 -0
- package/corpus/templates/mail/changelog/2026-07-23-scheduled-emails-now-send-only-once-when-multiple-requests-r.md +6 -0
- package/corpus/templates/mail/server/lib/jobs.ts +13 -4
- package/corpus/templates/mail/server/plugins/mail-jobs.ts +1 -1
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +7 -18
- package/corpus/templates/slides/app/lib/agent-visible-message.ts +28 -0
- package/corpus/templates/slides/app/pages/Index.tsx +6 -34
- package/corpus/templates/slides/changelog/2026-07-23-full-prompts-stay-visible-in-chat-when-creating-decks-or-add.md +6 -0
- package/corpus/toolkit/CHANGELOG.md +13 -0
- package/corpus/toolkit/package.json +1 -1
- package/corpus/toolkit/src/editor/SharedRichEditor.tsx +23 -2
- package/corpus/toolkit/src/editor/SlashCommandMenu.tsx +68 -2
- package/corpus/toolkit/src/editor/index.ts +1 -0
- package/corpus/toolkit/src/editor.css +75 -0
- package/corpus/toolkit/src/ui/button.tsx +3 -2
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +96 -115
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts +9 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +26 -0
- 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 +69 -9
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/cli/create.d.ts +2 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +43 -6
- package/dist/cli/create.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +32 -10
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +2 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +9 -3
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/repo-helpers.d.ts +4 -0
- package/dist/client/chat/repo-helpers.d.ts.map +1 -1
- package/dist/client/chat/repo-helpers.js +61 -0
- package/dist/client/chat/repo-helpers.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +2 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +10 -9
- package/dist/client/chat/tool-call-display.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 +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
- package/dist/provider-api/actions/provider-api.d.ts +7 -7
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat/framework-prompts.d.ts.map +1 -1
- package/dist/server/agent-chat/framework-prompts.js +3 -1
- package/dist/server/agent-chat/framework-prompts.js.map +1 -1
- package/dist/server/agent-chat/plugin-options.d.ts +9 -0
- package/dist/server/agent-chat/plugin-options.d.ts.map +1 -1
- package/dist/server/agent-chat/plugin-options.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +11 -2
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +4 -4
- package/src/agent/production-agent.ts +107 -125
- package/src/agent/run-manager.ts +45 -2
- package/src/agent/thread-data-builder.ts +85 -8
- package/src/cli/create.ts +44 -5
- package/src/client/AssistantChat.tsx +37 -9
- package/src/client/chat/message-components.tsx +9 -1
- package/src/client/chat/repo-helpers.ts +77 -0
- package/src/client/chat/tool-call-display.tsx +51 -15
- package/src/server/agent-chat/framework-prompts.ts +3 -1
- package/src/server/agent-chat/plugin-options.ts +9 -0
- package/src/server/agent-chat-plugin.ts +12 -3
- package/src/templates/chat/actions/hello.spec.ts +0 -23
- package/src/templates/chat/actions/navigate.spec.ts +0 -68
- package/src/templates/chat/actions/view-screen.spec.ts +0 -40
- package/src/templates/chat/app/lib/agent-page.spec.tsx +0 -61
|
@@ -1,10 +1,71 @@
|
|
|
1
1
|
// Owns: typed helpers for reading/comparing the assistant-ui message repository shape.
|
|
2
|
+
// The assistant-ui ExportedMessageRepository type is structurally complex and
|
|
3
|
+
// the normalised internal form diverges slightly. We define a structural
|
|
4
|
+
// interface covering the shapes both `threadRuntime.export()` and
|
|
5
|
+
// `normalizeThreadRepository()` produce, and use it everywhere instead of `any`.
|
|
6
|
+
import { ASSISTANT_RUN_DURATION_METADATA_KEY } from "../../agent/thread-data-builder.js";
|
|
2
7
|
export function getRepoMessages(repo) {
|
|
3
8
|
return Array.isArray(repo?.messages) ? repo.messages : [];
|
|
4
9
|
}
|
|
5
10
|
export function getRepoMessage(entry) {
|
|
6
11
|
return (entry?.message ?? entry);
|
|
7
12
|
}
|
|
13
|
+
export function getAssistantRunDurationMs(message) {
|
|
14
|
+
const metadata = message?.metadata && typeof message.metadata === "object"
|
|
15
|
+
? message.metadata
|
|
16
|
+
: null;
|
|
17
|
+
const custom = metadata?.custom && typeof metadata.custom === "object"
|
|
18
|
+
? metadata.custom
|
|
19
|
+
: null;
|
|
20
|
+
const durationMs = custom?.[ASSISTANT_RUN_DURATION_METADATA_KEY];
|
|
21
|
+
return typeof durationMs === "number" &&
|
|
22
|
+
Number.isFinite(durationMs) &&
|
|
23
|
+
durationMs >= 0
|
|
24
|
+
? durationMs
|
|
25
|
+
: null;
|
|
26
|
+
}
|
|
27
|
+
export function withLastAssistantRunDuration(repo, durationMs) {
|
|
28
|
+
if (!Array.isArray(repo.messages) ||
|
|
29
|
+
typeof durationMs !== "number" ||
|
|
30
|
+
!Number.isFinite(durationMs) ||
|
|
31
|
+
durationMs < 0) {
|
|
32
|
+
return repo;
|
|
33
|
+
}
|
|
34
|
+
let messageIndex = -1;
|
|
35
|
+
for (let index = repo.messages.length - 1; index >= 0; index -= 1) {
|
|
36
|
+
if (getRepoMessage(repo.messages[index])?.role === "assistant") {
|
|
37
|
+
messageIndex = index;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (messageIndex < 0)
|
|
42
|
+
return repo;
|
|
43
|
+
const entry = repo.messages[messageIndex];
|
|
44
|
+
const message = getRepoMessage(entry);
|
|
45
|
+
if (!message || getAssistantRunDurationMs(message) === durationMs) {
|
|
46
|
+
return repo;
|
|
47
|
+
}
|
|
48
|
+
const metadata = message.metadata ?? {};
|
|
49
|
+
const custom = metadata.custom && typeof metadata.custom === "object"
|
|
50
|
+
? metadata.custom
|
|
51
|
+
: {};
|
|
52
|
+
const nextMessage = {
|
|
53
|
+
...message,
|
|
54
|
+
metadata: {
|
|
55
|
+
...metadata,
|
|
56
|
+
custom: {
|
|
57
|
+
...custom,
|
|
58
|
+
[ASSISTANT_RUN_DURATION_METADATA_KEY]: durationMs,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
const messages = repo.messages.slice();
|
|
63
|
+
messages[messageIndex] =
|
|
64
|
+
entry.message === undefined
|
|
65
|
+
? nextMessage
|
|
66
|
+
: { ...entry, message: nextMessage };
|
|
67
|
+
return { ...repo, messages };
|
|
68
|
+
}
|
|
8
69
|
/**
|
|
9
70
|
* Collapse duplicate message ids before a repository is handed to
|
|
10
71
|
* `threadRuntime.import()`. assistant-ui's `MessageRepository` throws
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repo-helpers.js","sourceRoot":"","sources":["../../../src/client/chat/repo-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["// Owns: typed helpers for reading/comparing the assistant-ui message repository shape.\n\n// The assistant-ui ExportedMessageRepository type is structurally complex and\n// the normalised internal form diverges slightly. We define a structural\n// interface covering the shapes both `threadRuntime.export()` and\n// `normalizeThreadRepository()` produce, and use it everywhere instead of `any`.\n\nexport interface RepoMessageStatus {\n type?: string;\n reason?: string;\n}\n\nexport interface RepoMessageContent {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\nexport interface RepoMessage {\n id?: string;\n role?: string;\n status?: RepoMessageStatus;\n content?: string | RepoMessageContent[];\n metadata?: Record<string, unknown>;\n createdAt?: Date | string | number;\n [key: string]: unknown;\n}\n\n/** Entry in `repo.messages` — may be flat or wrapped `{ message: RepoMessage }`. */\nexport interface RepoEntry {\n parentId?: string | null;\n message?: RepoMessage;\n // Flat (unwrapped) fields are also legal:\n id?: string;\n role?: string;\n status?: RepoMessageStatus;\n content?: string | RepoMessageContent[];\n [key: string]: unknown;\n}\n\n/** Minimal structure of the normalised thread repository used by AssistantChat. */\nexport interface NormalizedRepo {\n messages?: RepoEntry[];\n headId?: string;\n queuedMessages?: unknown[];\n [key: string]: unknown;\n}\n\nexport function getRepoMessages(\n repo: NormalizedRepo | null | undefined,\n): RepoEntry[] {\n return Array.isArray(repo?.messages) ? repo.messages : [];\n}\n\nexport function getRepoMessage(entry: RepoEntry): RepoMessage | null {\n return (entry?.message ?? entry) as RepoMessage | null;\n}\n\n/**\n * Collapse duplicate message ids before a repository is handed to\n * `threadRuntime.import()`. assistant-ui's `MessageRepository` throws\n * \"MessageRepository(performOp/link): A message with the same id already exists\n * in the parent tree\" when the imported messages contain the same id more than\n * once (Sentry AGENT-NATIVE-BROWSER-2Q). Duplicate ids are never valid thread\n * data — they come from optimistic+echo races, streaming reconnect replays, or\n * multi-tab merges — so keep only the LAST occurrence of each id (the most\n * recent, most complete copy). parentId references stay valid because the\n * surviving entry keeps the same id.\n *\n * Returns the input unchanged (same reference) when there are no duplicates, so\n * the overwhelmingly common no-dupe case is a cheap no-op with zero behavioural\n * change for normal threads.\n */\nexport function dedupeRepoMessagesById<T extends NormalizedRepo>(\n repo: T | null | undefined,\n): T | null | undefined {\n if (!repo || !Array.isArray(repo.messages)) return repo;\n const entries = repo.messages;\n const lastIndexById = new Map<string, number>();\n let hasDuplicate = false;\n entries.forEach((entry, index) => {\n const id = getRepoMessage(entry)?.id;\n if (typeof id !== \"string\" || !id) return;\n if (lastIndexById.has(id)) hasDuplicate = true;\n lastIndexById.set(id, index);\n });\n if (!hasDuplicate) return repo;\n const deduped = entries.filter((entry, index) => {\n const id = getRepoMessage(entry)?.id;\n // Keep id-less entries untouched; for duplicated ids keep only the last.\n if (typeof id !== \"string\" || !id) return true;\n return lastIndexById.get(id) === index;\n });\n return { ...repo, messages: deduped };\n}\n\nfunction repoMessageContentIsEmpty(content: unknown): boolean {\n if (typeof content === \"string\") return content.trim().length === 0;\n if (!Array.isArray(content)) return true;\n return !content.some((part) => {\n if (!part || typeof part !== \"object\") return false;\n const type = (part as { type?: unknown }).type;\n if (type === \"text\") {\n const text = (part as { text?: unknown }).text;\n return typeof text === \"string\" && text.trim().length > 0;\n }\n return true;\n });\n}\n\nfunction entryWithParentId(\n entry: RepoEntry,\n parentId: string | null,\n): RepoEntry {\n return { ...entry, parentId };\n}\n\nfunction repairRepoLinks<T extends NormalizedRepo>(\n repo: T,\n entries: RepoEntry[],\n): T {\n const seenIds = new Set<string>();\n let previousId: string | null = null;\n const repaired: RepoEntry[] = [];\n\n for (const entry of entries) {\n const id = getRepoMessage(entry)?.id;\n if (typeof id !== \"string\" || !id) continue;\n const requestedParentId = entry.parentId;\n const parentId =\n requestedParentId === null\n ? null\n : typeof requestedParentId === \"string\" &&\n seenIds.has(requestedParentId)\n ? requestedParentId\n : previousId;\n repaired.push(entryWithParentId(entry, parentId));\n seenIds.add(id);\n previousId = id;\n }\n\n const headId =\n typeof repo.headId === \"string\" && seenIds.has(repo.headId)\n ? repo.headId\n : previousId;\n return { ...repo, messages: repaired, headId: headId ?? undefined };\n}\n\nexport function dropEmptyAssistantMessages<T extends NormalizedRepo>(\n repo: T | null | undefined,\n): T | null | undefined {\n if (!repo || !Array.isArray(repo.messages)) return repo;\n\n let changed = false;\n const messages = repo.messages.filter((entry) => {\n const message = getRepoMessage(entry);\n const drop =\n message?.role === \"assistant\" &&\n repoMessageContentIsEmpty(message.content);\n if (drop) changed = true;\n return !drop;\n });\n\n if (!changed) return repo;\n return repairRepoLinks(repo, messages);\n}\n\nexport function isAssistantMessageTerminal(\n message: RepoMessage | null,\n): boolean {\n const statusType = message?.status?.type;\n return statusType === \"complete\" || statusType === \"incomplete\";\n}\n\nexport function repoHasAssistantMessage(\n repo: NormalizedRepo | null | undefined,\n): boolean {\n return getRepoMessages(repo).some(\n (m) => getRepoMessage(m)?.role === \"assistant\",\n );\n}\n\nfunction repoTextLength(repo: NormalizedRepo | null | undefined): number {\n let length = 0;\n for (const entry of getRepoMessages(repo)) {\n const message = getRepoMessage(entry);\n const content = message?.content;\n if (typeof content === \"string\") {\n length += content.length;\n } else if (Array.isArray(content)) {\n for (const part of content) {\n if (part?.type === \"text\" && typeof part.text === \"string\") {\n length += part.text.length;\n }\n }\n }\n }\n return length;\n}\n\nfunction repoTerminalAssistantCount(\n repo: NormalizedRepo | null | undefined,\n): number {\n return getRepoMessages(repo).filter((entry) => {\n const message = getRepoMessage(entry);\n return message?.role === \"assistant\" && isAssistantMessageTerminal(message);\n }).length;\n}\n\nfunction toolCallProgressScore(part: RepoMessageContent): number {\n if (part.type !== \"tool-call\") return 0;\n let score = 1;\n if (part.activity !== true) score += 1;\n if (\"result\" in part) score += 4;\n return score;\n}\n\nfunction repoToolCallProgress(repo: NormalizedRepo | null | undefined): {\n total: number;\n materialized: number;\n completed: number;\n score: number;\n} {\n const progress = {\n total: 0,\n materialized: 0,\n completed: 0,\n score: 0,\n };\n for (const entry of getRepoMessages(repo)) {\n const message = getRepoMessage(entry);\n const content = message?.content;\n if (!Array.isArray(content)) continue;\n for (const part of content) {\n if (part?.type !== \"tool-call\") continue;\n progress.total += 1;\n if (part.activity !== true) progress.materialized += 1;\n if (\"result\" in part) progress.completed += 1;\n progress.score += toolCallProgressScore(part);\n }\n }\n return progress;\n}\n\nexport function shouldImportServerThreadData(\n currentRepo: NormalizedRepo | null | undefined,\n incomingRepo: NormalizedRepo | null | undefined,\n): boolean {\n const incomingCount = getRepoMessages(incomingRepo).length;\n if (incomingCount === 0) return false;\n\n const currentCount = getRepoMessages(currentRepo).length;\n if (currentCount === 0) return true;\n if (incomingCount < currentCount) return false;\n\n if (incomingCount === currentCount) {\n const currentTerminalAssistants = repoTerminalAssistantCount(currentRepo);\n const incomingTerminalAssistants = repoTerminalAssistantCount(incomingRepo);\n if (incomingTerminalAssistants < currentTerminalAssistants) {\n return false;\n }\n if (\n incomingTerminalAssistants <= currentTerminalAssistants &&\n repoTextLength(incomingRepo) < repoTextLength(currentRepo)\n ) {\n return false;\n }\n const currentTools = repoToolCallProgress(currentRepo);\n const incomingTools = repoToolCallProgress(incomingRepo);\n if (\n incomingTools.total < currentTools.total ||\n incomingTools.materialized < currentTools.materialized ||\n incomingTools.completed < currentTools.completed ||\n incomingTools.score < currentTools.score\n ) {\n return false;\n }\n }\n\n return true;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"repo-helpers.js","sourceRoot":"","sources":["../../../src/client/chat/repo-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["// Owns: typed helpers for reading/comparing the assistant-ui message repository shape.\n\n// The assistant-ui ExportedMessageRepository type is structurally complex and\n// the normalised internal form diverges slightly. We define a structural\n// interface covering the shapes both `threadRuntime.export()` and\n// `normalizeThreadRepository()` produce, and use it everywhere instead of `any`.\n\nimport { ASSISTANT_RUN_DURATION_METADATA_KEY } from \"../../agent/thread-data-builder.js\";\n\nexport interface RepoMessageStatus {\n type?: string;\n reason?: string;\n}\n\nexport interface RepoMessageContent {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\nexport interface RepoMessage {\n id?: string;\n role?: string;\n status?: RepoMessageStatus;\n content?: string | RepoMessageContent[];\n metadata?: Record<string, unknown>;\n createdAt?: Date | string | number;\n [key: string]: unknown;\n}\n\n/** Entry in `repo.messages` — may be flat or wrapped `{ message: RepoMessage }`. */\nexport interface RepoEntry {\n parentId?: string | null;\n message?: RepoMessage;\n // Flat (unwrapped) fields are also legal:\n id?: string;\n role?: string;\n status?: RepoMessageStatus;\n content?: string | RepoMessageContent[];\n [key: string]: unknown;\n}\n\n/** Minimal structure of the normalised thread repository used by AssistantChat. */\nexport interface NormalizedRepo {\n messages?: RepoEntry[];\n headId?: string;\n queuedMessages?: unknown[];\n [key: string]: unknown;\n}\n\nexport function getRepoMessages(\n repo: NormalizedRepo | null | undefined,\n): RepoEntry[] {\n return Array.isArray(repo?.messages) ? repo.messages : [];\n}\n\nexport function getRepoMessage(entry: RepoEntry): RepoMessage | null {\n return (entry?.message ?? entry) as RepoMessage | null;\n}\n\nexport function getAssistantRunDurationMs(\n message:\n | {\n metadata?: unknown;\n }\n | null\n | undefined,\n): number | null {\n const metadata =\n message?.metadata && typeof message.metadata === \"object\"\n ? (message.metadata as Record<string, unknown>)\n : null;\n const custom =\n metadata?.custom && typeof metadata.custom === \"object\"\n ? (metadata.custom as Record<string, unknown>)\n : null;\n const durationMs = custom?.[ASSISTANT_RUN_DURATION_METADATA_KEY];\n return typeof durationMs === \"number\" &&\n Number.isFinite(durationMs) &&\n durationMs >= 0\n ? durationMs\n : null;\n}\n\nexport function withLastAssistantRunDuration<T extends NormalizedRepo>(\n repo: T,\n durationMs: number | null | undefined,\n): T {\n if (\n !Array.isArray(repo.messages) ||\n typeof durationMs !== \"number\" ||\n !Number.isFinite(durationMs) ||\n durationMs < 0\n ) {\n return repo;\n }\n\n let messageIndex = -1;\n for (let index = repo.messages.length - 1; index >= 0; index -= 1) {\n if (getRepoMessage(repo.messages[index]!)?.role === \"assistant\") {\n messageIndex = index;\n break;\n }\n }\n if (messageIndex < 0) return repo;\n\n const entry = repo.messages[messageIndex]!;\n const message = getRepoMessage(entry);\n if (!message || getAssistantRunDurationMs(message) === durationMs) {\n return repo;\n }\n\n const metadata = message.metadata ?? {};\n const custom =\n metadata.custom && typeof metadata.custom === \"object\"\n ? (metadata.custom as Record<string, unknown>)\n : {};\n const nextMessage: RepoMessage = {\n ...message,\n metadata: {\n ...metadata,\n custom: {\n ...custom,\n [ASSISTANT_RUN_DURATION_METADATA_KEY]: durationMs,\n },\n },\n };\n const messages = repo.messages.slice();\n messages[messageIndex] =\n entry.message === undefined\n ? (nextMessage as RepoEntry)\n : { ...entry, message: nextMessage };\n return { ...repo, messages };\n}\n\n/**\n * Collapse duplicate message ids before a repository is handed to\n * `threadRuntime.import()`. assistant-ui's `MessageRepository` throws\n * \"MessageRepository(performOp/link): A message with the same id already exists\n * in the parent tree\" when the imported messages contain the same id more than\n * once (Sentry AGENT-NATIVE-BROWSER-2Q). Duplicate ids are never valid thread\n * data — they come from optimistic+echo races, streaming reconnect replays, or\n * multi-tab merges — so keep only the LAST occurrence of each id (the most\n * recent, most complete copy). parentId references stay valid because the\n * surviving entry keeps the same id.\n *\n * Returns the input unchanged (same reference) when there are no duplicates, so\n * the overwhelmingly common no-dupe case is a cheap no-op with zero behavioural\n * change for normal threads.\n */\nexport function dedupeRepoMessagesById<T extends NormalizedRepo>(\n repo: T | null | undefined,\n): T | null | undefined {\n if (!repo || !Array.isArray(repo.messages)) return repo;\n const entries = repo.messages;\n const lastIndexById = new Map<string, number>();\n let hasDuplicate = false;\n entries.forEach((entry, index) => {\n const id = getRepoMessage(entry)?.id;\n if (typeof id !== \"string\" || !id) return;\n if (lastIndexById.has(id)) hasDuplicate = true;\n lastIndexById.set(id, index);\n });\n if (!hasDuplicate) return repo;\n const deduped = entries.filter((entry, index) => {\n const id = getRepoMessage(entry)?.id;\n // Keep id-less entries untouched; for duplicated ids keep only the last.\n if (typeof id !== \"string\" || !id) return true;\n return lastIndexById.get(id) === index;\n });\n return { ...repo, messages: deduped };\n}\n\nfunction repoMessageContentIsEmpty(content: unknown): boolean {\n if (typeof content === \"string\") return content.trim().length === 0;\n if (!Array.isArray(content)) return true;\n return !content.some((part) => {\n if (!part || typeof part !== \"object\") return false;\n const type = (part as { type?: unknown }).type;\n if (type === \"text\") {\n const text = (part as { text?: unknown }).text;\n return typeof text === \"string\" && text.trim().length > 0;\n }\n return true;\n });\n}\n\nfunction entryWithParentId(\n entry: RepoEntry,\n parentId: string | null,\n): RepoEntry {\n return { ...entry, parentId };\n}\n\nfunction repairRepoLinks<T extends NormalizedRepo>(\n repo: T,\n entries: RepoEntry[],\n): T {\n const seenIds = new Set<string>();\n let previousId: string | null = null;\n const repaired: RepoEntry[] = [];\n\n for (const entry of entries) {\n const id = getRepoMessage(entry)?.id;\n if (typeof id !== \"string\" || !id) continue;\n const requestedParentId = entry.parentId;\n const parentId =\n requestedParentId === null\n ? null\n : typeof requestedParentId === \"string\" &&\n seenIds.has(requestedParentId)\n ? requestedParentId\n : previousId;\n repaired.push(entryWithParentId(entry, parentId));\n seenIds.add(id);\n previousId = id;\n }\n\n const headId =\n typeof repo.headId === \"string\" && seenIds.has(repo.headId)\n ? repo.headId\n : previousId;\n return { ...repo, messages: repaired, headId: headId ?? undefined };\n}\n\nexport function dropEmptyAssistantMessages<T extends NormalizedRepo>(\n repo: T | null | undefined,\n): T | null | undefined {\n if (!repo || !Array.isArray(repo.messages)) return repo;\n\n let changed = false;\n const messages = repo.messages.filter((entry) => {\n const message = getRepoMessage(entry);\n const drop =\n message?.role === \"assistant\" &&\n repoMessageContentIsEmpty(message.content);\n if (drop) changed = true;\n return !drop;\n });\n\n if (!changed) return repo;\n return repairRepoLinks(repo, messages);\n}\n\nexport function isAssistantMessageTerminal(\n message: RepoMessage | null,\n): boolean {\n const statusType = message?.status?.type;\n return statusType === \"complete\" || statusType === \"incomplete\";\n}\n\nexport function repoHasAssistantMessage(\n repo: NormalizedRepo | null | undefined,\n): boolean {\n return getRepoMessages(repo).some(\n (m) => getRepoMessage(m)?.role === \"assistant\",\n );\n}\n\nfunction repoTextLength(repo: NormalizedRepo | null | undefined): number {\n let length = 0;\n for (const entry of getRepoMessages(repo)) {\n const message = getRepoMessage(entry);\n const content = message?.content;\n if (typeof content === \"string\") {\n length += content.length;\n } else if (Array.isArray(content)) {\n for (const part of content) {\n if (part?.type === \"text\" && typeof part.text === \"string\") {\n length += part.text.length;\n }\n }\n }\n }\n return length;\n}\n\nfunction repoTerminalAssistantCount(\n repo: NormalizedRepo | null | undefined,\n): number {\n return getRepoMessages(repo).filter((entry) => {\n const message = getRepoMessage(entry);\n return message?.role === \"assistant\" && isAssistantMessageTerminal(message);\n }).length;\n}\n\nfunction toolCallProgressScore(part: RepoMessageContent): number {\n if (part.type !== \"tool-call\") return 0;\n let score = 1;\n if (part.activity !== true) score += 1;\n if (\"result\" in part) score += 4;\n return score;\n}\n\nfunction repoToolCallProgress(repo: NormalizedRepo | null | undefined): {\n total: number;\n materialized: number;\n completed: number;\n score: number;\n} {\n const progress = {\n total: 0,\n materialized: 0,\n completed: 0,\n score: 0,\n };\n for (const entry of getRepoMessages(repo)) {\n const message = getRepoMessage(entry);\n const content = message?.content;\n if (!Array.isArray(content)) continue;\n for (const part of content) {\n if (part?.type !== \"tool-call\") continue;\n progress.total += 1;\n if (part.activity !== true) progress.materialized += 1;\n if (\"result\" in part) progress.completed += 1;\n progress.score += toolCallProgressScore(part);\n }\n }\n return progress;\n}\n\nexport function shouldImportServerThreadData(\n currentRepo: NormalizedRepo | null | undefined,\n incomingRepo: NormalizedRepo | null | undefined,\n): boolean {\n const incomingCount = getRepoMessages(incomingRepo).length;\n if (incomingCount === 0) return false;\n\n const currentCount = getRepoMessages(currentRepo).length;\n if (currentCount === 0) return true;\n if (incomingCount < currentCount) return false;\n\n if (incomingCount === currentCount) {\n const currentTerminalAssistants = repoTerminalAssistantCount(currentRepo);\n const incomingTerminalAssistants = repoTerminalAssistantCount(incomingRepo);\n if (incomingTerminalAssistants < currentTerminalAssistants) {\n return false;\n }\n if (\n incomingTerminalAssistants <= currentTerminalAssistants &&\n repoTextLength(incomingRepo) < repoTextLength(currentRepo)\n ) {\n return false;\n }\n const currentTools = repoToolCallProgress(currentRepo);\n const incomingTools = repoToolCallProgress(incomingRepo);\n if (\n incomingTools.total < currentTools.total ||\n incomingTools.materialized < currentTools.materialized ||\n incomingTools.completed < currentTools.completed ||\n incomingTools.score < currentTools.score\n ) {\n return false;\n }\n }\n\n return true;\n}\n"]}
|
|
@@ -31,10 +31,11 @@ export type ApprovalContextValue = {
|
|
|
31
31
|
};
|
|
32
32
|
export declare const ApprovalContext: React.Context<ApprovalContextValue | null>;
|
|
33
33
|
export declare const TOOL_LONG_RUNNING_HINT_DELAY_MS = 45000;
|
|
34
|
-
export declare function ToolActivityPresentation({ toolName, isRunning, isActiveTail, children, }: {
|
|
34
|
+
export declare function ToolActivityPresentation({ toolName, isRunning, isActiveTail, suppressLongRunningHint, children, }: {
|
|
35
35
|
toolName: string;
|
|
36
36
|
isRunning: boolean;
|
|
37
37
|
isActiveTail: boolean;
|
|
38
|
+
suppressLongRunningHint?: boolean;
|
|
38
39
|
children: React.ReactNode;
|
|
39
40
|
}): React.JSX.Element;
|
|
40
41
|
type ToolDetailSection = "input" | "result";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-call-display.d.ts","sourceRoot":"","sources":["../../../src/client/chat/tool-call-display.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAgBpE,OAAO,KAMN,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"tool-call-display.d.ts","sourceRoot":"","sources":["../../../src/client/chat/tool-call-display.tsx"],"names":[],"mappings":"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"}
|
|
@@ -20,14 +20,14 @@ export const ChatRunDurationContext = React.createContext(null);
|
|
|
20
20
|
export const ASSISTANT_VISIBLE_TOOL_CALL_LIMIT = 3;
|
|
21
21
|
export const ApprovalContext = React.createContext(null);
|
|
22
22
|
export const TOOL_LONG_RUNNING_HINT_DELAY_MS = 45_000;
|
|
23
|
-
export function ToolActivityPresentation({ toolName, isRunning, isActiveTail, children, }) {
|
|
23
|
+
export function ToolActivityPresentation({ toolName, isRunning, isActiveTail, suppressLongRunningHint = false, children, }) {
|
|
24
24
|
const [showLongRunningHint, setShowLongRunningHint] = useState(false);
|
|
25
25
|
// A batched update can first reveal a tool with its result already attached.
|
|
26
26
|
// Presentation follows the active chat tail rather than execution state so
|
|
27
27
|
// that newly revealed completed tools still get their entrance motion.
|
|
28
28
|
const [animateEntry] = useState(isActiveTail);
|
|
29
29
|
useEffect(() => {
|
|
30
|
-
if (!isRunning) {
|
|
30
|
+
if (!isRunning || suppressLongRunningHint) {
|
|
31
31
|
setShowLongRunningHint(false);
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
@@ -36,7 +36,7 @@ export function ToolActivityPresentation({ toolName, isRunning, isActiveTail, ch
|
|
|
36
36
|
setShowLongRunningHint(true);
|
|
37
37
|
}, TOOL_LONG_RUNNING_HINT_DELAY_MS);
|
|
38
38
|
return () => window.clearTimeout(timeout);
|
|
39
|
-
}, [isRunning, toolName]);
|
|
39
|
+
}, [isRunning, suppressLongRunningHint, toolName]);
|
|
40
40
|
return (_jsxs("div", { className: cn("agent-tool-call", animateEntry && "agent-tool-call--entering"), "data-running": isRunning ? "true" : undefined, children: [children, isRunning && showLongRunningHint && (_jsx("div", { className: "mt-0.5 px-2.5 pb-2 text-[11px] leading-snug text-muted-foreground/80", children: "Still working. Large updates can take a minute or two." }))] }));
|
|
41
41
|
}
|
|
42
42
|
function stringifyToolValue(value, pretty = false) {
|
|
@@ -243,7 +243,7 @@ export function ToolCallDisplay({ toolName, argsText, args, result, mcpApp, chat
|
|
|
243
243
|
// These must be separate components so hook order in ToolCallDisplayGeneric
|
|
244
244
|
// is always stable (no conditional hook calls).
|
|
245
245
|
const toolKind = structuredMeta?.toolKind;
|
|
246
|
-
const wrapToolDisplay = (children) => (_jsx(ToolActivityPresentation, { toolName: toolName, isRunning: isRunning, isActiveTail: showActiveTail, children: children }));
|
|
246
|
+
const wrapToolDisplay = (children) => (_jsx(ToolActivityPresentation, { toolName: toolName, isRunning: isRunning, isActiveTail: showActiveTail, suppressLongRunningHint: toolName === "call-agent" || toolName.startsWith("agent:"), children: children }));
|
|
247
247
|
if (toolKind === "bash") {
|
|
248
248
|
return wrapToolDisplay(_jsx(BashCell, { meta: structuredMeta, output: result, isRunning: isRunning }));
|
|
249
249
|
}
|
|
@@ -376,11 +376,7 @@ function AgentCallCell({ agentName, activity, progress, responseText, isRunning,
|
|
|
376
376
|
const tool = activity?.toolCalls?.[index];
|
|
377
377
|
return (_jsxs(React.Fragment, { children: [reasoningText && (_jsx(ReasoningCell, { text: reasoningText, isStreaming: isRunning &&
|
|
378
378
|
activity.activePhase === "reasoning" &&
|
|
379
|
-
index === activity.reasoning.length - 1, defaultOpen: index === activity.reasoning.length - 1, collapseWhenReplaced: index < activity.toolCalls.length })), tool && (_jsx(
|
|
380
|
-
? "Failed"
|
|
381
|
-
: tool.status === "completed"
|
|
382
|
-
? "Done"
|
|
383
|
-
: undefined, isActiveTail: isRunning && index === activity.toolCalls.length - 1 }))] }, `activity-${index}`));
|
|
379
|
+
index === activity.reasoning.length - 1, defaultOpen: index === activity.reasoning.length - 1, collapseWhenReplaced: index < activity.toolCalls.length })), tool && (_jsx(AgentActivityToolCallRow, { tool: tool, isActiveTail: isRunning && index === activity.toolCalls.length - 1 }))] }, `activity-${index}`));
|
|
384
380
|
}) })) : null;
|
|
385
381
|
const progressState = progress?.state.replaceAll(/[-_]+/g, " ");
|
|
386
382
|
const progressText = isRunning && !activity && progress && progressState
|
|
@@ -397,6 +393,11 @@ function AgentCallCell({ agentName, activity, progress, responseText, isRunning,
|
|
|
397
393
|
return (_jsxs("div", { className: "group/tool my-0.5 w-full", children: [_jsxs("button", { type: "button", onClick: () => setOpen((value) => !value), "aria-expanded": open, className: "flex w-full items-center gap-1.5 rounded-md py-0.5 text-left text-[13px] text-muted-foreground transition-colors hover:text-foreground", children: [isRunning ? (_jsx(IconLoader2, { className: "size-3.5 animate-spin" })) : isError ? (_jsx(IconCircleX, { className: "size-3.5 text-destructive" })) : (_jsx(IconChevronRight, { className: cn("size-3.5 transition-transform", open && "rotate-90") })), _jsx("span", { className: cn("min-w-0 truncate font-normal", isRunning && "agent-running-shimmer"), children: label })] }), _jsx(AnimatedCollapse, { open: open, children: _jsxs("div", { className: "ms-1 border-s border-border/50 ps-2 pt-1", children: [workContent &&
|
|
398
394
|
(isRunning ? (workContent) : (_jsx(WorkedForSummary, { durationMs: durationMs, children: workContent }))), progressText && (_jsx("p", { className: "ps-5 pb-1 text-xs text-muted-foreground", "data-testid": "agent-call-progress", "aria-live": "polite", children: progressText })), finalText && (_jsx("div", { className: "ps-5 pb-1", children: _jsx(SmoothMarkdownText, { text: finalText, streaming: isRunning, resetKey: `agent-response-${agentName}`, statusType: isRunning ? "running" : "complete" }) }))] }) })] }));
|
|
399
395
|
}
|
|
396
|
+
function AgentActivityToolCallRow({ tool, isActiveTail, }) {
|
|
397
|
+
const isRunning = tool.status === "running";
|
|
398
|
+
const ToolIcon = resolveToolIcon(tool.name);
|
|
399
|
+
return (_jsx(ToolActivityPresentation, { toolName: tool.name, isRunning: isRunning, isActiveTail: isActiveTail, suppressLongRunningHint: true, children: _jsxs("div", { className: "my-0.5 flex w-full items-center gap-1.5 rounded-md py-0.5 text-left text-[13px] text-muted-foreground", children: [_jsx("span", { className: "flex size-4 shrink-0 items-center justify-center", children: isRunning ? (_jsx(IconLoader2, { className: "size-3.5 animate-spin" })) : (_jsx(ToolIcon, { className: "size-3.5" })) }), _jsx("span", { className: cn("min-w-0 truncate font-normal", isActiveTail && "agent-running-shimmer"), children: humanizeToolName(tool.name) })] }) }));
|
|
400
|
+
}
|
|
400
401
|
// ─── ToolCallFallback ──────────────────────────────────────────────────────────
|
|
401
402
|
export function ToolCallFallback({ toolName, args, argsText, result, ...rest }) {
|
|
402
403
|
const chatRunning = React.useContext(ChatRunningContext);
|