@agent-native/dispatch 0.16.2 → 0.16.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/actions/get-agent-thread-debug.d.ts +9 -0
  2. package/dist/actions/index.d.ts.map +1 -1
  3. package/dist/actions/index.js +2 -0
  4. package/dist/actions/index.js.map +1 -1
  5. package/dist/actions/list-agent-run-failures.d.ts +61 -0
  6. package/dist/actions/list-agent-run-failures.d.ts.map +1 -0
  7. package/dist/actions/list-agent-run-failures.js +38 -0
  8. package/dist/actions/list-agent-run-failures.js.map +1 -0
  9. package/dist/actions/provider-api-register.d.ts +12 -12
  10. package/dist/actions/upsert-destination.d.ts +12 -12
  11. package/dist/actions/view-screen.js +32 -5
  12. package/dist/actions/view-screen.js.map +1 -1
  13. package/dist/hooks/use-navigation-state.d.ts +6 -0
  14. package/dist/hooks/use-navigation-state.d.ts.map +1 -1
  15. package/dist/hooks/use-navigation-state.js +30 -0
  16. package/dist/hooks/use-navigation-state.js.map +1 -1
  17. package/dist/routes/pages/thread-debug.d.ts.map +1 -1
  18. package/dist/routes/pages/thread-debug.js +291 -77
  19. package/dist/routes/pages/thread-debug.js.map +1 -1
  20. package/dist/server/lib/thread-debug-store.d.ts +72 -0
  21. package/dist/server/lib/thread-debug-store.d.ts.map +1 -1
  22. package/dist/server/lib/thread-debug-store.js +215 -19
  23. package/dist/server/lib/thread-debug-store.js.map +1 -1
  24. package/dist/server/plugins/agent-chat.js +1 -0
  25. package/dist/server/plugins/agent-chat.js.map +1 -1
  26. package/package.json +3 -3
  27. package/src/actions/index.ts +2 -0
  28. package/src/actions/list-agent-run-failures.ts +44 -0
  29. package/src/actions/view-screen.spec.ts +91 -0
  30. package/src/actions/view-screen.ts +34 -4
  31. package/src/hooks/use-navigation-state.spec.ts +45 -0
  32. package/src/hooks/use-navigation-state.ts +28 -0
  33. package/src/routes/pages/thread-debug.spec.tsx +272 -0
  34. package/src/routes/pages/thread-debug.tsx +843 -224
  35. package/src/server/lib/thread-debug-store.spec.ts +292 -16
  36. package/src/server/lib/thread-debug-store.ts +318 -22
  37. package/src/server/plugins/agent-chat.spec.ts +30 -0
  38. package/src/server/plugins/agent-chat.ts +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"use-navigation-state.js","sourceRoot":"","sources":["../../src/hooks/use-navigation-state.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n isAgentChatHomeHandoffActive,\n markAgentChatHomeHandoff,\n} from \"@agent-native/core/client/agent-chat\";\nimport {\n agentNativePath,\n appBasePath,\n appPath,\n} from \"@agent-native/core/client/api-path\";\nimport { extensionIdFromPathname } from \"@agent-native/core/client/extensions\";\nimport { useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport { useEffect } from \"react\";\nimport { useLocation, useNavigate } from \"react-router\";\n\nimport type {\n DispatchExtensionConfig,\n DispatchNavItem,\n} from \"../components/index.js\";\n\nexport interface NavigationState {\n view: string;\n path?: string;\n extensionId?: string;\n extensionSlug?: string;\n dreamId?: string;\n sourceId?: string;\n query?: string;\n threadId?: string;\n}\n\nexport function useNavigationState(extensions?: DispatchExtensionConfig) {\n const location = useLocation();\n const navigate = useNavigate();\n const qc = useQueryClient();\n\n // Sync current route to application state\n useEffect(() => {\n const localPathname = routerPath(location.pathname);\n const state = buildDispatchNavigationState(\n localPathname,\n location.search,\n extensions,\n );\n\n fetch(agentNativePath(\"/_agent-native/application-state/navigation\"), {\n method: \"PUT\",\n keepalive: true,\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(state),\n }).catch(() => {});\n }, [extensions, location.pathname, location.search]);\n\n // Listen for navigate commands from agent\n const { data: navCommand } = useQuery({\n queryKey: [\"navigate-command\"],\n queryFn: async () => {\n const res = await fetch(\n agentNativePath(\"/_agent-native/application-state/navigate\"),\n );\n if (!res.ok) return null;\n const data = await res.json();\n if (data) {\n // Return with a timestamp to ensure uniqueness\n return { ...data, _ts: Date.now() };\n }\n return null;\n },\n structuralSharing: false,\n });\n\n useEffect(() => {\n if (!navCommand) return;\n // Delete the one-shot command AFTER reading it\n fetch(agentNativePath(\"/_agent-native/application-state/navigate\"), {\n method: \"DELETE\",\n headers: { \"X-Agent-Native-CSRF\": \"1\" },\n }).catch(() => {});\n const cmd = navCommand as NavigationState;\n\n // Navigate to a specific path or resolve view name to path\n const resolvedPath =\n cmd.path || resolvePath(cmd.view, extensions, cmd) || \"/overview\";\n const path =\n cmd.view === \"dreams\" && cmd.dreamId && !resolvedPath.includes(\"?\")\n ? `${resolvedPath}?dreamId=${encodeURIComponent(cmd.dreamId)}`\n : resolvedPath;\n const nextPath = routerPath(path);\n if (\n isChatPath(routerPath(location.pathname)) &&\n !isChatPath(pathnameFromPath(nextPath))\n ) {\n if (isAgentChatHomeHandoffActive(\"dispatch\")) {\n markAgentChatHomeHandoff(\"dispatch\");\n }\n }\n navigate(nextPath);\n qc.setQueryData([\"navigate-command\"], null);\n }, [extensions, location.pathname, navCommand, navigate, qc]);\n}\n\nfunction pathnameFromPath(path: string): string {\n return path.split(/[?#]/, 1)[0] || \"/\";\n}\n\nfunction isChatPath(pathname: string): boolean {\n return pathname === \"/chat\" || pathname.startsWith(\"/chat/\");\n}\n\nfunction threadIdFromPath(pathname: string): string | null {\n const match = 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\nexport function buildDispatchNavigationState(\n pathname: string,\n search = \"\",\n extensions?: DispatchExtensionConfig,\n): NavigationState {\n const state: NavigationState = {\n view: resolveView(pathname, extensions),\n path: appPath(pathname),\n };\n\n const threadId = threadIdFromPath(pathname);\n if (threadId) state.threadId = threadId;\n\n const extensionId = extensionIdFromPathname(pathname);\n if (extensionId) {\n state.view = \"extensions\";\n state.extensionId = extensionId;\n const slug = extensionSlugFromPathname(pathname);\n if (slug) state.extensionSlug = slug;\n return state;\n }\n\n if (state.view === \"dreams\") {\n const params = new URLSearchParams(search);\n const dreamId = params.get(\"dreamId\");\n const sourceId = params.get(\"sourceId\");\n const query = params.get(\"query\");\n if (dreamId) state.dreamId = dreamId;\n if (sourceId) state.sourceId = sourceId;\n if (query) state.query = query;\n }\n\n return state;\n}\n\nfunction routerPath(path: string): string {\n const basePath = appBasePath();\n if (!basePath) return path;\n let result = path;\n // Iteratively strip basename. A path that arrives doubly-prefixed\n // (e.g. \"/dispatch/dispatch/overview\", possibly from a stale link or a\n // prior bug) would otherwise get partially stripped here and then\n // re-prefixed by react-router's basename, restoring the bad URL.\n for (let i = 0; i < 4; i += 1) {\n if (result === basePath) return \"/\";\n if (!result.startsWith(`${basePath}/`)) break;\n result = result.slice(basePath.length) || \"/\";\n }\n return result;\n}\n\nfunction extensionItemMatchesPath(\n item: DispatchNavItem,\n pathname: string,\n): boolean {\n if (item.match) {\n try {\n if (item.match(pathname)) return true;\n } catch {\n return false;\n }\n }\n return pathname === item.to || pathname.startsWith(`${item.to}/`);\n}\n\nfunction resolveExtensionView(\n pathname: string,\n extensions?: DispatchExtensionConfig,\n): string | undefined {\n return extensions?.navItems?.find((item) =>\n extensionItemMatchesPath(item, pathname),\n )?.id;\n}\n\nfunction resolveExtensionPath(\n view: string | undefined,\n extensions?: DispatchExtensionConfig,\n): string | undefined {\n if (!view) return undefined;\n return extensions?.navItems?.find((item) => item.id === view)?.to;\n}\n\nfunction resolveView(\n pathname: string,\n extensions?: DispatchExtensionConfig,\n): string {\n const extensionView = resolveExtensionView(pathname, extensions);\n if (extensionView) return extensionView;\n if (pathname === \"/extensions\" || pathname.startsWith(\"/extensions/\")) {\n return \"extensions\";\n }\n if (pathname.startsWith(\"/browser-chat\")) return \"browser-chat\";\n if (pathname.startsWith(\"/chat\")) return \"chat\";\n if (pathname.startsWith(\"/apps\")) return \"apps\";\n if (pathname.startsWith(\"/metrics\")) return \"metrics\";\n if (pathname.startsWith(\"/new-app\")) return \"new-app\";\n if (pathname.startsWith(\"/vault\")) return \"vault\";\n if (pathname.startsWith(\"/integrations\")) return \"integrations\";\n if (pathname.startsWith(\"/workspace\")) return \"workspace\";\n if (pathname.startsWith(\"/agents\")) return \"agents\";\n if (pathname.startsWith(\"/messaging\")) return \"messaging\";\n if (pathname.startsWith(\"/destinations\")) return \"destinations\";\n if (pathname.startsWith(\"/identities\")) return \"identities\";\n if (pathname.startsWith(\"/approvals\")) return \"approvals\";\n if (pathname.startsWith(\"/automations\")) return \"automations\";\n if (pathname.startsWith(\"/audit\")) return \"audit\";\n if (pathname.startsWith(\"/dreams\")) return \"dreams\";\n if (pathname.startsWith(\"/thread-debug\")) return \"thread-debug\";\n if (pathname.startsWith(\"/team\")) return \"settings\";\n return \"overview\";\n}\n\nfunction resolvePath(\n view?: string,\n extensions?: DispatchExtensionConfig,\n command?: Pick<NavigationState, \"extensionId\" | \"threadId\">,\n): string | undefined {\n switch (view) {\n case \"chat\":\n case \"ask\":\n return command?.threadId && command.threadId.trim()\n ? `/chat/${encodeURIComponent(command.threadId.trim())}`\n : \"/chat\";\n case \"overview\":\n return \"/overview\";\n case \"apps\":\n return \"/apps\";\n case \"metrics\":\n case \"usage\":\n return \"/metrics\";\n case \"new-app\":\n case \"create-app\":\n return \"/new-app\";\n case \"vault\":\n case \"secrets\":\n return \"/vault\";\n case \"integrations\":\n return \"/integrations\";\n case \"workspace\":\n case \"resources\":\n return \"/workspace\";\n case \"agents\":\n return \"/agents\";\n case \"messaging\":\n return \"/messaging\";\n case \"destinations\":\n case \"routes\":\n return \"/destinations\";\n case \"identities\":\n return \"/identities\";\n case \"approvals\":\n return \"/approvals\";\n case \"automations\":\n case \"jobs\":\n return \"/automations\";\n case \"audit\":\n return \"/audit\";\n case \"dreams\":\n return \"/dreams\";\n case \"thread-debug\":\n case \"threads\":\n return \"/thread-debug\";\n case \"team\":\n return \"/settings#organization\";\n case \"extensions\":\n return command?.extensionId\n ? `/extensions/${encodeURIComponent(command.extensionId)}`\n : \"/extensions\";\n default:\n return resolveExtensionPath(view, extensions);\n }\n}\n\nfunction extensionSlugFromPathname(pathname: string): string | undefined {\n const match = pathname.match(/^\\/extensions\\/[^/]+\\/([^/?#]+)/);\n if (!match?.[1]) return undefined;\n try {\n return decodeURIComponent(match[1]);\n } catch {\n return match[1];\n }\n}\n"]}
