@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.
Files changed (41) hide show
  1. package/CHANGELOG.md +44 -1
  2. package/README.md +140 -6
  3. package/dist/ag-ui-web-component.bundle.js +145 -47
  4. package/dist/ag-ui-web-component.bundle.js.map +4 -4
  5. package/dist/core/ag_ui_chat.d.ts +16 -0
  6. package/dist/core/ag_ui_chat.d.ts.map +1 -1
  7. package/dist/core/agui_client.d.ts +16 -0
  8. package/dist/core/agui_client.d.ts.map +1 -1
  9. package/dist/index.d.ts +3 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +672 -228
  12. package/dist/index.js.map +3 -3
  13. package/dist/tools/page_action_tools.d.ts +31 -0
  14. package/dist/tools/page_action_tools.d.ts.map +1 -0
  15. package/dist/ui/attachment_tray.d.ts +3 -0
  16. package/dist/ui/attachment_tray.d.ts.map +1 -1
  17. package/dist/ui/confirmation_card.d.ts +4 -1
  18. package/dist/ui/confirmation_card.d.ts.map +1 -1
  19. package/dist/ui/relative_time.d.ts +5 -3
  20. package/dist/ui/relative_time.d.ts.map +1 -1
  21. package/dist/ui/styles.d.ts +1 -1
  22. package/dist/ui/styles.d.ts.map +1 -1
  23. package/dist/ui/thread_drawer.d.ts +7 -1
  24. package/dist/ui/thread_drawer.d.ts.map +1 -1
  25. package/dist/ui/tool_call_card.d.ts +6 -2
  26. package/dist/ui/tool_call_card.d.ts.map +1 -1
  27. package/dist/ui/ui_strings.d.ts +126 -0
  28. package/dist/ui/ui_strings.d.ts.map +1 -0
  29. package/package.json +1 -1
  30. package/src/core/ag_ui_chat.ts +213 -41
  31. package/src/core/agui_client.ts +33 -2
  32. package/src/index.ts +7 -0
  33. package/src/tools/page_action_tools.ts +130 -0
  34. package/src/ui/attachment_tray.ts +13 -7
  35. package/src/ui/confirmation_card.ts +15 -5
  36. package/src/ui/relative_time.ts +15 -8
  37. package/src/ui/styles.ts +98 -0
  38. package/src/ui/thread_drawer.ts +53 -25
  39. package/src/ui/tool_call_card.ts +40 -17
  40. package/src/ui/ui_strings.ts +208 -0
  41. package/src/version.ts +1 -1
@@ -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
- const STATUS_LABEL: Record<ToolCallStatus, string> = {
14
- [TOOL_CALL_STATUS.PENDING]: "running…",
15
- [TOOL_CALL_STATUS.DONE]: "✓ done",
16
- [TOOL_CALL_STATUS.ERROR]: "⚠ error",
17
- [TOOL_CALL_STATUS.DECLINED]: "⊘ declined",
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
- const RESULT_LABEL: Record<SettledStatus, string> = {
22
- [TOOL_CALL_STATUS.DONE]: "Result",
23
- [TOOL_CALL_STATUS.ERROR]: "Error",
24
- [TOOL_CALL_STATUS.DECLINED]: "Declined",
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.textContent = STATUS_LABEL[TOOL_CALL_STATUS.PENDING];
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 = STATUS_LABEL[status];
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 = "Details";
134
+ toggle.textContent = this.#strings.details;
112
135
  output.textContent = `args: ${JSON.stringify(this.#args)}\n\n${text}`;
113
136
  } else {
114
- toggle.textContent = RESULT_LABEL[status];
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.6.0";
1
+ export const VERSION: string = "0.7.0";