@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
package/src/types.ts ADDED
@@ -0,0 +1,320 @@
1
+ /**
2
+ * The headless view-model's public types (wave-3a design §7, guuey#135).
3
+ *
4
+ * Everything here is DATA — no clocks, no DOM, no React. `planTranscript`
5
+ * (see `plan.ts`) is a pure function of these inputs; the renderers (React in
6
+ * 3b, RN in 3c) are thin walks of its output.
7
+ *
8
+ * Category vocabulary is ADOPTED from AgJSON (`@silverprotocol/core` owns
9
+ * it — the spec's "adopt, never invent" invariant): the matrix rows R0–R15
10
+ * map onto the fold's real block types plus `invokeTurn`'s turn-level
11
+ * events. A category this UI needs but AgJSON cannot express is an upstream
12
+ * silverprotocol change, never a guuey-side extension.
13
+ */
14
+ import type { AgReduceResult, AgSource, JsonValue } from "@silverprotocol/core";
15
+ import type { AgentInvokeStatus, HistoryCard } from "@guuey/agent-client";
16
+ import type { ViewHostPhase, ViewMount, ViewMountChannel } from "@guuey/mcp-apps-host";
17
+
18
+ /**
19
+ * One settled entry of the flat conversation transcript — structurally
20
+ * compatible with the hook's `AgentMessage`, plus the optional
21
+ * `clientMessageId` the R0 send-lifecycle join needs (the 3b live assembler
22
+ * threads it through; history entries and older callers simply omit it).
23
+ */
24
+ export interface TranscriptMessage {
25
+ role: "user" | "assistant";
26
+ text: string;
27
+ /** Present on live-sent user turns — the `sendStates` join key (R0). */
28
+ clientMessageId?: string;
29
+ }
30
+
31
+ /**
32
+ * A pending/resolved consent or link ask (R10) — the turn-level
33
+ * `profile-consent` / `profile-link` events lifted into renderable state.
34
+ * The assembler (3b) accumulates these from `invokeTurn` events; `id` is
35
+ * assembler-chosen and stable for the ask's lifetime.
36
+ */
37
+ export interface PromptItemInput {
38
+ id: string;
39
+ kind: "consent" | "link";
40
+ appId: string;
41
+ requested: "read" | "read-write";
42
+ state: "pending" | "answered" | "declined" | "dismissed";
43
+ }
44
+
45
+ /** Everything the plan derives from. All fields are data — no clocks, no DOM. */
46
+ export interface TranscriptInputs {
47
+ /** The Reducer's fold (silver mode); null on bypass-frame streams. */
48
+ result: AgReduceResult | null;
49
+ /**
50
+ * The in-flight turn's cumulative text fold (ALWAYS present; the sole
51
+ * assistant text source in bypass mode). Ignored once `status` is back to
52
+ * `ready` — the settled transcript owns finished turns — EXCEPT when
53
+ * `aborted` is set, where it carries the kept partial (R1
54
+ * aborted-partial).
55
+ */
56
+ assistantText: string;
57
+ status: AgentInvokeStatus;
58
+ /** Renderer-supplied elapsed ms in the current status; drives R12 escalation. */
59
+ statusElapsedMs: number;
60
+ activeTool: string | null;
61
+ error: { message: string; code: string | null } | null;
62
+ /** Pending/answered consent + link asks (R10). */
63
+ prompts: PromptItemInput[];
64
+ /**
65
+ * The settled conversation, both roles, in order. Assistant entries are
66
+ * the flat-text projection; when `result` is present the FOLD owns
67
+ * assistant content and these entries' assistant text is not re-rendered
68
+ * (one unified plan owns both — spec §9 Change-1).
69
+ */
70
+ messages: TranscriptMessage[];
71
+ historyCards?: HistoryCard[];
72
+ /** R13 rehydration state; absent means loaded. */
73
+ historyState?: "loading" | "gone" | "loaded";
74
+ /** R0: optimistic-send lifecycle, keyed by clientMessageId; absent = settled. */
75
+ sendStates?: Readonly<Record<string, "sending" | "failed">>;
76
+ /** mountKey → live phase (R6 states). Keys match `ViewMountItem.key`. */
77
+ viewPhases?: Readonly<Record<string, ViewHostPhase>>;
78
+ /** The last turn ended by user abort (R1 aborted-partial + "Stopped."). */
79
+ aborted?: boolean;
80
+ /**
81
+ * The last turn was ADOPTED from history after a mid-stream stall
82
+ * (guuey#192's watchdog). Calm renders it identically to a streamed turn;
83
+ * debug appends the recovered marker (spec §3, F10). The hook sets this
84
+ * in the 3b live assembler.
85
+ */
86
+ adopted?: boolean;
87
+ }
88
+
89
+ /** Stable per-item identity — survives streaming updates (spec §7). */
90
+ export type ItemKey = string;
91
+
92
+ /** User-toggled collapse state — OWNED by the renderer, passed in (purity). */
93
+ export type TranscriptOverrides = Readonly<Record<ItemKey, { expanded?: boolean }>>;
94
+
95
+ // ─── DisplayItem variants (one per matrix row) ─────────────────────────────
96
+
97
+ interface BaseItem {
98
+ key: ItemKey;
99
+ /** Resolved collapse state: policy default, then `overrides[key]` wins. */
100
+ expanded: boolean;
101
+ }
102
+
103
+ /** R0 — the caller's own turn. */
104
+ export interface UserMessageItem extends BaseItem {
105
+ kind: "user";
106
+ text: string;
107
+ state: "sending" | "sent" | "failed";
108
+ /** The failed-state affordance (policy-gated); never silently disappears. */
109
+ retry: boolean;
110
+ }
111
+
112
+ /** R1 — assistant text. */
113
+ export interface TextItem extends BaseItem {
114
+ kind: "text";
115
+ text: string;
116
+ markdown: boolean;
117
+ streaming: boolean;
118
+ /** Aborted-partial: kept, marked with `strings.stopped`. */
119
+ stopped: boolean;
120
+ }
121
+
122
+ /** R2 — reasoning. */
123
+ export interface ReasoningItem extends BaseItem {
124
+ kind: "reasoning";
125
+ label: string;
126
+ text: string;
127
+ streaming: boolean;
128
+ }
129
+
130
+ /** R5 — a data result, embedded inside its R3 row's expansion. */
131
+ export interface DataResultItem extends BaseItem {
132
+ kind: "data-result";
133
+ /**
134
+ * A bounded pretty-printed preview — NEVER the full payload (the plan
135
+ * stays cheap; fixture 6). Null for binary/unrenderable content.
136
+ */
137
+ preview: string | null;
138
+ byteCount: number;
139
+ state: "small" | "giant" | "binary" | "empty";
140
+ showBytes: boolean;
141
+ }
142
+
143
+ /** R3 — one tool call lifecycle line. */
144
+ export interface ToolItem extends BaseItem {
145
+ kind: "tool";
146
+ toolCallId: string;
147
+ /** The wire name. */
148
+ name: string;
149
+ /** The humanized display title (policy's humanizer). */
150
+ title: string;
151
+ state: "running" | "done" | "failed" | "orphaned";
152
+ /** Bounded args preview (policy-gated); null when args are hidden. */
153
+ argsPreview: string | null;
154
+ /** The result inside this row's expansion (R5); null while running. */
155
+ result: DataResultItem | null;
156
+ /**
157
+ * True when this call's result renders as its own transcript row (an R6
158
+ * view) and calm folds this line into that row's chrome as attribution
159
+ * instead of a standalone line (R4's display-bearing rule).
160
+ */
161
+ attribution: boolean;
162
+ }
163
+
164
+ /** R4 — a collapsed run of adjacent settled SILENT tools. */
165
+ export interface ToolGroupItem extends BaseItem {
166
+ kind: "tool-group";
167
+ label: string;
168
+ tools: ToolItem[];
169
+ failureCount: number;
170
+ /** Non-empty when failureCount > 0 ("1 failed" — badge without unrolling). */
171
+ failureBadge: string | null;
172
+ }
173
+
174
+ /** R6 — a renderable result mounting through the wave-2 host. */
175
+ export interface ViewMountItem extends BaseItem {
176
+ kind: "view";
177
+ /** The mount material; null when the locator is dead (R13 expired path). */
178
+ mount: ViewMount | null;
179
+ channel: ViewMountChannel | null;
180
+ /** Live host phase, or the R13 dead-locator state. */
181
+ phase: ViewHostPhase | "expired";
182
+ /** The channel-aware state label the renderer shows for non-connected phases. */
183
+ label: string | null;
184
+ /** Calm chrome: "via {tool}" when this mount broke an R4 group. */
185
+ attribution: string | null;
186
+ /** The producing call's humanized title (live mounts); null for history cards. */
187
+ toolTitle: string | null;
188
+ /**
189
+ * The persisted `ui://` locator a mounted card's runtime actions bind to
190
+ * (guuey#158) — the block's `uiData.resourceUri` for live mounts, the
191
+ * card's own persisted identity for history snapshots; never a ggui
192
+ * shell's synthetic payload uri. `null` → the host's relay answers its
193
+ * in-band "not available" stub.
194
+ */
195
+ actionScope: string | null;
196
+ }
197
+
198
+ /** R7 — media blocks. */
199
+ export interface MediaItem extends BaseItem {
200
+ kind: "media";
201
+ media: "image" | "audio" | "file" | "document";
202
+ source: AgSource;
203
+ name: string | null;
204
+ presentation: "inline" | "chip";
205
+ }
206
+
207
+ /** R8 — code blocks. */
208
+ export interface CodeItem extends BaseItem {
209
+ kind: "code";
210
+ language: string;
211
+ code: string;
212
+ wrap: boolean;
213
+ }
214
+
215
+ /** R9 — a citation run collapsed to a chip row. */
216
+ export interface CitationsItem extends BaseItem {
217
+ kind: "citations";
218
+ label: string;
219
+ sources: { title: string | null; url: string | null }[];
220
+ style: "chips" | "list";
221
+ }
222
+
223
+ /** R10 — a consent/link prompt card. */
224
+ export interface PromptItem extends BaseItem {
225
+ kind: "prompt";
226
+ /** The `PromptItemInput.id` this row records — the host's resolution key. */
227
+ promptId: string;
228
+ promptKind: "consent" | "link";
229
+ appId: string;
230
+ requested: "read" | "read-write";
231
+ state: "pending" | "answered" | "declined" | "dismissed";
232
+ /** Raw ask payload, populated only under the debug policy. */
233
+ raw: JsonValue | null;
234
+ }
235
+
236
+ /** R11 — a coded, human-worded error notice. */
237
+ export interface ErrorItem extends BaseItem {
238
+ kind: "error";
239
+ /**
240
+ * The source message (wire body or client-side error copy), regardless of
241
+ * policy — `copy` is the calm family sentence; overrides that keep a
242
+ * surface's own voice (the widget renders pod messages verbatim) need the
243
+ * original without opting into debug's `verbatim` formatting.
244
+ */
245
+ message: string;
246
+ family: "auth" | "quota" | "transient" | "invalid";
247
+ code: string | null;
248
+ copy: string;
249
+ /** The wire message verbatim, populated only under the debug policy. */
250
+ verbatim: string | null;
251
+ }
252
+
253
+ /** R13 — history rehydration boundary states. */
254
+ export interface HistoryBoundaryItem extends BaseItem {
255
+ kind: "history-boundary";
256
+ state: "loading" | "gone";
257
+ label: string;
258
+ }
259
+
260
+ /** R14 — the compaction divider. */
261
+ export interface CompactionItem extends BaseItem {
262
+ kind: "compaction";
263
+ label: string;
264
+ }
265
+
266
+ /** R15 — the trust invariant: labeled, collapsed, never blank, never raw. */
267
+ export interface UnknownItem extends BaseItem {
268
+ kind: "unknown";
269
+ label: string;
270
+ typeName: string;
271
+ byteSize: number;
272
+ /** Pretty-printed payload, populated only under the debug policy. */
273
+ raw: JsonValue | null;
274
+ }
275
+
276
+ export type DisplayItem =
277
+ | UserMessageItem
278
+ | TextItem
279
+ | ReasoningItem
280
+ | ToolItem
281
+ | ToolGroupItem
282
+ | DataResultItem
283
+ | ViewMountItem
284
+ | MediaItem
285
+ | CodeItem
286
+ | CitationsItem
287
+ | PromptItem
288
+ | ErrorItem
289
+ | HistoryBoundaryItem
290
+ | CompactionItem
291
+ | UnknownItem;
292
+
293
+ /** R12/§4 — the derived status line with its resolved copy. */
294
+ export interface StatusLineItem {
295
+ kind: "status";
296
+ key: "status";
297
+ state:
298
+ | "connecting"
299
+ | "starting"
300
+ | "long-start"
301
+ | "thinking"
302
+ | "using-tool"
303
+ | "aborted";
304
+ copy: string;
305
+ /** Literal state + elapsed, populated only under the debug policy. */
306
+ detail: string | null;
307
+ }
308
+
309
+ export interface TranscriptPlan {
310
+ /** Ordered, stable keys (spec §7's determinism contract). */
311
+ items: DisplayItem[];
312
+ /** Null when there is nothing to show (`ready`, `responding`). */
313
+ status: StatusLineItem | null;
314
+ /**
315
+ * The #192 recovered-turn marker: the resolved marker string under the
316
+ * debug policy when `inputs.adopted` is set, else null — calm plans stay
317
+ * byte-identical to a streamed turn's (fixture 17).
318
+ */
319
+ recovery: string | null;
320
+ }