1
+ {"version":3,"file":"use-navigation-state.js","sourceRoot":"","sources":["../../src/hooks/use-navigation-state.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n isAgentChatHomeHandoffActive,\n markAgentChatHomeHandoff,\n} from \"@agent-native/core/client/agent-chat\";\nimport {\n agentNativePath,\n appBasePath,\n appPath,\n} from \"@agent-native/core/client/api-path\";\nimport { extensionIdFromPathname } from \"@agent-native/core/client/extensions\";\nimport { useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport { useEffect } from \"react\";\nimport { useLocation, useNavigate } from \"react-router\";\n\nimport type {\n DispatchExtensionConfig,\n DispatchNavItem,\n} from \"../components/index.js\";\n\nexport interface NavigationState {\n view: string;\n path?: string;\n extensionId?: string;\n extensionSlug?: string;\n dreamId?: string;\n threadDebugMode?: string;\n sourceId?: string;\n inspectSourceId?: string;\n ownerEmail?: string;\n failureStatus?: string;\n range?: string;\n query?: string;\n runId?: string;\n threadId?: string;\n}\n\nexport function useNavigationState(extensions?: DispatchExtensionConfig) {\n const location = useLocation();\n const navigate = useNavigate();\n const qc = useQueryClient();\n\n // Sync current route to application state\n useEffect(() => {\n const localPathname = routerPath(location.pathname);\n const state = buildDispatchNavigationState(\n localPathname,\n location.search,\n extensions,\n );\n\n fetch(agentNativePath(\"/_agent-native/application-state/navigation\"), {\n method: \"PUT\",\n keepalive: true,\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(state),\n }).catch(() => {});\n }, [extensions, location.pathname, location.search]);\n\n // Listen for navigate commands from agent\n const { data: navCommand } = useQuery({\n queryKey: [\"navigate-command\"],\n queryFn: async () => {\n const res = await fetch(\n agentNativePath(\"/_agent-native/application-state/navigate\"),\n );\n if (!res.ok) return null;\n const data = await res.json();\n if (data) {\n // Return with a timestamp to ensure uniqueness\n return { ...data, _ts: Date.now() };\n }\n return null;\n },\n structuralSharing: false,\n });\n\n useEffect(() => {\n if (!navCommand) return;\n // Delete the one-shot command AFTER reading it\n fetch(agentNativePath(\"/_agent-native/application-state/navigate\"), {\n method: \"DELETE\",\n headers: { \"X-Agent-Native-CSRF\": \"1\" },\n }).catch(() => {});\n const cmd = navCommand as NavigationState;\n\n // Navigate to a specific path or resolve view name to path\n const resolvedPath =\n cmd.path || resolvePath(cmd.view, extensions, cmd) || \"/overview\";\n const path =\n cmd.view === \"dreams\" && cmd.dreamId && !resolvedPath.includes(\"?\")\n ? `${resolvedPath}?dreamId=${encodeURIComponent(cmd.dreamId)}`\n : resolvedPath;\n const nextPath = routerPath(path);\n if (\n isChatPath(routerPath(location.pathname)) &&\n !isChatPath(pathnameFromPath(nextPath))\n ) {\n if (isAgentChatHomeHandoffActive(\"dispatch\")) {\n markAgentChatHomeHandoff(\"dispatch\");\n }\n }\n navigate(nextPath);\n qc.setQueryData([\"navigate-command\"], null);\n }, [extensions, location.pathname, navCommand, navigate, qc]);\n}\n\nfunction pathnameFromPath(path: string): string {\n return path.split(/[?#]/, 1)[0] || \"/\";\n}\n\nfunction isChatPath(pathname: string): boolean {\n return pathname === \"/chat\" || pathname.startsWith(\"/chat/\");\n}\n\nfunction threadIdFromPath(pathname: string): string | null {\n const match = 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\nexport function buildDispatchNavigationState(\n pathname: string,\n search = \"\",\n extensions?: DispatchExtensionConfig,\n): NavigationState {\n const state: NavigationState = {\n view: resolveView(pathname, extensions),\n path: appPath(pathname),\n };\n\n const threadId = threadIdFromPath(pathname);\n if (threadId) state.threadId = threadId;\n\n const extensionId = extensionIdFromPathname(pathname);\n if (extensionId) {\n state.view = \"extensions\";\n state.extensionId = extensionId;\n const slug = extensionSlugFromPathname(pathname);\n if (slug) state.extensionSlug = slug;\n return state;\n }\n\n if (state.view === \"dreams\") {\n const params = new URLSearchParams(search);\n const dreamId = params.get(\"dreamId\");\n const sourceId = params.get(\"sourceId\");\n const query = params.get(\"query\");\n if (dreamId) state.dreamId = dreamId;\n if (sourceId) state.sourceId = sourceId;\n if (query) state.query = query;\n }\n\n if (state.view === \"thread-debug\") {\n const params = new URLSearchParams(search);\n const mode = params.get(\"mode\");\n const sourceId = params.get(\"source\");\n const inspectSourceId = params.get(\"inspectSource\");\n const ownerEmail = params.get(\"owner\");\n const status = params.get(\"status\");\n const range = params.get(\"range\");\n const query = params.get(\"query\");\n const runId = params.get(\"runId\");\n const selectedThreadId = params.get(\"threadId\");\n if (mode) state.threadDebugMode = mode;\n if (sourceId) state.sourceId = sourceId;\n if (inspectSourceId) state.inspectSourceId = inspectSourceId;\n if (ownerEmail) state.ownerEmail = ownerEmail;\n if (status) state.failureStatus = status;\n if (range) state.range = range;\n if (query) state.query = query;\n if (runId) state.runId = runId;\n if (selectedThreadId) state.threadId = selectedThreadId;\n }\n\n return state;\n}\n\nfunction routerPath(path: string): string {\n const basePath = appBasePath();\n if (!basePath) return path;\n let result = path;\n // Iteratively strip basename. A path that arrives doubly-prefixed\n // (e.g. \"/dispatch/dispatch/overview\", possibly from a stale link or a\n // prior bug) would otherwise get partially stripped here and then\n // re-prefixed by react-router's basename, restoring the bad URL.\n for (let i = 0; i < 4; i += 1) {\n if (result === basePath) return \"/\";\n if (!result.startsWith(`${basePath}/`)) break;\n result = result.slice(basePath.length) || \"/\";\n }\n return result;\n}\n\nfunction extensionItemMatchesPath(\n item: DispatchNavItem,\n pathname: string,\n): boolean {\n if (item.match) {\n try {\n if (item.match(pathname)) return true;\n } catch {\n return false;\n }\n }\n return pathname === item.to || pathname.startsWith(`${item.to}/`);\n}\n\nfunction resolveExtensionView(\n pathname: string,\n extensions?: DispatchExtensionConfig,\n): string | undefined {\n return extensions?.navItems?.find((item) =>\n extensionItemMatchesPath(item, pathname),\n )?.id;\n}\n\nfunction resolveExtensionPath(\n view: string | undefined,\n extensions?: DispatchExtensionConfig,\n): string | undefined {\n if (!view) return undefined;\n return extensions?.navItems?.find((item) => item.id === view)?.to;\n}\n\nfunction resolveView(\n pathname: string,\n extensions?: DispatchExtensionConfig,\n): string {\n const extensionView = resolveExtensionView(pathname, extensions);\n if (extensionView) return extensionView;\n if (pathname === \"/extensions\" || pathname.startsWith(\"/extensions/\")) {\n return \"extensions\";\n }\n if (pathname.startsWith(\"/browser-chat\")) return \"browser-chat\";\n if (pathname.startsWith(\"/chat\")) return \"chat\";\n if (pathname.startsWith(\"/apps\")) return \"apps\";\n if (pathname.startsWith(\"/metrics\")) return \"metrics\";\n if (pathname.startsWith(\"/new-app\")) return \"new-app\";\n if (pathname.startsWith(\"/vault\")) return \"vault\";\n if (pathname.startsWith(\"/integrations\")) return \"integrations\";\n if (pathname.startsWith(\"/workspace\")) return \"workspace\";\n if (pathname.startsWith(\"/agents\")) return \"agents\";\n if (pathname.startsWith(\"/messaging\")) return \"messaging\";\n if (pathname.startsWith(\"/destinations\")) return \"destinations\";\n if (pathname.startsWith(\"/identities\")) return \"identities\";\n if (pathname.startsWith(\"/approvals\")) return \"approvals\";\n if (pathname.startsWith(\"/automations\")) return \"automations\";\n if (pathname.startsWith(\"/audit\")) return \"audit\";\n if (pathname.startsWith(\"/dreams\")) return \"dreams\";\n if (pathname.startsWith(\"/thread-debug\")) return \"thread-debug\";\n if (pathname.startsWith(\"/team\")) return \"settings\";\n return \"overview\";\n}\n\nfunction resolvePath(\n view?: string,\n extensions?: DispatchExtensionConfig,\n command?: Pick<NavigationState, \"extensionId\" | \"threadId\">,\n): string | undefined {\n switch (view) {\n case \"chat\":\n case \"ask\":\n return command?.threadId && command.threadId.trim()\n ? `/chat/${encodeURIComponent(command.threadId.trim())}`\n : \"/chat\";\n case \"overview\":\n return \"/overview\";\n case \"apps\":\n return \"/apps\";\n case \"metrics\":\n case \"usage\":\n return \"/metrics\";\n case \"new-app\":\n case \"create-app\":\n return \"/new-app\";\n case \"vault\":\n case \"secrets\":\n return \"/vault\";\n case \"integrations\":\n return \"/integrations\";\n case \"workspace\":\n case \"resources\":\n return \"/workspace\";\n case \"agents\":\n return \"/agents\";\n case \"messaging\":\n return \"/messaging\";\n case \"destinations\":\n case \"routes\":\n return \"/destinations\";\n case \"identities\":\n return \"/identities\";\n case \"approvals\":\n return \"/approvals\";\n case \"automations\":\n case \"jobs\":\n return \"/automations\";\n case \"audit\":\n return \"/audit\";\n case \"dreams\":\n return \"/dreams\";\n case \"thread-debug\":\n case \"threads\":\n return \"/thread-debug\";\n case \"team\":\n return \"/settings#organization\";\n case \"extensions\":\n return command?.extensionId\n ? `/extensions/${encodeURIComponent(command.extensionId)}`\n : \"/extensions\";\n default:\n return resolveExtensionPath(view, extensions);\n }\n}\n\nfunction extensionSlugFromPathname(pathname: string): string | undefined {\n const match = pathname.match(/^\\/extensions\\/[^/]+\\/([^/?#]+)/);\n if (!match?.[1]) return undefined;\n try {\n return decodeURIComponent(match[1]);\n } catch {\n return match[1];\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"thread-debug.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/thread-debug.tsx"],"names":[],"mappings":"AAgCA,wBAAgB,IAAI;;IAEnB;AAiYD,MAAM,CAAC,OAAO,UAAU,gBAAgB,oDA8SvC"}
1
+ {"version":3,"file":"thread-debug.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/thread-debug.tsx"],"names":[],"mappings":"AAkCA,wBAAgB,IAAI;;IAEnB;AA6pBD,MAAM,CAAC,OAAO,UAAU,gBAAgB,oDA2nBvC"}
@@ -1,8 +1,8 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { agentNativePath } from "@agent-native/core/client/api-path";
3
2
  import { useActionQuery } from "@agent-native/core/client/hooks";
4
- import { IconDatabase, IconFileSearch, IconRefresh, IconSearch, } from "@tabler/icons-react";
5
- import { useEffect, useMemo, useState } from "react";
3
+ import { useT } from "@agent-native/core/client/i18n";
4
+ import { IconAlertTriangle, IconClock, IconDatabase, IconFileSearch, IconRefresh, IconSearch, } from "@tabler/icons-react";
5
+ import { useMemo, useState } from "react";
6
6
  import { useSearchParams } from "react-router";
7
7
  import { ActionQueryError } from "../../components/action-query-error.js";
8
8
  import { DispatchShell } from "../../components/dispatch-shell.js";
@@ -16,6 +16,28 @@ import { cn } from "../../lib/utils.js";
16
16
  export function meta() {
17
17
  return [{ title: "Thread Debug — Dispatch" }];
18
18
  }
19
+ const FAILURE_RANGE_HOURS = {
20
+ "24h": 24,
21
+ "7d": 7 * 24,
22
+ "30d": 30 * 24,
23
+ };
24
+ function parseMode(value) {
25
+ return value === "threads" ? "threads" : "failures";
26
+ }
27
+ function parseFailureStatus(value) {
28
+ return value === "errored" || value === "aborted" || value === "truncated"
29
+ ? value
30
+ : "all";
31
+ }
32
+ function parseFailureRange(value) {
33
+ return value === "7d" || value === "30d" ? value : "24h";
34
+ }
35
+ function failureSourceId(failure) {
36
+ return failure.sourceId || failure.source?.id || "current";
37
+ }
38
+ function failureSourceLabel(failure) {
39
+ return (failure.sourceLabel || failure.source?.label || failureSourceId(failure));
40
+ }
19
41
  function formatDate(value) {
20
42
  if (value == null || value === "")
21
43
  return "n/a";
@@ -25,6 +47,15 @@ function formatDate(value) {
25
47
  return "n/a";
26
48
  return date.toLocaleString();
27
49
  }
50
+ function formatDuration(value) {
51
+ if (value == null || !Number.isFinite(value))
52
+ return "n/a";
53
+ if (value < 1_000)
54
+ return `${Math.round(value)}ms`;
55
+ if (value < 60_000)
56
+ return `${(value / 1_000).toFixed(1)}s`;
57
+ return `${(value / 60_000).toFixed(1)}m`;
58
+ }
28
59
  function json(value) {
29
60
  try {
30
61
  return JSON.stringify(value, null, 2);
@@ -53,6 +84,23 @@ function messageTitle(message) {
53
84
  function toolParts(message) {
54
85
  return message.contentParts.filter((part) => part?.type === "tool-call");
55
86
  }
87
+ function diagnosticStage(value) {
88
+ if (!value)
89
+ return null;
90
+ try {
91
+ const parsed = JSON.parse(value);
92
+ const stage = typeof parsed.stage === "string" && parsed.stage.trim()
93
+ ? parsed.stage.trim()
94
+ : value;
95
+ const detail = typeof parsed.detail === "string" && parsed.detail.trim()
96
+ ? parsed.detail.trim()
97
+ : "";
98
+ return detail ? `${stage}: ${detail}` : stage;
99
+ }
100
+ catch {
101
+ return value;
102
+ }
103
+ }
56
104
  function RawBlock({ value, className, }) {
57
105
  return (_jsx("pre", { className: cn("max-h-[520px] overflow-auto rounded-lg border bg-muted/30 p-3 text-xs leading-relaxed text-foreground", "whitespace-pre-wrap break-words", className), children: typeof value === "string" ? value : json(value) }));
58
106
  }
@@ -64,11 +112,39 @@ function ResultCard({ result, selected, onSelect, }) {
64
112
  ? "border-foreground bg-muted"
65
113
  : "bg-card hover:border-foreground/30 hover:bg-muted/40"), children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate text-sm font-medium text-foreground", children: result.title || result.preview || result.id }), _jsx("div", { className: "mt-1 truncate font-mono text-[11px] text-muted-foreground", children: result.id })] }), _jsx(Badge, { variant: "outline", className: "shrink-0", children: result.messageCount })] }), _jsx("div", { className: "mt-2 line-clamp-3 text-xs leading-relaxed text-muted-foreground", children: result.snippet || result.preview || "No preview" }), _jsxs("div", { className: "mt-2 flex items-center justify-between gap-3 text-[11px] text-muted-foreground", children: [_jsx("span", { className: "truncate", children: result.ownerEmail }), _jsx("span", { className: "shrink-0", children: formatDate(result.updatedAt) })] })] }));
66
114
  }
115
+ function FailureCard({ failure, selected, onSelect, }) {
116
+ const t = useT();
117
+ const summary = failure.errorCode ||
118
+ failure.terminalReason ||
119
+ failure.abortReason ||
120
+ failure.status;
121
+ const statusLabel = failure.status === "errored"
122
+ ? t("dispatch.pages.threadDebugErrored", {
123
+ defaultValue: "Errored",
124
+ })
125
+ : failure.status === "aborted"
126
+ ? t("dispatch.pages.threadDebugAborted", {
127
+ defaultValue: "Aborted",
128
+ })
129
+ : failure.status === "truncated"
130
+ ? t("dispatch.pages.threadDebugTruncated", {
131
+ defaultValue: "Truncated",
132
+ })
133
+ : failure.status;
134
+ return (_jsxs("button", { type: "button", onClick: onSelect, className: cn("w-full rounded-lg border px-3 py-3 text-left transition-colors", selected
135
+ ? "border-foreground bg-muted"
136
+ : "bg-card hover:border-foreground/30 hover:bg-muted/40"), children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate text-sm font-medium text-foreground", children: failure.threadTitle || failure.threadPreview || failure.threadId }), _jsx("div", { className: "mt-1 truncate font-mono text-[11px] text-muted-foreground", children: failure.id })] }), _jsx(Badge, { variant: "outline", className: "shrink-0", children: statusLabel })] }), _jsxs("div", { className: "mt-2 flex items-center gap-1.5 text-xs text-foreground", children: [_jsx(IconAlertTriangle, { className: "size-3.5 shrink-0 text-muted-foreground" }), _jsx("span", { className: "truncate", children: summary })] }), failure.errorDetail ? (_jsx("div", { className: "mt-1 line-clamp-2 text-xs leading-relaxed text-muted-foreground", children: failure.errorDetail })) : null, _jsxs("div", { className: "mt-2 flex items-center justify-between gap-3 text-[11px] text-muted-foreground", children: [_jsxs("span", { className: "truncate", children: [failureSourceLabel(failure), " \u00B7 ", failure.ownerEmail] }), _jsxs("span", { className: "inline-flex shrink-0 items-center gap-1", children: [_jsx(IconClock, { className: "size-3" }), formatDate(failure.completedAt ?? failure.startedAt), failure.durationMs == null
137
+ ? null
138
+ : ` · ${formatDuration(failure.durationMs)}`] })] }), _jsx("span", { className: "sr-only", children: t("dispatch.pages.threadDebugInspectFailure", {
139
+ defaultValue: "Inspect failed run",
140
+ }) })] }));
141
+ }
67
142
  function MessageBlock({ message }) {
68
143
  const tools = toolParts(message);
69
144
  return (_jsxs("div", { className: "rounded-lg bg-card", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 border-b px-3 py-2", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Badge, { variant: message.role === "assistant" ? "default" : "secondary", children: message.role }), _jsx("span", { className: "truncate text-sm font-medium text-foreground", children: messageTitle(message) })] }), _jsxs("div", { className: "flex items-center gap-2 text-[11px] text-muted-foreground", children: [message.attachments.length > 0 ? (_jsxs(Badge, { variant: "outline", children: [message.attachments.length, " files"] })) : null, _jsx("span", { children: formatDate(message.createdAt) })] })] }), _jsxs("div", { className: "space-y-3 px-3 py-3", children: [message.text ? (_jsx("div", { className: "whitespace-pre-wrap break-words text-sm leading-relaxed text-foreground", children: message.text })) : (_jsx("div", { className: "text-sm text-muted-foreground", children: "No text content" })), tools.length > 0 ? (_jsx("div", { className: "space-y-2", children: tools.map((tool, index) => (_jsxs("details", { className: "rounded-md border bg-muted/30 px-3 py-2", children: [_jsx("summary", { className: "cursor-pointer text-xs font-medium text-foreground", children: tool.toolName ?? tool.name ?? "tool-call" }), _jsx(RawBlock, { value: tool, className: "mt-2 max-h-72" })] }, `${message.id ?? message.index}-tool-${index}`))) })) : null] })] }));
70
145
  }
71
146
  function ThreadDetail({ detail }) {
147
+ const t = useT();
72
148
  const rawBundle = useMemo(() => ({
73
149
  thread: detail.thread,
74
150
  debug: detail.debug,
@@ -82,7 +158,24 @@ function ThreadDetail({ detail }) {
82
158
  evals: detail.evals,
83
159
  checkpoints: detail.checkpoints,
84
160
  }), [detail]);
85
- return (_jsxs("div", { className: "rounded-lg bg-card", children: [_jsxs("div", { className: "border-b px-4 py-3", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate text-base font-semibold text-foreground", children: detail.thread.title || detail.thread.preview || detail.thread.id }), _jsx("div", { className: "mt-1 truncate font-mono text-xs text-muted-foreground", children: detail.thread.id })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs(Badge, { variant: "secondary", children: [detail.messages.length, " messages"] }), _jsxs(Badge, { variant: "secondary", children: [detail.runs.length, " runs"] }), _jsx(Badge, { variant: "outline", children: detail.source.label })] })] }), _jsxs("div", { className: "mt-3 grid gap-2 text-xs text-muted-foreground sm:grid-cols-3", children: [_jsxs("div", { className: "truncate", children: ["Owner: ", detail.thread.ownerEmail] }), _jsxs("div", { children: ["Created: ", formatDate(detail.thread.createdAt)] }), _jsxs("div", { children: ["Updated: ", formatDate(detail.thread.updatedAt)] })] })] }), _jsxs(Tabs, { defaultValue: "transcript", className: "p-4", children: [_jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "transcript", children: "Transcript" }), _jsx(TabsTrigger, { value: "runs", children: "Runs" }), _jsx(TabsTrigger, { value: "internals", children: "Internals" }), _jsx(TabsTrigger, { value: "raw", children: "Raw" })] }), _jsx(TabsContent, { value: "transcript", className: "mt-4 space-y-3", children: detail.messages.length > 0 ? (detail.messages.map((message) => (_jsx(MessageBlock, { message: message }, message.id ?? `message-${message.index}`)))) : (_jsx("div", { className: "rounded-lg border border-dashed px-4 py-8 text-center text-sm text-muted-foreground", children: "No persisted messages." })) }), _jsx(TabsContent, { value: "runs", className: "mt-4 space-y-3", children: detail.runs.length > 0 ? (detail.runs.map((run) => (_jsxs("details", { className: "rounded-lg bg-card", children: [_jsx("summary", { className: "cursor-pointer px-4 py-3", children: _jsxs("div", { className: "inline-flex flex-wrap items-center gap-2", children: [_jsx(Badge, { variant: "outline", children: run.status }), _jsx("span", { className: "font-mono text-xs text-foreground", children: run.id }), _jsx("span", { className: "text-xs text-muted-foreground", children: formatDate(run.startedAt) })] }) }), _jsxs("div", { className: "space-y-2 border-t px-4 py-3", children: [run.events.map((event) => (_jsxs("details", { className: "rounded-md border bg-muted/30 px-3 py-2", children: [_jsxs("summary", { className: "cursor-pointer text-xs font-medium text-foreground", children: ["#", event.seq, " ", eventLabel(event.event)] }), _jsx(RawBlock, { value: event.event, className: "mt-2 max-h-72" })] }, `${run.id}-${event.seq}`))), run.events.length === 0 ? (_jsx("div", { className: "text-sm text-muted-foreground", children: "No retained run events." })) : null] })] }, run.id)))) : (_jsx("div", { className: "rounded-lg border border-dashed px-4 py-8 text-center text-sm text-muted-foreground", children: "No retained runs." })) }), _jsx(TabsContent, { value: "internals", className: "mt-4 space-y-4", children: _jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [_jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-medium text-foreground", children: "Debug Runs" }), _jsx(RawBlock, { value: detail.debugRuns.length > 0
161
+ return (_jsxs("div", { className: "rounded-lg bg-card", children: [_jsxs("div", { className: "border-b px-4 py-3", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate text-base font-semibold text-foreground", children: detail.thread.title || detail.thread.preview || detail.thread.id }), _jsx("div", { className: "mt-1 truncate font-mono text-xs text-muted-foreground", children: detail.thread.id })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs(Badge, { variant: "secondary", children: [detail.messages.length, " messages"] }), _jsxs(Badge, { variant: "secondary", children: [detail.runs.length, " runs"] }), _jsx(Badge, { variant: "outline", children: detail.source.label })] })] }), _jsxs("div", { className: "mt-3 grid gap-2 text-xs text-muted-foreground sm:grid-cols-3", children: [_jsxs("div", { className: "truncate", children: ["Owner: ", detail.thread.ownerEmail] }), _jsxs("div", { children: ["Created: ", formatDate(detail.thread.createdAt)] }), _jsxs("div", { children: ["Updated: ", formatDate(detail.thread.updatedAt)] })] })] }), _jsxs(Tabs, { defaultValue: "transcript", className: "p-4", children: [_jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "transcript", children: "Transcript" }), _jsx(TabsTrigger, { value: "runs", children: "Runs" }), _jsx(TabsTrigger, { value: "internals", children: "Internals" }), _jsx(TabsTrigger, { value: "raw", children: "Raw" })] }), _jsx(TabsContent, { value: "transcript", className: "mt-4 space-y-3", children: detail.messages.length > 0 ? (detail.messages.map((message) => (_jsx(MessageBlock, { message: message }, message.id ?? `message-${message.index}`)))) : (_jsx("div", { className: "rounded-lg border border-dashed px-4 py-8 text-center text-sm text-muted-foreground", children: "No persisted messages." })) }), _jsx(TabsContent, { value: "runs", className: "mt-4 space-y-3", children: detail.runs.length > 0 ? (detail.runs.map((run) => (_jsxs("details", { className: "rounded-lg bg-card", children: [_jsx("summary", { className: "cursor-pointer px-4 py-3", children: _jsxs("div", { className: "inline-flex flex-wrap items-center gap-2", children: [_jsx(Badge, { variant: "outline", children: run.status }), _jsx("span", { className: "font-mono text-xs text-foreground", children: run.id }), run.errorCode ? (_jsx("span", { className: "font-mono text-xs text-destructive", children: run.errorCode })) : null, _jsx("span", { className: "text-xs text-muted-foreground", children: formatDate(run.startedAt) })] }) }), _jsxs("div", { className: "space-y-3 border-t px-4 py-3", children: [_jsxs("div", { className: "grid gap-2 text-xs sm:grid-cols-2 xl:grid-cols-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground", children: t("dispatch.pages.threadDebugFailureCode", {
162
+ defaultValue: "Failure code",
163
+ }) }), _jsx("div", { className: "mt-0.5 break-words font-mono text-foreground", children: run.errorCode || "n/a" })] }), _jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground", children: t("dispatch.pages.threadDebugTerminalReason", {
164
+ defaultValue: "Terminal reason",
165
+ }) }), _jsx("div", { className: "mt-0.5 break-words font-mono text-foreground", children: run.terminalReason || run.abortReason || "n/a" })] }), _jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground", children: t("dispatch.pages.threadDebugDispatchMode", {
166
+ defaultValue: "Dispatch mode",
167
+ }) }), _jsx("div", { className: "mt-0.5 break-words font-mono text-foreground", children: run.dispatchMode || "foreground" })] }), _jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground", children: t("dispatch.pages.threadDebugLastStage", {
168
+ defaultValue: "Last stage",
169
+ }) }), _jsx("div", { className: "mt-0.5 break-words font-mono text-foreground", children: diagnosticStage(run.workerStage) ||
170
+ diagnosticStage(run.diagStage) ||
171
+ "n/a" })] }), _jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground", children: t("dispatch.pages.threadDebugDuration", {
172
+ defaultValue: "Duration",
173
+ }) }), _jsx("div", { className: "mt-0.5 text-foreground", children: formatDuration(run.durationMs ??
174
+ (run.completedAt == null
175
+ ? null
176
+ : run.completedAt - run.startedAt)) })] }), _jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground", children: t("dispatch.pages.threadDebugLastProgress", {
177
+ defaultValue: "Last progress",
178
+ }) }), _jsx("div", { className: "mt-0.5 text-foreground", children: formatDate(run.lastProgressAt ?? run.heartbeatAt) })] })] }), run.errorDetail ? (_jsx("div", { className: "rounded-md bg-destructive/10 px-3 py-2 text-xs leading-relaxed text-destructive", children: run.errorDetail })) : null, run.events.map((event) => (_jsxs("details", { className: "rounded-md border bg-muted/30 px-3 py-2", children: [_jsxs("summary", { className: "cursor-pointer text-xs font-medium text-foreground", children: ["#", event.seq, " ", eventLabel(event.event)] }), _jsx(RawBlock, { value: event.event, className: "mt-2 max-h-72" })] }, `${run.id}-${event.seq}`))), run.events.length === 0 ? (_jsx("div", { className: "text-sm text-muted-foreground", children: "No retained run events." })) : null] })] }, run.id)))) : (_jsx("div", { className: "rounded-lg border border-dashed px-4 py-8 text-center text-sm text-muted-foreground", children: "No retained runs." })) }), _jsx(TabsContent, { value: "internals", className: "mt-4 space-y-4", children: _jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [_jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-medium text-foreground", children: "Debug Runs" }), _jsx(RawBlock, { value: detail.debugRuns.length > 0
86
179
  ? detail.debugRuns
87
180
  : (detail.debug ?? {}) })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-medium text-foreground", children: "Trace Summaries" }), _jsx(RawBlock, { value: detail.traces.summaries })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-medium text-foreground", children: "Trace Spans" }), _jsx(RawBlock, { value: detail.traces.spans })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-medium text-foreground", children: "Feedback And Evals" }), _jsx(RawBlock, { value: {
