@tambo-ai/react 0.72.0 → 0.73.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.
Files changed (129) hide show
  1. package/dist/v1/hooks/use-tambo-v1-messages.test.js +22 -9
  2. package/dist/v1/hooks/use-tambo-v1-messages.test.js.map +1 -1
  3. package/dist/v1/hooks/use-tambo-v1-send-message.d.ts +1 -0
  4. package/dist/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -1
  5. package/dist/v1/hooks/use-tambo-v1-send-message.js +9 -2
  6. package/dist/v1/hooks/use-tambo-v1-send-message.js.map +1 -1
  7. package/dist/v1/hooks/use-tambo-v1-send-message.test.js +22 -9
  8. package/dist/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -1
  9. package/dist/v1/hooks/use-tambo-v1-suggestions.d.ts +91 -0
  10. package/dist/v1/hooks/use-tambo-v1-suggestions.d.ts.map +1 -0
  11. package/dist/v1/hooks/use-tambo-v1-suggestions.js +152 -0
  12. package/dist/v1/hooks/use-tambo-v1-suggestions.js.map +1 -0
  13. package/dist/v1/hooks/use-tambo-v1-suggestions.test.d.ts +2 -0
  14. package/dist/v1/hooks/use-tambo-v1-suggestions.test.d.ts.map +1 -0
  15. package/dist/v1/hooks/use-tambo-v1-suggestions.test.js +511 -0
  16. package/dist/v1/hooks/use-tambo-v1-suggestions.test.js.map +1 -0
  17. package/dist/v1/hooks/use-tambo-v1-thread-input.d.ts +6 -57
  18. package/dist/v1/hooks/use-tambo-v1-thread-input.d.ts.map +1 -1
  19. package/dist/v1/hooks/use-tambo-v1-thread-input.js +7 -67
  20. package/dist/v1/hooks/use-tambo-v1-thread-input.js.map +1 -1
  21. package/dist/v1/hooks/use-tambo-v1-thread-input.test.js +201 -72
  22. package/dist/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -1
  23. package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts +6 -4
  24. package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -1
  25. package/dist/v1/hooks/use-tambo-v1-thread-list.js +2 -2
  26. package/dist/v1/hooks/use-tambo-v1-thread-list.js.map +1 -1
  27. package/dist/v1/hooks/use-tambo-v1-thread-list.test.js +2 -2
  28. package/dist/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -1
  29. package/dist/v1/hooks/use-tambo-v1.test.js +16 -7
  30. package/dist/v1/hooks/use-tambo-v1.test.js.map +1 -1
  31. package/dist/v1/index.d.ts +22 -13
  32. package/dist/v1/index.d.ts.map +1 -1
  33. package/dist/v1/index.js +31 -39
  34. package/dist/v1/index.js.map +1 -1
  35. package/dist/v1/providers/tambo-v1-provider.d.ts +27 -9
  36. package/dist/v1/providers/tambo-v1-provider.d.ts.map +1 -1
  37. package/dist/v1/providers/tambo-v1-provider.js +22 -11
  38. package/dist/v1/providers/tambo-v1-provider.js.map +1 -1
  39. package/dist/v1/providers/tambo-v1-provider.test.js +27 -10
  40. package/dist/v1/providers/tambo-v1-provider.test.js.map +1 -1
  41. package/dist/v1/providers/tambo-v1-stream-context.d.ts +19 -10
  42. package/dist/v1/providers/tambo-v1-stream-context.d.ts.map +1 -1
  43. package/dist/v1/providers/tambo-v1-stream-context.js +43 -53
  44. package/dist/v1/providers/tambo-v1-stream-context.js.map +1 -1
  45. package/dist/v1/providers/tambo-v1-stream-context.test.js +94 -19
  46. package/dist/v1/providers/tambo-v1-stream-context.test.js.map +1 -1
  47. package/dist/v1/providers/tambo-v1-stub-provider.d.ts +74 -0
  48. package/dist/v1/providers/tambo-v1-stub-provider.d.ts.map +1 -0
  49. package/dist/v1/providers/tambo-v1-stub-provider.js +212 -0
  50. package/dist/v1/providers/tambo-v1-stub-provider.js.map +1 -0
  51. package/dist/v1/providers/tambo-v1-stub-provider.test.d.ts +2 -0
  52. package/dist/v1/providers/tambo-v1-stub-provider.test.d.ts.map +1 -0
  53. package/dist/v1/providers/tambo-v1-stub-provider.test.js +162 -0
  54. package/dist/v1/providers/tambo-v1-stub-provider.test.js.map +1 -0
  55. package/dist/v1/providers/tambo-v1-thread-input-provider.d.ts +105 -0
  56. package/dist/v1/providers/tambo-v1-thread-input-provider.d.ts.map +1 -0
  57. package/dist/v1/providers/tambo-v1-thread-input-provider.js +191 -0
  58. package/dist/v1/providers/tambo-v1-thread-input-provider.js.map +1 -0
  59. package/dist/v1/utils/component-renderer.d.ts +15 -67
  60. package/dist/v1/utils/component-renderer.d.ts.map +1 -1
  61. package/dist/v1/utils/component-renderer.js +3 -149
  62. package/dist/v1/utils/component-renderer.js.map +1 -1
  63. package/dist/v1/utils/component-renderer.test.js +15 -350
  64. package/dist/v1/utils/component-renderer.test.js.map +1 -1
  65. package/esm/v1/hooks/use-tambo-v1-messages.test.js +22 -9
  66. package/esm/v1/hooks/use-tambo-v1-messages.test.js.map +1 -1
  67. package/esm/v1/hooks/use-tambo-v1-send-message.d.ts +1 -0
  68. package/esm/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -1
  69. package/esm/v1/hooks/use-tambo-v1-send-message.js +9 -2
  70. package/esm/v1/hooks/use-tambo-v1-send-message.js.map +1 -1
  71. package/esm/v1/hooks/use-tambo-v1-send-message.test.js +22 -9
  72. package/esm/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -1
  73. package/esm/v1/hooks/use-tambo-v1-suggestions.d.ts +91 -0
  74. package/esm/v1/hooks/use-tambo-v1-suggestions.d.ts.map +1 -0
  75. package/esm/v1/hooks/use-tambo-v1-suggestions.js +149 -0
  76. package/esm/v1/hooks/use-tambo-v1-suggestions.js.map +1 -0
  77. package/esm/v1/hooks/use-tambo-v1-suggestions.test.d.ts +2 -0
  78. package/esm/v1/hooks/use-tambo-v1-suggestions.test.d.ts.map +1 -0
  79. package/esm/v1/hooks/use-tambo-v1-suggestions.test.js +506 -0
  80. package/esm/v1/hooks/use-tambo-v1-suggestions.test.js.map +1 -0
  81. package/esm/v1/hooks/use-tambo-v1-thread-input.d.ts +6 -57
  82. package/esm/v1/hooks/use-tambo-v1-thread-input.d.ts.map +1 -1
  83. package/esm/v1/hooks/use-tambo-v1-thread-input.js +5 -66
  84. package/esm/v1/hooks/use-tambo-v1-thread-input.js.map +1 -1
  85. package/esm/v1/hooks/use-tambo-v1-thread-input.test.js +199 -73
  86. package/esm/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -1
  87. package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts +6 -4
  88. package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -1
  89. package/esm/v1/hooks/use-tambo-v1-thread-list.js +2 -2
  90. package/esm/v1/hooks/use-tambo-v1-thread-list.js.map +1 -1
  91. package/esm/v1/hooks/use-tambo-v1-thread-list.test.js +2 -2
  92. package/esm/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -1
  93. package/esm/v1/hooks/use-tambo-v1.test.js +16 -7
  94. package/esm/v1/hooks/use-tambo-v1.test.js.map +1 -1
  95. package/esm/v1/index.d.ts +22 -13
  96. package/esm/v1/index.d.ts.map +1 -1
  97. package/esm/v1/index.js +23 -18
  98. package/esm/v1/index.js.map +1 -1
  99. package/esm/v1/providers/tambo-v1-provider.d.ts +27 -9
  100. package/esm/v1/providers/tambo-v1-provider.d.ts.map +1 -1
  101. package/esm/v1/providers/tambo-v1-provider.js +20 -10
  102. package/esm/v1/providers/tambo-v1-provider.js.map +1 -1
  103. package/esm/v1/providers/tambo-v1-provider.test.js +28 -11
  104. package/esm/v1/providers/tambo-v1-provider.test.js.map +1 -1
  105. package/esm/v1/providers/tambo-v1-stream-context.d.ts +19 -10
  106. package/esm/v1/providers/tambo-v1-stream-context.d.ts.map +1 -1
  107. package/esm/v1/providers/tambo-v1-stream-context.js +44 -54
  108. package/esm/v1/providers/tambo-v1-stream-context.js.map +1 -1
  109. package/esm/v1/providers/tambo-v1-stream-context.test.js +95 -20
  110. package/esm/v1/providers/tambo-v1-stream-context.test.js.map +1 -1
  111. package/esm/v1/providers/tambo-v1-stub-provider.d.ts +74 -0
  112. package/esm/v1/providers/tambo-v1-stub-provider.d.ts.map +1 -0
  113. package/esm/v1/providers/tambo-v1-stub-provider.js +176 -0
  114. package/esm/v1/providers/tambo-v1-stub-provider.js.map +1 -0
  115. package/esm/v1/providers/tambo-v1-stub-provider.test.d.ts +2 -0
  116. package/esm/v1/providers/tambo-v1-stub-provider.test.d.ts.map +1 -0
  117. package/esm/v1/providers/tambo-v1-stub-provider.test.js +157 -0
  118. package/esm/v1/providers/tambo-v1-stub-provider.test.js.map +1 -0
  119. package/esm/v1/providers/tambo-v1-thread-input-provider.d.ts +105 -0
  120. package/esm/v1/providers/tambo-v1-thread-input-provider.d.ts.map +1 -0
  121. package/esm/v1/providers/tambo-v1-thread-input-provider.js +153 -0
  122. package/esm/v1/providers/tambo-v1-thread-input-provider.js.map +1 -0
  123. package/esm/v1/utils/component-renderer.d.ts +15 -67
  124. package/esm/v1/utils/component-renderer.d.ts.map +1 -1
  125. package/esm/v1/utils/component-renderer.js +4 -146
  126. package/esm/v1/utils/component-renderer.js.map +1 -1
  127. package/esm/v1/utils/component-renderer.test.js +16 -351
  128. package/esm/v1/utils/component-renderer.test.js.map +1 -1
  129. package/package.json +2 -2
