@tylertech/forge-ai 0.15.2 → 0.15.3-dev.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 (88) hide show
  1. package/custom-elements.json +4501 -1781
  2. package/dist/ai-artifact-card/ai-artifact-card.d.ts +75 -0
  3. package/dist/ai-artifact-card/ai-artifact-card.mjs +142 -0
  4. package/dist/ai-artifact-card/ai-artifact-card.scss.mjs +283 -0
  5. package/dist/ai-artifact-card/index.d.ts +1 -0
  6. package/dist/ai-artifact-card/index.mjs +5 -0
  7. package/dist/ai-artifact-card-group/ai-artifact-card-group.d.ts +57 -0
  8. package/dist/ai-artifact-card-group/ai-artifact-card-group.mjs +137 -0
  9. package/dist/ai-artifact-card-group/ai-artifact-card-group.scss.mjs +173 -0
  10. package/dist/ai-artifact-card-group/index.d.ts +1 -0
  11. package/dist/ai-artifact-card-group/index.mjs +5 -0
  12. package/dist/ai-assistant-response/ai-assistant-response.d.ts +2 -2
  13. package/dist/ai-assistant-response/ai-assistant-response.mjs +26 -2
  14. package/dist/ai-canvas/ai-canvas.d.ts +43 -0
  15. package/dist/ai-canvas/ai-canvas.mjs +95 -0
  16. package/dist/ai-canvas/ai-canvas.scss.mjs +4 -0
  17. package/dist/ai-canvas/index.d.ts +1 -0
  18. package/dist/ai-canvas/index.mjs +5 -0
  19. package/dist/ai-chatbot/ag-ui-adapter.d.ts +2 -2
  20. package/dist/ai-chatbot/ag-ui-adapter.mjs +1 -1
  21. package/dist/ai-chatbot/agent-adapter.d.ts +111 -4
  22. package/dist/ai-chatbot/agent-adapter.mjs +22 -0
  23. package/dist/ai-chatbot/agent-runner.d.ts +2 -2
  24. package/dist/ai-chatbot/ai-chatbot-base.d.ts +29 -2
  25. package/dist/ai-chatbot/ai-chatbot-base.mjs +147 -3
  26. package/dist/ai-chatbot/ai-chatbot-tool-call.d.ts +2 -2
  27. package/dist/ai-chatbot/ai-chatbot-tool-call.mjs +88 -10
  28. package/dist/ai-chatbot/ai-chatbot.d.ts +24 -1
  29. package/dist/ai-chatbot/ai-chatbot.mjs +102 -2
  30. package/dist/ai-chatbot/ai-chatbot.scss.mjs +1 -1
  31. package/dist/ai-chatbot/create-tool-renderer.d.ts +5 -5
  32. package/dist/ai-chatbot/index.d.ts +3 -2
  33. package/dist/ai-chatbot/index.mjs +3 -0
  34. package/dist/ai-chatbot/message-state-controller.d.ts +10 -1
  35. package/dist/ai-chatbot/message-state-controller.mjs +78 -20
  36. package/dist/ai-chatbot/tool-canvas.d.ts +60 -0
  37. package/dist/ai-chatbot/tool-canvas.mjs +128 -0
  38. package/dist/ai-chatbot/types.d.ts +325 -15
  39. package/dist/ai-chatbot/utils.d.ts +8 -3
  40. package/dist/ai-chatbot/utils.mjs +7 -1
  41. package/dist/ai-chatbot-launcher/ai-chatbot-launcher.d.ts +40 -2
  42. package/dist/ai-chatbot-launcher/ai-chatbot-launcher.mjs +224 -7
  43. package/dist/ai-chatbot-launcher/ai-chatbot-launcher.scss.mjs +1 -1
  44. package/dist/ai-embedded-chat/ai-embedded-chat.mjs +1 -0
  45. package/dist/ai-message-thread/ai-message-thread.d.ts +3 -2
  46. package/dist/ai-message-thread/ai-message-thread.mjs +36 -3
  47. package/dist/ai-steps/ai-steps.d.ts +67 -0
  48. package/dist/ai-steps/ai-steps.mjs +163 -0
  49. package/dist/ai-steps/ai-steps.scss.mjs +4 -0
  50. package/dist/ai-steps/index.d.ts +1 -0
  51. package/dist/ai-steps/index.mjs +5 -0
  52. package/dist/ai-tool-call-indicator/ai-tool-call-indicator.d.ts +2 -2
  53. package/dist/ai-tool-call-indicator/ai-tool-call-indicator.mjs +1 -1
  54. package/dist/core/canvas-controller.d.ts +81 -0
  55. package/dist/core/canvas-controller.mjs +221 -0
  56. package/dist/core/chatbot-core-controller.d.ts +4 -2
  57. package/dist/core/chatbot-core-controller.mjs +121 -4
  58. package/dist/core/index.d.ts +2 -1
  59. package/dist/core/index.mjs +2 -0
  60. package/dist/core/resize-controller.d.ts +5 -0
  61. package/dist/core/resize-controller.mjs +7 -5
  62. package/dist/index.d.ts +4 -0
  63. package/dist/index.mjs +15 -0
  64. package/dist/tools/ai-data-table/ai-data-table-definition.mjs +1 -0
  65. package/dist/tools/ai-mcp-app/ai-mcp-app.d.ts +70 -0
  66. package/dist/tools/ai-mcp-app/ai-mcp-app.mjs +589 -0
  67. package/dist/tools/ai-mcp-app/ai-mcp-app.scss.mjs +4 -0
  68. package/dist/tools/ai-mcp-app/index.d.ts +3 -0
  69. package/dist/tools/ai-mcp-app/index.mjs +6 -0
  70. package/dist/tools/ai-mcp-app/mcp-app-bridge-controller.d.ts +60 -0
  71. package/dist/tools/ai-mcp-app/mcp-app-bridge-controller.mjs +147 -0
  72. package/dist/tools/ai-mcp-app/mcp-app-bridge-types.d.ts +124 -0
  73. package/dist/tools/ai-mcp-app/mcp-app-bridge.d.ts +41 -0
  74. package/dist/tools/ai-mcp-app/mcp-app-bridge.mjs +293 -0
  75. package/dist/tools/ai-mcp-app/mcp-app-context.d.ts +46 -0
  76. package/dist/tools/ai-mcp-app/mcp-app-context.mjs +5 -0
  77. package/dist/tools/ai-steps/ai-steps-definition.d.ts +2 -0
  78. package/dist/tools/ai-steps/ai-steps-definition.mjs +51 -0
  79. package/dist/tools/ai-steps/ai-steps.d.ts +28 -0
  80. package/dist/tools/ai-steps/ai-steps.mjs +49 -0
  81. package/dist/tools/ai-steps/ai-steps.scss.mjs +4 -0
  82. package/dist/tools/ai-steps/index.d.ts +2 -0
  83. package/dist/tools/ai-steps/index.mjs +6 -0
  84. package/dist/tools/index.d.ts +1 -0
  85. package/dist/tools/index.mjs +5 -1
  86. package/dist/utils/inert-outside.d.ts +7 -0
  87. package/dist/utils/inert-outside.mjs +28 -0
  88. package/package.json +4 -1
