@tylertech/forge-ai 0.15.1 → 0.15.3-dev.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.
Files changed (71) hide show
  1. package/custom-elements.json +8152 -6309
  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.mjs +25 -2
  13. package/dist/ai-chatbot/ag-ui-adapter.mjs +1 -1
  14. package/dist/ai-chatbot/agent-adapter.d.ts +108 -1
  15. package/dist/ai-chatbot/agent-adapter.mjs +22 -0
  16. package/dist/ai-chatbot/ai-chatbot-base.d.ts +26 -0
  17. package/dist/ai-chatbot/ai-chatbot-base.mjs +136 -3
  18. package/dist/ai-chatbot/index.d.ts +2 -2
  19. package/dist/ai-chatbot/message-state-controller.d.ts +10 -1
  20. package/dist/ai-chatbot/message-state-controller.mjs +78 -20
  21. package/dist/ai-chatbot/types.d.ts +199 -1
  22. package/dist/ai-chatbot/utils.mjs +3 -1
  23. package/dist/ai-chatbot-launcher/ai-chatbot-launcher.mjs +14 -4
  24. package/dist/ai-message-thread/ai-message-thread.d.ts +1 -0
  25. package/dist/ai-message-thread/ai-message-thread.mjs +35 -3
  26. package/dist/ai-sidebar/ai-sidebar.d.ts +17 -6
  27. package/dist/ai-sidebar/ai-sidebar.mjs +78 -36
  28. package/dist/ai-sidebar/ai-sidebar.scss.mjs +1 -1
  29. package/dist/ai-sidebar/index.d.ts +1 -0
  30. package/dist/ai-sidebar-chat/ai-sidebar-chat.d.ts +14 -1
  31. package/dist/ai-sidebar-chat/ai-sidebar-chat.mjs +18 -14
  32. package/dist/ai-steps/ai-steps.d.ts +67 -0
  33. package/dist/ai-steps/ai-steps.mjs +163 -0
  34. package/dist/ai-steps/ai-steps.scss.mjs +4 -0
  35. package/dist/ai-steps/index.d.ts +1 -0
  36. package/dist/ai-steps/index.mjs +5 -0
  37. package/dist/ai-tool-call-indicator/ai-tool-call-indicator.mjs +1 -1
  38. package/dist/core/chatbot-core-controller.d.ts +2 -0
  39. package/dist/core/chatbot-core-controller.mjs +99 -4
  40. package/dist/core/resize-controller.d.ts +1 -0
  41. package/dist/core/resize-controller.mjs +11 -2
  42. package/dist/index.d.ts +3 -0
  43. package/dist/index.mjs +9 -0
  44. package/dist/tools/ai-mcp-app/ai-mcp-app.d.ts +69 -0
  45. package/dist/tools/ai-mcp-app/ai-mcp-app.mjs +574 -0
  46. package/dist/tools/ai-mcp-app/ai-mcp-app.scss.mjs +4 -0
  47. package/dist/tools/ai-mcp-app/index.d.ts +3 -0
  48. package/dist/tools/ai-mcp-app/index.mjs +6 -0
  49. package/dist/tools/ai-mcp-app/mcp-app-bridge-controller.d.ts +61 -0
  50. package/dist/tools/ai-mcp-app/mcp-app-bridge-controller.mjs +156 -0
  51. package/dist/tools/ai-mcp-app/mcp-app-bridge-types.d.ts +123 -0
  52. package/dist/tools/ai-mcp-app/mcp-app-bridge.d.ts +41 -0
  53. package/dist/tools/ai-mcp-app/mcp-app-bridge.mjs +293 -0
  54. package/dist/tools/ai-mcp-app/mcp-app-context.d.ts +46 -0
  55. package/dist/tools/ai-mcp-app/mcp-app-context.mjs +5 -0
  56. package/dist/tools/ai-steps/ai-steps-definition.d.ts +2 -0
  57. package/dist/tools/ai-steps/ai-steps-definition.mjs +50 -0
  58. package/dist/tools/ai-steps/ai-steps.d.ts +28 -0
  59. package/dist/tools/ai-steps/ai-steps.mjs +49 -0
  60. package/dist/tools/ai-steps/ai-steps.scss.mjs +4 -0
  61. package/dist/tools/ai-steps/index.d.ts +2 -0
  62. package/dist/tools/ai-steps/index.mjs +6 -0
  63. package/dist/tools/index.d.ts +1 -0
  64. package/dist/tools/index.mjs +5 -1
  65. package/dist/utils/index.d.ts +1 -0
  66. package/dist/utils/index.mjs +5 -1
  67. package/dist/utils/inert-outside.d.ts +7 -0
  68. package/dist/utils/inert-outside.mjs +28 -0
  69. package/dist/utils/storage-utils.d.ts +26 -0
  70. package/dist/utils/storage-utils.mjs +32 -0
  71. package/package.json +4 -1
