@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.
- package/LICENSE +21 -0
- package/README.md +137 -0
- package/dist/history-inputs.d.ts +24 -0
- package/dist/history-inputs.d.ts.map +1 -0
- package/dist/history-inputs.js +34 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/plan.d.ts +5 -0
- package/dist/plan.d.ts.map +1 -0
- package/dist/plan.js +629 -0
- package/dist/policy.d.ts +110 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +75 -0
- package/dist/react/components.d.ts +87 -0
- package/dist/react/components.d.ts.map +1 -0
- package/dist/react/components.js +270 -0
- package/dist/react/guuey-chat.d.ts +84 -0
- package/dist/react/guuey-chat.d.ts.map +1 -0
- package/dist/react/guuey-chat.js +103 -0
- package/dist/react/markdown.d.ts +32 -0
- package/dist/react/markdown.d.ts.map +1 -0
- package/dist/react/markdown.js +40 -0
- package/dist/react/theme-css.d.ts +16 -0
- package/dist/react/theme-css.d.ts.map +1 -0
- package/dist/react/theme-css.js +37 -0
- package/dist/react/transcript.d.ts +42 -0
- package/dist/react/transcript.d.ts.map +1 -0
- package/dist/react/transcript.js +88 -0
- package/dist/react/use-transcript.d.ts +39 -0
- package/dist/react/use-transcript.d.ts.map +1 -0
- package/dist/react/use-transcript.js +201 -0
- package/dist/react.d.ts +21 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +20 -0
- package/dist/strings.d.ts +74 -0
- package/dist/strings.d.ts.map +1 -0
- package/dist/strings.js +45 -0
- package/dist/theme.d.ts +99 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +182 -0
- package/dist/types.d.ts +283 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +87 -0
- package/src/corpus/README.md +40 -0
- package/src/corpus/__snapshots__/corpus.test.ts.snap +1590 -0
- package/src/corpus/capture.ts +67 -0
- package/src/corpus/captures/issue2627-render-capture.coalesced.sse.txt +173 -0
- package/src/corpus/drive.ts +184 -0
- package/src/corpus/fixtures.ts +338 -0
- package/src/history-inputs.ts +48 -0
- package/src/index.ts +58 -0
- package/src/plan.ts +740 -0
- package/src/policy.ts +146 -0
- package/src/react/components.tsx +655 -0
- package/src/react/guuey-chat.tsx +227 -0
- package/src/react/markdown.tsx +114 -0
- package/src/react/theme-css.ts +50 -0
- package/src/react/transcript.tsx +187 -0
- package/src/react/use-transcript.ts +274 -0
- package/src/react.tsx +51 -0
- package/src/strings.ts +144 -0
- package/src/theme.ts +195 -0
- package/src/types.ts +320 -0
- 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
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|