@agent-native/dispatch 0.30.2 → 0.30.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,6 +9,7 @@ declare const _default: import("@agent-native/core").ActionDefinition<{
9
9
  taskId: string;
10
10
  status: string;
11
11
  response?: string;
12
+ receipts?: import("node_modules/@agent-native/core/dist/a2a/artifact-response.js").A2APersistedMutationReceipt[];
12
13
  error?: string;
13
14
  inputRequired?: string;
14
15
  statusRead?: "unavailable";
@@ -7,6 +7,7 @@ declare const _default: import("@agent-native/core").ActionDefinition<{
7
7
  taskId: string;
8
8
  status: string;
9
9
  response?: string;
10
+ receipts?: import("node_modules/@agent-native/core/dist/a2a/artifact-response.js").A2APersistedMutationReceipt[];
10
11
  error?: string;
11
12
  inputRequired?: string;
12
13
  statusRead?: "unavailable";
@@ -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":"AAsGA,wBAAgB,IAAI;;IAEnB;AAED,MAAM,CAAC,OAAO,UAAU,SAAS,oDAoOhC"}
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 { useCallback, useEffect, useMemo, useRef, } from "react";
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 (_jsx("div", { className: "flex h-full min-h-0 flex-col bg-background", children: _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", {
176
- defaultValue: "Route work, inspect status, or create something new from one place.",
177
- }), emptyStateDisplay: "hidden", ...(!prompt?.message
178
- ? {
179
- centerComposerWhenEmpty: true,
180
- composerLayoutVariant: "hero",
181
- }
182
- : {}), composerPlaceholder: agent
183
- ? `Ask ${agent.name}...`
184
- : t("dispatch.pages.chatPromptPlaceholder", {
185
- defaultValue: "Ask Dispatch...",
186
- }), 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", {
187
- defaultValue: "Chat across your apps",
188
- }) }), _jsx("p", { children: t("dispatch.pages.chatAcrossAppsDescription", {
189
- defaultValue: "Route work, inspect status, or create something new from one place.",
190
- }) })] })) : null }, agent ? `agent-${agent.id}` : "dispatch") }));
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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch-integrations.d.ts","sourceRoot":"","sources":["../../../src/server/lib/dispatch-integrations.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,eAAe,EACf,2BAA2B,EAC3B,eAAe,EAChB,MAAM,2BAA2B,CAAC;AA2BnC,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,eAAe,GACxB,MAAM,GAAG,IAAI,CAmBf;AAwOD,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,MAAM,CAAC,CA8DjB;AAED;;;;GAIG;AACH,wBAAsB,+BAA+B,CACnD,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,2BAA2B,CAAC,CAgGtC;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,CAAC,CAwDxE"}
1
+ {"version":3,"file":"dispatch-integrations.d.ts","sourceRoot":"","sources":["../../../src/server/lib/dispatch-integrations.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,eAAe,EACf,2BAA2B,EAC3B,eAAe,EAChB,MAAM,2BAA2B,CAAC;AA2BnC,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,eAAe,GACxB,MAAM,GAAG,IAAI,CAmBf;AA+VD,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,MAAM,CAAC,CA8DjB;AAED;;;;GAIG;AACH,wBAAsB,+BAA+B,CACnD,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,2BAA2B,CAAC,CAwHtC;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,CAAC,CA0FxE"}
@@ -1,6 +1,6 @@
1
1
  import crypto from "node:crypto";
2
2
  import { evaluateIntegrationScopePolicy, getActiveIntegrationInstallationByKey, getIntegrationScope, resolveIntegrationTokenBundle, resolveSlackBotTokenForIncoming, saveIntegrationScope, slackInstallationKey, } from "@agent-native/core/integrations";
3
- import { resolveOrgIdForEmail } from "@agent-native/core/org";
3
+ import { isOrgMember, resolveOrgIdForEmail } from "@agent-native/core/org";
4
4
  import { withConfiguredAppBasePath } from "@agent-native/core/server";
5
5
  import { handleRemoteCodeCommand } from "./dispatch-remote-commands.js";
6
6
  import { dispatchIntegrationRoutingHint, } from "./dispatch-routing.js";
@@ -82,14 +82,30 @@ async function resolveManagedSlackInstallation(incoming) {
82
82
  if (incoming.platform !== "slack")
83
83
  return null;
84
84
  const teamId = contextString(incoming.platformContext.teamId);
85
+ const enterpriseId = contextString(incoming.platformContext.enterpriseId);
85
86
  const apiAppId = contextString(incoming.platformContext.apiAppId);
86
- if (!teamId)
87
+ const isEnterpriseInstall = incoming.platformContext.isEnterpriseInstall === true;
88
+ if ((!teamId && !enterpriseId) || (isEnterpriseInstall && !enterpriseId))
87
89
  return null;
90
+ return getActiveIntegrationInstallationByKey("slack", slackInstallationKey({
91
+ teamId,
92
+ enterpriseId,
93
+ apiAppId,
94
+ isEnterpriseInstall,
95
+ }));
96
+ }
97
+ class ManagedSlackInstallationLookupError extends Error {
98
+ constructor(options) {
99
+ super("Managed Slack installation identity is temporarily unavailable", options);
100
+ this.name = "ManagedSlackInstallationLookupError";
101
+ }
102
+ }
103
+ async function resolveManagedSlackInstallationOrFail(incoming) {
88
104
  try {
89
- return await getActiveIntegrationInstallationByKey("slack", slackInstallationKey({ teamId, apiAppId }));
105
+ return await resolveManagedSlackInstallation(incoming);
90
106
  }
91
- catch {
92
- return null;
107
+ catch (cause) {
108
+ throw new ManagedSlackInstallationLookupError({ cause });
93
109
  }
94
110
  }
95
111
  async function resolveManagedSlackToken(incoming) {
@@ -113,6 +129,12 @@ function formatSlackLinkRequiredMessage() {
113
129
  : "Open Dispatch while signed in, create a Slack link token, then send `/link <token>` in this DM.";
114
130
  return `Agent Native is ready, but this Slack account is not linked to an Agent Native user yet. ${linkStep}`;
115
131
  }
132
+ function formatSlackIdentityVerificationFailedMessage() {
133
+ return "I couldn't verify your Slack identity just now, so I can't run this request. Please try again in a moment.";
134
+ }
135
+ function formatSlackIdentityDeniedMessage() {
136
+ return "This assistant is only available to members of this workspace's organization.";
137
+ }
116
138
  async function resolveSlackSenderProfile(incoming) {
117
139
  if (incoming.platform !== "slack") {
118
140
  return { email: null, name: null, trust: "unknown" };
@@ -147,7 +169,8 @@ async function resolveSlackSenderProfile(incoming) {
147
169
  data.user?.real_name?.trim() ||
148
170
  data.user?.name?.trim() ||
149
171
  null,
150
- trust: data.user?.is_ultra_restricted === true
172
+ trust: data.user?.is_stranger === true ||
173
+ data.user?.is_ultra_restricted === true
151
174
  ? "external_shared"
152
175
  : data.user?.is_restricted === true
153
176
  ? "guest"
@@ -179,6 +202,74 @@ async function resolveSlackOwnerFromVerifiedEmail(incoming) {
179
202
  const orgId = await resolveOrgIdForEmail(profile.email);
180
203
  return orgId ? profile.email : null;
181
204
  }
205
+ async function resolveManagedSlackDmExecutionContext(incoming, installation) {
206
+ const profile = await resolveSlackSenderProfile(incoming);
207
+ incoming.actorTrust = {
208
+ memberType: profile.trust === "guest"
209
+ ? "guest"
210
+ : profile.trust === "external_shared"
211
+ ? "external"
212
+ : profile.trust === "trusted"
213
+ ? "member"
214
+ : "unknown",
215
+ verified: profile.trust !== "unknown",
216
+ };
217
+ incoming.senderVerified = profile.email !== null;
218
+ if (profile.email) {
219
+ incoming.senderEmail = profile.email;
220
+ incoming.platformContext.senderEmail = profile.email;
221
+ }
222
+ if (profile.name) {
223
+ incoming.senderName = profile.name;
224
+ incoming.platformContext.senderName = profile.name;
225
+ }
226
+ const deniedContext = () => ({
227
+ ownerEmail: fallbackOwnerForIncoming(incoming),
228
+ orgId: null,
229
+ principalType: "user",
230
+ installationId: installation.id,
231
+ });
232
+ if (profile.trust === "unknown") {
233
+ incoming.platformContext.identityVerificationFailed = true;
234
+ return deniedContext();
235
+ }
236
+ if (profile.trust === "guest" || profile.trust === "external_shared") {
237
+ incoming.platformContext.identityAccessDenied = true;
238
+ return deniedContext();
239
+ }
240
+ if (!installation.orgId) {
241
+ incoming.platformContext.identityLinkRequired = true;
242
+ return deniedContext();
243
+ }
244
+ incoming.platformContext.managedInstallationOrgId = installation.orgId;
245
+ let linkedOwner;
246
+ try {
247
+ linkedOwner = await resolveLinkedOwner("slack", identityKeyForIncoming(incoming), { orgId: installation.orgId });
248
+ }
249
+ catch {
250
+ incoming.platformContext.identityVerificationFailed = true;
251
+ return deniedContext();
252
+ }
253
+ const candidates = [profile.email, linkedOwner].filter((email, index, values) => !!email && values.indexOf(email) === index);
254
+ for (const ownerEmail of candidates) {
255
+ try {
256
+ if (await isOrgMember(installation.orgId, ownerEmail)) {
257
+ return {
258
+ ownerEmail,
259
+ orgId: installation.orgId,
260
+ principalType: "user",
261
+ installationId: installation.id,
262
+ };
263
+ }
264
+ }
265
+ catch {
266
+ incoming.platformContext.identityVerificationFailed = true;
267
+ return deniedContext();
268
+ }
269
+ }
270
+ incoming.platformContext.identityLinkRequired = true;
271
+ return deniedContext();
272
+ }
182
273
  async function resolveSlackConversationTrust(incoming, actorTrust) {
183
274
  if (incoming.triggerKind === "dm") {
184
275
  return { trust: actorTrust, conversationType: "direct_message" };
@@ -276,6 +367,31 @@ export async function resolveDispatchOwner(incoming) {
276
367
  * personal credentials or memory.
277
368
  */
278
369
  export async function resolveDispatchExecutionContext(incoming) {
370
+ if (incoming.platform === "slack" && incoming.triggerKind === "dm") {
371
+ let installation;
372
+ try {
373
+ installation = await resolveManagedSlackInstallationOrFail(incoming);
374
+ }
375
+ catch (error) {
376
+ if (!(error instanceof ManagedSlackInstallationLookupError))
377
+ throw error;
378
+ incoming.platformContext.identityVerificationFailed = true;
379
+ return {
380
+ ownerEmail: fallbackOwnerForIncoming(incoming),
381
+ orgId: null,
382
+ principalType: "user",
383
+ };
384
+ }
385
+ if (installation) {
386
+ return resolveManagedSlackDmExecutionContext(incoming, installation);
387
+ }
388
+ incoming.platformContext.identityVerificationFailed = true;
389
+ return {
390
+ ownerEmail: fallbackOwnerForIncoming(incoming),
391
+ orgId: null,
392
+ principalType: "user",
393
+ };
394
+ }
279
395
  if (incoming.platform !== "slack" || incoming.triggerKind === "dm") {
280
396
  const ownerEmail = await resolveDispatchOwner(incoming);
281
397
  if (incoming.platform === "slack" &&
@@ -291,7 +407,7 @@ export async function resolveDispatchExecutionContext(incoming) {
291
407
  principalType: "user",
292
408
  };
293
409
  }
294
- const installation = await resolveManagedSlackInstallation(incoming);
410
+ const installation = await resolveManagedSlackInstallationOrFail(incoming);
295
411
  if (!installation) {
296
412
  // Preserve the legacy manually configured app path while managed installs
297
413
  // roll out. Its behavior remains explicit and visible in Settings.
@@ -365,6 +481,30 @@ export async function beforeDispatchProcess(incoming, adapter) {
365
481
  const trimmed = incoming.text.trim();
366
482
  const commandText = contextString(incoming.platformContext.rawText) || trimmed;
367
483
  const match = commandText.match(/^\/link(?:@\w+)?\s+([a-zA-Z0-9_-]+)$/);
484
+ if (match &&
485
+ incoming.platform === "slack" &&
486
+ incoming.triggerKind === "dm" &&
487
+ !contextString(incoming.platformContext.managedInstallationOrgId) &&
488
+ incoming.platformContext.identityVerificationFailed !== true &&
489
+ incoming.platformContext.identityAccessDenied !== true) {
490
+ await resolveDispatchExecutionContext(incoming);
491
+ }
492
+ if (incoming.platform === "slack" &&
493
+ incoming.triggerKind === "dm" &&
494
+ incoming.platformContext.identityVerificationFailed === true) {
495
+ return {
496
+ handled: true,
497
+ responseText: formatSlackIdentityVerificationFailedMessage(),
498
+ };
499
+ }
500
+ if (incoming.platform === "slack" &&
501
+ incoming.triggerKind === "dm" &&
502
+ incoming.platformContext.identityAccessDenied === true) {
503
+ return {
504
+ handled: true,
505
+ responseText: formatSlackIdentityDeniedMessage(),
506
+ };
507
+ }
368
508
  if (!match) {
369
509
  const routedIncoming = incoming;
370
510
  routedIncoming.routingHint ??= dispatchIntegrationRoutingHint(trimmed);
@@ -390,11 +530,13 @@ export async function beforeDispatchProcess(incoming, adapter) {
390
530
  });
391
531
  }
392
532
  try {
533
+ const expectedOrgId = contextString(incoming.platformContext.managedInstallationOrgId);
393
534
  const owner = await consumeLinkToken({
394
535
  platform: incoming.platform,
395
536
  token: match[1],
396
537
  externalUserId: identityKeyForIncoming(incoming),
397
538
  externalUserName: incoming.senderName || null,
539
+ ...(expectedOrgId ? { expectedOrgId } : {}),
398
540
  });
399
541
  return {
400
542
  handled: true,