@artooi/ag-ui-web-component 0.28.0 → 0.30.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 (65) hide show
  1. package/CHANGELOG.md +615 -1
  2. package/README.md +564 -35
  3. package/dist/ag-ui-web-component.bundle.js +491 -50
  4. package/dist/ag-ui-web-component.bundle.js.map +4 -4
  5. package/dist/constants.d.ts +129 -1
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/core/ag_ui_chat.d.ts +232 -1
  8. package/dist/core/ag_ui_chat.d.ts.map +1 -1
  9. package/dist/core/agui_client.d.ts +56 -1
  10. package/dist/core/agui_client.d.ts.map +1 -1
  11. package/dist/index.d.ts +8 -3
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +2081 -98
  14. package/dist/index.js.map +4 -4
  15. package/dist/ui/approval_card.d.ts +18 -0
  16. package/dist/ui/approval_card.d.ts.map +1 -1
  17. package/dist/ui/checkpoint_menu.d.ts +10 -0
  18. package/dist/ui/checkpoint_menu.d.ts.map +1 -1
  19. package/dist/ui/confirmation_card.d.ts +16 -0
  20. package/dist/ui/confirmation_card.d.ts.map +1 -1
  21. package/dist/ui/message_actions.d.ts +56 -0
  22. package/dist/ui/message_actions.d.ts.map +1 -0
  23. package/dist/ui/page_quote_offer.d.ts +33 -0
  24. package/dist/ui/page_quote_offer.d.ts.map +1 -0
  25. package/dist/ui/quote_selection.d.ts +66 -0
  26. package/dist/ui/quote_selection.d.ts.map +1 -0
  27. package/dist/ui/relative_time.d.ts +10 -0
  28. package/dist/ui/relative_time.d.ts.map +1 -1
  29. package/dist/ui/stick_to_bottom.d.ts +55 -0
  30. package/dist/ui/stick_to_bottom.d.ts.map +1 -0
  31. package/dist/ui/styles.d.ts +1 -1
  32. package/dist/ui/styles.d.ts.map +1 -1
  33. package/dist/ui/subagent_panel.d.ts +92 -0
  34. package/dist/ui/subagent_panel.d.ts.map +1 -0
  35. package/dist/ui/subagent_update.d.ts +19 -0
  36. package/dist/ui/subagent_update.d.ts.map +1 -0
  37. package/dist/ui/suggestion_chips.d.ts +29 -0
  38. package/dist/ui/suggestion_chips.d.ts.map +1 -0
  39. package/dist/ui/thread_drawer.d.ts +10 -0
  40. package/dist/ui/thread_drawer.d.ts.map +1 -1
  41. package/dist/ui/tool_call_card.d.ts +81 -1
  42. package/dist/ui/tool_call_card.d.ts.map +1 -1
  43. package/dist/ui/ui_strings.d.ts +50 -0
  44. package/dist/ui/ui_strings.d.ts.map +1 -1
  45. package/package.json +1 -1
  46. package/src/constants.ts +138 -1
  47. package/src/core/ag_ui_chat.ts +1081 -73
  48. package/src/core/agui_client.ts +89 -2
  49. package/src/index.ts +43 -0
  50. package/src/ui/approval_card.ts +90 -2
  51. package/src/ui/checkpoint_menu.ts +22 -5
  52. package/src/ui/confirmation_card.ts +29 -1
  53. package/src/ui/message_actions.ts +170 -0
  54. package/src/ui/page_quote_offer.ts +215 -0
  55. package/src/ui/quote_selection.ts +345 -0
  56. package/src/ui/relative_time.ts +11 -0
  57. package/src/ui/stick_to_bottom.ts +126 -0
  58. package/src/ui/styles.ts +410 -0
  59. package/src/ui/subagent_panel.ts +213 -0
  60. package/src/ui/subagent_update.ts +80 -0
  61. package/src/ui/suggestion_chips.ts +73 -0
  62. package/src/ui/thread_drawer.ts +22 -2
  63. package/src/ui/tool_call_card.ts +138 -3
  64. package/src/ui/ui_strings.ts +75 -0
  65. package/src/version.ts +1 -1
