@tambo-ai/react 0.72.0 → 0.73.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/dist/mcp/mcp-hooks.d.ts +4 -0
  2. package/dist/mcp/mcp-hooks.d.ts.map +1 -1
  3. package/dist/mcp/mcp-hooks.js +4 -0
  4. package/dist/mcp/mcp-hooks.js.map +1 -1
  5. package/dist/providers/tambo-provider.d.ts +3 -0
  6. package/dist/providers/tambo-provider.d.ts.map +1 -1
  7. package/dist/providers/tambo-provider.js +3 -0
  8. package/dist/providers/tambo-provider.js.map +1 -1
  9. package/dist/util/resource-content-resolver.d.ts.map +1 -1
  10. package/dist/util/resource-content-resolver.js +2 -0
  11. package/dist/util/resource-content-resolver.js.map +1 -1
  12. package/dist/v1/hooks/use-tambo-v1-messages.test.js +22 -9
  13. package/dist/v1/hooks/use-tambo-v1-messages.test.js.map +1 -1
  14. package/dist/v1/hooks/use-tambo-v1-send-message.d.ts +1 -0
  15. package/dist/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -1
  16. package/dist/v1/hooks/use-tambo-v1-send-message.js +9 -2
  17. package/dist/v1/hooks/use-tambo-v1-send-message.js.map +1 -1
  18. package/dist/v1/hooks/use-tambo-v1-send-message.test.js +22 -9
  19. package/dist/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -1
  20. package/dist/v1/hooks/use-tambo-v1-suggestions.d.ts +91 -0
  21. package/dist/v1/hooks/use-tambo-v1-suggestions.d.ts.map +1 -0
  22. package/dist/v1/hooks/use-tambo-v1-suggestions.js +152 -0
  23. package/dist/v1/hooks/use-tambo-v1-suggestions.js.map +1 -0
  24. package/dist/v1/hooks/use-tambo-v1-suggestions.test.d.ts +2 -0
  25. package/dist/v1/hooks/use-tambo-v1-suggestions.test.d.ts.map +1 -0
  26. package/dist/v1/hooks/use-tambo-v1-suggestions.test.js +511 -0
  27. package/dist/v1/hooks/use-tambo-v1-suggestions.test.js.map +1 -0
  28. package/dist/v1/hooks/use-tambo-v1-thread-input.d.ts +6 -57
  29. package/dist/v1/hooks/use-tambo-v1-thread-input.d.ts.map +1 -1
  30. package/dist/v1/hooks/use-tambo-v1-thread-input.js +7 -67
  31. package/dist/v1/hooks/use-tambo-v1-thread-input.js.map +1 -1
  32. package/dist/v1/hooks/use-tambo-v1-thread-input.test.js +201 -72
  33. package/dist/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -1
  34. package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts +6 -4
  35. package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -1
  36. package/dist/v1/hooks/use-tambo-v1-thread-list.js +2 -2
  37. package/dist/v1/hooks/use-tambo-v1-thread-list.js.map +1 -1
  38. package/dist/v1/hooks/use-tambo-v1-thread-list.test.js +2 -2
  39. package/dist/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -1
  40. package/dist/v1/hooks/use-tambo-v1.test.js +16 -7
  41. package/dist/v1/hooks/use-tambo-v1.test.js.map +1 -1
  42. package/dist/v1/index.d.ts +22 -13
  43. package/dist/v1/index.d.ts.map +1 -1
  44. package/dist/v1/index.js +31 -39
  45. package/dist/v1/index.js.map +1 -1
  46. package/dist/v1/providers/tambo-v1-provider.d.ts +27 -9
  47. package/dist/v1/providers/tambo-v1-provider.d.ts.map +1 -1
  48. package/dist/v1/providers/tambo-v1-provider.js +22 -11
  49. package/dist/v1/providers/tambo-v1-provider.js.map +1 -1
  50. package/dist/v1/providers/tambo-v1-provider.test.js +27 -10
  51. package/dist/v1/providers/tambo-v1-provider.test.js.map +1 -1
  52. package/dist/v1/providers/tambo-v1-stream-context.d.ts +19 -10
  53. package/dist/v1/providers/tambo-v1-stream-context.d.ts.map +1 -1
  54. package/dist/v1/providers/tambo-v1-stream-context.js +43 -53
  55. package/dist/v1/providers/tambo-v1-stream-context.js.map +1 -1
  56. package/dist/v1/providers/tambo-v1-stream-context.test.js +94 -19
  57. package/dist/v1/providers/tambo-v1-stream-context.test.js.map +1 -1
  58. package/dist/v1/providers/tambo-v1-stub-provider.d.ts +74 -0
  59. package/dist/v1/providers/tambo-v1-stub-provider.d.ts.map +1 -0
  60. package/dist/v1/providers/tambo-v1-stub-provider.js +212 -0
  61. package/dist/v1/providers/tambo-v1-stub-provider.js.map +1 -0
  62. package/dist/v1/providers/tambo-v1-stub-provider.test.d.ts +2 -0
  63. package/dist/v1/providers/tambo-v1-stub-provider.test.d.ts.map +1 -0
  64. package/dist/v1/providers/tambo-v1-stub-provider.test.js +162 -0
  65. package/dist/v1/providers/tambo-v1-stub-provider.test.js.map +1 -0
  66. package/dist/v1/providers/tambo-v1-thread-input-provider.d.ts +105 -0
  67. package/dist/v1/providers/tambo-v1-thread-input-provider.d.ts.map +1 -0
  68. package/dist/v1/providers/tambo-v1-thread-input-provider.js +191 -0
  69. package/dist/v1/providers/tambo-v1-thread-input-provider.js.map +1 -0
  70. package/dist/v1/utils/component-renderer.d.ts +15 -67
  71. package/dist/v1/utils/component-renderer.d.ts.map +1 -1
  72. package/dist/v1/utils/component-renderer.js +3 -149
  73. package/dist/v1/utils/component-renderer.js.map +1 -1
  74. package/dist/v1/utils/component-renderer.test.js +15 -350
  75. package/dist/v1/utils/component-renderer.test.js.map +1 -1
  76. package/esm/mcp/mcp-hooks.d.ts +4 -0
  77. package/esm/mcp/mcp-hooks.d.ts.map +1 -1
  78. package/esm/mcp/mcp-hooks.js +4 -0
  79. package/esm/mcp/mcp-hooks.js.map +1 -1
  80. package/esm/providers/tambo-provider.d.ts +3 -0
  81. package/esm/providers/tambo-provider.d.ts.map +1 -1
  82. package/esm/providers/tambo-provider.js +3 -0
  83. package/esm/providers/tambo-provider.js.map +1 -1
  84. package/esm/util/resource-content-resolver.d.ts.map +1 -1
  85. package/esm/util/resource-content-resolver.js +2 -0
  86. package/esm/util/resource-content-resolver.js.map +1 -1
  87. package/esm/v1/hooks/use-tambo-v1-messages.test.js +22 -9
  88. package/esm/v1/hooks/use-tambo-v1-messages.test.js.map +1 -1
  89. package/esm/v1/hooks/use-tambo-v1-send-message.d.ts +1 -0
  90. package/esm/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -1
  91. package/esm/v1/hooks/use-tambo-v1-send-message.js +9 -2
  92. package/esm/v1/hooks/use-tambo-v1-send-message.js.map +1 -1
  93. package/esm/v1/hooks/use-tambo-v1-send-message.test.js +22 -9
  94. package/esm/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -1
  95. package/esm/v1/hooks/use-tambo-v1-suggestions.d.ts +91 -0
  96. package/esm/v1/hooks/use-tambo-v1-suggestions.d.ts.map +1 -0
  97. package/esm/v1/hooks/use-tambo-v1-suggestions.js +149 -0
  98. package/esm/v1/hooks/use-tambo-v1-suggestions.js.map +1 -0
  99. package/esm/v1/hooks/use-tambo-v1-suggestions.test.d.ts +2 -0
  100. package/esm/v1/hooks/use-tambo-v1-suggestions.test.d.ts.map +1 -0
  101. package/esm/v1/hooks/use-tambo-v1-suggestions.test.js +506 -0
  102. package/esm/v1/hooks/use-tambo-v1-suggestions.test.js.map +1 -0
  103. package/esm/v1/hooks/use-tambo-v1-thread-input.d.ts +6 -57
  104. package/esm/v1/hooks/use-tambo-v1-thread-input.d.ts.map +1 -1
  105. package/esm/v1/hooks/use-tambo-v1-thread-input.js +5 -66
  106. package/esm/v1/hooks/use-tambo-v1-thread-input.js.map +1 -1
  107. package/esm/v1/hooks/use-tambo-v1-thread-input.test.js +199 -73
  108. package/esm/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -1
  109. package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts +6 -4
  110. package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -1
  111. package/esm/v1/hooks/use-tambo-v1-thread-list.js +2 -2
  112. package/esm/v1/hooks/use-tambo-v1-thread-list.js.map +1 -1
  113. package/esm/v1/hooks/use-tambo-v1-thread-list.test.js +2 -2
  114. package/esm/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -1
  115. package/esm/v1/hooks/use-tambo-v1.test.js +16 -7
  116. package/esm/v1/hooks/use-tambo-v1.test.js.map +1 -1
  117. package/esm/v1/index.d.ts +22 -13
  118. package/esm/v1/index.d.ts.map +1 -1
  119. package/esm/v1/index.js +23 -18
  120. package/esm/v1/index.js.map +1 -1
  121. package/esm/v1/providers/tambo-v1-provider.d.ts +27 -9
  122. package/esm/v1/providers/tambo-v1-provider.d.ts.map +1 -1
  123. package/esm/v1/providers/tambo-v1-provider.js +20 -10
  124. package/esm/v1/providers/tambo-v1-provider.js.map +1 -1
  125. package/esm/v1/providers/tambo-v1-provider.test.js +28 -11
  126. package/esm/v1/providers/tambo-v1-provider.test.js.map +1 -1
  127. package/esm/v1/providers/tambo-v1-stream-context.d.ts +19 -10
  128. package/esm/v1/providers/tambo-v1-stream-context.d.ts.map +1 -1
  129. package/esm/v1/providers/tambo-v1-stream-context.js +44 -54
  130. package/esm/v1/providers/tambo-v1-stream-context.js.map +1 -1
  131. package/esm/v1/providers/tambo-v1-stream-context.test.js +95 -20
  132. package/esm/v1/providers/tambo-v1-stream-context.test.js.map +1 -1
  133. package/esm/v1/providers/tambo-v1-stub-provider.d.ts +74 -0
  134. package/esm/v1/providers/tambo-v1-stub-provider.d.ts.map +1 -0
  135. package/esm/v1/providers/tambo-v1-stub-provider.js +176 -0
  136. package/esm/v1/providers/tambo-v1-stub-provider.js.map +1 -0
  137. package/esm/v1/providers/tambo-v1-stub-provider.test.d.ts +2 -0
  138. package/esm/v1/providers/tambo-v1-stub-provider.test.d.ts.map +1 -0
  139. package/esm/v1/providers/tambo-v1-stub-provider.test.js +157 -0
  140. package/esm/v1/providers/tambo-v1-stub-provider.test.js.map +1 -0
  141. package/esm/v1/providers/tambo-v1-thread-input-provider.d.ts +105 -0
  142. package/esm/v1/providers/tambo-v1-thread-input-provider.d.ts.map +1 -0
  143. package/esm/v1/providers/tambo-v1-thread-input-provider.js +153 -0
  144. package/esm/v1/providers/tambo-v1-thread-input-provider.js.map +1 -0
  145. package/esm/v1/utils/component-renderer.d.ts +15 -67
  146. package/esm/v1/utils/component-renderer.d.ts.map +1 -1
  147. package/esm/v1/utils/component-renderer.js +4 -146
  148. package/esm/v1/utils/component-renderer.js.map +1 -1
  149. package/esm/v1/utils/component-renderer.test.js +16 -351
  150. package/esm/v1/utils/component-renderer.test.js.map +1 -1
  151. package/package.json +2 -2