@@ -0,0 +1,137 @@
1
+ import { unsafeCSS, LitElement, html, nothing } from "lit";
2
+ import { property, queryAssignedElements, customElement } from "lit/decorators.js";
3
+ import { AI_ARTIFACT_CARD_COLLAPSED_ATTRIBUTE } from "../ai-artifact-card/ai-artifact-card.mjs";
4
+ import styles from "./ai-artifact-card-group.scss.mjs";
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __typeError = (msg) => {
8
+ throw TypeError(msg);
9
+ };
10
+ var __decorateClass = (decorators, target, key, kind) => {
11
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
12
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
13
+ if (decorator = decorators[i])
14
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
15
+ if (kind && result) __defProp(target, key, result);
16
+ return result;
17
+ };
18
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
19
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
20
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
21
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
22
+ var _AiArtifactCardGroupComponent_instances, visibleCards_get, collapsedCount_get, overflowCount_get, _chevronDownIcon, _chevronUpIcon, syncCardVisibility_fn, handleSlotChange_fn, handleToggle_fn, toggle_get;
23
+ const AiArtifactCardGroupComponentTagName = "forge-ai-artifact-card-group";
24
+ const DEFAULT_VISIBLE_COUNT = 3;
25
+ let AiArtifactCardGroupComponent = class extends LitElement {
26
+ constructor() {
27
+ super(...arguments);
28
+ __privateAdd(this, _AiArtifactCardGroupComponent_instances);
29
+ this.visibleCount = DEFAULT_VISIBLE_COUNT;
30
+ this.expanded = false;
31
+ this.showMoreText = "{count} more";
32
+ this.showLessText = "Show less";
33
+ __privateAdd(this, _chevronDownIcon, html`
34
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18" fill="none" aria-hidden="true">
35
+ <path
36
+ d="M4.5 6.75L9 11.25L13.5 6.75"
37
+ stroke="currentColor"
38
+ stroke-width="1.5"
39
+ stroke-linecap="round"
40
+ stroke-linejoin="round" />
41
+ </svg>
42
+ `);
43
+ __privateAdd(this, _chevronUpIcon, html`
44
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18" fill="none" aria-hidden="true">
45
+ <path
46
+ d="M13.5 11.25L9 6.75L4.5 11.25"
47
+ stroke="currentColor"
48
+ stroke-width="1.5"
49
+ stroke-linecap="round"
50
+ stroke-linejoin="round" />
51
+ </svg>
52
+ `);
53
+ }
54
+ updated(changedProperties) {
55
+ super.updated(changedProperties);
56
+ __privateMethod(this, _AiArtifactCardGroupComponent_instances, syncCardVisibility_fn).call(this);
57
+ }
58
+ render() {
59
+ return html`
60
+ <div class="artifact-card-group">
61
+ <div class="list" role="list">
62
+ <slot @slotchange=${__privateMethod(this, _AiArtifactCardGroupComponent_instances, handleSlotChange_fn)}></slot>
63
+ </div>
64
+ ${__privateGet(this, _AiArtifactCardGroupComponent_instances, toggle_get)}
65
+ </div>
66
+ `;
67
+ }
68
+ };
69
+ _AiArtifactCardGroupComponent_instances = /* @__PURE__ */ new WeakSet();
70
+ visibleCards_get = function() {
71
+ return this._cards.filter((card) => !card.hidden);
72
+ };
73
+ collapsedCount_get = function() {
74
+ if (!Number.isFinite(this.visibleCount)) {
75
+ return DEFAULT_VISIBLE_COUNT;
76
+ }
77
+ return Math.max(1, Math.floor(this.visibleCount));
78
+ };
79
+ overflowCount_get = function() {
80
+ return Math.max(0, __privateGet(this, _AiArtifactCardGroupComponent_instances, visibleCards_get).length - __privateGet(this, _AiArtifactCardGroupComponent_instances, collapsedCount_get));
81
+ };
82
+ _chevronDownIcon = /* @__PURE__ */ new WeakMap();
83
+ _chevronUpIcon = /* @__PURE__ */ new WeakMap();
84
+ syncCardVisibility_fn = function() {
85
+ __privateGet(this, _AiArtifactCardGroupComponent_instances, visibleCards_get).forEach((card, index) => {
86
+ card.toggleAttribute(AI_ARTIFACT_CARD_COLLAPSED_ATTRIBUTE, !this.expanded && index >= __privateGet(this, _AiArtifactCardGroupComponent_instances, collapsedCount_get));
87
+ });
88
+ };
89
+ handleSlotChange_fn = function() {
90
+ this.requestUpdate();
91
+ };
92
+ handleToggle_fn = function() {
93
+ this.expanded = !this.expanded;
94
+ this.dispatchEvent(
95
+ new CustomEvent("forge-ai-artifact-card-group-toggle", {
96
+ detail: { expanded: this.expanded },
97
+ bubbles: true,
98
+ composed: true
99
+ })
100
+ );
101
+ };
102
+ toggle_get = function() {
103
+ if (__privateGet(this, _AiArtifactCardGroupComponent_instances, overflowCount_get) === 0) {
104
+ return nothing;
105
+ }
106
+ const label = this.expanded ? this.showLessText : this.showMoreText.replace("{count}", String(__privateGet(this, _AiArtifactCardGroupComponent_instances, overflowCount_get)));
107
+ return html`
108
+ <button class="toggle" type="button" aria-expanded=${this.expanded} @click=${__privateMethod(this, _AiArtifactCardGroupComponent_instances, handleToggle_fn)}>
109
+ ${this.expanded ? __privateGet(this, _chevronUpIcon) : __privateGet(this, _chevronDownIcon)}
110
+ <span>${label}</span>
111
+ <span class="focus-indicator"></span>
112
+ </button>
113
+ `;
114
+ };
115
+ AiArtifactCardGroupComponent.styles = unsafeCSS(styles);
116
+ __decorateClass([
117
+ property({ type: Number, attribute: "visible-count" })
118
+ ], AiArtifactCardGroupComponent.prototype, "visibleCount", 2);
119
+ __decorateClass([
120
+ property({ type: Boolean, reflect: true })
121
+ ], AiArtifactCardGroupComponent.prototype, "expanded", 2);
122
+ __decorateClass([
123
+ property({ attribute: "show-more-text" })
124
+ ], AiArtifactCardGroupComponent.prototype, "showMoreText", 2);
125
+ __decorateClass([
126
+ property({ attribute: "show-less-text" })
127
+ ], AiArtifactCardGroupComponent.prototype, "showLessText", 2);
128
+ __decorateClass([
129
+ queryAssignedElements({ selector: "forge-ai-artifact-card", flatten: true })
130
+ ], AiArtifactCardGroupComponent.prototype, "_cards", 2);
131
+ AiArtifactCardGroupComponent = __decorateClass([
132
+ customElement(AiArtifactCardGroupComponentTagName)
133
+ ], AiArtifactCardGroupComponent);
134
+ export {
135
+ AiArtifactCardGroupComponent,
136
+ AiArtifactCardGroupComponentTagName
137
+ };
@@ -0,0 +1,173 @@
1
+ const styles = `/* prettier-ignore */
2
+ @keyframes forge-focus-indicator-outward-grow {
3
+ from {
4
+ outline-width: 0;
5
+ }
6
+ to {
7
+ outline-width: var(--_focus-indicator-active-width);
8
+ }
9
+ }
10
+ @keyframes forge-focus-indicator-outward-shrink {
11
+ from {
12
+ outline-width: var(--_focus-indicator-active-width);
13
+ }
14
+ }
15
+ @keyframes forge-focus-indicator-inward-grow {
16
+ from {
17
+ border-width: 0;
18
+ }
19
+ to {
20
+ border-width: var(--_focus-indicator-active-width);
21
+ }
22
+ }
23
+ @keyframes forge-focus-indicator-inward-shrink {
24
+ from {
25
+ border-width: var(--_focus-indicator-active-width);
26
+ }
27
+ }
28
+ :host {
29
+ display: block;
30
+ }
31
+
32
+ .artifact-card-group {
33
+ overflow: hidden;
34
+ border: 1px solid var(--forge-theme-outline, #e0e0e0);
35
+ border-radius: var(--forge-ai-artifact-card-group-border-radius, 12px);
36
+ background: var(--forge-theme-surface, #ffffff);
37
+ }
38
+
39
+ /*
40
+ * Every row carries a top divider and the list is pulled up by one pixel so the first visible row's
41
+ * divider hides under the group border, whichever row that is once cards are hidden or collapsed.
42
+ */
43
+ .list {
44
+ margin-top: -1px;
45
+ }
46
+
47
+ ::slotted(*) {
48
+ border-top: 1px solid var(--forge-theme-outline, #e0e0e0);
49
+ }
50
+
51
+ /*
52
+ * Rows meeting the group's rounded corners get its inner radius for their focus rings. The bottom row only
53
+ * does when no toggle sits below it.
54
+ */
55
+ .list ::slotted(:nth-child(1 of :not([hidden], [data-collapsed]))) {
56
+ --_forge-ai-artifact-card-group-start-radius: calc(var(--forge-ai-artifact-card-group-border-radius, 12px) - 1px);
57
+ }
58
+
59
+ .artifact-card-group:not(:has(.toggle)) ::slotted(:nth-last-child(1 of :not([hidden], [data-collapsed]))) {
60
+ --_forge-ai-artifact-card-group-end-radius: calc(var(--forge-ai-artifact-card-group-border-radius, 12px) - 1px);
61
+ }
62
+
63
+ .toggle {
64
+ -moz-osx-font-smoothing: grayscale;
65
+ -webkit-font-smoothing: antialiased;
66
+ font-family: var(--forge-typography-body1-font-family, var(--forge-typography-font-family, "Roboto", sans-serif));
67
+ font-size: var(--forge-typography-body1-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-font-size-scale, 0.875)));
68
+ font-weight: var(--forge-typography-body1-font-weight, 400);
69
+ line-height: var(--forge-typography-body1-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-line-height-scale, 1.125)));
70
+ letter-spacing: var(--forge-typography-body1-letter-spacing, 0.0357142857em);
71
+ text-transform: var(--forge-typography-body1-text-transform, inherit);
72
+ text-decoration: var(--forge-typography-body1-text-decoration, inherit);
73
+ position: relative;
74
+ display: flex;
75
+ align-items: center;
76
+ gap: var(--forge-spacing-xsmall, 8px);
77
+ width: 100%;
78
+ min-height: var(--forge-spacing-xxlarge, 48px);
79
+ padding: var(--forge-spacing-small, 12px);
80
+ border: none;
81
+ border-top: 1px solid var(--forge-theme-outline, #e0e0e0);
82
+ background: transparent;
83
+ color: var(--forge-theme-text-high, rgba(0, 0, 0, 0.87));
84
+ text-align: start;
85
+ cursor: pointer;
86
+ outline: none;
87
+ --_state-layer-display: var(--forge-state-layer-display, flex);
88
+ --_state-layer-color: var(--forge-state-layer-color, var(--forge-theme-on-surface, #000000));
89
+ --_state-layer-hover-color: var(--forge-state-layer-hover-color, var(--_state-layer-color));
90
+ --_state-layer-hover-opacity: var(--forge-state-layer-hover-opacity, 0.08);
91
+ --_state-layer-pressed-color: var(--forge-state-layer-pressed-color, var(--_state-layer-color));
92
+ --_state-layer-pressed-opacity: var(--forge-state-layer-pressed-opacity, 0.12);
93
+ --_state-layer-hover-duration: var(--forge-state-layer-hover-duration, 15ms);
94
+ --_state-layer-pressed-duration: var(--forge-state-layer-pressed-duration, 105ms);
95
+ --_state-layer-animation-duration: var(--forge-state-layer-animation-duration, 375ms);
96
+ }
97
+ .toggle::before {
98
+ opacity: 0;
99
+ position: absolute;
100
+ backface-visibility: hidden;
101
+ transform: translateZ(0);
102
+ background-color: var(--_state-layer-hover-color);
103
+ inset: 0;
104
+ transition: opacity var(--_state-layer-hover-duration) linear, background-color var(--_state-layer-hover-duration) linear;
105
+ --_state-layer-hover-duration: var(--forge-state-layer-hover-duration, 100ms);
106
+ content: "";
107
+ opacity: 0;
108
+ border-radius: inherit;
109
+ }
110
+ .toggle:hover::before {
111
+ background-color: var(--_state-layer-hover-color);
112
+ opacity: var(--_state-layer-hover-opacity);
113
+ }
114
+ .toggle:active::before {
115
+ opacity: var(--_state-layer-pressed-opacity);
116
+ transition-duration: var(--_state-layer-pressed-duration);
117
+ --_state-layer-pressed-opacity: var(--forge-state-layer-pressed-opacity, 0.18);
118
+ }
119
+
120
+ .toggle svg {
121
+ flex-shrink: 0;
122
+ width: 18px;
123
+ height: 18px;
124
+ }
125
+
126
+ .focus-indicator {
127
+ position: absolute;
128
+ display: none;
129
+ }
130
+
131
+ /* The toggle is always the bottom row, so its lower corners follow the group's inner radius */
132
+ .toggle:focus-visible .focus-indicator {
133
+ --_focus-indicator-display: var(--forge-focus-indicator-display, flex);
134
+ --_focus-indicator-width: var(--forge-focus-indicator-width, var(--forge-border-medium, 2px));
135
+ --_focus-indicator-active-width: var(--forge-focus-indicator-active-width, 6px);
136
+ --_focus-indicator-color: var(--forge-focus-indicator-color, var(--forge-theme-primary, #3f51b5));
137
+ --_focus-indicator-shape: var(--forge-focus-indicator-shape, calc(var(--forge-shape-extra-small, 1px) * var(--forge-shape-factor, 1)));
138
+ --_focus-indicator-duration: var(--forge-focus-indicator-duration, var(--forge-animation-duration-long4, 600ms));
139
+ --_focus-indicator-easing: var(--forge-focus-indicator-easing, var(--forge-animation-easing-emphasized, cubic-bezier(0.2, 0, 0, 1)));
140
+ --_focus-indicator-shape-start-start: var(--forge-focus-indicator-shape-start-start, var(--_focus-indicator-shape));
141
+ --_focus-indicator-shape-start-end: var(--forge-focus-indicator-shape-start-end, var(--_focus-indicator-shape));
142
+ --_focus-indicator-shape-end-end: var(--forge-focus-indicator-shape-end-end, var(--_focus-indicator-shape));
143
+ --_focus-indicator-shape-end-start: var(--forge-focus-indicator-shape-end-start, var(--_focus-indicator-shape));
144
+ --_focus-indicator-outward-offset: var(--forge-focus-indicator-outward-offset, var(--forge-spacing-xxsmall, 4px));
145
+ --_focus-indicator-inward-offset: var(--forge-focus-indicator-inward-offset, 0px);
146
+ --_focus-indicator-offset-block: var(--forge-focus-indicator-offset-block, 0);
147
+ --_focus-indicator-offset-inline: var(--forge-focus-indicator-offset-inline, 0);
148
+ animation-delay: 0s, calc(var(--_focus-indicator-duration) * 0.25);
149
+ animation-duration: calc(var(--_focus-indicator-duration) * 0.25), calc(var(--_focus-indicator-duration) * 0.75);
150
+ animation-timing-function: var(--_focus-indicator-easing);
151
+ box-sizing: border-box;
152
+ color: var(--_focus-indicator-color);
153
+ display: none;
154
+ pointer-events: none;
155
+ position: absolute;
156
+ margin-block: var(--_focus-indicator-offset-block);
157
+ margin-inline: var(--_focus-indicator-offset-inline);
158
+ animation-name: forge-focus-indicator-inward-grow, forge-focus-indicator-inward-shrink;
159
+ border-end-end-radius: calc(var(--_focus-indicator-shape-end-end) - var(--_focus-indicator-inward-offset));
160
+ border-end-start-radius: calc(var(--_focus-indicator-shape-end-start) - var(--_focus-indicator-inward-offset));
161
+ border-start-end-radius: calc(var(--_focus-indicator-shape-start-end) - var(--_focus-indicator-inward-offset));
162
+ border-start-start-radius: calc(var(--_focus-indicator-shape-start-start) - var(--_focus-indicator-inward-offset));
163
+ border: var(--_focus-indicator-width) solid currentColor;
164
+ inset: var(--_focus-indicator-inward-offset);
165
+ display: block;
166
+ --forge-focus-indicator-shape-start-start: 0px;
167
+ --forge-focus-indicator-shape-start-end: 0px;
168
+ --forge-focus-indicator-shape-end-start: calc(var(--forge-ai-artifact-card-group-border-radius, 12px) - 1px);
169
+ --forge-focus-indicator-shape-end-end: calc(var(--forge-ai-artifact-card-group-border-radius, 12px) - 1px);
170
+ }`;
171
+ export {
172
+ styles as default
173
+ };
@@ -0,0 +1 @@
1
+ export * from './ai-artifact-card-group';
@@ -0,0 +1,5 @@
1
+ import { AiArtifactCardGroupComponent, AiArtifactCardGroupComponentTagName } from "./ai-artifact-card-group.mjs";
2
+ export {
3
+ AiArtifactCardGroupComponent,
4
+ AiArtifactCardGroupComponentTagName
5
+ };
@@ -2,11 +2,13 @@ import { unsafeCSS, LitElement, html, nothing } from "lit";
2
2
  import { property, customElement } from "lit/decorators.js";
