@agent-native/core 0.35.3 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +249 -11
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +25 -25
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +32 -15
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +68 -24
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.js +174 -8
- package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
- package/dist/client/composer/PromptComposer.d.ts +2 -0
- package/dist/client/composer/PromptComposer.d.ts.map +1 -1
- package/dist/client/composer/PromptComposer.js +2 -2
- package/dist/client/composer/PromptComposer.js.map +1 -1
- package/dist/client/composer/TiptapComposer.js +1 -1
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/context-xray/ContextMeter.d.ts +2 -1
- package/dist/client/context-xray/ContextMeter.d.ts.map +1 -1
- package/dist/client/context-xray/ContextMeter.js +19 -25
- package/dist/client/context-xray/ContextMeter.js.map +1 -1
- package/dist/client/context-xray/ContextXRayPanel.d.ts +1 -3
- package/dist/client/context-xray/ContextXRayPanel.d.ts.map +1 -1
- package/dist/client/context-xray/ContextXRayPanel.js +27 -24
- package/dist/client/context-xray/ContextXRayPanel.js.map +1 -1
- package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
- package/dist/client/conversation/AgentConversation.js +2 -1
- package/dist/client/conversation/AgentConversation.js.map +1 -1
- package/dist/client/dynamic-suggestions.d.ts +13 -7
- package/dist/client/dynamic-suggestions.d.ts.map +1 -1
- package/dist/client/dynamic-suggestions.js +23 -12
- package/dist/client/dynamic-suggestions.js.map +1 -1
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/route-state.d.ts +116 -0
- package/dist/client/route-state.d.ts.map +1 -0
- package/dist/client/route-state.js +205 -0
- package/dist/client/route-state.js.map +1 -0
- package/dist/client/sse-event-processor.d.ts +1 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +62 -15
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/tool-display.d.ts +4 -0
- package/dist/client/tool-display.d.ts.map +1 -0
- package/dist/client/tool-display.js +28 -0
- package/dist/client/tool-display.js.map +1 -0
- package/dist/client/use-chat-threads.d.ts.map +1 -1
- package/dist/client/use-chat-threads.js +40 -31
- package/dist/client/use-chat-threads.js.map +1 -1
- package/dist/client/use-external-value.d.ts.map +1 -1
- package/dist/client/use-external-value.js +14 -7
- package/dist/client/use-external-value.js.map +1 -1
- package/dist/extensions/html-shell.d.ts +3 -2
- package/dist/extensions/html-shell.d.ts.map +1 -1
- package/dist/extensions/html-shell.js +12 -2
- package/dist/extensions/html-shell.js.map +1 -1
- package/dist/extensions/routes.js +2 -7
- package/dist/extensions/routes.js.map +1 -1
- package/dist/server/core-routes-plugin.js +2 -2
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/security-headers.d.ts +16 -19
- package/dist/server/security-headers.d.ts.map +1 -1
- package/dist/server/security-headers.js +24 -25
- package/dist/server/security-headers.js.map +1 -1
- package/dist/templates/default/AGENTS.md +7 -1
- package/dist/templates/default/app/hooks/use-navigation-state.ts +10 -76
- package/docs/content/context-awareness.md +90 -48
- package/docs/content/creating-templates.md +22 -1
- package/docs/content/external-agents.md +1 -1
- package/package.json +2 -1
- package/src/templates/default/AGENTS.md +7 -1
- package/src/templates/default/app/hooks/use-navigation-state.ts +10 -76
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
2
|
+
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import { useLocation, useNavigate, } from "react-router";
|
|
4
|
+
import { deleteClientAppState, readClientAppState, setClientAppState, } from "./application-state.js";
|
|
5
|
+
const SAFE_BROWSER_TAB_ID_RE = /^[A-Za-z0-9_-]{1,96}$/;
|
|
6
|
+
function normalizeBrowserTabId(browserTabId) {
|
|
7
|
+
if (typeof browserTabId !== "string")
|
|
8
|
+
return undefined;
|
|
9
|
+
const trimmed = browserTabId.trim();
|
|
10
|
+
return SAFE_BROWSER_TAB_ID_RE.test(trimmed) ? trimmed : undefined;
|
|
11
|
+
}
|
|
12
|
+
function appStateKeyForBrowserTab(key, browserTabId) {
|
|
13
|
+
return browserTabId ? `${key}:${browserTabId}` : key;
|
|
14
|
+
}
|
|
15
|
+
function routeLocationFromReactRouter(location) {
|
|
16
|
+
return {
|
|
17
|
+
pathname: location.pathname,
|
|
18
|
+
search: location.search,
|
|
19
|
+
hash: location.hash,
|
|
20
|
+
searchParams: new URLSearchParams(location.search),
|
|
21
|
+
location,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function uniqueKeys(keys) {
|
|
25
|
+
return Array.from(new Set(keys));
|
|
26
|
+
}
|
|
27
|
+
function defaultCommandDedupKey(command) {
|
|
28
|
+
if (command && typeof command === "object" && "_writeId" in command) {
|
|
29
|
+
const writeId = command._writeId;
|
|
30
|
+
if (typeof writeId === "string" && writeId)
|
|
31
|
+
return writeId;
|
|
32
|
+
}
|
|
33
|
+
return JSON.stringify(command);
|
|
34
|
+
}
|
|
35
|
+
function currentRouterPath(location) {
|
|
36
|
+
return `${location.pathname}${location.search}${location.hash}`;
|
|
37
|
+
}
|
|
38
|
+
function stringifyForWriteDedup(value) {
|
|
39
|
+
try {
|
|
40
|
+
return JSON.stringify(value);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return "";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Keeps semantic UI state agent-visible and consumes agent-authored one-shot
|
|
48
|
+
* commands. This is the framework primitive behind route/navigation sync; it
|
|
49
|
+
* intentionally knows nothing about app-specific route shapes.
|
|
50
|
+
*/
|
|
51
|
+
export function useSemanticNavigationState(options) {
|
|
52
|
+
const { requestSource, commandRefetchInterval = 2_000, enabled = true, keepalive = true, writeDebounceMs = 0, } = options;
|
|
53
|
+
const queryClient = useQueryClient();
|
|
54
|
+
const navigationKeys = useMemo(() => uniqueKeys(options.navigationKeys ?? ["navigation"]), [options.navigationKeys]);
|
|
55
|
+
const commandKeys = useMemo(() => uniqueKeys(options.commandKeys ?? ["navigate"]), [options.commandKeys]);
|
|
56
|
+
const commandQueryKey = useMemo(() => options.commandQueryKey ?? ["navigate-command"], [options.commandQueryKey]);
|
|
57
|
+
const navigationState = options.state ?? null;
|
|
58
|
+
const navigationWriteDedup = stringifyForWriteDedup({
|
|
59
|
+
keys: navigationKeys,
|
|
60
|
+
state: navigationState,
|
|
61
|
+
});
|
|
62
|
+
const getCommandDedupKeyRef = useRef(options.getCommandDedupKey);
|
|
63
|
+
const onCommandRef = useRef(options.onCommand);
|
|
64
|
+
const onErrorRef = useRef(options.onError);
|
|
65
|
+
getCommandDedupKeyRef.current = options.getCommandDedupKey;
|
|
66
|
+
onCommandRef.current = options.onCommand;
|
|
67
|
+
onErrorRef.current = options.onError;
|
|
68
|
+
const lastNavigationWriteRef = useRef(null);
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (!enabled)
|
|
71
|
+
return;
|
|
72
|
+
if (lastNavigationWriteRef.current === navigationWriteDedup)
|
|
73
|
+
return;
|
|
74
|
+
lastNavigationWriteRef.current = navigationWriteDedup;
|
|
75
|
+
const write = () => {
|
|
76
|
+
for (const key of navigationKeys) {
|
|
77
|
+
setClientAppState(key, navigationState, {
|
|
78
|
+
keepalive,
|
|
79
|
+
requestSource,
|
|
80
|
+
}).catch((error) => onErrorRef.current?.(error));
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
if (writeDebounceMs > 0) {
|
|
84
|
+
const timer = setTimeout(write, writeDebounceMs);
|
|
85
|
+
return () => clearTimeout(timer);
|
|
86
|
+
}
|
|
87
|
+
write();
|
|
88
|
+
}, [
|
|
89
|
+
enabled,
|
|
90
|
+
keepalive,
|
|
91
|
+
navigationKeys,
|
|
92
|
+
navigationState,
|
|
93
|
+
navigationWriteDedup,
|
|
94
|
+
requestSource,
|
|
95
|
+
writeDebounceMs,
|
|
96
|
+
]);
|
|
97
|
+
const commandQuery = useQuery({
|
|
98
|
+
queryKey: commandQueryKey,
|
|
99
|
+
enabled,
|
|
100
|
+
retry: false,
|
|
101
|
+
refetchInterval: commandRefetchInterval,
|
|
102
|
+
queryFn: async () => {
|
|
103
|
+
for (const key of commandKeys) {
|
|
104
|
+
const command = await readClientAppState(key);
|
|
105
|
+
if (command !== null && command !== undefined) {
|
|
106
|
+
return { key, command };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
const clearCommand = useCallback(async () => {
|
|
113
|
+
await Promise.all(commandKeys.map((key) => deleteClientAppState(key, { requestSource }).catch((error) => {
|
|
114
|
+
onErrorRef.current?.(error);
|
|
115
|
+
})));
|
|
116
|
+
queryClient.setQueryData(commandQueryKey, null);
|
|
117
|
+
}, [commandKeys, commandQueryKey, queryClient, requestSource]);
|
|
118
|
+
const lastProcessedDedupKeyRef = useRef(null);
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
const envelope = commandQuery.data;
|
|
121
|
+
if (!enabled || !envelope)
|
|
122
|
+
return;
|
|
123
|
+
const dedupKey = getCommandDedupKeyRef.current?.(envelope.command) ??
|
|
124
|
+
defaultCommandDedupKey(envelope.command);
|
|
125
|
+
const consume = () => {
|
|
126
|
+
deleteClientAppState(envelope.key, { requestSource }).catch((error) => onErrorRef.current?.(error));
|
|
127
|
+
queryClient.setQueryData(commandQueryKey, null);
|
|
128
|
+
};
|
|
129
|
+
if (lastProcessedDedupKeyRef.current === dedupKey) {
|
|
130
|
+
consume();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
lastProcessedDedupKeyRef.current = dedupKey;
|
|
134
|
+
consume();
|
|
135
|
+
Promise.resolve(onCommandRef.current(envelope.command)).catch((error) => onErrorRef.current?.(error));
|
|
136
|
+
}, [commandQuery.data, commandQueryKey, enabled, queryClient, requestSource]);
|
|
137
|
+
return {
|
|
138
|
+
navigationState,
|
|
139
|
+
command: commandQuery.data,
|
|
140
|
+
commandQueryKey,
|
|
141
|
+
clearCommand,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* React Router convenience wrapper around `useSemanticNavigationState`.
|
|
146
|
+
*
|
|
147
|
+
* Use URL query params as the source of truth for shareable filters. This hook
|
|
148
|
+
* writes semantic aliases and stable IDs to `navigation`; the framework's
|
|
149
|
+
* built-in URL sync separately exposes raw `pathname`, `search`, and
|
|
150
|
+
* `searchParams` through `<current-url>` and the `set-search-params` tool.
|
|
151
|
+
*/
|
|
152
|
+
export function useAgentRouteState(options) {
|
|
153
|
+
const { navigationKey = "navigation", commandKey = "navigate", writeGlobalNavigation = true, readGlobalCommandFallback = true, } = options;
|
|
154
|
+
const location = useLocation();
|
|
155
|
+
const navigate = useNavigate();
|
|
156
|
+
const browserTabId = useMemo(() => normalizeBrowserTabId(options.browserTabId), [options.browserTabId]);
|
|
157
|
+
const navigationKeys = useMemo(() => {
|
|
158
|
+
const scopedKey = appStateKeyForBrowserTab(navigationKey, browserTabId);
|
|
159
|
+
const keys = [scopedKey];
|
|
160
|
+
if (browserTabId && writeGlobalNavigation)
|
|
161
|
+
keys.push(navigationKey);
|
|
162
|
+
return uniqueKeys(keys);
|
|
163
|
+
}, [browserTabId, navigationKey, writeGlobalNavigation]);
|
|
164
|
+
const commandKeys = useMemo(() => {
|
|
165
|
+
const scopedKey = appStateKeyForBrowserTab(commandKey, browserTabId);
|
|
166
|
+
const keys = [scopedKey];
|
|
167
|
+
if (browserTabId && readGlobalCommandFallback)
|
|
168
|
+
keys.push(commandKey);
|
|
169
|
+
return uniqueKeys(keys);
|
|
170
|
+
}, [browserTabId, commandKey, readGlobalCommandFallback]);
|
|
171
|
+
const commandQueryKey = useMemo(() => options.commandQueryKey ?? [
|
|
172
|
+
"navigate-command",
|
|
173
|
+
commandKey,
|
|
174
|
+
browserTabId ?? "global",
|
|
175
|
+
], [browserTabId, commandKey, options.commandQueryKey]);
|
|
176
|
+
const routeLocation = useMemo(() => routeLocationFromReactRouter(location), [location]);
|
|
177
|
+
const navigationState = options.getNavigationState(routeLocation) ?? null;
|
|
178
|
+
return useSemanticNavigationState({
|
|
179
|
+
state: navigationState,
|
|
180
|
+
navigationKeys,
|
|
181
|
+
commandKeys,
|
|
182
|
+
commandQueryKey,
|
|
183
|
+
requestSource: options.requestSource,
|
|
184
|
+
commandRefetchInterval: options.refetchInterval,
|
|
185
|
+
enabled: options.enabled,
|
|
186
|
+
keepalive: options.keepalive,
|
|
187
|
+
writeDebounceMs: options.writeDebounceMs,
|
|
188
|
+
getCommandDedupKey: options.getCommandDedupKey,
|
|
189
|
+
onError: options.onError,
|
|
190
|
+
onCommand: (command) => {
|
|
191
|
+
const path = options.getCommandPath(command);
|
|
192
|
+
if (!path)
|
|
193
|
+
return;
|
|
194
|
+
options.onNavigate?.(command, path);
|
|
195
|
+
if (path === currentRouterPath(location))
|
|
196
|
+
return;
|
|
197
|
+
const navigateOptions = options.navigateOptions;
|
|
198
|
+
const resolvedOptions = typeof navigateOptions === "function"
|
|
199
|
+
? navigateOptions(command)
|
|
200
|
+
: navigateOptions;
|
|
201
|
+
navigate(path, resolvedOptions);
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=route-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-state.js","sourceRoot":"","sources":["../../src/client/route-state.ts"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { useQuery, useQueryClient, type QueryKey } from \"@tanstack/react-query\";\nimport {\n useLocation,\n useNavigate,\n type Location,\n type NavigateOptions,\n} from \"react-router\";\nimport {\n deleteClientAppState,\n readClientAppState,\n setClientAppState,\n} from \"./application-state.js\";\n\nconst SAFE_BROWSER_TAB_ID_RE = /^[A-Za-z0-9_-]{1,96}$/;\n\nexport interface SemanticNavigationCommandEnvelope<NavigateCommand> {\n key: string;\n command: NavigateCommand;\n}\n\nexport interface UseSemanticNavigationStateOptions<\n NavigationState,\n NavigateCommand = NavigationState,\n> {\n /**\n * Compact, semantic screen state to expose to the agent: view names, record\n * IDs, active tabs, and useful aliases. Keep URL query params in the URL\n * unless the app needs a human-readable semantic alias.\n */\n state: NavigationState | null | undefined;\n /** Application-state keys the UI should write. Defaults to [`navigation`]. */\n navigationKeys?: readonly string[];\n /** Application-state keys to read for one-shot agent commands. Defaults to [`navigate`]. */\n commandKeys?: readonly string[];\n /** React Query key used for command polling/cache. Defaults to [`navigate-command`]. */\n commandQueryKey?: QueryKey;\n /** Request source tag for `useDbSync({ ignoreSource })` jitter prevention. */\n requestSource?: string;\n /** Poll interval for command reads. Defaults to 2000ms. Pass false to disable polling. */\n commandRefetchInterval?: number | false;\n /** Disable both navigation writes and command reads. */\n enabled?: boolean;\n /** Navigation writes use keepalive by default because they often fire during unload. */\n keepalive?: boolean;\n /** Debounce navigation writes. Defaults to 0ms. */\n writeDebounceMs?: number;\n /** Custom duplicate-command key. Defaults to `_writeId` or JSON content. */\n getCommandDedupKey?: (command: NavigateCommand) => string;\n /** Called once for each non-duplicate command after the command is consumed. */\n onCommand: (command: NavigateCommand) => void | Promise<void>;\n /** Optional sink for best-effort navigation write/read/delete/command errors. */\n onError?: (error: unknown) => void;\n}\n\nexport interface UseSemanticNavigationStateResult<\n NavigationState,\n NavigateCommand = NavigationState,\n> {\n navigationState: NavigationState | null;\n command:\n | SemanticNavigationCommandEnvelope<NavigateCommand>\n | null\n | undefined;\n commandQueryKey: QueryKey;\n clearCommand: () => Promise<void>;\n}\n\nexport interface AgentRouteLocation {\n pathname: string;\n search: string;\n hash: string;\n searchParams: URLSearchParams;\n location: Location;\n}\n\nexport interface UseAgentRouteStateOptions<\n NavigationState,\n NavigateCommand = NavigationState,\n> {\n /**\n * Derive compact, semantic screen state from the current React Router URL.\n * The framework separately exposes raw `pathname`, `search`, and parsed\n * `searchParams` through `<current-url>`.\n */\n getNavigationState: (\n location: AgentRouteLocation,\n ) => NavigationState | null | undefined;\n /**\n * Convert an agent-authored one-shot command into an app-local React Router\n * path. Return null to consume and ignore malformed or unsupported commands.\n */\n getCommandPath: (command: NavigateCommand) => string | null | undefined;\n /** Application-state key the UI writes. Defaults to `navigation`. */\n navigationKey?: string;\n /** Application-state key the agent writes for one-shot navigation. */\n commandKey?: string;\n /** Current browser tab id. Enables tab-scoped reads/writes. */\n browserTabId?: string;\n /** Request source tag for `useDbSync({ ignoreSource })` jitter prevention. */\n requestSource?: string;\n /**\n * Also write the unscoped navigation key when browserTabId is present.\n * Defaults to true so CLI/external agents still have a useful fallback.\n */\n writeGlobalNavigation?: boolean;\n /**\n * Fall back to the unscoped command key when no tab-scoped command exists.\n * Defaults to true for backwards compatibility with existing navigate tools.\n */\n readGlobalCommandFallback?: boolean;\n /** React Query key used for command polling/cache. */\n commandQueryKey?: QueryKey;\n /** Poll interval for command reads. Defaults to 2000ms. Pass false to disable polling. */\n refetchInterval?: number | false;\n /** Disable both navigation writes and command reads. */\n enabled?: boolean;\n /** Navigation writes use keepalive by default because they often fire during unload. */\n keepalive?: boolean;\n /** Debounce navigation writes. Defaults to 0ms. */\n writeDebounceMs?: number;\n /** Custom duplicate-command key. Defaults to `_writeId` or JSON content. */\n getCommandDedupKey?: (command: NavigateCommand) => string;\n /** React Router navigate options, or a function of the consumed command. */\n navigateOptions?:\n | NavigateOptions\n | ((command: NavigateCommand) => NavigateOptions | undefined);\n /** Called after a command is consumed and before React Router navigation. */\n onNavigate?: (command: NavigateCommand, path: string) => void;\n /** Optional sink for best-effort navigation write/read/delete errors. */\n onError?: (error: unknown) => void;\n}\n\nexport interface UseAgentRouteStateResult<\n NavigationState,\n NavigateCommand = NavigationState,\n> extends UseSemanticNavigationStateResult<NavigationState, NavigateCommand> {}\n\nfunction normalizeBrowserTabId(browserTabId?: string): string | undefined {\n if (typeof browserTabId !== \"string\") return undefined;\n const trimmed = browserTabId.trim();\n return SAFE_BROWSER_TAB_ID_RE.test(trimmed) ? trimmed : undefined;\n}\n\nfunction appStateKeyForBrowserTab(key: string, browserTabId?: string): string {\n return browserTabId ? `${key}:${browserTabId}` : key;\n}\n\nfunction routeLocationFromReactRouter(location: Location): AgentRouteLocation {\n return {\n pathname: location.pathname,\n search: location.search,\n hash: location.hash,\n searchParams: new URLSearchParams(location.search),\n location,\n };\n}\n\nfunction uniqueKeys(keys: readonly string[]): string[] {\n return Array.from(new Set(keys));\n}\n\nfunction defaultCommandDedupKey(command: unknown): string {\n if (command && typeof command === \"object\" && \"_writeId\" in command) {\n const writeId = (command as { _writeId?: unknown })._writeId;\n if (typeof writeId === \"string\" && writeId) return writeId;\n }\n return JSON.stringify(command);\n}\n\nfunction currentRouterPath(location: Location): string {\n return `${location.pathname}${location.search}${location.hash}`;\n}\n\nfunction stringifyForWriteDedup(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return \"\";\n }\n}\n\n/**\n * Keeps semantic UI state agent-visible and consumes agent-authored one-shot\n * commands. This is the framework primitive behind route/navigation sync; it\n * intentionally knows nothing about app-specific route shapes.\n */\nexport function useSemanticNavigationState<\n NavigationState,\n NavigateCommand = NavigationState,\n>(\n options: UseSemanticNavigationStateOptions<NavigationState, NavigateCommand>,\n): UseSemanticNavigationStateResult<NavigationState, NavigateCommand> {\n const {\n requestSource,\n commandRefetchInterval = 2_000,\n enabled = true,\n keepalive = true,\n writeDebounceMs = 0,\n } = options;\n\n const queryClient = useQueryClient();\n const navigationKeys = useMemo(\n () => uniqueKeys(options.navigationKeys ?? [\"navigation\"]),\n [options.navigationKeys],\n );\n const commandKeys = useMemo(\n () => uniqueKeys(options.commandKeys ?? [\"navigate\"]),\n [options.commandKeys],\n );\n const commandQueryKey = useMemo<QueryKey>(\n () => options.commandQueryKey ?? [\"navigate-command\"],\n [options.commandQueryKey],\n );\n const navigationState = options.state ?? null;\n const navigationWriteDedup = stringifyForWriteDedup({\n keys: navigationKeys,\n state: navigationState,\n });\n\n const getCommandDedupKeyRef = useRef(options.getCommandDedupKey);\n const onCommandRef = useRef(options.onCommand);\n const onErrorRef = useRef(options.onError);\n getCommandDedupKeyRef.current = options.getCommandDedupKey;\n onCommandRef.current = options.onCommand;\n onErrorRef.current = options.onError;\n\n const lastNavigationWriteRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!enabled) return;\n if (lastNavigationWriteRef.current === navigationWriteDedup) return;\n lastNavigationWriteRef.current = navigationWriteDedup;\n\n const write = () => {\n for (const key of navigationKeys) {\n setClientAppState(key, navigationState, {\n keepalive,\n requestSource,\n }).catch((error) => onErrorRef.current?.(error));\n }\n };\n\n if (writeDebounceMs > 0) {\n const timer = setTimeout(write, writeDebounceMs);\n return () => clearTimeout(timer);\n }\n write();\n }, [\n enabled,\n keepalive,\n navigationKeys,\n navigationState,\n navigationWriteDedup,\n requestSource,\n writeDebounceMs,\n ]);\n\n const commandQuery =\n useQuery<SemanticNavigationCommandEnvelope<NavigateCommand> | null>({\n queryKey: commandQueryKey,\n enabled,\n retry: false,\n refetchInterval: commandRefetchInterval,\n queryFn: async () => {\n for (const key of commandKeys) {\n const command = await readClientAppState<NavigateCommand>(key);\n if (command !== null && command !== undefined) {\n return { key, command };\n }\n }\n return null;\n },\n });\n\n const clearCommand = useCallback(async () => {\n await Promise.all(\n commandKeys.map((key) =>\n deleteClientAppState(key, { requestSource }).catch((error) => {\n onErrorRef.current?.(error);\n }),\n ),\n );\n queryClient.setQueryData(commandQueryKey, null);\n }, [commandKeys, commandQueryKey, queryClient, requestSource]);\n\n const lastProcessedDedupKeyRef = useRef<string | null>(null);\n\n useEffect(() => {\n const envelope = commandQuery.data;\n if (!enabled || !envelope) return;\n\n const dedupKey =\n getCommandDedupKeyRef.current?.(envelope.command) ??\n defaultCommandDedupKey(envelope.command);\n const consume = () => {\n deleteClientAppState(envelope.key, { requestSource }).catch((error) =>\n onErrorRef.current?.(error),\n );\n queryClient.setQueryData(commandQueryKey, null);\n };\n\n if (lastProcessedDedupKeyRef.current === dedupKey) {\n consume();\n return;\n }\n lastProcessedDedupKeyRef.current = dedupKey;\n consume();\n\n Promise.resolve(onCommandRef.current(envelope.command)).catch((error) =>\n onErrorRef.current?.(error),\n );\n }, [commandQuery.data, commandQueryKey, enabled, queryClient, requestSource]);\n\n return {\n navigationState,\n command: commandQuery.data,\n commandQueryKey,\n clearCommand,\n };\n}\n\n/**\n * React Router convenience wrapper around `useSemanticNavigationState`.\n *\n * Use URL query params as the source of truth for shareable filters. This hook\n * writes semantic aliases and stable IDs to `navigation`; the framework's\n * built-in URL sync separately exposes raw `pathname`, `search`, and\n * `searchParams` through `<current-url>` and the `set-search-params` tool.\n */\nexport function useAgentRouteState<\n NavigationState,\n NavigateCommand = NavigationState,\n>(\n options: UseAgentRouteStateOptions<NavigationState, NavigateCommand>,\n): UseAgentRouteStateResult<NavigationState, NavigateCommand> {\n const {\n navigationKey = \"navigation\",\n commandKey = \"navigate\",\n writeGlobalNavigation = true,\n readGlobalCommandFallback = true,\n } = options;\n\n const location = useLocation();\n const navigate = useNavigate();\n const browserTabId = useMemo(\n () => normalizeBrowserTabId(options.browserTabId),\n [options.browserTabId],\n );\n const navigationKeys = useMemo(() => {\n const scopedKey = appStateKeyForBrowserTab(navigationKey, browserTabId);\n const keys = [scopedKey];\n if (browserTabId && writeGlobalNavigation) keys.push(navigationKey);\n return uniqueKeys(keys);\n }, [browserTabId, navigationKey, writeGlobalNavigation]);\n const commandKeys = useMemo(() => {\n const scopedKey = appStateKeyForBrowserTab(commandKey, browserTabId);\n const keys = [scopedKey];\n if (browserTabId && readGlobalCommandFallback) keys.push(commandKey);\n return uniqueKeys(keys);\n }, [browserTabId, commandKey, readGlobalCommandFallback]);\n const commandQueryKey = useMemo<QueryKey>(\n () =>\n options.commandQueryKey ?? [\n \"navigate-command\",\n commandKey,\n browserTabId ?? \"global\",\n ],\n [browserTabId, commandKey, options.commandQueryKey],\n );\n\n const routeLocation = useMemo(\n () => routeLocationFromReactRouter(location),\n [location],\n );\n const navigationState = options.getNavigationState(routeLocation) ?? null;\n\n return useSemanticNavigationState<NavigationState, NavigateCommand>({\n state: navigationState,\n navigationKeys,\n commandKeys,\n commandQueryKey,\n requestSource: options.requestSource,\n commandRefetchInterval: options.refetchInterval,\n enabled: options.enabled,\n keepalive: options.keepalive,\n writeDebounceMs: options.writeDebounceMs,\n getCommandDedupKey: options.getCommandDedupKey,\n onError: options.onError,\n onCommand: (command) => {\n const path = options.getCommandPath(command);\n if (!path) return;\n options.onNavigate?.(command, path);\n if (path === currentRouterPath(location)) return;\n\n const navigateOptions = options.navigateOptions;\n const resolvedOptions =\n typeof navigateOptions === \"function\"\n ? navigateOptions(command)\n : navigateOptions;\n navigate(path, resolvedOptions);\n },\n });\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse-event-processor.d.ts","sourceRoot":"","sources":["../../src/client/sse-event-processor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"sse-event-processor.d.ts","sourceRoot":"","sources":["../../src/client/sse-event-processor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAItE,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEN,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,uBAAuB,GAC/B,aAAa,GACb,YAAY,GACZ,aAAa,GACb,cAAc,GACd,WAAW,CAAC;AAEhB,MAAM,MAAM,uBAAuB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,uBAAuB,EAAE,CAAC;gBAEtC,OAAO,EAAE;QACnB,MAAM,EAAE,uBAAuB,CAAC;QAChC,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,aAAa,CAAC,EAAE,uBAAuB,EAAE,CAAC;KAC3C;CAOF;AAED,eAAO,MAAM,0BAA0B,QAAS,CAAC;AA+KjD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,EAAE,EAAE,QAAQ,EACZ,OAAO,EAAE,WAAW,EAAE,EACtB,eAAe,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAClC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB;IACD,MAAM,EACF,UAAU,GACV,MAAM,GACN,OAAO,GACP,OAAO,GACP,iBAAiB,GACjB,eAAe,CAAC;IACpB,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,YAAY,CAAC,EAAE;QACb,MAAM,EAAE,uBAAuB,CAAC;QAChC,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH,CAiVA;AAED;;;;;;;;GAQG;AACH,wBAAuB,aAAa,CAClC,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,EAChC,OAAO,EAAE,WAAW,EAAE,EACtB,eAAe,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAClC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EAC7B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACpB,cAAc,CAAC,kBAAkB,CAAC,CAqIpC;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,EAChC,OAAO,EAAE,WAAW,EAAE,EACtB,eAAe,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAClC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,IAAI,GACzC,OAAO,CAAC,IAAI,CAAC,CA0Ff"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { formatChatErrorText, normalizeChatError } from "./error-format.js";
|
|
2
|
+
import { humanizeToolLabelText, runningToolLabel } from "./tool-display.js";
|
|
2
3
|
export class AgentAutoContinueSignal extends Error {
|
|
3
4
|
reason;
|
|
4
5
|
maxIterations;
|
|
@@ -12,6 +13,17 @@ export class AgentAutoContinueSignal extends Error {
|
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
15
|
export const SSE_NO_PROGRESS_TIMEOUT_MS = 75_000;
|
|
16
|
+
function findPendingToolCallIndex(content, toolName) {
|
|
17
|
+
for (let i = content.length - 1; i >= 0; i--) {
|
|
18
|
+
const part = content[i];
|
|
19
|
+
if (part.type === "tool-call" &&
|
|
20
|
+
part.toolName === toolName &&
|
|
21
|
+
part.result === undefined) {
|
|
22
|
+
return i;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return -1;
|
|
26
|
+
}
|
|
15
27
|
function appendActivityTrail(trail, next) {
|
|
16
28
|
const label = next.label.trim();
|
|
17
29
|
if (!label)
|
|
@@ -169,19 +181,36 @@ export function processEvent(ev, content, toolCallCounter, tabId) {
|
|
|
169
181
|
};
|
|
170
182
|
}
|
|
171
183
|
if (ev.type === "activity") {
|
|
184
|
+
const tool = ev.tool?.trim() || undefined;
|
|
185
|
+
const label = humanizeToolLabelText(ev.label ?? "Working", tool);
|
|
172
186
|
if (typeof window !== "undefined") {
|
|
173
187
|
window.dispatchEvent(new CustomEvent("agent-chat:activity", {
|
|
174
188
|
detail: {
|
|
175
|
-
label
|
|
176
|
-
...(
|
|
189
|
+
label,
|
|
190
|
+
...(tool ? { tool } : {}),
|
|
177
191
|
tabId,
|
|
178
192
|
},
|
|
179
193
|
}));
|
|
180
194
|
}
|
|
181
|
-
|
|
195
|
+
if (!tool)
|
|
196
|
+
return { action: "continue" };
|
|
197
|
+
const pendingToolCallIndex = findPendingToolCallIndex(content, tool);
|
|
198
|
+
if (pendingToolCallIndex === -1) {
|
|
199
|
+
content.push({
|
|
200
|
+
type: "tool-call",
|
|
201
|
+
toolCallId: `tc_${++toolCallCounter.value}`,
|
|
202
|
+
toolName: tool,
|
|
203
|
+
argsText: "",
|
|
204
|
+
args: {},
|
|
205
|
+
activity: true,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
action: "yield",
|
|
210
|
+
result: { content: [...content] },
|
|
211
|
+
};
|
|
182
212
|
}
|
|
183
213
|
if (ev.type === "tool_start") {
|
|
184
|
-
const toolCallId = `tc_${++toolCallCounter.value}`;
|
|
185
214
|
const args = (ev.input ?? {});
|
|
186
215
|
const tool = ev.tool ?? "unknown";
|
|
187
216
|
if (typeof window !== "undefined") {
|
|
@@ -190,19 +219,36 @@ export function processEvent(ev, content, toolCallCounter, tabId) {
|
|
|
190
219
|
}));
|
|
191
220
|
window.dispatchEvent(new CustomEvent("agent-chat:activity", {
|
|
192
221
|
detail: {
|
|
193
|
-
label:
|
|
222
|
+
label: runningToolLabel(tool),
|
|
194
223
|
tool,
|
|
195
224
|
tabId,
|
|
196
225
|
},
|
|
197
226
|
}));
|
|
198
227
|
}
|
|
199
|
-
content
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
228
|
+
const pendingToolCallIndex = findPendingToolCallIndex(content, tool);
|
|
229
|
+
const pendingToolCall = pendingToolCallIndex >= 0 ? content[pendingToolCallIndex] : undefined;
|
|
230
|
+
if (pendingToolCall &&
|
|
231
|
+
pendingToolCall.type === "tool-call" &&
|
|
232
|
+
pendingToolCall.activity === true &&
|
|
233
|
+
pendingToolCall.argsText === "" &&
|
|
234
|
+
Object.keys(pendingToolCall.args).length === 0) {
|
|
235
|
+
content[pendingToolCallIndex] = {
|
|
236
|
+
type: "tool-call",
|
|
237
|
+
toolCallId: pendingToolCall.toolCallId,
|
|
238
|
+
toolName: tool,
|
|
239
|
+
argsText: JSON.stringify(args),
|
|
240
|
+
args,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
content.push({
|
|
245
|
+
type: "tool-call",
|
|
246
|
+
toolCallId: `tc_${++toolCallCounter.value}`,
|
|
247
|
+
toolName: tool,
|
|
248
|
+
argsText: JSON.stringify(args),
|
|
249
|
+
args,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
206
252
|
return {
|
|
207
253
|
action: "yield",
|
|
208
254
|
result: { content: [...content] },
|
|
@@ -492,15 +538,16 @@ export async function* readSSEStream(body, content, toolCallCounter, tabId, onSe
|
|
|
492
538
|
activityTrail.length = 0;
|
|
493
539
|
}
|
|
494
540
|
else if (ev.type === "activity") {
|
|
541
|
+
const tool = ev.tool?.trim() || undefined;
|
|
495
542
|
appendActivityTrail(activityTrail, {
|
|
496
|
-
label: ev.label ?? "Working",
|
|
497
|
-
...(
|
|
543
|
+
label: humanizeToolLabelText(ev.label ?? "Working", tool),
|
|
544
|
+
...(tool ? { tool } : {}),
|
|
498
545
|
});
|
|
499
546
|
}
|
|
500
547
|
else if (ev.type === "tool_start") {
|
|
501
548
|
const tool = ev.tool ?? "unknown";
|
|
502
549
|
appendActivityTrail(activityTrail, {
|
|
503
|
-
label:
|
|
550
|
+
label: runningToolLabel(tool),
|
|
504
551
|
tool,
|
|
505
552
|
});
|
|
506
553
|
}
|