@tambo-ai/react 0.72.0 → 0.73.1
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/mcp/mcp-hooks.d.ts +4 -0
- package/dist/mcp/mcp-hooks.d.ts.map +1 -1
- package/dist/mcp/mcp-hooks.js +4 -0
- package/dist/mcp/mcp-hooks.js.map +1 -1
- package/dist/providers/tambo-provider.d.ts +3 -0
- package/dist/providers/tambo-provider.d.ts.map +1 -1
- package/dist/providers/tambo-provider.js +3 -0
- package/dist/providers/tambo-provider.js.map +1 -1
- package/dist/util/resource-content-resolver.d.ts.map +1 -1
- package/dist/util/resource-content-resolver.js +2 -0
- package/dist/util/resource-content-resolver.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-messages.test.js +22 -9
- package/dist/v1/hooks/use-tambo-v1-messages.test.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-send-message.d.ts +1 -0
- package/dist/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-send-message.js +9 -2
- package/dist/v1/hooks/use-tambo-v1-send-message.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-send-message.test.js +22 -9
- package/dist/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-suggestions.d.ts +91 -0
- package/dist/v1/hooks/use-tambo-v1-suggestions.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-suggestions.js +152 -0
- package/dist/v1/hooks/use-tambo-v1-suggestions.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-suggestions.test.d.ts +2 -0
- package/dist/v1/hooks/use-tambo-v1-suggestions.test.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-suggestions.test.js +511 -0
- package/dist/v1/hooks/use-tambo-v1-suggestions.test.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-thread-input.d.ts +6 -57
- package/dist/v1/hooks/use-tambo-v1-thread-input.d.ts.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-thread-input.js +7 -67
- package/dist/v1/hooks/use-tambo-v1-thread-input.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-thread-input.test.js +201 -72
- package/dist/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts +6 -4
- package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-thread-list.js +2 -2
- package/dist/v1/hooks/use-tambo-v1-thread-list.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-thread-list.test.js +2 -2
- package/dist/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1.test.js +16 -7
- package/dist/v1/hooks/use-tambo-v1.test.js.map +1 -1
- package/dist/v1/index.d.ts +22 -13
- package/dist/v1/index.d.ts.map +1 -1
- package/dist/v1/index.js +31 -39
- package/dist/v1/index.js.map +1 -1
- package/dist/v1/providers/tambo-v1-provider.d.ts +27 -9
- package/dist/v1/providers/tambo-v1-provider.d.ts.map +1 -1
- package/dist/v1/providers/tambo-v1-provider.js +22 -11
- package/dist/v1/providers/tambo-v1-provider.js.map +1 -1
- package/dist/v1/providers/tambo-v1-provider.test.js +27 -10
- package/dist/v1/providers/tambo-v1-provider.test.js.map +1 -1
- package/dist/v1/providers/tambo-v1-stream-context.d.ts +19 -10
- package/dist/v1/providers/tambo-v1-stream-context.d.ts.map +1 -1
- package/dist/v1/providers/tambo-v1-stream-context.js +43 -53
- package/dist/v1/providers/tambo-v1-stream-context.js.map +1 -1
- package/dist/v1/providers/tambo-v1-stream-context.test.js +94 -19
- package/dist/v1/providers/tambo-v1-stream-context.test.js.map +1 -1
- package/dist/v1/providers/tambo-v1-stub-provider.d.ts +74 -0
- package/dist/v1/providers/tambo-v1-stub-provider.d.ts.map +1 -0
- package/dist/v1/providers/tambo-v1-stub-provider.js +212 -0
- package/dist/v1/providers/tambo-v1-stub-provider.js.map +1 -0
- package/dist/v1/providers/tambo-v1-stub-provider.test.d.ts +2 -0
- package/dist/v1/providers/tambo-v1-stub-provider.test.d.ts.map +1 -0
- package/dist/v1/providers/tambo-v1-stub-provider.test.js +162 -0
- package/dist/v1/providers/tambo-v1-stub-provider.test.js.map +1 -0
- package/dist/v1/providers/tambo-v1-thread-input-provider.d.ts +105 -0
- package/dist/v1/providers/tambo-v1-thread-input-provider.d.ts.map +1 -0
- package/dist/v1/providers/tambo-v1-thread-input-provider.js +191 -0
- package/dist/v1/providers/tambo-v1-thread-input-provider.js.map +1 -0
- package/dist/v1/utils/component-renderer.d.ts +15 -67
- package/dist/v1/utils/component-renderer.d.ts.map +1 -1
- package/dist/v1/utils/component-renderer.js +3 -149
- package/dist/v1/utils/component-renderer.js.map +1 -1
- package/dist/v1/utils/component-renderer.test.js +15 -350
- package/dist/v1/utils/component-renderer.test.js.map +1 -1
- package/esm/mcp/mcp-hooks.d.ts +4 -0
- package/esm/mcp/mcp-hooks.d.ts.map +1 -1
- package/esm/mcp/mcp-hooks.js +4 -0
- package/esm/mcp/mcp-hooks.js.map +1 -1
- package/esm/providers/tambo-provider.d.ts +3 -0
- package/esm/providers/tambo-provider.d.ts.map +1 -1
- package/esm/providers/tambo-provider.js +3 -0
- package/esm/providers/tambo-provider.js.map +1 -1
- package/esm/util/resource-content-resolver.d.ts.map +1 -1
- package/esm/util/resource-content-resolver.js +2 -0
- package/esm/util/resource-content-resolver.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-messages.test.js +22 -9
- package/esm/v1/hooks/use-tambo-v1-messages.test.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-send-message.d.ts +1 -0
- package/esm/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-send-message.js +9 -2
- package/esm/v1/hooks/use-tambo-v1-send-message.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-send-message.test.js +22 -9
- package/esm/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-suggestions.d.ts +91 -0
- package/esm/v1/hooks/use-tambo-v1-suggestions.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-suggestions.js +149 -0
- package/esm/v1/hooks/use-tambo-v1-suggestions.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-suggestions.test.d.ts +2 -0
- package/esm/v1/hooks/use-tambo-v1-suggestions.test.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-suggestions.test.js +506 -0
- package/esm/v1/hooks/use-tambo-v1-suggestions.test.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-thread-input.d.ts +6 -57
- package/esm/v1/hooks/use-tambo-v1-thread-input.d.ts.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread-input.js +5 -66
- package/esm/v1/hooks/use-tambo-v1-thread-input.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread-input.test.js +199 -73
- package/esm/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts +6 -4
- package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread-list.js +2 -2
- package/esm/v1/hooks/use-tambo-v1-thread-list.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread-list.test.js +2 -2
- package/esm/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1.test.js +16 -7
- package/esm/v1/hooks/use-tambo-v1.test.js.map +1 -1
- package/esm/v1/index.d.ts +22 -13
- package/esm/v1/index.d.ts.map +1 -1
- package/esm/v1/index.js +23 -18
- package/esm/v1/index.js.map +1 -1
- package/esm/v1/providers/tambo-v1-provider.d.ts +27 -9
- package/esm/v1/providers/tambo-v1-provider.d.ts.map +1 -1
- package/esm/v1/providers/tambo-v1-provider.js +20 -10
- package/esm/v1/providers/tambo-v1-provider.js.map +1 -1
- package/esm/v1/providers/tambo-v1-provider.test.js +28 -11
- package/esm/v1/providers/tambo-v1-provider.test.js.map +1 -1
- package/esm/v1/providers/tambo-v1-stream-context.d.ts +19 -10
- package/esm/v1/providers/tambo-v1-stream-context.d.ts.map +1 -1
- package/esm/v1/providers/tambo-v1-stream-context.js +44 -54
- package/esm/v1/providers/tambo-v1-stream-context.js.map +1 -1
- package/esm/v1/providers/tambo-v1-stream-context.test.js +95 -20
- package/esm/v1/providers/tambo-v1-stream-context.test.js.map +1 -1
- package/esm/v1/providers/tambo-v1-stub-provider.d.ts +74 -0
- package/esm/v1/providers/tambo-v1-stub-provider.d.ts.map +1 -0
- package/esm/v1/providers/tambo-v1-stub-provider.js +176 -0
- package/esm/v1/providers/tambo-v1-stub-provider.js.map +1 -0
- package/esm/v1/providers/tambo-v1-stub-provider.test.d.ts +2 -0
- package/esm/v1/providers/tambo-v1-stub-provider.test.d.ts.map +1 -0
- package/esm/v1/providers/tambo-v1-stub-provider.test.js +157 -0
- package/esm/v1/providers/tambo-v1-stub-provider.test.js.map +1 -0
- package/esm/v1/providers/tambo-v1-thread-input-provider.d.ts +105 -0
- package/esm/v1/providers/tambo-v1-thread-input-provider.d.ts.map +1 -0
- package/esm/v1/providers/tambo-v1-thread-input-provider.js +153 -0
- package/esm/v1/providers/tambo-v1-thread-input-provider.js.map +1 -0
- package/esm/v1/utils/component-renderer.d.ts +15 -67
- package/esm/v1/utils/component-renderer.d.ts.map +1 -1
- package/esm/v1/utils/component-renderer.js +4 -146
- package/esm/v1/utils/component-renderer.js.map +1 -1
- package/esm/v1/utils/component-renderer.test.js +16 -351
- package/esm/v1/utils/component-renderer.test.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { TamboV1StubProvider } from "./tambo-v1-stub-provider";
|
|
4
|
+
import { useTamboV1 } from "../hooks/use-tambo-v1";
|
|
5
|
+
import { useTamboV1ThreadInput } from "../hooks/use-tambo-v1-thread-input";
|
|
6
|
+
import { useTamboRegistry } from "../../providers/tambo-registry-provider";
|
|
7
|
+
import { useTamboClient } from "../../providers/tambo-client-provider";
|
|
8
|
+
describe("TamboV1StubProvider", () => {
|
|
9
|
+
const mockThread = {
|
|
10
|
+
id: "thread_123",
|
|
11
|
+
messages: [
|
|
12
|
+
{
|
|
13
|
+
id: "msg_1",
|
|
14
|
+
role: "user",
|
|
15
|
+
content: [{ type: "text", text: "Hello" }],
|
|
16
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: "msg_2",
|
|
20
|
+
role: "assistant",
|
|
21
|
+
content: [{ type: "text", text: "Hi there!" }],
|
|
22
|
+
createdAt: "2024-01-01T00:00:01Z",
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
status: "idle",
|
|
26
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
27
|
+
updatedAt: "2024-01-01T00:00:01Z",
|
|
28
|
+
};
|
|
29
|
+
describe("useTamboV1", () => {
|
|
30
|
+
it("provides thread data via useTamboV1", () => {
|
|
31
|
+
const wrapper = ({ children }) => (React.createElement(TamboV1StubProvider, { thread: mockThread }, children));
|
|
32
|
+
const { result } = renderHook(() => useTamboV1("thread_123"), {
|
|
33
|
+
wrapper,
|
|
34
|
+
});
|
|
35
|
+
expect(result.current.messages).toHaveLength(2);
|
|
36
|
+
expect(result.current.messages[0].id).toBe("msg_1");
|
|
37
|
+
expect(result.current.messages[1].id).toBe("msg_2");
|
|
38
|
+
expect(result.current.isIdle).toBe(true);
|
|
39
|
+
expect(result.current.isStreaming).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
it("returns empty messages when no thread provided", () => {
|
|
42
|
+
const wrapper = ({ children }) => (React.createElement(TamboV1StubProvider, null, children));
|
|
43
|
+
const { result } = renderHook(() => useTamboV1("stub_thread"), {
|
|
44
|
+
wrapper,
|
|
45
|
+
});
|
|
46
|
+
expect(result.current.messages).toHaveLength(0);
|
|
47
|
+
expect(result.current.isIdle).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
it("shows streaming state when isStreaming prop is true", () => {
|
|
50
|
+
const wrapper = ({ children }) => (React.createElement(TamboV1StubProvider, { thread: mockThread, isStreaming: true }, children));
|
|
51
|
+
const { result } = renderHook(() => useTamboV1("thread_123"), {
|
|
52
|
+
wrapper,
|
|
53
|
+
});
|
|
54
|
+
expect(result.current.isStreaming).toBe(true);
|
|
55
|
+
expect(result.current.isIdle).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe("useTamboV1ThreadInput", () => {
|
|
59
|
+
it("provides thread input context", () => {
|
|
60
|
+
const wrapper = ({ children }) => (React.createElement(TamboV1StubProvider, { thread: mockThread }, children));
|
|
61
|
+
const { result } = renderHook(() => useTamboV1ThreadInput(), { wrapper });
|
|
62
|
+
expect(result.current.value).toBe("");
|
|
63
|
+
expect(result.current.threadId).toBe("thread_123");
|
|
64
|
+
expect(typeof result.current.setValue).toBe("function");
|
|
65
|
+
expect(typeof result.current.submit).toBe("function");
|
|
66
|
+
});
|
|
67
|
+
it("uses initial input value when provided", () => {
|
|
68
|
+
const wrapper = ({ children }) => (React.createElement(TamboV1StubProvider, { thread: mockThread, inputValue: "Hello world" }, children));
|
|
69
|
+
const { result } = renderHook(() => useTamboV1ThreadInput(), { wrapper });
|
|
70
|
+
expect(result.current.value).toBe("Hello world");
|
|
71
|
+
});
|
|
72
|
+
it("calls custom onSubmit when provided", async () => {
|
|
73
|
+
const mockOnSubmit = jest
|
|
74
|
+
.fn()
|
|
75
|
+
.mockResolvedValue({ threadId: "new_thread" });
|
|
76
|
+
const wrapper = ({ children }) => (React.createElement(TamboV1StubProvider, { thread: mockThread, onSubmit: mockOnSubmit }, children));
|
|
77
|
+
const { result } = renderHook(() => useTamboV1ThreadInput(), { wrapper });
|
|
78
|
+
const response = await result.current.submit();
|
|
79
|
+
expect(mockOnSubmit).toHaveBeenCalled();
|
|
80
|
+
expect(response.threadId).toBe("new_thread");
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
describe("Registry", () => {
|
|
84
|
+
it("registers provided components", () => {
|
|
85
|
+
const TestComponent = () => React.createElement("div", null, "Test");
|
|
86
|
+
const components = [
|
|
87
|
+
{
|
|
88
|
+
name: "TestComponent",
|
|
89
|
+
description: "A test component",
|
|
90
|
+
component: TestComponent,
|
|
91
|
+
},
|
|
92
|
+
];
|
|
93
|
+
const wrapper = ({ children }) => (React.createElement(TamboV1StubProvider, { thread: mockThread, components: components }, children));
|
|
94
|
+
const { result } = renderHook(() => useTamboRegistry(), { wrapper });
|
|
95
|
+
expect(result.current.componentList.TestComponent).toBeDefined();
|
|
96
|
+
expect(result.current.componentList.TestComponent.name).toBe("TestComponent");
|
|
97
|
+
});
|
|
98
|
+
it("registers provided tools", () => {
|
|
99
|
+
const tools = [
|
|
100
|
+
{
|
|
101
|
+
name: "testTool",
|
|
102
|
+
description: "A test tool",
|
|
103
|
+
tool: async () => "result",
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
const wrapper = ({ children }) => (React.createElement(TamboV1StubProvider, { thread: mockThread, tools: tools }, children));
|
|
107
|
+
const { result } = renderHook(() => useTamboRegistry(), { wrapper });
|
|
108
|
+
expect(result.current.toolRegistry.testTool).toBeDefined();
|
|
109
|
+
expect(result.current.toolRegistry.testTool.name).toBe("testTool");
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
describe("Client", () => {
|
|
113
|
+
it("provides stub client", () => {
|
|
114
|
+
const wrapper = ({ children }) => (React.createElement(TamboV1StubProvider, { thread: mockThread }, children));
|
|
115
|
+
const { result } = renderHook(() => useTamboClient(), { wrapper });
|
|
116
|
+
expect(result.current).toBeDefined();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe("Thread management", () => {
|
|
120
|
+
it("provides thread management functions", () => {
|
|
121
|
+
const wrapper = ({ children }) => (React.createElement(TamboV1StubProvider, { thread: mockThread }, children));
|
|
122
|
+
const { result } = renderHook(() => useTamboV1("thread_123"), {
|
|
123
|
+
wrapper,
|
|
124
|
+
});
|
|
125
|
+
expect(typeof result.current.startNewThread).toBe("function");
|
|
126
|
+
expect(typeof result.current.switchThread).toBe("function");
|
|
127
|
+
expect(typeof result.current.initThread).toBe("function");
|
|
128
|
+
});
|
|
129
|
+
it("calls custom onStartNewThread when provided", () => {
|
|
130
|
+
const mockStartNewThread = jest.fn().mockReturnValue("custom_thread_id");
|
|
131
|
+
const wrapper = ({ children }) => (React.createElement(TamboV1StubProvider, { thread: mockThread, onStartNewThread: mockStartNewThread }, children));
|
|
132
|
+
const { result } = renderHook(() => useTamboV1("thread_123"), {
|
|
133
|
+
wrapper,
|
|
134
|
+
});
|
|
135
|
+
const newThreadId = result.current.startNewThread();
|
|
136
|
+
expect(mockStartNewThread).toHaveBeenCalled();
|
|
137
|
+
expect(newThreadId).toBe("custom_thread_id");
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
describe("Messages-only thread", () => {
|
|
141
|
+
it("accepts just messages array instead of full thread", () => {
|
|
142
|
+
const messages = [
|
|
143
|
+
{
|
|
144
|
+
id: "msg_1",
|
|
145
|
+
role: "user",
|
|
146
|
+
content: [{ type: "text", text: "Hello" }],
|
|
147
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
148
|
+
},
|
|
149
|
+
];
|
|
150
|
+
const wrapper = ({ children }) => (React.createElement(TamboV1StubProvider, { thread: { messages }, threadId: "custom_id" }, children));
|
|
151
|
+
const { result } = renderHook(() => useTamboV1("custom_id"), { wrapper });
|
|
152
|
+
expect(result.current.messages).toHaveLength(1);
|
|
153
|
+
expect(result.current.messages[0].id).toBe("msg_1");
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
//# sourceMappingURL=tambo-v1-stub-provider.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tambo-v1-stub-provider.test.js","sourceRoot":"","sources":["../../../src/v1/providers/tambo-v1-stub-provider.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import { renderHook } from \"@testing-library/react\";\nimport React from \"react\";\nimport { TamboV1StubProvider } from \"./tambo-v1-stub-provider\";\nimport { useTamboV1 } from \"../hooks/use-tambo-v1\";\nimport { useTamboV1ThreadInput } from \"../hooks/use-tambo-v1-thread-input\";\nimport { useTamboRegistry } from \"../../providers/tambo-registry-provider\";\nimport { useTamboClient } from \"../../providers/tambo-client-provider\";\nimport type { TamboV1Thread } from \"../types/thread\";\n\ndescribe(\"TamboV1StubProvider\", () => {\n const mockThread: TamboV1Thread = {\n id: \"thread_123\",\n messages: [\n {\n id: \"msg_1\",\n role: \"user\",\n content: [{ type: \"text\", text: \"Hello\" }],\n createdAt: \"2024-01-01T00:00:00Z\",\n },\n {\n id: \"msg_2\",\n role: \"assistant\",\n content: [{ type: \"text\", text: \"Hi there!\" }],\n createdAt: \"2024-01-01T00:00:01Z\",\n },\n ],\n status: \"idle\",\n createdAt: \"2024-01-01T00:00:00Z\",\n updatedAt: \"2024-01-01T00:00:01Z\",\n };\n\n describe(\"useTamboV1\", () => {\n it(\"provides thread data via useTamboV1\", () => {\n const wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboV1StubProvider thread={mockThread}>\n {children}\n </TamboV1StubProvider>\n );\n\n const { result } = renderHook(() => useTamboV1(\"thread_123\"), {\n wrapper,\n });\n\n expect(result.current.messages).toHaveLength(2);\n expect(result.current.messages[0].id).toBe(\"msg_1\");\n expect(result.current.messages[1].id).toBe(\"msg_2\");\n expect(result.current.isIdle).toBe(true);\n expect(result.current.isStreaming).toBe(false);\n });\n\n it(\"returns empty messages when no thread provided\", () => {\n const wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboV1StubProvider>{children}</TamboV1StubProvider>\n );\n\n const { result } = renderHook(() => useTamboV1(\"stub_thread\"), {\n wrapper,\n });\n\n expect(result.current.messages).toHaveLength(0);\n expect(result.current.isIdle).toBe(true);\n });\n\n it(\"shows streaming state when isStreaming prop is true\", () => {\n const wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboV1StubProvider thread={mockThread} isStreaming>\n {children}\n </TamboV1StubProvider>\n );\n\n const { result } = renderHook(() => useTamboV1(\"thread_123\"), {\n wrapper,\n });\n\n expect(result.current.isStreaming).toBe(true);\n expect(result.current.isIdle).toBe(false);\n });\n });\n\n describe(\"useTamboV1ThreadInput\", () => {\n it(\"provides thread input context\", () => {\n const wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboV1StubProvider thread={mockThread}>\n {children}\n </TamboV1StubProvider>\n );\n\n const { result } = renderHook(() => useTamboV1ThreadInput(), { wrapper });\n\n expect(result.current.value).toBe(\"\");\n expect(result.current.threadId).toBe(\"thread_123\");\n expect(typeof result.current.setValue).toBe(\"function\");\n expect(typeof result.current.submit).toBe(\"function\");\n });\n\n it(\"uses initial input value when provided\", () => {\n const wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboV1StubProvider thread={mockThread} inputValue=\"Hello world\">\n {children}\n </TamboV1StubProvider>\n );\n\n const { result } = renderHook(() => useTamboV1ThreadInput(), { wrapper });\n\n expect(result.current.value).toBe(\"Hello world\");\n });\n\n it(\"calls custom onSubmit when provided\", async () => {\n const mockOnSubmit = jest\n .fn()\n .mockResolvedValue({ threadId: \"new_thread\" });\n\n const wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboV1StubProvider thread={mockThread} onSubmit={mockOnSubmit}>\n {children}\n </TamboV1StubProvider>\n );\n\n const { result } = renderHook(() => useTamboV1ThreadInput(), { wrapper });\n\n const response = await result.current.submit();\n\n expect(mockOnSubmit).toHaveBeenCalled();\n expect(response.threadId).toBe(\"new_thread\");\n });\n });\n\n describe(\"Registry\", () => {\n it(\"registers provided components\", () => {\n const TestComponent = () => <div>Test</div>;\n const components = [\n {\n name: \"TestComponent\",\n description: \"A test component\",\n component: TestComponent,\n },\n ];\n\n const wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboV1StubProvider thread={mockThread} components={components}>\n {children}\n </TamboV1StubProvider>\n );\n\n const { result } = renderHook(() => useTamboRegistry(), { wrapper });\n\n expect(result.current.componentList.TestComponent).toBeDefined();\n expect(result.current.componentList.TestComponent.name).toBe(\n \"TestComponent\",\n );\n });\n\n it(\"registers provided tools\", () => {\n const tools = [\n {\n name: \"testTool\",\n description: \"A test tool\",\n tool: async () => \"result\",\n },\n ];\n\n const wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboV1StubProvider thread={mockThread} tools={tools as any}>\n {children}\n </TamboV1StubProvider>\n );\n\n const { result } = renderHook(() => useTamboRegistry(), { wrapper });\n\n expect(result.current.toolRegistry.testTool).toBeDefined();\n expect(result.current.toolRegistry.testTool.name).toBe(\"testTool\");\n });\n });\n\n describe(\"Client\", () => {\n it(\"provides stub client\", () => {\n const wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboV1StubProvider thread={mockThread}>\n {children}\n </TamboV1StubProvider>\n );\n\n const { result } = renderHook(() => useTamboClient(), { wrapper });\n\n expect(result.current).toBeDefined();\n });\n });\n\n describe(\"Thread management\", () => {\n it(\"provides thread management functions\", () => {\n const wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboV1StubProvider thread={mockThread}>\n {children}\n </TamboV1StubProvider>\n );\n\n const { result } = renderHook(() => useTamboV1(\"thread_123\"), {\n wrapper,\n });\n\n expect(typeof result.current.startNewThread).toBe(\"function\");\n expect(typeof result.current.switchThread).toBe(\"function\");\n expect(typeof result.current.initThread).toBe(\"function\");\n });\n\n it(\"calls custom onStartNewThread when provided\", () => {\n const mockStartNewThread = jest.fn().mockReturnValue(\"custom_thread_id\");\n\n const wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboV1StubProvider\n thread={mockThread}\n onStartNewThread={mockStartNewThread}\n >\n {children}\n </TamboV1StubProvider>\n );\n\n const { result } = renderHook(() => useTamboV1(\"thread_123\"), {\n wrapper,\n });\n\n const newThreadId = result.current.startNewThread();\n\n expect(mockStartNewThread).toHaveBeenCalled();\n expect(newThreadId).toBe(\"custom_thread_id\");\n });\n });\n\n describe(\"Messages-only thread\", () => {\n it(\"accepts just messages array instead of full thread\", () => {\n const messages = [\n {\n id: \"msg_1\",\n role: \"user\" as const,\n content: [{ type: \"text\" as const, text: \"Hello\" }],\n createdAt: \"2024-01-01T00:00:00Z\",\n },\n ];\n\n const wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboV1StubProvider thread={{ messages }} threadId=\"custom_id\">\n {children}\n </TamboV1StubProvider>\n );\n\n const { result } = renderHook(() => useTamboV1(\"custom_id\"), { wrapper });\n\n expect(result.current.messages).toHaveLength(1);\n expect(result.current.messages[0].id).toBe(\"msg_1\");\n });\n });\n});\n"]}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TamboV1ThreadInputProvider - Shared Thread Input Context for v1 API
|
|
3
|
+
*
|
|
4
|
+
* Provides shared input state across all components, enabling features like
|
|
5
|
+
* suggestions to update the input field directly.
|
|
6
|
+
*
|
|
7
|
+
* This mirrors the beta SDK's TamboThreadInputProvider pattern.
|
|
8
|
+
*/
|
|
9
|
+
import React, { type PropsWithChildren } from "react";
|
|
10
|
+
import { type StagedImage } from "../../hooks/use-message-images";
|
|
11
|
+
import { type UseTamboMutationResult } from "../../hooks/react-query-hooks";
|
|
12
|
+
export declare const INPUT_ERROR_MESSAGES: {
|
|
13
|
+
readonly EMPTY: "Message cannot be empty";
|
|
14
|
+
readonly VALIDATION: "Invalid message format";
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Options for submitting a message
|
|
18
|
+
*/
|
|
19
|
+
export interface SubmitOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Enable debug logging for the stream
|
|
22
|
+
*/
|
|
23
|
+
debug?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Context props for thread input state
|
|
27
|
+
*/
|
|
28
|
+
export interface TamboV1ThreadInputContextProps extends Omit<UseTamboMutationResult<{
|
|
29
|
+
threadId: string | undefined;
|
|
30
|
+
}, Error, SubmitOptions | undefined>, "mutate" | "mutateAsync"> {
|
|
31
|
+
/** Current value of the input field */
|
|
32
|
+
value: string;
|
|
33
|
+
/**
|
|
34
|
+
* Function to update the input value
|
|
35
|
+
* @param value - New value for the input field
|
|
36
|
+
*/
|
|
37
|
+
setValue: React.Dispatch<React.SetStateAction<string>>;
|
|
38
|
+
/**
|
|
39
|
+
* Function to submit the current input value
|
|
40
|
+
* @param options - Submission options
|
|
41
|
+
* @returns Promise with the threadId
|
|
42
|
+
*/
|
|
43
|
+
submit: (options?: SubmitOptions) => Promise<{
|
|
44
|
+
threadId: string | undefined;
|
|
45
|
+
}>;
|
|
46
|
+
/** Currently staged images */
|
|
47
|
+
images: StagedImage[];
|
|
48
|
+
/** Add a single image */
|
|
49
|
+
addImage: (file: File) => Promise<void>;
|
|
50
|
+
/** Add multiple images */
|
|
51
|
+
addImages: (files: File[]) => Promise<void>;
|
|
52
|
+
/** Remove an image by id */
|
|
53
|
+
removeImage: (id: string) => void;
|
|
54
|
+
/** Clear all staged images */
|
|
55
|
+
clearImages: () => void;
|
|
56
|
+
/** Current thread ID being used for input */
|
|
57
|
+
threadId: string | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Set the thread ID for input submission.
|
|
60
|
+
* If not set, a new thread will be created on submit.
|
|
61
|
+
*/
|
|
62
|
+
setThreadId: React.Dispatch<React.SetStateAction<string | undefined>>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Context for thread input state.
|
|
66
|
+
* @internal
|
|
67
|
+
*/
|
|
68
|
+
export declare const TamboV1ThreadInputContext: React.Context<TamboV1ThreadInputContextProps | undefined>;
|
|
69
|
+
/**
|
|
70
|
+
* Provider that manages shared thread input state across all components.
|
|
71
|
+
*
|
|
72
|
+
* This ensures that useTamboV1ThreadInput, useTamboV1Suggestions, and other components
|
|
73
|
+
* all share the same input state.
|
|
74
|
+
* @param props - Provider props
|
|
75
|
+
* @param props.children - Child components
|
|
76
|
+
* @returns Thread input context provider
|
|
77
|
+
*/
|
|
78
|
+
export declare function TamboV1ThreadInputProvider({ children }: PropsWithChildren): React.JSX.Element;
|
|
79
|
+
/**
|
|
80
|
+
* Hook to access the shared thread input state.
|
|
81
|
+
*
|
|
82
|
+
* All components using this hook share the same input state, enabling
|
|
83
|
+
* features like suggestions to update the input field directly.
|
|
84
|
+
* @returns The shared thread input context
|
|
85
|
+
* @throws {Error} If used outside TamboV1ThreadInputProvider
|
|
86
|
+
* @example
|
|
87
|
+
* ```tsx
|
|
88
|
+
* function ChatInput() {
|
|
89
|
+
* const { value, setValue, submit, isPending } = useTamboV1ThreadInput();
|
|
90
|
+
*
|
|
91
|
+
* return (
|
|
92
|
+
* <form onSubmit={(e) => { e.preventDefault(); submit(); }}>
|
|
93
|
+
* <input
|
|
94
|
+
* value={value}
|
|
95
|
+
* onChange={(e) => setValue(e.target.value)}
|
|
96
|
+
* disabled={isPending}
|
|
97
|
+
* />
|
|
98
|
+
* <button type="submit" disabled={isPending}>Send</button>
|
|
99
|
+
* </form>
|
|
100
|
+
* );
|
|
101
|
+
* }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export declare function useTamboV1ThreadInput(): TamboV1ThreadInputContextProps;
|
|
105
|
+
//# sourceMappingURL=tambo-v1-thread-input-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tambo-v1-thread-input-provider.d.ts","sourceRoot":"","sources":["../../../src/v1/providers/tambo-v1-thread-input-provider.tsx"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,EAKZ,KAAK,iBAAiB,EACvB,MAAM,OAAO,CAAC;AACf,OAAO,EAEL,KAAK,WAAW,EACjB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,+BAA+B,CAAC;AASvC,eAAO,MAAM,oBAAoB;;;CAGvB,CAAC;AAkCX;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,8BAA+B,SAAQ,IAAI,CAC1D,sBAAsB,CACpB;IAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,EAChC,KAAK,EACL,aAAa,GAAG,SAAS,CAC1B,EACD,QAAQ,GAAG,aAAa,CACzB;IACC,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IAEvD;;;;OAIG;IACH,MAAM,EAAE,CACN,OAAO,CAAC,EAAE,aAAa,KACpB,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC,CAAC;IAE/C,8BAA8B;IAC9B,MAAM,EAAE,WAAW,EAAE,CAAC;IAEtB,yBAAyB;IACzB,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAExC,0BAA0B;IAC1B,SAAS,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5C,4BAA4B;IAC5B,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC,8BAA8B;IAC9B,WAAW,EAAE,MAAM,IAAI,CAAC;IAExB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAE7B;;;OAGG;IACH,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;CACvE;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,2DAE1B,CAAC;AAEb;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,QAAQ,EAAE,EAAE,iBAAiB,qBAoFzE;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,IAAI,8BAA8B,CAQtE"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
/**
|
|
3
|
+
* TamboV1ThreadInputProvider - Shared Thread Input Context for v1 API
|
|
4
|
+
*
|
|
5
|
+
* Provides shared input state across all components, enabling features like
|
|
6
|
+
* suggestions to update the input field directly.
|
|
7
|
+
*
|
|
8
|
+
* This mirrors the beta SDK's TamboThreadInputProvider pattern.
|
|
9
|
+
*/
|
|
10
|
+
import React, { createContext, useCallback, useContext, useState, } from "react";
|
|
11
|
+
import { useMessageImages, } from "../../hooks/use-message-images";
|
|
12
|
+
import { useTamboMutation, } from "../../hooks/react-query-hooks";
|
|
13
|
+
import { useTamboV1SendMessage } from "../hooks/use-tambo-v1-send-message";
|
|
14
|
+
import { useStreamState } from "./tambo-v1-stream-context";
|
|
15
|
+
// Error messages for various input-related error scenarios.
|
|
16
|
+
// TODO: Reintroduce explicit `NETWORK` and `SERVER` keys once `submit()` maps
|
|
17
|
+
// failures into a small, stable set of user-facing error codes (at minimum:
|
|
18
|
+
// connectivity failures vs non-2xx responses).
|
|
19
|
+
export const INPUT_ERROR_MESSAGES = {
|
|
20
|
+
EMPTY: "Message cannot be empty",
|
|
21
|
+
VALIDATION: "Invalid message format",
|
|
22
|
+
};
|
|
23
|
+
function stagedImageToResourceContent(image) {
|
|
24
|
+
if (!image.dataUrl.startsWith("data:")) {
|
|
25
|
+
throw new Error(INPUT_ERROR_MESSAGES.VALIDATION);
|
|
26
|
+
}
|
|
27
|
+
const commaIndex = image.dataUrl.indexOf(",");
|
|
28
|
+
if (commaIndex === -1) {
|
|
29
|
+
throw new Error(INPUT_ERROR_MESSAGES.VALIDATION);
|
|
30
|
+
}
|
|
31
|
+
const header = image.dataUrl.slice("data:".length, commaIndex);
|
|
32
|
+
const [mimeType, ...params] = header.split(";");
|
|
33
|
+
const isBase64 = params.includes("base64");
|
|
34
|
+
if (mimeType !== image.type || !isBase64) {
|
|
35
|
+
throw new Error(INPUT_ERROR_MESSAGES.VALIDATION);
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
type: "resource",
|
|
39
|
+
resource: {
|
|
40
|
+
name: image.name,
|
|
41
|
+
mimeType: image.type,
|
|
42
|
+
// Shared.Resource.blob expects base64-encoded data; this is the base64
|
|
43
|
+
// payload from the `data:` URL.
|
|
44
|
+
blob: image.dataUrl.slice(commaIndex + 1),
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Context for thread input state.
|
|
50
|
+
* @internal
|
|
51
|
+
*/
|
|
52
|
+
export const TamboV1ThreadInputContext = createContext(undefined);
|
|
53
|
+
/**
|
|
54
|
+
* Provider that manages shared thread input state across all components.
|
|
55
|
+
*
|
|
56
|
+
* This ensures that useTamboV1ThreadInput, useTamboV1Suggestions, and other components
|
|
57
|
+
* all share the same input state.
|
|
58
|
+
* @param props - Provider props
|
|
59
|
+
* @param props.children - Child components
|
|
60
|
+
* @returns Thread input context provider
|
|
61
|
+
*/
|
|
62
|
+
export function TamboV1ThreadInputProvider({ children }) {
|
|
63
|
+
const [inputValue, setInputValue] = useState("");
|
|
64
|
+
const [threadId, setThreadId] = useState(undefined);
|
|
65
|
+
const imageState = useMessageImages();
|
|
66
|
+
const streamState = useStreamState();
|
|
67
|
+
// Use the current thread from stream state if no explicit threadId is set
|
|
68
|
+
const inheritedThreadId = streamState.currentThreadId ?? undefined;
|
|
69
|
+
const effectiveThreadId = threadId ?? inheritedThreadId;
|
|
70
|
+
const shouldAdoptThreadId = threadId === undefined && inheritedThreadId === undefined;
|
|
71
|
+
const sendMessage = useTamboV1SendMessage(effectiveThreadId);
|
|
72
|
+
const submitFn = useCallback(async (options) => {
|
|
73
|
+
const trimmedValue = inputValue.trim();
|
|
74
|
+
// Check if we have content to send
|
|
75
|
+
if (!trimmedValue && imageState.images.length === 0) {
|
|
76
|
+
throw new Error(INPUT_ERROR_MESSAGES.EMPTY);
|
|
77
|
+
}
|
|
78
|
+
const content = [];
|
|
79
|
+
if (trimmedValue) {
|
|
80
|
+
content.push({ type: "text", text: trimmedValue });
|
|
81
|
+
}
|
|
82
|
+
for (const image of imageState.images) {
|
|
83
|
+
content.push(stagedImageToResourceContent(image));
|
|
84
|
+
}
|
|
85
|
+
const result = await sendMessage.mutateAsync({
|
|
86
|
+
message: {
|
|
87
|
+
role: "user",
|
|
88
|
+
content,
|
|
89
|
+
},
|
|
90
|
+
debug: options?.debug,
|
|
91
|
+
});
|
|
92
|
+
// Clear input and images after successful submission
|
|
93
|
+
setInputValue("");
|
|
94
|
+
imageState.clearImages();
|
|
95
|
+
// Update threadId if a new thread was created
|
|
96
|
+
if (result.threadId && shouldAdoptThreadId) {
|
|
97
|
+
setThreadId(result.threadId);
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
},
|
|
101
|
+
// `stagedImageToResourceContent` is a pure module-level helper (not a hook value).
|
|
102
|
+
[inputValue, imageState, sendMessage, shouldAdoptThreadId]);
|
|
103
|
+
const { mutateAsync: submitAsync, mutate: _unusedSubmit, ...mutationState } = useTamboMutation({
|
|
104
|
+
mutationFn: submitFn,
|
|
105
|
+
});
|
|
106
|
+
const contextValue = {
|
|
107
|
+
...mutationState,
|
|
108
|
+
value: inputValue,
|
|
109
|
+
setValue: setInputValue,
|
|
110
|
+
submit: submitAsync,
|
|
111
|
+
images: imageState.images,
|
|
112
|
+
addImage: imageState.addImage,
|
|
113
|
+
addImages: imageState.addImages,
|
|
114
|
+
removeImage: imageState.removeImage,
|
|
115
|
+
clearImages: imageState.clearImages,
|
|
116
|
+
threadId: effectiveThreadId,
|
|
117
|
+
setThreadId,
|
|
118
|
+
};
|
|
119
|
+
return (React.createElement(TamboV1ThreadInputContext.Provider, { value: contextValue }, children));
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Hook to access the shared thread input state.
|
|
123
|
+
*
|
|
124
|
+
* All components using this hook share the same input state, enabling
|
|
125
|
+
* features like suggestions to update the input field directly.
|
|
126
|
+
* @returns The shared thread input context
|
|
127
|
+
* @throws {Error} If used outside TamboV1ThreadInputProvider
|
|
128
|
+
* @example
|
|
129
|
+
* ```tsx
|
|
130
|
+
* function ChatInput() {
|
|
131
|
+
* const { value, setValue, submit, isPending } = useTamboV1ThreadInput();
|
|
132
|
+
*
|
|
133
|
+
* return (
|
|
134
|
+
* <form onSubmit={(e) => { e.preventDefault(); submit(); }}>
|
|
135
|
+
* <input
|
|
136
|
+
* value={value}
|
|
137
|
+
* onChange={(e) => setValue(e.target.value)}
|
|
138
|
+
* disabled={isPending}
|
|
139
|
+
* />
|
|
140
|
+
* <button type="submit" disabled={isPending}>Send</button>
|
|
141
|
+
* </form>
|
|
142
|
+
* );
|
|
143
|
+
* }
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
export function useTamboV1ThreadInput() {
|
|
147
|
+
const context = useContext(TamboV1ThreadInputContext);
|
|
148
|
+
if (!context) {
|
|
149
|
+
throw new Error("useTamboV1ThreadInput must be used within TamboV1ThreadInputProvider");
|
|
150
|
+
}
|
|
151
|
+
return context;
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=tambo-v1-thread-input-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tambo-v1-thread-input-provider.js","sourceRoot":"","sources":["../../../src/v1/providers/tambo-v1-thread-input-provider.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\n/**\n * TamboV1ThreadInputProvider - Shared Thread Input Context for v1 API\n *\n * Provides shared input state across all components, enabling features like\n * suggestions to update the input field directly.\n *\n * This mirrors the beta SDK's TamboThreadInputProvider pattern.\n */\n\nimport React, {\n createContext,\n useCallback,\n useContext,\n useState,\n type PropsWithChildren,\n} from \"react\";\nimport {\n useMessageImages,\n type StagedImage,\n} from \"../../hooks/use-message-images\";\nimport {\n useTamboMutation,\n type UseTamboMutationResult,\n} from \"../../hooks/react-query-hooks\";\nimport { useTamboV1SendMessage } from \"../hooks/use-tambo-v1-send-message\";\nimport type { InputMessage } from \"../types/message\";\nimport { useStreamState } from \"./tambo-v1-stream-context\";\n\n// Error messages for various input-related error scenarios.\n// TODO: Reintroduce explicit `NETWORK` and `SERVER` keys once `submit()` maps\n// failures into a small, stable set of user-facing error codes (at minimum:\n// connectivity failures vs non-2xx responses).\nexport const INPUT_ERROR_MESSAGES = {\n EMPTY: \"Message cannot be empty\",\n VALIDATION: \"Invalid message format\",\n} as const;\n\nfunction stagedImageToResourceContent(\n image: StagedImage,\n): InputMessage[\"content\"][number] {\n if (!image.dataUrl.startsWith(\"data:\")) {\n throw new Error(INPUT_ERROR_MESSAGES.VALIDATION);\n }\n\n const commaIndex = image.dataUrl.indexOf(\",\");\n if (commaIndex === -1) {\n throw new Error(INPUT_ERROR_MESSAGES.VALIDATION);\n }\n\n const header = image.dataUrl.slice(\"data:\".length, commaIndex);\n const [mimeType, ...params] = header.split(\";\");\n const isBase64 = params.includes(\"base64\");\n\n if (mimeType !== image.type || !isBase64) {\n throw new Error(INPUT_ERROR_MESSAGES.VALIDATION);\n }\n\n return {\n type: \"resource\",\n resource: {\n name: image.name,\n mimeType: image.type,\n // Shared.Resource.blob expects base64-encoded data; this is the base64\n // payload from the `data:` URL.\n blob: image.dataUrl.slice(commaIndex + 1),\n },\n };\n}\n\n/**\n * Options for submitting a message\n */\nexport interface SubmitOptions {\n /**\n * Enable debug logging for the stream\n */\n debug?: boolean;\n}\n\n/**\n * Context props for thread input state\n */\nexport interface TamboV1ThreadInputContextProps extends Omit<\n UseTamboMutationResult<\n { threadId: string | undefined },\n Error,\n SubmitOptions | undefined\n >,\n \"mutate\" | \"mutateAsync\"\n> {\n /** Current value of the input field */\n value: string;\n\n /**\n * Function to update the input value\n * @param value - New value for the input field\n */\n setValue: React.Dispatch<React.SetStateAction<string>>;\n\n /**\n * Function to submit the current input value\n * @param options - Submission options\n * @returns Promise with the threadId\n */\n submit: (\n options?: SubmitOptions,\n ) => Promise<{ threadId: string | undefined }>;\n\n /** Currently staged images */\n images: StagedImage[];\n\n /** Add a single image */\n addImage: (file: File) => Promise<void>;\n\n /** Add multiple images */\n addImages: (files: File[]) => Promise<void>;\n\n /** Remove an image by id */\n removeImage: (id: string) => void;\n\n /** Clear all staged images */\n clearImages: () => void;\n\n /** Current thread ID being used for input */\n threadId: string | undefined;\n\n /**\n * Set the thread ID for input submission.\n * If not set, a new thread will be created on submit.\n */\n setThreadId: React.Dispatch<React.SetStateAction<string | undefined>>;\n}\n\n/**\n * Context for thread input state.\n * @internal\n */\nexport const TamboV1ThreadInputContext = createContext<\n TamboV1ThreadInputContextProps | undefined\n>(undefined);\n\n/**\n * Provider that manages shared thread input state across all components.\n *\n * This ensures that useTamboV1ThreadInput, useTamboV1Suggestions, and other components\n * all share the same input state.\n * @param props - Provider props\n * @param props.children - Child components\n * @returns Thread input context provider\n */\nexport function TamboV1ThreadInputProvider({ children }: PropsWithChildren) {\n const [inputValue, setInputValue] = useState(\"\");\n const [threadId, setThreadId] = useState<string | undefined>(undefined);\n const imageState = useMessageImages();\n const streamState = useStreamState();\n\n // Use the current thread from stream state if no explicit threadId is set\n const inheritedThreadId = streamState.currentThreadId ?? undefined;\n const effectiveThreadId = threadId ?? inheritedThreadId;\n const shouldAdoptThreadId =\n threadId === undefined && inheritedThreadId === undefined;\n const sendMessage = useTamboV1SendMessage(effectiveThreadId);\n\n const submitFn = useCallback(\n async (\n options?: SubmitOptions,\n ): Promise<{ threadId: string | undefined }> => {\n const trimmedValue = inputValue.trim();\n\n // Check if we have content to send\n if (!trimmedValue && imageState.images.length === 0) {\n throw new Error(INPUT_ERROR_MESSAGES.EMPTY);\n }\n\n const content: InputMessage[\"content\"] = [];\n\n if (trimmedValue) {\n content.push({ type: \"text\", text: trimmedValue });\n }\n\n for (const image of imageState.images) {\n content.push(stagedImageToResourceContent(image));\n }\n\n const result = await sendMessage.mutateAsync({\n message: {\n role: \"user\",\n content,\n },\n debug: options?.debug,\n });\n\n // Clear input and images after successful submission\n setInputValue(\"\");\n imageState.clearImages();\n\n // Update threadId if a new thread was created\n if (result.threadId && shouldAdoptThreadId) {\n setThreadId(result.threadId);\n }\n\n return result;\n },\n // `stagedImageToResourceContent` is a pure module-level helper (not a hook value).\n [inputValue, imageState, sendMessage, shouldAdoptThreadId],\n );\n\n const {\n mutateAsync: submitAsync,\n mutate: _unusedSubmit,\n ...mutationState\n } = useTamboMutation({\n mutationFn: submitFn,\n });\n\n const contextValue: TamboV1ThreadInputContextProps = {\n ...mutationState,\n value: inputValue,\n setValue: setInputValue,\n submit: submitAsync,\n images: imageState.images,\n addImage: imageState.addImage,\n addImages: imageState.addImages,\n removeImage: imageState.removeImage,\n clearImages: imageState.clearImages,\n threadId: effectiveThreadId,\n setThreadId,\n };\n\n return (\n <TamboV1ThreadInputContext.Provider value={contextValue}>\n {children}\n </TamboV1ThreadInputContext.Provider>\n );\n}\n\n/**\n * Hook to access the shared thread input state.\n *\n * All components using this hook share the same input state, enabling\n * features like suggestions to update the input field directly.\n * @returns The shared thread input context\n * @throws {Error} If used outside TamboV1ThreadInputProvider\n * @example\n * ```tsx\n * function ChatInput() {\n * const { value, setValue, submit, isPending } = useTamboV1ThreadInput();\n *\n * return (\n * <form onSubmit={(e) => { e.preventDefault(); submit(); }}>\n * <input\n * value={value}\n * onChange={(e) => setValue(e.target.value)}\n * disabled={isPending}\n * />\n * <button type=\"submit\" disabled={isPending}>Send</button>\n * </form>\n * );\n * }\n * ```\n */\nexport function useTamboV1ThreadInput(): TamboV1ThreadInputContextProps {\n const context = useContext(TamboV1ThreadInputContext);\n if (!context) {\n throw new Error(\n \"useTamboV1ThreadInput must be used within TamboV1ThreadInputProvider\",\n );\n }\n return context;\n}\n"]}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Component Renderer Utility for v1 API
|
|
3
|
+
*
|
|
4
|
+
* Provides the component content context for rendered components.
|
|
5
|
+
* Components can use useV1ComponentContent() to access their context.
|
|
6
|
+
*/
|
|
7
|
+
import React from "react";
|
|
3
8
|
/**
|
|
4
9
|
* Context for component content blocks.
|
|
5
10
|
* Provides access to the component ID and thread ID for component state hooks.
|
|
@@ -14,6 +19,14 @@ export interface V1ComponentContentContext {
|
|
|
14
19
|
/** Component name */
|
|
15
20
|
componentName: string;
|
|
16
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Provider for component content context.
|
|
24
|
+
* Wraps rendered components to provide access to component metadata.
|
|
25
|
+
* @returns Provider component with memoized context value
|
|
26
|
+
*/
|
|
27
|
+
export declare function V1ComponentContentProvider({ children, componentId, threadId, messageId, componentName, }: V1ComponentContentContext & {
|
|
28
|
+
children: React.ReactNode;
|
|
29
|
+
}): React.JSX.Element;
|
|
17
30
|
/**
|
|
18
31
|
* Hook to access the current component content context.
|
|
19
32
|
* Must be used within a rendered component.
|
|
@@ -21,69 +34,4 @@ export interface V1ComponentContentContext {
|
|
|
21
34
|
* @throws {Error} If used outside a rendered component
|
|
22
35
|
*/
|
|
23
36
|
export declare function useV1ComponentContent(): V1ComponentContentContext;
|
|
24
|
-
/**
|
|
25
|
-
* Hook to optionally access the current component content context.
|
|
26
|
-
* Returns null if not within a rendered component.
|
|
27
|
-
* @returns Component content context or null
|
|
28
|
-
*/
|
|
29
|
-
export declare function useV1ComponentContentOptional(): V1ComponentContentContext | null;
|
|
30
|
-
/**
|
|
31
|
-
* Options for rendering a component content block.
|
|
32
|
-
*/
|
|
33
|
-
export interface RenderComponentOptions {
|
|
34
|
-
/** Thread ID for the component context */
|
|
35
|
-
threadId: string;
|
|
36
|
-
/** Message ID the component belongs to */
|
|
37
|
-
messageId: string;
|
|
38
|
-
/** Component registry to look up components */
|
|
39
|
-
componentList: ComponentRegistry;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Check if a content block is a component.
|
|
43
|
-
* @param content - Content block to check
|
|
44
|
-
* @returns True if content is a V1ComponentContent
|
|
45
|
-
*/
|
|
46
|
-
export declare function isComponentContent(content: Content): content is V1ComponentContent;
|
|
47
|
-
/**
|
|
48
|
-
* Render a component content block into a React element.
|
|
49
|
-
*
|
|
50
|
-
* Looks up the component in the registry, creates a React element with props,
|
|
51
|
-
* and wraps it with the component content context provider.
|
|
52
|
-
* @param content - Component content block to render
|
|
53
|
-
* @param options - Rendering options including registry and context info
|
|
54
|
-
* @returns V1ComponentContent with the renderedComponent attached
|
|
55
|
-
* @example
|
|
56
|
-
* ```tsx
|
|
57
|
-
* const rendered = renderComponentContent(componentContent, {
|
|
58
|
-
* threadId: 'thread_123',
|
|
59
|
-
* messageId: 'msg_456',
|
|
60
|
-
* componentList: registry.componentList,
|
|
61
|
-
* });
|
|
62
|
-
*
|
|
63
|
-
* // Use in JSX:
|
|
64
|
-
* {rendered.renderedComponent}
|
|
65
|
-
* ```
|
|
66
|
-
*/
|
|
67
|
-
export declare function renderComponentContent(content: V1ComponentContent, options: RenderComponentOptions): V1ComponentContent;
|
|
68
|
-
/**
|
|
69
|
-
* Render all component content blocks in a message.
|
|
70
|
-
*
|
|
71
|
-
* Renders component content blocks and attaches renderedComponent.
|
|
72
|
-
* Non-component content blocks are passed through unchanged.
|
|
73
|
-
* @param content - Array of content blocks
|
|
74
|
-
* @param options - Rendering options including registry and context info
|
|
75
|
-
* @returns Array of content with rendered components
|
|
76
|
-
*/
|
|
77
|
-
export declare function renderMessageContent(content: Content[], options: RenderComponentOptions): Content[];
|
|
78
|
-
/**
|
|
79
|
-
* Render all components in a message.
|
|
80
|
-
*
|
|
81
|
-
* Creates a new message object with all component content blocks rendered.
|
|
82
|
-
* @param message - Message to render components for
|
|
83
|
-
* @param options - Rendering options (threadId is extracted from message if not provided)
|
|
84
|
-
* @returns Message with rendered component content
|
|
85
|
-
*/
|
|
86
|
-
export declare function renderMessageComponents(message: TamboV1Message, options: Omit<RenderComponentOptions, "messageId"> & {
|
|
87
|
-
threadId: string;
|
|
88
|
-
}): TamboV1Message;
|
|
89
37
|
//# sourceMappingURL=component-renderer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-renderer.d.ts","sourceRoot":"","sources":["../../../src/v1/utils/component-renderer.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"component-renderer.d.ts","sourceRoot":"","sources":["../../../src/v1/utils/component-renderer.tsx"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,OAAO,KAA6C,MAAM,OAAO,CAAC;AAElE;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAMD;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,SAAS,EACT,aAAa,GACd,EAAE,yBAAyB,GAAG;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,qBAY3D;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,yBAAyB,CAQjE"}
|