@artooi/ag-ui-web-component 0.6.0 → 0.7.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/CHANGELOG.md +44 -1
- package/README.md +140 -6
- package/dist/ag-ui-web-component.bundle.js +145 -47
- package/dist/ag-ui-web-component.bundle.js.map +4 -4
- package/dist/core/ag_ui_chat.d.ts +16 -0
- package/dist/core/ag_ui_chat.d.ts.map +1 -1
- package/dist/core/agui_client.d.ts +16 -0
- package/dist/core/agui_client.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +672 -228
- package/dist/index.js.map +3 -3
- package/dist/tools/page_action_tools.d.ts +31 -0
- package/dist/tools/page_action_tools.d.ts.map +1 -0
- package/dist/ui/attachment_tray.d.ts +3 -0
- package/dist/ui/attachment_tray.d.ts.map +1 -1
- package/dist/ui/confirmation_card.d.ts +4 -1
- package/dist/ui/confirmation_card.d.ts.map +1 -1
- package/dist/ui/relative_time.d.ts +5 -3
- package/dist/ui/relative_time.d.ts.map +1 -1
- package/dist/ui/styles.d.ts +1 -1
- package/dist/ui/styles.d.ts.map +1 -1
- package/dist/ui/thread_drawer.d.ts +7 -1
- package/dist/ui/thread_drawer.d.ts.map +1 -1
- package/dist/ui/tool_call_card.d.ts +6 -2
- package/dist/ui/tool_call_card.d.ts.map +1 -1
- package/dist/ui/ui_strings.d.ts +126 -0
- package/dist/ui/ui_strings.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/core/ag_ui_chat.ts +213 -41
- package/src/core/agui_client.ts +33 -2
- package/src/index.ts +7 -0
- package/src/tools/page_action_tools.ts +130 -0
- package/src/ui/attachment_tray.ts +13 -7
- package/src/ui/confirmation_card.ts +15 -5
- package/src/ui/relative_time.ts +15 -8
- package/src/ui/styles.ts +98 -0
- package/src/ui/thread_drawer.ts +53 -25
- package/src/ui/tool_call_card.ts +40 -17
- package/src/ui/ui_strings.ts +208 -0
- package/src/version.ts +1 -1
package/src/ui/tool_call_card.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TOOL_CALL_STATUS, TOOL_DISPLAY } from "../constants.js";
|
|
2
|
+
import { DEFAULT_UI_STRINGS, type UiStrings } from "./ui_strings.js";
|
|
2
3
|
|
|
3
4
|
/** Any state a tool-call card can be in. */
|
|
4
5
|
export type ToolCallStatus = (typeof TOOL_CALL_STATUS)[keyof typeof TOOL_CALL_STATUS];
|
|
@@ -9,20 +10,24 @@ export type ToolDisplayMode = (typeof TOOL_DISPLAY)[keyof typeof TOOL_DISPLAY];
|
|
|
9
10
|
/** The terminal states a card settles into (everything but `pending`). */
|
|
10
11
|
export type SettledStatus = Exclude<ToolCallStatus, typeof TOOL_CALL_STATUS.PENDING>;
|
|
11
12
|
|
|
12
|
-
/** Short pill text shown for each status. */
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
/** Short pill text shown for each status, drawn from the string table. */
|
|
14
|
+
function statusLabels(strings: UiStrings): Record<ToolCallStatus, string> {
|
|
15
|
+
return {
|
|
16
|
+
[TOOL_CALL_STATUS.PENDING]: strings.toolRunning,
|
|
17
|
+
[TOOL_CALL_STATUS.DONE]: strings.toolDone,
|
|
18
|
+
[TOOL_CALL_STATUS.ERROR]: strings.toolError,
|
|
19
|
+
[TOOL_CALL_STATUS.DECLINED]: strings.toolDeclined,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
19
22
|
|
|
20
23
|
/** Toggle-button label for each settled outcome's collapsible body (full mode). */
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
function resultLabels(strings: UiStrings): Record<SettledStatus, string> {
|
|
25
|
+
return {
|
|
26
|
+
[TOOL_CALL_STATUS.DONE]: strings.resultLabel,
|
|
27
|
+
[TOOL_CALL_STATUS.ERROR]: strings.errorLabel,
|
|
28
|
+
[TOOL_CALL_STATUS.DECLINED]: strings.declinedLabel,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
26
31
|
|
|
27
32
|
/**
|
|
28
33
|
* A live tool-call card for the chat transcript.
|
|
@@ -37,7 +42,8 @@ const RESULT_LABEL: Record<SettledStatus, string> = {
|
|
|
37
42
|
* - `full` — the result (or error / decline message) behind its own toggle.
|
|
38
43
|
*
|
|
39
44
|
* Pure DOM (no framework); the host appends {@link element} into its shadow
|
|
40
|
-
* root and themes it via the `--ag-ui-*` custom properties
|
|
45
|
+
* root and themes it via the `--ag-ui-*` custom properties or the exposed
|
|
46
|
+
* `tool-card*` `part`s. All visible text is sourced from {@link UiStrings}.
|
|
41
47
|
*/
|
|
42
48
|
export class ToolCallCard {
|
|
43
49
|
/** The card's root element; append this into the message list. */
|
|
@@ -46,33 +52,41 @@ export class ToolCallCard {
|
|
|
46
52
|
readonly #status: HTMLSpanElement;
|
|
47
53
|
readonly #mode: ToolDisplayMode;
|
|
48
54
|
readonly #args: Record<string, unknown>;
|
|
55
|
+
readonly #strings: UiStrings;
|
|
56
|
+
#settled = false;
|
|
49
57
|
|
|
50
58
|
constructor(
|
|
51
59
|
name: string,
|
|
52
60
|
args: Record<string, unknown>,
|
|
53
61
|
mode: ToolDisplayMode = TOOL_DISPLAY.FULL,
|
|
54
62
|
summary?: string,
|
|
63
|
+
strings: UiStrings = DEFAULT_UI_STRINGS,
|
|
55
64
|
) {
|
|
56
65
|
this.#mode = mode;
|
|
57
66
|
this.#args = args;
|
|
67
|
+
this.#strings = strings;
|
|
58
68
|
|
|
59
69
|
this.element = document.createElement("div");
|
|
60
70
|
this.element.className = "tool-call";
|
|
71
|
+
this.element.setAttribute("part", "tool-card");
|
|
61
72
|
this.element.setAttribute("data-tool-name", name);
|
|
62
73
|
this.element.setAttribute("data-status", TOOL_CALL_STATUS.PENDING);
|
|
63
74
|
this.element.setAttribute("data-display", mode);
|
|
64
75
|
|
|
65
76
|
const head = document.createElement("div");
|
|
66
77
|
head.className = "tool-call-head";
|
|
78
|
+
head.setAttribute("part", "tool-card-head");
|
|
67
79
|
|
|
68
80
|
const label = document.createElement("span");
|
|
69
81
|
label.className = "tool-call-name";
|
|
82
|
+
label.setAttribute("part", "tool-card-name");
|
|
70
83
|
// A server-provided `x-summary` label reads better than the raw tool name.
|
|
71
84
|
label.textContent = `🔧 ${summary ?? name}`;
|
|
72
85
|
|
|
73
86
|
this.#status = document.createElement("span");
|
|
74
87
|
this.#status.className = "tool-call-status";
|
|
75
|
-
this.#status.
|
|
88
|
+
this.#status.setAttribute("part", "tool-card-status");
|
|
89
|
+
this.#status.textContent = statusLabels(strings)[TOOL_CALL_STATUS.PENDING];
|
|
76
90
|
|
|
77
91
|
head.append(label, this.#status);
|
|
78
92
|
this.element.append(head);
|
|
@@ -80,19 +94,26 @@ export class ToolCallCard {
|
|
|
80
94
|
if (mode === TOOL_DISPLAY.FULL) {
|
|
81
95
|
const argsEl = document.createElement("pre");
|
|
82
96
|
argsEl.className = "tool-call-args";
|
|
97
|
+
argsEl.setAttribute("part", "tool-card-args");
|
|
83
98
|
argsEl.textContent = JSON.stringify(args, null, 2);
|
|
84
99
|
this.element.append(argsEl);
|
|
85
100
|
}
|
|
86
101
|
}
|
|
87
102
|
|
|
103
|
+
/** Whether {@link settle} has already run (so a terminal sweep can skip it). */
|
|
104
|
+
get settled(): boolean {
|
|
105
|
+
return this.#settled;
|
|
106
|
+
}
|
|
107
|
+
|
|
88
108
|
/**
|
|
89
109
|
* Flip the status pill to ``status`` and, unless in `minimal` mode, append a
|
|
90
110
|
* collapsed body behind a click-to-expand toggle: the result alone (`full`),
|
|
91
111
|
* or the args + result together (`compact`).
|
|
92
112
|
*/
|
|
93
113
|
settle(status: SettledStatus, text: string): void {
|
|
114
|
+
this.#settled = true;
|
|
94
115
|
this.element.setAttribute("data-status", status);
|
|
95
|
-
this.#status.textContent =
|
|
116
|
+
this.#status.textContent = statusLabels(this.#strings)[status];
|
|
96
117
|
|
|
97
118
|
if (this.#mode === TOOL_DISPLAY.MINIMAL) {
|
|
98
119
|
return;
|
|
@@ -101,17 +122,19 @@ export class ToolCallCard {
|
|
|
101
122
|
const toggle = document.createElement("button");
|
|
102
123
|
toggle.type = "button";
|
|
103
124
|
toggle.className = "tool-call-toggle";
|
|
125
|
+
toggle.setAttribute("part", "tool-card-toggle");
|
|
104
126
|
toggle.setAttribute("aria-expanded", "false");
|
|
105
127
|
|
|
106
128
|
const output = document.createElement("pre");
|
|
107
129
|
output.className = "tool-call-result";
|
|
130
|
+
output.setAttribute("part", "tool-card-result");
|
|
108
131
|
output.hidden = true;
|
|
109
132
|
|
|
110
133
|
if (this.#mode === TOOL_DISPLAY.COMPACT) {
|
|
111
|
-
toggle.textContent =
|
|
134
|
+
toggle.textContent = this.#strings.details;
|
|
112
135
|
output.textContent = `args: ${JSON.stringify(this.#args)}\n\n${text}`;
|
|
113
136
|
} else {
|
|
114
|
-
toggle.textContent =
|
|
137
|
+
toggle.textContent = resultLabels(this.#strings)[status];
|
|
115
138
|
output.textContent = text;
|
|
116
139
|
}
|
|
117
140
|
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The flat table of every user-facing string the chat shell renders — labels,
|
|
3
|
+
* placeholders, `aria-label`s, and `title` tooltips. A localizable seam, not a
|
|
4
|
+
* framework: a host overrides any subset (via the element's `strings` property
|
|
5
|
+
* or its `data-strings` JSON attribute) and the rest fall back to the English
|
|
6
|
+
* defaults.
|
|
7
|
+
*
|
|
8
|
+
* A handful of values are **templates** carrying `{token}` placeholders the call
|
|
9
|
+
* site fills in (e.g. `minutesAgo` → `"{n}m ago"`); the token names are noted on
|
|
10
|
+
* each key. Translators keep the token verbatim.
|
|
11
|
+
*
|
|
12
|
+
* This module is one cohesive unit — the `UiStrings` shape, its `DEFAULT_UI_STRINGS`
|
|
13
|
+
* constant-like backing, and the {@link mergeUiStrings} merge over those defaults —
|
|
14
|
+
* so it bends the one-symbol-per-file rule the way `tool_call_card.ts` (class +
|
|
15
|
+
* its types) and `route_map.ts` (factory + its types) already do.
|
|
16
|
+
*/
|
|
17
|
+
export interface UiStrings {
|
|
18
|
+
// ── Header ────────────────────────────────────────────────────────────────
|
|
19
|
+
/** Default header title (the `title-text` attribute overrides per element). */
|
|
20
|
+
title: string;
|
|
21
|
+
/** History button + drawer dialog label. */
|
|
22
|
+
chatHistory: string;
|
|
23
|
+
/** New-chat button (header + drawer). */
|
|
24
|
+
newChat: string;
|
|
25
|
+
/** Collapse button. */
|
|
26
|
+
collapse: string;
|
|
27
|
+
/** Expand affordance (the sidebar rail toggle). */
|
|
28
|
+
expand: string;
|
|
29
|
+
|
|
30
|
+
// ── Messages region ─────────────────────────────────────────────────────────
|
|
31
|
+
/** `aria-label` of the scrolling message log. */
|
|
32
|
+
conversation: string;
|
|
33
|
+
/** `aria-label` of the "thinking" pending indicator. */
|
|
34
|
+
thinking: string;
|
|
35
|
+
/** The muted note after a cancelled run. */
|
|
36
|
+
stopped: string;
|
|
37
|
+
/** Error shown when the stream drops without a terminal AG-UI event. */
|
|
38
|
+
connectionLost: string;
|
|
39
|
+
/** Fallback when a tool call produced no result. */
|
|
40
|
+
noResult: string;
|
|
41
|
+
/** Tool-result content when the user declines a confirmed action. */
|
|
42
|
+
declinedAction: string;
|
|
43
|
+
/** A navigating tool's card text while the page reloads. */
|
|
44
|
+
navigating: string;
|
|
45
|
+
/** Missing-placeholder skill hint. Tokens: `{title}`, `{fields}`. */
|
|
46
|
+
skillNeeds: string;
|
|
47
|
+
|
|
48
|
+
// ── Composer ────────────────────────────────────────────────────────────────
|
|
49
|
+
/** `aria-label` of the message textarea. */
|
|
50
|
+
message: string;
|
|
51
|
+
/** Placeholder of the message textarea. */
|
|
52
|
+
inputPlaceholder: string;
|
|
53
|
+
/** Send button (idle composer). */
|
|
54
|
+
send: string;
|
|
55
|
+
/** Stop button (composer while a run is in flight). */
|
|
56
|
+
stop: string;
|
|
57
|
+
/** Attach-files button. */
|
|
58
|
+
attachFiles: string;
|
|
59
|
+
|
|
60
|
+
// ── Tool-call card ──────────────────────────────────────────────────────────
|
|
61
|
+
/** Status pill while the call runs. */
|
|
62
|
+
toolRunning: string;
|
|
63
|
+
/** Status pill on success. */
|
|
64
|
+
toolDone: string;
|
|
65
|
+
/** Status pill on error. */
|
|
66
|
+
toolError: string;
|
|
67
|
+
/** Status pill on a declined call. */
|
|
68
|
+
toolDeclined: string;
|
|
69
|
+
/** Toggle label revealing a successful result (full mode). */
|
|
70
|
+
resultLabel: string;
|
|
71
|
+
/** Toggle label revealing an error (full mode). */
|
|
72
|
+
errorLabel: string;
|
|
73
|
+
/** Toggle label revealing a declined call (full mode). */
|
|
74
|
+
declinedLabel: string;
|
|
75
|
+
/** Toggle label revealing args + result together (compact mode). */
|
|
76
|
+
details: string;
|
|
77
|
+
|
|
78
|
+
// ── Confirmation card ───────────────────────────────────────────────────────
|
|
79
|
+
/** `aria-label` of the inline confirmation card. */
|
|
80
|
+
confirmAction: string;
|
|
81
|
+
/** Generic confirmation prompt when a tool has no `x-confirm`. Token: `{tool}`. */
|
|
82
|
+
confirmRun: string;
|
|
83
|
+
/** Confirm button. */
|
|
84
|
+
confirm: string;
|
|
85
|
+
/** Cancel button (confirmation + delete confirm). */
|
|
86
|
+
cancel: string;
|
|
87
|
+
|
|
88
|
+
// ── Chat-history drawer ─────────────────────────────────────────────────────
|
|
89
|
+
/** Drawer heading. */
|
|
90
|
+
chats: string;
|
|
91
|
+
/** Empty-state line when there are no threads. */
|
|
92
|
+
noConversations: string;
|
|
93
|
+
/** Rename row button (`title`). */
|
|
94
|
+
rename: string;
|
|
95
|
+
/** Rename row button `aria-label`. */
|
|
96
|
+
renameConversation: string;
|
|
97
|
+
/** Delete row button (`title`) + the inline-confirm action. */
|
|
98
|
+
delete: string;
|
|
99
|
+
/** Delete row button `aria-label`. */
|
|
100
|
+
deleteConversation: string;
|
|
101
|
+
/** Inline delete-confirm prompt. */
|
|
102
|
+
deletePrompt: string;
|
|
103
|
+
|
|
104
|
+
// ── Attachments ─────────────────────────────────────────────────────────────
|
|
105
|
+
/** Oversize rejection. Token: `{size}`. */
|
|
106
|
+
tooLarge: string;
|
|
107
|
+
/** Disallowed-type rejection. */
|
|
108
|
+
fileTypeNotAllowed: string;
|
|
109
|
+
/** Generic upload failure (when the error carries no message). */
|
|
110
|
+
uploadFailed: string;
|
|
111
|
+
/** Retry-upload button (`title`). */
|
|
112
|
+
retry: string;
|
|
113
|
+
/** Retry-upload button `aria-label`. */
|
|
114
|
+
retryUpload: string;
|
|
115
|
+
/** Remove-attachment button (`title`). */
|
|
116
|
+
remove: string;
|
|
117
|
+
/** Remove-attachment button `aria-label`. */
|
|
118
|
+
removeAttachment: string;
|
|
119
|
+
|
|
120
|
+
// ── Relative time (drawer rows) ─────────────────────────────────────────────
|
|
121
|
+
/** Under a minute ago. */
|
|
122
|
+
justNow: string;
|
|
123
|
+
/** Minutes ago. Token: `{n}`. */
|
|
124
|
+
minutesAgo: string;
|
|
125
|
+
/** Hours ago. Token: `{n}`. */
|
|
126
|
+
hoursAgo: string;
|
|
127
|
+
/** Days ago. Token: `{n}`. */
|
|
128
|
+
daysAgo: string;
|
|
129
|
+
/** Weeks ago. Token: `{n}`. */
|
|
130
|
+
weeksAgo: string;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** The built-in English strings — the fallback every override merges over. */
|
|
134
|
+
export const DEFAULT_UI_STRINGS: UiStrings = {
|
|
135
|
+
title: "Assistant",
|
|
136
|
+
chatHistory: "Chat history",
|
|
137
|
+
newChat: "New chat",
|
|
138
|
+
collapse: "Collapse",
|
|
139
|
+
expand: "Expand",
|
|
140
|
+
|
|
141
|
+
conversation: "Conversation",
|
|
142
|
+
thinking: "Assistant is thinking…",
|
|
143
|
+
stopped: "⏹ Stopped",
|
|
144
|
+
connectionLost: "Connection lost",
|
|
145
|
+
noResult: "No result returned.",
|
|
146
|
+
declinedAction: "User declined the action.",
|
|
147
|
+
navigating: "Navigating…",
|
|
148
|
+
skillNeeds: "“{title}” needs: {fields}",
|
|
149
|
+
|
|
150
|
+
message: "Message",
|
|
151
|
+
inputPlaceholder: "Ask anything…",
|
|
152
|
+
send: "Send",
|
|
153
|
+
stop: "Stop",
|
|
154
|
+
attachFiles: "Attach files",
|
|
155
|
+
|
|
156
|
+
toolRunning: "running…",
|
|
157
|
+
toolDone: "✓ done",
|
|
158
|
+
toolError: "⚠ error",
|
|
159
|
+
toolDeclined: "⊘ declined",
|
|
160
|
+
resultLabel: "Result",
|
|
161
|
+
errorLabel: "Error",
|
|
162
|
+
declinedLabel: "Declined",
|
|
163
|
+
details: "Details",
|
|
164
|
+
|
|
165
|
+
confirmAction: "Confirm action",
|
|
166
|
+
confirmRun: "Run “{tool}”?",
|
|
167
|
+
confirm: "Confirm",
|
|
168
|
+
cancel: "Cancel",
|
|
169
|
+
|
|
170
|
+
chats: "Chats",
|
|
171
|
+
noConversations: "No conversations yet.",
|
|
172
|
+
rename: "Rename",
|
|
173
|
+
renameConversation: "Rename conversation",
|
|
174
|
+
delete: "Delete",
|
|
175
|
+
deleteConversation: "Delete conversation",
|
|
176
|
+
deletePrompt: "Delete?",
|
|
177
|
+
|
|
178
|
+
tooLarge: "Too large (max {size})",
|
|
179
|
+
fileTypeNotAllowed: "File type not allowed",
|
|
180
|
+
uploadFailed: "upload failed",
|
|
181
|
+
retry: "Retry",
|
|
182
|
+
retryUpload: "Retry upload",
|
|
183
|
+
remove: "Remove",
|
|
184
|
+
removeAttachment: "Remove attachment",
|
|
185
|
+
|
|
186
|
+
justNow: "just now",
|
|
187
|
+
minutesAgo: "{n}m ago",
|
|
188
|
+
hoursAgo: "{n}h ago",
|
|
189
|
+
daysAgo: "{n}d ago",
|
|
190
|
+
weeksAgo: "{n}w ago",
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Merge a partial set of overrides over {@link DEFAULT_UI_STRINGS}, yielding a
|
|
195
|
+
* complete {@link UiStrings}. Keys whose override is `undefined` keep the
|
|
196
|
+
* default (so a `data-strings` JSON with only a few keys — or a property carrying
|
|
197
|
+
* explicit `undefined` — leaves the rest English).
|
|
198
|
+
*/
|
|
199
|
+
export function mergeUiStrings(overrides: Partial<UiStrings>): UiStrings {
|
|
200
|
+
const merged: UiStrings = { ...DEFAULT_UI_STRINGS };
|
|
201
|
+
for (const key of Object.keys(overrides) as (keyof UiStrings)[]) {
|
|
202
|
+
const value = overrides[key];
|
|
203
|
+
if (value !== undefined) {
|
|
204
|
+
merged[key] = value;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return merged;
|
|
208
|
+
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION: string = "0.
|
|
1
|
+
export const VERSION: string = "0.7.0";
|