@artooi/ag-ui-web-component 0.9.0 → 0.11.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 (61) hide show
  1. package/CHANGELOG.md +104 -7
  2. package/README.md +89 -7
  3. package/dist/ag-ui-web-component.bundle.js +168 -47
  4. package/dist/ag-ui-web-component.bundle.js.map +4 -4
  5. package/dist/core/ag_ui_chat.d.ts +39 -1
  6. package/dist/core/ag_ui_chat.d.ts.map +1 -1
  7. package/dist/core/agui_client.d.ts +28 -1
  8. package/dist/core/agui_client.d.ts.map +1 -1
  9. package/dist/core/attachment.d.ts +5 -0
  10. package/dist/core/attachment.d.ts.map +1 -1
  11. package/dist/core/conversation_store.d.ts +8 -0
  12. package/dist/core/conversation_store.d.ts.map +1 -1
  13. package/dist/core/remote_conversation_store.d.ts.map +1 -1
  14. package/dist/core/upload_attachment.d.ts +8 -2
  15. package/dist/core/upload_attachment.d.ts.map +1 -1
  16. package/dist/index.d.ts +3 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +887 -128
  19. package/dist/index.js.map +4 -4
  20. package/dist/ui/approval_card.d.ts +51 -0
  21. package/dist/ui/approval_card.d.ts.map +1 -0
  22. package/dist/ui/attachment_chips.d.ts.map +1 -1
  23. package/dist/ui/attachment_tray.d.ts +7 -1
  24. package/dist/ui/attachment_tray.d.ts.map +1 -1
  25. package/dist/ui/question_card.d.ts +52 -0
  26. package/dist/ui/question_card.d.ts.map +1 -0
  27. package/dist/ui/relative_time.d.ts +5 -3
  28. package/dist/ui/relative_time.d.ts.map +1 -1
  29. package/dist/ui/skills_menu.d.ts.map +1 -1
  30. package/dist/ui/styles.d.ts +1 -1
  31. package/dist/ui/styles.d.ts.map +1 -1
  32. package/dist/ui/thoughts_block.d.ts +2 -2
  33. package/dist/ui/thoughts_block.d.ts.map +1 -1
  34. package/dist/ui/thread_drawer.d.ts.map +1 -1
  35. package/dist/ui/tool_call_card.d.ts.map +1 -1
  36. package/dist/ui/ui_strings.d.ts +16 -0
  37. package/dist/ui/ui_strings.d.ts.map +1 -1
  38. package/dist/ui/voice_input.d.ts +9 -1
  39. package/dist/ui/voice_input.d.ts.map +1 -1
  40. package/dist/version.d.ts.map +1 -1
  41. package/package.json +4 -4
  42. package/src/core/ag_ui_chat.ts +251 -14
  43. package/src/core/agui_client.ts +95 -9
  44. package/src/core/attachment.ts +21 -1
  45. package/src/core/conversation_store.ts +84 -18
  46. package/src/core/remote_conversation_store.ts +24 -3
  47. package/src/core/upload_attachment.ts +8 -1
  48. package/src/index.ts +14 -0
  49. package/src/ui/approval_card.ts +119 -0
  50. package/src/ui/attachment_chips.ts +5 -0
  51. package/src/ui/attachment_tray.ts +50 -5
  52. package/src/ui/question_card.ts +216 -0
  53. package/src/ui/relative_time.ts +8 -3
  54. package/src/ui/skills_menu.ts +6 -0
  55. package/src/ui/styles.ts +130 -9
  56. package/src/ui/thoughts_block.ts +3 -2
  57. package/src/ui/thread_drawer.ts +94 -9
  58. package/src/ui/tool_call_card.ts +6 -0
  59. package/src/ui/ui_strings.ts +30 -0
  60. package/src/ui/voice_input.ts +21 -1
  61. package/src/version.ts +1 -1
