@tylertech/forge-ai 0.15.2 → 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.
- package/custom-elements.json +8266 -6476
- package/dist/ai-artifact-card/ai-artifact-card.d.ts +75 -0
- package/dist/ai-artifact-card/ai-artifact-card.mjs +142 -0
- package/dist/ai-artifact-card/ai-artifact-card.scss.mjs +283 -0
- package/dist/ai-artifact-card/index.d.ts +1 -0
- package/dist/ai-artifact-card/index.mjs +5 -0
- package/dist/ai-artifact-card-group/ai-artifact-card-group.d.ts +57 -0
- package/dist/ai-artifact-card-group/ai-artifact-card-group.mjs +137 -0
- package/dist/ai-artifact-card-group/ai-artifact-card-group.scss.mjs +173 -0
- package/dist/ai-artifact-card-group/index.d.ts +1 -0
- package/dist/ai-artifact-card-group/index.mjs +5 -0
- package/dist/ai-assistant-response/ai-assistant-response.mjs +25 -2
- package/dist/ai-chatbot/ag-ui-adapter.mjs +1 -1
- package/dist/ai-chatbot/agent-adapter.d.ts +108 -1
- package/dist/ai-chatbot/agent-adapter.mjs +22 -0
- package/dist/ai-chatbot/ai-chatbot-base.d.ts +26 -0
- package/dist/ai-chatbot/ai-chatbot-base.mjs +136 -3
- package/dist/ai-chatbot/index.d.ts +2 -2
- package/dist/ai-chatbot/message-state-controller.d.ts +10 -1
- package/dist/ai-chatbot/message-state-controller.mjs +78 -20
- package/dist/ai-chatbot/types.d.ts +199 -1
- package/dist/ai-chatbot/utils.mjs +3 -1
- package/dist/ai-chatbot-launcher/ai-chatbot-launcher.mjs +0 -2
- package/dist/ai-message-thread/ai-message-thread.d.ts +1 -0
- package/dist/ai-message-thread/ai-message-thread.mjs +35 -3
- package/dist/ai-steps/ai-steps.d.ts +67 -0
- package/dist/ai-steps/ai-steps.mjs +163 -0
- package/dist/ai-steps/ai-steps.scss.mjs +4 -0
- package/dist/ai-steps/index.d.ts +1 -0
- package/dist/ai-steps/index.mjs +5 -0
- package/dist/ai-tool-call-indicator/ai-tool-call-indicator.mjs +1 -1
- package/dist/core/chatbot-core-controller.d.ts +2 -0
- package/dist/core/chatbot-core-controller.mjs +99 -4
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +9 -0
- package/dist/tools/ai-mcp-app/ai-mcp-app.d.ts +69 -0
- package/dist/tools/ai-mcp-app/ai-mcp-app.mjs +574 -0
- package/dist/tools/ai-mcp-app/ai-mcp-app.scss.mjs +4 -0
- package/dist/tools/ai-mcp-app/index.d.ts +3 -0
- package/dist/tools/ai-mcp-app/index.mjs +6 -0
- package/dist/tools/ai-mcp-app/mcp-app-bridge-controller.d.ts +61 -0
- package/dist/tools/ai-mcp-app/mcp-app-bridge-controller.mjs +156 -0
- package/dist/tools/ai-mcp-app/mcp-app-bridge-types.d.ts +123 -0
- package/dist/tools/ai-mcp-app/mcp-app-bridge.d.ts +41 -0
- package/dist/tools/ai-mcp-app/mcp-app-bridge.mjs +293 -0
- package/dist/tools/ai-mcp-app/mcp-app-context.d.ts +46 -0
- package/dist/tools/ai-mcp-app/mcp-app-context.mjs +5 -0
- package/dist/tools/ai-steps/ai-steps-definition.d.ts +2 -0
- package/dist/tools/ai-steps/ai-steps-definition.mjs +50 -0
- package/dist/tools/ai-steps/ai-steps.d.ts +28 -0
- package/dist/tools/ai-steps/ai-steps.mjs +49 -0
- package/dist/tools/ai-steps/ai-steps.scss.mjs +4 -0
- package/dist/tools/ai-steps/index.d.ts +2 -0
- package/dist/tools/ai-steps/index.mjs +6 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.mjs +5 -1
- package/dist/utils/inert-outside.d.ts +7 -0
- package/dist/utils/inert-outside.mjs +28 -0
- package/package.json +4 -1
|
@@ -479,7 +479,6 @@ threadName_get = function() {
|
|
|
479
479
|
isEditing,
|
|
480
480
|
() => html`
|
|
481
481
|
<forge-ai-edit-thread
|
|
482
|
-
density="medium"
|
|
483
482
|
.thread=${{
|
|
484
483
|
id: threadId,
|
|
485
484
|
title: this.threadName || "",
|
|
@@ -522,7 +521,6 @@ threadActionsMenu_get = function() {
|
|
|
522
521
|
};
|
|
523
522
|
return html`
|
|
524
523
|
<forge-ai-thread-actions-menu
|
|
525
|
-
density="medium"
|
|
526
524
|
.thread=${thread}
|
|
527
525
|
?show-rename=${this.showThreadRename}
|
|
528
526
|
?show-delete=${this.showThreadDelete}
|
|
@@ -61,6 +61,7 @@ export declare class AiMessageThreadComponent extends LitElement {
|
|
|
61
61
|
debugMode: boolean;
|
|
62
62
|
autoScroll: FeatureToggle;
|
|
63
63
|
private _messageThreadContainer;
|
|
64
|
+
private _messageThreadContent;
|
|
64
65
|
connectedCallback(): void;
|
|
65
66
|
disconnectedCallback(): void;
|
|
66
67
|
firstUpdated(): void;
|
|
@@ -2,6 +2,7 @@ import { unsafeCSS, LitElement, html, nothing } from "lit";
|
|
|
2
2
|
import { property, query, customElement } from "lit/decorators.js";
|
|
3
3
|
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
4
4
|
import { when } from "lit/directives/when.js";
|
|
5
|
+
import { keyed } from "lit/directives/keyed.js";
|
|
5
6
|
import { MarkdownStreamController } from "../ai-chatbot/markdown-stream-controller.mjs";
|
|
6
7
|
import "../ai-assistant-response/ai-assistant-response.mjs";
|
|
7
8
|
import "../ai-client-message/ai-client-message.mjs";
|
|
@@ -12,6 +13,7 @@ import "../ai-thinking-indicator/ai-thinking-indicator.mjs";
|
|
|
12
13
|
import "../ai-user-message/ai-user-message.mjs";
|
|
13
14
|
import "../ai-chatbot/ai-chatbot-tool-call.mjs";
|
|
14
15
|
import "../core/tooltip/tooltip.mjs";
|
|
16
|
+
import "../tools/ai-mcp-app/ai-mcp-app.mjs";
|
|
15
17
|
import styles from "./ai-message-thread.scss.mjs";
|
|
16
18
|
var __defProp = Object.defineProperty;
|
|
17
19
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -31,7 +33,7 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
|
|
|
31
33
|
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);
|
|
32
34
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
|
|
33
35
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
34
|
-
var _markdownController, _canAutoScroll, _resizeObserver, _AiMessageThreadComponent_instances, scheduleScroll_fn, checkScrollState_fn, _handleScroll, _handleScrollToBottomClick, scrollToBottomButton_get, handleCopy_fn, handleResend_fn, handleThumbsUp_fn, handleThumbsDown_fn, handleUserCopy_fn, handleUserResend_fn, handleUserEdit_fn, renderToolCall_fn, activeResponse_get, renderAssistantResponse_fn, emptyState_get, thinkingIndicator_get, messages_get, dispatchEvent_fn;
|
|
36
|
+
var _markdownController, _canAutoScroll, _lastScrollTop, _resizeObserver, _contentResizeObserver, _AiMessageThreadComponent_instances, observe_fn, handleContentResize_fn, scheduleScroll_fn, checkScrollState_fn, _handleScroll, _handleScrollToBottomClick, scrollToBottomButton_get, handleCopy_fn, handleResend_fn, handleThumbsUp_fn, handleThumbsDown_fn, handleUserCopy_fn, handleUserResend_fn, handleUserEdit_fn, renderToolCall_fn, activeResponse_get, renderAssistantResponse_fn, emptyState_get, thinkingIndicator_get, messages_get, dispatchEvent_fn;
|
|
35
37
|
const AiMessageThreadComponentTagName = "forge-ai-message-thread";
|
|
36
38
|
const SCROLL_THRESHOLD = 100;
|
|
37
39
|
let AiMessageThreadComponent = class extends LitElement {
|
|
@@ -45,7 +47,9 @@ let AiMessageThreadComponent = class extends LitElement {
|
|
|
45
47
|
this.autoScroll = "on";
|
|
46
48
|
__privateAdd(this, _markdownController);
|
|
47
49
|
__privateAdd(this, _canAutoScroll, true);
|
|
50
|
+
__privateAdd(this, _lastScrollTop, 0);
|
|
48
51
|
__privateAdd(this, _resizeObserver);
|
|
52
|
+
__privateAdd(this, _contentResizeObserver);
|
|
49
53
|
__privateAdd(this, _handleScroll, () => {
|
|
50
54
|
__privateMethod(this, _AiMessageThreadComponent_instances, checkScrollState_fn).call(this);
|
|
51
55
|
});
|
|
@@ -57,13 +61,18 @@ let AiMessageThreadComponent = class extends LitElement {
|
|
|
57
61
|
super.connectedCallback();
|
|
58
62
|
__privateSet(this, _markdownController, new MarkdownStreamController(this));
|
|
59
63
|
__privateSet(this, _resizeObserver, new ResizeObserver(() => __privateMethod(this, _AiMessageThreadComponent_instances, checkScrollState_fn).call(this)));
|
|
64
|
+
__privateSet(this, _contentResizeObserver, new ResizeObserver(() => __privateMethod(this, _AiMessageThreadComponent_instances, handleContentResize_fn).call(this)));
|
|
65
|
+
if (this.hasUpdated) {
|
|
66
|
+
__privateMethod(this, _AiMessageThreadComponent_instances, observe_fn).call(this);
|
|
67
|
+
}
|
|
60
68
|
}
|
|
61
69
|
disconnectedCallback() {
|
|
62
70
|
super.disconnectedCallback();
|
|
63
71
|
__privateGet(this, _resizeObserver)?.disconnect();
|
|
72
|
+
__privateGet(this, _contentResizeObserver)?.disconnect();
|
|
64
73
|
}
|
|
65
74
|
firstUpdated() {
|
|
66
|
-
|
|
75
|
+
__privateMethod(this, _AiMessageThreadComponent_instances, observe_fn).call(this);
|
|
67
76
|
}
|
|
68
77
|
updated(changedProperties) {
|
|
69
78
|
super.updated(changedProperties);
|
|
@@ -95,8 +104,19 @@ let AiMessageThreadComponent = class extends LitElement {
|
|
|
95
104
|
};
|
|
96
105
|
_markdownController = /* @__PURE__ */ new WeakMap();
|
|
97
106
|
_canAutoScroll = /* @__PURE__ */ new WeakMap();
|
|
107
|
+
_lastScrollTop = /* @__PURE__ */ new WeakMap();
|
|
98
108
|
_resizeObserver = /* @__PURE__ */ new WeakMap();
|
|
109
|
+
_contentResizeObserver = /* @__PURE__ */ new WeakMap();
|
|
99
110
|
_AiMessageThreadComponent_instances = /* @__PURE__ */ new WeakSet();
|
|
111
|
+
observe_fn = function() {
|
|
112
|
+
__privateGet(this, _resizeObserver)?.observe(this._messageThreadContainer);
|
|
113
|
+
__privateGet(this, _contentResizeObserver)?.observe(this._messageThreadContent);
|
|
114
|
+
};
|
|
115
|
+
handleContentResize_fn = function() {
|
|
116
|
+
if (this.autoScroll === "on") {
|
|
117
|
+
this.scrollToBottom({ behavior: "instant" });
|
|
118
|
+
}
|
|
119
|
+
};
|
|
100
120
|
scheduleScroll_fn = async function() {
|
|
101
121
|
await this.updateComplete;
|
|
102
122
|
await new Promise(requestAnimationFrame);
|
|
@@ -108,7 +128,10 @@ checkScrollState_fn = function() {
|
|
|
108
128
|
return;
|
|
109
129
|
}
|
|
110
130
|
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
111
|
-
const
|
|
131
|
+
const isNearBottom = scrollTop + clientHeight >= scrollHeight - SCROLL_THRESHOLD;
|
|
132
|
+
const scrolledUp = scrollTop < __privateGet(this, _lastScrollTop);
|
|
133
|
+
__privateSet(this, _lastScrollTop, scrollTop);
|
|
134
|
+
const canAutoScroll = isNearBottom || __privateGet(this, _canAutoScroll) && !scrolledUp;
|
|
112
135
|
if (canAutoScroll !== __privateGet(this, _canAutoScroll)) {
|
|
113
136
|
__privateSet(this, _canAutoScroll, canAutoScroll);
|
|
114
137
|
this.requestUpdate();
|
|
@@ -173,6 +196,9 @@ handleUserEdit_fn = function(messageId, content) {
|
|
|
173
196
|
});
|
|
174
197
|
};
|
|
175
198
|
renderToolCall_fn = function(toolCall) {
|
|
199
|
+
if (toolCall.uiResource) {
|
|
200
|
+
return keyed(toolCall.id, html`<forge-ai-mcp-app .toolCall=${toolCall}></forge-ai-mcp-app>`);
|
|
201
|
+
}
|
|
176
202
|
const toolDefinition = this.tools?.get(toolCall.name);
|
|
177
203
|
return html`<forge-ai-chatbot-tool-call
|
|
178
204
|
.toolCall=${toolCall}
|
|
@@ -231,6 +257,9 @@ messages_get = function() {
|
|
|
231
257
|
return true;
|
|
232
258
|
}
|
|
233
259
|
if (item.type === "toolCall") {
|
|
260
|
+
if (item.data.uiResource) {
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
234
263
|
const toolDef = this.tools?.get(item.data.name);
|
|
235
264
|
return !!toolDef?.renderer;
|
|
236
265
|
}
|
|
@@ -318,6 +347,9 @@ __decorateClass([
|
|
|
318
347
|
__decorateClass([
|
|
319
348
|
query(".message-thread")
|
|
320
349
|
], AiMessageThreadComponent.prototype, "_messageThreadContainer", 2);
|
|
350
|
+
__decorateClass([
|
|
351
|
+
query(".message-thread-content")
|
|
352
|
+
], AiMessageThreadComponent.prototype, "_messageThreadContent", 2);
|
|
321
353
|
AiMessageThreadComponent = __decorateClass([
|
|
322
354
|
customElement(AiMessageThreadComponentTagName)
|
|
323
355
|
], AiMessageThreadComponent);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { LitElement, PropertyValues, nothing, TemplateResult, CSSResult } from 'lit';
|
|
2
|
+
declare global {
|
|
3
|
+
interface HTMLElementTagNameMap {
|
|
4
|
+
'forge-ai-steps': AiStepsComponent;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export declare const AiStepsComponentTagName: keyof HTMLElementTagNameMap;
|
|
8
|
+
/** Lifecycle state of an individual step. */
|
|
9
|
+
export type AiStepStatus = 'pending' | 'running' | 'complete';
|
|
10
|
+
/**
|
|
11
|
+
* A single step in the timeline. Every field is supplied by the agent — the component derives no
|
|
12
|
+
* labels of its own and makes no assumption about how the agent names its work.
|
|
13
|
+
*/
|
|
14
|
+
export interface AiStep {
|
|
15
|
+
/**
|
|
16
|
+
* Agent-provided label for the step, e.g. `'Filtered by \`crime_category\`'`. Rendered as inline
|
|
17
|
+
* markdown, so the agent decides which part of its own label to emphasize. Literal `*`, `_` and
|
|
18
|
+
* `` ` `` characters need escaping.
|
|
19
|
+
*/
|
|
20
|
+
label: string;
|
|
21
|
+
/**
|
|
22
|
+
* Optional agent-provided elaboration, rendered as a detail card beneath the label. Also rendered
|
|
23
|
+
* as inline markdown.
|
|
24
|
+
*/
|
|
25
|
+
detail?: string;
|
|
26
|
+
/** Lifecycle state of this step. Defaults to `'complete'` when omitted. */
|
|
27
|
+
status?: AiStepStatus;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* @tag forge-ai-steps
|
|
31
|
+
*
|
|
32
|
+
* @summary Expandable timeline summarizing the steps an agent took while producing a response.
|
|
33
|
+
*
|
|
34
|
+
* @description
|
|
35
|
+
* Collapsed, it shows a step count and a summary of the first couple of step labels. When expanded,
|
|
36
|
+
* it lists each step as a row in a vertical timeline along with its status. Steps carrying a
|
|
37
|
+
* `detail` render as detail cards; steps without one render as a simple labeled row.
|
|
38
|
+
*
|
|
39
|
+
* Labels and details are rendered as sanitized inline markdown, so the agent controls its own
|
|
40
|
+
* emphasis — bold, italic, strikethrough, `code` and links — rather than the component or the
|
|
41
|
+
* consumer prescribing which part of a step matters.
|
|
42
|
+
*
|
|
43
|
+
* This is a presentational primitive: it renders whatever `steps` it is given and knows nothing
|
|
44
|
+
* about tool calls or tool definitions. `forge-ai-tool-steps` is the tool renderer that maps an
|
|
45
|
+
* agent's `displaySteps` tool call onto these properties.
|
|
46
|
+
*
|
|
47
|
+
* While `running` is `true` the timeline stays expanded and the summary row is hidden. When
|
|
48
|
+
* `running` flips back to `false` the timeline auto-collapses, leaving the summary row as the way
|
|
49
|
+
* back in. An element that mounts with `running` already `false` renders expanded, so static usage
|
|
50
|
+
* (a finished run, or a Storybook story) is readable without interaction.
|
|
51
|
+
*
|
|
52
|
+
* @property {AiStep[]} steps - The steps to render as timeline rows
|
|
53
|
+
* @property {boolean} running - Whether the run producing these steps is still in progress
|
|
54
|
+
*/
|
|
55
|
+
export declare class AiStepsComponent extends LitElement {
|
|
56
|
+
#private;
|
|
57
|
+
static styles: CSSResult;
|
|
58
|
+
steps: AiStep[];
|
|
59
|
+
/**
|
|
60
|
+
* Whether the run producing these steps is still in progress. While `true` the timeline is held
|
|
61
|
+
* open and the summary row is hidden; the transition back to `false` collapses the timeline.
|
|
62
|
+
*/
|
|
63
|
+
running: boolean;
|
|
64
|
+
private _expanded;
|
|
65
|
+
willUpdate(changedProperties: PropertyValues<this>): void;
|
|
66
|
+
render(): TemplateResult | typeof nothing;
|
|
67
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { unsafeCSS, LitElement, html, nothing } from "lit";
|
|
2
|
+
import { property, state, customElement } from "lit/decorators.js";
|
|
3
|
+
import { join } from "lit/directives/join.js";
|
|
4
|
+
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
5
|
+
import { when } from "lit/directives/when.js";
|
|
6
|
+
import { renderInlineMarkdown } from "../utils/markdown.mjs";
|
|
7
|
+
import styles from "./ai-steps.scss.mjs";
|
|
8
|
+
var __defProp = Object.defineProperty;
|
|
9
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
10
|
+
var __typeError = (msg) => {
|
|
11
|
+
throw TypeError(msg);
|
|
12
|
+
};
|
|
13
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
14
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
15
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
16
|
+
if (decorator = decorators[i])
|
|
17
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
18
|
+
if (kind && result) __defProp(target, key, result);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
22
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
23
|
+
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);
|
|
24
|
+
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
25
|
+
var _chevronIcon, _rowMarker, _AiStepsComponent_instances, renderInline_fn, summaryLabel_get, toggle_fn, renderNoDetailStep_fn, renderStep_fn, isExpanded_get, steps_get, stepsSummary_get, stepsCountLabel_get;
|
|
26
|
+
const AiStepsComponentTagName = "forge-ai-steps";
|
|
27
|
+
const MAX_DETAIL_LENGTH = 2e3;
|
|
28
|
+
let AiStepsComponent = class extends LitElement {
|
|
29
|
+
constructor() {
|
|
30
|
+
super(...arguments);
|
|
31
|
+
__privateAdd(this, _AiStepsComponent_instances);
|
|
32
|
+
this.steps = [];
|
|
33
|
+
this.running = false;
|
|
34
|
+
this._expanded = true;
|
|
35
|
+
__privateAdd(this, _chevronIcon, html`
|
|
36
|
+
<svg
|
|
37
|
+
class="chevron"
|
|
38
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
39
|
+
viewBox="0 0 24 24"
|
|
40
|
+
height="20"
|
|
41
|
+
width="20"
|
|
42
|
+
fill="currentColor"
|
|
43
|
+
aria-hidden="true">
|
|
44
|
+
<path d="M7.41 8.59 12 13.17l4.59-4.58L18 10l-6 6-6-6z" />
|
|
45
|
+
</svg>
|
|
46
|
+
`);
|
|
47
|
+
__privateAdd(this, _rowMarker, html`<span class="row-marker"></span>`);
|
|
48
|
+
}
|
|
49
|
+
willUpdate(changedProperties) {
|
|
50
|
+
if (changedProperties.has("running") && !this.running && changedProperties.get("running") === true) {
|
|
51
|
+
this._expanded = false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
render() {
|
|
55
|
+
if (this.steps.length === 0) {
|
|
56
|
+
return nothing;
|
|
57
|
+
}
|
|
58
|
+
return html`
|
|
59
|
+
<div class="steps">
|
|
60
|
+
<div class="steps-count">${__privateGet(this, _AiStepsComponent_instances, stepsCountLabel_get)}</div>
|
|
61
|
+
${__privateGet(this, _AiStepsComponent_instances, stepsSummary_get)} ${__privateGet(this, _AiStepsComponent_instances, steps_get)}
|
|
62
|
+
</div>
|
|
63
|
+
`;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
_chevronIcon = /* @__PURE__ */ new WeakMap();
|
|
67
|
+
_rowMarker = /* @__PURE__ */ new WeakMap();
|
|
68
|
+
_AiStepsComponent_instances = /* @__PURE__ */ new WeakSet();
|
|
69
|
+
renderInline_fn = function(value) {
|
|
70
|
+
return html`${unsafeHTML(renderInlineMarkdown(value))}`;
|
|
71
|
+
};
|
|
72
|
+
summaryLabel_get = function() {
|
|
73
|
+
const stepLabels = this.steps.map((step) => html`<span>${__privateMethod(this, _AiStepsComponent_instances, renderInline_fn).call(this, step.label)}</span>`);
|
|
74
|
+
const visibleLabels = stepLabels.slice(0, 2);
|
|
75
|
+
const remaining = stepLabels.length - visibleLabels.length;
|
|
76
|
+
return remaining > 0 ? html`${join(visibleLabels, html`, `)} +${remaining} more` : html`${join(visibleLabels, html`, `)}`;
|
|
77
|
+
};
|
|
78
|
+
toggle_fn = function() {
|
|
79
|
+
this._expanded = !this._expanded;
|
|
80
|
+
};
|
|
81
|
+
renderNoDetailStep_fn = function(step) {
|
|
82
|
+
return html`
|
|
83
|
+
<div class="timeline-row" data-status=${step.status ?? "complete"}>
|
|
84
|
+
<div class="row-header">
|
|
85
|
+
${__privateGet(this, _rowMarker)}
|
|
86
|
+
<span class="row-label">
|
|
87
|
+
<span class="row-name">${__privateMethod(this, _AiStepsComponent_instances, renderInline_fn).call(this, step.label)}</span>
|
|
88
|
+
</span>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
`;
|
|
92
|
+
};
|
|
93
|
+
renderStep_fn = function(step) {
|
|
94
|
+
const detail = step.detail;
|
|
95
|
+
if (!detail) {
|
|
96
|
+
return __privateMethod(this, _AiStepsComponent_instances, renderNoDetailStep_fn).call(this, step);
|
|
97
|
+
}
|
|
98
|
+
const truncated = detail.length > MAX_DETAIL_LENGTH ? `${detail.slice(0, MAX_DETAIL_LENGTH)}… (truncated)` : detail;
|
|
99
|
+
return html`
|
|
100
|
+
<div class="timeline-row" data-status=${step.status ?? "complete"}>
|
|
101
|
+
<div class="row-header">
|
|
102
|
+
${__privateGet(this, _rowMarker)}
|
|
103
|
+
<div class="step-card">
|
|
104
|
+
<span class="step-card-title">${__privateMethod(this, _AiStepsComponent_instances, renderInline_fn).call(this, step.label)}</span>
|
|
105
|
+
<div class="step-card-body">
|
|
106
|
+
<div class="step-card-result">${__privateMethod(this, _AiStepsComponent_instances, renderInline_fn).call(this, truncated)}</div>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
`;
|
|
112
|
+
};
|
|
113
|
+
isExpanded_get = function() {
|
|
114
|
+
return this.running || this._expanded;
|
|
115
|
+
};
|
|
116
|
+
steps_get = function() {
|
|
117
|
+
return html`
|
|
118
|
+
<div
|
|
119
|
+
id="timeline-content"
|
|
120
|
+
class="timeline ${__privateGet(this, _AiStepsComponent_instances, isExpanded_get) ? "expanded" : ""}"
|
|
121
|
+
aria-hidden=${__privateGet(this, _AiStepsComponent_instances, isExpanded_get) ? "false" : "true"}>
|
|
122
|
+
<div class="timeline-content">${this.steps.map((step) => __privateMethod(this, _AiStepsComponent_instances, renderStep_fn).call(this, step))}</div>
|
|
123
|
+
</div>
|
|
124
|
+
`;
|
|
125
|
+
};
|
|
126
|
+
stepsSummary_get = function() {
|
|
127
|
+
return when(
|
|
128
|
+
!this.running,
|
|
129
|
+
() => html`
|
|
130
|
+
<button
|
|
131
|
+
class="summary"
|
|
132
|
+
type="button"
|
|
133
|
+
aria-expanded=${this._expanded}
|
|
134
|
+
aria-controls="timeline-content"
|
|
135
|
+
@click=${__privateMethod(this, _AiStepsComponent_instances, toggle_fn)}>
|
|
136
|
+
${__privateGet(this, _chevronIcon)}
|
|
137
|
+
<span class="status-text">${__privateGet(this, _AiStepsComponent_instances, summaryLabel_get)}</span>
|
|
138
|
+
<span class="focus-indicator"></span>
|
|
139
|
+
</button>
|
|
140
|
+
`
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
stepsCountLabel_get = function() {
|
|
144
|
+
const count = this.steps.length;
|
|
145
|
+
return `${count} step${count === 1 ? "" : "s"}`;
|
|
146
|
+
};
|
|
147
|
+
AiStepsComponent.styles = unsafeCSS(styles);
|
|
148
|
+
__decorateClass([
|
|
149
|
+
property({ attribute: false })
|
|
150
|
+
], AiStepsComponent.prototype, "steps", 2);
|
|
151
|
+
__decorateClass([
|
|
152
|
+
property({ type: Boolean, reflect: true })
|
|
153
|
+
], AiStepsComponent.prototype, "running", 2);
|
|
154
|
+
__decorateClass([
|
|
155
|
+
state()
|
|
156
|
+
], AiStepsComponent.prototype, "_expanded", 2);
|
|
157
|
+
AiStepsComponent = __decorateClass([
|
|
158
|
+
customElement(AiStepsComponentTagName)
|
|
159
|
+
], AiStepsComponent);
|
|
160
|
+
export {
|
|
161
|
+
AiStepsComponent,
|
|
162
|
+
AiStepsComponentTagName
|
|
163
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
const styles = '/* prettier-ignore */\n@keyframes fadein {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes forge-focus-indicator-outward-grow {\n from {\n outline-width: 0;\n }\n to {\n outline-width: var(--_focus-indicator-active-width);\n }\n}\n@keyframes forge-focus-indicator-outward-shrink {\n from {\n outline-width: var(--_focus-indicator-active-width);\n }\n}\n@keyframes forge-focus-indicator-inward-grow {\n from {\n border-width: 0;\n }\n to {\n border-width: var(--_focus-indicator-active-width);\n }\n}\n@keyframes forge-focus-indicator-inward-shrink {\n from {\n border-width: var(--_focus-indicator-active-width);\n }\n}\n:host {\n display: flex;\n flex-direction: column;\n gap: var(--forge-spacing-small, 12px);\n}\n\n.summary {\n display: flex;\n align-items: center;\n gap: var(--forge-spacing-xsmall, 8px);\n padding-block: var(--forge-spacing-xxsmall, 4px);\n padding-inline: var(--forge-spacing-xsmall, 8px);\n border: none;\n background-color: var(--forge-theme-surface-container-minimum, #f5f5f5);\n border-radius: calc(var(--forge-shape-large, 8px) * var(--forge-shape-factor, 1));\n cursor: pointer;\n text-align: start;\n position: relative;\n outline: none;\n --_state-layer-display: var(--forge-state-layer-display, flex);\n --_state-layer-color: var(--forge-state-layer-color, var(--forge-theme-on-surface, #000000));\n --_state-layer-hover-color: var(--forge-state-layer-hover-color, var(--_state-layer-color));\n --_state-layer-hover-opacity: var(--forge-state-layer-hover-opacity, 0.08);\n --_state-layer-pressed-color: var(--forge-state-layer-pressed-color, var(--_state-layer-color));\n --_state-layer-pressed-opacity: var(--forge-state-layer-pressed-opacity, 0.12);\n --_state-layer-hover-duration: var(--forge-state-layer-hover-duration, 15ms);\n --_state-layer-pressed-duration: var(--forge-state-layer-pressed-duration, 105ms);\n --_state-layer-animation-duration: var(--forge-state-layer-animation-duration, 375ms);\n}\n.summary::before {\n opacity: 0;\n position: absolute;\n backface-visibility: hidden;\n transform: translateZ(0);\n background-color: var(--_state-layer-hover-color);\n inset: 0;\n transition: opacity var(--_state-layer-hover-duration) linear, background-color var(--_state-layer-hover-duration) linear;\n --_state-layer-hover-duration: var(--forge-state-layer-hover-duration, 100ms);\n content: "";\n opacity: 0;\n border-radius: inherit;\n}\n.summary:hover::before {\n background-color: var(--_state-layer-hover-color);\n opacity: var(--_state-layer-hover-opacity);\n}\n.summary:active::before {\n opacity: var(--_state-layer-pressed-opacity);\n transition-duration: var(--_state-layer-pressed-duration);\n --_state-layer-pressed-opacity: var(--forge-state-layer-pressed-opacity, 0.18);\n}\n\n.status-text {\n -moz-osx-font-smoothing: grayscale;\n -webkit-font-smoothing: antialiased;\n font-family: var(--forge-typography-body1-font-family, var(--forge-typography-font-family, "Roboto", sans-serif));\n font-size: var(--forge-typography-body1-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-font-size-scale, 0.875)));\n font-weight: var(--forge-typography-body1-font-weight, 400);\n line-height: var(--forge-typography-body1-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-line-height-scale, 1.125)));\n letter-spacing: var(--forge-typography-body1-letter-spacing, 0.0357142857em);\n text-transform: var(--forge-typography-body1-text-transform, inherit);\n text-decoration: var(--forge-typography-body1-text-decoration, inherit);\n}\n\n.chevron {\n flex-shrink: 0;\n transform: rotate(-90deg);\n transition: transform var(--forge-animation-duration-short4, 200ms) var(--forge-animation-easing-standard, cubic-bezier(0.2, 0, 0, 1));\n}\n\n.summary[aria-expanded=true] .chevron {\n transform: rotate(0deg);\n}\n\n.focus-indicator {\n position: absolute;\n display: none;\n}\n\n:host .summary:focus .focus-indicator {\n --_focus-indicator-display: var(--forge-focus-indicator-display, flex);\n --_focus-indicator-width: var(--forge-focus-indicator-width, var(--forge-border-medium, 2px));\n --_focus-indicator-active-width: var(--forge-focus-indicator-active-width, 6px);\n --_focus-indicator-color: var(--forge-focus-indicator-color, var(--forge-theme-primary, #3f51b5));\n --_focus-indicator-shape: var(--forge-focus-indicator-shape, calc(var(--forge-shape-extra-small, 1px) * var(--forge-shape-factor, 1)));\n --_focus-indicator-duration: var(--forge-focus-indicator-duration, var(--forge-animation-duration-long4, 600ms));\n --_focus-indicator-easing: var(--forge-focus-indicator-easing, var(--forge-animation-easing-emphasized, cubic-bezier(0.2, 0, 0, 1)));\n --_focus-indicator-shape-start-start: var(--forge-focus-indicator-shape-start-start, var(--_focus-indicator-shape));\n --_focus-indicator-shape-start-end: var(--forge-focus-indicator-shape-start-end, var(--_focus-indicator-shape));\n --_focus-indicator-shape-end-end: var(--forge-focus-indicator-shape-end-end, var(--_focus-indicator-shape));\n --_focus-indicator-shape-end-start: var(--forge-focus-indicator-shape-end-start, var(--_focus-indicator-shape));\n --_focus-indicator-outward-offset: var(--forge-focus-indicator-outward-offset, var(--forge-spacing-xxsmall, 4px));\n --_focus-indicator-inward-offset: var(--forge-focus-indicator-inward-offset, 0px);\n --_focus-indicator-offset-block: var(--forge-focus-indicator-offset-block, 0);\n --_focus-indicator-offset-inline: var(--forge-focus-indicator-offset-inline, 0);\n animation-delay: 0s, calc(var(--_focus-indicator-duration) * 0.25);\n animation-duration: calc(var(--_focus-indicator-duration) * 0.25), calc(var(--_focus-indicator-duration) * 0.75);\n animation-timing-function: var(--_focus-indicator-easing);\n box-sizing: border-box;\n color: var(--_focus-indicator-color);\n display: none;\n pointer-events: none;\n position: absolute;\n margin-block: var(--_focus-indicator-offset-block);\n margin-inline: var(--_focus-indicator-offset-inline);\n animation-name: forge-focus-indicator-inward-grow, forge-focus-indicator-inward-shrink;\n border-end-end-radius: calc(var(--_focus-indicator-shape-end-end) - var(--_focus-indicator-inward-offset));\n border-end-start-radius: calc(var(--_focus-indicator-shape-end-start) - var(--_focus-indicator-inward-offset));\n border-start-end-radius: calc(var(--_focus-indicator-shape-start-end) - var(--_focus-indicator-inward-offset));\n border-start-start-radius: calc(var(--_focus-indicator-shape-start-start) - var(--_focus-indicator-inward-offset));\n border: var(--_focus-indicator-width) solid currentColor;\n inset: var(--_focus-indicator-inward-offset);\n}\n:host .summary:focus .focus-indicator::before {\n content: "";\n}\n:host .summary:focus .focus-indicator {\n display: block;\n --forge-focus-indicator-shape: calc(var(--forge-shape-large, 8px) * var(--forge-shape-factor, 1));\n}\n\n.steps {\n display: flex;\n flex-direction: column;\n gap: var(--forge-spacing-xsmall, 8px);\n -moz-osx-font-smoothing: grayscale;\n -webkit-font-smoothing: antialiased;\n font-family: var(--forge-typography-body1-font-family, var(--forge-typography-font-family, "Roboto", sans-serif));\n font-size: var(--forge-typography-body1-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-font-size-scale, 0.875)));\n font-weight: var(--forge-typography-body1-font-weight, 400);\n line-height: var(--forge-typography-body1-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-line-height-scale, 1.125)));\n letter-spacing: var(--forge-typography-body1-letter-spacing, 0.0357142857em);\n text-transform: var(--forge-typography-body1-text-transform, inherit);\n text-decoration: var(--forge-typography-body1-text-decoration, inherit);\n font-size: var(--forge-ai-markdown-font-size, 0.875rem);\n line-height: var(--forge-ai-markdown-line-height, 1.5rem);\n color: var(--forge-theme-on-surface, #000000);\n overflow-wrap: break-word;\n}\n.steps h1,\n.steps h2,\n.steps h3,\n.steps h4,\n.steps h5,\n.steps h6 {\n margin: 1.75rem 0 var(--forge-spacing-small, 12px);\n}\n.steps strong {\n font-weight: 500;\n}\n.steps a {\n color: var(--forge-theme-primary, #3f51b5);\n}\n.steps hr {\n border: none;\n border-top: 1px solid var(--forge-theme-outline, #e0e0e0);\n}\n.steps code {\n color: var(--forge-theme-on-surface-container-low, #000000);\n background-color: var(--forge-theme-surface-container-low, #ebebeb);\n border-radius: calc(var(--forge-shape-medium, 4px) * var(--forge-shape-factor, 1));\n padding: var(--forge-spacing-xxxsmall, 2px) var(--forge-spacing-xxsmall, 4px);\n font-size: 0.75em;\n}\n.steps pre {\n border: 1px solid var(--forge-theme-outline, #e0e0e0);\n border-radius: calc(var(--forge-shape-medium, 4px) * var(--forge-shape-factor, 1));\n margin: 0;\n max-width: 100%;\n overflow-x: auto;\n}\n.steps pre:focus-visible {\n outline: 2px solid var(--forge-theme-primary, #3f51b5);\n outline-offset: 2px;\n}\n.steps pre code {\n display: block;\n padding: var(--forge-spacing-xsmall, 8px) var(--forge-spacing-small, 12px);\n color: var(--forge-theme-on-surface-container-minimum, #000000);\n background: var(--forge-theme-surface-container-minimum, #f5f5f5);\n white-space: pre;\n}\n.steps [data-scroll-region=table] {\n max-width: 100%;\n overflow-x: auto;\n border-radius: calc(var(--forge-shape-large, 8px) * var(--forge-shape-factor, 1));\n margin-block: var(--forge-spacing-medium, 16px);\n}\n.steps [data-scroll-region=table]:focus-visible {\n outline: 2px solid var(--forge-theme-primary, #3f51b5);\n outline-offset: 2px;\n}\n.steps [data-scroll-region=table] table {\n margin-block: 0;\n}\n.steps table {\n width: 100%;\n border-spacing: 0;\n background-color: var(--forge-theme-surface, #ffffff);\n border-radius: calc(var(--forge-shape-large, 8px) * var(--forge-shape-factor, 1));\n overflow: hidden;\n margin-block: var(--forge-spacing-medium, 16px);\n}\n.steps table thead {\n color: var(--forge-theme-text-medium, rgba(0, 0, 0, 0.6));\n font-weight: bold;\n text-align: left;\n font-size: calc(var(--forge-typography-font-size, 1rem) * 0.75);\n box-sizing: border-box;\n}\n.steps table tr {\n height: 36px;\n height: 32px;\n}\n.steps table tr:nth-child(even) {\n background-color: var(--forge-theme-surface-dim, #fafafa);\n}\n.steps table tr:last-child td {\n border-bottom: none;\n}\n.steps table th,\n.steps table td {\n -moz-osx-font-smoothing: grayscale;\n -webkit-font-smoothing: antialiased;\n font-family: var(--forge-typography-label1-font-family, var(--forge-typography-font-family, "Roboto", sans-serif));\n font-size: var(--forge-typography-label1-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-label-font-size-scale, 0.75)));\n font-weight: var(--forge-typography-label1-font-weight, 400);\n line-height: var(--forge-typography-label1-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-label-line-height-scale, 1.25)));\n letter-spacing: var(--forge-typography-label1-letter-spacing, 0.0357142857em);\n text-transform: var(--forge-typography-label1-text-transform, inherit);\n text-decoration: var(--forge-typography-label1-text-decoration, inherit);\n padding-block: var(--forge-spacing-xsmall, 8px);\n padding-inline-start: var(--forge-spacing-xsmall, 8px);\n padding-inline-end: var(--forge-spacing-medium, 16px);\n border-bottom-width: 1px;\n border-bottom-style: solid;\n border-bottom-color: var(--forge-theme-outline, #e0e0e0);\n}\n.steps table th {\n -moz-osx-font-smoothing: grayscale;\n -webkit-font-smoothing: antialiased;\n font-family: var(--forge-typography-label2-font-family, var(--forge-typography-font-family, "Roboto", sans-serif));\n font-size: var(--forge-typography-label2-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-label-font-size-scale, 0.8125)));\n font-weight: var(--forge-typography-label2-font-weight, 400);\n line-height: var(--forge-typography-label2-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-label-line-height-scale, 1.25)));\n letter-spacing: var(--forge-typography-label2-letter-spacing, 0.0096153846em);\n text-transform: var(--forge-typography-label2-text-transform, inherit);\n text-decoration: var(--forge-typography-label2-text-decoration, inherit);\n font-weight: 600;\n}\n.steps > p:has(+ ol),\n.steps > p:has(+ ul) {\n margin-block-end: var(--forge-spacing-small, 12px);\n}\n.steps > ul {\n list-style-type: disc;\n padding-inline-start: 1.6875rem;\n}\n.steps > ol {\n padding-inline-start: 1.75rem;\n}\n.steps > ol,\n.steps > ul {\n margin: var(--forge-spacing-xsmall, 8px) 0;\n margin-block-end: var(--forge-spacing-medium, 16px);\n}\n.steps > :first-child {\n margin-block-start: 0;\n}\n.steps > p {\n margin-block-end: var(--forge-spacing-medium, 16px);\n overflow-wrap: anywhere;\n}\n.steps > p:first-child {\n margin-block-start: 0;\n}\n.steps > p:last-child {\n margin-block-end: 0;\n}\n.steps-count {\n color: var(--forge-theme-text-medium, rgba(0, 0, 0, 0.6));\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.timeline {\n display: grid;\n grid-template-rows: 0fr;\n transition: grid-template-rows var(--forge-animation-duration-medium2, 300ms) var(--forge-animation-easing-decelerate, cubic-bezier(0, 0, 0, 1));\n}\n.timeline.expanded {\n grid-template-rows: 1fr;\n}\n\n.timeline-content {\n overflow: hidden;\n min-height: 0;\n padding-inline-start: var(--forge-spacing-small, 12px);\n}\n\n.timeline-row {\n position: relative;\n padding-inline-start: var(--forge-spacing-large, 24px);\n padding-block-end: var(--forge-spacing-medium, 16px);\n}\n.timeline-row::before {\n content: "";\n position: absolute;\n inset-block-start: calc((var(--forge-spacing-medium-large, 20px) - var(--forge-spacing-xsmall, 8px)) / 2);\n inset-block-end: calc(-1 * var(--forge-spacing-xsmall, 8px));\n inset-inline-start: calc((var(--forge-spacing-medium-large, 20px) - 1px) / 2);\n width: 1px;\n background-color: var(--forge-theme-outline, #e0e0e0);\n}\n.timeline-row:last-child::before {\n display: none;\n}\n\n.row-header {\n display: flex;\n align-items: flex-start;\n gap: var(--forge-spacing-small, 12px);\n width: 100%;\n min-height: var(--forge-spacing-medium-large, 20px);\n margin-inline-start: calc(-1 * var(--forge-spacing-large, 24px));\n}\n\n.row-marker {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--forge-spacing-medium-large, 20px);\n height: var(--forge-spacing-medium-large, 20px);\n border-radius: calc(var(--forge-shape-round, 50%) * var(--forge-shape-factor, 1));\n}\n.row-marker::before {\n content: "";\n flex-shrink: 0;\n width: var(--forge-spacing-xsmall, 8px);\n height: var(--forge-spacing-xsmall, 8px);\n border-radius: calc(var(--forge-shape-round, 50%) * var(--forge-shape-factor, 1));\n background-color: currentColor;\n position: relative;\n z-index: 1;\n}\n\n.row-label {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-width: 0;\n gap: var(--forge-spacing-xxxsmall, 2px);\n}\n\n.row-name {\n -moz-osx-font-smoothing: grayscale;\n -webkit-font-smoothing: antialiased;\n font-family: var(--forge-typography-body1-font-family, var(--forge-typography-font-family, "Roboto", sans-serif));\n font-size: var(--forge-typography-body1-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-font-size-scale, 0.875)));\n font-weight: var(--forge-typography-body1-font-weight, 400);\n line-height: var(--forge-typography-body1-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-line-height-scale, 1.125)));\n letter-spacing: var(--forge-typography-body1-letter-spacing, 0.0357142857em);\n text-transform: var(--forge-typography-body1-text-transform, inherit);\n text-decoration: var(--forge-typography-body1-text-decoration, inherit);\n display: flex;\n align-items: center;\n gap: var(--forge-spacing-xsmall, 8px);\n line-height: normal;\n font-weight: 500;\n color: var(--forge-theme-text-high, rgba(0, 0, 0, 0.87));\n}\n\n.step-card {\n width: 100%;\n}\n.step-card-title {\n -moz-osx-font-smoothing: grayscale;\n -webkit-font-smoothing: antialiased;\n font-family: var(--forge-typography-body1-font-family, var(--forge-typography-font-family, "Roboto", sans-serif));\n font-size: var(--forge-typography-body1-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-font-size-scale, 0.875)));\n font-weight: var(--forge-typography-body1-font-weight, 400);\n line-height: var(--forge-typography-body1-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-line-height-scale, 1.125)));\n letter-spacing: var(--forge-typography-body1-letter-spacing, 0.0357142857em);\n text-transform: var(--forge-typography-body1-text-transform, inherit);\n text-decoration: var(--forge-typography-body1-text-decoration, inherit);\n font-weight: 700;\n}\n.step-card-result {\n -moz-osx-font-smoothing: grayscale;\n -webkit-font-smoothing: antialiased;\n font-family: var(--forge-typography-body1-font-family, var(--forge-typography-font-family, "Roboto", sans-serif));\n font-size: var(--forge-typography-body1-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-font-size-scale, 0.875)));\n font-weight: var(--forge-typography-body1-font-weight, 400);\n line-height: var(--forge-typography-body1-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-line-height-scale, 1.125)));\n letter-spacing: var(--forge-typography-body1-letter-spacing, 0.0357142857em);\n text-transform: var(--forge-typography-body1-text-transform, inherit);\n text-decoration: var(--forge-typography-body1-text-decoration, inherit);\n}\n\n.row-name strong,\n.step-card-title strong {\n font-weight: 700;\n}';
|
|
2
|
+
export {
|
|
3
|
+
styles as default
|
|
4
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ai-steps';
|
|
@@ -218,7 +218,7 @@ highlightJson_fn = function(value) {
|
|
|
218
218
|
return html`${unsafeHTML(highlighted)}`;
|
|
219
219
|
};
|
|
220
220
|
statusMarker_fn = function(toolCall) {
|
|
221
|
-
if (toolCall.status === "error") {
|
|
221
|
+
if (toolCall.status === "error" || toolCall.status === "cancelled") {
|
|
222
222
|
return html`<span class="row-marker row-marker--error">${__privateGet(this, _errorIcon)}</span>`;
|
|
223
223
|
}
|
|
224
224
|
if (isToolCallSettled(toolCall, this.tools?.get(toolCall.name))) {
|
|
@@ -38,6 +38,8 @@ export declare class ChatbotCoreController implements ReactiveController {
|
|
|
38
38
|
getMessages(): ChatMessage[];
|
|
39
39
|
setMessages(messages: ChatMessage[]): void;
|
|
40
40
|
updateMessageContent(id: string, content: string): void;
|
|
41
|
+
/** Tool call ids rendered at or after `index` in {@link messageItems}. */
|
|
42
|
+
getToolCallIdsFrom(index: number): string[];
|
|
41
43
|
removeMessageItemsFrom(index: number): void;
|
|
42
44
|
setResponseFeedback(responseId: string, feedback: {
|
|
43
45
|
type: 'positive' | 'negative';
|
|
@@ -2,6 +2,7 @@ import { SubscriptionManager } from "../ai-chatbot/event-emitter.mjs";
|
|
|
2
2
|
import { FileUploadManager } from "../ai-chatbot/file-upload-manager.mjs";
|
|
3
3
|
import { MessageStateController } from "../ai-chatbot/message-state-controller.mjs";
|
|
4
4
|
import { generateId } from "../ai-chatbot/utils.mjs";
|
|
5
|
+
const UNSETTLED_TOOL_CALL_STATUSES = ["pending", "parsing", "executing"];
|
|
5
6
|
class ChatbotCoreController {
|
|
6
7
|
#host;
|
|
7
8
|
#callbacks;
|
|
@@ -10,6 +11,14 @@ class ChatbotCoreController {
|
|
|
10
11
|
#adapterSubscriptions;
|
|
11
12
|
#adapter;
|
|
12
13
|
#executingToolHandlers = 0;
|
|
14
|
+
/** Tool calls announced by an `mcp-ui-resource` event; they only settle via a tool result. */
|
|
15
|
+
#mcpAppToolCallIds = /* @__PURE__ */ new Set();
|
|
16
|
+
/** Agent tool calls marked complete on their `tool-call` chunk, before any result arrived. */
|
|
17
|
+
#presumedCompleteToolCallIds = /* @__PURE__ */ new Set();
|
|
18
|
+
/** Resolved UI resources whose tool call is not in state yet. */
|
|
19
|
+
#pendingUiResources = /* @__PURE__ */ new Map();
|
|
20
|
+
/** Bumped whenever the thread is cleared or replaced, so in-flight UI resource resolves from before are dropped. */
|
|
21
|
+
#threadGeneration = 0;
|
|
13
22
|
constructor(host, config) {
|
|
14
23
|
this.#host = host;
|
|
15
24
|
this.#callbacks = config.callbacks;
|
|
@@ -83,6 +92,7 @@ class ChatbotCoreController {
|
|
|
83
92
|
this.#adapter.onToolCallEnd(this.#handleToolCallEnd.bind(this)),
|
|
84
93
|
this.#adapter.onToolCall(this.#handleToolCall.bind(this)),
|
|
85
94
|
this.#adapter.onToolCallResult(this.#handleToolCallResult.bind(this)),
|
|
95
|
+
this.#adapter.onMcpUiResource(this.#handleMcpUiResource.bind(this)),
|
|
86
96
|
this.#adapter.onStepStarted(this.#handleStepStarted.bind(this)),
|
|
87
97
|
this.#adapter.onStepFinished(this.#handleStepFinished.bind(this)),
|
|
88
98
|
this.#adapter.onRunFinished(this.#handleRunFinished.bind(this)),
|
|
@@ -115,10 +125,29 @@ class ChatbotCoreController {
|
|
|
115
125
|
#handleRunFinished() {
|
|
116
126
|
this.#tryCompleteResponse();
|
|
117
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* A run ended (finished, aborted, or errored) without delivering a result for an
|
|
130
|
+
* MCP-app tool call: mark it cancelled so the widget receives `tool-cancelled`.
|
|
131
|
+
*/
|
|
132
|
+
#cancelUnsettledMcpAppToolCalls() {
|
|
133
|
+
for (const id of this.#mcpAppToolCallIds) {
|
|
134
|
+
const toolCall = this.#messageStateController.getToolCall(id);
|
|
135
|
+
if (toolCall && UNSETTLED_TOOL_CALL_STATUSES.includes(toolCall.status)) {
|
|
136
|
+
this.#messageStateController.updateToolCallInResponse(id, { status: "cancelled" });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
this.#mcpAppToolCallIds.clear();
|
|
140
|
+
this.#presumedCompleteToolCallIds.clear();
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Finalizes once the run is truly over. An executing client-tool handler or a running
|
|
144
|
+
* adapter means a continuation follows, so widgets stay open for it to settle (§2).
|
|
145
|
+
*/
|
|
118
146
|
#tryCompleteResponse() {
|
|
119
147
|
if (this.#executingToolHandlers > 0 || this.#adapter?.isRunning) {
|
|
120
148
|
return;
|
|
121
149
|
}
|
|
150
|
+
this.#cancelUnsettledMcpAppToolCalls();
|
|
122
151
|
this.#messageStateController.tryFinalizeResponse();
|
|
123
152
|
const messages = this.getMessages();
|
|
124
153
|
const lastMessage = messages[messages.length - 1];
|
|
@@ -134,7 +163,8 @@ class ChatbotCoreController {
|
|
|
134
163
|
args: {},
|
|
135
164
|
argsBuffer: "",
|
|
136
165
|
status: "parsing",
|
|
137
|
-
type: this.tools.has(event.name) ? "client" : "agent"
|
|
166
|
+
type: this.tools.has(event.name) ? "client" : "agent",
|
|
167
|
+
...this.#takePendingUiResource(event.id)
|
|
138
168
|
};
|
|
139
169
|
this.#messageStateController.addToolCallToResponse(toolCall);
|
|
140
170
|
const toolDef = this.tools.get(event.name);
|
|
@@ -195,7 +225,8 @@ class ChatbotCoreController {
|
|
|
195
225
|
name: event.name,
|
|
196
226
|
args: event.args,
|
|
197
227
|
status: "executing",
|
|
198
|
-
type: this.tools.has(event.name) ? "client" : "agent"
|
|
228
|
+
type: this.tools.has(event.name) ? "client" : "agent",
|
|
229
|
+
...this.#takePendingUiResource(event.id)
|
|
199
230
|
};
|
|
200
231
|
this.#messageStateController.addToolCallToResponse(toolCall);
|
|
201
232
|
}
|
|
@@ -211,7 +242,8 @@ class ChatbotCoreController {
|
|
|
211
242
|
} else {
|
|
212
243
|
this.#sendToolResult(event.id, this.#createToolResponse(event.name));
|
|
213
244
|
}
|
|
214
|
-
} else {
|
|
245
|
+
} else if (!this.#mcpAppToolCallIds.has(event.id)) {
|
|
246
|
+
this.#presumedCompleteToolCallIds.add(event.id);
|
|
215
247
|
this.#messageStateController.updateToolCallInResponse(event.id, { status: "complete" });
|
|
216
248
|
}
|
|
217
249
|
}
|
|
@@ -249,6 +281,7 @@ class ChatbotCoreController {
|
|
|
249
281
|
}
|
|
250
282
|
}
|
|
251
283
|
#handleError(event) {
|
|
284
|
+
this.#cancelUnsettledMcpAppToolCalls();
|
|
252
285
|
const errorMessage = {
|
|
253
286
|
id: generateId(),
|
|
254
287
|
role: "assistant",
|
|
@@ -261,6 +294,7 @@ class ChatbotCoreController {
|
|
|
261
294
|
this.#callbacks.onDispatchEvent("forge-ai-chatbot-error", { error: event.message });
|
|
262
295
|
}
|
|
263
296
|
#handleRunAborted() {
|
|
297
|
+
this.#cancelUnsettledMcpAppToolCalls();
|
|
264
298
|
this.#messageStateController.tryFinalizeResponse();
|
|
265
299
|
const id = this.#messageStateController.addClientMessage({ content: "Run cancelled" });
|
|
266
300
|
const abortMessage = this.#messageStateController.getMessage(id);
|
|
@@ -272,8 +306,53 @@ class ChatbotCoreController {
|
|
|
272
306
|
this.#callbacks.onRequestUpdate();
|
|
273
307
|
}
|
|
274
308
|
#handleToolCallResult(event) {
|
|
309
|
+
this.#presumedCompleteToolCallIds.delete(event.toolCallId);
|
|
275
310
|
this.#messageStateController.completeToolCallInResponse(event.toolCallId, event.result, event);
|
|
276
311
|
}
|
|
312
|
+
/**
|
|
313
|
+
* Resolves and stamps the UI resource. Works whether the event arrives before or after
|
|
314
|
+
* the tool call's chunks, mid-run, after the run ended, or after `setMessages` for
|
|
315
|
+
* tool calls restored from history. A resolve that outlives the thread it started in
|
|
316
|
+
* (cleared/replaced, or the adapter swapped) is dropped.
|
|
317
|
+
*/
|
|
318
|
+
async #handleMcpUiResource(event) {
|
|
319
|
+
const adapter = this.#adapter;
|
|
320
|
+
if (!adapter?.resolveMcpAppResource) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
const { toolCallId, resourceUri } = event;
|
|
324
|
+
const generation = this.#threadGeneration;
|
|
325
|
+
this.#mcpAppToolCallIds.add(toolCallId);
|
|
326
|
+
if (this.#presumedCompleteToolCallIds.delete(toolCallId)) {
|
|
327
|
+
this.#messageStateController.updateToolCallInResponse(toolCallId, {
|
|
328
|
+
status: "executing",
|
|
329
|
+
endTimestamp: void 0
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
let uiResource;
|
|
333
|
+
try {
|
|
334
|
+
uiResource = await adapter.resolveMcpAppResource({ resourceUri, toolCallId });
|
|
335
|
+
} catch (error) {
|
|
336
|
+
console.warn(`[forge-ai-mcp-app] Failed to resolve UI resource for tool call ${toolCallId}:`, error);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (!uiResource || adapter !== this.#adapter || generation !== this.#threadGeneration) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
if (this.#messageStateController.getToolCall(toolCallId)) {
|
|
343
|
+
this.#messageStateController.updateToolCallInResponse(toolCallId, { uiResource });
|
|
344
|
+
} else {
|
|
345
|
+
this.#pendingUiResources.set(toolCallId, uiResource);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
#takePendingUiResource(toolCallId) {
|
|
349
|
+
const uiResource = this.#pendingUiResources.get(toolCallId);
|
|
350
|
+
if (!uiResource) {
|
|
351
|
+
return {};
|
|
352
|
+
}
|
|
353
|
+
this.#pendingUiResources.delete(toolCallId);
|
|
354
|
+
return { uiResource };
|
|
355
|
+
}
|
|
277
356
|
async #sendToolResult(toolCallId, result) {
|
|
278
357
|
const toolCall = this.#messageStateController.getToolCall(toolCallId);
|
|
279
358
|
if (!toolCall || !this.#adapter) {
|
|
@@ -366,6 +445,10 @@ class ChatbotCoreController {
|
|
|
366
445
|
return this.#messageStateController.getToolCall(id);
|
|
367
446
|
}
|
|
368
447
|
clearMessages() {
|
|
448
|
+
this.#threadGeneration++;
|
|
449
|
+
this.#mcpAppToolCallIds.clear();
|
|
450
|
+
this.#presumedCompleteToolCallIds.clear();
|
|
451
|
+
this.#pendingUiResources.clear();
|
|
369
452
|
this.#messageStateController.clearMessages();
|
|
370
453
|
this.#fileUploadManager.clear();
|
|
371
454
|
}
|
|
@@ -373,13 +456,25 @@ class ChatbotCoreController {
|
|
|
373
456
|
return this.#messageStateController.getMessages();
|
|
374
457
|
}
|
|
375
458
|
setMessages(messages) {
|
|
459
|
+
this.#threadGeneration++;
|
|
460
|
+
this.#mcpAppToolCallIds.clear();
|
|
461
|
+
this.#presumedCompleteToolCallIds.clear();
|
|
462
|
+
this.#pendingUiResources.clear();
|
|
376
463
|
this.#messageStateController.setMessages(messages);
|
|
377
464
|
}
|
|
378
465
|
updateMessageContent(id, content) {
|
|
379
466
|
this.#messageStateController.updateMessageContent(id, content);
|
|
380
467
|
}
|
|
468
|
+
/** Tool call ids rendered at or after `index` in {@link messageItems}. */
|
|
469
|
+
getToolCallIdsFrom(index) {
|
|
470
|
+
return this.#messageStateController.getToolCallIdsFrom(index);
|
|
471
|
+
}
|
|
381
472
|
removeMessageItemsFrom(index) {
|
|
382
|
-
this.#messageStateController.removeMessageItemsFrom(index)
|
|
473
|
+
for (const id of this.#messageStateController.removeMessageItemsFrom(index)) {
|
|
474
|
+
this.#mcpAppToolCallIds.delete(id);
|
|
475
|
+
this.#presumedCompleteToolCallIds.delete(id);
|
|
476
|
+
this.#pendingUiResources.delete(id);
|
|
477
|
+
}
|
|
383
478
|
}
|
|
384
479
|
setResponseFeedback(responseId, feedback) {
|
|
385
480
|
this.#messageStateController.setResponseFeedback(responseId, feedback);
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ export * from './ai-agent-info';
|
|
|
5
5
|
export * from './ai-agent-selector';
|
|
6
6
|
export * from './ai-tool-call-indicator';
|
|
7
7
|
export * from './ai-artifact';
|
|
8
|
+
export * from './ai-artifact-card';
|
|
9
|
+
export * from './ai-artifact-card-group';
|
|
8
10
|
export * from './ai-attachment';
|
|
9
11
|
export * from './ai-button';
|
|
10
12
|
export * from './ai-chain-of-thought';
|
|
@@ -40,6 +42,7 @@ export * from './ai-response-message';
|
|
|
40
42
|
export * from './ai-sidebar';
|
|
41
43
|
export * from './ai-sidebar-chat';
|
|
42
44
|
export * from './ai-slash-command-menu';
|
|
45
|
+
export * from './ai-steps';
|
|
43
46
|
export * from './ai-suggestions';
|
|
44
47
|
export * from './ai-thinking-indicator';
|
|
45
48
|
export * from './ai-threads';
|