@tambo-ai/react 0.71.0 → 0.72.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-component-state.d.ts +44 -0
- package/dist/v1/hooks/use-tambo-v1-component-state.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-component-state.js +134 -0
- package/dist/v1/hooks/use-tambo-v1-component-state.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-component-state.test.d.ts +2 -0
- package/dist/v1/hooks/use-tambo-v1-component-state.test.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-component-state.test.js +292 -0
- package/dist/v1/hooks/use-tambo-v1-component-state.test.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-thread-input.d.ts +62 -0
- package/dist/v1/hooks/use-tambo-v1-thread-input.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-thread-input.js +76 -0
- package/dist/v1/hooks/use-tambo-v1-thread-input.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-thread-input.test.d.ts +2 -0
- package/dist/v1/hooks/use-tambo-v1-thread-input.test.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-thread-input.test.js +168 -0
- package/dist/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -0
- package/dist/v1/index.d.ts +23 -12
- package/dist/v1/index.d.ts.map +1 -1
- package/dist/v1/index.js +48 -14
- package/dist/v1/index.js.map +1 -1
- package/dist/v1/providers/tambo-v1-provider.d.ts +43 -1
- package/dist/v1/providers/tambo-v1-provider.d.ts.map +1 -1
- package/dist/v1/providers/tambo-v1-provider.js +24 -3
- package/dist/v1/providers/tambo-v1-provider.js.map +1 -1
- package/dist/v1/providers/tambo-v1-provider.test.js +58 -0
- package/dist/v1/providers/tambo-v1-provider.test.js.map +1 -1
- package/dist/v1/types/message.d.ts +27 -2
- package/dist/v1/types/message.d.ts.map +1 -1
- package/dist/v1/types/message.js.map +1 -1
- package/dist/v1/utils/component-renderer.d.ts +89 -0
- package/dist/v1/utils/component-renderer.d.ts.map +1 -0
- package/dist/v1/utils/component-renderer.js +216 -0
- package/dist/v1/utils/component-renderer.js.map +1 -0
- package/dist/v1/utils/component-renderer.test.d.ts +2 -0
- package/dist/v1/utils/component-renderer.test.d.ts.map +1 -0
- package/dist/v1/utils/component-renderer.test.js +380 -0
- package/dist/v1/utils/component-renderer.test.js.map +1 -0
- package/dist/v1/utils/event-accumulator.js +28 -8
- package/dist/v1/utils/event-accumulator.js.map +1 -1
- package/dist/v1/utils/event-accumulator.test.js +201 -6
- package/dist/v1/utils/event-accumulator.test.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-component-state.d.ts +44 -0
- package/esm/v1/hooks/use-tambo-v1-component-state.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-component-state.js +131 -0
- package/esm/v1/hooks/use-tambo-v1-component-state.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-component-state.test.d.ts +2 -0
- package/esm/v1/hooks/use-tambo-v1-component-state.test.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-component-state.test.js +290 -0
- package/esm/v1/hooks/use-tambo-v1-component-state.test.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-thread-input.d.ts +62 -0
- package/esm/v1/hooks/use-tambo-v1-thread-input.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-thread-input.js +73 -0
- package/esm/v1/hooks/use-tambo-v1-thread-input.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-thread-input.test.d.ts +2 -0
- package/esm/v1/hooks/use-tambo-v1-thread-input.test.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-thread-input.test.js +166 -0
- package/esm/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -0
- package/esm/v1/index.d.ts +23 -12
- package/esm/v1/index.d.ts.map +1 -1
- package/esm/v1/index.js +31 -12
- package/esm/v1/index.js.map +1 -1
- package/esm/v1/providers/tambo-v1-provider.d.ts +43 -1
- package/esm/v1/providers/tambo-v1-provider.d.ts.map +1 -1
- package/esm/v1/providers/tambo-v1-provider.js +24 -4
- package/esm/v1/providers/tambo-v1-provider.js.map +1 -1
- package/esm/v1/providers/tambo-v1-provider.test.js +59 -1
- package/esm/v1/providers/tambo-v1-provider.test.js.map +1 -1
- package/esm/v1/types/message.d.ts +27 -2
- package/esm/v1/types/message.d.ts.map +1 -1
- package/esm/v1/types/message.js.map +1 -1
- package/esm/v1/utils/component-renderer.d.ts +89 -0
- package/esm/v1/utils/component-renderer.d.ts.map +1 -0
- package/esm/v1/utils/component-renderer.js +175 -0
- package/esm/v1/utils/component-renderer.js.map +1 -0
- package/esm/v1/utils/component-renderer.test.d.ts +2 -0
- package/esm/v1/utils/component-renderer.test.d.ts.map +1 -0
- package/esm/v1/utils/component-renderer.test.js +375 -0
- package/esm/v1/utils/component-renderer.test.js.map +1 -0
- package/esm/v1/utils/event-accumulator.js +28 -8
- package/esm/v1/utils/event-accumulator.js.map +1 -1
- package/esm/v1/utils/event-accumulator.test.js +201 -6
- package/esm/v1/utils/event-accumulator.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { act, renderHook } from "@testing-library/react";
|
|
2
|
+
import { useTamboV1ComponentState } from "./use-tambo-v1-component-state";
|
|
3
|
+
// Mock the required modules
|
|
4
|
+
jest.mock("../../providers/tambo-client-provider", () => ({
|
|
5
|
+
useTamboClient: jest.fn(),
|
|
6
|
+
}));
|
|
7
|
+
jest.mock("../providers/tambo-v1-stream-context", () => ({
|
|
8
|
+
useStreamState: jest.fn(),
|
|
9
|
+
}));
|
|
10
|
+
jest.mock("../utils/component-renderer", () => ({
|
|
11
|
+
useV1ComponentContent: jest.fn(),
|
|
12
|
+
}));
|
|
13
|
+
// Create a mock debounced function with flush method
|
|
14
|
+
const createMockDebouncedFunction = (fn) => {
|
|
15
|
+
const debouncedFn = jest.fn((...args) => fn(...args));
|
|
16
|
+
debouncedFn.flush = jest.fn();
|
|
17
|
+
debouncedFn.cancel = jest.fn();
|
|
18
|
+
debouncedFn.isPending = jest.fn(() => false);
|
|
19
|
+
return debouncedFn;
|
|
20
|
+
};
|
|
21
|
+
// Mock use-debounce
|
|
22
|
+
jest.mock("use-debounce", () => ({
|
|
23
|
+
useDebouncedCallback: jest.fn(),
|
|
24
|
+
}));
|
|
25
|
+
// Import the mocked modules
|
|
26
|
+
import { useTamboClient } from "../../providers/tambo-client-provider";
|
|
27
|
+
import { useStreamState } from "../providers/tambo-v1-stream-context";
|
|
28
|
+
import { useV1ComponentContent } from "../utils/component-renderer";
|
|
29
|
+
import { useDebouncedCallback } from "use-debounce";
|
|
30
|
+
describe("useTamboV1ComponentState", () => {
|
|
31
|
+
const mockUpdateState = jest.fn();
|
|
32
|
+
const mockComponentId = "comp_test123";
|
|
33
|
+
const mockThreadId = "thread_abc";
|
|
34
|
+
const mockMessageId = "msg_xyz";
|
|
35
|
+
// Helper to create mock stream state
|
|
36
|
+
const createMockStreamState = (componentState) => ({
|
|
37
|
+
threadMap: {
|
|
38
|
+
[mockThreadId]: {
|
|
39
|
+
thread: {
|
|
40
|
+
id: mockThreadId,
|
|
41
|
+
messages: [
|
|
42
|
+
{
|
|
43
|
+
id: mockMessageId,
|
|
44
|
+
role: "assistant",
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
type: "component",
|
|
48
|
+
id: mockComponentId,
|
|
49
|
+
name: "TestComponent",
|
|
50
|
+
props: {},
|
|
51
|
+
state: componentState,
|
|
52
|
+
streamingState: "done",
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
createdAt: new Date().toISOString(),
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
status: "idle",
|
|
59
|
+
createdAt: new Date().toISOString(),
|
|
60
|
+
updatedAt: new Date().toISOString(),
|
|
61
|
+
},
|
|
62
|
+
streaming: { status: "idle" },
|
|
63
|
+
accumulatingToolArgs: new Map(),
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
currentThreadId: mockThreadId,
|
|
67
|
+
});
|
|
68
|
+
beforeEach(() => {
|
|
69
|
+
jest.clearAllMocks();
|
|
70
|
+
// Setup default mocks
|
|
71
|
+
jest.mocked(useTamboClient).mockReturnValue({
|
|
72
|
+
threads: {
|
|
73
|
+
state: {
|
|
74
|
+
updateState: mockUpdateState,
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
jest.mocked(useV1ComponentContent).mockReturnValue({
|
|
79
|
+
componentId: mockComponentId,
|
|
80
|
+
threadId: mockThreadId,
|
|
81
|
+
messageId: mockMessageId,
|
|
82
|
+
componentName: "TestComponent",
|
|
83
|
+
});
|
|
84
|
+
jest.mocked(useStreamState).mockReturnValue(createMockStreamState());
|
|
85
|
+
// Setup default mock for useDebouncedCallback
|
|
86
|
+
jest
|
|
87
|
+
.mocked(useDebouncedCallback)
|
|
88
|
+
.mockImplementation((fn) => createMockDebouncedFunction(fn));
|
|
89
|
+
});
|
|
90
|
+
afterEach(() => {
|
|
91
|
+
jest.restoreAllMocks();
|
|
92
|
+
});
|
|
93
|
+
describe("Initial State Management", () => {
|
|
94
|
+
it("should initialize with initialValue when no server state exists", () => {
|
|
95
|
+
const initialValue = "test-initial";
|
|
96
|
+
jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));
|
|
97
|
+
const { result } = renderHook(() => useTamboV1ComponentState("testKey", initialValue));
|
|
98
|
+
expect(result.current[0]).toBe(initialValue);
|
|
99
|
+
});
|
|
100
|
+
it("should use server state over initialValue", () => {
|
|
101
|
+
const initialValue = "initial";
|
|
102
|
+
const serverValue = "server-value";
|
|
103
|
+
jest
|
|
104
|
+
.mocked(useStreamState)
|
|
105
|
+
.mockReturnValue(createMockStreamState({ testKey: serverValue }));
|
|
106
|
+
const { result } = renderHook(() => useTamboV1ComponentState("testKey", initialValue));
|
|
107
|
+
expect(result.current[0]).toBe(serverValue);
|
|
108
|
+
});
|
|
109
|
+
it("should handle undefined initialValue gracefully", () => {
|
|
110
|
+
jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));
|
|
111
|
+
const { result } = renderHook(() => useTamboV1ComponentState("testKey"));
|
|
112
|
+
expect(result.current[0]).toBeUndefined();
|
|
113
|
+
});
|
|
114
|
+
it("should handle different data types correctly", () => {
|
|
115
|
+
const testCases = [
|
|
116
|
+
{ value: "string" },
|
|
117
|
+
{ value: 42 },
|
|
118
|
+
{ value: true },
|
|
119
|
+
{ value: { name: "test" } },
|
|
120
|
+
{ value: [1, 2, 3] },
|
|
121
|
+
];
|
|
122
|
+
testCases.forEach(({ value }) => {
|
|
123
|
+
jest
|
|
124
|
+
.mocked(useStreamState)
|
|
125
|
+
.mockReturnValue(createMockStreamState({ testKey: value }));
|
|
126
|
+
const { result } = renderHook(() => useTamboV1ComponentState("testKey", value));
|
|
127
|
+
expect(result.current[0]).toEqual(value);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
describe("State Updates", () => {
|
|
132
|
+
it("should update local state immediately when setState is called", () => {
|
|
133
|
+
const initialValue = "initial";
|
|
134
|
+
jest
|
|
135
|
+
.mocked(useStreamState)
|
|
136
|
+
.mockReturnValue(createMockStreamState({ testKey: initialValue }));
|
|
137
|
+
const { result } = renderHook(() => useTamboV1ComponentState("testKey", initialValue));
|
|
138
|
+
const newValue = "updated";
|
|
139
|
+
act(() => {
|
|
140
|
+
result.current[1](newValue);
|
|
141
|
+
});
|
|
142
|
+
expect(result.current[0]).toBe(newValue);
|
|
143
|
+
});
|
|
144
|
+
it("should support functional updates", () => {
|
|
145
|
+
const initialValue = 5;
|
|
146
|
+
jest
|
|
147
|
+
.mocked(useStreamState)
|
|
148
|
+
.mockReturnValue(createMockStreamState({ counter: initialValue }));
|
|
149
|
+
const { result } = renderHook(() => useTamboV1ComponentState("counter", initialValue));
|
|
150
|
+
act(() => {
|
|
151
|
+
result.current[1]((prev) => (prev ?? 0) + 1);
|
|
152
|
+
});
|
|
153
|
+
expect(result.current[0]).toBe(6);
|
|
154
|
+
});
|
|
155
|
+
it("should trigger debounced API call when setState is called", () => {
|
|
156
|
+
const initialValue = "initial";
|
|
157
|
+
jest
|
|
158
|
+
.mocked(useStreamState)
|
|
159
|
+
.mockReturnValue(createMockStreamState({ testKey: initialValue }));
|
|
160
|
+
const { result } = renderHook(() => useTamboV1ComponentState("testKey", initialValue));
|
|
161
|
+
const newValue = "updated";
|
|
162
|
+
act(() => {
|
|
163
|
+
result.current[1](newValue);
|
|
164
|
+
});
|
|
165
|
+
// The debounced function should be called
|
|
166
|
+
expect(mockUpdateState).toHaveBeenCalledWith(mockComponentId, {
|
|
167
|
+
threadId: mockThreadId,
|
|
168
|
+
state: { testKey: newValue },
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
it("should work with complex objects", () => {
|
|
172
|
+
const initialValue = { name: "test", items: [1, 2, 3] };
|
|
173
|
+
jest
|
|
174
|
+
.mocked(useStreamState)
|
|
175
|
+
.mockReturnValue(createMockStreamState({ data: initialValue }));
|
|
176
|
+
const { result } = renderHook(() => useTamboV1ComponentState("data", initialValue));
|
|
177
|
+
const newValue = { name: "updated", items: [4, 5, 6] };
|
|
178
|
+
act(() => {
|
|
179
|
+
result.current[1](newValue);
|
|
180
|
+
});
|
|
181
|
+
expect(result.current[0]).toEqual(newValue);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
describe("Metadata", () => {
|
|
185
|
+
it("should return isPending and error in meta", () => {
|
|
186
|
+
jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));
|
|
187
|
+
const { result } = renderHook(() => useTamboV1ComponentState("testKey", "initial"));
|
|
188
|
+
expect(result.current[2]).toEqual({
|
|
189
|
+
isPending: false,
|
|
190
|
+
error: null,
|
|
191
|
+
flush: expect.any(Function),
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
it("should provide a flush function", () => {
|
|
195
|
+
const mockFlush = jest.fn();
|
|
196
|
+
const mockDebouncedFn = createMockDebouncedFunction(jest.fn());
|
|
197
|
+
mockDebouncedFn.flush = mockFlush;
|
|
198
|
+
jest.mocked(useDebouncedCallback).mockReturnValue(mockDebouncedFn);
|
|
199
|
+
jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));
|
|
200
|
+
const { result } = renderHook(() => useTamboV1ComponentState("testKey", "initial"));
|
|
201
|
+
act(() => {
|
|
202
|
+
result.current[2].flush();
|
|
203
|
+
});
|
|
204
|
+
expect(mockFlush).toHaveBeenCalled();
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
describe("Debouncing Behavior", () => {
|
|
208
|
+
it("should use default debounce time of 500ms", () => {
|
|
209
|
+
jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));
|
|
210
|
+
renderHook(() => useTamboV1ComponentState("testKey", "initial"));
|
|
211
|
+
expect(useDebouncedCallback).toHaveBeenCalledWith(expect.any(Function), 500);
|
|
212
|
+
});
|
|
213
|
+
it("should use custom debounce time when provided", () => {
|
|
214
|
+
jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));
|
|
215
|
+
const customDebounceTime = 1000;
|
|
216
|
+
renderHook(() => useTamboV1ComponentState("testKey", "initial", customDebounceTime));
|
|
217
|
+
expect(useDebouncedCallback).toHaveBeenCalledWith(expect.any(Function), customDebounceTime);
|
|
218
|
+
});
|
|
219
|
+
it("should flush debounced callback on unmount", () => {
|
|
220
|
+
const mockFlush = jest.fn();
|
|
221
|
+
const mockDebouncedFn = createMockDebouncedFunction(jest.fn());
|
|
222
|
+
mockDebouncedFn.flush = mockFlush;
|
|
223
|
+
jest.mocked(useDebouncedCallback).mockReturnValue(mockDebouncedFn);
|
|
224
|
+
jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));
|
|
225
|
+
const { unmount } = renderHook(() => useTamboV1ComponentState("testKey", "initial"));
|
|
226
|
+
unmount();
|
|
227
|
+
expect(mockFlush).toHaveBeenCalled();
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
describe("Server State Sync", () => {
|
|
231
|
+
it("should sync with server state changes from streaming", () => {
|
|
232
|
+
const streamState = createMockStreamState({ testKey: "initial" });
|
|
233
|
+
jest.mocked(useStreamState).mockReturnValue(streamState);
|
|
234
|
+
const { result, rerender } = renderHook(() => useTamboV1ComponentState("testKey", "initial"));
|
|
235
|
+
expect(result.current[0]).toBe("initial");
|
|
236
|
+
// Simulate server state change from streaming
|
|
237
|
+
const updatedStreamState = createMockStreamState({
|
|
238
|
+
testKey: "updated-from-server",
|
|
239
|
+
});
|
|
240
|
+
jest.mocked(useStreamState).mockReturnValue(updatedStreamState);
|
|
241
|
+
rerender();
|
|
242
|
+
expect(result.current[0]).toBe("updated-from-server");
|
|
243
|
+
});
|
|
244
|
+
it("should handle component not found in stream state", () => {
|
|
245
|
+
// Empty stream state (no matching component)
|
|
246
|
+
jest.mocked(useStreamState).mockReturnValue({
|
|
247
|
+
threadMap: {},
|
|
248
|
+
currentThreadId: null,
|
|
249
|
+
});
|
|
250
|
+
const { result } = renderHook(() => useTamboV1ComponentState("testKey", "default"));
|
|
251
|
+
expect(result.current[0]).toBe("default");
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
describe("Error Handling", () => {
|
|
255
|
+
it("should handle API errors gracefully", async () => {
|
|
256
|
+
const mockError = new Error("API Error");
|
|
257
|
+
mockUpdateState.mockRejectedValue(mockError);
|
|
258
|
+
// Create a sync mock that calls the function immediately
|
|
259
|
+
jest.mocked(useDebouncedCallback).mockImplementation((fn) => {
|
|
260
|
+
const debouncedFn = Object.assign(async (...args) => fn(...args), {
|
|
261
|
+
flush: jest.fn(),
|
|
262
|
+
cancel: jest.fn(),
|
|
263
|
+
isPending: () => false,
|
|
264
|
+
});
|
|
265
|
+
return debouncedFn;
|
|
266
|
+
});
|
|
267
|
+
jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));
|
|
268
|
+
const consoleSpy = jest.spyOn(console, "error").mockImplementation();
|
|
269
|
+
const { result } = renderHook(() => useTamboV1ComponentState("testKey", "initial"));
|
|
270
|
+
await act(async () => {
|
|
271
|
+
result.current[1]("new-value");
|
|
272
|
+
// Wait for async operations
|
|
273
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
274
|
+
});
|
|
275
|
+
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to sync state"), mockError);
|
|
276
|
+
consoleSpy.mockRestore();
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
describe("Context Requirements", () => {
|
|
280
|
+
it("should throw when used outside component content context", () => {
|
|
281
|
+
jest.mocked(useV1ComponentContent).mockImplementation(() => {
|
|
282
|
+
throw new Error("useV1ComponentContent must be used within a rendered component");
|
|
283
|
+
});
|
|
284
|
+
expect(() => {
|
|
285
|
+
renderHook(() => useTamboV1ComponentState("testKey", "initial"));
|
|
286
|
+
}).toThrow("useV1ComponentContent must be used within a rendered component");
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
//# sourceMappingURL=use-tambo-v1-component-state.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-tambo-v1-component-state.test.js","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-component-state.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import { act, renderHook } from \"@testing-library/react\";\nimport { useTamboV1ComponentState } from \"./use-tambo-v1-component-state\";\n\n// Mock the required modules\njest.mock(\"../../providers/tambo-client-provider\", () => ({\n useTamboClient: jest.fn(),\n}));\n\njest.mock(\"../providers/tambo-v1-stream-context\", () => ({\n useStreamState: jest.fn(),\n}));\n\njest.mock(\"../utils/component-renderer\", () => ({\n useV1ComponentContent: jest.fn(),\n}));\n\n// Create a mock debounced function with flush method\nconst createMockDebouncedFunction = (fn: (...args: unknown[]) => unknown) => {\n const debouncedFn = jest.fn((...args: unknown[]) =>\n fn(...args),\n ) as jest.Mock & {\n flush: jest.Mock;\n cancel: jest.Mock;\n isPending: () => boolean;\n };\n debouncedFn.flush = jest.fn();\n debouncedFn.cancel = jest.fn();\n debouncedFn.isPending = jest.fn(() => false);\n return debouncedFn;\n};\n\n// Mock use-debounce\njest.mock(\"use-debounce\", () => ({\n useDebouncedCallback: jest.fn(),\n}));\n\n// Import the mocked modules\nimport { useTamboClient } from \"../../providers/tambo-client-provider\";\nimport { useStreamState } from \"../providers/tambo-v1-stream-context\";\nimport { useV1ComponentContent } from \"../utils/component-renderer\";\nimport { useDebouncedCallback } from \"use-debounce\";\nimport type { StreamState } from \"../utils/event-accumulator\";\nimport type { V1ComponentContent } from \"../types/message\";\n\ndescribe(\"useTamboV1ComponentState\", () => {\n const mockUpdateState = jest.fn();\n const mockComponentId = \"comp_test123\";\n const mockThreadId = \"thread_abc\";\n const mockMessageId = \"msg_xyz\";\n\n // Helper to create mock stream state\n const createMockStreamState = (\n componentState?: Record<string, unknown>,\n ): StreamState => ({\n threadMap: {\n [mockThreadId]: {\n thread: {\n id: mockThreadId,\n messages: [\n {\n id: mockMessageId,\n role: \"assistant\",\n content: [\n {\n type: \"component\",\n id: mockComponentId,\n name: \"TestComponent\",\n props: {},\n state: componentState,\n streamingState: \"done\",\n } as V1ComponentContent,\n ],\n createdAt: new Date().toISOString(),\n },\n ],\n status: \"idle\",\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n },\n streaming: { status: \"idle\" },\n accumulatingToolArgs: new Map(),\n },\n },\n currentThreadId: mockThreadId,\n });\n\n beforeEach(() => {\n jest.clearAllMocks();\n\n // Setup default mocks\n jest.mocked(useTamboClient).mockReturnValue({\n threads: {\n state: {\n updateState: mockUpdateState,\n },\n },\n } as unknown as ReturnType<typeof useTamboClient>);\n\n jest.mocked(useV1ComponentContent).mockReturnValue({\n componentId: mockComponentId,\n threadId: mockThreadId,\n messageId: mockMessageId,\n componentName: \"TestComponent\",\n });\n\n jest.mocked(useStreamState).mockReturnValue(createMockStreamState());\n\n // Setup default mock for useDebouncedCallback\n jest\n .mocked(useDebouncedCallback)\n .mockImplementation((fn) => createMockDebouncedFunction(fn));\n });\n\n afterEach(() => {\n jest.restoreAllMocks();\n });\n\n describe(\"Initial State Management\", () => {\n it(\"should initialize with initialValue when no server state exists\", () => {\n const initialValue = \"test-initial\";\n jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));\n\n const { result } = renderHook(() =>\n useTamboV1ComponentState(\"testKey\", initialValue),\n );\n\n expect(result.current[0]).toBe(initialValue);\n });\n\n it(\"should use server state over initialValue\", () => {\n const initialValue = \"initial\";\n const serverValue = \"server-value\";\n jest\n .mocked(useStreamState)\n .mockReturnValue(createMockStreamState({ testKey: serverValue }));\n\n const { result } = renderHook(() =>\n useTamboV1ComponentState(\"testKey\", initialValue),\n );\n\n expect(result.current[0]).toBe(serverValue);\n });\n\n it(\"should handle undefined initialValue gracefully\", () => {\n jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));\n\n const { result } = renderHook(() => useTamboV1ComponentState(\"testKey\"));\n\n expect(result.current[0]).toBeUndefined();\n });\n\n it(\"should handle different data types correctly\", () => {\n const testCases = [\n { value: \"string\" },\n { value: 42 },\n { value: true },\n { value: { name: \"test\" } },\n { value: [1, 2, 3] },\n ];\n\n testCases.forEach(({ value }) => {\n jest\n .mocked(useStreamState)\n .mockReturnValue(createMockStreamState({ testKey: value }));\n\n const { result } = renderHook(() =>\n useTamboV1ComponentState(\"testKey\", value),\n );\n\n expect(result.current[0]).toEqual(value);\n });\n });\n });\n\n describe(\"State Updates\", () => {\n it(\"should update local state immediately when setState is called\", () => {\n const initialValue = \"initial\";\n jest\n .mocked(useStreamState)\n .mockReturnValue(createMockStreamState({ testKey: initialValue }));\n\n const { result } = renderHook(() =>\n useTamboV1ComponentState(\"testKey\", initialValue),\n );\n\n const newValue = \"updated\";\n act(() => {\n result.current[1](newValue);\n });\n\n expect(result.current[0]).toBe(newValue);\n });\n\n it(\"should support functional updates\", () => {\n const initialValue = 5;\n jest\n .mocked(useStreamState)\n .mockReturnValue(createMockStreamState({ counter: initialValue }));\n\n const { result } = renderHook(() =>\n useTamboV1ComponentState(\"counter\", initialValue),\n );\n\n act(() => {\n result.current[1]((prev) => (prev ?? 0) + 1);\n });\n\n expect(result.current[0]).toBe(6);\n });\n\n it(\"should trigger debounced API call when setState is called\", () => {\n const initialValue = \"initial\";\n jest\n .mocked(useStreamState)\n .mockReturnValue(createMockStreamState({ testKey: initialValue }));\n\n const { result } = renderHook(() =>\n useTamboV1ComponentState(\"testKey\", initialValue),\n );\n\n const newValue = \"updated\";\n act(() => {\n result.current[1](newValue);\n });\n\n // The debounced function should be called\n expect(mockUpdateState).toHaveBeenCalledWith(mockComponentId, {\n threadId: mockThreadId,\n state: { testKey: newValue },\n });\n });\n\n it(\"should work with complex objects\", () => {\n const initialValue = { name: \"test\", items: [1, 2, 3] };\n jest\n .mocked(useStreamState)\n .mockReturnValue(createMockStreamState({ data: initialValue }));\n\n const { result } = renderHook(() =>\n useTamboV1ComponentState(\"data\", initialValue),\n );\n\n const newValue = { name: \"updated\", items: [4, 5, 6] };\n act(() => {\n result.current[1](newValue);\n });\n\n expect(result.current[0]).toEqual(newValue);\n });\n });\n\n describe(\"Metadata\", () => {\n it(\"should return isPending and error in meta\", () => {\n jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));\n\n const { result } = renderHook(() =>\n useTamboV1ComponentState(\"testKey\", \"initial\"),\n );\n\n expect(result.current[2]).toEqual({\n isPending: false,\n error: null,\n flush: expect.any(Function),\n });\n });\n\n it(\"should provide a flush function\", () => {\n const mockFlush = jest.fn();\n const mockDebouncedFn = createMockDebouncedFunction(jest.fn());\n mockDebouncedFn.flush = mockFlush;\n jest.mocked(useDebouncedCallback).mockReturnValue(mockDebouncedFn);\n\n jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));\n\n const { result } = renderHook(() =>\n useTamboV1ComponentState(\"testKey\", \"initial\"),\n );\n\n act(() => {\n result.current[2].flush();\n });\n\n expect(mockFlush).toHaveBeenCalled();\n });\n });\n\n describe(\"Debouncing Behavior\", () => {\n it(\"should use default debounce time of 500ms\", () => {\n jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));\n\n renderHook(() => useTamboV1ComponentState(\"testKey\", \"initial\"));\n\n expect(useDebouncedCallback).toHaveBeenCalledWith(\n expect.any(Function),\n 500,\n );\n });\n\n it(\"should use custom debounce time when provided\", () => {\n jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));\n const customDebounceTime = 1000;\n\n renderHook(() =>\n useTamboV1ComponentState(\"testKey\", \"initial\", customDebounceTime),\n );\n\n expect(useDebouncedCallback).toHaveBeenCalledWith(\n expect.any(Function),\n customDebounceTime,\n );\n });\n\n it(\"should flush debounced callback on unmount\", () => {\n const mockFlush = jest.fn();\n const mockDebouncedFn = createMockDebouncedFunction(jest.fn());\n mockDebouncedFn.flush = mockFlush;\n jest.mocked(useDebouncedCallback).mockReturnValue(mockDebouncedFn);\n\n jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));\n\n const { unmount } = renderHook(() =>\n useTamboV1ComponentState(\"testKey\", \"initial\"),\n );\n\n unmount();\n\n expect(mockFlush).toHaveBeenCalled();\n });\n });\n\n describe(\"Server State Sync\", () => {\n it(\"should sync with server state changes from streaming\", () => {\n const streamState = createMockStreamState({ testKey: \"initial\" });\n jest.mocked(useStreamState).mockReturnValue(streamState);\n\n const { result, rerender } = renderHook(() =>\n useTamboV1ComponentState(\"testKey\", \"initial\"),\n );\n\n expect(result.current[0]).toBe(\"initial\");\n\n // Simulate server state change from streaming\n const updatedStreamState = createMockStreamState({\n testKey: \"updated-from-server\",\n });\n jest.mocked(useStreamState).mockReturnValue(updatedStreamState);\n\n rerender();\n\n expect(result.current[0]).toBe(\"updated-from-server\");\n });\n\n it(\"should handle component not found in stream state\", () => {\n // Empty stream state (no matching component)\n jest.mocked(useStreamState).mockReturnValue({\n threadMap: {},\n currentThreadId: null,\n });\n\n const { result } = renderHook(() =>\n useTamboV1ComponentState(\"testKey\", \"default\"),\n );\n\n expect(result.current[0]).toBe(\"default\");\n });\n });\n\n describe(\"Error Handling\", () => {\n it(\"should handle API errors gracefully\", async () => {\n const mockError = new Error(\"API Error\");\n mockUpdateState.mockRejectedValue(mockError);\n\n // Create a sync mock that calls the function immediately\n jest.mocked(useDebouncedCallback).mockImplementation((fn) => {\n const debouncedFn = Object.assign(\n async (...args: unknown[]) => fn(...args),\n {\n flush: jest.fn(),\n cancel: jest.fn(),\n isPending: () => false,\n },\n ) as unknown as ReturnType<typeof useDebouncedCallback>;\n return debouncedFn;\n });\n\n jest.mocked(useStreamState).mockReturnValue(createMockStreamState({}));\n\n const consoleSpy = jest.spyOn(console, \"error\").mockImplementation();\n\n const { result } = renderHook(() =>\n useTamboV1ComponentState(\"testKey\", \"initial\"),\n );\n\n await act(async () => {\n result.current[1](\"new-value\");\n // Wait for async operations\n await new Promise((resolve) => setTimeout(resolve, 0));\n });\n\n expect(consoleSpy).toHaveBeenCalledWith(\n expect.stringContaining(\"Failed to sync state\"),\n mockError,\n );\n\n consoleSpy.mockRestore();\n });\n });\n\n describe(\"Context Requirements\", () => {\n it(\"should throw when used outside component content context\", () => {\n jest.mocked(useV1ComponentContent).mockImplementation(() => {\n throw new Error(\n \"useV1ComponentContent must be used within a rendered component\",\n );\n });\n\n expect(() => {\n renderHook(() => useTamboV1ComponentState(\"testKey\", \"initial\"));\n }).toThrow(\n \"useV1ComponentContent must be used within a rendered component\",\n );\n });\n });\n});\n"]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for submitting a message
|
|
3
|
+
*/
|
|
4
|
+
export interface SubmitOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Enable debug logging for the stream
|
|
7
|
+
*/
|
|
8
|
+
debug?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Return type for useTamboV1ThreadInput hook
|
|
12
|
+
*/
|
|
13
|
+
export interface UseTamboV1ThreadInputReturn {
|
|
14
|
+
/** Current value of the input field */
|
|
15
|
+
value: string;
|
|
16
|
+
/** Function to update the input value */
|
|
17
|
+
setValue: React.Dispatch<React.SetStateAction<string>>;
|
|
18
|
+
/** Submit the current input. Clears input on success. */
|
|
19
|
+
submit: (options?: SubmitOptions) => Promise<{
|
|
20
|
+
threadId: string | undefined;
|
|
21
|
+
}>;
|
|
22
|
+
isPending: boolean;
|
|
23
|
+
isError: boolean;
|
|
24
|
+
error: Error | null;
|
|
25
|
+
isSuccess: boolean;
|
|
26
|
+
reset: () => void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Hook to manage thread input state and message submission.
|
|
30
|
+
*
|
|
31
|
+
* Provides a similar API to the beta SDK's useTamboThreadInput,
|
|
32
|
+
* managing input value state and providing a submit function.
|
|
33
|
+
* @param threadId - Optional thread ID to send messages to. If not provided, creates new thread
|
|
34
|
+
* @returns Thread input state and submit function
|
|
35
|
+
* @example
|
|
36
|
+
* ```tsx
|
|
37
|
+
* function ChatInput({ threadId }: { threadId?: string }) {
|
|
38
|
+
* const { value, setValue, submit, isPending } = useTamboV1ThreadInput(threadId);
|
|
39
|
+
*
|
|
40
|
+
* const handleSubmit = async (e: React.FormEvent) => {
|
|
41
|
+
* e.preventDefault();
|
|
42
|
+
* const result = await submit();
|
|
43
|
+
* console.log('Sent to thread:', result.threadId);
|
|
44
|
+
* };
|
|
45
|
+
*
|
|
46
|
+
* return (
|
|
47
|
+
* <form onSubmit={handleSubmit}>
|
|
48
|
+
* <input
|
|
49
|
+
* value={value}
|
|
50
|
+
* onChange={(e) => setValue(e.target.value)}
|
|
51
|
+
* disabled={isPending}
|
|
52
|
+
* />
|
|
53
|
+
* <button type="submit" disabled={isPending || !value.trim()}>
|
|
54
|
+
* Send
|
|
55
|
+
* </button>
|
|
56
|
+
* </form>
|
|
57
|
+
* );
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function useTamboV1ThreadInput(threadId?: string): UseTamboV1ThreadInputReturn;
|
|
62
|
+
//# sourceMappingURL=use-tambo-v1-thread-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-tambo-v1-thread-input.d.ts","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-thread-input.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IACvD,yDAAyD;IACzD,MAAM,EAAE,CACN,OAAO,CAAC,EAAE,aAAa,KACpB,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC,CAAC;IAC/C,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,CAAC,EAAE,MAAM,GAChB,2BAA2B,CAqC7B"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
/**
|
|
3
|
+
* useTamboV1ThreadInput - Thread Input Hook for v1 API
|
|
4
|
+
*
|
|
5
|
+
* Manages thread input state and message submission, mirroring
|
|
6
|
+
* the beta SDK's useTamboThreadInput API.
|
|
7
|
+
*/
|
|
8
|
+
import { useCallback, useState } from "react";
|
|
9
|
+
import { useTamboV1SendMessage } from "./use-tambo-v1-send-message";
|
|
10
|
+
/**
|
|
11
|
+
* Hook to manage thread input state and message submission.
|
|
12
|
+
*
|
|
13
|
+
* Provides a similar API to the beta SDK's useTamboThreadInput,
|
|
14
|
+
* managing input value state and providing a submit function.
|
|
15
|
+
* @param threadId - Optional thread ID to send messages to. If not provided, creates new thread
|
|
16
|
+
* @returns Thread input state and submit function
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* function ChatInput({ threadId }: { threadId?: string }) {
|
|
20
|
+
* const { value, setValue, submit, isPending } = useTamboV1ThreadInput(threadId);
|
|
21
|
+
*
|
|
22
|
+
* const handleSubmit = async (e: React.FormEvent) => {
|
|
23
|
+
* e.preventDefault();
|
|
24
|
+
* const result = await submit();
|
|
25
|
+
* console.log('Sent to thread:', result.threadId);
|
|
26
|
+
* };
|
|
27
|
+
*
|
|
28
|
+
* return (
|
|
29
|
+
* <form onSubmit={handleSubmit}>
|
|
30
|
+
* <input
|
|
31
|
+
* value={value}
|
|
32
|
+
* onChange={(e) => setValue(e.target.value)}
|
|
33
|
+
* disabled={isPending}
|
|
34
|
+
* />
|
|
35
|
+
* <button type="submit" disabled={isPending || !value.trim()}>
|
|
36
|
+
* Send
|
|
37
|
+
* </button>
|
|
38
|
+
* </form>
|
|
39
|
+
* );
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function useTamboV1ThreadInput(threadId) {
|
|
44
|
+
const [value, setValue] = useState("");
|
|
45
|
+
const mutation = useTamboV1SendMessage(threadId);
|
|
46
|
+
const submit = useCallback(async (options) => {
|
|
47
|
+
const trimmedValue = value.trim();
|
|
48
|
+
if (!trimmedValue) {
|
|
49
|
+
throw new Error("Message cannot be empty");
|
|
50
|
+
}
|
|
51
|
+
const result = await mutation.mutateAsync({
|
|
52
|
+
message: {
|
|
53
|
+
role: "user",
|
|
54
|
+
content: [{ type: "text", text: trimmedValue }],
|
|
55
|
+
},
|
|
56
|
+
debug: options?.debug,
|
|
57
|
+
});
|
|
58
|
+
// Clear input on successful submission
|
|
59
|
+
setValue("");
|
|
60
|
+
return result;
|
|
61
|
+
}, [value, mutation]);
|
|
62
|
+
return {
|
|
63
|
+
value,
|
|
64
|
+
setValue,
|
|
65
|
+
submit,
|
|
66
|
+
isPending: mutation.isPending,
|
|
67
|
+
isError: mutation.isError,
|
|
68
|
+
error: mutation.error,
|
|
69
|
+
isSuccess: mutation.isSuccess,
|
|
70
|
+
reset: mutation.reset,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=use-tambo-v1-thread-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-tambo-v1-thread-input.js","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-thread-input.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AA+BpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAiB;IAEjB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAEjD,MAAM,MAAM,GAAG,WAAW,CACxB,KAAK,EAAE,OAAuB,EAAE,EAAE;QAChC,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC;YACxC,OAAO,EAAE;gBACP,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;aAChD;YACD,KAAK,EAAE,OAAO,EAAE,KAAK;SACtB,CAAC,CAAC;QAEH,uCAAuC;QACvC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAEb,OAAO,MAAM,CAAC;IAChB,CAAC,EACD,CAAC,KAAK,EAAE,QAAQ,CAAC,CAClB,CAAC;IAEF,OAAO;QACL,KAAK;QACL,QAAQ;QACR,MAAM;QACN,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,KAAK,EAAE,QAAQ,CAAC,KAAK;KACtB,CAAC;AACJ,CAAC","sourcesContent":["\"use client\";\n\n/**\n * useTamboV1ThreadInput - Thread Input Hook for v1 API\n *\n * Manages thread input state and message submission, mirroring\n * the beta SDK's useTamboThreadInput API.\n */\n\nimport { useCallback, useState } from \"react\";\nimport { useTamboV1SendMessage } from \"./use-tambo-v1-send-message\";\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 * Return type for useTamboV1ThreadInput hook\n */\nexport interface UseTamboV1ThreadInputReturn {\n /** Current value of the input field */\n value: string;\n /** Function to update the input value */\n setValue: React.Dispatch<React.SetStateAction<string>>;\n /** Submit the current input. Clears input on success. */\n submit: (\n options?: SubmitOptions,\n ) => Promise<{ threadId: string | undefined }>;\n isPending: boolean;\n isError: boolean;\n error: Error | null;\n isSuccess: boolean;\n reset: () => void;\n}\n\n/**\n * Hook to manage thread input state and message submission.\n *\n * Provides a similar API to the beta SDK's useTamboThreadInput,\n * managing input value state and providing a submit function.\n * @param threadId - Optional thread ID to send messages to. If not provided, creates new thread\n * @returns Thread input state and submit function\n * @example\n * ```tsx\n * function ChatInput({ threadId }: { threadId?: string }) {\n * const { value, setValue, submit, isPending } = useTamboV1ThreadInput(threadId);\n *\n * const handleSubmit = async (e: React.FormEvent) => {\n * e.preventDefault();\n * const result = await submit();\n * console.log('Sent to thread:', result.threadId);\n * };\n *\n * return (\n * <form onSubmit={handleSubmit}>\n * <input\n * value={value}\n * onChange={(e) => setValue(e.target.value)}\n * disabled={isPending}\n * />\n * <button type=\"submit\" disabled={isPending || !value.trim()}>\n * Send\n * </button>\n * </form>\n * );\n * }\n * ```\n */\nexport function useTamboV1ThreadInput(\n threadId?: string,\n): UseTamboV1ThreadInputReturn {\n const [value, setValue] = useState(\"\");\n const mutation = useTamboV1SendMessage(threadId);\n\n const submit = useCallback(\n async (options?: SubmitOptions) => {\n const trimmedValue = value.trim();\n if (!trimmedValue) {\n throw new Error(\"Message cannot be empty\");\n }\n\n const result = await mutation.mutateAsync({\n message: {\n role: \"user\",\n content: [{ type: \"text\", text: trimmedValue }],\n },\n debug: options?.debug,\n });\n\n // Clear input on successful submission\n setValue(\"\");\n\n return result;\n },\n [value, mutation],\n );\n\n return {\n value,\n setValue,\n submit,\n isPending: mutation.isPending,\n isError: mutation.isError,\n error: mutation.error,\n isSuccess: mutation.isSuccess,\n reset: mutation.reset,\n };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-tambo-v1-thread-input.test.d.ts","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-thread-input.test.tsx"],"names":[],"mappings":""}
|