@@ -3,370 +3,30 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- // React import needed for JSX transform (jsxImportSource is not set to react-jsx)
7
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
8
6
  const react_1 = __importDefault(require("react"));
9
7
  const react_2 = require("@testing-library/react");
10
8
  const component_renderer_1 = require("./component-renderer");
11
- // Test component that displays its props
12
- function TestComponent({ title, count }) {
13
- return (react_1.default.createElement("div", { "data-testid": "test-component" },
14
- react_1.default.createElement("span", { "data-testid": "title" }, title),
15
- react_1.default.createElement("span", { "data-testid": "count" }, count)));
16
- }
17
- // Test loading component
18
- function TestLoadingComponent() {
19
- return react_1.default.createElement("div", { "data-testid": "loading" }, "Loading...");
20
- }
21
9
  // Test component that uses the content context
22
- function ContextAwareComponent() {
10
+ const ContextAwareComponent = () => {
23
11
  const context = (0, component_renderer_1.useV1ComponentContent)();
24
12
  return (react_1.default.createElement("div", { "data-testid": "context-aware" },
25
13
  react_1.default.createElement("span", { "data-testid": "componentId" }, context.componentId),
26
14
  react_1.default.createElement("span", { "data-testid": "threadId" }, context.threadId),
27
- react_1.default.createElement("span", { "data-testid": "messageId" }, context.messageId)));
28
- }
29
- const mockRegistry = {
30
- TestComponent: {
31
- component: TestComponent,
32
- name: "TestComponent",
33
- description: "A test component",
34
- props: {},
35
- contextTools: [],
36
- },
37
- TestWithLoading: {
38
- component: TestComponent,
39
- loadingComponent: TestLoadingComponent,
40
- name: "TestWithLoading",
41
- description: "A test component with loading state",
42
- props: {},
43
- contextTools: [],
44
- },
45
- ContextAware: {
46
- component: ContextAwareComponent,
47
- name: "ContextAware",
48
- description: "A context-aware component",
49
- props: {},
50
- contextTools: [],
51
- },
15
+ react_1.default.createElement("span", { "data-testid": "messageId" }, context.messageId),
16
+ react_1.default.createElement("span", { "data-testid": "componentName" }, context.componentName)));
52
17
  };
