@guuey/chat 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +137 -0
  3. package/dist/history-inputs.d.ts +24 -0
  4. package/dist/history-inputs.d.ts.map +1 -0
  5. package/dist/history-inputs.js +34 -0
  6. package/dist/index.d.ts +19 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +17 -0
  9. package/dist/plan.d.ts +5 -0
  10. package/dist/plan.d.ts.map +1 -0
  11. package/dist/plan.js +629 -0
  12. package/dist/policy.d.ts +110 -0
  13. package/dist/policy.d.ts.map +1 -0
  14. package/dist/policy.js +75 -0
  15. package/dist/react/components.d.ts +87 -0
  16. package/dist/react/components.d.ts.map +1 -0
  17. package/dist/react/components.js +270 -0
  18. package/dist/react/guuey-chat.d.ts +84 -0
  19. package/dist/react/guuey-chat.d.ts.map +1 -0
  20. package/dist/react/guuey-chat.js +103 -0
  21. package/dist/react/markdown.d.ts +32 -0
  22. package/dist/react/markdown.d.ts.map +1 -0
  23. package/dist/react/markdown.js +40 -0
  24. package/dist/react/theme-css.d.ts +16 -0
  25. package/dist/react/theme-css.d.ts.map +1 -0
  26. package/dist/react/theme-css.js +37 -0
  27. package/dist/react/transcript.d.ts +42 -0
  28. package/dist/react/transcript.d.ts.map +1 -0
  29. package/dist/react/transcript.js +88 -0
  30. package/dist/react/use-transcript.d.ts +39 -0
  31. package/dist/react/use-transcript.d.ts.map +1 -0
  32. package/dist/react/use-transcript.js +201 -0
  33. package/dist/react.d.ts +21 -0
  34. package/dist/react.d.ts.map +1 -0
  35. package/dist/react.js +20 -0
  36. package/dist/strings.d.ts +74 -0
  37. package/dist/strings.d.ts.map +1 -0
  38. package/dist/strings.js +45 -0
  39. package/dist/theme.d.ts +99 -0
  40. package/dist/theme.d.ts.map +1 -0
  41. package/dist/theme.js +182 -0
  42. package/dist/types.d.ts +283 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/types.js +1 -0
  45. package/package.json +87 -0
  46. package/src/corpus/README.md +40 -0
  47. package/src/corpus/__snapshots__/corpus.test.ts.snap +1590 -0
  48. package/src/corpus/capture.ts +67 -0
  49. package/src/corpus/captures/issue2627-render-capture.coalesced.sse.txt +173 -0
  50. package/src/corpus/drive.ts +184 -0
  51. package/src/corpus/fixtures.ts +338 -0
  52. package/src/history-inputs.ts +48 -0
  53. package/src/index.ts +58 -0
  54. package/src/plan.ts +740 -0
  55. package/src/policy.ts +146 -0
  56. package/src/react/components.tsx +655 -0
  57. package/src/react/guuey-chat.tsx +227 -0
  58. package/src/react/markdown.tsx +114 -0
  59. package/src/react/theme-css.ts +50 -0
  60. package/src/react/transcript.tsx +187 -0
  61. package/src/react/use-transcript.ts +274 -0
  62. package/src/react.tsx +51 -0
  63. package/src/strings.ts +144 -0
  64. package/src/theme.ts +195 -0
  65. package/src/types.ts +320 -0
  66. package/styles.css +514 -0
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Presets as complete policy bundles (spec §5): `calm` (end-user, THE
3
+ * default) and `debug` (builder) are exported policy VALUES, not modes
4
+ * scattered through components. Every §3 knob lives here; the factories
5
+ * take partial overrides so a builder tunes one knob without forfeiting the
6
+ * rest of the preset.
7
+ */
8
+ import { type ChatStrings } from "./strings.js";
9
+ export interface TranscriptPolicy {
10
+ /** The i18n seam — override any string without forking components (§4.2). */
11
+ strings: ChatStrings;
12
+ /** Chrome locale (a view's own locale rides the wave-2 hostContext instead). */
13
+ locale: string;
14
+ /**
15
+ * The debug master switch: raw-state suffixes on the status line, the
16
+ * #192 recovered marker, verbatim wire errors, raw prompt payloads, and
17
+ * R15's full pretty-printed payload all key off it.
18
+ */
19
+ debugDetail: boolean;
20
+ /** R0. */
21
+ userMessage: {
22
+ retryAffordance: boolean;
23
+ };
24
+ /** R1 (markdown sanitization itself is the 3b renderer's security surface). */
25
+ text: {
26
+ markdown: boolean;
27
+ };
28
+ /** R2. */
29
+ reasoning: {
30
+ show: boolean;
31
+ expandedByDefault: boolean;
32
+ };
33
+ /** R3. */
34
+ tool: {
35
+ expandByDefault: boolean;
36
+ argsVisible: boolean;
37
+ humanizeTitle: (wireName: string) => string;
38
+ };
39
+ /** R4 — `false` disables grouping entirely (debug's default). */
40
+ toolGroup: {
41
+ threshold: number | false;
42
+ };
43
+ /** R5. */
44
+ dataResult: {
45
+ capRem: number;
46
+ prettyPrint: boolean;
47
+ alwaysShowBytes: boolean;
48
+ /** Preview bound — the plan never carries a full giant payload (fixture 6). */
49
+ previewChars: number;
50
+ };
51
+ /** R6 (sandbox overrides pass through to `<GuueyView>` in 3b). */
52
+ view: {
53
+ timeoutMs: number;
54
+ };
55
+ /** R7. */
56
+ media: {
57
+ inlineImageCapRem: number;
58
+ chipOnly: boolean;
59
+ };
60
+ /** R8. */
61
+ code: {
62
+ capRem: number;
63
+ wrap: boolean;
64
+ };
65
+ /** R9. */
66
+ citations: {
67
+ style: "chips" | "list";
68
+ };
69
+ /** R10. */
70
+ prompt: {
71
+ placement: "inline" | "modal";
72
+ rawPayload: boolean;
73
+ };
74
+ /**
75
+ * R11. `copyByCode` is the specced per-code copy knob (the directive's
76
+ * `errorCopy`, nested here so it doesn't stutter as `error.errorCopy`):
77
+ * an exact wire-code → sentence map that wins over everything else.
78
+ * `verbatimCodes` renders the SOURCE message instead of family copy for
79
+ * the listed codes — or for every error (`"all"`, the widget's #162
80
+ * posture: pod refusal bodies are already written for a reader, and
81
+ * client-side identity copy arrives code-less). Precedence per error:
82
+ * `copyByCode[code]` → verbatim source message (when matched and
83
+ * non-empty) → family copy. `verbatim` stays the DEBUG formatting knob
84
+ * (code-prefixed raw line under the notice), independent of voice.
85
+ */
86
+ error: {
87
+ verbatim: boolean;
88
+ copyByCode: Readonly<Record<string, string>>;
89
+ verbatimCodes: readonly string[] | "all";
90
+ };
91
+ /** R12 — thresholds are chosen-not-measured (§10-F6; 3b validates vs #188 data). */
92
+ status: {
93
+ wakingMs: number;
94
+ longStartMs: number;
95
+ };
96
+ /** R14. */
97
+ compaction: {
98
+ show: boolean;
99
+ };
100
+ /** R15. */
101
+ unknown: {
102
+ show: boolean;
103
+ raw: boolean;
104
+ };
105
+ }
106
+ /** The `calm` preset — the end-user default (spec §5). */
107
+ export declare function calmPolicy(overrides?: Partial<TranscriptPolicy>): TranscriptPolicy;
108
+ /** The `debug` preset — the builder surface (Studio's test chat, spec §5). */
109
+ export declare function debugPolicy(overrides?: Partial<TranscriptPolicy>): TranscriptPolicy;
110
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAwC,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAEtF,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,OAAO,EAAE,WAAW,CAAC;IACrB,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU;IACV,WAAW,EAAE;QAAE,eAAe,EAAE,OAAO,CAAA;KAAE,CAAC;IAC1C,+EAA+E;IAC/E,IAAI,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAC5B,UAAU;IACV,SAAS,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,iBAAiB,EAAE,OAAO,CAAA;KAAE,CAAC;IACzD,UAAU;IACV,IAAI,EAAE;QACJ,eAAe,EAAE,OAAO,CAAC;QACzB,WAAW,EAAE,OAAO,CAAC;QACrB,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;KAC7C,CAAC;IACF,iEAAiE;IACjE,SAAS,EAAE;QAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAAA;KAAE,CAAC;IACzC,UAAU;IACV,UAAU,EAAE;QACV,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,OAAO,CAAC;QACrB,eAAe,EAAE,OAAO,CAAC;QACzB,+EAA+E;QAC/E,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,kEAAkE;IAClE,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,UAAU;IACV,KAAK,EAAE;QAAE,iBAAiB,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IACxD,UAAU;IACV,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;IACxC,UAAU;IACV,SAAS,EAAE;QAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAAA;KAAE,CAAC;IACvC,WAAW;IACX,MAAM,EAAE;QAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/D;;;;;;;;;;;OAWG;IACH,KAAK,EAAE;QACL,QAAQ,EAAE,OAAO,CAAC;QAClB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAC7C,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,KAAK,CAAC;KAC1C,CAAC;IACF,oFAAoF;IACpF,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,WAAW;IACX,UAAU,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9B,WAAW;IACX,OAAO,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;CAC1C;AAkDD,0DAA0D;AAC1D,wBAAgB,UAAU,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,gBAAgB,CAElF;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,gBAAgB,CAcnF"}
package/dist/policy.js ADDED
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Presets as complete policy bundles (spec §5): `calm` (end-user, THE
3
+ * default) and `debug` (builder) are exported policy VALUES, not modes
4
+ * scattered through components. Every §3 knob lives here; the factories
5
+ * take partial overrides so a builder tunes one knob without forfeiting the
6
+ * rest of the preset.
7
+ */
8
+ import { defaultChatStrings, humanizeToolName } from "./strings.js";
9
+ /** Deep-ish merge for the one level of nesting policies actually have. */
10
+ function withOverrides(base, overrides) {
11
+ if (!overrides)
12
+ return base;
13
+ return {
14
+ ...base,
15
+ ...overrides,
16
+ strings: { ...base.strings, ...(overrides.strings ?? {}) },
17
+ userMessage: { ...base.userMessage, ...(overrides.userMessage ?? {}) },
18
+ text: { ...base.text, ...(overrides.text ?? {}) },
19
+ reasoning: { ...base.reasoning, ...(overrides.reasoning ?? {}) },
20
+ tool: { ...base.tool, ...(overrides.tool ?? {}) },
21
+ toolGroup: { ...base.toolGroup, ...(overrides.toolGroup ?? {}) },
22
+ dataResult: { ...base.dataResult, ...(overrides.dataResult ?? {}) },
23
+ view: { ...base.view, ...(overrides.view ?? {}) },
24
+ media: { ...base.media, ...(overrides.media ?? {}) },
25
+ code: { ...base.code, ...(overrides.code ?? {}) },
26
+ citations: { ...base.citations, ...(overrides.citations ?? {}) },
27
+ prompt: { ...base.prompt, ...(overrides.prompt ?? {}) },
28
+ error: { ...base.error, ...(overrides.error ?? {}) },
29
+ status: { ...base.status, ...(overrides.status ?? {}) },
30
+ compaction: { ...base.compaction, ...(overrides.compaction ?? {}) },
31
+ unknown: { ...base.unknown, ...(overrides.unknown ?? {}) },
32
+ };
33
+ }
34
+ function calmBase() {
35
+ return {
36
+ strings: defaultChatStrings,
37
+ locale: "en",
38
+ debugDetail: false,
39
+ userMessage: { retryAffordance: true },
40
+ text: { markdown: true },
41
+ reasoning: { show: true, expandedByDefault: false },
42
+ tool: { expandByDefault: false, argsVisible: false, humanizeTitle: humanizeToolName },
43
+ toolGroup: { threshold: 2 },
44
+ dataResult: { capRem: 16, prettyPrint: true, alwaysShowBytes: false, previewChars: 2048 },
45
+ view: { timeoutMs: 8000 },
46
+ media: { inlineImageCapRem: 20, chipOnly: false },
47
+ code: { capRem: 16, wrap: false },
48
+ citations: { style: "chips" },
49
+ prompt: { placement: "inline", rawPayload: false },
50
+ error: { verbatim: false, copyByCode: {}, verbatimCodes: [] },
51
+ status: { wakingMs: 2500, longStartMs: 15_000 },
52
+ compaction: { show: true },
53
+ unknown: { show: true, raw: false },
54
+ };
55
+ }
56
+ /** The `calm` preset — the end-user default (spec §5). */
57
+ export function calmPolicy(overrides) {
58
+ return withOverrides(calmBase(), overrides);
59
+ }
60
+ /** The `debug` preset — the builder surface (Studio's test chat, spec §5). */
61
+ export function debugPolicy(overrides) {
62
+ const base = calmBase();
63
+ const debug = {
64
+ ...base,
65
+ debugDetail: true,
66
+ reasoning: { ...base.reasoning, expandedByDefault: true },
67
+ tool: { ...base.tool, expandByDefault: true, argsVisible: true },
68
+ toolGroup: { threshold: false },
69
+ dataResult: { ...base.dataResult, capRem: 32, alwaysShowBytes: true },
70
+ prompt: { ...base.prompt, rawPayload: true },
71
+ error: { ...base.error, verbatim: true },
72
+ unknown: { ...base.unknown, raw: true },
73
+ };
74
+ return withOverrides(debug, overrides);
75
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * The per-category component kit (spec §3's override slots): one component
3
+ * per `DisplayItem` variant, each a THIN walk of its item — every rendering
4
+ * decision (states, labels, collapse defaults, copy) was already made by
5
+ * `planTranscript`; components translate the decided item into markup and
6
+ * never consult policy or invent copy.
7
+ *
8
+ * Override contract: `TranscriptComponents` is the component map
9
+ * (`{ tool: MyToolChip }` replaces one row's renderer without forfeiting
10
+ * the rest); every default is exported for composition.
11
+ *
12
+ * Accessibility (spec §3.2, acceptance criteria):
13
+ * - every `expanded` toggle is a real `<button aria-expanded aria-controls>`
14
+ * (keyboard-operable for free);
15
+ * - the status line is `role="status"` (a polite live region);
16
+ * - a streaming text bubble announces via `aria-live="polite"`;
17
+ * - R10 prompts take focus on appearance and return it on resolution;
18
+ * - shimmer/pulse is CSS-only and disabled under `prefers-reduced-motion`
19
+ * (see styles.css).
20
+ */
21
+ import { type ComponentType, type ReactNode } from "react";
22
+ import { type GuueyViewProps } from "@guuey/mcp-apps-host/react";
23
+ import type { ResolvedViewMount, ViewHostPhase } from "@guuey/mcp-apps-host";
24
+ import type { ChatStrings } from "../strings.js";
25
+ import type { CitationsItem, CodeItem, CompactionItem, DataResultItem, DisplayItem, ErrorItem, HistoryBoundaryItem, ItemKey, MediaItem, PromptItem, ReasoningItem, StatusLineItem, ToolGroupItem, ToolItem, UnknownItem, UserMessageItem, TextItem, ViewMountItem } from "../types.js";
26
+ /** Everything a rendered item may need beyond itself. */
27
+ export interface TranscriptItemContext {
28
+ strings: ChatStrings;
29
+ /** Flip an item's collapse state (the renderer owns override state). */
30
+ onToggle: (key: ItemKey) => void;
31
+ /** R0 failed-send retry. */
32
+ onRetry?: (item: UserMessageItem) => void;
33
+ /** R10 prompt actions — the host owns what accept/decline DO. */
34
+ onPromptAction?: (item: PromptItem, action: "accept" | "decline" | "dismiss") => void;
35
+ /** R11 action slots (sign-in / upgrade / retry affordances). */
36
+ onErrorAction?: (item: ErrorItem) => void;
37
+ /** R6: locator mounts resolved by `useTranscript` ("expired" = failed). */
38
+ resolvedMounts: ReadonlyMap<ItemKey, ResolvedViewMount | "expired">;
39
+ /** R6: live phase reports wired back into the next plan. */
40
+ onViewPhase: (key: ItemKey, phase: ViewHostPhase) => void;
41
+ /** R6 pass-through (sandbox overrides etc. — policy-gated by the host). */
42
+ viewProps?: Pick<GuueyViewProps, "hostCapabilities" | "hostInfo" | "hostContext" | "onCallTool" | "negotiationTimeoutMs" | "dangerouslyAddSandboxFlags" | "allow">;
43
+ }
44
+ interface ItemProps<T> {
45
+ item: T;
46
+ ctx: TranscriptItemContext;
47
+ }
48
+ export declare function DefaultUserMessage({ item, ctx }: ItemProps<UserMessageItem>): ReactNode;
49
+ export declare function DefaultText({ item, ctx }: ItemProps<TextItem>): ReactNode;
50
+ export declare function DefaultReasoning({ item, ctx }: ItemProps<ReasoningItem>): ReactNode;
51
+ export declare function DefaultDataResult({ item, ctx }: ItemProps<DataResultItem>): ReactNode;
52
+ export declare function DefaultTool({ item, ctx }: ItemProps<ToolItem>): ReactNode;
53
+ export declare function DefaultToolGroup({ item, ctx }: ItemProps<ToolGroupItem>): ReactNode;
54
+ export declare function DefaultView({ item, ctx }: ItemProps<ViewMountItem>): ReactNode;
55
+ export declare function DefaultMedia({ item }: ItemProps<MediaItem>): ReactNode;
56
+ export declare function DefaultCode({ item, ctx }: ItemProps<CodeItem>): ReactNode;
57
+ export declare function DefaultCitations({ item, ctx }: ItemProps<CitationsItem>): ReactNode;
58
+ export declare function DefaultPrompt({ item, ctx }: ItemProps<PromptItem>): ReactNode;
59
+ export declare function DefaultError({ item, ctx }: ItemProps<ErrorItem>): ReactNode;
60
+ export declare function DefaultHistoryBoundary({ item }: ItemProps<HistoryBoundaryItem>): ReactNode;
61
+ export declare function DefaultCompaction({ item }: ItemProps<CompactionItem>): ReactNode;
62
+ export declare function DefaultUnknown({ item, ctx }: ItemProps<UnknownItem>): ReactNode;
63
+ export declare function DefaultStatus({ item }: ItemProps<StatusLineItem>): ReactNode;
64
+ /** One component per §3 override slot. */
65
+ export interface TranscriptComponents {
66
+ userMessage: ComponentType<ItemProps<UserMessageItem>>;
67
+ text: ComponentType<ItemProps<TextItem>>;
68
+ reasoning: ComponentType<ItemProps<ReasoningItem>>;
69
+ tool: ComponentType<ItemProps<ToolItem>>;
70
+ toolGroup: ComponentType<ItemProps<ToolGroupItem>>;
71
+ dataResult: ComponentType<ItemProps<DataResultItem>>;
72
+ view: ComponentType<ItemProps<ViewMountItem>>;
73
+ media: ComponentType<ItemProps<MediaItem>>;
74
+ code: ComponentType<ItemProps<CodeItem>>;
75
+ citations: ComponentType<ItemProps<CitationsItem>>;
76
+ prompt: ComponentType<ItemProps<PromptItem>>;
77
+ error: ComponentType<ItemProps<ErrorItem>>;
78
+ history: ComponentType<ItemProps<HistoryBoundaryItem>>;
79
+ compaction: ComponentType<ItemProps<CompactionItem>>;
80
+ unknown: ComponentType<ItemProps<UnknownItem>>;
81
+ status: ComponentType<ItemProps<StatusLineItem>>;
82
+ }
83
+ export declare const defaultTranscriptComponents: TranscriptComponents;
84
+ /** Dispatch one display item through the (possibly overridden) map. */
85
+ export declare function renderItem(item: DisplayItem, components: TranscriptComponents, ctx: TranscriptItemContext): ReactNode;
86
+ export {};
87
+ //# sourceMappingURL=components.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/react/components.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,270 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * The per-category component kit (spec §3's override slots): one component
4
+ * per `DisplayItem` variant, each a THIN walk of its item — every rendering
5
+ * decision (states, labels, collapse defaults, copy) was already made by
6
+ * `planTranscript`; components translate the decided item into markup and
7
+ * never consult policy or invent copy.
8
+ *
9
+ * Override contract: `TranscriptComponents` is the component map
10
+ * (`{ tool: MyToolChip }` replaces one row's renderer without forfeiting
11
+ * the rest); every default is exported for composition.
12
+ *
13
+ * Accessibility (spec §3.2, acceptance criteria):
14
+ * - every `expanded` toggle is a real `<button aria-expanded aria-controls>`
15
+ * (keyboard-operable for free);
16
+ * - the status line is `role="status"` (a polite live region);
17
+ * - a streaming text bubble announces via `aria-live="polite"`;
18
+ * - R10 prompts take focus on appearance and return it on resolution;
19
+ * - shimmer/pulse is CSS-only and disabled under `prefers-reduced-motion`
20
+ * (see styles.css).
21
+ */
22
+ import { useEffect, useRef, useState, } from "react";
23
+ import { GuueyView } from "@guuey/mcp-apps-host/react";
24
+ import { Markdown } from "./markdown.js";
25
+ /** A collapse toggle + body pair with correct ARIA plumbing. */
26
+ function Collapsible({ itemKey, expanded, header, ctx, className, children, }) {
27
+ const bodyId = `guuey-chat-body-${itemKey}`;
28
+ return (_jsxs("div", { className: className, children: [_jsxs("button", { type: "button", className: "guuey-chat-toggle", "aria-expanded": expanded, "aria-controls": bodyId, onClick: () => ctx.onToggle(itemKey), children: [header, _jsx("span", { "aria-hidden": "true", className: "guuey-chat-toggle-glyph", children: expanded ? "▾" : "▸" })] }), expanded ? (_jsx("div", { id: bodyId, className: "guuey-chat-body", children: children })) : null] }));
29
+ }
30
+ /** A copy-to-clipboard affordance with a transient confirmation state. */
31
+ function CopyButton({ text, ctx }) {
32
+ const [copied, setCopied] = useState(false);
33
+ useEffect(() => {
34
+ if (!copied)
35
+ return;
36
+ const timer = setTimeout(() => setCopied(false), 1500);
37
+ return () => clearTimeout(timer);
38
+ }, [copied]);
39
+ return (_jsx("button", { type: "button", className: "guuey-chat-copy", onClick: () => {
40
+ void navigator.clipboard?.writeText(text).then(() => setCopied(true));
41
+ }, children: copied ? ctx.strings.copied : ctx.strings.copy }));
42
+ }
43
+ // ─── R0 ────────────────────────────────────────────────────────────────────
44
+ export function DefaultUserMessage({ item, ctx }) {
45
+ return (_jsxs("div", { className: `guuey-chat-user guuey-chat-user-${item.state}`, children: [_jsx("div", { className: "guuey-chat-user-bubble", children: item.text }), item.state === "failed" ? (_jsxs("p", { className: "guuey-chat-send-failed", role: "status", children: [ctx.strings.userCouldntSend, item.retry ? (_jsx("button", { type: "button", className: "guuey-chat-retry", onClick: () => ctx.onRetry?.(item), children: ctx.strings.userRetry })) : null] })) : null] }));
46
+ }
47
+ // ─── R1 ────────────────────────────────────────────────────────────────────
48
+ export function DefaultText({ item, ctx }) {
49
+ return (_jsxs("div", { className: "guuey-chat-text", ...(item.streaming ? { "aria-live": "polite" } : {}), children: [item.markdown ? (_jsx(Markdown, { text: item.text })) : (_jsx("p", { className: "guuey-chat-verbatim", children: item.text })), item.streaming ? (_jsx("span", { "aria-hidden": "true", className: "guuey-chat-cursor", children: " ▍" })) : null, item.stopped ? _jsx("p", { className: "guuey-chat-stopped", children: ctx.strings.stopped }) : null] }));
50
+ }
51
+ // ─── R2 ────────────────────────────────────────────────────────────────────
52
+ export function DefaultReasoning({ item, ctx }) {
53
+ return (_jsx(Collapsible, { itemKey: item.key, expanded: item.expanded, ctx: ctx, className: `guuey-chat-reasoning${item.streaming ? " guuey-chat-pulse" : ""}`, header: _jsx("span", { children: item.label }), children: _jsx("p", { className: "guuey-chat-reasoning-text", children: item.text }) }));
54
+ }
55
+ // ─── R5 (also embedded inside R3's expansion) ──────────────────────────────
56
+ export function DefaultDataResult({ item, ctx }) {
57
+ const bytes = ctx.strings.bytes(item.byteCount);
58
+ return (_jsx("div", { className: `guuey-chat-data guuey-chat-data-${item.state}`, children: item.state === "empty" ? (_jsx("p", { className: "guuey-chat-data-empty", children: ctx.strings.noOutput })) : item.preview === null ? (_jsx("p", { className: "guuey-chat-data-binary", children: bytes })) : (_jsxs(_Fragment, { children: [_jsx("pre", { className: "guuey-chat-data-preview", children: item.preview }), _jsxs("div", { className: "guuey-chat-data-meta", children: [item.showBytes ? _jsx("span", { children: bytes }) : null, _jsx(CopyButton, { text: item.preview, ctx: ctx })] })] })) }));
59
+ }
60
+ // ─── R3 ────────────────────────────────────────────────────────────────────
61
+ const TOOL_GLYPH = {
62
+ running: "◌",
63
+ done: "✓",
64
+ failed: "✕",
65
+ orphaned: "–",
66
+ };
67
+ export function DefaultTool({ item, ctx }) {
68
+ // R4's display-bearing rule: in calm this call's line lives in its view
69
+ // row's chrome ("via {tool}") — rendering it here too would double it.
70
+ if (item.attribution)
71
+ return null;
72
+ const expandable = item.argsPreview !== null || item.result !== null;
73
+ const header = (_jsxs("span", { className: `guuey-chat-tool-line guuey-chat-tool-${item.state}`, children: [_jsx("span", { "aria-hidden": "true", className: "guuey-chat-tool-glyph", children: TOOL_GLYPH[item.state] }), _jsx("span", { className: "guuey-chat-tool-title", children: item.title }), item.state === "orphaned" ? (_jsx("span", { className: "guuey-chat-tool-note", children: ctx.strings.toolDidntFinish })) : null] }));
74
+ if (!expandable)
75
+ return _jsx("div", { className: "guuey-chat-tool", children: header });
76
+ return (_jsxs(Collapsible, { itemKey: item.key, expanded: item.expanded, ctx: ctx, className: "guuey-chat-tool", header: header, children: [item.argsPreview !== null ? (_jsx("pre", { className: "guuey-chat-tool-args", children: item.argsPreview })) : null, item.result !== null ? _jsx(DefaultDataResult, { item: item.result, ctx: ctx }) : null] }));
77
+ }
78
+ // ─── R4 ────────────────────────────────────────────────────────────────────
79
+ export function DefaultToolGroup({ item, ctx }) {
80
+ return (_jsx(Collapsible, { itemKey: item.key, expanded: item.expanded, ctx: ctx, className: "guuey-chat-tool-group", header: _jsxs("span", { children: [item.label, item.failureBadge !== null ? (_jsx("span", { className: "guuey-chat-failure-badge", children: item.failureBadge })) : null] }), children: item.tools.map((tool) => (_jsx(DefaultTool, { item: tool, ctx: ctx }, tool.key))) }));
81
+ }
82
+ // ─── R6 ────────────────────────────────────────────────────────────────────
83
+ export function DefaultView({ item, ctx }) {
84
+ // Resolve what to actually mount: direct material, or the locator's
85
+ // resolution from `useTranscript` (renderer state — "expired" = miss).
86
+ const resolution = ctx.resolvedMounts.get(item.key);
87
+ const mount = item.mount !== null && item.mount.channel !== "locator"
88
+ ? item.mount
89
+ : resolution !== undefined && resolution !== "expired"
90
+ ? resolution
91
+ : null;
92
+ const expired = item.phase === "expired" || resolution === "expired";
93
+ if (expired) {
94
+ return (_jsx("div", { className: "guuey-chat-view guuey-chat-view-expired", children: _jsx("p", { role: "status", children: ctx.strings.viewExpired }) }));
95
+ }
96
+ if (mount === null) {
97
+ // A locator still resolving (or a plan-level expired mount) — labeled,
98
+ // never blank.
99
+ return (_jsx("div", { className: "guuey-chat-view guuey-chat-view-negotiating guuey-chat-shimmer", children: _jsx("p", { role: "status", children: item.label ?? ctx.strings.viewNegotiating }) }));
100
+ }
101
+ return (_jsxs("div", { className: "guuey-chat-view", children: [_jsx(GuueyView, { mount: mount, ...(ctx.viewProps ?? {}), onPhaseChange: (phase) => ctx.onViewPhase(item.key, phase) }), item.attribution !== null ? (_jsx("p", { className: "guuey-chat-attribution", children: item.attribution })) : null] }));
102
+ }
103
+ // ─── R7 ────────────────────────────────────────────────────────────────────
104
+ /** Inline images allow https URLs and image/* base64 data — nothing else. */
105
+ function imageSrc(item) {
106
+ const source = item.source;
107
+ if (source.type === "url" && /^https:\/\//i.test(source.url))
108
+ return source.url;
109
+ if (source.type === "base64" && /^image\//.test(source.mediaType)) {
110
+ return `data:${source.mediaType};base64,${source.data}`;
111
+ }
112
+ return null;
113
+ }
114
+ export function DefaultMedia({ item }) {
115
+ const [failed, setFailed] = useState(false);
116
+ if (item.presentation === "inline" && item.media === "image" && !failed) {
117
+ const src = imageSrc(item);
118
+ if (src !== null) {
119
+ return (_jsx("a", { className: "guuey-chat-media-image", href: src, target: "_blank", rel: "noopener noreferrer", children: _jsx("img", { src: src, alt: item.name ?? "", onError: () => setFailed(true) }) }));
120
+ }
121
+ }
122
+ if (item.media === "audio" && item.source.type === "url" && /^https:\/\//i.test(item.source.url)) {
123
+ return _jsx("audio", { className: "guuey-chat-media-audio", controls: true, src: item.source.url });
124
+ }
125
+ // Attachment chip: files, documents, unloadable/oversized media.
126
+ return (_jsx("span", { className: `guuey-chat-media-chip guuey-chat-media-${item.media}`, children: item.name ?? item.media }));
127
+ }
128
+ // ─── R8 ────────────────────────────────────────────────────────────────────
129
+ export function DefaultCode({ item, ctx }) {
130
+ return (_jsxs("div", { className: "guuey-chat-code", children: [_jsxs("div", { className: "guuey-chat-code-meta", children: [_jsx("span", { className: "guuey-chat-code-lang", children: item.language }), _jsx(CopyButton, { text: item.code, ctx: ctx })] }), _jsx("pre", { className: item.wrap ? "guuey-chat-code-wrap" : undefined, children: item.code })] }));
131
+ }
132
+ // ─── R9 ────────────────────────────────────────────────────────────────────
133
+ /** Citation links navigate only to http(s) targets. */
134
+ function safeCitationUrl(url) {
135
+ return url !== null && /^https?:\/\//i.test(url) ? url : null;
136
+ }
137
+ export function DefaultCitations({ item, ctx }) {
138
+ return (_jsx(Collapsible, { itemKey: item.key, expanded: item.expanded, ctx: ctx, className: "guuey-chat-citations", header: _jsx("span", { children: item.label }), children: _jsx("ul", { className: `guuey-chat-citations-${item.style}`, children: item.sources.map((source, i) => {
139
+ const url = safeCitationUrl(source.url);
140
+ const label = source.title ?? source.url ?? "";
141
+ return (_jsx("li", { children: url !== null ? (_jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", children: label })) : (_jsx("span", { children: label })) }, i));
142
+ }) }) }));
143
+ }
144
+ // ─── R10 ───────────────────────────────────────────────────────────────────
145
+ export function DefaultPrompt({ item, ctx }) {
146
+ const firstAction = useRef(null);
147
+ const restoreTo = useRef(null);
148
+ const wasPending = useRef(false);
149
+ // Focus management (§3.2): take focus when the ask appears, hand it back
150
+ // when the ask resolves.
151
+ useEffect(() => {
152
+ if (item.state === "pending" && !wasPending.current) {
153
+ restoreTo.current = document.activeElement;
154
+ firstAction.current?.focus();
155
+ }
156
+ if (item.state !== "pending" && wasPending.current) {
157
+ const target = restoreTo.current;
158
+ if (target instanceof HTMLElement && target.isConnected)
159
+ target.focus();
160
+ }
161
+ wasPending.current = item.state === "pending";
162
+ }, [item.state]);
163
+ if (item.state !== "pending") {
164
+ return (_jsxs("p", { className: `guuey-chat-prompt-record guuey-chat-prompt-${item.state}`, children: [item.promptKind, ": ", item.state] }));
165
+ }
166
+ return (_jsxs("div", { className: "guuey-chat-prompt", role: "group", children: [_jsx("p", { className: "guuey-chat-prompt-ask", children: item.promptKind === "consent"
167
+ ? `${item.appId} requests ${item.requested} access`
168
+ : `Link your account to ${item.appId}` }), _jsxs("div", { className: "guuey-chat-prompt-actions", children: [_jsx("button", { ref: firstAction, type: "button", className: "guuey-chat-prompt-accept", onClick: () => ctx.onPromptAction?.(item, "accept"), children: "Allow" }), _jsx("button", { type: "button", onClick: () => ctx.onPromptAction?.(item, "decline"), children: "Decline" })] }), item.raw !== null ? (_jsx("pre", { className: "guuey-chat-prompt-raw", children: JSON.stringify(item.raw, null, 2) })) : null] }));
169
+ }
170
+ // ─── R11 ───────────────────────────────────────────────────────────────────
171
+ export function DefaultError({ item, ctx }) {
172
+ return (_jsxs("div", { className: `guuey-chat-error guuey-chat-error-${item.family}`, role: "alert", children: [_jsx("p", { children: item.copy }), ctx.onErrorAction !== undefined && (item.family === "transient" || item.family === "auth") ? (_jsx("button", { type: "button", className: "guuey-chat-error-action", onClick: () => ctx.onErrorAction?.(item), children: item.family === "auth" ? ctx.strings.errorAuth : ctx.strings.userRetry })) : null, item.verbatim !== null ? _jsx("pre", { className: "guuey-chat-error-verbatim", children: item.verbatim }) : null] }));
173
+ }
174
+ // ─── R13 / R14 / R15 ───────────────────────────────────────────────────────
175
+ export function DefaultHistoryBoundary({ item }) {
176
+ return (_jsx("div", { className: `guuey-chat-history guuey-chat-history-${item.state}${item.state === "loading" ? " guuey-chat-shimmer" : ""}`, role: "status", children: item.label }));
177
+ }
178
+ export function DefaultCompaction({ item }) {
179
+ return (_jsx("div", { className: "guuey-chat-compaction", role: "separator", children: item.label }));
180
+ }
181
+ export function DefaultUnknown({ item, ctx }) {
182
+ return (_jsx(Collapsible, { itemKey: item.key, expanded: item.expanded, ctx: ctx, className: "guuey-chat-unknown", header: _jsxs("span", { children: [item.label, " ", _jsxs("span", { className: "guuey-chat-unknown-type", children: ["(", item.typeName, ")"] })] }), children: item.raw !== null ? (_jsx("pre", { className: "guuey-chat-unknown-raw", children: JSON.stringify(item.raw, null, 2) })) : (_jsx("p", { className: "guuey-chat-unknown-size", children: ctx.strings.bytes(item.byteSize) })) }));
183
+ }
184
+ // ─── R12 / §4 ──────────────────────────────────────────────────────────────
185
+ export function DefaultStatus({ item }) {
186
+ return (_jsxs("p", { className: `guuey-chat-status guuey-chat-status-${item.state} guuey-chat-pulse`, role: "status", children: [item.copy, item.detail !== null ? _jsxs("span", { className: "guuey-chat-status-detail", children: [" \u00B7 ", item.detail] }) : null] }));
187
+ }
188
+ export const defaultTranscriptComponents = {
189
+ userMessage: DefaultUserMessage,
190
+ text: DefaultText,
191
+ reasoning: DefaultReasoning,
192
+ tool: DefaultTool,
193
+ toolGroup: DefaultToolGroup,
194
+ dataResult: DefaultDataResult,
195
+ view: DefaultView,
196
+ media: DefaultMedia,
197
+ code: DefaultCode,
198
+ citations: DefaultCitations,
199
+ prompt: DefaultPrompt,
200
+ error: DefaultError,
201
+ history: DefaultHistoryBoundary,
202
+ compaction: DefaultCompaction,
203
+ unknown: DefaultUnknown,
204
+ status: DefaultStatus,
205
+ };
206
+ /** Dispatch one display item through the (possibly overridden) map. */
207
+ export function renderItem(item, components, ctx) {
208
+ switch (item.kind) {
209
+ case "user": {
210
+ const C = components.userMessage;
211
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
212
+ }
213
+ case "text": {
214
+ const C = components.text;
215
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
216
+ }
217
+ case "reasoning": {
218
+ const C = components.reasoning;
219
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
220
+ }
221
+ case "tool": {
222
+ const C = components.tool;
223
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
224
+ }
225
+ case "tool-group": {
226
+ const C = components.toolGroup;
227
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
228
+ }
229
+ case "data-result": {
230
+ const C = components.dataResult;
231
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
232
+ }
233
+ case "view": {
234
+ const C = components.view;
235
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
236
+ }
237
+ case "media": {
238
+ const C = components.media;
239
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
240
+ }
241
+ case "code": {
242
+ const C = components.code;
243
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
244
+ }
245
+ case "citations": {
246
+ const C = components.citations;
247
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
248
+ }
249
+ case "prompt": {
250
+ const C = components.prompt;
251
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
252
+ }
253
+ case "error": {
254
+ const C = components.error;
255
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
256
+ }
257
+ case "history-boundary": {
258
+ const C = components.history;
259
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
260
+ }
261
+ case "compaction": {
262
+ const C = components.compaction;
263
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
264
+ }
265
+ case "unknown": {
266
+ const C = components.unknown;
267
+ return _jsx(C, { item: item, ctx: ctx }, item.key);
268
+ }
269
+ }
270
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * `<GuueyChat>` — the batteries-included surface (guuey#135 wave 3c): the
3
+ * whole tier stack wired end to end, PLUS the composer (which arrives here
4
+ * per the founder ruling — earlier tiers are transcript-only).
5
+ *
6
+ * useAgentInvoke → useTranscriptInputs → useTranscript → <Transcript>
7
+ * + the composer
8
+ *
9
+ * It is a THIN composition of the exported tiers — every wire below is a
10
+ * public API, so a builder ejects one level down (own composer around
11
+ * `<Transcript>`, own renderer over `planTranscript`, own everything over
12
+ * `invokeTurn`) without a cliff. Every prop beyond the connection
13
+ * essentials is optional.
14
+ *
15
+ * ## Composer state matrix
16
+ *
17
+ * - `endpointUrl === null` → input disabled, `composerUnavailable`
18
+ * placeholder (chat cannot exist).
19
+ * - idle (`status === "ready"`) → input enabled; **Send** enabled iff the
20
+ * input has non-whitespace text.
21
+ * - in flight (any other status, cold-start waits included — R12's status
22
+ * line owns the WHY) → input stays enabled (type the next message while
23
+ * the agent works), Send is replaced by **Stop**, which aborts the turn
24
+ * (partial text kept, "Stopped." marked — the hook's contract).
25
+ * - Enter sends; Shift+Enter inserts a newline; an IME-composing Enter
26
+ * never sends (the candidate commit is not a submit).
27
+ *
28
+ * ## History
29
+ *
30
+ * Thread rehydration is the HOOK's mechanics: give `adapters` a `history`
31
+ * adapter (e.g. `createWebAdapters({ apiBaseUrl, … })`) and a persisted
32
+ * threadId rehydrates on mount — text transcript + persisted cards, which
33
+ * mount through the same R6 path as live views. Nothing here to configure.
34
+ */
35
+ import { type CSSProperties, type ReactNode } from "react";
36
+ import { type AgentInvokeAdapters } from "@guuey/agent-client";
37
+ import type { UiResourceReader } from "@guuey/mcp-apps-host";
38
+ import { type TranscriptPolicy } from "../policy.js";
39
+ import { type ChatStrings } from "../strings.js";
40
+ import { type GuueyChatTheme } from "../theme.js";
41
+ import type { ErrorItem, PromptItem } from "../types.js";
42
+ import type { ThemeMode } from "./theme-css.js";
43
+ import { type TranscriptWindowing } from "./transcript.js";
44
+ import type { TranscriptComponents, TranscriptItemContext } from "./components.js";
45
+ export interface GuueyChatProps {
46
+ /** Pod base URL (with or without `/agent/invoke`). `null` disables chat. */
47
+ endpointUrl: string | null;
48
+ /** Owning app id — namespaces the persisted threadId. */
49
+ appId?: string;
50
+ /**
51
+ * Host couplings (storage / id / transport / history). Default:
52
+ * `createWebAdapters()` — localStorage thread persistence + the web SSE
53
+ * transport (cookie/guest identity, saturation + cold-start retries).
54
+ */
55
+ adapters?: AgentInvokeAdapters;
56
+ /** Policy preset (spec §5). Default `"calm"`. */
57
+ preset?: "calm" | "debug";
58
+ /** Knob overrides applied on top of the preset (spec §3's columns). */
59
+ policy?: Partial<TranscriptPolicy>;
60
+ /** Per-slot component overrides (spec §3's override column). */
61
+ components?: Partial<TranscriptComponents>;
62
+ /** String overrides — merged over the preset's `ChatStrings` (§4.2). */
63
+ strings?: Partial<ChatStrings>;
64
+ theme?: GuueyChatTheme;
65
+ mode?: ThemeMode;
66
+ /** DOM windowing (§3.2). `false` renders everything. */
67
+ window?: TranscriptWindowing | false;
68
+ /** R6 locator resolution (history cards). See `useTranscript`. */
69
+ reader?: UiResourceReader;
70
+ /** R6 pass-through (relay hook, sandbox page/flags, host context…). */
71
+ viewProps?: TranscriptItemContext["viewProps"];
72
+ /**
73
+ * R10: what accept/decline actually DO (the grant channel is the host's).
74
+ * The transcript record moves regardless; without a handler the prompt
75
+ * card is record-only.
76
+ */
77
+ onPromptAction?: (item: PromptItem, action: "accept" | "decline" | "dismiss") => void;
78
+ /** R11 action slot (sign-in / retry affordances). */
79
+ onErrorAction?: (item: ErrorItem) => void;
80
+ className?: string;
81
+ style?: CSSProperties;
82
+ }
83
+ export declare function GuueyChat(props: GuueyChatProps): ReactNode;
84
+ //# sourceMappingURL=guuey-chat.d.ts.map