@@ -1,4 +1,14 @@
1
1
  import { generateId } from "./utils.mjs";
2
+ function withoutMcpAppResource(toolCall) {
3
+ if (!toolCall.uiResource && !toolCall.uiResourceStatus) {
4
+ return toolCall;
5
+ }
6
+ const { uiResource: _uiResource, uiResourceStatus: _uiResourceStatus, ...rest } = toolCall;
7
+ return rest;
8
+ }
9
+ function responseItemWithoutMcpAppResource(item) {
10
+ return item.type === "toolCall" ? { type: "toolCall", data: withoutMcpAppResource(item.data) } : item;
11
+ }
2
12
  class MessageStateController {
3
13
  constructor(_host, _config) {
4
14
  this._host = _host;
@@ -103,33 +113,61 @@ class MessageStateController {
103
113
  this.#updateResponseInItems();
104
114
  this.#notifyStateChange();
105
115
  }
116
+ /**
117
+ * Applies `updates` to a tool call wherever it is rendered: the in-progress response,
118
+ * an already finalized/restored response, or a top-level tool-call item.
119
+ */
106
120
  updateToolCallInResponse(toolCallId, updates) {
107
121
  const toolCall = this._toolCalls.get(toolCallId);
108
122
  if (!toolCall) {
109
123
  return;
110
124
  }
111
- const isCompleting = updates.status === "complete" || updates.status === "error";
125
+ const isFinishing = updates.status === "complete" || updates.status === "error" || updates.status === "cancelled";
112
126
  const updated = {
113
127
  ...toolCall,
114
128
  ...updates,
115
- ...isCompleting && !toolCall.endTimestamp ? { endTimestamp: Date.now() } : {}
129
+ ...isFinishing && !toolCall.endTimestamp ? { endTimestamp: Date.now() } : {}
116
130
  };
117
131
  this._toolCalls.set(toolCallId, updated);
118
- if (this._activeResponse) {
119
- for (const child of this._activeResponse.children) {
120
- if (child.type === "toolCall" && child.data.id === toolCallId) {
121
- child.data = updated;
122
- break;
123
- }
124
- }
125
- }
126
- this.#updateResponseInItems();
132
+ this.#replaceToolCall(updated);
127
133
  this.#notifyStateChange();
128
134
  }
129
135
  completeToolCallInResponse(toolCallId, result, event) {
130
136
  this.updateToolCallInResponse(toolCallId, {
131
137
  result,
132
- status: event?.isError === true ? "error" : "complete"
138
+ status: this.#resultStatus(event),
139
+ ...event ? {
140
+ structuredContent: event.structuredContent,
141
+ structuredContentOmitted: event.structuredContentOmitted,
142
+ mcpResult: event.mcpResult,
143
+ mcpResultOmitted: event.mcpResultOmitted
144
+ } : {}
145
+ });
146
+ }
147
+ #resultStatus(event) {
148
+ if (event?.cancelled) {
149
+ return "cancelled";
150
+ }
151
+ return event?.isError ? "error" : "complete";
152
+ }
153
+ #replaceToolCall(updated) {
154
+ const matches = (child) => child.type === "toolCall" && child.data.id === updated.id;
155
+ const replace = (children) => children.map((child) => matches(child) ? { type: "toolCall", data: updated } : child);
156
+ const activeResponse = this._activeResponse;
157
+ if (activeResponse?.children.some(matches)) {
158
+ activeResponse.children = replace(activeResponse.children);
159
+ }
160
+ this._messageItems = this._messageItems.map((item) => {
161
+ if (item.type === "toolCall" && item.data.id === updated.id) {
162
+ return { type: "toolCall", data: updated };
163
+ }
164
+ if (item.type !== "assistant" || !item.data.children.some(matches)) {
165
+ return item;
166
+ }
167
+ if (item.data.id === activeResponse?.id) {
168
+ return { type: "assistant", data: { ...activeResponse } };
169
+ }
170
+ return { type: "assistant", data: { ...item.data, children: replace(item.data.children) } };
133
171
  });
134
172
  }
