@pgege/kaboo-react 0.1.0 → 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.
package/AGENTS.md CHANGED
@@ -25,11 +25,11 @@ yarn examples:typecheck # type-check examples/ against built types
25
25
  - **Two barrels.**
26
26
  - `kaboo-react` (`src/index.ts`) — framework-agnostic contexts, hooks,
27
27
  components, utils, formatters, types.
28
- - `@pgege/kaboo-react/copilotkit` (`src/copilotkit.ts`) — integrations coupled to
28
+ - `kaboo-react/copilotkit` (`src/copilotkit.ts`) — integrations coupled to
29
29
  CopilotKit. **Put any CopilotKit-dependent code here, never in the main
30
30
  barrel.**
31
31
  - **Stylesheet.** `src/styles.css` is copied to `dist/styles.css` by tsup and
32
- exported as `@pgege/kaboo-react/styles.css`. Theming is via CSS variables only
32
+ exported as `kaboo-react/styles.css`. Theming is via CSS variables only
33
33
  (`--background`/`--foreground`/`--card`/`--muted`/`--border` + `--kaboo-*`
34
34
  overrides). Do not add a CSS-in-JS dependency.
35
35
  - **Peer deps.** `react`, `react-dom`, `@copilotkit/react-core`. Do not add
@@ -96,6 +96,6 @@ yarn examples:typecheck # type-check examples/ against built types
96
96
 
