@tambo-ai/react 0.46.5 → 0.48.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/dist/context-helpers/__tests__/context-helpers-provider.test.js +9 -5
- package/dist/context-helpers/__tests__/context-helpers-provider.test.js.map +1 -1
- package/dist/context-helpers/current-interactables-context-helper.d.ts +28 -0
- package/dist/context-helpers/current-interactables-context-helper.d.ts.map +1 -0
- package/dist/context-helpers/current-interactables-context-helper.js +61 -0
- package/dist/context-helpers/current-interactables-context-helper.js.map +1 -0
- package/dist/context-helpers/index.d.ts +1 -0
- package/dist/context-helpers/index.d.ts.map +1 -1
- package/dist/context-helpers/index.js +1 -0
- package/dist/context-helpers/index.js.map +1 -1
- package/dist/context-helpers/registry.d.ts +1 -22
- package/dist/context-helpers/registry.d.ts.map +1 -1
- package/dist/context-helpers/registry.js +1 -35
- package/dist/context-helpers/registry.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/__tests__/tambo-mcp-provider.test.d.ts +2 -0
- package/dist/mcp/__tests__/tambo-mcp-provider.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/tambo-mcp-provider.test.js +115 -0
- package/dist/mcp/__tests__/tambo-mcp-provider.test.js.map +1 -0
- package/dist/mcp/tambo-mcp-provider.d.ts +6 -0
- package/dist/mcp/tambo-mcp-provider.d.ts.map +1 -1
- package/dist/mcp/tambo-mcp-provider.js +25 -2
- package/dist/mcp/tambo-mcp-provider.js.map +1 -1
- package/dist/providers/__tests__/tambo-context-helpers-provider.test.js +0 -34
- package/dist/providers/__tests__/tambo-context-helpers-provider.test.js.map +1 -1
- package/dist/providers/__tests__/tambo-interactables-additional-context-edge-cases.test.d.ts +2 -0
- package/dist/providers/__tests__/tambo-interactables-additional-context-edge-cases.test.d.ts.map +1 -0
- package/dist/providers/__tests__/tambo-interactables-additional-context-edge-cases.test.js +339 -0
- package/dist/providers/__tests__/tambo-interactables-additional-context-edge-cases.test.js.map +1 -0
- package/dist/providers/__tests__/tambo-interactables-additional-context.test.d.ts +2 -0
- package/dist/providers/__tests__/tambo-interactables-additional-context.test.d.ts.map +1 -0
- package/dist/providers/__tests__/tambo-interactables-additional-context.test.js +299 -0
- package/dist/providers/__tests__/tambo-interactables-additional-context.test.js.map +1 -0
- package/dist/providers/tambo-context-helpers-provider.d.ts +1 -1
- package/dist/providers/tambo-context-helpers-provider.d.ts.map +1 -1
- package/dist/providers/tambo-context-helpers-provider.js +33 -21
- package/dist/providers/tambo-context-helpers-provider.js.map +1 -1
- package/dist/providers/tambo-interactable-provider.d.ts +20 -0
- package/dist/providers/tambo-interactable-provider.d.ts.map +1 -1
- package/dist/providers/tambo-interactable-provider.js +117 -85
- package/dist/providers/tambo-interactable-provider.js.map +1 -1
- package/esm/context-helpers/__tests__/context-helpers-provider.test.js +10 -6
- package/esm/context-helpers/__tests__/context-helpers-provider.test.js.map +1 -1
- package/esm/context-helpers/current-interactables-context-helper.d.ts +28 -0
- package/esm/context-helpers/current-interactables-context-helper.d.ts.map +1 -0
- package/esm/context-helpers/current-interactables-context-helper.js +56 -0
- package/esm/context-helpers/current-interactables-context-helper.js.map +1 -0
- package/esm/context-helpers/index.d.ts +1 -0
- package/esm/context-helpers/index.d.ts.map +1 -1
- package/esm/context-helpers/index.js +1 -0
- package/esm/context-helpers/index.js.map +1 -1
- package/esm/context-helpers/registry.d.ts +1 -22
- package/esm/context-helpers/registry.d.ts.map +1 -1
- package/esm/context-helpers/registry.js +1 -31
- package/esm/context-helpers/registry.js.map +1 -1
- package/esm/index.d.ts +1 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -1
- package/esm/index.js.map +1 -1
- package/esm/mcp/__tests__/tambo-mcp-provider.test.d.ts +2 -0
- package/esm/mcp/__tests__/tambo-mcp-provider.test.d.ts.map +1 -0
- package/esm/mcp/__tests__/tambo-mcp-provider.test.js +113 -0
- package/esm/mcp/__tests__/tambo-mcp-provider.test.js.map +1 -0
- package/esm/mcp/tambo-mcp-provider.d.ts +6 -0
- package/esm/mcp/tambo-mcp-provider.d.ts.map +1 -1
- package/esm/mcp/tambo-mcp-provider.js +24 -2
- package/esm/mcp/tambo-mcp-provider.js.map +1 -1
- package/esm/providers/__tests__/tambo-context-helpers-provider.test.js +0 -34
- package/esm/providers/__tests__/tambo-context-helpers-provider.test.js.map +1 -1
- package/esm/providers/__tests__/tambo-interactables-additional-context-edge-cases.test.d.ts +2 -0
- package/esm/providers/__tests__/tambo-interactables-additional-context-edge-cases.test.d.ts.map +1 -0
- package/esm/providers/__tests__/tambo-interactables-additional-context-edge-cases.test.js +334 -0
- package/esm/providers/__tests__/tambo-interactables-additional-context-edge-cases.test.js.map +1 -0
- package/esm/providers/__tests__/tambo-interactables-additional-context.test.d.ts +2 -0
- package/esm/providers/__tests__/tambo-interactables-additional-context.test.d.ts.map +1 -0
- package/esm/providers/__tests__/tambo-interactables-additional-context.test.js +294 -0
- package/esm/providers/__tests__/tambo-interactables-additional-context.test.js.map +1 -0
- package/esm/providers/tambo-context-helpers-provider.d.ts +1 -1
- package/esm/providers/tambo-context-helpers-provider.d.ts.map +1 -1
- package/esm/providers/tambo-context-helpers-provider.js +35 -23
- package/esm/providers/tambo-context-helpers-provider.js.map +1 -1
- package/esm/providers/tambo-interactable-provider.d.ts +20 -0
- package/esm/providers/tambo-interactable-provider.d.ts.map +1 -1
- package/esm/providers/tambo-interactable-provider.js +115 -84
- package/esm/providers/tambo-interactable-provider.js.map +1 -1
- package/package.json +8 -8
- package/dist/mcp/mcp-tools-client.d.ts +0 -96
- package/dist/mcp/mcp-tools-client.d.ts.map +0 -1
- package/dist/mcp/mcp-tools-client.js +0 -178
- package/dist/mcp/mcp-tools-client.js.map +0 -1
- package/esm/mcp/mcp-tools-client.d.ts +0 -96
- package/esm/mcp/mcp-tools-client.d.ts.map +0 -1
- package/esm/mcp/mcp-tools-client.js +0 -174
- package/esm/mcp/mcp-tools-client.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tambo-interactables-additional-context.test.d.ts","sourceRoot":"","sources":["../../../src/providers/__tests__/tambo-interactables-additional-context.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const react_1 = require("@testing-library/react");
|
|
7
|
+
const react_2 = __importDefault(require("react"));
|
|
8
|
+
const zod_1 = require("zod");
|
|
9
|
+
const tambo_context_helpers_provider_1 = require("../tambo-context-helpers-provider");
|
|
10
|
+
const tambo_interactable_provider_1 = require("../tambo-interactable-provider");
|
|
11
|
+
const tambo_stubs_1 = require("../tambo-stubs");
|
|
12
|
+
const with_tambo_interactable_1 = require("../hoc/with-tambo-interactable");
|
|
13
|
+
function wrapperWithProviders(children) {
|
|
14
|
+
const thread = {
|
|
15
|
+
id: "t-1",
|
|
16
|
+
projectId: "p-1",
|
|
17
|
+
createdAt: new Date().toISOString(),
|
|
18
|
+
updatedAt: new Date().toISOString(),
|
|
19
|
+
messages: [],
|
|
20
|
+
metadata: {},
|
|
21
|
+
};
|
|
22
|
+
return (react_2.default.createElement(tambo_stubs_1.TamboStubProvider, { thread: thread, registerTool: () => { }, registerTools: () => { }, registerComponent: () => { }, addToolAssociation: () => { } },
|
|
23
|
+
react_2.default.createElement(tambo_context_helpers_provider_1.TamboContextHelpersProvider, null, children)));
|
|
24
|
+
}
|
|
25
|
+
describe("Interactables AdditionalContext (provider-based)", () => {
|
|
26
|
+
test("registers default helper and returns payload with description and components", async () => {
|
|
27
|
+
const Note = ({ title }) => react_2.default.createElement("div", null, title);
|
|
28
|
+
const InteractableNote = (0, with_tambo_interactable_1.withTamboInteractable)(Note, {
|
|
29
|
+
componentName: "Note",
|
|
30
|
+
description: "A note",
|
|
31
|
+
propsSchema: zod_1.z.object({ title: zod_1.z.string() }),
|
|
32
|
+
});
|
|
33
|
+
let capturedContexts = [];
|
|
34
|
+
const TestComponent = () => {
|
|
35
|
+
const { getAdditionalContext } = (0, tambo_context_helpers_provider_1.useTamboContextHelpers)();
|
|
36
|
+
react_2.default.useEffect(() => {
|
|
37
|
+
let mounted = true;
|
|
38
|
+
getAdditionalContext().then((contexts) => {
|
|
39
|
+
if (mounted) {
|
|
40
|
+
capturedContexts = contexts;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return () => {
|
|
44
|
+
mounted = false;
|
|
45
|
+
};
|
|
46
|
+
}, [getAdditionalContext]);
|
|
47
|
+
return react_2.default.createElement("div", { "data-testid": "ready" }, "ready");
|
|
48
|
+
};
|
|
49
|
+
const { getByTestId } = (0, react_1.render)(wrapperWithProviders(react_2.default.createElement(tambo_interactable_provider_1.TamboInteractableProvider, null,
|
|
50
|
+
react_2.default.createElement(InteractableNote, { title: "hello" }),
|
|
51
|
+
react_2.default.createElement(TestComponent, null))));
|
|
52
|
+
await (0, react_1.waitFor)(() => {
|
|
53
|
+
expect(getByTestId("ready")).toBeInTheDocument();
|
|
54
|
+
const entry = capturedContexts.find((c) => c.name === "interactables");
|
|
55
|
+
expect(entry).toBeDefined();
|
|
56
|
+
expect(entry?.context?.description).toMatch(/interactable components/i);
|
|
57
|
+
expect(Array.isArray(entry?.context?.components)).toBe(true);
|
|
58
|
+
const comp = entry.context.components[0];
|
|
59
|
+
expect(comp.componentName).toBe("Note");
|
|
60
|
+
expect(comp.props).toEqual({ title: "hello" });
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
test("returns null when no interactable components are present", async () => {
|
|
64
|
+
let capturedContexts = [];
|
|
65
|
+
const TestComponent = () => {
|
|
66
|
+
const { getAdditionalContext } = (0, tambo_context_helpers_provider_1.useTamboContextHelpers)();
|
|
67
|
+
react_2.default.useEffect(() => {
|
|
68
|
+
let mounted = true;
|
|
69
|
+
getAdditionalContext().then((contexts) => {
|
|
70
|
+
if (mounted) {
|
|
71
|
+
capturedContexts = contexts;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return () => {
|
|
75
|
+
mounted = false;
|
|
76
|
+
};
|
|
77
|
+
}, [getAdditionalContext]);
|
|
78
|
+
return react_2.default.createElement("div", { "data-testid": "ready" }, "ready");
|
|
79
|
+
};
|
|
80
|
+
const { getByTestId } = (0, react_1.render)(wrapperWithProviders(react_2.default.createElement(tambo_interactable_provider_1.TamboInteractableProvider, null,
|
|
81
|
+
react_2.default.createElement("div", null, "No interactables here"),
|
|
82
|
+
react_2.default.createElement(TestComponent, null))));
|
|
83
|
+
await (0, react_1.waitFor)(() => {
|
|
84
|
+
expect(getByTestId("ready")).toBeInTheDocument();
|
|
85
|
+
const entry = capturedContexts.find((c) => c.name === "interactables");
|
|
86
|
+
expect(entry).toBeUndefined(); // Should be filtered out when helper returns null
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
test("context includes proper AI prompt with clear instructions", async () => {
|
|
90
|
+
const Note = ({ title }) => react_2.default.createElement("div", null, title);
|
|
91
|
+
const InteractableNote = (0, with_tambo_interactable_1.withTamboInteractable)(Note, {
|
|
92
|
+
componentName: "Note",
|
|
93
|
+
description: "A simple note",
|
|
94
|
+
propsSchema: zod_1.z.object({ title: zod_1.z.string() }),
|
|
95
|
+
});
|
|
96
|
+
let capturedContexts = [];
|
|
97
|
+
const TestComponent = () => {
|
|
98
|
+
const { getAdditionalContext } = (0, tambo_context_helpers_provider_1.useTamboContextHelpers)();
|
|
99
|
+
react_2.default.useEffect(() => {
|
|
100
|
+
let mounted = true;
|
|
101
|
+
getAdditionalContext().then((contexts) => {
|
|
102
|
+
if (mounted) {
|
|
103
|
+
capturedContexts = contexts;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
return () => {
|
|
107
|
+
mounted = false;
|
|
108
|
+
};
|
|
109
|
+
}, [getAdditionalContext]);
|
|
110
|
+
return react_2.default.createElement("div", { "data-testid": "ready" }, "ready");
|
|
111
|
+
};
|
|
112
|
+
const { getByTestId } = (0, react_1.render)(wrapperWithProviders(react_2.default.createElement(tambo_interactable_provider_1.TamboInteractableProvider, null,
|
|
113
|
+
react_2.default.createElement(InteractableNote, { title: "test" }),
|
|
114
|
+
react_2.default.createElement(TestComponent, null))));
|
|
115
|
+
await (0, react_1.waitFor)(() => {
|
|
116
|
+
expect(getByTestId("ready")).toBeInTheDocument();
|
|
117
|
+
const entry = capturedContexts.find((c) => c.name === "interactables");
|
|
118
|
+
expect(entry?.context?.description).toContain("interactable components");
|
|
119
|
+
expect(entry?.context?.description).toContain("visible on the page");
|
|
120
|
+
expect(entry?.context?.description).toContain("you can read and modify");
|
|
121
|
+
expect(entry?.context?.description).toContain("tools to update");
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
test("includes component metadata in expected format", async () => {
|
|
125
|
+
const Note = ({ title, color = "white", }) => react_2.default.createElement("div", { className: `note-${color}` }, title);
|
|
126
|
+
const InteractableNote = (0, with_tambo_interactable_1.withTamboInteractable)(Note, {
|
|
127
|
+
componentName: "Note",
|
|
128
|
+
description: "A colorful note component",
|
|
129
|
+
propsSchema: zod_1.z.object({
|
|
130
|
+
title: zod_1.z.string(),
|
|
131
|
+
color: zod_1.z.string().optional(),
|
|
132
|
+
}),
|
|
133
|
+
});
|
|
134
|
+
let capturedContexts = [];
|
|
135
|
+
const TestComponent = () => {
|
|
136
|
+
const { getAdditionalContext } = (0, tambo_context_helpers_provider_1.useTamboContextHelpers)();
|
|
137
|
+
react_2.default.useEffect(() => {
|
|
138
|
+
let mounted = true;
|
|
139
|
+
getAdditionalContext().then((contexts) => {
|
|
140
|
+
if (mounted) {
|
|
141
|
+
capturedContexts = contexts;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
return () => {
|
|
145
|
+
mounted = false;
|
|
146
|
+
};
|
|
147
|
+
}, [getAdditionalContext]);
|
|
148
|
+
return react_2.default.createElement("div", { "data-testid": "ready" }, "ready");
|
|
149
|
+
};
|
|
150
|
+
const { getByTestId } = (0, react_1.render)(wrapperWithProviders(react_2.default.createElement(tambo_interactable_provider_1.TamboInteractableProvider, null,
|
|
151
|
+
react_2.default.createElement(InteractableNote, { title: "test note", color: "blue" }),
|
|
152
|
+
react_2.default.createElement(TestComponent, null))));
|
|
153
|
+
await (0, react_1.waitFor)(() => {
|
|
154
|
+
expect(getByTestId("ready")).toBeInTheDocument();
|
|
155
|
+
const entry = capturedContexts.find((c) => c.name === "interactables");
|
|
156
|
+
const component = entry.context.components[0];
|
|
157
|
+
expect(component).toMatchObject({
|
|
158
|
+
id: expect.any(String),
|
|
159
|
+
componentName: "Note",
|
|
160
|
+
description: "A colorful note component",
|
|
161
|
+
props: { title: "test note", color: "blue" },
|
|
162
|
+
propsSchema: "Available - use component-specific update tools",
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
test("snapshot hook returns immutable copies", async () => {
|
|
167
|
+
const Note = ({ title }) => react_2.default.createElement("div", null, title);
|
|
168
|
+
const InteractableNote = (0, with_tambo_interactable_1.withTamboInteractable)(Note, {
|
|
169
|
+
componentName: "Note",
|
|
170
|
+
description: "A note",
|
|
171
|
+
propsSchema: zod_1.z.object({ title: zod_1.z.string() }),
|
|
172
|
+
});
|
|
173
|
+
const TestComponent = () => {
|
|
174
|
+
const snapshot = (0, tambo_interactable_provider_1.useCurrentInteractablesSnapshot)();
|
|
175
|
+
const [testResult, setTestResult] = react_2.default.useState("pending");
|
|
176
|
+
react_2.default.useEffect(() => {
|
|
177
|
+
if (snapshot.length > 0) {
|
|
178
|
+
const originalLength = snapshot.length;
|
|
179
|
+
// Try to mutate the returned array and props
|
|
180
|
+
snapshot.push({
|
|
181
|
+
id: "fake",
|
|
182
|
+
name: "Fake",
|
|
183
|
+
description: "",
|
|
184
|
+
component: () => null,
|
|
185
|
+
props: {},
|
|
186
|
+
});
|
|
187
|
+
snapshot[0].props.title = "MUTATED";
|
|
188
|
+
// The mutations should succeed on the returned copy, proving it's a separate object
|
|
189
|
+
if (snapshot.length === originalLength + 1 &&
|
|
190
|
+
snapshot[0].props.title === "MUTATED") {
|
|
191
|
+
setTestResult("mutation-successful-but-isolated");
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
setTestResult("mutation-failed");
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}, [snapshot]);
|
|
198
|
+
return react_2.default.createElement("div", { "data-testid": "test-result" }, testResult);
|
|
199
|
+
};
|
|
200
|
+
const { getByTestId } = (0, react_1.render)(wrapperWithProviders(react_2.default.createElement(tambo_interactable_provider_1.TamboInteractableProvider, null,
|
|
201
|
+
react_2.default.createElement(InteractableNote, { title: "immutable test" }),
|
|
202
|
+
react_2.default.createElement(TestComponent, null))));
|
|
203
|
+
await (0, react_1.waitFor)(() => {
|
|
204
|
+
const result = getByTestId("test-result").textContent;
|
|
205
|
+
expect(result).toBe("mutation-successful-but-isolated");
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
test("multiple interactables from same provider appear in context", async () => {
|
|
209
|
+
const Note = ({ title }) => react_2.default.createElement("div", null, title);
|
|
210
|
+
const Counter = ({ count }) => (react_2.default.createElement("div", null, count));
|
|
211
|
+
const InteractableNote = (0, with_tambo_interactable_1.withTamboInteractable)(Note, {
|
|
212
|
+
componentName: "Note",
|
|
213
|
+
description: "A note",
|
|
214
|
+
propsSchema: zod_1.z.object({ title: zod_1.z.string() }),
|
|
215
|
+
});
|
|
216
|
+
const InteractableCounter = (0, with_tambo_interactable_1.withTamboInteractable)(Counter, {
|
|
217
|
+
componentName: "Counter",
|
|
218
|
+
description: "A counter",
|
|
219
|
+
propsSchema: zod_1.z.object({ count: zod_1.z.number() }),
|
|
220
|
+
});
|
|
221
|
+
let capturedContexts = [];
|
|
222
|
+
const TestComponent = () => {
|
|
223
|
+
const { getAdditionalContext } = (0, tambo_context_helpers_provider_1.useTamboContextHelpers)();
|
|
224
|
+
react_2.default.useEffect(() => {
|
|
225
|
+
let mounted = true;
|
|
226
|
+
getAdditionalContext().then((contexts) => {
|
|
227
|
+
if (mounted) {
|
|
228
|
+
capturedContexts = contexts;
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
return () => {
|
|
232
|
+
mounted = false;
|
|
233
|
+
};
|
|
234
|
+
}, [getAdditionalContext]);
|
|
235
|
+
return react_2.default.createElement("div", { "data-testid": "ready" }, "ready");
|
|
236
|
+
};
|
|
237
|
+
const { getByTestId } = (0, react_1.render)(wrapperWithProviders(react_2.default.createElement(tambo_interactable_provider_1.TamboInteractableProvider, null,
|
|
238
|
+
react_2.default.createElement(InteractableNote, { title: "first" }),
|
|
239
|
+
react_2.default.createElement(InteractableCounter, { count: 42 }),
|
|
240
|
+
react_2.default.createElement(TestComponent, null))));
|
|
241
|
+
await (0, react_1.waitFor)(() => {
|
|
242
|
+
expect(getByTestId("ready")).toBeInTheDocument();
|
|
243
|
+
const entry = capturedContexts.find((c) => c.name === "interactables");
|
|
244
|
+
expect(entry?.context?.components).toHaveLength(2);
|
|
245
|
+
const components = entry.context.components;
|
|
246
|
+
expect(components[0].componentName).toBe("Note");
|
|
247
|
+
expect(components[0].props).toEqual({ title: "first" });
|
|
248
|
+
expect(components[1].componentName).toBe("Counter");
|
|
249
|
+
expect(components[1].props).toEqual({ count: 42 });
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
test("can be disabled by returning null", async () => {
|
|
253
|
+
const Note = ({ title }) => react_2.default.createElement("div", null, title);
|
|
254
|
+
const InteractableNote = (0, with_tambo_interactable_1.withTamboInteractable)(Note, {
|
|
255
|
+
componentName: "Note",
|
|
256
|
+
description: "A note",
|
|
257
|
+
propsSchema: zod_1.z.object({ title: zod_1.z.string() }),
|
|
258
|
+
});
|
|
259
|
+
// Create a context helpers provider with a disabled interactables helper
|
|
260
|
+
const DisabledContextHelpers = ({ children, }) => (react_2.default.createElement(tambo_context_helpers_provider_1.TamboContextHelpersProvider, { contextHelpers: {
|
|
261
|
+
["interactables"]: () => null,
|
|
262
|
+
} }, children));
|
|
263
|
+
let capturedContexts = [];
|
|
264
|
+
const TestComponent = () => {
|
|
265
|
+
const { getAdditionalContext } = (0, tambo_context_helpers_provider_1.useTamboContextHelpers)();
|
|
266
|
+
react_2.default.useEffect(() => {
|
|
267
|
+
let mounted = true;
|
|
268
|
+
getAdditionalContext().then((contexts) => {
|
|
269
|
+
if (mounted) {
|
|
270
|
+
capturedContexts = contexts;
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
return () => {
|
|
274
|
+
mounted = false;
|
|
275
|
+
};
|
|
276
|
+
}, [getAdditionalContext]);
|
|
277
|
+
return react_2.default.createElement("div", { "data-testid": "ready" }, "ready");
|
|
278
|
+
};
|
|
279
|
+
const thread = {
|
|
280
|
+
id: "t-1",
|
|
281
|
+
projectId: "p-1",
|
|
282
|
+
createdAt: new Date().toISOString(),
|
|
283
|
+
updatedAt: new Date().toISOString(),
|
|
284
|
+
messages: [],
|
|
285
|
+
metadata: {},
|
|
286
|
+
};
|
|
287
|
+
const { getByTestId } = (0, react_1.render)(react_2.default.createElement(tambo_stubs_1.TamboStubProvider, { thread: thread, registerTool: () => { }, registerTools: () => { }, registerComponent: () => { }, addToolAssociation: () => { } },
|
|
288
|
+
react_2.default.createElement(DisabledContextHelpers, null,
|
|
289
|
+
react_2.default.createElement(tambo_interactable_provider_1.TamboInteractableProvider, null,
|
|
290
|
+
react_2.default.createElement(InteractableNote, { title: "should not appear" }),
|
|
291
|
+
react_2.default.createElement(TestComponent, null)))));
|
|
292
|
+
await (0, react_1.waitFor)(() => {
|
|
293
|
+
expect(getByTestId("ready")).toBeInTheDocument();
|
|
294
|
+
const entry = capturedContexts.find((c) => c.name === "interactables");
|
|
295
|
+
expect(entry).toBeUndefined(); // Should be filtered out when helper returns null
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
//# sourceMappingURL=tambo-interactables-additional-context.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tambo-interactables-additional-context.test.js","sourceRoot":"","sources":["../../../src/providers/__tests__/tambo-interactables-additional-context.test.tsx"],"names":[],"mappings":";;;;;AAAA,kDAAyD;AACzD,kDAA0B;AAC1B,6BAAwB;AACxB,sFAG2C;AAC3C,gFAGwC;AACxC,gDAAmD;AACnD,4EAAuE;AAEvE,SAAS,oBAAoB,CAAC,QAAyB;IACrD,MAAM,MAAM,GAAG;QACb,EAAE,EAAE,KAAK;QACT,SAAS,EAAE,KAAK;QAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,QAAQ,EAAE,EAAE;QACZ,QAAQ,EAAE,EAAE;KACN,CAAC;IAET,OAAO,CACL,8BAAC,+BAAiB,IAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,GAAG,EAAE,GAAE,CAAC,EACtB,aAAa,EAAE,GAAG,EAAE,GAAE,CAAC,EACvB,iBAAiB,EAAE,GAAG,EAAE,GAAE,CAAC,EAC3B,kBAAkB,EAAE,GAAG,EAAE,GAAE,CAAC;QAE5B,8BAAC,4DAA2B,QAAE,QAAQ,CAA+B,CACnD,CACrB,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,kDAAkD,EAAE,GAAG,EAAE;IAChE,IAAI,CAAC,8EAA8E,EAAE,KAAK,IAAI,EAAE;QAC9F,MAAM,IAAI,GAAgC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,2CAAM,KAAK,CAAO,CAAC;QAE5E,MAAM,gBAAgB,GAAG,IAAA,+CAAqB,EAAC,IAAI,EAAE;YACnD,aAAa,EAAE,MAAM;YACrB,WAAW,EAAE,QAAQ;YACrB,WAAW,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,EAAE,CAAC;SAC7C,CAAC,CAAC;QAEH,IAAI,gBAAgB,GAAU,EAAE,CAAC;QACjC,MAAM,aAAa,GAAG,GAAG,EAAE;YACzB,MAAM,EAAE,oBAAoB,EAAE,GAAG,IAAA,uDAAsB,GAAE,CAAC;YAE1D,eAAK,CAAC,SAAS,CAAC,GAAG,EAAE;gBACnB,IAAI,OAAO,GAAG,IAAI,CAAC;gBACnB,oBAAoB,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;oBACvC,IAAI,OAAO,EAAE,CAAC;wBACZ,gBAAgB,GAAG,QAAQ,CAAC;oBAC9B,CAAC;gBACH,CAAC,CAAC,CAAC;gBACH,OAAO,GAAG,EAAE;oBACV,OAAO,GAAG,KAAK,CAAC;gBAClB,CAAC,CAAC;YACJ,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAE3B,OAAO,sDAAiB,OAAO,YAAY,CAAC;QAC9C,CAAC,CAAC;QAEF,MAAM,EAAE,WAAW,EAAE,GAAG,IAAA,cAAM,EAC5B,oBAAoB,CAClB,8BAAC,uDAAyB;YACxB,8BAAC,gBAAgB,IAAC,KAAK,EAAC,OAAO,GAAG;YAClC,8BAAC,aAAa,OAAG,CACS,CAC7B,CACF,CAAC;QAEF,MAAM,IAAA,eAAO,EAAC,GAAG,EAAE;YACjB,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC;YACjD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CACjC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CACvC,CAAC;YACF,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;YAC5B,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;YACxE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7D,MAAM,IAAI,GAAG,KAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QAC1E,IAAI,gBAAgB,GAAU,EAAE,CAAC;QACjC,MAAM,aAAa,GAAG,GAAG,EAAE;YACzB,MAAM,EAAE,oBAAoB,EAAE,GAAG,IAAA,uDAAsB,GAAE,CAAC;YAE1D,eAAK,CAAC,SAAS,CAAC,GAAG,EAAE;gBACnB,IAAI,OAAO,GAAG,IAAI,CAAC;gBACnB,oBAAoB,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;oBACvC,IAAI,OAAO,EAAE,CAAC;wBACZ,gBAAgB,GAAG,QAAQ,CAAC;oBAC9B,CAAC;gBACH,CAAC,CAAC,CAAC;gBACH,OAAO,GAAG,EAAE;oBACV,OAAO,GAAG,KAAK,CAAC;gBAClB,CAAC,CAAC;YACJ,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAE3B,OAAO,sDAAiB,OAAO,YAAY,CAAC;QAC9C,CAAC,CAAC;QAEF,MAAM,EAAE,WAAW,EAAE,GAAG,IAAA,cAAM,EAC5B,oBAAoB,CAClB,8BAAC,uDAAyB;YACxB,mEAAgC;YAChC,8BAAC,aAAa,OAAG,CACS,CAC7B,CACF,CAAC;QAEF,MAAM,IAAA,eAAO,EAAC,GAAG,EAAE;YACjB,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC;YACjD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CACjC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CACvC,CAAC;YACF,MAAM,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,kDAAkD;QACnF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,IAAI,GAAgC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,2CAAM,KAAK,CAAO,CAAC;QAC5E,MAAM,gBAAgB,GAAG,IAAA,+CAAqB,EAAC,IAAI,EAAE;YACnD,aAAa,EAAE,MAAM;YACrB,WAAW,EAAE,eAAe;YAC5B,WAAW,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,EAAE,CAAC;SAC7C,CAAC,CAAC;QAEH,IAAI,gBAAgB,GAAU,EAAE,CAAC;QACjC,MAAM,aAAa,GAAG,GAAG,EAAE;YACzB,MAAM,EAAE,oBAAoB,EAAE,GAAG,IAAA,uDAAsB,GAAE,CAAC;YAE1D,eAAK,CAAC,SAAS,CAAC,GAAG,EAAE;gBACnB,IAAI,OAAO,GAAG,IAAI,CAAC;gBACnB,oBAAoB,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;oBACvC,IAAI,OAAO,EAAE,CAAC;wBACZ,gBAAgB,GAAG,QAAQ,CAAC;oBAC9B,CAAC;gBACH,CAAC,CAAC,CAAC;gBACH,OAAO,GAAG,EAAE;oBACV,OAAO,GAAG,KAAK,CAAC;gBAClB,CAAC,CAAC;YACJ,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAE3B,OAAO,sDAAiB,OAAO,YAAY,CAAC;QAC9C,CAAC,CAAC;QAEF,MAAM,EAAE,WAAW,EAAE,GAAG,IAAA,cAAM,EAC5B,oBAAoB,CAClB,8BAAC,uDAAyB;YACxB,8BAAC,gBAAgB,IAAC,KAAK,EAAC,MAAM,GAAG;YACjC,8BAAC,aAAa,OAAG,CACS,CAC7B,CACF,CAAC;QAEF,MAAM,IAAA,eAAO,EAAC,GAAG,EAAE;YACjB,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC;YACjD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CACjC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CACvC,CAAC;YACF,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;YACzE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC;YACrE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;YACzE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,IAAI,GAAgD,CAAC,EACzD,KAAK,EACL,KAAK,GAAG,OAAO,GAChB,EAAE,EAAE,CAAC,uCAAK,SAAS,EAAE,QAAQ,KAAK,EAAE,IAAG,KAAK,CAAO,CAAC;QAErD,MAAM,gBAAgB,GAAG,IAAA,+CAAqB,EAAC,IAAI,EAAE;YACnD,aAAa,EAAE,MAAM;YACrB,WAAW,EAAE,2BAA2B;YACxC,WAAW,EAAE,OAAC,CAAC,MAAM,CAAC;gBACpB,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;gBACjB,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC7B,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,gBAAgB,GAAU,EAAE,CAAC;QACjC,MAAM,aAAa,GAAG,GAAG,EAAE;YACzB,MAAM,EAAE,oBAAoB,EAAE,GAAG,IAAA,uDAAsB,GAAE,CAAC;YAE1D,eAAK,CAAC,SAAS,CAAC,GAAG,EAAE;gBACnB,IAAI,OAAO,GAAG,IAAI,CAAC;gBACnB,oBAAoB,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;oBACvC,IAAI,OAAO,EAAE,CAAC;wBACZ,gBAAgB,GAAG,QAAQ,CAAC;oBAC9B,CAAC;gBACH,CAAC,CAAC,CAAC;gBACH,OAAO,GAAG,EAAE;oBACV,OAAO,GAAG,KAAK,CAAC;gBAClB,CAAC,CAAC;YACJ,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAE3B,OAAO,sDAAiB,OAAO,YAAY,CAAC;QAC9C,CAAC,CAAC;QAEF,MAAM,EAAE,WAAW,EAAE,GAAG,IAAA,cAAM,EAC5B,oBAAoB,CAClB,8BAAC,uDAAyB;YACxB,8BAAC,gBAAgB,IAAC,KAAK,EAAC,WAAW,EAAC,KAAK,EAAC,MAAM,GAAG;YACnD,8BAAC,aAAa,OAAG,CACS,CAC7B,CACF,CAAC;QAEF,MAAM,IAAA,eAAO,EAAC,GAAG,EAAE;YACjB,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC;YACjD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CACjC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CACvC,CAAC;YACF,MAAM,SAAS,GAAG,KAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAE/C,MAAM,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC;gBAC9B,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;gBACtB,aAAa,EAAE,MAAM;gBACrB,WAAW,EAAE,2BAA2B;gBACxC,KAAK,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE;gBAC5C,WAAW,EAAE,iDAAiD;aAC/D,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,IAAI,GAAgC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,2CAAM,KAAK,CAAO,CAAC;QAC5E,MAAM,gBAAgB,GAAG,IAAA,+CAAqB,EAAC,IAAI,EAAE;YACnD,aAAa,EAAE,MAAM;YACrB,WAAW,EAAE,QAAQ;YACrB,WAAW,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,EAAE,CAAC;SAC7C,CAAC,CAAC;QAEH,MAAM,aAAa,GAAG,GAAG,EAAE;YACzB,MAAM,QAAQ,GAAG,IAAA,6DAA+B,GAAE,CAAC;YACnD,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,eAAK,CAAC,QAAQ,CAAS,SAAS,CAAC,CAAC;YAEtE,eAAK,CAAC,SAAS,CAAC,GAAG,EAAE;gBACnB,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACxB,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC;oBAEvC,6CAA6C;oBAC7C,QAAQ,CAAC,IAAI,CAAC;wBACZ,EAAE,EAAE,MAAM;wBACV,IAAI,EAAE,MAAM;wBACZ,WAAW,EAAE,EAAE;wBACf,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI;wBACrB,KAAK,EAAE,EAAE;qBACH,CAAC,CAAC;oBACT,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAa,CAAC,KAAK,GAAG,SAAS,CAAC;oBAE7C,oFAAoF;oBACpF,IACE,QAAQ,CAAC,MAAM,KAAK,cAAc,GAAG,CAAC;wBACtC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,EACrC,CAAC;wBACD,aAAa,CAAC,kCAAkC,CAAC,CAAC;oBACpD,CAAC;yBAAM,CAAC;wBACN,aAAa,CAAC,iBAAiB,CAAC,CAAC;oBACnC,CAAC;gBACH,CAAC;YACH,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAEf,OAAO,sDAAiB,aAAa,IAAE,UAAU,CAAO,CAAC;QAC3D,CAAC,CAAC;QAEF,MAAM,EAAE,WAAW,EAAE,GAAG,IAAA,cAAM,EAC5B,oBAAoB,CAClB,8BAAC,uDAAyB;YACxB,8BAAC,gBAAgB,IAAC,KAAK,EAAC,gBAAgB,GAAG;YAC3C,8BAAC,aAAa,OAAG,CACS,CAC7B,CACF,CAAC;QAEF,MAAM,IAAA,eAAO,EAAC,GAAG,EAAE;YACjB,MAAM,MAAM,GAAG,WAAW,CAAC,aAAa,CAAC,CAAC,WAAW,CAAC;YACtD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC7E,MAAM,IAAI,GAAgC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,2CAAM,KAAK,CAAO,CAAC;QAC5E,MAAM,OAAO,GAAgC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAC1D,2CAAM,KAAK,CAAO,CACnB,CAAC;QAEF,MAAM,gBAAgB,GAAG,IAAA,+CAAqB,EAAC,IAAI,EAAE;YACnD,aAAa,EAAE,MAAM;YACrB,WAAW,EAAE,QAAQ;YACrB,WAAW,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,EAAE,CAAC;SAC7C,CAAC,CAAC;QAEH,MAAM,mBAAmB,GAAG,IAAA,+CAAqB,EAAC,OAAO,EAAE;YACzD,aAAa,EAAE,SAAS;YACxB,WAAW,EAAE,WAAW;YACxB,WAAW,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,EAAE,CAAC;SAC7C,CAAC,CAAC;QAEH,IAAI,gBAAgB,GAAU,EAAE,CAAC;QACjC,MAAM,aAAa,GAAG,GAAG,EAAE;YACzB,MAAM,EAAE,oBAAoB,EAAE,GAAG,IAAA,uDAAsB,GAAE,CAAC;YAE1D,eAAK,CAAC,SAAS,CAAC,GAAG,EAAE;gBACnB,IAAI,OAAO,GAAG,IAAI,CAAC;gBACnB,oBAAoB,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;oBACvC,IAAI,OAAO,EAAE,CAAC;wBACZ,gBAAgB,GAAG,QAAQ,CAAC;oBAC9B,CAAC;gBACH,CAAC,CAAC,CAAC;gBACH,OAAO,GAAG,EAAE;oBACV,OAAO,GAAG,KAAK,CAAC;gBAClB,CAAC,CAAC;YACJ,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAE3B,OAAO,sDAAiB,OAAO,YAAY,CAAC;QAC9C,CAAC,CAAC;QAEF,MAAM,EAAE,WAAW,EAAE,GAAG,IAAA,cAAM,EAC5B,oBAAoB,CAClB,8BAAC,uDAAyB;YACxB,8BAAC,gBAAgB,IAAC,KAAK,EAAC,OAAO,GAAG;YAClC,8BAAC,mBAAmB,IAAC,KAAK,EAAE,EAAE,GAAI;YAClC,8BAAC,aAAa,OAAG,CACS,CAC7B,CACF,CAAC;QAEF,MAAM,IAAA,eAAO,EAAC,GAAG,EAAE;YACjB,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC;YACjD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CACjC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CACvC,CAAC;YACF,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAEnD,MAAM,UAAU,GAAG,KAAM,CAAC,OAAO,CAAC,UAAU,CAAC;YAC7C,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACjD,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YACxD,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACpD,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,IAAI,GAAgC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,2CAAM,KAAK,CAAO,CAAC;QAC5E,MAAM,gBAAgB,GAAG,IAAA,+CAAqB,EAAC,IAAI,EAAE;YACnD,aAAa,EAAE,MAAM;YACrB,WAAW,EAAE,QAAQ;YACrB,WAAW,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,EAAE,CAAC;SAC7C,CAAC,CAAC;QAEH,yEAAyE;QACzE,MAAM,sBAAsB,GAAG,CAAC,EAC9B,QAAQ,GAGT,EAAE,EAAE,CAAC,CACJ,8BAAC,4DAA2B,IAC1B,cAAc,EAAE;gBACd,CAAC,eAAe,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI;aAC9B,IAEA,QAAQ,CACmB,CAC/B,CAAC;QAEF,IAAI,gBAAgB,GAAU,EAAE,CAAC;QACjC,MAAM,aAAa,GAAG,GAAG,EAAE;YACzB,MAAM,EAAE,oBAAoB,EAAE,GAAG,IAAA,uDAAsB,GAAE,CAAC;YAE1D,eAAK,CAAC,SAAS,CAAC,GAAG,EAAE;gBACnB,IAAI,OAAO,GAAG,IAAI,CAAC;gBACnB,oBAAoB,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;oBACvC,IAAI,OAAO,EAAE,CAAC;wBACZ,gBAAgB,GAAG,QAAQ,CAAC;oBAC9B,CAAC;gBACH,CAAC,CAAC,CAAC;gBACH,OAAO,GAAG,EAAE;oBACV,OAAO,GAAG,KAAK,CAAC;gBAClB,CAAC,CAAC;YACJ,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAE3B,OAAO,sDAAiB,OAAO,YAAY,CAAC;QAC9C,CAAC,CAAC;QAEF,MAAM,MAAM,GAAG;YACb,EAAE,EAAE,KAAK;YACT,SAAS,EAAE,KAAK;YAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,QAAQ,EAAE,EAAE;YACZ,QAAQ,EAAE,EAAE;SACN,CAAC;QAET,MAAM,EAAE,WAAW,EAAE,GAAG,IAAA,cAAM,EAC5B,8BAAC,+BAAiB,IAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,GAAG,EAAE,GAAE,CAAC,EACtB,aAAa,EAAE,GAAG,EAAE,GAAE,CAAC,EACvB,iBAAiB,EAAE,GAAG,EAAE,GAAE,CAAC,EAC3B,kBAAkB,EAAE,GAAG,EAAE,GAAE,CAAC;YAE5B,8BAAC,sBAAsB;gBACrB,8BAAC,uDAAyB;oBACxB,8BAAC,gBAAgB,IAAC,KAAK,EAAC,mBAAmB,GAAG;oBAC9C,8BAAC,aAAa,OAAG,CACS,CACL,CACP,CACrB,CAAC;QAEF,MAAM,IAAA,eAAO,EAAC,GAAG,EAAE;YACjB,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC;YACjD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CACjC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CACvC,CAAC;YACF,MAAM,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,kDAAkD;QACnF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { render, waitFor } from \"@testing-library/react\";\nimport React from \"react\";\nimport { z } from \"zod\";\nimport {\n useTamboContextHelpers,\n TamboContextHelpersProvider,\n} from \"../tambo-context-helpers-provider\";\nimport {\n TamboInteractableProvider,\n useCurrentInteractablesSnapshot,\n} from \"../tambo-interactable-provider\";\nimport { TamboStubProvider } from \"../tambo-stubs\";\nimport { withTamboInteractable } from \"../hoc/with-tambo-interactable\";\n\nfunction wrapperWithProviders(children: React.ReactNode) {\n const thread = {\n id: \"t-1\",\n projectId: \"p-1\",\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n messages: [],\n metadata: {},\n } as any;\n\n return (\n <TamboStubProvider\n thread={thread}\n registerTool={() => {}}\n registerTools={() => {}}\n registerComponent={() => {}}\n addToolAssociation={() => {}}\n >\n <TamboContextHelpersProvider>{children}</TamboContextHelpersProvider>\n </TamboStubProvider>\n );\n}\n\ndescribe(\"Interactables AdditionalContext (provider-based)\", () => {\n test(\"registers default helper and returns payload with description and components\", async () => {\n const Note: React.FC<{ title: string }> = ({ title }) => <div>{title}</div>;\n\n const InteractableNote = withTamboInteractable(Note, {\n componentName: \"Note\",\n description: \"A note\",\n propsSchema: z.object({ title: z.string() }),\n });\n\n let capturedContexts: any[] = [];\n const TestComponent = () => {\n const { getAdditionalContext } = useTamboContextHelpers();\n\n React.useEffect(() => {\n let mounted = true;\n getAdditionalContext().then((contexts) => {\n if (mounted) {\n capturedContexts = contexts;\n }\n });\n return () => {\n mounted = false;\n };\n }, [getAdditionalContext]);\n\n return <div data-testid=\"ready\">ready</div>;\n };\n\n const { getByTestId } = render(\n wrapperWithProviders(\n <TamboInteractableProvider>\n <InteractableNote title=\"hello\" />\n <TestComponent />\n </TamboInteractableProvider>,\n ),\n );\n\n await waitFor(() => {\n expect(getByTestId(\"ready\")).toBeInTheDocument();\n const entry = capturedContexts.find(\n (c: any) => c.name === \"interactables\",\n );\n expect(entry).toBeDefined();\n expect(entry?.context?.description).toMatch(/interactable components/i);\n expect(Array.isArray(entry?.context?.components)).toBe(true);\n const comp = entry!.context.components[0];\n expect(comp.componentName).toBe(\"Note\");\n expect(comp.props).toEqual({ title: \"hello\" });\n });\n });\n\n test(\"returns null when no interactable components are present\", async () => {\n let capturedContexts: any[] = [];\n const TestComponent = () => {\n const { getAdditionalContext } = useTamboContextHelpers();\n\n React.useEffect(() => {\n let mounted = true;\n getAdditionalContext().then((contexts) => {\n if (mounted) {\n capturedContexts = contexts;\n }\n });\n return () => {\n mounted = false;\n };\n }, [getAdditionalContext]);\n\n return <div data-testid=\"ready\">ready</div>;\n };\n\n const { getByTestId } = render(\n wrapperWithProviders(\n <TamboInteractableProvider>\n <div>No interactables here</div>\n <TestComponent />\n </TamboInteractableProvider>,\n ),\n );\n\n await waitFor(() => {\n expect(getByTestId(\"ready\")).toBeInTheDocument();\n const entry = capturedContexts.find(\n (c: any) => c.name === \"interactables\",\n );\n expect(entry).toBeUndefined(); // Should be filtered out when helper returns null\n });\n });\n\n test(\"context includes proper AI prompt with clear instructions\", async () => {\n const Note: React.FC<{ title: string }> = ({ title }) => <div>{title}</div>;\n const InteractableNote = withTamboInteractable(Note, {\n componentName: \"Note\",\n description: \"A simple note\",\n propsSchema: z.object({ title: z.string() }),\n });\n\n let capturedContexts: any[] = [];\n const TestComponent = () => {\n const { getAdditionalContext } = useTamboContextHelpers();\n\n React.useEffect(() => {\n let mounted = true;\n getAdditionalContext().then((contexts) => {\n if (mounted) {\n capturedContexts = contexts;\n }\n });\n return () => {\n mounted = false;\n };\n }, [getAdditionalContext]);\n\n return <div data-testid=\"ready\">ready</div>;\n };\n\n const { getByTestId } = render(\n wrapperWithProviders(\n <TamboInteractableProvider>\n <InteractableNote title=\"test\" />\n <TestComponent />\n </TamboInteractableProvider>,\n ),\n );\n\n await waitFor(() => {\n expect(getByTestId(\"ready\")).toBeInTheDocument();\n const entry = capturedContexts.find(\n (c: any) => c.name === \"interactables\",\n );\n expect(entry?.context?.description).toContain(\"interactable components\");\n expect(entry?.context?.description).toContain(\"visible on the page\");\n expect(entry?.context?.description).toContain(\"you can read and modify\");\n expect(entry?.context?.description).toContain(\"tools to update\");\n });\n });\n\n test(\"includes component metadata in expected format\", async () => {\n const Note: React.FC<{ title: string; color?: string }> = ({\n title,\n color = \"white\",\n }) => <div className={`note-${color}`}>{title}</div>;\n\n const InteractableNote = withTamboInteractable(Note, {\n componentName: \"Note\",\n description: \"A colorful note component\",\n propsSchema: z.object({\n title: z.string(),\n color: z.string().optional(),\n }),\n });\n\n let capturedContexts: any[] = [];\n const TestComponent = () => {\n const { getAdditionalContext } = useTamboContextHelpers();\n\n React.useEffect(() => {\n let mounted = true;\n getAdditionalContext().then((contexts) => {\n if (mounted) {\n capturedContexts = contexts;\n }\n });\n return () => {\n mounted = false;\n };\n }, [getAdditionalContext]);\n\n return <div data-testid=\"ready\">ready</div>;\n };\n\n const { getByTestId } = render(\n wrapperWithProviders(\n <TamboInteractableProvider>\n <InteractableNote title=\"test note\" color=\"blue\" />\n <TestComponent />\n </TamboInteractableProvider>,\n ),\n );\n\n await waitFor(() => {\n expect(getByTestId(\"ready\")).toBeInTheDocument();\n const entry = capturedContexts.find(\n (c: any) => c.name === \"interactables\",\n );\n const component = entry!.context.components[0];\n\n expect(component).toMatchObject({\n id: expect.any(String),\n componentName: \"Note\",\n description: \"A colorful note component\",\n props: { title: \"test note\", color: \"blue\" },\n propsSchema: \"Available - use component-specific update tools\",\n });\n });\n });\n\n test(\"snapshot hook returns immutable copies\", async () => {\n const Note: React.FC<{ title: string }> = ({ title }) => <div>{title}</div>;\n const InteractableNote = withTamboInteractable(Note, {\n componentName: \"Note\",\n description: \"A note\",\n propsSchema: z.object({ title: z.string() }),\n });\n\n const TestComponent = () => {\n const snapshot = useCurrentInteractablesSnapshot();\n const [testResult, setTestResult] = React.useState<string>(\"pending\");\n\n React.useEffect(() => {\n if (snapshot.length > 0) {\n const originalLength = snapshot.length;\n\n // Try to mutate the returned array and props\n snapshot.push({\n id: \"fake\",\n name: \"Fake\",\n description: \"\",\n component: () => null,\n props: {},\n } as any);\n (snapshot[0].props as any).title = \"MUTATED\";\n\n // The mutations should succeed on the returned copy, proving it's a separate object\n if (\n snapshot.length === originalLength + 1 &&\n snapshot[0].props.title === \"MUTATED\"\n ) {\n setTestResult(\"mutation-successful-but-isolated\");\n } else {\n setTestResult(\"mutation-failed\");\n }\n }\n }, [snapshot]);\n\n return <div data-testid=\"test-result\">{testResult}</div>;\n };\n\n const { getByTestId } = render(\n wrapperWithProviders(\n <TamboInteractableProvider>\n <InteractableNote title=\"immutable test\" />\n <TestComponent />\n </TamboInteractableProvider>,\n ),\n );\n\n await waitFor(() => {\n const result = getByTestId(\"test-result\").textContent;\n expect(result).toBe(\"mutation-successful-but-isolated\");\n });\n });\n\n test(\"multiple interactables from same provider appear in context\", async () => {\n const Note: React.FC<{ title: string }> = ({ title }) => <div>{title}</div>;\n const Counter: React.FC<{ count: number }> = ({ count }) => (\n <div>{count}</div>\n );\n\n const InteractableNote = withTamboInteractable(Note, {\n componentName: \"Note\",\n description: \"A note\",\n propsSchema: z.object({ title: z.string() }),\n });\n\n const InteractableCounter = withTamboInteractable(Counter, {\n componentName: \"Counter\",\n description: \"A counter\",\n propsSchema: z.object({ count: z.number() }),\n });\n\n let capturedContexts: any[] = [];\n const TestComponent = () => {\n const { getAdditionalContext } = useTamboContextHelpers();\n\n React.useEffect(() => {\n let mounted = true;\n getAdditionalContext().then((contexts) => {\n if (mounted) {\n capturedContexts = contexts;\n }\n });\n return () => {\n mounted = false;\n };\n }, [getAdditionalContext]);\n\n return <div data-testid=\"ready\">ready</div>;\n };\n\n const { getByTestId } = render(\n wrapperWithProviders(\n <TamboInteractableProvider>\n <InteractableNote title=\"first\" />\n <InteractableCounter count={42} />\n <TestComponent />\n </TamboInteractableProvider>,\n ),\n );\n\n await waitFor(() => {\n expect(getByTestId(\"ready\")).toBeInTheDocument();\n const entry = capturedContexts.find(\n (c: any) => c.name === \"interactables\",\n );\n expect(entry?.context?.components).toHaveLength(2);\n\n const components = entry!.context.components;\n expect(components[0].componentName).toBe(\"Note\");\n expect(components[0].props).toEqual({ title: \"first\" });\n expect(components[1].componentName).toBe(\"Counter\");\n expect(components[1].props).toEqual({ count: 42 });\n });\n });\n\n test(\"can be disabled by returning null\", async () => {\n const Note: React.FC<{ title: string }> = ({ title }) => <div>{title}</div>;\n const InteractableNote = withTamboInteractable(Note, {\n componentName: \"Note\",\n description: \"A note\",\n propsSchema: z.object({ title: z.string() }),\n });\n\n // Create a context helpers provider with a disabled interactables helper\n const DisabledContextHelpers = ({\n children,\n }: {\n children: React.ReactNode;\n }) => (\n <TamboContextHelpersProvider\n contextHelpers={{\n [\"interactables\"]: () => null,\n }}\n >\n {children}\n </TamboContextHelpersProvider>\n );\n\n let capturedContexts: any[] = [];\n const TestComponent = () => {\n const { getAdditionalContext } = useTamboContextHelpers();\n\n React.useEffect(() => {\n let mounted = true;\n getAdditionalContext().then((contexts) => {\n if (mounted) {\n capturedContexts = contexts;\n }\n });\n return () => {\n mounted = false;\n };\n }, [getAdditionalContext]);\n\n return <div data-testid=\"ready\">ready</div>;\n };\n\n const thread = {\n id: \"t-1\",\n projectId: \"p-1\",\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n messages: [],\n metadata: {},\n } as any;\n\n const { getByTestId } = render(\n <TamboStubProvider\n thread={thread}\n registerTool={() => {}}\n registerTools={() => {}}\n registerComponent={() => {}}\n addToolAssociation={() => {}}\n >\n <DisabledContextHelpers>\n <TamboInteractableProvider>\n <InteractableNote title=\"should not appear\" />\n <TestComponent />\n </TamboInteractableProvider>\n </DisabledContextHelpers>\n </TamboStubProvider>,\n );\n\n await waitFor(() => {\n expect(getByTestId(\"ready\")).toBeInTheDocument();\n const entry = capturedContexts.find(\n (c: any) => c.name === \"interactables\",\n );\n expect(entry).toBeUndefined(); // Should be filtered out when helper returns null\n });\n });\n});\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { PropsWithChildren } from "react";
|
|
2
|
-
import { AdditionalContext,
|
|
2
|
+
import { AdditionalContext, ContextHelperFn, ContextHelpers } from "../context-helpers";
|
|
3
3
|
export interface TamboContextHelpersProviderProps {
|
|
4
4
|
/**
|
|
5
5
|
* A dictionary of context helper functions.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tambo-context-helpers-provider.d.ts","sourceRoot":"","sources":["../../src/providers/tambo-context-helpers-provider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAEZ,iBAAiB,
|
|
1
|
+
{"version":3,"file":"tambo-context-helpers-provider.d.ts","sourceRoot":"","sources":["../../src/providers/tambo-context-helpers-provider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAEZ,iBAAiB,EAMlB,MAAM,OAAO,CAAC;AACf,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,cAAc,EACf,MAAM,oBAAoB,CAAC;AAG5B,MAAM,WAAW,gCAAgC;IAC/C;;;;OAIG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,MAAM,WAAW,+BAA+B;IAC9C,iEAAiE;IACjE,oBAAoB,EAAE,MAAM,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACzD,0CAA0C;IAC1C,iBAAiB,EAAE,MAAM,cAAc,CAAC;IACxC,6CAA6C;IAC7C,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IAClE,sCAAsC;IACtC,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAKD;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,EAAE,KAAK,CAAC,EAAE,CAChD,iBAAiB,CAAC,gCAAgC,CAAC,CAkEpD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,uCAmBlC,CAAC"}
|
|
@@ -48,38 +48,42 @@ const TamboContextHelpersContext = (0, react_1.createContext)(null);
|
|
|
48
48
|
* @returns The provider that exposes context helper APIs via useTamboContextHelpers.
|
|
49
49
|
*/
|
|
50
50
|
const TamboContextHelpersProvider = ({ children, contextHelpers }) => {
|
|
51
|
+
const [helpers, setHelpers] = (0, react_1.useState)({});
|
|
52
|
+
const addContextHelper = (0, react_1.useCallback)((name, fn) => {
|
|
53
|
+
setHelpers((prev) => ({ ...prev, [name]: fn }));
|
|
54
|
+
}, []);
|
|
55
|
+
const removeContextHelper = (0, react_1.useCallback)((name, fn) => {
|
|
56
|
+
setHelpers((prev) => {
|
|
57
|
+
const { [name]: registeredFn, ...rest } = prev;
|
|
58
|
+
if (fn === undefined || registeredFn === fn) {
|
|
59
|
+
return rest;
|
|
60
|
+
}
|
|
61
|
+
return prev;
|
|
62
|
+
});
|
|
63
|
+
}, []);
|
|
51
64
|
// Hydrate the global registry with initial helpers (runs on prop changes)
|
|
52
|
-
react_1.
|
|
65
|
+
(0, react_1.useEffect)(() => {
|
|
53
66
|
const addedEntries = [];
|
|
54
67
|
if (contextHelpers) {
|
|
55
68
|
for (const [name, fn] of Object.entries(contextHelpers)) {
|
|
56
|
-
(
|
|
69
|
+
addContextHelper(name, fn);
|
|
57
70
|
addedEntries.push([name, fn]);
|
|
58
71
|
}
|
|
59
72
|
}
|
|
60
73
|
return () => {
|
|
61
|
-
const current = (0, registry_1.getHelpers)();
|
|
62
74
|
for (const [name, fn] of addedEntries) {
|
|
63
75
|
// Only remove if the registry still points to the same function
|
|
64
|
-
|
|
65
|
-
(0, registry_1.removeHelper)(name);
|
|
66
|
-
}
|
|
76
|
+
removeContextHelper(name, fn);
|
|
67
77
|
}
|
|
68
78
|
};
|
|
69
|
-
}, [contextHelpers]);
|
|
79
|
+
}, [addContextHelper, contextHelpers, removeContextHelper]);
|
|
70
80
|
const getAdditionalContext = (0, react_1.useCallback)(async () => {
|
|
71
|
-
const contexts = await (0, registry_1.resolveAdditionalContext)();
|
|
81
|
+
const contexts = await (0, registry_1.resolveAdditionalContext)(helpers);
|
|
72
82
|
return contexts;
|
|
73
|
-
}, []);
|
|
83
|
+
}, [helpers]);
|
|
74
84
|
const getContextHelpers = (0, react_1.useCallback)(() => {
|
|
75
|
-
return
|
|
76
|
-
}, []);
|
|
77
|
-
const addContextHelper = (0, react_1.useCallback)((name, helper) => {
|
|
78
|
-
(0, registry_1.addHelper)(name, helper);
|
|
79
|
-
}, []);
|
|
80
|
-
const removeContextHelper = (0, react_1.useCallback)((name) => {
|
|
81
|
-
(0, registry_1.removeHelper)(name);
|
|
82
|
-
}, []);
|
|
85
|
+
return helpers;
|
|
86
|
+
}, [helpers]);
|
|
83
87
|
const value = (0, react_1.useMemo)(() => ({
|
|
84
88
|
getAdditionalContext,
|
|
85
89
|
getContextHelpers,
|
|
@@ -105,10 +109,18 @@ const useTamboContextHelpers = () => {
|
|
|
105
109
|
return context;
|
|
106
110
|
// Fallback to global registry so the API is standalone outside any provider
|
|
107
111
|
return {
|
|
108
|
-
getAdditionalContext: async () =>
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
getAdditionalContext: async () => {
|
|
113
|
+
throw new Error("No provider found");
|
|
114
|
+
},
|
|
115
|
+
getContextHelpers: () => {
|
|
116
|
+
throw new Error("No provider found");
|
|
117
|
+
},
|
|
118
|
+
addContextHelper: (_name, _helper) => {
|
|
119
|
+
throw new Error("No provider found");
|
|
120
|
+
},
|
|
121
|
+
removeContextHelper: (_name) => {
|
|
122
|
+
throw new Error("No provider found");
|
|
123
|
+
},
|
|
112
124
|
};
|
|
113
125
|
};
|
|
114
126
|
exports.useTamboContextHelpers = useTamboContextHelpers;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tambo-context-helpers-provider.js","sourceRoot":"","sources":["../../src/providers/tambo-context-helpers-provider.tsx"],"names":[],"mappings":";AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACb,+
|
|
1
|
+
{"version":3,"file":"tambo-context-helpers-provider.js","sourceRoot":"","sources":["../../src/providers/tambo-context-helpers-provider.tsx"],"names":[],"mappings":";AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACb,+CAQe;AAMf,0DAAuE;AAsBvE,MAAM,0BAA0B,GAC9B,IAAA,qBAAa,EAAyC,IAAI,CAAC,CAAC;AAE9D;;;;;;;;GAQG;AACI,MAAM,2BAA2B,GAEpC,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE;IACnC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,IAAA,gBAAQ,EAAkC,EAAE,CAAC,CAAC;IAC5E,MAAM,gBAAgB,GAAG,IAAA,mBAAW,EAAC,CAAC,IAAY,EAAE,EAAmB,EAAE,EAAE;QACzE,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IAClD,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,MAAM,mBAAmB,GAAG,IAAA,mBAAW,EACrC,CAAC,IAAY,EAAE,EAAoB,EAAE,EAAE;QACrC,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE;YAClB,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;YAC/C,IAAI,EAAE,KAAK,SAAS,IAAI,YAAY,KAAK,EAAE,EAAE,CAAC;gBAC5C,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,EACD,EAAE,CACH,CAAC;IACF,0EAA0E;IAC1E,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,MAAM,YAAY,GAAgC,EAAE,CAAC;QAErD,IAAI,cAAc,EAAE,CAAC;YACnB,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;gBACxD,gBAAgB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBAC3B,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAED,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,YAAY,EAAE,CAAC;gBACtC,gEAAgE;gBAChE,mBAAmB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAChC,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,gBAAgB,EAAE,cAAc,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAE5D,MAAM,oBAAoB,GAAG,IAAA,mBAAW,EAAC,KAAK,IAAI,EAAE;QAClD,MAAM,QAAQ,GAAG,MAAM,IAAA,mCAAwB,EAAC,OAAO,CAAC,CAAC;QACzD,OAAO,QAA+B,CAAC;IACzC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,MAAM,iBAAiB,GAAG,IAAA,mBAAW,EAAC,GAAG,EAAE;QACzC,OAAO,OAAyB,CAAC;IACnC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,MAAM,KAAK,GAAG,IAAA,eAAO,EACnB,GAAG,EAAE,CAAC,CAAC;QACL,oBAAoB;QACpB,iBAAiB;QACjB,gBAAgB;QAChB,mBAAmB;KACpB,CAAC,EACF;QACE,oBAAoB;QACpB,iBAAiB;QACjB,gBAAgB;QAChB,mBAAmB;KACpB,CACF,CAAC;IAEF,OAAO,CACL,8BAAC,0BAA0B,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,IAC9C,QAAQ,CAC2B,CACvC,CAAC;AACJ,CAAC,CAAC;AAnEW,QAAA,2BAA2B,+BAmEtC;AAEF;;;;GAIG;AACI,MAAM,sBAAsB,GAAG,GAAG,EAAE;IACzC,MAAM,OAAO,GAAG,IAAA,kBAAU,EAAC,0BAA0B,CAAC,CAAC;IACvD,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAE5B,4EAA4E;IAC5E,OAAO;QACL,oBAAoB,EAAE,KAAK,IAAI,EAAE;YAC/B,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QACD,iBAAiB,EAAE,GAAG,EAAE;YACtB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QACD,gBAAgB,EAAE,CAAC,KAAa,EAAE,OAAwB,EAAE,EAAE;YAC5D,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QACD,mBAAmB,EAAE,CAAC,KAAa,EAAE,EAAE;YACrC,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;KACiC,CAAC;AACvC,CAAC,CAAC;AAnBW,QAAA,sBAAsB,0BAmBjC","sourcesContent":["\"use client\";\nimport React, {\n createContext,\n PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport {\n AdditionalContext,\n ContextHelperFn,\n ContextHelpers,\n} from \"../context-helpers\";\nimport { resolveAdditionalContext } from \"../context-helpers/registry\";\n\nexport interface TamboContextHelpersProviderProps {\n /**\n * A dictionary of context helper functions.\n * The key becomes the AdditionalContext.name and the function returns the value.\n * Return null/undefined to skip including that context.\n */\n contextHelpers?: ContextHelpers;\n}\n\nexport interface TamboContextHelpersContextProps {\n /** Get all additional context by running all helper functions */\n getAdditionalContext: () => Promise<AdditionalContext[]>;\n /** Get the current context helpers map */\n getContextHelpers: () => ContextHelpers;\n /** Add or update a context helper by name */\n addContextHelper: (name: string, helper: ContextHelperFn) => void;\n /** Remove a context helper by name */\n removeContextHelper: (name: string) => void;\n}\n\nconst TamboContextHelpersContext =\n createContext<TamboContextHelpersContextProps | null>(null);\n\n/**\n * Provider for managing additional context helpers.\n * Accepts a map of { key: () => any | null | undefined | Promise<any | null | undefined> }.\n * Returning null/undefined skips inclusion; returned values are wrapped as { name: key, context: value }.\n * @param props - The props for the TamboContextHelpersProvider.\n * @param props.contextHelpers - A dictionary of context helper functions keyed by context name.\n * @param props.children - The children to render.\n * @returns The provider that exposes context helper APIs via useTamboContextHelpers.\n */\nexport const TamboContextHelpersProvider: React.FC<\n PropsWithChildren<TamboContextHelpersProviderProps>\n> = ({ children, contextHelpers }) => {\n const [helpers, setHelpers] = useState<Record<string, ContextHelperFn>>({});\n const addContextHelper = useCallback((name: string, fn: ContextHelperFn) => {\n setHelpers((prev) => ({ ...prev, [name]: fn }));\n }, []);\n const removeContextHelper = useCallback(\n (name: string, fn?: ContextHelperFn) => {\n setHelpers((prev) => {\n const { [name]: registeredFn, ...rest } = prev;\n if (fn === undefined || registeredFn === fn) {\n return rest;\n }\n return prev;\n });\n },\n [],\n );\n // Hydrate the global registry with initial helpers (runs on prop changes)\n useEffect(() => {\n const addedEntries: [string, ContextHelperFn][] = [];\n\n if (contextHelpers) {\n for (const [name, fn] of Object.entries(contextHelpers)) {\n addContextHelper(name, fn);\n addedEntries.push([name, fn]);\n }\n }\n\n return () => {\n for (const [name, fn] of addedEntries) {\n // Only remove if the registry still points to the same function\n removeContextHelper(name, fn);\n }\n };\n }, [addContextHelper, contextHelpers, removeContextHelper]);\n\n const getAdditionalContext = useCallback(async () => {\n const contexts = await resolveAdditionalContext(helpers);\n return contexts as AdditionalContext[];\n }, [helpers]);\n\n const getContextHelpers = useCallback(() => {\n return helpers as ContextHelpers;\n }, [helpers]);\n\n const value = useMemo(\n () => ({\n getAdditionalContext,\n getContextHelpers,\n addContextHelper,\n removeContextHelper,\n }),\n [\n getAdditionalContext,\n getContextHelpers,\n addContextHelper,\n removeContextHelper,\n ],\n );\n\n return (\n <TamboContextHelpersContext.Provider value={value}>\n {children}\n </TamboContextHelpersContext.Provider>\n );\n};\n\n/**\n * Hook to access context helpers functionality.\n * Safe to call even when no provider is present: proxies to the global registry.\n * @returns The context helpers context props (registry-backed).\n */\nexport const useTamboContextHelpers = () => {\n const context = useContext(TamboContextHelpersContext);\n if (context) return context;\n\n // Fallback to global registry so the API is standalone outside any provider\n return {\n getAdditionalContext: async () => {\n throw new Error(\"No provider found\");\n },\n getContextHelpers: () => {\n throw new Error(\"No provider found\");\n },\n addContextHelper: (_name: string, _helper: ContextHelperFn) => {\n throw new Error(\"No provider found\");\n },\n removeContextHelper: (_name: string) => {\n throw new Error(\"No provider found\");\n },\n } as TamboContextHelpersContextProps;\n};\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { PropsWithChildren } from "react";
|
|
2
|
+
import { z } from "zod";
|
|
2
3
|
import { type TamboInteractableContext } from "../model/tambo-interactable";
|
|
3
4
|
declare const TamboInteractableContext: React.Context<TamboInteractableContext>;
|
|
4
5
|
/**
|
|
@@ -16,5 +17,24 @@ export declare const TamboInteractableProvider: React.FC<PropsWithChildren>;
|
|
|
16
17
|
* @returns The interactable component management functions
|
|
17
18
|
*/
|
|
18
19
|
export declare const useTamboInteractable: () => TamboInteractableContext;
|
|
20
|
+
/**
|
|
21
|
+
* Hook to get a cloned snapshot of the current interactables.
|
|
22
|
+
* Returns a shallow copy of the array with cloned items and props to prevent
|
|
23
|
+
* external mutation from affecting internal state.
|
|
24
|
+
* @returns The current interactables snapshot (cloned).
|
|
25
|
+
*/
|
|
26
|
+
export declare const useCurrentInteractablesSnapshot: () => {
|
|
27
|
+
props: {
|
|
28
|
+
[x: string]: any;
|
|
29
|
+
};
|
|
30
|
+
id: string;
|
|
31
|
+
name: string;
|
|
32
|
+
description: string;
|
|
33
|
+
component: React.ComponentType<any>;
|
|
34
|
+
propsSchema?: z.ZodTypeAny | import("json-schema").JSONSchema7;
|
|
35
|
+
propsDefinition?: any;
|
|
36
|
+
loadingComponent?: React.ComponentType<any>;
|
|
37
|
+
associatedTools?: import(".").TamboTool[];
|
|
38
|
+
}[];
|
|
19
39
|
export {};
|
|
20
40
|
//# sourceMappingURL=tambo-interactable-provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tambo-interactable-provider.d.ts","sourceRoot":"","sources":["../../src/providers/tambo-interactable-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAEZ,iBAAiB,EAKlB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"tambo-interactable-provider.d.ts","sourceRoot":"","sources":["../../src/providers/tambo-interactable-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAEZ,iBAAiB,EAKlB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAEL,KAAK,wBAAwB,EAC9B,MAAM,6BAA6B,CAAC;AAKrC,QAAA,MAAM,wBAAwB,yCAQ5B,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA6QjE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,gCAEhC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B;;;;;;;;;;;;GAU3C,CAAC"}
|