@tambo-ai/react 0.70.0 → 0.71.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/v1/hooks/use-tambo-v1-messages.d.ts +58 -0
- package/dist/v1/hooks/use-tambo-v1-messages.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-messages.js +54 -0
- package/dist/v1/hooks/use-tambo-v1-messages.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-messages.test.d.ts +2 -0
- package/dist/v1/hooks/use-tambo-v1-messages.test.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-messages.test.js +137 -0
- package/dist/v1/hooks/use-tambo-v1-messages.test.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-send-message.d.ts +96 -0
- package/dist/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-send-message.js +227 -0
- package/dist/v1/hooks/use-tambo-v1-send-message.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-send-message.test.d.ts +2 -0
- package/dist/v1/hooks/use-tambo-v1-send-message.test.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-send-message.test.js +827 -0
- package/dist/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts +61 -0
- package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-thread-list.js +56 -0
- package/dist/v1/hooks/use-tambo-v1-thread-list.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-thread-list.test.d.ts +2 -0
- package/dist/v1/hooks/use-tambo-v1-thread-list.test.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-thread-list.test.js +98 -0
- package/dist/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-thread.d.ts +37 -0
- package/dist/v1/hooks/use-tambo-v1-thread.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-thread.js +49 -0
- package/dist/v1/hooks/use-tambo-v1-thread.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-thread.test.d.ts +2 -0
- package/dist/v1/hooks/use-tambo-v1-thread.test.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-thread.test.js +83 -0
- package/dist/v1/hooks/use-tambo-v1-thread.test.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1.d.ts +107 -0
- package/dist/v1/hooks/use-tambo-v1.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1.js +87 -0
- package/dist/v1/hooks/use-tambo-v1.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1.test.d.ts +2 -0
- package/dist/v1/hooks/use-tambo-v1.test.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1.test.js +150 -0
- package/dist/v1/hooks/use-tambo-v1.test.js.map +1 -0
- package/dist/v1/index.d.ts +54 -16
- package/dist/v1/index.d.ts.map +1 -1
- package/dist/v1/index.js +85 -26
- package/dist/v1/index.js.map +1 -1
- package/dist/v1/providers/tambo-v1-provider.d.ts +91 -0
- package/dist/v1/providers/tambo-v1-provider.d.ts.map +1 -0
- package/dist/v1/providers/tambo-v1-provider.js +110 -0
- package/dist/v1/providers/tambo-v1-provider.js.map +1 -0
- package/dist/v1/providers/tambo-v1-provider.test.d.ts +2 -0
- package/dist/v1/providers/tambo-v1-provider.test.d.ts.map +1 -0
- package/dist/v1/providers/tambo-v1-provider.test.js +123 -0
- package/dist/v1/providers/tambo-v1-provider.test.js.map +1 -0
- package/dist/v1/providers/tambo-v1-stream-context.d.ts +136 -0
- package/dist/v1/providers/tambo-v1-stream-context.d.ts.map +1 -0
- package/dist/v1/providers/tambo-v1-stream-context.js +230 -0
- package/dist/v1/providers/tambo-v1-stream-context.js.map +1 -0
- package/dist/v1/providers/tambo-v1-stream-context.test.d.ts +2 -0
- package/dist/v1/providers/tambo-v1-stream-context.test.d.ts.map +1 -0
- package/dist/v1/providers/tambo-v1-stream-context.test.js +85 -0
- package/dist/v1/providers/tambo-v1-stream-context.test.js.map +1 -0
- package/dist/v1/types/component.d.ts +5 -2
- package/dist/v1/types/component.d.ts.map +1 -1
- package/dist/v1/types/component.js +5 -2
- package/dist/v1/types/component.js.map +1 -1
- package/dist/v1/types/event.d.ts +21 -12
- package/dist/v1/types/event.d.ts.map +1 -1
- package/dist/v1/types/event.js +46 -1
- package/dist/v1/types/event.js.map +1 -1
- package/dist/v1/types/event.test.d.ts +2 -0
- package/dist/v1/types/event.test.d.ts.map +1 -0
- package/dist/v1/types/event.test.js +70 -0
- package/dist/v1/types/event.test.js.map +1 -0
- package/dist/v1/types/message.d.ts +4 -8
- package/dist/v1/types/message.d.ts.map +1 -1
- package/dist/v1/types/message.js +1 -1
- package/dist/v1/types/message.js.map +1 -1
- package/dist/v1/types/thread.d.ts +1 -3
- package/dist/v1/types/thread.d.ts.map +1 -1
- package/dist/v1/types/thread.js +1 -1
- package/dist/v1/types/thread.js.map +1 -1
- package/dist/v1/utils/event-accumulator.d.ts +100 -0
- package/dist/v1/utils/event-accumulator.d.ts.map +1 -0
- package/dist/v1/utils/event-accumulator.js +715 -0
- package/dist/v1/utils/event-accumulator.js.map +1 -0
- package/dist/v1/utils/event-accumulator.test.d.ts +2 -0
- package/dist/v1/utils/event-accumulator.test.d.ts.map +1 -0
- package/dist/v1/utils/event-accumulator.test.js +1010 -0
- package/dist/v1/utils/event-accumulator.test.js.map +1 -0
- package/dist/v1/utils/json-patch.d.ts +18 -0
- package/dist/v1/utils/json-patch.d.ts.map +1 -0
- package/dist/v1/utils/json-patch.js +35 -0
- package/dist/v1/utils/json-patch.js.map +1 -0
- package/dist/v1/utils/json-patch.test.d.ts +2 -0
- package/dist/v1/utils/json-patch.test.d.ts.map +1 -0
- package/dist/v1/utils/json-patch.test.js +28 -0
- package/dist/v1/utils/json-patch.test.js.map +1 -0
- package/dist/v1/utils/registry-conversion.d.ts +53 -0
- package/dist/v1/utils/registry-conversion.d.ts.map +1 -0
- package/dist/v1/utils/registry-conversion.js +114 -0
- package/dist/v1/utils/registry-conversion.js.map +1 -0
- package/dist/v1/utils/registry-conversion.test.d.ts +2 -0
- package/dist/v1/utils/registry-conversion.test.d.ts.map +1 -0
- package/dist/v1/utils/registry-conversion.test.js +179 -0
- package/dist/v1/utils/registry-conversion.test.js.map +1 -0
- package/dist/v1/utils/stream-handler.d.ts +45 -0
- package/dist/v1/utils/stream-handler.d.ts.map +1 -0
- package/dist/v1/utils/stream-handler.js +47 -0
- package/dist/v1/utils/stream-handler.js.map +1 -0
- package/dist/v1/utils/stream-handler.test.d.ts +2 -0
- package/dist/v1/utils/stream-handler.test.d.ts.map +1 -0
- package/dist/v1/utils/stream-handler.test.js +74 -0
- package/dist/v1/utils/stream-handler.test.js.map +1 -0
- package/dist/v1/utils/tool-call-tracker.d.ts +41 -0
- package/dist/v1/utils/tool-call-tracker.d.ts.map +1 -0
- package/dist/v1/utils/tool-call-tracker.js +90 -0
- package/dist/v1/utils/tool-call-tracker.js.map +1 -0
- package/dist/v1/utils/tool-executor.d.ts +33 -0
- package/dist/v1/utils/tool-executor.d.ts.map +1 -0
- package/dist/v1/utils/tool-executor.js +103 -0
- package/dist/v1/utils/tool-executor.js.map +1 -0
- package/dist/v1/utils/tool-executor.test.d.ts +2 -0
- package/dist/v1/utils/tool-executor.test.d.ts.map +1 -0
- package/dist/v1/utils/tool-executor.test.js +222 -0
- package/dist/v1/utils/tool-executor.test.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-messages.d.ts +58 -0
- package/esm/v1/hooks/use-tambo-v1-messages.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-messages.js +51 -0
- package/esm/v1/hooks/use-tambo-v1-messages.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-messages.test.d.ts +2 -0
- package/esm/v1/hooks/use-tambo-v1-messages.test.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-messages.test.js +132 -0
- package/esm/v1/hooks/use-tambo-v1-messages.test.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-send-message.d.ts +96 -0
- package/esm/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-send-message.js +223 -0
- package/esm/v1/hooks/use-tambo-v1-send-message.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-send-message.test.d.ts +2 -0
- package/esm/v1/hooks/use-tambo-v1-send-message.test.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-send-message.test.js +822 -0
- package/esm/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts +61 -0
- package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-thread-list.js +53 -0
- package/esm/v1/hooks/use-tambo-v1-thread-list.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-thread-list.test.d.ts +2 -0
- package/esm/v1/hooks/use-tambo-v1-thread-list.test.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-thread-list.test.js +93 -0
- package/esm/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-thread.d.ts +37 -0
- package/esm/v1/hooks/use-tambo-v1-thread.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-thread.js +46 -0
- package/esm/v1/hooks/use-tambo-v1-thread.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-thread.test.d.ts +2 -0
- package/esm/v1/hooks/use-tambo-v1-thread.test.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-thread.test.js +78 -0
- package/esm/v1/hooks/use-tambo-v1-thread.test.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1.d.ts +107 -0
- package/esm/v1/hooks/use-tambo-v1.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1.js +84 -0
- package/esm/v1/hooks/use-tambo-v1.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1.test.d.ts +2 -0
- package/esm/v1/hooks/use-tambo-v1.test.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1.test.js +145 -0
- package/esm/v1/hooks/use-tambo-v1.test.js.map +1 -0
- package/esm/v1/index.d.ts +54 -16
- package/esm/v1/index.d.ts.map +1 -1
- package/esm/v1/index.js +64 -27
- package/esm/v1/index.js.map +1 -1
- package/esm/v1/providers/tambo-v1-provider.d.ts +91 -0
- package/esm/v1/providers/tambo-v1-provider.d.ts.map +1 -0
- package/esm/v1/providers/tambo-v1-provider.js +74 -0
- package/esm/v1/providers/tambo-v1-provider.js.map +1 -0
- package/esm/v1/providers/tambo-v1-provider.test.d.ts +2 -0
- package/esm/v1/providers/tambo-v1-provider.test.d.ts.map +1 -0
- package/esm/v1/providers/tambo-v1-provider.test.js +118 -0
- package/esm/v1/providers/tambo-v1-provider.test.js.map +1 -0
- package/esm/v1/providers/tambo-v1-stream-context.d.ts +136 -0
- package/esm/v1/providers/tambo-v1-stream-context.d.ts.map +1 -0
- package/esm/v1/providers/tambo-v1-stream-context.js +191 -0
- package/esm/v1/providers/tambo-v1-stream-context.js.map +1 -0
- package/esm/v1/providers/tambo-v1-stream-context.test.d.ts +2 -0
- package/esm/v1/providers/tambo-v1-stream-context.test.d.ts.map +1 -0
- package/esm/v1/providers/tambo-v1-stream-context.test.js +80 -0
- package/esm/v1/providers/tambo-v1-stream-context.test.js.map +1 -0
- package/esm/v1/types/component.d.ts +5 -2
- package/esm/v1/types/component.d.ts.map +1 -1
- package/esm/v1/types/component.js +5 -2
- package/esm/v1/types/component.js.map +1 -1
- package/esm/v1/types/event.d.ts +21 -12
- package/esm/v1/types/event.d.ts.map +1 -1
- package/esm/v1/types/event.js +44 -2
- package/esm/v1/types/event.js.map +1 -1
- package/esm/v1/types/event.test.d.ts +2 -0
- package/esm/v1/types/event.test.d.ts.map +1 -0
- package/esm/v1/types/event.test.js +68 -0
- package/esm/v1/types/event.test.js.map +1 -0
- package/esm/v1/types/message.d.ts +4 -8
- package/esm/v1/types/message.d.ts.map +1 -1
- package/esm/v1/types/message.js +1 -1
- package/esm/v1/types/message.js.map +1 -1
- package/esm/v1/types/thread.d.ts +1 -3
- package/esm/v1/types/thread.d.ts.map +1 -1
- package/esm/v1/types/thread.js +1 -1
- package/esm/v1/types/thread.js.map +1 -1
- package/esm/v1/utils/event-accumulator.d.ts +100 -0
- package/esm/v1/utils/event-accumulator.d.ts.map +1 -0
- package/esm/v1/utils/event-accumulator.js +708 -0
- package/esm/v1/utils/event-accumulator.js.map +1 -0
- package/esm/v1/utils/event-accumulator.test.d.ts +2 -0
- package/esm/v1/utils/event-accumulator.test.d.ts.map +1 -0
- package/esm/v1/utils/event-accumulator.test.js +1008 -0
- package/esm/v1/utils/event-accumulator.test.js.map +1 -0
- package/esm/v1/utils/json-patch.d.ts +18 -0
- package/esm/v1/utils/json-patch.d.ts.map +1 -0
- package/esm/v1/utils/json-patch.js +32 -0
- package/esm/v1/utils/json-patch.js.map +1 -0
- package/esm/v1/utils/json-patch.test.d.ts +2 -0
- package/esm/v1/utils/json-patch.test.d.ts.map +1 -0
- package/esm/v1/utils/json-patch.test.js +26 -0
- package/esm/v1/utils/json-patch.test.js.map +1 -0
- package/esm/v1/utils/registry-conversion.d.ts +53 -0
- package/esm/v1/utils/registry-conversion.d.ts.map +1 -0
- package/esm/v1/utils/registry-conversion.js +108 -0
- package/esm/v1/utils/registry-conversion.js.map +1 -0
- package/esm/v1/utils/registry-conversion.test.d.ts +2 -0
- package/esm/v1/utils/registry-conversion.test.d.ts.map +1 -0
- package/esm/v1/utils/registry-conversion.test.js +177 -0
- package/esm/v1/utils/registry-conversion.test.js.map +1 -0
- package/esm/v1/utils/stream-handler.d.ts +45 -0
- package/esm/v1/utils/stream-handler.d.ts.map +1 -0
- package/esm/v1/utils/stream-handler.js +44 -0
- package/esm/v1/utils/stream-handler.js.map +1 -0
- package/esm/v1/utils/stream-handler.test.d.ts +2 -0
- package/esm/v1/utils/stream-handler.test.d.ts.map +1 -0
- package/esm/v1/utils/stream-handler.test.js +72 -0
- package/esm/v1/utils/stream-handler.test.js.map +1 -0
- package/esm/v1/utils/tool-call-tracker.d.ts +41 -0
- package/esm/v1/utils/tool-call-tracker.d.ts.map +1 -0
- package/esm/v1/utils/tool-call-tracker.js +86 -0
- package/esm/v1/utils/tool-call-tracker.js.map +1 -0
- package/esm/v1/utils/tool-executor.d.ts +33 -0
- package/esm/v1/utils/tool-executor.d.ts.map +1 -0
- package/esm/v1/utils/tool-executor.js +99 -0
- package/esm/v1/utils/tool-executor.js.map +1 -0
- package/esm/v1/utils/tool-executor.test.d.ts +2 -0
- package/esm/v1/utils/tool-executor.test.d.ts.map +1 -0
- package/esm/v1/utils/tool-executor.test.js +220 -0
- package/esm/v1/utils/tool-executor.test.js.map +1 -0
- package/package.json +7 -6
- package/dist/v1/types/tool.d.ts +0 -52
- package/dist/v1/types/tool.d.ts.map +0 -1
- package/dist/v1/types/tool.js +0 -11
- package/dist/v1/types/tool.js.map +0 -1
- package/esm/v1/types/tool.d.ts +0 -52
- package/esm/v1/types/tool.d.ts.map +0 -1
- package/esm/v1/types/tool.js +0 -10
- package/esm/v1/types/tool.js.map +0 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tool Executor for v1 API
|
|
4
|
+
*
|
|
5
|
+
* Handles automatic execution of client-side tools when the model
|
|
6
|
+
* requests them via `tambo.run.awaiting_input` events.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.executeClientTool = executeClientTool;
|
|
10
|
+
exports.executeAllPendingTools = executeAllPendingTools;
|
|
11
|
+
/**
|
|
12
|
+
* Execute a single client-side tool and return the result.
|
|
13
|
+
* @param tool - The tool definition from the registry
|
|
14
|
+
* @param toolCallId - The ID of the tool call to respond to
|
|
15
|
+
* @param args - The parsed arguments for the tool
|
|
16
|
+
* @returns ToolResultContent with the execution result or error
|
|
17
|
+
*/
|
|
18
|
+
async function executeClientTool(tool, toolCallId, args) {
|
|
19
|
+
try {
|
|
20
|
+
const result = await tool.tool(args);
|
|
21
|
+
// Transform result to content if transformer provided
|
|
22
|
+
let content;
|
|
23
|
+
if (tool.transformToContent) {
|
|
24
|
+
// transformToContent may return content parts in beta format
|
|
25
|
+
// Convert to v1 format (TextContent | ResourceContent)
|
|
26
|
+
const transformed = await tool.transformToContent(result);
|
|
27
|
+
content = transformed.map((part) => {
|
|
28
|
+
if (part.type === "text" && "text" in part && part.text) {
|
|
29
|
+
return { type: "text", text: part.text };
|
|
30
|
+
}
|
|
31
|
+
// For other types, stringify as text
|
|
32
|
+
return {
|
|
33
|
+
type: "text",
|
|
34
|
+
text: JSON.stringify(part),
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// Default: stringify result as text
|
|
40
|
+
content = [
|
|
41
|
+
{
|
|
42
|
+
type: "text",
|
|
43
|
+
text: typeof result === "string" ? result : JSON.stringify(result),
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
type: "tool_result",
|
|
49
|
+
toolUseId: toolCallId,
|
|
50
|
+
content,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
return {
|
|
55
|
+
type: "tool_result",
|
|
56
|
+
toolUseId: toolCallId,
|
|
57
|
+
content: [
|
|
58
|
+
{
|
|
59
|
+
type: "text",
|
|
60
|
+
text: error instanceof Error ? error.message : "Tool execution failed",
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Execute all pending tool calls and return their results.
|
|
68
|
+
* Tools are executed sequentially to avoid race conditions when
|
|
69
|
+
* tools may have side effects that depend on each other.
|
|
70
|
+
* @param toolCalls - Map of tool call IDs to their call details
|
|
71
|
+
* @param registry - Registry of tool names to their definitions (Map or Record)
|
|
72
|
+
* @returns Array of ToolResultContent for all executed tools
|
|
73
|
+
*/
|
|
74
|
+
async function executeAllPendingTools(toolCalls, registry) {
|
|
75
|
+
const results = [];
|
|
76
|
+
// Normalize registry to allow lookup regardless of Map or Record
|
|
77
|
+
const getTool = (name) => {
|
|
78
|
+
if (registry instanceof Map) {
|
|
79
|
+
return registry.get(name);
|
|
80
|
+
}
|
|
81
|
+
return registry[name];
|
|
82
|
+
};
|
|
83
|
+
for (const [toolCallId, { name, input }] of toolCalls) {
|
|
84
|
+
const tool = getTool(name);
|
|
85
|
+
if (!tool) {
|
|
86
|
+
results.push({
|
|
87
|
+
type: "tool_result",
|
|
88
|
+
toolUseId: toolCallId,
|
|
89
|
+
content: [
|
|
90
|
+
{
|
|
91
|
+
type: "text",
|
|
92
|
+
text: `Tool "${name}" not found in registry`,
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
});
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const result = await executeClientTool(tool, toolCallId, input);
|
|
99
|
+
results.push(result);
|
|
100
|
+
}
|
|
101
|
+
return results;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=tool-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-executor.js","sourceRoot":"","sources":["../../../src/v1/utils/tool-executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tool Executor for v1 API\n *\n * Handles automatic execution of client-side tools when the model\n * requests them via `tambo.run.awaiting_input` events.\n */\n\nimport type { TamboTool } from \"../../model/component-metadata\";\nimport type {\n ToolResultContent,\n TextContent,\n ResourceContent,\n} from \"@tambo-ai/typescript-sdk/resources/threads/threads\";\n\n/**\n * Pending tool call from the stream accumulator\n */\nexport interface PendingToolCall {\n name: string;\n input: Record<string, unknown>;\n}\n\n/**\n * Execute a single client-side tool and return the result.\n * @param tool - The tool definition from the registry\n * @param toolCallId - The ID of the tool call to respond to\n * @param args - The parsed arguments for the tool\n * @returns ToolResultContent with the execution result or error\n */\nexport async function executeClientTool(\n tool: TamboTool,\n toolCallId: string,\n args: Record<string, unknown>,\n): Promise<ToolResultContent> {\n try {\n const result = await tool.tool(args);\n\n // Transform result to content if transformer provided\n let content: (TextContent | ResourceContent)[];\n if (tool.transformToContent) {\n // transformToContent may return content parts in beta format\n // Convert to v1 format (TextContent | ResourceContent)\n const transformed = await tool.transformToContent(result);\n content = transformed.map((part) => {\n if (part.type === \"text\" && \"text\" in part && part.text) {\n return { type: \"text\" as const, text: part.text };\n }\n // For other types, stringify as text\n return {\n type: \"text\" as const,\n text: JSON.stringify(part),\n };\n });\n } else {\n // Default: stringify result as text\n content = [\n {\n type: \"text\" as const,\n text: typeof result === \"string\" ? result : JSON.stringify(result),\n },\n ];\n }\n\n return {\n type: \"tool_result\",\n toolUseId: toolCallId,\n content,\n };\n } catch (error) {\n return {\n type: \"tool_result\",\n toolUseId: toolCallId,\n content: [\n {\n type: \"text\" as const,\n text:\n error instanceof Error ? error.message : \"Tool execution failed\",\n },\n ],\n };\n }\n}\n\n/**\n * Execute all pending tool calls and return their results.\n * Tools are executed sequentially to avoid race conditions when\n * tools may have side effects that depend on each other.\n * @param toolCalls - Map of tool call IDs to their call details\n * @param registry - Registry of tool names to their definitions (Map or Record)\n * @returns Array of ToolResultContent for all executed tools\n */\nexport async function executeAllPendingTools(\n toolCalls: Map<string, PendingToolCall>,\n registry: Map<string, TamboTool> | Record<string, TamboTool>,\n): Promise<ToolResultContent[]> {\n const results: ToolResultContent[] = [];\n\n // Normalize registry to allow lookup regardless of Map or Record\n const getTool = (name: string): TamboTool | undefined => {\n if (registry instanceof Map) {\n return registry.get(name);\n }\n return registry[name];\n };\n\n for (const [toolCallId, { name, input }] of toolCalls) {\n const tool = getTool(name);\n if (!tool) {\n results.push({\n type: \"tool_result\",\n toolUseId: toolCallId,\n content: [\n {\n type: \"text\" as const,\n text: `Tool \"${name}\" not found in registry`,\n },\n ],\n });\n continue;\n }\n\n const result = await executeClientTool(tool, toolCallId, input);\n results.push(result);\n }\n\n return results;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-executor.test.d.ts","sourceRoot":"","sources":["../../../src/v1/utils/tool-executor.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const zod_1 = require("zod");
|
|
4
|
+
const tool_executor_1 = require("./tool-executor");
|
|
5
|
+
describe("tool-executor", () => {
|
|
6
|
+
describe("executeClientTool", () => {
|
|
7
|
+
it("executes a tool and returns text result", async () => {
|
|
8
|
+
const tool = {
|
|
9
|
+
name: "get_weather",
|
|
10
|
+
description: "Gets weather",
|
|
11
|
+
tool: async ({ city }) => `Weather in ${city} is sunny`,
|
|
12
|
+
inputSchema: zod_1.z.object({ city: zod_1.z.string() }),
|
|
13
|
+
outputSchema: zod_1.z.string(),
|
|
14
|
+
};
|
|
15
|
+
const result = await (0, tool_executor_1.executeClientTool)(tool, "call-1", {
|
|
16
|
+
city: "Seattle",
|
|
17
|
+
});
|
|
18
|
+
expect(result).toEqual({
|
|
19
|
+
type: "tool_result",
|
|
20
|
+
toolUseId: "call-1",
|
|
21
|
+
content: [{ type: "text", text: "Weather in Seattle is sunny" }],
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
it("stringifies non-string results", async () => {
|
|
25
|
+
const tool = {
|
|
26
|
+
name: "get_data",
|
|
27
|
+
description: "Gets data",
|
|
28
|
+
tool: async () => ({ value: 42 }),
|
|
29
|
+
inputSchema: zod_1.z.object({}),
|
|
30
|
+
outputSchema: zod_1.z.object({ value: zod_1.z.number() }),
|
|
31
|
+
};
|
|
32
|
+
const result = await (0, tool_executor_1.executeClientTool)(tool, "call-2", {});
|
|
33
|
+
expect(result).toEqual({
|
|
34
|
+
type: "tool_result",
|
|
35
|
+
toolUseId: "call-2",
|
|
36
|
+
content: [{ type: "text", text: '{"value":42}' }],
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
it("uses transformToContent when provided", async () => {
|
|
40
|
+
const tool = {
|
|
41
|
+
name: "custom_tool",
|
|
42
|
+
description: "Custom tool",
|
|
43
|
+
tool: async () => "custom result",
|
|
44
|
+
inputSchema: zod_1.z.object({}),
|
|
45
|
+
outputSchema: zod_1.z.string(),
|
|
46
|
+
transformToContent: (result) => [
|
|
47
|
+
{ type: "text", text: `Transformed: ${result}` },
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
const result = await (0, tool_executor_1.executeClientTool)(tool, "call-3", {});
|
|
51
|
+
expect(result).toEqual({
|
|
52
|
+
type: "tool_result",
|
|
53
|
+
toolUseId: "call-3",
|
|
54
|
+
content: [{ type: "text", text: "Transformed: custom result" }],
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
it("handles transformToContent with non-text types by stringifying", async () => {
|
|
58
|
+
const tool = {
|
|
59
|
+
name: "image_tool",
|
|
60
|
+
description: "Image tool",
|
|
61
|
+
tool: async () => "image data",
|
|
62
|
+
inputSchema: zod_1.z.object({}),
|
|
63
|
+
outputSchema: zod_1.z.string(),
|
|
64
|
+
transformToContent: () => [
|
|
65
|
+
{
|
|
66
|
+
type: "image_url",
|
|
67
|
+
image_url: { url: "https://example.com/image.png" },
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
const result = await (0, tool_executor_1.executeClientTool)(tool, "call-4", {});
|
|
72
|
+
expect(result).toEqual({
|
|
73
|
+
type: "tool_result",
|
|
74
|
+
toolUseId: "call-4",
|
|
75
|
+
content: [
|
|
76
|
+
{
|
|
77
|
+
type: "text",
|
|
78
|
+
text: '{"type":"image_url","image_url":{"url":"https://example.com/image.png"}}',
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
it("handles tool execution errors gracefully", async () => {
|
|
84
|
+
const tool = {
|
|
85
|
+
name: "failing_tool",
|
|
86
|
+
description: "A tool that fails",
|
|
87
|
+
tool: async () => {
|
|
88
|
+
throw new Error("Tool failed!");
|
|
89
|
+
},
|
|
90
|
+
inputSchema: zod_1.z.object({}),
|
|
91
|
+
outputSchema: zod_1.z.void(),
|
|
92
|
+
};
|
|
93
|
+
const result = await (0, tool_executor_1.executeClientTool)(tool, "call-5", {});
|
|
94
|
+
expect(result).toEqual({
|
|
95
|
+
type: "tool_result",
|
|
96
|
+
toolUseId: "call-5",
|
|
97
|
+
content: [{ type: "text", text: "Tool failed!" }],
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
it("handles non-Error throws gracefully", async () => {
|
|
101
|
+
const tool = {
|
|
102
|
+
name: "throwing_tool",
|
|
103
|
+
description: "A tool that throws a string",
|
|
104
|
+
tool: async () => {
|
|
105
|
+
throw "string error";
|
|
106
|
+
},
|
|
107
|
+
inputSchema: zod_1.z.object({}),
|
|
108
|
+
outputSchema: zod_1.z.void(),
|
|
109
|
+
};
|
|
110
|
+
const result = await (0, tool_executor_1.executeClientTool)(tool, "call-6", {});
|
|
111
|
+
expect(result).toEqual({
|
|
112
|
+
type: "tool_result",
|
|
113
|
+
toolUseId: "call-6",
|
|
114
|
+
content: [{ type: "text", text: "Tool execution failed" }],
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
describe("executeAllPendingTools", () => {
|
|
119
|
+
it("executes multiple tools with Map registry", async () => {
|
|
120
|
+
const registry = new Map([
|
|
121
|
+
[
|
|
122
|
+
"add",
|
|
123
|
+
{
|
|
124
|
+
name: "add",
|
|
125
|
+
description: "Adds numbers",
|
|
126
|
+
tool: async ({ a, b }) => a + b,
|
|
127
|
+
inputSchema: zod_1.z.object({ a: zod_1.z.number(), b: zod_1.z.number() }),
|
|
128
|
+
outputSchema: zod_1.z.number(),
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
[
|
|
132
|
+
"multiply",
|
|
133
|
+
{
|
|
134
|
+
name: "multiply",
|
|
135
|
+
description: "Multiplies numbers",
|
|
136
|
+
tool: async ({ a, b }) => a * b,
|
|
137
|
+
inputSchema: zod_1.z.object({ a: zod_1.z.number(), b: zod_1.z.number() }),
|
|
138
|
+
outputSchema: zod_1.z.number(),
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
]);
|
|
142
|
+
const toolCalls = new Map([
|
|
143
|
+
["call-1", { name: "add", input: { a: 2, b: 3 } }],
|
|
144
|
+
["call-2", { name: "multiply", input: { a: 4, b: 5 } }],
|
|
145
|
+
]);
|
|
146
|
+
const results = await (0, tool_executor_1.executeAllPendingTools)(toolCalls, registry);
|
|
147
|
+
expect(results).toHaveLength(2);
|
|
148
|
+
expect(results[0]).toEqual({
|
|
149
|
+
type: "tool_result",
|
|
150
|
+
toolUseId: "call-1",
|
|
151
|
+
content: [{ type: "text", text: "5" }],
|
|
152
|
+
});
|
|
153
|
+
expect(results[1]).toEqual({
|
|
154
|
+
type: "tool_result",
|
|
155
|
+
toolUseId: "call-2",
|
|
156
|
+
content: [{ type: "text", text: "20" }],
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
it("executes tools with Record registry", async () => {
|
|
160
|
+
const registry = {
|
|
161
|
+
greet: {
|
|
162
|
+
name: "greet",
|
|
163
|
+
description: "Greets user",
|
|
164
|
+
tool: async ({ name }) => `Hello, ${name}!`,
|
|
165
|
+
inputSchema: zod_1.z.object({ name: zod_1.z.string() }),
|
|
166
|
+
outputSchema: zod_1.z.string(),
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
const toolCalls = new Map([
|
|
170
|
+
["call-1", { name: "greet", input: { name: "World" } }],
|
|
171
|
+
]);
|
|
172
|
+
const results = await (0, tool_executor_1.executeAllPendingTools)(toolCalls, registry);
|
|
173
|
+
expect(results).toHaveLength(1);
|
|
174
|
+
expect(results[0]).toEqual({
|
|
175
|
+
type: "tool_result",
|
|
176
|
+
toolUseId: "call-1",
|
|
177
|
+
content: [{ type: "text", text: "Hello, World!" }],
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
it("returns error result for unknown tools", async () => {
|
|
181
|
+
const registry = new Map();
|
|
182
|
+
const toolCalls = new Map([
|
|
183
|
+
["call-1", { name: "unknown_tool", input: {} }],
|
|
184
|
+
]);
|
|
185
|
+
const results = await (0, tool_executor_1.executeAllPendingTools)(toolCalls, registry);
|
|
186
|
+
expect(results).toHaveLength(1);
|
|
187
|
+
expect(results[0]).toEqual({
|
|
188
|
+
type: "tool_result",
|
|
189
|
+
toolUseId: "call-1",
|
|
190
|
+
content: [
|
|
191
|
+
{ type: "text", text: 'Tool "unknown_tool" not found in registry' },
|
|
192
|
+
],
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
it("handles mixed known and unknown tools", async () => {
|
|
196
|
+
const registry = new Map([
|
|
197
|
+
[
|
|
198
|
+
"known",
|
|
199
|
+
{
|
|
200
|
+
name: "known",
|
|
201
|
+
description: "Known tool",
|
|
202
|
+
tool: async () => "success",
|
|
203
|
+
inputSchema: zod_1.z.object({}),
|
|
204
|
+
outputSchema: zod_1.z.string(),
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
]);
|
|
208
|
+
const toolCalls = new Map([
|
|
209
|
+
["call-1", { name: "known", input: {} }],
|
|
210
|
+
["call-2", { name: "unknown", input: {} }],
|
|
211
|
+
]);
|
|
212
|
+
const results = await (0, tool_executor_1.executeAllPendingTools)(toolCalls, registry);
|
|
213
|
+
expect(results).toHaveLength(2);
|
|
214
|
+
expect(results[0].content[0]).toEqual({ type: "text", text: "success" });
|
|
215
|
+
expect(results[1].content[0]).toEqual({
|
|
216
|
+
type: "text",
|
|
217
|
+
text: 'Tool "unknown" not found in registry',
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
//# sourceMappingURL=tool-executor.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-executor.test.js","sourceRoot":"","sources":["../../../src/v1/utils/tool-executor.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\nimport type { TamboTool } from \"../../model/component-metadata\";\nimport {\n executeClientTool,\n executeAllPendingTools,\n type PendingToolCall,\n} from \"./tool-executor\";\n\ndescribe(\"tool-executor\", () => {\n describe(\"executeClientTool\", () => {\n it(\"executes a tool and returns text result\", async () => {\n const tool: TamboTool = {\n name: \"get_weather\",\n description: \"Gets weather\",\n tool: async ({ city }: { city: string }) =>\n `Weather in ${city} is sunny`,\n inputSchema: z.object({ city: z.string() }),\n outputSchema: z.string(),\n };\n\n const result = await executeClientTool(tool, \"call-1\", {\n city: \"Seattle\",\n });\n\n expect(result).toEqual({\n type: \"tool_result\",\n toolUseId: \"call-1\",\n content: [{ type: \"text\", text: \"Weather in Seattle is sunny\" }],\n });\n });\n\n it(\"stringifies non-string results\", async () => {\n const tool: TamboTool = {\n name: \"get_data\",\n description: \"Gets data\",\n tool: async () => ({ value: 42 }),\n inputSchema: z.object({}),\n outputSchema: z.object({ value: z.number() }),\n };\n\n const result = await executeClientTool(tool, \"call-2\", {});\n\n expect(result).toEqual({\n type: \"tool_result\",\n toolUseId: \"call-2\",\n content: [{ type: \"text\", text: '{\"value\":42}' }],\n });\n });\n\n it(\"uses transformToContent when provided\", async () => {\n const tool: TamboTool = {\n name: \"custom_tool\",\n description: \"Custom tool\",\n tool: async () => \"custom result\",\n inputSchema: z.object({}),\n outputSchema: z.string(),\n transformToContent: (result) => [\n { type: \"text\", text: `Transformed: ${result}` },\n ],\n };\n\n const result = await executeClientTool(tool, \"call-3\", {});\n\n expect(result).toEqual({\n type: \"tool_result\",\n toolUseId: \"call-3\",\n content: [{ type: \"text\", text: \"Transformed: custom result\" }],\n });\n });\n\n it(\"handles transformToContent with non-text types by stringifying\", async () => {\n const tool: TamboTool = {\n name: \"image_tool\",\n description: \"Image tool\",\n tool: async () => \"image data\",\n inputSchema: z.object({}),\n outputSchema: z.string(),\n transformToContent: () => [\n {\n type: \"image_url\",\n image_url: { url: \"https://example.com/image.png\" },\n },\n ],\n };\n\n const result = await executeClientTool(tool, \"call-4\", {});\n\n expect(result).toEqual({\n type: \"tool_result\",\n toolUseId: \"call-4\",\n content: [\n {\n type: \"text\",\n text: '{\"type\":\"image_url\",\"image_url\":{\"url\":\"https://example.com/image.png\"}}',\n },\n ],\n });\n });\n\n it(\"handles tool execution errors gracefully\", async () => {\n const tool: TamboTool = {\n name: \"failing_tool\",\n description: \"A tool that fails\",\n tool: async () => {\n throw new Error(\"Tool failed!\");\n },\n inputSchema: z.object({}),\n outputSchema: z.void(),\n };\n\n const result = await executeClientTool(tool, \"call-5\", {});\n\n expect(result).toEqual({\n type: \"tool_result\",\n toolUseId: \"call-5\",\n content: [{ type: \"text\", text: \"Tool failed!\" }],\n });\n });\n\n it(\"handles non-Error throws gracefully\", async () => {\n const tool: TamboTool = {\n name: \"throwing_tool\",\n description: \"A tool that throws a string\",\n tool: async () => {\n throw \"string error\";\n },\n inputSchema: z.object({}),\n outputSchema: z.void(),\n };\n\n const result = await executeClientTool(tool, \"call-6\", {});\n\n expect(result).toEqual({\n type: \"tool_result\",\n toolUseId: \"call-6\",\n content: [{ type: \"text\", text: \"Tool execution failed\" }],\n });\n });\n });\n\n describe(\"executeAllPendingTools\", () => {\n it(\"executes multiple tools with Map registry\", async () => {\n const registry = new Map<string, TamboTool>([\n [\n \"add\",\n {\n name: \"add\",\n description: \"Adds numbers\",\n tool: async ({ a, b }: { a: number; b: number }) => a + b,\n inputSchema: z.object({ a: z.number(), b: z.number() }),\n outputSchema: z.number(),\n },\n ],\n [\n \"multiply\",\n {\n name: \"multiply\",\n description: \"Multiplies numbers\",\n tool: async ({ a, b }: { a: number; b: number }) => a * b,\n inputSchema: z.object({ a: z.number(), b: z.number() }),\n outputSchema: z.number(),\n },\n ],\n ]);\n\n const toolCalls = new Map<string, PendingToolCall>([\n [\"call-1\", { name: \"add\", input: { a: 2, b: 3 } }],\n [\"call-2\", { name: \"multiply\", input: { a: 4, b: 5 } }],\n ]);\n\n const results = await executeAllPendingTools(toolCalls, registry);\n\n expect(results).toHaveLength(2);\n expect(results[0]).toEqual({\n type: \"tool_result\",\n toolUseId: \"call-1\",\n content: [{ type: \"text\", text: \"5\" }],\n });\n expect(results[1]).toEqual({\n type: \"tool_result\",\n toolUseId: \"call-2\",\n content: [{ type: \"text\", text: \"20\" }],\n });\n });\n\n it(\"executes tools with Record registry\", async () => {\n const registry: Record<string, TamboTool> = {\n greet: {\n name: \"greet\",\n description: \"Greets user\",\n tool: async ({ name }: { name: string }) => `Hello, ${name}!`,\n inputSchema: z.object({ name: z.string() }),\n outputSchema: z.string(),\n },\n };\n\n const toolCalls = new Map<string, PendingToolCall>([\n [\"call-1\", { name: \"greet\", input: { name: \"World\" } }],\n ]);\n\n const results = await executeAllPendingTools(toolCalls, registry);\n\n expect(results).toHaveLength(1);\n expect(results[0]).toEqual({\n type: \"tool_result\",\n toolUseId: \"call-1\",\n content: [{ type: \"text\", text: \"Hello, World!\" }],\n });\n });\n\n it(\"returns error result for unknown tools\", async () => {\n const registry = new Map<string, TamboTool>();\n\n const toolCalls = new Map<string, PendingToolCall>([\n [\"call-1\", { name: \"unknown_tool\", input: {} }],\n ]);\n\n const results = await executeAllPendingTools(toolCalls, registry);\n\n expect(results).toHaveLength(1);\n expect(results[0]).toEqual({\n type: \"tool_result\",\n toolUseId: \"call-1\",\n content: [\n { type: \"text\", text: 'Tool \"unknown_tool\" not found in registry' },\n ],\n });\n });\n\n it(\"handles mixed known and unknown tools\", async () => {\n const registry = new Map<string, TamboTool>([\n [\n \"known\",\n {\n name: \"known\",\n description: \"Known tool\",\n tool: async () => \"success\",\n inputSchema: z.object({}),\n outputSchema: z.string(),\n },\n ],\n ]);\n\n const toolCalls = new Map<string, PendingToolCall>([\n [\"call-1\", { name: \"known\", input: {} }],\n [\"call-2\", { name: \"unknown\", input: {} }],\n ]);\n\n const results = await executeAllPendingTools(toolCalls, registry);\n\n expect(results).toHaveLength(2);\n expect(results[0].content[0]).toEqual({ type: \"text\", text: \"success\" });\n expect(results[1].content[0]).toEqual({\n type: \"text\",\n text: 'Tool \"unknown\" not found in registry',\n });\n });\n });\n});\n"]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { TamboV1Message } from "../types/message";
|
|
2
|
+
/**
|
|
3
|
+
* Return type for useTamboV1Messages hook
|
|
4
|
+
*/
|
|
5
|
+
export interface UseTamboV1MessagesReturn {
|
|
6
|
+
/**
|
|
7
|
+
* All messages in the thread
|
|
8
|
+
*/
|
|
9
|
+
messages: TamboV1Message[];
|
|
10
|
+
/**
|
|
11
|
+
* The most recent message (last in the list)
|
|
12
|
+
*/
|
|
13
|
+
lastMessage: TamboV1Message | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* User messages only
|
|
16
|
+
*/
|
|
17
|
+
userMessages: TamboV1Message[];
|
|
18
|
+
/**
|
|
19
|
+
* Assistant messages only
|
|
20
|
+
*/
|
|
21
|
+
assistantMessages: TamboV1Message[];
|
|
22
|
+
/**
|
|
23
|
+
* Whether there are any messages
|
|
24
|
+
*/
|
|
25
|
+
hasMessages: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Total message count
|
|
28
|
+
*/
|
|
29
|
+
messageCount: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Hook to access messages in a thread.
|
|
33
|
+
*
|
|
34
|
+
* Provides filtered views of messages (user-only, assistant-only)
|
|
35
|
+
* and metadata about the message list.
|
|
36
|
+
* @param threadId - Thread ID to get messages for
|
|
37
|
+
* @returns Message list and utilities
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* function MessageList({ threadId }: { threadId: string }) {
|
|
41
|
+
* const { messages, hasMessages, lastMessage } = useTamboV1Messages(threadId);
|
|
42
|
+
*
|
|
43
|
+
* if (!hasMessages) {
|
|
44
|
+
* return <EmptyState />;
|
|
45
|
+
* }
|
|
46
|
+
*
|
|
47
|
+
* return (
|
|
48
|
+
* <div>
|
|
49
|
+
* {messages.map(msg => (
|
|
50
|
+
* <Message key={msg.id} message={msg} />
|
|
51
|
+
* ))}
|
|
52
|
+
* </div>
|
|
53
|
+
* );
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function useTamboV1Messages(threadId: string): UseTamboV1MessagesReturn;
|
|
58
|
+
//# sourceMappingURL=use-tambo-v1-messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-tambo-v1-messages.d.ts","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-messages.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,QAAQ,EAAE,cAAc,EAAE,CAAC;IAE3B;;OAEG;IACH,WAAW,EAAE,cAAc,GAAG,SAAS,CAAC;IAExC;;OAEG;IACH,YAAY,EAAE,cAAc,EAAE,CAAC;IAE/B;;OAEG;IACH,iBAAiB,EAAE,cAAc,EAAE,CAAC;IAEpC;;OAEG;IACH,WAAW,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,wBAAwB,CAgB7E"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
/**
|
|
3
|
+
* useTamboV1Messages - Messages Hook for v1 API
|
|
4
|
+
*
|
|
5
|
+
* Provides access to messages in a thread with streaming state awareness.
|
|
6
|
+
* Messages are accumulated from AG-UI events during streaming.
|
|
7
|
+
*/
|
|
8
|
+
import { useMemo } from "react";
|
|
9
|
+
import { useStreamState } from "../providers/tambo-v1-stream-context";
|
|
10
|
+
/**
|
|
11
|
+
* Hook to access messages in a thread.
|
|
12
|
+
*
|
|
13
|
+
* Provides filtered views of messages (user-only, assistant-only)
|
|
14
|
+
* and metadata about the message list.
|
|
15
|
+
* @param threadId - Thread ID to get messages for
|
|
16
|
+
* @returns Message list and utilities
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* function MessageList({ threadId }: { threadId: string }) {
|
|
20
|
+
* const { messages, hasMessages, lastMessage } = useTamboV1Messages(threadId);
|
|
21
|
+
*
|
|
22
|
+
* if (!hasMessages) {
|
|
23
|
+
* return <EmptyState />;
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* return (
|
|
27
|
+
* <div>
|
|
28
|
+
* {messages.map(msg => (
|
|
29
|
+
* <Message key={msg.id} message={msg} />
|
|
30
|
+
* ))}
|
|
31
|
+
* </div>
|
|
32
|
+
* );
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function useTamboV1Messages(threadId) {
|
|
37
|
+
const streamState = useStreamState();
|
|
38
|
+
const threadState = streamState.threadMap[threadId];
|
|
39
|
+
return useMemo(() => {
|
|
40
|
+
const messages = threadState?.thread.messages ?? [];
|
|
41
|
+
return {
|
|
42
|
+
messages,
|
|
43
|
+
lastMessage: messages[messages.length - 1],
|
|
44
|
+
userMessages: messages.filter((m) => m.role === "user"),
|
|
45
|
+
assistantMessages: messages.filter((m) => m.role === "assistant"),
|
|
46
|
+
hasMessages: messages.length > 0,
|
|
47
|
+
messageCount: messages.length,
|
|
48
|
+
};
|
|
49
|
+
}, [threadState?.thread.messages]);
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=use-tambo-v1-messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-tambo-v1-messages.js","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-messages.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAsCtE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,MAAM,WAAW,GAAG,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAEpD,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,QAAQ,GAAG,WAAW,EAAE,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;QAEpD,OAAO;YACL,QAAQ;YACR,WAAW,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;YAC1C,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;YACvD,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC;YACjE,WAAW,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC;YAChC,YAAY,EAAE,QAAQ,CAAC,MAAM;SAC9B,CAAC;IACJ,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;AACrC,CAAC","sourcesContent":["\"use client\";\n\n/**\n * useTamboV1Messages - Messages Hook for v1 API\n *\n * Provides access to messages in a thread with streaming state awareness.\n * Messages are accumulated from AG-UI events during streaming.\n */\n\nimport { useMemo } from \"react\";\nimport { useStreamState } from \"../providers/tambo-v1-stream-context\";\nimport type { TamboV1Message } from \"../types/message\";\n\n/**\n * Return type for useTamboV1Messages hook\n */\nexport interface UseTamboV1MessagesReturn {\n /**\n * All messages in the thread\n */\n messages: TamboV1Message[];\n\n /**\n * The most recent message (last in the list)\n */\n lastMessage: TamboV1Message | undefined;\n\n /**\n * User messages only\n */\n userMessages: TamboV1Message[];\n\n /**\n * Assistant messages only\n */\n assistantMessages: TamboV1Message[];\n\n /**\n * Whether there are any messages\n */\n hasMessages: boolean;\n\n /**\n * Total message count\n */\n messageCount: number;\n}\n\n/**\n * Hook to access messages in a thread.\n *\n * Provides filtered views of messages (user-only, assistant-only)\n * and metadata about the message list.\n * @param threadId - Thread ID to get messages for\n * @returns Message list and utilities\n * @example\n * ```tsx\n * function MessageList({ threadId }: { threadId: string }) {\n * const { messages, hasMessages, lastMessage } = useTamboV1Messages(threadId);\n *\n * if (!hasMessages) {\n * return <EmptyState />;\n * }\n *\n * return (\n * <div>\n * {messages.map(msg => (\n * <Message key={msg.id} message={msg} />\n * ))}\n * </div>\n * );\n * }\n * ```\n */\nexport function useTamboV1Messages(threadId: string): UseTamboV1MessagesReturn {\n const streamState = useStreamState();\n const threadState = streamState.threadMap[threadId];\n\n return useMemo(() => {\n const messages = threadState?.thread.messages ?? [];\n\n return {\n messages,\n lastMessage: messages[messages.length - 1],\n userMessages: messages.filter((m) => m.role === \"user\"),\n assistantMessages: messages.filter((m) => m.role === \"assistant\"),\n hasMessages: messages.length > 0,\n messageCount: messages.length,\n };\n }, [threadState?.thread.messages]);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-tambo-v1-messages.test.d.ts","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-messages.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { EventType, } from "@ag-ui/core";
|
|
2
|
+
import { renderHook, act } from "@testing-library/react";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { TamboV1StreamProvider, useStreamDispatch, } from "../providers/tambo-v1-stream-context";
|
|
5
|
+
import { useTamboV1Messages } from "./use-tambo-v1-messages";
|
|
6
|
+
describe("useTamboV1Messages", () => {
|
|
7
|
+
function TestWrapper({ children }) {
|
|
8
|
+
return (React.createElement(TamboV1StreamProvider, { threadId: "thread_123" }, children));
|
|
9
|
+
}
|
|
10
|
+
it("returns empty messages when thread has no messages", () => {
|
|
11
|
+
const { result } = renderHook(() => useTamboV1Messages("thread_123"), {
|
|
12
|
+
wrapper: TestWrapper,
|
|
13
|
+
});
|
|
14
|
+
expect(result.current.messages).toEqual([]);
|
|
15
|
+
expect(result.current.hasMessages).toBe(false);
|
|
16
|
+
expect(result.current.messageCount).toBe(0);
|
|
17
|
+
expect(result.current.lastMessage).toBeUndefined();
|
|
18
|
+
expect(result.current.userMessages).toEqual([]);
|
|
19
|
+
expect(result.current.assistantMessages).toEqual([]);
|
|
20
|
+
});
|
|
21
|
+
it("returns messages after events are dispatched", () => {
|
|
22
|
+
const { result } = renderHook(() => ({
|
|
23
|
+
messages: useTamboV1Messages("thread_123"),
|
|
24
|
+
dispatch: useStreamDispatch(),
|
|
25
|
+
}), { wrapper: TestWrapper });
|
|
26
|
+
// Simulate a text message being received
|
|
27
|
+
act(() => {
|
|
28
|
+
result.current.dispatch({
|
|
29
|
+
type: "EVENT",
|
|
30
|
+
event: {
|
|
31
|
+
type: EventType.TEXT_MESSAGE_START,
|
|
32
|
+
messageId: "msg_1",
|
|
33
|
+
role: "assistant",
|
|
34
|
+
},
|
|
35
|
+
threadId: "thread_123",
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
act(() => {
|
|
39
|
+
result.current.dispatch({
|
|
40
|
+
type: "EVENT",
|
|
41
|
+
event: {
|
|
42
|
+
type: EventType.TEXT_MESSAGE_CONTENT,
|
|
43
|
+
messageId: "msg_1",
|
|
44
|
+
delta: "Hello",
|
|
45
|
+
},
|
|
46
|
+
threadId: "thread_123",
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
act(() => {
|
|
50
|
+
result.current.dispatch({
|
|
51
|
+
type: "EVENT",
|
|
52
|
+
event: {
|
|
53
|
+
type: EventType.TEXT_MESSAGE_END,
|
|
54
|
+
messageId: "msg_1",
|
|
55
|
+
},
|
|
56
|
+
threadId: "thread_123",
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
expect(result.current.messages.messages.length).toBe(1);
|
|
60
|
+
expect(result.current.messages.hasMessages).toBe(true);
|
|
61
|
+
expect(result.current.messages.messageCount).toBe(1);
|
|
62
|
+
expect(result.current.messages.lastMessage?.id).toBe("msg_1");
|
|
63
|
+
expect(result.current.messages.lastMessage?.role).toBe("assistant");
|
|
64
|
+
expect(result.current.messages.assistantMessages.length).toBe(1);
|
|
65
|
+
expect(result.current.messages.userMessages.length).toBe(0);
|
|
66
|
+
});
|
|
67
|
+
it("filters user and assistant messages correctly", () => {
|
|
68
|
+
const { result } = renderHook(() => ({
|
|
69
|
+
messages: useTamboV1Messages("thread_123"),
|
|
70
|
+
dispatch: useStreamDispatch(),
|
|
71
|
+
}), { wrapper: TestWrapper });
|
|
72
|
+
// Add user message
|
|
73
|
+
act(() => {
|
|
74
|
+
result.current.dispatch({
|
|
75
|
+
type: "EVENT",
|
|
76
|
+
event: {
|
|
77
|
+
type: EventType.TEXT_MESSAGE_START,
|
|
78
|
+
messageId: "msg_user",
|
|
79
|
+
role: "user",
|
|
80
|
+
},
|
|
81
|
+
threadId: "thread_123",
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
act(() => {
|
|
85
|
+
result.current.dispatch({
|
|
86
|
+
type: "EVENT",
|
|
87
|
+
event: {
|
|
88
|
+
type: EventType.TEXT_MESSAGE_END,
|
|
89
|
+
messageId: "msg_user",
|
|
90
|
+
},
|
|
91
|
+
threadId: "thread_123",
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
// Add assistant message
|
|
95
|
+
act(() => {
|
|
96
|
+
result.current.dispatch({
|
|
97
|
+
type: "EVENT",
|
|
98
|
+
event: {
|
|
99
|
+
type: EventType.TEXT_MESSAGE_START,
|
|
100
|
+
messageId: "msg_assistant",
|
|
101
|
+
role: "assistant",
|
|
102
|
+
},
|
|
103
|
+
threadId: "thread_123",
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
act(() => {
|
|
107
|
+
result.current.dispatch({
|
|
108
|
+
type: "EVENT",
|
|
109
|
+
event: {
|
|
110
|
+
type: EventType.TEXT_MESSAGE_END,
|
|
111
|
+
messageId: "msg_assistant",
|
|
112
|
+
},
|
|
113
|
+
threadId: "thread_123",
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
expect(result.current.messages.messageCount).toBe(2);
|
|
117
|
+
expect(result.current.messages.userMessages.length).toBe(1);
|
|
118
|
+
expect(result.current.messages.userMessages[0].id).toBe("msg_user");
|
|
119
|
+
expect(result.current.messages.assistantMessages.length).toBe(1);
|
|
120
|
+
expect(result.current.messages.assistantMessages[0].id).toBe("msg_assistant");
|
|
121
|
+
expect(result.current.messages.lastMessage?.id).toBe("msg_assistant");
|
|
122
|
+
});
|
|
123
|
+
it("returns empty messages when threadId does not exist in threadMap", () => {
|
|
124
|
+
const { result } = renderHook(() => useTamboV1Messages("nonexistent_thread"), {
|
|
125
|
+
wrapper: TestWrapper,
|
|
126
|
+
});
|
|
127
|
+
expect(result.current.messages).toEqual([]);
|
|
128
|
+
expect(result.current.hasMessages).toBe(false);
|
|
129
|
+
expect(result.current.messageCount).toBe(0);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
//# sourceMappingURL=use-tambo-v1-messages.test.js.map
|