@tambo-ai/react 0.73.0 → 0.74.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 +12 -12
- package/dist/hooks/use-component-state.d.ts +1 -1
- package/dist/hooks/use-component-state.js.map +1 -1
- package/dist/hooks/use-streaming-props.d.ts +1 -1
- package/dist/hooks/use-streaming-props.js +1 -1
- package/dist/hooks/use-streaming-props.js.map +1 -1
- package/dist/hooks/use-tambo-stream-status.d.ts +1 -1
- package/dist/hooks/use-tambo-stream-status.js +1 -1
- package/dist/hooks/use-tambo-stream-status.js.map +1 -1
- package/dist/mcp/mcp-hooks.d.ts +4 -0
- package/dist/mcp/mcp-hooks.d.ts.map +1 -1
- package/dist/mcp/mcp-hooks.js +4 -0
- package/dist/mcp/mcp-hooks.js.map +1 -1
- package/dist/providers/tambo-interactable-provider-partial-updates.test.js +3 -3
- package/dist/providers/tambo-interactable-provider-partial-updates.test.js.map +1 -1
- package/dist/providers/tambo-interactable-provider.js +2 -2
- package/dist/providers/tambo-interactable-provider.js.map +1 -1
- package/dist/providers/tambo-interactable-provider.test.js +3 -3
- package/dist/providers/tambo-interactable-provider.test.js.map +1 -1
- package/dist/providers/tambo-provider.d.ts +3 -0
- package/dist/providers/tambo-provider.d.ts.map +1 -1
- package/dist/providers/tambo-provider.js +3 -0
- package/dist/providers/tambo-provider.js.map +1 -1
- package/dist/providers/tambo-thread-input-provider.d.ts.map +1 -1
- package/dist/providers/tambo-thread-input-provider.js +1 -0
- package/dist/providers/tambo-thread-input-provider.js.map +1 -1
- package/dist/util/resource-content-resolver.d.ts.map +1 -1
- package/dist/util/resource-content-resolver.js +2 -0
- package/dist/util/resource-content-resolver.js.map +1 -1
- package/dist/v1/__tests__/v1-interactables.test.d.ts +2 -0
- package/dist/v1/__tests__/v1-interactables.test.d.ts.map +1 -0
- package/dist/v1/__tests__/v1-interactables.test.js +135 -0
- package/dist/v1/__tests__/v1-interactables.test.js.map +1 -0
- package/dist/v1/components/v1-component-renderer.d.ts +48 -0
- package/dist/v1/components/v1-component-renderer.d.ts.map +1 -0
- package/dist/v1/components/v1-component-renderer.js +137 -0
- package/dist/v1/components/v1-component-renderer.js.map +1 -0
- package/dist/v1/components/v1-component-renderer.test.d.ts +2 -0
- package/dist/v1/components/v1-component-renderer.test.d.ts.map +1 -0
- package/dist/v1/components/v1-component-renderer.test.js +270 -0
- package/dist/v1/components/v1-component-renderer.test.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-component-state.d.ts.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-component-state.js +2 -25
- package/dist/v1/hooks/use-tambo-v1-component-state.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-component-state.test.js +2 -1
- package/dist/v1/hooks/use-tambo-v1-component-state.test.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-messages.test.js +25 -1
- package/dist/v1/hooks/use-tambo-v1-messages.test.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-send-message.d.ts +18 -0
- package/dist/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-send-message.js +204 -17
- package/dist/v1/hooks/use-tambo-v1-send-message.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-send-message.test.js +261 -7
- package/dist/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-stream-status.d.ts +90 -0
- package/dist/v1/hooks/use-tambo-v1-stream-status.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-stream-status.js +179 -0
- package/dist/v1/hooks/use-tambo-v1-stream-status.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-stream-status.test.d.ts +2 -0
- package/dist/v1/hooks/use-tambo-v1-stream-status.test.d.ts.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-stream-status.test.js +371 -0
- package/dist/v1/hooks/use-tambo-v1-stream-status.test.js.map +1 -0
- package/dist/v1/hooks/use-tambo-v1-suggestions.d.ts +78 -54
- package/dist/v1/hooks/use-tambo-v1-suggestions.d.ts.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-suggestions.js +153 -87
- package/dist/v1/hooks/use-tambo-v1-suggestions.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-suggestions.test.js +213 -134
- package/dist/v1/hooks/use-tambo-v1-suggestions.test.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-thread-input.test.js +148 -13
- package/dist/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts +8 -21
- package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-thread-list.js +11 -10
- package/dist/v1/hooks/use-tambo-v1-thread-list.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-thread-list.test.js +37 -2
- package/dist/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-thread.d.ts +1 -1
- package/dist/v1/hooks/use-tambo-v1-thread.d.ts.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-thread.js +2 -7
- package/dist/v1/hooks/use-tambo-v1-thread.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1-thread.test.js +2 -0
- package/dist/v1/hooks/use-tambo-v1-thread.test.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1.d.ts +12 -28
- package/dist/v1/hooks/use-tambo-v1.d.ts.map +1 -1
- package/dist/v1/hooks/use-tambo-v1.js +164 -31
- package/dist/v1/hooks/use-tambo-v1.js.map +1 -1
- package/dist/v1/hooks/use-tambo-v1.test.js +891 -18
- package/dist/v1/hooks/use-tambo-v1.test.js.map +1 -1
- package/dist/v1/index.d.ts +7 -1
- package/dist/v1/index.d.ts.map +1 -1
- package/dist/v1/index.js +18 -1
- package/dist/v1/index.js.map +1 -1
- package/dist/v1/providers/tambo-v1-provider.d.ts +16 -6
- package/dist/v1/providers/tambo-v1-provider.d.ts.map +1 -1
- package/dist/v1/providers/tambo-v1-provider.js +14 -19
- package/dist/v1/providers/tambo-v1-provider.js.map +1 -1
- package/dist/v1/providers/tambo-v1-provider.test.js +34 -20
- package/dist/v1/providers/tambo-v1-provider.test.js.map +1 -1
- package/dist/v1/providers/tambo-v1-stream-context.d.ts +3 -3
- package/dist/v1/providers/tambo-v1-stream-context.d.ts.map +1 -1
- package/dist/v1/providers/tambo-v1-stream-context.js +60 -12
- package/dist/v1/providers/tambo-v1-stream-context.js.map +1 -1
- package/dist/v1/providers/tambo-v1-stream-context.test.js +49 -20
- package/dist/v1/providers/tambo-v1-stream-context.test.js.map +1 -1
- package/dist/v1/providers/tambo-v1-stub-provider.d.ts.map +1 -1
- package/dist/v1/providers/tambo-v1-stub-provider.js +2 -0
- package/dist/v1/providers/tambo-v1-stub-provider.js.map +1 -1
- package/dist/v1/providers/tambo-v1-stub-provider.test.js +7 -6
- package/dist/v1/providers/tambo-v1-stub-provider.test.js.map +1 -1
- package/dist/v1/providers/tambo-v1-thread-input-provider.d.ts +1 -6
- package/dist/v1/providers/tambo-v1-thread-input-provider.d.ts.map +1 -1
- package/dist/v1/providers/tambo-v1-thread-input-provider.js +14 -12
- package/dist/v1/providers/tambo-v1-thread-input-provider.js.map +1 -1
- package/dist/v1/types/event.d.ts +9 -1
- package/dist/v1/types/event.d.ts.map +1 -1
- package/dist/v1/types/event.js.map +1 -1
- package/dist/v1/types/event.test.js +5 -1
- package/dist/v1/types/event.test.js.map +1 -1
- package/dist/v1/types/message.d.ts +65 -7
- package/dist/v1/types/message.d.ts.map +1 -1
- package/dist/v1/types/message.js.map +1 -1
- package/dist/v1/types/thread.d.ts +4 -0
- package/dist/v1/types/thread.d.ts.map +1 -1
- package/dist/v1/types/thread.js.map +1 -1
- package/dist/v1/utils/event-accumulator.d.ts +40 -4
- package/dist/v1/utils/event-accumulator.d.ts.map +1 -1
- package/dist/v1/utils/event-accumulator.js +444 -35
- package/dist/v1/utils/event-accumulator.js.map +1 -1
- package/dist/v1/utils/event-accumulator.test.js +1041 -28
- package/dist/v1/utils/event-accumulator.test.js.map +1 -1
- package/dist/v1/utils/registry-conversion.d.ts +9 -9
- package/dist/v1/utils/registry-conversion.d.ts.map +1 -1
- package/dist/v1/utils/registry-conversion.js +10 -11
- package/dist/v1/utils/registry-conversion.js.map +1 -1
- package/dist/v1/utils/registry-conversion.test.js +39 -11
- package/dist/v1/utils/registry-conversion.test.js.map +1 -1
- package/dist/v1/utils/thread-utils.d.ts +16 -0
- package/dist/v1/utils/thread-utils.d.ts.map +1 -0
- package/dist/v1/utils/thread-utils.js +34 -0
- package/dist/v1/utils/thread-utils.js.map +1 -0
- package/dist/v1/utils/tool-executor.d.ts.map +1 -1
- package/dist/v1/utils/tool-executor.js +2 -0
- package/dist/v1/utils/tool-executor.js.map +1 -1
- package/dist/v1/utils/tool-executor.test.js +5 -0
- package/dist/v1/utils/tool-executor.test.js.map +1 -1
- package/esm/context-helpers/context-helpers-provider.test.js +2 -2
- package/esm/context-helpers/context-helpers.test.js +1 -1
- package/esm/context-helpers/current-interactables-context-helper.d.ts +1 -1
- package/esm/context-helpers/current-page-context-helper.d.ts +1 -1
- package/esm/context-helpers/current-time-context-helper.d.ts +1 -1
- package/esm/context-helpers/index.d.ts +4 -4
- package/esm/context-helpers/index.js +4 -4
- package/esm/hoc/with-tambo-interactable.d.ts +1 -1
- package/esm/hoc/with-tambo-interactable.js +2 -2
- package/esm/hoc/with-tambo-interactable.test.js +3 -3
- package/esm/hooks/index.d.ts +8 -8
- package/esm/hooks/index.js +8 -8
- package/esm/hooks/react-query-hooks.js +1 -1
- package/esm/hooks/use-component-state.d.ts +1 -1
- package/esm/hooks/use-component-state.js +3 -3
- package/esm/hooks/use-component-state.js.map +1 -1
- package/esm/hooks/use-component-state.test.js +5 -5
- package/esm/hooks/use-current-message.d.ts +1 -1
- package/esm/hooks/use-current-message.test.js +1 -1
- package/esm/hooks/use-message-images.test.js +1 -1
- package/esm/hooks/use-streaming-props.d.ts +1 -1
- package/esm/hooks/use-streaming-props.js +1 -1
- package/esm/hooks/use-streaming-props.js.map +1 -1
- package/esm/hooks/use-suggestions.d.ts +2 -2
- package/esm/hooks/use-suggestions.js +10 -10
- package/esm/hooks/use-suggestions.test.js +7 -7
- package/esm/hooks/use-tambo-stream-status.d.ts +1 -1
- package/esm/hooks/use-tambo-stream-status.js +4 -4
- package/esm/hooks/use-tambo-stream-status.js.map +1 -1
- package/esm/hooks/use-tambo-stream-status.test.js +4 -4
- package/esm/hooks/use-tambo-threads.js +3 -3
- package/esm/hooks/use-tambo-threads.test.js +3 -3
- package/esm/hooks/use-tambo-voice.js +2 -2
- package/esm/hooks/use-tambo-voice.test.js +3 -3
- package/esm/index.d.ts +22 -22
- package/esm/index.js +15 -15
- package/esm/mcp/elicitation.d.ts +1 -1
- package/esm/mcp/elicitation.test.js +1 -1
- package/esm/mcp/index.d.ts +7 -7
- package/esm/mcp/index.js +3 -3
- package/esm/mcp/mcp-client.d.ts +1 -1
- package/esm/mcp/mcp-client.js +1 -1
- package/esm/mcp/mcp-client.test.js +1 -1
- package/esm/mcp/mcp-hooks.d.ts +5 -1
- package/esm/mcp/mcp-hooks.d.ts.map +1 -1
- package/esm/mcp/mcp-hooks.js +8 -4
- package/esm/mcp/mcp-hooks.js.map +1 -1
- package/esm/mcp/mcp-hooks.test.js +6 -6
- package/esm/mcp/tambo-mcp-provider.d.ts +4 -4
- package/esm/mcp/tambo-mcp-provider.js +7 -7
- package/esm/mcp/tambo-mcp-provider.test.js +5 -5
- package/esm/mcp/use-mcp-servers.test.js +4 -4
- package/esm/model/generate-component-response.d.ts +1 -1
- package/esm/model/tambo-interactable.d.ts +1 -1
- package/esm/model/tambo-thread.d.ts +1 -1
- package/esm/providers/__tests__/thread-input-resource-resolution.test.js +3 -3
- package/esm/providers/hooks/use-tambo-session-token.test.js +1 -1
- package/esm/providers/index.d.ts +12 -12
- package/esm/providers/index.js +10 -10
- package/esm/providers/tambo-client-provider.js +1 -1
- package/esm/providers/tambo-client-provider.test.js +2 -2
- package/esm/providers/tambo-component-provider.d.ts +1 -1
- package/esm/providers/tambo-component-provider.js +2 -2
- package/esm/providers/tambo-context-attachment-provider.js +1 -1
- package/esm/providers/tambo-context-attachment-provider.test.js +2 -2
- package/esm/providers/tambo-context-helpers-provider.d.ts +1 -1
- package/esm/providers/tambo-context-helpers-provider.js +1 -1
- package/esm/providers/tambo-context-helpers-provider.test.js +2 -2
- package/esm/providers/tambo-interactable-provider-partial-updates.test.js +4 -4
- package/esm/providers/tambo-interactable-provider-partial-updates.test.js.map +1 -1
- package/esm/providers/tambo-interactable-provider.d.ts +5 -5
- package/esm/providers/tambo-interactable-provider.js +6 -6
- package/esm/providers/tambo-interactable-provider.js.map +1 -1
- package/esm/providers/tambo-interactable-provider.test.js +4 -4
- package/esm/providers/tambo-interactable-provider.test.js.map +1 -1
- package/esm/providers/tambo-interactables-additional-context-edge-cases.test.js +4 -4
- package/esm/providers/tambo-interactables-additional-context.test.js +4 -4
- package/esm/providers/tambo-mcp-token-provider.js +2 -2
- package/esm/providers/tambo-prop-stream-provider/index.d.ts +8 -8
- package/esm/providers/tambo-prop-stream-provider/index.js +9 -9
- package/esm/providers/tambo-prop-stream-provider/pending.d.ts +1 -1
- package/esm/providers/tambo-prop-stream-provider/pending.js +2 -2
- package/esm/providers/tambo-prop-stream-provider/provider.d.ts +1 -1
- package/esm/providers/tambo-prop-stream-provider/provider.js +2 -2
- package/esm/providers/tambo-prop-stream-provider/streaming.d.ts +1 -1
- package/esm/providers/tambo-prop-stream-provider/streaming.js +2 -2
- package/esm/providers/tambo-prop-stream-provider/success.d.ts +1 -1
- package/esm/providers/tambo-prop-stream-provider/success.js +2 -2
- package/esm/providers/tambo-prop-stream-provider/types.d.ts +1 -1
- package/esm/providers/tambo-prop-stream-provider.test.js +4 -4
- package/esm/providers/tambo-provider.d.ts +10 -7
- package/esm/providers/tambo-provider.d.ts.map +1 -1
- package/esm/providers/tambo-provider.js +13 -10
- package/esm/providers/tambo-provider.js.map +1 -1
- package/esm/providers/tambo-registry-provider.d.ts +3 -3
- package/esm/providers/tambo-registry-provider.js +3 -3
- package/esm/providers/tambo-registry-provider.test.js +2 -2
- package/esm/providers/tambo-registry-schema-compat.test.js +2 -2
- package/esm/providers/tambo-stubs.d.ts +4 -4
- package/esm/providers/tambo-stubs.js +9 -9
- package/esm/providers/tambo-stubs.test.js +2 -2
- package/esm/providers/tambo-thread-input-provider.d.ts +2 -2
- package/esm/providers/tambo-thread-input-provider.d.ts.map +1 -1
- package/esm/providers/tambo-thread-input-provider.js +11 -10
- package/esm/providers/tambo-thread-input-provider.js.map +1 -1
- package/esm/providers/tambo-thread-provider-initial-messages.test.js +6 -6
- package/esm/providers/tambo-thread-provider.d.ts +2 -2
- package/esm/providers/tambo-thread-provider.js +8 -8
- package/esm/providers/tambo-thread-provider.test.js +7 -7
- package/esm/schema/index.d.ts +4 -4
- package/esm/schema/index.js +4 -4
- package/esm/schema/json-schema.test.js +1 -1
- package/esm/schema/schema.d.ts +1 -1
- package/esm/schema/schema.js +2 -2
- package/esm/schema/schema.test.js +3 -3
- package/esm/schema/standard-schema.test.js +1 -1
- package/esm/schema/validate.js +2 -2
- package/esm/schema/validate.test.js +1 -1
- package/esm/testing/tools.d.ts +3 -3
- package/esm/testing/tools.js +2 -2
- package/esm/util/content-parts.test.js +1 -1
- package/esm/util/generate-component.d.ts +2 -2
- package/esm/util/generate-component.js +4 -4
- package/esm/util/generate-component.test.js +2 -2
- package/esm/util/is-promise.test.js +1 -1
- package/esm/util/mcp-server-utils.d.ts +1 -1
- package/esm/util/mcp-server-utils.js +1 -1
- package/esm/util/mcp-server-utils.test.js +2 -2
- package/esm/util/message-builder.d.ts +1 -1
- package/esm/util/message-builder.test.js +1 -1
- package/esm/util/query-utils.test.js +1 -1
- package/esm/util/registry-validators.d.ts +1 -1
- package/esm/util/registry-validators.js +2 -2
- package/esm/util/registry-validators.test.js +1 -1
- package/esm/util/registry.d.ts +1 -1
- package/esm/util/registry.js +1 -1
- package/esm/util/registry.test.js +2 -2
- package/esm/util/resource-content-resolver.d.ts +2 -2
- package/esm/util/resource-content-resolver.d.ts.map +1 -1
- package/esm/util/resource-content-resolver.js +3 -1
- package/esm/util/resource-content-resolver.js.map +1 -1
- package/esm/util/resource-content-resolver.test.js +3 -3
- package/esm/util/resource-validators.d.ts +1 -1
- package/esm/util/resource-validators.test.js +1 -1
- package/esm/util/tool-caller.d.ts +1 -1
- package/esm/util/tool-caller.js +1 -1
- package/esm/util/validate-component-name.test.js +1 -1
- package/esm/v1/__tests__/v1-interactables.test.d.ts +2 -0
- package/esm/v1/__tests__/v1-interactables.test.d.ts.map +1 -0
- package/esm/v1/__tests__/v1-interactables.test.js +130 -0
- package/esm/v1/__tests__/v1-interactables.test.js.map +1 -0
- package/esm/v1/components/v1-component-renderer.d.ts +48 -0
- package/esm/v1/components/v1-component-renderer.d.ts.map +1 -0
- package/esm/v1/components/v1-component-renderer.js +100 -0
- package/esm/v1/components/v1-component-renderer.js.map +1 -0
- package/esm/v1/components/v1-component-renderer.test.d.ts +2 -0
- package/esm/v1/components/v1-component-renderer.test.d.ts.map +1 -0
- package/esm/v1/components/v1-component-renderer.test.js +265 -0
- package/esm/v1/components/v1-component-renderer.test.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-component-state.d.ts.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-component-state.js +4 -27
- package/esm/v1/hooks/use-tambo-v1-component-state.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-component-state.test.js +6 -5
- package/esm/v1/hooks/use-tambo-v1-component-state.test.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-messages.d.ts +1 -1
- package/esm/v1/hooks/use-tambo-v1-messages.js +1 -1
- package/esm/v1/hooks/use-tambo-v1-messages.test.js +27 -3
- package/esm/v1/hooks/use-tambo-v1-messages.test.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-send-message.d.ts +20 -2
- package/esm/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-send-message.js +213 -26
- package/esm/v1/hooks/use-tambo-v1-send-message.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-send-message.test.js +266 -12
- package/esm/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-stream-status.d.ts +90 -0
- package/esm/v1/hooks/use-tambo-v1-stream-status.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-stream-status.js +176 -0
- package/esm/v1/hooks/use-tambo-v1-stream-status.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-stream-status.test.d.ts +2 -0
- package/esm/v1/hooks/use-tambo-v1-stream-status.test.d.ts.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-stream-status.test.js +369 -0
- package/esm/v1/hooks/use-tambo-v1-stream-status.test.js.map +1 -0
- package/esm/v1/hooks/use-tambo-v1-suggestions.d.ts +78 -54
- package/esm/v1/hooks/use-tambo-v1-suggestions.d.ts.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-suggestions.js +157 -91
- package/esm/v1/hooks/use-tambo-v1-suggestions.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-suggestions.test.js +218 -139
- package/esm/v1/hooks/use-tambo-v1-suggestions.test.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread-input.d.ts +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread-input.js +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread-input.test.js +151 -16
- package/esm/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts +8 -21
- package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread-list.js +12 -11
- package/esm/v1/hooks/use-tambo-v1-thread-list.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread-list.test.js +39 -4
- package/esm/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread.d.ts +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread.d.ts.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread.js +3 -8
- package/esm/v1/hooks/use-tambo-v1-thread.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1-thread.test.js +4 -2
- package/esm/v1/hooks/use-tambo-v1-thread.test.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1.d.ts +15 -31
- package/esm/v1/hooks/use-tambo-v1.d.ts.map +1 -1
- package/esm/v1/hooks/use-tambo-v1.js +134 -34
- package/esm/v1/hooks/use-tambo-v1.js.map +1 -1
- package/esm/v1/hooks/use-tambo-v1.test.js +862 -19
- package/esm/v1/hooks/use-tambo-v1.test.js.map +1 -1
- package/esm/v1/index.d.ts +28 -22
- package/esm/v1/index.d.ts.map +1 -1
- package/esm/v1/index.js +30 -18
- package/esm/v1/index.js.map +1 -1
- package/esm/v1/providers/tambo-v1-provider.d.ts +21 -11
- package/esm/v1/providers/tambo-v1-provider.d.ts.map +1 -1
- package/esm/v1/providers/tambo-v1-provider.js +20 -25
- package/esm/v1/providers/tambo-v1-provider.js.map +1 -1
- package/esm/v1/providers/tambo-v1-provider.test.js +40 -26
- package/esm/v1/providers/tambo-v1-provider.test.js.map +1 -1
- package/esm/v1/providers/tambo-v1-stream-context.d.ts +4 -4
- package/esm/v1/providers/tambo-v1-stream-context.d.ts.map +1 -1
- package/esm/v1/providers/tambo-v1-stream-context.js +62 -14
- package/esm/v1/providers/tambo-v1-stream-context.js.map +1 -1
- package/esm/v1/providers/tambo-v1-stream-context.test.js +50 -21
- package/esm/v1/providers/tambo-v1-stream-context.test.js.map +1 -1
- package/esm/v1/providers/tambo-v1-stub-provider.d.ts +3 -3
- package/esm/v1/providers/tambo-v1-stub-provider.d.ts.map +1 -1
- package/esm/v1/providers/tambo-v1-stub-provider.js +7 -5
- package/esm/v1/providers/tambo-v1-stub-provider.js.map +1 -1
- package/esm/v1/providers/tambo-v1-stub-provider.test.js +12 -11
- package/esm/v1/providers/tambo-v1-stub-provider.test.js.map +1 -1
- package/esm/v1/providers/tambo-v1-thread-input-provider.d.ts +3 -8
- package/esm/v1/providers/tambo-v1-thread-input-provider.d.ts.map +1 -1
- package/esm/v1/providers/tambo-v1-thread-input-provider.js +18 -16
- package/esm/v1/providers/tambo-v1-thread-input-provider.js.map +1 -1
- package/esm/v1/types/event.d.ts +9 -1
- package/esm/v1/types/event.d.ts.map +1 -1
- package/esm/v1/types/event.js.map +1 -1
- package/esm/v1/types/event.test.js +6 -2
- package/esm/v1/types/event.test.js.map +1 -1
- package/esm/v1/types/message.d.ts +65 -7
- package/esm/v1/types/message.d.ts.map +1 -1
- package/esm/v1/types/message.js.map +1 -1
- package/esm/v1/types/thread.d.ts +5 -1
- package/esm/v1/types/thread.d.ts.map +1 -1
- package/esm/v1/types/thread.js.map +1 -1
- package/esm/v1/utils/component-renderer.test.js +1 -1
- package/esm/v1/utils/event-accumulator.d.ts +41 -5
- package/esm/v1/utils/event-accumulator.d.ts.map +1 -1
- package/esm/v1/utils/event-accumulator.js +444 -36
- package/esm/v1/utils/event-accumulator.js.map +1 -1
- package/esm/v1/utils/event-accumulator.test.js +1042 -29
- package/esm/v1/utils/event-accumulator.test.js.map +1 -1
- package/esm/v1/utils/json-patch.test.js +1 -1
- package/esm/v1/utils/registry-conversion.d.ts +9 -9
- package/esm/v1/utils/registry-conversion.d.ts.map +1 -1
- package/esm/v1/utils/registry-conversion.js +11 -12
- package/esm/v1/utils/registry-conversion.js.map +1 -1
- package/esm/v1/utils/registry-conversion.test.js +40 -12
- package/esm/v1/utils/registry-conversion.test.js.map +1 -1
- package/esm/v1/utils/stream-handler.test.js +1 -1
- package/esm/v1/utils/thread-utils.d.ts +16 -0
- package/esm/v1/utils/thread-utils.d.ts.map +1 -0
- package/esm/v1/utils/thread-utils.js +31 -0
- package/esm/v1/utils/thread-utils.js.map +1 -0
- package/esm/v1/utils/tool-call-tracker.d.ts +1 -1
- package/esm/v1/utils/tool-executor.d.ts +1 -1
- package/esm/v1/utils/tool-executor.d.ts.map +1 -1
- package/esm/v1/utils/tool-executor.js +2 -0
- package/esm/v1/utils/tool-executor.js.map +1 -1
- package/esm/v1/utils/tool-executor.test.js +6 -1
- package/esm/v1/utils/tool-executor.test.js.map +1 -1
- package/package.json +11 -10
|
@@ -4,18 +4,141 @@
|
|
|
4
4
|
*
|
|
5
5
|
* React Query mutation hook for sending messages and handling streaming responses.
|
|
6
6
|
*/
|
|
7
|
-
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
8
7
|
import { useContext } from "react";
|
|
9
8
|
import { EventType } from "@ag-ui/core";
|
|
10
|
-
import { asTamboCustomEvent } from "../types/event";
|
|
11
|
-
import { useTamboClient } from "../../providers/tambo-client-provider";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
9
|
+
import { asTamboCustomEvent } from "../types/event.js";
|
|
10
|
+
import { useTamboClient, useTamboQueryClient, } from "../../providers/tambo-client-provider.js";
|
|
11
|
+
import { useTamboMutation } from "../../hooks/react-query-hooks.js";
|
|
12
|
+
import { TamboRegistryContext, } from "../../providers/tambo-registry-provider.js";
|
|
13
|
+
import { useStreamDispatch, useStreamState, } from "../providers/tambo-v1-stream-context.js";
|
|
14
|
+
import { useTamboV1Config } from "../providers/tambo-v1-provider.js";
|
|
15
|
+
import { useTamboContextHelpers } from "../../providers/tambo-context-helpers-provider.js";
|
|
16
|
+
import { isPlaceholderThreadId, } from "../utils/event-accumulator.js";
|
|
17
|
+
import { toAvailableComponents, toAvailableTools, } from "../utils/registry-conversion.js";
|
|
18
|
+
import { handleEventStream } from "../utils/stream-handler.js";
|
|
19
|
+
import { executeAllPendingTools } from "../utils/tool-executor.js";
|
|
20
|
+
import { ToolCallTracker } from "../utils/tool-call-tracker.js";
|
|
21
|
+
/**
|
|
22
|
+
* Dispatches synthetic AG-UI events to show a user message in the thread.
|
|
23
|
+
* @param dispatch - Stream state dispatcher
|
|
24
|
+
* @param targetThreadId - Thread to add the message to
|
|
25
|
+
* @param messageId - Stable ID for the user message
|
|
26
|
+
* @param messageText - Text content of the message
|
|
27
|
+
*/
|
|
28
|
+
function dispatchUserMessage(dispatch, targetThreadId, messageId, messageText) {
|
|
29
|
+
dispatch({
|
|
30
|
+
type: "EVENT",
|
|
31
|
+
threadId: targetThreadId,
|
|
32
|
+
event: {
|
|
33
|
+
type: EventType.TEXT_MESSAGE_START,
|
|
34
|
+
messageId,
|
|
35
|
+
role: "user",
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
dispatch({
|
|
39
|
+
type: "EVENT",
|
|
40
|
+
threadId: targetThreadId,
|
|
41
|
+
event: {
|
|
42
|
+
type: EventType.TEXT_MESSAGE_CONTENT,
|
|
43
|
+
messageId,
|
|
44
|
+
delta: messageText,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
dispatch({
|
|
48
|
+
type: "EVENT",
|
|
49
|
+
threadId: targetThreadId,
|
|
50
|
+
event: {
|
|
51
|
+
type: EventType.TEXT_MESSAGE_END,
|
|
52
|
+
messageId,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Dispatches synthetic events for tool results as optimistic local state.
|
|
58
|
+
* The server doesn't echo these back for client-side tools.
|
|
59
|
+
* @param dispatch - Stream state dispatcher
|
|
60
|
+
* @param targetThreadId - Thread to add results to
|
|
61
|
+
* @param toolResults - Tool execution results to dispatch
|
|
62
|
+
*/
|
|
63
|
+
function dispatchToolResults(dispatch, targetThreadId, toolResults) {
|
|
64
|
+
if (toolResults.length === 0)
|
|
65
|
+
return;
|
|
66
|
+
const toolResultMessageId = `msg_tool_result_${Date.now()}`;
|
|
67
|
+
dispatch({
|
|
68
|
+
type: "EVENT",
|
|
69
|
+
threadId: targetThreadId,
|
|
70
|
+
event: {
|
|
71
|
+
type: EventType.TEXT_MESSAGE_START,
|
|
72
|
+
messageId: toolResultMessageId,
|
|
73
|
+
role: "user",
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
for (const result of toolResults) {
|
|
77
|
+
dispatch({
|
|
78
|
+
type: "EVENT",
|
|
79
|
+
threadId: targetThreadId,
|
|
80
|
+
event: {
|
|
81
|
+
type: EventType.TOOL_CALL_RESULT,
|
|
82
|
+
toolCallId: result.toolUseId,
|
|
83
|
+
messageId: toolResultMessageId,
|
|
84
|
+
content: result.content
|
|
85
|
+
.filter((c) => c.type === "text")
|
|
86
|
+
.map((c) => c.text)
|
|
87
|
+
.join("") || JSON.stringify(result.content),
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
dispatch({
|
|
92
|
+
type: "EVENT",
|
|
93
|
+
threadId: targetThreadId,
|
|
94
|
+
event: {
|
|
95
|
+
type: EventType.TEXT_MESSAGE_END,
|
|
96
|
+
messageId: toolResultMessageId,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Checks whether a thread name should be auto-generated based on config
|
|
102
|
+
* and the current thread state.
|
|
103
|
+
* @param threadId - The thread ID (undefined or placeholder means no)
|
|
104
|
+
* @param threadAlreadyHasTitle - Whether the thread already has a title
|
|
105
|
+
* @param preMutationMessageCount - Message count before the current mutation
|
|
106
|
+
* @param autoGenerateNameThreshold - Minimum message count to trigger generation
|
|
107
|
+
* @returns Whether to generate a thread name
|
|
108
|
+
*/
|
|
109
|
+
function shouldGenerateThreadName(threadId, threadAlreadyHasTitle, preMutationMessageCount, autoGenerateNameThreshold) {
|
|
110
|
+
return (!threadAlreadyHasTitle &&
|
|
111
|
+
!!threadId &&
|
|
112
|
+
!isPlaceholderThreadId(threadId) &&
|
|
113
|
+
// +2 accounts for the user message and assistant response just added
|
|
114
|
+
preMutationMessageCount + 2 >= autoGenerateNameThreshold);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Generates a thread name via the beta API, dispatches the title update,
|
|
118
|
+
* and invalidates the thread list cache. Errors are logged, never thrown.
|
|
119
|
+
* @param client - The Tambo API client
|
|
120
|
+
* @param dispatch - Stream state dispatcher
|
|
121
|
+
* @param queryClient - React Query client for cache invalidation
|
|
122
|
+
* @param threadId - The thread to generate a name for
|
|
123
|
+
*/
|
|
124
|
+
async function generateThreadName(client, dispatch, queryClient, threadId) {
|
|
125
|
+
try {
|
|
126
|
+
const threadWithName = await client.beta.threads.generateName(threadId);
|
|
127
|
+
if (threadWithName.name) {
|
|
128
|
+
dispatch({
|
|
129
|
+
type: "UPDATE_THREAD_TITLE",
|
|
130
|
+
threadId,
|
|
131
|
+
title: threadWithName.name,
|
|
132
|
+
});
|
|
133
|
+
await queryClient.invalidateQueries({
|
|
134
|
+
queryKey: ["v1-threads", "list"],
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
console.error("[useTamboV1SendMessage] Failed to auto-generate thread name:", error);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
19
142
|
/**
|
|
20
143
|
* Executes pending tools and returns a continuation stream.
|
|
21
144
|
*
|
|
@@ -23,27 +146,29 @@ import { ToolCallTracker } from "../utils/tool-call-tracker";
|
|
|
23
146
|
* the tools and returns the new stream for the caller to process. This enables
|
|
24
147
|
* the flat loop pattern that correctly handles multi-round tool execution.
|
|
25
148
|
* @param params - The parameters for tool execution
|
|
26
|
-
* @returns The continuation stream
|
|
149
|
+
* @returns The continuation stream and tool results for optimistic local state updates
|
|
27
150
|
*/
|
|
28
151
|
async function executeToolsAndContinue(params) {
|
|
29
|
-
const { event, toolTracker, registry, client, threadId, runId, userKey } = params;
|
|
30
|
-
const
|
|
152
|
+
const { event, toolTracker, registry, client, threadId, runId, userKey, additionalContext, } = params;
|
|
153
|
+
const pendingToolCallIds = event.value.pendingToolCalls.map((tc) => tc.toolCallId);
|
|
31
154
|
const toolCallsToExecute = toolTracker.getToolCallsById(pendingToolCallIds);
|
|
32
155
|
// Execute tools
|
|
33
156
|
const toolResults = await executeAllPendingTools(toolCallsToExecute, registry.toolRegistry);
|
|
34
157
|
// Clear executed tool calls before continuing
|
|
35
158
|
toolTracker.clearToolCalls(pendingToolCallIds);
|
|
36
|
-
// Return the continuation stream
|
|
37
|
-
|
|
159
|
+
// Return the continuation stream and tool results
|
|
160
|
+
const stream = await client.threads.runs.run(threadId, {
|
|
38
161
|
message: {
|
|
39
162
|
role: "user",
|
|
40
163
|
content: toolResults,
|
|
164
|
+
additionalContext,
|
|
41
165
|
},
|
|
42
166
|
previousRunId: runId,
|
|
43
167
|
availableComponents: toAvailableComponents(registry.componentList),
|
|
44
168
|
tools: toAvailableTools(registry.toolRegistry),
|
|
45
169
|
userKey,
|
|
46
170
|
});
|
|
171
|
+
return { stream, toolResults };
|
|
47
172
|
}
|
|
48
173
|
/**
|
|
49
174
|
* Creates a run stream by calling the appropriate API method.
|
|
@@ -54,24 +179,35 @@ async function executeToolsAndContinue(params) {
|
|
|
54
179
|
* @returns The stream and initial thread ID (undefined if creating new thread)
|
|
55
180
|
*/
|
|
56
181
|
export async function createRunStream(params) {
|
|
57
|
-
const { client, threadId, message, registry, userKey } = params;
|
|
182
|
+
const { client, threadId, message, registry, userKey, previousRunId, additionalContext, } = params;
|
|
183
|
+
// Merge helper context with any caller-provided additionalContext on the message
|
|
184
|
+
const mergedContext = additionalContext || message.additionalContext
|
|
185
|
+
? {
|
|
186
|
+
...(message.additionalContext ?? {}),
|
|
187
|
+
...additionalContext,
|
|
188
|
+
}
|
|
189
|
+
: undefined;
|
|
190
|
+
const messageWithContext = mergedContext
|
|
191
|
+
? { ...message, additionalContext: mergedContext }
|
|
192
|
+
: message;
|
|
58
193
|
// Convert registry components/tools to v1 API format
|
|
59
194
|
const availableComponents = toAvailableComponents(registry.componentList);
|
|
60
195
|
const availableTools = toAvailableTools(registry.toolRegistry);
|
|
61
196
|
if (threadId) {
|
|
62
197
|
// Run on existing thread
|
|
63
198
|
const stream = await client.threads.runs.run(threadId, {
|
|
64
|
-
message,
|
|
199
|
+
message: messageWithContext,
|
|
65
200
|
availableComponents,
|
|
66
201
|
tools: availableTools,
|
|
67
202
|
userKey,
|
|
203
|
+
previousRunId,
|
|
68
204
|
});
|
|
69
205
|
return { stream, initialThreadId: threadId };
|
|
70
206
|
}
|
|
71
207
|
else {
|
|
72
208
|
// Create new thread
|
|
73
209
|
const stream = await client.threads.runs.create({
|
|
74
|
-
message,
|
|
210
|
+
message: messageWithContext,
|
|
75
211
|
availableComponents,
|
|
76
212
|
tools: availableTools,
|
|
77
213
|
thread: userKey ? { userKey } : undefined,
|
|
@@ -127,23 +263,58 @@ export async function createRunStream(params) {
|
|
|
127
263
|
export function useTamboV1SendMessage(threadId) {
|
|
128
264
|
const client = useTamboClient();
|
|
129
265
|
const dispatch = useStreamDispatch();
|
|
130
|
-
const
|
|
266
|
+
const streamState = useStreamState();
|
|
267
|
+
const { userKey, autoGenerateThreadName = true, autoGenerateNameThreshold = 3, } = useTamboV1Config();
|
|
131
268
|
const registry = useContext(TamboRegistryContext);
|
|
132
|
-
const queryClient =
|
|
269
|
+
const queryClient = useTamboQueryClient();
|
|
270
|
+
const { getAdditionalContext } = useTamboContextHelpers();
|
|
133
271
|
if (!registry) {
|
|
134
272
|
throw new Error("useTamboV1SendMessage must be used within TamboRegistryProvider");
|
|
135
273
|
}
|
|
136
|
-
|
|
274
|
+
// Placeholder ID isn't a valid API thread ID - treat as new thread creation
|
|
275
|
+
const isNewThread = isPlaceholderThreadId(threadId);
|
|
276
|
+
const apiThreadId = isNewThread ? undefined : threadId;
|
|
277
|
+
// Get previousRunId from the thread's streaming state (if thread exists and has messages)
|
|
278
|
+
const threadState = apiThreadId
|
|
279
|
+
? streamState.threadMap[apiThreadId]
|
|
280
|
+
: undefined;
|
|
281
|
+
const previousRunId = threadState?.streaming.runId;
|
|
282
|
+
return useTamboMutation({
|
|
137
283
|
mutationFn: async (options) => {
|
|
138
|
-
const { message, debug = false } = options;
|
|
284
|
+
const { message, userMessageText, debug = false } = options;
|
|
285
|
+
// Capture pre-mutation state for auto thread name generation
|
|
286
|
+
const existingThread = streamState.threadMap[apiThreadId ?? ""];
|
|
287
|
+
const preMutationMessageCount = existingThread?.thread.messages.length ?? 0;
|
|
288
|
+
const threadAlreadyHasTitle = !!existingThread?.thread.title;
|
|
139
289
|
const toolTracker = new ToolCallTracker();
|
|
290
|
+
// Generate a stable message ID for the user message
|
|
291
|
+
const userMessageId = userMessageText
|
|
292
|
+
? `user_msg_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`
|
|
293
|
+
: undefined;
|
|
294
|
+
// Add user message immediately for instant feedback
|
|
295
|
+
// Use threadId (which could be temp_xxx for new threads) for display
|
|
296
|
+
if (threadId && userMessageText && userMessageId) {
|
|
297
|
+
dispatchUserMessage(dispatch, threadId, userMessageId, userMessageText);
|
|
298
|
+
}
|
|
299
|
+
// Gather additional context from all registered context helpers.
|
|
300
|
+
// TODO: This snapshot is captured once and reused for the entire multi-round
|
|
301
|
+
// tool loop. If interactables change during streaming (e.g. user interactions),
|
|
302
|
+
// continuations will send stale context. Re-gather before each continuation
|
|
303
|
+
// if freshness matters.
|
|
304
|
+
const helperContexts = await getAdditionalContext();
|
|
305
|
+
const additionalContext = {};
|
|
306
|
+
for (const helperContext of helperContexts) {
|
|
307
|
+
additionalContext[helperContext.name] = helperContext.context;
|
|
308
|
+
}
|
|
140
309
|
// Create the run stream
|
|
141
310
|
const { stream, initialThreadId } = await createRunStream({
|
|
142
311
|
client,
|
|
143
|
-
threadId,
|
|
312
|
+
threadId: apiThreadId,
|
|
144
313
|
message,
|
|
145
314
|
registry,
|
|
146
315
|
userKey,
|
|
316
|
+
previousRunId,
|
|
317
|
+
additionalContext,
|
|
147
318
|
});
|
|
148
319
|
let actualThreadId = initialThreadId;
|
|
149
320
|
let runId;
|
|
@@ -162,6 +333,12 @@ export function useTamboV1SendMessage(threadId) {
|
|
|
162
333
|
if (event.type === EventType.RUN_STARTED) {
|
|
163
334
|
runId = event.runId;
|
|
164
335
|
actualThreadId ??= event.threadId;
|
|
336
|
+
// For threads with no ID at all: add user message now that we have the real threadId
|
|
337
|
+
// Note: temp thread migration (temp_xxx -> real ID) is handled automatically
|
|
338
|
+
// by the reducer when it sees RUN_STARTED with a different threadId
|
|
339
|
+
if (!threadId && userMessageText && userMessageId) {
|
|
340
|
+
dispatchUserMessage(dispatch, actualThreadId, userMessageId, userMessageText);
|
|
341
|
+
}
|
|
165
342
|
}
|
|
166
343
|
else if (!actualThreadId) {
|
|
167
344
|
throw new Error(`Expected first event to be RUN_STARTED with threadId, got: ${event.type}`);
|
|
@@ -186,7 +363,7 @@ export function useTamboV1SendMessage(threadId) {
|
|
|
186
363
|
if (!runId || !actualThreadId) {
|
|
187
364
|
throw new Error("Cannot continue run after awaiting_input: missing runId or threadId");
|
|
188
365
|
}
|
|
189
|
-
|
|
366
|
+
const { stream: continuationStream, toolResults } = await executeToolsAndContinue({
|
|
190
367
|
event: pendingAwaitingInput,
|
|
191
368
|
toolTracker,
|
|
192
369
|
registry,
|
|
@@ -194,9 +371,16 @@ export function useTamboV1SendMessage(threadId) {
|
|
|
194
371
|
threadId: actualThreadId,
|
|
195
372
|
runId,
|
|
196
373
|
userKey,
|
|
374
|
+
additionalContext,
|
|
197
375
|
});
|
|
376
|
+
dispatchToolResults(dispatch, actualThreadId, toolResults);
|
|
377
|
+
currentStream = continuationStream;
|
|
198
378
|
}
|
|
199
|
-
return {
|
|
379
|
+
return {
|
|
380
|
+
threadId: actualThreadId,
|
|
381
|
+
preMutationMessageCount,
|
|
382
|
+
threadAlreadyHasTitle,
|
|
383
|
+
};
|
|
200
384
|
}
|
|
201
385
|
catch (error) {
|
|
202
386
|
// Dispatch a synthetic RUN_ERROR event to clean up thread state
|
|
@@ -217,10 +401,13 @@ export function useTamboV1SendMessage(threadId) {
|
|
|
217
401
|
}
|
|
218
402
|
},
|
|
219
403
|
onSuccess: async (result) => {
|
|
220
|
-
// Invalidate thread queries to refetch updated state
|
|
221
404
|
await queryClient.invalidateQueries({
|
|
222
405
|
queryKey: ["v1-threads", result.threadId],
|
|
223
406
|
});
|
|
407
|
+
if (autoGenerateThreadName &&
|
|
408
|
+
shouldGenerateThreadName(result.threadId, result.threadAlreadyHasTitle, result.preMutationMessageCount, autoGenerateNameThreshold)) {
|
|
409
|
+
await generateThreadName(client, dispatch, queryClient, result.threadId);
|
|
410
|
+
}
|
|
224
411
|
},
|
|
225
412
|
onError: (error) => {
|
|
226
413
|
console.error("[useTamboV1SendMessage] Mutation failed:", error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-tambo-v1-send-message.js","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-send-message.ts"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\n/**\n * Send Message Hook for v1 API\n *\n * React Query mutation hook for sending messages and handling streaming responses.\n */\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { useContext } from \"react\";\nimport { EventType, type RunErrorEvent } from \"@ag-ui/core\";\nimport { asTamboCustomEvent, type RunAwaitingInputEvent } from \"../types/event\";\nimport type TamboAI from \"@tambo-ai/typescript-sdk\";\nimport type { Stream } from \"@tambo-ai/typescript-sdk/core/streaming\";\nimport { useTamboClient } from \"../../providers/tambo-client-provider\";\nimport {\n TamboRegistryContext,\n type TamboRegistryContext as TamboRegistry,\n} from \"../../providers/tambo-registry-provider\";\nimport { useStreamDispatch } from \"../providers/tambo-v1-stream-context\";\nimport { useTamboV1Config } from \"../providers/tambo-v1-provider\";\nimport type { InputMessage } from \"../types/message\";\nimport {\n toAvailableComponents,\n toAvailableTools,\n} from \"../utils/registry-conversion\";\nimport { handleEventStream } from \"../utils/stream-handler\";\nimport { executeAllPendingTools } from \"../utils/tool-executor\";\nimport { ToolCallTracker } from \"../utils/tool-call-tracker\";\n\n/**\n * Options for sending a message\n */\nexport interface SendMessageOptions {\n /**\n * The message to send\n */\n message: InputMessage;\n\n /**\n * Enable debug logging for the stream\n */\n debug?: boolean;\n}\n\n/**\n * Parameters for creating a run stream\n */\nexport interface CreateRunStreamParams {\n client: TamboAI;\n threadId: string | undefined;\n message: InputMessage;\n registry: TamboRegistry;\n userKey: string | undefined;\n}\n\n/**\n * Stream types from the SDK\n */\ntype RunStream = Stream<TamboAI.Threads.Runs.RunRunResponse>;\ntype CreateStream = Stream<TamboAI.Threads.Runs.RunCreateResponse>;\n\n/**\n * Result from creating a run stream\n */\nexport interface CreateRunStreamResult {\n stream: RunStream | CreateStream;\n initialThreadId: string | undefined;\n}\n\n/**\n * Parameters for executing tools and continuing the run\n */\ninterface ExecuteToolsParams {\n event: RunAwaitingInputEvent;\n toolTracker: ToolCallTracker;\n registry: TamboRegistry;\n client: TamboAI;\n threadId: string;\n runId: string;\n userKey: string | undefined;\n}\n\n/**\n * Executes pending tools and returns a continuation stream.\n *\n * This function does NOT process the continuation stream - it just executes\n * the tools and returns the new stream for the caller to process. This enables\n * the flat loop pattern that correctly handles multi-round tool execution.\n * @param params - The parameters for tool execution\n * @returns The continuation stream to process\n */\nasync function executeToolsAndContinue(\n params: ExecuteToolsParams,\n): Promise<RunStream> {\n const { event, toolTracker, registry, client, threadId, runId, userKey } =\n params;\n\n const { pendingToolCallIds } = event.value;\n const toolCallsToExecute = toolTracker.getToolCallsById(pendingToolCallIds);\n\n // Execute tools\n const toolResults = await executeAllPendingTools(\n toolCallsToExecute,\n registry.toolRegistry,\n );\n\n // Clear executed tool calls before continuing\n toolTracker.clearToolCalls(pendingToolCallIds);\n\n // Return the continuation stream (caller will process it)\n return await client.threads.runs.run(threadId, {\n message: {\n role: \"user\",\n content: toolResults,\n },\n previousRunId: runId,\n availableComponents: toAvailableComponents(registry.componentList),\n tools: toAvailableTools(registry.toolRegistry),\n userKey,\n });\n}\n\n/**\n * Creates a run stream by calling the appropriate API method.\n *\n * If threadId is provided, runs on existing thread via client.threads.runs.run().\n * If no threadId, creates new thread via client.threads.runs.create().\n * @param params - The parameters for creating the run stream\n * @returns The stream and initial thread ID (undefined if creating new thread)\n */\nexport async function createRunStream(\n params: CreateRunStreamParams,\n): Promise<CreateRunStreamResult> {\n const { client, threadId, message, registry, userKey } = params;\n\n // Convert registry components/tools to v1 API format\n const availableComponents = toAvailableComponents(registry.componentList);\n const availableTools = toAvailableTools(registry.toolRegistry);\n\n if (threadId) {\n // Run on existing thread\n const stream = await client.threads.runs.run(threadId, {\n message,\n availableComponents,\n tools: availableTools,\n userKey,\n });\n return { stream, initialThreadId: threadId };\n } else {\n // Create new thread\n const stream = await client.threads.runs.create({\n message,\n availableComponents,\n tools: availableTools,\n thread: userKey ? { userKey } : undefined,\n });\n // threadId will be extracted from first event (RUN_STARTED)\n return { stream, initialThreadId: undefined };\n }\n}\n\n/**\n * Hook to send a message and handle streaming responses.\n *\n * This hook handles two scenarios:\n * - If threadId provided: runs on existing thread via client.threads.runs.run()\n * - If no threadId: creates new thread via client.threads.runs.create()\n *\n * The hook:\n * - Sends a user message to the API\n * - Streams AG-UI events in real-time\n * - Dispatches events to the stream reducer\n * - Extracts threadId from events when creating new thread\n * - Handles tool execution (Phase 6)\n * - Invalidates thread queries on completion\n * @param threadId - Optional thread ID to send message to. If not provided, creates new thread\n * @returns React Query mutation object with threadId in mutation result\n * @example\n * ```tsx\n * function ChatInput({ threadId }: { threadId?: string }) {\n * const sendMessage = useTamboV1SendMessage(threadId);\n *\n * const handleSubmit = async (text: string) => {\n * const result = await sendMessage.mutateAsync({\n * message: {\n * role: \"user\",\n * content: [{ type: \"text\", text }],\n * },\n * });\n *\n * // If threadId wasn't provided, a new thread was created\n * if (!threadId) {\n * console.log(\"Created thread:\", result.threadId);\n * }\n * };\n *\n * return (\n * <div>\n * <input onSubmit={handleSubmit} />\n * {sendMessage.isPending && <Spinner />}\n * </div>\n * );\n * }\n * ```\n */\nexport function useTamboV1SendMessage(threadId?: string) {\n const client = useTamboClient();\n const dispatch = useStreamDispatch();\n const { userKey } = useTamboV1Config();\n const registry = useContext(TamboRegistryContext);\n const queryClient = useQueryClient();\n\n if (!registry) {\n throw new Error(\n \"useTamboV1SendMessage must be used within TamboRegistryProvider\",\n );\n }\n\n return useMutation({\n mutationFn: async (options: SendMessageOptions) => {\n const { message, debug = false } = options;\n\n const toolTracker = new ToolCallTracker();\n\n // Create the run stream\n const { stream, initialThreadId } = await createRunStream({\n client,\n threadId,\n message,\n registry,\n userKey,\n });\n\n let actualThreadId = initialThreadId;\n let runId: string | undefined;\n let currentStream: CreateRunStreamResult[\"stream\"] = stream;\n\n try {\n // Outer loop handles stream replacement for multi-round tool execution.\n // When we hit awaiting_input, we execute tools, get a new stream, and continue.\n // This flat loop pattern correctly handles tool→AI→tool→AI chains.\n while (true) {\n let pendingAwaitingInput: RunAwaitingInputEvent | undefined;\n\n // Process current stream until completion or awaiting_input\n for await (const event of handleEventStream(currentStream, {\n debug,\n })) {\n // Extract threadId and runId from RUN_STARTED event\n if (event.type === EventType.RUN_STARTED) {\n runId = event.runId;\n actualThreadId ??= event.threadId;\n } else if (!actualThreadId) {\n throw new Error(\n `Expected first event to be RUN_STARTED with threadId, got: ${event.type}`,\n );\n }\n\n toolTracker.handleEvent(event);\n dispatch({ type: \"EVENT\", event, threadId: actualThreadId });\n\n // Check for awaiting_input - if found, break to execute tools\n if (event.type === EventType.CUSTOM) {\n const customEvent = asTamboCustomEvent(event);\n if (customEvent?.name === \"tambo.run.awaiting_input\") {\n pendingAwaitingInput = customEvent;\n break; // Exit stream loop to handle tool execution\n }\n }\n }\n\n // If stream finished without awaiting_input, we're done\n if (!pendingAwaitingInput) {\n break;\n }\n\n // Execute tools and get continuation stream\n // These checks should never fail since awaiting_input comes after RUN_STARTED\n if (!runId || !actualThreadId) {\n throw new Error(\n \"Cannot continue run after awaiting_input: missing runId or threadId\",\n );\n }\n\n currentStream = await executeToolsAndContinue({\n event: pendingAwaitingInput,\n toolTracker,\n registry,\n client,\n threadId: actualThreadId,\n runId,\n userKey,\n });\n }\n\n return { threadId: actualThreadId };\n } catch (error) {\n // Dispatch a synthetic RUN_ERROR event to clean up thread state\n // This ensures the thread doesn't stay stuck in \"streaming\" status\n if (actualThreadId) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown streaming error\";\n const errorEvent: RunErrorEvent = {\n type: EventType.RUN_ERROR,\n message: errorMessage,\n };\n dispatch({\n type: \"EVENT\",\n event: errorEvent,\n threadId: actualThreadId,\n });\n }\n throw error;\n }\n },\n onSuccess: async (result) => {\n // Invalidate thread queries to refetch updated state\n await queryClient.invalidateQueries({\n queryKey: [\"v1-threads\", result.threadId],\n });\n },\n onError: (error) => {\n console.error(\"[useTamboV1SendMessage] Mutation failed:\", error);\n },\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"use-tambo-v1-send-message.js","sourceRoot":"","sources":["../../../src/v1/hooks/use-tambo-v1-send-message.ts"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\n/**\n * Send Message Hook for v1 API\n *\n * React Query mutation hook for sending messages and handling streaming responses.\n */\n\nimport React, { useContext } from \"react\";\nimport { EventType, type RunErrorEvent } from \"@ag-ui/core\";\nimport { asTamboCustomEvent, type RunAwaitingInputEvent } from \"../types/event\";\nimport type TamboAI from \"@tambo-ai/typescript-sdk\";\nimport type { Stream } from \"@tambo-ai/typescript-sdk/core/streaming\";\nimport {\n useTamboClient,\n useTamboQueryClient,\n} from \"../../providers/tambo-client-provider\";\nimport { useTamboMutation } from \"../../hooks/react-query-hooks\";\nimport {\n TamboRegistryContext,\n type TamboRegistryContext as TamboRegistry,\n} from \"../../providers/tambo-registry-provider\";\nimport {\n useStreamDispatch,\n useStreamState,\n} from \"../providers/tambo-v1-stream-context\";\nimport { useTamboV1Config } from \"../providers/tambo-v1-provider\";\nimport { useTamboContextHelpers } from \"../../providers/tambo-context-helpers-provider\";\nimport type { InputMessage } from \"../types/message\";\nimport {\n isPlaceholderThreadId,\n type StreamAction,\n} from \"../utils/event-accumulator\";\nimport {\n toAvailableComponents,\n toAvailableTools,\n} from \"../utils/registry-conversion\";\nimport { handleEventStream } from \"../utils/stream-handler\";\nimport { executeAllPendingTools } from \"../utils/tool-executor\";\nimport type { ToolResultContent } from \"@tambo-ai/typescript-sdk/resources/threads/threads\";\nimport { ToolCallTracker } from \"../utils/tool-call-tracker\";\n\n/**\n * Dispatches synthetic AG-UI events to show a user message in the thread.\n * @param dispatch - Stream state dispatcher\n * @param targetThreadId - Thread to add the message to\n * @param messageId - Stable ID for the user message\n * @param messageText - Text content of the message\n */\nfunction dispatchUserMessage(\n dispatch: React.Dispatch<StreamAction>,\n targetThreadId: string,\n messageId: string,\n messageText: string,\n): void {\n dispatch({\n type: \"EVENT\",\n threadId: targetThreadId,\n event: {\n type: EventType.TEXT_MESSAGE_START,\n messageId,\n role: \"user\" as const,\n },\n });\n\n dispatch({\n type: \"EVENT\",\n threadId: targetThreadId,\n event: {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId,\n delta: messageText,\n },\n });\n\n dispatch({\n type: \"EVENT\",\n threadId: targetThreadId,\n event: {\n type: EventType.TEXT_MESSAGE_END,\n messageId,\n },\n });\n}\n\n/**\n * Dispatches synthetic events for tool results as optimistic local state.\n * The server doesn't echo these back for client-side tools.\n * @param dispatch - Stream state dispatcher\n * @param targetThreadId - Thread to add results to\n * @param toolResults - Tool execution results to dispatch\n */\nfunction dispatchToolResults(\n dispatch: React.Dispatch<StreamAction>,\n targetThreadId: string,\n toolResults: ToolResultContent[],\n): void {\n if (toolResults.length === 0) return;\n\n const toolResultMessageId = `msg_tool_result_${Date.now()}`;\n\n dispatch({\n type: \"EVENT\",\n threadId: targetThreadId,\n event: {\n type: EventType.TEXT_MESSAGE_START,\n messageId: toolResultMessageId,\n role: \"user\" as const,\n },\n });\n\n for (const result of toolResults) {\n dispatch({\n type: \"EVENT\",\n threadId: targetThreadId,\n event: {\n type: EventType.TOOL_CALL_RESULT,\n toolCallId: result.toolUseId,\n messageId: toolResultMessageId,\n content:\n result.content\n .filter((c) => c.type === \"text\")\n .map((c) => (c as { type: \"text\"; text: string }).text)\n .join(\"\") || JSON.stringify(result.content),\n },\n });\n }\n\n dispatch({\n type: \"EVENT\",\n threadId: targetThreadId,\n event: {\n type: EventType.TEXT_MESSAGE_END,\n messageId: toolResultMessageId,\n },\n });\n}\n\n/**\n * Checks whether a thread name should be auto-generated based on config\n * and the current thread state.\n * @param threadId - The thread ID (undefined or placeholder means no)\n * @param threadAlreadyHasTitle - Whether the thread already has a title\n * @param preMutationMessageCount - Message count before the current mutation\n * @param autoGenerateNameThreshold - Minimum message count to trigger generation\n * @returns Whether to generate a thread name\n */\nfunction shouldGenerateThreadName(\n threadId: string | undefined,\n threadAlreadyHasTitle: boolean,\n preMutationMessageCount: number,\n autoGenerateNameThreshold: number,\n): threadId is string {\n return (\n !threadAlreadyHasTitle &&\n !!threadId &&\n !isPlaceholderThreadId(threadId) &&\n // +2 accounts for the user message and assistant response just added\n preMutationMessageCount + 2 >= autoGenerateNameThreshold\n );\n}\n\n/**\n * Generates a thread name via the beta API, dispatches the title update,\n * and invalidates the thread list cache. Errors are logged, never thrown.\n * @param client - The Tambo API client\n * @param dispatch - Stream state dispatcher\n * @param queryClient - React Query client for cache invalidation\n * @param threadId - The thread to generate a name for\n */\nasync function generateThreadName(\n client: TamboAI,\n dispatch: React.Dispatch<StreamAction>,\n queryClient: ReturnType<typeof useTamboQueryClient>,\n threadId: string,\n): Promise<void> {\n try {\n const threadWithName = await client.beta.threads.generateName(threadId);\n if (threadWithName.name) {\n dispatch({\n type: \"UPDATE_THREAD_TITLE\",\n threadId,\n title: threadWithName.name,\n });\n await queryClient.invalidateQueries({\n queryKey: [\"v1-threads\", \"list\"],\n });\n }\n } catch (error) {\n console.error(\n \"[useTamboV1SendMessage] Failed to auto-generate thread name:\",\n error,\n );\n }\n}\n\n/**\n * Options for sending a message\n */\nexport interface SendMessageOptions {\n /**\n * The message to send\n */\n message: InputMessage;\n\n /**\n * User message text for optimistic display.\n * If provided, synthetic AG-UI events will be dispatched to show\n * the user message in the thread immediately after getting the threadId.\n */\n userMessageText?: string;\n\n /**\n * Enable debug logging for the stream\n */\n debug?: boolean;\n}\n\n/**\n * Parameters for creating a run stream\n */\nexport interface CreateRunStreamParams {\n client: TamboAI;\n threadId: string | undefined;\n message: InputMessage;\n registry: TamboRegistry;\n userKey: string | undefined;\n /**\n * Previous run ID for continuing a thread with existing messages.\n * Required when threadId is provided and the thread has previous runs.\n */\n previousRunId: string | undefined;\n /**\n * Additional context gathered from context helpers (including interactables).\n * Merged into the message's additionalContext before sending.\n */\n additionalContext?: Record<string, unknown>;\n}\n\n/**\n * Stream types from the SDK\n */\ntype RunStream = Stream<TamboAI.Threads.Runs.RunRunResponse>;\ntype CreateStream = Stream<TamboAI.Threads.Runs.RunCreateResponse>;\n\n/**\n * Result from creating a run stream\n */\nexport interface CreateRunStreamResult {\n stream: RunStream | CreateStream;\n initialThreadId: string | undefined;\n}\n\n/**\n * Parameters for executing tools and continuing the run\n */\ninterface ExecuteToolsParams {\n event: RunAwaitingInputEvent;\n toolTracker: ToolCallTracker;\n registry: TamboRegistry;\n client: TamboAI;\n threadId: string;\n runId: string;\n userKey: string | undefined;\n additionalContext?: Record<string, unknown>;\n}\n\n/**\n * Result from executing tools and continuing the run\n */\ninterface ExecuteToolsResult {\n stream: RunStream;\n toolResults: ToolResultContent[];\n}\n\n/**\n * Executes pending tools and returns a continuation stream.\n *\n * This function does NOT process the continuation stream - it just executes\n * the tools and returns the new stream for the caller to process. This enables\n * the flat loop pattern that correctly handles multi-round tool execution.\n * @param params - The parameters for tool execution\n * @returns The continuation stream and tool results for optimistic local state updates\n */\nasync function executeToolsAndContinue(\n params: ExecuteToolsParams,\n): Promise<ExecuteToolsResult> {\n const {\n event,\n toolTracker,\n registry,\n client,\n threadId,\n runId,\n userKey,\n additionalContext,\n } = params;\n\n const pendingToolCallIds = event.value.pendingToolCalls.map(\n (tc) => tc.toolCallId,\n );\n const toolCallsToExecute = toolTracker.getToolCallsById(pendingToolCallIds);\n\n // Execute tools\n const toolResults = await executeAllPendingTools(\n toolCallsToExecute,\n registry.toolRegistry,\n );\n\n // Clear executed tool calls before continuing\n toolTracker.clearToolCalls(pendingToolCallIds);\n\n // Return the continuation stream and tool results\n const stream = await client.threads.runs.run(threadId, {\n message: {\n role: \"user\",\n content: toolResults,\n additionalContext,\n },\n previousRunId: runId,\n availableComponents: toAvailableComponents(registry.componentList),\n tools: toAvailableTools(registry.toolRegistry),\n userKey,\n });\n\n return { stream, toolResults };\n}\n\n/**\n * Creates a run stream by calling the appropriate API method.\n *\n * If threadId is provided, runs on existing thread via client.threads.runs.run().\n * If no threadId, creates new thread via client.threads.runs.create().\n * @param params - The parameters for creating the run stream\n * @returns The stream and initial thread ID (undefined if creating new thread)\n */\nexport async function createRunStream(\n params: CreateRunStreamParams,\n): Promise<CreateRunStreamResult> {\n const {\n client,\n threadId,\n message,\n registry,\n userKey,\n previousRunId,\n additionalContext,\n } = params;\n\n // Merge helper context with any caller-provided additionalContext on the message\n const mergedContext =\n additionalContext || message.additionalContext\n ? {\n ...((message.additionalContext as Record<string, unknown>) ?? {}),\n ...additionalContext,\n }\n : undefined;\n const messageWithContext: InputMessage = mergedContext\n ? { ...message, additionalContext: mergedContext }\n : message;\n\n // Convert registry components/tools to v1 API format\n const availableComponents = toAvailableComponents(registry.componentList);\n const availableTools = toAvailableTools(registry.toolRegistry);\n\n if (threadId) {\n // Run on existing thread\n const stream = await client.threads.runs.run(threadId, {\n message: messageWithContext,\n availableComponents,\n tools: availableTools,\n userKey,\n previousRunId,\n });\n return { stream, initialThreadId: threadId };\n } else {\n // Create new thread\n const stream = await client.threads.runs.create({\n message: messageWithContext,\n availableComponents,\n tools: availableTools,\n thread: userKey ? { userKey } : undefined,\n });\n // threadId will be extracted from first event (RUN_STARTED)\n return { stream, initialThreadId: undefined };\n }\n}\n\n/**\n * Hook to send a message and handle streaming responses.\n *\n * This hook handles two scenarios:\n * - If threadId provided: runs on existing thread via client.threads.runs.run()\n * - If no threadId: creates new thread via client.threads.runs.create()\n *\n * The hook:\n * - Sends a user message to the API\n * - Streams AG-UI events in real-time\n * - Dispatches events to the stream reducer\n * - Extracts threadId from events when creating new thread\n * - Handles tool execution (Phase 6)\n * - Invalidates thread queries on completion\n * @param threadId - Optional thread ID to send message to. If not provided, creates new thread\n * @returns React Query mutation object with threadId in mutation result\n * @example\n * ```tsx\n * function ChatInput({ threadId }: { threadId?: string }) {\n * const sendMessage = useTamboV1SendMessage(threadId);\n *\n * const handleSubmit = async (text: string) => {\n * const result = await sendMessage.mutateAsync({\n * message: {\n * role: \"user\",\n * content: [{ type: \"text\", text }],\n * },\n * });\n *\n * // If threadId wasn't provided, a new thread was created\n * if (!threadId) {\n * console.log(\"Created thread:\", result.threadId);\n * }\n * };\n *\n * return (\n * <div>\n * <input onSubmit={handleSubmit} />\n * {sendMessage.isPending && <Spinner />}\n * </div>\n * );\n * }\n * ```\n */\nexport function useTamboV1SendMessage(threadId?: string) {\n const client = useTamboClient();\n const dispatch = useStreamDispatch();\n const streamState = useStreamState();\n const {\n userKey,\n autoGenerateThreadName = true,\n autoGenerateNameThreshold = 3,\n } = useTamboV1Config();\n const registry = useContext(TamboRegistryContext);\n const queryClient = useTamboQueryClient();\n const { getAdditionalContext } = useTamboContextHelpers();\n\n if (!registry) {\n throw new Error(\n \"useTamboV1SendMessage must be used within TamboRegistryProvider\",\n );\n }\n\n // Placeholder ID isn't a valid API thread ID - treat as new thread creation\n const isNewThread = isPlaceholderThreadId(threadId);\n const apiThreadId = isNewThread ? undefined : threadId;\n\n // Get previousRunId from the thread's streaming state (if thread exists and has messages)\n const threadState = apiThreadId\n ? streamState.threadMap[apiThreadId]\n : undefined;\n const previousRunId = threadState?.streaming.runId;\n\n return useTamboMutation({\n mutationFn: async (options: SendMessageOptions) => {\n const { message, userMessageText, debug = false } = options;\n\n // Capture pre-mutation state for auto thread name generation\n const existingThread = streamState.threadMap[apiThreadId ?? \"\"];\n const preMutationMessageCount =\n existingThread?.thread.messages.length ?? 0;\n const threadAlreadyHasTitle = !!existingThread?.thread.title;\n\n const toolTracker = new ToolCallTracker();\n\n // Generate a stable message ID for the user message\n const userMessageId = userMessageText\n ? `user_msg_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`\n : undefined;\n\n // Add user message immediately for instant feedback\n // Use threadId (which could be temp_xxx for new threads) for display\n if (threadId && userMessageText && userMessageId) {\n dispatchUserMessage(dispatch, threadId, userMessageId, userMessageText);\n }\n\n // Gather additional context from all registered context helpers.\n // TODO: This snapshot is captured once and reused for the entire multi-round\n // tool loop. If interactables change during streaming (e.g. user interactions),\n // continuations will send stale context. Re-gather before each continuation\n // if freshness matters.\n const helperContexts = await getAdditionalContext();\n const additionalContext: Record<string, unknown> = {};\n for (const helperContext of helperContexts) {\n additionalContext[helperContext.name] = helperContext.context;\n }\n\n // Create the run stream\n const { stream, initialThreadId } = await createRunStream({\n client,\n threadId: apiThreadId,\n message,\n registry,\n userKey,\n previousRunId,\n additionalContext,\n });\n\n let actualThreadId = initialThreadId;\n let runId: string | undefined;\n let currentStream: CreateRunStreamResult[\"stream\"] = stream;\n\n try {\n // Outer loop handles stream replacement for multi-round tool execution.\n // When we hit awaiting_input, we execute tools, get a new stream, and continue.\n // This flat loop pattern correctly handles tool→AI→tool→AI chains.\n while (true) {\n let pendingAwaitingInput: RunAwaitingInputEvent | undefined;\n\n // Process current stream until completion or awaiting_input\n for await (const event of handleEventStream(currentStream, {\n debug,\n })) {\n // Extract threadId and runId from RUN_STARTED event\n if (event.type === EventType.RUN_STARTED) {\n runId = event.runId;\n actualThreadId ??= event.threadId;\n\n // For threads with no ID at all: add user message now that we have the real threadId\n // Note: temp thread migration (temp_xxx -> real ID) is handled automatically\n // by the reducer when it sees RUN_STARTED with a different threadId\n if (!threadId && userMessageText && userMessageId) {\n dispatchUserMessage(\n dispatch,\n actualThreadId,\n userMessageId,\n userMessageText,\n );\n }\n } else if (!actualThreadId) {\n throw new Error(\n `Expected first event to be RUN_STARTED with threadId, got: ${event.type}`,\n );\n }\n\n toolTracker.handleEvent(event);\n dispatch({ type: \"EVENT\", event, threadId: actualThreadId });\n\n // Check for awaiting_input - if found, break to execute tools\n if (event.type === EventType.CUSTOM) {\n const customEvent = asTamboCustomEvent(event);\n if (customEvent?.name === \"tambo.run.awaiting_input\") {\n pendingAwaitingInput = customEvent;\n break; // Exit stream loop to handle tool execution\n }\n }\n }\n\n // If stream finished without awaiting_input, we're done\n if (!pendingAwaitingInput) {\n break;\n }\n\n // Execute tools and get continuation stream\n // These checks should never fail since awaiting_input comes after RUN_STARTED\n if (!runId || !actualThreadId) {\n throw new Error(\n \"Cannot continue run after awaiting_input: missing runId or threadId\",\n );\n }\n\n const { stream: continuationStream, toolResults } =\n await executeToolsAndContinue({\n event: pendingAwaitingInput,\n toolTracker,\n registry,\n client,\n threadId: actualThreadId,\n runId,\n userKey,\n additionalContext,\n });\n\n dispatchToolResults(dispatch, actualThreadId, toolResults);\n\n currentStream = continuationStream;\n }\n\n return {\n threadId: actualThreadId,\n preMutationMessageCount,\n threadAlreadyHasTitle,\n };\n } catch (error) {\n // Dispatch a synthetic RUN_ERROR event to clean up thread state\n // This ensures the thread doesn't stay stuck in \"streaming\" status\n if (actualThreadId) {\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown streaming error\";\n const errorEvent: RunErrorEvent = {\n type: EventType.RUN_ERROR,\n message: errorMessage,\n };\n dispatch({\n type: \"EVENT\",\n event: errorEvent,\n threadId: actualThreadId,\n });\n }\n throw error;\n }\n },\n onSuccess: async (result) => {\n await queryClient.invalidateQueries({\n queryKey: [\"v1-threads\", result.threadId],\n });\n\n if (\n autoGenerateThreadName &&\n shouldGenerateThreadName(\n result.threadId,\n result.threadAlreadyHasTitle,\n result.preMutationMessageCount,\n autoGenerateNameThreshold,\n )\n ) {\n await generateThreadName(\n client,\n dispatch,\n queryClient,\n result.threadId,\n );\n }\n },\n onError: (error) => {\n console.error(\"[useTamboV1SendMessage] Mutation failed:\", error);\n },\n });\n}\n"]}
|