@@ -9,6 +9,11 @@ export interface ApprovalRequest {
9
9
  message?: string;
10
10
  /** Tool name, surfaced as a `data-tool-name` attribute for styling/tests. */
11
11
  toolName?: string;
12
+ /**
13
+ * The call's arguments, shown for editing when {@link ApprovalOptions.onEdit}
14
+ * is set. Omitted when the interrupt names no call whose arguments are known.
15
+ */
16
+ args?: Record<string, unknown>;
12
17
  }
13
18
  /** Options for {@link requestApproval}. */
14
19
  export interface ApprovalOptions {
@@ -19,6 +24,19 @@ export interface ApprovalOptions {
19
24
  signal?: AbortSignal;
20
25
  /** Localized strings; defaults to the English {@link DEFAULT_UI_STRINGS}. */
21
26
  strings?: UiStrings;
27
+ /**
28
+ * Offer the call's arguments for editing, and receive what the user approved.
29
+ *
30
+ * Called **only** on approval, and only when the text parses and differs from
31
+ * what was proposed -- an untouched call resolves as a plain approval, so a
32
+ * server sees `editedArgs` exactly when something was actually edited.
33
+ *
34
+ * Absent means no editor, which is deliberate: AG-UI gates this on the
35
+ * agent's own `approveWithEdits` capability, and a card that let a user
36
+ * rewrite arguments a server will discard is worse than one that does not
37
+ * offer to.
38
+ */
39
+ onEdit?: (args: Record<string, unknown>) => void;
22
40
  }
23
41
  /**
24
42
  * A fully custom renderer for a server-side-tool approval, set via
@@ -1 +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;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;GAOG;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;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,IAAI,GAAG,UAAU,EACvB,OAAO,EAAE,eAAe,EACxB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,OAAO,CAAC,CAkDlB"}
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;IAClB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAYD,2CAA2C;AAC3C,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CAClD;AAED;;;;;;;GAOG;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;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,IAAI,GAAG,UAAU,EACvB,OAAO,EAAE,eAAe,EACxB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,OAAO,CAAC,CA4DlB"}
@@ -1,4 +1,5 @@
1
1
  import type { RunRow } from "../core/run_index.js";
2
+ import { type RelativeTimeFormatter } from "./relative_time.js";
2
3
  import { type UiStrings } from "./ui_strings.js";
3
4
  /** How the host continues a picked run. */
4
5
  export type CheckpointVerb = "resume" | "fork";
@@ -23,6 +24,15 @@ export declare class CheckpointMenu {
23
24
  /** Replace the rows. The host passes only `continuable` runs. */
24
25
  setRuns(runs: readonly RunRow[]): void;
25
26
  /** Re-localize a panel built before the host's strings resolved. */
27
+ /**
28
+ * Replace the timestamp formatter, or restore the built-in with `null`.
29
+ *
30
+ * The built-in is deliberately locale-neutral -- there is no `Intl` anywhere
31
+ * in this component, so it never disagrees with a host's own formatting by
32
+ * guessing a locale. That is a defensible default and a poor requirement, so
33
+ * this is the way out.
34
+ */
35
+ setRelativeTimeFormatter(format: RelativeTimeFormatter | null): void;
26
36
  setStrings(strings: UiStrings): void;
27
37
  open(): void;
28
38
  close(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"checkpoint_menu.d.ts","sourceRoot":"","sources":["../../src/ui/checkpoint_menu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE,2CAA2C;AAC3C,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,MAAM,CAAC;AAqB/C;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAc;;IACzB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IAUjC,YACE,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,KAAK,IAAI,EACrD,OAAO,GAAE,SAA8B,EA+BxC;IAED,iEAAiE;IACjE,OAAO,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAGrC;IAED,oEAAoE;IACpE,UAAU,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI,CAKnC;IAED,IAAI,IAAI,IAAI,CAYX;IAED,KAAK,IAAI,IAAI,CAOZ;IAqCD,IAAI,KAAK,IAAI,OAAO,CAEnB;CAuHF"}
1
+ {"version":3,"file":"checkpoint_menu.d.ts","sourceRoot":"","sources":["../../src/ui/checkpoint_menu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,KAAK,qBAAqB,EAAgB,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE,2CAA2C;AAC3C,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,MAAM,CAAC;AAqB/C;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAc;;IACzB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IAWjC,YACE,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,KAAK,IAAI,EACrD,OAAO,GAAE,SAA8B,EA+BxC;IAED,iEAAiE;IACjE,OAAO,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAGrC;IAED,oEAAoE;IACpE;;;;;;;OAOG;IACH,wBAAwB,CAAC,MAAM,EAAE,qBAAqB,GAAG,IAAI,GAAG,IAAI,CAEnE;IASD,UAAU,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI,CAKnC;IAED,IAAI,IAAI,IAAI,CAYX;IAED,KAAK,IAAI,IAAI,CAOZ;IAqCD,IAAI,KAAK,IAAI,OAAO,CAEnB;CAoHF"}
@@ -19,6 +19,16 @@ export interface ConfirmationOptions {
19
19
  signal?: AbortSignal;
20
20
  /** Localized strings; defaults to the English {@link DEFAULT_UI_STRINGS}. */
21
21
  strings?: UiStrings;
22
+ /**
23
+ * Offer a third button — "always allow, this session" — and call this when
24
+ * the user picks it. The card still resolves `true`: the extra decision is
25
+ * *in addition to* approving this call, not instead of it.
26
+ *
27
+ * Absent means no button, which is deliberate: presence of the handler is
28
+ * what enables it, so the affordance can never be rendered with nothing
29
+ * listening. A caller that cannot honour the waiver simply does not pass one.
30
+ */
31
+ onAlwaysAllow?: () => void;
22
32
  }
23
33
  /**
24
34
  * Append an inline confirmation card to `host` (the chat message list) and
@@ -30,6 +40,12 @@ export interface ConfirmationOptions {
30
40
  * Answering it removes it: the record of the decision belongs to the tool card
31
41
  * this gates, which settles to `done` or `declined` and carries it. A spent
32
42
  * form left in place reads as still outstanding.
43
+ *
44
+ * With `onAlwaysAllow` set the card offers a third button. A prompt that is
45
+ * approved nearly every time is not a decision, it is a speed bump — and the
46
+ * reflex it trains is what makes the rare refusal easy to miss. Letting the
47
+ * user say "not this one again, this session" is the affordance that keeps the
48
+ * remaining prompts meaningful.
33
49
  */
34
50
  export declare function requestConfirmation(host: Node & ParentNode, request: ConfirmationRequest, options?: ConfirmationOptions): Promise<boolean>;
35
51
  //# sourceMappingURL=confirmation_card.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"confirmation_card.d.ts","sourceRoot":"","sources":["../../src/ui/confirmation_card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE,kDAAkD;AAClD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAYD,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,IAAI,GAAG,UAAU,EACvB,OAAO,EAAE,mBAAmB,EAC5B,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,OAAO,CAAC,CAyDlB"}
1
+ {"version":3,"file":"confirmation_card.d.ts","sourceRoot":"","sources":["../../src/ui/confirmation_card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE,kDAAkD;AAClD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAYD,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,IAAI,GAAG,UAAU,EACvB,OAAO,EAAE,mBAAmB,EAC5B,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,OAAO,CAAC,CAqElB"}
@@ -0,0 +1,56 @@
1
+ import type { UiStrings } from "./ui_strings.js";
2
+ /** What an action bar can do, beyond copying. */
3
+ export interface MessageActionsOptions {
4
+ /** Localized strings. */
5
+ strings: UiStrings;
6
+ /**
7
+ * The text Copy puts on the clipboard. Absent means no copy button.
8
+ *
9
+ * A function rather than a string because a bubble's content is rewritten
10
+ * while it streams, and the bar is attached to the element rather than to a
11
+ * snapshot of it. Optional for the same reason `onFeedback` is: what a button
12
+ * needs to do its job is also the statement that the button belongs here, so
13
+ * there is no second flag saying the same thing and no way for the two to
14
+ * disagree.
15
+ */
16
+ text?: () => string;
17
+ /**
18
+ * Report a rating for this message. Absent means no feedback buttons.
19
+ *
20
+ * The component stores nothing: a rating is the host's to keep, and a
21
+ * write-only table nobody reads is not worth a schema.
22
+ */
23
+ onFeedback?: (rating: "up" | "down") => void;
24
+ }
25
+ /**
26
+ * Give one finished message bubble its row of actions.
27
+ *
28
+ * **Finished** is load-bearing. A streaming bubble reassigns its `innerHTML` on
29
+ * every delta, so anything attached mid-stream is discarded and rebuilt for
30
+ * each one -- the same constraint `attachCopyButtons` records, one level up.
31
+ *
32
+ * Retry is deliberately **not** here: it belongs to the last turn only, so the
33
+ * element owns it and moves it as the transcript grows. Everything on this bar
34
+ * is safe to offer on any message, however old.
35
+ *
36
+ * Idempotent -- a bubble already given a bar is skipped, so a re-render or a
37
+ * second call cannot stack rows.
38
+ *
39
+ * Each button is present because the option it needs was passed: `text` for
40
+ * Copy, `onFeedback` for the rating pair. Passing neither builds an empty row,
41
+ * which is a caller's mistake rather than a state to guard against -- the
42
+ * element skips the call entirely when a host has turned both off.
43
+ */
44
+ export declare function attachMessageActions(bubble: HTMLElement, options: MessageActionsOptions): void;
45
+ /**
46
+ * The empty action row on `bubble`, created if it has none yet.
47
+ *
48
+ * Shared so a bubble that wants *only* Retry -- a failed run, which has nothing
49
+ * worth copying and nothing to rate -- gets the same row, the same part name
50
+ * and the same accessible grouping as every other message, rather than a
51
+ * second thing that looks like one.
52
+ */
53
+ export declare function messageActionBar(bubble: HTMLElement, strings: UiStrings): HTMLElement;
54
+ /** Build one action button, labelled for screen readers rather than by glyph. */
55
+ export declare function messageActionButton(modifier: string, label: string, glyph: string): HTMLButtonElement;
56
+ //# sourceMappingURL=message_actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message_actions.d.ts","sourceRoot":"","sources":["../../src/ui/message_actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAKjD,iDAAiD;AACjD,MAAM,WAAW,qBAAqB;IACpC,yBAAyB;IACzB,OAAO,EAAE,SAAS,CAAC;IACnB;;;;;;;;;OASG;IACH,IAAI,CAAC,EAAE,MAAM,MAAM,CAAC;IACpB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAe9F;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,GAAG,WAAW,CAmBrF;AAQD,iFAAiF;AACjF,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,iBAAiB,CAYnB"}
@@ -0,0 +1,33 @@
1
+ /** A live page-side offer. */
2
+ export interface PageQuoteOffer {
3
+ /** The button itself, for a host that wants to style or inspect it. */
4
+ readonly element: HTMLButtonElement;
5
+ /** Stop offering: every listener removed, the button and its styles gone. */
6
+ detach(): void;
7
+ }
8
+ /** What {@link attachQuoteOffer} needs to know. */
9
+ export interface PageQuoteOfferOptions {
10
+ /** Where a selection is worth offering to quote. */
11
+ within: HTMLElement;
12
+ /** What the offer says. */
13
+ label: string;
14
+ /**
15
+ * A subtree to stay out of -- the chat widget itself.
16
+ *
17
+ * Its transcript runs this same gesture on the inside, so without this a
18
+ * selection there would be offered twice and quoted twice.
19
+ */
20
+ exclude: Node;
21
+ /** Take the offer. */
22
+ onQuote: (text: string) => void;
23
+ }
24
+ /**
25
+ * Offer to quote what the user selects inside `within`.
26
+ *
27
+ * Nothing is quoted until the offer is taken -- which is the whole point. An
28
+ * automatic version of this is easy to write and horrible to use: every drag
29
+ * made to read, to copy, or to fix a typo silently appends to whatever the user
30
+ * was in the middle of typing.
31
+ */
32
+ export declare function attachQuoteOffer(options: PageQuoteOfferOptions): PageQuoteOffer;
33
+ //# sourceMappingURL=page_quote_offer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page_quote_offer.d.ts","sourceRoot":"","sources":["../../src/ui/page_quote_offer.ts"],"names":[],"mappings":"AAuDA,8BAA8B;AAC9B,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,6EAA6E;IAC7E,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,mDAAmD;AACnD,MAAM,WAAW,qBAAqB;IACpC,oDAAoD;IACpD,MAAM,EAAE,WAAW,CAAC;IACpB,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,OAAO,EAAE,IAAI,CAAC;IACd,sBAAsB;IACtB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,cAAc,CA4F/E"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Reading a text selection out of the shadow tree, and shaping it for the
3
+ * composer.
4
+ *
5
+ * Selection is the one DOM API shadow encapsulation genuinely broke, and it
6
+ * broke it in two different directions. WebKit rescopes a selection made inside
7
+ * a shadow tree to the **host** element, so `document.getSelection()` reports
8
+ * the whole widget and none of the words; Chromium exposes the shadow nodes
9
+ * directly, so the same call reports exactly the words. `getComposedRanges` is
10
+ * the settled answer to both -- it hands back real endpoints for each shadow
11
+ * root it is *given permission to see* -- but it is recent enough that the
12
+ * direct read has to stay behind it.
13
+ */
14
+ /**
15
+ * The longest quotation put into the composer, in characters.
16
+ *
17
+ * A cap rather than no cap because the point of a quotation is to say *which*
18
+ * part of an answer the next question is about. Select-all-then-quote is a
19
+ * gesture the transcript already answers -- it is the whole conversation, which
20
+ * the model has -- and pasting it back costs the user tokens to say nothing.
21
+ */
22
+ export declare const MAX_QUOTE_CHARS = 500;
23
+ /** A selection worth offering to quote. */
24
+ export interface QuotableSelection {
25
+ /** The selected text, trimmed. Never empty. */
26
+ readonly text: string;
27
+ /**
28
+ * One **line** of the selection, for placing the affordance beside it.
29
+ *
30
+ * Deliberately not the selection's bounding box. See {@link lineToHangFrom}:
31
+ * the union of a selection spanning several elements has a centre with no
32
+ * selected text anywhere near it.
33
+ */
34
+ readonly rect: DOMRect;
35
+ }
36
+ /** Where a gesture ended, in viewport coordinates. */
37
+ export interface Point {
38
+ readonly x: number;
39
+ readonly y: number;
40
+ }
41
+ /**
42
+ * The current selection, when it lies wholly inside `container`.
43
+ *
44
+ * `roots` are the shadow roots the read is allowed to look inside, in the shape
45
+ * `getComposedRanges` itself takes. Pass the one holding `container` for a
46
+ * selection made in a shadow tree, or nothing at all for one made in the page.
47
+ *
48
+ * `near` is where the gesture ended, when a pointer made it -- it decides which
49
+ * line of a multi-line selection the offer is hung from.
50
+ *
51
+ * `null` for no selection, a collapsed one, whitespace only, or one that
52
+ * starts or ends outside `container` -- a drag that ran off the transcript and
53
+ * into the page is not a quotation from the transcript.
54
+ */
55
+ export declare function quotableSelection(container: HTMLElement, roots?: readonly ShadowRoot[], near?: Point): QuotableSelection | null;
56
+ /**
57
+ * Wrap `text` as a markdown blockquote, ready to be followed by a question.
58
+ *
59
+ * Markdown rather than a bespoke fence because the transcript renders markdown
60
+ * and the server reads markdown: a quotation that survives both ends without a
61
+ * convention to agree on first. The trailing blank line is what leaves the
62
+ * caret on a fresh paragraph, which is the whole point of quoting into a
63
+ * composer rather than sending straight away.
64
+ */
65
+ export declare function asQuote(text: string): string;
66
+ //# sourceMappingURL=quote_selection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quote_selection.d.ts","sourceRoot":"","sources":["../../src/ui/quote_selection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,2CAA2C;AAC3C,MAAM,WAAW,iBAAiB;IAChC,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED,sDAAsD;AACtD,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAOD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,WAAW,EACtB,KAAK,GAAE,SAAS,UAAU,EAAO,EACjC,IAAI,CAAC,EAAE,KAAK,GACX,iBAAiB,GAAG,IAAI,CAqB1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAa5C"}
@@ -10,4 +10,14 @@ import { type UiStrings } from "./ui_strings.js";
10
10
  * filled in here; the bucketing stays integer-rounded and locale-neutral.
11
11
  */
12
12
  export declare function relativeTime(timestamp: number, now?: number, strings?: UiStrings): string;
13
+ /**
14
+ * A host's replacement for {@link relativeTime}.
15
+ *
16
+ * Takes an epoch-milliseconds timestamp and returns the text a row shows.
17
+ * `Intl.RelativeTimeFormat` is the obvious implementation and is deliberately
18
+ * *not* the default: a component that guessed a locale would disagree with the
19
+ * host page's own formatting, and being wrong in a second language is worse
20
+ * than being neutral in one.
21
+ */
22
+ export type RelativeTimeFormatter = (timestamp: number) => string;
13
23
  //# 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,CAqBR"}
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,CAqBR;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC"}
@@ -0,0 +1,55 @@
1
+ /** A transcript that follows new content, unless the reader has other ideas. */
2
+ export interface StickToBottom {
3
+ /**
4
+ * New content arrived. Scrolls to the bottom only while following, so
5
+ * reading older messages during a run is no longer undone on the next token.
6
+ */
7
+ readonly follow: () => void;
8
+ /** Go to the bottom and resume following, whatever the reader was doing. */
9
+ readonly jump: () => void;
10
+ /** Whether the transcript is currently following new content. */
11
+ readonly following: () => boolean;
12
+ readonly dispose: () => void;
13
+ }
14
+ export interface StickToBottomOptions {
15
+ /** The scrolling element -- the message list. */
16
+ readonly viewport: HTMLElement;
17
+ /**
18
+ * Called whenever the answer to "should a jump-to-latest affordance show?"
19
+ * changes. True means the reader has scrolled away *and* has since missed
20
+ * something; scrolling up through a settled transcript is not a reason to
21
+ * nag.
22
+ */
23
+ readonly onMissedContent: (missed: boolean) => void;
24
+ }
25
+ /**
26
+ * Follow the foot of a scrolling transcript, and stop when the reader scrolls
27
+ * away.
28
+ *
29
+ * Before this, eleven separate sites assigned `scrollTop = scrollHeight`
30
+ * unconditionally and nothing anywhere listened for a `scroll` event -- so
31
+ * nothing knew the reader had scrolled up, and scrolling back through a run was
32
+ * undone by the next token. Stick-to-bottom with a jump-to-latest affordance is
33
+ * a named primitive elsewhere for exactly this reason: shadcn ships it as
34
+ * `MessageScroller`, AI Elements as `ConversationScrollButton`.
35
+ *
36
+ * **Telling a reader's scroll from our own is the whole problem**, and the
37
+ * answer here is that it does not have to be told. A programmatic scroll only
38
+ * ever happens while already following, and it lands at the bottom, so the
39
+ * `scroll` event it provokes recomputes "at the bottom" as true and changes
40
+ * nothing. A reader's scroll is the only kind that can move the answer.
41
+ *
42
+ * A `ResizeObserver` covers the case scroll events cannot see: the *viewport*
43
+ * changing size. Resizing the panel, or the keyboard opening on a phone, moves
44
+ * the foot without anything scrolling and without any content arriving, so a
45
+ * pinned transcript would silently come unpinned.
46
+ *
47
+ * ⚠ It does **not** cover content that grows after insertion -- an image
48
+ * decoding, a chart laying out. A `ResizeObserver` on a scroll container does
49
+ * not fire when its `scrollHeight` changes, so catching that means observing
50
+ * every child, and the payoff is one late nudge in a case the reader can fix by
51
+ * scrolling. Insertion itself is covered: every site that adds to the
52
+ * transcript calls {@link StickToBottom.follow}.
53
+ */
54
+ export declare function createStickToBottom({ viewport, onMissedContent, }: StickToBottomOptions): StickToBottom;
55
+ //# sourceMappingURL=stick_to_bottom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stick_to_bottom.d.ts","sourceRoot":"","sources":["../../src/ui/stick_to_bottom.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC;IAC5B,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,SAAS,EAAE,MAAM,OAAO,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CACrD;AAWD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,eAAe,GAChB,EAAE,oBAAoB,GAAG,aAAa,CA0DtC"}