@@ -2,72 +2,11 @@
2
2
  /**
3
3
  * useTamboV1ThreadInput - Thread Input Hook for v1 API
4
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
- * };
5
+ * Re-exports the shared thread input hook from the provider.
6
+ * This hook uses shared context, enabling features like suggestions
7
+ * to update the input field directly.
27
8
  *
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
- * ```
9
+ * For direct thread control without shared state, use useTamboV1SendMessage instead.
42
10
  */
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
- }
11
+ export { useTamboV1ThreadInput, } from "../providers/tambo-v1-thread-input-provider";
73
12
  //# sourceMappingURL=use-tambo-v1-thread-input.js.map
@@ -1 +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"]}
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;;;;;;;;GAQG;AAEH,OAAO,EACL,qBAAqB,GAGtB,MAAM,6CAA6C,CAAC","sourcesContent":["\"use client\";\n\n/**\n * useTamboV1ThreadInput - Thread Input Hook for v1 API\n *\n * Re-exports the shared thread input hook from the provider.\n * This hook uses shared context, enabling features like suggestions\n * to update the input field directly.\n *\n * For direct thread control without shared state, use useTamboV1SendMessage instead.\n */\n\nexport {\n useTamboV1ThreadInput,\n type TamboV1ThreadInputContextProps,\n type SubmitOptions,\n} from \"../providers/tambo-v1-thread-input-provider\";\n"]}
@@ -1,56 +1,99 @@
1
- import { renderHook, act } from "@testing-library/react";
2
- import { useTamboV1ThreadInput } from "./use-tambo-v1-thread-input";
3
- // Create mock functions
4
- const mockMutateAsync = jest.fn();
5
- const mockMutate = jest.fn();
6
- const mockReset = jest.fn();
7
- // Mock useTamboV1SendMessage module
8
- jest.mock("./use-tambo-v1-send-message");
1
+ import { renderHook, act, waitFor } from "@testing-library/react";
2
+ import React from "react";
3
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
4
+ import { TamboV1ThreadInputProvider, useTamboV1ThreadInput, } from "../providers/tambo-v1-thread-input-provider";
5
+ import { TamboV1StreamProvider } from "../providers/tambo-v1-stream-context";
9
6
  import { useTamboV1SendMessage } from "./use-tambo-v1-send-message";
