@artooi/ag-ui-web-component 0.12.0 → 0.14.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/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  var ELEMENT_TAG = "ag-ui-chat";
3
3
  var SUBMIT_EVENT = "ag-ui-submit";
4
4
  var TOGGLE_EVENT = "ag-ui-toggle";
5
+ var STATE_EVENT = "ag-ui-state";
5
6
  var MESSAGE_ROLE = {
6
7
  USER: "user",
7
8
  ASSISTANT: "assistant"
@@ -29,6 +30,8 @@ var TOOL_DISPLAY = {
29
30
  COMPACT: "compact",
30
31
  FULL: "full"
31
32
  };
33
+ var COMPACTION_ACTIVITY_TYPE = "compaction";
34
+ var LOAD_CAPABILITY_TOOL = "load_capability";
32
35
 
33
36
  // src/skills/fill_template.ts
34
37
  var PLACEHOLDER_RE = /\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g;
@@ -318,6 +321,38 @@ function createPageMapContext(getPageMap, autoInject) {
318
321
  return [{ description: "page_map", value: JSON.stringify(getPageMap()) }];
319
322
  }
320
323
 
324
+ // src/tools/page_state.ts
325
+ function createPageStateTools(binding) {
326
+ const tools = [
327
+ {
328
+ name: `read_${binding.name}`,
329
+ description: `Read the "${binding.name}" state.`,
330
+ parameters: {
331
+ type: "object",
332
+ properties: {},
333
+ required: [],
334
+ [X_SUMMARY_KEY]: `Read ${binding.name}`
335
+ },
336
+ handler: () => binding.read()
337
+ }
338
+ ];
339
+ const write = binding.write;
340
+ if (write !== void 0) {
341
+ tools.push({
342
+ name: `set_${binding.name}`,
343
+ description: `Update the "${binding.name}" state.`,
344
+ parameters: {
345
+ ...binding.schema ?? { type: "object" },
346
+ [X_DESTRUCTIVE_KEY]: true,
347
+ [X_SUMMARY_KEY]: `Update ${binding.name}`
348
+ },
349
+ handler: (args) => write(args)
350
+ });
351
+ }
352
+ return tools;
353
+ }
354
+ var createStateHookTools = createPageStateTools;
355
+
321
356
  // src/tools/parse_tool_catalog.ts
322
357
  function parseToolCatalog(data) {
323
358
  const out = {};
@@ -412,37 +447,6 @@ function createRouteTools(getRouteMap, getNavigate) {
412
447
  ];
413
448
  }
414
449
 
415
- // src/tools/state_hook.ts
416
- function createStateHookTools(hook) {
417
- const tools = [
418
- {
419
- name: `read_${hook.name}`,
420
- description: `Read the "${hook.name}" state.`,
421
- parameters: {
422
- type: "object",
423
- properties: {},
424
- required: [],
425
- [X_SUMMARY_KEY]: `Read ${hook.name}`
426
- },
427
- handler: () => hook.read()
428
- }
429
- ];
430
- const write = hook.write;
431
- if (write !== void 0) {
432
- tools.push({
433
- name: `set_${hook.name}`,
434
- description: `Update the "${hook.name}" state.`,
435
- parameters: {
436
- ...hook.schema ?? { type: "object" },
437
- [X_DESTRUCTIVE_KEY]: true,
438
- [X_SUMMARY_KEY]: `Update ${hook.name}`
439
- },
440
- handler: (args) => write(args)
441
- });
442
- }
443
- return tools;
444
- }
445
-
446
450
  // src/ui/ui_strings.ts
447
451
  var DEFAULT_UI_STRINGS = {
448
452
  title: "Assistant",
@@ -464,6 +468,8 @@ var DEFAULT_UI_STRINGS = {
464
468
  noResult: "No result returned.",
465
469
  declinedAction: "User declined the action.",
466
470
  navigating: "Navigating\u2026",
471
+ historyCompacted: "Earlier turns condensed to fit the context window ({count} removed)",
472
+ usingSkill: "Using skill {name}",
467
473
  skillNeeds: "\u201C{title}\u201D needs: {fields}",
468
474
  message: "Message",
469
475
  inputPlaceholder: "Ask anything\u2026",
@@ -3713,6 +3719,25 @@ function wrapWords(root) {
3713
3719
  }
3714
3720
  }
3715
3721
 
3722
+ // src/ui/run_notice.ts
3723
+ function renderRunNotice(icon, text2, kind) {
3724
+ const notice = document.createElement("div");
3725
+ notice.className = `run-notice run-notice--${kind}`;
3726
+ notice.setAttribute("part", `run-notice run-notice-${kind}`);
3727
+ notice.setAttribute("role", "status");
3728
+ const glyph = document.createElement("span");
3729
+ glyph.className = "run-notice-icon";
3730
+ glyph.setAttribute("part", "run-notice-icon");
3731
+ glyph.textContent = icon;
3732
+ glyph.setAttribute("aria-hidden", "true");
3733
+ const label = document.createElement("span");
3734
+ label.className = "run-notice-text";
3735
+ label.setAttribute("part", "run-notice-text");
3736
+ label.textContent = text2;
3737
+ notice.append(glyph, label);
3738
+ return notice;
3739
+ }
3740
+
3716
3741
  // src/ui/skills_menu.ts
3717
3742
  var SkillsMenu = class {
3718
3743
  /** Chips row — append above the input. Hidden unless chips are enabled and present. */
@@ -4746,6 +4771,32 @@ var STYLES = `
4746
4771
  margin-top: 6px;
4747
4772
  }
4748
4773
 
4774
+ .run-notice {
4775
+ display: inline-flex;
4776
+ align-items: center;
4777
+ gap: 6px;
4778
+ align-self: flex-start;
4779
+ max-width: 100%;
4780
+ margin: 2px 0;
4781
+ padding: 3px 10px;
4782
+ border: 1px dashed var(--ag-ui-border);
4783
+ border-radius: 999px;
4784
+ background: transparent;
4785
+ color: var(--ag-ui-muted);
4786
+ font-size: 0.8em;
4787
+ line-height: 1.4;
4788
+ }
4789
+
4790
+ .run-notice-icon {
4791
+ flex: none;
4792
+ opacity: 0.75;
4793
+ }
4794
+
4795
+ .run-notice-text {
4796
+ min-width: 0;
4797
+ overflow-wrap: anywhere;
4798
+ }
4799
+
4749
4800
  .attachment-chip {
4750
4801
  display: inline-flex;
4751
4802
  align-items: center;
@@ -5917,6 +5968,22 @@ var AgUiClient = class {
5917
5968
  this.#onPersist = config.onPersist ?? (() => {
5918
5969
  });
5919
5970
  this.#connectionLostMessage = config.connectionLostMessage ?? "Connection lost";
5971
+ const onStateChanged = config.onStateChanged;
5972
+ if (onStateChanged !== void 0) {
5973
+ this.#agent.subscribe({
5974
+ onStateChanged: ({ state }) => {
5975
+ onStateChanged(state);
5976
+ }
5977
+ });
5978
+ }
5979
+ }
5980
+ /** The current AG-UI shared state, as the agent last applied it. */
5981
+ get state() {
5982
+ return this.#agent.state;
5983
+ }
5984
+ /** Replace the shared state; the next run sends it as `RunAgentInput.state`. */
5985
+ setState(state) {
5986
+ this.#agent.setState({ ...state });
5920
5987
  }
5921
5988
  /** Whether a run is currently in flight. */
5922
5989
  get running() {
@@ -6080,6 +6147,9 @@ var AgUiClient = class {
6080
6147
  onToolCallResultEvent({ event }) {
6081
6148
  h.onToolResult(event.toolCallId, event.content);
6082
6149
  },
6150
+ onActivitySnapshotEvent({ event }) {
6151
+ h.onActivity(event.activityType, event.content);
6152
+ },
6083
6153
  // Reasoning. `@ag-ui/client` already maps the deprecated
6084
6154
  // THINKING_* events onto these REASONING_* callbacks, so handling the
6085
6155
  // reasoning family alone covers both protocol versions.
@@ -6314,6 +6384,7 @@ function createHttpAgent(options) {
6314
6384
  return new HttpAgent({
6315
6385
  url: options.endpoint,
6316
6386
  headers: options.headers ?? {},
6387
+ initialState: { ...options.initialState ?? {} },
6317
6388
  // HttpAgent invokes its configured fetch as a method (`this.fetch(...)`),
6318
6389
  // which would rebind the global `fetch` to the agent instance and trigger
6319
6390
  // "Illegal invocation" in browsers. Wrap it so `fetch` is always called as
@@ -6647,7 +6718,7 @@ var AgUiChat = class extends HTMLElement {
6647
6718
  /**
6648
6719
  * Per-run frontend tool catalog provider. Defaults to the built-in
6649
6720
  * `route.*` tools (when a {@link routeMap} is set) plus the tools registered
6650
- * via {@link registerTool} / {@link registerStateHook}; override to supply a
6721
+ * via {@link registerTool} / {@link registerPageState}; override to supply a
6651
6722
  * fully custom catalog.
6652
6723
  */
6653
6724
  getTools = () => [
@@ -6795,6 +6866,10 @@ var AgUiChat = class extends HTMLElement {
6795
6866
  /** Refs attached to the message currently being sent (the context manifest). */
6796
6867
  #runAttachments = [];
6797
6868
  #client = null;
6869
+ // Seed for the next client. Once one exists it owns the live value (the
6870
+ // agent applies STATE_SNAPSHOT / STATE_DELTA into it), so this is only the
6871
+ // starting point — `sharedState` reads through to the client when present.
6872
+ #sharedState = {};
6798
6873
  // Whether an interaction is in flight (first onRunStart → onSettled). Drives
6799
6874
  // the Send⇄Stop button: `agent.isRunning` is false between frontend-tool
6800
6875
  // rounds, but the user must still be able to stop there.
@@ -6941,12 +7016,40 @@ var AgUiChat = class extends HTMLElement {
6941
7016
  registerTool(tool) {
6942
7017
  this.#toolRegistry.register(tool);
6943
7018
  }
6944
- /** Bind a piece of host state to `read_<name>` / `set_<name>` tools. */
6945
- registerStateHook(hook) {
6946
- for (const tool of createStateHookTools(hook)) {
7019
+ /**
7020
+ * AG-UI **shared state** for this conversation — the protocol's own state
7021
+ * channel, sent as `RunAgentInput.state` on every run and replaced in place
7022
+ * when the server streams `STATE_SNAPSHOT` / `STATE_DELTA`. Assigning seeds
7023
+ * the next run; reading returns whatever the agent last applied.
7024
+ *
7025
+ * Listen for {@link STATE_EVENT} to react to server-driven changes.
7026
+ *
7027
+ * Not to be confused with {@link registerPageState}, which exposes host
7028
+ * state to the agent as ordinary *tools*.
7029
+ */
7030
+ get sharedState() {
7031
+ return this.#client?.state ?? this.#sharedState;
7032
+ }
7033
+ set sharedState(state) {
7034
+ this.#sharedState = { ...state };
7035
+ this.#client?.setState(this.#sharedState);
7036
+ }
7037
+ /** Bind a piece of host page state to `read_<name>` / `set_<name>` tools. */
7038
+ registerPageState(binding) {
7039
+ for (const tool of createPageStateTools(binding)) {
6947
7040
  this.#toolRegistry.register(tool);
6948
7041
  }
6949
7042
  }
7043
+ /**
7044
+ * @deprecated Renamed to {@link registerPageState}. The old name read as
7045
+ * AG-UI shared-state sync (`STATE_SNAPSHOT` / `STATE_DELTA`), which this
7046
+ * component does not implement — these are ordinary client tools over host
7047
+ * page state. Behaviour is unchanged; this alias will be removed in a future
7048
+ * major.
7049
+ */
7050
+ registerStateHook(binding) {
7051
+ this.registerPageState(binding);
7052
+ }
6950
7053
  /** The built-in `route.*` tools, present only when a route map is set. */
6951
7054
  #routeTools() {
6952
7055
  if (this.routeMap.length === 0) {
@@ -7537,11 +7640,15 @@ Use the read_attachment tool with an id to read a file's contents.`
7537
7640
  const toolCalls = message.toolCalls;
7538
7641
  if (toolCalls !== void 0) {
7539
7642
  for (const call of toolCalls) {
7540
- this.#cardFor({
7643
+ const restored = {
7541
7644
  id: call.id,
7542
7645
  name: call.function.name,
7543
7646
  args: this.#parseArgs(call.function.arguments)
7544
- });
7647
+ };
7648
+ if (this.#noticeIfSkillLoad(restored)) {
7649
+ continue;
7650
+ }
7651
+ this.#cardFor(restored);
7545
7652
  }
7546
7653
  }
7547
7654
  return;
@@ -7872,7 +7979,8 @@ Use the read_attachment tool with an id to read a file's contents.`
7872
7979
  // re-reads this on each call.
7873
7980
  getHeaders: () => this.headers,
7874
7981
  threadId: this.#threadId,
7875
- initialMessages: this.#initialMessages
7982
+ initialMessages: this.#initialMessages,
7983
+ initialState: this.#sharedState
7876
7984
  });
