You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

60 lines
1.9 KiB

import type { ClientEvent, ServerEvent } from '../protocol.js';
import { formatToolError } from '../tools.js';
export type ClientToolHandler = (args: Record<string, unknown>) => Promise<unknown>;
/**
* The subset of `RealtimeClient`'s (or `ResilientRealtimeClient`'s) surface
* this needs — accepted structurally so either transport works here without
* this module caring which one it's given.
*/
export interface ToolDispatchClient {
send(event: ClientEvent): void;
on(handler: (event: ServerEvent) => void): () => void;
}
/**
* Wires a client to a map of client-side tool handlers: listens for
* `tool.call`, runs the matching handler, and sends its result back — kept
* out of the transport itself, which stays transport-only. Handler
* implementations are project-owned (`$lib/client/project/tools`); this is
* just the generic dispatch mechanism.
*
* Returns an unsubscribe function, matching `on()`'s convention.
*/
export function createToolDispatcher(
client: ToolDispatchClient,
handlers: Record<string, ClientToolHandler>
): () => void {
return client.on((event) => {
if (event.type !== 'tool.call') return;
void dispatch(client, handlers, event);
});
}
async function dispatch(
client: ToolDispatchClient,
handlers: Record<string, ClientToolHandler>,
event: { callId: string; name: string; arguments: string }
): Promise<void> {
const handler = handlers[event.name];
if (!handler) {
client.send({
type: 'tool.result',
callId: event.callId,
output: formatToolError(`No client handler for tool "${event.name}".`)
});
return;
}
try {
const args = JSON.parse(event.arguments);
const result = await handler(args);
client.send({ type: 'tool.result', callId: event.callId, output: JSON.stringify(result) });
} catch (err) {
client.send({
type: 'tool.result',
callId: event.callId,
output: formatToolError(err instanceof Error ? err.message : 'Tool execution failed.')
});
}
}