3
3
  import { unsafeHTML } from "lit/directives/unsafe-html.js";
4
4
  import { ifDefined } from "lit/directives/if-defined.js";
5
+ import { keyed } from "lit/directives/keyed.js";
5
6
  import { MarkdownStreamController } from "../ai-chatbot/markdown-stream-controller.mjs";
6
7
  import "../ai-response-message-toolbar/ai-response-message-toolbar.mjs";
7
8
  import "../ai-chatbot/ai-chatbot-tool-call.mjs";
8
9
  import "../ai-tool-call-indicator/ai-tool-call-indicator.mjs";
9
10
  import "../ai-thinking-indicator/ai-thinking-indicator.mjs";
11
+ import "../tools/ai-mcp-app/ai-mcp-app.mjs";
10
12
  import styles from "./ai-assistant-response.scss.mjs";
11
13
  var __defProp = Object.defineProperty;
12
14
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -26,7 +28,7 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
26
28
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
27
29
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
28
30
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
29
- var _internals, _markdownController, _AiAssistantResponseComponent_instances, hasVisibleContent_get, updateEmptyState_fn, renderTextChunk_fn, renderToolCall_fn, children_get, handleToolbarAction_fn, handleToolbarFeedback_fn, toolbar_get, thinkingIndicator_get;
31
+ var _internals, _markdownController, _AiAssistantResponseComponent_instances, hasVisibleContent_get, updateEmptyState_fn, renderTextChunk_fn, isMcpAppToolCall_fn, renderToolCall_fn, children_get, handleToolbarAction_fn, handleToolbarFeedback_fn, toolbar_get, thinkingIndicator_get;
30
32
  const AiAssistantResponseComponentTagName = "forge-ai-assistant-response";
