@cubos/agent-sdk-react 0.0.1136563
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/README.md +304 -0
- package/dist/blocks.d.ts +47 -0
- package/dist/context.d.ts +23 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +876 -0
- package/dist/index.js.map +15 -0
- package/dist/use-conversation-events.d.ts +47 -0
- package/dist/use-conversation-list.d.ts +32 -0
- package/dist/use-conversation.d.ts +358 -0
- package/dist/use-identity.d.ts +9 -0
- package/package.json +51 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { type Activity, type Block, type ClientTool, type Conversation, type Message, type PlanSnapshot, type Todo, type ToolActivity, type WorkspaceEntry } from "@cubos/agent-sdk";
|
|
2
|
+
import { type ReactNode } from "react";
|
|
3
|
+
import { type ComponentMap } from "./blocks.js";
|
|
4
|
+
export interface UseConversationOptions {
|
|
5
|
+
/**
|
|
6
|
+
* How many events a history page asks for. Counts events, not messages, so a
|
|
7
|
+
* page of a tool-heavy turn can yield only a couple of bubbles — which is why
|
|
8
|
+
* a UI should keep calling `loadOlder` until `hasOlder` is false rather than
|
|
9
|
+
* assuming one page fills the viewport.
|
|
10
|
+
*/
|
|
11
|
+
pageSize?: number;
|
|
12
|
+
/** Which agent a conversation created by the first `send` talks to. Optional
|
|
13
|
+
* when the token names exactly one. */
|
|
14
|
+
agentSlug?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Called once, with the conversation the first `send` created, when this hook
|
|
17
|
+
* was given `null`. Point it at whatever owns the selection — `setState`, a
|
|
18
|
+
* router navigation — and pass the id back on the next render.
|
|
19
|
+
*
|
|
20
|
+
* The messages already on screen survive that hand-off, so the user's first
|
|
21
|
+
* message doesn't blink out while the conversation is adopted.
|
|
22
|
+
*
|
|
23
|
+
* **Awaited.** It runs after the conversation exists and before the message
|
|
24
|
+
* is posted, which is the only window in which an app can set something up
|
|
25
|
+
* that the very first turn depends on — declaring its own client tools, for
|
|
26
|
+
* one. Returning a promise holds the send until it resolves; a throw fails
|
|
27
|
+
* the send, which is the honest outcome for setup that did not happen.
|
|
28
|
+
*/
|
|
29
|
+
onCreated?: (conversation: Conversation) => void | Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Functions the agent may call, keyed by tool name. Declared on the
|
|
32
|
+
* conversation, then executed here as the agent calls them: the turn suspends
|
|
33
|
+
* on the call and resumes with whatever the handler returns.
|
|
34
|
+
*
|
|
35
|
+
* They ride the subscription this hook already holds — no second stream.
|
|
36
|
+
*/
|
|
37
|
+
clientTools?: Record<string, ClientTool<never, unknown>>;
|
|
38
|
+
/**
|
|
39
|
+
* Whether this hook declares `clientTools` on the conversation. Defaults to
|
|
40
|
+
* true, which is what an app with a fixed tool set wants.
|
|
41
|
+
*
|
|
42
|
+
* Turn it off to declare the set yourself, with `setClientTools`, and pass
|
|
43
|
+
* every handler the agent might ever call here. That splits two things this
|
|
44
|
+
* hook otherwise ties together: *what can run* (the handlers, which must
|
|
45
|
+
* cover any call that arrives) and *what the agent is told about* (the
|
|
46
|
+
* declaration). An app whose tools depend on the open screen needs that
|
|
47
|
+
* split — the declaration should change on navigation, while the handlers
|
|
48
|
+
* must stay complete, or a call issued a moment earlier would find no
|
|
49
|
+
* implementation.
|
|
50
|
+
*/
|
|
51
|
+
declareClientTools?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* What your app currently has on screen — the open page, the selected record,
|
|
54
|
+
* the filters in force. Free-form: prose or JSON, whatever the agent reads
|
|
55
|
+
* best.
|
|
56
|
+
*
|
|
57
|
+
* Set it and forget it — update it as often as your screen moves. Nothing is
|
|
58
|
+
* sent while nobody is listening: the value is held and flushed at the two
|
|
59
|
+
* moments the agent can actually read it, just before a message and on any
|
|
60
|
+
* change while a turn is running. A user browsing eleven screens before typing
|
|
61
|
+
* anything costs one request, and the agent is told once.
|
|
62
|
+
*
|
|
63
|
+
* Undefined leaves it alone; `null` clears it.
|
|
64
|
+
*/
|
|
65
|
+
context?: string | null;
|
|
66
|
+
/**
|
|
67
|
+
* What draws each component, keyed by tag name (PascalCase, as the agent
|
|
68
|
+
* writes them). Renderers only — what the agent is *told* about a component
|
|
69
|
+
* comes from the libraries below.
|
|
70
|
+
*
|
|
71
|
+
* Extra entries are fine and useful: they draw components of older messages
|
|
72
|
+
* that no enabled library offers any more.
|
|
73
|
+
*/
|
|
74
|
+
components?: ComponentMap;
|
|
75
|
+
/**
|
|
76
|
+
* Slugs of the component libraries this screen can render. Replaces the
|
|
77
|
+
* conversation's list, so pass the complete one; `[]` takes the agent back to
|
|
78
|
+
* plain markdown.
|
|
79
|
+
*
|
|
80
|
+
* The libraries are authored by the operator over the admin API, because their
|
|
81
|
+
* entries reach the model verbatim. This is the half that depends on which of
|
|
82
|
+
* your screens is open, which is why it is yours. Narrow it as the app
|
|
83
|
+
* navigates — the hook only re-declares at moments the change can't disturb a
|
|
84
|
+
* turn in flight.
|
|
85
|
+
*
|
|
86
|
+
* A tag the libraries offer with no renderer in `components` is a block the
|
|
87
|
+
* agent will write and nothing will draw, so the hook logs a warning naming
|
|
88
|
+
* it. The reverse is never warned about.
|
|
89
|
+
*/
|
|
90
|
+
componentLibraries?: string[];
|
|
91
|
+
/** Draws the prose around those components. Without it markdown renders as
|
|
92
|
+
* plain text — see `renderBlocks`. */
|
|
93
|
+
renderMarkdown?: (text: string) => ReactNode;
|
|
94
|
+
/** Wraps each block of an agent message, so the app can lay prose and
|
|
95
|
+
* components out differently — see `renderBlocks`. */
|
|
96
|
+
wrapBlock?: (node: ReactNode, block: Block) => ReactNode;
|
|
97
|
+
/** A client tool's handler threw, or its result couldn't be delivered. The
|
|
98
|
+
* agent is told either way; this is for your logs. */
|
|
99
|
+
onClientToolError?: (err: unknown) => void;
|
|
100
|
+
}
|
|
101
|
+
export interface UseConversationResult {
|
|
102
|
+
conversation: Conversation | null;
|
|
103
|
+
/** Oldest first, deduped by id, including any message still in flight. */
|
|
104
|
+
messages: Message[];
|
|
105
|
+
/** Every tool the agent used, folded and ordered by `seq`. Use `trailFor` to
|
|
106
|
+
* get the ones behind a given reply; this is the whole conversation's. */
|
|
107
|
+
toolActivity: ToolActivity[];
|
|
108
|
+
/**
|
|
109
|
+
* The steps behind one reply — what the agent did between the message before
|
|
110
|
+
* it and this one — for a "how I got here" disclosure.
|
|
111
|
+
*
|
|
112
|
+
* Empty for a user message: a trail belongs to the answer, not the question.
|
|
113
|
+
* Every entry carries its `arguments` once the call that issued them has been
|
|
114
|
+
* seen — which for a step still running can be a moment later, so phrase from
|
|
115
|
+
* the tool name and let the arguments sharpen it.
|
|
116
|
+
*/
|
|
117
|
+
trailFor: (message: Message) => ToolActivity[];
|
|
118
|
+
/**
|
|
119
|
+
* The steps no reply has claimed yet — what the agent has done since the last
|
|
120
|
+
* message. Non-empty while a turn is running, which is what lets a UI draw the
|
|
121
|
+
* trail as it happens instead of only once the answer lands, and non-empty
|
|
122
|
+
* after a turn that produced no message at all.
|
|
123
|
+
*/
|
|
124
|
+
pendingTrail: ToolActivity[];
|
|
125
|
+
/** The plan the given reply was written under, or null when the agent kept
|
|
126
|
+
* none — the last revision inside the same window as `trailFor`, so an old
|
|
127
|
+
* answer never shows a newer plan. */
|
|
128
|
+
planFor: (message: Message) => Todo[] | null;
|
|
129
|
+
/** The plan of the turn still running, for the same reason `pendingTrail`
|
|
130
|
+
* exists. */
|
|
131
|
+
pendingPlan: Todo[] | null;
|
|
132
|
+
/** The newest plan in the conversation, regardless of which turn wrote it. */
|
|
133
|
+
todos: Todo[];
|
|
134
|
+
activity: Activity;
|
|
135
|
+
/**
|
|
136
|
+
* Whether a turn is running right now — the signal to key a "working"
|
|
137
|
+
* indicator on.
|
|
138
|
+
*
|
|
139
|
+
* The server decides this, not you and not the SDK: `hasPendingTurn` is a
|
|
140
|
+
* trigger over the event log ("a user message newer than the last
|
|
141
|
+
* `turn_done`"), pushed on connect and on every change, so it cannot read
|
|
142
|
+
* false while a turn is in flight — not between two replies of one turn, not
|
|
143
|
+
* while a tool runs, not while a client tool suspends it.
|
|
144
|
+
*
|
|
145
|
+
* Not the same as `activity.isProcessing`, and the difference is the whole
|
|
146
|
+
* reason this exists: a client tool **suspends** the turn while your app
|
|
147
|
+
* answers it, so the conversation stops being "processing" for as long as
|
|
148
|
+
* that takes. A UI keyed on activity alone stops its spinner in the middle of
|
|
149
|
+
* the work and starts it again a second later.
|
|
150
|
+
*
|
|
151
|
+
* True from the moment a message is sent until the `turn_done` that follows
|
|
152
|
+
* it, and true whenever the server says it is processing — either is enough.
|
|
153
|
+
*/
|
|
154
|
+
isTurnRunning: boolean;
|
|
155
|
+
/** True until the first history page and the first stream frame land. False
|
|
156
|
+
* immediately when the conversation came from the client's cache. */
|
|
157
|
+
isLoading: boolean;
|
|
158
|
+
/** There is older history behind what is loaded. */
|
|
159
|
+
hasOlder: boolean;
|
|
160
|
+
/** A `loadOlder` is in flight. */
|
|
161
|
+
isLoadingOlder: boolean;
|
|
162
|
+
/**
|
|
163
|
+
* Prepends the page before the oldest message held. Safe to call while the
|
|
164
|
+
* agent is mid-turn — live messages keep arriving and land in order.
|
|
165
|
+
*
|
|
166
|
+
* Resolves to the number of messages added, so a list can tell "nothing came
|
|
167
|
+
* back" from "we reached the beginning" without watching `hasOlder`.
|
|
168
|
+
*/
|
|
169
|
+
loadOlder: () => Promise<number>;
|
|
170
|
+
/** Set on a failed send or an unrecoverable load. Stream hiccups don't land
|
|
171
|
+
* here — the SDK reconnects on its own. */
|
|
172
|
+
error: Error | null;
|
|
173
|
+
/**
|
|
174
|
+
* Appends the message optimistically, then reconciles with the server's echo.
|
|
175
|
+
* Rejects on failure, having already rolled the optimistic copy back.
|
|
176
|
+
*
|
|
177
|
+
* On the blank slate (`null` id) it creates the conversation first and reports
|
|
178
|
+
* it through `onCreated`, so a UI never branches on "no conversation yet".
|
|
179
|
+
*/
|
|
180
|
+
send: (content: string) => Promise<void>;
|
|
181
|
+
/** Uploads a recorded clip. The words appear once the agent's STT model has
|
|
182
|
+
* transcribed it, so nothing is echoed optimistically — there is no text to
|
|
183
|
+
* echo yet. Creates the conversation on the blank slate, like `send`. */
|
|
184
|
+
sendAudio: (audio: Blob) => Promise<void>;
|
|
185
|
+
/**
|
|
186
|
+
* Up to 10 images as ONE message, so the agent reasons over the set instead of
|
|
187
|
+
* one turn per picture. `caption` becomes the message's text, and a per-image
|
|
188
|
+
* `label` names it for the model.
|
|
189
|
+
*
|
|
190
|
+
* Nothing is echoed optimistically: the bubble needs the server's attachment
|
|
191
|
+
* ids to fetch the bytes back, so it appears with the echo. Creates the
|
|
192
|
+
* conversation on the blank slate, like `send`.
|
|
193
|
+
*/
|
|
194
|
+
sendImages: (images: Array<{
|
|
195
|
+
image: Blob;
|
|
196
|
+
filename?: string;
|
|
197
|
+
label?: string;
|
|
198
|
+
}>, caption?: string) => Promise<void>;
|
|
199
|
+
steer: (content: string) => Promise<void>;
|
|
200
|
+
/** True while a send is in flight. */
|
|
201
|
+
isSending: boolean;
|
|
202
|
+
/**
|
|
203
|
+
* The agent's reply as React nodes: your components where it used them, your
|
|
204
|
+
* markdown renderer around them.
|
|
205
|
+
*
|
|
206
|
+
* Null for a message with no blocks — every user message, and any agent
|
|
207
|
+
* message from a server that predates them. Render `content` for those.
|
|
208
|
+
*/
|
|
209
|
+
renderMessage: (message: Message) => ReactNode[] | null;
|
|
210
|
+
/**
|
|
211
|
+
* Declare the current `clientTools` now.
|
|
212
|
+
*
|
|
213
|
+
* Rarely needed: the hook already declares when the session starts and before
|
|
214
|
+
* every message, which covers an app whose tool set follows the open screen.
|
|
215
|
+
* This is for the one moment it cannot see — inside a tool that just moved the
|
|
216
|
+
* app, where the verbs of the new screen have to be available for the step the
|
|
217
|
+
* agent takes next, and where declaring is safe because the call running it
|
|
218
|
+
* holds the lease.
|
|
219
|
+
*/
|
|
220
|
+
syncClientTools: () => Promise<void>;
|
|
221
|
+
/**
|
|
222
|
+
* Bumped whenever the conversation's files change, from any source — the
|
|
223
|
+
* agent writing one, this app uploading one, another tab deleting one.
|
|
224
|
+
*
|
|
225
|
+
* The hook does not hold the listing itself, for the same reason it does not
|
|
226
|
+
* hold which conversation is open: the directory the user is looking at is
|
|
227
|
+
* the app's state. What only the hook can supply is *when* to look again,
|
|
228
|
+
* since it already has the stream. Use it as a dependency:
|
|
229
|
+
*
|
|
230
|
+
* ```ts
|
|
231
|
+
* useEffect(() => { void listFiles(path).then(setEntries) }, [listFiles, path, workspaceRevision])
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
234
|
+
workspaceRevision: number;
|
|
235
|
+
/** One directory, never recursive. Empty on the blank slate — there is no
|
|
236
|
+
* conversation yet, and listing is not a reason to create one. */
|
|
237
|
+
listFiles: (path?: string) => Promise<WorkspaceEntry[]>;
|
|
238
|
+
/** One file's bytes. */
|
|
239
|
+
readFile: (path: string) => Promise<Blob>;
|
|
240
|
+
/**
|
|
241
|
+
* Uploads files. Creates the conversation on the blank slate, like `send`.
|
|
242
|
+
*
|
|
243
|
+
* Starts no turn: the user dropping a file is not asking a question. The
|
|
244
|
+
* agent is told what changed at the start of its next request, so upload
|
|
245
|
+
* first and then `send` if you want it acted on — those are one turn, not two.
|
|
246
|
+
*/
|
|
247
|
+
writeFiles: (files: Array<{
|
|
248
|
+
path: string;
|
|
249
|
+
file: Blob;
|
|
250
|
+
filename?: string;
|
|
251
|
+
}>) => Promise<void>;
|
|
252
|
+
deleteFile: (path: string) => Promise<void>;
|
|
253
|
+
moveFile: (from: string, to: string) => Promise<void>;
|
|
254
|
+
}
|
|
255
|
+
/** A message can arrive twice — once in a history page, once as a stream frame —
|
|
256
|
+
* and a `loadOlder` page lands in front of what is already held. Key by id and
|
|
257
|
+
* sort by seq so both are non-events. */
|
|
258
|
+
export declare function mergeMessages(existing: Message[], incoming: Message[]): Message[];
|
|
259
|
+
/**
|
|
260
|
+
* The steps behind one reply: what the agent did between the message before it
|
|
261
|
+
* and this one.
|
|
262
|
+
*
|
|
263
|
+
* The previous message is what bounds the turn. Without it the first reply
|
|
264
|
+
* would claim every step ever taken, and each later one would claim the steps
|
|
265
|
+
* of the reply before it. Exported for its test — the hook is the only caller.
|
|
266
|
+
*
|
|
267
|
+
* Expects `messages` ordered by `seq`.
|
|
268
|
+
*/
|
|
269
|
+
export declare function trailOf(message: Message, messages: Message[], activity: ToolActivity[]): ToolActivity[];
|
|
270
|
+
/**
|
|
271
|
+
* The steps that no reply has claimed yet: everything after the last message
|
|
272
|
+
* held.
|
|
273
|
+
*
|
|
274
|
+
* This is what makes a trail watchable while it happens. `trailOf` needs a
|
|
275
|
+
* message to hang steps on, and mid-turn there is none — the agent is still
|
|
276
|
+
* working. These are those steps.
|
|
277
|
+
*
|
|
278
|
+
* It also covers the turn that ends with **no** message at all: an agent can
|
|
279
|
+
* call tools and stop without writing a reply, and without this those steps
|
|
280
|
+
* would never be shown by anything, because nothing would ever arrive to anchor
|
|
281
|
+
* them.
|
|
282
|
+
*
|
|
283
|
+
* The optimistic copy of a just-sent message is skipped: it carries
|
|
284
|
+
* `MAX_SAFE_INTEGER` as its seq, so counting it would put the boundary past
|
|
285
|
+
* every real step and this would always come back empty.
|
|
286
|
+
*
|
|
287
|
+
* Expects `messages` ordered by `seq`.
|
|
288
|
+
*/
|
|
289
|
+
export declare function trailAfterLast(messages: Message[], activity: ToolActivity[]): ToolActivity[];
|
|
290
|
+
/**
|
|
291
|
+
* Is a turn running?
|
|
292
|
+
*
|
|
293
|
+
* Three signals, and none of them is a comparison this file makes up.
|
|
294
|
+
*
|
|
295
|
+
* `hasPendingTurn` is the server's, and the trigger behind it computes exactly
|
|
296
|
+
* "there is a user message newer than the last `turn_done`" — which is what
|
|
297
|
+
* being owed a reply means, and it stays true while a client tool suspends the
|
|
298
|
+
* turn, when nothing is processing and the agent has answered nothing yet.
|
|
299
|
+
* `isProcessing` says the work is happening right now. The optimistic copy
|
|
300
|
+
* covers the moment between pressing enter and the first frame.
|
|
301
|
+
*
|
|
302
|
+
* Both arrive as `conversation_status` frames on the *event* stream, which is
|
|
303
|
+
* what makes reading them here safe. Published on the metadata stream instead —
|
|
304
|
+
* a second connection — they raced the reply they were about, and the UI showed
|
|
305
|
+
* a finished turn with nothing in it for as long as that race lasted.
|
|
306
|
+
*
|
|
307
|
+
* What is deliberately *not* here is a rule deriving "finished" from the log.
|
|
308
|
+
* Twice now that has been wrong in opposite directions: reading a missing turn
|
|
309
|
+
* cursor as "no turn has ended" left the dots on a conversation idle for hours,
|
|
310
|
+
* and reading a *previous* turn's `turn_done` as this turn's end collapsed the
|
|
311
|
+
* trail mid-work, while the agent was paused waiting on a client tool. The
|
|
312
|
+
* server already publishes the answer; recomputing it from a cursor the client
|
|
313
|
+
* keeps separately only creates two halves that can disagree.
|
|
314
|
+
*
|
|
315
|
+
* Exported for its test; the hook is the only caller.
|
|
316
|
+
*/
|
|
317
|
+
export declare function turnIsRunning(messages: Message[], activity: Activity): boolean;
|
|
318
|
+
/**
|
|
319
|
+
* Plan revisions, deduped by `seq` and ordered.
|
|
320
|
+
*
|
|
321
|
+
* The same revision arrives twice routinely — once from the history page and
|
|
322
|
+
* again from the stream frame that follows it — and two identical plans against
|
|
323
|
+
* one turn would make `planOf` pick arbitrarily between them.
|
|
324
|
+
*/
|
|
325
|
+
export declare function mergePlans(existing: PlanSnapshot[], incoming: PlanSnapshot[]): PlanSnapshot[];
|
|
326
|
+
/**
|
|
327
|
+
* The plan as it stood when a reply was written.
|
|
328
|
+
*
|
|
329
|
+
* The agent revises the list several times per turn — one revision per step it
|
|
330
|
+
* ticks off. Showing them all would be a diff log; showing the newest against
|
|
331
|
+
* an old answer would be a lie. So: the last revision in the same window
|
|
332
|
+
* `trailOf` uses, which is the plan the reply was written under.
|
|
333
|
+
*
|
|
334
|
+
* Returns null rather than an empty list when there is none, so a caller can
|
|
335
|
+
* tell "no plan" from "a plan with nothing in it".
|
|
336
|
+
*
|
|
337
|
+
* Expects `messages` and `plans` ordered by `seq`.
|
|
338
|
+
*/
|
|
339
|
+
export declare function planOf(message: Message, messages: Message[], plans: PlanSnapshot[]): Todo[] | null;
|
|
340
|
+
/** The plan of the turn still running — the counterpart of `trailAfterLast`. */
|
|
341
|
+
export declare function planAfterLast(messages: Message[], plans: PlanSnapshot[]): Todo[] | null;
|
|
342
|
+
/**
|
|
343
|
+
* One conversation, live: history, streamed messages, the agent's plan and
|
|
344
|
+
* whether it is working right now.
|
|
345
|
+
*
|
|
346
|
+
* The id is yours to own — component state, a route param, whatever. Pass
|
|
347
|
+
* `null` for the blank slate: nothing connects, and the first `send` creates the
|
|
348
|
+
* conversation and hands it to `onCreated`.
|
|
349
|
+
*
|
|
350
|
+
* ```tsx
|
|
351
|
+
* const [id, setId] = useState<string | null>(null);
|
|
352
|
+
* const { messages, send } = useConversation(id, {
|
|
353
|
+
* agentSlug: "support",
|
|
354
|
+
* onCreated: (c) => setId(c.id),
|
|
355
|
+
* });
|
|
356
|
+
* ```
|
|
357
|
+
*/
|
|
358
|
+
export declare function useConversation(conversationId: string | null, options?: UseConversationOptions): UseConversationResult;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Identity } from "@cubos/agent-sdk";
|
|
2
|
+
export interface UseIdentityResult {
|
|
3
|
+
identity: Identity | null;
|
|
4
|
+
isLoading: boolean;
|
|
5
|
+
error: Error | null;
|
|
6
|
+
}
|
|
7
|
+
/** Who the current token acts as, and which agents it may talk to. Resolved once
|
|
8
|
+
* per client and cached inside it. */
|
|
9
|
+
export declare function useIdentity(): UseIdentityResult;
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cubos/agent-sdk-react",
|
|
3
|
+
"version": "0.0.1136563",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Headless React hooks for the Cubos Agent conversation API. No DOM — works in React Native too.",
|
|
6
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"cubos",
|
|
9
|
+
"agent",
|
|
10
|
+
"react",
|
|
11
|
+
"react-native",
|
|
12
|
+
"chat",
|
|
13
|
+
"hooks",
|
|
14
|
+
"sdk",
|
|
15
|
+
"headless"
|
|
16
|
+
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://git.cubos.io/agent/cubos-agent.git",
|
|
20
|
+
"directory": "packages/sdk-react"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://git.cubos.io/agent/cubos-agent/-/tree/main/packages/sdk-react",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://git.cubos.io/agent/cubos-agent/-/issues"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"default": "./dist/index.js"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "bun scripts/build.ts",
|
|
37
|
+
"typecheck": "tsgo --noEmit",
|
|
38
|
+
"test": "bun test"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"@cubos/agent-sdk": "0.0.x",
|
|
42
|
+
"react": ">=18"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@cubos/agent-sdk": "0.0.x",
|
|
46
|
+
"@types/bun": "^1.4.0",
|
|
47
|
+
"@types/react": "^19.2.18",
|
|
48
|
+
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
49
|
+
"react": "^19.2.8"
|
|
50
|
+
}
|
|
51
|
+
}
|