88
181
  feedback: detail.feedback,
@@ -92,91 +185,212 @@ function ThreadDetail({ detail }) {
92
185
  } })] })] }) }), _jsxs(TabsContent, { value: "raw", className: "mt-4 space-y-4", children: [_jsx(RawBlock, { value: rawBundle }), _jsx(RawBlock, { value: detail.rawThreadData })] })] })] }));
93
186
  }
94
187
  export default function ThreadDebugRoute() {
95
- const [routeSearchParams] = useSearchParams();
96
- const initialSourceId = routeSearchParams.get("source") || "current";
97
- const initialQuery = routeSearchParams.get("query") || "";
98
- const initialOwnerEmail = routeSearchParams.get("ownerEmail") || "";
99
- const [sourceId, setSourceId] = useState(initialSourceId);
100
- const [query, setQuery] = useState(initialQuery);
101
- const [ownerEmail, setOwnerEmail] = useState(initialOwnerEmail);
188
+ const t = useT();
189
+ const [routeSearchParams, setRouteSearchParams] = useSearchParams();
190
+ const mode = parseMode(routeSearchParams.get("mode"));
191
+ const sourceId = routeSearchParams.get("source") ||
192
+ (mode === "failures" ? "all" : "current");
193
+ const ownerEmail = routeSearchParams.get("owner") || "";
194
+ const query = routeSearchParams.get("query") || "";
195
+ const status = parseFailureStatus(routeSearchParams.get("status"));
196
+ const range = parseFailureRange(routeSearchParams.get("range"));
197
+ const runId = routeSearchParams.get("runId") || "";
198
+ const threadId = routeSearchParams.get("threadId") || "";
199
+ const inspectSourceId = routeSearchParams.get("inspectSource") || "";
102
200
  const [lookupId, setLookupId] = useState("");
103
- const [submittedSearch, setSubmittedSearch] = useState({
104
- sourceId: initialSourceId,
105
- query: initialQuery,
106
- ownerEmail: initialOwnerEmail,
107
- });
108
- const [selected, setSelected] = useState(null);
201
+ function updateRouteState(updates) {
202
+ const next = new URLSearchParams(routeSearchParams);
203
+ for (const [key, value] of Object.entries(updates)) {
204
+ if (value == null || value === "")
205
+ next.delete(key);
206
+ else
207
+ next.set(key, value);
208
+ }
209
+ setRouteSearchParams(next, { replace: true });
210
+ }
109
211
  const sourcesQuery = useActionQuery("list-agent-thread-sources", {});
110
212
  const { data: sourcesData, isLoading: sourcesLoading } = sourcesQuery;
111
213
  const sources = sourcesData?.sources ?? [];
214
+ const failureParams = useMemo(() => ({
215
+ sourceId,
216
+ ownerEmail: ownerEmail.trim() || undefined,
217
+ status,
218
+ lookbackHours: FAILURE_RANGE_HOURS[range],
219
+ limit: 25,
220
+ }), [ownerEmail, range, sourceId, status]);
221
+ const { data: failuresData, isLoading: failuresLoading, error: failuresError, refetch: refetchFailures, } = useActionQuery("list-agent-run-failures", failureParams, { enabled: mode === "failures" });
222
+ const failures = failuresData?.failures ?? [];
223
+ const unavailableFailureSources = (failuresData?.sources ?? []).filter((source) => source.status !== "ok");
224
+ const failureSourceStatusLabels = {
225
+ ok: "ok",
226
+ disconnected: t("dispatch.pages.threadDebugDisconnected", {
227
+ defaultValue: "disconnected",
228
+ }),
229
+ unsupported: t("dispatch.pages.threadDebugUnsupported", {
230
+ defaultValue: "unsupported",
231
+ }),
232
+ unavailable: t("dispatch.pages.threadDebugUnavailable", {
233
+ defaultValue: "unavailable",
234
+ }),
235
+ };
236
+ const threadSourceId = sourceId === "all" ? "current" : sourceId;
237
+ const detailSourceId = runId && inspectSourceId ? inspectSourceId : threadSourceId;
112
238
  const searchParams = useMemo(() => ({
113
- sourceId: submittedSearch.sourceId,
114
- query: submittedSearch.query || undefined,
115
- ownerEmail: submittedSearch.ownerEmail || undefined,
239
+ sourceId: threadSourceId,
240
+ query: query.trim() || undefined,
241
+ ownerEmail: ownerEmail.trim() || undefined,
116
242
  limit: 25,
117
- }), [submittedSearch]);
118
- const { data: searchData, isLoading: searchLoading, error: searchError, refetch: refetchSearch, } = useActionQuery("search-agent-threads", searchParams);
243
+ }), [ownerEmail, query, threadSourceId]);
244
+ const { data: searchData, isLoading: searchLoading, error: searchError, refetch: refetchSearch, } = useActionQuery("search-agent-threads", searchParams, { enabled: mode === "threads" });
119
245
  const searchThreads = searchData?.threads ?? [];