31
33
  let AiAssistantResponseComponent = class extends LitElement {
32
34
  constructor() {
@@ -81,7 +83,21 @@ renderTextChunk_fn = function(child) {
81
83
  const renderedHtml = __privateGet(this, _markdownController).getCachedHtml(child.messageId, content);
82
84
  return html`<div class="text-chunk">${unsafeHTML(renderedHtml)}</div>`;
83
85
  };
86
+ isMcpAppToolCall_fn = function(toolCall) {
87
+ return !!toolCall.uiResource || this.tools?.get(toolCall.name)?.mcpApp !== void 0;
88
+ };
84
89
  renderToolCall_fn = function(toolCall) {
90
+ if (toolCall.uiResource) {
91
+ return keyed(
92
+ toolCall.id,
93
+ html`<forge-ai-mcp-app
94
+ .toolCall=${toolCall}
95
+ .toolDefinition=${this.tools?.get(toolCall.name)}></forge-ai-mcp-app>`
96
+ );
97
+ }
98
+ if (__privateMethod(this, _AiAssistantResponseComponent_instances, isMcpAppToolCall_fn).call(this, toolCall)) {
99
+ return nothing;
100
+ }
85
101
  const toolDefinition = this.tools?.get(toolCall.name);
86
102
  if (!toolDefinition?.renderer) {
87
103
  return nothing;
@@ -113,6 +129,9 @@ children_get = function() {
113
129
  if (child.type === "text") {
114
130
  flushIndicator();
115
131
  results.push(__privateMethod(this, _AiAssistantResponseComponent_instances, renderTextChunk_fn).call(this, child));
132
+ } else if (__privateMethod(this, _AiAssistantResponseComponent_instances, isMcpAppToolCall_fn).call(this, child.data)) {
133
+ flushIndicator();
134
+ results.push(__privateMethod(this, _AiAssistantResponseComponent_instances, renderToolCall_fn).call(this, child.data));
116
135
  } else {
117
136
  toolBuffer.push(child.data);
118
137
  }
@@ -178,7 +197,11 @@ thinkingIndicator_get = function() {
178
197
  if (child.type !== "toolCall") {
179
198
  return false;
180
199
  }
181
- return child.data.status === "parsing" || child.data.status === "executing" || child.data.status === "pending";
200
+ const isUnsettled = child.data.status === "parsing" || child.data.status === "executing" || child.data.status === "pending";
201
+ if (__privateMethod(this, _AiAssistantResponseComponent_instances, isMcpAppToolCall_fn).call(this, child.data)) {
202
+ return !!child.data.uiResource && isUnsettled;
203
+ }
204
+ return isUnsettled;
182
205
  });
183
206
  if (hasActiveToolCall) {
184
207
  return nothing;
@@ -61,7 +61,7 @@ class AgUiAdapter extends AgentAdapter {
61
61
  const transformedMessages = this.#transformMessages(messages);
62
62
  const context = Object.keys(this.#context).length ? this.#transformContext(this.#context) : void 0;
63
63
  this.#agent.setMessages(transformedMessages);
64
- const tools = this.#transformTools(this._tools);
64
+ const tools = this.#transformTools(this.getModelFacingTools());
65
65
  this.#agent.runAgent({ tools, context });
66
66
  }
67
67
  sendToolResult(toolCallId, result, messages) {
@@ -1,4 +1,4 @@
1
- import { ChatMessage, FileUploadCallbacks, ToolDefinition } from './types.js';
1
+ import { ChatMessage, FileUploadCallbacks, McpAppUiResource, McpToolResult, ToolDefinition } from './types.js';
2
2
  import { EventEmitter, Subscription } from './event-emitter.js';
3
3
  export interface MessageStartEvent {
4
4
  messageId: string;
@@ -44,11 +44,70 @@ export interface ToolCallEndEvent {
44
44
  }
45
45
  export interface ToolResultEvent {
46
46
  toolCallId: string;
47
+ /** Model-facing result. Never delivered to an MCP-app View. */
47
48
  result: unknown;
48
49
  message: ChatMessage;
50
+ /** Companion structured payload delivered to an MCP-app widget, stripped from LLM context. */
51
+ structuredContent?: unknown;
52
+ /** `true` when the backend dropped `structuredContent` (size caps). */
53
+ structuredContentOmitted?: boolean;
54
+ /** Raw MCP result for an MCP-app tool call; the View's `tool-result` is built from it. */
55
+ mcpResult?: McpToolResult;
56
+ /** `true` when the backend dropped `mcpResult` (size caps). */
57
+ mcpResultOmitted?: boolean;
49
58
  isError?: boolean;
59
+ /** `true` when the tool call was cancelled rather than failed; takes precedence over `isError`. */
60
+ cancelled?: boolean;
50
61
  rawEvent?: unknown;
51
62
  }
63
+ /**
64
+ * Emitted when the backend signals that a tool call is backed by an MCP-app UI
65
+ * resource. Carries only the widget binding — the HTML and the `csp`/`permissions`
66
+ * policy come from {@link AgentAdapter.resolveMcpAppResource}. The core controller
67
+ * resolves the resource and stamps a {@link McpAppUiResource} onto the tool call.
68
+ *
69
+ * May be emitted before or after the matching `tool-call` chunk, and also after
70
+ * `setMessages`/`setThreadState` to remount widgets restored from history.
71
+ */
72
+ export interface McpUiResourceEvent {
73
+ toolCallId: string;
74
+ toolName?: string;
75
+ /** The concrete resolved `ui://` URI (interpolation done server-side). */
76
+ resourceUri: string;
77
+ serverId?: string;
78
+ mimeType?: string;
79
+ rawEvent?: unknown;
80
+ }
81
+ /** Parameters for {@link AgentAdapter.resolveMcpAppResource}. */
82
+ export interface McpAppResourceResolveParams {
83
+ /** The concrete resolved `ui://` URI from the `mcp-ui-resource` event. */
84
+ resourceUri: string;
85
+ /** The widget's tool call id; template reads are bound to it. */
86
+ toolCallId: string;
87
+ }
88
+ /**
89
+ * Parameters an MCP-app widget passes when forwarding a `tools/call` to the server.
90
+ * The library never owns a `Client`; these delegate to the adapter.
91
+ */
92
+ export interface McpToolCallParams {
93
+ name: string;
94
+ arguments?: Record<string, unknown>;
95
+ /** The calling widget's tool call id; the backend derives the MCP server from it. */
96
+ toolCallId: string;
97
+ }
98
+ /** Parameters for an MCP-app widget-initiated `resources/read`. */
99
+ export interface McpResourceReadParams {
100
+ uri: string;
101
+ /** The calling widget's tool call id. */
102
+ toolCallId: string;
103
+ }
104
+ /** Payload of a widget's `ui/update-model-context`, forwarded to the adapter. */
105
+ export interface McpModelContextUpdateParams {
106
+ /** The widget's tool call id. */
107
+ toolCallId: string;
108
+ content?: unknown[];
109
+ structuredContent?: unknown;
110
+ }
52
111
  export interface AdapterState {
53
112
  isConnected: boolean;
54
113
  isConnecting: boolean;
@@ -121,6 +180,7 @@ export declare abstract class AgentAdapter {
121
180
  toolCallArgs: EventEmitter<ToolCallArgsEvent>;
122
181
  toolCallEnd: EventEmitter<ToolCallEndEvent>;
123
182
  toolResult: EventEmitter<ToolResultEvent>;
183
+ mcpUiResource: EventEmitter<McpUiResourceEvent>;
124
184
  fileUpload: EventEmitter<FileUploadEvent>;
125
185
  fileRemove: EventEmitter<FileRemoveEvent>;
126
186
  error: EventEmitter<ErrorEvent>;
@@ -143,8 +203,46 @@ export declare abstract class AgentAdapter {
143
203
  abstract get threadId(): string;
144
204
  abstract set threadId(value: string);
145
205
  clearMemory?(): Promise<void>;
206
+ /**
207
+ * Resolve the MCP-app UI resource for an already-resolved `resourceUri`, bound to the
208
+ * widget's `toolCallId`. The adapter fetches the template for that concrete URI and
209
+ * fills `csp`/`permissions` from the template response's `_meta.ui` (`{}` when absent).
210
+ * It MUST NOT re-derive the URI (templated-URI interpolation is server-side only).
211
+ */
212
+ resolveMcpAppResource?(params: McpAppResourceResolveParams): Promise<McpAppUiResource | undefined>;
213
+ /**
214
+ * Forward a widget-initiated `tools/call` to the MCP server. Resolve with the View's
215
+ * `CallToolResult` (tool-level errors resolve with `isError: true`); reject for
216
+ * transport/HTTP errors (e.g. a 403 for a tool without `"app"` visibility) — the
217
+ * rejection is returned to the View as a JSON-RPC error.
218
+ */
219
+ callMcpTool?(params: McpToolCallParams): Promise<unknown>;
220
+ /**
221
+ * Forward a widget-initiated `resources/read` to the MCP server. When not implemented
222
+ * the View's request is rejected with a JSON-RPC error.
223
+ */
224
+ readMcpResource?(params: McpResourceReadParams): Promise<unknown>;
225
+ /**
226
+ * Called when a widget sends `ui/update-model-context`. Each call replaces the previous
227
+ * context for that `toolCallId`; adapters should debounce and may hold the latest value
228
+ * until the run ends.
229
+ */
230
+ updateMcpModelContext?(params: McpModelContextUpdateParams): Promise<void>;
231
+ /**
232
+ * Called after a widget is torn down (its turn left the visible thread, or the thread was
233
+ * cleared/replaced). Drop any state held for that `toolCallId`, e.g. a pending model context.
234
+ */
235
+ disposeMcpAppView?(params: {
236
+ toolCallId: string;
237
+ }): void;
146
238
  setTools(tools: ToolDefinition[]): void;
147
239
  getTools(): ToolDefinition[];
240
+ /**
241
+ * Tools to forward to the backend agent, excluding MCP-app tools (`ToolDefinition.mcpApp`).
242
+ * MCP-app tools are a host-internal mechanism for streaming a UI resource into an existing
243
+ * tool call — the model never calls them directly, so they must never reach the agent.
244
+ */
245
+ getModelFacingTools(): ToolDefinition[];
148
246
  getState(): AdapterState;
149
247
  get isConnected(): boolean;
150
248
  get isConnecting(): boolean;
@@ -160,6 +258,7 @@ export declare abstract class AgentAdapter {
160
258
  onToolCallArgs(callback: (event: ToolCallArgsEvent) => void): Subscription;
161
259
  onToolCallEnd(callback: (event: ToolCallEndEvent) => void): Subscription;
162
260
  onToolCallResult(callback: (event: ToolResultEvent) => void): Subscription;
261
+ onMcpUiResource(callback: (event: McpUiResourceEvent) => void): Subscription;
163
262
  onFileUpload(callback: (event: FileUploadEvent) => void): Subscription;
164
263
  onFileRemove(callback: (event: FileRemoveEvent) => void): Subscription;
165
264
  onError(callback: (event: ErrorEvent) => void): Subscription;
@@ -184,6 +283,14 @@ export declare abstract class AgentAdapter {
184
283
  protected _emitToolCallArgs(event: ToolCallArgsEvent, rawEvent?: unknown): void;
185
284
  protected _emitToolCallEnd(event: ToolCallEndEvent, rawEvent?: unknown): void;
186
285
  protected _emitToolResult(event: ToolResultEvent, rawEvent?: unknown): void;
286
+ /**
287
+ * Announce that a tool call renders as an MCP-app widget. Also the way to remount
288
+ * widgets restored from history: call it per widget after `setMessages`/`setThreadState`
289
+ * — the resource is resolved and stamped onto the restored (already finalized) tool
290
+ * call. If the tool call isn't in state yet, the resource is held and applied when it
291
+ * arrives.
292
+ */
293
+ protected _emitMcpUiResource(event: McpUiResourceEvent, rawEvent?: unknown): void;
187
294
  emitFileUpload(file: File, callbacks: FileUploadCallbacks): void;
188
295
  emitFileRemove(fileId: string, callbacks: {
189
296
  onSuccess: () => void;
@@ -15,6 +15,7 @@ class AgentAdapter {
15
15
  toolCallArgs: new EventEmitter(),
16
16
  toolCallEnd: new EventEmitter(),
17
17
  toolResult: new EventEmitter(),
18
+ mcpUiResource: new EventEmitter(),
18
19
  fileUpload: new EventEmitter(),
19
20
  fileRemove: new EventEmitter(),
20
21
  error: new EventEmitter(),
@@ -36,6 +37,14 @@ class AgentAdapter {
36
37
  getTools() {
37
38
  return [...this._tools];
38
39
  }
40
+ /**
41
+ * Tools to forward to the backend agent, excluding MCP-app tools (`ToolDefinition.mcpApp`).
42
+ * MCP-app tools are a host-internal mechanism for streaming a UI resource into an existing
43
+ * tool call — the model never calls them directly, so they must never reach the agent.
44
+ */
45
+ getModelFacingTools() {
46
+ return this._tools.filter((tool) => tool.mcpApp === void 0);
47
+ }
39
48
  getState() {
40
49
  return { ...this._state };
41
50
  }
@@ -81,6 +90,9 @@ class AgentAdapter {
81
90
  onToolCallResult(callback) {
82
91
  return this._events.toolResult.subscribe(callback);
83
92
  }
93
+ onMcpUiResource(callback) {
94
+ return this._events.mcpUiResource.subscribe(callback);
95
+ }
84
96
  onFileUpload(callback) {
85
97
  return this._events.fileUpload.subscribe(callback);
86
98
  }
@@ -153,6 +165,16 @@ class AgentAdapter {
153
165
  _emitToolResult(event, rawEvent) {
154
166
  this._events.toolResult.emit({ ...event, rawEvent });
155
167
  }
168
+ /**
169
+ * Announce that a tool call renders as an MCP-app widget. Also the way to remount
170
+ * widgets restored from history: call it per widget after `setMessages`/`setThreadState`
171
+ * — the resource is resolved and stamped onto the restored (already finalized) tool
172
+ * call. If the tool call isn't in state yet, the resource is held and applied when it
173
+ * arrives.
174
+ */
175
+ _emitMcpUiResource(event, rawEvent) {
176
+ this._events.mcpUiResource.emit({ ...event, rawEvent });
177
+ }
156
178
  emitFileUpload(file, callbacks) {
157
179
  this._events.fileUpload.emit({ file, ...callbacks });
158
180
  }
@@ -13,6 +13,7 @@ import { ChatbotCoreController } from '../core/chatbot-core-controller.js';
13
13
  import { Agent, ChatMessage, ClientMessageInput, ContextItem, HeadingLevel, MessageItem, SlashCommand, ThreadState, ToolDefinition } from './types.js';
14
14
  export type FeatureToggle = 'on' | 'off';
15
15
  export declare abstract class AiChatbotBase extends LitElement {
16
+ #private;
16
17
  protected abstract _messageThreadRef: Ref<AiMessageThreadComponent>;
17
18
  protected abstract _promptRef: Ref<AiPromptComponent>;
18
19
  adapter?: AgentAdapter;
@@ -34,6 +35,24 @@ export declare abstract class AiChatbotBase extends LitElement {
34
35
  agents: Agent[];
35
36
  selectedAgentId?: string;
36
37
  contextItems: ContextItem[];
38
+ mcpAppSandboxUrl?: string;
39
+ /**
40
+ * Theme fed into an MCP-app widget's `hostContext.theme`. The chatbot's own appearance
41
+ * comes from Forge tokens and is unaffected. Set this whenever the app switches between
42
+ * light and dark: it is the signal that re-sends `theme` and the Forge-derived
43
+ * `styles.variables` to widgets, since token changes alone can't be detected. Absent →
44
+ * follows `prefers-color-scheme`.
45
+ */
46
+ mcpAppTheme?: 'light' | 'dark';
47
+ private _mcpAppHost;
48
+ /**
49
+ * Sends `ui/resource-teardown` to mounted MCP-app widgets (all, or only `toolCallIds`) and
50
+ * releases them immediately, without waiting for acks. The adapter then drops any state it
51
+ * holds for them (e.g. a pending model context).
52
+ */
53
+ protected _teardownMcpAppViews({ toolCallIds }?: {
54
+ toolCallIds?: string[];
55
+ }): void;
37
56
  protected _coreController: ChatbotCoreController;
38
57
  protected get _isStreaming(): boolean;
39
58
  protected get _isUploading(): boolean;
@@ -42,6 +61,7 @@ export declare abstract class AiChatbotBase extends LitElement {
42
61
  protected get _hasMessages(): boolean;
43
62
  protected get _allContextItems(): ContextItem[];
44
63
  connectedCallback(): void;
64
+ disconnectedCallback(): void;
45
65
  willUpdate(changedProperties: PropertyValues<this>): void;
46
66
  protected _onConnected(): void;
47
67
  protected get _slashCommands(): SlashCommand[];
@@ -136,6 +156,12 @@ export declare abstract class AiChatbotBase extends LitElement {
136
156
  removeClientMessage(id: string): void;
137
157
  sendMessage(content: string, files?: File[]): Promise<void>;
138
158
  abort(): void;
159
+ /**
160
+ * Re-sends the Forge-derived `styles.variables` to every MCP-app widget. Call after
161
+ * changing Forge tokens without a light/dark switch (e.g. a brand change); for light/dark,
162
+ * set {@link mcpAppTheme} instead.
163
+ */
164
+ refreshMcpAppStyles(): void;
139
165
  scrollToBottom({ behavior }?: {
140
166
  behavior?: ScrollBehavior;
141
167
  }): Promise<void>;