@agno-hq/chat-react 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/index.js ADDED
@@ -0,0 +1,1928 @@
1
+ 'use client';
2
+ import { useMemo, useState, useRef, useEffect, useCallback } from 'react';
3
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
+
5
+ // src/useAgnoChat.ts
6
+
7
+ // src/stream.ts
8
+ function isEnvelope(data) {
9
+ return typeof data === "object" && data !== null && "event" in data && "data" in data && typeof data.event === "string";
10
+ }
11
+ function isFlatEvent(data) {
12
+ return typeof data === "object" && data !== null && "event" in data && !("data" in data) && typeof data.event === "string";
13
+ }
14
+ function normaliseEnvelope(env) {
15
+ let parsed = {};
16
+ if (typeof env.data === "string") {
17
+ try {
18
+ parsed = JSON.parse(env.data);
19
+ } catch {
20
+ parsed = {};
21
+ }
22
+ } else if (env.data && typeof env.data === "object") {
23
+ parsed = env.data;
24
+ }
25
+ return { event: env.event, ...parsed };
26
+ }
27
+ function drainBuffer(buffer, onEvent) {
28
+ let start = buffer.indexOf("{");
29
+ while (start !== -1 && start < buffer.length) {
30
+ let depth = 0;
31
+ let inString = false;
32
+ let escape = false;
33
+ let end = -1;
34
+ for (let i = start; i < buffer.length; i++) {
35
+ const ch = buffer[i];
36
+ if (inString) {
37
+ if (escape) escape = false;
38
+ else if (ch === "\\") escape = true;
39
+ else if (ch === '"') inString = false;
40
+ } else if (ch === '"') {
41
+ inString = true;
42
+ } else if (ch === "{") {
43
+ depth++;
44
+ } else if (ch === "}") {
45
+ depth--;
46
+ if (depth === 0) {
47
+ end = i;
48
+ break;
49
+ }
50
+ }
51
+ }
52
+ if (end === -1) break;
53
+ const slice = buffer.slice(start, end + 1);
54
+ try {
55
+ const parsed = JSON.parse(slice);
56
+ if (isEnvelope(parsed)) onEvent(normaliseEnvelope(parsed));
57
+ else if (isFlatEvent(parsed)) onEvent(parsed);
58
+ } catch {
59
+ start = buffer.indexOf("{", start + 1);
60
+ continue;
61
+ }
62
+ buffer = buffer.slice(end + 1).trim();
63
+ start = buffer.indexOf("{");
64
+ }
65
+ return buffer;
66
+ }
67
+ async function streamRun(options) {
68
+ const { url, body, headers = {}, signal, onEvent, onError, onComplete } = options;
69
+ let buffer = "";
70
+ try {
71
+ const response = await fetch(url, {
72
+ method: "POST",
73
+ headers: {
74
+ ...!(body instanceof FormData) && { "Content-Type": "application/json" },
75
+ ...headers
76
+ },
77
+ body: body instanceof FormData ? body : JSON.stringify(body),
78
+ signal
79
+ });
80
+ if (!response.ok) {
81
+ let detail;
82
+ try {
83
+ const err = await response.json();
84
+ detail = err?.detail ? String(err.detail) : `${response.status} ${response.statusText}`;
85
+ } catch {
86
+ detail = `${response.status} ${response.statusText}`;
87
+ }
88
+ throw new Error(detail);
89
+ }
90
+ if (!response.body) throw new Error("No response body");
91
+ const reader = response.body.getReader();
92
+ const decoder = new TextDecoder();
93
+ for (; ; ) {
94
+ const { done, value } = await reader.read();
95
+ if (done) {
96
+ buffer = drainBuffer(buffer, onEvent);
97
+ onComplete();
98
+ return;
99
+ }
100
+ buffer += decoder.decode(value, { stream: true });
101
+ buffer = drainBuffer(buffer, onEvent);
102
+ }
103
+ } catch (error) {
104
+ if (error instanceof DOMException && error.name === "AbortError") {
105
+ onComplete();
106
+ return;
107
+ }
108
+ onError(error instanceof Error ? error : new Error(String(error)));
109
+ }
110
+ }
111
+
112
+ // src/client.ts
113
+ function normaliseBaseUrl(value) {
114
+ if (!value) return "";
115
+ let url = value.trim();
116
+ if (!/^https?:\/\//.test(url)) {
117
+ const isLocal = url.startsWith("localhost") || /^\d{1,3}(\.\d{1,3}){3}/.test(url);
118
+ url = `${isLocal ? "http" : "https"}://${url}`;
119
+ }
120
+ return url.replace(/\/+$/, "");
121
+ }
122
+ var RUN_PATH = {
123
+ agent: "agents",
124
+ team: "teams",
125
+ workflow: "workflows"
126
+ };
127
+ var AgnoClient = class {
128
+ constructor(options) {
129
+ this.baseUrl = normaliseBaseUrl(options.baseUrl);
130
+ this.headers = options.headers ?? {};
131
+ this.dbId = options.dbId;
132
+ }
133
+ async getJson(path) {
134
+ const res = await fetch(`${this.baseUrl}${path}`, { headers: this.headers });
135
+ if (!res.ok) throw new Error(`GET ${path} failed: ${res.status} ${res.statusText}`);
136
+ return res.json();
137
+ }
138
+ /** Liveness check against /health. Returns the HTTP status code. */
139
+ async health() {
140
+ try {
141
+ const res = await fetch(`${this.baseUrl}/health`, { headers: this.headers });
142
+ return res.status;
143
+ } catch {
144
+ return 0;
145
+ }
146
+ }
147
+ /* ----------------------------- discovery ----------------------------- */
148
+ async getAgents() {
149
+ const data = await this.getJson("/agents").catch(() => []);
150
+ return data.map((a) => ({
151
+ type: "agent",
152
+ id: a.agent_id ?? a.id,
153
+ name: a.name ?? a.agent_id ?? a.id,
154
+ description: a.description,
155
+ model: a.model,
156
+ db_id: a.db_id
157
+ }));
158
+ }
159
+ async getTeams() {
160
+ const data = await this.getJson("/teams").catch(() => []);
161
+ return data.map((t) => ({
162
+ type: "team",
163
+ id: t.team_id ?? t.id,
164
+ name: t.name ?? t.team_id ?? t.id,
165
+ description: t.description,
166
+ model: t.model,
167
+ db_id: t.db_id
168
+ }));
169
+ }
170
+ async getWorkflows() {
171
+ const data = await this.getJson("/workflows").catch(() => []);
172
+ return data.map((w) => ({
173
+ type: "workflow",
174
+ id: w.workflow_id ?? w.id,
175
+ name: w.name ?? w.workflow_id ?? w.id,
176
+ description: w.description,
177
+ model: w.model,
178
+ db_id: w.db_id
179
+ }));
180
+ }
181
+ /** All runnable entities (agents, teams, workflows) in one list. */
182
+ async getEntities() {
183
+ const [agents, teams, workflows] = await Promise.all([
184
+ this.getAgents(),
185
+ this.getTeams(),
186
+ this.getWorkflows()
187
+ ]);
188
+ return [...agents, ...teams, ...workflows];
189
+ }
190
+ /* ------------------------------ sessions ----------------------------- */
191
+ async getSessions(type, componentId, dbId) {
192
+ const url = new URL(`${this.baseUrl}/sessions`);
193
+ url.searchParams.set("type", type);
194
+ url.searchParams.set("component_id", componentId);
195
+ const db = dbId ?? this.dbId;
196
+ if (db) url.searchParams.set("db_id", db);
197
+ try {
198
+ const res = await fetch(url.toString(), { headers: this.headers });
199
+ if (!res.ok) return { data: [] };
200
+ return await res.json();
201
+ } catch {
202
+ return { data: [] };
203
+ }
204
+ }
205
+ /** Runs (with messages/tools/events) for a session — used to rehydrate chat history. */
206
+ async getSessionRuns(type, sessionId, dbId) {
207
+ const url = new URL(`${this.baseUrl}/sessions/${sessionId}/runs`);
208
+ url.searchParams.set("type", type);
209
+ const db = dbId ?? this.dbId;
210
+ if (db) url.searchParams.set("db_id", db);
211
+ const res = await fetch(url.toString(), { headers: this.headers });
212
+ if (!res.ok) throw new Error(`Failed to load session: ${res.statusText}`);
213
+ return res.json();
214
+ }
215
+ async deleteSession(sessionId, dbId) {
216
+ const url = new URL(`${this.baseUrl}/sessions/${sessionId}`);
217
+ const db = dbId ?? this.dbId;
218
+ if (db) url.searchParams.set("db_id", db);
219
+ const res = await fetch(url.toString(), { method: "DELETE", headers: this.headers });
220
+ return res.ok;
221
+ }
222
+ /* -------------------------------- runs ------------------------------- */
223
+ /** Start a streaming run for an agent, team or workflow. */
224
+ async run(args) {
225
+ const form = new FormData();
226
+ if (args.message != null) form.append("message", args.message);
227
+ form.append("stream", "true");
228
+ if (args.sessionId) form.append("session_id", args.sessionId);
229
+ if (args.userId) form.append("user_id", args.userId);
230
+ for (const file of args.files ?? []) form.append("files", file);
231
+ for (const [k, v] of Object.entries(args.extra ?? {})) form.append(k, v);
232
+ const url = `${this.baseUrl}/${RUN_PATH[args.type]}/${args.id}/runs`;
233
+ return streamRun({
234
+ url,
235
+ body: form,
236
+ headers: this.headers,
237
+ signal: args.signal,
238
+ onEvent: (e) => args.onEvent(e),
239
+ onError: args.onError,
240
+ onComplete: args.onComplete
241
+ });
242
+ }
243
+ /** Continue a paused run (resolving a human-in-the-loop requirement). */
244
+ async continueRun(args) {
245
+ const form = new FormData();
246
+ form.append("stream", "true");
247
+ if (args.sessionId) form.append("session_id", args.sessionId);
248
+ if (args.userId) form.append("user_id", args.userId);
249
+ if (args.type === "workflow") {
250
+ if (args.stepRequirements) form.append("step_requirements", JSON.stringify(args.stepRequirements));
251
+ } else if (args.tools) {
252
+ form.append("tools", JSON.stringify(args.tools));
253
+ }
254
+ const url = `${this.baseUrl}/${RUN_PATH[args.type]}/${args.id}/runs/${args.runId}/continue`;
255
+ return streamRun({
256
+ url,
257
+ body: form,
258
+ headers: this.headers,
259
+ signal: args.signal,
260
+ onEvent: (e) => args.onEvent(e),
261
+ onError: args.onError,
262
+ onComplete: args.onComplete
263
+ });
264
+ }
265
+ /** Cancel an in-flight run. */
266
+ async cancelRun(type, id2, runId, sessionId) {
267
+ const url = new URL(`${this.baseUrl}/${RUN_PATH[type]}/${id2}/runs/${runId}/cancel`);
268
+ if (sessionId) url.searchParams.set("session_id", sessionId);
269
+ try {
270
+ const res = await fetch(url.toString(), { method: "POST", headers: this.headers });
271
+ return res.ok;
272
+ } catch {
273
+ return false;
274
+ }
275
+ }
276
+ };
277
+
278
+ // src/events.ts
279
+ var name = (e) => String(e.event ?? "");
280
+ var isStartedEvent = (e) => name(e) === "RunStarted" || name(e) === "TeamRunStarted" || name(e) === "WorkflowStarted" || name(e) === "ReasoningStarted" || name(e) === "TeamReasoningStarted";
281
+ var isContentEvent = (e) => name(e) === "RunContent" || name(e) === "TeamRunContent" || name(e) === "WorkflowAgentCompleted";
282
+ var isCompletedEvent = (e) => name(e) === "RunCompleted" || name(e) === "TeamRunCompleted" || name(e) === "WorkflowCompleted";
283
+ var isErrorEvent = (e) => name(e) === "RunError" || name(e) === "TeamRunError" || name(e) === "WorkflowError" || name(e) === "StepError" || name(e) === "ToolCallError" || name(e) === "TeamToolCallError";
284
+ var isCancelledEvent = (e) => name(e) === "RunCancelled" || name(e) === "TeamRunCancelled" || name(e) === "WorkflowCancelled";
285
+ var isPausedEvent = (e) => name(e) === "RunPaused" || name(e) === "TeamRunPaused" || name(e) === "WorkflowPaused" || name(e) === "StepPaused" || name(e) === "RouterPaused" || name(e) === "ConditionPaused";
286
+ var isToolStartedEvent = (e) => name(e) === "ToolCallStarted" || name(e) === "TeamToolCallStarted";
287
+ var isToolCompletedEvent = (e) => name(e) === "ToolCallCompleted" || name(e) === "TeamToolCallCompleted";
288
+ var isToolEvent = (e) => isToolStartedEvent(e) || isToolCompletedEvent(e) || name(e) === "ToolCallError" || name(e) === "TeamToolCallError";
289
+ var isReasoningStepEvent = (e) => name(e) === "ReasoningStep" || name(e) === "TeamReasoningStep";
290
+ var isReasoningCompletedEvent = (e) => name(e) === "ReasoningCompleted" || name(e) === "TeamReasoningCompleted";
291
+ function isSubRunEvent(e) {
292
+ if (!e.parent_run_id) return false;
293
+ const ev = name(e);
294
+ return isContentEvent(e) || isToolEvent(e) || isCompletedEvent(e) || isErrorEvent(e) || ev === "RunStarted" || ev === "TeamRunStarted";
295
+ }
296
+ function isStepEvent(e) {
297
+ const ev = name(e);
298
+ return ev === "StepStarted" || ev === "StepCompleted" || ev === "StepOutput" || ev === "StepError";
299
+ }
300
+ function toolsFromEvent(e) {
301
+ const out = [];
302
+ if (e.tool) out.push(e.tool);
303
+ if (Array.isArray(e.tools)) out.push(...e.tools);
304
+ return out;
305
+ }
306
+ function activityLabel(e) {
307
+ const ev = name(e);
308
+ switch (ev) {
309
+ case "RunStarted":
310
+ case "TeamRunStarted":
311
+ case "WorkflowStarted":
312
+ return "Thinking";
313
+ case "ModelRequestStarted":
314
+ case "TeamModelRequestStarted":
315
+ return "Generating";
316
+ case "ReasoningStarted":
317
+ case "TeamReasoningStarted":
318
+ case "ReasoningStep":
319
+ case "TeamReasoningStep":
320
+ case "ReasoningContentDelta":
321
+ case "TeamReasoningContentDelta":
322
+ return "Reasoning";
323
+ case "MemoryUpdateStarted":
324
+ case "TeamMemoryUpdateStarted":
325
+ return "Updating memory";
326
+ case "SessionSummaryStarted":
327
+ case "TeamSessionSummaryStarted":
328
+ return "Summarising session";
329
+ case "CompressionStarted":
330
+ return "Compressing context";
331
+ case "ToolCallStarted":
332
+ case "TeamToolCallStarted": {
333
+ const tool = e.tool?.tool_name;
334
+ return tool ? `Calling ${tool}` : "Calling tool";
335
+ }
336
+ case "ToolCallCompleted":
337
+ case "TeamToolCallCompleted":
338
+ return "Generating";
339
+ case "StepStarted":
340
+ return e.step_name ? `Running step: ${e.step_name}` : "Running step";
341
+ case "LoopIterationStarted":
342
+ return `Loop iteration ${e.iteration ?? ""}`.trim();
343
+ case "ParallelExecutionStarted":
344
+ return "Running parallel steps";
345
+ case "RouterExecutionStarted":
346
+ return "Routing";
347
+ case "ConditionExecutionStarted":
348
+ return "Evaluating condition";
349
+ default:
350
+ return null;
351
+ }
352
+ }
353
+ function textOf(value) {
354
+ if (typeof value === "string") return value;
355
+ if (value && typeof value === "object") return "```json\n" + JSON.stringify(value, null, 2) + "\n```";
356
+ return void 0;
357
+ }
358
+ function applySubRunEvent(message, e, kind) {
359
+ const rid = e.run_id || e.parent_run_id || "sub";
360
+ const members = message.members ? [...message.members] : [];
361
+ const idx = members.findIndex((s) => s.run_id === rid);
362
+ const base = idx >= 0 ? { ...members[idx] } : { run_id: rid, kind, content: "", status: "running" };
363
+ base.name = base.name || e.agent_name || e.team_name || e.agent_id;
364
+ const tools = toolsFromEvent(e);
365
+ if (tools.length) {
366
+ let tc = base.tool_calls ?? [];
367
+ for (const t of tools) tc = mergeTool(tc, t);
368
+ base.tool_calls = tc;
369
+ }
370
+ if (isErrorEvent(e)) {
371
+ base.status = "error";
372
+ } else if (isCompletedEvent(e)) {
373
+ base.status = "completed";
374
+ const final = textOf(e.content);
375
+ if (final) base.content = final;
376
+ } else if (isContentEvent(e)) {
377
+ const delta = typeof e.content === "string" ? e.content : "";
378
+ if (delta) base.content += delta;
379
+ }
380
+ if (idx >= 0) members[idx] = base;
381
+ else members.push(base);
382
+ return { ...message, members };
383
+ }
384
+ function applyStepEvent(message, e) {
385
+ const ev = name(e);
386
+ const key = e.step_name || `step-${JSON.stringify(e.step_index ?? "")}`;
387
+ const steps = message.steps ? [...message.steps] : [];
388
+ const idx = steps.findIndex((s) => s.key === key);
389
+ const step = idx >= 0 ? { ...steps[idx] } : { key, name: e.step_name, index: e.step_index, status: "running" };
390
+ if (ev === "StepStarted") {
391
+ step.status = "running";
392
+ } else if (ev === "StepError") {
393
+ step.status = "error";
394
+ step.error = e.error || (typeof e.content === "string" ? e.content : void 0);
395
+ } else {
396
+ step.status = "completed";
397
+ const stepResponse = e.step_response ?? e.step_output;
398
+ const content = textOf(e.content) ?? textOf(stepResponse?.content);
399
+ if (content) step.content = content;
400
+ }
401
+ if (idx >= 0) steps[idx] = step;
402
+ else steps.push(step);
403
+ return { ...message, steps };
404
+ }
405
+ function mergeTool(list, tool) {
406
+ const key = tool.tool_call_id || `${tool.tool_name}-${tool.created_at}`;
407
+ const idx = list.findIndex((t) => {
408
+ if (t.tool_call_id && tool.tool_call_id) return t.tool_call_id === tool.tool_call_id;
409
+ return `${t.tool_name}-${t.created_at}` === key;
410
+ });
411
+ if (idx >= 0) {
412
+ const next = [...list];
413
+ next[idx] = { ...next[idx], ...tool };
414
+ return next;
415
+ }
416
+ return [...list, tool];
417
+ }
418
+
419
+ // src/session.ts
420
+ function toText(value) {
421
+ if (value == null) return "";
422
+ if (typeof value === "string") return value;
423
+ if (Array.isArray(value)) {
424
+ return value.map(
425
+ (part) => part && typeof part === "object" && "text" in part ? String(part.text) : ""
426
+ ).filter(Boolean).join(" ");
427
+ }
428
+ if (typeof value === "object") {
429
+ const obj = value;
430
+ if (typeof obj.input_content === "string") return obj.input_content;
431
+ if (typeof obj.message === "string") return obj.message;
432
+ if (typeof obj.content === "string") return obj.content;
433
+ return "```json\n" + JSON.stringify(value, null, 2) + "\n```";
434
+ }
435
+ return String(value);
436
+ }
437
+ var seq = 0;
438
+ var id = (prefix) => `${prefix}-${seq++}`;
439
+ function sessionRunsToMessages(runs) {
440
+ if (!Array.isArray(runs)) return [];
441
+ const messages = [];
442
+ for (const run of runs) {
443
+ const created = run.created_at ?? Math.floor(Date.now() / 1e3);
444
+ const userContent = toText(run.run_input);
445
+ if (userContent) {
446
+ messages.push({
447
+ id: id("hist-u"),
448
+ role: "user",
449
+ content: userContent,
450
+ created_at: created
451
+ });
452
+ }
453
+ messages.push({
454
+ id: id("hist-a"),
455
+ role: "agent",
456
+ content: toText(run.content),
457
+ created_at: created,
458
+ status: "completed",
459
+ run_id: run.run_id,
460
+ session_id: run.session_id,
461
+ tool_calls: run.tools && run.tools.length ? run.tools : void 0,
462
+ reasoning_steps: run.reasoning_steps ?? run.extra_data?.reasoning_steps,
463
+ references: run.references ?? run.extra_data?.references,
464
+ images: run.images,
465
+ videos: run.videos,
466
+ audio: run.audio,
467
+ response_audio: run.response_audio
468
+ });
469
+ }
470
+ return messages;
471
+ }
472
+
473
+ // src/useAgnoChat.ts
474
+ var messageCounter = 0;
475
+ var nextId = () => `m${Date.now().toString(36)}-${(messageCounter++).toString(36)}`;
476
+ var nowSeconds = () => Math.floor(Date.now() / 1e3);
477
+ function useAgnoChat(options) {
478
+ const { entity, userId, onEvent, onSessionId } = options;
479
+ const client = useMemo(() => {
480
+ if (options.client) return options.client;
481
+ return new AgnoClient({ baseUrl: options.baseUrl ?? "", headers: options.headers });
482
+ }, [options.client, options.baseUrl, JSON.stringify(options.headers)]);
483
+ const [messages, setMessages] = useState(options.initialMessages ?? []);
484
+ const [events, setEvents] = useState([]);
485
+ const [currentEvent, setCurrentEvent] = useState(null);
486
+ const [status, setStatus] = useState("idle");
487
+ const [activity, setActivity] = useState(null);
488
+ const [error, setError] = useState(null);
489
+ const [sessionId, setSessionId] = useState(options.sessionId);
490
+ const [sessions, setSessions] = useState([]);
491
+ const [sessionsLoading, setSessionsLoading] = useState(false);
492
+ const abortRef = useRef(null);
493
+ const activeMsgIdRef = useRef(null);
494
+ const lastContentRef = useRef("");
495
+ const runIdRef = useRef(void 0);
496
+ const entityRef = useRef(entity);
497
+ const sessionIdRef = useRef(options.sessionId);
498
+ useEffect(() => {
499
+ entityRef.current = entity;
500
+ }, [entity]);
501
+ useEffect(() => {
502
+ sessionIdRef.current = sessionId;
503
+ }, [sessionId]);
504
+ const patchActive = useCallback((patch) => {
505
+ const id2 = activeMsgIdRef.current;
506
+ if (!id2) return;
507
+ setMessages((prev) => prev.map((m) => m.id === id2 ? patch(m) : m));
508
+ }, []);
509
+ const applyEvent = useCallback(
510
+ (e) => {
511
+ setEvents((prev) => [...prev, e]);
512
+ setCurrentEvent(e);
513
+ onEvent?.(e);
514
+ const label2 = activityLabel(e);
515
+ if (label2) setActivity(label2);
516
+ if (e.session_id && e.session_id !== sessionIdRef.current) {
517
+ sessionIdRef.current = e.session_id;
518
+ setSessionId(e.session_id);
519
+ onSessionId?.(e.session_id);
520
+ }
521
+ if (e.run_id && !e.parent_run_id) runIdRef.current = e.run_id;
522
+ if (isSubRunEvent(e)) {
523
+ const kind = entityRef.current?.type === "workflow" ? "executor" : "member";
524
+ patchActive((m) => applySubRunEvent(m, e, kind));
525
+ return;
526
+ }
527
+ if (isStepEvent(e)) {
528
+ patchActive((m) => applyStepEvent(m, e));
529
+ return;
530
+ }
531
+ if (isStartedEvent(e)) {
532
+ patchActive((m) => ({ ...m, run_id: e.run_id ?? m.run_id, session_id: e.session_id ?? m.session_id, status: "streaming" }));
533
+ return;
534
+ }
535
+ if (isToolEvent(e)) {
536
+ const incoming = toolsFromEvent(e);
537
+ if (incoming.length) {
538
+ patchActive((m) => {
539
+ let tool_calls = m.tool_calls ?? [];
540
+ for (const t of incoming) tool_calls = mergeTool(tool_calls, t);
541
+ return { ...m, tool_calls };
542
+ });
543
+ }
544
+ return;
545
+ }
546
+ if (isContentEvent(e)) {
547
+ patchActive((m) => {
548
+ const next = { ...m };
549
+ if (typeof e.content === "string" && e.content) {
550
+ const unique = e.content.startsWith(lastContentRef.current) ? e.content.slice(lastContentRef.current.length) : e.content;
551
+ next.content = (m.content ?? "") + unique;
552
+ lastContentRef.current = e.content.length >= lastContentRef.current.length ? e.content : lastContentRef.current;
553
+ } else if (e.content && typeof e.content === "object") {
554
+ next.content = (m.content ?? "") + "\n```json\n" + JSON.stringify(e.content, null, 2) + "\n```\n";
555
+ }
556
+ if (e.reasoning_steps?.length) next.reasoning_steps = e.reasoning_steps;
557
+ if (e.extra_data?.reasoning_steps?.length) next.reasoning_steps = e.extra_data.reasoning_steps;
558
+ if (e.references?.length) next.references = e.references;
559
+ if (e.extra_data?.references?.length) next.references = e.extra_data.references;
560
+ if (e.citations) next.citations = e.citations;
561
+ const tools = toolsFromEvent(e);
562
+ if (tools.length) {
563
+ let tc = m.tool_calls ?? [];
564
+ for (const t of tools) tc = mergeTool(tc, t);
565
+ next.tool_calls = tc;
566
+ }
567
+ if (e.images?.length) next.images = e.images;
568
+ if (e.videos?.length) next.videos = e.videos;
569
+ if (e.audio?.length) next.audio = e.audio;
570
+ if (e.response_audio?.transcript) {
571
+ next.response_audio = {
572
+ ...m.response_audio,
573
+ transcript: (m.response_audio?.transcript ?? "") + e.response_audio.transcript
574
+ };
575
+ }
576
+ return next;
577
+ });
578
+ return;
579
+ }
580
+ if (isReasoningStepEvent(e)) {
581
+ const incoming = e.reasoning_steps ?? e.extra_data?.reasoning_steps ?? [];
582
+ if (incoming.length) {
583
+ patchActive((m) => ({
584
+ ...m,
585
+ reasoning_steps: [...m.reasoning_steps ?? [], ...incoming]
586
+ }));
587
+ }
588
+ return;
589
+ }
590
+ if (isReasoningCompletedEvent(e)) {
591
+ const steps = e.reasoning_steps ?? e.extra_data?.reasoning_steps;
592
+ if (steps?.length) patchActive((m) => ({ ...m, reasoning_steps: steps }));
593
+ return;
594
+ }
595
+ if (isPausedEvent(e)) {
596
+ const requirements = e.requirements ?? [];
597
+ const pausedTools2 = toolsFromEvent(e);
598
+ setStatus("paused");
599
+ setActivity("Waiting for input");
600
+ patchActive((m) => {
601
+ let tool_calls = m.tool_calls ?? [];
602
+ for (const t of pausedTools2) tool_calls = mergeTool(tool_calls, t);
603
+ return { ...m, status: "paused", streaming: false, requirements, tool_calls };
604
+ });
605
+ return;
606
+ }
607
+ if (isCompletedEvent(e)) {
608
+ patchActive((m) => {
609
+ const next = { ...m, streaming: false, status: "completed" };
610
+ if (typeof e.content === "string" && e.content) next.content = e.content;
611
+ const tools = toolsFromEvent(e);
612
+ if (tools.length) {
613
+ let tc = m.tool_calls ?? [];
614
+ for (const t of tools) tc = mergeTool(tc, t);
615
+ next.tool_calls = tc;
616
+ }
617
+ if (e.reasoning_steps?.length) next.reasoning_steps = e.reasoning_steps;
618
+ if (e.references?.length) next.references = e.references;
619
+ if (e.images?.length) next.images = e.images;
620
+ if (e.videos?.length) next.videos = e.videos;
621
+ if (e.audio?.length) next.audio = e.audio;
622
+ if (e.response_audio) next.response_audio = e.response_audio;
623
+ return next;
624
+ });
625
+ return;
626
+ }
627
+ if (isCancelledEvent(e)) {
628
+ patchActive((m) => ({ ...m, streaming: false, status: "cancelled" }));
629
+ setStatus("cancelled");
630
+ return;
631
+ }
632
+ if (isErrorEvent(e)) {
633
+ const msg = typeof e.content === "string" ? e.content : e.error || "Error during run";
634
+ patchActive((m) => ({ ...m, streaming: false, status: "error", error: msg }));
635
+ setError(msg);
636
+ setStatus("error");
637
+ return;
638
+ }
639
+ },
640
+ [onEvent, onSessionId, patchActive]
641
+ );
642
+ const drive = useCallback(
643
+ async (starter) => {
644
+ const controller = new AbortController();
645
+ abortRef.current = controller;
646
+ setError(null);
647
+ setStatus("streaming");
648
+ lastContentRef.current = "";
649
+ await starter({
650
+ signal: controller.signal,
651
+ onEvent: applyEvent,
652
+ onError: (err) => {
653
+ patchActive((m) => ({ ...m, streaming: false, status: "error", error: err.message }));
654
+ setError(err.message);
655
+ setStatus("error");
656
+ },
657
+ onComplete: () => {
658
+ setActivity(null);
659
+ patchActive((m) => m.streaming ? { ...m, streaming: false } : m);
660
+ setStatus((s) => s === "streaming" ? "completed" : s);
661
+ }
662
+ });
663
+ abortRef.current = null;
664
+ },
665
+ [applyEvent, patchActive]
666
+ );
667
+ const sendMessage = useCallback(
668
+ async (message, sendOptions) => {
669
+ const ent = entityRef.current;
670
+ if (!ent) {
671
+ setError("No agent, team or workflow selected.");
672
+ return;
673
+ }
674
+ const userMsg = {
675
+ id: nextId(),
676
+ role: "user",
677
+ content: message,
678
+ created_at: nowSeconds()
679
+ };
680
+ const agentMsg = {
681
+ id: nextId(),
682
+ role: "agent",
683
+ content: "",
684
+ created_at: nowSeconds() + 1,
685
+ streaming: true,
686
+ status: "streaming",
687
+ tool_calls: [],
688
+ events: []
689
+ };
690
+ activeMsgIdRef.current = agentMsg.id;
691
+ setEvents([]);
692
+ setCurrentEvent(null);
693
+ setMessages((prev) => [...prev, userMsg, agentMsg]);
694
+ await drive(
695
+ (cb) => client.run({
696
+ type: ent.type,
697
+ id: ent.id,
698
+ message,
699
+ sessionId: sessionIdRef.current,
700
+ userId,
701
+ files: sendOptions?.files,
702
+ ...cb
703
+ })
704
+ );
705
+ },
706
+ [client, drive, userId]
707
+ );
708
+ const continueRun = useCallback(
709
+ async (resolution) => {
710
+ const ent = entityRef.current;
711
+ const runId = runIdRef.current;
712
+ if (!ent || !runId) {
713
+ setError("No paused run to continue.");
714
+ return;
715
+ }
716
+ patchActive((m) => ({ ...m, streaming: true, status: "streaming", requirements: void 0 }));
717
+ await drive(
718
+ (cb) => client.continueRun({
719
+ type: ent.type,
720
+ id: ent.id,
721
+ runId,
722
+ sessionId: sessionIdRef.current,
723
+ userId,
724
+ tools: resolution.tools,
725
+ stepRequirements: resolution.stepRequirements,
726
+ ...cb
727
+ })
728
+ );
729
+ },
730
+ [client, drive, patchActive, userId]
731
+ );
732
+ const activeMessage = useMemo(
733
+ () => messages.find((m) => m.id === activeMsgIdRef.current) ?? null,
734
+ [messages]
735
+ );
736
+ const pausedTools = useMemo(
737
+ () => (activeMessage?.tool_calls ?? []).filter((t) => t.requires_confirmation || t.requires_user_input),
738
+ [activeMessage]
739
+ );
740
+ const respondToConfirmation = useCallback(
741
+ async (approve) => {
742
+ const ent = entityRef.current;
743
+ if (ent?.type === "workflow") {
744
+ const reqs = (activeMessage?.requirements ?? []).map((r) => ({ ...r, confirmation: approve }));
745
+ await continueRun({ stepRequirements: reqs });
746
+ return;
747
+ }
748
+ const resolved = pausedTools.map((t) => ({ ...t, confirmed: approve }));
749
+ await continueRun({ tools: resolved });
750
+ },
751
+ [activeMessage, continueRun, pausedTools]
752
+ );
753
+ const submitUserInput = useCallback(
754
+ async (values) => {
755
+ const ent = entityRef.current;
756
+ if (ent?.type === "workflow") {
757
+ const reqs = (activeMessage?.requirements ?? []).map((r) => ({
758
+ ...r,
759
+ user_input_schema: (r.user_input_schema ?? []).map((f) => ({
760
+ ...f,
761
+ value: f.name in values ? values[f.name] : f.value
762
+ }))
763
+ }));
764
+ await continueRun({ stepRequirements: reqs });
765
+ return;
766
+ }
767
+ const resolved = pausedTools.map((t) => ({
768
+ ...t,
769
+ confirmed: true,
770
+ user_input_schema: (t.user_input_schema ?? []).map((f) => ({
771
+ ...f,
772
+ value: f.name in values ? values[f.name] : f.value
773
+ }))
774
+ }));
775
+ await continueRun({ tools: resolved });
776
+ },
777
+ [activeMessage, continueRun, pausedTools]
778
+ );
779
+ const cancel = useCallback(async () => {
780
+ abortRef.current?.abort();
781
+ const ent = entityRef.current;
782
+ const runId = runIdRef.current;
783
+ setStatus("cancelled");
784
+ setActivity(null);
785
+ patchActive((m) => m.streaming ? { ...m, streaming: false, status: "cancelled" } : m);
786
+ if (ent && runId) await client.cancelRun(ent.type, ent.id, runId, sessionIdRef.current);
787
+ }, [client, patchActive]);
788
+ const refreshSessions = useCallback(async () => {
789
+ const ent = entityRef.current;
790
+ if (!ent) {
791
+ setSessions([]);
792
+ return;
793
+ }
794
+ setSessionsLoading(true);
795
+ try {
796
+ const res = await client.getSessions(ent.type, ent.id, ent.db_id);
797
+ setSessions(res.data ?? []);
798
+ } finally {
799
+ setSessionsLoading(false);
800
+ }
801
+ }, [client]);
802
+ const loadSession = useCallback(
803
+ async (id2) => {
804
+ const ent = entityRef.current;
805
+ if (!ent) return;
806
+ abortRef.current?.abort();
807
+ activeMsgIdRef.current = null;
808
+ runIdRef.current = void 0;
809
+ lastContentRef.current = "";
810
+ setEvents([]);
811
+ setCurrentEvent(null);
812
+ setStatus("idle");
813
+ setActivity(null);
814
+ setError(null);
815
+ sessionIdRef.current = id2;
816
+ setSessionId(id2);
817
+ onSessionId?.(id2);
818
+ try {
819
+ const runs = await client.getSessionRuns(ent.type, id2, ent.db_id);
820
+ setMessages(sessionRunsToMessages(runs));
821
+ } catch (err) {
822
+ setError(err instanceof Error ? err.message : String(err));
823
+ }
824
+ },
825
+ [client, onSessionId]
826
+ );
827
+ const deleteSession = useCallback(
828
+ async (id2) => {
829
+ const ent = entityRef.current;
830
+ const ok = await client.deleteSession(id2, ent?.db_id);
831
+ if (ok) {
832
+ setSessions((prev) => prev.filter((s) => s.session_id !== id2));
833
+ if (sessionIdRef.current === id2) {
834
+ sessionIdRef.current = void 0;
835
+ setSessionId(void 0);
836
+ setMessages([]);
837
+ }
838
+ }
839
+ },
840
+ [client]
841
+ );
842
+ const reset = useCallback(() => {
843
+ abortRef.current?.abort();
844
+ abortRef.current = null;
845
+ activeMsgIdRef.current = null;
846
+ runIdRef.current = void 0;
847
+ lastContentRef.current = "";
848
+ sessionIdRef.current = void 0;
849
+ setMessages([]);
850
+ setEvents([]);
851
+ setCurrentEvent(null);
852
+ setStatus("idle");
853
+ setActivity(null);
854
+ setError(null);
855
+ setSessionId(void 0);
856
+ }, []);
857
+ useEffect(() => () => abortRef.current?.abort(), []);
858
+ const streamingMessage = useMemo(
859
+ () => messages.find((m) => m.role === "agent" && m.streaming) ?? null,
860
+ [messages]
861
+ );
862
+ return {
863
+ messages,
864
+ streamingMessage,
865
+ events,
866
+ currentEvent,
867
+ status,
868
+ activity,
869
+ isStreaming: status === "streaming",
870
+ isPaused: status === "paused",
871
+ error,
872
+ sessionId,
873
+ entityType: entity?.type,
874
+ tools: activeMessage?.tool_calls ?? [],
875
+ reasoning: activeMessage?.reasoning_steps,
876
+ pendingRequirements: activeMessage?.requirements ?? [],
877
+ sessions,
878
+ sessionsLoading,
879
+ sendMessage,
880
+ cancel,
881
+ continueRun,
882
+ respondToConfirmation,
883
+ submitUserInput,
884
+ refreshSessions,
885
+ loadSession,
886
+ deleteSession,
887
+ reset,
888
+ setMessages,
889
+ client
890
+ };
891
+ }
892
+ function ChatInput({
893
+ onSend,
894
+ onStop,
895
+ disabled,
896
+ busy,
897
+ placeholder = "Ask anything",
898
+ allowFiles = false
899
+ }) {
900
+ const [value, setValue] = useState("");
901
+ const [files, setFiles] = useState([]);
902
+ const fileRef = useRef(null);
903
+ const submit = () => {
904
+ const text = value.trim();
905
+ if (!text && files.length === 0) return;
906
+ onSend(text, files.length ? files : void 0);
907
+ setValue("");
908
+ setFiles([]);
909
+ };
910
+ return /* @__PURE__ */ jsxs("div", { className: "agno-input", children: [
911
+ files.length > 0 && /* @__PURE__ */ jsx("div", { className: "agno-input__files", children: files.map((f, i) => /* @__PURE__ */ jsxs("span", { className: "agno-input__file", children: [
912
+ f.name,
913
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setFiles((prev) => prev.filter((_, j) => j !== i)), "aria-label": "Remove", children: "\xD7" })
914
+ ] }, i)) }),
915
+ /* @__PURE__ */ jsxs("div", { className: "agno-input__row", children: [
916
+ allowFiles && /* @__PURE__ */ jsxs(Fragment, { children: [
917
+ /* @__PURE__ */ jsx(
918
+ "button",
919
+ {
920
+ type: "button",
921
+ className: "agno-input__attach",
922
+ onClick: () => fileRef.current?.click(),
923
+ disabled,
924
+ "aria-label": "Attach files",
925
+ children: "\u{1F4CE}"
926
+ }
927
+ ),
928
+ /* @__PURE__ */ jsx(
929
+ "input",
930
+ {
931
+ ref: fileRef,
932
+ type: "file",
933
+ multiple: true,
934
+ hidden: true,
935
+ onChange: (e) => setFiles((prev) => [...prev, ...Array.from(e.target.files ?? [])])
936
+ }
937
+ )
938
+ ] }),
939
+ /* @__PURE__ */ jsx(
940
+ "textarea",
941
+ {
942
+ className: "agno-input__textarea",
943
+ value,
944
+ placeholder,
945
+ disabled,
946
+ rows: 1,
947
+ onChange: (e) => setValue(e.target.value),
948
+ onKeyDown: (e) => {
949
+ if (e.key === "Enter" && !e.shiftKey) {
950
+ e.preventDefault();
951
+ submit();
952
+ }
953
+ }
954
+ }
955
+ ),
956
+ busy && onStop ? /* @__PURE__ */ jsx("button", { type: "button", className: "agno-input__send agno-input__send--stop", onClick: onStop, "aria-label": "Stop", children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\u25A0" }) }) : /* @__PURE__ */ jsx(
957
+ "button",
958
+ {
959
+ type: "button",
960
+ className: "agno-input__send",
961
+ onClick: submit,
962
+ disabled: disabled || !value.trim() && files.length === 0,
963
+ "aria-label": "Send",
964
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\u27A4" })
965
+ }
966
+ )
967
+ ] })
968
+ ] });
969
+ }
970
+ var isBoolField = (f) => f.field_type === "bool" || f.field_type === "boolean";
971
+ function buildAsks(message, entityType) {
972
+ const fromTools = (message.tool_calls ?? []).filter((t) => t.requires_confirmation || t.requires_user_input).map((t) => ({
973
+ id: t.tool_call_id ?? `${t.tool_name}`,
974
+ name: t.tool_name,
975
+ args: t.tool_args,
976
+ needsConfirmation: Boolean(t.requires_confirmation) && t.confirmed == null,
977
+ fields: t.requires_user_input ? t.user_input_schema ?? [] : [],
978
+ tool: t
979
+ }));
980
+ const fromReqs = (message.requirements ?? []).map((r) => ({
981
+ id: r.id,
982
+ name: r.tool_execution?.tool_name,
983
+ args: r.tool_execution?.tool_args,
984
+ needsConfirmation: Boolean(r.tool_execution?.requires_confirmation) || r.confirmation == null,
985
+ fields: r.user_input_schema ?? r.tool_execution?.user_input_schema ?? [],
986
+ requirement: r
987
+ }));
988
+ if (entityType === "workflow") return fromReqs.length ? fromReqs : fromTools;
989
+ return fromTools.length ? fromTools : fromReqs;
990
+ }
991
+ function HumanInput({ message, entityType, busy, onResolve }) {
992
+ const asks = useMemo(() => buildAsks(message, entityType), [message, entityType]);
993
+ const [choices, setChoices] = useState({});
994
+ const [values, setValues] = useState({});
995
+ const [reasons, setReasons] = useState({});
996
+ const [openArgs, setOpenArgs] = useState({});
997
+ if (asks.length === 0) return null;
998
+ const setValue = (id2, name2, value) => setValues((v) => ({ ...v, [id2]: { ...v[id2] ?? {}, [name2]: value } }));
999
+ const valueFor = (ask, field) => values[ask.id]?.[field.name] ?? field.value ?? (isBoolField(field) ? false : "");
1000
+ const fillFields = (ask) => ask.fields.map((f) => ({ ...f, value: valueFor(ask, f) }));
1001
+ const ready = asks.every((a) => !a.needsConfirmation || choices[a.id]);
1002
+ const submit = () => {
1003
+ if (entityType === "workflow") {
1004
+ const stepRequirements = asks.map((a) => {
1005
+ const approved = a.needsConfirmation ? choices[a.id] === "confirm" : true;
1006
+ return {
1007
+ id: a.id,
1008
+ confirmation: approved,
1009
+ ...a.fields.length ? { user_input_schema: fillFields(a) } : {},
1010
+ tool_execution: a.requirement?.tool_execution,
1011
+ ...reasons[a.id] ? { confirmation_note: reasons[a.id] } : {}
1012
+ };
1013
+ });
1014
+ onResolve({ stepRequirements });
1015
+ return;
1016
+ }
1017
+ const tools = asks.map((a) => {
1018
+ const base = a.tool ?? { tool_call_id: a.id, tool_name: a.name };
1019
+ const approved = a.needsConfirmation ? choices[a.id] === "confirm" : true;
1020
+ return {
1021
+ ...base,
1022
+ ...a.needsConfirmation ? { confirmed: approved } : {},
1023
+ ...a.fields.length ? { answered: true, user_input_schema: fillFields(a) } : {},
1024
+ ...reasons[a.id] ? { confirmation_note: reasons[a.id] } : {}
1025
+ };
1026
+ });
1027
+ onResolve({ tools });
1028
+ };
1029
+ return /* @__PURE__ */ jsxs("div", { className: "agno-hitl", children: [
1030
+ /* @__PURE__ */ jsxs("div", { className: "agno-hitl__title", children: [
1031
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\u270B" }),
1032
+ " Your input is needed"
1033
+ ] }),
1034
+ asks.map((ask) => {
1035
+ const choice = choices[ask.id];
1036
+ const hasArgs = ask.args && Object.keys(ask.args).length > 0;
1037
+ const argsOpen = openArgs[ask.id] ?? true;
1038
+ return /* @__PURE__ */ jsxs("div", { className: "agno-hitl-card", children: [
1039
+ /* @__PURE__ */ jsxs("div", { className: "agno-hitl-card__head", children: [
1040
+ /* @__PURE__ */ jsxs("span", { className: "agno-hitl-card__tool", children: [
1041
+ /* @__PURE__ */ jsx("span", { className: "agno-hitl-card__icon", "aria-hidden": true, children: "\u{1F527}" }),
1042
+ ask.name ?? "tool"
1043
+ ] }),
1044
+ ask.needsConfirmation && /* @__PURE__ */ jsxs("span", { className: "agno-hitl-card__choices", children: [
1045
+ /* @__PURE__ */ jsx(
1046
+ "button",
1047
+ {
1048
+ type: "button",
1049
+ className: `agno-hitl-card__choice ${choice === "reject" ? "is-active is-reject" : ""}`,
1050
+ "aria-label": "Reject",
1051
+ disabled: busy,
1052
+ onClick: () => setChoices((c) => ({ ...c, [ask.id]: "reject" })),
1053
+ children: "\u2715"
1054
+ }
1055
+ ),
1056
+ /* @__PURE__ */ jsx(
1057
+ "button",
1058
+ {
1059
+ type: "button",
1060
+ className: `agno-hitl-card__choice ${choice === "confirm" ? "is-active is-confirm" : ""}`,
1061
+ "aria-label": "Approve",
1062
+ disabled: busy,
1063
+ onClick: () => setChoices((c) => ({ ...c, [ask.id]: "confirm" })),
1064
+ children: "\u2713"
1065
+ }
1066
+ )
1067
+ ] })
1068
+ ] }),
1069
+ hasArgs && /* @__PURE__ */ jsxs("div", { className: "agno-hitl-card__args", children: [
1070
+ /* @__PURE__ */ jsxs(
1071
+ "button",
1072
+ {
1073
+ type: "button",
1074
+ className: "agno-hitl-card__args-head",
1075
+ onClick: () => setOpenArgs((o) => ({ ...o, [ask.id]: !argsOpen })),
1076
+ children: [
1077
+ "Arguments",
1078
+ /* @__PURE__ */ jsx("span", { className: "agno-hitl-card__chev", children: argsOpen ? "\u25B2" : "\u25BC" })
1079
+ ]
1080
+ }
1081
+ ),
1082
+ argsOpen && /* @__PURE__ */ jsx("div", { className: "agno-hitl-card__args-body", children: Object.entries(ask.args ?? {}).map(([k, v]) => /* @__PURE__ */ jsxs("div", { className: "agno-hitl-card__arg", children: [
1083
+ /* @__PURE__ */ jsx("span", { className: "agno-hitl-card__arg-key", children: k }),
1084
+ /* @__PURE__ */ jsx("span", { className: "agno-hitl-card__arg-val", children: typeof v === "object" ? JSON.stringify(v) : String(v) })
1085
+ ] }, k)) })
1086
+ ] }),
1087
+ choice === "reject" && /* @__PURE__ */ jsx(
1088
+ "textarea",
1089
+ {
1090
+ className: "agno-hitl-card__reason",
1091
+ placeholder: "Reason for rejection (optional)\u2026",
1092
+ rows: 2,
1093
+ value: reasons[ask.id] ?? "",
1094
+ disabled: busy,
1095
+ onChange: (e) => setReasons((r) => ({ ...r, [ask.id]: e.target.value }))
1096
+ }
1097
+ ),
1098
+ ask.fields.length > 0 && /* @__PURE__ */ jsx("div", { className: "agno-hitl-card__fields", children: ask.fields.map((field) => /* @__PURE__ */ jsxs("label", { className: `agno-hitl-card__field ${isBoolField(field) ? "is-bool" : ""}`, children: [
1099
+ /* @__PURE__ */ jsx("span", { className: "agno-hitl-card__field-name", children: field.description || field.name }),
1100
+ isBoolField(field) ? /* @__PURE__ */ jsx(
1101
+ "input",
1102
+ {
1103
+ type: "checkbox",
1104
+ checked: Boolean(valueFor(ask, field)),
1105
+ disabled: busy,
1106
+ onChange: (e) => setValue(ask.id, field.name, e.target.checked)
1107
+ }
1108
+ ) : /* @__PURE__ */ jsx(
1109
+ "input",
1110
+ {
1111
+ className: "agno-hitl-card__input",
1112
+ value: String(valueFor(ask, field) ?? ""),
1113
+ placeholder: field.field_type ?? "text",
1114
+ disabled: busy,
1115
+ onChange: (e) => setValue(ask.id, field.name, e.target.value)
1116
+ }
1117
+ )
1118
+ ] }, field.name)) })
1119
+ ] }, ask.id);
1120
+ }),
1121
+ /* @__PURE__ */ jsx("div", { className: "agno-hitl__actions", children: /* @__PURE__ */ jsx("button", { type: "button", className: "agno-btn agno-btn--primary", disabled: busy || !ready, onClick: submit, children: "Continue" }) })
1122
+ ] });
1123
+ }
1124
+ function Citations({
1125
+ references,
1126
+ citations
1127
+ }) {
1128
+ const [open, setOpen] = useState(false);
1129
+ const refCount = references?.reduce((n, r) => n + (r.references?.length ?? 0), 0) ?? 0;
1130
+ const urls = citations?.urls ?? [];
1131
+ const total = refCount + urls.length;
1132
+ if (total === 0) return null;
1133
+ return /* @__PURE__ */ jsxs("div", { className: "agno-citations", children: [
1134
+ /* @__PURE__ */ jsxs("button", { type: "button", className: "agno-citations__toggle", onClick: () => setOpen((v) => !v), children: [
1135
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\u{1F4DA}" }),
1136
+ " ",
1137
+ total,
1138
+ " source",
1139
+ total > 1 ? "s" : "",
1140
+ /* @__PURE__ */ jsx("span", { className: "agno-citations__chev", children: open ? "\u25B2" : "\u25BC" })
1141
+ ] }),
1142
+ open && /* @__PURE__ */ jsxs("div", { className: "agno-citations__body", children: [
1143
+ references?.map(
1144
+ (group, gi) => (group.references ?? []).map((ref, ri) => /* @__PURE__ */ jsxs("div", { className: "agno-citations__item", children: [
1145
+ /* @__PURE__ */ jsx("div", { className: "agno-citations__name", children: ref.name ?? "reference" }),
1146
+ /* @__PURE__ */ jsx("div", { className: "agno-citations__snippet", children: ref.content })
1147
+ ] }, `r-${gi}-${ri}`))
1148
+ ),
1149
+ urls.map((u, i) => /* @__PURE__ */ jsx(
1150
+ "a",
1151
+ {
1152
+ className: "agno-citations__url",
1153
+ href: u.url,
1154
+ target: "_blank",
1155
+ rel: "noreferrer noopener",
1156
+ children: u.title ?? u.url
1157
+ },
1158
+ `u-${i}`
1159
+ ))
1160
+ ] })
1161
+ ] });
1162
+ }
1163
+ function renderInline(text, keyPrefix) {
1164
+ const nodes = [];
1165
+ const regex = /(`[^`]+`)|(\*\*[^*]+\*\*)|(\*[^*]+\*)|(\[[^\]]+\]\([^)]+\))/g;
1166
+ let last = 0;
1167
+ let match;
1168
+ let i = 0;
1169
+ while ((match = regex.exec(text)) !== null) {
1170
+ if (match.index > last) nodes.push(text.slice(last, match.index));
1171
+ const token = match[0];
1172
+ const key = `${keyPrefix}-${i++}`;
1173
+ if (token.startsWith("`")) {
1174
+ nodes.push(/* @__PURE__ */ jsx("code", { className: "agno-md-code", children: token.slice(1, -1) }, key));
1175
+ } else if (token.startsWith("**")) {
1176
+ nodes.push(/* @__PURE__ */ jsx("strong", { children: token.slice(2, -2) }, key));
1177
+ } else if (token.startsWith("*")) {
1178
+ nodes.push(/* @__PURE__ */ jsx("em", { children: token.slice(1, -1) }, key));
1179
+ } else {
1180
+ const m = /\[([^\]]+)\]\(([^)]+)\)/.exec(token);
1181
+ if (m) {
1182
+ nodes.push(
1183
+ /* @__PURE__ */ jsx("a", { href: m[2], target: "_blank", rel: "noreferrer noopener", children: m[1] }, key)
1184
+ );
1185
+ } else {
1186
+ nodes.push(token);
1187
+ }
1188
+ }
1189
+ last = match.index + token.length;
1190
+ }
1191
+ if (last < text.length) nodes.push(text.slice(last));
1192
+ return nodes;
1193
+ }
1194
+ function Markdown({ content, className }) {
1195
+ const blocks = [];
1196
+ const segments = content.split(/(```[\s\S]*?```)/g);
1197
+ segments.forEach((segment, si) => {
1198
+ if (segment.startsWith("```")) {
1199
+ const body = segment.replace(/^```[^\n]*\n?/, "").replace(/```$/, "");
1200
+ blocks.push(
1201
+ /* @__PURE__ */ jsx("pre", { className: "agno-md-pre", children: /* @__PURE__ */ jsx("code", { children: body }) }, `pre-${si}`)
1202
+ );
1203
+ return;
1204
+ }
1205
+ const lines = segment.split("\n");
1206
+ let listBuffer = [];
1207
+ const flushList = (key) => {
1208
+ if (!listBuffer.length) return;
1209
+ blocks.push(
1210
+ /* @__PURE__ */ jsx("ul", { className: "agno-md-list", children: listBuffer.map((item, ii) => /* @__PURE__ */ jsx("li", { children: renderInline(item, `${key}-${ii}`) }, ii)) }, key)
1211
+ );
1212
+ listBuffer = [];
1213
+ };
1214
+ lines.forEach((line, li) => {
1215
+ const key = `${si}-${li}`;
1216
+ const heading = /^(#{1,4})\s+(.*)$/.exec(line);
1217
+ const listItem = /^\s*[-*]\s+(.*)$/.exec(line);
1218
+ if (listItem) {
1219
+ listBuffer.push(listItem[1]);
1220
+ return;
1221
+ }
1222
+ flushList(`ul-${key}`);
1223
+ if (heading) {
1224
+ const level = heading[1].length;
1225
+ const Tag = `h${Math.min(level + 1, 6)}`;
1226
+ blocks.push(
1227
+ /* @__PURE__ */ jsx(Tag, { className: "agno-md-heading", children: renderInline(heading[2], `h-${key}`) }, `h-${key}`)
1228
+ );
1229
+ } else if (line.trim() === "") ; else {
1230
+ blocks.push(
1231
+ /* @__PURE__ */ jsx("p", { className: "agno-md-p", children: renderInline(line, `p-${key}`) }, `p-${key}`)
1232
+ );
1233
+ }
1234
+ });
1235
+ flushList(`ul-end-${si}`);
1236
+ });
1237
+ return /* @__PURE__ */ jsx("div", { className: ["agno-md", className].filter(Boolean).join(" "), children: blocks });
1238
+ }
1239
+ function statusOf(tool) {
1240
+ if (tool.tool_call_error) return { label: "error", cls: "error" };
1241
+ if (tool.requires_confirmation && tool.confirmed == null) return { label: "awaiting approval", cls: "paused" };
1242
+ if (tool.requires_user_input && !tool.answered) return { label: "awaiting input", cls: "paused" };
1243
+ if (tool.result != null) return { label: "done", cls: "done" };
1244
+ return { label: "running", cls: "running" };
1245
+ }
1246
+ function ToolCall({ tool }) {
1247
+ const [open, setOpen] = useState(false);
1248
+ const status = statusOf(tool);
1249
+ const hasDetail = Boolean(tool.tool_args && Object.keys(tool.tool_args).length) || tool.result != null;
1250
+ return /* @__PURE__ */ jsxs("div", { className: `agno-tool agno-tool--${status.cls}`, children: [
1251
+ /* @__PURE__ */ jsxs(
1252
+ "button",
1253
+ {
1254
+ type: "button",
1255
+ className: "agno-tool__head",
1256
+ onClick: () => hasDetail && setOpen((v) => !v),
1257
+ "aria-expanded": open,
1258
+ children: [
1259
+ /* @__PURE__ */ jsx("span", { className: "agno-tool__icon", "aria-hidden": true, children: "\u{1F527}" }),
1260
+ /* @__PURE__ */ jsx("span", { className: "agno-tool__name", children: tool.tool_name ?? "tool" }),
1261
+ /* @__PURE__ */ jsx("span", { className: `agno-tool__status agno-tool__status--${status.cls}`, children: status.label }),
1262
+ hasDetail && /* @__PURE__ */ jsx("span", { className: "agno-tool__chev", children: open ? "\u25B2" : "\u25BC" })
1263
+ ]
1264
+ }
1265
+ ),
1266
+ open && hasDetail && /* @__PURE__ */ jsxs("div", { className: "agno-tool__body", children: [
1267
+ tool.tool_args && Object.keys(tool.tool_args).length > 0 && /* @__PURE__ */ jsxs("div", { className: "agno-tool__section", children: [
1268
+ /* @__PURE__ */ jsx("div", { className: "agno-tool__label", children: "Arguments" }),
1269
+ /* @__PURE__ */ jsx("pre", { className: "agno-tool__pre", children: JSON.stringify(tool.tool_args, null, 2) })
1270
+ ] }),
1271
+ tool.result != null && /* @__PURE__ */ jsxs("div", { className: "agno-tool__section", children: [
1272
+ /* @__PURE__ */ jsx("div", { className: "agno-tool__label", children: "Result" }),
1273
+ /* @__PURE__ */ jsx("pre", { className: "agno-tool__pre", children: String(tool.result) })
1274
+ ] })
1275
+ ] })
1276
+ ] });
1277
+ }
1278
+ function ToolCalls({ tools }) {
1279
+ if (!tools || tools.length === 0) return null;
1280
+ return /* @__PURE__ */ jsx("div", { className: "agno-tools", children: tools.map((tool, i) => /* @__PURE__ */ jsx(ToolCall, { tool }, tool.tool_call_id ?? `${tool.tool_name}-${i}`)) });
1281
+ }
1282
+ function statusDot(status) {
1283
+ if (status === "error") return "error";
1284
+ if (status === "completed") return "done";
1285
+ return "running";
1286
+ }
1287
+ function MemberCard({ member, renderMarkdown }) {
1288
+ const [open, setOpen] = useState(true);
1289
+ const label2 = member.kind === "executor" ? "Step executor" : "Member";
1290
+ return /* @__PURE__ */ jsxs("div", { className: "agno-member", children: [
1291
+ /* @__PURE__ */ jsxs("button", { type: "button", className: "agno-member__head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
1292
+ /* @__PURE__ */ jsx("span", { className: `agno-member__dot agno-member__dot--${statusDot(member.status)}`, "aria-hidden": true }),
1293
+ /* @__PURE__ */ jsx("span", { className: "agno-member__name", children: member.name ?? member.agent_id ?? label2 }),
1294
+ /* @__PURE__ */ jsx("span", { className: "agno-member__kind", children: label2 }),
1295
+ /* @__PURE__ */ jsx("span", { className: "agno-member__chev", children: open ? "\u25B2" : "\u25BC" })
1296
+ ] }),
1297
+ open && /* @__PURE__ */ jsxs("div", { className: "agno-member__body", children: [
1298
+ /* @__PURE__ */ jsx(ToolCalls, { tools: member.tool_calls }),
1299
+ member.content && /* @__PURE__ */ jsx("div", { className: "agno-member__content", children: renderMarkdown ? renderMarkdown(member.content) : /* @__PURE__ */ jsx(Markdown, { content: member.content }) })
1300
+ ] })
1301
+ ] });
1302
+ }
1303
+ function MemberResponses({
1304
+ members,
1305
+ renderMarkdown,
1306
+ title = "Member responses"
1307
+ }) {
1308
+ if (!members || members.length === 0) return null;
1309
+ return /* @__PURE__ */ jsxs("div", { className: "agno-members", children: [
1310
+ /* @__PURE__ */ jsxs("div", { className: "agno-members__title", children: [
1311
+ title,
1312
+ " (",
1313
+ members.length,
1314
+ ")"
1315
+ ] }),
1316
+ members.map((m) => /* @__PURE__ */ jsx(MemberCard, { member: m, renderMarkdown }, m.run_id))
1317
+ ] });
1318
+ }
1319
+ function audioSrc(a) {
1320
+ if (a.url) return a.url;
1321
+ if (a.base64_audio) return `data:${a.mime_type ?? "audio/mpeg"};base64,${a.base64_audio}`;
1322
+ if (a.content) return `data:${a.mime_type ?? "audio/wav"};base64,${a.content}`;
1323
+ return void 0;
1324
+ }
1325
+ function Multimedia({
1326
+ images,
1327
+ videos,
1328
+ audio,
1329
+ responseAudio
1330
+ }) {
1331
+ const audios = [...audio ?? [], ...responseAudio ? [responseAudio] : []];
1332
+ if (!images?.length && !videos?.length && !audios.length) return null;
1333
+ return /* @__PURE__ */ jsxs("div", { className: "agno-media", children: [
1334
+ images?.map(
1335
+ (img, i) => img.url ? /* @__PURE__ */ jsx("img", { className: "agno-media__img", src: img.url, alt: img.revised_prompt ?? "image" }, `img-${i}`) : null
1336
+ ),
1337
+ videos?.map(
1338
+ (v, i) => v.url ? /* @__PURE__ */ jsx("video", { className: "agno-media__video", src: v.url, controls: true }, `vid-${i}`) : null
1339
+ ),
1340
+ audios.map((a, i) => {
1341
+ const src = audioSrc(a);
1342
+ return src ? /* @__PURE__ */ jsx("audio", { className: "agno-media__audio", src, controls: true }, `aud-${i}`) : null;
1343
+ })
1344
+ ] });
1345
+ }
1346
+ function Reasoning({
1347
+ steps,
1348
+ defaultOpen = false
1349
+ }) {
1350
+ const [open, setOpen] = useState(defaultOpen);
1351
+ if (!steps || steps.length === 0) return null;
1352
+ return /* @__PURE__ */ jsxs("div", { className: "agno-reasoning", children: [
1353
+ /* @__PURE__ */ jsxs("button", { type: "button", className: "agno-reasoning__toggle", onClick: () => setOpen((v) => !v), children: [
1354
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\u{1F4AD}" }),
1355
+ " Reasoning (",
1356
+ steps.length,
1357
+ " step",
1358
+ steps.length > 1 ? "s" : "",
1359
+ ")",
1360
+ /* @__PURE__ */ jsx("span", { className: "agno-reasoning__chev", children: open ? "\u25B2" : "\u25BC" })
1361
+ ] }),
1362
+ open && /* @__PURE__ */ jsx("ol", { className: "agno-reasoning__list", children: steps.map((step, i) => /* @__PURE__ */ jsxs("li", { className: "agno-reasoning__step", children: [
1363
+ step.title && /* @__PURE__ */ jsx("div", { className: "agno-reasoning__title", children: step.title }),
1364
+ step.reasoning && /* @__PURE__ */ jsx("div", { className: "agno-reasoning__text", children: step.reasoning }),
1365
+ step.action && /* @__PURE__ */ jsxs("div", { className: "agno-reasoning__meta", children: [
1366
+ "Action: ",
1367
+ step.action
1368
+ ] }),
1369
+ step.result && /* @__PURE__ */ jsxs("div", { className: "agno-reasoning__meta", children: [
1370
+ "Result: ",
1371
+ step.result
1372
+ ] }),
1373
+ typeof step.confidence === "number" && /* @__PURE__ */ jsxs("div", { className: "agno-reasoning__meta", children: [
1374
+ "Confidence: ",
1375
+ Math.round(step.confidence * 100),
1376
+ "%"
1377
+ ] })
1378
+ ] }, i)) })
1379
+ ] });
1380
+ }
1381
+ function StepRow({ step, renderMarkdown }) {
1382
+ const [open, setOpen] = useState(false);
1383
+ const hasBody = Boolean(step.content || step.error);
1384
+ return /* @__PURE__ */ jsxs("div", { className: `agno-step agno-step--${step.status}`, children: [
1385
+ /* @__PURE__ */ jsxs(
1386
+ "button",
1387
+ {
1388
+ type: "button",
1389
+ className: "agno-step__head",
1390
+ onClick: () => hasBody && setOpen((v) => !v),
1391
+ "aria-expanded": open,
1392
+ children: [
1393
+ /* @__PURE__ */ jsx("span", { className: `agno-step__icon agno-step__icon--${step.status}`, "aria-hidden": true, children: step.status === "completed" ? "\u2713" : step.status === "error" ? "!" : "\u25CF" }),
1394
+ /* @__PURE__ */ jsx("span", { className: "agno-step__name", children: step.name ?? step.key }),
1395
+ hasBody && /* @__PURE__ */ jsx("span", { className: "agno-step__chev", children: open ? "\u25B2" : "\u25BC" })
1396
+ ]
1397
+ }
1398
+ ),
1399
+ open && hasBody && /* @__PURE__ */ jsx("div", { className: "agno-step__body", children: step.error ? /* @__PURE__ */ jsx("div", { className: "agno-step__error", children: step.error }) : step.content ? renderMarkdown ? renderMarkdown(step.content) : /* @__PURE__ */ jsx(Markdown, { content: step.content }) : null })
1400
+ ] });
1401
+ }
1402
+ function WorkflowSteps({
1403
+ steps,
1404
+ renderMarkdown,
1405
+ title = "Steps"
1406
+ }) {
1407
+ if (!steps || steps.length === 0) return null;
1408
+ return /* @__PURE__ */ jsxs("div", { className: "agno-steps", children: [
1409
+ /* @__PURE__ */ jsxs("div", { className: "agno-steps__title", children: [
1410
+ title,
1411
+ " (",
1412
+ steps.length,
1413
+ ")"
1414
+ ] }),
1415
+ /* @__PURE__ */ jsx("div", { className: "agno-steps__list", children: steps.map((s) => /* @__PURE__ */ jsx(StepRow, { step: s, renderMarkdown }, s.key)) })
1416
+ ] });
1417
+ }
1418
+ function Message({ message, renderMarkdown, activity, hideReasoning, hideTools }) {
1419
+ const isUser = message.role === "user";
1420
+ const isAgent = message.role === "agent";
1421
+ const hasActivity = !message.content && !message.tool_calls?.length && !message.steps?.length && !message.members?.length && !message.reasoning_steps?.length;
1422
+ return /* @__PURE__ */ jsxs("div", { className: `agno-msg agno-msg--${message.role}`, "data-status": message.status, children: [
1423
+ /* @__PURE__ */ jsx("div", { className: "agno-msg__avatar", "aria-hidden": true, children: isUser ? "\u{1F464}" : isAgent ? "A" : "\u2699" }),
1424
+ /* @__PURE__ */ jsxs("div", { className: "agno-msg__body", children: [
1425
+ isAgent && !hideReasoning && /* @__PURE__ */ jsx(Reasoning, { steps: message.reasoning_steps }),
1426
+ isAgent && /* @__PURE__ */ jsx(WorkflowSteps, { steps: message.steps, renderMarkdown }),
1427
+ isAgent && /* @__PURE__ */ jsx(MemberResponses, { members: message.members, renderMarkdown }),
1428
+ isAgent && !hideTools && /* @__PURE__ */ jsx(ToolCalls, { tools: message.tool_calls }),
1429
+ message.content ? /* @__PURE__ */ jsxs("div", { className: "agno-msg__content", children: [
1430
+ renderMarkdown ? renderMarkdown(message.content) : /* @__PURE__ */ jsx(Markdown, { content: message.content }),
1431
+ message.streaming && /* @__PURE__ */ jsx("span", { className: "agno-msg__caret", "aria-hidden": true })
1432
+ ] }) : isAgent && message.streaming && hasActivity && /* @__PURE__ */ jsxs("div", { className: "agno-msg__activity", role: "status", "aria-live": "polite", children: [
1433
+ /* @__PURE__ */ jsxs("span", { className: "agno-status__dots", "aria-hidden": true, children: [
1434
+ /* @__PURE__ */ jsx("span", {}),
1435
+ /* @__PURE__ */ jsx("span", {}),
1436
+ /* @__PURE__ */ jsx("span", {})
1437
+ ] }),
1438
+ /* @__PURE__ */ jsx("span", { className: "agno-msg__activity-label", children: activity ?? "Working" })
1439
+ ] }),
1440
+ /* @__PURE__ */ jsx(
1441
+ Multimedia,
1442
+ {
1443
+ images: message.images,
1444
+ videos: message.videos,
1445
+ audio: message.audio,
1446
+ responseAudio: message.response_audio
1447
+ }
1448
+ ),
1449
+ isAgent && /* @__PURE__ */ jsx(Citations, { references: message.references, citations: message.citations }),
1450
+ message.error && /* @__PURE__ */ jsx("div", { className: "agno-msg__error", children: message.error })
1451
+ ] })
1452
+ ] });
1453
+ }
1454
+ function MessageList({
1455
+ messages,
1456
+ status,
1457
+ activity,
1458
+ renderMarkdown,
1459
+ emptyState,
1460
+ footer
1461
+ }) {
1462
+ const endRef = useRef(null);
1463
+ const stick = useRef(true);
1464
+ const containerRef = useRef(null);
1465
+ const onScroll = () => {
1466
+ const el = containerRef.current;
1467
+ if (!el) return;
1468
+ stick.current = el.scrollHeight - el.scrollTop - el.clientHeight < 80;
1469
+ };
1470
+ useEffect(() => {
1471
+ if (stick.current) endRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
1472
+ }, [messages, activity, status]);
1473
+ return /* @__PURE__ */ jsxs("div", { className: "agno-list", ref: containerRef, onScroll, children: [
1474
+ messages.length === 0 && /* @__PURE__ */ jsx("div", { className: "agno-list__empty", children: emptyState ?? "Start the conversation." }),
1475
+ messages.map((m) => /* @__PURE__ */ jsx(
1476
+ Message,
1477
+ {
1478
+ message: m,
1479
+ renderMarkdown,
1480
+ activity: m.streaming && status === "streaming" ? activity : void 0
1481
+ },
1482
+ m.id
1483
+ )),
1484
+ footer,
1485
+ /* @__PURE__ */ jsx("div", { ref: endRef })
1486
+ ] });
1487
+ }
1488
+ function ChatWindow({
1489
+ chat,
1490
+ placeholder,
1491
+ emptyState,
1492
+ allowFiles,
1493
+ disabled,
1494
+ renderMarkdown,
1495
+ className
1496
+ }) {
1497
+ const pausedMessage = chat.isPaused ? [...chat.messages].reverse().find((m) => m.status === "paused") : void 0;
1498
+ return /* @__PURE__ */ jsxs("div", { className: ["agno-chat", className].filter(Boolean).join(" "), children: [
1499
+ /* @__PURE__ */ jsx(
1500
+ MessageList,
1501
+ {
1502
+ messages: chat.messages,
1503
+ status: chat.status,
1504
+ activity: chat.activity,
1505
+ renderMarkdown,
1506
+ emptyState,
1507
+ footer: pausedMessage ? /* @__PURE__ */ jsx(
1508
+ HumanInput,
1509
+ {
1510
+ message: pausedMessage,
1511
+ entityType: chat.entityType,
1512
+ busy: chat.isStreaming,
1513
+ onResolve: chat.continueRun
1514
+ }
1515
+ ) : null
1516
+ }
1517
+ ),
1518
+ chat.error && !chat.isPaused && /* @__PURE__ */ jsx("div", { className: "agno-chat__error", children: chat.error }),
1519
+ /* @__PURE__ */ jsx(
1520
+ ChatInput,
1521
+ {
1522
+ onSend: (message, files) => chat.sendMessage(message, files ? { files } : void 0),
1523
+ onStop: chat.cancel,
1524
+ busy: chat.isStreaming,
1525
+ disabled: disabled || chat.isPaused,
1526
+ placeholder,
1527
+ allowFiles
1528
+ }
1529
+ )
1530
+ ] });
1531
+ }
1532
+ var TYPE_LABEL = {
1533
+ agent: "Agents",
1534
+ team: "Teams",
1535
+ workflow: "Workflows"
1536
+ };
1537
+ var ORDER = ["agent", "team", "workflow"];
1538
+ function EntitySelector({
1539
+ entities,
1540
+ value,
1541
+ onChange,
1542
+ disabled,
1543
+ placeholder = "Select an agent, team or workflow"
1544
+ }) {
1545
+ const [open, setOpen] = useState(false);
1546
+ const rootRef = useRef(null);
1547
+ const key = (e) => `${e.type}:${e.id}`;
1548
+ useEffect(() => {
1549
+ if (!open) return;
1550
+ const onDocClick = (e) => {
1551
+ if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false);
1552
+ };
1553
+ const onKey = (e) => {
1554
+ if (e.key === "Escape") setOpen(false);
1555
+ };
1556
+ document.addEventListener("mousedown", onDocClick);
1557
+ document.addEventListener("keydown", onKey);
1558
+ return () => {
1559
+ document.removeEventListener("mousedown", onDocClick);
1560
+ document.removeEventListener("keydown", onKey);
1561
+ };
1562
+ }, [open]);
1563
+ return /* @__PURE__ */ jsxs("div", { className: "agno-select", ref: rootRef, children: [
1564
+ /* @__PURE__ */ jsxs(
1565
+ "button",
1566
+ {
1567
+ type: "button",
1568
+ className: "agno-select__trigger",
1569
+ disabled,
1570
+ "aria-haspopup": "listbox",
1571
+ "aria-expanded": open,
1572
+ onClick: () => setOpen((v) => !v),
1573
+ children: [
1574
+ /* @__PURE__ */ jsx("span", { className: "agno-select__value", children: value ? value.name : placeholder }),
1575
+ /* @__PURE__ */ jsx("span", { className: `agno-select__chev ${open ? "is-open" : ""}`, "aria-hidden": true, children: "\u2304" })
1576
+ ]
1577
+ }
1578
+ ),
1579
+ open && /* @__PURE__ */ jsxs("div", { className: "agno-select__panel", role: "listbox", children: [
1580
+ entities.length === 0 && /* @__PURE__ */ jsx("div", { className: "agno-select__empty", children: "Nothing available" }),
1581
+ ORDER.map((type) => {
1582
+ const items = entities.filter((e) => e.type === type);
1583
+ if (items.length === 0) return null;
1584
+ return /* @__PURE__ */ jsxs("div", { className: "agno-select__group", children: [
1585
+ /* @__PURE__ */ jsx("div", { className: "agno-select__group-label", children: TYPE_LABEL[type] }),
1586
+ items.map((ent) => {
1587
+ const selected = value ? key(value) === key(ent) : false;
1588
+ return /* @__PURE__ */ jsxs(
1589
+ "button",
1590
+ {
1591
+ type: "button",
1592
+ role: "option",
1593
+ "aria-selected": selected,
1594
+ className: `agno-select__option ${selected ? "is-selected" : ""}`,
1595
+ onClick: () => {
1596
+ onChange(ent);
1597
+ setOpen(false);
1598
+ },
1599
+ children: [
1600
+ /* @__PURE__ */ jsx("span", { className: "agno-select__check", "aria-hidden": true, children: selected ? "\u2713" : "" }),
1601
+ /* @__PURE__ */ jsx("span", { className: "agno-select__label", children: ent.name }),
1602
+ ent.model?.model && /* @__PURE__ */ jsx("span", { className: "agno-select__model", children: ent.model.model })
1603
+ ]
1604
+ },
1605
+ key(ent)
1606
+ );
1607
+ })
1608
+ ] }, type);
1609
+ })
1610
+ ] })
1611
+ ] });
1612
+ }
1613
+ function sourceOf(e) {
1614
+ return e.agent_name || e.team_name || e.workflow_name || e.agent_id || e.team_id || e.workflow_id || void 0;
1615
+ }
1616
+ function fold(events) {
1617
+ const rows = [];
1618
+ for (const e of events) {
1619
+ const name2 = String(e.event);
1620
+ const source = sourceOf(e);
1621
+ const last = rows[rows.length - 1];
1622
+ if (last && last.event === name2 && last.source === source) {
1623
+ last.count += 1;
1624
+ last.created_at = e.created_at ?? last.created_at;
1625
+ continue;
1626
+ }
1627
+ rows.push({ event: name2, source, count: 1, created_at: e.created_at, detail: activityLabel(e) });
1628
+ }
1629
+ return rows;
1630
+ }
1631
+ function EventLog({
1632
+ events,
1633
+ autoScroll = true,
1634
+ maxHeight = 240
1635
+ }) {
1636
+ const ref = useRef(null);
1637
+ const rows = useMemo(() => fold(events), [events]);
1638
+ useEffect(() => {
1639
+ if (autoScroll && ref.current) ref.current.scrollTop = ref.current.scrollHeight;
1640
+ }, [rows, autoScroll]);
1641
+ return /* @__PURE__ */ jsxs("div", { className: "agno-eventlog", ref, style: { maxHeight }, children: [
1642
+ rows.length === 0 && /* @__PURE__ */ jsx("div", { className: "agno-eventlog__empty", children: "No events yet." }),
1643
+ rows.map((row, i) => /* @__PURE__ */ jsxs("div", { className: "agno-eventlog__row", children: [
1644
+ /* @__PURE__ */ jsx("span", { className: "agno-eventlog__name", children: row.event }),
1645
+ row.count > 1 && /* @__PURE__ */ jsxs("span", { className: "agno-eventlog__count", children: [
1646
+ "\xD7",
1647
+ row.count
1648
+ ] }),
1649
+ row.source && /* @__PURE__ */ jsx("span", { className: "agno-eventlog__source", children: row.source }),
1650
+ row.created_at && /* @__PURE__ */ jsx("span", { className: "agno-eventlog__time", children: new Date(row.created_at * 1e3).toLocaleTimeString() })
1651
+ ] }, i))
1652
+ ] });
1653
+ }
1654
+ function label(session) {
1655
+ return session.session_name?.trim() || session.session_id;
1656
+ }
1657
+ function formatDate(value) {
1658
+ if (value == null) return "";
1659
+ let date;
1660
+ if (typeof value === "number") {
1661
+ date = new Date(value < 1e12 ? value * 1e3 : value);
1662
+ } else {
1663
+ date = new Date(value);
1664
+ }
1665
+ if (Number.isNaN(date.getTime())) return "";
1666
+ return date.toLocaleDateString();
1667
+ }
1668
+ function SessionList({
1669
+ sessions,
1670
+ activeSessionId,
1671
+ loading,
1672
+ onSelect,
1673
+ onDelete,
1674
+ onNew,
1675
+ title = "Sessions"
1676
+ }) {
1677
+ return /* @__PURE__ */ jsxs("div", { className: "agno-sessions", children: [
1678
+ onNew && /* @__PURE__ */ jsxs("button", { type: "button", className: "agno-sessions__new", onClick: onNew, "aria-label": "New chat", children: [
1679
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "+" }),
1680
+ " New Chat"
1681
+ ] }),
1682
+ /* @__PURE__ */ jsx("div", { className: "agno-sessions__head", children: /* @__PURE__ */ jsx("span", { className: "agno-sessions__title", children: title }) }),
1683
+ loading && /* @__PURE__ */ jsx("div", { className: "agno-sessions__empty", children: "Loading\u2026" }),
1684
+ !loading && sessions.length === 0 && /* @__PURE__ */ jsx("div", { className: "agno-sessions__empty", children: "No past sessions." }),
1685
+ /* @__PURE__ */ jsx("ul", { className: "agno-sessions__list", children: sessions.map((session) => /* @__PURE__ */ jsxs(
1686
+ "li",
1687
+ {
1688
+ className: `agno-sessions__item ${session.session_id === activeSessionId ? "is-active" : ""}`,
1689
+ children: [
1690
+ /* @__PURE__ */ jsxs("button", { type: "button", className: "agno-sessions__select", onClick: () => onSelect(session.session_id), children: [
1691
+ /* @__PURE__ */ jsx("span", { className: "agno-sessions__name", children: label(session) }),
1692
+ formatDate(session.created_at) && /* @__PURE__ */ jsx("span", { className: "agno-sessions__date", children: formatDate(session.created_at) })
1693
+ ] }),
1694
+ onDelete && /* @__PURE__ */ jsx(
1695
+ "button",
1696
+ {
1697
+ type: "button",
1698
+ className: "agno-sessions__delete",
1699
+ "aria-label": "Delete session",
1700
+ onClick: () => onDelete(session.session_id),
1701
+ children: "\u{1F5D1}"
1702
+ }
1703
+ )
1704
+ ]
1705
+ },
1706
+ session.session_id
1707
+ )) })
1708
+ ] });
1709
+ }
1710
+ function AgnoChat(props) {
1711
+ const client = useMemo(
1712
+ () => props.client ?? new AgnoClient({ baseUrl: props.baseUrl ?? "", headers: props.headers }),
1713
+ [props.client, props.baseUrl, props.headers]
1714
+ );
1715
+ const [discovered, setDiscovered] = useState(props.entities ?? []);
1716
+ const [selected, setSelected] = useState(props.entity ?? null);
1717
+ const [showLog, setShowLog] = useState(false);
1718
+ const [discoveryDone, setDiscoveryDone] = useState(Boolean(props.entity || props.entities));
1719
+ useEffect(() => {
1720
+ if (props.entity || props.entities) return;
1721
+ let cancelled = false;
1722
+ setDiscoveryDone(false);
1723
+ client.getEntities().then((list) => {
1724
+ if (cancelled) return;
1725
+ setDiscovered(list);
1726
+ setSelected((cur) => cur ?? list[0] ?? null);
1727
+ setDiscoveryDone(true);
1728
+ });
1729
+ return () => {
1730
+ cancelled = true;
1731
+ };
1732
+ }, [client, props.entity, props.entities]);
1733
+ const entity = props.entity ?? selected;
1734
+ const chat = useAgnoChat({ client, entity, userId: props.userId });
1735
+ const { refreshSessions } = chat;
1736
+ useEffect(() => {
1737
+ if (props.showSessions && entity) refreshSessions();
1738
+ }, [props.showSessions, entity?.type, entity?.id, refreshSessions]);
1739
+ useEffect(() => {
1740
+ if (props.showSessions && entity && chat.status === "completed") refreshSessions();
1741
+ }, [chat.status]);
1742
+ const onSelect = (e) => {
1743
+ setSelected(e);
1744
+ chat.reset();
1745
+ };
1746
+ const showSelector = !props.entity;
1747
+ const entities = props.entities ?? discovered;
1748
+ const noEntities = showSelector && discoveryDone && entities.length === 0;
1749
+ return /* @__PURE__ */ jsxs(
1750
+ "div",
1751
+ {
1752
+ className: ["agno-root", props.className].filter(Boolean).join(" "),
1753
+ style: { height: props.height ?? 560 },
1754
+ children: [
1755
+ /* @__PURE__ */ jsxs("div", { className: "agno-header", children: [
1756
+ /* @__PURE__ */ jsxs("div", { className: "agno-header__brand", children: [
1757
+ /* @__PURE__ */ jsx("span", { className: "agno-logo", "aria-hidden": true, children: "A" }),
1758
+ /* @__PURE__ */ jsx("span", { className: "agno-header__title", children: props.title ?? entity?.name ?? "Agent UI" })
1759
+ ] }),
1760
+ /* @__PURE__ */ jsxs("div", { className: "agno-header__controls", children: [
1761
+ showSelector && /* @__PURE__ */ jsx(EntitySelector, { entities, value: entity, onChange: onSelect, disabled: chat.isStreaming }),
1762
+ props.showEventLog && /* @__PURE__ */ jsx(
1763
+ "button",
1764
+ {
1765
+ type: "button",
1766
+ className: `agno-btn agno-btn--ghost ${showLog ? "is-active" : ""}`,
1767
+ onClick: () => setShowLog((v) => !v),
1768
+ children: "Events"
1769
+ }
1770
+ ),
1771
+ /* @__PURE__ */ jsx("button", { type: "button", className: "agno-btn agno-btn--ghost", onClick: chat.reset, disabled: chat.isStreaming, children: "New chat" })
1772
+ ] })
1773
+ ] }),
1774
+ noEntities && /* @__PURE__ */ jsxs("div", { className: "agno-banner", children: [
1775
+ "No agents, teams or workflows found at ",
1776
+ /* @__PURE__ */ jsx("code", { children: client.baseUrl || "(no URL)" }),
1777
+ ". Check the URL is correct, that AgentOS is running, and that this origin is in its CORS allowlist (",
1778
+ /* @__PURE__ */ jsx("code", { children: "cors_allowed_origins" }),
1779
+ ")."
1780
+ ] }),
1781
+ /* @__PURE__ */ jsxs("div", { className: "agno-main", children: [
1782
+ props.showSessions && /* @__PURE__ */ jsx("div", { className: "agno-sidebar agno-sidebar--left", children: /* @__PURE__ */ jsx(
1783
+ SessionList,
1784
+ {
1785
+ sessions: chat.sessions,
1786
+ activeSessionId: chat.sessionId,
1787
+ loading: chat.sessionsLoading,
1788
+ onSelect: chat.loadSession,
1789
+ onDelete: chat.deleteSession,
1790
+ onNew: chat.reset
1791
+ }
1792
+ ) }),
1793
+ /* @__PURE__ */ jsx(
1794
+ ChatWindow,
1795
+ {
1796
+ chat,
1797
+ placeholder: props.placeholder,
1798
+ allowFiles: props.allowFiles,
1799
+ disabled: !entity,
1800
+ renderMarkdown: props.renderMarkdown,
1801
+ emptyState: entity ? `Chat with ${entity.name}.` : "Select an agent, team or workflow to begin."
1802
+ }
1803
+ ),
1804
+ props.showEventLog && showLog && /* @__PURE__ */ jsxs("div", { className: "agno-sidebar", children: [
1805
+ /* @__PURE__ */ jsx("div", { className: "agno-sidebar__title", children: "Event stream" }),
1806
+ /* @__PURE__ */ jsx(EventLog, { events: chat.events })
1807
+ ] })
1808
+ ] })
1809
+ ]
1810
+ }
1811
+ );
1812
+ }
1813
+ function StatusIndicator({
1814
+ status,
1815
+ activity
1816
+ }) {
1817
+ if (status !== "streaming" && status !== "paused") return null;
1818
+ const label2 = activity ?? (status === "paused" ? "Waiting for input" : "Working");
1819
+ return /* @__PURE__ */ jsxs("div", { className: `agno-status agno-status--${status}`, role: "status", "aria-live": "polite", children: [
1820
+ /* @__PURE__ */ jsxs("span", { className: "agno-status__dots", "aria-hidden": true, children: [
1821
+ /* @__PURE__ */ jsx("span", {}),
1822
+ /* @__PURE__ */ jsx("span", {}),
1823
+ /* @__PURE__ */ jsx("span", {})
1824
+ ] }),
1825
+ /* @__PURE__ */ jsx("span", { className: "agno-status__label", children: label2 })
1826
+ ] });
1827
+ }
1828
+
1829
+ // src/types.ts
1830
+ var RunEvent = /* @__PURE__ */ ((RunEvent2) => {
1831
+ RunEvent2["RunStarted"] = "RunStarted";
1832
+ RunEvent2["RunContent"] = "RunContent";
1833
+ RunEvent2["RunContentCompleted"] = "RunContentCompleted";
1834
+ RunEvent2["RunIntermediateContent"] = "RunIntermediateContent";
1835
+ RunEvent2["RunCompleted"] = "RunCompleted";
1836
+ RunEvent2["RunError"] = "RunError";
1837
+ RunEvent2["RunCancelled"] = "RunCancelled";
1838
+ RunEvent2["RunPaused"] = "RunPaused";
1839
+ RunEvent2["RunContinued"] = "RunContinued";
1840
+ RunEvent2["PreHookStarted"] = "PreHookStarted";
1841
+ RunEvent2["PreHookCompleted"] = "PreHookCompleted";
1842
+ RunEvent2["PostHookStarted"] = "PostHookStarted";
1843
+ RunEvent2["PostHookCompleted"] = "PostHookCompleted";
1844
+ RunEvent2["ToolCallStarted"] = "ToolCallStarted";
1845
+ RunEvent2["ToolCallCompleted"] = "ToolCallCompleted";
1846
+ RunEvent2["ToolCallError"] = "ToolCallError";
1847
+ RunEvent2["ReasoningStarted"] = "ReasoningStarted";
1848
+ RunEvent2["ReasoningStep"] = "ReasoningStep";
1849
+ RunEvent2["ReasoningContentDelta"] = "ReasoningContentDelta";
1850
+ RunEvent2["ReasoningCompleted"] = "ReasoningCompleted";
1851
+ RunEvent2["MemoryUpdateStarted"] = "MemoryUpdateStarted";
1852
+ RunEvent2["MemoryUpdateCompleted"] = "MemoryUpdateCompleted";
1853
+ RunEvent2["SessionSummaryStarted"] = "SessionSummaryStarted";
1854
+ RunEvent2["SessionSummaryCompleted"] = "SessionSummaryCompleted";
1855
+ RunEvent2["ParserModelResponseStarted"] = "ParserModelResponseStarted";
1856
+ RunEvent2["ParserModelResponseCompleted"] = "ParserModelResponseCompleted";
1857
+ RunEvent2["OutputModelResponseStarted"] = "OutputModelResponseStarted";
1858
+ RunEvent2["OutputModelResponseCompleted"] = "OutputModelResponseCompleted";
1859
+ RunEvent2["ModelRequestStarted"] = "ModelRequestStarted";
1860
+ RunEvent2["ModelRequestCompleted"] = "ModelRequestCompleted";
1861
+ RunEvent2["CompressionStarted"] = "CompressionStarted";
1862
+ RunEvent2["CompressionCompleted"] = "CompressionCompleted";
1863
+ RunEvent2["FollowupsStarted"] = "FollowupsStarted";
1864
+ RunEvent2["FollowupsCompleted"] = "FollowupsCompleted";
1865
+ RunEvent2["CustomEvent"] = "CustomEvent";
1866
+ return RunEvent2;
1867
+ })(RunEvent || {});
1868
+ var TeamRunEvent = /* @__PURE__ */ ((TeamRunEvent2) => {
1869
+ TeamRunEvent2["TeamRunStarted"] = "TeamRunStarted";
1870
+ TeamRunEvent2["TeamRunContent"] = "TeamRunContent";
1871
+ TeamRunEvent2["TeamRunIntermediateContent"] = "TeamRunIntermediateContent";
1872
+ TeamRunEvent2["TeamRunContentCompleted"] = "TeamRunContentCompleted";
1873
+ TeamRunEvent2["TeamRunCompleted"] = "TeamRunCompleted";
1874
+ TeamRunEvent2["TeamRunError"] = "TeamRunError";
1875
+ TeamRunEvent2["TeamRunCancelled"] = "TeamRunCancelled";
1876
+ TeamRunEvent2["TeamRunPaused"] = "TeamRunPaused";
1877
+ TeamRunEvent2["TeamRunContinued"] = "TeamRunContinued";
1878
+ TeamRunEvent2["TeamToolCallStarted"] = "TeamToolCallStarted";
1879
+ TeamRunEvent2["TeamToolCallCompleted"] = "TeamToolCallCompleted";
1880
+ TeamRunEvent2["TeamToolCallError"] = "TeamToolCallError";
1881
+ TeamRunEvent2["TeamReasoningStarted"] = "TeamReasoningStarted";
1882
+ TeamRunEvent2["TeamReasoningStep"] = "TeamReasoningStep";
1883
+ TeamRunEvent2["TeamReasoningContentDelta"] = "TeamReasoningContentDelta";
1884
+ TeamRunEvent2["TeamReasoningCompleted"] = "TeamReasoningCompleted";
1885
+ TeamRunEvent2["TeamMemoryUpdateStarted"] = "TeamMemoryUpdateStarted";
1886
+ TeamRunEvent2["TeamMemoryUpdateCompleted"] = "TeamMemoryUpdateCompleted";
1887
+ TeamRunEvent2["TeamTaskIterationStarted"] = "TeamTaskIterationStarted";
1888
+ TeamRunEvent2["TeamTaskIterationCompleted"] = "TeamTaskIterationCompleted";
1889
+ TeamRunEvent2["TeamTaskStateUpdated"] = "TeamTaskStateUpdated";
1890
+ TeamRunEvent2["TeamTaskCreated"] = "TeamTaskCreated";
1891
+ TeamRunEvent2["TeamTaskUpdated"] = "TeamTaskUpdated";
1892
+ return TeamRunEvent2;
1893
+ })(TeamRunEvent || {});
1894
+ var WorkflowRunEvent = /* @__PURE__ */ ((WorkflowRunEvent2) => {
1895
+ WorkflowRunEvent2["WorkflowStarted"] = "WorkflowStarted";
1896
+ WorkflowRunEvent2["WorkflowCompleted"] = "WorkflowCompleted";
1897
+ WorkflowRunEvent2["WorkflowPaused"] = "WorkflowPaused";
1898
+ WorkflowRunEvent2["WorkflowCancelled"] = "WorkflowCancelled";
1899
+ WorkflowRunEvent2["WorkflowError"] = "WorkflowError";
1900
+ WorkflowRunEvent2["WorkflowAgentStarted"] = "WorkflowAgentStarted";
1901
+ WorkflowRunEvent2["WorkflowAgentCompleted"] = "WorkflowAgentCompleted";
1902
+ WorkflowRunEvent2["StepStarted"] = "StepStarted";
1903
+ WorkflowRunEvent2["StepCompleted"] = "StepCompleted";
1904
+ WorkflowRunEvent2["StepPaused"] = "StepPaused";
1905
+ WorkflowRunEvent2["StepContinued"] = "StepContinued";
1906
+ WorkflowRunEvent2["StepError"] = "StepError";
1907
+ WorkflowRunEvent2["StepOutput"] = "StepOutput";
1908
+ WorkflowRunEvent2["StepOutputReview"] = "StepOutputReview";
1909
+ WorkflowRunEvent2["LoopExecutionStarted"] = "LoopExecutionStarted";
1910
+ WorkflowRunEvent2["LoopIterationStarted"] = "LoopIterationStarted";
1911
+ WorkflowRunEvent2["LoopIterationCompleted"] = "LoopIterationCompleted";
1912
+ WorkflowRunEvent2["LoopExecutionCompleted"] = "LoopExecutionCompleted";
1913
+ WorkflowRunEvent2["ParallelExecutionStarted"] = "ParallelExecutionStarted";
1914
+ WorkflowRunEvent2["ParallelExecutionCompleted"] = "ParallelExecutionCompleted";
1915
+ WorkflowRunEvent2["ConditionExecutionStarted"] = "ConditionExecutionStarted";
1916
+ WorkflowRunEvent2["ConditionExecutionCompleted"] = "ConditionExecutionCompleted";
1917
+ WorkflowRunEvent2["ConditionPaused"] = "ConditionPaused";
1918
+ WorkflowRunEvent2["RouterExecutionStarted"] = "RouterExecutionStarted";
1919
+ WorkflowRunEvent2["RouterExecutionCompleted"] = "RouterExecutionCompleted";
1920
+ WorkflowRunEvent2["RouterPaused"] = "RouterPaused";
1921
+ WorkflowRunEvent2["StepsExecutionStarted"] = "StepsExecutionStarted";
1922
+ WorkflowRunEvent2["StepsExecutionCompleted"] = "StepsExecutionCompleted";
1923
+ return WorkflowRunEvent2;
1924
+ })(WorkflowRunEvent || {});
1925
+
1926
+ export { AgnoChat, AgnoClient, ChatInput, ChatWindow, Citations, EntitySelector, EventLog, HumanInput, Markdown, MemberResponses, Message, MessageList, Multimedia, Reasoning, RunEvent, SessionList, StatusIndicator, TeamRunEvent, ToolCalls, WorkflowRunEvent, WorkflowSteps, activityLabel, applyStepEvent, applySubRunEvent, isCompletedEvent, isContentEvent, isErrorEvent, isPausedEvent, isReasoningStepEvent, isStepEvent, isSubRunEvent, isToolEvent, mergeTool, normaliseBaseUrl, sessionRunsToMessages, streamRun, toolsFromEvent, useAgnoChat };
1927
+ //# sourceMappingURL=index.js.map
1928
+ //# sourceMappingURL=index.js.map