@tambo-ai/react 0.68.0 → 0.69.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/context-helpers/context-helpers.test.js +16 -4
- package/dist/context-helpers/context-helpers.test.js.map +1 -1
- package/dist/context-helpers/current-interactables-context-helper.d.ts +2 -2
- package/dist/context-helpers/current-interactables-context-helper.d.ts.map +1 -1
- package/dist/context-helpers/current-interactables-context-helper.js +31 -15
- package/dist/context-helpers/current-interactables-context-helper.js.map +1 -1
- package/dist/context-helpers/registry.d.ts +2 -2
- package/dist/context-helpers/registry.d.ts.map +1 -1
- package/dist/context-helpers/registry.js.map +1 -1
- package/dist/context-helpers/types.d.ts +2 -2
- package/dist/context-helpers/types.d.ts.map +1 -1
- package/dist/context-helpers/types.js.map +1 -1
- package/dist/hooks/use-message-images.test.js +174 -37
- package/dist/hooks/use-message-images.test.js.map +1 -1
- package/dist/hooks/use-tambo-voice.d.ts +1 -1
- package/dist/hooks/use-tambo-voice.js +1 -1
- package/dist/hooks/use-tambo-voice.js.map +1 -1
- package/dist/hooks/use-tambo-voice.test.d.ts +2 -0
- package/dist/hooks/use-tambo-voice.test.d.ts.map +1 -0
- package/dist/hooks/use-tambo-voice.test.js +239 -0
- package/dist/hooks/use-tambo-voice.test.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/elicitation.d.ts.map +1 -1
- package/dist/mcp/elicitation.js +12 -0
- package/dist/mcp/elicitation.js.map +1 -1
- package/dist/mcp/elicitation.test.js +8 -1
- package/dist/mcp/elicitation.test.js.map +1 -1
- package/dist/mcp/mcp-client.d.ts +6 -10
- package/dist/mcp/mcp-client.d.ts.map +1 -1
- package/dist/mcp/mcp-client.js.map +1 -1
- package/dist/mcp/mcp-hooks.d.ts +12 -60
- package/dist/mcp/mcp-hooks.d.ts.map +1 -1
- package/dist/mcp/mcp-hooks.js +90 -10
- package/dist/mcp/mcp-hooks.js.map +1 -1
- package/dist/mcp/mcp-hooks.test.js +423 -0
- package/dist/mcp/mcp-hooks.test.js.map +1 -1
- package/dist/mcp/tambo-mcp-provider.d.ts.map +1 -1
- package/dist/mcp/tambo-mcp-provider.js +3 -0
- package/dist/mcp/tambo-mcp-provider.js.map +1 -1
- package/dist/mcp/tambo-mcp-provider.test.js +37 -0
- package/dist/mcp/tambo-mcp-provider.test.js.map +1 -1
- package/dist/model/component-metadata.d.ts +53 -20
- package/dist/model/component-metadata.d.ts.map +1 -1
- package/dist/model/component-metadata.js.map +1 -1
- package/dist/model/tambo-interactable.d.ts +6 -0
- package/dist/model/tambo-interactable.d.ts.map +1 -1
- package/dist/model/tambo-interactable.js.map +1 -1
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/tambo-client-provider.d.ts +8 -0
- package/dist/providers/tambo-client-provider.d.ts.map +1 -1
- package/dist/providers/tambo-client-provider.js +10 -11
- package/dist/providers/tambo-client-provider.js.map +1 -1
- package/dist/providers/tambo-client-provider.test.d.ts +2 -0
- package/dist/providers/tambo-client-provider.test.d.ts.map +1 -0
- package/dist/providers/tambo-client-provider.test.js +208 -0
- package/dist/providers/tambo-client-provider.test.js.map +1 -0
- package/dist/providers/tambo-context-attachment-provider.d.ts +34 -92
- package/dist/providers/tambo-context-attachment-provider.d.ts.map +1 -1
- package/dist/providers/tambo-context-attachment-provider.js +62 -105
- package/dist/providers/tambo-context-attachment-provider.js.map +1 -1
- package/dist/providers/tambo-context-attachment-provider.test.js +229 -463
- package/dist/providers/tambo-context-attachment-provider.test.js.map +1 -1
- package/dist/providers/tambo-interactable-provider.d.ts +2 -0
- package/dist/providers/tambo-interactable-provider.d.ts.map +1 -1
- package/dist/providers/tambo-interactable-provider.js +29 -4
- package/dist/providers/tambo-interactable-provider.js.map +1 -1
- package/dist/providers/tambo-interactable-provider.test.js +1 -1
- package/dist/providers/tambo-interactable-provider.test.js.map +1 -1
- package/dist/providers/tambo-interactables-additional-context.test.js +2 -5
- package/dist/providers/tambo-interactables-additional-context.test.js.map +1 -1
- package/dist/providers/tambo-provider.d.ts +2 -3
- package/dist/providers/tambo-provider.d.ts.map +1 -1
- package/dist/providers/tambo-provider.js +5 -6
- package/dist/providers/tambo-provider.js.map +1 -1
- package/dist/providers/tambo-registry-provider.test.js +16 -0
- package/dist/providers/tambo-registry-provider.test.js.map +1 -1
- package/dist/providers/tambo-registry-schema-compat.test.js +31 -0
- package/dist/providers/tambo-registry-schema-compat.test.js.map +1 -1
- package/dist/providers/tambo-thread-input-provider.d.ts +1 -1
- package/dist/providers/tambo-thread-input-provider.d.ts.map +1 -1
- package/dist/providers/tambo-thread-input-provider.js +5 -1
- package/dist/providers/tambo-thread-input-provider.js.map +1 -1
- package/dist/providers/tambo-thread-provider-initial-messages.test.js +84 -2
- package/dist/providers/tambo-thread-provider-initial-messages.test.js.map +1 -1
- package/dist/providers/tambo-thread-provider.d.ts.map +1 -1
- package/dist/providers/tambo-thread-provider.js +56 -43
- package/dist/providers/tambo-thread-provider.js.map +1 -1
- package/dist/providers/tambo-thread-provider.test.js +456 -262
- package/dist/providers/tambo-thread-provider.test.js.map +1 -1
- package/dist/schema/json-schema.js +29 -29
- package/dist/schema/json-schema.js.map +1 -1
- package/dist/schema/schema.test.js +237 -0
- package/dist/schema/schema.test.js.map +1 -1
- package/dist/schema/standard-schema.d.ts +1 -0
- package/dist/schema/standard-schema.d.ts.map +1 -1
- package/dist/schema/standard-schema.js +18 -13
- package/dist/schema/standard-schema.js.map +1 -1
- package/dist/schema/standard-schema.test.d.ts +2 -0
- package/dist/schema/standard-schema.test.d.ts.map +1 -0
- package/dist/schema/standard-schema.test.js +165 -0
- package/dist/schema/standard-schema.test.js.map +1 -0
- package/dist/schema/validate.test.js +149 -0
- package/dist/schema/validate.test.js.map +1 -1
- package/dist/schema/zod.d.ts +7 -4
- package/dist/schema/zod.d.ts.map +1 -1
- package/dist/schema/zod.js +65 -22
- package/dist/schema/zod.js.map +1 -1
- package/dist/schema/zod.test.js +112 -0
- package/dist/schema/zod.test.js.map +1 -1
- package/dist/testing/tools.d.ts +4 -1
- package/dist/testing/tools.d.ts.map +1 -1
- package/dist/testing/tools.js +6 -1
- package/dist/testing/tools.js.map +1 -1
- package/dist/util/generate-component.d.ts.map +1 -1
- package/dist/util/generate-component.js +18 -3
- package/dist/util/generate-component.js.map +1 -1
- package/dist/util/generate-component.test.d.ts +2 -0
- package/dist/util/generate-component.test.d.ts.map +1 -0
- package/dist/util/generate-component.test.js +340 -0
- package/dist/util/generate-component.test.js.map +1 -0
- package/dist/util/is-promise.d.ts +9 -0
- package/dist/util/is-promise.d.ts.map +1 -0
- package/dist/util/is-promise.js +20 -0
- package/dist/util/is-promise.js.map +1 -0
- package/dist/util/is-promise.test.d.ts +2 -0
- package/dist/util/is-promise.test.d.ts.map +1 -0
- package/dist/util/is-promise.test.js +48 -0
- package/dist/util/is-promise.test.js.map +1 -0
- package/dist/util/query-utils.test.d.ts +2 -0
- package/dist/util/query-utils.test.d.ts.map +1 -0
- package/dist/util/query-utils.test.js +382 -0
- package/dist/util/query-utils.test.js.map +1 -0
- package/dist/util/registry-validators.d.ts.map +1 -1
- package/dist/util/registry-validators.js +7 -0
- package/dist/util/registry-validators.js.map +1 -1
- package/dist/util/registry-validators.test.js +57 -0
- package/dist/util/registry-validators.test.js.map +1 -1
- package/dist/util/registry.d.ts.map +1 -1
- package/dist/util/registry.js +9 -0
- package/dist/util/registry.js.map +1 -1
- package/dist/util/registry.test.js +323 -1
- package/dist/util/registry.test.js.map +1 -1
- package/dist/util/resource-validators.test.d.ts +2 -0
- package/dist/util/resource-validators.test.d.ts.map +1 -0
- package/dist/util/resource-validators.test.js +90 -0
- package/dist/util/resource-validators.test.js.map +1 -0
- package/dist/util/tool-caller.d.ts +2 -2
- package/dist/util/tool-caller.d.ts.map +1 -1
- package/dist/util/tool-caller.js +8 -8
- package/dist/util/tool-caller.js.map +1 -1
- package/dist/util/validate-component-name.test.d.ts +2 -0
- package/dist/util/validate-component-name.test.d.ts.map +1 -0
- package/dist/util/validate-component-name.test.js +35 -0
- package/dist/util/validate-component-name.test.js.map +1 -0
- package/esm/context-helpers/context-helpers.test.js +16 -4
- package/esm/context-helpers/context-helpers.test.js.map +1 -1
- package/esm/context-helpers/current-interactables-context-helper.d.ts +2 -2
- package/esm/context-helpers/current-interactables-context-helper.d.ts.map +1 -1
- package/esm/context-helpers/current-interactables-context-helper.js +31 -15
- package/esm/context-helpers/current-interactables-context-helper.js.map +1 -1
- package/esm/context-helpers/registry.d.ts +2 -2
- package/esm/context-helpers/registry.d.ts.map +1 -1
- package/esm/context-helpers/registry.js.map +1 -1
- package/esm/context-helpers/types.d.ts +2 -2
- package/esm/context-helpers/types.d.ts.map +1 -1
- package/esm/context-helpers/types.js.map +1 -1
- package/esm/hooks/use-message-images.test.js +174 -37
- package/esm/hooks/use-message-images.test.js.map +1 -1
- package/esm/hooks/use-tambo-voice.d.ts +1 -1
- package/esm/hooks/use-tambo-voice.js +1 -1
- package/esm/hooks/use-tambo-voice.js.map +1 -1
- package/esm/hooks/use-tambo-voice.test.d.ts +2 -0
- package/esm/hooks/use-tambo-voice.test.d.ts.map +1 -0
- package/esm/hooks/use-tambo-voice.test.js +234 -0
- package/esm/hooks/use-tambo-voice.test.js.map +1 -0
- package/esm/index.d.ts +2 -2
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js.map +1 -1
- package/esm/mcp/elicitation.d.ts.map +1 -1
- package/esm/mcp/elicitation.js +12 -0
- package/esm/mcp/elicitation.js.map +1 -1
- package/esm/mcp/elicitation.test.js +8 -1
- package/esm/mcp/elicitation.test.js.map +1 -1
- package/esm/mcp/mcp-client.d.ts +6 -10
- package/esm/mcp/mcp-client.d.ts.map +1 -1
- package/esm/mcp/mcp-client.js.map +1 -1
- package/esm/mcp/mcp-hooks.d.ts +12 -60
- package/esm/mcp/mcp-hooks.d.ts.map +1 -1
- package/esm/mcp/mcp-hooks.js +57 -10
- package/esm/mcp/mcp-hooks.js.map +1 -1
- package/esm/mcp/mcp-hooks.test.js +423 -0
- package/esm/mcp/mcp-hooks.test.js.map +1 -1
- package/esm/mcp/tambo-mcp-provider.d.ts.map +1 -1
- package/esm/mcp/tambo-mcp-provider.js +3 -0
- package/esm/mcp/tambo-mcp-provider.js.map +1 -1
- package/esm/mcp/tambo-mcp-provider.test.js +37 -0
- package/esm/mcp/tambo-mcp-provider.test.js.map +1 -1
- package/esm/model/component-metadata.d.ts +53 -20
- package/esm/model/component-metadata.d.ts.map +1 -1
- package/esm/model/component-metadata.js.map +1 -1
- package/esm/model/tambo-interactable.d.ts +6 -0
- package/esm/model/tambo-interactable.d.ts.map +1 -1
- package/esm/model/tambo-interactable.js.map +1 -1
- package/esm/providers/index.d.ts +1 -1
- package/esm/providers/index.d.ts.map +1 -1
- package/esm/providers/index.js.map +1 -1
- package/esm/providers/tambo-client-provider.d.ts +8 -0
- package/esm/providers/tambo-client-provider.d.ts.map +1 -1
- package/esm/providers/tambo-client-provider.js +11 -12
- package/esm/providers/tambo-client-provider.js.map +1 -1
- package/esm/providers/tambo-client-provider.test.d.ts +2 -0
- package/esm/providers/tambo-client-provider.test.d.ts.map +1 -0
- package/esm/providers/tambo-client-provider.test.js +203 -0
- package/esm/providers/tambo-client-provider.test.js.map +1 -0
- package/esm/providers/tambo-context-attachment-provider.d.ts +34 -92
- package/esm/providers/tambo-context-attachment-provider.d.ts.map +1 -1
- package/esm/providers/tambo-context-attachment-provider.js +63 -106
- package/esm/providers/tambo-context-attachment-provider.js.map +1 -1
- package/esm/providers/tambo-context-attachment-provider.test.js +230 -464
- package/esm/providers/tambo-context-attachment-provider.test.js.map +1 -1
- package/esm/providers/tambo-interactable-provider.d.ts +2 -0
- package/esm/providers/tambo-interactable-provider.d.ts.map +1 -1
- package/esm/providers/tambo-interactable-provider.js +29 -4
- package/esm/providers/tambo-interactable-provider.js.map +1 -1
- package/esm/providers/tambo-interactable-provider.test.js +1 -1
- package/esm/providers/tambo-interactable-provider.test.js.map +1 -1
- package/esm/providers/tambo-interactables-additional-context.test.js +2 -5
- package/esm/providers/tambo-interactables-additional-context.test.js.map +1 -1
- package/esm/providers/tambo-provider.d.ts +2 -3
- package/esm/providers/tambo-provider.d.ts.map +1 -1
- package/esm/providers/tambo-provider.js +5 -6
- package/esm/providers/tambo-provider.js.map +1 -1
- package/esm/providers/tambo-registry-provider.test.js +16 -0
- package/esm/providers/tambo-registry-provider.test.js.map +1 -1
- package/esm/providers/tambo-registry-schema-compat.test.js +31 -0
- package/esm/providers/tambo-registry-schema-compat.test.js.map +1 -1
- package/esm/providers/tambo-thread-input-provider.d.ts +1 -1
- package/esm/providers/tambo-thread-input-provider.d.ts.map +1 -1
- package/esm/providers/tambo-thread-input-provider.js +5 -1
- package/esm/providers/tambo-thread-input-provider.js.map +1 -1
- package/esm/providers/tambo-thread-provider-initial-messages.test.js +84 -2
- package/esm/providers/tambo-thread-provider-initial-messages.test.js.map +1 -1
- package/esm/providers/tambo-thread-provider.d.ts.map +1 -1
- package/esm/providers/tambo-thread-provider.js +56 -43
- package/esm/providers/tambo-thread-provider.js.map +1 -1
- package/esm/providers/tambo-thread-provider.test.js +456 -262
- package/esm/providers/tambo-thread-provider.test.js.map +1 -1
- package/esm/schema/json-schema.js +1 -1
- package/esm/schema/json-schema.js.map +1 -1
- package/esm/schema/schema.test.js +238 -1
- package/esm/schema/schema.test.js.map +1 -1
- package/esm/schema/standard-schema.d.ts +1 -0
- package/esm/schema/standard-schema.d.ts.map +1 -1
- package/esm/schema/standard-schema.js +18 -13
- package/esm/schema/standard-schema.js.map +1 -1
- package/esm/schema/standard-schema.test.d.ts +2 -0
- package/esm/schema/standard-schema.test.d.ts.map +1 -0
- package/esm/schema/standard-schema.test.js +130 -0
- package/esm/schema/standard-schema.test.js.map +1 -0
- package/esm/schema/validate.test.js +149 -0
- package/esm/schema/validate.test.js.map +1 -1
- package/esm/schema/zod.d.ts +7 -4
- package/esm/schema/zod.d.ts.map +1 -1
- package/esm/schema/zod.js +65 -22
- package/esm/schema/zod.js.map +1 -1
- package/esm/schema/zod.test.js +113 -1
- package/esm/schema/zod.test.js.map +1 -1
- package/esm/testing/tools.d.ts +4 -1
- package/esm/testing/tools.d.ts.map +1 -1
- package/esm/testing/tools.js +6 -1
- package/esm/testing/tools.js.map +1 -1
- package/esm/util/generate-component.d.ts.map +1 -1
- package/esm/util/generate-component.js +18 -3
- package/esm/util/generate-component.js.map +1 -1
- package/esm/util/generate-component.test.d.ts +2 -0
- package/esm/util/generate-component.test.d.ts.map +1 -0
- package/esm/util/generate-component.test.js +302 -0
- package/esm/util/generate-component.test.js.map +1 -0
- package/esm/util/is-promise.d.ts +9 -0
- package/esm/util/is-promise.d.ts.map +1 -0
- package/esm/util/is-promise.js +17 -0
- package/esm/util/is-promise.js.map +1 -0
- package/esm/util/is-promise.test.d.ts +2 -0
- package/esm/util/is-promise.test.d.ts.map +1 -0
- package/esm/util/is-promise.test.js +46 -0
- package/esm/util/is-promise.test.js.map +1 -0
- package/esm/util/query-utils.test.d.ts +2 -0
- package/esm/util/query-utils.test.d.ts.map +1 -0
- package/esm/util/query-utils.test.js +380 -0
- package/esm/util/query-utils.test.js.map +1 -0
- package/esm/util/registry-validators.d.ts.map +1 -1
- package/esm/util/registry-validators.js +7 -0
- package/esm/util/registry-validators.js.map +1 -1
- package/esm/util/registry-validators.test.js +57 -0
- package/esm/util/registry-validators.test.js.map +1 -1
- package/esm/util/registry.d.ts.map +1 -1
- package/esm/util/registry.js +9 -0
- package/esm/util/registry.js.map +1 -1
- package/esm/util/registry.test.js +324 -2
- package/esm/util/registry.test.js.map +1 -1
- package/esm/util/resource-validators.test.d.ts +2 -0
- package/esm/util/resource-validators.test.d.ts.map +1 -0
- package/esm/util/resource-validators.test.js +88 -0
- package/esm/util/resource-validators.test.js.map +1 -0
- package/esm/util/tool-caller.d.ts +2 -2
- package/esm/util/tool-caller.d.ts.map +1 -1
- package/esm/util/tool-caller.js +8 -8
- package/esm/util/tool-caller.js.map +1 -1
- package/esm/util/validate-component-name.test.d.ts +2 -0
- package/esm/util/validate-component-name.test.d.ts.map +1 -0
- package/esm/util/validate-component-name.test.js +33 -0
- package/esm/util/validate-component-name.test.js.map +1 -0
- package/package.json +15 -23
- package/dist/schema/alias.d.ts +0 -3
- package/dist/schema/alias.d.ts.map +0 -1
- package/dist/schema/alias.js +0 -6
- package/dist/schema/alias.js.map +0 -1
- package/esm/schema/alias.d.ts +0 -3
- package/esm/schema/alias.d.ts.map +0 -1
- package/esm/schema/alias.js +0 -13
- package/esm/schema/alias.js.map +0 -1
|
@@ -110,8 +110,18 @@ describe("TamboThreadProvider", () => {
|
|
|
110
110
|
],
|
|
111
111
|
},
|
|
112
112
|
];
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
/**
|
|
114
|
+
* Creates a test wrapper component with configurable options.
|
|
115
|
+
* Reduces duplication across tests by centralizing provider setup.
|
|
116
|
+
* @param options - Configuration options for the wrapper
|
|
117
|
+
* @param options.components - The Tambo components to register
|
|
118
|
+
* @param options.streaming - Whether to enable streaming responses
|
|
119
|
+
* @param options.onCallUnregisteredTool - Handler for unregistered tool calls
|
|
120
|
+
* @param options.autoGenerateThreadName - Whether to auto-generate thread names
|
|
121
|
+
* @param options.autoGenerateNameThreshold - Token threshold for auto-generating names
|
|
122
|
+
* @returns A React component that wraps children with the necessary providers
|
|
123
|
+
*/
|
|
124
|
+
const createWrapper = ({ components = mockRegistry, streaming = false, onCallUnregisteredTool, autoGenerateThreadName, autoGenerateNameThreshold, } = {}) => function TestWrapper({ children }) {
|
|
115
125
|
const client = useTamboClient();
|
|
116
126
|
const queryClient = useTamboQueryClient();
|
|
117
127
|
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
@@ -119,14 +129,16 @@ describe("TamboThreadProvider", () => {
|
|
|
119
129
|
queryClient,
|
|
120
130
|
isUpdatingToken: false,
|
|
121
131
|
} },
|
|
122
|
-
React.createElement(TamboRegistryProvider, { components:
|
|
132
|
+
React.createElement(TamboRegistryProvider, { components: components, onCallUnregisteredTool: onCallUnregisteredTool },
|
|
123
133
|
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
124
134
|
currentTimeContextHelper: () => null,
|
|
125
135
|
currentPageContextHelper: () => null,
|
|
126
136
|
} },
|
|
127
137
|
React.createElement(TamboMcpTokenProvider, null,
|
|
128
|
-
React.createElement(TamboThreadProvider, { streaming:
|
|
138
|
+
React.createElement(TamboThreadProvider, { streaming: streaming, autoGenerateThreadName: autoGenerateThreadName, autoGenerateNameThreshold: autoGenerateNameThreshold }, children))))));
|
|
129
139
|
};
|
|
140
|
+
// Default wrapper for most tests
|
|
141
|
+
const Wrapper = createWrapper();
|
|
130
142
|
beforeEach(() => {
|
|
131
143
|
jest.clearAllMocks();
|
|
132
144
|
// Setup mock query client
|
|
@@ -344,22 +356,6 @@ describe("TamboThreadProvider", () => {
|
|
|
344
356
|
const mockOnCallUnregisteredTool = jest
|
|
345
357
|
.fn()
|
|
346
358
|
.mockResolvedValue("unregistered-tool-result");
|
|
347
|
-
const WrapperWithUnregisteredTool = ({ children, }) => {
|
|
348
|
-
const client = useTamboClient();
|
|
349
|
-
const queryClient = useTamboQueryClient();
|
|
350
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
351
|
-
client,
|
|
352
|
-
queryClient,
|
|
353
|
-
isUpdatingToken: false,
|
|
354
|
-
} },
|
|
355
|
-
React.createElement(TamboRegistryProvider, { components: mockRegistry, onCallUnregisteredTool: mockOnCallUnregisteredTool },
|
|
356
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
357
|
-
currentTimeContextHelper: () => null,
|
|
358
|
-
currentPageContextHelper: () => null,
|
|
359
|
-
} },
|
|
360
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
361
|
-
React.createElement(TamboThreadProvider, { streaming: false }, children))))));
|
|
362
|
-
};
|
|
363
359
|
const mockUnregisteredToolCallResponse = {
|
|
364
360
|
responseMessageDto: {
|
|
365
361
|
id: "unregistered-tool-call-1",
|
|
@@ -394,7 +390,9 @@ describe("TamboThreadProvider", () => {
|
|
|
394
390
|
mcpAccessToken: "test-mcp-access-token",
|
|
395
391
|
});
|
|
396
392
|
const { result } = renderHook(() => useTamboThread(), {
|
|
397
|
-
wrapper:
|
|
393
|
+
wrapper: createWrapper({
|
|
394
|
+
onCallUnregisteredTool: mockOnCallUnregisteredTool,
|
|
395
|
+
}),
|
|
398
396
|
});
|
|
399
397
|
await act(async () => {
|
|
400
398
|
await result.current.sendThreadMessage("Use unregistered tool", {
|
|
@@ -451,23 +449,6 @@ describe("TamboThreadProvider", () => {
|
|
|
451
449
|
});
|
|
452
450
|
describe("streaming behavior", () => {
|
|
453
451
|
it("should call advanceStream when streamResponse=true", async () => {
|
|
454
|
-
// Use wrapper with streaming=true to show that explicit streamResponse=true works
|
|
455
|
-
const WrapperWithStreaming = ({ children, }) => {
|
|
456
|
-
const client = useTamboClient();
|
|
457
|
-
const queryClient = useTamboQueryClient();
|
|
458
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
459
|
-
client,
|
|
460
|
-
queryClient,
|
|
461
|
-
isUpdatingToken: false,
|
|
462
|
-
} },
|
|
463
|
-
React.createElement(TamboRegistryProvider, { components: mockRegistry },
|
|
464
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
465
|
-
currentTimeContextHelper: () => null,
|
|
466
|
-
currentPageContextHelper: () => null,
|
|
467
|
-
} },
|
|
468
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
469
|
-
React.createElement(TamboThreadProvider, { streaming: true }, children))))));
|
|
470
|
-
};
|
|
471
452
|
const mockStreamResponse = {
|
|
472
453
|
responseMessageDto: {
|
|
473
454
|
id: "stream-response",
|
|
@@ -488,7 +469,7 @@ describe("TamboThreadProvider", () => {
|
|
|
488
469
|
};
|
|
489
470
|
jest.mocked(advanceStream).mockResolvedValue(mockAsyncIterator);
|
|
490
471
|
const { result } = renderHook(() => useTamboThread(), {
|
|
491
|
-
wrapper:
|
|
472
|
+
wrapper: createWrapper({ streaming: true }),
|
|
492
473
|
});
|
|
493
474
|
await act(async () => {
|
|
494
475
|
await result.current.sendThreadMessage("Hello streaming", {
|
|
@@ -523,24 +504,8 @@ describe("TamboThreadProvider", () => {
|
|
|
523
504
|
});
|
|
524
505
|
it("should call advanceById when streamResponse=false for existing thread", async () => {
|
|
525
506
|
// Use wrapper with streaming=true to show that explicit streamResponse=false overrides provider setting
|
|
526
|
-
const WrapperWithStreaming = ({ children, }) => {
|
|
527
|
-
const client = useTamboClient();
|
|
528
|
-
const queryClient = useTamboQueryClient();
|
|
529
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
530
|
-
client,
|
|
531
|
-
queryClient,
|
|
532
|
-
isUpdatingToken: false,
|
|
533
|
-
} },
|
|
534
|
-
React.createElement(TamboRegistryProvider, { components: mockRegistry },
|
|
535
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
536
|
-
currentTimeContextHelper: () => null,
|
|
537
|
-
currentPageContextHelper: () => null,
|
|
538
|
-
} },
|
|
539
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
540
|
-
React.createElement(TamboThreadProvider, { streaming: true }, children))))));
|
|
541
|
-
};
|
|
542
507
|
const { result } = renderHook(() => useTamboThread(), {
|
|
543
|
-
wrapper:
|
|
508
|
+
wrapper: createWrapper({ streaming: true }),
|
|
544
509
|
});
|
|
545
510
|
await act(async () => {
|
|
546
511
|
await result.current.sendThreadMessage("Hello non-streaming", {
|
|
@@ -575,24 +540,8 @@ describe("TamboThreadProvider", () => {
|
|
|
575
540
|
});
|
|
576
541
|
it("should call advanceById when streamResponse is undefined and provider streaming=false", async () => {
|
|
577
542
|
// Use wrapper with streaming=false to test that undefined streamResponse respects provider setting
|
|
578
|
-
const WrapperWithoutStreaming = ({ children, }) => {
|
|
579
|
-
const client = useTamboClient();
|
|
580
|
-
const queryClient = useTamboQueryClient();
|
|
581
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
582
|
-
client,
|
|
583
|
-
queryClient,
|
|
584
|
-
isUpdatingToken: false,
|
|
585
|
-
} },
|
|
586
|
-
React.createElement(TamboRegistryProvider, { components: mockRegistry },
|
|
587
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
588
|
-
currentTimeContextHelper: () => null,
|
|
589
|
-
currentPageContextHelper: () => null,
|
|
590
|
-
} },
|
|
591
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
592
|
-
React.createElement(TamboThreadProvider, { streaming: false }, children))))));
|
|
593
|
-
};
|
|
594
543
|
const { result } = renderHook(() => useTamboThread(), {
|
|
595
|
-
wrapper:
|
|
544
|
+
wrapper: createWrapper({ streaming: false }),
|
|
596
545
|
});
|
|
597
546
|
await act(async () => {
|
|
598
547
|
await result.current.sendThreadMessage("Hello default", {
|
|
@@ -626,23 +575,6 @@ describe("TamboThreadProvider", () => {
|
|
|
626
575
|
expect(advanceStream).not.toHaveBeenCalled();
|
|
627
576
|
});
|
|
628
577
|
it("should call advanceStream when streamResponse is undefined and provider streaming=true (default)", async () => {
|
|
629
|
-
// Use wrapper with streaming=true (default) to test that undefined streamResponse respects provider setting
|
|
630
|
-
const WrapperWithDefaultStreaming = ({ children, }) => {
|
|
631
|
-
const client = useTamboClient();
|
|
632
|
-
const queryClient = useTamboQueryClient();
|
|
633
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
634
|
-
client,
|
|
635
|
-
queryClient,
|
|
636
|
-
isUpdatingToken: false,
|
|
637
|
-
} },
|
|
638
|
-
React.createElement(TamboRegistryProvider, { components: mockRegistry },
|
|
639
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
640
|
-
currentTimeContextHelper: () => null,
|
|
641
|
-
currentPageContextHelper: () => null,
|
|
642
|
-
} },
|
|
643
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
644
|
-
React.createElement(TamboThreadProvider, null, children))))));
|
|
645
|
-
};
|
|
646
578
|
const mockStreamResponse = {
|
|
647
579
|
responseMessageDto: {
|
|
648
580
|
id: "stream-response",
|
|
@@ -663,7 +595,7 @@ describe("TamboThreadProvider", () => {
|
|
|
663
595
|
};
|
|
664
596
|
jest.mocked(advanceStream).mockResolvedValue(mockAsyncIterator);
|
|
665
597
|
const { result } = renderHook(() => useTamboThread(), {
|
|
666
|
-
wrapper:
|
|
598
|
+
wrapper: createWrapper({ streaming: true }),
|
|
667
599
|
});
|
|
668
600
|
await act(async () => {
|
|
669
601
|
await result.current.sendThreadMessage("Hello default streaming", {
|
|
@@ -698,24 +630,8 @@ describe("TamboThreadProvider", () => {
|
|
|
698
630
|
});
|
|
699
631
|
it("should call advance when streamResponse=false for placeholder thread", async () => {
|
|
700
632
|
// Use wrapper with streaming=true to show that explicit streamResponse=false overrides provider setting
|
|
701
|
-
const WrapperWithStreaming = ({ children, }) => {
|
|
702
|
-
const client = useTamboClient();
|
|
703
|
-
const queryClient = useTamboQueryClient();
|
|
704
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
705
|
-
client,
|
|
706
|
-
queryClient,
|
|
707
|
-
isUpdatingToken: false,
|
|
708
|
-
} },
|
|
709
|
-
React.createElement(TamboRegistryProvider, { components: mockRegistry },
|
|
710
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
711
|
-
currentTimeContextHelper: () => null,
|
|
712
|
-
currentPageContextHelper: () => null,
|
|
713
|
-
} },
|
|
714
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
715
|
-
React.createElement(TamboThreadProvider, { streaming: true }, children))))));
|
|
716
|
-
};
|
|
717
633
|
const { result } = renderHook(() => useTamboThread(), {
|
|
718
|
-
wrapper:
|
|
634
|
+
wrapper: createWrapper({ streaming: true }),
|
|
719
635
|
});
|
|
720
636
|
// Start with placeholder thread (which is the default state)
|
|
721
637
|
expect(result.current.thread.id).toBe("placeholder");
|
|
@@ -751,23 +667,6 @@ describe("TamboThreadProvider", () => {
|
|
|
751
667
|
expect(advanceStream).not.toHaveBeenCalled();
|
|
752
668
|
});
|
|
753
669
|
it("should call advanceStream when streamResponse=true for placeholder thread", async () => {
|
|
754
|
-
// Use wrapper with streaming=false to show that explicit streamResponse=true overrides provider setting
|
|
755
|
-
const WrapperWithoutStreaming = ({ children, }) => {
|
|
756
|
-
const client = useTamboClient();
|
|
757
|
-
const queryClient = useTamboQueryClient();
|
|
758
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
759
|
-
client,
|
|
760
|
-
queryClient,
|
|
761
|
-
isUpdatingToken: false,
|
|
762
|
-
} },
|
|
763
|
-
React.createElement(TamboRegistryProvider, { components: mockRegistry },
|
|
764
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
765
|
-
currentTimeContextHelper: () => null,
|
|
766
|
-
currentPageContextHelper: () => null,
|
|
767
|
-
} },
|
|
768
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
769
|
-
React.createElement(TamboThreadProvider, { streaming: false }, children))))));
|
|
770
|
-
};
|
|
771
670
|
const mockStreamResponse = {
|
|
772
671
|
responseMessageDto: {
|
|
773
672
|
id: "stream-response",
|
|
@@ -788,7 +687,7 @@ describe("TamboThreadProvider", () => {
|
|
|
788
687
|
};
|
|
789
688
|
jest.mocked(advanceStream).mockResolvedValue(mockAsyncIterator);
|
|
790
689
|
const { result } = renderHook(() => useTamboThread(), {
|
|
791
|
-
wrapper:
|
|
690
|
+
wrapper: createWrapper({ streaming: false }),
|
|
792
691
|
});
|
|
793
692
|
// Start with placeholder thread (which is the default state)
|
|
794
693
|
expect(result.current.thread.id).toBe("placeholder");
|
|
@@ -823,6 +722,94 @@ describe("TamboThreadProvider", () => {
|
|
|
823
722
|
expect(mockThreadsApi.advance).not.toHaveBeenCalled();
|
|
824
723
|
expect(mockThreadsApi.advanceByID).not.toHaveBeenCalled();
|
|
825
724
|
});
|
|
725
|
+
it("should handle multiple sequential messages during streaming (server tool scenario)", async () => {
|
|
726
|
+
// This test verifies the fix for the bug where the second message doesn't render
|
|
727
|
+
// during server tool response streaming. The scenario:
|
|
728
|
+
// 1. First message: "I will call the tool..." with statusMessage
|
|
729
|
+
// 2. Second message: The tool result response streaming in
|
|
730
|
+
// First message - tool announcement (server tools don't have componentName set during streaming)
|
|
731
|
+
const mockFirstMessage = {
|
|
732
|
+
responseMessageDto: {
|
|
733
|
+
id: "msg-first",
|
|
734
|
+
content: [{ type: "text", text: "I will search the docs..." }],
|
|
735
|
+
role: "assistant",
|
|
736
|
+
threadId: "test-thread-1",
|
|
737
|
+
component: {
|
|
738
|
+
componentName: "",
|
|
739
|
+
componentState: {},
|
|
740
|
+
message: "",
|
|
741
|
+
props: {},
|
|
742
|
+
statusMessage: "searching the Tambo docs...",
|
|
743
|
+
},
|
|
744
|
+
componentState: {},
|
|
745
|
+
createdAt: new Date().toISOString(),
|
|
746
|
+
},
|
|
747
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
748
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
749
|
+
};
|
|
750
|
+
// Second message - tool result (different ID!)
|
|
751
|
+
const mockSecondMessageChunk1 = {
|
|
752
|
+
responseMessageDto: {
|
|
753
|
+
id: "msg-second",
|
|
754
|
+
content: [{ type: "text", text: "Here's what I found..." }],
|
|
755
|
+
role: "assistant",
|
|
756
|
+
threadId: "test-thread-1",
|
|
757
|
+
componentState: {},
|
|
758
|
+
createdAt: new Date().toISOString(),
|
|
759
|
+
},
|
|
760
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
761
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
762
|
+
};
|
|
763
|
+
const mockSecondMessageChunk2 = {
|
|
764
|
+
responseMessageDto: {
|
|
765
|
+
id: "msg-second",
|
|
766
|
+
content: [
|
|
767
|
+
{
|
|
768
|
+
type: "text",
|
|
769
|
+
text: "Here's what I found in the documentation about that topic.",
|
|
770
|
+
},
|
|
771
|
+
],
|
|
772
|
+
role: "assistant",
|
|
773
|
+
threadId: "test-thread-1",
|
|
774
|
+
componentState: {},
|
|
775
|
+
createdAt: new Date().toISOString(),
|
|
776
|
+
},
|
|
777
|
+
generationStage: GenerationStage.COMPLETE,
|
|
778
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
779
|
+
};
|
|
780
|
+
const mockAsyncIterator = {
|
|
781
|
+
[Symbol.asyncIterator]: async function* () {
|
|
782
|
+
yield mockFirstMessage;
|
|
783
|
+
yield mockSecondMessageChunk1;
|
|
784
|
+
yield mockSecondMessageChunk2;
|
|
785
|
+
},
|
|
786
|
+
};
|
|
787
|
+
jest.mocked(advanceStream).mockResolvedValue(mockAsyncIterator);
|
|
788
|
+
const { result } = renderHook(() => useTamboThread(), {
|
|
789
|
+
wrapper: createWrapper({ streaming: true }),
|
|
790
|
+
});
|
|
791
|
+
await act(async () => {
|
|
792
|
+
await result.current.sendThreadMessage("Search the docs", {
|
|
793
|
+
threadId: "test-thread-1",
|
|
794
|
+
streamResponse: true,
|
|
795
|
+
});
|
|
796
|
+
});
|
|
797
|
+
// Thread should have 3 messages: user message + 2 assistant messages
|
|
798
|
+
expect(result.current.thread.messages).toHaveLength(3);
|
|
799
|
+
// Filter to assistant messages only
|
|
800
|
+
const assistantMessages = result.current.thread.messages.filter((m) => m.role === "assistant");
|
|
801
|
+
expect(assistantMessages).toHaveLength(2);
|
|
802
|
+
// First assistant message should have the tool status
|
|
803
|
+
const firstMsg = result.current.thread.messages.find((m) => m.id === "msg-first");
|
|
804
|
+
expect(firstMsg).toBeDefined();
|
|
805
|
+
expect(firstMsg?.content[0]?.text).toContain("search the docs");
|
|
806
|
+
// Second assistant message should have the final content
|
|
807
|
+
const secondMsg = result.current.thread.messages.find((m) => m.id === "msg-second");
|
|
808
|
+
expect(secondMsg).toBeDefined();
|
|
809
|
+
expect(secondMsg?.content[0]?.text).toContain("what I found in the documentation");
|
|
810
|
+
// Generation should be complete
|
|
811
|
+
expect(result.current.generationStage).toBe(GenerationStage.COMPLETE);
|
|
812
|
+
});
|
|
826
813
|
});
|
|
827
814
|
describe("error handling", () => {
|
|
828
815
|
it("should set generation stage to ERROR when non-streaming sendThreadMessage fails", async () => {
|
|
@@ -973,22 +960,6 @@ describe("TamboThreadProvider", () => {
|
|
|
973
960
|
],
|
|
974
961
|
},
|
|
975
962
|
];
|
|
976
|
-
const WrapperWithCustomTool = ({ children, }) => {
|
|
977
|
-
const client = useTamboClient();
|
|
978
|
-
const queryClient = useTamboQueryClient();
|
|
979
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
980
|
-
client,
|
|
981
|
-
queryClient,
|
|
982
|
-
isUpdatingToken: false,
|
|
983
|
-
} },
|
|
984
|
-
React.createElement(TamboRegistryProvider, { components: customToolRegistry },
|
|
985
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
986
|
-
currentTimeContextHelper: () => null,
|
|
987
|
-
currentPageContextHelper: () => null,
|
|
988
|
-
} },
|
|
989
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
990
|
-
React.createElement(TamboThreadProvider, { streaming: false }, children))))));
|
|
991
|
-
};
|
|
992
963
|
const mockToolCallResponse = {
|
|
993
964
|
responseMessageDto: {
|
|
994
965
|
id: "tool-call-1",
|
|
@@ -1021,7 +992,7 @@ describe("TamboThreadProvider", () => {
|
|
|
1021
992
|
mcpAccessToken: "test-mcp-access-token",
|
|
1022
993
|
});
|
|
1023
994
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1024
|
-
wrapper:
|
|
995
|
+
wrapper: createWrapper({ components: customToolRegistry }),
|
|
1025
996
|
});
|
|
1026
997
|
await act(async () => {
|
|
1027
998
|
await result.current.sendThreadMessage("Use custom tool", {
|
|
@@ -1074,22 +1045,6 @@ describe("TamboThreadProvider", () => {
|
|
|
1074
1045
|
],
|
|
1075
1046
|
},
|
|
1076
1047
|
];
|
|
1077
|
-
const WrapperWithAsyncTool = ({ children, }) => {
|
|
1078
|
-
const client = useTamboClient();
|
|
1079
|
-
const queryClient = useTamboQueryClient();
|
|
1080
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
1081
|
-
client,
|
|
1082
|
-
queryClient,
|
|
1083
|
-
isUpdatingToken: false,
|
|
1084
|
-
} },
|
|
1085
|
-
React.createElement(TamboRegistryProvider, { components: customToolRegistry },
|
|
1086
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
1087
|
-
currentTimeContextHelper: () => null,
|
|
1088
|
-
currentPageContextHelper: () => null,
|
|
1089
|
-
} },
|
|
1090
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
1091
|
-
React.createElement(TamboThreadProvider, { streaming: true }, children))))));
|
|
1092
|
-
};
|
|
1093
1048
|
const mockToolCallChunk = {
|
|
1094
1049
|
responseMessageDto: {
|
|
1095
1050
|
id: "tool-call-chunk",
|
|
@@ -1135,7 +1090,10 @@ describe("TamboThreadProvider", () => {
|
|
|
1135
1090
|
},
|
|
1136
1091
|
});
|
|
1137
1092
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1138
|
-
wrapper:
|
|
1093
|
+
wrapper: createWrapper({
|
|
1094
|
+
components: customToolRegistry,
|
|
1095
|
+
streaming: true,
|
|
1096
|
+
}),
|
|
1139
1097
|
});
|
|
1140
1098
|
await act(async () => {
|
|
1141
1099
|
await result.current.sendThreadMessage("Use async tool", {
|
|
@@ -1183,22 +1141,6 @@ describe("TamboThreadProvider", () => {
|
|
|
1183
1141
|
],
|
|
1184
1142
|
},
|
|
1185
1143
|
];
|
|
1186
|
-
const WrapperWithoutTransform = ({ children, }) => {
|
|
1187
|
-
const client = useTamboClient();
|
|
1188
|
-
const queryClient = useTamboQueryClient();
|
|
1189
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
1190
|
-
client,
|
|
1191
|
-
queryClient,
|
|
1192
|
-
isUpdatingToken: false,
|
|
1193
|
-
} },
|
|
1194
|
-
React.createElement(TamboRegistryProvider, { components: toolWithoutTransform },
|
|
1195
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
1196
|
-
currentTimeContextHelper: () => null,
|
|
1197
|
-
currentPageContextHelper: () => null,
|
|
1198
|
-
} },
|
|
1199
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
1200
|
-
React.createElement(TamboThreadProvider, { streaming: false }, children))))));
|
|
1201
|
-
};
|
|
1202
1144
|
const mockToolCallResponse = {
|
|
1203
1145
|
responseMessageDto: {
|
|
1204
1146
|
id: "tool-call-1",
|
|
@@ -1231,7 +1173,7 @@ describe("TamboThreadProvider", () => {
|
|
|
1231
1173
|
mcpAccessToken: "test-mcp-access-token",
|
|
1232
1174
|
});
|
|
1233
1175
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1234
|
-
wrapper:
|
|
1176
|
+
wrapper: createWrapper({ components: toolWithoutTransform }),
|
|
1235
1177
|
});
|
|
1236
1178
|
await act(async () => {
|
|
1237
1179
|
await result.current.sendThreadMessage("Use tool without transform", {
|
|
@@ -1281,22 +1223,6 @@ describe("TamboThreadProvider", () => {
|
|
|
1281
1223
|
],
|
|
1282
1224
|
},
|
|
1283
1225
|
];
|
|
1284
|
-
const WrapperWithErrorTool = ({ children, }) => {
|
|
1285
|
-
const client = useTamboClient();
|
|
1286
|
-
const queryClient = useTamboQueryClient();
|
|
1287
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
1288
|
-
client,
|
|
1289
|
-
queryClient,
|
|
1290
|
-
isUpdatingToken: false,
|
|
1291
|
-
} },
|
|
1292
|
-
React.createElement(TamboRegistryProvider, { components: toolWithTransform },
|
|
1293
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
1294
|
-
currentTimeContextHelper: () => null,
|
|
1295
|
-
currentPageContextHelper: () => null,
|
|
1296
|
-
} },
|
|
1297
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
1298
|
-
React.createElement(TamboThreadProvider, { streaming: false }, children))))));
|
|
1299
|
-
};
|
|
1300
1226
|
const mockToolCallResponse = {
|
|
1301
1227
|
responseMessageDto: {
|
|
1302
1228
|
id: "tool-call-1",
|
|
@@ -1329,7 +1255,7 @@ describe("TamboThreadProvider", () => {
|
|
|
1329
1255
|
mcpAccessToken: "test-mcp-access-token",
|
|
1330
1256
|
});
|
|
1331
1257
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1332
|
-
wrapper:
|
|
1258
|
+
wrapper: createWrapper({ components: toolWithTransform }),
|
|
1333
1259
|
});
|
|
1334
1260
|
await act(async () => {
|
|
1335
1261
|
await result.current.sendThreadMessage("Use error tool", {
|
|
@@ -1355,26 +1281,339 @@ describe("TamboThreadProvider", () => {
|
|
|
1355
1281
|
}));
|
|
1356
1282
|
});
|
|
1357
1283
|
});
|
|
1284
|
+
describe("tamboStreamableHint streaming behavior", () => {
|
|
1285
|
+
it("should call streamable tool during streaming when tamboStreamableHint is true", async () => {
|
|
1286
|
+
const streamableToolFn = jest
|
|
1287
|
+
.fn()
|
|
1288
|
+
.mockResolvedValue({ data: "streamed" });
|
|
1289
|
+
const customToolRegistry = [
|
|
1290
|
+
{
|
|
1291
|
+
name: "TestComponent",
|
|
1292
|
+
component: () => React.createElement("div", null, "Test"),
|
|
1293
|
+
description: "Test",
|
|
1294
|
+
propsSchema: z.object({ test: z.string() }),
|
|
1295
|
+
associatedTools: [
|
|
1296
|
+
{
|
|
1297
|
+
name: "streamable-tool",
|
|
1298
|
+
tool: streamableToolFn,
|
|
1299
|
+
description: "Tool safe for streaming",
|
|
1300
|
+
inputSchema: z.object({ input: z.string() }),
|
|
1301
|
+
outputSchema: z.object({ data: z.string() }),
|
|
1302
|
+
annotations: { tamboStreamableHint: true },
|
|
1303
|
+
},
|
|
1304
|
+
],
|
|
1305
|
+
},
|
|
1306
|
+
];
|
|
1307
|
+
// First chunk initializes finalMessage
|
|
1308
|
+
const mockInitialChunk = {
|
|
1309
|
+
responseMessageDto: {
|
|
1310
|
+
id: "initial-chunk",
|
|
1311
|
+
content: [{ type: "text", text: "Starting..." }],
|
|
1312
|
+
role: "assistant",
|
|
1313
|
+
threadId: "test-thread-1",
|
|
1314
|
+
componentState: {},
|
|
1315
|
+
createdAt: new Date().toISOString(),
|
|
1316
|
+
},
|
|
1317
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
1318
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1319
|
+
};
|
|
1320
|
+
// Second chunk has the tool call - this triggers streaming tool handling
|
|
1321
|
+
const mockToolCallChunk = {
|
|
1322
|
+
responseMessageDto: {
|
|
1323
|
+
id: "initial-chunk", // Same ID as initial - it's an update
|
|
1324
|
+
content: [{ type: "text", text: "Streaming..." }],
|
|
1325
|
+
role: "assistant",
|
|
1326
|
+
threadId: "test-thread-1",
|
|
1327
|
+
component: {
|
|
1328
|
+
componentName: "",
|
|
1329
|
+
componentState: {},
|
|
1330
|
+
message: "",
|
|
1331
|
+
props: {},
|
|
1332
|
+
toolCallRequest: {
|
|
1333
|
+
toolName: "streamable-tool",
|
|
1334
|
+
parameters: [
|
|
1335
|
+
{ parameterName: "input", parameterValue: "stream-test" },
|
|
1336
|
+
],
|
|
1337
|
+
},
|
|
1338
|
+
},
|
|
1339
|
+
componentState: {},
|
|
1340
|
+
createdAt: new Date().toISOString(),
|
|
1341
|
+
},
|
|
1342
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
1343
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1344
|
+
};
|
|
1345
|
+
const mockFinalChunk = {
|
|
1346
|
+
responseMessageDto: {
|
|
1347
|
+
id: "initial-chunk",
|
|
1348
|
+
content: [{ type: "text", text: "Complete" }],
|
|
1349
|
+
role: "assistant",
|
|
1350
|
+
threadId: "test-thread-1",
|
|
1351
|
+
componentState: {},
|
|
1352
|
+
createdAt: new Date().toISOString(),
|
|
1353
|
+
},
|
|
1354
|
+
generationStage: GenerationStage.COMPLETE,
|
|
1355
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1356
|
+
};
|
|
1357
|
+
const mockAsyncIterator = {
|
|
1358
|
+
[Symbol.asyncIterator]: async function* () {
|
|
1359
|
+
yield mockInitialChunk;
|
|
1360
|
+
yield mockToolCallChunk;
|
|
1361
|
+
yield mockFinalChunk;
|
|
1362
|
+
},
|
|
1363
|
+
};
|
|
1364
|
+
jest.mocked(advanceStream).mockResolvedValueOnce(mockAsyncIterator);
|
|
1365
|
+
const { result } = renderHook(() => useTamboThread(), {
|
|
1366
|
+
wrapper: createWrapper({
|
|
1367
|
+
components: customToolRegistry,
|
|
1368
|
+
streaming: true,
|
|
1369
|
+
}),
|
|
1370
|
+
});
|
|
1371
|
+
await act(async () => {
|
|
1372
|
+
await result.current.sendThreadMessage("Test streamable tool", {
|
|
1373
|
+
threadId: "test-thread-1",
|
|
1374
|
+
streamResponse: true,
|
|
1375
|
+
});
|
|
1376
|
+
});
|
|
1377
|
+
// Streamable tool should be called during streaming
|
|
1378
|
+
expect(streamableToolFn).toHaveBeenCalledWith({ input: "stream-test" });
|
|
1379
|
+
});
|
|
1380
|
+
it("should NOT call non-streamable tool during streaming", async () => {
|
|
1381
|
+
const nonStreamableToolFn = jest
|
|
1382
|
+
.fn()
|
|
1383
|
+
.mockResolvedValue({ data: "result" });
|
|
1384
|
+
const customToolRegistry = [
|
|
1385
|
+
{
|
|
1386
|
+
name: "TestComponent",
|
|
1387
|
+
component: () => React.createElement("div", null, "Test"),
|
|
1388
|
+
description: "Test",
|
|
1389
|
+
propsSchema: z.object({ test: z.string() }),
|
|
1390
|
+
associatedTools: [
|
|
1391
|
+
{
|
|
1392
|
+
name: "non-streamable-tool",
|
|
1393
|
+
tool: nonStreamableToolFn,
|
|
1394
|
+
description: "Tool not safe for streaming",
|
|
1395
|
+
inputSchema: z.object({ input: z.string() }),
|
|
1396
|
+
outputSchema: z.object({ data: z.string() }),
|
|
1397
|
+
// No tamboStreamableHint - defaults to false
|
|
1398
|
+
},
|
|
1399
|
+
],
|
|
1400
|
+
},
|
|
1401
|
+
];
|
|
1402
|
+
// First chunk initializes finalMessage
|
|
1403
|
+
const mockInitialChunk = {
|
|
1404
|
+
responseMessageDto: {
|
|
1405
|
+
id: "streaming-chunk",
|
|
1406
|
+
content: [{ type: "text", text: "Starting..." }],
|
|
1407
|
+
role: "assistant",
|
|
1408
|
+
threadId: "test-thread-1",
|
|
1409
|
+
componentState: {},
|
|
1410
|
+
createdAt: new Date().toISOString(),
|
|
1411
|
+
},
|
|
1412
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
1413
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1414
|
+
};
|
|
1415
|
+
// Second chunk has the tool call - but tool is NOT streamable
|
|
1416
|
+
const mockToolCallChunk = {
|
|
1417
|
+
responseMessageDto: {
|
|
1418
|
+
id: "streaming-chunk",
|
|
1419
|
+
content: [{ type: "text", text: "Streaming..." }],
|
|
1420
|
+
role: "assistant",
|
|
1421
|
+
threadId: "test-thread-1",
|
|
1422
|
+
component: {
|
|
1423
|
+
componentName: "",
|
|
1424
|
+
componentState: {},
|
|
1425
|
+
message: "",
|
|
1426
|
+
props: {},
|
|
1427
|
+
toolCallRequest: {
|
|
1428
|
+
toolName: "non-streamable-tool",
|
|
1429
|
+
parameters: [{ parameterName: "input", parameterValue: "test" }],
|
|
1430
|
+
},
|
|
1431
|
+
},
|
|
1432
|
+
componentState: {},
|
|
1433
|
+
createdAt: new Date().toISOString(),
|
|
1434
|
+
},
|
|
1435
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
1436
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1437
|
+
};
|
|
1438
|
+
const mockFinalChunk = {
|
|
1439
|
+
responseMessageDto: {
|
|
1440
|
+
id: "streaming-chunk",
|
|
1441
|
+
content: [{ type: "text", text: "Complete" }],
|
|
1442
|
+
role: "assistant",
|
|
1443
|
+
threadId: "test-thread-1",
|
|
1444
|
+
componentState: {},
|
|
1445
|
+
createdAt: new Date().toISOString(),
|
|
1446
|
+
},
|
|
1447
|
+
generationStage: GenerationStage.COMPLETE,
|
|
1448
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1449
|
+
};
|
|
1450
|
+
const mockAsyncIterator = {
|
|
1451
|
+
[Symbol.asyncIterator]: async function* () {
|
|
1452
|
+
yield mockInitialChunk;
|
|
1453
|
+
yield mockToolCallChunk;
|
|
1454
|
+
yield mockFinalChunk;
|
|
1455
|
+
},
|
|
1456
|
+
};
|
|
1457
|
+
jest.mocked(advanceStream).mockResolvedValueOnce(mockAsyncIterator);
|
|
1458
|
+
const { result } = renderHook(() => useTamboThread(), {
|
|
1459
|
+
wrapper: createWrapper({
|
|
1460
|
+
components: customToolRegistry,
|
|
1461
|
+
streaming: true,
|
|
1462
|
+
}),
|
|
1463
|
+
});
|
|
1464
|
+
await act(async () => {
|
|
1465
|
+
await result.current.sendThreadMessage("Test non-streamable tool", {
|
|
1466
|
+
threadId: "test-thread-1",
|
|
1467
|
+
streamResponse: true,
|
|
1468
|
+
});
|
|
1469
|
+
});
|
|
1470
|
+
// Non-streamable tool should NOT be called during the streaming chunk phase
|
|
1471
|
+
// (it would only be called when generationStage is COMPLETE with a toolCallRequest)
|
|
1472
|
+
expect(nonStreamableToolFn).not.toHaveBeenCalled();
|
|
1473
|
+
});
|
|
1474
|
+
it("should only call streamable tools during streaming when mixed", async () => {
|
|
1475
|
+
const streamableToolFn = jest
|
|
1476
|
+
.fn()
|
|
1477
|
+
.mockResolvedValue({ data: "streamed" });
|
|
1478
|
+
const nonStreamableToolFn = jest
|
|
1479
|
+
.fn()
|
|
1480
|
+
.mockResolvedValue({ data: "not-streamed" });
|
|
1481
|
+
const customToolRegistry = [
|
|
1482
|
+
{
|
|
1483
|
+
name: "TestComponent",
|
|
1484
|
+
component: () => React.createElement("div", null, "Test"),
|
|
1485
|
+
description: "Test",
|
|
1486
|
+
propsSchema: z.object({ test: z.string() }),
|
|
1487
|
+
associatedTools: [
|
|
1488
|
+
{
|
|
1489
|
+
name: "streamable-tool",
|
|
1490
|
+
tool: streamableToolFn,
|
|
1491
|
+
description: "Tool safe for streaming",
|
|
1492
|
+
inputSchema: z.object({ input: z.string() }),
|
|
1493
|
+
outputSchema: z.object({ data: z.string() }),
|
|
1494
|
+
annotations: { tamboStreamableHint: true },
|
|
1495
|
+
},
|
|
1496
|
+
{
|
|
1497
|
+
name: "non-streamable-tool",
|
|
1498
|
+
tool: nonStreamableToolFn,
|
|
1499
|
+
description: "Tool not safe for streaming",
|
|
1500
|
+
inputSchema: z.object({ input: z.string() }),
|
|
1501
|
+
outputSchema: z.object({ data: z.string() }),
|
|
1502
|
+
annotations: { tamboStreamableHint: false },
|
|
1503
|
+
},
|
|
1504
|
+
],
|
|
1505
|
+
},
|
|
1506
|
+
];
|
|
1507
|
+
// First chunk initializes finalMessage
|
|
1508
|
+
const mockInitialChunk = {
|
|
1509
|
+
responseMessageDto: {
|
|
1510
|
+
id: "streaming-chunk",
|
|
1511
|
+
content: [{ type: "text", text: "Starting..." }],
|
|
1512
|
+
role: "assistant",
|
|
1513
|
+
threadId: "test-thread-1",
|
|
1514
|
+
componentState: {},
|
|
1515
|
+
createdAt: new Date().toISOString(),
|
|
1516
|
+
},
|
|
1517
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
1518
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1519
|
+
};
|
|
1520
|
+
// Second chunk calls the streamable tool
|
|
1521
|
+
const mockStreamableToolChunk = {
|
|
1522
|
+
responseMessageDto: {
|
|
1523
|
+
id: "streaming-chunk",
|
|
1524
|
+
content: [{ type: "text", text: "Calling streamable..." }],
|
|
1525
|
+
role: "assistant",
|
|
1526
|
+
threadId: "test-thread-1",
|
|
1527
|
+
component: {
|
|
1528
|
+
componentName: "",
|
|
1529
|
+
componentState: {},
|
|
1530
|
+
message: "",
|
|
1531
|
+
props: {},
|
|
1532
|
+
toolCallRequest: {
|
|
1533
|
+
toolName: "streamable-tool",
|
|
1534
|
+
parameters: [
|
|
1535
|
+
{ parameterName: "input", parameterValue: "streamed-input" },
|
|
1536
|
+
],
|
|
1537
|
+
},
|
|
1538
|
+
},
|
|
1539
|
+
componentState: {},
|
|
1540
|
+
createdAt: new Date().toISOString(),
|
|
1541
|
+
},
|
|
1542
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
1543
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1544
|
+
};
|
|
1545
|
+
// Third chunk calls the non-streamable tool
|
|
1546
|
+
const mockNonStreamableToolChunk = {
|
|
1547
|
+
responseMessageDto: {
|
|
1548
|
+
id: "streaming-chunk",
|
|
1549
|
+
content: [{ type: "text", text: "Calling non-streamable..." }],
|
|
1550
|
+
role: "assistant",
|
|
1551
|
+
threadId: "test-thread-1",
|
|
1552
|
+
component: {
|
|
1553
|
+
componentName: "",
|
|
1554
|
+
componentState: {},
|
|
1555
|
+
message: "",
|
|
1556
|
+
props: {},
|
|
1557
|
+
toolCallRequest: {
|
|
1558
|
+
toolName: "non-streamable-tool",
|
|
1559
|
+
parameters: [
|
|
1560
|
+
{
|
|
1561
|
+
parameterName: "input",
|
|
1562
|
+
parameterValue: "non-streamed-input",
|
|
1563
|
+
},
|
|
1564
|
+
],
|
|
1565
|
+
},
|
|
1566
|
+
},
|
|
1567
|
+
componentState: {},
|
|
1568
|
+
createdAt: new Date().toISOString(),
|
|
1569
|
+
},
|
|
1570
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
1571
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1572
|
+
};
|
|
1573
|
+
const mockFinalChunk = {
|
|
1574
|
+
responseMessageDto: {
|
|
1575
|
+
id: "streaming-chunk",
|
|
1576
|
+
content: [{ type: "text", text: "Complete" }],
|
|
1577
|
+
role: "assistant",
|
|
1578
|
+
threadId: "test-thread-1",
|
|
1579
|
+
componentState: {},
|
|
1580
|
+
createdAt: new Date().toISOString(),
|
|
1581
|
+
},
|
|
1582
|
+
generationStage: GenerationStage.COMPLETE,
|
|
1583
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1584
|
+
};
|
|
1585
|
+
const mockAsyncIterator = {
|
|
1586
|
+
[Symbol.asyncIterator]: async function* () {
|
|
1587
|
+
yield mockInitialChunk;
|
|
1588
|
+
yield mockStreamableToolChunk;
|
|
1589
|
+
yield mockNonStreamableToolChunk;
|
|
1590
|
+
yield mockFinalChunk;
|
|
1591
|
+
},
|
|
1592
|
+
};
|
|
1593
|
+
jest.mocked(advanceStream).mockResolvedValueOnce(mockAsyncIterator);
|
|
1594
|
+
const { result } = renderHook(() => useTamboThread(), {
|
|
1595
|
+
wrapper: createWrapper({
|
|
1596
|
+
components: customToolRegistry,
|
|
1597
|
+
streaming: true,
|
|
1598
|
+
}),
|
|
1599
|
+
});
|
|
1600
|
+
await act(async () => {
|
|
1601
|
+
await result.current.sendThreadMessage("Test mixed tools", {
|
|
1602
|
+
threadId: "test-thread-1",
|
|
1603
|
+
streamResponse: true,
|
|
1604
|
+
});
|
|
1605
|
+
});
|
|
1606
|
+
// Only the streamable tool should be called during streaming
|
|
1607
|
+
expect(streamableToolFn).toHaveBeenCalledWith({
|
|
1608
|
+
input: "streamed-input",
|
|
1609
|
+
});
|
|
1610
|
+
expect(nonStreamableToolFn).not.toHaveBeenCalled();
|
|
1611
|
+
});
|
|
1612
|
+
});
|
|
1358
1613
|
describe("auto-generate thread name", () => {
|
|
1359
1614
|
it("should auto-generate thread name after reaching threshold", async () => {
|
|
1360
|
-
const WrapperWithAutoGenerate = ({ children, }) => {
|
|
1361
|
-
const client = useTamboClient();
|
|
1362
|
-
const queryClient = useTamboQueryClient();
|
|
1363
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
1364
|
-
client,
|
|
1365
|
-
queryClient,
|
|
1366
|
-
isUpdatingToken: false,
|
|
1367
|
-
} },
|
|
1368
|
-
React.createElement(TamboRegistryProvider, { components: mockRegistry },
|
|
1369
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
1370
|
-
currentTimeContextHelper: () => null,
|
|
1371
|
-
currentPageContextHelper: () => null,
|
|
1372
|
-
} },
|
|
1373
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
1374
|
-
React.createElement(TamboThreadProvider, { streaming: false, autoGenerateNameThreshold: 2 }, children))))));
|
|
1375
|
-
};
|
|
1376
1615
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1377
|
-
wrapper:
|
|
1616
|
+
wrapper: createWrapper({ autoGenerateNameThreshold: 2 }),
|
|
1378
1617
|
});
|
|
1379
1618
|
const existingThread = createMockThread({
|
|
1380
1619
|
id: "test-thread-1",
|
|
@@ -1411,24 +1650,11 @@ describe("TamboThreadProvider", () => {
|
|
|
1411
1650
|
expect(mockQueryClient.setQueryData).toHaveBeenCalledWith(["threads", "test-project-id", undefined], expect.any(Function));
|
|
1412
1651
|
});
|
|
1413
1652
|
it("should NOT auto-generate when autoGenerateThreadName is false", async () => {
|
|
1414
|
-
const WrapperWithDisabled = ({ children, }) => {
|
|
1415
|
-
const client = useTamboClient();
|
|
1416
|
-
const queryClient = useTamboQueryClient();
|
|
1417
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
1418
|
-
client,
|
|
1419
|
-
queryClient,
|
|
1420
|
-
isUpdatingToken: false,
|
|
1421
|
-
} },
|
|
1422
|
-
React.createElement(TamboRegistryProvider, { components: mockRegistry },
|
|
1423
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
1424
|
-
currentTimeContextHelper: () => null,
|
|
1425
|
-
currentPageContextHelper: () => null,
|
|
1426
|
-
} },
|
|
1427
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
1428
|
-
React.createElement(TamboThreadProvider, { streaming: false, autoGenerateThreadName: false, autoGenerateNameThreshold: 2 }, children))))));
|
|
1429
|
-
};
|
|
1430
1653
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1431
|
-
wrapper:
|
|
1654
|
+
wrapper: createWrapper({
|
|
1655
|
+
autoGenerateThreadName: false,
|
|
1656
|
+
autoGenerateNameThreshold: 2,
|
|
1657
|
+
}),
|
|
1432
1658
|
});
|
|
1433
1659
|
const existingThread = createMockThread({
|
|
1434
1660
|
id: "test-thread-1",
|
|
@@ -1461,24 +1687,8 @@ describe("TamboThreadProvider", () => {
|
|
|
1461
1687
|
expect(mockThreadsApi.generateName).not.toHaveBeenCalled();
|
|
1462
1688
|
});
|
|
1463
1689
|
it("should NOT auto-generate when thread already has a name", async () => {
|
|
1464
|
-
const WrapperWithAutoGenerate = ({ children, }) => {
|
|
1465
|
-
const client = useTamboClient();
|
|
1466
|
-
const queryClient = useTamboQueryClient();
|
|
1467
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
1468
|
-
client,
|
|
1469
|
-
queryClient,
|
|
1470
|
-
isUpdatingToken: false,
|
|
1471
|
-
} },
|
|
1472
|
-
React.createElement(TamboRegistryProvider, { components: mockRegistry },
|
|
1473
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
1474
|
-
currentTimeContextHelper: () => null,
|
|
1475
|
-
currentPageContextHelper: () => null,
|
|
1476
|
-
} },
|
|
1477
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
1478
|
-
React.createElement(TamboThreadProvider, { streaming: false, autoGenerateNameThreshold: 2 }, children))))));
|
|
1479
|
-
};
|
|
1480
1690
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1481
|
-
wrapper:
|
|
1691
|
+
wrapper: createWrapper({ autoGenerateNameThreshold: 2 }),
|
|
1482
1692
|
});
|
|
1483
1693
|
const threadWithName = createMockThread({
|
|
1484
1694
|
id: "test-thread-1",
|
|
@@ -1516,24 +1726,8 @@ describe("TamboThreadProvider", () => {
|
|
|
1516
1726
|
expect(mockThreadsApi.generateName).not.toHaveBeenCalled();
|
|
1517
1727
|
});
|
|
1518
1728
|
it("should NOT auto-generate for placeholder thread", async () => {
|
|
1519
|
-
const WrapperWithAutoGenerate = ({ children, }) => {
|
|
1520
|
-
const client = useTamboClient();
|
|
1521
|
-
const queryClient = useTamboQueryClient();
|
|
1522
|
-
return (React.createElement(TamboClientContext.Provider, { value: {
|
|
1523
|
-
client,
|
|
1524
|
-
queryClient,
|
|
1525
|
-
isUpdatingToken: false,
|
|
1526
|
-
} },
|
|
1527
|
-
React.createElement(TamboRegistryProvider, { components: mockRegistry },
|
|
1528
|
-
React.createElement(TamboContextHelpersProvider, { contextHelpers: {
|
|
1529
|
-
currentTimeContextHelper: () => null,
|
|
1530
|
-
currentPageContextHelper: () => null,
|
|
1531
|
-
} },
|
|
1532
|
-
React.createElement(TamboMcpTokenProvider, null,
|
|
1533
|
-
React.createElement(TamboThreadProvider, { streaming: false, autoGenerateNameThreshold: 2 }, children))))));
|
|
1534
|
-
};
|
|
1535
1729
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1536
|
-
wrapper:
|
|
1730
|
+
wrapper: createWrapper({ autoGenerateNameThreshold: 2 }),
|
|
1537
1731
|
});
|
|
1538
1732
|
// Stay on placeholder thread
|
|
1539
1733
|
expect(result.current.thread.id).toBe("placeholder");
|