@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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Loqu, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # @guuey/chat
2
+
3
+ The default end-user transcript UI for [guuey](https://guuey.com) agents —
4
+ the presentation layer that makes a long, tool-heavy agent turn _readable_:
5
+ tool calls collapse into calm one-liners, generative-UI views mount inline,
6
+ cold starts and failures are designed states instead of blank screens, and
7
+ every unknown block renders as a labeled row (never blank, never raw JSON).
8
+
9
+ ```bash
10
+ npm install @guuey/chat
11
+ ```
12
+
13
+ ## The React kit (`@guuey/chat/react`)
14
+
15
+ The fastest path on the web — the component kit over the live assembler,
16
+ with the default stylesheet:
17
+
18
+ ```tsx
19
+ import { useAgentInvoke, createWebAdapters } from "@guuey/agent-client/react";
20
+ import { calmPolicy } from "@guuey/chat";
21
+ import { Transcript, useTranscript, useTranscriptInputs } from "@guuey/chat/react";
22
+ import "@guuey/chat/styles.css";
23
+
24
+ function Chat({ endpointUrl }: { endpointUrl: string }) {
25
+ const invoke = useAgentInvoke({ endpointUrl, appId: "my-app", adapters: createWebAdapters() });
26
+ const { inputs } = useTranscriptInputs(invoke);
27
+ const { plan, toggle, onViewPhase, resolvedMounts } = useTranscript({
28
+ inputs,
29
+ policy: calmPolicy(),
30
+ });
31
+ return (
32
+ <Transcript
33
+ plan={plan}
34
+ onToggle={toggle}
35
+ onViewPhase={onViewPhase}
36
+ resolvedMounts={resolvedMounts}
37
+ />
38
+ );
39
+ }
40
+ ```
41
+
42
+ What the kit owns (so you don't): stick-to-bottom scroll with a
43
+ jump-to-latest release, windowed rendering for long transcripts,
44
+ `aria-live`/keyboard/focus accessibility, sanitized markdown (typed AST —
45
+ raw HTML is unrepresentable, links are scheme-allowlisted), generative-UI
46
+ views mounting through `@guuey/mcp-apps-host`'s sandboxed host, and theming
47
+ from the `GuueyChatTheme` token schema (`--guuey-chat-*` custom properties;
48
+ `GUUEY_CHAT_THEME` ships beside the neutral default).
49
+
50
+ Override one row without forfeiting the rest:
51
+
52
+ ```tsx
53
+ <Transcript plan={plan} components={{ tool: MyToolChip }} … />
54
+ ```
55
+
56
+ Server-side (no hook, no DOM): assemble inputs from a persisted thread read
57
+ with `transcriptInputsFromHistory` and plan/render anywhere Node runs.
58
+
59
+ ## The headless view-model (the root subpath)
60
+
61
+ The **headless** half — a pure function from agent state to an ordered
62
+ display plan. The root subpath stays React-free forever (the
63
+ batteries-included `<GuueyChat>` surface arrives in the next wave).
64
+
65
+ ```ts
66
+ import { planTranscript, calmPolicy } from "@guuey/chat";
67
+
68
+ const plan = planTranscript(
69
+ {
70
+ result: reduceResult, // the @silverprotocol/core Reducer's fold (or null)
71
+ assistantText, // the in-flight turn's cumulative text
72
+ status, // ready | connecting | thinking | using-tool | responding
73
+ statusElapsedMs, // you supply elapsed time — the function has no clock
74
+ activeTool,
75
+ error: null,
76
+ prompts: [],
77
+ messages, // the settled conversation, both roles
78
+ },
79
+ calmPolicy()
80
+ );
81
+
82
+ for (const item of plan.items) {
83
+ // item.kind: "user" | "text" | "tool" | "tool-group" | "view" | "media"
84
+ // | "code" | "citations" | "prompt" | "error" | "reasoning"
85
+ // | "data-result" | "history-boundary" | "compaction" | "unknown"
86
+ }
87
+ plan.status; // the derived status line ("Starting your agent…") or null
88
+ ```
89
+
90
+ Determinism contract: same inputs + policy + overrides ⇒ a deeply equal
91
+ plan, with **stable item keys** across streaming updates (a tool's key
92
+ survives from `running` to `done`), so renderer state and DOM identity hold.
93
+
94
+ ## Presets
95
+
96
+ `calmPolicy()` is the end-user default: tool runs group into "Ran N tools ▸",
97
+ reasoning collapses to a line, results are scroll-capped. `debugPolicy()` is
98
+ the builder surface: every tool its own row, args and results expanded, wire
99
+ codes verbatim, raw payloads on unknown content.
100
+
101
+ Both are complete policy bundles — override any knob or any user-facing
102
+ string (`ChatStrings`, the i18n seam) without forfeiting the rest:
103
+
104
+ ```ts
105
+ calmPolicy({ toolGroup: { threshold: 3 }, strings: { thinking: "Pondering…" } });
106
+ ```
107
+
108
+ ## Theme
109
+
110
+ `GuueyChatTheme` is a serializable token schema (zod) — the same object a
111
+ builder configures on platform.guuey.com. Parsing is lenient and resolution
112
+ falls back **per token** to the default theme, so a partial or old-schema
113
+ theme can never produce an unreadable surface:
114
+
115
+ ```ts
116
+ import { resolveTheme, GUUEY_CHAT_THEME } from "@guuey/chat";
117
+ const theme = resolveTheme(appConfiguredTheme); // never throws
118
+ ```
119
+
120
+ Two constants ship: the brand-neutral default and `GUUEY_CHAT_THEME` (the
121
+ guuey identity — portal's default look).
122
+
123
+ ## The fixture corpus
124
+
125
+ `src/corpus/` holds the recorded-transcript corpus that DEFINES "comfortably
126
+ readable" — forty-tool turns, mid-stream failures, cold starts, dead view
127
+ locators, unknown-block storms. The standing rule: a new weird transcript
128
+ found in production becomes a fixture before its fix lands. The corpus only
129
+ grows.
130
+
131
+ ## Part of the guuey SDK cohort
132
+
133
+ Consumes [`@guuey/agent-client`](https://www.npmjs.com/package/@guuey/agent-client)
134
+ (the invoke stream + fold) and
135
+ [`@guuey/mcp-apps-host`](https://www.npmjs.com/package/@guuey/mcp-apps-host)
136
+ (the MCP-Apps host role that mounts generative views). Issues:
137
+ [withguuey/guuey-sdks](https://github.com/withguuey/guuey-sdks/issues).
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The HISTORY input assembler (spec §7 "Input assembly") — persisted thread
3
+ * read → `TranscriptInputs`, no hook, no DOM, no React: the seam that makes
4
+ * server-side transcript rendering real. Give it what the read plane
5
+ * returned (an agent-client `HistoryLoadResult`, or `null` while the read is
6
+ * in flight) and plan the result with `planTranscript` anywhere Node runs.
7
+ *
8
+ * The LIVE twin (`useTranscriptInputs`, `@guuey/chat/react`) assembles the
9
+ * same shape from `useAgentInvoke`'s state; the two produce byte-identical
10
+ * inputs for the same settled conversation — that identity is what lets a
11
+ * server-rendered transcript hydrate under the live one without a repaint.
12
+ */
13
+ import type { HistoryLoadResult } from "@guuey/agent-client";
14
+ import type { TranscriptInputs } from "./types.js";
15
+ /**
16
+ * Assemble transcript inputs from a history read.
17
+ *
18
+ * - `null` (read still in flight) → the R13 `loading` skeleton state;
19
+ * - `{ gone: true }` → the R13 `thread-gone` labeled empty state;
20
+ * - a transcript → the settled conversation, with any persisted cards
21
+ * riding the R13 → R6 remount path.
22
+ */
23
+ export declare function transcriptInputsFromHistory(load: HistoryLoadResult | null): TranscriptInputs;
24
+ //# sourceMappingURL=history-inputs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history-inputs.d.ts","sourceRoot":"","sources":["../src/history-inputs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAgBnD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,GAAG,gBAAgB,CAU5F"}
@@ -0,0 +1,34 @@
1
+ /** The settled-idle baseline every assembled input starts from. */
2
+ function idleInputs() {
3
+ return {
4
+ result: null,
5
+ assistantText: "",
6
+ status: "ready",
7
+ statusElapsedMs: 0,
8
+ activeTool: null,
9
+ error: null,
10
+ prompts: [],
11
+ messages: [],
12
+ };
13
+ }
14
+ /**
15
+ * Assemble transcript inputs from a history read.
16
+ *
17
+ * - `null` (read still in flight) → the R13 `loading` skeleton state;
18
+ * - `{ gone: true }` → the R13 `thread-gone` labeled empty state;
19
+ * - a transcript → the settled conversation, with any persisted cards
20
+ * riding the R13 → R6 remount path.
21
+ */
22
+ export function transcriptInputsFromHistory(load) {
23
+ const base = idleInputs();
24
+ if (load === null)
25
+ return { ...base, historyState: "loading" };
26
+ if ("gone" in load)
27
+ return { ...base, historyState: "gone" };
28
+ return {
29
+ ...base,
30
+ historyState: "loaded",
31
+ messages: load.messages,
32
+ ...(load.cards && load.cards.length > 0 ? { historyCards: load.cards } : {}),
33
+ };
34
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `@guuey/chat` — the default end-user transcript UI for guuey agents.
3
+ *
4
+ * Wave 3a (guuey#135): the HEADLESS half — `planTranscript` (the pure
5
+ * view-model over the AgJSON fold + the invoke status surface), the
6
+ * `calm`/`debug` policy presets, the `GuueyChatTheme` platform-data token
7
+ * schema, and the `ChatStrings` i18n seam. Zero DOM, zero React.
8
+ *
9
+ * Wave 3b adds `./react` (the component kit + `<GuueyChat>` arrives in 3c);
10
+ * this root subpath stays React-free forever — server-side transcript
11
+ * rendering, tests, and RN bundlers consume the view-model directly.
12
+ */
13
+ export { planTranscript, } from "./plan.js";
14
+ export { calmPolicy, debugPolicy, type TranscriptPolicy, } from "./policy.js";
15
+ export { defaultChatStrings, humanizeToolName, type ChatStrings, } from "./strings.js";
16
+ export { transcriptInputsFromHistory } from "./history-inputs.js";
17
+ export { DEFAULT_CHAT_THEME, GUUEY_CHAT_THEME, GuueyChatPalette, GuueyChatTheme, resolveTheme, } from "./theme.js";
18
+ export type { CitationsItem, CodeItem, CompactionItem, DataResultItem, DisplayItem, ErrorItem, HistoryBoundaryItem, ItemKey, MediaItem, PromptItem, PromptItemInput, ReasoningItem, StatusLineItem, TextItem, ToolGroupItem, ToolItem, TranscriptInputs, TranscriptMessage, TranscriptOverrides, TranscriptPlan, UnknownItem, UserMessageItem, ViewMountItem, } from "./types.js";
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,UAAU,EACV,WAAW,EACX,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,KAAK,WAAW,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,aAAa,EACb,QAAQ,EACR,cAAc,EACd,cAAc,EACd,WAAW,EACX,SAAS,EACT,mBAAmB,EACnB,OAAO,EACP,SAAS,EACT,UAAU,EACV,eAAe,EACf,aAAa,EACb,cAAc,EACd,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `@guuey/chat` — the default end-user transcript UI for guuey agents.
3
+ *
4
+ * Wave 3a (guuey#135): the HEADLESS half — `planTranscript` (the pure
5
+ * view-model over the AgJSON fold + the invoke status surface), the
6
+ * `calm`/`debug` policy presets, the `GuueyChatTheme` platform-data token
7
+ * schema, and the `ChatStrings` i18n seam. Zero DOM, zero React.
8
+ *
9
+ * Wave 3b adds `./react` (the component kit + `<GuueyChat>` arrives in 3c);
10
+ * this root subpath stays React-free forever — server-side transcript
11
+ * rendering, tests, and RN bundlers consume the view-model directly.
12
+ */
13
+ export { planTranscript, } from "./plan.js";
14
+ export { calmPolicy, debugPolicy, } from "./policy.js";
15
+ export { defaultChatStrings, humanizeToolName, } from "./strings.js";
16
+ export { transcriptInputsFromHistory } from "./history-inputs.js";
17
+ export { DEFAULT_CHAT_THEME, GUUEY_CHAT_THEME, GuueyChatPalette, GuueyChatTheme, resolveTheme, } from "./theme.js";
package/dist/plan.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import type { TranscriptPolicy } from "./policy.js";
2
+ import type { TranscriptInputs, TranscriptOverrides, TranscriptPlan } from "./types.js";
3
+ /** The one pure function (spec §7). */
4
+ export declare function planTranscript(inputs: TranscriptInputs, policy: TranscriptPolicy, overrides?: TranscriptOverrides): TranscriptPlan;
5
+ //# sourceMappingURL=plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAQV,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EAGf,MAAM,YAAY,CAAC;AAoiBpB,uCAAuC;AACvC,wBAAgB,cAAc,CAC5B,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,gBAAgB,EACxB,SAAS,GAAE,mBAAwB,GAClC,cAAc,CA4IhB"}