@codespring-app/use-agent 0.1.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/dist/react.js ADDED
@@ -0,0 +1,1148 @@
1
+ import {
2
+ createBrowserClient
3
+ } from "./chunk-FAD2XMPA.js";
4
+
5
+ // src/react.tsx
6
+ import {
7
+ createContext,
8
+ createElement,
9
+ useContext,
10
+ useEffect,
11
+ useMemo,
12
+ useRef,
13
+ useState,
14
+ useSyncExternalStore
15
+ } from "react";
16
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
17
+ var agentThemeVariables = Object.freeze({
18
+ canvas: "--codespring-agent-canvas",
19
+ ink: "--codespring-agent-ink",
20
+ inkSecondary: "--codespring-agent-ink-secondary",
21
+ inkTertiary: "--codespring-agent-ink-tertiary",
22
+ well: "--codespring-agent-well",
23
+ hairline: "--codespring-agent-hairline",
24
+ statusGood: "--codespring-agent-status-good",
25
+ statusBad: "--codespring-agent-status-bad",
26
+ statusWarn: "--codespring-agent-status-warn",
27
+ accent: "--codespring-agent-accent",
28
+ fontFamily: "--codespring-agent-font-family",
29
+ monoFamily: "--codespring-agent-mono-family",
30
+ contentMaxWidth: "--codespring-agent-content-max-width",
31
+ containerRadius: "--codespring-agent-container-radius",
32
+ wellRadius: "--codespring-agent-well-radius"
33
+ });
34
+ var paperLightTheme = Object.freeze({
35
+ canvas: "#FFFFFF",
36
+ ink: "#141414",
37
+ inkSecondary: "#68686D",
38
+ inkTertiary: "#9B9BA0",
39
+ well: "#F5F5F8",
40
+ hairline: "#E4E4E8",
41
+ statusGood: "#0E7B3F",
42
+ statusBad: "#C33530",
43
+ statusWarn: "#A06C02",
44
+ accent: "#3B6AC5",
45
+ fontFamily: "Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif",
46
+ monoFamily: "SFMono-Regular, SF Mono, ui-monospace, Menlo, Consolas, monospace",
47
+ contentMaxWidth: 760,
48
+ containerRadius: 10,
49
+ wellRadius: 8
50
+ });
51
+ var paperDarkTheme = Object.freeze({
52
+ ...paperLightTheme,
53
+ canvas: "#161618",
54
+ ink: "#ECECEC",
55
+ inkSecondary: "#98989D",
56
+ inkTertiary: "#66666B",
57
+ well: "#1D1D1F",
58
+ hairline: "#29292C",
59
+ statusGood: "#63C180",
60
+ statusBad: "#DF5048",
61
+ statusWarn: "#E3A648",
62
+ accent: "#87B1FD"
63
+ });
64
+ var defaultAgentCopy = Object.freeze({
65
+ title: "Assistant",
66
+ empty: "Start a conversation",
67
+ loading: "Loading conversation\u2026",
68
+ thinking: "Working\u2026",
69
+ placeholder: "Message the agent \u2014 Shift+Enter for a new line",
70
+ send: "Send message",
71
+ sending: "Sending\u2026",
72
+ failed: "The agent could not complete this message.",
73
+ cancelled: "This message was cancelled.",
74
+ userLabel: "You",
75
+ assistantLabel: "Assistant",
76
+ toolRunning: "Running",
77
+ toolCompleted: "Completed",
78
+ toolFailed: "Failed",
79
+ toolApprovalRequired: "Approval required"
80
+ });
81
+ function createAgentAppearance({
82
+ mode = "light",
83
+ theme,
84
+ copy
85
+ } = {}) {
86
+ return Object.freeze({
87
+ theme: Object.freeze({ ...mode === "dark" ? paperDarkTheme : paperLightTheme, ...theme }),
88
+ copy: Object.freeze({ ...defaultAgentCopy, ...copy })
89
+ });
90
+ }
91
+ var paperAppearance = createAgentAppearance();
92
+ var paperDarkAppearance = createAgentAppearance({ mode: "dark" });
93
+ function cssLength(value) {
94
+ return typeof value === "number" ? `${value}px` : value;
95
+ }
96
+ function cssVariable(name, fallback) {
97
+ return fallback === `var(${name})` || fallback.startsWith(`var(${name},`) ? fallback : `var(${name}, ${fallback})`;
98
+ }
99
+ function withThemeVariables(theme) {
100
+ return {
101
+ canvas: cssVariable(agentThemeVariables.canvas, theme.canvas),
102
+ ink: cssVariable(agentThemeVariables.ink, theme.ink),
103
+ inkSecondary: cssVariable(agentThemeVariables.inkSecondary, theme.inkSecondary),
104
+ inkTertiary: cssVariable(agentThemeVariables.inkTertiary, theme.inkTertiary),
105
+ well: cssVariable(agentThemeVariables.well, theme.well),
106
+ hairline: cssVariable(agentThemeVariables.hairline, theme.hairline),
107
+ statusGood: cssVariable(agentThemeVariables.statusGood, theme.statusGood),
108
+ statusBad: cssVariable(agentThemeVariables.statusBad, theme.statusBad),
109
+ statusWarn: cssVariable(agentThemeVariables.statusWarn, theme.statusWarn),
110
+ accent: cssVariable(agentThemeVariables.accent, theme.accent),
111
+ fontFamily: cssVariable(agentThemeVariables.fontFamily, theme.fontFamily),
112
+ monoFamily: cssVariable(agentThemeVariables.monoFamily, theme.monoFamily),
113
+ contentMaxWidth: cssVariable(agentThemeVariables.contentMaxWidth, cssLength(theme.contentMaxWidth)),
114
+ containerRadius: cssVariable(agentThemeVariables.containerRadius, cssLength(theme.containerRadius)),
115
+ wellRadius: cssVariable(agentThemeVariables.wellRadius, cssLength(theme.wellRadius))
116
+ };
117
+ }
118
+ function withThemeOverrides(base, overrides) {
119
+ if (!overrides) return base;
120
+ const resolvedOverrides = withThemeVariables({ ...paperLightTheme, ...overrides });
121
+ const merged = { ...base };
122
+ for (const key of Object.keys(overrides)) {
123
+ if (overrides[key] !== void 0) merged[key] = resolvedOverrides[key];
124
+ }
125
+ return merged;
126
+ }
127
+ var AgentContext = createContext(null);
128
+ function shallowEqual(left, right) {
129
+ const leftKeys = Object.keys(left);
130
+ const rightKeys = Object.keys(right);
131
+ return leftKeys.length === rightKeys.length && leftKeys.every((key) => left[key] === right[key]);
132
+ }
133
+ function useStablePartial(value) {
134
+ const stable = useRef(value);
135
+ if (!shallowEqual(stable.current ?? {}, value ?? {})) stable.current = value;
136
+ return stable.current;
137
+ }
138
+ function AgentProvider({
139
+ client,
140
+ appearance = paperAppearance,
141
+ theme,
142
+ copy,
143
+ children
144
+ }) {
145
+ const stableTheme = useStablePartial(theme);
146
+ const stableCopy = useStablePartial(copy);
147
+ const resolvedTheme = useMemo(
148
+ () => Object.freeze(withThemeVariables({ ...appearance.theme, ...stableTheme })),
149
+ [appearance.theme, stableTheme]
150
+ );
151
+ const resolvedCopy = useMemo(
152
+ () => Object.freeze({ ...appearance.copy, ...stableCopy }),
153
+ [appearance.copy, stableCopy]
154
+ );
155
+ const stores = useMemo(() => /* @__PURE__ */ new Map(), [client]);
156
+ useEffect(() => () => {
157
+ for (const store of stores.values()) store.dispose();
158
+ stores.clear();
159
+ }, [stores]);
160
+ const value = useMemo(
161
+ () => ({
162
+ client,
163
+ theme: resolvedTheme,
164
+ copy: resolvedCopy,
165
+ stores
166
+ }),
167
+ [client, resolvedTheme, resolvedCopy, stores]
168
+ );
169
+ return createElement(AgentContext.Provider, { value }, children);
170
+ }
171
+ function useAgentContext() {
172
+ const value = useContext(AgentContext);
173
+ if (!value) throw new Error("Agent React APIs must be used inside AgentProvider");
174
+ return value;
175
+ }
176
+ function useAgentClient() {
177
+ return useAgentContext().client;
178
+ }
179
+ function createAgentClient({
180
+ endpoint,
181
+ clientTokenEndpoint,
182
+ fetch: fetchImplementation,
183
+ credentials = "same-origin",
184
+ clientTokenTtlMs,
185
+ refreshSkewMs
186
+ }) {
187
+ return createBrowserClient({
188
+ endpoint,
189
+ getClientToken: async () => {
190
+ const request = fetchImplementation ?? globalThis.fetch;
191
+ if (!request) throw new TypeError("A fetch implementation is required");
192
+ const response = await request(clientTokenEndpoint, {
193
+ method: "POST",
194
+ credentials,
195
+ headers: { Accept: "application/json" }
196
+ });
197
+ if (!response.ok) throw new Error(`Client token request failed with ${response.status}`);
198
+ const contentType = response.headers.get("content-type") ?? "";
199
+ if (!contentType.includes("application/json")) return response.text();
200
+ const body = await response.json();
201
+ if (typeof body.token !== "string") throw new Error("Client token response is missing token");
202
+ return {
203
+ token: body.token,
204
+ ...typeof body.expiresAt === "string" || typeof body.expiresAt === "number" ? { expiresAt: body.expiresAt } : {}
205
+ };
206
+ },
207
+ ...fetchImplementation === void 0 ? {} : { fetch: fetchImplementation },
208
+ ...clientTokenTtlMs === void 0 ? {} : { clientTokenTtlMs },
209
+ ...refreshSkewMs === void 0 ? {} : { refreshSkewMs }
210
+ });
211
+ }
212
+ function useAgentTheme() {
213
+ return useAgentContext().theme;
214
+ }
215
+ function useAgentCopy() {
216
+ return useAgentContext().copy;
217
+ }
218
+ function stringField(data, key) {
219
+ if (!data || typeof data !== "object") return void 0;
220
+ const value = data[key];
221
+ return typeof value === "string" ? value : void 0;
222
+ }
223
+ function unknownField(data, key) {
224
+ if (!data || typeof data !== "object") return void 0;
225
+ return data[key];
226
+ }
227
+ function reduceAgentMessages(events) {
228
+ const messages = /* @__PURE__ */ new Map();
229
+ for (const event of events) {
230
+ if (!event.turnId) continue;
231
+ const inputId = `${event.turnId}:user`;
232
+ const outputId = `${event.turnId}:assistant:${event.attempt}`;
233
+ if (event.type === "message.input") {
234
+ messages.set(inputId, {
235
+ id: inputId,
236
+ turnId: event.turnId,
237
+ role: "user",
238
+ content: stringField(event.data, "content") ?? "",
239
+ status: "completed",
240
+ createdAt: event.createdAt,
241
+ eventId: event.id
242
+ });
243
+ continue;
244
+ }
245
+ if (event.type === "message.started") {
246
+ messages.set(outputId, {
247
+ id: outputId,
248
+ turnId: event.turnId,
249
+ role: "assistant",
250
+ content: "",
251
+ status: "streaming",
252
+ createdAt: event.createdAt,
253
+ eventId: event.id
254
+ });
255
+ continue;
256
+ }
257
+ if (event.type === "message.delta") {
258
+ const current = messages.get(outputId);
259
+ if (current) {
260
+ messages.set(outputId, {
261
+ ...current,
262
+ content: current.content + (stringField(event.data, "delta") ?? ""),
263
+ eventId: event.id
264
+ });
265
+ }
266
+ continue;
267
+ }
268
+ if (event.type === "message.completed") {
269
+ const current = messages.get(outputId);
270
+ messages.set(outputId, {
271
+ id: outputId,
272
+ turnId: event.turnId,
273
+ role: "assistant",
274
+ content: stringField(event.data, "content") ?? current?.content ?? "",
275
+ status: "completed",
276
+ createdAt: current?.createdAt ?? event.createdAt,
277
+ eventId: event.id
278
+ });
279
+ continue;
280
+ }
281
+ if (event.type === "message.attempt_abandoned") {
282
+ messages.delete(outputId);
283
+ continue;
284
+ }
285
+ if (event.type === "turn.failed" || event.type === "turn.cancelled") {
286
+ const current = [...messages.values()].filter((message) => message.turnId === event.turnId && message.role === "assistant").at(-1);
287
+ const terminalId = current?.id ?? `${event.turnId}:assistant:${event.attempt}`;
288
+ messages.set(terminalId, {
289
+ id: terminalId,
290
+ turnId: event.turnId,
291
+ role: "assistant",
292
+ content: current?.content ?? "",
293
+ status: event.type === "turn.failed" ? "failed" : "cancelled",
294
+ createdAt: current?.createdAt ?? event.createdAt,
295
+ eventId: event.id
296
+ });
297
+ }
298
+ }
299
+ return [...messages.values()].sort((left, right) => left.eventId - right.eventId);
300
+ }
301
+ function reduceAgentToolCalls(events) {
302
+ const calls = /* @__PURE__ */ new Map();
303
+ for (const event of events) {
304
+ if (!event.turnId || !event.type.startsWith("tool.call.")) continue;
305
+ const eventName = stringField(event.data, "name");
306
+ const callId = stringField(event.data, "toolCallId") ?? `${event.turnId}:${event.attempt}:${eventName ?? "tool"}`;
307
+ const current = calls.get(callId);
308
+ const name = eventName ?? current?.name ?? "tool";
309
+ const summary = stringField(event.data, "summary");
310
+ const status = event.type === "tool.call.completed" ? "completed" : event.type === "tool.call.failed" ? "failed" : event.type === "tool.call.approval_required" ? "approval_required" : event.type === "tool.call.started" ? "running" : "proposed";
311
+ calls.set(callId, {
312
+ id: callId,
313
+ turnId: event.turnId,
314
+ name,
315
+ label: stringField(event.data, "label") ?? current?.label ?? name,
316
+ ...summary === void 0 ? current?.summary === void 0 ? {} : { summary: current.summary } : { summary },
317
+ status,
318
+ ...unknownField(event.data, "input") === void 0 ? current?.input === void 0 ? {} : { input: current.input } : { input: unknownField(event.data, "input") },
319
+ ...unknownField(event.data, "output") === void 0 ? current?.output === void 0 ? {} : { output: current.output } : { output: unknownField(event.data, "output") },
320
+ createdAt: current?.createdAt ?? event.createdAt,
321
+ eventId: event.id
322
+ });
323
+ }
324
+ return [...calls.values()].sort((left, right) => left.eventId - right.eventId);
325
+ }
326
+ var initialSessionState = {
327
+ status: "idle",
328
+ snapshot: null,
329
+ events: [],
330
+ messages: [],
331
+ toolCalls: [],
332
+ error: null
333
+ };
334
+ var SessionStore = class {
335
+ constructor(session) {
336
+ this.session = session;
337
+ }
338
+ session;
339
+ state = initialSessionState;
340
+ listeners = /* @__PURE__ */ new Set();
341
+ controller = null;
342
+ refreshTimer = null;
343
+ subscribe = (listener) => {
344
+ this.listeners.add(listener);
345
+ if (this.listeners.size === 1) void this.refresh();
346
+ return () => {
347
+ this.listeners.delete(listener);
348
+ if (this.listeners.size === 0) {
349
+ this.controller?.abort();
350
+ if (this.refreshTimer) clearTimeout(this.refreshTimer);
351
+ this.refreshTimer = null;
352
+ }
353
+ };
354
+ };
355
+ getSnapshot = () => this.state;
356
+ getServerSnapshot = () => initialSessionState;
357
+ setState(state) {
358
+ this.state = state;
359
+ for (const listener of this.listeners) listener();
360
+ }
361
+ scheduleRefresh() {
362
+ if (this.refreshTimer) clearTimeout(this.refreshTimer);
363
+ const isWorking = this.state.snapshot?.turns.some(
364
+ (turn) => turn.status === "queued" || turn.status === "running"
365
+ );
366
+ this.refreshTimer = isWorking && this.listeners.size > 0 ? setTimeout(() => void this.refresh(), 1e3) : null;
367
+ }
368
+ async refresh() {
369
+ this.controller?.abort();
370
+ this.controller = new AbortController();
371
+ const { signal } = this.controller;
372
+ this.setState({
373
+ ...this.state,
374
+ status: this.state.snapshot ? "ready" : "loading",
375
+ error: null
376
+ });
377
+ try {
378
+ const snapshot = await this.session.get({ signal });
379
+ const events = [];
380
+ let cursor = 0;
381
+ let hasMore = true;
382
+ let pages = 0;
383
+ while (hasMore && pages < 100) {
384
+ const page = await this.session.events(cursor, 100, { signal });
385
+ events.push(...page.events);
386
+ cursor = page.cursor;
387
+ hasMore = page.hasMore;
388
+ pages += 1;
389
+ }
390
+ if (hasMore) throw new Error("Conversation history exceeds the current 10,000-event UI limit");
391
+ this.setState({
392
+ status: "ready",
393
+ snapshot,
394
+ events,
395
+ messages: reduceAgentMessages(events),
396
+ toolCalls: reduceAgentToolCalls(events),
397
+ error: null
398
+ });
399
+ this.scheduleRefresh();
400
+ } catch (error) {
401
+ if (signal.aborted) return;
402
+ this.setState({
403
+ ...this.state,
404
+ status: "error",
405
+ error: error instanceof Error ? error : new Error(String(error))
406
+ });
407
+ this.scheduleRefresh();
408
+ }
409
+ }
410
+ dispose() {
411
+ this.controller?.abort();
412
+ if (this.refreshTimer) clearTimeout(this.refreshTimer);
413
+ this.refreshTimer = null;
414
+ }
415
+ };
416
+ function useAgentSession(sessionId) {
417
+ const context = useAgentContext();
418
+ const store = useMemo(() => {
419
+ const existing = context.stores.get(sessionId);
420
+ if (existing) return existing;
421
+ const created = new SessionStore(context.client.sessions.get(sessionId));
422
+ context.stores.set(sessionId, created);
423
+ return created;
424
+ }, [context.client, context.stores, sessionId]);
425
+ const state = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getServerSnapshot);
426
+ return {
427
+ ...state,
428
+ session: store.session,
429
+ refresh: () => store.refresh(),
430
+ submit: async (content, options) => {
431
+ const result = await store.session.submit(content, options);
432
+ await store.refresh();
433
+ return result;
434
+ },
435
+ cancel: async (turnId) => {
436
+ await store.session.cancel(turnId);
437
+ await store.refresh();
438
+ }
439
+ };
440
+ }
441
+ function useAgentMessages(sessionId) {
442
+ return useAgentSession(sessionId).messages;
443
+ }
444
+ function useAgentToolCalls(sessionId) {
445
+ return useAgentSession(sessionId).toolCalls;
446
+ }
447
+ function inlineMarkdown(text, colors) {
448
+ const nodes = [];
449
+ const pattern = /(\*\*[^*]+\*\*|`[^`]+`|\[[^\]]+\]\(https?:\/\/[^\s)]+\))/gu;
450
+ let cursor = 0;
451
+ for (const match of text.matchAll(pattern)) {
452
+ const index = match.index ?? 0;
453
+ if (index > cursor) nodes.push(text.slice(cursor, index));
454
+ const token = match[0];
455
+ if (token.startsWith("**")) {
456
+ nodes.push(/* @__PURE__ */ jsx("strong", { style: { fontWeight: 650 }, children: token.slice(2, -2) }, `${index}:strong`));
457
+ } else if (token.startsWith("`")) {
458
+ nodes.push(
459
+ /* @__PURE__ */ jsx(
460
+ "code",
461
+ {
462
+ style: {
463
+ padding: "1px 4px",
464
+ borderRadius: 4,
465
+ background: colors.well,
466
+ fontFamily: colors.monoFamily,
467
+ fontSize: 12
468
+ },
469
+ children: token.slice(1, -1)
470
+ },
471
+ `${index}:code`
472
+ )
473
+ );
474
+ } else {
475
+ const parts = /^\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)$/u.exec(token);
476
+ nodes.push(
477
+ /* @__PURE__ */ jsx(
478
+ "a",
479
+ {
480
+ href: parts?.[2],
481
+ target: "_blank",
482
+ rel: "noreferrer",
483
+ style: { color: colors.accent, textDecorationThickness: 1, textUnderlineOffset: 2 },
484
+ children: parts?.[1]
485
+ },
486
+ `${index}:link`
487
+ )
488
+ );
489
+ }
490
+ cursor = index + token.length;
491
+ }
492
+ if (cursor < text.length) nodes.push(text.slice(cursor));
493
+ return nodes;
494
+ }
495
+ function AgentMarkdown({ content, colors }) {
496
+ const lines = content.split("\n");
497
+ const blocks = [];
498
+ let index = 0;
499
+ while (index < lines.length) {
500
+ const line = lines[index] ?? "";
501
+ if (line.startsWith("```")) {
502
+ const language = line.slice(3).trim();
503
+ const code = [];
504
+ index += 1;
505
+ while (index < lines.length && !lines[index]?.startsWith("```")) {
506
+ code.push(lines[index] ?? "");
507
+ index += 1;
508
+ }
509
+ if (index < lines.length) index += 1;
510
+ blocks.push(
511
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", margin: "8px 0" }, children: [
512
+ language ? /* @__PURE__ */ jsx(
513
+ "span",
514
+ {
515
+ style: {
516
+ position: "absolute",
517
+ top: 7,
518
+ right: 9,
519
+ color: colors.inkTertiary,
520
+ fontFamily: colors.monoFamily,
521
+ fontSize: 10
522
+ },
523
+ children: language
524
+ }
525
+ ) : null,
526
+ /* @__PURE__ */ jsx(
527
+ "pre",
528
+ {
529
+ style: {
530
+ margin: 0,
531
+ padding: language ? "25px 12px 11px" : "11px 12px",
532
+ overflowX: "auto",
533
+ borderRadius: colors.wellRadius,
534
+ background: colors.well,
535
+ fontFamily: colors.monoFamily,
536
+ fontSize: 12,
537
+ lineHeight: 1.5
538
+ },
539
+ children: /* @__PURE__ */ jsx("code", { children: code.join("\n") })
540
+ }
541
+ )
542
+ ] }, `code:${index}`)
543
+ );
544
+ continue;
545
+ }
546
+ const heading = /^(#{1,3})\s+(.+)$/u.exec(line);
547
+ if (heading) {
548
+ const level = heading[1]?.length ?? 3;
549
+ blocks.push(
550
+ /* @__PURE__ */ jsx(
551
+ "div",
552
+ {
553
+ role: "heading",
554
+ "aria-level": level,
555
+ style: {
556
+ margin: index === 0 ? "0 0 6px" : "14px 0 6px",
557
+ fontSize: level === 1 ? 15 : 13,
558
+ fontWeight: level < 3 ? 650 : 550,
559
+ lineHeight: 1.35
560
+ },
561
+ children: inlineMarkdown(heading[2] ?? "", colors)
562
+ },
563
+ `heading:${index}`
564
+ )
565
+ );
566
+ index += 1;
567
+ continue;
568
+ }
569
+ if (/^[-*]\s+/u.test(line)) {
570
+ const items = [];
571
+ while (index < lines.length && /^[-*]\s+/u.test(lines[index] ?? "")) {
572
+ items.push((lines[index] ?? "").replace(/^[-*]\s+/u, ""));
573
+ index += 1;
574
+ }
575
+ blocks.push(
576
+ /* @__PURE__ */ jsx("ul", { style: { margin: "6px 0", paddingLeft: 19 }, children: items.map((item, itemIndex) => /* @__PURE__ */ jsx("li", { style: { margin: "3px 0", paddingLeft: 2 }, children: inlineMarkdown(item, colors) }, itemIndex)) }, `list:${index}`)
577
+ );
578
+ continue;
579
+ }
580
+ if (line.startsWith("> ")) {
581
+ const quote = [];
582
+ while (index < lines.length && (lines[index] ?? "").startsWith("> ")) {
583
+ quote.push((lines[index] ?? "").slice(2));
584
+ index += 1;
585
+ }
586
+ blocks.push(
587
+ /* @__PURE__ */ jsx(
588
+ "blockquote",
589
+ {
590
+ style: {
591
+ margin: "8px 0",
592
+ paddingLeft: 10,
593
+ borderLeft: `2px solid ${colors.hairline}`,
594
+ color: colors.inkSecondary
595
+ },
596
+ children: inlineMarkdown(quote.join("\n"), colors)
597
+ },
598
+ `quote:${index}`
599
+ )
600
+ );
601
+ continue;
602
+ }
603
+ if (!line.trim()) {
604
+ index += 1;
605
+ continue;
606
+ }
607
+ const paragraph = [line];
608
+ index += 1;
609
+ while (index < lines.length && (lines[index] ?? "").trim() && !/^(#{1,3})\s+|^```|^[-*]\s+|^> /u.test(lines[index] ?? "")) {
610
+ paragraph.push(lines[index] ?? "");
611
+ index += 1;
612
+ }
613
+ blocks.push(
614
+ /* @__PURE__ */ jsx("p", { style: { margin: "0 0 9px", whiteSpace: "pre-wrap" }, children: inlineMarkdown(paragraph.join("\n"), colors) }, `paragraph:${index}`)
615
+ );
616
+ }
617
+ return /* @__PURE__ */ jsx(Fragment, { children: blocks });
618
+ }
619
+ function AgentMessage({ message, className, style, theme, copy }) {
620
+ const context = useAgentContext();
621
+ const colors = withThemeOverrides(context.theme, theme);
622
+ const labels = { ...context.copy, ...copy };
623
+ const isUser = message.role === "user";
624
+ const fallback = message.status === "failed" ? labels.failed : message.status === "cancelled" ? labels.cancelled : labels.thinking;
625
+ return /* @__PURE__ */ jsx(
626
+ "article",
627
+ {
628
+ className,
629
+ "aria-label": isUser ? labels.userLabel : labels.assistantLabel,
630
+ style: {
631
+ alignSelf: isUser ? "flex-end" : "stretch",
632
+ maxWidth: isUser ? "min(82%, 620px)" : "100%",
633
+ color: message.status === "failed" ? colors.statusBad : colors.ink,
634
+ background: isUser ? colors.well : "transparent",
635
+ borderRadius: isUser ? colors.containerRadius : 0,
636
+ padding: isUser ? "8px 12px" : 0,
637
+ fontSize: 13,
638
+ lineHeight: 1.52,
639
+ whiteSpace: isUser ? "pre-wrap" : "normal",
640
+ overflowWrap: "anywhere",
641
+ ...style
642
+ },
643
+ children: message.content ? isUser ? message.content : /* @__PURE__ */ jsx(AgentMarkdown, { content: message.content, colors }) : fallback
644
+ }
645
+ );
646
+ }
647
+ function formatToolPayload(payload) {
648
+ if (typeof payload === "string") return payload;
649
+ try {
650
+ return JSON.stringify(payload, null, 2);
651
+ } catch {
652
+ return String(payload);
653
+ }
654
+ }
655
+ function humanizeToolName(name) {
656
+ const action = name.split(/[./:]/u).at(-1) ?? name;
657
+ const words = action.replace(/([a-z])([A-Z])/gu, "$1 $2").replace(/[_-]+/gu, " ").trim();
658
+ return words ? words[0]?.toUpperCase() + words.slice(1) : "Use tool";
659
+ }
660
+ function deriveToolSummary(input) {
661
+ if (!input || typeof input !== "object" || Array.isArray(input)) return void 0;
662
+ const entry = Object.entries(input).find(
663
+ ([, value2]) => typeof value2 === "string" || typeof value2 === "number"
664
+ );
665
+ if (!entry) return void 0;
666
+ const value = String(entry[1]);
667
+ return value.length > 42 ? `${value.slice(0, 39)}\u2026` : value;
668
+ }
669
+ function ToolActionGlyph({ name, color }) {
670
+ const normalized = name.toLowerCase();
671
+ if (normalized.includes("search") || normalized.includes("lookup") || normalized.includes("find")) {
672
+ return /* @__PURE__ */ jsxs("svg", { width: "11", height: "11", viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", children: [
673
+ /* @__PURE__ */ jsx("circle", { cx: "5", cy: "5", r: "3.25", stroke: color, strokeWidth: "1.2" }),
674
+ /* @__PURE__ */ jsx("path", { d: "m7.5 7.5 2.3 2.3", stroke: color, strokeWidth: "1.2", strokeLinecap: "round" })
675
+ ] });
676
+ }
677
+ if (normalized.includes("read") || normalized.includes("file") || normalized.includes("document")) {
678
+ return /* @__PURE__ */ jsxs("svg", { width: "11", height: "11", viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", children: [
679
+ /* @__PURE__ */ jsx("path", { d: "M3 1.5h4l2 2V10.5H3z", stroke: color, strokeWidth: "1.1", strokeLinejoin: "round" }),
680
+ /* @__PURE__ */ jsx("path", { d: "M7 1.8V4h2.1", stroke: color, strokeWidth: "1.1" })
681
+ ] });
682
+ }
683
+ return /* @__PURE__ */ jsx("svg", { width: "11", height: "11", viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M4.2 2.2 2.1 6l2.1 3.8M7.8 2.2 9.9 6 7.8 9.8", stroke: color, strokeWidth: "1.1", strokeLinecap: "round", strokeLinejoin: "round" }) });
684
+ }
685
+ function StatusGlyph({ status, colors }) {
686
+ if (status === "completed") {
687
+ return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { color: colors.statusGood, fontSize: 12 }, children: "\u2713" });
688
+ }
689
+ if (status === "failed") {
690
+ return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { color: colors.statusBad, fontSize: 13 }, children: "\xD7" });
691
+ }
692
+ if (status === "approval_required") {
693
+ return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { color: colors.statusWarn, fontSize: 11 }, children: "?" });
694
+ }
695
+ return /* @__PURE__ */ jsx(
696
+ "span",
697
+ {
698
+ "aria-hidden": "true",
699
+ style: {
700
+ width: 10,
701
+ height: 10,
702
+ border: `1.5px solid ${colors.hairline}`,
703
+ borderTopColor: colors.inkSecondary,
704
+ borderRadius: "50%"
705
+ }
706
+ }
707
+ );
708
+ }
709
+ function AgentToolCall({ toolCall, className, style, theme, copy }) {
710
+ const context = useAgentContext();
711
+ const colors = withThemeOverrides(context.theme, theme);
712
+ const labels = { ...context.copy, ...copy };
713
+ const [expanded, setExpanded] = useState(false);
714
+ const [hovered, setHovered] = useState(false);
715
+ const hasDetails = toolCall.input !== void 0 || toolCall.output !== void 0;
716
+ const title = toolCall.label === toolCall.name ? humanizeToolName(toolCall.name) : toolCall.label;
717
+ const summary = toolCall.summary ?? deriveToolSummary(toolCall.input);
718
+ const statusLabel = toolCall.status === "completed" ? labels.toolCompleted : toolCall.status === "failed" ? labels.toolFailed : toolCall.status === "approval_required" ? labels.toolApprovalRequired : labels.toolRunning;
719
+ return /* @__PURE__ */ jsxs("div", { className, style: { color: colors.inkSecondary, ...style }, children: [
720
+ /* @__PURE__ */ jsxs(
721
+ "button",
722
+ {
723
+ type: "button",
724
+ "aria-expanded": hasDetails ? expanded : void 0,
725
+ "aria-label": `${title}: ${statusLabel}`,
726
+ disabled: !hasDetails,
727
+ onClick: () => hasDetails && setExpanded((current) => !current),
728
+ onMouseEnter: () => setHovered(true),
729
+ onMouseLeave: () => setHovered(false),
730
+ onFocus: () => setHovered(true),
731
+ onBlur: () => setHovered(false),
732
+ style: {
733
+ display: "flex",
734
+ width: "100%",
735
+ minHeight: 28,
736
+ alignItems: "center",
737
+ gap: 7,
738
+ padding: "0 4px",
739
+ border: 0,
740
+ borderRadius: 6,
741
+ color: "inherit",
742
+ background: hovered ? colors.well : "transparent",
743
+ cursor: hasDetails ? "pointer" : "default",
744
+ font: "inherit",
745
+ textAlign: "left"
746
+ },
747
+ children: [
748
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { display: "grid", width: 12, placeItems: "center", flex: "0 0 12px" }, children: hovered && hasDetails ? /* @__PURE__ */ jsx("span", { style: { fontSize: 14, lineHeight: 1, transform: expanded ? "rotate(90deg)" : void 0 }, children: "\u203A" }) : /* @__PURE__ */ jsx(ToolActionGlyph, { name: toolCall.name, color: colors.inkSecondary }) }),
749
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 11, fontWeight: 550, lineHeight: 1.2 }, children: title }),
750
+ summary ? /* @__PURE__ */ jsx(
751
+ "span",
752
+ {
753
+ style: {
754
+ minWidth: 0,
755
+ maxWidth: "55%",
756
+ overflow: "hidden",
757
+ padding: "3px 6px",
758
+ borderRadius: 5,
759
+ background: colors.well,
760
+ color: colors.inkSecondary,
761
+ fontSize: 11,
762
+ lineHeight: 1,
763
+ textOverflow: "ellipsis",
764
+ whiteSpace: "nowrap"
765
+ },
766
+ children: summary
767
+ }
768
+ ) : null,
769
+ /* @__PURE__ */ jsx("span", { style: { flex: 1 } }),
770
+ /* @__PURE__ */ jsx("span", { style: { display: "grid", width: 16, minHeight: 24, placeItems: "center" }, children: /* @__PURE__ */ jsx(StatusGlyph, { status: toolCall.status, colors }) })
771
+ ]
772
+ }
773
+ ),
774
+ expanded && hasDetails ? /* @__PURE__ */ jsxs(
775
+ "div",
776
+ {
777
+ style: {
778
+ display: "grid",
779
+ gap: 8,
780
+ margin: "3px 0 7px 9px",
781
+ padding: "3px 0 3px 14px",
782
+ borderLeft: `1px solid ${colors.hairline}`,
783
+ color: colors.inkSecondary,
784
+ fontFamily: colors.monoFamily,
785
+ fontSize: 11,
786
+ lineHeight: 1.45
787
+ },
788
+ children: [
789
+ toolCall.input !== void 0 ? /* @__PURE__ */ jsxs("div", { children: [
790
+ /* @__PURE__ */ jsx("div", { style: { marginBottom: 2, color: colors.inkTertiary, fontFamily: colors.fontFamily }, children: "Input" }),
791
+ /* @__PURE__ */ jsx("pre", { style: { margin: 0, whiteSpace: "pre-wrap", overflowWrap: "anywhere", font: "inherit" }, children: formatToolPayload(toolCall.input) })
792
+ ] }) : null,
793
+ toolCall.output !== void 0 ? /* @__PURE__ */ jsxs("div", { children: [
794
+ /* @__PURE__ */ jsx("div", { style: { marginBottom: 2, color: colors.inkTertiary, fontFamily: colors.fontFamily }, children: "Output" }),
795
+ /* @__PURE__ */ jsx("pre", { style: { margin: 0, whiteSpace: "pre-wrap", overflowWrap: "anywhere", font: "inherit" }, children: formatToolPayload(toolCall.output) })
796
+ ] }) : null
797
+ ]
798
+ }
799
+ ) : null
800
+ ] });
801
+ }
802
+ function AgentMessageList({
803
+ messages,
804
+ toolCalls = [],
805
+ isWorking = false,
806
+ renderMessage,
807
+ renderToolCall,
808
+ className,
809
+ style,
810
+ theme,
811
+ copy
812
+ }) {
813
+ const context = useAgentContext();
814
+ const colors = withThemeOverrides(context.theme, theme);
815
+ const labels = { ...context.copy, ...copy };
816
+ const end = useRef(null);
817
+ const scrollSurface = useRef(null);
818
+ const atLiveEdge = useRef(true);
819
+ const transcript = [
820
+ ...messages.map((message) => ({ type: "message", item: message })),
821
+ ...toolCalls.map((toolCall) => ({ type: "tool", item: toolCall }))
822
+ ].sort((left, right) => left.item.eventId - right.item.eventId);
823
+ useEffect(() => {
824
+ if (atLiveEdge.current) end.current?.scrollIntoView({ block: "end" });
825
+ }, [messages, toolCalls, isWorking]);
826
+ return /* @__PURE__ */ jsxs(
827
+ "div",
828
+ {
829
+ className,
830
+ "aria-live": "polite",
831
+ ref: scrollSurface,
832
+ onScroll: () => {
833
+ const element = scrollSurface.current;
834
+ if (element) atLiveEdge.current = element.scrollHeight - element.scrollTop - element.clientHeight < 48;
835
+ },
836
+ style: {
837
+ display: "flex",
838
+ width: "100%",
839
+ maxWidth: colors.contentMaxWidth,
840
+ flex: 1,
841
+ flexDirection: "column",
842
+ alignSelf: "center",
843
+ gap: 16,
844
+ overflowY: "auto",
845
+ padding: "20px 24px 24px",
846
+ ...style
847
+ },
848
+ children: [
849
+ transcript.length === 0 && !isWorking ? /* @__PURE__ */ jsx("div", { style: { margin: "auto", color: colors.inkSecondary, fontSize: 13 }, children: labels.empty }) : null,
850
+ transcript.map((row) => {
851
+ if (row.type === "tool") {
852
+ return renderToolCall ? /* @__PURE__ */ jsx("div", { children: renderToolCall(row.item) }, `tool:${row.item.id}`) : /* @__PURE__ */ jsx(
853
+ AgentToolCall,
854
+ {
855
+ toolCall: row.item,
856
+ ...theme === void 0 ? {} : { theme },
857
+ ...copy === void 0 ? {} : { copy }
858
+ },
859
+ `tool:${row.item.id}`
860
+ );
861
+ }
862
+ return renderMessage ? /* @__PURE__ */ jsx("div", { children: renderMessage(row.item) }, `message:${row.item.id}`) : /* @__PURE__ */ jsx(
863
+ AgentMessage,
864
+ {
865
+ message: row.item,
866
+ ...theme === void 0 ? {} : { theme },
867
+ ...copy === void 0 ? {} : { copy }
868
+ },
869
+ `message:${row.item.id}`
870
+ );
871
+ }),
872
+ isWorking && !messages.some((message) => message.status === "streaming") ? /* @__PURE__ */ jsxs(
873
+ "div",
874
+ {
875
+ role: "status",
876
+ style: { display: "flex", alignItems: "center", gap: 7, color: colors.inkSecondary, fontSize: 11 },
877
+ children: [
878
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { color: colors.inkTertiary, fontSize: 10 }, children: "\u2726" }),
879
+ labels.thinking
880
+ ]
881
+ }
882
+ ) : null,
883
+ /* @__PURE__ */ jsx("div", { ref: end })
884
+ ]
885
+ }
886
+ );
887
+ }
888
+ function AgentComposer({
889
+ value,
890
+ onChange,
891
+ onSubmit,
892
+ disabled = false,
893
+ error,
894
+ leadingActions,
895
+ trailingActions,
896
+ onCancel,
897
+ className,
898
+ style,
899
+ theme,
900
+ copy
901
+ }) {
902
+ const context = useAgentContext();
903
+ const colors = withThemeOverrides(context.theme, theme);
904
+ const labels = { ...context.copy, ...copy };
905
+ const onKeyDown = (event) => {
906
+ if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
907
+ event.preventDefault();
908
+ if (value.trim() && !disabled) void onSubmit();
909
+ }
910
+ };
911
+ return /* @__PURE__ */ jsxs(
912
+ "div",
913
+ {
914
+ className,
915
+ style: {
916
+ width: "100%",
917
+ maxWidth: colors.contentMaxWidth,
918
+ margin: "0 auto",
919
+ padding: "16px 24px 10px",
920
+ ...style
921
+ },
922
+ children: [
923
+ /* @__PURE__ */ jsxs(
924
+ "div",
925
+ {
926
+ style: {
927
+ display: "grid",
928
+ gap: 8,
929
+ padding: "12px 10px 10px 14px",
930
+ background: colors.well,
931
+ border: `1px solid ${error ? colors.statusBad : colors.hairline}`,
932
+ borderRadius: 14
933
+ },
934
+ children: [
935
+ /* @__PURE__ */ jsx(
936
+ "textarea",
937
+ {
938
+ "aria-label": labels.placeholder,
939
+ rows: 1,
940
+ value,
941
+ disabled,
942
+ placeholder: disabled ? labels.sending : labels.placeholder,
943
+ onChange: (event) => onChange(event.target.value),
944
+ onKeyDown,
945
+ style: {
946
+ flex: 1,
947
+ width: "100%",
948
+ minHeight: 22,
949
+ maxHeight: 160,
950
+ resize: "vertical",
951
+ border: 0,
952
+ outline: 0,
953
+ padding: 0,
954
+ color: colors.ink,
955
+ background: "transparent",
956
+ fontFamily: colors.fontFamily,
957
+ fontSize: 13,
958
+ lineHeight: 1.45
959
+ }
960
+ }
961
+ ),
962
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", minHeight: 28, alignItems: "center", gap: 7 }, children: [
963
+ leadingActions,
964
+ /* @__PURE__ */ jsx("span", { style: { flex: 1 } }),
965
+ trailingActions,
966
+ /* @__PURE__ */ jsx(
967
+ "button",
968
+ {
969
+ type: "button",
970
+ "aria-label": disabled && onCancel ? "Stop agent" : labels.send,
971
+ title: disabled && onCancel ? "Stop agent" : labels.send,
972
+ disabled: disabled ? !onCancel : !value.trim(),
973
+ onClick: () => void (disabled && onCancel ? onCancel() : onSubmit()),
974
+ style: {
975
+ display: "grid",
976
+ width: 26,
977
+ height: 26,
978
+ placeItems: "center",
979
+ padding: 0,
980
+ border: 0,
981
+ borderRadius: "50%",
982
+ color: colors.canvas,
983
+ background: disabled && !onCancel ? colors.inkTertiary : colors.ink,
984
+ cursor: disabled && !onCancel ? "default" : !disabled && !value.trim() ? "default" : "pointer",
985
+ opacity: !disabled && !value.trim() ? 0.38 : 1
986
+ },
987
+ children: disabled && onCancel ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { width: 7, height: 7, borderRadius: 1, background: colors.canvas } }) : /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M6 9.5v-7M3.2 5.2 6 2.4l2.8 2.8", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round" }) })
988
+ }
989
+ )
990
+ ] })
991
+ ]
992
+ }
993
+ ),
994
+ error ? /* @__PURE__ */ jsx("div", { style: { color: colors.statusBad, fontSize: 11, padding: "7px 4px 0" }, children: error }) : null
995
+ ]
996
+ }
997
+ );
998
+ }
999
+ function AgentChat({
1000
+ sessionId,
1001
+ header,
1002
+ composerLeadingActions,
1003
+ composerTrailingActions,
1004
+ title,
1005
+ className,
1006
+ style,
1007
+ theme,
1008
+ copy,
1009
+ renderMessage,
1010
+ renderToolCall,
1011
+ onError
1012
+ }) {
1013
+ const context = useAgentContext();
1014
+ const colors = withThemeOverrides(context.theme, theme);
1015
+ const labels = { ...context.copy, ...copy };
1016
+ const session = useAgentSession(sessionId);
1017
+ const [draft, setDraft] = useState("");
1018
+ const [submitError, setSubmitError] = useState(null);
1019
+ const isWorking = session.snapshot?.turns.some((turn) => turn.status === "queued" || turn.status === "running") ?? false;
1020
+ const activeTurn = session.snapshot?.turns.find(
1021
+ (turn) => turn.status === "queued" || turn.status === "running"
1022
+ );
1023
+ const submit = async () => {
1024
+ const content = draft.trim();
1025
+ if (!content || isWorking) return;
1026
+ setDraft("");
1027
+ setSubmitError(null);
1028
+ try {
1029
+ await session.submit(content);
1030
+ } catch (error) {
1031
+ setDraft(content);
1032
+ const normalized = error instanceof Error ? error : new Error(String(error));
1033
+ setSubmitError(normalized.message);
1034
+ onError?.(normalized);
1035
+ }
1036
+ };
1037
+ return /* @__PURE__ */ jsxs(
1038
+ "section",
1039
+ {
1040
+ className,
1041
+ style: {
1042
+ display: "flex",
1043
+ width: "100%",
1044
+ minHeight: 480,
1045
+ height: "100%",
1046
+ flexDirection: "column",
1047
+ overflow: "hidden",
1048
+ color: colors.ink,
1049
+ background: colors.canvas,
1050
+ fontFamily: colors.fontFamily,
1051
+ fontSize: 13,
1052
+ ...style
1053
+ },
1054
+ children: [
1055
+ header ?? title ? /* @__PURE__ */ jsx(
1056
+ "header",
1057
+ {
1058
+ style: {
1059
+ width: "100%",
1060
+ maxWidth: colors.contentMaxWidth,
1061
+ margin: "0 auto",
1062
+ padding: "16px 24px 8px",
1063
+ color: colors.ink,
1064
+ fontSize: 15,
1065
+ fontWeight: 650
1066
+ },
1067
+ children: header ?? title
1068
+ }
1069
+ ) : null,
1070
+ /* @__PURE__ */ jsxs(
1071
+ "div",
1072
+ {
1073
+ style: {
1074
+ display: "flex",
1075
+ width: "100%",
1076
+ minHeight: 0,
1077
+ flex: 1,
1078
+ flexDirection: "column"
1079
+ },
1080
+ children: [
1081
+ session.status === "loading" && session.messages.length === 0 ? /* @__PURE__ */ jsx("div", { style: { margin: "auto", color: colors.inkSecondary, fontSize: 13 }, children: labels.loading }) : /* @__PURE__ */ jsx(
1082
+ AgentMessageList,
1083
+ {
1084
+ messages: session.messages,
1085
+ toolCalls: session.toolCalls,
1086
+ isWorking,
1087
+ ...renderMessage === void 0 ? {} : { renderMessage },
1088
+ ...renderToolCall === void 0 ? {} : { renderToolCall },
1089
+ ...theme === void 0 ? {} : { theme },
1090
+ ...copy === void 0 ? {} : { copy }
1091
+ }
1092
+ ),
1093
+ /* @__PURE__ */ jsx(
1094
+ "div",
1095
+ {
1096
+ style: {
1097
+ flex: "0 0 auto",
1098
+ background: `linear-gradient(to bottom, transparent 0, ${colors.canvas} 18%)`
1099
+ },
1100
+ children: /* @__PURE__ */ jsx(
1101
+ AgentComposer,
1102
+ {
1103
+ value: draft,
1104
+ onChange: setDraft,
1105
+ onSubmit: submit,
1106
+ disabled: isWorking,
1107
+ error: submitError ?? session.error?.message ?? null,
1108
+ leadingActions: composerLeadingActions,
1109
+ trailingActions: composerTrailingActions,
1110
+ ...activeTurn ? { onCancel: () => session.cancel(activeTurn.id) } : {},
1111
+ ...theme === void 0 ? {} : { theme },
1112
+ ...copy === void 0 ? {} : { copy }
1113
+ }
1114
+ )
1115
+ }
1116
+ )
1117
+ ]
1118
+ }
1119
+ )
1120
+ ]
1121
+ }
1122
+ );
1123
+ }
1124
+ export {
1125
+ AgentChat,
1126
+ AgentComposer,
1127
+ AgentMessage,
1128
+ AgentMessageList,
1129
+ AgentProvider,
1130
+ AgentToolCall,
1131
+ agentThemeVariables,
1132
+ createAgentAppearance,
1133
+ createAgentClient,
1134
+ createBrowserClient,
1135
+ defaultAgentCopy,
1136
+ paperAppearance,
1137
+ paperDarkAppearance,
1138
+ paperDarkTheme,
1139
+ paperLightTheme,
1140
+ reduceAgentMessages,
1141
+ reduceAgentToolCalls,
1142
+ useAgentClient,
1143
+ useAgentCopy,
1144
+ useAgentMessages,
1145
+ useAgentSession,
1146
+ useAgentTheme,
1147
+ useAgentToolCalls
1148
+ };