7877
7985
  this.#client = new AgUiClient({
7878
7986
  agent,
@@ -7882,11 +7990,23 @@ Use the read_attachment tool with an id to read a file's contents.`
7882
7990
  executeTool: (call) => this.#executeTool(call),
7883
7991
  resolveInterrupts: (interrupts) => this.#resolveInterrupts(interrupts),
7884
7992
  onPersist: (messages) => this.conversationStore.saveMessages(this.#threadId, messages),
7993
+ onStateChanged: (state) => this.#onSharedStateChanged(state),
7885
7994
  connectionLostMessage: this.#strings.connectionLost
7886
7995
  });
7887
7996
  }
7888
7997
  return this.#client;
7889
7998
  }
7999
+ /** Mirror the agent's applied state and tell the host it moved. */
8000
+ #onSharedStateChanged(state) {
8001
+ this.#sharedState = { ...state };
8002
+ this.dispatchEvent(
8003
+ new CustomEvent(STATE_EVENT, {
8004
+ detail: { state: this.#sharedState },
8005
+ bubbles: true,
8006
+ composed: true
8007
+ })
8008
+ );
8009
+ }
7890
8010
  /** Whether ``call`` should be gated behind the confirmation card. */
7891
8011
  async #needsConfirmation(call, tool) {
