agentic-ui-kit 0.0.0-stage → 0.2.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 (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +241 -2
  3. package/dist/core.js +1 -0
  4. package/dist/index.js +2875 -0
  5. package/dist/sse-BA_ebMcH.js +408 -0
  6. package/dist/styles.css +3 -0
  7. package/dist/tailwind.css +350 -0
  8. package/dist/types/core/src/blocks.d.ts +22 -0
  9. package/dist/types/core/src/events.d.ts +75 -0
  10. package/dist/types/core/src/index.d.ts +7 -0
  11. package/dist/types/core/src/partial-json.d.ts +7 -0
  12. package/dist/types/core/src/reduce.d.ts +33 -0
  13. package/dist/types/core/src/sse.d.ts +8 -0
  14. package/dist/types/core/src/types.d.ts +171 -0
  15. package/dist/types/react/src/components/activity-group.d.ts +13 -0
  16. package/dist/types/react/src/components/approval-card.d.ts +11 -0
  17. package/dist/types/react/src/components/attachments.d.ts +78 -0
  18. package/dist/types/react/src/components/chat-header.d.ts +30 -0
  19. package/dist/types/react/src/components/chat-list.d.ts +47 -0
  20. package/dist/types/react/src/components/composer.d.ts +45 -0
  21. package/dist/types/react/src/components/context-panel.d.ts +13 -0
  22. package/dist/types/react/src/components/markdown.d.ts +8 -0
  23. package/dist/types/react/src/components/message-list.d.ts +18 -0
  24. package/dist/types/react/src/components/messages.d.ts +33 -0
  25. package/dist/types/react/src/components/model-picker.d.ts +16 -0
  26. package/dist/types/react/src/components/token-counter.d.ts +16 -0
  27. package/dist/types/react/src/components/tools.d.ts +68 -0
  28. package/dist/types/react/src/components/word-fade.d.ts +19 -0
  29. package/dist/types/react/src/core.d.ts +1 -0
  30. package/dist/types/react/src/hooks/agent.d.ts +86 -0
  31. package/dist/types/react/src/hooks/sidebar-state.d.ts +18 -0
  32. package/dist/types/react/src/hooks/smooth-text.d.ts +9 -0
  33. package/dist/types/react/src/hooks/sse-transport.d.ts +15 -0
  34. package/dist/types/react/src/hooks/use-chat.d.ts +68 -0
  35. package/dist/types/react/src/index.d.ts +57 -0
  36. package/dist/types/react/src/primitives/appearance.d.ts +38 -0
  37. package/dist/types/react/src/primitives/badge.d.ts +15 -0
  38. package/dist/types/react/src/primitives/button.d.ts +32 -0
  39. package/dist/types/react/src/primitives/caret.d.ts +4 -0
  40. package/dist/types/react/src/primitives/chat-theme.d.ts +22 -0
  41. package/dist/types/react/src/primitives/code-block.d.ts +13 -0
  42. package/dist/types/react/src/primitives/context-menu.d.ts +13 -0
  43. package/dist/types/react/src/primitives/disclosure.d.ts +16 -0
  44. package/dist/types/react/src/primitives/highlight.d.ts +13 -0
  45. package/dist/types/react/src/primitives/menu.d.ts +52 -0
  46. package/dist/types/react/src/primitives/overlay.d.ts +21 -0
  47. package/dist/types/react/src/primitives/panel.d.ts +19 -0
  48. package/dist/types/react/src/primitives/tooltip.d.ts +10 -0
  49. package/dist/types/react/src/views/app-shell.d.ts +20 -0
  50. package/dist/types/react/src/views/chat-view.d.ts +51 -0
  51. package/dist/types/react/src/views/sidebar.d.ts +38 -0
  52. package/package.json +80 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 bushshrub
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 CHANGED
@@ -1,3 +1,242 @@
1
- # Temporary Holding Version
1
+ # agentic-ui-kit
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ React components for LLM chat and agentic apps: streaming replies with Markdown, math and code; thinking and
4
+ tool-call rows; approvals; tools that change the page around the chat. Themed entirely with CSS variables, so it
5
+ can take on your app's look.
6
+
7
+ > [!WARNING]
8
+ > **This is AI-written slop. You probably shouldn't use it.**
9
+ > It isn't reviewed or hardened, the API will change without notice, and it may stop being maintained at
10
+ > any time. If you still want to try it, pin an exact version, or fork it and treat the code as your own.
11
+
12
+ ![A full chat app built from the kit](docs/images/app.png)
13
+
14
+ ## Install
15
+
16
+ ```sh
17
+ npm install agentic-ui-kit
18
+ ```
19
+
20
+ Requires React 19. React is an optional peer dependency, so a server can use `agentic-ui-kit/core` on its own.
21
+
22
+ | Import | What it is |
23
+ | ---------------------------- | ------------------------------------------------------------------------------ |
24
+ | `agentic-ui-kit` | React components and hooks |
25
+ | `agentic-ui-kit/core` | Types, stream events, the message reducer, SSE helpers. No React, no DOM. |
26
+ | `agentic-ui-kit/styles.css` | Precompiled styles, for apps without Tailwind |
27
+ | `agentic-ui-kit/tailwind.css`| The same styles as Tailwind v4 source, for apps that use Tailwind |
28
+
29
+ ### Install from source
30
+
31
+ ```sh
32
+ git clone https://github.com/bushshrub/agentic-ui-kit
33
+ cd agentic-ui-kit && pnpm install
34
+ pnpm --filter agentic-ui-kit pack # builds and writes agentic-ui-kit-0.1.0.tgz here
35
+ cd ../your-app && npm install ../agentic-ui-kit/agentic-ui-kit-0.1.0.tgz
36
+ ```
37
+
38
+ ## Quick start
39
+
40
+ ```tsx
41
+ import { ChatView, sseTransport, useChat } from "agentic-ui-kit";
42
+ import "agentic-ui-kit/styles.css";
43
+
44
+ const transport = sseTransport({ url: "/api/chat" });
45
+
46
+ export function App() {
47
+ const chat = useChat({ transport });
48
+ return (
49
+ <div style={{ height: "100dvh" }}>
50
+ <ChatView
51
+ messages={chat.messages}
52
+ busy={chat.busy}
53
+ onSend={(text) => chat.send(text)}
54
+ onStop={chat.stop}
55
+ approvals={chat.approvals}
56
+ onApprove={chat.respond}
57
+ />
58
+ </div>
59
+ );
60
+ }
61
+ ```
62
+
63
+ `ChatView` sizes itself from its container, so it works as a full page, a side panel or a small box in a form
64
+ (`density="full" | "panel" | "inline"`), and several fit side by side.
65
+
66
+ ### Using Tailwind v4?
67
+
68
+ Import the Tailwind source instead of `styles.css`, so utilities are generated once by your build:
69
+
70
+ ```css
71
+ @import "tailwindcss";
72
+ @import "agentic-ui-kit/tailwind.css";
73
+ ```
74
+
75
+ `styles.css` includes Tailwind's base reset (preflight). In an app that already has its own reset, use
76
+ `tailwind.css`.
77
+
78
+ ## The backend
79
+
80
+ The kit talks to your backend through a `Transport`. `sseTransport` POSTs the request as JSON and reads a
81
+ `text/event-stream` of events back. Your server translates whatever model API it uses into these events:
82
+
83
+ ```ts
84
+ import { formatEvent, type StreamEvent } from "agentic-ui-kit/core";
85
+ import type { SseRequestBody } from "agentic-ui-kit";
86
+
87
+ export async function POST(request: Request) {
88
+ const body = (await request.json()) as SseRequestBody; // { message, history, model, tools, context, ... }
89
+ const runId = crypto.randomUUID();
90
+ let seq = 0;
91
+
92
+ const stream = new ReadableStream({
93
+ async start(controller) {
94
+ const send = (event: object) =>
95
+ controller.enqueue(new TextEncoder().encode(formatEvent({ ...event, runId, seq: seq++ } as StreamEvent)));
96
+
97
+ send({ type: "run.start", messageId: crypto.randomUUID(), parentId: body.message.id, createdAt: new Date().toISOString() });
98
+ send({ type: "part.start", part: { type: "text", id: "p1", text: "", status: "streaming" } });
99
+ for await (const chunk of callYourModel(body.history)) send({ type: "part.delta", partId: "p1", text: chunk });
100
+ send({ type: "part.end", partId: "p1" });
101
+ send({ type: "run.end", status: "done" });
102
+ controller.close();
103
+ },
104
+ });
105
+ return new Response(stream, { headers: { "content-type": "text/event-stream" } });
106
+ }
107
+ ```
108
+
109
+ | Event | Meaning |
110
+ | ------------ | ----------------------------------------------------------------------------------------------- |
111
+ | `run.start` | A reply starts. Reusing an existing `messageId` continues that message (after tools ran). |
112
+ | `part.start` | A new part: `text`, `thinking`, `tool_call`, attachments, or your own custom type. |
113
+ | `part.delta` | Appends `text`, or `inputJson` for a tool call's arguments as the model writes them. |
114
+ | `part.update`| Sets fields: `status`, `title`, `subtitle`, `result`, `error`, … |
115
+ | `part.end` | Closes a part. A tool call's input is parsed here; invalid JSON fails the call. |
116
+ | `run.usage` | Token counts so far. |
117
+ | `run.end` | `done`, `stopped` or `error`. |
118
+ | `title` | A title for the conversation. |
119
+
120
+ Every event carries `runId` and an increasing `seq`, so a client can resume a dropped stream. Not using SSE?
121
+ Implement `Transport` yourself: one `send(request)` that returns an async iterable of events.
122
+
123
+ ## Agent tools
124
+
125
+ ![The model proposes calendar events; the page draws them and asks before adding them](docs/images/calendar.png)
126
+
127
+ Pages register the tools they own while they are mounted, so the model's tools follow what's on screen. One
128
+ definition covers both kinds:
129
+
130
+ - **Client tools** have `execute`. They run in the browser and can change the page directly; the result is
131
+ sent back and the model continues.
132
+ - **Server tools** run on your backend. The page still sees every call, through `onCall` (each change, e.g.
133
+ arguments streaming in) and `onResult` (once, done or failed), and can draw previews or refresh data.
134
+
135
+ ```tsx
136
+ import { AgentProvider, useAgentContext, useChatTool } from "agentic-ui-kit";
137
+
138
+ function ApplicationForm() {
139
+ const [values, setValues] = useState(empty);
140
+ useAgentContext("application", values); // sent with each request
141
+
142
+ // Client tool: the model fills in the form on screen.
143
+ useChatTool({
144
+ name: "fill_fields",
145
+ description: "Fill in fields of the application form.",
146
+ inputSchema: { type: "object", properties: { fields: { type: "object" } }, required: ["fields"] },
147
+ execute: ({ fields }) => {
148
+ setValues((v) => ({ ...v, ...fields }));
149
+ return { filled: Object.keys(fields) };
150
+ },
151
+ view: { label: (call) => (call.status === "done" ? "Filled in the form" : "Filling in the form") },
152
+ });
153
+
154
+ // Server tool that needs the user's OK: the backend sets `needsApproval` on the call.
155
+ useChatTool({
156
+ name: "submit_application",
157
+ view: { ask: () => "Submit your application?" },
158
+ onResult: (call) => call.status === "done" && setSubmitted(true),
159
+ });
160
+ // ...
161
+ }
162
+
163
+ // Wrap the page and the chat so they share tools and context.
164
+ <AgentProvider>
165
+ <ApplicationForm />
166
+ <Assistant /> {/* uses useChat() and ChatView as in the quick start */}
167
+ </AgentProvider>;
168
+ ```
169
+
170
+ While a tool call's arguments stream in, `call.partialInput` holds what has been written so far, parsed from
171
+ incomplete JSON. Use it to show a preview as the model writes: draw calendar events field by field, or type an
172
+ edit into an open file. If the stream breaks or the arguments aren't valid JSON, the call ends with
173
+ `status: "error"` and the preview should go away.
174
+
175
+ A tool's `view` sets how it looks in the chat: `label`, `subtitle`, `summary`, a `Detail` component for the
176
+ expanded row and the approval card, and `ask` for the approval question. `Block` renders a call on its own
177
+ instead of inside the activity group.
178
+
179
+ ## Theming
180
+
181
+ Every colour, font, radius and width is a `--chat-*` CSS variable. Set them on `:root` to theme the whole app,
182
+ or on any element to theme part of it:
183
+
184
+ ```css
185
+ :root {
186
+ --chat-bg: #fbfaf7;
187
+ --chat-fg: #1f1d1a;
188
+ --chat-accent: #c4552d;
189
+ --chat-font-sans: "IBM Plex Sans", sans-serif;
190
+ --chat-radius-md: 10px;
191
+ color-scheme: light;
192
+ }
193
+ ```
194
+
195
+ To theme only part of a page, wrap it in `<ChatTheme theme="mine">` and match `[data-chat-theme="mine"]` in
196
+ your CSS. Menus and dialogs opened inside then render into that element, so they get the same theme.
197
+
198
+ `ChatTheme` also takes two appearance props. `codeThemes` picks the Shiki themes for code blocks and Markdown
199
+ fences (any bundled theme id; an unknown id falls back to the default with one console warning):
200
+ `<ChatTheme codeThemes={{ light: "catppuccin-latte", dark: "dracula" }}>`. Blocks keep `--chat-code-bg` unless you
201
+ add `background: "theme"`, which uses the Shiki theme's own background and text color. `motion` is `"system"`
202
+ (default: follow the OS reduced-motion setting), `"reduce"` (always use the reduced rules) or `"full"` (keep
203
+ animations even when the OS asks for less). It sets `data-chat-motion` on the element; an app that does not use
204
+ `ChatTheme` can put `data-chat-motion="reduce"` on `<html>` instead.
205
+
206
+ The full list of variables is at the top of
207
+ [`packages/react/src/styles.css`](packages/react/src/styles.css).
208
+
209
+ ## What's in the kit
210
+
211
+ The React package has four layers, each built only from the ones before it:
212
+
213
+ | Layer | Examples |
214
+ | ---------- | --------------------------------------------------------------------------------------------- |
215
+ | Primitives | `Button`, `IconButton`, `Menu`, `ContextMenu`, `Modal`, `Drawer`, `Panel`, `Tooltip`, `CodeBlock`, `ChatTheme` |
216
+ | Hooks | `useChat`, `sseTransport`, `AgentProvider`, `useAgentTool`, `useAgentContext`, `useSmoothText` |
217
+ | Components | `Composer`, `ModelPicker`, `MessageList`, `ActivityGroup`, `ApprovalCard`, `Markdown`, `ChatHeader`, `ChatList`, `ContextPanel` |
218
+ | Views | `ChatView`, `AppShell`, `Sidebar` |
219
+
220
+ Use `ChatView` for the whole thing, or build your own layout from the components.
221
+
222
+ Bundle size: Markdown, KaTeX and Shiki are most of it, about 345 KB gzipped for a chat page. Shiki's language
223
+ grammars load on demand.
224
+
225
+ ## Development
226
+
227
+ ```sh
228
+ pnpm install
229
+ pnpm storybook # playground on http://localhost:6006: components, host themes, agent tool examples
230
+ pnpm -r typecheck
231
+ pnpm test # vitest in packages/core and packages/react
232
+ ```
233
+
234
+ | Path | Contents |
235
+ | ----------------- | -------------------------------------------------------------- |
236
+ | `packages/core` | Types, events, reducer, SSE. Bundled into `agentic-ui-kit/core`. |
237
+ | `packages/react` | The published `agentic-ui-kit` package |
238
+ | `apps/playground` | Storybook |
239
+
240
+ ## License
241
+
242
+ MIT
package/dist/core.js ADDED
@@ -0,0 +1 @@
1
+ export { a as activityTokens, o as applyEvent, s as awaitingToolCalls, c as estimateTokens, t as formatEvent, r as isActivityPart, l as outputTokens, p as parsePartialJson, n as readEventStream, u as reduceEvents, d as resolveEffort, f as settleToolCall, i as toBlocks } from "./sse-BA_ebMcH.js";