97
97
  - [kaboo-workflows](https://github.com/gl-pgege/kaboo-workflows)
98
98
  - [kaboo-runtime](https://github.com/gl-pgege/kaboo-runtime)
99
- - [kaboo-workflows-demo](https://github.com/gl-pgege/kaboo-docs/tree/main/examples/kaboo-workflows-demo) — the
99
+ - [kaboo-workflows-demo](https://github.com/gl-pgege/kaboo-workflows-demo) — the
100
100
  runnable, end-to-end reference that consumes this library.
101
101
  - [The kaboo stack](https://gl-pgege.github.io/kaboo-docs/) — umbrella landing.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.0]
11
+
12
+ ### Added
13
+
14
+ - **References & attachments.** A pluggable `@`/`+` reference system for the chat
15
+ composer:
16
+ - `KabooReferenceInput` — a drop-in `<CopilotChat input={…}>` slot that keeps
17
+ CopilotKit's native input chrome but renders each reference as an interactive
18
+ inline chip, with a shared searchable popover for both `+` and `@`.
19
+ - `ReferencesProvider` / `ReferenceStateSync` / `useReferences` — register
20
+ providers, stage pending references, and sync object references onto
21
+ `agent.state`.
22
+ - `uploadProvider` (+ `isUploadProvider`, `buildAttachmentsConfig`,
23
+ `uploadFileToReference`, `UPLOAD_MARKER`) — the built-in file-attachment
24
+ provider, with URL or base64 upload.
25
+ - Serialization helpers (`mintReferenceId`, `referenceMarker`,
26
+ `attachmentToInputContent`, `objectToStateEntry`, `serializeReferences`,
27
+ `withReferenceState`, `buildUserContent`).
28
+ - Public types/constants: `ReferenceProvider`, `ReferenceItem`,
29
+ `PendingReference`, `ReferenceTransport`, `REFERENCE_METADATA_KEYS`,
30
+ `REFERENCES_STATE_KEY`.
31
+ - `kaboo-react/copilotkit`: `KabooUserMessage` — renders sent references as
32
+ non-interactive chips (inline `@` mentions and a file/object chip row) in the
33
+ user bubble.
34
+ - "References & providers" guide (`docs/references.md`) documenting the provider
35
+ contract, both transports, and searchable vs action-only providers.
36
+
37
+ ### Changed
38
+
39
+ - `KabooMessageView` now wires `KabooUserMessage` so references sent with a
40
+ message render as chips instead of raw text.
41
+
10
42
  ## [0.1.0]
11
43
 
12
44
  Initial release.
@@ -20,10 +52,11 @@ Initial release.
20
52
  `MiniTable`, `GlassTabs`, `DrillDetailView`, `MarkdownContent`,
21
53
  `InterruptRenderer`), group helpers (`topLevelGroups`, `directChildren`) and
22
54
  formatters (`formatToolInput`, `formatToolResult`, `normalizeResult`).
23
- - `@pgege/kaboo-react/copilotkit` subpath: CopilotKit-coupled integrations
55
+ - `kaboo-react/copilotkit` subpath: CopilotKit-coupled integrations
24
56
  (`KabooMessageView`, `KabooAssistantMessage`, `KabooInlineCards`,
25
57
  `KabooInterruptHandler`, `KabooAskUser`, `KabooToolRender`).
26
- - `@pgege/kaboo-react/styles.css` stylesheet with themeable `--kaboo-*` design tokens.
58
+ - `kaboo-react/styles.css` stylesheet with themeable `--kaboo-*` design tokens.
27
59
 
28
- [Unreleased]: https://github.com/gl-pgege/kaboo-react/compare/v0.1.0...HEAD
60
+ [Unreleased]: https://github.com/gl-pgege/kaboo-react/compare/v0.2.0...HEAD
61
+ [0.2.0]: https://github.com/gl-pgege/kaboo-react/compare/v0.1.0...v0.2.0
29
62
  [0.1.0]: https://github.com/gl-pgege/kaboo-react/releases/tag/v0.1.0
package/README.md CHANGED
@@ -23,6 +23,8 @@ endpoint to wire up: kaboo-react is a batteries-included CopilotKit plugin.
23
23
  - **Human-in-the-loop** — approval gates and forms, with N parallel interrupts
24
24
  resolved independently.
25
25
  - **Structured renderers** — plug custom UI for schema-shaped agent output.
26
+ - **References & attachments** — files and your own objects (tables, dashboards,
27
+ …) as interactive inline chips, added from one shared **+** / **@** popover.
26
28
  - **Batteries included** — one `KabooProvider` renders `<CopilotKit>` and mounts
27
29
  every context and handler for you.
28
30
  - **Themeable** — styled with CSS variables and `--kaboo-*` tokens.
@@ -86,9 +88,65 @@ props via `copilotKitProps`.
86
88
  - **Theming via CSS variables.** Components read standard design-system tokens and
87
89
  accept `--kaboo-*` overrides.
88
90
 
91
+ ## References & attachments
92
+
93
+ Let users attach things to a message. Everything is driven by **reference
94
+ providers** registered on `<KabooProvider references={…}>` and rendered by the
95
+ `KabooReferenceInput` slot. There are two transports:
96
+
97
+ - **Attachment** — a file/blob. Register the built-in `uploadProvider({ onUpload })`;
98
+ choosing "Attach a file" (from **+** or **@**) opens the picker, uploads, and
99
+ drops a file chip inline. Files ride the message as parts stamped with
100
+ `kaboo_id` / `kaboo_kind` / `kaboo_name`.
101
+ - **Object** — a pointer to one of *your* entities (`table`, `dashboard`, …).
102
+ Register a `ReferenceProvider`; selected objects sync into
103
+ `state.kaboo_references` for the backend to resolve, and appear inline as
104
+ `@name`.
105
+
106
+ ```tsx no-verify
107
+ import {
108
+ KabooProvider,
109
+ KabooReferenceInput,
110
+ uploadProvider,
111
+ type ReferenceProvider,
112
+ } from "@pgege/kaboo-react";
113
+
114
+ // A custom object reference: three fields make it work.
115
+ const tableProvider: ReferenceProvider = {
116
+ id: "table",
117
+ label: "Tables",
118
+ icon: <Table2 size={16} />,
119
+ search: (q) => TABLES.filter((t) => t.label.includes(q)), // items under @
120
+ toReference: (item) => ({ transport: "object", kind: "table", id: item.id, name: item.label }),
121
+ };
122
+
123
+ <KabooProvider
124
+ runtimeUrl="/api/copilotkit"
125
+ agent={agent}
126
+ references={[uploadProvider({ accept: "image/*,.pdf", onUpload }), tableProvider]}
127
+ >
128
+ <CopilotChat input={KabooReferenceInput} messageView={KabooMessageView} />
129
+ </KabooProvider>;
130
+ ```
131
+
132
+ `KabooReferenceInput` is a drop-in `<CopilotChat input={…}>` slot. It keeps
133
+ CopilotKit's native input chrome (send button, disclaimer, theme) but swaps the
134
+ plain textarea for a lightweight editor where every reference renders as an
135
+ **interactive inline chip**: click a chip to swap it for another, or its `×` to
136
+ remove it. The **+** button and the **@** key open the *same* searchable
137
+ popover; it dismisses on outside-click / `Escape`. On submit the editor builds
138
+ the multimodal message (files as attachment parts, objects on
139
+ `state.kaboo_references`, cleared only after the run starts) and runs the agent.
140
+ `onUpload` should return a fetchable URL (not base64) so the transport and
141
+ persisted event log stay small. See [References & providers](./docs/references.md)
142
+ for the full provider contract (both transports, searchable vs action-only,
143
+ `toReference`), and kaboo-workflows' *Attachments & Multimodal* chapter for how
144
+ references reach each agent.
145
+
89
146
  ## Guides
90
147
 
91
148
  - [Getting started](./docs/getting-started.md)
149
+ - [References & providers](./docs/references.md)
92
150
  - [Theming](./docs/theming.md)
93
151
  - [Structured renderers](./docs/structured-renderers.md)
94
152
  - [Human-in-the-loop](./docs/hitl.md)
@@ -1144,6 +1144,167 @@ function InlineCardRenderer({
1144
1144
  );
1145
1145
  }
1146
1146
 
1147
+ // src/references/types.ts
1148
+ var REFERENCE_METADATA_KEYS = {
1149
+ /** Metadata key carrying the reference id. */
1150
+ id: "kaboo_id",
1151
+ /** Metadata key carrying the reference kind. */
1152
+ kind: "kaboo_kind",
1153
+ /** Metadata key carrying the reference display name. */
1154
+ name: "kaboo_name"
1155
+ };
1156
+ var REFERENCES_STATE_KEY = "kaboo_references";
1157
+
1158
+ // src/references/serialize.ts
1159
+ function mintReferenceId(kind) {
1160
+ const rand = typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : Math.random().toString(36).slice(2);
1161
+ return `${kind}_${rand}`;
1162
+ }
1163
+ function referenceMarker(ref) {
1164
+ return `[${ref.kind}:${ref.id}]`;
1165
+ }
1166
+ function modalityFor(mimeType) {
1167
+ if (mimeType.startsWith("image/")) return "image";
1168
+ if (mimeType.startsWith("audio/")) return "audio";
1169
+ if (mimeType.startsWith("video/")) return "video";
1170
+ return "document";
1171
+ }
1172
+ function attachmentToInputContent(ref) {
1173
+ const source = "url" in ref.source ? { type: "url", value: ref.source.url, mimeType: ref.mimeType } : { type: "data", value: ref.source.data, mimeType: ref.mimeType };
1174
+ return {
1175
+ type: modalityFor(ref.mimeType),
1176
+ source,
1177
+ metadata: {
1178
+ [REFERENCE_METADATA_KEYS.id]: ref.id,
1179
+ [REFERENCE_METADATA_KEYS.kind]: ref.kind,
1180
+ [REFERENCE_METADATA_KEYS.name]: ref.name,
1181
+ filename: ref.name
1182
+ }
1183
+ };
1184
+ }
1185
+ function objectToStateEntry(ref) {
1186
+ return { kind: ref.kind, id: ref.id, name: ref.name, meta: ref.meta };
1187
+ }
1188
+ function serializeReferences(refs) {
1189
+ const attachmentParts = [];
1190
+ const objectReferences = [];
1191
+ for (const ref of refs) {
1192
+ if (ref.transport === "attachment") {
1193
+ attachmentParts.push(attachmentToInputContent(ref));
1194
+ } else {
1195
+ objectReferences.push(objectToStateEntry(ref));
1196
+ }
1197
+ }
1198
+ return { attachmentParts, objectReferences };
1199
+ }
1200
+ function withReferenceState(state, objectReferences) {
1201
+ const next = { ...state ?? {} };
1202
+ if (objectReferences.length > 0) {
1203
+ next[REFERENCES_STATE_KEY] = objectReferences;
1204
+ } else {
1205
+ delete next[REFERENCES_STATE_KEY];
1206
+ }
1207
+ return next;
1208
+ }
1209
+ function buildUserContent(text, attachmentParts) {
1210
+ const parts = [];
1211
+ if (text.length > 0) parts.push({ type: "text", text });
1212
+ parts.push(...attachmentParts);
1213
+ return parts;
1214
+ }
1215
+
1216
+ // src/references/ReferencesProvider.tsx
1217
+ import {
1218
+ createContext as createContext4,
1219
+ useCallback as useCallback3,
1220
+ useContext as useContext5,
1221
+ useEffect as useEffect4,
1222
+ useMemo,
1223
+ useState as useState7
1224
+ } from "react";
1225
+ import { useAgent as useAgent2 } from "@copilotkit/react-core/v2";
1226
+ import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
1227
+ var ReferencesContext = createContext4({
1228
+ providers: [],
1229
+ pending: [],
1230
+ addReference: () => {
1231
+ },
1232
+ removeReference: () => {
1233
+ },
1234
+ clearReferences: () => {
1235
+ },
1236
+ messageReferences: {},
1237
+ recordMessageReferences: () => {
1238
+ }
1239
+ });
1240
+ function ReferencesProvider({
1241
+ providers = [],
1242
+ syncObjectStateTo = false,
1243
+ children
1244
+ }) {
1245
+ const [pending, setPending] = useState7([]);
1246
+ const [messageReferences, setMessageReferences] = useState7({});
1247
+ const addReference = useCallback3((ref) => {
1248
+ setPending(
1249
+ (prev) => prev.some((r) => r.id === ref.id) ? prev : [...prev, ref]
1250
+ );
1251
+ }, []);
1252
+ const removeReference = useCallback3((id) => {
1253
+ setPending((prev) => prev.filter((r) => r.id !== id));
1254
+ }, []);
1255
+ const clearReferences = useCallback3(() => setPending([]), []);
1256
+ const recordMessageReferences = useCallback3(
1257
+ (messageId, refs) => {
1258
+ if (refs.length === 0) return;
1259
+ setMessageReferences((prev) => ({ ...prev, [messageId]: refs }));
1260
+ },
1261
+ []
1262
+ );
1263
+ const value = useMemo(
1264
+ () => ({
1265
+ providers,
1266
+ pending,
1267
+ addReference,
1268
+ removeReference,
1269
+ clearReferences,
1270
+ messageReferences,
1271
+ recordMessageReferences
1272
+ }),
1273
+ [
1274
+ providers,
1275
+ pending,
1276
+ addReference,
1277
+ removeReference,
1278
+ clearReferences,
1279
+ messageReferences,
1280
+ recordMessageReferences
1281
+ ]
1282
+ );
1283
+ return /* @__PURE__ */ jsxs9(ReferencesContext.Provider, { value, children: [
1284
+ syncObjectStateTo !== false && /* @__PURE__ */ jsx15(ReferenceStateSync, { agentId: syncObjectStateTo, pending }),
1285
+ children
1286
+ ] });
1287
+ }
1288
+ function ReferenceStateSync({
1289
+ agentId,
1290
+ pending
1291
+ }) {
1292
+ const { agent } = useAgent2(agentId ? { agentId } : void 0);
1293
+ const objectRefs = useMemo(
1294
+ () => pending.filter((r) => r.transport === "object").map(objectToStateEntry),
1295
+ [pending]
1296
+ );
1297
+ const key = JSON.stringify(objectRefs);
1298
+ useEffect4(() => {
1299
+ if (!agent || typeof agent.setState !== "function") return;
1300
+ agent.setState(withReferenceState(agent.state, objectRefs));
1301
+ }, [agent, key]);
1302
+ return null;
1303
+ }
1304
+ function useReferences() {
1305
+ return useContext5(ReferencesContext);
1306
+ }
1307
+
1147
1308
  export {
1148
1309
  StructuredRenderersContext,
1149
1310
  KabooActivityProvider,
@@ -1172,6 +1333,18 @@ export {
1172
1333
  useDrill,
1173
1334
  AgentCard,
1174
1335
  KabooToolRender,
1175
- KabooInlineCards
1336
+ KabooInlineCards,
1337
+ REFERENCE_METADATA_KEYS,
1338
+ REFERENCES_STATE_KEY,
1339
+ mintReferenceId,
1340
+ referenceMarker,
1341
+ attachmentToInputContent,
1342
+ objectToStateEntry,
1343
+ serializeReferences,
1344
+ withReferenceState,
1345
+ buildUserContent,
1346
+ ReferencesProvider,
1347
+ ReferenceStateSync,
1348
+ useReferences
1176
1349
  };
1177
- //# sourceMappingURL=chunk-RXZWOBSI.js.map
1350
+ //# sourceMappingURL=chunk-4TDUEMK5.js.map