53
- describe("isComponentContent", () => {
54
- it("returns true for component content", () => {
55
- const content = {
56
- type: "component",
57
- id: "comp_1",
58
- name: "Test",
59
- props: {},
60
- streamingState: "done",
61
- };
62
- expect((0, component_renderer_1.isComponentContent)(content)).toBe(true);
63
- });
64
- it("returns false for text content", () => {
65
- const content = { type: "text", text: "hello" };
66
- expect((0, component_renderer_1.isComponentContent)(content)).toBe(false);
67
- });
68
- });
69
- describe("renderComponentContent", () => {
70
- it("renders a component from registry", () => {
71
- const content = {
72
- type: "component",
73
- id: "comp_1",
74
- name: "TestComponent",
75
- props: { title: "Hello", count: 42 },
76
- streamingState: "done",
77
- };
78
- const result = (0, component_renderer_1.renderComponentContent)(content, {
79
- threadId: "thread_1",
80
- messageId: "msg_1",
81
- componentList: mockRegistry,
82
- });
83
- expect(result.renderedComponent).not.toBeNull();
84
- // Render and check output
85
- (0, react_2.render)(react_1.default.createElement(react_1.default.Fragment, null, result.renderedComponent));
86
- expect(react_2.screen.getByTestId("title")).toHaveTextContent("Hello");
87
- expect(react_2.screen.getByTestId("count")).toHaveTextContent("42");
88
- });
89
- it("returns null renderedComponent for unknown component", () => {
90
- const content = {
91
- type: "component",
92
- id: "comp_1",
93
- name: "UnknownComponent",
94
- props: {},
95
- streamingState: "done",
96
- };
97
- const consoleWarn = jest.spyOn(console, "warn").mockImplementation();
98
- const result = (0, component_renderer_1.renderComponentContent)(content, {
99
- threadId: "thread_1",
100
- messageId: "msg_1",
101
- componentList: mockRegistry,
102
- });
103
- expect(result.renderedComponent).toBeNull();
104
- expect(consoleWarn).toHaveBeenCalledWith('Component "UnknownComponent" not found in registry');
105
- consoleWarn.mockRestore();
106
- });
107
- it("shows loading component when streaming", () => {
108
- const content = {
109
- type: "component",
110
- id: "comp_1",
111
- name: "TestWithLoading",
112
- props: { title: "Loading Test", count: 0 },
113
- streamingState: "streaming",
114
- };
115
- const result = (0, component_renderer_1.renderComponentContent)(content, {
116
- threadId: "thread_1",
117
- messageId: "msg_1",
118
- componentList: mockRegistry,
119
- });
120
- (0, react_2.render)(react_1.default.createElement(react_1.default.Fragment, null, result.renderedComponent));
121
- expect(react_2.screen.getByTestId("loading")).toHaveTextContent("Loading...");
122
- });
123
- it("shows main component when done streaming", () => {
124
- const content = {
125
- type: "component",
126
- id: "comp_1",
127
- name: "TestWithLoading",
128
- props: { title: "Done Test", count: 99 },
129
- streamingState: "done",
130
- };
131
- const result = (0, component_renderer_1.renderComponentContent)(content, {
132
- threadId: "thread_1",
133
- messageId: "msg_1",
134
- componentList: mockRegistry,
135
- });
136
- (0, react_2.render)(react_1.default.createElement(react_1.default.Fragment, null, result.renderedComponent));
137
- expect(react_2.screen.getByTestId("title")).toHaveTextContent("Done Test");
138
- expect(react_2.screen.getByTestId("count")).toHaveTextContent("99");
139
- });
140
- it("provides component context to rendered components", () => {
141
- const content = {
142
- type: "component",
143
- id: "comp_123",
144
- name: "ContextAware",
145
- props: {},
146
- streamingState: "done",
147
- };
148
- const result = (0, component_renderer_1.renderComponentContent)(content, {
149
- threadId: "thread_456",
150
- messageId: "msg_789",
151
- componentList: mockRegistry,
152
- });
153
- (0, react_2.render)(react_1.default.createElement(react_1.default.Fragment, null, result.renderedComponent));
18
+ describe("V1ComponentContentProvider", () => {
19
+ it("provides context to child components", () => {
20
+ (0, react_2.render)(react_1.default.createElement(component_renderer_1.V1ComponentContentProvider, { componentId: "comp_123", threadId: "thread_456", messageId: "msg_789", componentName: "TestComponent" },
21
+ react_1.default.createElement(ContextAwareComponent, null)));
154
22
  expect(react_2.screen.getByTestId("componentId")).toHaveTextContent("comp_123");
155
23
  expect(react_2.screen.getByTestId("threadId")).toHaveTextContent("thread_456");
156
24
  expect(react_2.screen.getByTestId("messageId")).toHaveTextContent("msg_789");
25
+ expect(react_2.screen.getByTestId("componentName")).toHaveTextContent("TestComponent");
157
26
  });
158
27
  });
159
- describe("renderMessageContent", () => {
160
- it("renders component content blocks and passes through others", () => {
161
- const content = [
162
- { type: "text", text: "Hello" },
163
- {
164
- type: "component",
165
- id: "comp_1",
166
- name: "TestComponent",
167
- props: { title: "Test", count: 1 },
168
- streamingState: "done",
169
- },
170
- { type: "text", text: "World" },
171
- ];
172
- const result = (0, component_renderer_1.renderMessageContent)(content, {
173
- threadId: "thread_1",
174
- messageId: "msg_1",
175
- componentList: mockRegistry,
176
- });
177
- expect(result).toHaveLength(3);
178
- expect(result[0]).toEqual({ type: "text", text: "Hello" });
179
- expect(result[1].renderedComponent).not.toBeNull();
180
- expect(result[2]).toEqual({ type: "text", text: "World" });
181
- });
182
- it("handles multiple component blocks in a message", () => {
183
- const content = [
184
- {
185
- type: "component",
186
- id: "comp_1",
187
- name: "TestComponent",
188
- props: { title: "First", count: 1 },
189
- streamingState: "done",
190
- },
191
- {
192
- type: "component",
193
- id: "comp_2",
194
- name: "TestComponent",
195
- props: { title: "Second", count: 2 },
196
- streamingState: "done",
197
- },
198
- ];
199
- const result = (0, component_renderer_1.renderMessageContent)(content, {
200
- threadId: "thread_1",
201
- messageId: "msg_1",
202
- componentList: mockRegistry,
203
- });
204
- expect(result).toHaveLength(2);
205
- expect(result[0].renderedComponent).not.toBeNull();
206
- expect(result[1].renderedComponent).not.toBeNull();
207
- });
208
- it("handles tool_use content blocks unchanged", () => {
209
- const content = [
210
- {
211
- type: "tool_use",
212
- id: "tool_1",
213
- name: "search",
214
- input: { query: "test" },
215
- },
216
- ];
217
- const result = (0, component_renderer_1.renderMessageContent)(content, {
218
- threadId: "thread_1",
219
- messageId: "msg_1",
220
- componentList: mockRegistry,
221
- });
222
- expect(result).toHaveLength(1);
223
- expect(result[0]).toEqual(content[0]);
224
- });
225
- });
226
- describe("renderComponentContent edge cases", () => {
227
- it("shows main component when streamingState is 'started' (no loading component)", () => {
228
- const content = {
229
- type: "component",
230
- id: "comp_1",
231
- name: "TestComponent",
232
- props: { title: "Started", count: 0 },
233
- streamingState: "started",
234
- };
235
- const result = (0, component_renderer_1.renderComponentContent)(content, {
236
- threadId: "thread_1",
237
- messageId: "msg_1",
238
- componentList: mockRegistry,
239
- });
240
- // TestComponent has no loading component, so it shows main even when streaming
241
- (0, react_2.render)(react_1.default.createElement(react_1.default.Fragment, null, result.renderedComponent));
242
- expect(react_2.screen.getByTestId("title")).toHaveTextContent("Started");
243
- });
244
- it("shows loading component when streamingState is 'started' and loading exists", () => {
245
- const content = {
246
- type: "component",
247
- id: "comp_1",
248
- name: "TestWithLoading",
249
- props: { title: "Started", count: 0 },
250
- streamingState: "started",
251
- };
252
- const result = (0, component_renderer_1.renderComponentContent)(content, {
253
- threadId: "thread_1",
254
- messageId: "msg_1",
255
- componentList: mockRegistry,
256
- });
257
- (0, react_2.render)(react_1.default.createElement(react_1.default.Fragment, null, result.renderedComponent));
258
- expect(react_2.screen.getByTestId("loading")).toHaveTextContent("Loading...");
259
- });
260
- it("passes state as initialState prop", () => {
261
- // Component that reads initialState
262
- function StatefulComponent({ initialState, }) {
263
- return (react_1.default.createElement("div", { "data-testid": "initial-count" }, initialState?.count ?? "none"));
264
- }
265
- const registryWithStateful = {
266
- StatefulComponent: {
267
- component: StatefulComponent,
268
- name: "StatefulComponent",
269
- description: "A stateful component",
270
- props: {},
271
- contextTools: [],
272
- },
273
- };
274
- const content = {
275
- type: "component",
276
- id: "comp_1",
277
- name: "StatefulComponent",
278
- props: {},
279
- state: { count: 42 },
280
- streamingState: "done",
281
- };
282
- const result = (0, component_renderer_1.renderComponentContent)(content, {
283
- threadId: "thread_1",
284
- messageId: "msg_1",
285
- componentList: registryWithStateful,
286
- });
287
- (0, react_2.render)(react_1.default.createElement(react_1.default.Fragment, null, result.renderedComponent));
288
- expect(react_2.screen.getByTestId("initial-count")).toHaveTextContent("42");
289
- });
290
- it("preserves original content properties in returned object", () => {
291
- const content = {
292
- type: "component",
293
- id: "comp_custom",
294
- name: "TestComponent",
295
- props: { title: "Test", count: 5 },
296
- state: { value: "preserved" },
297
- streamingState: "done",
298
- };
299
- const result = (0, component_renderer_1.renderComponentContent)(content, {
300
- threadId: "thread_1",
301
- messageId: "msg_1",
302
- componentList: mockRegistry,
303
- });
304
- expect(result.id).toBe("comp_custom");
305
- expect(result.name).toBe("TestComponent");
306
- expect(result.props).toEqual({ title: "Test", count: 5 });
307
- expect(result.state).toEqual({ value: "preserved" });
308
- expect(result.streamingState).toBe("done");
309
- });
310
- });
311
- describe("useV1ComponentContentOptional", () => {
312
- it("returns null when used outside rendered component", () => {
313
- function TestConsumer() {
314
- const context = (0, component_renderer_1.useV1ComponentContentOptional)();
315
- return (react_1.default.createElement("div", { "data-testid": "context" }, context ? "has context" : "no context"));
316
- }
317
- (0, react_2.render)(react_1.default.createElement(TestConsumer, null));
318
- expect(react_2.screen.getByTestId("context")).toHaveTextContent("no context");
319
- });
320
- });
321
- describe("renderMessageComponents", () => {
322
- it("renders all components in a message", () => {
323
- const message = {
324
- id: "msg_1",
325
- role: "assistant",
326
- content: [
327
- { type: "text", text: "Here is the weather:" },
328
- {
329
- type: "component",
330
- id: "comp_1",
331
- name: "TestComponent",
332
- props: { title: "Weather", count: 72 },
333
- streamingState: "done",
334
- },
335
- ],
336
- createdAt: "2024-01-01T00:00:00.000Z",
337
- };
338
- const result = (0, component_renderer_1.renderMessageComponents)(message, {
339
- threadId: "thread_1",
340
- componentList: mockRegistry,
341
- });
342
- expect(result.id).toBe("msg_1");
343
- expect(result.content).toHaveLength(2);
344
- expect(result.content[0]).toEqual({
345
- type: "text",
346
- text: "Here is the weather:",
347
- });
348
- expect(result.content[1].renderedComponent).not.toBeNull();
349
- });
350
- it("preserves message metadata", () => {
351
- const message = {
352
- id: "msg_123",
353
- role: "assistant",
354
- content: [],
355
- createdAt: "2024-01-01T00:00:00.000Z",
356
- metadata: { custom: "value" },
357
- };
358
- const result = (0, component_renderer_1.renderMessageComponents)(message, {
359
- threadId: "thread_1",
360
- componentList: mockRegistry,
361
- });
362
- expect(result.id).toBe("msg_123");
363
- expect(result.role).toBe("assistant");
364
- expect(result.createdAt).toBe("2024-01-01T00:00:00.000Z");
365
- expect(result.metadata).toEqual({ custom: "value" });
366
- });
367
- });
368
- describe("useV1ComponentContent error handling", () => {
369
- it("throws when used outside rendered component", () => {
28
+ describe("useV1ComponentContent", () => {
29
+ it("throws when used outside provider", () => {
370
30
  function TestConsumer() {
371
31
  (0, component_renderer_1.useV1ComponentContent)();
372
32
  return react_1.default.createElement("div", null, "Should not render");
@@ -376,5 +36,10 @@ describe("useV1ComponentContent error handling", () => {
376
36
  expect(() => (0, react_2.render)(react_1.default.createElement(TestConsumer, null))).toThrow("useV1ComponentContent must be used within a rendered component");
377
37
  consoleSpy.mockRestore();
378
38
  });
39
+ it("returns context when used within provider", () => {
40
+ (0, react_2.render)(react_1.default.createElement(component_renderer_1.V1ComponentContentProvider, { componentId: "comp_test", threadId: "thread_test", messageId: "msg_test", componentName: "TestComp" },
41
+ react_1.default.createElement(ContextAwareComponent, null)));
42
+ expect(react_2.screen.getByTestId("componentId")).toHaveTextContent("comp_test");
43
+ });
379
44
  });
380
45
  //# sourceMappingURL=component-renderer.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"component-renderer.test.js","sourceRoot":"","sources":["../../../src/v1/utils/component-renderer.test.tsx"],"names":[],"mappings":"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","sourcesContent":["// React import needed for JSX transform (jsxImportSource is not set to react-jsx)\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport React from \"react\";\nimport { render, screen } from \"@testing-library/react\";\nimport type { ComponentRegistry } from \"../../model/component-metadata\";\nimport type { V1ComponentContent } from \"../types/message\";\nimport {\n isComponentContent,\n renderComponentContent,\n renderMessageContent,\n renderMessageComponents,\n useV1ComponentContent,\n useV1ComponentContentOptional,\n} from \"./component-renderer\";\n\n// Test component that displays its props\nfunction TestComponent({ title, count }: { title: string; count: number }) {\n return (\n <div data-testid=\"test-component\">\n <span data-testid=\"title\">{title}</span>\n <span data-testid=\"count\">{count}</span>\n </div>\n );\n}\n\n// Test loading component\nfunction TestLoadingComponent() {\n return <div data-testid=\"loading\">Loading...</div>;\n}\n\n// Test component that uses the content context\nfunction ContextAwareComponent() {\n const context = useV1ComponentContent();\n return (\n <div data-testid=\"context-aware\">\n <span data-testid=\"componentId\">{context.componentId}</span>\n <span data-testid=\"threadId\">{context.threadId}</span>\n <span data-testid=\"messageId\">{context.messageId}</span>\n </div>\n );\n}\n\nconst mockRegistry: ComponentRegistry = {\n TestComponent: {\n component: TestComponent,\n name: \"TestComponent\",\n description: \"A test component\",\n props: {},\n contextTools: [],\n },\n TestWithLoading: {\n component: TestComponent,\n loadingComponent: TestLoadingComponent,\n name: \"TestWithLoading\",\n description: \"A test component with loading state\",\n props: {},\n contextTools: [],\n },\n ContextAware: {\n component: ContextAwareComponent,\n name: \"ContextAware\",\n description: \"A context-aware component\",\n props: {},\n contextTools: [],\n },\n};\n\ndescribe(\"isComponentContent\", () => {\n it(\"returns true for component content\", () => {\n const content: V1ComponentContent = {\n type: \"component\",\n id: \"comp_1\",\n name: \"Test\",\n props: {},\n streamingState: \"done\",\n };\n expect(isComponentContent(content)).toBe(true);\n });\n\n it(\"returns false for text content\", () => {\n const content = { type: \"text\", text: \"hello\" };\n expect(isComponentContent(content as any)).toBe(false);\n });\n});\n\ndescribe(\"renderComponentContent\", () => {\n it(\"renders a component from registry\", () => {\n const content: V1ComponentContent = {\n type: \"component\",\n id: \"comp_1\",\n name: \"TestComponent\",\n props: { title: \"Hello\", count: 42 },\n streamingState: \"done\",\n };\n\n const result = renderComponentContent(content, {\n threadId: \"thread_1\",\n messageId: \"msg_1\",\n componentList: mockRegistry,\n });\n\n expect(result.renderedComponent).not.toBeNull();\n\n // Render and check output\n render(<>{result.renderedComponent}</>);\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Hello\");\n expect(screen.getByTestId(\"count\")).toHaveTextContent(\"42\");\n });\n\n it(\"returns null renderedComponent for unknown component\", () => {\n const content: V1ComponentContent = {\n type: \"component\",\n id: \"comp_1\",\n name: \"UnknownComponent\",\n props: {},\n streamingState: \"done\",\n };\n\n const consoleWarn = jest.spyOn(console, \"warn\").mockImplementation();\n\n const result = renderComponentContent(content, {\n threadId: \"thread_1\",\n messageId: \"msg_1\",\n componentList: mockRegistry,\n });\n\n expect(result.renderedComponent).toBeNull();\n expect(consoleWarn).toHaveBeenCalledWith(\n 'Component \"UnknownComponent\" not found in registry',\n );\n\n consoleWarn.mockRestore();\n });\n\n it(\"shows loading component when streaming\", () => {\n const content: V1ComponentContent = {\n type: \"component\",\n id: \"comp_1\",\n name: \"TestWithLoading\",\n props: { title: \"Loading Test\", count: 0 },\n streamingState: \"streaming\",\n };\n\n const result = renderComponentContent(content, {\n threadId: \"thread_1\",\n messageId: \"msg_1\",\n componentList: mockRegistry,\n });\n\n render(<>{result.renderedComponent}</>);\n expect(screen.getByTestId(\"loading\")).toHaveTextContent(\"Loading...\");\n });\n\n it(\"shows main component when done streaming\", () => {\n const content: V1ComponentContent = {\n type: \"component\",\n id: \"comp_1\",\n name: \"TestWithLoading\",\n props: { title: \"Done Test\", count: 99 },\n streamingState: \"done\",\n };\n\n const result = renderComponentContent(content, {\n threadId: \"thread_1\",\n messageId: \"msg_1\",\n componentList: mockRegistry,\n });\n\n render(<>{result.renderedComponent}</>);\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Done Test\");\n expect(screen.getByTestId(\"count\")).toHaveTextContent(\"99\");\n });\n\n it(\"provides component context to rendered components\", () => {\n const content: V1ComponentContent = {\n type: \"component\",\n id: \"comp_123\",\n name: \"ContextAware\",\n props: {},\n streamingState: \"done\",\n };\n\n const result = renderComponentContent(content, {\n threadId: \"thread_456\",\n messageId: \"msg_789\",\n componentList: mockRegistry,\n });\n\n render(<>{result.renderedComponent}</>);\n expect(screen.getByTestId(\"componentId\")).toHaveTextContent(\"comp_123\");\n expect(screen.getByTestId(\"threadId\")).toHaveTextContent(\"thread_456\");\n expect(screen.getByTestId(\"messageId\")).toHaveTextContent(\"msg_789\");\n });\n});\n\ndescribe(\"renderMessageContent\", () => {\n it(\"renders component content blocks and passes through others\", () => {\n const content = [\n { type: \"text\", text: \"Hello\" },\n {\n type: \"component\",\n id: \"comp_1\",\n name: \"TestComponent\",\n props: { title: \"Test\", count: 1 },\n streamingState: \"done\",\n } as V1ComponentContent,\n { type: \"text\", text: \"World\" },\n ];\n\n const result = renderMessageContent(content as any, {\n threadId: \"thread_1\",\n messageId: \"msg_1\",\n componentList: mockRegistry,\n });\n\n expect(result).toHaveLength(3);\n expect(result[0]).toEqual({ type: \"text\", text: \"Hello\" });\n expect((result[1] as any).renderedComponent).not.toBeNull();\n expect(result[2]).toEqual({ type: \"text\", text: \"World\" });\n });\n\n it(\"handles multiple component blocks in a message\", () => {\n const content = [\n {\n type: \"component\",\n id: \"comp_1\",\n name: \"TestComponent\",\n props: { title: \"First\", count: 1 },\n streamingState: \"done\",\n } as V1ComponentContent,\n {\n type: \"component\",\n id: \"comp_2\",\n name: \"TestComponent\",\n props: { title: \"Second\", count: 2 },\n streamingState: \"done\",\n } as V1ComponentContent,\n ];\n\n const result = renderMessageContent(content as any, {\n threadId: \"thread_1\",\n messageId: \"msg_1\",\n componentList: mockRegistry,\n });\n\n expect(result).toHaveLength(2);\n expect((result[0] as V1ComponentContent).renderedComponent).not.toBeNull();\n expect((result[1] as V1ComponentContent).renderedComponent).not.toBeNull();\n });\n\n it(\"handles tool_use content blocks unchanged\", () => {\n const content = [\n {\n type: \"tool_use\",\n id: \"tool_1\",\n name: \"search\",\n input: { query: \"test\" },\n },\n ];\n\n const result = renderMessageContent(content as any, {\n threadId: \"thread_1\",\n messageId: \"msg_1\",\n componentList: mockRegistry,\n });\n\n expect(result).toHaveLength(1);\n expect(result[0]).toEqual(content[0]);\n });\n});\n\ndescribe(\"renderComponentContent edge cases\", () => {\n it(\"shows main component when streamingState is 'started' (no loading component)\", () => {\n const content: V1ComponentContent = {\n type: \"component\",\n id: \"comp_1\",\n name: \"TestComponent\",\n props: { title: \"Started\", count: 0 },\n streamingState: \"started\",\n };\n\n const result = renderComponentContent(content, {\n threadId: \"thread_1\",\n messageId: \"msg_1\",\n componentList: mockRegistry,\n });\n\n // TestComponent has no loading component, so it shows main even when streaming\n render(<>{result.renderedComponent}</>);\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Started\");\n });\n\n it(\"shows loading component when streamingState is 'started' and loading exists\", () => {\n const content: V1ComponentContent = {\n type: \"component\",\n id: \"comp_1\",\n name: \"TestWithLoading\",\n props: { title: \"Started\", count: 0 },\n streamingState: \"started\",\n };\n\n const result = renderComponentContent(content, {\n threadId: \"thread_1\",\n messageId: \"msg_1\",\n componentList: mockRegistry,\n });\n\n render(<>{result.renderedComponent}</>);\n expect(screen.getByTestId(\"loading\")).toHaveTextContent(\"Loading...\");\n });\n\n it(\"passes state as initialState prop\", () => {\n // Component that reads initialState\n function StatefulComponent({\n initialState,\n }: {\n initialState?: { count: number };\n }) {\n return (\n <div data-testid=\"initial-count\">{initialState?.count ?? \"none\"}</div>\n );\n }\n\n const registryWithStateful: ComponentRegistry = {\n StatefulComponent: {\n component: StatefulComponent,\n name: \"StatefulComponent\",\n description: \"A stateful component\",\n props: {},\n contextTools: [],\n },\n };\n\n const content: V1ComponentContent = {\n type: \"component\",\n id: \"comp_1\",\n name: \"StatefulComponent\",\n props: {},\n state: { count: 42 },\n streamingState: \"done\",\n };\n\n const result = renderComponentContent(content, {\n threadId: \"thread_1\",\n messageId: \"msg_1\",\n componentList: registryWithStateful,\n });\n\n render(<>{result.renderedComponent}</>);\n expect(screen.getByTestId(\"initial-count\")).toHaveTextContent(\"42\");\n });\n\n it(\"preserves original content properties in returned object\", () => {\n const content: V1ComponentContent = {\n type: \"component\",\n id: \"comp_custom\",\n name: \"TestComponent\",\n props: { title: \"Test\", count: 5 },\n state: { value: \"preserved\" },\n streamingState: \"done\",\n };\n\n const result = renderComponentContent(content, {\n threadId: \"thread_1\",\n messageId: \"msg_1\",\n componentList: mockRegistry,\n });\n\n expect(result.id).toBe(\"comp_custom\");\n expect(result.name).toBe(\"TestComponent\");\n expect(result.props).toEqual({ title: \"Test\", count: 5 });\n expect(result.state).toEqual({ value: \"preserved\" });\n expect(result.streamingState).toBe(\"done\");\n });\n});\n\ndescribe(\"useV1ComponentContentOptional\", () => {\n it(\"returns null when used outside rendered component\", () => {\n function TestConsumer() {\n const context = useV1ComponentContentOptional();\n return (\n <div data-testid=\"context\">\n {context ? \"has context\" : \"no context\"}\n </div>\n );\n }\n\n render(<TestConsumer />);\n expect(screen.getByTestId(\"context\")).toHaveTextContent(\"no context\");\n });\n});\n\ndescribe(\"renderMessageComponents\", () => {\n it(\"renders all components in a message\", () => {\n const message = {\n id: \"msg_1\",\n role: \"assistant\" as const,\n content: [\n { type: \"text\" as const, text: \"Here is the weather:\" },\n {\n type: \"component\",\n id: \"comp_1\",\n name: \"TestComponent\",\n props: { title: \"Weather\", count: 72 },\n streamingState: \"done\",\n } as V1ComponentContent,\n ],\n createdAt: \"2024-01-01T00:00:00.000Z\",\n };\n\n const result = renderMessageComponents(message, {\n threadId: \"thread_1\",\n componentList: mockRegistry,\n });\n\n expect(result.id).toBe(\"msg_1\");\n expect(result.content).toHaveLength(2);\n expect(result.content[0]).toEqual({\n type: \"text\",\n text: \"Here is the weather:\",\n });\n expect(\n (result.content[1] as V1ComponentContent).renderedComponent,\n ).not.toBeNull();\n });\n\n it(\"preserves message metadata\", () => {\n const message = {\n id: \"msg_123\",\n role: \"assistant\" as const,\n content: [],\n createdAt: \"2024-01-01T00:00:00.000Z\",\n metadata: { custom: \"value\" },\n };\n\n const result = renderMessageComponents(message, {\n threadId: \"thread_1\",\n componentList: mockRegistry,\n });\n\n expect(result.id).toBe(\"msg_123\");\n expect(result.role).toBe(\"assistant\");\n expect(result.createdAt).toBe(\"2024-01-01T00:00:00.000Z\");\n expect(result.metadata).toEqual({ custom: \"value\" });\n });\n});\n\ndescribe(\"useV1ComponentContent error handling\", () => {\n it(\"throws when used outside rendered component\", () => {\n function TestConsumer() {\n useV1ComponentContent();\n return <div>Should not render</div>;\n }\n\n // Suppress React error boundary logs\n const consoleSpy = jest.spyOn(console, \"error\").mockImplementation();\n\n expect(() => render(<TestConsumer />)).toThrow(\n \"useV1ComponentContent must be used within a rendered component\",\n );\n\n consoleSpy.mockRestore();\n });\n});\n"]}
1
+ {"version":3,"file":"component-renderer.test.js","sourceRoot":"","sources":["../../../src/v1/utils/component-renderer.test.tsx"],"names":[],"mappings":";;;;;AAAA,kDAA0B;AAC1B,kDAAwD;AACxD,6DAG8B;AAE9B,+CAA+C;AAC/C,MAAM,qBAAqB,GAAa,GAAG,EAAE;IAC3C,MAAM,OAAO,GAAG,IAAA,0CAAqB,GAAE,CAAC;IACxC,OAAO,CACL,sDAAiB,eAAe;QAC9B,uDAAkB,aAAa,IAAE,OAAO,CAAC,WAAW,CAAQ;QAC5D,uDAAkB,UAAU,IAAE,OAAO,CAAC,QAAQ,CAAQ;QACtD,uDAAkB,WAAW,IAAE,OAAO,CAAC,SAAS,CAAQ;QACxD,uDAAkB,eAAe,IAAE,OAAO,CAAC,aAAa,CAAQ,CAC5D,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,IAAA,cAAM,EACJ,8BAAC,+CAA0B,IACzB,WAAW,EAAC,UAAU,EACtB,QAAQ,EAAC,YAAY,EACrB,SAAS,EAAC,SAAS,EACnB,aAAa,EAAC,eAAe;YAE7B,8BAAC,qBAAqB,OAAG,CACE,CAC9B,CAAC;QAEF,MAAM,CAAC,cAAM,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;QACxE,MAAM,CAAC,cAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;QACvE,MAAM,CAAC,cAAM,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QACrE,MAAM,CAAC,cAAM,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,iBAAiB,CAC3D,eAAe,CAChB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,SAAS,YAAY;YACnB,IAAA,0CAAqB,GAAE,CAAC;YACxB,OAAO,+DAA4B,CAAC;QACtC,CAAC;QAED,qCAAqC;QACrC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,kBAAkB,EAAE,CAAC;QAErE,MAAM,CAAC,GAAG,EAAE,CAAC,IAAA,cAAM,EAAC,8BAAC,YAAY,OAAG,CAAC,CAAC,CAAC,OAAO,CAC5C,gEAAgE,CACjE,CAAC;QAEF,UAAU,CAAC,WAAW,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,IAAA,cAAM,EACJ,8BAAC,+CAA0B,IACzB,WAAW,EAAC,WAAW,EACvB,QAAQ,EAAC,aAAa,EACtB,SAAS,EAAC,UAAU,EACpB,aAAa,EAAC,UAAU;YAExB,8BAAC,qBAAqB,OAAG,CACE,CAC9B,CAAC;QAEF,MAAM,CAAC,cAAM,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import React from \"react\";\nimport { render, screen } from \"@testing-library/react\";\nimport {\n useV1ComponentContent,\n V1ComponentContentProvider,\n} from \"./component-renderer\";\n\n// Test component that uses the content context\nconst ContextAwareComponent: React.FC = () => {\n const context = useV1ComponentContent();\n return (\n <div data-testid=\"context-aware\">\n <span data-testid=\"componentId\">{context.componentId}</span>\n <span data-testid=\"threadId\">{context.threadId}</span>\n <span data-testid=\"messageId\">{context.messageId}</span>\n <span data-testid=\"componentName\">{context.componentName}</span>\n </div>\n );\n};\n\ndescribe(\"V1ComponentContentProvider\", () => {\n it(\"provides context to child components\", () => {\n render(\n <V1ComponentContentProvider\n componentId=\"comp_123\"\n threadId=\"thread_456\"\n messageId=\"msg_789\"\n componentName=\"TestComponent\"\n >\n <ContextAwareComponent />\n </V1ComponentContentProvider>,\n );\n\n expect(screen.getByTestId(\"componentId\")).toHaveTextContent(\"comp_123\");\n expect(screen.getByTestId(\"threadId\")).toHaveTextContent(\"thread_456\");\n expect(screen.getByTestId(\"messageId\")).toHaveTextContent(\"msg_789\");\n expect(screen.getByTestId(\"componentName\")).toHaveTextContent(\n \"TestComponent\",\n );\n });\n});\n\ndescribe(\"useV1ComponentContent\", () => {\n it(\"throws when used outside provider\", () => {\n function TestConsumer() {\n useV1ComponentContent();\n return <div>Should not render</div>;\n }\n\n // Suppress React error boundary logs\n const consoleSpy = jest.spyOn(console, \"error\").mockImplementation();\n\n expect(() => render(<TestConsumer />)).toThrow(\n \"useV1ComponentContent must be used within a rendered component\",\n );\n\n consoleSpy.mockRestore();\n });\n\n it(\"returns context when used within provider\", () => {\n render(\n <V1ComponentContentProvider\n componentId=\"comp_test\"\n threadId=\"thread_test\"\n messageId=\"msg_test\"\n componentName=\"TestComp\"\n >\n <ContextAwareComponent />\n </V1ComponentContentProvider>,\n );\n\n expect(screen.getByTestId(\"componentId\")).toHaveTextContent(\"comp_test\");\n });\n});\n"]}
@@ -29,6 +29,8 @@ export interface McpResourceEntry {
29
29
  export type ListResourceEntry = RegistryResourceEntry | McpResourceEntry;
30
30
  /**
31
31
  * Type guard for narrowing a `ListResourceEntry` to an MCP-backed resource.
32
+ * @param entry - The resource entry to check
33
+ * @returns True if the entry is from an MCP server, false if it's from the registry
32
34
  */
33
35
  export declare function isMcpResourceEntry(entry: ListResourceEntry): entry is McpResourceEntry;
34
36
  /**
@@ -73,6 +75,8 @@ export declare function useTamboMcpPromptList(search?: string): {
73
75
  /**
74
76
  * Type guard for narrowing McpServer to ConnectedMcpServer.
75
77
  * A connected server has a non-null client.
78
+ * @param server - The MCP server to check
79
+ * @returns True if the server is connected, false otherwise
76
80
  */
77
81
  export declare function isConnectedMcpServer(server: McpServer): server is ConnectedMcpServer;
78
82
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-hooks.d.ts","sourceRoot":"","sources":["../../src/mcp/mcp-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAEzB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAKvD,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,SAAS,EAEf,MAAM,sBAAsB,CAAC;AAE9B,MAAM,MAAM,cAAc,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAClE,MAAM,WAAW,eAAe;IAE9B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,IAAI,CAAC;IACb,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,GAAG,gBAAgB,CAAC;AAoBzE;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,iBAAiB,GACvB,KAAK,IAAI,gBAAgB,CAE3B;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;gBA7D3C,kBAAkB;;WAyHnB,KAAK,GAAG,IAAI;YACX,KAAK,EAAE;eACJ,OAAO;eACP,OAAO;aACT,OAAO;cACN,OAAO;kBACH,OAAO;gBACT,OAAO;eACR,OAAO;aACT,MAAM,OAAO,CAAC,IAAI,CAAC;EAb7B;AAmDD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,GAChB,MAAM,IAAI,kBAAkB,CAE9B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0ClC;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE,MAAM;;WAnH9C,KAAK,GAAG,IAAI;YACX,KAAK,EAAE;eACJ,OAAO;eACP,OAAO;aACT,OAAO;cACN,OAAO;kBACH,OAAO;gBACT,OAAO;eACR,OAAO;aACT,MAAM,OAAO,CAAC,IAAI,CAAC;EAsO7B;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;iBAoElE"}
1
+ {"version":3,"file":"mcp-hooks.d.ts","sourceRoot":"","sources":["../../src/mcp/mcp-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAEzB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAKvD,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,SAAS,EAEf,MAAM,sBAAsB,CAAC;AAE9B,MAAM,MAAM,cAAc,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAClE,MAAM,WAAW,eAAe;IAE9B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,IAAI,CAAC;IACb,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,GAAG,gBAAgB,CAAC;AAoBzE;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,iBAAiB,GACvB,KAAK,IAAI,gBAAgB,CAE3B;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;gBA/D3C,kBAAkB;;WA2HnB,KAAK,GAAG,IAAI;YACX,KAAK,EAAE;eACJ,OAAO;eACP,OAAO;aACT,OAAO;cACN,OAAO;kBACH,OAAO;gBACT,OAAO;eACR,OAAO;aACT,MAAM,OAAO,CAAC,IAAI,CAAC;EAb7B;AAmDD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,GAChB,MAAM,IAAI,kBAAkB,CAE9B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0ClC;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE,MAAM;;WArH9C,KAAK,GAAG,IAAI;YACX,KAAK,EAAE;eACJ,OAAO;eACP,OAAO;aACT,OAAO;cACN,OAAO;kBACH,OAAO;gBACT,OAAO;eACR,OAAO;aACT,MAAM,OAAO,CAAC,IAAI,CAAC;EAwO7B;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;iBAoElE"}
@@ -12,6 +12,8 @@ function toPublicResourceEntry(entry) {
12
12
  }
13
13
  /**
14
14
  * Type guard for narrowing a `ListResourceEntry` to an MCP-backed resource.
15
+ * @param entry - The resource entry to check
16
+ * @returns True if the entry is from an MCP server, false if it's from the registry
15
17
  */
16
18
  export function isMcpResourceEntry(entry) {
17
19
  return entry.server !== null && isConnectedMcpServer(entry.server);
@@ -105,6 +107,8 @@ function combineArrayResults(results) {
105
107
  /**
106
108
  * Type guard for narrowing McpServer to ConnectedMcpServer.
107
109
  * A connected server has a non-null client.
110
+ * @param server - The MCP server to check
111
+ * @returns True if the server is connected, false otherwise
108
112
  */
109
113
  export function isConnectedMcpServer(server) {
110
114
  return "client" in server && server.client != null;