7892
8012
  if (this.autoConfirm) {
@@ -7898,6 +8018,9 @@ Use the read_attachment tool with an id to read a file's contents.`
7898
8018
  return isDestructive(tool.parameters);
7899
8019
  }
7900
8020
  async #executeTool(call) {
8021
+ if (skillNameFrom(call) !== null) {
8022
+ return null;
8023
+ }
7901
8024
  const card = this.#cardFor(call);
7902
8025
  this.#toolCards.delete(call.id);
7903
8026
  const tool = this.#resolveTool(call.name);
@@ -8023,8 +8146,25 @@ Use the read_attachment tool with an id to read a file's contents.`
8023
8146
  },
8024
8147
  onToolCall: (call) => {
8025
8148
  this.#hidePending();
8149
+ if (this.#noticeIfSkillLoad(call)) {
8150
+ return;
8151
+ }
8026
8152
  this.#cardFor(call);
8027
8153
  },
8154
+ onActivity: (activityType, content) => {
8155
+ if (activityType !== COMPACTION_ACTIVITY_TYPE) {
8156
+ return;
8157
+ }
8158
+ const removed = compactionRemoved(content);
8159
+ if (removed === null) {
8160
+ return;
8161
+ }
8162
+ this.#appendNotice(
8163
+ "\u{1F5DC}",
8164
+ this.#strings.historyCompacted.replace("{count}", String(removed)),
8165
+ "compaction"
8166
+ );
8167
+ },
8028
8168
  onToolResult: (toolCallId, content) => {
8029
8169
  const card = this.#toolCards.get(toolCallId);
8030
8170
  if (card === void 0) {
@@ -8136,6 +8276,32 @@ Use the read_attachment tool with an id to read a file's contents.`
8136
8276
  * {@link AgUiClientHandlers.onToolCall} creates the card (pending) during the
8137
8277
  * run; {@link #executeTool} later retrieves the same card to settle it.
8138
8278
  */
8279
+ /**
8280
+ * Append an ambient run notice to the current group.
8281
+ *
8282
+ * Goes through {@link #ensureGroup} like a tool card so it lands *inside* the
8283
+ * assistant turn it annotates rather than floating between turns, and shares
8284
+ * the same pending-hide / scroll behaviour.
8285
+ */
8286
+ /**
8287
+ * Render a skill notice for a `load_capability` call; ``true`` when handled.
8288
+ *
8289
+ * Shared by the live stream and history replay so the transcript looks the
8290
+ * same before and after a reload.
8291
+ */
8292
+ #noticeIfSkillLoad(call) {
8293
+ const skill = skillNameFrom(call);
8294
+ if (skill === null) {
8295
+ return false;
8296
+ }
8297
+ this.#appendNotice("\u2728", this.#strings.usingSkill.replace("{name}", skill), "skill");
8298
+ return true;
8299
+ }
8300
+ #appendNotice(icon, text2, kind) {
8301
+ this.#ensureGroup().appendChild(renderRunNotice(icon, text2, kind));
8302
+ this.#updateEmptyState();
8303
+ this.#messages.scrollTop = this.#messages.scrollHeight;
8304
+ }
8139
8305
  #cardFor(call) {
8140
8306
  const existing = this.#toolCards.get(call.id);
8141
8307
  if (existing !== void 0) {
@@ -8151,6 +8317,17 @@ Use the read_attachment tool with an id to read a file's contents.`
8151
8317
  return card;
8152
8318
  }
8153
8319
  };