@@ -0,0 +1,51 @@
1
+ import { type UiStrings } from "./ui_strings.js";
2
+ /** What the inline approval card displays for one server-side-tool interrupt. */
3
+ export interface ApprovalRequest {
4
+ /**
5
+ * Human-readable prompt from the AG-UI interrupt (e.g.
6
+ * `Approve delete_thing({…})?`). Falls back to the generic
7
+ * {@link UiStrings.approvalPrompt} when the interrupt carries no message.
8
+ */
9
+ message?: string;
10
+ /** Tool name, surfaced as a `data-tool-name` attribute for styling/tests. */
11
+ toolName?: string;
12
+ }
13
+ /** Options for {@link requestApproval}. */
14
+ export interface ApprovalOptions {
15
+ /**
16
+ * Aborting this signal resolves the card as **denied** (buttons disabled,
17
+ * `data-resolved="denied"`) — the hook a Stop control uses to dismiss a
18
+ * pending approval when the user cancels the whole run.
19
+ */
20
+ signal?: AbortSignal;
21
+ /** Localized strings; defaults to the English {@link DEFAULT_UI_STRINGS}. */
22
+ strings?: UiStrings;
23
+ }
24
+ /**
25
+ * A fully custom renderer for a server-side-tool approval, set via
26
+ * `AgUiChat.approvalRenderer`. Receives the {@link ApprovalRequest} (the
27
+ * interrupt's message + tool name) and an `AbortSignal` that fires when the run
28
+ * is stopped, and resolves `true` to approve or `false` to deny. When provided
29
+ * it **replaces** the built-in {@link requestApproval} card entirely — the host
30
+ * owns the DOM, so it can render a native modal, a framework component, or
31
+ * anything else. See the `strings` / `::part()` seams for styling the built-in
32
+ * card instead of replacing it.
33
+ */
34
+ export type ApprovalRenderer = (request: ApprovalRequest, options: {
35
+ signal: AbortSignal;
36
+ }) => Promise<boolean>;
37
+ /**
38
+ * Append an inline **approval** card to ``host`` and resolve when the user
39
+ * decides whether a gated *server-side* tool may run.
40
+ *
41
+ * The server-side approval gate is distinct from the client-tool confirmation
42
+ * card ({@link requestConfirmation}): a destructive server tool defers instead
43
+ * of executing, and the run finishes on an AG-UI *interrupt* the client answers
44
+ * with `resume[]`. This card is the browser half of that loop — it reads
45
+ * naturally after the tool-call card whose execution it gates, and resolves
46
+ * ``true`` to approve (run the tool) or ``false`` to deny. The card stays in the
47
+ * transcript as a resolved record (buttons disabled, `data-resolved` set)
48
+ * rather than vanishing.
49
+ */
50
+ export declare function requestApproval(host: Node & ParentNode, request: ApprovalRequest, options?: ApprovalOptions): Promise<boolean>;
51
+ //# sourceMappingURL=approval_card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval_card.d.ts","sourceRoot":"","sources":["../../src/ui/approval_card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAYD,2CAA2C;AAC3C,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,KAC7B,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,IAAI,GAAG,UAAU,EACvB,OAAO,EAAE,eAAe,EACxB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,OAAO,CAAC,CAkDlB"}
@@ -1 +1 @@
1
- {"version":3,"file":"attachment_chips.d.ts","sourceRoot":"","sources":["../../src/ui/attachment_chips.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,SAAS,aAAa,EAAE,GAAG,cAAc,CAOpF;AAwBD,wEAAwE;AACxE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW5C;AAED,0DAA0D;AAC1D,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAajD"}
1
+ {"version":3,"file":"attachment_chips.d.ts","sourceRoot":"","sources":["../../src/ui/attachment_chips.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,SAAS,aAAa,EAAE,GAAG,cAAc,CAQpF;AA4BD,wEAAwE;AACxE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW5C;AAED,0DAA0D;AAC1D,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAajD"}
@@ -39,7 +39,13 @@ export declare class AttachmentTray {
39
39
  isEmpty(): boolean;
40
40
  /** Drop the settled (ready / error) chips, leaving any still uploading. */
41
41
  clearReady(): void;
42
- /** Drop every chip (a reset / new-chat). */
42
+ /** Drop every chip (a reset / new-chat), aborting any in-flight upload. */
43
43
  clear(): void;
44
+ /**
45
+ * Abort every in-flight upload without touching the rendered chips — the
46
+ * teardown path when the host element is removed mid-upload, so a cancelled
47
+ * transfer doesn't orphan a server-side file.
48
+ */
49
+ dispose(): void;
44
50
  }
45
51
  //# sourceMappingURL=attachment_tray.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"attachment_tray.d.ts","sourceRoot":"","sources":["../../src/ui/attachment_tray.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAKrE,yDAAyD;AACzD,MAAM,WAAW,oBAAoB;IACnC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,oFAAoF;IACpF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAC/B,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;CAC9B;AAYD;;;;;;;;;GASG;AACH,qBAAa,cAAc;;IACzB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;gBAMrB,MAAM,EAAE,oBAAoB;IASxC,gFAAgF;IAChF,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAuBrB,8DAA8D;IAC9D,SAAS,IAAI,SAAS,aAAa,EAAE;IAUrC,gFAAgF;IAChF,UAAU,IAAI,OAAO;IAIrB,uCAAuC;IACvC,OAAO,IAAI,OAAO;IAIlB,2EAA2E;IAC3E,UAAU,IAAI,IAAI;IAKlB,4CAA4C;IAC5C,KAAK,IAAI,IAAI;CA2Gd"}
1
+ {"version":3,"file":"attachment_tray.d.ts","sourceRoot":"","sources":["../../src/ui/attachment_tray.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAKrE,yDAAyD;AACzD,MAAM,WAAW,oBAAoB;IACnC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,oFAAoF;IACpF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAC/B,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;CAC9B;AAcD;;;;;;;;;GASG;AACH,qBAAa,cAAc;;IACzB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;gBAMrB,MAAM,EAAE,oBAAoB;IASxC,gFAAgF;IAChF,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAwBrB,8DAA8D;IAC9D,SAAS,IAAI,SAAS,aAAa,EAAE;IAUrC,gFAAgF;IAChF,UAAU,IAAI,OAAO;IAIrB,uCAAuC;IACvC,OAAO,IAAI,OAAO;IAIlB,2EAA2E;IAC3E,UAAU,IAAI,IAAI;IAKlB,2EAA2E;IAC3E,KAAK,IAAI,IAAI;IAQb;;;;OAIG;IACH,OAAO,IAAI,IAAI;CAwIhB"}
@@ -0,0 +1,52 @@
1
+ import { type UiStrings } from "./ui_strings.js";
2
+ /** What the inline question card asks (the `ask_user` frontend tool's args). */
3
+ export interface QuestionRequest {
4
+ /** The question shown to the user. */
5
+ question: string;
6
+ /**
7
+ * Preset choices rendered as radios. When empty/omitted the card is a plain
8
+ * free-text prompt.
9
+ */
10
+ options?: readonly string[];
11
+ /**
12
+ * Whether the user may type a custom answer. With `options`, adds an "other"
13
+ * radio revealing a text field; without options the card is free-text anyway.
14
+ */
15
+ allowCustom?: boolean;
16
+ }
17
+ /** Options for {@link requestQuestion}. */
18
+ export interface QuestionOptions {
19
+ /**
20
+ * Aborting this signal resolves the card with an empty answer (fields
21
+ * disabled) — the hook a Stop control uses to dismiss an open question when
22
+ * the user cancels the whole run.
23
+ */
24
+ signal?: AbortSignal;
25
+ /** Localized strings; defaults to the English {@link DEFAULT_UI_STRINGS}. */
26
+ strings?: UiStrings;
27
+ }
28
+ /**
29
+ * A fully custom renderer for the `ask_user` question, set via
30
+ * `AgUiChat.askUserRenderer`. Receives the parsed {@link QuestionRequest} and an
31
+ * `AbortSignal` that fires when the run is stopped, and resolves with the user's
32
+ * answer (an empty string signals "no answer", e.g. on abort). When provided it
33
+ * **replaces** the built-in {@link requestQuestion} card entirely — the host owns
34
+ * the DOM, so it can render a native modal, a framework component, or anything
35
+ * else. See the `strings` / `::part()` seams for styling the built-in card
36
+ * instead of replacing it.
37
+ */
38
+ export type QuestionRenderer = (request: QuestionRequest, options: {
39
+ signal: AbortSignal;
40
+ }) => Promise<string>;
41
+ /**
42
+ * Append an inline **question** card to ``host`` and resolve with the user's
43
+ * answer — the browser half of the built-in `ask_user` frontend tool.
44
+ *
45
+ * Unlike the confirmation/approval cards (which resolve a yes/no), this collects
46
+ * a typed answer: a radio pick from ``options``, or free text (when
47
+ * ``allowCustom`` or no ``options`` are given). The card stays in the transcript
48
+ * as a resolved record (controls disabled, `data-resolved` set) rather than
49
+ * vanishing. A Stop while it is open resolves it with an empty string.
50
+ */
51
+ export declare function requestQuestion(host: Node & ParentNode, request: QuestionRequest, options?: QuestionOptions): Promise<string>;
52
+ //# sourceMappingURL=question_card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"question_card.d.ts","sourceRoot":"","sources":["../../src/ui/question_card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,2CAA2C;AAC3C,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,KAC7B,OAAO,CAAC,MAAM,CAAC,CAAC;AAYrB;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,IAAI,GAAG,UAAU,EACvB,OAAO,EAAE,eAAe,EACxB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAkJjB"}
@@ -5,9 +5,11 @@ import { type UiStrings } from "./ui_strings.js";
5
5
  *
6
6
  * `now` is injectable so callers (and tests) can pin the reference point; it
7
7
  * defaults to the current time. A timestamp in the future (clock skew) reads as
8
- * `"just now"`. The unit words come from {@link UiStrings} (the `{n}` token is
9
- * filled in here) so a localized host translates them; the bucketing stays
10
- * integer-rounded and locale-neutral.
8
+ * `"just now"`. A non-finite timestamp an unparseable or missing `updated_at`
9
+ * that arrived as `NaN` has no meaningful age, so it falls back to `justNow`
10
+ * rather than rendering `"NaNw ago"` or `"~2950w ago"`. The unit words come from
11
+ * {@link UiStrings} (the `{n}` token is filled in here) so a localized host
12
+ * translates them; the bucketing stays integer-rounded and locale-neutral.
11
13
  */
12
14
  export declare function relativeTime(timestamp: number, now?: number, strings?: UiStrings): string;
13
15
  //# sourceMappingURL=relative_time.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"relative_time.d.ts","sourceRoot":"","sources":["../../src/ui/relative_time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAAmB,EACxB,OAAO,GAAE,SAA8B,GACtC,MAAM,CAkBR"}
1
+ {"version":3,"file":"relative_time.d.ts","sourceRoot":"","sources":["../../src/ui/relative_time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAAmB,EACxB,OAAO,GAAE,SAA8B,GACtC,MAAM,CAqBR"}
@@ -1 +1 @@
1
- {"version":3,"file":"skills_menu.d.ts","sourceRoot":"","sources":["../../src/ui/skills_menu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAEhD;;;;;;GAMG;AACH,qBAAa,UAAU;;IACrB,uFAAuF;IACvF,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,gFAAgF;IAChF,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;gBASrB,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;IAW1C,6DAA6D;IAC7D,SAAS,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,IAAI;IAKzC,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKnC,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAInC,6CAA6C;IAC7C,MAAM,IAAI,OAAO;IAIjB;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAQ5B;;;OAGG;IACH,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;IA2BxC,yBAAyB;IACzB,KAAK,IAAI,IAAI;CAyEd"}
1
+ {"version":3,"file":"skills_menu.d.ts","sourceRoot":"","sources":["../../src/ui/skills_menu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAEhD;;;;;;GAMG;AACH,qBAAa,UAAU;;IACrB,uFAAuF;IACvF,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,gFAAgF;IAChF,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;gBASrB,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;IAa1C,6DAA6D;IAC7D,SAAS,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,IAAI;IAKzC,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKnC,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAInC,6CAA6C;IAC7C,MAAM,IAAI,OAAO;IAIjB;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAQ5B;;;OAGG;IACH,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;IA2BxC,yBAAyB;IACzB,KAAK,IAAI,IAAI;CA6Ed"}
@@ -1,2 +1,2 @@
1
- export declare const STYLES = "\n:host {\n /* Colors */\n --ag-ui-bg: #ffffff;\n --ag-ui-fg: #1a1a2e;\n --ag-ui-accent: #4f46e5;\n --ag-ui-user-bg: #4f46e5;\n --ag-ui-user-fg: #ffffff;\n --ag-ui-assistant-bg: #f1f1f6;\n --ag-ui-input-bg: var(--ag-ui-bg);\n --ag-ui-tool-bg: var(--ag-ui-assistant-bg);\n --ag-ui-tool-fg: var(--ag-ui-accent);\n --ag-ui-header-bg: var(--ag-ui-accent);\n --ag-ui-header-fg: #ffffff;\n --ag-ui-border: #e2e2ec;\n --ag-ui-radius: 12px;\n\n /* Status accents for tool-call cards. */\n --ag-ui-success: #15803d;\n --ag-ui-danger: #b91c1c;\n --ag-ui-muted: #6b7280;\n\n /* Tool-call status icon glyphs (override to re-theme) + spinner speed.\n The pending state is the animated ring; the settled states use these. */\n --ag-ui-tool-icon-done: \"\u2713\";\n --ag-ui-tool-icon-error: \"\u2715\";\n --ag-ui-tool-icon-declined: \"\u2298\";\n --ag-ui-tool-spin-duration: 0.7s;\n\n /* Answer well (opt-in via data-answer-well) \u2014 boxes a whole assistant turn. */\n --ag-ui-well-bg: transparent;\n --ag-ui-well-border: var(--ag-ui-border);\n\n /* Surface \u2014 set --ag-ui-shadow: none for a flush, embedded panel. */\n --ag-ui-shadow: 0 12px 32px rgba(20, 20, 50, 0.18);\n --ag-ui-font: inherit;\n --ag-ui-font-size: 14px;\n --ag-ui-code-font: ui-monospace, \"SF Mono\", Menlo, monospace;\n\n /* Spacing \u2014 the density preset overrides these. */\n --ag-ui-space: 10px;\n --ag-ui-pad: 16px;\n --ag-ui-msg-pad: 8px 12px;\n --ag-ui-msg-radius: 14px;\n\n /* Layout \u2014 override from outside to dock the widget anywhere.\n Set --ag-ui-position: static (and place this element in your own\n grid/flex layout) to embed it in the page flow instead of floating. */\n --ag-ui-position: fixed;\n --ag-ui-z-index: 2147483000;\n --ag-ui-width: 380px;\n --ag-ui-height: 560px;\n --ag-ui-inset: auto 24px 24px auto;\n --ag-ui-max-width: calc(100vw - 48px);\n --ag-ui-max-height: calc(100vh - 48px);\n /* Reading-column width for placement=\"page\" (full-bleed, centred content). */\n --ag-ui-content-max-width: 820px;\n\n position: var(--ag-ui-position);\n inset: var(--ag-ui-inset);\n z-index: var(--ag-ui-z-index);\n width: var(--ag-ui-width);\n max-width: var(--ag-ui-max-width);\n height: var(--ag-ui-height);\n max-height: var(--ag-ui-max-height);\n display: flex;\n font-family: var(--ag-ui-font);\n font-size: var(--ag-ui-font-size);\n color: var(--ag-ui-fg);\n}\n\n/* \u2500\u2500 Themes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Themes only re-set the colour variables; layout/spacing are unaffected.\n theme=\"auto\" follows the OS via prefers-color-scheme. */\n:host([theme=\"dark\"]) {\n --ag-ui-bg: #15151f;\n --ag-ui-fg: #e8e8f2;\n --ag-ui-assistant-bg: #25253a;\n --ag-ui-header-bg: #1f1f30;\n --ag-ui-header-fg: #e8e8f2;\n --ag-ui-border: #33334a;\n --ag-ui-muted: #9aa0b4;\n --ag-ui-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);\n}\n\n@media (prefers-color-scheme: dark) {\n :host([theme=\"auto\"]) {\n --ag-ui-bg: #15151f;\n --ag-ui-fg: #e8e8f2;\n --ag-ui-assistant-bg: #25253a;\n --ag-ui-header-bg: #1f1f30;\n --ag-ui-header-fg: #e8e8f2;\n --ag-ui-border: #33334a;\n --ag-ui-muted: #9aa0b4;\n --ag-ui-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);\n }\n}\n\n/* A terminal-flavoured \"code\" theme: dark, monospace, green accent. */\n:host([theme=\"code\"]) {\n --ag-ui-bg: #0d1117;\n --ag-ui-fg: #c9d1d9;\n --ag-ui-accent: #3fb950;\n --ag-ui-user-bg: #238636;\n --ag-ui-assistant-bg: #161b22;\n --ag-ui-header-bg: #010409;\n --ag-ui-header-fg: #c9d1d9;\n --ag-ui-border: #30363d;\n --ag-ui-muted: #8b949e;\n --ag-ui-font: var(--ag-ui-code-font);\n --ag-ui-shadow: 0 12px 32px rgba(0, 0, 0, 0.6);\n}\n\n/* \u2500\u2500 Density \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n:host([density=\"compact\"]) {\n --ag-ui-font-size: 13px;\n --ag-ui-space: 6px;\n --ag-ui-pad: 10px;\n --ag-ui-msg-pad: 5px 9px;\n --ag-ui-msg-radius: 10px;\n}\n\n/* \u2500\u2500 Placement presets \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n:host([placement=\"bottom-left\"]) {\n --ag-ui-inset: auto auto 24px 24px;\n}\n\n:host([placement=\"side\"]) {\n --ag-ui-inset: 0 0 0 auto;\n --ag-ui-width: 420px;\n --ag-ui-height: 100vh;\n --ag-ui-max-height: 100vh;\n --ag-ui-radius: 0;\n}\n\n:host([placement=\"full\"]) {\n --ag-ui-inset: 0;\n --ag-ui-width: 100vw;\n --ag-ui-height: 100vh;\n --ag-ui-max-width: 100vw;\n --ag-ui-max-height: 100vh;\n --ag-ui-radius: 0;\n}\n\n/* Page (PAGE-1): full-bleed background with a centred reading column. Unlike\n \"full\" (edge-to-edge, left-aligned messages) the content sits in a column\n capped at --ag-ui-content-max-width. The column is produced by symmetric auto\n padding on the scroll area + composer (no per-row wrapper), so user pills\n still right-align and the assistant well spans the column. */\n:host([placement=\"page\"]) {\n --ag-ui-inset: 0;\n --ag-ui-width: 100vw;\n --ag-ui-height: 100vh;\n --ag-ui-max-width: 100vw;\n --ag-ui-max-height: 100vh;\n --ag-ui-radius: 0;\n}\n\n:host([placement=\"page\"]) .messages {\n padding-inline: max(var(--ag-ui-pad), calc((100% - var(--ag-ui-content-max-width)) / 2));\n}\n\n:host([placement=\"page\"]) .input-row {\n padding-inline: max(12px, calc((100% - var(--ag-ui-content-max-width)) / 2));\n}\n\n/* The rows between the message list and the composer (skill chips, the\n /-command palette, the missing-placeholder hint, the upload tray) line up\n with the column too \u2014 chips are padding-based, the palette/hint/tray are\n margin-based, so each gets its own inline axis nudged by the same gutter. */\n:host([placement=\"page\"]) .skill-chips,\n:host([placement=\"page\"]) .attachment-tray {\n padding-inline: max(12px, calc((100% - var(--ag-ui-content-max-width)) / 2));\n}\n\n:host([placement=\"page\"]) .skill-palette,\n:host([placement=\"page\"]) .skill-hint {\n margin-inline: max(12px, calc((100% - var(--ag-ui-content-max-width)) / 2));\n}\n\n/* In the reading column the assistant well uses the full width; the user\n message stays a right-aligned pill (its default align-self + max-width). */\n:host([placement=\"page\"]) .message--assistant {\n max-width: 100%;\n}\n\n/* Sidebar (CUST-3): a full-height docked panel that slides open/closed and\n collapses to a slim icon rail (not the floating launcher). Docked right by\n default; data-side=\"left\" docks it left. Overlay by default \u2014 set\n --ag-ui-position: static (and place this element in your own layout) for a\n host-managed push instead. */\n:host([placement=\"sidebar\"]) {\n --ag-ui-inset: 0 0 0 auto;\n --ag-ui-width: 420px;\n --ag-ui-height: 100vh;\n --ag-ui-max-height: 100vh;\n --ag-ui-radius: 0;\n --ag-ui-rail-width: 52px;\n transition: width 0.28s ease;\n}\n\n:host([placement=\"sidebar\"][data-side=\"left\"]) {\n --ag-ui-inset: 0 auto 0 0;\n}\n\n:host([placement=\"sidebar\"]) .chat {\n transition: transform 0.28s ease;\n}\n\n/* Collapsed sidebar: shrink the host to the rail width, hide the panel, and\n reveal the rail. Higher specificity than the generic collapse rules, so it\n wins regardless of source order. */\n:host([placement=\"sidebar\"][collapsed]) {\n width: var(--ag-ui-rail-width);\n height: 100vh;\n max-height: 100vh;\n bottom: 0;\n}\n\n:host([placement=\"sidebar\"][collapsed]) .chat {\n display: none;\n}\n\n/* The rail is a sibling of the panel (so it survives the panel being hidden);\n shown only for a collapsed sidebar. */\n.rail {\n display: none;\n border: none;\n font: inherit;\n}\n\n:host([placement=\"sidebar\"][collapsed]) .rail {\n display: flex;\n position: absolute;\n inset: 0;\n align-items: flex-start;\n justify-content: center;\n padding-top: 16px;\n border: 1px solid var(--ag-ui-border);\n background: var(--ag-ui-header-bg);\n color: var(--ag-ui-header-fg);\n cursor: pointer;\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host([placement=\"sidebar\"]),\n :host([placement=\"sidebar\"]) .chat {\n transition: none;\n }\n}\n\n/* Embedded: drop the floating chrome and the high z-index stacking context so\n the widget lives in the host's own layout (fixes overlay/z-index clashes). */\n:host([placement=\"embedded\"]) {\n --ag-ui-position: static;\n --ag-ui-width: 100%;\n --ag-ui-height: 100%;\n --ag-ui-max-width: 100%;\n --ag-ui-max-height: 100%;\n --ag-ui-shadow: none;\n --ag-ui-z-index: auto;\n}\n\n.chat {\n position: relative;\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n background: var(--ag-ui-bg);\n border: 1px solid var(--ag-ui-border);\n border-radius: var(--ag-ui-radius);\n box-shadow: var(--ag-ui-shadow);\n overflow: hidden;\n}\n\n.header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 10px 14px;\n border-bottom: 1px solid var(--ag-ui-border);\n background: var(--ag-ui-header-bg);\n color: var(--ag-ui-header-fg);\n}\n\n.header-title {\n flex: 1;\n min-width: 0;\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Header / launcher icon holder (CUST-2): a slot, with a data-icon-url <img>\n fallback, sized via --ag-ui-icon-size. */\n.icon-holder {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: var(--ag-ui-icon-size, 22px);\n height: var(--ag-ui-icon-size, 22px);\n line-height: 1;\n}\n\n.icon-img {\n width: 100%;\n height: 100%;\n object-fit: contain;\n border-radius: var(--ag-ui-icon-radius, 4px);\n}\n\n.header-controls {\n display: flex;\n gap: 2px;\n flex: none;\n}\n\n.header-btn {\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1;\n padding: 4px 7px;\n border-radius: 6px;\n cursor: pointer;\n opacity: 0.85;\n}\n\n.header-btn:hover {\n opacity: 1;\n background: rgba(255, 255, 255, 0.18);\n}\n\n/* Collapsed: keep just the header bar \u2014 hide the whole body, and let the host\n shrink to the header. (A host can also fully hide the element itself.) */\n:host([collapsed]) {\n height: auto;\n max-height: none;\n}\n\n:host([collapsed]) .messages,\n:host([collapsed]) .input-row,\n:host([collapsed]) .skill-chips,\n:host([collapsed]) .skill-palette,\n:host([collapsed]) .skill-hint {\n display: none;\n}\n\n/* Edge-docked placements pin top *and* bottom, which would otherwise keep the\n panel full-height when collapsed; unpin the bottom so it shrinks to the\n header. (Floating/bottom-left pin only the bottom, so they already shrink.) */\n:host([collapsed][placement=\"side\"]),\n:host([collapsed][placement=\"full\"]) {\n bottom: auto;\n}\n\n.messages {\n flex: 1;\n overflow-y: auto;\n padding: var(--ag-ui-pad);\n display: flex;\n flex-direction: column;\n gap: var(--ag-ui-space);\n}\n\n/* Empty-state region (CUST-1 slot): centred while it's the only thing in the\n list, hidden as soon as a message, card, or pending indicator renders. */\n.empty {\n margin: auto;\n text-align: center;\n color: var(--ag-ui-muted);\n}\n\n.empty[hidden] {\n display: none;\n}\n\n/* \u2500\u2500 Answer group / well (WELL-1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n One .answer per assistant turn wraps the streamed text, its tool cards,\n and the pending indicator so a whole answer reads (and can be boxed) as one\n unit. A flex column on the message-list gap, stretched to the list width so\n its children keep their own left/right alignment. data-answer-well opts into\n the bordered \"well\"; without it the layout is today's flat stack. */\n.answer {\n display: flex;\n flex-direction: column;\n gap: var(--ag-ui-space);\n align-self: stretch;\n min-width: 0;\n}\n\n:host([data-answer-well]) .answer {\n padding: var(--ag-ui-pad);\n background: var(--ag-ui-well-bg);\n border: 1px solid var(--ag-ui-well-border);\n border-radius: var(--ag-ui-radius);\n}\n\n.message {\n max-width: 80%;\n padding: var(--ag-ui-msg-pad);\n border-radius: var(--ag-ui-msg-radius);\n line-height: 1.4;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n/* \u2500\u2500 Incoming-text animations (data-text-animation) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n/* .message--restored (rehydrated history) is excluded: entrance animations are\n for freshly-arriving messages, not the whole transcript replaying on reload.\n Word mode is excluded implicitly \u2014 restored bubbles aren't wrapped. */\n:host([data-text-animation=\"fade\"]) .message--assistant:not(.message--restored) {\n animation: ag-ui-msg-fade 0.25s ease both;\n}\n\n@keyframes ag-ui-msg-fade {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: none; }\n}\n\n.message--assistant .word {\n animation: ag-ui-word-in 0.3s ease both;\n animation-delay: calc(var(--ag-ui-word-index, 0) * 35ms);\n}\n\n@keyframes ag-ui-word-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host([data-text-animation=\"fade\"]) .message--assistant,\n .message--assistant .word {\n animation: none;\n }\n}\n\n.message--user {\n align-self: flex-end;\n background: var(--ag-ui-user-bg);\n color: var(--ag-ui-user-fg);\n border-bottom-right-radius: 4px;\n}\n\n.message--assistant {\n align-self: flex-start;\n background: var(--ag-ui-assistant-bg);\n border-bottom-left-radius: 4px;\n /* Assistant bubbles hold rendered markdown/HTML, so collapse the source\n whitespace the renderer leaves between block tags. */\n white-space: normal;\n}\n\n/* Rendered-markdown elements inside an assistant bubble. */\n.message--assistant > :first-child {\n margin-top: 0;\n}\n\n.message--assistant > :last-child {\n margin-bottom: 0;\n}\n\n.message--assistant p,\n.message--assistant ul,\n.message--assistant ol,\n.message--assistant blockquote,\n.message--assistant pre {\n margin: 0.5em 0;\n}\n\n.message--assistant ul,\n.message--assistant ol {\n padding-left: 1.3em;\n}\n\n.message--assistant a {\n color: var(--ag-ui-accent);\n text-decoration: underline;\n}\n\n.message--assistant code {\n font-family: ui-monospace, \"SF Mono\", Menlo, monospace;\n font-size: 0.92em;\n background: rgba(127, 127, 127, 0.16);\n padding: 1px 4px;\n border-radius: 4px;\n}\n\n.message--assistant pre {\n padding: 8px 10px;\n overflow: auto;\n background: var(--ag-ui-bg);\n border: 1px solid var(--ag-ui-border);\n border-radius: 6px;\n}\n\n.message--assistant pre code {\n background: none;\n padding: 0;\n}\n\n.message--assistant blockquote {\n padding-left: 10px;\n border-left: 3px solid var(--ag-ui-border);\n color: var(--ag-ui-muted);\n}\n\n.pending {\n align-self: flex-start;\n display: inline-flex;\n gap: 4px;\n align-items: center;\n padding: 12px 14px;\n background: var(--ag-ui-assistant-bg);\n border-radius: 14px;\n border-bottom-left-radius: 4px;\n}\n\n.pending-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--ag-ui-muted);\n animation: ag-ui-pending 1.2s infinite ease-in-out both;\n}\n\n.pending-dot:nth-child(2) {\n animation-delay: 0.16s;\n}\n\n.pending-dot:nth-child(3) {\n animation-delay: 0.32s;\n}\n\n@keyframes ag-ui-pending {\n 0%, 80%, 100% { opacity: 0.3; transform: translateY(0); }\n 40% { opacity: 1; transform: translateY(-3px); }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .pending-dot {\n animation: none;\n opacity: 0.6;\n }\n}\n\n/* \u2500\u2500 Thoughts region (THINK-1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n A muted, collapsible chain-of-thought at the top of the answer group: open\n while the model reasons, folded once the answer text starts. */\n.thoughts {\n align-self: stretch;\n display: flex;\n flex-direction: column;\n gap: 4px;\n font-size: 12px;\n color: var(--ag-ui-muted);\n}\n\n.thoughts-toggle {\n align-self: flex-start;\n border: none;\n padding: 0;\n background: none;\n font: inherit;\n font-size: 12px;\n font-weight: 600;\n color: var(--ag-ui-muted);\n cursor: pointer;\n}\n\n.thoughts-toggle::before {\n content: \"\u25BE \";\n}\n\n.thoughts-toggle[aria-expanded=\"false\"]::before {\n content: \"\u25B8 \";\n}\n\n/* A gentle pulse on the label while reasoning is still streaming. */\n.thoughts[data-streaming] .thoughts-label {\n animation: ag-ui-thoughts-pulse 1.4s ease-in-out infinite;\n}\n\n@keyframes ag-ui-thoughts-pulse {\n 0%, 100% { opacity: 0.55; }\n 50% { opacity: 1; }\n}\n\n.thoughts-body {\n margin: 0;\n padding: 4px 0 4px 10px;\n border-left: 2px solid var(--ag-ui-border);\n max-height: 220px;\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: inherit;\n}\n\n.thoughts-body[hidden] {\n display: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .thoughts[data-streaming] .thoughts-label {\n animation: none;\n }\n}\n\n.tool-call {\n align-self: flex-start;\n max-width: 80%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 6px;\n font-size: 12px;\n font-family: ui-monospace, \"SF Mono\", Menlo, monospace;\n padding: 8px 10px;\n border-radius: 8px;\n background: var(--ag-ui-tool-bg);\n border: 1px solid var(--ag-ui-border);\n color: var(--ag-ui-tool-fg);\n}\n\n.tool-call-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.tool-call-name {\n flex: 1;\n min-width: 0;\n font-weight: 600;\n word-break: break-word;\n}\n\n/* Leading status icon (CARD-1). Empty in the DOM \u2014 the glyph/spinner is drawn\n here from the card's data-status, so it stays themeable. */\n.tool-call-icon {\n flex: none;\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 14px;\n font-size: 12px;\n line-height: 1;\n}\n\n/* Pending: a real spinning ring. Speed is tunable; reduced motion stops it. */\n.tool-call[data-status=\"pending\"] .tool-call-icon {\n border: 2px solid var(--ag-ui-muted);\n border-top-color: transparent;\n border-radius: 50%;\n animation: ag-ui-tool-spin var(--ag-ui-tool-spin-duration) linear infinite;\n}\n\n@keyframes ag-ui-tool-spin {\n to { transform: rotate(360deg); }\n}\n\n/* Settled: a themeable glyph coloured by outcome. */\n.tool-call[data-status=\"done\"] .tool-call-icon::before {\n content: var(--ag-ui-tool-icon-done);\n color: var(--ag-ui-success);\n}\n\n.tool-call[data-status=\"error\"] .tool-call-icon::before {\n content: var(--ag-ui-tool-icon-error);\n color: var(--ag-ui-danger);\n}\n\n.tool-call[data-status=\"declined\"] .tool-call-icon::before {\n content: var(--ag-ui-tool-icon-declined);\n color: var(--ag-ui-muted);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .tool-call[data-status=\"pending\"] .tool-call-icon {\n animation: none;\n }\n}\n\n/* Inline display mode (CARD-1): the lightest card \u2014 drop the box chrome so the\n status row reads as one line of the answer; the result toggle still expands\n below it. */\n.tool-call[data-display=\"inline\"] {\n max-width: 100%;\n background: transparent;\n border: none;\n padding: 2px 0;\n gap: 2px;\n}\n\n.tool-call-status {\n flex: none;\n padding: 1px 8px;\n border-radius: 999px;\n font-size: 11px;\n font-weight: 600;\n background: rgba(127, 127, 127, 0.16);\n color: var(--ag-ui-muted);\n}\n\n.tool-call[data-status=\"done\"] .tool-call-status {\n color: var(--ag-ui-success);\n}\n\n.tool-call[data-status=\"error\"] .tool-call-status {\n color: var(--ag-ui-danger);\n}\n\n.tool-call[data-status=\"declined\"] .tool-call-status {\n color: var(--ag-ui-muted);\n}\n\n.tool-call-args,\n.tool-call-result {\n margin: 0;\n padding: 6px 8px;\n max-height: 160px;\n overflow: auto;\n background: var(--ag-ui-bg);\n border: 1px solid var(--ag-ui-border);\n border-radius: 6px;\n white-space: pre-wrap;\n word-break: break-word;\n color: var(--ag-ui-fg);\n}\n\n.tool-call-toggle {\n align-self: flex-start;\n border: none;\n padding: 0;\n background: none;\n font: inherit;\n font-weight: 600;\n color: var(--ag-ui-accent);\n cursor: pointer;\n}\n\n.tool-call-toggle::before {\n content: \"\u25B8 \";\n}\n\n.tool-call-toggle[aria-expanded=\"true\"]::before {\n content: \"\u25BE \";\n}\n\n.input-row {\n display: flex;\n gap: 8px;\n padding: 12px;\n border-top: 1px solid var(--ag-ui-border);\n}\n\n.input {\n flex: 1;\n resize: none;\n background: var(--ag-ui-input-bg);\n border: 1px solid var(--ag-ui-border);\n border-radius: 8px;\n padding: 8px 10px;\n font: inherit;\n color: inherit;\n outline: none;\n}\n\n.input:focus {\n border-color: var(--ag-ui-accent);\n}\n\n.send {\n border: none;\n border-radius: 8px;\n padding: 0 16px;\n background: var(--ag-ui-accent);\n color: #ffffff;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n}\n\n.send:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n/* The composer button doubles as the Stop control while a run is in flight. */\n.send[data-state=\"running\"] {\n background: var(--ag-ui-muted);\n}\n\n/* \u2500\u2500 File attachments \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n/* The \uD83D\uDCCE picker button sits left of the input; hidden until data-attachments-url. */\n.attach-btn {\n border: 1px solid var(--ag-ui-border);\n border-radius: 8px;\n padding: 0 10px;\n background: var(--ag-ui-input-bg);\n color: inherit;\n font: inherit;\n cursor: pointer;\n}\n\n.attach-btn:hover {\n border-color: var(--ag-ui-accent);\n}\n\n.attach-input {\n display: none;\n}\n\n/* The \uD83C\uDFA4 mic button (VOICE-1); shown only once #wireVoice mounts it. */\n.voice-slot {\n display: contents;\n}\n\n.voice-btn {\n border: 1px solid var(--ag-ui-border);\n border-radius: 8px;\n padding: 0 10px;\n background: var(--ag-ui-input-bg);\n color: inherit;\n font: inherit;\n cursor: pointer;\n}\n\n.voice-btn:hover {\n border-color: var(--ag-ui-accent);\n}\n\n.voice-btn:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n/* Recording: a red tint + a gentle pulse so it's clearly \"live\". */\n.voice-btn[data-state=\"recording\"] {\n border-color: var(--ag-ui-danger);\n background: var(--ag-ui-danger);\n color: #ffffff;\n animation: ag-ui-voice-pulse 1.2s ease-in-out infinite;\n}\n\n@keyframes ag-ui-voice-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.6; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .voice-btn[data-state=\"recording\"] {\n animation: none;\n }\n}\n\n/* Pending-attachments tray, above the input row; collapses (hidden) when empty. */\n.attachment-slot {\n display: contents;\n}\n\n.attachment-tray {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 8px 12px 0;\n}\n\n.attachment-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 6px;\n}\n\n.attachment-chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n max-width: 100%;\n padding: 4px 8px;\n border: 1px solid var(--ag-ui-border);\n border-radius: 999px;\n background: var(--ag-ui-assistant-bg);\n font-size: 0.85em;\n position: relative;\n}\n\n.attachment-chip--error {\n border-color: var(--ag-ui-danger);\n color: var(--ag-ui-danger);\n}\n\n.attachment-chip-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 14ch;\n}\n\n.attachment-chip-size {\n color: var(--ag-ui-muted);\n white-space: nowrap;\n}\n\n.attachment-chip--error .attachment-chip-size {\n color: var(--ag-ui-danger);\n}\n\n/* The progress bar fills as the file uploads. */\n.attachment-chip-bar {\n flex-basis: 100%;\n height: 3px;\n border-radius: 2px;\n background: var(--ag-ui-border);\n overflow: hidden;\n}\n\n.attachment-chip-bar-fill {\n height: 100%;\n background: var(--ag-ui-accent);\n transition: width 0.15s ease;\n}\n\n.attachment-chip-remove,\n.attachment-chip-retry {\n border: none;\n background: none;\n color: inherit;\n cursor: pointer;\n padding: 0;\n line-height: 1;\n opacity: 0.7;\n}\n\n.attachment-chip-remove:hover,\n.attachment-chip-retry:hover {\n opacity: 1;\n}\n\n/* A subtle outline while a file is dragged over the shell. */\n.chat--dragover {\n outline: 2px dashed var(--ag-ui-accent);\n outline-offset: -4px;\n}\n\n/* Muted \"\u23F9 Stopped\" line after a cancelled run \u2014 a note, not an error bubble. */\n.stopped-note {\n align-self: flex-start;\n color: var(--ag-ui-muted);\n font-size: 12px;\n padding: 2px 4px;\n}\n\n/* Inline confirmation card \u2014 lives in the transcript, no focus-stealing overlay. */\n.confirm {\n align-self: stretch;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n background: var(--ag-ui-bg);\n border: 1px solid var(--ag-ui-accent);\n border-radius: 10px;\n}\n\n.confirm[data-resolved] {\n opacity: 0.7;\n border-color: var(--ag-ui-border);\n}\n\n.confirm-body {\n font-weight: 600;\n}\n\n.confirm-args {\n margin: 0;\n padding: 8px 10px;\n max-height: 140px;\n overflow: auto;\n font-size: 12px;\n font-family: ui-monospace, \"SF Mono\", Menlo, monospace;\n background: var(--ag-ui-assistant-bg);\n border-radius: 8px;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.confirm-actions {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n}\n\n.confirm-btn {\n border: 1px solid var(--ag-ui-border);\n border-radius: 8px;\n padding: 8px 14px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n background: var(--ag-ui-bg);\n color: var(--ag-ui-fg);\n}\n\n.confirm-btn:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.confirm-btn--confirm {\n border-color: var(--ag-ui-accent);\n background: var(--ag-ui-accent);\n color: #ffffff;\n}\n\n/* Skills \u2014 chips row + the /-command palette, above the input. */\n.skill-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 10px 12px;\n}\n\n.skill-chip {\n border: 1px solid var(--ag-ui-border);\n border-radius: 999px;\n padding: 4px 12px;\n font: inherit;\n font-size: 0.9em;\n cursor: pointer;\n background: var(--ag-ui-assistant-bg);\n color: var(--ag-ui-fg);\n}\n\n.skill-chip:hover {\n border-color: var(--ag-ui-accent);\n}\n\n.skill-palette {\n margin: 8px 12px 0;\n display: flex;\n flex-direction: column;\n max-height: 220px;\n overflow: auto;\n background: var(--ag-ui-bg);\n border: 1px solid var(--ag-ui-border);\n border-radius: 8px;\n box-shadow: 0 8px 24px rgba(20, 20, 50, 0.16);\n}\n\n.skill-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n align-items: flex-start;\n padding: 8px 12px;\n border: none;\n background: none;\n font: inherit;\n text-align: left;\n cursor: pointer;\n color: var(--ag-ui-fg);\n}\n\n.skill-item[aria-selected=\"true\"] {\n background: var(--ag-ui-assistant-bg);\n}\n\n.skill-item-title {\n font-weight: 600;\n}\n\n.skill-item-desc {\n font-size: 0.85em;\n color: var(--ag-ui-muted);\n}\n\n.skill-hint {\n margin: 8px 12px 0;\n font-size: 0.85em;\n color: var(--ag-ui-danger);\n}\n\n/* Chat-history drawer \u2014 a slide-over within the chat panel. */\n.drawer {\n position: absolute;\n inset: 0;\n z-index: 5;\n display: flex;\n}\n\n.drawer[hidden] {\n display: none;\n}\n\n.drawer-backdrop {\n position: absolute;\n inset: 0;\n background: rgba(20, 20, 50, 0.32);\n}\n\n.drawer-panel {\n position: relative;\n display: flex;\n flex-direction: column;\n width: min(300px, 85%);\n height: 100%;\n background: var(--ag-ui-bg);\n border-right: 1px solid var(--ag-ui-border);\n box-shadow: var(--ag-ui-shadow);\n overflow: hidden;\n}\n\n.drawer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--ag-ui-space);\n padding: var(--ag-ui-pad);\n border-bottom: 1px solid var(--ag-ui-border);\n}\n\n.drawer-title {\n font-weight: 600;\n}\n\n.drawer-new {\n border: 1px solid var(--ag-ui-border);\n border-radius: var(--ag-ui-radius);\n background: var(--ag-ui-bg);\n color: var(--ag-ui-accent);\n padding: 4px 10px;\n font: inherit;\n font-size: 0.85em;\n cursor: pointer;\n}\n\n.drawer-list {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n\n.drawer-empty {\n padding: var(--ag-ui-pad);\n font-size: 0.9em;\n color: var(--ag-ui-muted);\n}\n\n.drawer-row {\n display: flex;\n align-items: stretch;\n border-bottom: 1px solid var(--ag-ui-border);\n}\n\n.drawer-row--active {\n background: var(--ag-ui-assistant-bg);\n}\n\n.drawer-row-select {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 8px 12px;\n border: none;\n background: none;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.drawer-row-title {\n font-weight: 600;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.drawer-row-time {\n font-size: 0.72em;\n color: var(--ag-ui-muted);\n}\n\n.drawer-row-preview {\n font-size: 0.8em;\n color: var(--ag-ui-muted);\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.drawer-row-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 0 6px;\n}\n\n.drawer-row-rename,\n.drawer-row-delete {\n border: none;\n background: none;\n color: var(--ag-ui-muted);\n font-size: 0.9em;\n padding: 4px;\n cursor: pointer;\n}\n\n.drawer-rename-input {\n flex: 1;\n min-width: 0;\n margin: 6px 10px;\n padding: 4px 8px;\n border: 1px solid var(--ag-ui-accent);\n border-radius: 6px;\n background: var(--ag-ui-input-bg);\n color: var(--ag-ui-fg);\n font: inherit;\n}\n\n.drawer-confirm {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n font-size: 0.85em;\n}\n\n.drawer-confirm-label {\n color: var(--ag-ui-danger);\n}\n\n.drawer-confirm-yes {\n border: none;\n border-radius: 6px;\n background: var(--ag-ui-danger);\n color: #ffffff;\n padding: 3px 10px;\n font: inherit;\n cursor: pointer;\n}\n\n.drawer-confirm-no {\n border: 1px solid var(--ag-ui-border);\n border-radius: 6px;\n background: none;\n color: inherit;\n padding: 3px 10px;\n font: inherit;\n cursor: pointer;\n}\n\n/* Embedded placement: an inline, flush side panel rather than a dimmed,\n floating slide-over. */\n:host([placement=\"embedded\"]) .drawer-backdrop {\n background: none;\n}\n\n:host([placement=\"embedded\"]) .drawer-panel {\n width: 100%;\n border-right: none;\n box-shadow: none;\n}\n";
1
+ export declare const STYLES = "\n:host {\n /* Colors */\n --ag-ui-bg: #ffffff;\n --ag-ui-fg: #1a1a2e;\n --ag-ui-accent: #4f46e5;\n --ag-ui-user-bg: #4f46e5;\n --ag-ui-user-fg: #ffffff;\n --ag-ui-assistant-bg: #f1f1f6;\n --ag-ui-input-bg: var(--ag-ui-bg);\n --ag-ui-tool-bg: var(--ag-ui-assistant-bg);\n --ag-ui-tool-fg: var(--ag-ui-accent);\n --ag-ui-header-bg: var(--ag-ui-accent);\n --ag-ui-header-fg: #ffffff;\n --ag-ui-border: #e2e2ec;\n --ag-ui-radius: 12px;\n\n /* Status accents for tool-call cards. */\n --ag-ui-success: #15803d;\n --ag-ui-danger: #b91c1c;\n --ag-ui-muted: #6b7280;\n\n /* Tool-call status icon glyphs (override to re-theme) + spinner speed.\n The pending state is the animated ring; the settled states use these. */\n --ag-ui-tool-icon-done: \"\u2713\";\n --ag-ui-tool-icon-error: \"\u2715\";\n --ag-ui-tool-icon-declined: \"\u2298\";\n --ag-ui-tool-spin-duration: 0.7s;\n\n /* Answer well (opt-in via data-answer-well) \u2014 boxes a whole assistant turn. */\n --ag-ui-well-bg: transparent;\n --ag-ui-well-border: var(--ag-ui-border);\n\n /* Surface \u2014 set --ag-ui-shadow: none for a flush, embedded panel. */\n --ag-ui-shadow: 0 12px 32px rgba(20, 20, 50, 0.18);\n --ag-ui-font: inherit;\n --ag-ui-font-size: 14px;\n --ag-ui-code-font: ui-monospace, \"SF Mono\", Menlo, monospace;\n\n /* Spacing \u2014 the density preset overrides these. */\n --ag-ui-space: 10px;\n --ag-ui-pad: 16px;\n --ag-ui-msg-pad: 8px 12px;\n --ag-ui-msg-radius: 14px;\n\n /* Layout \u2014 override from outside to dock the widget anywhere.\n Set --ag-ui-position: static (and place this element in your own\n grid/flex layout) to embed it in the page flow instead of floating. */\n --ag-ui-position: fixed;\n --ag-ui-z-index: 2147483000;\n --ag-ui-width: 380px;\n --ag-ui-height: 560px;\n --ag-ui-inset: auto 24px 24px auto;\n --ag-ui-max-width: calc(100vw - 48px);\n --ag-ui-max-height: calc(100vh - 48px);\n /* Reading-column width for placement=\"page\" (full-bleed, centred content). */\n --ag-ui-content-max-width: 820px;\n\n position: var(--ag-ui-position);\n inset: var(--ag-ui-inset);\n z-index: var(--ag-ui-z-index);\n width: var(--ag-ui-width);\n max-width: var(--ag-ui-max-width);\n height: var(--ag-ui-height);\n max-height: var(--ag-ui-max-height);\n display: flex;\n font-family: var(--ag-ui-font);\n font-size: var(--ag-ui-font-size);\n color: var(--ag-ui-fg);\n}\n\n/* \u2500\u2500 Themes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Themes only re-set the colour variables; layout/spacing are unaffected.\n theme=\"auto\" follows the OS via prefers-color-scheme. */\n:host([theme=\"dark\"]) {\n --ag-ui-bg: #15151f;\n --ag-ui-fg: #e8e8f2;\n --ag-ui-assistant-bg: #25253a;\n --ag-ui-header-bg: #1f1f30;\n --ag-ui-header-fg: #e8e8f2;\n --ag-ui-border: #33334a;\n --ag-ui-muted: #9aa0b4;\n --ag-ui-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);\n}\n\n@media (prefers-color-scheme: dark) {\n :host([theme=\"auto\"]) {\n --ag-ui-bg: #15151f;\n --ag-ui-fg: #e8e8f2;\n --ag-ui-assistant-bg: #25253a;\n --ag-ui-header-bg: #1f1f30;\n --ag-ui-header-fg: #e8e8f2;\n --ag-ui-border: #33334a;\n --ag-ui-muted: #9aa0b4;\n --ag-ui-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);\n }\n}\n\n/* A terminal-flavoured \"code\" theme: dark, monospace, green accent. */\n:host([theme=\"code\"]) {\n --ag-ui-bg: #0d1117;\n --ag-ui-fg: #c9d1d9;\n --ag-ui-accent: #3fb950;\n --ag-ui-user-bg: #238636;\n --ag-ui-assistant-bg: #161b22;\n --ag-ui-header-bg: #010409;\n --ag-ui-header-fg: #c9d1d9;\n --ag-ui-border: #30363d;\n --ag-ui-muted: #8b949e;\n --ag-ui-font: var(--ag-ui-code-font);\n --ag-ui-shadow: 0 12px 32px rgba(0, 0, 0, 0.6);\n}\n\n/* \u2500\u2500 Density \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n:host([density=\"compact\"]) {\n --ag-ui-font-size: 13px;\n --ag-ui-space: 6px;\n --ag-ui-pad: 10px;\n --ag-ui-msg-pad: 5px 9px;\n --ag-ui-msg-radius: 10px;\n}\n\n/* \u2500\u2500 Placement presets \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n:host([placement=\"bottom-left\"]) {\n --ag-ui-inset: auto auto 24px 24px;\n}\n\n:host([placement=\"side\"]) {\n --ag-ui-inset: 0 0 0 auto;\n --ag-ui-width: 420px;\n --ag-ui-height: 100vh;\n --ag-ui-max-height: 100vh;\n --ag-ui-radius: 0;\n}\n\n:host([placement=\"full\"]) {\n --ag-ui-inset: 0;\n --ag-ui-width: 100vw;\n --ag-ui-height: 100vh;\n --ag-ui-max-width: 100vw;\n --ag-ui-max-height: 100vh;\n --ag-ui-radius: 0;\n}\n\n/* Page: full-bleed background with a centred reading column. Unlike\n \"full\" (edge-to-edge, left-aligned messages) the content sits in a column\n capped at --ag-ui-content-max-width. The column is produced by symmetric auto\n padding on the scroll area + composer (no per-row wrapper), so user pills\n still right-align and the assistant well spans the column. */\n:host([placement=\"page\"]) {\n --ag-ui-inset: 0;\n --ag-ui-width: 100vw;\n --ag-ui-height: 100vh;\n --ag-ui-max-width: 100vw;\n --ag-ui-max-height: 100vh;\n --ag-ui-radius: 0;\n}\n\n:host([placement=\"page\"]) .messages {\n padding-inline: max(var(--ag-ui-pad), calc((100% - var(--ag-ui-content-max-width)) / 2));\n}\n\n:host([placement=\"page\"]) .input-row {\n padding-inline: max(12px, calc((100% - var(--ag-ui-content-max-width)) / 2));\n}\n\n/* The rows between the message list and the composer (skill chips, the\n /-command palette, the missing-placeholder hint, the upload tray) line up\n with the column too \u2014 chips are padding-based, the palette/hint/tray are\n margin-based, so each gets its own inline axis nudged by the same gutter. */\n:host([placement=\"page\"]) .skill-chips,\n:host([placement=\"page\"]) .attachment-tray {\n padding-inline: max(12px, calc((100% - var(--ag-ui-content-max-width)) / 2));\n}\n\n:host([placement=\"page\"]) .skill-palette,\n:host([placement=\"page\"]) .skill-hint {\n margin-inline: max(12px, calc((100% - var(--ag-ui-content-max-width)) / 2));\n}\n\n/* In the reading column the assistant well uses the full width; the user\n message stays a right-aligned pill (its default align-self + max-width). */\n:host([placement=\"page\"]) .message--assistant {\n max-width: 100%;\n}\n\n/* Sidebar: a full-height docked panel that slides open/closed and\n collapses to a slim icon rail (not the floating launcher). Docked right by\n default; data-side=\"left\" docks it left. Overlay by default \u2014 set\n --ag-ui-position: static (and place this element in your own layout) for a\n host-managed push instead. */\n:host([placement=\"sidebar\"]) {\n --ag-ui-inset: 0 0 0 auto;\n --ag-ui-width: 420px;\n --ag-ui-height: 100vh;\n --ag-ui-max-height: 100vh;\n --ag-ui-radius: 0;\n --ag-ui-rail-width: 52px;\n transition: width 0.28s ease;\n}\n\n:host([placement=\"sidebar\"][data-side=\"left\"]) {\n --ag-ui-inset: 0 auto 0 0;\n}\n\n:host([placement=\"sidebar\"]) .chat {\n transition: transform 0.28s ease;\n}\n\n/* Collapsed sidebar: shrink the host to the rail width, hide the panel, and\n reveal the rail. Higher specificity than the generic collapse rules, so it\n wins regardless of source order. */\n:host([placement=\"sidebar\"][collapsed]) {\n width: var(--ag-ui-rail-width);\n height: 100vh;\n max-height: 100vh;\n bottom: 0;\n}\n\n:host([placement=\"sidebar\"][collapsed]) .chat {\n display: none;\n}\n\n/* The rail is a sibling of the panel (so it survives the panel being hidden);\n shown only for a collapsed sidebar. */\n.rail {\n display: none;\n border: none;\n font: inherit;\n}\n\n:host([placement=\"sidebar\"][collapsed]) .rail {\n display: flex;\n position: absolute;\n inset: 0;\n align-items: flex-start;\n justify-content: center;\n padding-top: 16px;\n border: 1px solid var(--ag-ui-border);\n background: var(--ag-ui-header-bg);\n color: var(--ag-ui-header-fg);\n cursor: pointer;\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host([placement=\"sidebar\"]),\n :host([placement=\"sidebar\"]) .chat {\n transition: none;\n }\n}\n\n/* Embedded: drop the floating chrome and the high z-index stacking context so\n the widget lives in the host's own layout (fixes overlay/z-index clashes). */\n:host([placement=\"embedded\"]) {\n --ag-ui-position: static;\n --ag-ui-width: 100%;\n --ag-ui-height: 100%;\n --ag-ui-max-width: 100%;\n --ag-ui-max-height: 100%;\n --ag-ui-shadow: none;\n --ag-ui-z-index: auto;\n}\n\n.chat {\n position: relative;\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n background: var(--ag-ui-bg);\n border: 1px solid var(--ag-ui-border);\n border-radius: var(--ag-ui-radius);\n box-shadow: var(--ag-ui-shadow);\n overflow: hidden;\n}\n\n.header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 10px 14px;\n border-bottom: 1px solid var(--ag-ui-border);\n background: var(--ag-ui-header-bg);\n color: var(--ag-ui-header-fg);\n}\n\n.header-title {\n flex: 1;\n min-width: 0;\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Header / launcher icon holder: a slot, with a data-icon-url <img>\n fallback, sized via --ag-ui-icon-size. */\n.icon-holder {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: var(--ag-ui-icon-size, 22px);\n height: var(--ag-ui-icon-size, 22px);\n line-height: 1;\n}\n\n.icon-img {\n width: 100%;\n height: 100%;\n object-fit: contain;\n border-radius: var(--ag-ui-icon-radius, 4px);\n}\n\n.header-controls {\n display: flex;\n gap: 2px;\n flex: none;\n}\n\n.header-btn {\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1;\n padding: 4px 7px;\n border-radius: 6px;\n cursor: pointer;\n opacity: 0.85;\n}\n\n.header-btn:hover {\n opacity: 1;\n background: rgba(255, 255, 255, 0.18);\n}\n\n/* Collapsed: keep just the header bar \u2014 hide the whole body, and let the host\n shrink to the header. (A host can also fully hide the element itself.) */\n:host([collapsed]) {\n height: auto;\n max-height: none;\n}\n\n:host([collapsed]) .messages,\n:host([collapsed]) .input-row,\n:host([collapsed]) .skill-chips,\n:host([collapsed]) .skill-palette,\n:host([collapsed]) .skill-hint {\n display: none;\n}\n\n/* Edge-docked placements pin top *and* bottom, which would otherwise keep the\n panel full-height when collapsed; unpin the bottom so it shrinks to the\n header. (Floating/bottom-left pin only the bottom, so they already shrink.) */\n:host([collapsed][placement=\"side\"]),\n:host([collapsed][placement=\"full\"]) {\n bottom: auto;\n}\n\n.messages {\n flex: 1;\n overflow-y: auto;\n padding: var(--ag-ui-pad);\n display: flex;\n flex-direction: column;\n gap: var(--ag-ui-space);\n}\n\n/* Empty-state region (slot): centred while it's the only thing in the\n list, hidden as soon as a message, card, or pending indicator renders. */\n.empty {\n margin: auto;\n text-align: center;\n color: var(--ag-ui-muted);\n}\n\n.empty[hidden] {\n display: none;\n}\n\n/* \u2500\u2500 Answer group / well \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n One .answer per assistant turn wraps the streamed text, its tool cards,\n and the pending indicator so a whole answer reads (and can be boxed) as one\n unit. A flex column on the message-list gap, stretched to the list width so\n its children keep their own left/right alignment. data-answer-well opts into\n the bordered \"well\"; without it the layout is today's flat stack. */\n.answer {\n display: flex;\n flex-direction: column;\n gap: var(--ag-ui-space);\n align-self: stretch;\n min-width: 0;\n}\n\n:host([data-answer-well]) .answer {\n padding: var(--ag-ui-pad);\n background: var(--ag-ui-well-bg);\n border: 1px solid var(--ag-ui-well-border);\n border-radius: var(--ag-ui-radius);\n}\n\n.message {\n max-width: 80%;\n padding: var(--ag-ui-msg-pad);\n border-radius: var(--ag-ui-msg-radius);\n line-height: 1.4;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n/* \u2500\u2500 Incoming-text animations (data-text-animation) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n/* .message--restored (rehydrated history) is excluded: entrance animations are\n for freshly-arriving messages, not the whole transcript replaying on reload.\n Word mode is excluded implicitly \u2014 restored bubbles aren't wrapped. */\n:host([data-text-animation=\"fade\"]) .message--assistant:not(.message--restored) {\n animation: ag-ui-msg-fade 0.25s ease both;\n}\n\n@keyframes ag-ui-msg-fade {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: none; }\n}\n\n.message--assistant .word {\n animation: ag-ui-word-in 0.3s ease both;\n animation-delay: calc(var(--ag-ui-word-index, 0) * 35ms);\n}\n\n@keyframes ag-ui-word-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host([data-text-animation=\"fade\"]) .message--assistant,\n .message--assistant .word {\n animation: none;\n }\n}\n\n.message--user {\n align-self: flex-end;\n background: var(--ag-ui-user-bg);\n color: var(--ag-ui-user-fg);\n border-bottom-right-radius: 4px;\n}\n\n.message--assistant {\n align-self: flex-start;\n background: var(--ag-ui-assistant-bg);\n border-bottom-left-radius: 4px;\n /* Assistant bubbles hold rendered markdown/HTML, so collapse the source\n whitespace the renderer leaves between block tags. */\n white-space: normal;\n}\n\n/* Rendered-markdown elements inside an assistant bubble. */\n.message--assistant > :first-child {\n margin-top: 0;\n}\n\n.message--assistant > :last-child {\n margin-bottom: 0;\n}\n\n.message--assistant p,\n.message--assistant ul,\n.message--assistant ol,\n.message--assistant blockquote,\n.message--assistant pre {\n margin: 0.5em 0;\n}\n\n.message--assistant ul,\n.message--assistant ol {\n padding-left: 1.3em;\n}\n\n.message--assistant a {\n color: var(--ag-ui-accent);\n text-decoration: underline;\n}\n\n.message--assistant code {\n font-family: ui-monospace, \"SF Mono\", Menlo, monospace;\n font-size: 0.92em;\n background: rgba(127, 127, 127, 0.16);\n padding: 1px 4px;\n border-radius: 4px;\n}\n\n.message--assistant pre {\n padding: 8px 10px;\n overflow: auto;\n background: var(--ag-ui-bg);\n border: 1px solid var(--ag-ui-border);\n border-radius: 6px;\n}\n\n.message--assistant pre code {\n background: none;\n padding: 0;\n}\n\n.message--assistant blockquote {\n padding-left: 10px;\n border-left: 3px solid var(--ag-ui-border);\n color: var(--ag-ui-muted);\n}\n\n.pending {\n align-self: flex-start;\n display: inline-flex;\n gap: 4px;\n align-items: center;\n padding: 12px 14px;\n background: var(--ag-ui-assistant-bg);\n border-radius: 14px;\n border-bottom-left-radius: 4px;\n}\n\n.pending-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--ag-ui-muted);\n animation: ag-ui-pending 1.2s infinite ease-in-out both;\n}\n\n.pending-dot:nth-child(2) {\n animation-delay: 0.16s;\n}\n\n.pending-dot:nth-child(3) {\n animation-delay: 0.32s;\n}\n\n@keyframes ag-ui-pending {\n 0%, 80%, 100% { opacity: 0.3; transform: translateY(0); }\n 40% { opacity: 1; transform: translateY(-3px); }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .pending-dot {\n animation: none;\n opacity: 0.6;\n }\n}\n\n/* \u2500\u2500 Thoughts region \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n A muted, collapsible chain-of-thought at the top of the answer group: open\n while the model reasons, folded once the answer text starts. */\n.thoughts {\n align-self: stretch;\n display: flex;\n flex-direction: column;\n gap: 4px;\n font-size: 12px;\n color: var(--ag-ui-muted);\n}\n\n.thoughts-toggle {\n align-self: flex-start;\n border: none;\n padding: 0;\n background: none;\n font: inherit;\n font-size: 12px;\n font-weight: 600;\n color: var(--ag-ui-muted);\n cursor: pointer;\n}\n\n.thoughts-toggle::before {\n content: \"\u25BE \";\n}\n\n.thoughts-toggle[aria-expanded=\"false\"]::before {\n content: \"\u25B8 \";\n}\n\n/* A gentle pulse on the label while reasoning is still streaming. */\n.thoughts[data-streaming] .thoughts-label {\n animation: ag-ui-thoughts-pulse 1.4s ease-in-out infinite;\n}\n\n@keyframes ag-ui-thoughts-pulse {\n 0%, 100% { opacity: 0.55; }\n 50% { opacity: 1; }\n}\n\n.thoughts-body {\n margin: 0;\n padding: 4px 0 4px 10px;\n border-left: 2px solid var(--ag-ui-border);\n max-height: 220px;\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: inherit;\n}\n\n.thoughts-body[hidden] {\n display: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .thoughts[data-streaming] .thoughts-label {\n animation: none;\n }\n}\n\n.tool-call {\n align-self: flex-start;\n max-width: 80%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 6px;\n font-size: 12px;\n font-family: ui-monospace, \"SF Mono\", Menlo, monospace;\n padding: 8px 10px;\n border-radius: 8px;\n background: var(--ag-ui-tool-bg);\n border: 1px solid var(--ag-ui-border);\n color: var(--ag-ui-tool-fg);\n}\n\n.tool-call-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.tool-call-name {\n flex: 1;\n min-width: 0;\n font-weight: 600;\n word-break: break-word;\n}\n\n/* Leading status icon. Empty in the DOM \u2014 the glyph/spinner is drawn\n here from the card's data-status, so it stays themeable. */\n.tool-call-icon {\n flex: none;\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 14px;\n font-size: 12px;\n line-height: 1;\n}\n\n/* Pending: a real spinning ring. Speed is tunable; reduced motion stops it. */\n.tool-call[data-status=\"pending\"] .tool-call-icon {\n border: 2px solid var(--ag-ui-muted);\n border-top-color: transparent;\n border-radius: 50%;\n animation: ag-ui-tool-spin var(--ag-ui-tool-spin-duration) linear infinite;\n}\n\n@keyframes ag-ui-tool-spin {\n to { transform: rotate(360deg); }\n}\n\n/* Settled: a themeable glyph coloured by outcome. */\n.tool-call[data-status=\"done\"] .tool-call-icon::before {\n content: var(--ag-ui-tool-icon-done);\n color: var(--ag-ui-success);\n}\n\n.tool-call[data-status=\"error\"] .tool-call-icon::before {\n content: var(--ag-ui-tool-icon-error);\n color: var(--ag-ui-danger);\n}\n\n.tool-call[data-status=\"declined\"] .tool-call-icon::before {\n content: var(--ag-ui-tool-icon-declined);\n color: var(--ag-ui-muted);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .tool-call[data-status=\"pending\"] .tool-call-icon {\n animation: none;\n }\n}\n\n/* Inline display mode: the lightest card \u2014 drop the box chrome so the\n status row reads as one line of the answer; the result toggle still expands\n below it. */\n.tool-call[data-display=\"inline\"] {\n max-width: 100%;\n background: transparent;\n border: none;\n padding: 2px 0;\n gap: 2px;\n}\n\n.tool-call-status {\n flex: none;\n padding: 1px 8px;\n border-radius: 999px;\n font-size: 11px;\n font-weight: 600;\n background: rgba(127, 127, 127, 0.16);\n color: var(--ag-ui-muted);\n}\n\n.tool-call[data-status=\"done\"] .tool-call-status {\n color: var(--ag-ui-success);\n}\n\n.tool-call[data-status=\"error\"] .tool-call-status {\n color: var(--ag-ui-danger);\n}\n\n.tool-call[data-status=\"declined\"] .tool-call-status {\n color: var(--ag-ui-muted);\n}\n\n.tool-call-args,\n.tool-call-result {\n margin: 0;\n padding: 6px 8px;\n max-height: 160px;\n overflow: auto;\n background: var(--ag-ui-bg);\n border: 1px solid var(--ag-ui-border);\n border-radius: 6px;\n white-space: pre-wrap;\n word-break: break-word;\n color: var(--ag-ui-fg);\n}\n\n.tool-call-toggle {\n align-self: flex-start;\n border: none;\n padding: 0;\n background: none;\n font: inherit;\n font-weight: 600;\n color: var(--ag-ui-accent);\n cursor: pointer;\n}\n\n.tool-call-toggle::before {\n content: \"\u25B8 \";\n}\n\n.tool-call-toggle[aria-expanded=\"true\"]::before {\n content: \"\u25BE \";\n}\n\n.input-row {\n display: flex;\n gap: 8px;\n padding: 12px;\n border-top: 1px solid var(--ag-ui-border);\n}\n\n.input {\n flex: 1;\n resize: none;\n background: var(--ag-ui-input-bg);\n border: 1px solid var(--ag-ui-border);\n border-radius: 8px;\n padding: 8px 10px;\n font: inherit;\n color: inherit;\n outline: none;\n}\n\n.input:focus {\n border-color: var(--ag-ui-accent);\n}\n\n.send {\n border: none;\n border-radius: 8px;\n padding: 0 16px;\n background: var(--ag-ui-accent);\n color: #ffffff;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n}\n\n.send:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n/* The composer button doubles as the Stop control while a run is in flight. */\n.send[data-state=\"running\"] {\n background: var(--ag-ui-muted);\n}\n\n/* \u2500\u2500 File attachments \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n/* The \uD83D\uDCCE picker button sits left of the input; hidden until data-attachments-url. */\n.attach-btn {\n border: 1px solid var(--ag-ui-border);\n border-radius: 8px;\n padding: 0 10px;\n background: var(--ag-ui-input-bg);\n color: inherit;\n font: inherit;\n cursor: pointer;\n}\n\n.attach-btn:hover {\n border-color: var(--ag-ui-accent);\n}\n\n.attach-input {\n display: none;\n}\n\n/* The \uD83C\uDFA4 mic button; shown only once #wireVoice mounts it. */\n.voice-slot {\n display: contents;\n}\n\n.voice-btn {\n border: 1px solid var(--ag-ui-border);\n border-radius: 8px;\n padding: 0 10px;\n background: var(--ag-ui-input-bg);\n color: inherit;\n font: inherit;\n cursor: pointer;\n}\n\n.voice-btn:hover {\n border-color: var(--ag-ui-accent);\n}\n\n.voice-btn:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n/* Recording: a red tint + a gentle pulse so it's clearly \"live\". */\n.voice-btn[data-state=\"recording\"] {\n border-color: var(--ag-ui-danger);\n background: var(--ag-ui-danger);\n color: #ffffff;\n animation: ag-ui-voice-pulse 1.2s ease-in-out infinite;\n}\n\n@keyframes ag-ui-voice-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.6; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .voice-btn[data-state=\"recording\"] {\n animation: none;\n }\n}\n\n/* Pending-attachments tray, above the input row; collapses (hidden) when empty. */\n.attachment-slot {\n display: contents;\n}\n\n.attachment-tray {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 8px 12px 0;\n}\n\n.attachment-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 6px;\n}\n\n.attachment-chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n max-width: 100%;\n padding: 4px 8px;\n border: 1px solid var(--ag-ui-border);\n border-radius: 999px;\n background: var(--ag-ui-assistant-bg);\n font-size: 0.85em;\n position: relative;\n}\n\n.attachment-chip--error {\n border-color: var(--ag-ui-danger);\n color: var(--ag-ui-danger);\n}\n\n.attachment-chip-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 14ch;\n}\n\n.attachment-chip-size {\n color: var(--ag-ui-muted);\n white-space: nowrap;\n}\n\n.attachment-chip--error .attachment-chip-size {\n color: var(--ag-ui-danger);\n}\n\n/* The progress bar fills as the file uploads. */\n.attachment-chip-bar {\n flex-basis: 100%;\n height: 3px;\n border-radius: 2px;\n background: var(--ag-ui-border);\n overflow: hidden;\n}\n\n.attachment-chip-bar-fill {\n height: 100%;\n background: var(--ag-ui-accent);\n transition: width 0.15s ease;\n}\n\n.attachment-chip-remove,\n.attachment-chip-retry {\n border: none;\n background: none;\n color: inherit;\n cursor: pointer;\n padding: 0;\n line-height: 1;\n opacity: 0.7;\n}\n\n.attachment-chip-remove:hover,\n.attachment-chip-retry:hover {\n opacity: 1;\n}\n\n/* A subtle outline while a file is dragged over the shell. */\n.chat--dragover {\n outline: 2px dashed var(--ag-ui-accent);\n outline-offset: -4px;\n}\n\n/* Muted \"\u23F9 Stopped\" line after a cancelled run \u2014 a note, not an error bubble. */\n.stopped-note {\n align-self: flex-start;\n color: var(--ag-ui-muted);\n font-size: 12px;\n padding: 2px 4px;\n}\n\n/* Inline confirmation card \u2014 lives in the transcript, no focus-stealing overlay. */\n.confirm {\n align-self: stretch;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n background: var(--ag-ui-bg);\n border: 1px solid var(--ag-ui-accent);\n border-radius: 10px;\n}\n\n.confirm[data-resolved] {\n opacity: 0.7;\n border-color: var(--ag-ui-border);\n}\n\n.confirm-body {\n font-weight: 600;\n}\n\n.confirm-args {\n margin: 0;\n padding: 8px 10px;\n max-height: 140px;\n overflow: auto;\n font-size: 12px;\n font-family: ui-monospace, \"SF Mono\", Menlo, monospace;\n background: var(--ag-ui-assistant-bg);\n border-radius: 8px;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.confirm-actions {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n}\n\n.confirm-btn {\n border: 1px solid var(--ag-ui-border);\n border-radius: 8px;\n padding: 8px 14px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n background: var(--ag-ui-bg);\n color: var(--ag-ui-fg);\n}\n\n.confirm-btn:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.confirm-btn--confirm {\n border-color: var(--ag-ui-accent);\n background: var(--ag-ui-accent);\n color: #ffffff;\n}\n\n/* Approval card \u2014 the server-side-tool gate (approve/deny an interrupt). */\n.approval {\n align-self: stretch;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n background: var(--ag-ui-bg);\n border: 1px solid var(--ag-ui-accent);\n border-radius: 10px;\n}\n\n.approval[data-resolved] {\n opacity: 0.7;\n border-color: var(--ag-ui-border);\n}\n\n.approval-body {\n font-weight: 600;\n}\n\n.approval-actions {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n}\n\n.approval-btn {\n border: 1px solid var(--ag-ui-border);\n border-radius: 8px;\n padding: 8px 14px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n background: var(--ag-ui-bg);\n color: var(--ag-ui-fg);\n}\n\n.approval-btn:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.approval-btn--approve {\n border-color: var(--ag-ui-accent);\n background: var(--ag-ui-accent);\n color: #ffffff;\n}\n\n/* Question card \u2014 the built-in ask_user prompt (radios and/or free text). */\n.question {\n align-self: stretch;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n background: var(--ag-ui-bg);\n border: 1px solid var(--ag-ui-accent);\n border-radius: 10px;\n}\n\n.question[data-resolved] {\n opacity: 0.7;\n border-color: var(--ag-ui-border);\n}\n\n.question-body {\n font-weight: 600;\n}\n\n.question-options {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.question-choice {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n}\n\n.question-input {\n box-sizing: border-box;\n width: 100%;\n padding: 8px 10px;\n font: inherit;\n color: var(--ag-ui-fg);\n background: var(--ag-ui-bg);\n border: 1px solid var(--ag-ui-border);\n border-radius: 8px;\n}\n\n.question-input:disabled {\n opacity: 0.6;\n}\n\n.question-actions {\n display: flex;\n justify-content: flex-end;\n}\n\n.question-btn {\n border: 1px solid var(--ag-ui-accent);\n border-radius: 8px;\n padding: 8px 14px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n background: var(--ag-ui-accent);\n color: #ffffff;\n}\n\n.question-btn:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n/* Skills \u2014 chips row + the /-command palette, above the input. */\n.skill-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 10px 12px;\n}\n\n.skill-chip {\n border: 1px solid var(--ag-ui-border);\n border-radius: 999px;\n padding: 4px 12px;\n font: inherit;\n font-size: 0.9em;\n cursor: pointer;\n background: var(--ag-ui-assistant-bg);\n color: var(--ag-ui-fg);\n}\n\n.skill-chip:hover {\n border-color: var(--ag-ui-accent);\n}\n\n.skill-palette {\n margin: 8px 12px 0;\n display: flex;\n flex-direction: column;\n max-height: 220px;\n overflow: auto;\n background: var(--ag-ui-bg);\n border: 1px solid var(--ag-ui-border);\n border-radius: 8px;\n box-shadow: 0 8px 24px rgba(20, 20, 50, 0.16);\n}\n\n.skill-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n align-items: flex-start;\n padding: 8px 12px;\n border: none;\n background: none;\n font: inherit;\n text-align: left;\n cursor: pointer;\n color: var(--ag-ui-fg);\n}\n\n.skill-item[aria-selected=\"true\"] {\n background: var(--ag-ui-assistant-bg);\n}\n\n.skill-item-title {\n font-weight: 600;\n}\n\n.skill-item-desc {\n font-size: 0.85em;\n color: var(--ag-ui-muted);\n}\n\n.skill-hint {\n margin: 8px 12px 0;\n font-size: 0.85em;\n color: var(--ag-ui-danger);\n}\n\n/* Chat-history drawer \u2014 a slide-over within the chat panel. */\n.drawer {\n position: absolute;\n inset: 0;\n z-index: 5;\n display: flex;\n}\n\n.drawer[hidden] {\n display: none;\n}\n\n.drawer-backdrop {\n position: absolute;\n inset: 0;\n background: rgba(20, 20, 50, 0.32);\n}\n\n.drawer-panel {\n position: relative;\n display: flex;\n flex-direction: column;\n width: min(300px, 85%);\n height: 100%;\n background: var(--ag-ui-bg);\n border-right: 1px solid var(--ag-ui-border);\n box-shadow: var(--ag-ui-shadow);\n overflow: hidden;\n}\n\n.drawer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--ag-ui-space);\n padding: var(--ag-ui-pad);\n border-bottom: 1px solid var(--ag-ui-border);\n}\n\n.drawer-title {\n font-weight: 600;\n}\n\n.drawer-new {\n border: 1px solid var(--ag-ui-border);\n border-radius: var(--ag-ui-radius);\n background: var(--ag-ui-bg);\n color: var(--ag-ui-accent);\n padding: 4px 10px;\n font: inherit;\n font-size: 0.85em;\n cursor: pointer;\n}\n\n.drawer-list {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n\n.drawer-empty {\n padding: var(--ag-ui-pad);\n font-size: 0.9em;\n color: var(--ag-ui-muted);\n}\n\n.drawer-row {\n display: flex;\n align-items: stretch;\n border-bottom: 1px solid var(--ag-ui-border);\n}\n\n.drawer-row--active {\n background: var(--ag-ui-assistant-bg);\n}\n\n.drawer-row-select {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 8px 12px;\n border: none;\n background: none;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.drawer-row-title {\n font-weight: 600;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.drawer-row-time {\n font-size: 0.72em;\n color: var(--ag-ui-muted);\n}\n\n.drawer-row-preview {\n font-size: 0.8em;\n color: var(--ag-ui-muted);\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.drawer-row-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 0 6px;\n}\n\n.drawer-row-rename,\n.drawer-row-delete {\n border: none;\n background: none;\n color: var(--ag-ui-muted);\n font-size: 0.9em;\n padding: 4px;\n cursor: pointer;\n}\n\n.drawer-rename-input {\n flex: 1;\n min-width: 0;\n margin: 6px 10px;\n padding: 4px 8px;\n border: 1px solid var(--ag-ui-accent);\n border-radius: 6px;\n background: var(--ag-ui-input-bg);\n color: var(--ag-ui-fg);\n font: inherit;\n}\n\n.drawer-confirm {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n font-size: 0.85em;\n}\n\n.drawer-confirm-label {\n color: var(--ag-ui-danger);\n}\n\n.drawer-confirm-yes {\n border: none;\n border-radius: 6px;\n background: var(--ag-ui-danger);\n color: #ffffff;\n padding: 3px 10px;\n font: inherit;\n cursor: pointer;\n}\n\n.drawer-confirm-no {\n border: 1px solid var(--ag-ui-border);\n border-radius: 6px;\n background: none;\n color: inherit;\n padding: 3px 10px;\n font: inherit;\n cursor: pointer;\n}\n\n/* Embedded placement: an inline, flush side panel rather than a dimmed,\n floating slide-over. */\n:host([placement=\"embedded\"]) .drawer-backdrop {\n background: none;\n}\n\n:host([placement=\"embedded\"]) .drawer-panel {\n width: 100%;\n border-right: none;\n box-shadow: none;\n}\n";
2
2
  //# sourceMappingURL=styles.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/ui/styles.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,MAAM,s3+BA6vClB,CAAC"}
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/ui/styles.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,MAAM,k/iCAs3ClB,CAAC"}
@@ -1,9 +1,9 @@
1
1
  import { type UiStrings } from "./ui_strings.js";
2
2
  /**
3
3
  * A muted, collapsible "thinking" region for a reasoning model's streamed
4
- * chain-of-thought (THINK-1).
4
+ * chain-of-thought.
5
5
  *
6
- * Lives at the top of the current answer group (the WELL-1 turn container): it
6
+ * Lives at the top of the current answer group (the turn container): it
7
7
  * opens expanded while the model reasons — {@link stream} replaces its body with
8
8
  * the running reasoning buffer — and {@link collapse} folds it away once the
9
9
  * answer's first text token arrives, so the thoughts don't crowd the answer.
@@ -1 +1 @@
1
- {"version":3,"file":"thoughts_block.d.ts","sourceRoot":"","sources":["../../src/ui/thoughts_block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE;;;;;;;;;;;;;GAaG;AACH,qBAAa,aAAa;;IACxB,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;gBAQrB,OAAO,GAAE,SAA8B;IAgCnD,iFAAiF;IACjF,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI5B;;;;OAIG;IACH,QAAQ,IAAI,IAAI;CAcjB"}
1
+ {"version":3,"file":"thoughts_block.d.ts","sourceRoot":"","sources":["../../src/ui/thoughts_block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE;;;;;;;;;;;;;GAaG;AACH,qBAAa,aAAa;;IACxB,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;gBAQrB,OAAO,GAAE,SAA8B;IAiCnD,iFAAiF;IACjF,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI5B;;;;OAIG;IACH,QAAQ,IAAI,IAAI;CAcjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"thread_drawer.d.ts","sourceRoot":"","sources":["../../src/ui/thread_drawer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE,sEAAsE;AACtE,MAAM,WAAW,qBAAqB;IACpC,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,oDAAoD;IACpD,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAC3B,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C;AAED;;;;;;;;;;GAUG;AACH,qBAAa,YAAY;;IACvB,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;gBAWrB,SAAS,EAAE,qBAAqB,EAAE,OAAO,GAAE,SAA8B;IA8CrF,iFAAiF;IACjF,UAAU,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI;IAQpC,MAAM,IAAI,OAAO;IAIjB,IAAI,IAAI,IAAI;IAIZ,KAAK,IAAI,IAAI;IAIb,MAAM,IAAI,IAAI;IAId,4EAA4E;IAC5E,UAAU,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;CAmHnE"}
1
+ {"version":3,"file":"thread_drawer.d.ts","sourceRoot":"","sources":["../../src/ui/thread_drawer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE,sEAAsE;AACtE,MAAM,WAAW,qBAAqB;IACpC,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,oDAAoD;IACpD,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAC3B,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C;AAED;;;;;;;;;;GAUG;AACH,qBAAa,YAAY;;IACvB,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;gBAarB,SAAS,EAAE,qBAAqB,EAAE,OAAO,GAAE,SAA8B;IAiDrF,iFAAiF;IACjF,UAAU,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI;IAQpC,MAAM,IAAI,OAAO;IAIjB,IAAI,IAAI,IAAI;IAWZ,KAAK,IAAI,IAAI;IASb,MAAM,IAAI,IAAI;IAsCd,4EAA4E;IAC5E,UAAU,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;CAqJnE"}
@@ -1 +1 @@
1
- {"version":3,"file":"tool_call_card.d.ts","sourceRoot":"","sources":["../../src/ui/tool_call_card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE,4CAA4C;AAC5C,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,OAAO,gBAAgB,CAAC,CAAC;AAEtF,sCAAsC;AACtC,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE/E,0EAA0E;AAC1E,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,cAAc,EAAE,OAAO,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAqBrF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,YAAY;;IACvB,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;gBAS/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,IAAI,GAAE,eAAmC,EACzC,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,GAAE,SAA8B;IAgDzC,gFAAgF;IAChF,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;CAoClD"}
1
+ {"version":3,"file":"tool_call_card.d.ts","sourceRoot":"","sources":["../../src/ui/tool_call_card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE,4CAA4C;AAC5C,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,OAAO,gBAAgB,CAAC,CAAC;AAEtF,sCAAsC;AACtC,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE/E,0EAA0E;AAC1E,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,cAAc,EAAE,OAAO,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAqBrF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,YAAY;;IACvB,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;gBAS/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,IAAI,GAAE,eAAmC,EACzC,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,GAAE,SAA8B;IAgDzC,gFAAgF;IAChF,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;CA0ClD"}
@@ -88,6 +88,22 @@ export interface UiStrings {
88
88
  confirm: string;
89
89
  /** Cancel button (confirmation + delete confirm). */
90
90
  cancel: string;
91
+ /** `aria-label` of the inline server-side-tool approval card. */
92
+ approveAction: string;
93
+ /** Fallback approval prompt when the interrupt carries no message. */
94
+ approvalPrompt: string;
95
+ /** Approve button (runs the gated server-side tool). */
96
+ approve: string;
97
+ /** Deny button (declines the gated server-side tool). */
98
+ deny: string;
99
+ /** `aria-label` of the inline question card. */
100
+ askUserAction: string;
101
+ /** Radio label for the free-text "other" choice (when custom answers are allowed). */
102
+ otherOption: string;
103
+ /** Placeholder for the free-text answer field. */
104
+ answerPlaceholder: string;
105
+ /** Submit button for the question card. */
106
+ submit: string;
91
107
  /** Drawer heading. */
92
108
  chats: string;
93
109
  /** Empty-state line when there are no threads. */
@@ -1 +1 @@
1
- {"version":3,"file":"ui_strings.d.ts","sourceRoot":"","sources":["../../src/ui/ui_strings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ui_strings.d.ts","sourceRoot":"","sources":["../../src/ui/ui_strings.ts"],"names":[],"mappings":"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"}
@@ -10,7 +10,7 @@ export interface VoiceInputOptions {
10
10
  readonly strings?: UiStrings;
11
11
  }
12
12
  /**
13
- * The composer's voice-input control (VOICE-1): a mic button that records via
13
+ * The composer's voice-input control: a mic button that records via
14
14
  * `MediaRecorder`, then POSTs the clip through a {@link TranscribeHandler} and
15
15
  * hands the transcript back via `onText`.
16
16
  *
@@ -29,5 +29,13 @@ export declare class VoiceInput {
29
29
  constructor(options: VoiceInputOptions);
30
30
  /** Start recording when idle, stop (and transcribe) when recording. */
31
31
  toggle(): Promise<void>;
32
+ /**
33
+ * Tear the control down — the teardown path when the host element is removed
34
+ * mid-recording. Stops any live `MediaRecorder`, releases the mic tracks (so
35
+ * the browser's recording indicator clears), and suppresses the pending
36
+ * transcription: a disconnected control must not fire `onText` back into a
37
+ * detached element.
38
+ */
39
+ dispose(): void;
32
40
  }
33
41
  //# sourceMappingURL=voice_input.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"voice_input.d.ts","sourceRoot":"","sources":["../../src/ui/voice_input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAKrE,mDAAmD;AACnD,MAAM,WAAW,iBAAiB;IAChC,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,yCAAyC;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;CAC9B;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,UAAU;;IACrB,kDAAkD;IAClD,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;gBAUxB,OAAO,EAAE,iBAAiB;IAgBtC,uEAAuE;IACjE,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CA0F9B"}
1
+ {"version":3,"file":"voice_input.d.ts","sourceRoot":"","sources":["../../src/ui/voice_input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAKrE,mDAAmD;AACnD,MAAM,WAAW,iBAAiB;IAChC,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,yCAAyC;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;CAC9B;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,UAAU;;IACrB,kDAAkD;IAClD,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;gBAWxB,OAAO,EAAE,iBAAiB;IAgBtC,uEAAuE;IACjE,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAsC7B;;;;;;OAMG;IACH,OAAO,IAAI,IAAI;CAgEhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,EAAE,MAAgB,CAAC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,EAAE,MAAiB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@artooi/ag-ui-web-component",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Framework-free <ag-ui-chat> Web Component over the AG-UI protocol. Drop-in chat sidebar with a pluggable client-side tool registry, DOM driver primitives, animations, and destructive-action confirmation modal.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -61,10 +61,10 @@
61
61
  },
62
62
  "devDependencies": {
63
63
  "@biomejs/biome": "^2.4.0",
64
- "@types/node": "^22.0.0",
64
+ "@types/node": "^26.1.0",
65
65
  "@vitest/coverage-v8": "^3.0.0",
66
- "esbuild": "^0.25.0",
67
- "happy-dom": "^16.0.0",
66
+ "esbuild": "^0.28.1",
67
+ "happy-dom": "^20.8.9",
68
68
  "typescript": "^5.7.0",
69
69
  "vitest": "^3.0.0"
70
70
  },