135
173
  tryFinalizeResponse() {
@@ -242,14 +280,32 @@ class MessageStateController {
242
280
  this.#notifyStateChange();
243
281
  this._config.onThreadSettled?.();
244
282
  }
283
+ /** Tool call ids rendered at or after `index`, inside assistant responses or as top-level items. */
284
+ getToolCallIdsFrom(index) {
285
+ return this._messageItems.slice(index).flatMap((item) => {
286
+ if (item.type === "toolCall") {
287
+ return [item.data.id];
288
+ }
289
+ if (item.type === "assistant") {
290
+ return item.data.children.flatMap((child) => child.type === "toolCall" ? [child.data.id] : []);
291
+ }
292
+ return [];
293
+ });
294
+ }
295
+ /** Removes items from `index` onward and returns the ids of the tool calls they held. */
245
296
  removeMessageItemsFrom(index) {
297
+ const removedToolCallIds = this.getToolCallIdsFrom(index);
298
+ removedToolCallIds.forEach((id) => this._toolCalls.delete(id));
246
299
  this._messageItems = this._messageItems.slice(0, index);
247
300
  this._activeResponse = null;
248
301
  this.#notifyStateChange();
302
+ return removedToolCallIds;
249
303
  }
250
304
  /**
251
305
  * Reconstructs the message hierarchy for API compatibility.
252
306
  * Converts assistant responses back to ChatMessage format with tool calls.
307
+ * MCP-app `uiResource`/`uiResourceStatus` are stripped: resources are re-resolved via the
308
+ * adapter on restore, never persisted or sent back to the agent.
253
309
  */
254
310
  getMessages() {
255
311
  const messages = [];
@@ -258,8 +314,9 @@ class MessageStateController {
258
314
  messages.push({ ...item.data, toolCalls: [] });
259
315
  } else if (item.type === "assistant") {
260
316
  const response = item.data;
261
- const textContent = response.children.filter((c) => c.type === "text").map((c) => c.content).join("");
262
- const toolCalls = response.children.filter((c) => c.type === "toolCall").map((c) => c.data);
317
+ const children = response.children.map(responseItemWithoutMcpAppResource);
318
+ const textContent = children.filter((c) => c.type === "text").map((c) => c.content).join("");
319
+ const toolCalls = children.filter((c) => c.type === "toolCall").map((c) => c.data);
263
320
  const message = {
264
321
  id: response.id,
265
322
  role: "assistant",
@@ -268,13 +325,13 @@ class MessageStateController {
268
325
  status: response.status === "streaming" ? "streaming" : response.status === "error" ? "error" : "complete",
269
326
  toolCalls: toolCalls.length ? toolCalls : void 0,
270
327
  feedback: response.feedback,
271
- children: response.children
328
+ children
272
329
  };
273
330
  messages.push(message);
274
331
  } else if (item.type === "toolCall") {
275
332
  const lastMsg = messages[messages.length - 1];
276
333
  if (lastMsg && lastMsg.role === "assistant") {
277
- lastMsg.toolCalls = [...lastMsg.toolCalls || [], item.data];
334
+ lastMsg.toolCalls = [...lastMsg.toolCalls || [], withoutMcpAppResource(item.data)];
278
335
  }
279
336
  }
280
337
  }
@@ -289,10 +346,11 @@ class MessageStateController {
289
346
  let children;
290
347
  if (msg.children?.length) {
291
348
  children = msg.children.map((child) => {
292
- if (child.type === "toolCall") {
293
- this._toolCalls.set(child.data.id, child.data);
349
+ const restored = responseItemWithoutMcpAppResource(child);
350
+ if (restored.type === "toolCall") {
351
+ this._toolCalls.set(restored.data.id, restored.data);
294
352
  }
295
- return child;
353
+ return restored;
296
354
  });
297
355
  } else {
298
356
  children = [];
@@ -300,7 +358,7 @@ class MessageStateController {
300
358
  children.push({ type: "text", messageId: msg.id, content: msg.content, status: "complete" });
301
359
  }
302
360
  if (msg.toolCalls) {
303
- for (const toolCall of msg.toolCalls) {
361
+ for (const toolCall of msg.toolCalls.map(withoutMcpAppResource)) {
304
362
  children.push({ type: "toolCall", data: toolCall });
305
363
  this._toolCalls.set(toolCall.id, toolCall);
306
364
  }
@@ -0,0 +1,60 @@
1
+ import { ToolCall, ToolCanvas, ToolCanvasInline, AnyToolDefinition, ToolPresentation } from './types.js';
2
+ export interface ForgeAiCanvasOpenRequestEventData {
3
+ toolCallId: string;
4
+ toolName: string;
5
+ title?: string;
6
+ /** Set to true by the host once the tool call is showing in the canvas. */
7
+ handled?: boolean;
8
+ }
9
+ export interface ForgeAiCanvasCloseRequestEventData {
10
+ toolCallId: string;
11
+ /** Set to true by the host once the canvas has closed. */
12
+ handled?: boolean;
13
+ }
14
+ declare global {
15
+ interface HTMLElementEventMap {
16
+ 'forge-ai-canvas-open-request': CustomEvent<ForgeAiCanvasOpenRequestEventData>;
17
+ 'forge-ai-canvas-close-request': CustomEvent<ForgeAiCanvasCloseRequestEventData>;
18
+ }
19
+ }
20
+ /** State a canvas host shares with the tool calls rendered in its thread. */
21
+ export interface ToolCanvasHostState {
22
+ /** Presentation assigned to inline renderers of canvas-enabled tools. */
23
+ presentation: ToolPresentation;
24
+ /** Tool call currently shown in the canvas, if any. */
25
+ openToolCallId?: string;
26
+ }
27
+ /**
28
+ * Provided by hosts that render tool calls next to a canvas panel. Without a provider, inline
29
+ * renderers get `inline`.
30
+ */
31
+ export declare const toolCanvasHostContext: {
32
+ __context__: ToolCanvasHostState;
33
+ };
34
+ /**
35
+ * Asks the nearest canvas host to show the given tool call. Hosts without a canvas leave the event
36
+ * unhandled. Returns whether the tool call is now showing.
37
+ */
38
+ export declare function requestCanvasOpen(target: EventTarget, detail: ForgeAiCanvasOpenRequestEventData): boolean;
39
+ /** Asks the nearest canvas host to close the canvas if it is showing the given tool call. Returns whether it closed. */
40
+ export declare function requestCanvasClose(target: EventTarget, detail: ForgeAiCanvasCloseRequestEventData): boolean;
41
+ export interface CreateToolCanvasConfig {
42
+ available: boolean;
43
+ /** Read live by `toggle()`; `isOpen` on the result is a snapshot taken when the controls are built. */
44
+ isOpen: () => boolean;
45
+ open: (options?: {
46
+ title?: string;
47
+ }) => boolean;
48
+ close: () => boolean;
49
+ }
50
+ /** Builds the `canvas` controls a host injects into a tool renderer. */
51
+ export declare function createToolCanvas({ available, isOpen, open, close }: CreateToolCanvasConfig): ToolCanvas;
52
+ export declare function resolveToolCanvasTitle(toolCall: ToolCall, toolDefinition: AnyToolDefinition): string;
53
+ export declare function resolveToolCanvasSubtitle(toolCall: ToolCall, toolDefinition: AnyToolDefinition): string | undefined;
54
+ export declare function resolveToolCanvasActionLabel(toolCall: ToolCall, toolDefinition: AnyToolDefinition, active: boolean): string;
55
+ /**
56
+ * Resolves the artifact card icon to a fresh `<svg>` element, or undefined for the card's default glyph.
57
+ * Markup strings are parsed and reduced to an allowlist of shape elements and presentation attributes.
58
+ */
59
+ export declare function resolveToolCanvasIcon(toolCall: ToolCall, toolDefinition: AnyToolDefinition): SVGElement | undefined;
60
+ export declare function resolveToolCanvasInline(toolDefinition: AnyToolDefinition): ToolCanvasInline;
@@ -0,0 +1,128 @@
1
+ import { createContext } from "@lit/context";
2
+ const toolCanvasHostContext = createContext(/* @__PURE__ */ Symbol("forge-ai-tool-canvas-host"));
3
+ function requestCanvasOpen(target, detail) {
4
+ const request = { ...detail, handled: false };
5
+ target.dispatchEvent(
6
+ new CustomEvent("forge-ai-canvas-open-request", {
7
+ detail: request,
8
+ bubbles: true,
9
+ composed: true
10
+ })
11
+ );
12
+ return request.handled;
13
+ }
14
+ function requestCanvasClose(target, detail) {
15
+ const request = { ...detail, handled: false };
16
+ target.dispatchEvent(
17
+ new CustomEvent("forge-ai-canvas-close-request", {
18
+ detail: request,
19
+ bubbles: true,
20
+ composed: true
21
+ })
22
+ );
23
+ return request.handled;
24
+ }
25
+ function createToolCanvas({ available, isOpen, open, close }) {
26
+ return {
27
+ available,
28
+ isOpen: isOpen(),
29
+ open: (options) => available && open(options),
30
+ close: () => available && close(),
31
+ toggle: () => available && (isOpen() ? close() : open())
32
+ };
33
+ }
34
+ const DEFAULT_ACTION_LABEL = { open: "Open in canvas", collapse: "Collapse canvas" };
35
+ function resolveToolCallValue(value, toolCall) {
36
+ if (typeof value === "function") {
37
+ return value(toolCall);
38
+ }
39
+ return value;
40
+ }
41
+ function resolveToolCanvasTitle(toolCall, toolDefinition) {
42
+ return resolveToolCallValue(toolDefinition.canvas?.title, toolCall) ?? toolDefinition.displayName ?? toolDefinition.name;
43
+ }
44
+ function resolveToolCanvasSubtitle(toolCall, toolDefinition) {
45
+ return resolveToolCallValue(toolDefinition.canvas?.subtitle, toolCall);
46
+ }
47
+ function resolveToolCanvasActionLabel(toolCall, toolDefinition, active) {
48
+ const labels = resolveToolCallValue(toolDefinition.canvas?.actionLabel, toolCall) ?? DEFAULT_ACTION_LABEL;
49
+ return active ? labels.collapse : labels.open;
50
+ }
51
+ function resolveToolCanvasIcon(toolCall, toolDefinition) {
52
+ const icon = resolveToolCallValue(toolDefinition.canvas?.icon, toolCall);
53
+ if (!icon) {
54
+ return void 0;
55
+ }
56
+ if (typeof icon !== "string") {
57
+ return icon.cloneNode(true);
58
+ }
59
+ const template = document.createElement("template");
60
+ template.innerHTML = icon;
61
+ const svg = template.content.querySelector("svg");
62
+ if (!svg) {
63
+ return void 0;
64
+ }
65
+ sanitizeSvg(svg);
66
+ return svg;
67
+ }
68
+ const SVG_ICON_ELEMENTS = /* @__PURE__ */ new Set(["svg", "g", "path", "circle", "ellipse", "rect", "line", "polyline", "polygon"]);
69
+ const SVG_ICON_ATTRIBUTES = /* @__PURE__ */ new Set([
70
+ "xmlns",
71
+ "viewBox",
72
+ "width",
73
+ "height",
74
+ "d",
75
+ "fill",
76
+ "fill-rule",
77
+ "clip-rule",
78
+ "stroke",
79
+ "stroke-width",
80
+ "stroke-linecap",
81
+ "stroke-linejoin",
82
+ "opacity",
83
+ "transform",
84
+ "cx",
85
+ "cy",
86
+ "r",
87
+ "rx",
88
+ "ry",
89
+ "x",
90
+ "y",
91
+ "x1",
92
+ "y1",
93
+ "x2",
94
+ "y2",
95
+ "points",
96
+ "aria-hidden"
97
+ ]);
98
+ function sanitizeSvg(svg) {
99
+ for (const element of [svg, ...svg.querySelectorAll("*")]) {
100
+ if (!SVG_ICON_ELEMENTS.has(element.localName)) {
101
+ element.remove();
102
+ continue;
103
+ }
104
+ for (const attribute of [...element.attributes]) {
105
+ if (!SVG_ICON_ATTRIBUTES.has(attribute.name)) {
106
+ element.removeAttribute(attribute.name);
107
+ }
108
+ }
109
+ }
110
+ }
111
+ function resolveToolCanvasInline(toolDefinition) {
112
+ const canvas = toolDefinition.canvas;
113
+ if (canvas?.inline) {
114
+ return canvas.inline;
115
+ }
116
+ return canvas?.open === "auto" ? "card" : "renderer";
117
+ }
118
+ export {
119
+ createToolCanvas,
120
+ requestCanvasClose,
121
+ requestCanvasOpen,
122
+ resolveToolCanvasActionLabel,
123
+ resolveToolCanvasIcon,
124
+ resolveToolCanvasInline,
125
+ resolveToolCanvasSubtitle,
126
+ resolveToolCanvasTitle,
127
+ toolCanvasHostContext
128
+ };