8320
+ function skillNameFrom(call) {
8321
+ if (call.name !== LOAD_CAPABILITY_TOOL) {
8322
+ return null;
8323
+ }
8324
+ const id = call.args?.id;
8325
+ return typeof id === "string" && id !== "" ? id : null;
8326
+ }
8327
+ function compactionRemoved(content) {
8328
+ const removed = content?.removed;
8329
+ return typeof removed === "number" ? removed : null;
8330
+ }
8154
8331
 
8155
8332
  // src/core/define_ag_ui_chat.ts
8156
8333
  function defineAgUiChat() {
@@ -8192,20 +8369,23 @@ function setControlValue(el, value) {
8192
8369
  }
8193
8370
 
8194
8371
  // src/version.ts
8195
- var VERSION = "0.12.0";
8372
+ var VERSION = "0.14.0";
8196
8373
  export {
8197
8374
  AgUiChat,
8198
8375
  AgUiClient,
8376
+ COMPACTION_ACTIVITY_TYPE,
8199
8377
  CheckpointMenu,
8200
8378
  ClientToolRegistry,
8201
8379
  ConnectionLostError,
8202
8380
  DEFAULT_UI_STRINGS,
8203
8381
  ELEMENT_TAG,
8382
+ LOAD_CAPABILITY_TOOL,
8204
8383
  MAX_TOOL_ROUNDS,
8205
8384
  MESSAGE_ROLE,
8206
8385
  PAGE_ACTIONS,
8207
8386
  RemoteConversationStore,
8208
8387
  RunIndex,
8388
+ STATE_EVENT,
8209
8389
  SUBMIT_EVENT,
8210
8390
  SessionStorageStore,
8211
8391
  TOGGLE_EVENT,
@@ -8221,6 +8401,7 @@ export {
8221
8401
  createHttpAgent,
8222
8402
  createPageActionTools,
8223
8403
  createPageMapContext,
8404
+ createPageStateTools,
8224
8405
  createRouteTools,
8225
8406
  createStateHookTools,
8226
8407
  defineAgUiChat,