@tambo-ai/react 0.68.0 → 0.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +53 -42
- package/dist/providers/tambo-thread-provider.js.map +1 -1
- package/dist/providers/tambo-thread-provider.test.js +368 -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 +53 -42
- package/esm/providers/tambo-thread-provider.js.map +1 -1
- package/esm/providers/tambo-thread-provider.test.js +368 -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");
|
|
@@ -973,22 +872,6 @@ describe("TamboThreadProvider", () => {
|
|
|
973
872
|
],
|
|
974
873
|
},
|
|
975
874
|
];
|
|
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
875
|
const mockToolCallResponse = {
|
|
993
876
|
responseMessageDto: {
|
|
994
877
|
id: "tool-call-1",
|
|
@@ -1021,7 +904,7 @@ describe("TamboThreadProvider", () => {
|
|
|
1021
904
|
mcpAccessToken: "test-mcp-access-token",
|
|
1022
905
|
});
|
|
1023
906
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1024
|
-
wrapper:
|
|
907
|
+
wrapper: createWrapper({ components: customToolRegistry }),
|
|
1025
908
|
});
|
|
1026
909
|
await act(async () => {
|
|
1027
910
|
await result.current.sendThreadMessage("Use custom tool", {
|
|
@@ -1074,22 +957,6 @@ describe("TamboThreadProvider", () => {
|
|
|
1074
957
|
],
|
|
1075
958
|
},
|
|
1076
959
|
];
|
|
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
960
|
const mockToolCallChunk = {
|
|
1094
961
|
responseMessageDto: {
|
|
1095
962
|
id: "tool-call-chunk",
|
|
@@ -1135,7 +1002,10 @@ describe("TamboThreadProvider", () => {
|
|
|
1135
1002
|
},
|
|
1136
1003
|
});
|
|
1137
1004
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1138
|
-
wrapper:
|
|
1005
|
+
wrapper: createWrapper({
|
|
1006
|
+
components: customToolRegistry,
|
|
1007
|
+
streaming: true,
|
|
1008
|
+
}),
|
|
1139
1009
|
});
|
|
1140
1010
|
await act(async () => {
|
|
1141
1011
|
await result.current.sendThreadMessage("Use async tool", {
|
|
@@ -1183,22 +1053,6 @@ describe("TamboThreadProvider", () => {
|
|
|
1183
1053
|
],
|
|
1184
1054
|
},
|
|
1185
1055
|
];
|
|
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
1056
|
const mockToolCallResponse = {
|
|
1203
1057
|
responseMessageDto: {
|
|
1204
1058
|
id: "tool-call-1",
|
|
@@ -1231,7 +1085,7 @@ describe("TamboThreadProvider", () => {
|
|
|
1231
1085
|
mcpAccessToken: "test-mcp-access-token",
|
|
1232
1086
|
});
|
|
1233
1087
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1234
|
-
wrapper:
|
|
1088
|
+
wrapper: createWrapper({ components: toolWithoutTransform }),
|
|
1235
1089
|
});
|
|
1236
1090
|
await act(async () => {
|
|
1237
1091
|
await result.current.sendThreadMessage("Use tool without transform", {
|
|
@@ -1281,22 +1135,6 @@ describe("TamboThreadProvider", () => {
|
|
|
1281
1135
|
],
|
|
1282
1136
|
},
|
|
1283
1137
|
];
|
|
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
1138
|
const mockToolCallResponse = {
|
|
1301
1139
|
responseMessageDto: {
|
|
1302
1140
|
id: "tool-call-1",
|
|
@@ -1329,7 +1167,7 @@ describe("TamboThreadProvider", () => {
|
|
|
1329
1167
|
mcpAccessToken: "test-mcp-access-token",
|
|
1330
1168
|
});
|
|
1331
1169
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1332
|
-
wrapper:
|
|
1170
|
+
wrapper: createWrapper({ components: toolWithTransform }),
|
|
1333
1171
|
});
|
|
1334
1172
|
await act(async () => {
|
|
1335
1173
|
await result.current.sendThreadMessage("Use error tool", {
|
|
@@ -1355,26 +1193,339 @@ describe("TamboThreadProvider", () => {
|
|
|
1355
1193
|
}));
|
|
1356
1194
|
});
|
|
1357
1195
|
});
|
|
1196
|
+
describe("tamboStreamableHint streaming behavior", () => {
|
|
1197
|
+
it("should call streamable tool during streaming when tamboStreamableHint is true", async () => {
|
|
1198
|
+
const streamableToolFn = jest
|
|
1199
|
+
.fn()
|
|
1200
|
+
.mockResolvedValue({ data: "streamed" });
|
|
1201
|
+
const customToolRegistry = [
|
|
1202
|
+
{
|
|
1203
|
+
name: "TestComponent",
|
|
1204
|
+
component: () => React.createElement("div", null, "Test"),
|
|
1205
|
+
description: "Test",
|
|
1206
|
+
propsSchema: z.object({ test: z.string() }),
|
|
1207
|
+
associatedTools: [
|
|
1208
|
+
{
|
|
1209
|
+
name: "streamable-tool",
|
|
1210
|
+
tool: streamableToolFn,
|
|
1211
|
+
description: "Tool safe for streaming",
|
|
1212
|
+
inputSchema: z.object({ input: z.string() }),
|
|
1213
|
+
outputSchema: z.object({ data: z.string() }),
|
|
1214
|
+
annotations: { tamboStreamableHint: true },
|
|
1215
|
+
},
|
|
1216
|
+
],
|
|
1217
|
+
},
|
|
1218
|
+
];
|
|
1219
|
+
// First chunk initializes finalMessage
|
|
1220
|
+
const mockInitialChunk = {
|
|
1221
|
+
responseMessageDto: {
|
|
1222
|
+
id: "initial-chunk",
|
|
1223
|
+
content: [{ type: "text", text: "Starting..." }],
|
|
1224
|
+
role: "assistant",
|
|
1225
|
+
threadId: "test-thread-1",
|
|
1226
|
+
componentState: {},
|
|
1227
|
+
createdAt: new Date().toISOString(),
|
|
1228
|
+
},
|
|
1229
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
1230
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1231
|
+
};
|
|
1232
|
+
// Second chunk has the tool call - this triggers streaming tool handling
|
|
1233
|
+
const mockToolCallChunk = {
|
|
1234
|
+
responseMessageDto: {
|
|
1235
|
+
id: "initial-chunk", // Same ID as initial - it's an update
|
|
1236
|
+
content: [{ type: "text", text: "Streaming..." }],
|
|
1237
|
+
role: "assistant",
|
|
1238
|
+
threadId: "test-thread-1",
|
|
1239
|
+
component: {
|
|
1240
|
+
componentName: "",
|
|
1241
|
+
componentState: {},
|
|
1242
|
+
message: "",
|
|
1243
|
+
props: {},
|
|
1244
|
+
toolCallRequest: {
|
|
1245
|
+
toolName: "streamable-tool",
|
|
1246
|
+
parameters: [
|
|
1247
|
+
{ parameterName: "input", parameterValue: "stream-test" },
|
|
1248
|
+
],
|
|
1249
|
+
},
|
|
1250
|
+
},
|
|
1251
|
+
componentState: {},
|
|
1252
|
+
createdAt: new Date().toISOString(),
|
|
1253
|
+
},
|
|
1254
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
1255
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1256
|
+
};
|
|
1257
|
+
const mockFinalChunk = {
|
|
1258
|
+
responseMessageDto: {
|
|
1259
|
+
id: "initial-chunk",
|
|
1260
|
+
content: [{ type: "text", text: "Complete" }],
|
|
1261
|
+
role: "assistant",
|
|
1262
|
+
threadId: "test-thread-1",
|
|
1263
|
+
componentState: {},
|
|
1264
|
+
createdAt: new Date().toISOString(),
|
|
1265
|
+
},
|
|
1266
|
+
generationStage: GenerationStage.COMPLETE,
|
|
1267
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1268
|
+
};
|
|
1269
|
+
const mockAsyncIterator = {
|
|
1270
|
+
[Symbol.asyncIterator]: async function* () {
|
|
1271
|
+
yield mockInitialChunk;
|
|
1272
|
+
yield mockToolCallChunk;
|
|
1273
|
+
yield mockFinalChunk;
|
|
1274
|
+
},
|
|
1275
|
+
};
|
|
1276
|
+
jest.mocked(advanceStream).mockResolvedValueOnce(mockAsyncIterator);
|
|
1277
|
+
const { result } = renderHook(() => useTamboThread(), {
|
|
1278
|
+
wrapper: createWrapper({
|
|
1279
|
+
components: customToolRegistry,
|
|
1280
|
+
streaming: true,
|
|
1281
|
+
}),
|
|
1282
|
+
});
|
|
1283
|
+
await act(async () => {
|
|
1284
|
+
await result.current.sendThreadMessage("Test streamable tool", {
|
|
1285
|
+
threadId: "test-thread-1",
|
|
1286
|
+
streamResponse: true,
|
|
1287
|
+
});
|
|
1288
|
+
});
|
|
1289
|
+
// Streamable tool should be called during streaming
|
|
1290
|
+
expect(streamableToolFn).toHaveBeenCalledWith({ input: "stream-test" });
|
|
1291
|
+
});
|
|
1292
|
+
it("should NOT call non-streamable tool during streaming", async () => {
|
|
1293
|
+
const nonStreamableToolFn = jest
|
|
1294
|
+
.fn()
|
|
1295
|
+
.mockResolvedValue({ data: "result" });
|
|
1296
|
+
const customToolRegistry = [
|
|
1297
|
+
{
|
|
1298
|
+
name: "TestComponent",
|
|
1299
|
+
component: () => React.createElement("div", null, "Test"),
|
|
1300
|
+
description: "Test",
|
|
1301
|
+
propsSchema: z.object({ test: z.string() }),
|
|
1302
|
+
associatedTools: [
|
|
1303
|
+
{
|
|
1304
|
+
name: "non-streamable-tool",
|
|
1305
|
+
tool: nonStreamableToolFn,
|
|
1306
|
+
description: "Tool not safe for streaming",
|
|
1307
|
+
inputSchema: z.object({ input: z.string() }),
|
|
1308
|
+
outputSchema: z.object({ data: z.string() }),
|
|
1309
|
+
// No tamboStreamableHint - defaults to false
|
|
1310
|
+
},
|
|
1311
|
+
],
|
|
1312
|
+
},
|
|
1313
|
+
];
|
|
1314
|
+
// First chunk initializes finalMessage
|
|
1315
|
+
const mockInitialChunk = {
|
|
1316
|
+
responseMessageDto: {
|
|
1317
|
+
id: "streaming-chunk",
|
|
1318
|
+
content: [{ type: "text", text: "Starting..." }],
|
|
1319
|
+
role: "assistant",
|
|
1320
|
+
threadId: "test-thread-1",
|
|
1321
|
+
componentState: {},
|
|
1322
|
+
createdAt: new Date().toISOString(),
|
|
1323
|
+
},
|
|
1324
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
1325
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1326
|
+
};
|
|
1327
|
+
// Second chunk has the tool call - but tool is NOT streamable
|
|
1328
|
+
const mockToolCallChunk = {
|
|
1329
|
+
responseMessageDto: {
|
|
1330
|
+
id: "streaming-chunk",
|
|
1331
|
+
content: [{ type: "text", text: "Streaming..." }],
|
|
1332
|
+
role: "assistant",
|
|
1333
|
+
threadId: "test-thread-1",
|
|
1334
|
+
component: {
|
|
1335
|
+
componentName: "",
|
|
1336
|
+
componentState: {},
|
|
1337
|
+
message: "",
|
|
1338
|
+
props: {},
|
|
1339
|
+
toolCallRequest: {
|
|
1340
|
+
toolName: "non-streamable-tool",
|
|
1341
|
+
parameters: [{ parameterName: "input", parameterValue: "test" }],
|
|
1342
|
+
},
|
|
1343
|
+
},
|
|
1344
|
+
componentState: {},
|
|
1345
|
+
createdAt: new Date().toISOString(),
|
|
1346
|
+
},
|
|
1347
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
1348
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1349
|
+
};
|
|
1350
|
+
const mockFinalChunk = {
|
|
1351
|
+
responseMessageDto: {
|
|
1352
|
+
id: "streaming-chunk",
|
|
1353
|
+
content: [{ type: "text", text: "Complete" }],
|
|
1354
|
+
role: "assistant",
|
|
1355
|
+
threadId: "test-thread-1",
|
|
1356
|
+
componentState: {},
|
|
1357
|
+
createdAt: new Date().toISOString(),
|
|
1358
|
+
},
|
|
1359
|
+
generationStage: GenerationStage.COMPLETE,
|
|
1360
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1361
|
+
};
|
|
1362
|
+
const mockAsyncIterator = {
|
|
1363
|
+
[Symbol.asyncIterator]: async function* () {
|
|
1364
|
+
yield mockInitialChunk;
|
|
1365
|
+
yield mockToolCallChunk;
|
|
1366
|
+
yield mockFinalChunk;
|
|
1367
|
+
},
|
|
1368
|
+
};
|
|
1369
|
+
jest.mocked(advanceStream).mockResolvedValueOnce(mockAsyncIterator);
|
|
1370
|
+
const { result } = renderHook(() => useTamboThread(), {
|
|
1371
|
+
wrapper: createWrapper({
|
|
1372
|
+
components: customToolRegistry,
|
|
1373
|
+
streaming: true,
|
|
1374
|
+
}),
|
|
1375
|
+
});
|
|
1376
|
+
await act(async () => {
|
|
1377
|
+
await result.current.sendThreadMessage("Test non-streamable tool", {
|
|
1378
|
+
threadId: "test-thread-1",
|
|
1379
|
+
streamResponse: true,
|
|
1380
|
+
});
|
|
1381
|
+
});
|
|
1382
|
+
// Non-streamable tool should NOT be called during the streaming chunk phase
|
|
1383
|
+
// (it would only be called when generationStage is COMPLETE with a toolCallRequest)
|
|
1384
|
+
expect(nonStreamableToolFn).not.toHaveBeenCalled();
|
|
1385
|
+
});
|
|
1386
|
+
it("should only call streamable tools during streaming when mixed", async () => {
|
|
1387
|
+
const streamableToolFn = jest
|
|
1388
|
+
.fn()
|
|
1389
|
+
.mockResolvedValue({ data: "streamed" });
|
|
1390
|
+
const nonStreamableToolFn = jest
|
|
1391
|
+
.fn()
|
|
1392
|
+
.mockResolvedValue({ data: "not-streamed" });
|
|
1393
|
+
const customToolRegistry = [
|
|
1394
|
+
{
|
|
1395
|
+
name: "TestComponent",
|
|
1396
|
+
component: () => React.createElement("div", null, "Test"),
|
|
1397
|
+
description: "Test",
|
|
1398
|
+
propsSchema: z.object({ test: z.string() }),
|
|
1399
|
+
associatedTools: [
|
|
1400
|
+
{
|
|
1401
|
+
name: "streamable-tool",
|
|
1402
|
+
tool: streamableToolFn,
|
|
1403
|
+
description: "Tool safe for streaming",
|
|
1404
|
+
inputSchema: z.object({ input: z.string() }),
|
|
1405
|
+
outputSchema: z.object({ data: z.string() }),
|
|
1406
|
+
annotations: { tamboStreamableHint: true },
|
|
1407
|
+
},
|
|
1408
|
+
{
|
|
1409
|
+
name: "non-streamable-tool",
|
|
1410
|
+
tool: nonStreamableToolFn,
|
|
1411
|
+
description: "Tool not safe for streaming",
|
|
1412
|
+
inputSchema: z.object({ input: z.string() }),
|
|
1413
|
+
outputSchema: z.object({ data: z.string() }),
|
|
1414
|
+
annotations: { tamboStreamableHint: false },
|
|
1415
|
+
},
|
|
1416
|
+
],
|
|
1417
|
+
},
|
|
1418
|
+
];
|
|
1419
|
+
// First chunk initializes finalMessage
|
|
1420
|
+
const mockInitialChunk = {
|
|
1421
|
+
responseMessageDto: {
|
|
1422
|
+
id: "streaming-chunk",
|
|
1423
|
+
content: [{ type: "text", text: "Starting..." }],
|
|
1424
|
+
role: "assistant",
|
|
1425
|
+
threadId: "test-thread-1",
|
|
1426
|
+
componentState: {},
|
|
1427
|
+
createdAt: new Date().toISOString(),
|
|
1428
|
+
},
|
|
1429
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
1430
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1431
|
+
};
|
|
1432
|
+
// Second chunk calls the streamable tool
|
|
1433
|
+
const mockStreamableToolChunk = {
|
|
1434
|
+
responseMessageDto: {
|
|
1435
|
+
id: "streaming-chunk",
|
|
1436
|
+
content: [{ type: "text", text: "Calling streamable..." }],
|
|
1437
|
+
role: "assistant",
|
|
1438
|
+
threadId: "test-thread-1",
|
|
1439
|
+
component: {
|
|
1440
|
+
componentName: "",
|
|
1441
|
+
componentState: {},
|
|
1442
|
+
message: "",
|
|
1443
|
+
props: {},
|
|
1444
|
+
toolCallRequest: {
|
|
1445
|
+
toolName: "streamable-tool",
|
|
1446
|
+
parameters: [
|
|
1447
|
+
{ parameterName: "input", parameterValue: "streamed-input" },
|
|
1448
|
+
],
|
|
1449
|
+
},
|
|
1450
|
+
},
|
|
1451
|
+
componentState: {},
|
|
1452
|
+
createdAt: new Date().toISOString(),
|
|
1453
|
+
},
|
|
1454
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
1455
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1456
|
+
};
|
|
1457
|
+
// Third chunk calls the non-streamable tool
|
|
1458
|
+
const mockNonStreamableToolChunk = {
|
|
1459
|
+
responseMessageDto: {
|
|
1460
|
+
id: "streaming-chunk",
|
|
1461
|
+
content: [{ type: "text", text: "Calling non-streamable..." }],
|
|
1462
|
+
role: "assistant",
|
|
1463
|
+
threadId: "test-thread-1",
|
|
1464
|
+
component: {
|
|
1465
|
+
componentName: "",
|
|
1466
|
+
componentState: {},
|
|
1467
|
+
message: "",
|
|
1468
|
+
props: {},
|
|
1469
|
+
toolCallRequest: {
|
|
1470
|
+
toolName: "non-streamable-tool",
|
|
1471
|
+
parameters: [
|
|
1472
|
+
{
|
|
1473
|
+
parameterName: "input",
|
|
1474
|
+
parameterValue: "non-streamed-input",
|
|
1475
|
+
},
|
|
1476
|
+
],
|
|
1477
|
+
},
|
|
1478
|
+
},
|
|
1479
|
+
componentState: {},
|
|
1480
|
+
createdAt: new Date().toISOString(),
|
|
1481
|
+
},
|
|
1482
|
+
generationStage: GenerationStage.STREAMING_RESPONSE,
|
|
1483
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1484
|
+
};
|
|
1485
|
+
const mockFinalChunk = {
|
|
1486
|
+
responseMessageDto: {
|
|
1487
|
+
id: "streaming-chunk",
|
|
1488
|
+
content: [{ type: "text", text: "Complete" }],
|
|
1489
|
+
role: "assistant",
|
|
1490
|
+
threadId: "test-thread-1",
|
|
1491
|
+
componentState: {},
|
|
1492
|
+
createdAt: new Date().toISOString(),
|
|
1493
|
+
},
|
|
1494
|
+
generationStage: GenerationStage.COMPLETE,
|
|
1495
|
+
mcpAccessToken: "test-mcp-access-token",
|
|
1496
|
+
};
|
|
1497
|
+
const mockAsyncIterator = {
|
|
1498
|
+
[Symbol.asyncIterator]: async function* () {
|
|
1499
|
+
yield mockInitialChunk;
|
|
1500
|
+
yield mockStreamableToolChunk;
|
|
1501
|
+
yield mockNonStreamableToolChunk;
|
|
1502
|
+
yield mockFinalChunk;
|
|
1503
|
+
},
|
|
1504
|
+
};
|
|
1505
|
+
jest.mocked(advanceStream).mockResolvedValueOnce(mockAsyncIterator);
|
|
1506
|
+
const { result } = renderHook(() => useTamboThread(), {
|
|
1507
|
+
wrapper: createWrapper({
|
|
1508
|
+
components: customToolRegistry,
|
|
1509
|
+
streaming: true,
|
|
1510
|
+
}),
|
|
1511
|
+
});
|
|
1512
|
+
await act(async () => {
|
|
1513
|
+
await result.current.sendThreadMessage("Test mixed tools", {
|
|
1514
|
+
threadId: "test-thread-1",
|
|
1515
|
+
streamResponse: true,
|
|
1516
|
+
});
|
|
1517
|
+
});
|
|
1518
|
+
// Only the streamable tool should be called during streaming
|
|
1519
|
+
expect(streamableToolFn).toHaveBeenCalledWith({
|
|
1520
|
+
input: "streamed-input",
|
|
1521
|
+
});
|
|
1522
|
+
expect(nonStreamableToolFn).not.toHaveBeenCalled();
|
|
1523
|
+
});
|
|
1524
|
+
});
|
|
1358
1525
|
describe("auto-generate thread name", () => {
|
|
1359
1526
|
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
1527
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1377
|
-
wrapper:
|
|
1528
|
+
wrapper: createWrapper({ autoGenerateNameThreshold: 2 }),
|
|
1378
1529
|
});
|
|
1379
1530
|
const existingThread = createMockThread({
|
|
1380
1531
|
id: "test-thread-1",
|
|
@@ -1411,24 +1562,11 @@ describe("TamboThreadProvider", () => {
|
|
|
1411
1562
|
expect(mockQueryClient.setQueryData).toHaveBeenCalledWith(["threads", "test-project-id", undefined], expect.any(Function));
|
|
1412
1563
|
});
|
|
1413
1564
|
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
1565
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1431
|
-
wrapper:
|
|
1566
|
+
wrapper: createWrapper({
|
|
1567
|
+
autoGenerateThreadName: false,
|
|
1568
|
+
autoGenerateNameThreshold: 2,
|
|
1569
|
+
}),
|
|
1432
1570
|
});
|
|
1433
1571
|
const existingThread = createMockThread({
|
|
1434
1572
|
id: "test-thread-1",
|
|
@@ -1461,24 +1599,8 @@ describe("TamboThreadProvider", () => {
|
|
|
1461
1599
|
expect(mockThreadsApi.generateName).not.toHaveBeenCalled();
|
|
1462
1600
|
});
|
|
1463
1601
|
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
1602
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1481
|
-
wrapper:
|
|
1603
|
+
wrapper: createWrapper({ autoGenerateNameThreshold: 2 }),
|
|
1482
1604
|
});
|
|
1483
1605
|
const threadWithName = createMockThread({
|
|
1484
1606
|
id: "test-thread-1",
|
|
@@ -1516,24 +1638,8 @@ describe("TamboThreadProvider", () => {
|
|
|
1516
1638
|
expect(mockThreadsApi.generateName).not.toHaveBeenCalled();
|
|
1517
1639
|
});
|
|
1518
1640
|
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
1641
|
const { result } = renderHook(() => useTamboThread(), {
|
|
1536
|
-
wrapper:
|
|
1642
|
+
wrapper: createWrapper({ autoGenerateNameThreshold: 2 }),
|
|
1537
1643
|
});
|
|
1538
1644
|
// Stay on placeholder thread
|
|
1539
1645
|
expect(result.current.thread.id).toBe("placeholder");
|