@tambo-ai/react 0.65.3 → 0.66.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 +120 -20
- package/dist/{providers/hoc → hoc}/with-tambo-interactable.d.ts +2 -2
- package/dist/hoc/with-tambo-interactable.d.ts.map +1 -0
- package/dist/{providers/hoc → hoc}/with-tambo-interactable.js +29 -2
- package/dist/hoc/with-tambo-interactable.js.map +1 -0
- package/dist/hoc/with-tambo-interactable.test.d.ts +2 -0
- package/dist/hoc/with-tambo-interactable.test.d.ts.map +1 -0
- package/dist/hoc/with-tambo-interactable.test.js +192 -0
- package/dist/hoc/with-tambo-interactable.test.js.map +1 -0
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/use-current-message.d.ts +51 -7
- package/dist/hooks/use-current-message.d.ts.map +1 -1
- package/dist/hooks/use-current-message.js +50 -6
- package/dist/hooks/use-current-message.js.map +1 -1
- package/dist/hooks/use-current-message.test.d.ts +2 -0
- package/dist/hooks/use-current-message.test.d.ts.map +1 -0
- package/dist/hooks/use-current-message.test.js +264 -0
- package/dist/hooks/use-current-message.test.js.map +1 -0
- package/dist/index.d.ts +10 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +2 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/mcp-hooks.d.ts +77 -6
- package/dist/mcp/mcp-hooks.d.ts.map +1 -1
- package/dist/mcp/mcp-hooks.js +104 -40
- package/dist/mcp/mcp-hooks.js.map +1 -1
- package/dist/mcp/mcp-hooks.test.js +83 -18
- 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 +2 -1
- package/dist/mcp/tambo-mcp-provider.js.map +1 -1
- package/dist/model/component-metadata.d.ts +444 -14
- package/dist/model/component-metadata.d.ts.map +1 -1
- package/dist/model/component-metadata.js.map +1 -1
- package/dist/model/generate-component-response.d.ts +12 -1
- package/dist/model/generate-component-response.d.ts.map +1 -1
- package/dist/model/generate-component-response.js.map +1 -1
- package/dist/model/resource-info.d.ts +55 -0
- package/dist/model/resource-info.d.ts.map +1 -0
- package/dist/model/resource-info.js +3 -0
- package/dist/model/resource-info.js.map +1 -0
- 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-component-provider.d.ts +4 -4
- package/dist/providers/tambo-component-provider.d.ts.map +1 -1
- package/dist/providers/tambo-component-provider.js.map +1 -1
- package/dist/providers/tambo-interactable-provider-partial-updates.test.js +87 -87
- package/dist/providers/tambo-interactable-provider-partial-updates.test.js.map +1 -1
- package/dist/providers/tambo-interactable-provider.d.ts +2 -3
- package/dist/providers/tambo-interactable-provider.d.ts.map +1 -1
- package/dist/providers/tambo-interactable-provider.js +47 -41
- package/dist/providers/tambo-interactable-provider.js.map +1 -1
- package/dist/providers/tambo-interactables-additional-context-edge-cases.test.js +9 -9
- package/dist/providers/tambo-interactables-additional-context-edge-cases.test.js.map +1 -1
- package/dist/providers/tambo-interactables-additional-context.test.js +11 -11
- package/dist/providers/tambo-interactables-additional-context.test.js.map +1 -1
- package/dist/providers/tambo-registry-provider.d.ts +28 -7
- package/dist/providers/tambo-registry-provider.d.ts.map +1 -1
- package/dist/providers/tambo-registry-provider.js +70 -181
- package/dist/providers/tambo-registry-provider.js.map +1 -1
- package/dist/providers/tambo-registry-provider.test.js +152 -30
- package/dist/providers/tambo-registry-provider.test.js.map +1 -1
- package/dist/providers/tambo-registry-schema-compat.test.d.ts +2 -0
- package/dist/providers/tambo-registry-schema-compat.test.d.ts.map +1 -0
- package/dist/providers/tambo-registry-schema-compat.test.js +616 -0
- package/dist/providers/tambo-registry-schema-compat.test.js.map +1 -0
- package/dist/providers/tambo-stubs.d.ts +2 -2
- package/dist/providers/tambo-stubs.d.ts.map +1 -1
- package/dist/providers/tambo-stubs.js +5 -0
- package/dist/providers/tambo-stubs.js.map +1 -1
- package/dist/providers/tambo-thread-input-provider.d.ts +1 -0
- package/dist/providers/tambo-thread-input-provider.d.ts.map +1 -1
- package/dist/providers/tambo-thread-input-provider.js +3 -3
- package/dist/providers/tambo-thread-input-provider.js.map +1 -1
- package/dist/providers/tambo-thread-provider.d.ts.map +1 -1
- package/dist/providers/tambo-thread-provider.js.map +1 -1
- package/dist/providers/tambo-thread-provider.test.js +32 -36
- package/dist/providers/tambo-thread-provider.test.js.map +1 -1
- package/dist/schema/index.d.ts +6 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +18 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/json-schema.d.ts +35 -0
- package/dist/schema/json-schema.d.ts.map +1 -0
- package/dist/schema/json-schema.js +103 -0
- package/dist/schema/json-schema.js.map +1 -0
- package/dist/schema/schema.d.ts +66 -0
- package/dist/schema/schema.d.ts.map +1 -0
- package/dist/schema/schema.js +192 -0
- package/dist/schema/schema.js.map +1 -0
- package/dist/schema/schema.test.d.ts +2 -0
- package/dist/schema/schema.test.d.ts.map +1 -0
- package/dist/schema/schema.test.js +41 -0
- package/dist/schema/schema.test.js.map +1 -0
- package/dist/schema/standard-schema.d.ts +21 -0
- package/dist/schema/standard-schema.d.ts.map +1 -0
- package/dist/schema/standard-schema.js +37 -0
- package/dist/schema/standard-schema.js.map +1 -0
- package/dist/schema/validate.d.ts +14 -0
- package/dist/schema/validate.d.ts.map +1 -0
- package/dist/schema/validate.js +148 -0
- package/dist/schema/validate.js.map +1 -0
- package/dist/schema/validate.test.d.ts +2 -0
- package/dist/schema/validate.test.d.ts.map +1 -0
- package/dist/schema/validate.test.js +128 -0
- package/dist/schema/validate.test.js.map +1 -0
- package/dist/schema/zod.d.ts +54 -0
- package/dist/schema/zod.d.ts.map +1 -0
- package/dist/schema/zod.js +135 -0
- package/dist/schema/zod.js.map +1 -0
- package/dist/testing/tools.d.ts +29 -15
- package/dist/testing/tools.d.ts.map +1 -1
- package/dist/testing/tools.js +64 -19
- package/dist/testing/tools.js.map +1 -1
- package/dist/util/generate-component.d.ts.map +1 -1
- package/dist/util/generate-component.js +3 -3
- package/dist/util/generate-component.js.map +1 -1
- package/dist/util/mcp-server-utils.d.ts +23 -0
- package/dist/util/mcp-server-utils.d.ts.map +1 -0
- package/dist/util/mcp-server-utils.js +107 -0
- package/dist/util/mcp-server-utils.js.map +1 -0
- package/dist/util/mcp-server-utils.test.d.ts +2 -0
- package/dist/util/mcp-server-utils.test.d.ts.map +1 -0
- package/dist/util/mcp-server-utils.test.js +287 -0
- package/dist/util/mcp-server-utils.test.js.map +1 -0
- package/dist/util/message-builder.d.ts +2 -1
- package/dist/util/message-builder.d.ts.map +1 -1
- package/dist/util/message-builder.js +54 -36
- package/dist/util/message-builder.js.map +1 -1
- package/dist/util/message-builder.test.js +500 -13
- package/dist/util/message-builder.test.js.map +1 -1
- package/dist/util/registry-validators.d.ts +26 -0
- package/dist/util/registry-validators.d.ts.map +1 -0
- package/dist/util/registry-validators.js +105 -0
- package/dist/util/registry-validators.js.map +1 -0
- package/dist/util/registry-validators.test.d.ts +2 -0
- package/dist/util/registry-validators.test.d.ts.map +1 -0
- package/dist/util/registry-validators.test.js +235 -0
- package/dist/util/registry-validators.test.js.map +1 -0
- package/dist/util/registry.d.ts +35 -7
- package/dist/util/registry.d.ts.map +1 -1
- package/dist/util/registry.js +60 -77
- package/dist/util/registry.js.map +1 -1
- package/dist/util/registry.test.d.ts +2 -0
- package/dist/util/registry.test.d.ts.map +1 -0
- package/dist/util/registry.test.js +204 -0
- package/dist/util/registry.test.js.map +1 -0
- package/dist/util/resource-validators.d.ts +16 -0
- package/dist/util/resource-validators.d.ts.map +1 -0
- package/dist/util/resource-validators.js +34 -0
- package/dist/util/resource-validators.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 +12 -4
- package/dist/util/tool-caller.js.map +1 -1
- package/esm/{providers/hoc → hoc}/with-tambo-interactable.d.ts +2 -2
- package/esm/hoc/with-tambo-interactable.d.ts.map +1 -0
- package/esm/{providers/hoc → hoc}/with-tambo-interactable.js +29 -2
- package/esm/hoc/with-tambo-interactable.js.map +1 -0
- package/esm/hoc/with-tambo-interactable.test.d.ts +2 -0
- package/esm/hoc/with-tambo-interactable.test.d.ts.map +1 -0
- package/esm/hoc/with-tambo-interactable.test.js +187 -0
- package/esm/hoc/with-tambo-interactable.test.js.map +1 -0
- package/esm/hooks/index.d.ts +1 -1
- package/esm/hooks/index.d.ts.map +1 -1
- package/esm/hooks/index.js +1 -1
- package/esm/hooks/index.js.map +1 -1
- package/esm/hooks/use-current-message.d.ts +51 -7
- package/esm/hooks/use-current-message.d.ts.map +1 -1
- package/esm/hooks/use-current-message.js +48 -5
- package/esm/hooks/use-current-message.js.map +1 -1
- package/esm/hooks/use-current-message.test.d.ts +2 -0
- package/esm/hooks/use-current-message.test.d.ts.map +1 -0
- package/esm/hooks/use-current-message.test.js +259 -0
- package/esm/hooks/use-current-message.test.js.map +1 -0
- package/esm/index.d.ts +10 -8
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +4 -2
- package/esm/index.js.map +1 -1
- package/esm/mcp/index.d.ts +1 -1
- package/esm/mcp/index.d.ts.map +1 -1
- package/esm/mcp/index.js +1 -1
- package/esm/mcp/index.js.map +1 -1
- package/esm/mcp/mcp-hooks.d.ts +77 -6
- package/esm/mcp/mcp-hooks.d.ts.map +1 -1
- package/esm/mcp/mcp-hooks.js +103 -40
- package/esm/mcp/mcp-hooks.js.map +1 -1
- package/esm/mcp/mcp-hooks.test.js +84 -19
- 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 +2 -1
- package/esm/mcp/tambo-mcp-provider.js.map +1 -1
- package/esm/model/component-metadata.d.ts +444 -14
- package/esm/model/component-metadata.d.ts.map +1 -1
- package/esm/model/component-metadata.js.map +1 -1
- package/esm/model/generate-component-response.d.ts +12 -1
- package/esm/model/generate-component-response.d.ts.map +1 -1
- package/esm/model/generate-component-response.js.map +1 -1
- package/esm/model/resource-info.d.ts +55 -0
- package/esm/model/resource-info.d.ts.map +1 -0
- package/esm/model/resource-info.js +2 -0
- package/esm/model/resource-info.js.map +1 -0
- 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-component-provider.d.ts +4 -4
- package/esm/providers/tambo-component-provider.d.ts.map +1 -1
- package/esm/providers/tambo-component-provider.js.map +1 -1
- package/esm/providers/tambo-interactable-provider-partial-updates.test.js +1 -1
- package/esm/providers/tambo-interactable-provider-partial-updates.test.js.map +1 -1
- package/esm/providers/tambo-interactable-provider.d.ts +2 -3
- package/esm/providers/tambo-interactable-provider.d.ts.map +1 -1
- package/esm/providers/tambo-interactable-provider.js +44 -38
- package/esm/providers/tambo-interactable-provider.js.map +1 -1
- package/esm/providers/tambo-interactables-additional-context-edge-cases.test.js +3 -3
- package/esm/providers/tambo-interactables-additional-context-edge-cases.test.js.map +1 -1
- package/esm/providers/tambo-interactables-additional-context.test.js +3 -3
- package/esm/providers/tambo-interactables-additional-context.test.js.map +1 -1
- package/esm/providers/tambo-registry-provider.d.ts +28 -7
- package/esm/providers/tambo-registry-provider.d.ts.map +1 -1
- package/esm/providers/tambo-registry-provider.js +67 -175
- package/esm/providers/tambo-registry-provider.js.map +1 -1
- package/esm/providers/tambo-registry-provider.test.js +148 -26
- package/esm/providers/tambo-registry-provider.test.js.map +1 -1
- package/esm/providers/tambo-registry-schema-compat.test.d.ts +2 -0
- package/esm/providers/tambo-registry-schema-compat.test.d.ts.map +1 -0
- package/esm/providers/tambo-registry-schema-compat.test.js +578 -0
- package/esm/providers/tambo-registry-schema-compat.test.js.map +1 -0
- package/esm/providers/tambo-stubs.d.ts +2 -2
- package/esm/providers/tambo-stubs.d.ts.map +1 -1
- package/esm/providers/tambo-stubs.js +5 -0
- package/esm/providers/tambo-stubs.js.map +1 -1
- package/esm/providers/tambo-thread-input-provider.d.ts +1 -0
- package/esm/providers/tambo-thread-input-provider.d.ts.map +1 -1
- package/esm/providers/tambo-thread-input-provider.js +3 -3
- package/esm/providers/tambo-thread-input-provider.js.map +1 -1
- package/esm/providers/tambo-thread-provider.d.ts.map +1 -1
- package/esm/providers/tambo-thread-provider.js.map +1 -1
- package/esm/providers/tambo-thread-provider.test.js +24 -28
- package/esm/providers/tambo-thread-provider.test.js.map +1 -1
- package/esm/schema/index.d.ts +6 -0
- package/esm/schema/index.d.ts.map +1 -0
- package/esm/schema/index.js +6 -0
- package/esm/schema/index.js.map +1 -0
- package/esm/schema/json-schema.d.ts +35 -0
- package/esm/schema/json-schema.d.ts.map +1 -0
- package/esm/schema/json-schema.js +98 -0
- package/esm/schema/json-schema.js.map +1 -0
- package/esm/schema/schema.d.ts +66 -0
- package/esm/schema/schema.d.ts.map +1 -0
- package/esm/schema/schema.js +185 -0
- package/esm/schema/schema.js.map +1 -0
- package/esm/schema/schema.test.d.ts +2 -0
- package/esm/schema/schema.test.d.ts.map +1 -0
- package/esm/schema/schema.test.js +39 -0
- package/esm/schema/schema.test.js.map +1 -0
- package/esm/schema/standard-schema.d.ts +21 -0
- package/esm/schema/standard-schema.d.ts.map +1 -0
- package/esm/schema/standard-schema.js +34 -0
- package/esm/schema/standard-schema.js.map +1 -0
- package/esm/schema/validate.d.ts +14 -0
- package/esm/schema/validate.d.ts.map +1 -0
- package/esm/schema/validate.js +145 -0
- package/esm/schema/validate.js.map +1 -0
- package/esm/schema/validate.test.d.ts +2 -0
- package/esm/schema/validate.test.d.ts.map +1 -0
- package/esm/schema/validate.test.js +126 -0
- package/esm/schema/validate.test.js.map +1 -0
- package/esm/schema/zod.d.ts +54 -0
- package/esm/schema/zod.d.ts.map +1 -0
- package/esm/schema/zod.js +124 -0
- package/esm/schema/zod.js.map +1 -0
- package/esm/testing/tools.d.ts +29 -15
- package/esm/testing/tools.d.ts.map +1 -1
- package/esm/testing/tools.js +62 -16
- package/esm/testing/tools.js.map +1 -1
- package/esm/util/generate-component.d.ts.map +1 -1
- package/esm/util/generate-component.js +3 -3
- package/esm/util/generate-component.js.map +1 -1
- package/esm/util/mcp-server-utils.d.ts +23 -0
- package/esm/util/mcp-server-utils.d.ts.map +1 -0
- package/esm/util/mcp-server-utils.js +102 -0
- package/esm/util/mcp-server-utils.js.map +1 -0
- package/esm/util/mcp-server-utils.test.d.ts +2 -0
- package/esm/util/mcp-server-utils.test.d.ts.map +1 -0
- package/esm/util/mcp-server-utils.test.js +285 -0
- package/esm/util/mcp-server-utils.test.js.map +1 -0
- package/esm/util/message-builder.d.ts +2 -1
- package/esm/util/message-builder.d.ts.map +1 -1
- package/esm/util/message-builder.js +54 -36
- package/esm/util/message-builder.js.map +1 -1
- package/esm/util/message-builder.test.js +500 -13
- package/esm/util/message-builder.test.js.map +1 -1
- package/esm/util/registry-validators.d.ts +26 -0
- package/esm/util/registry-validators.d.ts.map +1 -0
- package/esm/util/registry-validators.js +100 -0
- package/esm/util/registry-validators.js.map +1 -0
- package/esm/util/registry-validators.test.d.ts +2 -0
- package/esm/util/registry-validators.test.d.ts.map +1 -0
- package/esm/util/registry-validators.test.js +233 -0
- package/esm/util/registry-validators.test.js.map +1 -0
- package/esm/util/registry.d.ts +35 -7
- package/esm/util/registry.d.ts.map +1 -1
- package/esm/util/registry.js +57 -73
- package/esm/util/registry.js.map +1 -1
- package/esm/util/registry.test.d.ts +2 -0
- package/esm/util/registry.test.d.ts.map +1 -0
- package/esm/util/registry.test.js +169 -0
- package/esm/util/registry.test.js.map +1 -0
- package/esm/util/resource-validators.d.ts +16 -0
- package/esm/util/resource-validators.d.ts.map +1 -0
- package/esm/util/resource-validators.js +30 -0
- package/esm/util/resource-validators.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 +12 -4
- package/esm/util/tool-caller.js.map +1 -1
- package/package.json +13 -8
- package/dist/providers/hoc/with-tambo-interactable.d.ts.map +0 -1
- package/dist/providers/hoc/with-tambo-interactable.js.map +0 -1
- package/dist/util/validate-zod-schema.d.ts +0 -10
- package/dist/util/validate-zod-schema.d.ts.map +0 -1
- package/dist/util/validate-zod-schema.js +0 -100
- package/dist/util/validate-zod-schema.js.map +0 -1
- package/dist/util/validate-zod-schema.test.d.ts +0 -2
- package/dist/util/validate-zod-schema.test.d.ts.map +0 -1
- package/dist/util/validate-zod-schema.test.js +0 -96
- package/dist/util/validate-zod-schema.test.js.map +0 -1
- package/esm/providers/hoc/with-tambo-interactable.d.ts.map +0 -1
- package/esm/providers/hoc/with-tambo-interactable.js.map +0 -1
- package/esm/util/validate-zod-schema.d.ts +0 -10
- package/esm/util/validate-zod-schema.d.ts.map +0 -1
- package/esm/util/validate-zod-schema.js +0 -97
- package/esm/util/validate-zod-schema.js.map +0 -1
- package/esm/util/validate-zod-schema.test.d.ts +0 -2
- package/esm/util/validate-zod-schema.test.d.ts.map +0 -1
- package/esm/util/validate-zod-schema.test.js +0 -94
- package/esm/util/validate-zod-schema.test.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-caller.js","sourceRoot":"","sources":["../../src/util/tool-caller.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"tool-caller.js","sourceRoot":"","sources":["../../src/util/tool-caller.ts"],"names":[],"mappings":";;;AAOA,sCAA2C;AAC3C,yCAAuD;AAEvD;;;;;GAKG;AACI,MAAM,cAAc,GAAG,KAAK,EACjC,OAA2C,EAC3C,YAA+B,EAC/B,sBAGoB,EAKnB,EAAE;IACH,IAAI,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,QAAQ,CAClC,OAAO,CAAC,eAAe,CAAC,QAAQ,EAChC,YAAY,CACb,CAAC;QACF,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,sBAAsB,EAAE,CAAC;gBAC3B,MAAM,MAAM,GAAG,MAAM,sBAAsB,CACzC,OAAO,CAAC,eAAe,CAAC,QAAQ,EAChC,OAAO,CAAC,eAAe,CAAC,UAAU,CACnC,CAAC;gBACF,OAAO;oBACL,MAAM;iBACP,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,KAAK,CACb,QAAQ,OAAO,CAAC,eAAe,CAAC,QAAQ,wBAAwB,CACjE,CAAC;QACJ,CAAC;QACD,OAAO;YACL,MAAM,EAAE,MAAM,aAAa,CAAC,OAAO,CAAC,eAAe,EAAE,IAAI,EAAE,SAAS,CAAC;YACrE,SAAS;SACV,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QAChD,OAAO;YACL,MAAM,EAAE,gCAAgC,OAAO,CAAC,eAAe,CAAC,QAAQ,kCAAkC,KAAK,0EAA0E;YACzL,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;SAChE,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AA9CW,QAAA,cAAc,kBA8CzB;AAEF,MAAM,QAAQ,GAAG,CACf,QAAgB,EAChB,YAA+B,EAMG,EAAE;IACpC,MAAM,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAE5C,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACzC,CAAC;IAED,MAAM,WAAW,GAAG,IAAA,oCAAyB,EAAC,YAAY,CAAC,CAAC;IAC5D,OAAO;QACL,IAAI,EAAE;YACJ,mBAAmB,EAAE,YAAY,CAAC,IAAI;YACtC,UAAU,EAAE,WAAW;SACxB;QACD,SAAS,EAAE,YAAY;KACxB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,KAAK,EACzB,eAAwC,EACxC,IAA0B,EAC1B,SAA8C,EAC5B,EAAE;IACpB,MAAM,UAAU,GAAG,eAAe,CAAC,UAAU,IAAI,EAAE,CAAC;IAEpD,2DAA2D;IAC3D,IAAI,IAAA,uBAAc,EAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,yDAAyD;QACzD,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CACpC,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC,CACvE,CAAC;QACF,OAAO,MAAM,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;IACrD,CAAC;IAED,iEAAiE;IACjE,MAAM,eAAe,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACxE,OAAO,MAAM,IAAI,CAAC,mBAAmB,CAAC,GAAG,eAAe,CAAC,CAAC;AAC5D,CAAC,CAAC","sourcesContent":["import TamboAI from \"@tambo-ai/typescript-sdk\";\nimport {\n ComponentContextTool,\n TamboTool,\n TamboToolRegistry,\n TamboToolWithToolSchema,\n} from \"../model/component-metadata\";\nimport { hasInputSchema } from \"../schema\";\nimport { mapTamboToolToContextTool } from \"./registry\";\n\n/**\n * Process a message from the thread, invoking the appropriate tool and returning the result.\n * @param message - The message to handle\n * @param toolRegistry - The tool registry\n * @returns The result of the tool call along with the tool definition\n */\nexport const handleToolCall = async (\n message: TamboAI.Beta.Threads.ThreadMessage,\n toolRegistry: TamboToolRegistry,\n onCallUnregisteredTool?: (\n toolName: string,\n args: TamboAI.ToolCallParameter[],\n ) => Promise<string>,\n): Promise<{\n result: unknown;\n error?: string;\n tamboTool?: TamboTool | TamboToolWithToolSchema;\n}> => {\n if (!message?.toolCallRequest?.toolName) {\n throw new Error(\"Tool name is required\");\n }\n\n try {\n const { tool, tamboTool } = findTool(\n message.toolCallRequest.toolName,\n toolRegistry,\n );\n if (!tool) {\n if (onCallUnregisteredTool) {\n const result = await onCallUnregisteredTool(\n message.toolCallRequest.toolName,\n message.toolCallRequest.parameters,\n );\n return {\n result,\n };\n }\n throw new Error(\n `Tool ${message.toolCallRequest.toolName} not found in registry`,\n );\n }\n return {\n result: await runToolChoice(message.toolCallRequest, tool, tamboTool),\n tamboTool,\n };\n } catch (error) {\n console.error(\"Error in calling tool: \", error);\n return {\n result: `When attempting to call tool ${message.toolCallRequest.toolName} the following error occurred: ${error}. Explain to the user that the tool call failed and try again if needed.`,\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n};\n\nconst findTool = (\n toolName: string,\n toolRegistry: TamboToolRegistry,\n):\n | {\n tool: ComponentContextTool;\n tamboTool: TamboTool | TamboToolWithToolSchema;\n }\n | { tool: null; tamboTool: null } => {\n const registryTool = toolRegistry[toolName];\n\n if (!registryTool) {\n return { tool: null, tamboTool: null };\n }\n\n const contextTool = mapTamboToolToContextTool(registryTool);\n return {\n tool: {\n getComponentContext: registryTool.tool,\n definition: contextTool,\n },\n tamboTool: registryTool,\n };\n};\n\nconst runToolChoice = async (\n toolCallRequest: TamboAI.ToolCallRequest,\n tool: ComponentContextTool,\n tamboTool: TamboTool | TamboToolWithToolSchema,\n): Promise<unknown> => {\n const parameters = toolCallRequest.parameters ?? [];\n\n // New interface (inputSchema): pass single object argument\n if (hasInputSchema(tamboTool)) {\n // Reconstruct the object from parameter name-value pairs\n const inputObject = Object.fromEntries(\n parameters.map((param) => [param.parameterName, param.parameterValue]),\n );\n return await tool.getComponentContext(inputObject);\n }\n\n // Deprecated interface (toolSchema): spread positional arguments\n const parameterValues = parameters.map((param) => param.parameterValue);\n return await tool.getComponentContext(...parameterValues);\n};\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { SupportedSchema } from "../schema";
|
|
3
3
|
export interface InteractableConfig {
|
|
4
4
|
componentName: string;
|
|
5
5
|
description: string;
|
|
6
|
-
propsSchema?:
|
|
6
|
+
propsSchema?: SupportedSchema;
|
|
7
7
|
}
|
|
8
8
|
export interface WithTamboInteractableProps {
|
|
9
9
|
interactableId?: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-tambo-interactable.d.ts","sourceRoot":"","sources":["../../src/hoc/with-tambo-interactable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAIxE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED,MAAM,WAAW,0BAA0B;IACzC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;CACzD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,MAAM,EACpD,gBAAgB,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EACxC,MAAM,EAAE,kBAAkB,4CAgH3B"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// react-sdk/src/providers/with-interactable.tsx
|
|
2
2
|
"use client";
|
|
3
3
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
-
import {
|
|
4
|
+
import { TamboMessageProvider } from "../hooks/use-current-message";
|
|
5
|
+
import { useTamboInteractable } from "../providers/tambo-interactable-provider";
|
|
5
6
|
/**
|
|
6
7
|
* Higher-Order Component that makes any component interactable by tambo.
|
|
7
8
|
* @param WrappedComponent - The component to make interactable
|
|
@@ -75,7 +76,33 @@ export function withTamboInteractable(WrappedComponent, config) {
|
|
|
75
76
|
updateInteractableComponentProps,
|
|
76
77
|
onPropsUpdate,
|
|
77
78
|
]);
|
|
78
|
-
|
|
79
|
+
// If the interactable ID is not yet set, render the component without provider
|
|
80
|
+
if (!interactableId) {
|
|
81
|
+
return React.createElement(WrappedComponent, { ...effectiveProps });
|
|
82
|
+
}
|
|
83
|
+
// Create a minimal message with interactable metadata
|
|
84
|
+
// This allows useTamboCurrentComponent to work with standalone interactable components
|
|
85
|
+
const minimalMessage = {
|
|
86
|
+
id: interactableId,
|
|
87
|
+
role: "assistant",
|
|
88
|
+
content: [],
|
|
89
|
+
threadId: "",
|
|
90
|
+
createdAt: new Date().toISOString(),
|
|
91
|
+
component: {
|
|
92
|
+
componentName: config.componentName,
|
|
93
|
+
componentState: {},
|
|
94
|
+
message: "",
|
|
95
|
+
props: effectiveProps,
|
|
96
|
+
},
|
|
97
|
+
componentState: {},
|
|
98
|
+
};
|
|
99
|
+
// Wrap with TamboMessageProvider including interactable metadata
|
|
100
|
+
return (React.createElement(TamboMessageProvider, { message: minimalMessage, interactableMetadata: {
|
|
101
|
+
id: interactableId,
|
|
102
|
+
componentName: config.componentName,
|
|
103
|
+
description: config.description,
|
|
104
|
+
} },
|
|
105
|
+
React.createElement(WrappedComponent, { ...effectiveProps })));
|
|
79
106
|
};
|
|
80
107
|
TamboInteractableWrapper.displayName = `withTamboInteractable(${displayName})`;
|
|
81
108
|
return TamboInteractableWrapper;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-tambo-interactable.js","sourceRoot":"","sources":["../../src/hoc/with-tambo-interactable.tsx"],"names":[],"mappings":"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","sourcesContent":["// react-sdk/src/providers/with-interactable.tsx\n\"use client\";\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { TamboMessageProvider } from \"../hooks/use-current-message\";\nimport { TamboThreadMessage } from \"../model/generate-component-response\";\nimport { useTamboInteractable } from \"../providers/tambo-interactable-provider\";\nimport { SupportedSchema } from \"../schema\";\n\nexport interface InteractableConfig {\n componentName: string;\n description: string;\n propsSchema?: SupportedSchema;\n}\n\nexport interface WithTamboInteractableProps {\n interactableId?: string;\n onInteractableReady?: (id: string) => void;\n onPropsUpdate?: (newProps: Record<string, any>) => void;\n}\n\n/**\n * Higher-Order Component that makes any component interactable by tambo.\n * @param WrappedComponent - The component to make interactable\n * @param config - Configuration for the interactable component\n * @returns A new component that is automatically registered as interactable\n * @example\n * ```tsx\n * const MyInteractableNote = withTamboInteractable(MyNote, {\n * componentName: \"MyNote\",\n * description: \"A note component\",\n * propsSchema: z.object({\n * title: z.string(),\n * content: z.string(),\n * }),\n * });\n *\n * // Usage\n * <MyInteractableNote title=\"My Note\" content=\"This is my note\" />\n * ```\n */\nexport function withTamboInteractable<P extends object>(\n WrappedComponent: React.ComponentType<P>,\n config: InteractableConfig,\n) {\n const displayName =\n WrappedComponent.displayName ?? WrappedComponent.name ?? \"Component\";\n\n const TamboInteractableWrapper: React.FC<P & WithTamboInteractableProps> = (\n props,\n ) => {\n const {\n addInteractableComponent,\n updateInteractableComponentProps,\n getInteractableComponent,\n } = useTamboInteractable();\n\n const [interactableId, setInteractableId] = useState<string | null>(null);\n const isInitialized = useRef(false);\n const lastParentProps = useRef<Record<string, any>>({});\n\n // Extract interactable-specific props\n const { onInteractableReady, onPropsUpdate, ...componentProps } = props;\n\n // Get the current interactable component to track prop updates\n const currentInteractable = interactableId\n ? getInteractableComponent(interactableId)\n : null;\n\n // Use the props from the interactable component if available, otherwise use the passed props\n // We need to be careful not to create a loop, so we only use stored props if they're different from passed props\n const effectiveProps = currentInteractable?.props ?? componentProps;\n\n // Memoize the registration function\n const registerComponent = useCallback(() => {\n if (!isInitialized.current) {\n const id = addInteractableComponent({\n name: config.componentName,\n description: config.description,\n component: WrappedComponent,\n props: componentProps,\n propsSchema: config.propsSchema,\n });\n\n setInteractableId(id);\n onInteractableReady?.(id);\n isInitialized.current = true;\n }\n }, [addInteractableComponent, componentProps, onInteractableReady]);\n\n // Register the component as interactable on mount (only once)\n useEffect(() => {\n registerComponent();\n }, [registerComponent]);\n\n // Update the interactable component when props change from parent\n useEffect(() => {\n if (interactableId && isInitialized.current) {\n // Only update if the props are different from what we last sent\n const lastPropsString = JSON.stringify(lastParentProps.current);\n const currentPropsString = JSON.stringify(componentProps);\n\n if (lastPropsString !== currentPropsString) {\n updateInteractableComponentProps(interactableId, componentProps);\n onPropsUpdate?.(componentProps);\n lastParentProps.current = componentProps;\n }\n }\n }, [\n interactableId,\n componentProps,\n updateInteractableComponentProps,\n onPropsUpdate,\n ]);\n\n // If the interactable ID is not yet set, render the component without provider\n if (!interactableId) {\n return <WrappedComponent {...(effectiveProps as P)} />;\n }\n\n // Create a minimal message with interactable metadata\n // This allows useTamboCurrentComponent to work with standalone interactable components\n const minimalMessage: TamboThreadMessage = {\n id: interactableId,\n role: \"assistant\" as const,\n content: [],\n threadId: \"\",\n createdAt: new Date().toISOString(),\n component: {\n componentName: config.componentName,\n componentState: {},\n message: \"\",\n props: effectiveProps,\n },\n componentState: {},\n };\n\n // Wrap with TamboMessageProvider including interactable metadata\n return (\n <TamboMessageProvider\n message={minimalMessage}\n interactableMetadata={{\n id: interactableId,\n componentName: config.componentName,\n description: config.description,\n }}\n >\n <WrappedComponent {...(effectiveProps as P)} />\n </TamboMessageProvider>\n );\n };\n\n TamboInteractableWrapper.displayName = `withTamboInteractable(${displayName})`;\n\n return TamboInteractableWrapper;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-tambo-interactable.test.d.ts","sourceRoot":"","sources":["../../src/hoc/with-tambo-interactable.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { render, screen, waitFor } from "@testing-library/react";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { z } from "zod/v3";
|
|
4
|
+
import { useTamboCurrentComponent } from "../hooks/use-current-message";
|
|
5
|
+
import { TamboInteractableProvider } from "../providers/tambo-interactable-provider";
|
|
6
|
+
import { withTamboInteractable } from "./with-tambo-interactable";
|
|
7
|
+
// Create a consistent mock implementation
|
|
8
|
+
const mockAddInteractableComponent = jest.fn(() => "mock-id-123");
|
|
9
|
+
const mockUpdateInteractableComponentProps = jest.fn();
|
|
10
|
+
const mockGetInteractableComponent = jest.fn(() => null);
|
|
11
|
+
const mockRemoveInteractableComponent = jest.fn();
|
|
12
|
+
const mockGetInteractableComponentsByName = jest.fn(() => []);
|
|
13
|
+
const mockClearAllInteractableComponents = jest.fn();
|
|
14
|
+
// Mock the interactable provider
|
|
15
|
+
jest.mock("../providers/tambo-interactable-provider", () => ({
|
|
16
|
+
TamboInteractableProvider: ({ children }) => (React.createElement("div", { "data-testid": "interactable-provider" }, children)),
|
|
17
|
+
useTamboInteractable: () => ({
|
|
18
|
+
addInteractableComponent: mockAddInteractableComponent,
|
|
19
|
+
updateInteractableComponentProps: mockUpdateInteractableComponentProps,
|
|
20
|
+
getInteractableComponent: mockGetInteractableComponent,
|
|
21
|
+
removeInteractableComponent: mockRemoveInteractableComponent,
|
|
22
|
+
getInteractableComponentsByName: mockGetInteractableComponentsByName,
|
|
23
|
+
clearAllInteractableComponents: mockClearAllInteractableComponents,
|
|
24
|
+
interactableComponents: [],
|
|
25
|
+
}),
|
|
26
|
+
}));
|
|
27
|
+
describe("withTamboInteractable", () => {
|
|
28
|
+
const TestComponent = ({ title, count }) => (React.createElement("div", null,
|
|
29
|
+
React.createElement("h1", { "data-testid": "title" }, title),
|
|
30
|
+
count !== undefined && React.createElement("span", { "data-testid": "count" }, count)));
|
|
31
|
+
const testSchema = z.object({
|
|
32
|
+
title: z.string(),
|
|
33
|
+
count: z.number().optional(),
|
|
34
|
+
});
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
jest.clearAllMocks();
|
|
37
|
+
// Reset mock implementations
|
|
38
|
+
mockAddInteractableComponent.mockReturnValue("mock-id-123");
|
|
39
|
+
mockGetInteractableComponent.mockReturnValue(null);
|
|
40
|
+
mockGetInteractableComponentsByName.mockReturnValue([]);
|
|
41
|
+
});
|
|
42
|
+
it("should render the wrapped component with provided props", () => {
|
|
43
|
+
const InteractableComponent = withTamboInteractable(TestComponent, {
|
|
44
|
+
componentName: "TestComponent",
|
|
45
|
+
description: "A test component",
|
|
46
|
+
propsSchema: testSchema,
|
|
47
|
+
});
|
|
48
|
+
render(React.createElement(TamboInteractableProvider, null,
|
|
49
|
+
React.createElement(InteractableComponent, { title: "Hello", count: 42 })));
|
|
50
|
+
expect(screen.getByTestId("title")).toHaveTextContent("Hello");
|
|
51
|
+
expect(screen.getByTestId("count")).toHaveTextContent("42");
|
|
52
|
+
});
|
|
53
|
+
it("should set displayName correctly", () => {
|
|
54
|
+
const InteractableComponent = withTamboInteractable(TestComponent, {
|
|
55
|
+
componentName: "TestComponent",
|
|
56
|
+
description: "A test component",
|
|
57
|
+
});
|
|
58
|
+
expect(InteractableComponent.displayName).toBe("withTamboInteractable(TestComponent)");
|
|
59
|
+
});
|
|
60
|
+
it("should handle components without displayName", () => {
|
|
61
|
+
const AnonymousComponent = () => React.createElement("div", null, "Anonymous");
|
|
62
|
+
const InteractableComponent = withTamboInteractable(AnonymousComponent, {
|
|
63
|
+
componentName: "AnonymousComponent",
|
|
64
|
+
description: "An anonymous component",
|
|
65
|
+
});
|
|
66
|
+
// Anonymous components get their name from the function name
|
|
67
|
+
expect(InteractableComponent.displayName).toBe("withTamboInteractable(AnonymousComponent)");
|
|
68
|
+
});
|
|
69
|
+
it("should provide TamboMessageProvider with interactable metadata", async () => {
|
|
70
|
+
// Child component that uses the context
|
|
71
|
+
const ContextConsumer = () => {
|
|
72
|
+
const component = useTamboCurrentComponent();
|
|
73
|
+
return (React.createElement("div", null,
|
|
74
|
+
React.createElement("span", { "data-testid": "interactable-id" }, component?.interactableId),
|
|
75
|
+
React.createElement("span", { "data-testid": "component-name" }, component?.componentName),
|
|
76
|
+
React.createElement("span", { "data-testid": "description" }, component?.description)));
|
|
77
|
+
};
|
|
78
|
+
// Wrap TestComponent to include ContextConsumer
|
|
79
|
+
const TestComponentWithConsumer = (props) => (React.createElement("div", null,
|
|
80
|
+
React.createElement(TestComponent, { ...props }),
|
|
81
|
+
React.createElement(ContextConsumer, null)));
|
|
82
|
+
const InteractableWithConsumer = withTamboInteractable(TestComponentWithConsumer, {
|
|
83
|
+
componentName: "TestComponent",
|
|
84
|
+
description: "A test component",
|
|
85
|
+
propsSchema: testSchema,
|
|
86
|
+
});
|
|
87
|
+
render(React.createElement(TamboInteractableProvider, null,
|
|
88
|
+
React.createElement(InteractableWithConsumer, { title: "Hello" })));
|
|
89
|
+
// Wait for the component to register and render
|
|
90
|
+
await waitFor(() => {
|
|
91
|
+
expect(screen.getByTestId("interactable-id")).toHaveTextContent("mock-id-123");
|
|
92
|
+
});
|
|
93
|
+
expect(screen.getByTestId("component-name")).toHaveTextContent("TestComponent");
|
|
94
|
+
expect(screen.getByTestId("description")).toHaveTextContent("A test component");
|
|
95
|
+
});
|
|
96
|
+
it("should create minimal message with correct structure", async () => {
|
|
97
|
+
// Child component that checks the message structure
|
|
98
|
+
const MessageChecker = () => {
|
|
99
|
+
const component = useTamboCurrentComponent();
|
|
100
|
+
return (React.createElement("div", null,
|
|
101
|
+
React.createElement("span", { "data-testid": "has-component-name" }, component?.componentName ? "yes" : "no"),
|
|
102
|
+
React.createElement("span", { "data-testid": "has-props" }, component?.props ? "yes" : "no"),
|
|
103
|
+
React.createElement("span", { "data-testid": "has-interactable-id" }, component?.interactableId ? "yes" : "no"),
|
|
104
|
+
React.createElement("span", { "data-testid": "has-description" }, component?.description ? "yes" : "no")));
|
|
105
|
+
};
|
|
106
|
+
const TestComponentWithChecker = (props) => (React.createElement("div", null,
|
|
107
|
+
React.createElement(TestComponent, { ...props }),
|
|
108
|
+
React.createElement(MessageChecker, null)));
|
|
109
|
+
const InteractableWithChecker = withTamboInteractable(TestComponentWithChecker, {
|
|
110
|
+
componentName: "TestComponent",
|
|
111
|
+
description: "A test component",
|
|
112
|
+
propsSchema: testSchema,
|
|
113
|
+
});
|
|
114
|
+
render(React.createElement(TamboInteractableProvider, null,
|
|
115
|
+
React.createElement(InteractableWithChecker, { title: "Hello", count: 42 })));
|
|
116
|
+
await waitFor(() => {
|
|
117
|
+
expect(screen.getByTestId("has-component-name")).toHaveTextContent("yes");
|
|
118
|
+
});
|
|
119
|
+
expect(screen.getByTestId("has-props")).toHaveTextContent("yes");
|
|
120
|
+
expect(screen.getByTestId("has-interactable-id")).toHaveTextContent("yes");
|
|
121
|
+
expect(screen.getByTestId("has-description")).toHaveTextContent("yes");
|
|
122
|
+
});
|
|
123
|
+
it("should pass through all component props correctly", () => {
|
|
124
|
+
const InteractableComponent = withTamboInteractable(TestComponent, {
|
|
125
|
+
componentName: "TestComponent",
|
|
126
|
+
description: "A test component",
|
|
127
|
+
propsSchema: testSchema,
|
|
128
|
+
});
|
|
129
|
+
render(React.createElement(TamboInteractableProvider, null,
|
|
130
|
+
React.createElement(InteractableComponent, { title: "Test Title", count: 100 })));
|
|
131
|
+
expect(screen.getByTestId("title")).toHaveTextContent("Test Title");
|
|
132
|
+
expect(screen.getByTestId("count")).toHaveTextContent("100");
|
|
133
|
+
});
|
|
134
|
+
it("should filter out interactable-specific props from component props", () => {
|
|
135
|
+
const ExtendedComponent = ({ title, onInteractableReady, onPropsUpdate, }) => (React.createElement("div", null,
|
|
136
|
+
React.createElement("span", { "data-testid": "title" }, title),
|
|
137
|
+
React.createElement("span", { "data-testid": "has-ready" }, onInteractableReady ? "yes" : "no"),
|
|
138
|
+
React.createElement("span", { "data-testid": "has-update" }, onPropsUpdate ? "yes" : "no")));
|
|
139
|
+
const InteractableComponent = withTamboInteractable(ExtendedComponent, {
|
|
140
|
+
componentName: "ExtendedComponent",
|
|
141
|
+
description: "An extended component",
|
|
142
|
+
});
|
|
143
|
+
const mockReady = jest.fn();
|
|
144
|
+
const mockUpdate = jest.fn();
|
|
145
|
+
render(React.createElement(TamboInteractableProvider, null,
|
|
146
|
+
React.createElement(InteractableComponent, { title: "Test", onInteractableReady: mockReady, onPropsUpdate: mockUpdate })));
|
|
147
|
+
expect(screen.getByTestId("title")).toHaveTextContent("Test");
|
|
148
|
+
// These props should be filtered out
|
|
149
|
+
expect(screen.getByTestId("has-ready")).toHaveTextContent("no");
|
|
150
|
+
expect(screen.getByTestId("has-update")).toHaveTextContent("no");
|
|
151
|
+
});
|
|
152
|
+
it("should work without propsSchema", () => {
|
|
153
|
+
const InteractableComponent = withTamboInteractable(TestComponent, {
|
|
154
|
+
componentName: "TestComponent",
|
|
155
|
+
description: "A test component",
|
|
156
|
+
});
|
|
157
|
+
render(React.createElement(TamboInteractableProvider, null,
|
|
158
|
+
React.createElement(InteractableComponent, { title: "No Schema" })));
|
|
159
|
+
expect(screen.getByTestId("title")).toHaveTextContent("No Schema");
|
|
160
|
+
});
|
|
161
|
+
it("should render before interactable ID is set", () => {
|
|
162
|
+
const InteractableComponent = withTamboInteractable(TestComponent, {
|
|
163
|
+
componentName: "TestComponent",
|
|
164
|
+
description: "A test component",
|
|
165
|
+
});
|
|
166
|
+
const { container } = render(React.createElement(TamboInteractableProvider, null,
|
|
167
|
+
React.createElement(InteractableComponent, { title: "Early Render" })));
|
|
168
|
+
// Component should render even before ID is available
|
|
169
|
+
expect(container.querySelector('[data-testid="title"]')).toBeInTheDocument();
|
|
170
|
+
});
|
|
171
|
+
it("should handle null/undefined values in props", () => {
|
|
172
|
+
const NullableComponent = ({ title, optional, nullable, }) => (React.createElement("div", null,
|
|
173
|
+
React.createElement("span", { "data-testid": "title" }, title),
|
|
174
|
+
React.createElement("span", { "data-testid": "optional" }, optional ?? "undefined"),
|
|
175
|
+
React.createElement("span", { "data-testid": "nullable" }, nullable ?? "null")));
|
|
176
|
+
const InteractableComponent = withTamboInteractable(NullableComponent, {
|
|
177
|
+
componentName: "NullableComponent",
|
|
178
|
+
description: "A component with nullable props",
|
|
179
|
+
});
|
|
180
|
+
render(React.createElement(TamboInteractableProvider, null,
|
|
181
|
+
React.createElement(InteractableComponent, { title: "Test", nullable: null })));
|
|
182
|
+
expect(screen.getByTestId("title")).toHaveTextContent("Test");
|
|
183
|
+
expect(screen.getByTestId("optional")).toHaveTextContent("undefined");
|
|
184
|
+
expect(screen.getByTestId("nullable")).toHaveTextContent("null");
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
//# sourceMappingURL=with-tambo-interactable.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-tambo-interactable.test.js","sourceRoot":"","sources":["../../src/hoc/with-tambo-interactable.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import { render, screen, waitFor } from \"@testing-library/react\";\nimport React from \"react\";\nimport { z } from \"zod/v3\";\nimport { useTamboCurrentComponent } from \"../hooks/use-current-message\";\nimport { TamboInteractableProvider } from \"../providers/tambo-interactable-provider\";\nimport { withTamboInteractable } from \"./with-tambo-interactable\";\n\n// Create a consistent mock implementation\nconst mockAddInteractableComponent = jest.fn(() => \"mock-id-123\");\nconst mockUpdateInteractableComponentProps = jest.fn();\nconst mockGetInteractableComponent = jest.fn(() => null);\nconst mockRemoveInteractableComponent = jest.fn();\nconst mockGetInteractableComponentsByName = jest.fn(() => []);\nconst mockClearAllInteractableComponents = jest.fn();\n\n// Mock the interactable provider\njest.mock(\"../providers/tambo-interactable-provider\", () => ({\n TamboInteractableProvider: ({ children }: { children: React.ReactNode }) => (\n <div data-testid=\"interactable-provider\">{children}</div>\n ),\n useTamboInteractable: () => ({\n addInteractableComponent: mockAddInteractableComponent,\n updateInteractableComponentProps: mockUpdateInteractableComponentProps,\n getInteractableComponent: mockGetInteractableComponent,\n removeInteractableComponent: mockRemoveInteractableComponent,\n getInteractableComponentsByName: mockGetInteractableComponentsByName,\n clearAllInteractableComponents: mockClearAllInteractableComponents,\n interactableComponents: [],\n }),\n}));\n\ndescribe(\"withTamboInteractable\", () => {\n // Simple test component\n interface TestComponentProps {\n title: string;\n count?: number;\n }\n\n const TestComponent: React.FC<TestComponentProps> = ({ title, count }) => (\n <div>\n <h1 data-testid=\"title\">{title}</h1>\n {count !== undefined && <span data-testid=\"count\">{count}</span>}\n </div>\n );\n\n const testSchema = z.object({\n title: z.string(),\n count: z.number().optional(),\n });\n\n beforeEach(() => {\n jest.clearAllMocks();\n // Reset mock implementations\n mockAddInteractableComponent.mockReturnValue(\"mock-id-123\");\n mockGetInteractableComponent.mockReturnValue(null);\n mockGetInteractableComponentsByName.mockReturnValue([]);\n });\n\n it(\"should render the wrapped component with provided props\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n propsSchema: testSchema,\n });\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"Hello\" count={42} />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Hello\");\n expect(screen.getByTestId(\"count\")).toHaveTextContent(\"42\");\n });\n\n it(\"should set displayName correctly\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n });\n\n expect(InteractableComponent.displayName).toBe(\n \"withTamboInteractable(TestComponent)\",\n );\n });\n\n it(\"should handle components without displayName\", () => {\n const AnonymousComponent = () => <div>Anonymous</div>;\n\n const InteractableComponent = withTamboInteractable(AnonymousComponent, {\n componentName: \"AnonymousComponent\",\n description: \"An anonymous component\",\n });\n\n // Anonymous components get their name from the function name\n expect(InteractableComponent.displayName).toBe(\n \"withTamboInteractable(AnonymousComponent)\",\n );\n });\n\n it(\"should provide TamboMessageProvider with interactable metadata\", async () => {\n // Child component that uses the context\n const ContextConsumer = () => {\n const component = useTamboCurrentComponent();\n return (\n <div>\n <span data-testid=\"interactable-id\">{component?.interactableId}</span>\n <span data-testid=\"component-name\">{component?.componentName}</span>\n <span data-testid=\"description\">{component?.description}</span>\n </div>\n );\n };\n\n // Wrap TestComponent to include ContextConsumer\n const TestComponentWithConsumer: React.FC<TestComponentProps> = (props) => (\n <div>\n <TestComponent {...props} />\n <ContextConsumer />\n </div>\n );\n\n const InteractableWithConsumer = withTamboInteractable(\n TestComponentWithConsumer,\n {\n componentName: \"TestComponent\",\n description: \"A test component\",\n propsSchema: testSchema,\n },\n );\n\n render(\n <TamboInteractableProvider>\n <InteractableWithConsumer title=\"Hello\" />\n </TamboInteractableProvider>,\n );\n\n // Wait for the component to register and render\n await waitFor(() => {\n expect(screen.getByTestId(\"interactable-id\")).toHaveTextContent(\n \"mock-id-123\",\n );\n });\n\n expect(screen.getByTestId(\"component-name\")).toHaveTextContent(\n \"TestComponent\",\n );\n expect(screen.getByTestId(\"description\")).toHaveTextContent(\n \"A test component\",\n );\n });\n\n it(\"should create minimal message with correct structure\", async () => {\n // Child component that checks the message structure\n const MessageChecker = () => {\n const component = useTamboCurrentComponent();\n return (\n <div>\n <span data-testid=\"has-component-name\">\n {component?.componentName ? \"yes\" : \"no\"}\n </span>\n <span data-testid=\"has-props\">{component?.props ? \"yes\" : \"no\"}</span>\n <span data-testid=\"has-interactable-id\">\n {component?.interactableId ? \"yes\" : \"no\"}\n </span>\n <span data-testid=\"has-description\">\n {component?.description ? \"yes\" : \"no\"}\n </span>\n </div>\n );\n };\n\n const TestComponentWithChecker: React.FC<TestComponentProps> = (props) => (\n <div>\n <TestComponent {...props} />\n <MessageChecker />\n </div>\n );\n\n const InteractableWithChecker = withTamboInteractable(\n TestComponentWithChecker,\n {\n componentName: \"TestComponent\",\n description: \"A test component\",\n propsSchema: testSchema,\n },\n );\n\n render(\n <TamboInteractableProvider>\n <InteractableWithChecker title=\"Hello\" count={42} />\n </TamboInteractableProvider>,\n );\n\n await waitFor(() => {\n expect(screen.getByTestId(\"has-component-name\")).toHaveTextContent(\"yes\");\n });\n\n expect(screen.getByTestId(\"has-props\")).toHaveTextContent(\"yes\");\n expect(screen.getByTestId(\"has-interactable-id\")).toHaveTextContent(\"yes\");\n expect(screen.getByTestId(\"has-description\")).toHaveTextContent(\"yes\");\n });\n\n it(\"should pass through all component props correctly\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n propsSchema: testSchema,\n });\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"Test Title\" count={100} />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Test Title\");\n expect(screen.getByTestId(\"count\")).toHaveTextContent(\"100\");\n });\n\n it(\"should filter out interactable-specific props from component props\", () => {\n interface ExtendedProps extends TestComponentProps {\n onInteractableReady?: (id: string) => void;\n onPropsUpdate?: (props: Record<string, any>) => void;\n }\n\n const ExtendedComponent: React.FC<ExtendedProps> = ({\n title,\n onInteractableReady,\n onPropsUpdate,\n }) => (\n <div>\n <span data-testid=\"title\">{title}</span>\n <span data-testid=\"has-ready\">\n {onInteractableReady ? \"yes\" : \"no\"}\n </span>\n <span data-testid=\"has-update\">{onPropsUpdate ? \"yes\" : \"no\"}</span>\n </div>\n );\n\n const InteractableComponent = withTamboInteractable(ExtendedComponent, {\n componentName: \"ExtendedComponent\",\n description: \"An extended component\",\n });\n\n const mockReady = jest.fn();\n const mockUpdate = jest.fn();\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent\n title=\"Test\"\n onInteractableReady={mockReady}\n onPropsUpdate={mockUpdate}\n />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Test\");\n // These props should be filtered out\n expect(screen.getByTestId(\"has-ready\")).toHaveTextContent(\"no\");\n expect(screen.getByTestId(\"has-update\")).toHaveTextContent(\"no\");\n });\n\n it(\"should work without propsSchema\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n });\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"No Schema\" />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"No Schema\");\n });\n\n it(\"should render before interactable ID is set\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n });\n\n const { container } = render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"Early Render\" />\n </TamboInteractableProvider>,\n );\n\n // Component should render even before ID is available\n expect(\n container.querySelector('[data-testid=\"title\"]'),\n ).toBeInTheDocument();\n });\n\n it(\"should handle null/undefined values in props\", () => {\n interface NullableProps {\n title: string;\n optional?: string;\n nullable: string | null;\n }\n\n const NullableComponent: React.FC<NullableProps> = ({\n title,\n optional,\n nullable,\n }) => (\n <div>\n <span data-testid=\"title\">{title}</span>\n <span data-testid=\"optional\">{optional ?? \"undefined\"}</span>\n <span data-testid=\"nullable\">{nullable ?? \"null\"}</span>\n </div>\n );\n\n const InteractableComponent = withTamboInteractable(NullableComponent, {\n componentName: \"NullableComponent\",\n description: \"A component with nullable props\",\n });\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"Test\" nullable={null} />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Test\");\n expect(screen.getByTestId(\"optional\")).toHaveTextContent(\"undefined\");\n expect(screen.getByTestId(\"nullable\")).toHaveTextContent(\"null\");\n });\n});\n"]}
|
package/esm/hooks/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from "./react-query-hooks";
|
|
2
2
|
export { useTamboComponentState } from "./use-component-state";
|
|
3
|
-
export { useTamboCurrentMessage } from "./use-current-message";
|
|
3
|
+
export { useTamboCurrentComponent, useTamboCurrentMessage, type TamboCurrentComponent, } from "./use-current-message";
|
|
4
4
|
export { useTamboStreamingProps } from "./use-streaming-props";
|
|
5
5
|
export * from "./use-suggestions";
|
|
6
6
|
export { useTamboStreamStatus, type PropStatus, type StreamStatus, } from "./use-tambo-stream-status";
|
package/esm/hooks/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AACA,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AACA,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,cAAc,mBAAmB,CAAC;AAClC,OAAO,EACL,oBAAoB,EACpB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
|
package/esm/hooks/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Export all hooks from this directory
|
|
2
2
|
export * from "./react-query-hooks";
|
|
3
3
|
export { useTamboComponentState } from "./use-component-state";
|
|
4
|
-
export { useTamboCurrentMessage } from "./use-current-message";
|
|
4
|
+
export { useTamboCurrentComponent, useTamboCurrentMessage, } from "./use-current-message";
|
|
5
5
|
export { useTamboStreamingProps } from "./use-streaming-props";
|
|
6
6
|
export * from "./use-suggestions";
|
|
7
7
|
export { useTamboStreamStatus, } from "./use-tambo-stream-status";
|
package/esm/hooks/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EACL,wBAAwB,EACxB,sBAAsB,GAEvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,cAAc,mBAAmB,CAAC;AAClC,OAAO,EACL,oBAAoB,GAGrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC","sourcesContent":["// Export all hooks from this directory\nexport * from \"./react-query-hooks\";\nexport { useTamboComponentState } from \"./use-component-state\";\nexport {\n useTamboCurrentComponent,\n useTamboCurrentMessage,\n type TamboCurrentComponent,\n} from \"./use-current-message\";\nexport { useTamboStreamingProps } from \"./use-streaming-props\";\nexport * from \"./use-suggestions\";\nexport {\n useTamboStreamStatus,\n type PropStatus,\n type StreamStatus,\n} from \"./use-tambo-stream-status\";\nexport { useTamboThreadList } from \"./use-tambo-threads\";\nexport { useTamboVoice } from \"./use-tambo-voice\";\n"]}
|
|
@@ -1,27 +1,71 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { TamboThreadMessage } from "../model/generate-component-response";
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { InteractableMetadata, TamboThreadMessage } from "../model/generate-component-response";
|
|
3
|
+
export interface TamboMessageProviderProps {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
message: TamboThreadMessage;
|
|
6
|
+
/** Optional interactable metadata for components wrapped with withInteractable */
|
|
7
|
+
interactableMetadata?: InteractableMetadata;
|
|
8
|
+
}
|
|
3
9
|
/**
|
|
4
|
-
* Wraps all components, so that they can find what message they are in
|
|
10
|
+
* Wraps all components, so that they can find what message they are in.
|
|
11
|
+
* Also supports optional interactable metadata for components wrapped with withInteractable.
|
|
5
12
|
* @param props - props for the TamboMessageProvider
|
|
6
13
|
* @param props.children - The children to wrap
|
|
7
14
|
* @param props.message - The message object
|
|
15
|
+
* @param props.interactableMetadata - Optional interactable component metadata
|
|
8
16
|
* @returns The wrapped component
|
|
9
17
|
*/
|
|
10
|
-
export declare const TamboMessageProvider: React.FC<
|
|
11
|
-
message: TamboThreadMessage;
|
|
12
|
-
}>>;
|
|
18
|
+
export declare const TamboMessageProvider: React.FC<TamboMessageProviderProps>;
|
|
13
19
|
/**
|
|
14
20
|
* Wraps a component with a TamboMessageProvider - this allows the provider
|
|
15
21
|
* to be used outside of a TSX file
|
|
16
22
|
* @param children - The children to wrap
|
|
17
23
|
* @param message - The message object
|
|
24
|
+
* @param interactableMetadata - Optional interactable metadata
|
|
18
25
|
* @returns The wrapped component
|
|
19
26
|
*/
|
|
20
|
-
export declare function wrapWithTamboMessageProvider(children: React.ReactNode, message: TamboThreadMessage): React.JSX.Element;
|
|
27
|
+
export declare function wrapWithTamboMessageProvider(children: React.ReactNode, message: TamboThreadMessage, interactableMetadata?: InteractableMetadata): React.JSX.Element;
|
|
21
28
|
/**
|
|
22
29
|
* Hook used inside a component wrapped with TamboMessageProvider, to get
|
|
23
30
|
* the current message.
|
|
24
31
|
* @returns The current message that is used to render the component
|
|
25
32
|
*/
|
|
26
33
|
export declare const useTamboCurrentMessage: () => TamboThreadMessage;
|
|
34
|
+
/**
|
|
35
|
+
* Component info extracted from the current message and interactable context.
|
|
36
|
+
* Provides a unified interface for accessing component metadata.
|
|
37
|
+
*/
|
|
38
|
+
export interface TamboCurrentComponent {
|
|
39
|
+
/** Component name from the message */
|
|
40
|
+
componentName?: string;
|
|
41
|
+
/** Component props from the message */
|
|
42
|
+
props?: Record<string, any>;
|
|
43
|
+
/** Interactable ID (only present for components wrapped with withInteractable) */
|
|
44
|
+
interactableId?: string;
|
|
45
|
+
/** Description (only present for components wrapped with withInteractable) */
|
|
46
|
+
description?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Hook to access the current component information from the message context.
|
|
50
|
+
* Provides a unified interface for both AI-generated and interactable components.
|
|
51
|
+
*
|
|
52
|
+
* **Use this hook when you need component metadata regardless of the context.**
|
|
53
|
+
* @returns Component info including name, props, and interactable metadata if available, or null if used outside TamboMessageProvider
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* function MyInlineEditor() {
|
|
57
|
+
* const component = useTamboCurrentComponent();
|
|
58
|
+
*
|
|
59
|
+
* if (!component) return null; // Not inside a component
|
|
60
|
+
*
|
|
61
|
+
* return (
|
|
62
|
+
* <div>
|
|
63
|
+
* Editing: {component.componentName}
|
|
64
|
+
* {component.interactableId && <span>ID: {component.interactableId}</span>}
|
|
65
|
+
* </div>
|
|
66
|
+
* );
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare const useTamboCurrentComponent: () => TamboCurrentComponent | null;
|
|
27
71
|
//# sourceMappingURL=use-current-message.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-current-message.d.ts","sourceRoot":"","sources":["../../src/hooks/use-current-message.tsx"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"use-current-message.d.ts","sourceRoot":"","sources":["../../src/hooks/use-current-message.tsx"],"names":[],"mappings":"AACA,OAAO,KAAoC,MAAM,OAAO,CAAC;AACzD,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,sCAAsC,CAAC;AAI9C,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,kFAAkF;IAClF,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CAC7C;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAkBpE,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,KAAK,CAAC,SAAS,EACzB,OAAO,EAAE,kBAAkB,EAC3B,oBAAoB,CAAC,EAAE,oBAAoB,qBAU5C;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,0BAQlC,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,kFAAkF;IAClF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,wBAAwB,QAAO,qBAAqB,GAAG,IAgBnE,CAAC"}
|
|
@@ -2,27 +2,34 @@
|
|
|
2
2
|
import React, { createContext, useContext } from "react";
|
|
3
3
|
const TamboMessageContext = createContext(null);
|
|
4
4
|
/**
|
|
5
|
-
* Wraps all components, so that they can find what message they are in
|
|
5
|
+
* Wraps all components, so that they can find what message they are in.
|
|
6
|
+
* Also supports optional interactable metadata for components wrapped with withInteractable.
|
|
6
7
|
* @param props - props for the TamboMessageProvider
|
|
7
8
|
* @param props.children - The children to wrap
|
|
8
9
|
* @param props.message - The message object
|
|
10
|
+
* @param props.interactableMetadata - Optional interactable component metadata
|
|
9
11
|
* @returns The wrapped component
|
|
10
12
|
*/
|
|
11
|
-
export const TamboMessageProvider = ({ children, message }) => {
|
|
13
|
+
export const TamboMessageProvider = ({ children, message, interactableMetadata, }) => {
|
|
14
|
+
// Merge interactable metadata into message if provided
|
|
15
|
+
const enhancedMessage = interactableMetadata
|
|
16
|
+
? { ...message, interactableMetadata }
|
|
17
|
+
: message;
|
|
12
18
|
// Use a unique key={...} to force a re-render when the message changes - this
|
|
13
19
|
// make sure that if the rendered component is swapped into a tree (like if
|
|
14
20
|
// you always show the last rendered component) then the state/etc is correct
|
|
15
|
-
return (React.createElement(TamboMessageContext.Provider, { value:
|
|
21
|
+
return (React.createElement(TamboMessageContext.Provider, { value: enhancedMessage, key: message.id }, children));
|
|
16
22
|
};
|
|
17
23
|
/**
|
|
18
24
|
* Wraps a component with a TamboMessageProvider - this allows the provider
|
|
19
25
|
* to be used outside of a TSX file
|
|
20
26
|
* @param children - The children to wrap
|
|
21
27
|
* @param message - The message object
|
|
28
|
+
* @param interactableMetadata - Optional interactable metadata
|
|
22
29
|
* @returns The wrapped component
|
|
23
30
|
*/
|
|
24
|
-
export function wrapWithTamboMessageProvider(children, message) {
|
|
25
|
-
return (React.createElement(TamboMessageProvider, { message: message }, children));
|
|
31
|
+
export function wrapWithTamboMessageProvider(children, message, interactableMetadata) {
|
|
32
|
+
return (React.createElement(TamboMessageProvider, { message: message, interactableMetadata: interactableMetadata }, children));
|
|
26
33
|
}
|
|
27
34
|
/**
|
|
28
35
|
* Hook used inside a component wrapped with TamboMessageProvider, to get
|
|
@@ -36,4 +43,40 @@ export const useTamboCurrentMessage = () => {
|
|
|
36
43
|
}
|
|
37
44
|
return message;
|
|
38
45
|
};
|
|
46
|
+
/**
|
|
47
|
+
* Hook to access the current component information from the message context.
|
|
48
|
+
* Provides a unified interface for both AI-generated and interactable components.
|
|
49
|
+
*
|
|
50
|
+
* **Use this hook when you need component metadata regardless of the context.**
|
|
51
|
+
* @returns Component info including name, props, and interactable metadata if available, or null if used outside TamboMessageProvider
|
|
52
|
+
* @example
|
|
53
|
+
* ```tsx
|
|
54
|
+
* function MyInlineEditor() {
|
|
55
|
+
* const component = useTamboCurrentComponent();
|
|
56
|
+
*
|
|
57
|
+
* if (!component) return null; // Not inside a component
|
|
58
|
+
*
|
|
59
|
+
* return (
|
|
60
|
+
* <div>
|
|
61
|
+
* Editing: {component.componentName}
|
|
62
|
+
* {component.interactableId && <span>ID: {component.interactableId}</span>}
|
|
63
|
+
* </div>
|
|
64
|
+
* );
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export const useTamboCurrentComponent = () => {
|
|
69
|
+
const message = useContext(TamboMessageContext);
|
|
70
|
+
if (!message) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
componentName: message.interactableMetadata?.componentName ??
|
|
75
|
+
message.component?.componentName ??
|
|
76
|
+
undefined,
|
|
77
|
+
props: message.component?.props,
|
|
78
|
+
interactableId: message.interactableMetadata?.id ?? undefined,
|
|
79
|
+
description: message.interactableMetadata?.description ?? undefined,
|
|
80
|
+
};
|
|
81
|
+
};
|
|
39
82
|
//# sourceMappingURL=use-current-message.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-current-message.js","sourceRoot":"","sources":["../../src/hooks/use-current-message.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;AACb,OAAO,KAAK,EAAE,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"use-current-message.js","sourceRoot":"","sources":["../../src/hooks/use-current-message.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;AACb,OAAO,KAAK,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAMzD,MAAM,mBAAmB,GAAG,aAAa,CAA4B,IAAI,CAAC,CAAC;AAS3E;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAwC,CAAC,EACxE,QAAQ,EACR,OAAO,EACP,oBAAoB,GACrB,EAAE,EAAE;IACH,uDAAuD;IACvD,MAAM,eAAe,GAAuB,oBAAoB;QAC9D,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,oBAAoB,EAAE;QACtC,CAAC,CAAC,OAAO,CAAC;IAEZ,8EAA8E;IAC9E,2EAA2E;IAC3E,6EAA6E;IAC7E,OAAO,CACL,oBAAC,mBAAmB,CAAC,QAAQ,IAAC,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,IAClE,QAAQ,CACoB,CAChC,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,4BAA4B,CAC1C,QAAyB,EACzB,OAA2B,EAC3B,oBAA2C;IAE3C,OAAO,CACL,oBAAC,oBAAoB,IACnB,OAAO,EAAE,OAAO,EAChB,oBAAoB,EAAE,oBAAoB,IAEzC,QAAQ,CACY,CACxB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,EAAE;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,mBAAmB,CAAC,CAAC;IAChD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,mEAAmE,CACpE,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAiBF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAiC,EAAE;IACzE,MAAM,OAAO,GAAG,UAAU,CAAC,mBAAmB,CAAC,CAAC;IAEhD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,aAAa,EACX,OAAO,CAAC,oBAAoB,EAAE,aAAa;YAC3C,OAAO,CAAC,SAAS,EAAE,aAAa;YAChC,SAAS;QACX,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,KAAwC;QAClE,cAAc,EAAE,OAAO,CAAC,oBAAoB,EAAE,EAAE,IAAI,SAAS;QAC7D,WAAW,EAAE,OAAO,CAAC,oBAAoB,EAAE,WAAW,IAAI,SAAS;KACpE,CAAC;AACJ,CAAC,CAAC","sourcesContent":["\"use client\";\nimport React, { createContext, useContext } from \"react\";\nimport {\n InteractableMetadata,\n TamboThreadMessage,\n} from \"../model/generate-component-response\";\n\nconst TamboMessageContext = createContext<TamboThreadMessage | null>(null);\n\nexport interface TamboMessageProviderProps {\n children: React.ReactNode;\n message: TamboThreadMessage;\n /** Optional interactable metadata for components wrapped with withInteractable */\n interactableMetadata?: InteractableMetadata;\n}\n\n/**\n * Wraps all components, so that they can find what message they are in.\n * Also supports optional interactable metadata for components wrapped with withInteractable.\n * @param props - props for the TamboMessageProvider\n * @param props.children - The children to wrap\n * @param props.message - The message object\n * @param props.interactableMetadata - Optional interactable component metadata\n * @returns The wrapped component\n */\nexport const TamboMessageProvider: React.FC<TamboMessageProviderProps> = ({\n children,\n message,\n interactableMetadata,\n}) => {\n // Merge interactable metadata into message if provided\n const enhancedMessage: TamboThreadMessage = interactableMetadata\n ? { ...message, interactableMetadata }\n : message;\n\n // Use a unique key={...} to force a re-render when the message changes - this\n // make sure that if the rendered component is swapped into a tree (like if\n // you always show the last rendered component) then the state/etc is correct\n return (\n <TamboMessageContext.Provider value={enhancedMessage} key={message.id}>\n {children}\n </TamboMessageContext.Provider>\n );\n};\n\n/**\n * Wraps a component with a TamboMessageProvider - this allows the provider\n * to be used outside of a TSX file\n * @param children - The children to wrap\n * @param message - The message object\n * @param interactableMetadata - Optional interactable metadata\n * @returns The wrapped component\n */\nexport function wrapWithTamboMessageProvider(\n children: React.ReactNode,\n message: TamboThreadMessage,\n interactableMetadata?: InteractableMetadata,\n) {\n return (\n <TamboMessageProvider\n message={message}\n interactableMetadata={interactableMetadata}\n >\n {children}\n </TamboMessageProvider>\n );\n}\n\n/**\n * Hook used inside a component wrapped with TamboMessageProvider, to get\n * the current message.\n * @returns The current message that is used to render the component\n */\nexport const useTamboCurrentMessage = () => {\n const message = useContext(TamboMessageContext);\n if (!message) {\n throw new Error(\n \"useTamboCurrentMessage must be used within a TamboMessageProvider\",\n );\n }\n return message;\n};\n\n/**\n * Component info extracted from the current message and interactable context.\n * Provides a unified interface for accessing component metadata.\n */\nexport interface TamboCurrentComponent {\n /** Component name from the message */\n componentName?: string;\n /** Component props from the message */\n props?: Record<string, any>;\n /** Interactable ID (only present for components wrapped with withInteractable) */\n interactableId?: string;\n /** Description (only present for components wrapped with withInteractable) */\n description?: string;\n}\n\n/**\n * Hook to access the current component information from the message context.\n * Provides a unified interface for both AI-generated and interactable components.\n *\n * **Use this hook when you need component metadata regardless of the context.**\n * @returns Component info including name, props, and interactable metadata if available, or null if used outside TamboMessageProvider\n * @example\n * ```tsx\n * function MyInlineEditor() {\n * const component = useTamboCurrentComponent();\n *\n * if (!component) return null; // Not inside a component\n *\n * return (\n * <div>\n * Editing: {component.componentName}\n * {component.interactableId && <span>ID: {component.interactableId}</span>}\n * </div>\n * );\n * }\n * ```\n */\nexport const useTamboCurrentComponent = (): TamboCurrentComponent | null => {\n const message = useContext(TamboMessageContext);\n\n if (!message) {\n return null;\n }\n\n return {\n componentName:\n message.interactableMetadata?.componentName ??\n message.component?.componentName ??\n undefined,\n props: message.component?.props as Record<string, any> | undefined,\n interactableId: message.interactableMetadata?.id ?? undefined,\n description: message.interactableMetadata?.description ?? undefined,\n };\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-current-message.test.d.ts","sourceRoot":"","sources":["../../src/hooks/use-current-message.test.tsx"],"names":[],"mappings":""}
|