10
- // Helper to set up the mock with default values
11
- function setupMock(overrides = {}) {
12
- const mockReturn = {
13
- mutateAsync: mockMutateAsync,
14
- mutate: mockMutate,
15
- isPending: false,
16
- isError: false,
17
- error: null,
18
- isSuccess: false,
19
- isIdle: true,
20
- isPaused: false,
21
- status: "idle",
22
- data: undefined,
23
- variables: undefined,
24
- failureCount: 0,
25
- failureReason: null,
26
- reset: mockReset,
27
- context: undefined,
28
- submittedAt: 0,
29
- ...overrides,
7
+ // Mock useTamboV1SendMessage
8
+ jest.mock("./use-tambo-v1-send-message", () => ({
9
+ useTamboV1SendMessage: jest.fn(),
10
+ }));
11
+ // Mock useTamboQueryClient to avoid TamboClientProvider dependency
12
+ jest.mock("../../providers/tambo-client-provider", () => ({
13
+ useTamboQueryClient: jest.fn(() => new QueryClient()),
14
+ useTamboClient: jest.fn(),
15
+ }));
16
+ const createSuccessfulFileReader = () => {
17
+ const reader = {
18
+ readAsDataURL: jest.fn(),
19
+ onload: null,
20
+ onerror: null,
21
+ result: "data:image/png;base64,mock-data",
30
22
  };
31
- jest.mocked(useTamboV1SendMessage).mockReturnValue(mockReturn);
32
- return mockReturn;
33
- }
23
+ reader.readAsDataURL = jest.fn(() => {
24
+ setTimeout(() => {
25
+ reader.onload?.({});
26
+ }, 0);
27
+ });
28
+ return reader;
29
+ };
30
+ const originalFileReader = global.FileReader;
34
31
  describe("useTamboV1ThreadInput", () => {
32
+ const mockMutateAsync = jest.fn();
33
+ let queryClient;
34
+ function createWrapper({ streamState } = {}) {
35
+ const noopDispatch = () => { };
36
+ return function Wrapper({ children }) {
37
+ const streamProviderProps = streamState === undefined
38
+ ? {}
39
+ : { state: streamState, dispatch: noopDispatch };
40
+ return (React.createElement(QueryClientProvider, { client: queryClient },
41
+ React.createElement(TamboV1StreamProvider, { ...streamProviderProps },
42
+ React.createElement(TamboV1ThreadInputProvider, null, children))));
43
+ };
44
+ }
35
45
  beforeEach(() => {
36
46
  jest.clearAllMocks();
47
+ global.FileReader = jest.fn(() => createSuccessfulFileReader());
48
+ queryClient = new QueryClient({
49
+ defaultOptions: {
50
+ queries: { retry: false },
51
+ mutations: { retry: false },
52
+ },
53
+ });
37
54
  mockMutateAsync.mockResolvedValue({ threadId: "thread_123" });
38
- setupMock();
55
+ jest.mocked(useTamboV1SendMessage).mockReturnValue({
56
+ mutateAsync: mockMutateAsync,
57
+ mutate: jest.fn(),
58
+ isPending: false,
59
+ isError: false,
60
+ error: null,
61
+ isSuccess: false,
62
+ isIdle: true,
63
+ isPaused: false,
64
+ status: "idle",
65
+ data: undefined,
66
+ variables: undefined,
67
+ failureCount: 0,
68
+ failureReason: null,
69
+ reset: jest.fn(),
70
+ context: undefined,
71
+ submittedAt: 0,
72
+ });
73
+ });
74
+ afterEach(() => {
75
+ global.FileReader = originalFileReader;
39
76
  });
40
77
  describe("State Management", () => {
41
78
  it("initializes with empty value", () => {
42
- const { result } = renderHook(() => useTamboV1ThreadInput());
79
+ const { result } = renderHook(() => useTamboV1ThreadInput(), {
80
+ wrapper: createWrapper(),
81
+ });
43
82
  expect(result.current.value).toBe("");
44
83
  });
45
84
  it("updates value via setValue", () => {
46
- const { result } = renderHook(() => useTamboV1ThreadInput());
85
+ const { result } = renderHook(() => useTamboV1ThreadInput(), {
86
+ wrapper: createWrapper(),
87
+ });
47
88
  act(() => {
48
89
  result.current.setValue("Hello world");
49
90
  });
50
91
  expect(result.current.value).toBe("Hello world");
51
92
  });
52
93
  it("supports functional updates for setValue", () => {
53
- const { result } = renderHook(() => useTamboV1ThreadInput());
94
+ const { result } = renderHook(() => useTamboV1ThreadInput(), {
95
+ wrapper: createWrapper(),
96
+ });
54
97
  act(() => {
55
98
  result.current.setValue("Hello");
56
99
  });
@@ -62,7 +105,9 @@ describe("useTamboV1ThreadInput", () => {
62
105
  });
63
106
  describe("Submit Behavior", () => {
64
107
  it("submits message and clears input on success", async () => {
65
- const { result } = renderHook(() => useTamboV1ThreadInput("thread_123"));
108
+ const { result } = renderHook(() => useTamboV1ThreadInput(), {
109
+ wrapper: createWrapper(),
110
+ });
66
111
  act(() => {
67
112
  result.current.setValue("Test message");
68
113
  });
@@ -71,7 +116,9 @@ describe("useTamboV1ThreadInput", () => {
71
116
  expect(response.threadId).toBe("thread_123");
72
117
  });
73
118
  // Input should be cleared
74
- expect(result.current.value).toBe("");
119
+ await waitFor(() => {
120
+ expect(result.current.value).toBe("");
121
+ });
75
122
  // Should have called mutateAsync with correct message format
76
123
  expect(mockMutateAsync).toHaveBeenCalledWith({
77
124
  message: {
@@ -82,12 +129,16 @@ describe("useTamboV1ThreadInput", () => {
82
129
  });
83
130
  });
84
131
  it("throws error when submitting empty message", async () => {
85
- const { result } = renderHook(() => useTamboV1ThreadInput());
132
+ const { result } = renderHook(() => useTamboV1ThreadInput(), {
133
+ wrapper: createWrapper(),
134
+ });
86
135
  await expect(result.current.submit()).rejects.toThrow("Message cannot be empty");
87
136
  expect(mockMutateAsync).not.toHaveBeenCalled();
88
137
  });
89
138
  it("throws error when submitting whitespace-only message", async () => {
90
- const { result } = renderHook(() => useTamboV1ThreadInput());
139
+ const { result } = renderHook(() => useTamboV1ThreadInput(), {
140
+ wrapper: createWrapper(),
141
+ });
91
142
  act(() => {
92
143
  result.current.setValue(" ");
93
144
  });
@@ -95,7 +146,9 @@ describe("useTamboV1ThreadInput", () => {
95
146
  expect(mockMutateAsync).not.toHaveBeenCalled();
96
147
  });
97
148
  it("passes debug option to mutation", async () => {
98
- const { result } = renderHook(() => useTamboV1ThreadInput());
149
+ const { result } = renderHook(() => useTamboV1ThreadInput(), {
150
+ wrapper: createWrapper(),
151
+ });
99
152
  act(() => {
100
153
  result.current.setValue("Debug message");
101
154
  });
@@ -110,10 +163,45 @@ describe("useTamboV1ThreadInput", () => {
110
163
  debug: true,
111
164
  });
112
165
  });
113
- it("trims whitespace from message", async () => {
114
- const { result } = renderHook(() => useTamboV1ThreadInput());
166
+ it("submits image-only messages as resource content", async () => {
167
+ const { result } = renderHook(() => useTamboV1ThreadInput(), {
168
+ wrapper: createWrapper(),
169
+ });
170
+ await act(async () => {
171
+ await result.current.addImage(new File(["image"], "photo.png", { type: "image/png" }));
172
+ });
173
+ await act(async () => {
174
+ await result.current.submit();
175
+ });
176
+ expect(mockMutateAsync).toHaveBeenCalledWith({
177
+ message: {
178
+ role: "user",
179
+ content: [
180
+ {
181
+ type: "resource",
182
+ resource: {
183
+ blob: "mock-data",
184
+ mimeType: "image/png",
185
+ name: "photo.png",
186
+ },
187
+ },
188
+ ],
189
+ },
190
+ debug: undefined,
191
+ });
192
+ await waitFor(() => {
193
+ expect(result.current.images).toEqual([]);
194
+ });
195
+ });
196
+ it("includes both text and image resource content when both are present", async () => {
197
+ const { result } = renderHook(() => useTamboV1ThreadInput(), {
198
+ wrapper: createWrapper(),
199
+ });
115
200
  act(() => {
116
- result.current.setValue(" Trimmed message ");
201
+ result.current.setValue("Test message");
202
+ });
203
+ await act(async () => {
204
+ await result.current.addImage(new File(["image"], "photo.png", { type: "image/png" }));
117
205
  });
118
206
  await act(async () => {
119
207
  await result.current.submit();
@@ -121,45 +209,83 @@ describe("useTamboV1ThreadInput", () => {
121
209
  expect(mockMutateAsync).toHaveBeenCalledWith({
122
210
  message: {
123
211
  role: "user",
124
- content: [{ type: "text", text: "Trimmed message" }],
212
+ content: [
213
+ { type: "text", text: "Test message" },
214
+ {
215
+ type: "resource",
216
+ resource: {
217
+ blob: "mock-data",
218
+ mimeType: "image/png",
219
+ name: "photo.png",
220
+ },
221
+ },
222
+ ],
125
223
  },
126
224
  debug: undefined,
127
225
  });
128
226
  });
129
227
  });
130
- describe("Thread ID Handling", () => {
131
- it("passes threadId to useTamboV1SendMessage", () => {
132
- renderHook(() => useTamboV1ThreadInput("custom_thread_id"));
133
- expect(useTamboV1SendMessage).toHaveBeenCalledWith("custom_thread_id");
228
+ describe("Thread ID Management", () => {
229
+ it("initializes with undefined threadId", () => {
230
+ const { result } = renderHook(() => useTamboV1ThreadInput(), {
231
+ wrapper: createWrapper(),
232
+ });
233
+ expect(result.current.threadId).toBeUndefined();
134
234
  });
135
- it("passes undefined threadId when not provided", () => {
136
- renderHook(() => useTamboV1ThreadInput());
137
- expect(useTamboV1SendMessage).toHaveBeenCalledWith(undefined);
235
+ it("allows setting threadId via setThreadId", () => {
236
+ const { result } = renderHook(() => useTamboV1ThreadInput(), {
237
+ wrapper: createWrapper(),
238
+ });
239
+ act(() => {
240
+ result.current.setThreadId("custom_thread_id");
241
+ });
242
+ expect(result.current.threadId).toBe("custom_thread_id");
138
243
  });
139
- });
140
- describe("Mutation State", () => {
141
- it("exposes isPending state", () => {
142
- setupMock({ isPending: true });
143
- const { result } = renderHook(() => useTamboV1ThreadInput());
144
- expect(result.current.isPending).toBe(true);
145
- });
146
- it("exposes isError state", () => {
147
- setupMock({ isError: true, error: new Error("Test error") });
148
- const { result } = renderHook(() => useTamboV1ThreadInput());
149
- expect(result.current.isError).toBe(true);
150
- expect(result.current.error?.message).toBe("Test error");
151
- });
152
- it("exposes isSuccess state", () => {
153
- setupMock({ isSuccess: true });
154
- const { result } = renderHook(() => useTamboV1ThreadInput());
155
- expect(result.current.isSuccess).toBe(true);
156
- });
157
- it("exposes reset function", () => {
158
- const { result } = renderHook(() => useTamboV1ThreadInput());
244
+ it("does not take ownership of threadId when inheriting stream selection", async () => {
245
+ const { result } = renderHook(() => useTamboV1ThreadInput(), {
246
+ wrapper: createWrapper({
247
+ streamState: { threadMap: {}, currentThreadId: "thread_stream" },
248
+ }),
249
+ });
250
+ expect(result.current.threadId).toBe("thread_stream");
251
+ expect(jest.mocked(useTamboV1SendMessage).mock.calls.map((call) => call[0])).toContain("thread_stream");
159
252
  act(() => {
160
- result.current.reset();
253
+ result.current.setValue("Test message");
254
+ });
255
+ await act(async () => {
256
+ await result.current.submit();
257
+ });
258
+ expect(result.current.threadId).toBe("thread_stream");
259
+ expect(jest.mocked(useTamboV1SendMessage).mock.calls.map((call) => call[0])).not.toContain("thread_123");
260
+ });
261
+ });
262
+ describe("Image State", () => {
263
+ it("initializes with empty images array", () => {
264
+ const { result } = renderHook(() => useTamboV1ThreadInput(), {
265
+ wrapper: createWrapper(),
266
+ });
267
+ expect(result.current.images).toEqual([]);
268
+ });
269
+ it("exposes image management functions", () => {
270
+ const { result } = renderHook(() => useTamboV1ThreadInput(), {
271
+ wrapper: createWrapper(),
161
272
  });
162
- expect(mockReset).toHaveBeenCalled();
273
+ expect(typeof result.current.addImage).toBe("function");
274
+ expect(typeof result.current.addImages).toBe("function");
275
+ expect(typeof result.current.removeImage).toBe("function");
276
+ expect(typeof result.current.clearImages).toBe("function");
277
+ });
278
+ });
279
+ describe("Error handling", () => {
280
+ it("throws error when used outside provider", () => {
281
+ // Suppress console.error for this test
282
+ const consoleSpy = jest
283
+ .spyOn(console, "error")
284
+ .mockImplementation(() => { });
285
+ expect(() => {
286
+ renderHook(() => useTamboV1ThreadInput());
287
+ }).toThrow("useTamboV1ThreadInput must be used within TamboV1ThreadInputProvider");
288
+ consoleSpy.mockRestore();
163
289
  });
164
290
  });
165
291
  });
@@ -1 +1 @@
1
- {"version":3,"file":"use-tambo-v1-thread-input.test.js","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-thread-input.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import { renderHook, act } from \"@testing-library/react\";\nimport { useTamboV1ThreadInput } from \"./use-tambo-v1-thread-input\";\n\n// Create mock functions\nconst mockMutateAsync = jest.fn();\nconst mockMutate = jest.fn();\nconst mockReset = jest.fn();\n\n// Mock useTamboV1SendMessage module\njest.mock(\"./use-tambo-v1-send-message\");\n\nimport { useTamboV1SendMessage } from \"./use-tambo-v1-send-message\";\n\n// Helper to set up the mock with default values\nfunction setupMock(overrides: Record<string, unknown> = {}) {\n const mockReturn = {\n mutateAsync: mockMutateAsync,\n mutate: mockMutate,\n isPending: false as const,\n isError: false as const,\n error: null,\n isSuccess: false as const,\n isIdle: true as const,\n isPaused: false as const,\n status: \"idle\" as const,\n data: undefined,\n variables: undefined,\n failureCount: 0,\n failureReason: null,\n reset: mockReset,\n context: undefined,\n submittedAt: 0,\n ...overrides,\n };\n jest.mocked(useTamboV1SendMessage).mockReturnValue(mockReturn);\n return mockReturn;\n}\n\ndescribe(\"useTamboV1ThreadInput\", () => {\n beforeEach(() => {\n jest.clearAllMocks();\n mockMutateAsync.mockResolvedValue({ threadId: \"thread_123\" });\n setupMock();\n });\n\n describe(\"State Management\", () => {\n it(\"initializes with empty value\", () => {\n const { result } = renderHook(() => useTamboV1ThreadInput());\n\n expect(result.current.value).toBe(\"\");\n });\n\n it(\"updates value via setValue\", () => {\n const { result } = renderHook(() => useTamboV1ThreadInput());\n\n act(() => {\n result.current.setValue(\"Hello world\");\n });\n\n expect(result.current.value).toBe(\"Hello world\");\n });\n\n it(\"supports functional updates for setValue\", () => {\n const { result } = renderHook(() => useTamboV1ThreadInput());\n\n act(() => {\n result.current.setValue(\"Hello\");\n });\n\n act(() => {\n result.current.setValue((prev) => `${prev} world`);\n });\n\n expect(result.current.value).toBe(\"Hello world\");\n });\n });\n\n describe(\"Submit Behavior\", () => {\n it(\"submits message and clears input on success\", async () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(\"thread_123\"));\n\n act(() => {\n result.current.setValue(\"Test message\");\n });\n\n await act(async () => {\n const response = await result.current.submit();\n expect(response.threadId).toBe(\"thread_123\");\n });\n\n // Input should be cleared\n expect(result.current.value).toBe(\"\");\n\n // Should have called mutateAsync with correct message format\n expect(mockMutateAsync).toHaveBeenCalledWith({\n message: {\n role: \"user\",\n content: [{ type: \"text\", text: \"Test message\" }],\n },\n debug: undefined,\n });\n });\n\n it(\"throws error when submitting empty message\", async () => {\n const { result } = renderHook(() => useTamboV1ThreadInput());\n\n await expect(result.current.submit()).rejects.toThrow(\n \"Message cannot be empty\",\n );\n\n expect(mockMutateAsync).not.toHaveBeenCalled();\n });\n\n it(\"throws error when submitting whitespace-only message\", async () => {\n const { result } = renderHook(() => useTamboV1ThreadInput());\n\n act(() => {\n result.current.setValue(\" \");\n });\n\n await expect(result.current.submit()).rejects.toThrow(\n \"Message cannot be empty\",\n );\n\n expect(mockMutateAsync).not.toHaveBeenCalled();\n });\n\n it(\"passes debug option to mutation\", async () => {\n const { result } = renderHook(() => useTamboV1ThreadInput());\n\n act(() => {\n result.current.setValue(\"Debug message\");\n });\n\n await act(async () => {\n await result.current.submit({ debug: true });\n });\n\n expect(mockMutateAsync).toHaveBeenCalledWith({\n message: {\n role: \"user\",\n content: [{ type: \"text\", text: \"Debug message\" }],\n },\n debug: true,\n });\n });\n\n it(\"trims whitespace from message\", async () => {\n const { result } = renderHook(() => useTamboV1ThreadInput());\n\n act(() => {\n result.current.setValue(\" Trimmed message \");\n });\n\n await act(async () => {\n await result.current.submit();\n });\n\n expect(mockMutateAsync).toHaveBeenCalledWith({\n message: {\n role: \"user\",\n content: [{ type: \"text\", text: \"Trimmed message\" }],\n },\n debug: undefined,\n });\n });\n });\n\n describe(\"Thread ID Handling\", () => {\n it(\"passes threadId to useTamboV1SendMessage\", () => {\n renderHook(() => useTamboV1ThreadInput(\"custom_thread_id\"));\n\n expect(useTamboV1SendMessage).toHaveBeenCalledWith(\"custom_thread_id\");\n });\n\n it(\"passes undefined threadId when not provided\", () => {\n renderHook(() => useTamboV1ThreadInput());\n\n expect(useTamboV1SendMessage).toHaveBeenCalledWith(undefined);\n });\n });\n\n describe(\"Mutation State\", () => {\n it(\"exposes isPending state\", () => {\n setupMock({ isPending: true });\n\n const { result } = renderHook(() => useTamboV1ThreadInput());\n\n expect(result.current.isPending).toBe(true);\n });\n\n it(\"exposes isError state\", () => {\n setupMock({ isError: true, error: new Error(\"Test error\") });\n\n const { result } = renderHook(() => useTamboV1ThreadInput());\n\n expect(result.current.isError).toBe(true);\n expect(result.current.error?.message).toBe(\"Test error\");\n });\n\n it(\"exposes isSuccess state\", () => {\n setupMock({ isSuccess: true });\n\n const { result } = renderHook(() => useTamboV1ThreadInput());\n\n expect(result.current.isSuccess).toBe(true);\n });\n\n it(\"exposes reset function\", () => {\n const { result } = renderHook(() => useTamboV1ThreadInput());\n\n act(() => {\n result.current.reset();\n });\n\n expect(mockReset).toHaveBeenCalled();\n });\n });\n});\n"]}
1
+ {"version":3,"file":"use-tambo-v1-thread-input.test.js","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-thread-input.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import { renderHook, act, waitFor } from \"@testing-library/react\";\nimport React from \"react\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport {\n TamboV1ThreadInputProvider,\n useTamboV1ThreadInput,\n} from \"../providers/tambo-v1-thread-input-provider\";\nimport { TamboV1StreamProvider } from \"../providers/tambo-v1-stream-context\";\nimport { useTamboV1SendMessage } from \"./use-tambo-v1-send-message\";\nimport type { StreamAction, StreamState } from \"../utils/event-accumulator\";\n\n// Mock useTamboV1SendMessage\njest.mock(\"./use-tambo-v1-send-message\", () => ({\n useTamboV1SendMessage: jest.fn(),\n}));\n\n// Mock useTamboQueryClient to avoid TamboClientProvider dependency\njest.mock(\"../../providers/tambo-client-provider\", () => ({\n useTamboQueryClient: jest.fn(() => new QueryClient()),\n useTamboClient: jest.fn(),\n}));\n\nconst createSuccessfulFileReader = () => {\n const reader = {\n readAsDataURL: jest.fn(),\n onload: null as ((e: unknown) => void) | null,\n onerror: null as ((e: unknown) => void) | null,\n result: \"data:image/png;base64,mock-data\",\n };\n\n reader.readAsDataURL = jest.fn(() => {\n setTimeout(() => {\n reader.onload?.({});\n }, 0);\n });\n\n return reader;\n};\n\nconst originalFileReader = (global as any).FileReader;\n\ndescribe(\"useTamboV1ThreadInput\", () => {\n const mockMutateAsync = jest.fn();\n let queryClient: QueryClient;\n\n function createWrapper({ streamState }: { streamState?: StreamState } = {}) {\n const noopDispatch: React.Dispatch<StreamAction> = () => {};\n\n return function Wrapper({ children }: { children: React.ReactNode }) {\n const streamProviderProps =\n streamState === undefined\n ? {}\n : { state: streamState, dispatch: noopDispatch };\n\n return (\n <QueryClientProvider client={queryClient}>\n <TamboV1StreamProvider {...streamProviderProps}>\n <TamboV1ThreadInputProvider>{children}</TamboV1ThreadInputProvider>\n </TamboV1StreamProvider>\n </QueryClientProvider>\n );\n };\n }\n\n beforeEach(() => {\n jest.clearAllMocks();\n (global as any).FileReader = jest.fn(() => createSuccessfulFileReader());\n\n queryClient = new QueryClient({\n defaultOptions: {\n queries: { retry: false },\n mutations: { retry: false },\n },\n });\n mockMutateAsync.mockResolvedValue({ threadId: \"thread_123\" });\n jest.mocked(useTamboV1SendMessage).mockReturnValue({\n mutateAsync: mockMutateAsync,\n mutate: jest.fn(),\n isPending: false,\n isError: false,\n error: null,\n isSuccess: false,\n isIdle: true,\n isPaused: false,\n status: \"idle\",\n data: undefined,\n variables: undefined,\n failureCount: 0,\n failureReason: null,\n reset: jest.fn(),\n context: undefined,\n submittedAt: 0,\n } as any);\n });\n\n afterEach(() => {\n (global as any).FileReader = originalFileReader;\n });\n\n describe(\"State Management\", () => {\n it(\"initializes with empty value\", () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(), {\n wrapper: createWrapper(),\n });\n\n expect(result.current.value).toBe(\"\");\n });\n\n it(\"updates value via setValue\", () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(), {\n wrapper: createWrapper(),\n });\n\n act(() => {\n result.current.setValue(\"Hello world\");\n });\n\n expect(result.current.value).toBe(\"Hello world\");\n });\n\n it(\"supports functional updates for setValue\", () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(), {\n wrapper: createWrapper(),\n });\n\n act(() => {\n result.current.setValue(\"Hello\");\n });\n\n act(() => {\n result.current.setValue((prev) => `${prev} world`);\n });\n\n expect(result.current.value).toBe(\"Hello world\");\n });\n });\n\n describe(\"Submit Behavior\", () => {\n it(\"submits message and clears input on success\", async () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(), {\n wrapper: createWrapper(),\n });\n\n act(() => {\n result.current.setValue(\"Test message\");\n });\n\n await act(async () => {\n const response = await result.current.submit();\n expect(response.threadId).toBe(\"thread_123\");\n });\n\n // Input should be cleared\n await waitFor(() => {\n expect(result.current.value).toBe(\"\");\n });\n\n // Should have called mutateAsync with correct message format\n expect(mockMutateAsync).toHaveBeenCalledWith({\n message: {\n role: \"user\",\n content: [{ type: \"text\", text: \"Test message\" }],\n },\n debug: undefined,\n });\n });\n\n it(\"throws error when submitting empty message\", async () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(), {\n wrapper: createWrapper(),\n });\n\n await expect(result.current.submit()).rejects.toThrow(\n \"Message cannot be empty\",\n );\n\n expect(mockMutateAsync).not.toHaveBeenCalled();\n });\n\n it(\"throws error when submitting whitespace-only message\", async () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(), {\n wrapper: createWrapper(),\n });\n\n act(() => {\n result.current.setValue(\" \");\n });\n\n await expect(result.current.submit()).rejects.toThrow(\n \"Message cannot be empty\",\n );\n\n expect(mockMutateAsync).not.toHaveBeenCalled();\n });\n\n it(\"passes debug option to mutation\", async () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(), {\n wrapper: createWrapper(),\n });\n\n act(() => {\n result.current.setValue(\"Debug message\");\n });\n\n await act(async () => {\n await result.current.submit({ debug: true });\n });\n\n expect(mockMutateAsync).toHaveBeenCalledWith({\n message: {\n role: \"user\",\n content: [{ type: \"text\", text: \"Debug message\" }],\n },\n debug: true,\n });\n });\n\n it(\"submits image-only messages as resource content\", async () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(), {\n wrapper: createWrapper(),\n });\n\n await act(async () => {\n await result.current.addImage(\n new File([\"image\"], \"photo.png\", { type: \"image/png\" }),\n );\n });\n\n await act(async () => {\n await result.current.submit();\n });\n\n expect(mockMutateAsync).toHaveBeenCalledWith({\n message: {\n role: \"user\",\n content: [\n {\n type: \"resource\",\n resource: {\n blob: \"mock-data\",\n mimeType: \"image/png\",\n name: \"photo.png\",\n },\n },\n ],\n },\n debug: undefined,\n });\n\n await waitFor(() => {\n expect(result.current.images).toEqual([]);\n });\n });\n\n it(\"includes both text and image resource content when both are present\", async () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(), {\n wrapper: createWrapper(),\n });\n\n act(() => {\n result.current.setValue(\"Test message\");\n });\n\n await act(async () => {\n await result.current.addImage(\n new File([\"image\"], \"photo.png\", { type: \"image/png\" }),\n );\n });\n\n await act(async () => {\n await result.current.submit();\n });\n\n expect(mockMutateAsync).toHaveBeenCalledWith({\n message: {\n role: \"user\",\n content: [\n { type: \"text\", text: \"Test message\" },\n {\n type: \"resource\",\n resource: {\n blob: \"mock-data\",\n mimeType: \"image/png\",\n name: \"photo.png\",\n },\n },\n ],\n },\n debug: undefined,\n });\n });\n });\n\n describe(\"Thread ID Management\", () => {\n it(\"initializes with undefined threadId\", () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(), {\n wrapper: createWrapper(),\n });\n\n expect(result.current.threadId).toBeUndefined();\n });\n\n it(\"allows setting threadId via setThreadId\", () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(), {\n wrapper: createWrapper(),\n });\n\n act(() => {\n result.current.setThreadId(\"custom_thread_id\");\n });\n\n expect(result.current.threadId).toBe(\"custom_thread_id\");\n });\n\n it(\"does not take ownership of threadId when inheriting stream selection\", async () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(), {\n wrapper: createWrapper({\n streamState: { threadMap: {}, currentThreadId: \"thread_stream\" },\n }),\n });\n\n expect(result.current.threadId).toBe(\"thread_stream\");\n expect(\n jest.mocked(useTamboV1SendMessage).mock.calls.map((call) => call[0]),\n ).toContain(\"thread_stream\");\n\n act(() => {\n result.current.setValue(\"Test message\");\n });\n\n await act(async () => {\n await result.current.submit();\n });\n\n expect(result.current.threadId).toBe(\"thread_stream\");\n expect(\n jest.mocked(useTamboV1SendMessage).mock.calls.map((call) => call[0]),\n ).not.toContain(\"thread_123\");\n });\n });\n\n describe(\"Image State\", () => {\n it(\"initializes with empty images array\", () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(), {\n wrapper: createWrapper(),\n });\n\n expect(result.current.images).toEqual([]);\n });\n\n it(\"exposes image management functions\", () => {\n const { result } = renderHook(() => useTamboV1ThreadInput(), {\n wrapper: createWrapper(),\n });\n\n expect(typeof result.current.addImage).toBe(\"function\");\n expect(typeof result.current.addImages).toBe(\"function\");\n expect(typeof result.current.removeImage).toBe(\"function\");\n expect(typeof result.current.clearImages).toBe(\"function\");\n });\n });\n\n describe(\"Error handling\", () => {\n it(\"throws error when used outside provider\", () => {\n // Suppress console.error for this test\n const consoleSpy = jest\n .spyOn(console, \"error\")\n .mockImplementation(() => {});\n\n expect(() => {\n renderHook(() => useTamboV1ThreadInput());\n }).toThrow(\n \"useTamboV1ThreadInput must be used within TamboV1ThreadInputProvider\",\n );\n\n consoleSpy.mockRestore();\n });\n });\n});\n"]}
@@ -10,9 +10,11 @@ import type { ThreadListResponse } from "@tambo-ai/typescript-sdk/resources/thre
10
10
  */
11
11
  export interface ThreadListOptions {
12
12
  /**
13
- * Optional context key to filter threads by
13
+ * User key to scope thread list.
14
+ * Only threads owned by this userKey will be returned.
15
+ * If not provided here, uses the userKey from TamboV1Provider context.
14
16
  */
15
- contextKey?: string;
17
+ userKey?: string;
16
18
  /**
17
19
  * Maximum number of threads to return (as string per SDK)
18
20
  */
@@ -35,9 +37,9 @@ export interface ThreadListOptions {
35
37
  * @returns React Query query object with thread list
36
38
  * @example
37
39
  * ```tsx
38
- * function ThreadList({ contextKey }: { contextKey?: string }) {
40
+ * function ThreadList({ userKey }: { userKey?: string }) {
39
41
  * const { data, isLoading, isError } = useTamboV1ThreadList({
40
- * contextKey,
42
+ * userKey,
41
43
  * limit: "20",
42
44
  * });
43
45
  *
@@ -1 +1 @@
1
- {"version":3,"file":"use-tambo-v1-thread-list.d.ts","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-thread-list.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,OAAO,EAAY,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oDAAoD,CAAC;AAG7F;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,CAAC,EAAE,iBAAiB,EAC/B,YAAY,CAAC,EAAE,IAAI,CACjB,eAAe,CAAC,kBAAkB,CAAC,EACnC,UAAU,GAAG,SAAS,CACvB,6EAUF"}
1
+ {"version":3,"file":"use-tambo-v1-thread-list.d.ts","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-thread-list.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,OAAO,EAAY,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oDAAoD,CAAC;AAG7F;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,CAAC,EAAE,iBAAiB,EAC/B,YAAY,CAAC,EAAE,IAAI,CACjB,eAAe,CAAC,kBAAkB,CAAC,EACnC,UAAU,GAAG,SAAS,CACvB,6EAUF"}
@@ -19,9 +19,9 @@ import { useTamboClient } from "../../providers/tambo-client-provider";
19
19
  * @returns React Query query object with thread list
20
20
  * @example
21
21
  * ```tsx
22
- * function ThreadList({ contextKey }: { contextKey?: string }) {
22
+ * function ThreadList({ userKey }: { userKey?: string }) {
23
23
  * const { data, isLoading, isError } = useTamboV1ThreadList({
24
- * contextKey,
24
+ * userKey,
25
25
  * limit: "20",
26
26
  * });
27
27
  *
@@ -1 +1 @@
1
- {"version":3,"file":"use-tambo-v1-thread-list.js","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-thread-list.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAwB,MAAM,uBAAuB,CAAC;AAEvE,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAsBvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,oBAAoB,CAClC,WAA+B,EAC/B,YAGC;IAED,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;IAEhC,OAAO,QAAQ,CAAC;QACd,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,CAAC;QAC7C,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;QAC3D,SAAS,EAAE,IAAI,EAAE,0BAA0B;QAC3C,GAAG,YAAY;KAChB,CAAC,CAAC;AACL,CAAC","sourcesContent":["\"use client\";\n\n/**\n * Thread List Query Hook for v1 API\n *\n * React Query hook for fetching a list of threads.\n */\n\nimport { useQuery, type UseQueryOptions } from \"@tanstack/react-query\";\nimport type { ThreadListResponse } from \"@tambo-ai/typescript-sdk/resources/threads/threads\";\nimport { useTamboClient } from \"../../providers/tambo-client-provider\";\n\n/**\n * Options for fetching thread list\n */\nexport interface ThreadListOptions {\n /**\n * Optional context key to filter threads by\n */\n contextKey?: string;\n\n /**\n * Maximum number of threads to return (as string per SDK)\n */\n limit?: string;\n\n /**\n * Pagination cursor for fetching next page\n */\n cursor?: string;\n}\n\n/**\n * Hook to fetch a list of threads.\n *\n * Uses React Query for caching and automatic refetching.\n * Threads are considered stale after 5 seconds.\n *\n * Returns the thread list directly from the SDK with no transformation.\n * Each thread includes runStatus, metadata, and all SDK fields.\n * @param listOptions - Filtering and pagination options\n * @param queryOptions - Additional React Query options\n * @returns React Query query object with thread list\n * @example\n * ```tsx\n * function ThreadList({ contextKey }: { contextKey?: string }) {\n * const { data, isLoading, isError } = useTamboV1ThreadList({\n * contextKey,\n * limit: \"20\",\n * });\n *\n * if (isLoading) return <Spinner />;\n * if (isError) return <Error />;\n *\n * return (\n * <ul>\n * {data.threads.map(thread => (\n * <li key={thread.id}>\n * {thread.id} - {thread.runStatus}\n * </li>\n * ))}\n * {data.hasMore && <LoadMoreButton cursor={data.nextCursor} />}\n * </ul>\n * );\n * }\n * ```\n */\nexport function useTamboV1ThreadList(\n listOptions?: ThreadListOptions,\n queryOptions?: Omit<\n UseQueryOptions<ThreadListResponse>,\n \"queryKey\" | \"queryFn\"\n >,\n) {\n const client = useTamboClient();\n\n return useQuery({\n queryKey: [\"v1-threads\", \"list\", listOptions],\n queryFn: async () => await client.threads.list(listOptions),\n staleTime: 5000, // Consider stale after 5s\n ...queryOptions,\n });\n}\n"]}
1
+ {"version":3,"file":"use-tambo-v1-thread-list.js","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-thread-list.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAwB,MAAM,uBAAuB,CAAC;AAEvE,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAwBvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,oBAAoB,CAClC,WAA+B,EAC/B,YAGC;IAED,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;IAEhC,OAAO,QAAQ,CAAC;QACd,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,CAAC;QAC7C,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;QAC3D,SAAS,EAAE,IAAI,EAAE,0BAA0B;QAC3C,GAAG,YAAY;KAChB,CAAC,CAAC;AACL,CAAC","sourcesContent":["\"use client\";\n\n/**\n * Thread List Query Hook for v1 API\n *\n * React Query hook for fetching a list of threads.\n */\n\nimport { useQuery, type UseQueryOptions } from \"@tanstack/react-query\";\nimport type { ThreadListResponse } from \"@tambo-ai/typescript-sdk/resources/threads/threads\";\nimport { useTamboClient } from \"../../providers/tambo-client-provider\";\n\n/**\n * Options for fetching thread list\n */\nexport interface ThreadListOptions {\n /**\n * User key to scope thread list.\n * Only threads owned by this userKey will be returned.\n * If not provided here, uses the userKey from TamboV1Provider context.\n */\n userKey?: string;\n\n /**\n * Maximum number of threads to return (as string per SDK)\n */\n limit?: string;\n\n /**\n * Pagination cursor for fetching next page\n */\n cursor?: string;\n}\n\n/**\n * Hook to fetch a list of threads.\n *\n * Uses React Query for caching and automatic refetching.\n * Threads are considered stale after 5 seconds.\n *\n * Returns the thread list directly from the SDK with no transformation.\n * Each thread includes runStatus, metadata, and all SDK fields.\n * @param listOptions - Filtering and pagination options\n * @param queryOptions - Additional React Query options\n * @returns React Query query object with thread list\n * @example\n * ```tsx\n * function ThreadList({ userKey }: { userKey?: string }) {\n * const { data, isLoading, isError } = useTamboV1ThreadList({\n * userKey,\n * limit: \"20\",\n * });\n *\n * if (isLoading) return <Spinner />;\n * if (isError) return <Error />;\n *\n * return (\n * <ul>\n * {data.threads.map(thread => (\n * <li key={thread.id}>\n * {thread.id} - {thread.runStatus}\n * </li>\n * ))}\n * {data.hasMore && <LoadMoreButton cursor={data.nextCursor} />}\n * </ul>\n * );\n * }\n * ```\n */\nexport function useTamboV1ThreadList(\n listOptions?: ThreadListOptions,\n queryOptions?: Omit<\n UseQueryOptions<ThreadListResponse>,\n \"queryKey\" | \"queryFn\"\n >,\n) {\n const client = useTamboClient();\n\n return useQuery({\n queryKey: [\"v1-threads\", \"list\", listOptions],\n queryFn: async () => await client.threads.list(listOptions),\n staleTime: 5000, // Consider stale after 5s\n ...queryOptions,\n });\n}\n"]}
@@ -51,14 +51,14 @@ describe("useTamboV1ThreadList", () => {
51
51
  it("passes list options to API", async () => {
52
52
  mockThreadsApi.list.mockResolvedValue(mockThreads);
53
53
  const { result } = renderHook(() => useTamboV1ThreadList({
54
- contextKey: "test-context",
54
+ userKey: "test-context",
55
55
  limit: "10",
56
56
  }), { wrapper: TestWrapper });
57
57
  await waitFor(() => {
58
58
  expect(result.current.data).toEqual(mockThreads);
59
59
  });
60
60
  expect(mockThreadsApi.list).toHaveBeenCalledWith({
61
- contextKey: "test-context",
61
+ userKey: "test-context",
62
62
  limit: "10",
63
63
  });
64
64
  });