@artooi/ag-ui-web-component 0.3.0 → 0.4.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.
@@ -36,6 +36,13 @@ export declare class AgUiChat extends HTMLElement {
36
36
  agentFactory: AgentFactory;
37
37
  /** Extra HTTP headers for the AG-UI endpoint (e.g. CSRF). */
38
38
  headers: Record<string, string>;
39
+ /**
40
+ * Permit `<img>` in rendered assistant markdown. **Off by default**: a
41
+ * model-controlled image URL is fetched with no user interaction, which
42
+ * makes it a zero-click exfiltration channel for prompt-injected page
43
+ * data. Enable only when the content source is trusted.
44
+ */
45
+ allowImages: boolean;
39
46
  /** When true, destructive tools execute without a confirmation modal. */
40
47
  autoConfirm: boolean;
41
48
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ag_ui_chat.d.ts","sourceRoot":"","sources":["../../src/core/ag_ui_chat.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ag_ui_chat.d.ts","sourceRoot":"","sources":["../../src/core/ag_ui_chat.ts"],"names":[],"mappings":"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"}
@@ -48,11 +48,19 @@ export interface AgUiClientHandlers {
48
48
  onToolResult(toolCallId: string, content: string): void;
49
49
  onRunEnd(): void;
50
50
  onError(message: string): void;
51
+ /**
52
+ * Fired when the user cancelled the run ({@link AgUiClient.cancel}) — the
53
+ * deliberate-stop sibling of `onError`. Any partial assistant text already
54
+ * streamed stays valid; the host should keep the bubble and show a muted
55
+ * "stopped" affordance rather than an error. `onSettled` still follows.
56
+ */
57
+ onCancelled(): void;
51
58
  /**
52
59
  * Fired exactly once when the whole interaction settles — after the run loop
53
60
  * ends for any reason (a server-only round, frontend-tool rounds exhausted,
54
- * or an error). The terminal guarantee that the UI returns to rest (pending
55
- * indicator cleared, input re-enabled) no matter how the run finished.
61
+ * a cancellation, or an error). The terminal guarantee that the UI returns
62
+ * to rest (pending indicator cleared, input re-enabled) no matter how the
63
+ * run finished.
56
64
  */
57
65
  onSettled(): void;
58
66
  }
@@ -108,5 +116,13 @@ export declare class AgUiClient {
108
116
  resume(): Promise<void>;
109
117
  /** Append a frontend tool result to history (used by the resume path). */
110
118
  addToolResult(toolCallId: string, content: string): void;
119
+ /**
120
+ * Cancel the in-flight run (AG-UI has no server cancel route — aborting the
121
+ * streaming request is the protocol's cancel; the server observes the
122
+ * disconnect). Safe to call with no run in flight. Partial text already
123
+ * streamed stays in history; {@link AgUiClientHandlers.onCancelled} fires
124
+ * instead of `onError`, and `onSettled` still follows.
125
+ */
126
+ cancel(): void;
111
127
  }
112
128
  //# sourceMappingURL=agui_client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agui_client.d.ts","sourceRoot":"","sources":["../../src/core/agui_client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAoC,MAAM,eAAe,CAAC;AACrF,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAG1D,8DAA8D;AAC9D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,mFAAmF;AACnF,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;AAEhF;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,IAAI,IAAI,CAAC;IACnB,yEAAyE;IACzE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,gFAAgF;IAChF,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,+EAA+E;IAC/E,UAAU,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IACrC;;;;OAIG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACxD,QAAQ,IAAI,IAAI,CAAC;IACjB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;;;;OAKG;IACH,SAAS,IAAI,IAAI,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,IAAI,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,OAAO,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,sEAAsE;IACtE,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,oEAAoE;IACpE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,KAAK,IAAI,CAAC;CACpD;AAED;;;;;;GAMG;AACH,qBAAa,UAAU;;gBAQT,MAAM,EAAE,gBAAgB;IASpC,4CAA4C;IAC5C,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,wEAAwE;IACxE,IAAI,QAAQ,IAAI,SAAS,OAAO,EAAE,CAEjC;IAED;;;;;;OAMG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM1C;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7B,0EAA0E;IAC1E,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;CAoFzD"}
1
+ {"version":3,"file":"agui_client.d.ts","sourceRoot":"","sources":["../../src/core/agui_client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAoC,MAAM,eAAe,CAAC;AACrF,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAG1D,8DAA8D;AAC9D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,mFAAmF;AACnF,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;AAEhF;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,IAAI,IAAI,CAAC;IACnB,yEAAyE;IACzE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,gFAAgF;IAChF,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,+EAA+E;IAC/E,UAAU,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IACrC;;;;OAIG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACxD,QAAQ,IAAI,IAAI,CAAC;IACjB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;;;;OAKG;IACH,WAAW,IAAI,IAAI,CAAC;IACpB;;;;;;OAMG;IACH,SAAS,IAAI,IAAI,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,IAAI,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,OAAO,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,sEAAsE;IACtE,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,oEAAoE;IACpE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,KAAK,IAAI,CAAC;CACpD;AAED;;;;;;GAMG;AACH,qBAAa,UAAU;;gBAWT,MAAM,EAAE,gBAAgB;IASpC,4CAA4C;IAC5C,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,wEAAwE;IACxE,IAAI,QAAQ,IAAI,SAAS,OAAO,EAAE,CAEjC;IAED;;;;;;OAMG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM1C;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7B,0EAA0E;IAC1E,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAKxD;;;;;;OAMG;IACH,MAAM,IAAI,IAAI;CAgHf"}
@@ -4,6 +4,15 @@ import type { Message } from "@ag-ui/core";
4
4
  export interface HttpAgentOptions {
5
5
  endpoint: string;
6
6
  headers?: Record<string, string>;
7
+ /**
8
+ * Live header source, re-read on **every** request. `HttpAgent` bakes the
9
+ * static `headers` into its constructor and the element caches the agent
10
+ * for the whole conversation — so a rotated token (CSRF, short-lived JWT)
11
+ * would otherwise never reach the agent endpoint and a long session 401s
12
+ * mid-conversation. When set, the fetch wrapper overlays these values on
13
+ * each call; `headers` still seeds the initial/static configuration.
14
+ */
15
+ getHeaders?: () => Record<string, string>;
7
16
  /** Stable conversation id, so the agent's runs share a thread. */
8
17
  threadId?: string;
9
18
  /** Rehydrated history to seed the agent with (durable conversation). */
@@ -1 +1 @@
1
- {"version":3,"file":"create_http_agent.d.ts","sourceRoot":"","sources":["../../src/core/create_http_agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAa,MAAM,eAAe,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,eAAe,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CACtC;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,aAAa,CAgBxE;AAED,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,gBAAgB,KAAK,aAAa,CAAC"}
1
+ {"version":3,"file":"create_http_agent.d.ts","sourceRoot":"","sources":["../../src/core/create_http_agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAa,MAAM,eAAe,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,eAAe,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CACtC;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,aAAa,CA4BxE;AAED,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,gBAAgB,KAAK,aAAa,CAAC"}
package/dist/index.d.ts CHANGED
@@ -15,8 +15,9 @@ export { createPageMapContext, type PageMap } from "./tools/page_map.js";
15
15
  export { parseToolCatalog, type ToolCatalogEntry } from "./tools/parse_tool_catalog.js";
16
16
  export { createRouteTools, type Route, type RouteMap, type RouteWithParams, } from "./tools/route_map.js";
17
17
  export { createStateHookTools, type StateHook } from "./tools/state_hook.js";
18
- export { type ConfirmationRequest, requestConfirmation } from "./ui/confirmation_card.js";
19
- export { renderMarkdown } from "./ui/render_markdown.js";
18
+ export { type ConfirmationOptions, type ConfirmationRequest, requestConfirmation, } from "./ui/confirmation_card.js";
19
+ export { prettifyToolName } from "./ui/prettify_tool_name.js";
20
+ export { type RenderMarkdownOptions, renderMarkdown } from "./ui/render_markdown.js";
20
21
  export { type SettledStatus, ToolCallCard, type ToolCallStatus, type ToolDisplayMode, } from "./ui/tool_call_card.js";
21
22
  export { VERSION } from "./version.js";
22
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EACX,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,aAAa,GACd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,QAAQ,EACR,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,UAAU,EACV,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,GACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,mBAAmB,GACpB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,KAAK,YAAY,EACjB,eAAe,EACf,KAAK,gBAAgB,GACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EACL,KAAK,YAAY,EACjB,cAAc,EACd,KAAK,qBAAqB,EAC1B,kBAAkB,EAClB,KAAK,YAAY,EACjB,oBAAoB,EACpB,cAAc,EACd,KAAK,aAAa,EAClB,oBAAoB,EACpB,YAAY,EACZ,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,aAAa,EACb,QAAQ,GACT,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,YAAY,EACZ,KAAK,gBAAgB,EACrB,SAAS,EACT,WAAW,EACX,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC1E,YAAY,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,KAAK,UAAU,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACtF,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACxF,OAAO,EACL,gBAAgB,EAChB,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,eAAe,GACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,oBAAoB,EAAE,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EAAE,KAAK,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EACL,KAAK,aAAa,EAClB,YAAY,EACZ,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EACX,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,aAAa,GACd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,QAAQ,EACR,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,UAAU,EACV,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,GACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,mBAAmB,GACpB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,KAAK,YAAY,EACjB,eAAe,EACf,KAAK,gBAAgB,GACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EACL,KAAK,YAAY,EACjB,cAAc,EACd,KAAK,qBAAqB,EAC1B,kBAAkB,EAClB,KAAK,YAAY,EACjB,oBAAoB,EACpB,cAAc,EACd,KAAK,aAAa,EAClB,oBAAoB,EACpB,YAAY,EACZ,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,aAAa,EACb,QAAQ,GACT,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,YAAY,EACZ,KAAK,gBAAgB,EACrB,SAAS,EACT,WAAW,EACX,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC1E,YAAY,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,KAAK,UAAU,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACtF,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACxF,OAAO,EACL,gBAAgB,EAChB,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,eAAe,GACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,oBAAoB,EAAE,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,mBAAmB,GACpB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,KAAK,qBAAqB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EACL,KAAK,aAAa,EAClB,YAAY,EACZ,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -239,7 +239,7 @@ function actionButton(modifier, label) {
239
239
  button.textContent = label;
240
240
  return button;
241
241
  }
242
- function requestConfirmation(host, request) {
242
+ function requestConfirmation(host, request, options = {}) {
243
243
  return new Promise((resolve) => {
244
244
  const card = document.createElement("div");
245
245
  card.className = "confirm";
@@ -256,7 +256,12 @@ function requestConfirmation(host, request) {
256
256
  actions.className = "confirm-actions";
257
257
  const cancel = actionButton("cancel", "Cancel");
258
258
  const confirm = actionButton("confirm", "Confirm");
259
+ let settled = false;
259
260
  const close = (accepted) => {
261
+ if (settled) {
262
+ return;
263
+ }
264
+ settled = true;
260
265
  cancel.disabled = true;
261
266
  confirm.disabled = true;
262
267
  card.setAttribute("data-resolved", accepted ? "confirmed" : "declined");
@@ -264,13 +269,27 @@ function requestConfirmation(host, request) {
264
269
  };
265
270
  cancel.addEventListener("click", () => close(false));
266
271
  confirm.addEventListener("click", () => close(true));
272
+ options.signal?.addEventListener("abort", () => close(false), { once: true });
267
273
  actions.append(cancel, confirm);
268
274
  card.append(body, args, actions);
269
275
  host.appendChild(card);
276
+ if (options.signal?.aborted === true) {
277
+ close(false);
278
+ return;
279
+ }
270
280
  confirm.focus();
271
281
  });
272
282
  }
273
283
 
284
+ // src/ui/prettify_tool_name.ts
285
+ function prettifyToolName(name) {
286
+ const spaced = name.replace(/[._-]+/g, " ").trim();
287
+ if (spaced === "") {
288
+ return name;
289
+ }
290
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1);
291
+ }
292
+
274
293
  // node_modules/.pnpm/dompurify@3.4.7/node_modules/dompurify/dist/purify.es.mjs
275
294
  function _arrayLikeToArray(r, a) {
276
295
  (null == a || a > r.length) && (a = r.length);
@@ -2711,7 +2730,7 @@ var Vt = b.parse;
2711
2730
  var Yt = x.lex;
2712
2731
 
2713
2732
  // src/ui/render_markdown.ts
2714
- g.setOptions({ gfm: true, breaks: true });
2733
+ var parser = new q({ gfm: true, breaks: true });
2715
2734
  var ALLOWED_TAGS = [
2716
2735
  "a",
2717
2736
  "p",
@@ -2742,13 +2761,18 @@ var ALLOWED_TAGS = [
2742
2761
  "tbody",
2743
2762
  "tr",
2744
2763
  "th",
2745
- "td",
2746
- "img"
2764
+ "td"
2747
2765
  ];
2748
- var ALLOWED_ATTR = ["href", "title", "class", "src", "alt", "width", "height"];
2749
- function renderMarkdown(text2) {
2750
- const rendered = g.parse(text2, { async: false });
2751
- const clean = purify.sanitize(rendered, { ALLOWED_TAGS, ALLOWED_ATTR });
2766
+ var ALLOWED_ATTR = ["href", "title", "class"];
2767
+ var ALLOWED_TAGS_WITH_IMAGES = [...ALLOWED_TAGS, "img"];
2768
+ var ALLOWED_ATTR_WITH_IMAGES = [...ALLOWED_ATTR, "src", "alt", "width", "height"];
2769
+ function renderMarkdown(text2, options) {
2770
+ const allowImages = options?.allowImages === true;
2771
+ const rendered = parser.parse(text2, { async: false });
2772
+ const clean = purify.sanitize(rendered, {
2773
+ ALLOWED_TAGS: allowImages ? ALLOWED_TAGS_WITH_IMAGES : ALLOWED_TAGS,
2774
+ ALLOWED_ATTR: allowImages ? ALLOWED_ATTR_WITH_IMAGES : ALLOWED_ATTR
2775
+ });
2752
2776
  const template = document.createElement("template");
2753
2777
  template.innerHTML = clean;
2754
2778
  for (const anchor of template.content.querySelectorAll("a[href]")) {
@@ -3435,6 +3459,19 @@ var STYLES = `
3435
3459
  cursor: default;
3436
3460
  }
3437
3461
 
3462
+ /* The composer button doubles as the Stop control while a run is in flight. */
3463
+ .send[data-state="running"] {
3464
+ background: var(--ag-ui-muted);
3465
+ }
3466
+
3467
+ /* Muted "\u23F9 Stopped" line after a cancelled run \u2014 a note, not an error bubble. */
3468
+ .stopped-note {
3469
+ align-self: flex-start;
3470
+ color: var(--ag-ui-muted);
3471
+ font-size: 12px;
3472
+ padding: 2px 4px;
3473
+ }
3474
+
3438
3475
  /* Inline confirmation card \u2014 lives in the transcript, no focus-stealing overlay. */
3439
3476
  .confirm {
3440
3477
  align-self: stretch;
@@ -3655,6 +3692,9 @@ var AgUiClient = class {
3655
3692
  #getContext;
3656
3693
  #executeTool;
3657
3694
  #onPersist;
3695
+ // Set by cancel(); reset at the top of each #run(). Checked by the loop so
3696
+ // a cancel between frontend-tool rounds doesn't start another round.
3697
+ #cancelled = false;
3658
3698
  constructor(config) {
3659
3699
  this.#agent = config.agent;
3660
3700
  this.#handlers = config.handlers;
@@ -3697,23 +3737,52 @@ var AgUiClient = class {
3697
3737
  this.#agent.addMessage({ id: randomUUID(), role: "tool", content, toolCallId });
3698
3738
  this.#onPersist(this.#agent.messages);
3699
3739
  }
3740
+ /**
3741
+ * Cancel the in-flight run (AG-UI has no server cancel route — aborting the
3742
+ * streaming request is the protocol's cancel; the server observes the
3743
+ * disconnect). Safe to call with no run in flight. Partial text already
3744
+ * streamed stays in history; {@link AgUiClientHandlers.onCancelled} fires
3745
+ * instead of `onError`, and `onSettled` still follows.
3746
+ */
3747
+ cancel() {
3748
+ this.#cancelled = true;
3749
+ this.#agent.abortRun();
3750
+ }
3700
3751
  async #run() {
3752
+ this.#cancelled = false;
3701
3753
  try {
3702
3754
  await this.#runLoop();
3755
+ if (this.#cancelled) {
3756
+ this.#onCancelled();
3757
+ }
3703
3758
  } catch (error) {
3704
- this.#handlers.onError(error instanceof Error ? error.message : String(error));
3759
+ if (this.#cancelled || isAbortError(error)) {
3760
+ this.#onCancelled();
3761
+ } else {
3762
+ this.#handlers.onError(error instanceof Error ? error.message : String(error));
3763
+ }
3705
3764
  } finally {
3706
3765
  this.#handlers.onSettled();
3707
3766
  }
3708
3767
  }
3768
+ #onCancelled() {
3769
+ this.#onPersist(this.#agent.messages);
3770
+ this.#handlers.onCancelled();
3771
+ }
3709
3772
  async #runLoop() {
3710
3773
  for (let round = 0; round < MAX_TOOL_ROUNDS; round += 1) {
3774
+ if (this.#cancelled) {
3775
+ return;
3776
+ }
3711
3777
  const pending = [];
3712
3778
  await this.#agent.runAgent(
3713
3779
  { tools: this.#getTools(), context: this.#getContext() },
3714
3780
  this.#buildSubscriber(pending)
3715
3781
  );
3716
3782
  this.#onPersist(this.#agent.messages);
3783
+ if (this.#cancelled) {
3784
+ return;
3785
+ }
3717
3786
  if (this.#executeTool === null || pending.length === 0) {
3718
3787
  return;
3719
3788
  }
@@ -3773,6 +3842,9 @@ var AgUiClient = class {
3773
3842
  };
3774
3843
  }
3775
3844
  };
3845
+ function isAbortError(error) {
3846
+ return error instanceof Error && error.name === "AbortError";
3847
+ }
3776
3848
 
3777
3849
  // src/core/conversation_store.ts
3778
3850
  import { randomUUID as randomUUID2 } from "@ag-ui/client";
@@ -3834,8 +3906,20 @@ function createHttpAgent(options) {
3834
3906
  // HttpAgent invokes its configured fetch as a method (`this.fetch(...)`),
3835
3907
  // which would rebind the global `fetch` to the agent instance and trigger
3836
3908
  // "Illegal invocation" in browsers. Wrap it so `fetch` is always called as
3837
- // a free function with the correct receiver.
3838
- fetch: (url, init) => fetch(url, init),
3909
+ // a free function with the correct receiver. The wrapper also overlays
3910
+ // `getHeaders()` per request, so header rotation (CSRF, short-lived JWT)
3911
+ // reaches the stream even though the agent instance is cached.
3912
+ fetch: (url, init) => {
3913
+ const fresh = options.getHeaders?.();
3914
+ if (fresh === void 0) {
3915
+ return fetch(url, init);
3916
+ }
3917
+ const headers = new Headers(init?.headers);
3918
+ for (const [name, value] of Object.entries(fresh)) {
3919
+ headers.set(name, value);
3920
+ }
3921
+ return fetch(url, { ...init, headers });
3922
+ },
3839
3923
  // Spread conditionally: under `exactOptionalPropertyTypes` an explicit
3840
3924
  // `undefined` is not assignable to these optional config fields.
3841
3925
  ...options.threadId !== void 0 ? { threadId: options.threadId } : {},
@@ -3850,6 +3934,13 @@ var AgUiChat = class extends HTMLElement {
3850
3934
  agentFactory = createHttpAgent;
3851
3935
  /** Extra HTTP headers for the AG-UI endpoint (e.g. CSRF). */
3852
3936
  headers = {};
3937
+ /**
3938
+ * Permit `<img>` in rendered assistant markdown. **Off by default**: a
3939
+ * model-controlled image URL is fetched with no user interaction, which
3940
+ * makes it a zero-click exfiltration channel for prompt-injected page
3941
+ * data. Enable only when the content source is trusted.
3942
+ */
3943
+ allowImages = false;
3853
3944
  /** When true, destructive tools execute without a confirmation modal. */
3854
3945
  autoConfirm = false;
3855
3946
  /**
@@ -3948,6 +4039,13 @@ var AgUiChat = class extends HTMLElement {
3948
4039
  #skillsMenu;
3949
4040
  #skillHint;
3950
4041
  #client = null;
4042
+ // Whether an interaction is in flight (first onRunStart → onSettled). Drives
4043
+ // the Send⇄Stop button: `agent.isRunning` is false between frontend-tool
4044
+ // rounds, but the user must still be able to stop there.
4045
+ #running = false;
4046
+ // Aborting this dismisses (declines) an open confirmation card when the run
4047
+ // is cancelled while the card awaits a decision. One controller per card.
4048
+ #confirmAbort = null;
3951
4049
  #streamingBubble = null;
3952
4050
  // Text deltas applied to the current streaming bubble. >1 ⇒ the message
3953
4051
  // revealed progressively as it streamed, so the word reveal must not re-animate
@@ -4183,6 +4281,7 @@ var AgUiChat = class extends HTMLElement {
4183
4281
  * in-memory run state, clear the transcript, and mint a new thread id.
4184
4282
  */
4185
4283
  newChat() {
4284
+ this.#cancelRun();
4186
4285
  this.conversationStore.clear(this.#threadId);
4187
4286
  this.#client = null;
4188
4287
  this.#streamingBubble = null;
@@ -4192,7 +4291,7 @@ var AgUiChat = class extends HTMLElement {
4192
4291
  this.#initialMessages = [];
4193
4292
  this.#messages.replaceChildren();
4194
4293
  this.#threadId = this.conversationStore.threadId();
4195
- this.#send.disabled = false;
4294
+ this.#setRunning(false);
4196
4295
  }
4197
4296
  /**
4198
4297
  * Restore the conversation from the store on mount, then — if a navigating
@@ -4287,7 +4386,7 @@ var AgUiChat = class extends HTMLElement {
4287
4386
  const bubble = document.createElement("div");
4288
4387
  bubble.className = `message message--${role}`;
4289
4388
  if (role === MESSAGE_ROLE.ASSISTANT) {
4290
- bubble.innerHTML = renderMarkdown(content);
4389
+ bubble.innerHTML = renderMarkdown(content, { allowImages: this.allowImages });
4291
4390
  } else {
4292
4391
  bubble.textContent = content;
4293
4392
  }
@@ -4337,7 +4436,13 @@ var AgUiChat = class extends HTMLElement {
4337
4436
  this.#send.className = "send";
4338
4437
  this.#send.type = "button";
4339
4438
  this.#send.textContent = "Send";
4439
+ this.#send.setAttribute("aria-label", "Send");
4440
+ this.#send.dataset["state"] = "idle";
4340
4441
  this.#send.addEventListener("click", () => {
4442
+ if (this.#running) {
4443
+ this.#cancelRun();
4444
+ return;
4445
+ }
4341
4446
  void this.#submit();
4342
4447
  });
4343
4448
  this.#skillHint.className = "skill-hint";
@@ -4363,11 +4468,34 @@ var AgUiChat = class extends HTMLElement {
4363
4468
  event.preventDefault();
4364
4469
  return;
4365
4470
  }
4471
+ if (event.key === "Escape" && this.#running) {
4472
+ event.preventDefault();
4473
+ this.#cancelRun();
4474
+ return;
4475
+ }
4366
4476
  if (event.key === "Enter" && !event.shiftKey) {
4367
4477
  event.preventDefault();
4368
4478
  void this.#submit();
4369
4479
  }
4370
4480
  }
4481
+ /**
4482
+ * Stop the in-flight run: decline any confirmation card awaiting a decision
4483
+ * (the loop is suspended on it), then cancel the client run — the abort
4484
+ * closes the streaming request, which is AG-UI's cancel (the server
4485
+ * observes the disconnect).
4486
+ */
4487
+ #cancelRun() {
4488
+ this.#confirmAbort?.abort();
4489
+ this.#client?.cancel();
4490
+ }
4491
+ /** Swap the composer button between Send (idle) and Stop (running). */
4492
+ #setRunning(running) {
4493
+ this.#running = running;
4494
+ const label = running ? "Stop" : "Send";
4495
+ this.#send.textContent = label;
4496
+ this.#send.setAttribute("aria-label", label);
4497
+ this.#send.dataset["state"] = running ? "running" : "idle";
4498
+ }
4371
4499
  async #submit() {
4372
4500
  const content = this.#input.value.trim();
4373
4501
  if (content === "") {
@@ -4395,6 +4523,10 @@ var AgUiChat = class extends HTMLElement {
4395
4523
  const agent = this.agentFactory({
4396
4524
  endpoint: this.endpoint,
4397
4525
  headers: this.headers,
4526
+ // Live getter: the client is built once and cached, but a rotated
4527
+ // token must still reach every request — the factory's fetch wrapper
4528
+ // re-reads this on each call.
4529
+ getHeaders: () => this.headers,
4398
4530
  threadId: this.#threadId,
4399
4531
  initialMessages: this.#initialMessages
4400
4532
  });
@@ -4435,9 +4567,13 @@ var AgUiChat = class extends HTMLElement {
4435
4567
  if (typeof confirmText === "string") {
4436
4568
  request.message = confirmText;
4437
4569
  }
4438
- const decision = requestConfirmation(this.#messages, request);
4570
+ this.#confirmAbort = new AbortController();
4571
+ const decision = requestConfirmation(this.#messages, request, {
4572
+ signal: this.#confirmAbort.signal
4573
+ });
4439
4574
  this.#messages.scrollTop = this.#messages.scrollHeight;
4440
4575
  const accepted = await decision;
4576
+ this.#confirmAbort = null;
4441
4577
  if (!accepted) {
4442
4578
  const message = "User declined the action.";
4443
4579
  card.settle(TOOL_CALL_STATUS.DECLINED, message);
@@ -4472,7 +4608,7 @@ var AgUiChat = class extends HTMLElement {
4472
4608
  #handlers() {
4473
4609
  return {
4474
4610
  onRunStart: () => {
4475
- this.#send.disabled = true;
4611
+ this.#setRunning(true);
4476
4612
  this.#showPending();
4477
4613
  },
4478
4614
  onTextDelta: (buffer) => {
@@ -4501,22 +4637,34 @@ var AgUiChat = class extends HTMLElement {
4501
4637
  },
4502
4638
  onRunEnd: () => {
4503
4639
  this.#hidePending();
4504
- this.#send.disabled = false;
4505
4640
  this.#streamingBubble = null;
4506
4641
  },
4507
4642
  onError: (message) => {
4508
4643
  this.#hidePending();
4509
4644
  this.#revealWords(this.appendMessage(MESSAGE_ROLE.ASSISTANT, `\u26A0\uFE0F ${message}`));
4510
- this.#send.disabled = false;
4645
+ this.#streamingBubble = null;
4646
+ },
4647
+ onCancelled: () => {
4648
+ this.#hidePending();
4649
+ this.#appendStoppedNote();
4511
4650
  this.#streamingBubble = null;
4512
4651
  },
4513
4652
  onSettled: () => {
4514
4653
  this.#hidePending();
4515
- this.#send.disabled = false;
4654
+ this.#setRunning(false);
4516
4655
  this.#streamingBubble = null;
4517
4656
  }
4518
4657
  };
4519
4658
  }
4659
+ /** A muted "⏹ Stopped" line in the transcript (distinct from the ⚠️ error bubble). */
4660
+ #appendStoppedNote() {
4661
+ const note = document.createElement("div");
4662
+ note.className = "stopped-note";
4663
+ note.setAttribute("role", "status");
4664
+ note.textContent = "\u23F9 Stopped";
4665
+ this.#messages.appendChild(note);
4666
+ this.#messages.scrollTop = this.#messages.scrollHeight;
4667
+ }
4520
4668
  /**
4521
4669
  * Show a "thinking" indicator while the agent is being awaited — both the
4522
4670
  * silent stretch before the first token and the gap after a tool result
@@ -4549,7 +4697,7 @@ var AgUiChat = class extends HTMLElement {
4549
4697
  this.#streamingBubble = this.appendMessage(MESSAGE_ROLE.ASSISTANT, "");
4550
4698
  this.#streamDeltas = 0;
4551
4699
  }
4552
- this.#streamingBubble.innerHTML = renderMarkdown(buffer);
4700
+ this.#streamingBubble.innerHTML = renderMarkdown(buffer, { allowImages: this.allowImages });
4553
4701
  this.#messages.scrollTop = this.#messages.scrollHeight;
4554
4702
  return this.#streamingBubble;
4555
4703
  }
@@ -4565,7 +4713,7 @@ var AgUiChat = class extends HTMLElement {
4565
4713
  return existing;
4566
4714
  }
4567
4715
  const labelled = this.#resolveTool(call.name)?.parameters[X_SUMMARY_KEY];
4568
- const summary = typeof labelled === "string" ? labelled : this.toolSummaries[call.name] ?? this.#toolCatalog[call.name];
4716
+ const summary = typeof labelled === "string" ? labelled : this.toolSummaries[call.name] ?? this.#toolCatalog[call.name] ?? prettifyToolName(call.name);
4569
4717
  const card = new ToolCallCard(call.name, call.args, this.toolDisplay, summary);
4570
4718
  this.#toolCards.set(call.id, card);
4571
4719
  this.#messages.appendChild(card.element);
@@ -4738,7 +4886,7 @@ function setControlValue(el, value) {
4738
4886
  }
4739
4887
 
4740
4888
  // src/version.ts
4741
- var VERSION = "0.3.0";
4889
+ var VERSION = "0.4.0";
4742
4890
  export {
4743
4891
  AgUiChat,
4744
4892
  AgUiClient,
@@ -4772,6 +4920,7 @@ export {
4772
4920
  prefersReducedMotion,
4773
4921
  pressButton,
4774
4922
  pressThenClick,
4923
+ prettifyToolName,
4775
4924
  renderMarkdown,
4776
4925
  requestConfirmation,
4777
4926
  scrollIntoCenterView,