@agent-native/dispatch 0.0.0-beta-20260819165421 → 0.0.0-beta-20260819173911
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/dist/actions/provider-api-register.d.ts +11 -11
- package/dist/routes/pages/chat.d.ts.map +1 -1
- package/dist/routes/pages/chat.js +45 -18
- package/dist/routes/pages/chat.js.map +1 -1
- package/package.json +4 -4
- package/src/routes/pages/chat.spec.tsx +49 -0
- package/src/routes/pages/chat.tsx +51 -0
|
@@ -47,10 +47,11 @@ declare const _default: import("node_modules/@agent-native/core/dist").ActionDef
|
|
|
47
47
|
notes?: string | undefined;
|
|
48
48
|
scope?: "org" | "user" | undefined;
|
|
49
49
|
}, {
|
|
50
|
-
message?: undefined;
|
|
51
50
|
id?: undefined;
|
|
52
51
|
provider?: undefined;
|
|
53
52
|
deleted?: undefined;
|
|
53
|
+
found?: undefined;
|
|
54
|
+
message?: undefined;
|
|
54
55
|
providers: {
|
|
55
56
|
id: string;
|
|
56
57
|
label: string;
|
|
@@ -61,45 +62,44 @@ declare const _default: import("node_modules/@agent-native/core/dist").ActionDef
|
|
|
61
62
|
updatedAt: number;
|
|
62
63
|
}[];
|
|
63
64
|
count: number;
|
|
64
|
-
found?: undefined;
|
|
65
65
|
registered?: undefined;
|
|
66
66
|
label?: undefined;
|
|
67
67
|
} | {
|
|
68
|
-
message?: undefined;
|
|
69
|
-
count?: undefined;
|
|
70
68
|
id?: undefined;
|
|
71
69
|
deleted?: undefined;
|
|
70
|
+
message?: undefined;
|
|
72
71
|
providers?: undefined;
|
|
72
|
+
count?: undefined;
|
|
73
73
|
found: boolean;
|
|
74
74
|
provider: import("node_modules/@agent-native/core/dist/provider-api").CustomProviderConfig;
|
|
75
75
|
registered?: undefined;
|
|
76
76
|
label?: undefined;
|
|
77
77
|
} | {
|
|
78
|
-
message?: undefined;
|
|
79
|
-
count?: undefined;
|
|
80
78
|
provider?: undefined;
|
|
81
79
|
deleted?: undefined;
|
|
80
|
+
message?: undefined;
|
|
82
81
|
providers?: undefined;
|
|
82
|
+
count?: undefined;
|
|
83
83
|
found: boolean;
|
|
84
84
|
id: string;
|
|
85
85
|
registered?: undefined;
|
|
86
86
|
label?: undefined;
|
|
87
87
|
} | {
|
|
88
|
-
message?: undefined;
|
|
89
|
-
count?: undefined;
|
|
90
88
|
provider?: undefined;
|
|
91
|
-
providers?: undefined;
|
|
92
89
|
found?: undefined;
|
|
90
|
+
message?: undefined;
|
|
91
|
+
providers?: undefined;
|
|
92
|
+
count?: undefined;
|
|
93
93
|
deleted: boolean;
|
|
94
94
|
id: string;
|
|
95
95
|
registered?: undefined;
|
|
96
96
|
label?: undefined;
|
|
97
97
|
} | {
|
|
98
|
-
count?: undefined;
|
|
99
98
|
provider?: undefined;
|
|
100
99
|
deleted?: undefined;
|
|
101
|
-
providers?: undefined;
|
|
102
100
|
found?: undefined;
|
|
101
|
+
providers?: undefined;
|
|
102
|
+
count?: undefined;
|
|
103
103
|
registered: boolean;
|
|
104
104
|
id: string;
|
|
105
105
|
label: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/chat.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/chat.tsx"],"names":[],"mappings":"AAmJA,wBAAgB,IAAI;;IAEnB;AAED,MAAM,CAAC,OAAO,UAAU,SAAS,oDA0OhC"}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { AgentChatSurface, insertAgentComposerReference, markAgentChatHomeHandoff, readChatFirstMode, } from "@agent-native/core/client/agent-chat";
|
|
2
|
+
import { AgentChatSurface, insertAgentComposerReference, markAgentChatHomeHandoff, readChatFirstMode, useActiveAgentChatRunId, } from "@agent-native/core/client/agent-chat";
|
|
3
3
|
import { appBasePath, appPath } from "@agent-native/core/client/api-path";
|
|
4
|
+
import { writeClipboardText } from "@agent-native/core/client/clipboard";
|
|
4
5
|
import { useActionQuery } from "@agent-native/core/client/hooks";
|
|
5
6
|
import { useT } from "@agent-native/core/client/i18n";
|
|
6
|
-
import {
|
|
7
|
+
import { IconCheck, IconCopy } from "@tabler/icons-react";
|
|
8
|
+
import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
7
9
|
import { useLocation, useNavigate } from "react-router";
|
|
8
10
|
import { ActionQueryError } from "../../components/action-query-error.js";
|
|
9
11
|
import { useDispatchExtensions } from "../../components/layout/Layout.js";
|
|
12
|
+
import { Button } from "../../components/ui/button.js";
|
|
10
13
|
import { Skeleton } from "../../components/ui/skeleton.js";
|
|
11
14
|
import { submitOverviewPrompt } from "../../lib/overview-chat.js";
|
|
12
15
|
function chatThreadPath(threadId, agentPath) {
|
|
@@ -54,6 +57,29 @@ function dispatchNavTarget(path) {
|
|
|
54
57
|
function DispatchAgentChatSurface(props) {
|
|
55
58
|
return _jsx(AgentChatSurface, { ...props });
|
|
56
59
|
}
|
|
60
|
+
function DispatchRequestIdButton({ requestId }) {
|
|
61
|
+
const t = useT();
|
|
62
|
+
const [copied, setCopied] = useState(false);
|
|
63
|
+
const handleCopy = useCallback(() => {
|
|
64
|
+
if (!requestId)
|
|
65
|
+
return;
|
|
66
|
+
void writeClipboardText(requestId).then((ok) => {
|
|
67
|
+
if (!ok)
|
|
68
|
+
return;
|
|
69
|
+
setCopied(true);
|
|
70
|
+
window.setTimeout(() => setCopied(false), 1000);
|
|
71
|
+
});
|
|
72
|
+
}, [requestId]);
|
|
73
|
+
return (_jsxs(Button, { type: "button", variant: "outline", size: "sm", disabled: !requestId, onClick: handleCopy, "aria-label": t("dispatch.pages.copyRequestId", {
|
|
74
|
+
defaultValue: requestId ? "Copy request ID" : "Request ID unavailable",
|
|
75
|
+
}), children: [copied ? (_jsx(IconCheck, { "aria-hidden": "true" })) : (_jsx(IconCopy, { "aria-hidden": "true" })), copied
|
|
76
|
+
? t("dispatch.pages.copied", { defaultValue: "Copied" })
|
|
77
|
+
: t("dispatch.pages.copyRequestId", {
|
|
78
|
+
defaultValue: requestId
|
|
79
|
+
? "Copy request ID"
|
|
80
|
+
: "Request ID unavailable",
|
|
81
|
+
})] }));
|
|
82
|
+
}
|
|
57
83
|
export function meta() {
|
|
58
84
|
return [{ title: "Chat — Dispatch" }];
|
|
59
85
|
}
|
|
@@ -62,6 +88,7 @@ export default function ChatRoute() {
|
|
|
62
88
|
const location = useLocation();
|
|
63
89
|
const navigate = useNavigate();
|
|
64
90
|
const routeThreadId = threadIdFromPath(location.pathname);
|
|
91
|
+
const activeRunId = useActiveAgentChatRunId(routeThreadId);
|
|
65
92
|
const agentPath = new URLSearchParams(location.search).get("agent");
|
|
66
93
|
const agentsQuery = useActionQuery("list-workspace-resources", { kind: "agent" }, { enabled: Boolean(agentPath), staleTime: 30_000 });
|
|
67
94
|
const agent = useMemo(() => agentPath
|
|
@@ -172,21 +199,21 @@ export default function ChatRoute() {
|
|
|
172
199
|
if (agentPath && !agent) {
|
|
173
200
|
return (_jsx("div", { className: "flex h-full min-h-0 items-center justify-center bg-background px-4 text-sm text-muted-foreground", children: "This agent is no longer available." }));
|
|
174
201
|
}
|
|
175
|
-
return (
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
202
|
+
return (_jsxs("div", { className: "flex h-full min-h-0 flex-col bg-background", children: [threadUrlSync.routeThreadId ? (_jsx("div", { className: "flex justify-end px-4 pt-4 sm:px-6", children: _jsx(DispatchRequestIdButton, { requestId: activeRunId }) })) : null, _jsx(DispatchAgentChatSurface, { mode: "page", chatViewTransition: true, className: "dispatch-chat-panel px-4 sm:px-6", defaultMode: "chat", storageKey: agent ? `dispatch-agent-${agent.id}` : "dispatch", scope: agentScope, threadUrlSync: threadUrlSync, showHeader: false, showTabBar: false, dynamicSuggestions: false, suppressInlineOpenApp: suppressInlineOpenApp, suggestions: [], emptyStateText: t("dispatch.pages.chatAcrossAppsDescription", {
|
|
203
|
+
defaultValue: "Route work, inspect status, or create something new from one place.",
|
|
204
|
+
}), emptyStateDisplay: "hidden", ...(!prompt?.message
|
|
205
|
+
? {
|
|
206
|
+
centerComposerWhenEmpty: true,
|
|
207
|
+
composerLayoutVariant: "hero",
|
|
208
|
+
}
|
|
209
|
+
: {}), composerPlaceholder: agent
|
|
210
|
+
? `Ask ${agent.name}...`
|
|
211
|
+
: t("dispatch.pages.chatPromptPlaceholder", {
|
|
212
|
+
defaultValue: "Ask Dispatch...",
|
|
213
|
+
}), composerSlot: agent ? (_jsxs("div", { className: "dispatch-chat-intro", children: [_jsx("h1", { children: agent.name }), agent.description ? _jsx("p", { children: agent.description }) : null] })) : !prompt?.message ? (_jsxs("div", { className: "dispatch-chat-intro", children: [_jsx("h1", { children: t("dispatch.pages.chatAcrossApps", {
|
|
214
|
+
defaultValue: "Chat across your apps",
|
|
215
|
+
}) }), _jsx("p", { children: t("dispatch.pages.chatAcrossAppsDescription", {
|
|
216
|
+
defaultValue: "Route work, inspect status, or create something new from one place.",
|
|
217
|
+
}) })] })) : null }, agent ? `agent-${agent.id}` : "dispatch")] }));
|
|
191
218
|
}
|
|
192
219
|
//# sourceMappingURL=chat.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../src/routes/pages/chat.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n AgentChatSurface,\n insertAgentComposerReference,\n markAgentChatHomeHandoff,\n readChatFirstMode,\n} from \"@agent-native/core/client/agent-chat\";\nimport { appBasePath, appPath } from \"@agent-native/core/client/api-path\";\nimport { useActionQuery } from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n type ComponentProps,\n} from \"react\";\nimport { useLocation, useNavigate } from \"react-router\";\n\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport { useDispatchExtensions } from \"../../components/layout/Layout\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\nimport { submitOverviewPrompt } from \"../../lib/overview-chat\";\n\ninterface WorkspaceAgentResource {\n id: string;\n name: string;\n description: string | null;\n path: string;\n content: string;\n scope: \"all\" | \"selected\";\n updatedAt: number;\n}\n\nfunction chatThreadPath(threadId: string | null, agentPath?: string): string {\n const path = threadId ? `/chat/${encodeURIComponent(threadId)}` : \"/chat\";\n return agentPath ? `${path}?agent=${encodeURIComponent(agentPath)}` : path;\n}\n\nfunction stripBasePath(pathname: string): string {\n const basePath = appBasePath();\n if (!basePath) return pathname;\n if (pathname === basePath) return \"/\";\n if (pathname.startsWith(`${basePath}/`)) {\n return pathname.slice(basePath.length) || \"/\";\n }\n return pathname;\n}\n\n// The chat surface renders for both `/chat` and the `/chat/:threadId` deep\n// link. The thread id is read from the pathname (not `useParams`) because the\n// param is owned by the nested deep-link route, not this leaf component.\nfunction threadIdFromPath(pathname: string): string | null {\n const match = stripBasePath(pathname).match(/^\\/chat\\/([^/]+)/);\n if (!match) return null;\n try {\n const value = decodeURIComponent(match[1]).trim();\n return value || null;\n } catch {\n return null;\n }\n}\n\n// Mirror the basename handling Dispatch's nav links use: pass a router-local\n// path when the live URL is already under the mount, otherwise prefix it.\nfunction dispatchNavTarget(path: string): string {\n if (typeof window === \"undefined\") return path;\n const basePath = appBasePath();\n if (!basePath) return path;\n const pathname = window.location.pathname;\n const routerHasBasename =\n pathname === basePath || pathname.startsWith(`${basePath}/`);\n return routerHasBasename ? path : appPath(path);\n}\n\ninterface DispatchThreadUrlSync {\n routeThreadId: string | null;\n getPath: (threadId: string | null) => string;\n navigate: (path: string, options?: { replace?: boolean }) => void;\n}\n\ntype DispatchAgentChatSurfaceProps = ComponentProps<typeof AgentChatSurface> & {\n threadUrlSync?: DispatchThreadUrlSync;\n};\n\nfunction DispatchAgentChatSurface(props: DispatchAgentChatSurfaceProps) {\n return <AgentChatSurface {...props} />;\n}\n\ninterface DispatchChatLocationState {\n dispatchPrompt?: {\n id?: string | number;\n message?: string;\n selectedModel?: string | null;\n selectedEngine?: string | null;\n selectedEffort?: ComponentProps<typeof AgentChatSurface>[\"selectedEffort\"];\n };\n dispatchThread?: {\n id?: string | number;\n threadId?: string;\n };\n}\n\nexport function meta() {\n return [{ title: \"Chat — Dispatch\" }];\n}\n\nexport default function ChatRoute() {\n const t = useT();\n const location = useLocation();\n const navigate = useNavigate();\n const routeThreadId = threadIdFromPath(location.pathname);\n const agentPath = new URLSearchParams(location.search).get(\"agent\");\n const agentsQuery = useActionQuery<WorkspaceAgentResource[]>(\n \"list-workspace-resources\",\n { kind: \"agent\" },\n { enabled: Boolean(agentPath), staleTime: 30_000 },\n );\n const agent = useMemo(\n () =>\n agentPath\n ? (agentsQuery.data ?? []).find((resource) => {\n const profileId = resource.path\n .replace(/^agents\\//, \"\")\n .replace(/\\.md$/, \"\");\n return (\n resource.path === agentPath ||\n resource.id === agentPath ||\n profileId === agentPath\n );\n })\n : undefined,\n [agentPath, agentsQuery.data],\n );\n const agentScope = useMemo(\n () =>\n agent\n ? {\n type: \"agent\",\n id: agent.id,\n label: agent.name,\n contextKey: `dispatch-agent:${agent.id}`,\n }\n : null,\n [agent],\n );\n const handledStateIds = useRef(new Set<string>());\n const extensions = useDispatchExtensions();\n const suppressInlineOpenApp =\n extensions?.chatFirst === true ||\n readChatFirstMode() ||\n new URLSearchParams(location.search).get(\"chatFirst\") === \"1\";\n\n const navigateThreadUrl = useCallback(\n (path: string, options?: { replace?: boolean }) =>\n navigate(dispatchNavTarget(path), options),\n [navigate],\n );\n const threadUrlSync = useMemo<DispatchThreadUrlSync>(\n () => ({\n routeThreadId: routeThreadId ?? null,\n getPath: (threadId) => chatThreadPath(threadId, agentPath ?? undefined),\n navigate: navigateThreadUrl,\n }),\n [agentPath, routeThreadId, navigateThreadUrl],\n );\n const state = location.state as DispatchChatLocationState | null;\n const prompt = state?.dispatchPrompt;\n const thread = state?.dispatchThread;\n\n useEffect(() => {\n const message = prompt?.message?.trim();\n const threadId = thread?.threadId?.trim();\n if (!message && !threadId) return;\n\n const stateId = String(\n prompt?.id ?? thread?.id ?? `${message ?? \"\"}:${threadId ?? \"\"}`,\n );\n if (handledStateIds.current.has(stateId)) return;\n handledStateIds.current.add(stateId);\n\n const timer = window.setTimeout(() => {\n if (threadId) {\n window.dispatchEvent(\n new CustomEvent(\"agent-chat:open-thread\", {\n detail: { threadId },\n }),\n );\n }\n if (message) {\n submitOverviewPrompt(message, prompt?.selectedModel, {\n openSidebar: false,\n selectedEngine: prompt?.selectedEngine,\n selectedEffort: prompt?.selectedEffort,\n });\n }\n navigate(`${location.pathname}${location.search}${location.hash}`, {\n replace: true,\n state: null,\n });\n }, 0);\n\n return () => window.clearTimeout(timer);\n }, [\n location.hash,\n location.pathname,\n location.search,\n navigate,\n prompt?.id,\n prompt?.message,\n prompt?.selectedModel,\n prompt?.selectedEngine,\n prompt?.selectedEffort,\n thread?.id,\n thread?.threadId,\n ]);\n\n useEffect(() => {\n function handleChatRunning(event: Event) {\n const detail = (event as CustomEvent).detail;\n if (detail?.isRunning === true) markAgentChatHomeHandoff(\"dispatch\");\n }\n\n window.addEventListener(\"agentNative.chatRunning\", handleChatRunning);\n return () =>\n window.removeEventListener(\"agentNative.chatRunning\", handleChatRunning);\n }, []);\n\n useEffect(() => {\n if (!agent) return;\n const timer = window.setTimeout(() => {\n insertAgentComposerReference(\n {\n label: agent.name,\n icon: \"agent\",\n source: \"agent:custom\",\n refType: \"custom-agent\",\n refId: agent.id,\n refPath: agent.path,\n slotKey: \"dispatch-agent\",\n slotLabel: \"Agent\",\n },\n { openSidebar: false },\n );\n }, 0);\n return () => window.clearTimeout(timer);\n }, [agent?.id, agent?.name, agent?.path]);\n\n if (agentPath && agentsQuery.isLoading) {\n return (\n <div className=\"flex h-full min-h-0 flex-col gap-4 bg-background px-4 py-6 sm:px-6\">\n <Skeleton className=\"mx-auto h-6 w-48\" />\n <Skeleton className=\"mx-auto h-12 w-full max-w-2xl\" />\n </div>\n );\n }\n\n if (agentPath && agentsQuery.isError) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center bg-background px-4\">\n <ActionQueryError\n error={agentsQuery.error}\n onRetry={() => void agentsQuery.refetch()}\n />\n </div>\n );\n }\n\n if (agentPath && !agent) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center bg-background px-4 text-sm text-muted-foreground\">\n This agent is no longer available.\n </div>\n );\n }\n\n return (\n <div className=\"flex h-full min-h-0 flex-col bg-background\">\n <DispatchAgentChatSurface\n key={agent ? `agent-${agent.id}` : \"dispatch\"}\n mode=\"page\"\n chatViewTransition\n className=\"dispatch-chat-panel px-4 sm:px-6\"\n defaultMode=\"chat\"\n storageKey={agent ? `dispatch-agent-${agent.id}` : \"dispatch\"}\n scope={agentScope}\n threadUrlSync={threadUrlSync}\n showHeader={false}\n showTabBar={false}\n dynamicSuggestions={false}\n suppressInlineOpenApp={suppressInlineOpenApp}\n suggestions={[]}\n emptyStateText={t(\"dispatch.pages.chatAcrossAppsDescription\", {\n defaultValue:\n \"Route work, inspect status, or create something new from one place.\",\n })}\n emptyStateDisplay=\"hidden\"\n {...(!prompt?.message\n ? {\n centerComposerWhenEmpty: true,\n composerLayoutVariant: \"hero\" as const,\n }\n : {})}\n composerPlaceholder={\n agent\n ? `Ask ${agent.name}...`\n : t(\"dispatch.pages.chatPromptPlaceholder\", {\n defaultValue: \"Ask Dispatch...\",\n })\n }\n composerSlot={\n agent ? (\n <div className=\"dispatch-chat-intro\">\n <h1>{agent.name}</h1>\n {agent.description ? <p>{agent.description}</p> : null}\n </div>\n ) : !prompt?.message ? (\n <div className=\"dispatch-chat-intro\">\n <h1>\n {t(\"dispatch.pages.chatAcrossApps\", {\n defaultValue: \"Chat across your apps\",\n })}\n </h1>\n <p>\n {t(\"dispatch.pages.chatAcrossAppsDescription\", {\n defaultValue:\n \"Route work, inspect status, or create something new from one place.\",\n })}\n </p>\n </div>\n ) : null\n }\n />\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../src/routes/pages/chat.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n AgentChatSurface,\n insertAgentComposerReference,\n markAgentChatHomeHandoff,\n readChatFirstMode,\n useActiveAgentChatRunId,\n} from \"@agent-native/core/client/agent-chat\";\nimport { appBasePath, appPath } from \"@agent-native/core/client/api-path\";\nimport { writeClipboardText } from \"@agent-native/core/client/clipboard\";\nimport { useActionQuery } from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport { IconCheck, IconCopy } from \"@tabler/icons-react\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentProps,\n} from \"react\";\nimport { useLocation, useNavigate } from \"react-router\";\n\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport { useDispatchExtensions } from \"../../components/layout/Layout\";\nimport { Button } from \"../../components/ui/button\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\nimport { submitOverviewPrompt } from \"../../lib/overview-chat\";\n\ninterface WorkspaceAgentResource {\n id: string;\n name: string;\n description: string | null;\n path: string;\n content: string;\n scope: \"all\" | \"selected\";\n updatedAt: number;\n}\n\nfunction chatThreadPath(threadId: string | null, agentPath?: string): string {\n const path = threadId ? `/chat/${encodeURIComponent(threadId)}` : \"/chat\";\n return agentPath ? `${path}?agent=${encodeURIComponent(agentPath)}` : path;\n}\n\nfunction stripBasePath(pathname: string): string {\n const basePath = appBasePath();\n if (!basePath) return pathname;\n if (pathname === basePath) return \"/\";\n if (pathname.startsWith(`${basePath}/`)) {\n return pathname.slice(basePath.length) || \"/\";\n }\n return pathname;\n}\n\n// The chat surface renders for both `/chat` and the `/chat/:threadId` deep\n// link. The thread id is read from the pathname (not `useParams`) because the\n// param is owned by the nested deep-link route, not this leaf component.\nfunction threadIdFromPath(pathname: string): string | null {\n const match = stripBasePath(pathname).match(/^\\/chat\\/([^/]+)/);\n if (!match) return null;\n try {\n const value = decodeURIComponent(match[1]).trim();\n return value || null;\n } catch {\n return null;\n }\n}\n\n// Mirror the basename handling Dispatch's nav links use: pass a router-local\n// path when the live URL is already under the mount, otherwise prefix it.\nfunction dispatchNavTarget(path: string): string {\n if (typeof window === \"undefined\") return path;\n const basePath = appBasePath();\n if (!basePath) return path;\n const pathname = window.location.pathname;\n const routerHasBasename =\n pathname === basePath || pathname.startsWith(`${basePath}/`);\n return routerHasBasename ? path : appPath(path);\n}\n\ninterface DispatchThreadUrlSync {\n routeThreadId: string | null;\n getPath: (threadId: string | null) => string;\n navigate: (path: string, options?: { replace?: boolean }) => void;\n}\n\ntype DispatchAgentChatSurfaceProps = ComponentProps<typeof AgentChatSurface> & {\n threadUrlSync?: DispatchThreadUrlSync;\n};\n\nfunction DispatchAgentChatSurface(props: DispatchAgentChatSurfaceProps) {\n return <AgentChatSurface {...props} />;\n}\n\nfunction DispatchRequestIdButton({ requestId }: { requestId: string | null }) {\n const t = useT();\n const [copied, setCopied] = useState(false);\n\n const handleCopy = useCallback(() => {\n if (!requestId) return;\n void writeClipboardText(requestId).then((ok) => {\n if (!ok) return;\n setCopied(true);\n window.setTimeout(() => setCopied(false), 1000);\n });\n }, [requestId]);\n\n return (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={!requestId}\n onClick={handleCopy}\n aria-label={t(\"dispatch.pages.copyRequestId\", {\n defaultValue: requestId ? \"Copy request ID\" : \"Request ID unavailable\",\n })}\n >\n {copied ? (\n <IconCheck aria-hidden=\"true\" />\n ) : (\n <IconCopy aria-hidden=\"true\" />\n )}\n {copied\n ? t(\"dispatch.pages.copied\", { defaultValue: \"Copied\" })\n : t(\"dispatch.pages.copyRequestId\", {\n defaultValue: requestId\n ? \"Copy request ID\"\n : \"Request ID unavailable\",\n })}\n </Button>\n );\n}\n\ninterface DispatchChatLocationState {\n dispatchPrompt?: {\n id?: string | number;\n message?: string;\n selectedModel?: string | null;\n selectedEngine?: string | null;\n selectedEffort?: ComponentProps<typeof AgentChatSurface>[\"selectedEffort\"];\n };\n dispatchThread?: {\n id?: string | number;\n threadId?: string;\n };\n}\n\nexport function meta() {\n return [{ title: \"Chat — Dispatch\" }];\n}\n\nexport default function ChatRoute() {\n const t = useT();\n const location = useLocation();\n const navigate = useNavigate();\n const routeThreadId = threadIdFromPath(location.pathname);\n const activeRunId = useActiveAgentChatRunId(routeThreadId);\n const agentPath = new URLSearchParams(location.search).get(\"agent\");\n const agentsQuery = useActionQuery<WorkspaceAgentResource[]>(\n \"list-workspace-resources\",\n { kind: \"agent\" },\n { enabled: Boolean(agentPath), staleTime: 30_000 },\n );\n const agent = useMemo(\n () =>\n agentPath\n ? (agentsQuery.data ?? []).find((resource) => {\n const profileId = resource.path\n .replace(/^agents\\//, \"\")\n .replace(/\\.md$/, \"\");\n return (\n resource.path === agentPath ||\n resource.id === agentPath ||\n profileId === agentPath\n );\n })\n : undefined,\n [agentPath, agentsQuery.data],\n );\n const agentScope = useMemo(\n () =>\n agent\n ? {\n type: \"agent\",\n id: agent.id,\n label: agent.name,\n contextKey: `dispatch-agent:${agent.id}`,\n }\n : null,\n [agent],\n );\n const handledStateIds = useRef(new Set<string>());\n const extensions = useDispatchExtensions();\n const suppressInlineOpenApp =\n extensions?.chatFirst === true ||\n readChatFirstMode() ||\n new URLSearchParams(location.search).get(\"chatFirst\") === \"1\";\n\n const navigateThreadUrl = useCallback(\n (path: string, options?: { replace?: boolean }) =>\n navigate(dispatchNavTarget(path), options),\n [navigate],\n );\n const threadUrlSync = useMemo<DispatchThreadUrlSync>(\n () => ({\n routeThreadId: routeThreadId ?? null,\n getPath: (threadId) => chatThreadPath(threadId, agentPath ?? undefined),\n navigate: navigateThreadUrl,\n }),\n [agentPath, routeThreadId, navigateThreadUrl],\n );\n const state = location.state as DispatchChatLocationState | null;\n const prompt = state?.dispatchPrompt;\n const thread = state?.dispatchThread;\n\n useEffect(() => {\n const message = prompt?.message?.trim();\n const threadId = thread?.threadId?.trim();\n if (!message && !threadId) return;\n\n const stateId = String(\n prompt?.id ?? thread?.id ?? `${message ?? \"\"}:${threadId ?? \"\"}`,\n );\n if (handledStateIds.current.has(stateId)) return;\n handledStateIds.current.add(stateId);\n\n const timer = window.setTimeout(() => {\n if (threadId) {\n window.dispatchEvent(\n new CustomEvent(\"agent-chat:open-thread\", {\n detail: { threadId },\n }),\n );\n }\n if (message) {\n submitOverviewPrompt(message, prompt?.selectedModel, {\n openSidebar: false,\n selectedEngine: prompt?.selectedEngine,\n selectedEffort: prompt?.selectedEffort,\n });\n }\n navigate(`${location.pathname}${location.search}${location.hash}`, {\n replace: true,\n state: null,\n });\n }, 0);\n\n return () => window.clearTimeout(timer);\n }, [\n location.hash,\n location.pathname,\n location.search,\n navigate,\n prompt?.id,\n prompt?.message,\n prompt?.selectedModel,\n prompt?.selectedEngine,\n prompt?.selectedEffort,\n thread?.id,\n thread?.threadId,\n ]);\n\n useEffect(() => {\n function handleChatRunning(event: Event) {\n const detail = (event as CustomEvent).detail;\n if (detail?.isRunning === true) markAgentChatHomeHandoff(\"dispatch\");\n }\n\n window.addEventListener(\"agentNative.chatRunning\", handleChatRunning);\n return () =>\n window.removeEventListener(\"agentNative.chatRunning\", handleChatRunning);\n }, []);\n\n useEffect(() => {\n if (!agent) return;\n const timer = window.setTimeout(() => {\n insertAgentComposerReference(\n {\n label: agent.name,\n icon: \"agent\",\n source: \"agent:custom\",\n refType: \"custom-agent\",\n refId: agent.id,\n refPath: agent.path,\n slotKey: \"dispatch-agent\",\n slotLabel: \"Agent\",\n },\n { openSidebar: false },\n );\n }, 0);\n return () => window.clearTimeout(timer);\n }, [agent?.id, agent?.name, agent?.path]);\n\n if (agentPath && agentsQuery.isLoading) {\n return (\n <div className=\"flex h-full min-h-0 flex-col gap-4 bg-background px-4 py-6 sm:px-6\">\n <Skeleton className=\"mx-auto h-6 w-48\" />\n <Skeleton className=\"mx-auto h-12 w-full max-w-2xl\" />\n </div>\n );\n }\n\n if (agentPath && agentsQuery.isError) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center bg-background px-4\">\n <ActionQueryError\n error={agentsQuery.error}\n onRetry={() => void agentsQuery.refetch()}\n />\n </div>\n );\n }\n\n if (agentPath && !agent) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center bg-background px-4 text-sm text-muted-foreground\">\n This agent is no longer available.\n </div>\n );\n }\n\n return (\n <div className=\"flex h-full min-h-0 flex-col bg-background\">\n {threadUrlSync.routeThreadId ? (\n <div className=\"flex justify-end px-4 pt-4 sm:px-6\">\n <DispatchRequestIdButton requestId={activeRunId} />\n </div>\n ) : null}\n <DispatchAgentChatSurface\n key={agent ? `agent-${agent.id}` : \"dispatch\"}\n mode=\"page\"\n chatViewTransition\n className=\"dispatch-chat-panel px-4 sm:px-6\"\n defaultMode=\"chat\"\n storageKey={agent ? `dispatch-agent-${agent.id}` : \"dispatch\"}\n scope={agentScope}\n threadUrlSync={threadUrlSync}\n showHeader={false}\n showTabBar={false}\n dynamicSuggestions={false}\n suppressInlineOpenApp={suppressInlineOpenApp}\n suggestions={[]}\n emptyStateText={t(\"dispatch.pages.chatAcrossAppsDescription\", {\n defaultValue:\n \"Route work, inspect status, or create something new from one place.\",\n })}\n emptyStateDisplay=\"hidden\"\n {...(!prompt?.message\n ? {\n centerComposerWhenEmpty: true,\n composerLayoutVariant: \"hero\" as const,\n }\n : {})}\n composerPlaceholder={\n agent\n ? `Ask ${agent.name}...`\n : t(\"dispatch.pages.chatPromptPlaceholder\", {\n defaultValue: \"Ask Dispatch...\",\n })\n }\n composerSlot={\n agent ? (\n <div className=\"dispatch-chat-intro\">\n <h1>{agent.name}</h1>\n {agent.description ? <p>{agent.description}</p> : null}\n </div>\n ) : !prompt?.message ? (\n <div className=\"dispatch-chat-intro\">\n <h1>\n {t(\"dispatch.pages.chatAcrossApps\", {\n defaultValue: \"Chat across your apps\",\n })}\n </h1>\n <p>\n {t(\"dispatch.pages.chatAcrossAppsDescription\", {\n defaultValue:\n \"Route work, inspect status, or create something new from one place.\",\n })}\n </p>\n </div>\n ) : null\n }\n />\n </div>\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/dispatch",
|
|
3
|
-
"version": "0.0.0-beta-
|
|
3
|
+
"version": "0.0.0-beta-20260819173911",
|
|
4
4
|
"description": "Dispatch — workspace control plane for agent-native apps. Vault, integrations, destinations, scheduled jobs, and cross-app delegation, shipped as a single drop-in package.",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"tailwind-merge": "^3.5.0",
|
|
88
88
|
"vaul": "^1.1.2",
|
|
89
89
|
"zod": "^4.3.6",
|
|
90
|
-
"@agent-native/toolkit": "0.16.
|
|
90
|
+
"@agent-native/toolkit": "0.16.7"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
93
|
"@react-router/dev": "^8.1.0",
|
|
@@ -101,10 +101,10 @@
|
|
|
101
101
|
"typescript-7": "npm:typescript@^7.0.2",
|
|
102
102
|
"vite": "8.1.0",
|
|
103
103
|
"vitest": "^4.1.5",
|
|
104
|
-
"@agent-native/core": "0.0.0-beta-
|
|
104
|
+
"@agent-native/core": "0.0.0-beta-20260819173911"
|
|
105
105
|
},
|
|
106
106
|
"peerDependencies": {
|
|
107
|
-
"@agent-native/core": "0.0.0-beta-
|
|
107
|
+
"@agent-native/core": "0.0.0-beta-20260819173911",
|
|
108
108
|
"react": ">=19.2.7",
|
|
109
109
|
"react-dom": ">=19.2.7",
|
|
110
110
|
"react-router": ">=8"
|
|
@@ -8,6 +8,8 @@ import ChatRoute from "./chat";
|
|
|
8
8
|
|
|
9
9
|
const clientState = vi.hoisted(() => ({
|
|
10
10
|
surfaceProps: null as Record<string, unknown> | null,
|
|
11
|
+
activeRunId: null as string | null,
|
|
12
|
+
writeClipboardText: vi.fn(),
|
|
11
13
|
agents: [] as Array<{
|
|
12
14
|
id: string;
|
|
13
15
|
name: string;
|
|
@@ -27,6 +29,7 @@ vi.mock("@agent-native/core/client/agent-chat", () => ({
|
|
|
27
29
|
insertAgentComposerReference: vi.fn(),
|
|
28
30
|
markAgentChatHomeHandoff: vi.fn(),
|
|
29
31
|
readChatFirstMode: () => true,
|
|
32
|
+
useActiveAgentChatRunId: () => clientState.activeRunId,
|
|
30
33
|
navigateWithAgentChatViewTransition: (
|
|
31
34
|
navigate: (path: string) => void,
|
|
32
35
|
path: string,
|
|
@@ -34,6 +37,10 @@ vi.mock("@agent-native/core/client/agent-chat", () => ({
|
|
|
34
37
|
sendToAgentChat: vi.fn(),
|
|
35
38
|
}));
|
|
36
39
|
|
|
40
|
+
vi.mock("@agent-native/core/client/clipboard", () => ({
|
|
41
|
+
writeClipboardText: clientState.writeClipboardText,
|
|
42
|
+
}));
|
|
43
|
+
|
|
37
44
|
vi.mock("@agent-native/core/client/hooks", () => ({
|
|
38
45
|
useActionQuery: () => ({
|
|
39
46
|
data: clientState.agents,
|
|
@@ -72,6 +79,7 @@ describe("Dispatch ChatRoute", () => {
|
|
|
72
79
|
vi.useFakeTimers();
|
|
73
80
|
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
74
81
|
clientState.surfaceProps = null;
|
|
82
|
+
clientState.activeRunId = null;
|
|
75
83
|
clientState.agents = [];
|
|
76
84
|
container = document.createElement("div");
|
|
77
85
|
document.body.appendChild(container);
|
|
@@ -180,4 +188,45 @@ describe("Dispatch ChatRoute", () => {
|
|
|
180
188
|
).getPath("thread-1"),
|
|
181
189
|
).toBe("/chat/thread-1?agent=agents%2Fresearch-partner.md");
|
|
182
190
|
});
|
|
191
|
+
|
|
192
|
+
it("exposes a copyable request ID affordance on threaded chats", async () => {
|
|
193
|
+
clientState.activeRunId = "run-456";
|
|
194
|
+
clientState.writeClipboardText.mockResolvedValue(true);
|
|
195
|
+
|
|
196
|
+
await act(async () => {
|
|
197
|
+
root.render(
|
|
198
|
+
<MemoryRouter initialEntries={["/chat/chat-123"]}>
|
|
199
|
+
<ChatRoute />
|
|
200
|
+
</MemoryRouter>,
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const button = Array.from(container.querySelectorAll("button")).find((el) =>
|
|
205
|
+
el.textContent?.includes("Copy request ID"),
|
|
206
|
+
);
|
|
207
|
+
expect(button).toBeTruthy();
|
|
208
|
+
|
|
209
|
+
await act(async () => {
|
|
210
|
+
button?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
211
|
+
await Promise.resolve();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
expect(clientState.writeClipboardText).toHaveBeenCalledWith("run-456");
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it("keeps the request ID affordance unavailable before a run starts", async () => {
|
|
218
|
+
await act(async () => {
|
|
219
|
+
root.render(
|
|
220
|
+
<MemoryRouter initialEntries={["/chat/chat-123"]}>
|
|
221
|
+
<ChatRoute />
|
|
222
|
+
</MemoryRouter>,
|
|
223
|
+
);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const button = Array.from(container.querySelectorAll("button")).find((el) =>
|
|
227
|
+
el.textContent?.includes("Request ID unavailable"),
|
|
228
|
+
);
|
|
229
|
+
expect(button).toBeTruthy();
|
|
230
|
+
expect(button).toHaveProperty("disabled", true);
|
|
231
|
+
});
|
|
183
232
|
});
|
|
@@ -3,21 +3,26 @@ import {
|
|
|
3
3
|
insertAgentComposerReference,
|
|
4
4
|
markAgentChatHomeHandoff,
|
|
5
5
|
readChatFirstMode,
|
|
6
|
+
useActiveAgentChatRunId,
|
|
6
7
|
} from "@agent-native/core/client/agent-chat";
|
|
7
8
|
import { appBasePath, appPath } from "@agent-native/core/client/api-path";
|
|
9
|
+
import { writeClipboardText } from "@agent-native/core/client/clipboard";
|
|
8
10
|
import { useActionQuery } from "@agent-native/core/client/hooks";
|
|
9
11
|
import { useT } from "@agent-native/core/client/i18n";
|
|
12
|
+
import { IconCheck, IconCopy } from "@tabler/icons-react";
|
|
10
13
|
import {
|
|
11
14
|
useCallback,
|
|
12
15
|
useEffect,
|
|
13
16
|
useMemo,
|
|
14
17
|
useRef,
|
|
18
|
+
useState,
|
|
15
19
|
type ComponentProps,
|
|
16
20
|
} from "react";
|
|
17
21
|
import { useLocation, useNavigate } from "react-router";
|
|
18
22
|
|
|
19
23
|
import { ActionQueryError } from "../../components/action-query-error";
|
|
20
24
|
import { useDispatchExtensions } from "../../components/layout/Layout";
|
|
25
|
+
import { Button } from "../../components/ui/button";
|
|
21
26
|
import { Skeleton } from "../../components/ui/skeleton";
|
|
22
27
|
import { submitOverviewPrompt } from "../../lib/overview-chat";
|
|
23
28
|
|
|
@@ -86,6 +91,46 @@ function DispatchAgentChatSurface(props: DispatchAgentChatSurfaceProps) {
|
|
|
86
91
|
return <AgentChatSurface {...props} />;
|
|
87
92
|
}
|
|
88
93
|
|
|
94
|
+
function DispatchRequestIdButton({ requestId }: { requestId: string | null }) {
|
|
95
|
+
const t = useT();
|
|
96
|
+
const [copied, setCopied] = useState(false);
|
|
97
|
+
|
|
98
|
+
const handleCopy = useCallback(() => {
|
|
99
|
+
if (!requestId) return;
|
|
100
|
+
void writeClipboardText(requestId).then((ok) => {
|
|
101
|
+
if (!ok) return;
|
|
102
|
+
setCopied(true);
|
|
103
|
+
window.setTimeout(() => setCopied(false), 1000);
|
|
104
|
+
});
|
|
105
|
+
}, [requestId]);
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<Button
|
|
109
|
+
type="button"
|
|
110
|
+
variant="outline"
|
|
111
|
+
size="sm"
|
|
112
|
+
disabled={!requestId}
|
|
113
|
+
onClick={handleCopy}
|
|
114
|
+
aria-label={t("dispatch.pages.copyRequestId", {
|
|
115
|
+
defaultValue: requestId ? "Copy request ID" : "Request ID unavailable",
|
|
116
|
+
})}
|
|
117
|
+
>
|
|
118
|
+
{copied ? (
|
|
119
|
+
<IconCheck aria-hidden="true" />
|
|
120
|
+
) : (
|
|
121
|
+
<IconCopy aria-hidden="true" />
|
|
122
|
+
)}
|
|
123
|
+
{copied
|
|
124
|
+
? t("dispatch.pages.copied", { defaultValue: "Copied" })
|
|
125
|
+
: t("dispatch.pages.copyRequestId", {
|
|
126
|
+
defaultValue: requestId
|
|
127
|
+
? "Copy request ID"
|
|
128
|
+
: "Request ID unavailable",
|
|
129
|
+
})}
|
|
130
|
+
</Button>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
89
134
|
interface DispatchChatLocationState {
|
|
90
135
|
dispatchPrompt?: {
|
|
91
136
|
id?: string | number;
|
|
@@ -109,6 +154,7 @@ export default function ChatRoute() {
|
|
|
109
154
|
const location = useLocation();
|
|
110
155
|
const navigate = useNavigate();
|
|
111
156
|
const routeThreadId = threadIdFromPath(location.pathname);
|
|
157
|
+
const activeRunId = useActiveAgentChatRunId(routeThreadId);
|
|
112
158
|
const agentPath = new URLSearchParams(location.search).get("agent");
|
|
113
159
|
const agentsQuery = useActionQuery<WorkspaceAgentResource[]>(
|
|
114
160
|
"list-workspace-resources",
|
|
@@ -275,6 +321,11 @@ export default function ChatRoute() {
|
|
|
275
321
|
|
|
276
322
|
return (
|
|
277
323
|
<div className="flex h-full min-h-0 flex-col bg-background">
|
|
324
|
+
{threadUrlSync.routeThreadId ? (
|
|
325
|
+
<div className="flex justify-end px-4 pt-4 sm:px-6">
|
|
326
|
+
<DispatchRequestIdButton requestId={activeRunId} />
|
|
327
|
+
</div>
|
|
328
|
+
) : null}
|
|
278
329
|
<DispatchAgentChatSurface
|
|
279
330
|
key={agent ? `agent-${agent.id}` : "dispatch"}
|
|
280
331
|
mode="page"
|