120
246
  const detailParams = useMemo(() => ({
121
- sourceId: selected?.sourceId ?? "current",
122
- ...(selected?.lookupKind === "run"
123
- ? { runId: selected.lookupId }
124
- : { threadId: selected?.lookupId ?? "" }),
125
- ownerEmail: selected?.ownerEmail,
247
+ sourceId: detailSourceId,
248
+ ...(runId ? { runId } : { threadId }),
249
+ ownerEmail: ownerEmail.trim() || undefined,
126
250
  maxRuns: 20,
127
251
  maxEvents: 800,
128
252
  maxTraceSpans: 600,
129
- }), [selected]);
253
+ }), [detailSourceId, ownerEmail, runId, threadId]);
130
254
  const { data: detail, isLoading: detailLoading, error: detailError, refetch: refetchDetail, } = useActionQuery("get-agent-thread-debug", detailParams, {
131
- enabled: Boolean(selected?.lookupId),
255
+ enabled: Boolean(runId || threadId),
132
256
  });
133
- const selectedSource = sources.find((source) => source.id === sourceId);
134
- useEffect(() => {
135
- fetch(agentNativePath("/_agent-native/application-state/navigation"), {
136
- method: "PUT",
137
- keepalive: true,
138
- headers: { "Content-Type": "application/json" },
139
- body: JSON.stringify({
140
- view: "thread-debug",
141
- path: typeof window === "undefined"
142
- ? "/thread-debug"
143
- : window.location.pathname,
144
- sourceId,
145
- query,
146
- ownerEmail: ownerEmail.trim() || undefined,
147
- threadId: selected?.lookupKind === "thread"
148
- ? selected.lookupId
149
- : !selected && lookupId.trim() && !lookupId.startsWith("run-")
150
- ? lookupId.trim()
151
- : undefined,
152
- runId: selected?.lookupKind === "run"
153
- ? selected.lookupId
154
- : !selected && lookupId.trim() && lookupId.startsWith("run-")
155
- ? lookupId.trim()
156
- : undefined,
157
- }),
158
- }).catch(() => { });
159
- }, [ownerEmail, query, selected, sourceId, lookupId]);
160
- return (_jsx(DispatchShell, { title: "Thread Debug", description: "Inspect persisted agent chat threads, run events, and AI internals.", children: _jsxs("div", { className: "space-y-4", children: [sourcesQuery.isError ? (_jsx(ActionQueryError, { error: sourcesQuery.error, onRetry: () => void sourcesQuery.refetch() })) : null, _jsxs("section", { className: "rounded-lg bg-card p-4", children: [_jsxs("div", { className: "grid gap-3 lg:grid-cols-[220px_1fr_260px_auto]", children: [_jsxs(Select, { value: sourceId, onValueChange: setSourceId, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Source" }) }), _jsxs(SelectContent, { children: [sources.map((source) => (_jsx(SelectItem, { value: source.id, children: source.label }, source.id))), sources.length === 0 ? (_jsx(SelectItem, { value: "current", children: "Current Dispatch DB" })) : null] })] }), _jsx(Input, { value: query, onChange: (event) => setQuery(event.target.value), placeholder: "Search title, preview, messages, tools" }), _jsx(Input, { value: ownerEmail, onChange: (event) => setOwnerEmail(event.target.value), placeholder: "Owner email" }), _jsxs(Button, { type: "button", onClick: () => setSubmittedSearch({
161
- sourceId,
162
- query: query.trim(),
163
- ownerEmail: ownerEmail.trim(),
164
- }), children: [_jsx(IconSearch, { size: 16 }), "Search"] })] }), _jsxs("div", { className: "mt-3 grid gap-3 lg:grid-cols-[1fr_auto]", children: [_jsx(Input, { value: lookupId, onChange: (event) => setLookupId(event.target.value), placeholder: "Paste thread or request/run ID", className: "font-mono" }), _jsxs(Button, { type: "button", variant: "outline", onClick: () => {
165
- const trimmed = lookupId.trim();
166
- if (!trimmed)
167
- return;
168
- setSelected({
169
- sourceId,
170
- lookupId: trimmed,
171
- lookupKind: trimmed.startsWith("run-") ? "run" : "thread",
172
- ownerEmail: ownerEmail.trim() || undefined,
173
- });
174
- }, children: [_jsx(IconFileSearch, { size: 16 }), "Inspect"] })] }), _jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2 text-xs text-muted-foreground", children: [sourcesLoading ? _jsx(Skeleton, { className: "h-5 w-32" }) : null, selectedSource ? _jsx(SourceBadge, { source: selectedSource }) : null, selectedSource?.databaseUrlEnv ? (_jsx(Badge, { variant: "outline", className: "font-mono", children: selectedSource.databaseUrlEnv })) : null, sourcesData?.access ? (_jsxs("span", { children: [sourcesData.access.viewerEmail, " \u00B7", " ", sourcesData.access.canInspectAll ? "admin scope" : "own scope"] })) : null] })] }), searchError ? (_jsx(ActionQueryError, { error: searchError, onRetry: () => void refetchSearch() })) : null, _jsxs("div", { className: "grid gap-4 xl:grid-cols-[380px_1fr]", children: [_jsxs("section", { className: "min-h-[520px] rounded-lg bg-card", children: [_jsxs("div", { className: "flex items-center justify-between border-b px-4 py-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-semibold text-foreground", children: "Threads" }), _jsxs("div", { className: "text-xs text-muted-foreground", children: [searchData?.count ?? 0, " results \u00B7", " ", searchData?.access?.scope ?? "current scope"] })] }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => refetchSearch(), "aria-label": "Refresh threads", children: _jsx(IconRefresh, { size: 16 }) })] }), _jsxs("div", { className: "max-h-[760px] space-y-2 overflow-auto p-3", children: [searchLoading ? (_jsxs(_Fragment, { children: [_jsx(Skeleton, { className: "h-28 w-full rounded-lg" }), _jsx(Skeleton, { className: "h-28 w-full rounded-lg" }), _jsx(Skeleton, { className: "h-28 w-full rounded-lg" })] })) : null, !searchLoading && searchThreads.length === 0 ? (_jsxs("div", { className: "flex min-h-64 flex-col items-center justify-center rounded-lg border border-dashed px-4 text-center text-sm text-muted-foreground", children: [_jsx(IconDatabase, { className: "mb-2 h-5 w-5" }), "No threads found."] })) : null, searchThreads.map((result) => (_jsx(ResultCard, { result: result, selected: selected?.lookupKind === "thread" &&
175
- selected.lookupId === result.id, onSelect: () => setSelected({
176
- sourceId: submittedSearch.sourceId,
177
- lookupId: result.id,
178
- lookupKind: "thread",
179
- ownerEmail: submittedSearch.ownerEmail || undefined,
180
- }) }, result.id)))] })] }), _jsxs("section", { className: "min-w-0", children: [detailError ? (_jsx(ActionQueryError, { error: detailError, onRetry: () => void refetchDetail() })) : null, detailLoading ? (_jsxs("div", { className: "rounded-lg bg-card p-4", children: [_jsx(Skeleton, { className: "h-6 w-72" }), _jsx(Skeleton, { className: "mt-3 h-4 w-96" }), _jsx(Skeleton, { className: "mt-6 h-[520px] w-full" })] })) : detail ? (_jsx(ThreadDetail, { detail: detail })) : (_jsxs("div", { className: "flex min-h-[520px] flex-col items-center justify-center rounded-lg border border-dashed bg-card px-4 text-center text-sm text-muted-foreground", children: [_jsx(IconFileSearch, { className: "mb-2 h-5 w-5" }), "Select or inspect a thread or request/run ID."] }))] })] })] }) }));
257
+ const selectedSource = sources.find((source) => source.id === threadSourceId);
258
+ const detailPane = (_jsxs("section", { className: "min-w-0", children: [detailError ? (_jsx(ActionQueryError, { error: detailError, onRetry: () => void refetchDetail() })) : null, detailLoading ? (_jsxs("div", { className: "rounded-lg bg-card p-4", children: [_jsx(Skeleton, { className: "h-6 w-72" }), _jsx(Skeleton, { className: "mt-3 h-4 w-96" }), _jsx(Skeleton, { className: "mt-6 h-[520px] w-full" })] })) : detail ? (_jsx(ThreadDetail, { detail: detail })) : (_jsxs("div", { className: "flex min-h-[520px] flex-col items-center justify-center rounded-lg border border-dashed bg-card px-4 text-center text-sm text-muted-foreground", children: [_jsx(IconFileSearch, { className: "mb-2 size-5" }), t("dispatch.pages.threadDebugSelectPrompt", {
259
+ defaultValue: "Select a failed run or thread to inspect.",
260
+ })] }))] }));
261
+ return (_jsx(DispatchShell, { title: t("dispatch.pages.threadDebugTitle", {
262
+ defaultValue: "Thread Debug",
263
+ }), description: t("dispatch.pages.threadDebugDescription", {
264
+ defaultValue: "Inspect failed agent runs, persisted threads, run events, and AI internals.",
265
+ }), children: _jsxs("div", { className: "space-y-4", children: [sourcesQuery.isError ? (_jsx(ActionQueryError, { error: sourcesQuery.error, onRetry: () => void sourcesQuery.refetch() })) : null, _jsxs(Tabs, { value: mode, onValueChange: (value) => {
266
+ const nextMode = parseMode(value);
267
+ updateRouteState({
268
+ mode: nextMode,
269
+ source: nextMode === "threads" && sourceId === "all"
270
+ ? "current"
271
+ : sourceId,
272
+ runId: null,
273
+ threadId: null,
274
+ inspectSource: null,
275
+ });
276
+ }, children: [_jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "failures", children: t("dispatch.pages.threadDebugFailedRuns", {
277
+ defaultValue: "Failed runs",
278
+ }) }), _jsx(TabsTrigger, { value: "threads", children: t("dispatch.pages.threadDebugThreads", {
279
+ defaultValue: "Threads",
280
+ }) })] }), _jsxs(TabsContent, { value: "failures", className: "mt-4 space-y-4", children: [_jsxs("section", { className: "rounded-lg bg-card p-4", children: [_jsxs("div", { className: "grid gap-3 md:grid-cols-2 xl:grid-cols-[220px_1fr_180px_150px]", children: [_jsxs(Select, { value: sourceId, onValueChange: (value) => updateRouteState({
281
+ source: value,
282
+ runId: null,
283
+ threadId: null,
284
+ inspectSource: null,
285
+ }), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: t("dispatch.pages.threadDebugSource", {
286
+ defaultValue: "Source",
287
+ }) }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: t("dispatch.pages.threadDebugAllSources", {
288
+ defaultValue: "All sources",
289
+ }) }), sources.map((source) => (_jsx(SelectItem, { value: source.id, children: source.label }, source.id)))] })] }), _jsx(Input, { value: ownerEmail, onChange: (event) => updateRouteState({ owner: event.target.value }), placeholder: t("dispatch.pages.threadDebugOwner", {
290
+ defaultValue: "Owner email",
291
+ }) }), _jsxs(Select, { value: status, onValueChange: (value) => updateRouteState({
292
+ status: parseFailureStatus(value),
293
+ runId: null,
294
+ inspectSource: null,
295
+ }), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: t("dispatch.pages.threadDebugStatus", {
296
+ defaultValue: "Status",
297
+ }) }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: t("dispatch.pages.threadDebugAllStatuses", {
298
+ defaultValue: "All statuses",
299
+ }) }), _jsx(SelectItem, { value: "errored", children: t("dispatch.pages.threadDebugErrored", {
300
+ defaultValue: "Errored",
301
+ }) }), _jsx(SelectItem, { value: "aborted", children: t("dispatch.pages.threadDebugAborted", {
302
+ defaultValue: "Aborted",
303
+ }) }), _jsx(SelectItem, { value: "truncated", children: t("dispatch.pages.threadDebugTruncated", {
304
+ defaultValue: "Truncated",
305
+ }) })] })] }), _jsxs(Select, { value: range, onValueChange: (value) => updateRouteState({
306
+ range: parseFailureRange(value),
307
+ runId: null,
308
+ inspectSource: null,
309
+ }), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: t("dispatch.pages.threadDebugRange", {
310
+ defaultValue: "Time range",
311
+ }) }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "24h", children: t("dispatch.pages.threadDebugRange24h", {
312
+ defaultValue: "Last 24 hours",
313
+ }) }), _jsx(SelectItem, { value: "7d", children: t("dispatch.pages.threadDebugRange7d", {
314
+ defaultValue: "Last 7 days",
315
+ }) }), _jsx(SelectItem, { value: "30d", children: t("dispatch.pages.threadDebugRange30d", {
316
+ defaultValue: "Last 30 days",
317
+ }) })] })] })] }), _jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2 text-xs text-muted-foreground", children: [_jsxs("span", { children: [failuresData?.count ?? failures.length, " ", t("dispatch.pages.threadDebugFailureResults", {
318
+ defaultValue: "failed runs",
319
+ })] }), _jsx("span", { children: "\u00B7" }), _jsx("span", { children: failuresData?.access?.scope ??
320
+ t("dispatch.pages.threadDebugCurrentScope", {
321
+ defaultValue: "current scope",
322
+ }) }), failuresData?.partial ? (_jsx(Badge, { variant: "outline", children: t("dispatch.pages.threadDebugPartialResults", {
323
+ defaultValue: "Partial results",
324
+ }) })) : null] }), unavailableFailureSources.length > 0 ? (_jsxs("div", { className: "mt-2 flex items-start gap-1.5 text-xs text-muted-foreground", children: [_jsx(IconAlertTriangle, { className: "mt-0.5 size-3.5 shrink-0" }), _jsxs("span", { children: [t("dispatch.pages.threadDebugUnavailableSources", {
325
+ defaultValue: "Unavailable sources:",
326
+ }), " ", unavailableFailureSources
327
+ .map(({ source, status: sourceStatus }) => `${source.label} (${failureSourceStatusLabels[sourceStatus]})`)
328
+ .join(", ")] })] })) : null] }), failuresError ? (_jsx(ActionQueryError, { error: failuresError, onRetry: () => void refetchFailures() })) : null, _jsxs("div", { className: "grid gap-4 xl:grid-cols-[380px_1fr]", children: [_jsxs("section", { className: "min-h-[520px] rounded-lg bg-card", children: [_jsxs("div", { className: "flex items-center justify-between border-b px-4 py-3", children: [_jsx("div", { className: "text-sm font-semibold text-foreground", children: t("dispatch.pages.threadDebugFailedRuns", {
329
+ defaultValue: "Failed runs",
330
+ }) }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => void refetchFailures(), "aria-label": t("dispatch.pages.threadDebugRefreshFailures", {
331
+ defaultValue: "Refresh failed runs",
332
+ }), children: _jsx(IconRefresh, { className: "size-4" }) })] }), _jsxs("div", { className: "max-h-[760px] space-y-2 overflow-auto p-3", children: [failuresLoading ? (_jsxs(_Fragment, { children: [_jsx(Skeleton, { className: "h-32 w-full rounded-lg" }), _jsx(Skeleton, { className: "h-32 w-full rounded-lg" }), _jsx(Skeleton, { className: "h-32 w-full rounded-lg" })] })) : null, !failuresLoading && failures.length === 0 ? (_jsxs("div", { className: "flex min-h-64 flex-col items-center justify-center rounded-lg border border-dashed px-4 text-center text-sm text-muted-foreground", children: [_jsx(IconDatabase, { className: "mb-2 size-5" }), t("dispatch.pages.threadDebugNoFailures", {
333
+ defaultValue: "No failed runs found.",
334
+ })] })) : null, failures.map((failure) => (_jsx(FailureCard, { failure: failure, selected: runId === failure.id &&
335
+ detailSourceId === failureSourceId(failure), onSelect: () => updateRouteState({
336
+ inspectSource: failureSourceId(failure),
337
+ runId: failure.id,
338
+ threadId: null,
339
+ }) }, `${failureSourceId(failure)}:${failure.id}`)))] })] }), detailPane] })] }), _jsxs(TabsContent, { value: "threads", className: "mt-4 space-y-4", children: [_jsxs("section", { className: "rounded-lg bg-card p-4", children: [_jsxs("div", { className: "grid gap-3 lg:grid-cols-[220px_1fr_260px_auto]", children: [_jsxs(Select, { value: threadSourceId, onValueChange: (value) => updateRouteState({
340
+ source: value,
341
+ runId: null,
342
+ threadId: null,
343
+ inspectSource: null,
344
+ }), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: t("dispatch.pages.threadDebugSource", {
345
+ defaultValue: "Source",
346
+ }) }) }), _jsxs(SelectContent, { children: [sources.map((source) => (_jsx(SelectItem, { value: source.id, children: source.label }, source.id))), sources.length === 0 ? (_jsx(SelectItem, { value: "current", children: t("dispatch.pages.threadDebugCurrentDatabase", {
347
+ defaultValue: "Current Dispatch DB",
348
+ }) })) : null] })] }), _jsx(Input, { value: query, onChange: (event) => updateRouteState({ query: event.target.value }), placeholder: t("dispatch.pages.threadDebugSearchPlaceholder", {
349
+ defaultValue: "Search title, preview, messages, tools",
350
+ }) }), _jsx(Input, { value: ownerEmail, onChange: (event) => updateRouteState({ owner: event.target.value }), placeholder: t("dispatch.pages.threadDebugOwner", {
351
+ defaultValue: "Owner email",
352
+ }) }), _jsxs(Button, { type: "button", onClick: () => void refetchSearch(), children: [_jsx(IconSearch, { className: "size-4" }), t("dispatch.pages.threadDebugSearch", {
353
+ defaultValue: "Search",
354
+ })] })] }), _jsxs("div", { className: "mt-3 grid gap-3 lg:grid-cols-[1fr_auto]", children: [_jsx(Input, { value: lookupId, onChange: (event) => setLookupId(event.target.value), placeholder: t("dispatch.pages.threadDebugLookupPlaceholder", {
355
+ defaultValue: "Paste thread or request/run ID",
356
+ }), className: "font-mono" }), _jsxs(Button, { type: "button", variant: "outline", onClick: () => {
357
+ const trimmed = lookupId.trim();
358
+ if (!trimmed)
359
+ return;
360
+ updateRouteState(trimmed.startsWith("run-")
361
+ ? {
362
+ runId: trimmed,
363
+ threadId: null,
364
+ inspectSource: null,
365
+ }
366
+ : {
367
+ threadId: trimmed,
368
+ runId: null,
369
+ inspectSource: null,
370
+ });
371
+ }, children: [_jsx(IconFileSearch, { className: "size-4" }), t("dispatch.pages.threadDebugInspect", {
372
+ defaultValue: "Inspect",
373
+ })] })] }), _jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2 text-xs text-muted-foreground", children: [sourcesLoading ? _jsx(Skeleton, { className: "h-5 w-32" }) : null, selectedSource ? (_jsx(SourceBadge, { source: selectedSource })) : null, selectedSource?.databaseUrlEnv ? (_jsx(Badge, { variant: "outline", className: "font-mono", children: selectedSource.databaseUrlEnv })) : null, sourcesData?.access ? (_jsxs("span", { children: [sourcesData.access.viewerEmail, " \u00B7", " ", sourcesData.access.canInspectAll
374
+ ? t("dispatch.pages.threadDebugAdminScope", {
375
+ defaultValue: "admin scope",
376
+ })
377
+ : t("dispatch.pages.threadDebugOwnScope", {
378
+ defaultValue: "own scope",
379
+ })] })) : null] })] }), searchError ? (_jsx(ActionQueryError, { error: searchError, onRetry: () => void refetchSearch() })) : null, _jsxs("div", { className: "grid gap-4 xl:grid-cols-[380px_1fr]", children: [_jsxs("section", { className: "min-h-[520px] rounded-lg bg-card", children: [_jsxs("div", { className: "flex items-center justify-between border-b px-4 py-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-semibold text-foreground", children: t("dispatch.pages.threadDebugThreads", {
380
+ defaultValue: "Threads",
381
+ }) }), _jsxs("div", { className: "text-xs text-muted-foreground", children: [searchData?.count ?? 0, " ", t("dispatch.pages.threadDebugResults", {
382
+ defaultValue: "results",
383
+ }), " ", "\u00B7", " ", searchData?.access?.scope ??
384
+ t("dispatch.pages.threadDebugCurrentScope", {
385
+ defaultValue: "current scope",
386
+ })] })] }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => void refetchSearch(), "aria-label": t("dispatch.pages.threadDebugRefreshThreads", {
387
+ defaultValue: "Refresh threads",
388
+ }), children: _jsx(IconRefresh, { className: "size-4" }) })] }), _jsxs("div", { className: "max-h-[760px] space-y-2 overflow-auto p-3", children: [searchLoading ? (_jsxs(_Fragment, { children: [_jsx(Skeleton, { className: "h-28 w-full rounded-lg" }), _jsx(Skeleton, { className: "h-28 w-full rounded-lg" }), _jsx(Skeleton, { className: "h-28 w-full rounded-lg" })] })) : null, !searchLoading && searchThreads.length === 0 ? (_jsxs("div", { className: "flex min-h-64 flex-col items-center justify-center rounded-lg border border-dashed px-4 text-center text-sm text-muted-foreground", children: [_jsx(IconDatabase, { className: "mb-2 size-5" }), t("dispatch.pages.threadDebugNoThreads", {
389
+ defaultValue: "No threads found.",
390
+ })] })) : null, searchThreads.map((result) => (_jsx(ResultCard, { result: result, selected: threadId === result.id, onSelect: () => updateRouteState({
391
+ threadId: result.id,
392
+ runId: null,
393
+ inspectSource: null,
394
+ }) }, result.id)))] })] }), detailPane] })] })] })] }) }));
181
395
  }
182
396
  //# sourceMappingURL=thread-debug.js.map