@devicai/ui 0.62.3 → 0.62.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/dist/cjs/api/types.js.map +1 -1
- package/dist/cjs/components/AICommandBar/useAICommandBar.js +5 -5
- package/dist/cjs/components/AICommandBar/useAICommandBar.js.map +1 -1
- package/dist/cjs/components/AIElementWrapper/useAIElementWrapper.js +5 -5
- package/dist/cjs/components/AIElementWrapper/useAIElementWrapper.js.map +1 -1
- package/dist/cjs/components/AIGenerationButton/useAIGenerationButton.js +5 -5
- package/dist/cjs/components/AIGenerationButton/useAIGenerationButton.js.map +1 -1
- package/dist/cjs/hooks/useDevicChat.js +7 -6
- package/dist/cjs/hooks/useDevicChat.js.map +1 -1
- package/dist/cjs/hooks/useModelInterface.js +109 -33
- package/dist/cjs/hooks/useModelInterface.js.map +1 -1
- package/dist/esm/api/types.d.ts +16 -0
- package/dist/esm/api/types.js.map +1 -1
- package/dist/esm/components/AICommandBar/useAICommandBar.js +5 -5
- package/dist/esm/components/AICommandBar/useAICommandBar.js.map +1 -1
- package/dist/esm/components/AIElementWrapper/useAIElementWrapper.js +5 -5
- package/dist/esm/components/AIElementWrapper/useAIElementWrapper.js.map +1 -1
- package/dist/esm/components/AIGenerationButton/useAIGenerationButton.js +5 -5
- package/dist/esm/components/AIGenerationButton/useAIGenerationButton.js.map +1 -1
- package/dist/esm/hooks/useDevicChat.js +7 -6
- package/dist/esm/hooks/useDevicChat.js.map +1 -1
- package/dist/esm/hooks/useModelInterface.d.ts +54 -1
- package/dist/esm/hooks/useModelInterface.js +108 -35
- package/dist/esm/hooks/useModelInterface.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,75 @@
|
|
|
1
|
-
import { useMemo, useCallback } from 'react';
|
|
1
|
+
import { useMemo, useRef, useCallback } from 'react';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* How long a call to a tool this client does not have is given to show up
|
|
5
|
+
* before it is answered as unavailable. Tools come and go with the screen the
|
|
6
|
+
* user is on, and the screen the model has just navigated to may not have
|
|
7
|
+
* registered its own yet.
|
|
8
|
+
*/
|
|
9
|
+
const UNAVAILABLE_TOOL_GRACE_MS = 5000;
|
|
10
|
+
const UNAVAILABLE_TOOL_CHECK_MS = 250;
|
|
11
|
+
/**
|
|
12
|
+
* The answer to a call for a client-side tool this client does not have loaded
|
|
13
|
+
* — typically one registered by a screen the user has since left.
|
|
14
|
+
*
|
|
15
|
+
* Answering is the point. The API holds the conversation in
|
|
16
|
+
* `waiting_for_tool_response` until every call it handed to the client is
|
|
17
|
+
* answered, and nothing else will answer this one: the run never resumes, and
|
|
18
|
+
* every later message is refused or parked behind it.
|
|
19
|
+
*/
|
|
20
|
+
function unavailableToolResponse(toolCall) {
|
|
21
|
+
return {
|
|
22
|
+
tool_call_id: toolCall.id,
|
|
23
|
+
content: {
|
|
24
|
+
error: `Tool "${toolCall.function.name}" is not available: the application no longer offers it in its current context (the user may have moved to another screen). Do not call it again unless it is offered again.`,
|
|
25
|
+
errorType: 'TOOL_UNAVAILABLE',
|
|
26
|
+
},
|
|
27
|
+
role: 'tool',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The calls still unanswered in the most recent assistant message that made
|
|
32
|
+
* any, narrowed to the ones `include` accepts.
|
|
33
|
+
*/
|
|
34
|
+
function unansweredToolCalls(messages, include) {
|
|
35
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
36
|
+
const message = messages[i];
|
|
37
|
+
if (message.role !== 'assistant' || !message.tool_calls?.length)
|
|
38
|
+
continue;
|
|
39
|
+
const answered = new Set(messages
|
|
40
|
+
.slice(i + 1)
|
|
41
|
+
.filter((m) => m.role === 'tool')
|
|
42
|
+
.map((m) => m.tool_call_id));
|
|
43
|
+
return message.tool_calls.filter((toolCall) => include(toolCall) && !answered.has(toolCall.id));
|
|
44
|
+
}
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The tool calls a client owes an answer to, given a realtime snapshot.
|
|
49
|
+
*
|
|
50
|
+
* While a run is going, only the calls to the client's own tools are its
|
|
51
|
+
* business: anything else in the same message is a backend tool the run is
|
|
52
|
+
* still executing. Once the API reports `waiting_for_tool_response` the backend
|
|
53
|
+
* has done its part — it runs its own tools before pausing — so every call
|
|
54
|
+
* still unanswered is waiting on the client, including one to a tool that is
|
|
55
|
+
* no longer loaded. Those are returned too, so they can be answered as
|
|
56
|
+
* unavailable instead of blocking the conversation.
|
|
57
|
+
*
|
|
58
|
+
* The exception is a backend tool that answers asynchronously: the
|
|
59
|
+
* conversation waits on it as well, but the answer comes from an external
|
|
60
|
+
* system, and the API lists it in `pendingAsyncToolCalls`.
|
|
61
|
+
*/
|
|
62
|
+
function resolvePendingToolCalls(data, isClientTool) {
|
|
63
|
+
if (data.pendingToolCalls)
|
|
64
|
+
return data.pendingToolCalls;
|
|
65
|
+
const messages = data.chatHistory ?? [];
|
|
66
|
+
if (data.status !== 'waiting_for_tool_response') {
|
|
67
|
+
return unansweredToolCalls(messages, (toolCall) => isClientTool(toolCall.function.name));
|
|
68
|
+
}
|
|
69
|
+
const answeredElsewhere = new Set((data.pendingAsyncToolCalls ?? []).map((call) => call.toolCallId));
|
|
70
|
+
return unansweredToolCalls(messages, (toolCall) => !answeredElsewhere.has(toolCall.id));
|
|
71
|
+
}
|
|
72
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3
73
|
/**
|
|
4
74
|
* Hook for implementing the Model Interface Protocol
|
|
5
75
|
*
|
|
@@ -31,7 +101,7 @@ import { useMemo, useCallback } from 'react';
|
|
|
31
101
|
* ```
|
|
32
102
|
*/
|
|
33
103
|
function useModelInterface(options) {
|
|
34
|
-
const { tools, onToolExecute, onToolComplete, onToolError } = options;
|
|
104
|
+
const { tools, onToolExecute, onToolComplete, onToolError, unavailableToolGraceMs = UNAVAILABLE_TOOL_GRACE_MS, } = options;
|
|
35
105
|
// Extract tool schemas for API
|
|
36
106
|
const toolSchemas = useMemo(() => {
|
|
37
107
|
return tools.map((tool) => tool.schema);
|
|
@@ -40,6 +110,12 @@ function useModelInterface(options) {
|
|
|
40
110
|
const toolMap = useMemo(() => {
|
|
41
111
|
return new Map(tools.map((tool) => [tool.toolName, tool]));
|
|
42
112
|
}, [tools]);
|
|
113
|
+
// The tools as of the latest render: a call waiting for a tool to appear
|
|
114
|
+
// has to see the ones registered after it started.
|
|
115
|
+
const toolMapRef = useRef(toolMap);
|
|
116
|
+
toolMapRef.current = toolMap;
|
|
117
|
+
const toolSchemasRef = useRef(toolSchemas);
|
|
118
|
+
toolSchemasRef.current = toolSchemas;
|
|
43
119
|
// Check if a tool is a client-side tool
|
|
44
120
|
const isClientTool = useCallback((toolName) => {
|
|
45
121
|
return toolMap.has(toolName);
|
|
@@ -50,11 +126,8 @@ function useModelInterface(options) {
|
|
|
50
126
|
const handleToolCalls = useCallback(async (toolCalls) => {
|
|
51
127
|
const responses = [];
|
|
52
128
|
const widgetCalls = [];
|
|
53
|
-
|
|
129
|
+
const handle = async (toolCall, tool) => {
|
|
54
130
|
const toolName = toolCall.function.name;
|
|
55
|
-
const tool = toolMap.get(toolName);
|
|
56
|
-
if (!tool)
|
|
57
|
-
continue;
|
|
58
131
|
let params = {};
|
|
59
132
|
try {
|
|
60
133
|
params = JSON.parse(toolCall.function.arguments || '{}');
|
|
@@ -70,7 +143,7 @@ function useModelInterface(options) {
|
|
|
70
143
|
widget: tool.responseWidget,
|
|
71
144
|
toolName,
|
|
72
145
|
});
|
|
73
|
-
|
|
146
|
+
return;
|
|
74
147
|
}
|
|
75
148
|
if (!tool.callback) {
|
|
76
149
|
// Neither callback nor widget — respond with error so the model can continue
|
|
@@ -79,7 +152,7 @@ function useModelInterface(options) {
|
|
|
79
152
|
content: { error: `Tool "${toolName}" has no callback or responseWidget` },
|
|
80
153
|
role: 'tool',
|
|
81
154
|
});
|
|
82
|
-
|
|
155
|
+
return;
|
|
83
156
|
}
|
|
84
157
|
try {
|
|
85
158
|
const result = await tool.callback(params);
|
|
@@ -99,35 +172,34 @@ function useModelInterface(options) {
|
|
|
99
172
|
role: 'tool',
|
|
100
173
|
});
|
|
101
174
|
}
|
|
175
|
+
};
|
|
176
|
+
const missing = [];
|
|
177
|
+
for (const toolCall of toolCalls) {
|
|
178
|
+
const tool = toolMapRef.current.get(toolCall.function.name);
|
|
179
|
+
if (tool)
|
|
180
|
+
await handle(toolCall, tool);
|
|
181
|
+
else
|
|
182
|
+
missing.push(toolCall);
|
|
102
183
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const respondedToolIds = new Set(messages
|
|
116
|
-
.slice(i + 1)
|
|
117
|
-
.filter((m) => m.role === 'tool')
|
|
118
|
-
.map((m) => m.tool_call_id));
|
|
119
|
-
// Get unresponded tool calls
|
|
120
|
-
for (const tc of clientToolCalls) {
|
|
121
|
-
if (!respondedToolIds.has(tc.id)) {
|
|
122
|
-
pendingCalls.push(tc);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
// Only check the most recent assistant message with tool calls
|
|
126
|
-
break;
|
|
184
|
+
if (missing.length > 0) {
|
|
185
|
+
const allLoaded = () => missing.every((toolCall) => toolMapRef.current.has(toolCall.function.name));
|
|
186
|
+
const deadline = Date.now() + unavailableToolGraceMs;
|
|
187
|
+
while (!allLoaded() && Date.now() < deadline) {
|
|
188
|
+
await sleep(Math.min(UNAVAILABLE_TOOL_CHECK_MS, deadline - Date.now()));
|
|
189
|
+
}
|
|
190
|
+
for (const toolCall of missing) {
|
|
191
|
+
const tool = toolMapRef.current.get(toolCall.function.name);
|
|
192
|
+
if (tool)
|
|
193
|
+
await handle(toolCall, tool);
|
|
194
|
+
else
|
|
195
|
+
responses.push(unavailableToolResponse(toolCall));
|
|
127
196
|
}
|
|
128
197
|
}
|
|
129
|
-
return
|
|
130
|
-
}, [
|
|
198
|
+
return { responses, widgetCalls, toolSchemas: toolSchemasRef.current };
|
|
199
|
+
}, [onToolExecute, onToolComplete, onToolError, unavailableToolGraceMs]);
|
|
200
|
+
// Extract pending tool calls from messages that need client handling
|
|
201
|
+
const extractPendingToolCalls = useCallback((messages) => unansweredToolCalls(messages, (toolCall) => isClientTool(toolCall.function.name)), [isClientTool]);
|
|
202
|
+
const resolvePending = useCallback((data) => resolvePendingToolCalls(data, isClientTool), [isClientTool]);
|
|
131
203
|
return {
|
|
132
204
|
toolSchemas,
|
|
133
205
|
isClientTool,
|
|
@@ -135,8 +207,9 @@ function useModelInterface(options) {
|
|
|
135
207
|
getTool,
|
|
136
208
|
handleToolCalls,
|
|
137
209
|
extractPendingToolCalls,
|
|
210
|
+
resolvePendingToolCalls: resolvePending,
|
|
138
211
|
};
|
|
139
212
|
}
|
|
140
213
|
|
|
141
|
-
export { useModelInterface };
|
|
214
|
+
export { UNAVAILABLE_TOOL_GRACE_MS, resolvePendingToolCalls, unavailableToolResponse, useModelInterface };
|
|
142
215
|
//# sourceMappingURL=useModelInterface.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useModelInterface.js","sources":["../../../src/hooks/useModelInterface.ts"],"sourcesContent":["import { useCallback, useMemo } from 'react';\nimport type {\n ModelInterfaceTool,\n ModelInterfaceToolSchema,\n ToolCall,\n ToolCallResponse,\n ChatMessage,\n ResponseWidgetConfig,\n} from '../api/types';\n\nexport interface PendingWidgetCall {\n toolCall: ToolCall;\n params: any;\n widget: ResponseWidgetConfig;\n toolName: string;\n}\n\nexport interface HandleToolCallsResult {\n /** Responses ready to send back to the API (from callback-based tools) */\n responses: ToolCallResponse[];\n /** Tool calls that require user interaction via a response widget */\n widgetCalls: PendingWidgetCall[];\n}\n\nexport interface UseModelInterfaceOptions {\n /**\n * Client-side tools available for model interface protocol\n */\n tools: ModelInterfaceTool[];\n\n /**\n * Callback when a tool is being executed\n */\n onToolExecute?: (toolName: string, params: any) => void;\n\n /**\n * Callback when a tool execution completes\n */\n onToolComplete?: (toolName: string, result: any) => void;\n\n /**\n * Callback when a tool execution fails\n */\n onToolError?: (toolName: string, error: Error) => void;\n}\n\nexport interface UseModelInterfaceResult {\n /**\n * Tool schemas to send to the API\n */\n toolSchemas: ModelInterfaceToolSchema[];\n\n /**\n * Check if a tool call should be handled client-side\n */\n isClientTool: (toolName: string) => boolean;\n\n /**\n * Check if a tool has a response widget (user-driven) instead of a callback\n */\n hasResponseWidget: (toolName: string) => boolean;\n\n /**\n * Get the tool definition by name\n */\n getTool: (toolName: string) => ModelInterfaceTool | undefined;\n\n /**\n * Handle tool calls from the model.\n * Callback-based tools are executed immediately and their responses returned.\n * Widget-based tools are returned as pending widget calls for user interaction.\n */\n handleToolCalls: (toolCalls: ToolCall[]) => Promise<HandleToolCallsResult>;\n\n /**\n * Process messages and extract pending tool calls that need client handling\n */\n extractPendingToolCalls: (messages: ChatMessage[]) => ToolCall[];\n}\n\n/**\n * Hook for implementing the Model Interface Protocol\n *\n * The Model Interface Protocol allows client-side tools to be executed\n * during an assistant conversation. When the model calls a client-side tool,\n * this hook handles executing the tool and preparing the response.\n *\n * @example\n * ```tsx\n * const { toolSchemas, handleToolCalls } = useModelInterface({\n * tools: [\n * {\n * toolName: 'get_user_location',\n * schema: {\n * type: 'function',\n * function: {\n * name: 'get_user_location',\n * description: 'Get user current location',\n * parameters: { type: 'object', properties: {} }\n * }\n * },\n * callback: async () => {\n * const pos = await getCurrentPosition();\n * return { lat: pos.coords.latitude, lng: pos.coords.longitude };\n * }\n * }\n * ]\n * });\n * ```\n */\nexport function useModelInterface(\n options: UseModelInterfaceOptions\n): UseModelInterfaceResult {\n const { tools, onToolExecute, onToolComplete, onToolError } = options;\n\n // Extract tool schemas for API\n const toolSchemas = useMemo(() => {\n return tools.map((tool) => tool.schema);\n }, [tools]);\n\n // Map of tool name to tool definition\n const toolMap = useMemo(() => {\n return new Map(tools.map((tool) => [tool.toolName, tool]));\n }, [tools]);\n\n // Check if a tool is a client-side tool\n const isClientTool = useCallback(\n (toolName: string): boolean => {\n return toolMap.has(toolName);\n },\n [toolMap]\n );\n\n const hasResponseWidget = useCallback(\n (toolName: string): boolean => Boolean(toolMap.get(toolName)?.responseWidget),\n [toolMap]\n );\n\n const getTool = useCallback(\n (toolName: string): ModelInterfaceTool | undefined => toolMap.get(toolName),\n [toolMap]\n );\n\n // Handle tool calls: execute callback tools, queue widget tools for user input\n const handleToolCalls = useCallback(\n async (toolCalls: ToolCall[]): Promise<HandleToolCallsResult> => {\n const responses: ToolCallResponse[] = [];\n const widgetCalls: PendingWidgetCall[] = [];\n\n for (const toolCall of toolCalls) {\n const toolName = toolCall.function.name;\n const tool = toolMap.get(toolName);\n\n if (!tool) continue;\n\n let params: any = {};\n try {\n params = JSON.parse(toolCall.function.arguments || '{}');\n } catch {\n // Keep empty params if parsing fails\n }\n\n onToolExecute?.(toolName, params);\n\n if (tool.responseWidget) {\n widgetCalls.push({\n toolCall,\n params,\n widget: tool.responseWidget,\n toolName,\n });\n continue;\n }\n\n if (!tool.callback) {\n // Neither callback nor widget — respond with error so the model can continue\n responses.push({\n tool_call_id: toolCall.id,\n content: { error: `Tool \"${toolName}\" has no callback or responseWidget` },\n role: 'tool',\n });\n continue;\n }\n\n try {\n const result = await tool.callback(params);\n onToolComplete?.(toolName, result);\n responses.push({\n tool_call_id: toolCall.id,\n content: result,\n role: 'tool',\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onToolError?.(toolName, error);\n responses.push({\n tool_call_id: toolCall.id,\n content: { error: error.message },\n role: 'tool',\n });\n }\n }\n\n return { responses, widgetCalls };\n },\n [toolMap, onToolExecute, onToolComplete, onToolError]\n );\n\n // Extract pending tool calls from messages that need client handling\n const extractPendingToolCalls = useCallback(\n (messages: ChatMessage[]): ToolCall[] => {\n const pendingCalls: ToolCall[] = [];\n\n // Look at the last assistant message\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i];\n\n if (message.role === 'assistant' && message.tool_calls?.length) {\n // Filter for client-side tools only\n const clientToolCalls = message.tool_calls.filter((tc) =>\n isClientTool(tc.function.name)\n );\n\n // Check if these tool calls have been responded to\n const respondedToolIds = new Set(\n messages\n .slice(i + 1)\n .filter((m) => m.role === 'tool')\n .map((m) => m.tool_call_id)\n );\n\n // Get unresponded tool calls\n for (const tc of clientToolCalls) {\n if (!respondedToolIds.has(tc.id)) {\n pendingCalls.push(tc);\n }\n }\n\n // Only check the most recent assistant message with tool calls\n break;\n }\n }\n\n return pendingCalls;\n },\n [isClientTool]\n );\n\n return {\n toolSchemas,\n isClientTool,\n hasResponseWidget,\n getTool,\n handleToolCalls,\n extractPendingToolCalls,\n };\n}\n"],"names":[],"mappings":";;AAgFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BG;AACG,SAAU,iBAAiB,CAC/B,OAAiC,EAAA;IAEjC,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,GAAG,OAAO;;AAGrE,IAAA,MAAM,WAAW,GAAG,OAAO,CAAC,MAAK;AAC/B,QAAA,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC;AACzC,IAAA,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;;AAGX,IAAA,MAAM,OAAO,GAAG,OAAO,CAAC,MAAK;QAC3B,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;AAC5D,IAAA,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;;AAGX,IAAA,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,QAAgB,KAAa;AAC5B,QAAA,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC9B,IAAA,CAAC,EACD,CAAC,OAAO,CAAC,CACV;IAED,MAAM,iBAAiB,GAAG,WAAW,CACnC,CAAC,QAAgB,KAAc,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC,EAC7E,CAAC,OAAO,CAAC,CACV;IAED,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,QAAgB,KAAqC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAC3E,CAAC,OAAO,CAAC,CACV;;IAGD,MAAM,eAAe,GAAG,WAAW,CACjC,OAAO,SAAqB,KAAoC;QAC9D,MAAM,SAAS,GAAuB,EAAE;QACxC,MAAM,WAAW,GAAwB,EAAE;AAE3C,QAAA,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;AAChC,YAAA,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI;YACvC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;AAElC,YAAA,IAAI,CAAC,IAAI;gBAAE;YAEX,IAAI,MAAM,GAAQ,EAAE;AACpB,YAAA,IAAI;AACF,gBAAA,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,IAAI,IAAI,CAAC;YAC1D;AAAE,YAAA,MAAM;;YAER;AAEA,YAAA,aAAa,GAAG,QAAQ,EAAE,MAAM,CAAC;AAEjC,YAAA,IAAI,IAAI,CAAC,cAAc,EAAE;gBACvB,WAAW,CAAC,IAAI,CAAC;oBACf,QAAQ;oBACR,MAAM;oBACN,MAAM,EAAE,IAAI,CAAC,cAAc;oBAC3B,QAAQ;AACT,iBAAA,CAAC;gBACF;YACF;AAEA,YAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;;gBAElB,SAAS,CAAC,IAAI,CAAC;oBACb,YAAY,EAAE,QAAQ,CAAC,EAAE;AACzB,oBAAA,OAAO,EAAE,EAAE,KAAK,EAAE,CAAA,MAAA,EAAS,QAAQ,qCAAqC,EAAE;AAC1E,oBAAA,IAAI,EAAE,MAAM;AACb,iBAAA,CAAC;gBACF;YACF;AAEA,YAAA,IAAI;gBACF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AAC1C,gBAAA,cAAc,GAAG,QAAQ,EAAE,MAAM,CAAC;gBAClC,SAAS,CAAC,IAAI,CAAC;oBACb,YAAY,EAAE,QAAQ,CAAC,EAAE;AACzB,oBAAA,OAAO,EAAE,MAAM;AACf,oBAAA,IAAI,EAAE,MAAM;AACb,iBAAA,CAAC;YACJ;YAAE,OAAO,GAAG,EAAE;gBACZ,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACjE,gBAAA,WAAW,GAAG,QAAQ,EAAE,KAAK,CAAC;gBAC9B,SAAS,CAAC,IAAI,CAAC;oBACb,YAAY,EAAE,QAAQ,CAAC,EAAE;AACzB,oBAAA,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE;AACjC,oBAAA,IAAI,EAAE,MAAM;AACb,iBAAA,CAAC;YACJ;QACF;AAEA,QAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE;IACnC,CAAC,EACD,CAAC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,CAAC,CACtD;;AAGD,IAAA,MAAM,uBAAuB,GAAG,WAAW,CACzC,CAAC,QAAuB,KAAgB;QACtC,MAAM,YAAY,GAAe,EAAE;;AAGnC,QAAA,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;AAC7C,YAAA,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC;AAE3B,YAAA,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE;;gBAE9D,MAAM,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,KACnD,YAAY,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAC/B;;AAGD,gBAAA,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAC9B;AACG,qBAAA,KAAK,CAAC,CAAC,GAAG,CAAC;qBACX,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,MAAM;qBAC/B,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAC9B;;AAGD,gBAAA,KAAK,MAAM,EAAE,IAAI,eAAe,EAAE;oBAChC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAChC,wBAAA,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;oBACvB;gBACF;;gBAGA;YACF;QACF;AAEA,QAAA,OAAO,YAAY;AACrB,IAAA,CAAC,EACD,CAAC,YAAY,CAAC,CACf;IAED,OAAO;QACL,WAAW;QACX,YAAY;QACZ,iBAAiB;QACjB,OAAO;QACP,eAAe;QACf,uBAAuB;KACxB;AACH;;;;"}
|
|
1
|
+
{"version":3,"file":"useModelInterface.js","sources":["../../../src/hooks/useModelInterface.ts"],"sourcesContent":["import { useCallback, useMemo, useRef } from 'react';\nimport type {\n ModelInterfaceTool,\n ModelInterfaceToolSchema,\n ToolCall,\n ToolCallResponse,\n ChatMessage,\n RealtimeChatHistory,\n ResponseWidgetConfig,\n} from '../api/types';\n\n/**\n * How long a call to a tool this client does not have is given to show up\n * before it is answered as unavailable. Tools come and go with the screen the\n * user is on, and the screen the model has just navigated to may not have\n * registered its own yet.\n */\nexport const UNAVAILABLE_TOOL_GRACE_MS = 5_000;\nconst UNAVAILABLE_TOOL_CHECK_MS = 250;\n\n/**\n * The answer to a call for a client-side tool this client does not have loaded\n * — typically one registered by a screen the user has since left.\n *\n * Answering is the point. The API holds the conversation in\n * `waiting_for_tool_response` until every call it handed to the client is\n * answered, and nothing else will answer this one: the run never resumes, and\n * every later message is refused or parked behind it.\n */\nexport function unavailableToolResponse(toolCall: ToolCall): ToolCallResponse {\n return {\n tool_call_id: toolCall.id,\n content: {\n error: `Tool \"${toolCall.function.name}\" is not available: the application no longer offers it in its current context (the user may have moved to another screen). Do not call it again unless it is offered again.`,\n errorType: 'TOOL_UNAVAILABLE',\n },\n role: 'tool',\n };\n}\n\n/**\n * The calls still unanswered in the most recent assistant message that made\n * any, narrowed to the ones `include` accepts.\n */\nfunction unansweredToolCalls(\n messages: ChatMessage[],\n include: (toolCall: ToolCall) => boolean\n): ToolCall[] {\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i];\n if (message.role !== 'assistant' || !message.tool_calls?.length) continue;\n\n const answered = new Set(\n messages\n .slice(i + 1)\n .filter((m) => m.role === 'tool')\n .map((m) => m.tool_call_id)\n );\n return message.tool_calls.filter(\n (toolCall) => include(toolCall) && !answered.has(toolCall.id)\n );\n }\n return [];\n}\n\n/**\n * The tool calls a client owes an answer to, given a realtime snapshot.\n *\n * While a run is going, only the calls to the client's own tools are its\n * business: anything else in the same message is a backend tool the run is\n * still executing. Once the API reports `waiting_for_tool_response` the backend\n * has done its part — it runs its own tools before pausing — so every call\n * still unanswered is waiting on the client, including one to a tool that is\n * no longer loaded. Those are returned too, so they can be answered as\n * unavailable instead of blocking the conversation.\n *\n * The exception is a backend tool that answers asynchronously: the\n * conversation waits on it as well, but the answer comes from an external\n * system, and the API lists it in `pendingAsyncToolCalls`.\n */\nexport function resolvePendingToolCalls(\n data: Pick<\n RealtimeChatHistory,\n 'status' | 'chatHistory' | 'pendingToolCalls' | 'pendingAsyncToolCalls'\n >,\n isClientTool: (toolName: string) => boolean\n): ToolCall[] {\n if (data.pendingToolCalls) return data.pendingToolCalls;\n\n const messages = data.chatHistory ?? [];\n if (data.status !== 'waiting_for_tool_response') {\n return unansweredToolCalls(messages, (toolCall) =>\n isClientTool(toolCall.function.name)\n );\n }\n\n const answeredElsewhere = new Set(\n (data.pendingAsyncToolCalls ?? []).map((call) => call.toolCallId)\n );\n return unansweredToolCalls(\n messages,\n (toolCall) => !answeredElsewhere.has(toolCall.id)\n );\n}\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nexport interface PendingWidgetCall {\n toolCall: ToolCall;\n params: any;\n widget: ResponseWidgetConfig;\n toolName: string;\n}\n\nexport interface HandleToolCallsResult {\n /** Responses ready to send back to the API (from callback-based tools) */\n responses: ToolCallResponse[];\n /** Tool calls that require user interaction via a response widget */\n widgetCalls: PendingWidgetCall[];\n /**\n * The tool schemas on offer once the calls were handled — what to restate\n * alongside the responses. It can differ from the ones at the start of the\n * call when the tools changed while an unavailable one was being waited for.\n */\n toolSchemas: ModelInterfaceToolSchema[];\n}\n\nexport interface UseModelInterfaceOptions {\n /**\n * Client-side tools available for model interface protocol\n */\n tools: ModelInterfaceTool[];\n\n /**\n * Callback when a tool is being executed\n */\n onToolExecute?: (toolName: string, params: any) => void;\n\n /**\n * Callback when a tool execution completes\n */\n onToolComplete?: (toolName: string, result: any) => void;\n\n /**\n * Callback when a tool execution fails\n */\n onToolError?: (toolName: string, error: Error) => void;\n\n /**\n * How long (ms) a call to a tool that is not loaded waits for it to appear\n * before it is answered as unavailable.\n * @default 5000\n */\n unavailableToolGraceMs?: number;\n}\n\nexport interface UseModelInterfaceResult {\n /**\n * Tool schemas to send to the API\n */\n toolSchemas: ModelInterfaceToolSchema[];\n\n /**\n * Check if a tool call should be handled client-side\n */\n isClientTool: (toolName: string) => boolean;\n\n /**\n * Check if a tool has a response widget (user-driven) instead of a callback\n */\n hasResponseWidget: (toolName: string) => boolean;\n\n /**\n * Get the tool definition by name\n */\n getTool: (toolName: string) => ModelInterfaceTool | undefined;\n\n /**\n * Handle tool calls from the model.\n * Callback-based tools are executed immediately and their responses returned.\n * Widget-based tools are returned as pending widget calls for user interaction.\n * A call to a tool that is not loaded waits `unavailableToolGraceMs` for it to\n * appear, and is otherwise answered as unavailable.\n */\n handleToolCalls: (toolCalls: ToolCall[]) => Promise<HandleToolCallsResult>;\n\n /**\n * Process messages and extract pending tool calls that need client handling\n */\n extractPendingToolCalls: (messages: ChatMessage[]) => ToolCall[];\n\n /**\n * The tool calls this client owes an answer to in a realtime snapshot: its\n * own pending calls, plus — while the API waits for a tool response — calls\n * to tools it does not have loaded, which must still be answered.\n */\n resolvePendingToolCalls: (data: RealtimeChatHistory) => ToolCall[];\n}\n\n/**\n * Hook for implementing the Model Interface Protocol\n *\n * The Model Interface Protocol allows client-side tools to be executed\n * during an assistant conversation. When the model calls a client-side tool,\n * this hook handles executing the tool and preparing the response.\n *\n * @example\n * ```tsx\n * const { toolSchemas, handleToolCalls } = useModelInterface({\n * tools: [\n * {\n * toolName: 'get_user_location',\n * schema: {\n * type: 'function',\n * function: {\n * name: 'get_user_location',\n * description: 'Get user current location',\n * parameters: { type: 'object', properties: {} }\n * }\n * },\n * callback: async () => {\n * const pos = await getCurrentPosition();\n * return { lat: pos.coords.latitude, lng: pos.coords.longitude };\n * }\n * }\n * ]\n * });\n * ```\n */\nexport function useModelInterface(\n options: UseModelInterfaceOptions\n): UseModelInterfaceResult {\n const {\n tools,\n onToolExecute,\n onToolComplete,\n onToolError,\n unavailableToolGraceMs = UNAVAILABLE_TOOL_GRACE_MS,\n } = options;\n\n // Extract tool schemas for API\n const toolSchemas = useMemo(() => {\n return tools.map((tool) => tool.schema);\n }, [tools]);\n\n // Map of tool name to tool definition\n const toolMap = useMemo(() => {\n return new Map(tools.map((tool) => [tool.toolName, tool]));\n }, [tools]);\n\n // The tools as of the latest render: a call waiting for a tool to appear\n // has to see the ones registered after it started.\n const toolMapRef = useRef(toolMap);\n toolMapRef.current = toolMap;\n const toolSchemasRef = useRef(toolSchemas);\n toolSchemasRef.current = toolSchemas;\n\n // Check if a tool is a client-side tool\n const isClientTool = useCallback(\n (toolName: string): boolean => {\n return toolMap.has(toolName);\n },\n [toolMap]\n );\n\n const hasResponseWidget = useCallback(\n (toolName: string): boolean => Boolean(toolMap.get(toolName)?.responseWidget),\n [toolMap]\n );\n\n const getTool = useCallback(\n (toolName: string): ModelInterfaceTool | undefined => toolMap.get(toolName),\n [toolMap]\n );\n\n // Handle tool calls: execute callback tools, queue widget tools for user input\n const handleToolCalls = useCallback(\n async (toolCalls: ToolCall[]): Promise<HandleToolCallsResult> => {\n const responses: ToolCallResponse[] = [];\n const widgetCalls: PendingWidgetCall[] = [];\n\n const handle = async (toolCall: ToolCall, tool: ModelInterfaceTool) => {\n const toolName = toolCall.function.name;\n\n let params: any = {};\n try {\n params = JSON.parse(toolCall.function.arguments || '{}');\n } catch {\n // Keep empty params if parsing fails\n }\n\n onToolExecute?.(toolName, params);\n\n if (tool.responseWidget) {\n widgetCalls.push({\n toolCall,\n params,\n widget: tool.responseWidget,\n toolName,\n });\n return;\n }\n\n if (!tool.callback) {\n // Neither callback nor widget — respond with error so the model can continue\n responses.push({\n tool_call_id: toolCall.id,\n content: { error: `Tool \"${toolName}\" has no callback or responseWidget` },\n role: 'tool',\n });\n return;\n }\n\n try {\n const result = await tool.callback(params);\n onToolComplete?.(toolName, result);\n responses.push({\n tool_call_id: toolCall.id,\n content: result,\n role: 'tool',\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onToolError?.(toolName, error);\n responses.push({\n tool_call_id: toolCall.id,\n content: { error: error.message },\n role: 'tool',\n });\n }\n };\n\n const missing: ToolCall[] = [];\n for (const toolCall of toolCalls) {\n const tool = toolMapRef.current.get(toolCall.function.name);\n if (tool) await handle(toolCall, tool);\n else missing.push(toolCall);\n }\n\n if (missing.length > 0) {\n const allLoaded = () =>\n missing.every((toolCall) => toolMapRef.current.has(toolCall.function.name));\n const deadline = Date.now() + unavailableToolGraceMs;\n while (!allLoaded() && Date.now() < deadline) {\n await sleep(Math.min(UNAVAILABLE_TOOL_CHECK_MS, deadline - Date.now()));\n }\n\n for (const toolCall of missing) {\n const tool = toolMapRef.current.get(toolCall.function.name);\n if (tool) await handle(toolCall, tool);\n else responses.push(unavailableToolResponse(toolCall));\n }\n }\n\n return { responses, widgetCalls, toolSchemas: toolSchemasRef.current };\n },\n [onToolExecute, onToolComplete, onToolError, unavailableToolGraceMs]\n );\n\n // Extract pending tool calls from messages that need client handling\n const extractPendingToolCalls = useCallback(\n (messages: ChatMessage[]): ToolCall[] =>\n unansweredToolCalls(messages, (toolCall) => isClientTool(toolCall.function.name)),\n [isClientTool]\n );\n\n const resolvePending = useCallback(\n (data: RealtimeChatHistory): ToolCall[] => resolvePendingToolCalls(data, isClientTool),\n [isClientTool]\n );\n\n return {\n toolSchemas,\n isClientTool,\n hasResponseWidget,\n getTool,\n handleToolCalls,\n extractPendingToolCalls,\n resolvePendingToolCalls: resolvePending,\n };\n}\n"],"names":[],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export type { UseDevicChatOptions, UseDevicChatResult, SendMessageResult, StopRe
|
|
|
30
30
|
export { DevicApiClient, DevicApiError } from './api/client';
|
|
31
31
|
export type { DevicApiClientConfig, TenantSessionToken } from './api/client';
|
|
32
32
|
export { AgentThreadState, } from './api/types';
|
|
33
|
-
export type { ChatMessage, ChatFile, MessageContent, ToolCall, ToolCallResponse, ProcessMessageDto, AssistantResponse, AsyncResponse, QueueDisposition, StopChatResponse, RealtimeChatHistory, RealtimeStatus, ChatHistory, AssistantSpecialization, ModelInterfaceTool, ModelInterfaceToolSchema, ResponseWidgetProps, ResponseWidgetConfig, PreviousMessage, ApiError, ConversationSummary, FeedbackSubmission, FeedbackEntry, AgentThreadDto, AgentTaskDto, AgentDto, HandOffToolResponse, ToolGroupCall, ToolGroupConfig, WhisperTranscriptionResponse, TenantLimitExceeded, TenantUsage, TenantUsageRule, TenantUsageHistoryRow, TenantUsageHistoryQuery, RecalledMemoryRecord, RecalledMemoryFact, RecalledMemoryEntity, RecalledMemoryTurn, CompactionCheckpoint, CompactionSummary, CompactionFact, CompactionActivity, CoreMemorySnapshot, CoreMemoryEntry, CoreMemoryLimits, CoreMemoryList, Integration, IntegrationAccount, IntegrationAuthField, IntegrationAuthScheme, IntegrationSetupRequired, TenantMcpAuthMode, TenantMcpConnection, TenantMcpServer, TenantMcpListing, TenantMcpAuthInput, TenantMcpConnectResult, } from './api/types';
|
|
33
|
+
export type { ChatMessage, ChatFile, MessageContent, ToolCall, ToolCallResponse, ProcessMessageDto, AssistantResponse, AsyncResponse, QueueDisposition, StopChatResponse, RealtimeChatHistory, RealtimeStatus, PendingAsyncToolCall, ChatHistory, AssistantSpecialization, ModelInterfaceTool, ModelInterfaceToolSchema, ResponseWidgetProps, ResponseWidgetConfig, PreviousMessage, ApiError, ConversationSummary, FeedbackSubmission, FeedbackEntry, AgentThreadDto, AgentTaskDto, AgentDto, HandOffToolResponse, ToolGroupCall, ToolGroupConfig, WhisperTranscriptionResponse, TenantLimitExceeded, TenantUsage, TenantUsageRule, TenantUsageHistoryRow, TenantUsageHistoryQuery, RecalledMemoryRecord, RecalledMemoryFact, RecalledMemoryEntity, RecalledMemoryTurn, CompactionCheckpoint, CompactionSummary, CompactionFact, CompactionActivity, CoreMemorySnapshot, CoreMemoryEntry, CoreMemoryLimits, CoreMemoryList, Integration, IntegrationAccount, IntegrationAuthField, IntegrationAuthScheme, IntegrationSetupRequired, TenantMcpAuthMode, TenantMcpConnection, TenantMcpServer, TenantMcpListing, TenantMcpAuthInput, TenantMcpConnectResult, } from './api/types';
|
|
34
34
|
export { MessageActions, FeedbackModal } from './components/Feedback';
|
|
35
35
|
export type { MessageActionsProps, FeedbackModalProps, FeedbackState, FeedbackTheme } from './components/Feedback';
|
|
36
36
|
export { generateId, deepMerge, debounce, throttle, formatFileSize, storage, segmentToolCalls } from './utils';
|