@aginies/webuikit 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,2467 @@
1
+ 'use client';
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var src_exports = {};
23
+ __export(src_exports, {
24
+ ATTACHMENT_LIMITS: () => ATTACHMENT_LIMITS,
25
+ AgentRunner: () => AgentRunner,
26
+ AginiesClient: () => AginiesClient,
27
+ AginiesError: () => AginiesError,
28
+ AginiesProvider: () => AginiesProvider,
29
+ ApprovalPanel: () => ApprovalPanel,
30
+ Button: () => Button,
31
+ ChatWidget: () => ChatWidget,
32
+ Chip: () => Chip,
33
+ CostBars: () => CostBars,
34
+ Eyebrow: () => Eyebrow,
35
+ Field: () => Field,
36
+ Input: () => Input,
37
+ Markdown: () => Markdown,
38
+ Panel: () => Panel,
39
+ RunTimeline: () => RunTimeline,
40
+ Spinner: () => Spinner,
41
+ Stat: () => Stat,
42
+ StatTiles: () => StatTiles,
43
+ StructuredUI: () => StructuredUI,
44
+ SuccessHeatmap: () => SuccessHeatmap,
45
+ Tag: () => Tag,
46
+ Textarea: () => Textarea,
47
+ buildSubmission: () => buildSubmission,
48
+ cx: () => cx,
49
+ fieldsOf: () => fieldsOf,
50
+ formatFieldValue: () => formatFieldValue,
51
+ getClient: () => getClient,
52
+ getPauseContext: () => getPauseContext,
53
+ getPausedExecution: () => getPausedExecution,
54
+ init: () => init,
55
+ initialValues: () => initialValues,
56
+ listPausedExecutions: () => listPausedExecutions,
57
+ outputOf: () => outputOf,
58
+ parseFieldValue: () => parseFieldValue,
59
+ parseRunSSE: () => parseRunSSE,
60
+ parseSSE: () => parseSSE,
61
+ parseStructured: () => parseStructured,
62
+ resumeExecution: () => resumeExecution,
63
+ runAgent: () => runAgent,
64
+ translator: () => translator,
65
+ useAgentRun: () => useAgentRun,
66
+ useAginies: () => useAginies,
67
+ useApproval: () => useApproval,
68
+ useChat: () => useChat,
69
+ useModule: () => useModule
70
+ });
71
+ module.exports = __toCommonJS(src_exports);
72
+
73
+ // src/client.ts
74
+ var AginiesError = class extends Error {
75
+ status;
76
+ code;
77
+ constructor(message, status, code) {
78
+ super(message);
79
+ this.name = "AginiesError";
80
+ this.status = status;
81
+ this.code = code;
82
+ }
83
+ };
84
+ var trimSlash = (s) => s.replace(/\/+$/, "");
85
+ var AginiesClient = class {
86
+ baseUrl;
87
+ token;
88
+ locale;
89
+ fetchImpl;
90
+ state = { status: "idle" };
91
+ listeners = /* @__PURE__ */ new Set();
92
+ activation = null;
93
+ session = null;
94
+ constructor(config) {
95
+ if (!config?.baseUrl) throw new AginiesError("baseUrl is required", 0, "MISSING_BASE_URL");
96
+ if (!config?.token) throw new AginiesError("token is required", 0, "MISSING_TOKEN");
97
+ this.baseUrl = trimSlash(config.baseUrl);
98
+ this.token = config.token;
99
+ this.locale = config.locale ?? detectLocale();
100
+ this.fetchImpl = config.fetch ?? ((...args) => fetch(...args));
101
+ }
102
+ getState() {
103
+ return this.state;
104
+ }
105
+ subscribe(listener) {
106
+ this.listeners.add(listener);
107
+ return () => this.listeners.delete(listener);
108
+ }
109
+ setState(next) {
110
+ this.state = next;
111
+ for (const l of this.listeners) l(next);
112
+ }
113
+ /**
114
+ * Runs the activation handshake once and caches the outcome. Components render only
115
+ * while the state is `active`; a rejected activation is final for this client.
116
+ */
117
+ activate() {
118
+ if (this.activation) return this.activation;
119
+ this.setState({ status: "activating" });
120
+ this.activation = (async () => {
121
+ try {
122
+ const res = await this.fetchImpl(`${this.baseUrl}/api/ui/activate`, {
123
+ method: "POST",
124
+ headers: { "Content-Type": "application/json" },
125
+ body: JSON.stringify({ token: this.token })
126
+ });
127
+ if (!res.ok) {
128
+ const body2 = await safeJson(res);
129
+ const reason = body2 && body2.error || `HTTP ${res.status}`;
130
+ this.setState({ status: "rejected", reason });
131
+ return this.state;
132
+ }
133
+ const body = await res.json();
134
+ if (!body.activated || !body.config) {
135
+ this.setState({ status: "rejected", reason: "Activation refused" });
136
+ return this.state;
137
+ }
138
+ this.session = body.session ?? null;
139
+ this.setState({ status: "active", config: body.config });
140
+ return this.state;
141
+ } catch (err) {
142
+ this.setState({
143
+ status: "rejected",
144
+ reason: err instanceof Error ? err.message : "Activation failed"
145
+ });
146
+ return this.state;
147
+ }
148
+ })();
149
+ return this.activation;
150
+ }
151
+ assertActive() {
152
+ if (this.state.status !== "active") {
153
+ throw new AginiesError("Client is not activated", 0, "NOT_ACTIVATED");
154
+ }
155
+ }
156
+ /** The current tenant session, if the activation issued one. */
157
+ getSession() {
158
+ return this.session;
159
+ }
160
+ /** Whether `module` may render under this activation. */
161
+ hasModule(module2) {
162
+ if (this.state.status !== "active") return false;
163
+ const modules = this.state.config.modules ?? [];
164
+ return modules.length === 0 || modules.includes(module2);
165
+ }
166
+ /**
167
+ * Re-runs the handshake to obtain a fresh session. Used when a call is refused with
168
+ * an expired bearer; the activation state stays `active` unless the platform now
169
+ * rejects the key.
170
+ */
171
+ async renewSession() {
172
+ this.activation = null;
173
+ const state = await this.activate();
174
+ return state.status === "active" && this.session !== null;
175
+ }
176
+ withSession(init2) {
177
+ if (!this.session) return init2;
178
+ const headers = new Headers(init2.headers ?? {});
179
+ if (!headers.has("Authorization")) headers.set("Authorization", `Bearer ${this.session.token}`);
180
+ return { ...init2, headers };
181
+ }
182
+ /**
183
+ * A platform request carrying cookies and, when a tenant session exists, its bearer.
184
+ * A 401/403 on a session that has expired triggers one renewal and one retry.
185
+ */
186
+ async request(path2, init2 = {}) {
187
+ const url = `${this.baseUrl}${path2.startsWith("/") ? path2 : `/${path2}`}`;
188
+ const send = () => this.fetchImpl(url, this.withSession({ credentials: "include", ...init2 }));
189
+ let res = await send();
190
+ if (this.session && (res.status === 401 || res.status === 403) && this.session.expiresAt * 1e3 <= Date.now() + 5e3) {
191
+ if (await this.renewSession()) res = await send();
192
+ }
193
+ return res;
194
+ }
195
+ /** A raw request against the platform for endpoints the client does not wrap. */
196
+ fetchRaw(path2, init2 = {}) {
197
+ this.assertActive();
198
+ return this.request(path2, init2);
199
+ }
200
+ /** Hosted-chat configuration. Resolves to an auth requirement instead of throwing on 401. */
201
+ async getChat(identifier) {
202
+ this.assertActive();
203
+ const res = await this.request(`/api/chat/${encodeURIComponent(identifier)}`);
204
+ const body = await safeJson(res);
205
+ if (res.status === 401 && body && typeof body.authRequired === "string") {
206
+ return body;
207
+ }
208
+ if (!res.ok) {
209
+ throw new AginiesError(body?.error || `HTTP ${res.status}`, res.status);
210
+ }
211
+ return body;
212
+ }
213
+ /**
214
+ * Sends one turn and yields the streamed events. Authentication for password / e-mail
215
+ * chats travels in the same body on the first call; the platform then sets a cookie.
216
+ */
217
+ async *sendMessage(identifier, input, signal) {
218
+ this.assertActive();
219
+ const res = await this.request(`/api/chat/${encodeURIComponent(identifier)}`, {
220
+ method: "POST",
221
+ headers: { "Content-Type": "application/json" },
222
+ body: JSON.stringify(input),
223
+ signal
224
+ });
225
+ if (!res.ok) {
226
+ const body = await safeJson(res);
227
+ if (res.status === 401 && body && typeof body.authRequired === "string") {
228
+ throw new AginiesError("Authentication required", 401, "AUTH_REQUIRED");
229
+ }
230
+ throw new AginiesError(body?.error || `HTTP ${res.status}`, res.status);
231
+ }
232
+ const contentType = res.headers.get("content-type") ?? "";
233
+ if (!contentType.includes("text/event-stream")) {
234
+ const body = await safeJson(res);
235
+ yield { type: "final", data: body };
236
+ yield { type: "done" };
237
+ return;
238
+ }
239
+ yield* parseSSE(res.body);
240
+ }
241
+ };
242
+ async function* parseSSE(stream) {
243
+ const reader = stream.getReader();
244
+ const decoder = new TextDecoder();
245
+ let buffer = "";
246
+ try {
247
+ while (true) {
248
+ const { done, value } = await reader.read();
249
+ if (done) break;
250
+ buffer += decoder.decode(value, { stream: true });
251
+ let sep = buffer.indexOf("\n\n");
252
+ while (sep !== -1) {
253
+ const frame = buffer.slice(0, sep);
254
+ buffer = buffer.slice(sep + 2);
255
+ const event = decodeFrame(frame);
256
+ if (event) yield event;
257
+ sep = buffer.indexOf("\n\n");
258
+ }
259
+ }
260
+ const tail = decodeFrame(buffer);
261
+ if (tail) yield tail;
262
+ } finally {
263
+ reader.releaseLock();
264
+ }
265
+ yield { type: "done" };
266
+ }
267
+ function decodeFrame(frame) {
268
+ const line = frame.split("\n").find((l) => l.startsWith("data:"));
269
+ if (!line) return null;
270
+ const data = line.slice(5).trim();
271
+ if (!data || data === "[DONE]") return null;
272
+ let json;
273
+ try {
274
+ json = JSON.parse(data);
275
+ } catch {
276
+ return { type: "chunk", text: data };
277
+ }
278
+ if (json.event === "error") {
279
+ return { type: "error", message: json.error || "Stream error" };
280
+ }
281
+ if (json.event === "final") {
282
+ return { type: "final", data: json.data };
283
+ }
284
+ if (typeof json.chunk === "string") {
285
+ return { type: "chunk", blockId: json.blockId, text: json.chunk };
286
+ }
287
+ return null;
288
+ }
289
+ async function safeJson(res) {
290
+ try {
291
+ return await res.json();
292
+ } catch {
293
+ return null;
294
+ }
295
+ }
296
+ function detectLocale() {
297
+ if (typeof document !== "undefined") {
298
+ const lang = document.documentElement.lang?.toLowerCase() ?? "";
299
+ if (lang.startsWith("tr")) return "tr";
300
+ }
301
+ if (typeof navigator !== "undefined" && navigator.language?.toLowerCase().startsWith("tr")) {
302
+ return "tr";
303
+ }
304
+ return "en";
305
+ }
306
+
307
+ // src/approval/approval-client.ts
308
+ var path = (workflowId, executionId, contextId) => `/api/resume/${encodeURIComponent(workflowId)}/${encodeURIComponent(executionId)}${contextId ? `/${encodeURIComponent(contextId)}` : ""}`;
309
+ async function readJson(res) {
310
+ let body = null;
311
+ try {
312
+ body = await res.json();
313
+ } catch {
314
+ }
315
+ if (!res.ok) {
316
+ const error = body?.error;
317
+ throw new AginiesError(
318
+ error || `HTTP ${res.status}`,
319
+ res.status,
320
+ res.status === 404 ? "NOT_FOUND" : res.status === 403 ? "FORBIDDEN" : void 0
321
+ );
322
+ }
323
+ return body;
324
+ }
325
+ function getPausedExecution(client, workflowId, executionId) {
326
+ return client.fetchRaw(path(workflowId, executionId)).then((r) => readJson(r));
327
+ }
328
+ function getPauseContext(client, workflowId, executionId, contextId) {
329
+ return client.fetchRaw(path(workflowId, executionId, contextId)).then((r) => readJson(r));
330
+ }
331
+ function listPausedExecutions(client, workflowId, status) {
332
+ const query = status ? `?status=${encodeURIComponent(status)}` : "";
333
+ return client.fetchRaw(`/api/workflows/${encodeURIComponent(workflowId)}/paused${query}`).then((r) => readJson(r)).then((b) => b.pausedExecutions ?? []);
334
+ }
335
+ function resumeExecution(client, workflowId, executionId, contextId, submission) {
336
+ return client.fetchRaw(path(workflowId, executionId, contextId), {
337
+ method: "POST",
338
+ headers: { "Content-Type": "application/json" },
339
+ body: JSON.stringify(submission ? { input: { submission } } : {})
340
+ }).then((r) => readJson(r));
341
+ }
342
+ function fieldsOf(point) {
343
+ const raw = point?.response?.data?.inputFormat;
344
+ if (!Array.isArray(raw)) return [];
345
+ return raw.map((f, index) => {
346
+ if (!f || typeof f !== "object") return null;
347
+ const field = f;
348
+ const name = typeof field.name === "string" ? field.name.trim() : "";
349
+ if (!name) return null;
350
+ const str = (v) => typeof v === "string" && v.trim() ? v.trim() : void 0;
351
+ return {
352
+ id: str(field.id) ?? `field_${index}`,
353
+ name,
354
+ label: str(field.label) ?? name,
355
+ type: str(field.type) ?? "string",
356
+ description: str(field.description),
357
+ placeholder: str(field.placeholder),
358
+ value: field.value,
359
+ required: field.required === true,
360
+ options: Array.isArray(field.options) ? field.options : void 0,
361
+ rows: typeof field.rows === "number" ? field.rows : void 0
362
+ };
363
+ }).filter((f) => f !== null);
364
+ }
365
+ function outputOf(point) {
366
+ const data = point?.response?.data;
367
+ if (!data || typeof data !== "object") return {};
368
+ const { inputFormat: _f, resumeLinks: _l, ...rest } = data;
369
+ return rest;
370
+ }
371
+ function formatFieldValue(field, value) {
372
+ if (value === void 0 || value === null) return "";
373
+ switch (field.type) {
374
+ case "boolean":
375
+ if (typeof value === "boolean") return value ? "true" : "false";
376
+ if (typeof value === "string" && ["true", "false"].includes(value.trim().toLowerCase()))
377
+ return value.trim().toLowerCase();
378
+ return "";
379
+ case "number":
380
+ return typeof value === "number" ? Number.isFinite(value) ? String(value) : "" : String(value);
381
+ case "array":
382
+ case "object":
383
+ case "files":
384
+ if (typeof value === "string") return value;
385
+ try {
386
+ return JSON.stringify(value, null, 2);
387
+ } catch {
388
+ return "";
389
+ }
390
+ default:
391
+ return typeof value === "string" ? value : JSON.stringify(value);
392
+ }
393
+ }
394
+ function parseFieldValue(field, raw) {
395
+ const text = raw.trim();
396
+ switch (field.type) {
397
+ case "boolean":
398
+ return { value: text === "true" };
399
+ case "number": {
400
+ const n = Number(text);
401
+ return Number.isFinite(n) ? { value: n } : { error: "number" };
402
+ }
403
+ case "array":
404
+ case "object":
405
+ case "files":
406
+ try {
407
+ return { value: JSON.parse(text) };
408
+ } catch {
409
+ return { error: "json" };
410
+ }
411
+ default:
412
+ return { value: raw };
413
+ }
414
+ }
415
+ function initialValues(fields) {
416
+ return Object.fromEntries(fields.map((f) => [f.name, formatFieldValue(f, f.value)]));
417
+ }
418
+ function buildSubmission(fields, values) {
419
+ const submission = {};
420
+ const errors = {};
421
+ for (const field of fields) {
422
+ const raw = values[field.name] ?? "";
423
+ const present = field.type === "boolean" ? raw === "true" || raw === "false" : raw.trim() !== "";
424
+ if (!present) {
425
+ if (field.required) errors[field.name] = "required";
426
+ continue;
427
+ }
428
+ const { value, error } = parseFieldValue(field, raw);
429
+ if (error) errors[field.name] = error;
430
+ else if (value !== void 0) submission[field.name] = value;
431
+ }
432
+ return { submission, errors };
433
+ }
434
+
435
+ // src/approval/approval-panel.tsx
436
+ var import_react3 = require("react");
437
+
438
+ // src/core/index.tsx
439
+ var import_react = require("react");
440
+ var import_jsx_runtime = require("react/jsx-runtime");
441
+ function cx(...parts) {
442
+ return parts.filter(Boolean).join(" ");
443
+ }
444
+ var Button = (0, import_react.forwardRef)(function Button2({ variant = "outline", size = "md", className, type = "button", ...props }, ref) {
445
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
446
+ "button",
447
+ {
448
+ ref,
449
+ type,
450
+ className: cx("agi-btn", `agi-btn--${variant}`, `agi-btn--${size}`, className),
451
+ ...props
452
+ }
453
+ );
454
+ });
455
+ function Tag({ tone = "default", className, ...props }) {
456
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
457
+ "span",
458
+ {
459
+ className: cx("agi-tag", tone !== "default" && `agi-tag--${tone}`, className),
460
+ ...props
461
+ }
462
+ );
463
+ }
464
+ function Chip({ pressed = false, className, type = "button", ...props }) {
465
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type, "aria-pressed": pressed, className: cx("agi-chip", className), ...props });
466
+ }
467
+ function Panel({ level = 1, className, ...props }) {
468
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cx("agi-panel", level === 2 && "agi-panel--2", className), ...props });
469
+ }
470
+ function Eyebrow({
471
+ className,
472
+ quiet,
473
+ ...props
474
+ }) {
475
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: cx("agi-eyebrow", quiet && "agi-eyebrow--quiet", className), ...props });
476
+ }
477
+ function Stat({ value, label, className, ...props }) {
478
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx("agi-stat", className), ...props, children: [
479
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "agi-stat__v", children: value }),
480
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "agi-stat__k", children: label })
481
+ ] });
482
+ }
483
+ function Field({ label, hint, error, className, children, ...props }) {
484
+ return (
485
+ // biome-ignore lint/a11y/noLabelWithoutControl: the control is passed as children
486
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: cx("agi-field", className), ...props, children: [
487
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agi-field__label", children: label }),
488
+ children,
489
+ error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agi-field__error", children: error }) : hint && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agi-field__hint", children: hint })
490
+ ] })
491
+ );
492
+ }
493
+ var Input = (0, import_react.forwardRef)(
494
+ function Input2({ className, ...props }, ref) {
495
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { ref, className: cx("agi-input", className), ...props });
496
+ }
497
+ );
498
+ var Textarea = (0, import_react.forwardRef)(function Textarea2({ className, ...props }, ref) {
499
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", { ref, className: cx("agi-input", "agi-textarea", className), ...props });
500
+ });
501
+ function Spinner({ className, label }) {
502
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("output", { className: cx("agi-spinner", className), "aria-label": label, children: [
503
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {}),
504
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {}),
505
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {})
506
+ ] });
507
+ }
508
+
509
+ // src/provider.tsx
510
+ var import_react2 = require("react");
511
+
512
+ // src/i18n.ts
513
+ var STRINGS = {
514
+ chat: {
515
+ open: { tr: "Sohbeti a\xE7", en: "Open chat" },
516
+ close: { tr: "Kapat", en: "Close" },
517
+ placeholder: { tr: "Mesaj\u0131n\u0131z\u0131 yaz\u0131n\u2026", en: "Type your message\u2026" },
518
+ send: { tr: "G\xF6nder", en: "Send" },
519
+ stop: { tr: "Durdur", en: "Stop" },
520
+ attach: { tr: "Dosya ekle", en: "Attach file" },
521
+ attachments: { tr: "Ekler", en: "Attachments" },
522
+ removeFile: { tr: "Dosyay\u0131 kald\u0131r", en: "Remove file" },
523
+ tooManyFiles: { tr: "En fazla 5 dosya ekleyebilirsiniz.", en: "You can attach up to 5 files." },
524
+ fileTooLarge: {
525
+ tr: "Dosyalar 10 MB'tan k\xFC\xE7\xFCk olmal\u0131.",
526
+ en: "Files must be smaller than 10 MB."
527
+ },
528
+ welcome: {
529
+ tr: "Merhaba! Size nas\u0131l yard\u0131mc\u0131 olabilirim?",
530
+ en: "Hi there! How can I help you today?"
531
+ },
532
+ thinking: { tr: "Yan\u0131t haz\u0131rlan\u0131yor", en: "Working on it" },
533
+ stopped: { tr: "Yan\u0131t durduruldu.", en: "Response stopped." },
534
+ error: {
535
+ tr: "Bir sorun olu\u015Ftu. L\xFCtfen tekrar deneyin.",
536
+ en: "Something went wrong. Please try again."
537
+ },
538
+ unavailable: {
539
+ tr: "Bu sohbet \u015Fu anda kullan\u0131lam\u0131yor.",
540
+ en: "This chat is currently unavailable."
541
+ },
542
+ poweredBy: { tr: "Aginies ile", en: "Powered by Aginies" },
543
+ you: { tr: "Siz", en: "You" },
544
+ assistant: { tr: "Ajan", en: "Agent" }
545
+ },
546
+ auth: {
547
+ passwordTitle: { tr: "Bu sohbet parola korumal\u0131", en: "This chat is password protected" },
548
+ passwordHint: { tr: "Devam etmek i\xE7in parolay\u0131 girin.", en: "Enter the password to continue." },
549
+ password: { tr: "Parola", en: "Password" },
550
+ emailTitle: { tr: "E-posta ile do\u011Frulama", en: "Verify with your e-mail" },
551
+ emailHint: {
552
+ tr: "\u0130\u015F e-postan\u0131z\u0131 girin; size bir kod g\xF6nderece\u011Fiz.",
553
+ en: "Enter your work e-mail; we will send you a code."
554
+ },
555
+ email: { tr: "E-posta", en: "E-mail" },
556
+ code: { tr: "Do\u011Frulama kodu", en: "Verification code" },
557
+ codeHint: {
558
+ tr: "E-postan\u0131za gelen 6 haneli kodu girin.",
559
+ en: "Enter the 6-digit code from your e-mail."
560
+ },
561
+ continue: { tr: "Devam et", en: "Continue" },
562
+ sendCode: { tr: "Kod g\xF6nder", en: "Send code" },
563
+ verify: { tr: "Do\u011Frula", en: "Verify" },
564
+ back: { tr: "Geri", en: "Back" },
565
+ invalidPassword: { tr: "Parola yanl\u0131\u015F.", en: "Wrong password." },
566
+ invalidEmail: {
567
+ tr: "Bu e-posta adresi yetkili de\u011Fil.",
568
+ en: "This e-mail address is not allowed."
569
+ },
570
+ invalidCode: {
571
+ tr: "Kod ge\xE7ersiz veya s\xFCresi dolmu\u015F.",
572
+ en: "The code is invalid or has expired."
573
+ },
574
+ codeSent: { tr: "Kod g\xF6nderildi.", en: "Code sent." },
575
+ codeError: {
576
+ tr: "Kod g\xF6nderilemedi. L\xFCtfen tekrar deneyin.",
577
+ en: "The code could not be sent. Please try again."
578
+ },
579
+ resend: { tr: "Kodu yeniden g\xF6nder", en: "Resend code" },
580
+ ssoTitle: { tr: "Kurumsal giri\u015F gerekli", en: "Sign in with your organisation" },
581
+ ssoHint: {
582
+ tr: "Bu sohbet kurumsal kimlikle a\xE7\u0131l\u0131r.",
583
+ en: "This chat opens with your organisation account."
584
+ },
585
+ ssoButton: { tr: "Kurumsal giri\u015F", en: "Sign in" }
586
+ },
587
+ run: {
588
+ submit: { tr: "\xC7al\u0131\u015Ft\u0131r", en: "Run" },
589
+ cancel: { tr: "\u0130ptal", en: "Cancel" },
590
+ running: { tr: "\xC7al\u0131\u015F\u0131yor", en: "Running" },
591
+ done: { tr: "Tamamland\u0131", en: "Completed" },
592
+ error: { tr: "Hata", en: "Error" },
593
+ failed: { tr: "\xC7al\u0131\u015Ft\u0131rma ba\u015Far\u0131s\u0131z oldu.", en: "The run failed." },
594
+ unauthorized: { tr: "API anahtar\u0131 reddedildi.", en: "The API key was rejected." },
595
+ steps: { tr: "Ad\u0131mlar", en: "Steps" },
596
+ execution: { tr: "\xE7al\u0131\u015Ft\u0131rma", en: "execution" }
597
+ },
598
+ approval: {
599
+ eyebrow: { tr: "\u0130nsan onay\u0131", en: "Human approval" },
600
+ title: { tr: "Onay bekleyen ad\u0131m", en: "A step is waiting for approval" },
601
+ execution: { tr: "\xE7al\u0131\u015Ft\u0131rma", en: "execution" },
602
+ pausedAt: { tr: "duraklat\u0131ld\u0131", en: "paused" },
603
+ points: { tr: "Onay noktalar\u0131", en: "Approval points" },
604
+ point: { tr: "Nokta", en: "Point" },
605
+ output: { tr: "Ajan\u0131n \xF6nerisi", en: "What the agent proposes" },
606
+ queuePosition: { tr: "S\u0131ra", en: "Queue position" },
607
+ submit: { tr: "Onayla ve devam et", en: "Approve and continue" },
608
+ submitting: { tr: "G\xF6nderiliyor", en: "Submitting" },
609
+ refresh: { tr: "Yenile", en: "Refresh" },
610
+ required: { tr: "Bu alan zorunlu.", en: "This field is required." },
611
+ notANumber: { tr: "Say\u0131 girin.", en: "Enter a number." },
612
+ notJson: { tr: "Ge\xE7erli JSON girin.", en: "Enter valid JSON." },
613
+ notFound: {
614
+ tr: "Bu onay bulunamad\u0131; s\xFCresi dolmu\u015F veya tamamlanm\u0131\u015F olabilir.",
615
+ en: "This approval could not be found; it may have expired or been completed."
616
+ },
617
+ loadError: { tr: "Onay y\xFCklenemedi.", en: "The approval could not be loaded." },
618
+ resumeError: { tr: "Devam ettirilemedi.", en: "The run could not be resumed." },
619
+ resumedMessage: {
620
+ tr: "Ajan kald\u0131\u011F\u0131 yerden devam ediyor.",
621
+ en: "The agent is continuing from where it paused."
622
+ },
623
+ queuedMessage: {
624
+ tr: "Onay s\u0131raya al\u0131nd\u0131; \xF6nceki devam i\u015Flemleri bitince \xE7al\u0131\u015Facak.",
625
+ en: "The approval is queued; it runs after the earlier resumes finish."
626
+ },
627
+ paused: { tr: "Onay bekliyor", en: "Awaiting approval" },
628
+ queued: { tr: "S\u0131rada", en: "Queued" },
629
+ resuming: { tr: "Devam ediyor", en: "Resuming" },
630
+ resumed: { tr: "Devam etti", en: "Resumed" },
631
+ failed: { tr: "Ba\u015Far\u0131s\u0131z", en: "Failed" }
632
+ },
633
+ common: {
634
+ loading: { tr: "Y\xFCkleniyor", en: "Loading" },
635
+ retry: { tr: "Tekrar dene", en: "Retry" },
636
+ notActivated: {
637
+ tr: "Aginies UI paketi etkinle\u015Ftirilmedi.",
638
+ en: "The Aginies UI package is not activated."
639
+ }
640
+ }
641
+ };
642
+ function translator(locale) {
643
+ return function t(section, key) {
644
+ const entry = STRINGS[section][key];
645
+ return entry[locale] ?? entry.en;
646
+ };
647
+ }
648
+
649
+ // src/provider.tsx
650
+ var import_jsx_runtime2 = require("react/jsx-runtime");
651
+ var defaultClient = null;
652
+ function init(config) {
653
+ defaultClient = new AginiesClient(config);
654
+ void defaultClient.activate();
655
+ return defaultClient;
656
+ }
657
+ function getClient() {
658
+ return defaultClient;
659
+ }
660
+ var AginiesContext = (0, import_react2.createContext)(null);
661
+ function useModule(module2) {
662
+ const { client } = useAginies();
663
+ const allowed = client.hasModule(module2);
664
+ (0, import_react2.useEffect)(() => {
665
+ if (!allowed && typeof console !== "undefined") {
666
+ console.warn(`[aginies] the "${module2}" module is not enabled for this activation key`);
667
+ }
668
+ }, [allowed, module2]);
669
+ return allowed;
670
+ }
671
+ function AginiesProvider({
672
+ client,
673
+ locale,
674
+ fallback = null,
675
+ children
676
+ }) {
677
+ const resolved = client ?? defaultClient;
678
+ const [state, setState] = (0, import_react2.useState)(
679
+ resolved?.getState() ?? { status: "rejected", reason: "init() was not called" }
680
+ );
681
+ (0, import_react2.useEffect)(() => {
682
+ if (!resolved) return;
683
+ setState(resolved.getState());
684
+ const unsubscribe = resolved.subscribe(setState);
685
+ void resolved.activate();
686
+ return unsubscribe;
687
+ }, [resolved]);
688
+ (0, import_react2.useEffect)(() => {
689
+ if (state.status === "rejected" && typeof console !== "undefined") {
690
+ console.warn(`[aginies] UI kit not activated: ${state.reason}`);
691
+ }
692
+ }, [state]);
693
+ const value = (0, import_react2.useMemo)(() => {
694
+ if (!resolved) return null;
695
+ const l = locale ?? resolved.locale;
696
+ return { client: resolved, state, locale: l, t: translator(l) };
697
+ }, [resolved, state, locale]);
698
+ if (!value) return null;
699
+ if (state.status === "idle" || state.status === "activating") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: fallback });
700
+ if (state.status === "rejected") return null;
701
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AginiesContext.Provider, { value, children });
702
+ }
703
+ function useAginies() {
704
+ const ctx = (0, import_react2.useContext)(AginiesContext);
705
+ if (!ctx) {
706
+ throw new Error("[aginies] useAginies must be used inside <AginiesProvider> after init()");
707
+ }
708
+ return ctx;
709
+ }
710
+
711
+ // src/approval/approval-panel.tsx
712
+ var import_jsx_runtime3 = require("react/jsx-runtime");
713
+ function useApproval(workflowId, executionId, contextId) {
714
+ const { client, t } = useAginies();
715
+ const [status, setStatus] = (0, import_react3.useState)("loading");
716
+ const [execution, setExecution] = (0, import_react3.useState)(null);
717
+ const [selected, setSelected] = (0, import_react3.useState)(contextId ?? null);
718
+ const [values, setValues] = (0, import_react3.useState)({});
719
+ const [errors, setErrors] = (0, import_react3.useState)({});
720
+ const [error, setError] = (0, import_react3.useState)(null);
721
+ const [outcome, setOutcome] = (0, import_react3.useState)(null);
722
+ const selectedRef = (0, import_react3.useRef)(contextId ?? null);
723
+ const pausePoint = (0, import_react3.useMemo)(() => {
724
+ if (!execution) return null;
725
+ return execution.pausePoints.find((p) => p.contextId === selected) ?? execution.pausePoints.find((p) => p.resumeStatus === "paused") ?? execution.pausePoints[0] ?? null;
726
+ }, [execution, selected]);
727
+ const fields = (0, import_react3.useMemo)(() => fieldsOf(pausePoint), [pausePoint]);
728
+ const load = (0, import_react3.useCallback)(async () => {
729
+ setStatus("loading");
730
+ setError(null);
731
+ try {
732
+ const detail = await getPausedExecution(client, workflowId, executionId);
733
+ setExecution(detail);
734
+ const wanted = contextId ?? selectedRef.current;
735
+ const point = detail.pausePoints.find((p) => p.contextId === wanted) ?? detail.pausePoints.find((p) => p.resumeStatus === "paused") ?? detail.pausePoints[0];
736
+ if (point) {
737
+ selectedRef.current = point.contextId;
738
+ setSelected(point.contextId);
739
+ setValues(initialValues(fieldsOf(point)));
740
+ }
741
+ setErrors({});
742
+ setStatus("ready");
743
+ } catch (err) {
744
+ if (err instanceof AginiesError && err.code === "NOT_FOUND") setStatus("not-found");
745
+ else {
746
+ setError(err instanceof Error ? err.message : t("approval", "loadError"));
747
+ setStatus("error");
748
+ }
749
+ }
750
+ }, [client, workflowId, executionId, contextId, t]);
751
+ (0, import_react3.useEffect)(() => {
752
+ void load();
753
+ }, [load]);
754
+ const select = (0, import_react3.useCallback)(
755
+ (nextContextId) => {
756
+ selectedRef.current = nextContextId;
757
+ setSelected(nextContextId);
758
+ const point = execution?.pausePoints.find((p) => p.contextId === nextContextId);
759
+ setValues(initialValues(fieldsOf(point)));
760
+ setErrors({});
761
+ },
762
+ [execution]
763
+ );
764
+ const setValue = (0, import_react3.useCallback)((name, value) => {
765
+ setValues((v) => ({ ...v, [name]: value }));
766
+ setErrors((e) => {
767
+ if (!(name in e)) return e;
768
+ const { [name]: _drop, ...rest } = e;
769
+ return rest;
770
+ });
771
+ }, []);
772
+ const submit = (0, import_react3.useCallback)(async () => {
773
+ if (!pausePoint || status === "submitting") return;
774
+ const { submission, errors: problems } = buildSubmission(fields, values);
775
+ if (Object.keys(problems).length > 0) {
776
+ setErrors(
777
+ Object.fromEntries(
778
+ Object.entries(problems).map(([k, v]) => [
779
+ k,
780
+ v === "required" ? t("approval", "required") : v === "number" ? t("approval", "notANumber") : t("approval", "notJson")
781
+ ])
782
+ )
783
+ );
784
+ return;
785
+ }
786
+ setStatus("submitting");
787
+ setError(null);
788
+ try {
789
+ const result = await resumeExecution(
790
+ client,
791
+ workflowId,
792
+ executionId,
793
+ pausePoint.contextId,
794
+ fields.length > 0 ? submission : null
795
+ );
796
+ setOutcome(result);
797
+ setStatus(result.status === "queued" ? "queued" : "resumed");
798
+ } catch (err) {
799
+ setError(err instanceof Error ? err.message : t("approval", "resumeError"));
800
+ setStatus("ready");
801
+ }
802
+ }, [client, workflowId, executionId, pausePoint, fields, values, status, t]);
803
+ return {
804
+ status,
805
+ execution,
806
+ pausePoint,
807
+ fields,
808
+ values,
809
+ errors,
810
+ error,
811
+ outcome,
812
+ select,
813
+ setValue,
814
+ submit,
815
+ reload: load
816
+ };
817
+ }
818
+ var STATUS_TONE = {
819
+ paused: "warn",
820
+ queued: "signal",
821
+ resuming: "signal",
822
+ resumed: "ok",
823
+ failed: "bad"
824
+ };
825
+ function ApprovalPanel({
826
+ workflowId,
827
+ executionId,
828
+ contextId,
829
+ title,
830
+ description,
831
+ submitLabel,
832
+ onResumed,
833
+ hideOutput = false,
834
+ className
835
+ }) {
836
+ const { t, locale } = useAginies();
837
+ const enabled = useModule("approval");
838
+ const a = useApproval(workflowId, executionId, contextId);
839
+ const onResumedRef = (0, import_react3.useRef)(onResumed);
840
+ onResumedRef.current = onResumed;
841
+ (0, import_react3.useEffect)(() => {
842
+ if ((a.status === "resumed" || a.status === "queued") && a.outcome) {
843
+ onResumedRef.current?.(a.outcome);
844
+ }
845
+ }, [a.status, a.outcome]);
846
+ if (!enabled) return null;
847
+ const point = a.pausePoint;
848
+ const output = hideOutput ? {} : outputOf(point);
849
+ const outputEntries = Object.entries(output);
850
+ const canSubmit = point?.resumeStatus === "paused" && a.status === "ready";
851
+ const fmt = (iso) => iso ? new Date(iso).toLocaleString(locale === "tr" ? "tr-TR" : "en-GB") : "";
852
+ const onSubmit = (e) => {
853
+ e.preventDefault();
854
+ void a.submit();
855
+ };
856
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Panel, { className: cx("agi-approval", className), "aria-busy": a.status === "loading", children: [
857
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("header", { className: "agi-approval__head", children: [
858
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Eyebrow, { children: t("approval", "eyebrow") }),
859
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "agi-approval__title", children: title ?? t("approval", "title") }),
860
+ description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "agi-approval__desc", children: description }),
861
+ a.execution && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "agi-approval__meta", children: [
862
+ t("approval", "execution"),
863
+ " ",
864
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "agi-approval__meta-value", children: a.execution.executionId.slice(0, 8) }),
865
+ a.execution.pausedAt && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
866
+ " \xB7 ",
867
+ t("approval", "pausedAt"),
868
+ " ",
869
+ fmt(a.execution.pausedAt)
870
+ ] })
871
+ ] })
872
+ ] }),
873
+ a.status === "loading" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "agi-approval__state", children: [
874
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Spinner, { label: t("common", "loading") }),
875
+ " ",
876
+ t("common", "loading")
877
+ ] }),
878
+ a.status === "not-found" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "agi-approval__state", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: t("approval", "notFound") }) }),
879
+ a.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "agi-approval__state", children: [
880
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "agi-approval__error", children: a.error }),
881
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { variant: "outline", size: "sm", onClick: () => void a.reload(), children: t("common", "retry") })
882
+ ] }),
883
+ a.execution && a.execution.pausePoints.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("nav", { className: "agi-approval__points", "aria-label": t("approval", "points"), children: a.execution.pausePoints.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
884
+ "button",
885
+ {
886
+ type: "button",
887
+ className: cx(
888
+ "agi-approval__point",
889
+ p.contextId === point?.contextId && "is-selected"
890
+ ),
891
+ onClick: () => a.select(p.contextId),
892
+ children: [
893
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
894
+ t("approval", "point"),
895
+ " ",
896
+ i + 1
897
+ ] }),
898
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Tag, { tone: STATUS_TONE[p.resumeStatus] ?? "default", children: t("approval", p.resumeStatus) })
899
+ ]
900
+ },
901
+ p.contextId
902
+ )) }),
903
+ point && a.status !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
904
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "agi-approval__status", children: [
905
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Tag, { tone: STATUS_TONE[point.resumeStatus] ?? "default", children: t("approval", point.resumeStatus) }),
906
+ typeof point.queuePosition === "number" && point.queuePosition > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "agi-approval__queue", children: [
907
+ t("approval", "queuePosition"),
908
+ " ",
909
+ point.queuePosition
910
+ ] })
911
+ ] }),
912
+ outputEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "agi-approval__output", "aria-label": t("approval", "output"), children: [
913
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "agi-approval__output-label", children: t("approval", "output") }),
914
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dl", { className: "agi-approval__kv", children: outputEntries.map(([k, v]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "agi-approval__kv-row", children: [
915
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dt", { children: k }),
916
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dd", { children: typeof v === "string" ? v : JSON.stringify(v, null, 2) })
917
+ ] }, k)) })
918
+ ] }),
919
+ (a.status === "resumed" || a.status === "queued") && a.outcome ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("output", { className: "agi-approval__done", children: [
920
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Tag, { tone: a.status === "queued" ? "signal" : "ok", children: t("approval", a.status === "queued" ? "queued" : "resumed") }),
921
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: a.status === "queued" ? t("approval", "queuedMessage") : t("approval", "resumedMessage") })
922
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { className: "agi-approval__form", onSubmit, children: [
923
+ a.fields.map((f) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { label: f.label, hint: f.description, error: a.errors[f.name], children: renderField(f, a.values[f.name] ?? "", (v) => a.setValue(f.name, v), !canSubmit) }, f.id)),
924
+ a.error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "agi-approval__error", children: a.error }),
925
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "agi-approval__actions", children: [
926
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { variant: "signal", type: "submit", disabled: !canSubmit, children: a.status === "submitting" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
927
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Spinner, { label: t("approval", "submitting") }),
928
+ " ",
929
+ t("approval", "submitting")
930
+ ] }) : submitLabel ?? t("approval", "submit") }),
931
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
932
+ Button,
933
+ {
934
+ variant: "outline",
935
+ type: "button",
936
+ onClick: () => void a.reload(),
937
+ disabled: a.status === "submitting",
938
+ children: t("approval", "refresh")
939
+ }
940
+ )
941
+ ] })
942
+ ] })
943
+ ] })
944
+ ] });
945
+ }
946
+ function renderField(f, value, set, disabled) {
947
+ switch (f.type) {
948
+ case "boolean":
949
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
950
+ "select",
951
+ {
952
+ className: "agi-input",
953
+ value,
954
+ disabled,
955
+ onChange: (e) => set(e.target.value),
956
+ children: [
957
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: "\u2014" }),
958
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "true", children: "true" }),
959
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "false", children: "false" })
960
+ ]
961
+ }
962
+ );
963
+ case "number":
964
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
965
+ Input,
966
+ {
967
+ type: "number",
968
+ value,
969
+ placeholder: f.placeholder,
970
+ required: f.required,
971
+ disabled,
972
+ onChange: (e) => set(e.target.value)
973
+ }
974
+ );
975
+ case "array":
976
+ case "object":
977
+ case "files":
978
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
979
+ Textarea,
980
+ {
981
+ value,
982
+ rows: f.rows ?? 4,
983
+ placeholder: f.placeholder ?? "{ }",
984
+ required: f.required,
985
+ disabled,
986
+ className: "agi-approval__json",
987
+ onChange: (e) => set(e.target.value)
988
+ }
989
+ );
990
+ default:
991
+ if (Array.isArray(f.options) && f.options.length > 0) {
992
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
993
+ "select",
994
+ {
995
+ className: "agi-input",
996
+ value,
997
+ disabled,
998
+ onChange: (e) => set(e.target.value),
999
+ children: [
1000
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: "\u2014" }),
1001
+ f.options.map((o) => {
1002
+ const opt = typeof o === "object" && o !== null ? o : { value: o, label: o };
1003
+ const v = String(opt.value ?? "");
1004
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: v, children: String(opt.label ?? v) }, v);
1005
+ })
1006
+ ]
1007
+ }
1008
+ );
1009
+ }
1010
+ if ((f.rows ?? 1) > 1) {
1011
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1012
+ Textarea,
1013
+ {
1014
+ value,
1015
+ rows: f.rows,
1016
+ placeholder: f.placeholder,
1017
+ required: f.required,
1018
+ disabled,
1019
+ onChange: (e) => set(e.target.value)
1020
+ }
1021
+ );
1022
+ }
1023
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1024
+ Input,
1025
+ {
1026
+ value,
1027
+ placeholder: f.placeholder,
1028
+ required: f.required,
1029
+ disabled,
1030
+ onChange: (e) => set(e.target.value)
1031
+ }
1032
+ );
1033
+ }
1034
+ }
1035
+
1036
+ // src/chat/chat-widget.tsx
1037
+ var import_react5 = require("react");
1038
+
1039
+ // src/chat/markdown.tsx
1040
+ var import_react4 = require("react");
1041
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1042
+ function Markdown({ text, className }) {
1043
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, children: renderBlocks(parseBlocks(text)) });
1044
+ }
1045
+ var FENCE = /^\s*(`{3,}|~{3,})\s*([\w+-]*)\s*$/;
1046
+ var HEADING = /^(#{1,6})\s+(.*?)\s*#*\s*$/;
1047
+ var RULE = /^\s*([-*_])(?:\s*\1){2,}\s*$/;
1048
+ var QUOTE = /^\s*>\s?(.*)$/;
1049
+ var LIST = /^\s*(?:([-*+])|(\d{1,9})[.)])\s+(.*)$/;
1050
+ var TABLE_SEPARATOR = /^\s*\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?\s*$/;
1051
+ function parseBlocks(text) {
1052
+ const lines = text.replace(/\r\n?/g, "\n").split("\n");
1053
+ const blocks = [];
1054
+ let i = 0;
1055
+ let paragraph = [];
1056
+ const flush = () => {
1057
+ if (paragraph.length > 0) {
1058
+ blocks.push({ kind: "paragraph", lines: paragraph });
1059
+ paragraph = [];
1060
+ }
1061
+ };
1062
+ while (i < lines.length) {
1063
+ const line = lines[i];
1064
+ if (line.trim() === "") {
1065
+ flush();
1066
+ i += 1;
1067
+ continue;
1068
+ }
1069
+ const fence = FENCE.exec(line);
1070
+ if (fence) {
1071
+ flush();
1072
+ const marker = fence[1];
1073
+ const lang = fence[2] ?? "";
1074
+ const code = [];
1075
+ i += 1;
1076
+ while (i < lines.length && !lines[i].trim().startsWith(marker)) {
1077
+ code.push(lines[i]);
1078
+ i += 1;
1079
+ }
1080
+ i += 1;
1081
+ blocks.push({ kind: "code", lang, code: code.join("\n") });
1082
+ continue;
1083
+ }
1084
+ const heading = HEADING.exec(line);
1085
+ if (heading) {
1086
+ flush();
1087
+ blocks.push({ kind: "heading", level: heading[1].length, text: heading[2] ?? "" });
1088
+ i += 1;
1089
+ continue;
1090
+ }
1091
+ if (RULE.test(line)) {
1092
+ flush();
1093
+ blocks.push({ kind: "rule" });
1094
+ i += 1;
1095
+ continue;
1096
+ }
1097
+ if (QUOTE.test(line)) {
1098
+ flush();
1099
+ const inner = [];
1100
+ while (i < lines.length && QUOTE.test(lines[i])) {
1101
+ inner.push(QUOTE.exec(lines[i])[1] ?? "");
1102
+ i += 1;
1103
+ }
1104
+ blocks.push({ kind: "quote", blocks: parseBlocks(inner.join("\n")) });
1105
+ continue;
1106
+ }
1107
+ const list = LIST.exec(line);
1108
+ if (list) {
1109
+ flush();
1110
+ const ordered = list[2] !== void 0;
1111
+ const start = ordered ? Number.parseInt(list[2], 10) : 1;
1112
+ const items = [];
1113
+ while (i < lines.length) {
1114
+ const m = LIST.exec(lines[i]);
1115
+ if (m && m[2] !== void 0 === ordered) {
1116
+ items.push(m[3] ?? "");
1117
+ i += 1;
1118
+ } else if (items.length > 0 && lines[i].trim() !== "" && /^\s{2,}/.test(lines[i]) && !LIST.test(lines[i])) {
1119
+ items[items.length - 1] = `${items[items.length - 1]} ${lines[i].trim()}`;
1120
+ i += 1;
1121
+ } else {
1122
+ break;
1123
+ }
1124
+ }
1125
+ blocks.push({ kind: "list", ordered, start, items });
1126
+ continue;
1127
+ }
1128
+ if (line.includes("|") && i + 1 < lines.length && TABLE_SEPARATOR.test(lines[i + 1])) {
1129
+ flush();
1130
+ const header = splitRow(line);
1131
+ const align = splitRow(lines[i + 1]).map((cell) => {
1132
+ const left = cell.startsWith(":");
1133
+ const right = cell.endsWith(":");
1134
+ if (left && right) return "center";
1135
+ if (right) return "right";
1136
+ if (left) return "left";
1137
+ return null;
1138
+ });
1139
+ const rows = [];
1140
+ i += 2;
1141
+ while (i < lines.length && lines[i].includes("|")) {
1142
+ rows.push(splitRow(lines[i]));
1143
+ i += 1;
1144
+ }
1145
+ blocks.push({ kind: "table", header, align, rows });
1146
+ continue;
1147
+ }
1148
+ paragraph.push(line);
1149
+ i += 1;
1150
+ }
1151
+ flush();
1152
+ return blocks;
1153
+ }
1154
+ function splitRow(line) {
1155
+ const trimmed = line.trim().replace(/^\|/, "").replace(/\|$/, "");
1156
+ return trimmed.split(/(?<!\\)\|/).map((cell) => cell.replace(/\\\|/g, "|").trim());
1157
+ }
1158
+ function renderBlocks(blocks) {
1159
+ return blocks.map((block, index) => {
1160
+ switch (block.kind) {
1161
+ case "paragraph":
1162
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: block.lines.map((line, n) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react4.Fragment, { children: [
1163
+ n > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("br", {}),
1164
+ renderInline(line)
1165
+ ] }, n)) }, index);
1166
+ case "heading": {
1167
+ const Tag2 = `h${Math.min(block.level + 2, 6)}`;
1168
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Tag2, { children: renderInline(block.text) }, index);
1169
+ }
1170
+ case "code":
1171
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("pre", { "data-lang": block.lang || void 0, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("code", { children: block.code }) }, index);
1172
+ case "quote":
1173
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("blockquote", { children: renderBlocks(block.blocks) }, index);
1174
+ case "list": {
1175
+ const items = block.items.map((item, n) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: renderInline(item) }, n));
1176
+ return block.ordered ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ol", { start: block.start === 1 ? void 0 : block.start, children: items }, index) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { children: items }, index);
1177
+ }
1178
+ case "table":
1179
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "agi-md__table", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("table", { children: [
1180
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tr", { children: block.header.map((cell, n) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { style: alignStyle(block.align[n]), children: renderInline(cell) }, n)) }) }),
1181
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tbody", { children: block.rows.map((row, r) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tr", { children: block.header.map((_, n) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { style: alignStyle(block.align[n]), children: renderInline(row[n] ?? "") }, n)) }, r)) })
1182
+ ] }) }, index);
1183
+ case "rule":
1184
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("hr", {}, index);
1185
+ }
1186
+ });
1187
+ }
1188
+ function alignStyle(align) {
1189
+ return align ? { textAlign: align } : void 0;
1190
+ }
1191
+ var INLINE = /(`+)([\s\S]*?)\1|\*\*([\s\S]+?)\*\*|(?<![\w`])__([\s\S]+?)__(?![\w])|~~([\s\S]+?)~~|\*([^*\n]+?)\*|(?<![\w`])_([^_\n]+?)_(?![\w])|\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)|(https?:\/\/[^\s<]*[^\s<.,;:!?)\]'"])/g;
1192
+ function renderInline(text) {
1193
+ const nodes = [];
1194
+ let last = 0;
1195
+ let key = 0;
1196
+ const inline = new RegExp(INLINE.source, "g");
1197
+ let match = inline.exec(text);
1198
+ while (match) {
1199
+ if (match.index > last) nodes.push(text.slice(last, match.index));
1200
+ const [, , code, bold, boldAlt, strike, italic, italicAlt, linkText, linkHref, autoHref] = match;
1201
+ if (code !== void 0) {
1202
+ nodes.push(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("code", { children: code.trim() }, key++));
1203
+ } else if (bold !== void 0 || boldAlt !== void 0) {
1204
+ nodes.push(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: renderInline(bold ?? boldAlt) }, key++));
1205
+ } else if (strike !== void 0) {
1206
+ nodes.push(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("del", { children: renderInline(strike) }, key++));
1207
+ } else if (italic !== void 0 || italicAlt !== void 0) {
1208
+ nodes.push(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("em", { children: renderInline(italic ?? italicAlt) }, key++));
1209
+ } else if (linkText !== void 0 && linkHref !== void 0) {
1210
+ nodes.push(link(key++, linkHref, renderInline(linkText)));
1211
+ } else if (autoHref !== void 0) {
1212
+ nodes.push(link(key++, autoHref, autoHref));
1213
+ }
1214
+ last = match.index + match[0].length;
1215
+ match = inline.exec(text);
1216
+ }
1217
+ if (last < text.length) nodes.push(text.slice(last));
1218
+ return nodes;
1219
+ }
1220
+ var SAFE_HREF = /^(https?:\/\/|mailto:)/i;
1221
+ function link(key, href, children) {
1222
+ if (!SAFE_HREF.test(href)) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react4.Fragment, { children }, key);
1223
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", children }, key);
1224
+ }
1225
+
1226
+ // src/chat/structured-ui.tsx
1227
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1228
+ var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
1229
+ var isStringArray = (v) => Array.isArray(v) && v.every((x) => typeof x === "string");
1230
+ var isNumberArray = (v) => Array.isArray(v) && v.every((x) => typeof x === "number");
1231
+ function isCard(v) {
1232
+ return isObject(v) && typeof v.title === "string" && typeof v.subtitle === "string" && typeof v.body === "string" && typeof v.image === "string";
1233
+ }
1234
+ function normaliseItem(raw) {
1235
+ if (!isObject(raw)) return null;
1236
+ const text = raw.text;
1237
+ const buttons = raw.buttons;
1238
+ const table = raw.table;
1239
+ const pie = raw.pie;
1240
+ const image = raw.image;
1241
+ const cards = Array.isArray(raw.cards) ? raw.cards : raw.card ? [raw.card] : [];
1242
+ if (!isObject(text) || typeof text.content !== "string") return null;
1243
+ if (!Array.isArray(buttons) || !buttons.every(
1244
+ (b) => isObject(b) && typeof b.label === "string" && typeof b.action === "string"
1245
+ ))
1246
+ return null;
1247
+ if (!isObject(table) || !isStringArray(table.headers) || !Array.isArray(table.rows) || !table.rows.every(isStringArray))
1248
+ return null;
1249
+ if (!cards.every(isCard)) return null;
1250
+ if (!isObject(pie) || !isStringArray(pie.labels) || !isNumberArray(pie.data)) return null;
1251
+ if (!isObject(image) || typeof image.url !== "string" || typeof image.caption !== "string")
1252
+ return null;
1253
+ return {
1254
+ text: { content: text.content },
1255
+ buttons,
1256
+ table,
1257
+ cards,
1258
+ pie,
1259
+ image
1260
+ };
1261
+ }
1262
+ function parseStructured(raw) {
1263
+ let parsed;
1264
+ try {
1265
+ parsed = JSON.parse(raw);
1266
+ } catch {
1267
+ return null;
1268
+ }
1269
+ const list = Array.isArray(parsed) ? parsed : isObject(parsed) && Array.isArray(parsed.items) ? parsed.items : null;
1270
+ if (!list) return null;
1271
+ const items = list.map(normaliseItem);
1272
+ if (items.some((i) => i === null)) return null;
1273
+ return { items };
1274
+ }
1275
+ function StructuredUI({ response, onAction }) {
1276
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agi-sui", children: response.items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agi-sui__item", children: [
1277
+ item.text.content && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agi-sui__text", children: item.text.content }),
1278
+ item.image.url && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("figure", { className: "agi-sui__figure", children: [
1279
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { src: item.image.url, alt: item.image.caption }),
1280
+ item.image.caption && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("figcaption", { children: item.image.caption })
1281
+ ] }),
1282
+ item.cards.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agi-sui__cards", children: item.cards.map((c, ci) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agi-panel agi-sui__card", children: [
1283
+ c.image && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { src: c.image, alt: "" }),
1284
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1285
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agi-sui__card-title", children: c.title }),
1286
+ c.subtitle && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agi-sui__card-sub", children: c.subtitle }),
1287
+ c.body && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: c.body })
1288
+ ] })
1289
+ ] }, ci)) }),
1290
+ item.table.headers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agi-sui__scroll", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("table", { className: "agi-table", children: [
1291
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { children: item.table.headers.map((h, hi) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { children: h }, hi)) }) }),
1292
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tbody", { children: item.table.rows.map((r, ri) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { children: r.map((cell, ci) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { children: cell }, ci)) }, ri)) })
1293
+ ] }) }),
1294
+ item.pie.labels.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Pie, { labels: item.pie.labels, data: item.pie.data }),
1295
+ item.buttons.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agi-sui__actions", children: item.buttons.map((b, bi) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1296
+ "button",
1297
+ {
1298
+ type: "button",
1299
+ className: "agi-chip",
1300
+ onClick: () => onAction?.(b.action),
1301
+ children: b.label
1302
+ },
1303
+ bi
1304
+ )) })
1305
+ ] }, i)) });
1306
+ }
1307
+ function Pie({ labels, data }) {
1308
+ const total = data.reduce((a, b) => a + Math.max(0, b), 0);
1309
+ if (total <= 0) return null;
1310
+ let angle = 0;
1311
+ const slices = labels.map((label, i) => {
1312
+ const value = Math.max(0, data[i] ?? 0);
1313
+ const start = angle;
1314
+ angle += value / total * 360;
1315
+ return { label, value, start, end: angle, color: `var(--data-${i % 6 + 1})` };
1316
+ });
1317
+ const arc = (start, end) => {
1318
+ const r = 48;
1319
+ const cx2 = 50;
1320
+ const cy = 50;
1321
+ const a0 = (start - 90) * Math.PI / 180;
1322
+ const a1 = (end - 90) * Math.PI / 180;
1323
+ const large = end - start > 180 ? 1 : 0;
1324
+ const x0 = cx2 + r * Math.cos(a0);
1325
+ const y0 = cy + r * Math.sin(a0);
1326
+ const x1 = cx2 + r * Math.cos(a1);
1327
+ const y1 = cy + r * Math.sin(a1);
1328
+ if (end - start >= 360) return `M${cx2} ${cy - r} A${r} ${r} 0 1 1 ${cx2 - 0.01} ${cy - r} Z`;
1329
+ return `M${cx2} ${cy} L${x0} ${y0} A${r} ${r} 0 ${large} 1 ${x1} ${y1} Z`;
1330
+ };
1331
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agi-sui__pie", children: [
1332
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { viewBox: "0 0 100 100", role: "img", "aria-label": labels.join(", "), children: [
1333
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("title", { children: labels.join(", ") }),
1334
+ slices.map((s) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: arc(s.start, s.end), fill: s.color }, s.label))
1335
+ ] }),
1336
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { children: slices.map((s) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { children: [
1337
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { background: s.color } }),
1338
+ s.label,
1339
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("b", { children: [
1340
+ Math.round(s.value / total * 100),
1341
+ "%"
1342
+ ] })
1343
+ ] }, s.label)) })
1344
+ ] });
1345
+ }
1346
+
1347
+ // src/chat/chat-widget.tsx
1348
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1349
+ var ATTACHMENT_LIMITS = { maxFiles: 5, maxBytes: 10 * 1024 * 1024 };
1350
+ function useChat(identifier, enabled = true) {
1351
+ const { client, t } = useAginies();
1352
+ const [config, setConfig] = (0, import_react5.useState)(null);
1353
+ const [authNeed, setAuthNeed] = (0, import_react5.useState)(null);
1354
+ const [authTitle, setAuthTitle] = (0, import_react5.useState)();
1355
+ const [loadError, setLoadError] = (0, import_react5.useState)(null);
1356
+ const [messages, setMessages] = (0, import_react5.useState)([]);
1357
+ const [busy, setBusy] = (0, import_react5.useState)(false);
1358
+ const [conversationId] = (0, import_react5.useState)(() => randomId());
1359
+ const abortRef = (0, import_react5.useRef)(null);
1360
+ const load = (0, import_react5.useCallback)(async () => {
1361
+ setLoadError(null);
1362
+ try {
1363
+ const res = await client.getChat(identifier);
1364
+ if ("authRequired" in res) {
1365
+ setAuthNeed(res.authRequired === "public" ? null : res.authRequired);
1366
+ setAuthTitle(res.title);
1367
+ return;
1368
+ }
1369
+ setConfig(res);
1370
+ setAuthNeed(null);
1371
+ } catch (err) {
1372
+ setLoadError(
1373
+ err instanceof AginiesError && err.status === 403 ? t("chat", "unavailable") : t("chat", "error")
1374
+ );
1375
+ }
1376
+ }, [client, identifier, t]);
1377
+ (0, import_react5.useEffect)(() => {
1378
+ if (enabled) void load();
1379
+ }, [load, enabled]);
1380
+ const chatPath = `/api/chat/${encodeURIComponent(identifier)}`;
1381
+ const authenticate = (0, import_react5.useCallback)(
1382
+ async ({ password }) => {
1383
+ const res = await client.fetchRaw(chatPath, {
1384
+ method: "POST",
1385
+ headers: { "Content-Type": "application/json" },
1386
+ body: JSON.stringify({ password, conversationId })
1387
+ });
1388
+ if (res.ok) {
1389
+ await load();
1390
+ return true;
1391
+ }
1392
+ return false;
1393
+ },
1394
+ [client, chatPath, conversationId, load]
1395
+ );
1396
+ const requestCode = (0, import_react5.useCallback)(
1397
+ async (email) => {
1398
+ const res = await client.fetchRaw(`${chatPath}/otp`, {
1399
+ method: "POST",
1400
+ headers: { "Content-Type": "application/json" },
1401
+ body: JSON.stringify({ email })
1402
+ });
1403
+ if (res.ok) return "sent";
1404
+ return res.status === 403 ? "unauthorized" : "error";
1405
+ },
1406
+ [client, chatPath]
1407
+ );
1408
+ const verifyCode = (0, import_react5.useCallback)(
1409
+ async (email, otp) => {
1410
+ const res = await client.fetchRaw(`${chatPath}/otp`, {
1411
+ method: "PUT",
1412
+ headers: { "Content-Type": "application/json" },
1413
+ body: JSON.stringify({ email, otp })
1414
+ });
1415
+ if (res.ok) {
1416
+ await load();
1417
+ return true;
1418
+ }
1419
+ return false;
1420
+ },
1421
+ [client, chatPath, load]
1422
+ );
1423
+ const stop = (0, import_react5.useCallback)(() => {
1424
+ abortRef.current?.abort();
1425
+ abortRef.current = null;
1426
+ setBusy(false);
1427
+ setMessages((prev) => {
1428
+ const last = prev[prev.length - 1];
1429
+ if (!last || last.role !== "assistant" || !last.streaming) return prev;
1430
+ return [
1431
+ ...prev.slice(0, -1),
1432
+ { ...last, streaming: false, content: last.content || t("chat", "stopped") }
1433
+ ];
1434
+ });
1435
+ }, [t]);
1436
+ const send = (0, import_react5.useCallback)(
1437
+ async (text, files = []) => {
1438
+ const input = text.trim();
1439
+ if (!input && files.length === 0 || busy) return;
1440
+ const userMessage = {
1441
+ id: randomId(),
1442
+ role: "user",
1443
+ content: input,
1444
+ attachments: files.map(({ name, type, size }) => ({ name, type, size }))
1445
+ };
1446
+ const assistantId = randomId();
1447
+ setMessages((prev) => [
1448
+ ...prev,
1449
+ userMessage,
1450
+ { id: assistantId, role: "assistant", content: "", streaming: true }
1451
+ ]);
1452
+ setBusy(true);
1453
+ const controller = new AbortController();
1454
+ abortRef.current = controller;
1455
+ let content = "";
1456
+ const update = (patch) => setMessages((prev) => prev.map((m) => m.id === assistantId ? { ...m, ...patch } : m));
1457
+ try {
1458
+ for await (const ev of client.sendMessage(
1459
+ identifier,
1460
+ { input, conversationId, files },
1461
+ controller.signal
1462
+ )) {
1463
+ if (ev.type === "chunk") {
1464
+ content += ev.text;
1465
+ update({ content });
1466
+ } else if (ev.type === "final") {
1467
+ const text2 = extractFinalText(ev.data);
1468
+ if (text2 && !content) {
1469
+ content = text2;
1470
+ update({ content });
1471
+ }
1472
+ } else if (ev.type === "error") {
1473
+ update({ content: ev.message, error: true, streaming: false });
1474
+ }
1475
+ }
1476
+ update({ streaming: false, structured: parseStructured(content) });
1477
+ } catch (err) {
1478
+ if (controller.signal.aborted) return;
1479
+ const message = err instanceof AginiesError && err.code === "AUTH_REQUIRED" ? t("chat", "unavailable") : t("chat", "error");
1480
+ update({ content: message, error: true, streaming: false });
1481
+ if (err instanceof AginiesError && err.code === "AUTH_REQUIRED") void load();
1482
+ } finally {
1483
+ abortRef.current = null;
1484
+ setBusy(false);
1485
+ }
1486
+ },
1487
+ [busy, client, identifier, conversationId, t, load]
1488
+ );
1489
+ return {
1490
+ config,
1491
+ authNeed,
1492
+ authTitle,
1493
+ loadError,
1494
+ messages,
1495
+ busy,
1496
+ send,
1497
+ stop,
1498
+ authenticate,
1499
+ requestCode,
1500
+ verifyCode,
1501
+ reload: load
1502
+ };
1503
+ }
1504
+ function extractFinalText(data) {
1505
+ if (!data || typeof data !== "object") return null;
1506
+ const d = data;
1507
+ if (!d.output) return null;
1508
+ for (const block of Object.values(d.output)) {
1509
+ if (block && typeof block === "object") {
1510
+ const b = block;
1511
+ if (typeof b.content === "string") return b.content;
1512
+ if (typeof b.result === "string") return b.result;
1513
+ }
1514
+ }
1515
+ return null;
1516
+ }
1517
+ function randomId() {
1518
+ if (typeof crypto !== "undefined" && "randomUUID" in crypto) return crypto.randomUUID();
1519
+ return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
1520
+ }
1521
+ function ChatWidget({
1522
+ identifier,
1523
+ mode = "inline",
1524
+ position = "right",
1525
+ launcherLabel,
1526
+ defaultOpen = false,
1527
+ theme = "auto",
1528
+ className
1529
+ }) {
1530
+ const [open, setOpen] = (0, import_react5.useState)(defaultOpen || mode !== "bubble");
1531
+ const { t } = useAginies();
1532
+ const enabled = useModule("chat");
1533
+ const chat = useChat(identifier, enabled);
1534
+ const title = chat.config?.title ?? chat.authTitle ?? launcherLabel ?? "Aginies";
1535
+ const themeClass = theme === "auto" ? void 0 : theme === "dark" ? "dark" : "light";
1536
+ if (!enabled) return null;
1537
+ const panel = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1538
+ "section",
1539
+ {
1540
+ className: cx("agi-chat", `agi-chat--${mode}`, themeClass, className),
1541
+ "data-theme": themeClass,
1542
+ "aria-label": title,
1543
+ children: [
1544
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("header", { className: "agi-chat__head", children: [
1545
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agi-chat__title", children: [
1546
+ chat.config?.customizations.imageUrl && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("img", { src: chat.config.customizations.imageUrl, alt: "" }),
1547
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
1548
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agi-chat__name", children: title }),
1549
+ chat.config?.description && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agi-chat__desc", children: chat.config.description })
1550
+ ] })
1551
+ ] }),
1552
+ mode === "bubble" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1553
+ "button",
1554
+ {
1555
+ type: "button",
1556
+ className: "agi-chat__close",
1557
+ onClick: () => setOpen(false),
1558
+ "aria-label": t("chat", "close"),
1559
+ children: "\xD7"
1560
+ }
1561
+ )
1562
+ ] }),
1563
+ chat.loadError ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agi-chat__state", children: [
1564
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: chat.loadError }),
1565
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { variant: "outline", size: "sm", onClick: () => void chat.reload(), children: t("common", "retry") })
1566
+ ] }) : chat.authNeed ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1567
+ ChatAuth,
1568
+ {
1569
+ need: chat.authNeed,
1570
+ onPassword: chat.authenticate,
1571
+ onRequestCode: chat.requestCode,
1572
+ onVerifyCode: chat.verifyCode
1573
+ }
1574
+ ) : !chat.config ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agi-chat__state", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Spinner, { label: t("common", "loading") }) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1575
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1576
+ MessageList,
1577
+ {
1578
+ messages: chat.messages,
1579
+ welcome: chat.config.customizations.welcomeMessage || t("chat", "welcome"),
1580
+ onAction: (action) => void chat.send(action)
1581
+ }
1582
+ ),
1583
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Composer, { busy: chat.busy, onSend: chat.send, onStop: chat.stop })
1584
+ ] }),
1585
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("footer", { className: "agi-chat__foot", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("a", { href: "https://www.aginies.com", target: "_blank", rel: "noreferrer", children: t("chat", "poweredBy") }) })
1586
+ ]
1587
+ }
1588
+ );
1589
+ if (mode !== "bubble") return panel;
1590
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1591
+ "div",
1592
+ {
1593
+ className: cx("agi-bubble", `agi-bubble--${position}`, themeClass),
1594
+ "data-theme": themeClass,
1595
+ children: [
1596
+ open && panel,
1597
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1598
+ "button",
1599
+ {
1600
+ type: "button",
1601
+ className: cx("agi-bubble__launcher", open && "agi-bubble__launcher--open"),
1602
+ onClick: () => setOpen((o) => !o),
1603
+ "aria-expanded": open,
1604
+ "aria-label": open ? t("chat", "close") : t("chat", "open"),
1605
+ children: [
1606
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1607
+ "svg",
1608
+ {
1609
+ width: "22",
1610
+ height: "22",
1611
+ viewBox: "0 0 24 24",
1612
+ fill: "none",
1613
+ stroke: "currentColor",
1614
+ strokeWidth: "1.7",
1615
+ strokeLinecap: "round",
1616
+ strokeLinejoin: "round",
1617
+ "aria-hidden": "true",
1618
+ children: [
1619
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M4 5.5A2.5 2.5 0 0 1 6.5 3h11A2.5 2.5 0 0 1 20 5.5v8a2.5 2.5 0 0 1-2.5 2.5H10l-5 4v-4H6.5A2.5 2.5 0 0 1 4 13.5v-8z" }),
1620
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M8 8h8M8 11.5h5" })
1621
+ ]
1622
+ }
1623
+ ),
1624
+ !open && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: launcherLabel ?? title })
1625
+ ]
1626
+ }
1627
+ )
1628
+ ]
1629
+ }
1630
+ );
1631
+ }
1632
+ function MessageList({
1633
+ messages,
1634
+ welcome,
1635
+ onAction
1636
+ }) {
1637
+ const { t } = useAginies();
1638
+ const endRef = (0, import_react5.useRef)(null);
1639
+ (0, import_react5.useEffect)(() => {
1640
+ endRef.current?.scrollIntoView?.({ block: "end" });
1641
+ }, []);
1642
+ return (
1643
+ // biome-ignore lint/a11y/useSemanticElements: no native element conveys a live log
1644
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agi-chat__messages", role: "log", "aria-live": "polite", children: [
1645
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agi-msg agi-msg--assistant", children: [
1646
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agi-msg__who", children: t("chat", "assistant") }),
1647
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agi-msg__body", children: welcome })
1648
+ ] }),
1649
+ messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1650
+ "div",
1651
+ {
1652
+ className: cx("agi-msg", `agi-msg--${m.role}`, m.error && "agi-msg--error"),
1653
+ children: [
1654
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agi-msg__who", children: m.role === "user" ? t("chat", "you") : t("chat", "assistant") }),
1655
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agi-msg__body", children: [
1656
+ m.structured ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StructuredUI, { response: m.structured, onAction }) : m.content ? m.role === "assistant" && !m.error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Markdown, { className: "agi-md", text: m.content }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: m.content }) : m.streaming ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "agi-msg__thinking", children: [
1657
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Spinner, { label: t("chat", "thinking") }),
1658
+ " ",
1659
+ t("chat", "thinking")
1660
+ ] }) : null,
1661
+ m.attachments && m.attachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "agi-msg__files", "aria-label": t("chat", "attachments"), children: m.attachments.map((file, n) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("li", { className: "agi-file", children: [
1662
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FileGlyph, {}),
1663
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agi-file__name", children: file.name }),
1664
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agi-file__size", children: formatBytes(file.size) })
1665
+ ] }, n)) })
1666
+ ] })
1667
+ ]
1668
+ },
1669
+ m.id
1670
+ )),
1671
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: endRef })
1672
+ ] })
1673
+ );
1674
+ }
1675
+ function Composer({
1676
+ busy,
1677
+ onSend,
1678
+ onStop
1679
+ }) {
1680
+ const { t } = useAginies();
1681
+ const [value, setValue] = (0, import_react5.useState)("");
1682
+ const [files, setFiles] = (0, import_react5.useState)([]);
1683
+ const [fileError, setFileError] = (0, import_react5.useState)(null);
1684
+ const fileInput = (0, import_react5.useRef)(null);
1685
+ const submit = (e) => {
1686
+ e.preventDefault();
1687
+ if (busy) return;
1688
+ const text = value;
1689
+ const attached = files;
1690
+ setValue("");
1691
+ setFiles([]);
1692
+ setFileError(null);
1693
+ void onSend(text, attached);
1694
+ };
1695
+ const pick = async (e) => {
1696
+ const chosen = Array.from(e.target.files ?? []);
1697
+ e.target.value = "";
1698
+ if (chosen.length === 0) return;
1699
+ if (files.length + chosen.length > ATTACHMENT_LIMITS.maxFiles) {
1700
+ setFileError(t("chat", "tooManyFiles"));
1701
+ return;
1702
+ }
1703
+ if (chosen.some((file) => file.size > ATTACHMENT_LIMITS.maxBytes)) {
1704
+ setFileError(t("chat", "fileTooLarge"));
1705
+ return;
1706
+ }
1707
+ setFileError(null);
1708
+ const payloads = await Promise.all(chosen.map(readFile));
1709
+ setFiles((prev) => [...prev, ...payloads]);
1710
+ };
1711
+ const canSend = value.trim().length > 0 || files.length > 0;
1712
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { className: "agi-chat__composer", onSubmit: submit, children: [
1713
+ (files.length > 0 || fileError) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agi-chat__pending", children: [
1714
+ files.map((file, n) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "agi-file agi-file--pending", children: [
1715
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FileGlyph, {}),
1716
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agi-file__name", children: file.name }),
1717
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1718
+ "button",
1719
+ {
1720
+ type: "button",
1721
+ className: "agi-file__remove",
1722
+ "aria-label": `${t("chat", "removeFile")}: ${file.name}`,
1723
+ onClick: () => setFiles((prev) => prev.filter((_, i) => i !== n)),
1724
+ children: "\xD7"
1725
+ }
1726
+ )
1727
+ ] }, n)),
1728
+ fileError && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agi-chat__file-error", children: fileError })
1729
+ ] }),
1730
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agi-chat__row", children: [
1731
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1732
+ "input",
1733
+ {
1734
+ ref: fileInput,
1735
+ type: "file",
1736
+ multiple: true,
1737
+ hidden: true,
1738
+ onChange: pick,
1739
+ "data-testid": "agi-file-input"
1740
+ }
1741
+ ),
1742
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1743
+ Button,
1744
+ {
1745
+ variant: "ghost",
1746
+ type: "button",
1747
+ "aria-label": t("chat", "attach"),
1748
+ title: t("chat", "attach"),
1749
+ disabled: busy,
1750
+ onClick: () => fileInput.current?.click(),
1751
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1752
+ "path",
1753
+ {
1754
+ d: "M21 12.5 12.8 20.7a5.5 5.5 0 0 1-7.8-7.8l8.6-8.6a3.5 3.5 0 0 1 5 5l-8.6 8.6a1.5 1.5 0 0 1-2.1-2.1L15.5 8",
1755
+ stroke: "currentColor",
1756
+ strokeWidth: "1.6",
1757
+ strokeLinecap: "round",
1758
+ strokeLinejoin: "round"
1759
+ }
1760
+ ) })
1761
+ }
1762
+ ),
1763
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1764
+ Input,
1765
+ {
1766
+ value,
1767
+ onChange: (e) => setValue(e.target.value),
1768
+ placeholder: t("chat", "placeholder"),
1769
+ "aria-label": t("chat", "placeholder"),
1770
+ autoComplete: "off"
1771
+ }
1772
+ ),
1773
+ busy ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { variant: "outline", onClick: onStop, children: t("chat", "stop") }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { variant: "signal", type: "submit", disabled: !canSend, children: t("chat", "send") })
1774
+ ] })
1775
+ ] });
1776
+ }
1777
+ function readFile(file) {
1778
+ return new Promise((resolve, reject) => {
1779
+ const reader = new FileReader();
1780
+ reader.onload = () => resolve({
1781
+ name: file.name,
1782
+ type: file.type || "application/octet-stream",
1783
+ size: file.size,
1784
+ data: String(reader.result),
1785
+ lastModified: file.lastModified
1786
+ });
1787
+ reader.onerror = () => reject(reader.error);
1788
+ reader.readAsDataURL(file);
1789
+ });
1790
+ }
1791
+ function formatBytes(size) {
1792
+ if (size < 1024) return `${size} B`;
1793
+ if (size < 1024 * 1024) return `${(size / 1024).toFixed(0)} KB`;
1794
+ return `${(size / (1024 * 1024)).toFixed(1)} MB`;
1795
+ }
1796
+ function FileGlyph() {
1797
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
1798
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1799
+ "path",
1800
+ {
1801
+ d: "M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8l-5-5z",
1802
+ stroke: "currentColor",
1803
+ strokeWidth: "1.8",
1804
+ strokeLinejoin: "round"
1805
+ }
1806
+ ),
1807
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M14 3v5h5", stroke: "currentColor", strokeWidth: "1.8", strokeLinejoin: "round" })
1808
+ ] });
1809
+ }
1810
+ function ChatAuth({
1811
+ need,
1812
+ onPassword,
1813
+ onRequestCode,
1814
+ onVerifyCode
1815
+ }) {
1816
+ const { t, client } = useAginies();
1817
+ if (need === "sso") {
1818
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agi-chat__state", children: [
1819
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: t("auth", "ssoTitle") }),
1820
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: t("auth", "ssoHint") }),
1821
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1822
+ Button,
1823
+ {
1824
+ variant: "signal",
1825
+ onClick: () => window.open(`${client.baseUrl}/chat/`, "_blank", "noopener"),
1826
+ children: t("auth", "ssoButton")
1827
+ }
1828
+ )
1829
+ ] });
1830
+ }
1831
+ if (need === "email") {
1832
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(EmailAuth, { onRequestCode, onVerifyCode });
1833
+ }
1834
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PasswordAuth, { onPassword });
1835
+ }
1836
+ function PasswordAuth({
1837
+ onPassword
1838
+ }) {
1839
+ const { t } = useAginies();
1840
+ const [value, setValue] = (0, import_react5.useState)("");
1841
+ const [error, setError] = (0, import_react5.useState)(null);
1842
+ const [pending, setPending] = (0, import_react5.useState)(false);
1843
+ const submit = async (e) => {
1844
+ e.preventDefault();
1845
+ setPending(true);
1846
+ setError(null);
1847
+ const ok = await onPassword({ password: value });
1848
+ setPending(false);
1849
+ if (!ok) setError(t("auth", "invalidPassword"));
1850
+ };
1851
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { className: "agi-chat__state agi-chat__auth", onSubmit: submit, children: [
1852
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: t("auth", "passwordTitle") }),
1853
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: t("auth", "passwordHint") }),
1854
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Field, { label: t("auth", "password"), error: error ?? void 0, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1855
+ Input,
1856
+ {
1857
+ type: "password",
1858
+ value,
1859
+ onChange: (e) => setValue(e.target.value),
1860
+ required: true,
1861
+ autoComplete: "current-password"
1862
+ }
1863
+ ) }),
1864
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { variant: "signal", type: "submit", disabled: pending || !value, children: t("auth", "continue") })
1865
+ ] });
1866
+ }
1867
+ function EmailAuth({
1868
+ onRequestCode,
1869
+ onVerifyCode
1870
+ }) {
1871
+ const { t } = useAginies();
1872
+ const [email, setEmail] = (0, import_react5.useState)("");
1873
+ const [code, setCode] = (0, import_react5.useState)("");
1874
+ const [step, setStep] = (0, import_react5.useState)("email");
1875
+ const [error, setError] = (0, import_react5.useState)(null);
1876
+ const [notice, setNotice] = (0, import_react5.useState)(null);
1877
+ const [pending, setPending] = (0, import_react5.useState)(false);
1878
+ const request = async () => {
1879
+ setPending(true);
1880
+ setError(null);
1881
+ setNotice(null);
1882
+ const result = await onRequestCode(email.trim());
1883
+ setPending(false);
1884
+ if (result === "sent") {
1885
+ setStep("code");
1886
+ setNotice(t("auth", "codeSent"));
1887
+ } else {
1888
+ setError(t("auth", result === "unauthorized" ? "invalidEmail" : "codeError"));
1889
+ }
1890
+ };
1891
+ const verify = async () => {
1892
+ setPending(true);
1893
+ setError(null);
1894
+ setNotice(null);
1895
+ const ok = await onVerifyCode(email.trim(), code.trim());
1896
+ setPending(false);
1897
+ if (!ok) setError(t("auth", "invalidCode"));
1898
+ };
1899
+ const submit = (e) => {
1900
+ e.preventDefault();
1901
+ void (step === "email" ? request() : verify());
1902
+ };
1903
+ if (step === "code") {
1904
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { className: "agi-chat__state agi-chat__auth", onSubmit: submit, children: [
1905
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: t("auth", "emailTitle") }),
1906
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { children: [
1907
+ t("auth", "codeHint"),
1908
+ " ",
1909
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: email })
1910
+ ] }),
1911
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Field, { label: t("auth", "code"), error: error ?? void 0, hint: notice ?? void 0, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1912
+ Input,
1913
+ {
1914
+ inputMode: "numeric",
1915
+ autoComplete: "one-time-code",
1916
+ pattern: "[0-9]{6}",
1917
+ maxLength: 6,
1918
+ value: code,
1919
+ onChange: (e) => setCode(e.target.value.replace(/\D/g, "")),
1920
+ required: true
1921
+ }
1922
+ ) }),
1923
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agi-chat__auth-actions", children: [
1924
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { variant: "signal", type: "submit", disabled: pending || code.length !== 6, children: t("auth", "verify") }),
1925
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { variant: "ghost", type: "button", disabled: pending, onClick: () => void request(), children: t("auth", "resend") }),
1926
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1927
+ Button,
1928
+ {
1929
+ variant: "ghost",
1930
+ type: "button",
1931
+ disabled: pending,
1932
+ onClick: () => {
1933
+ setStep("email");
1934
+ setCode("");
1935
+ setError(null);
1936
+ setNotice(null);
1937
+ },
1938
+ children: t("auth", "back")
1939
+ }
1940
+ )
1941
+ ] })
1942
+ ] });
1943
+ }
1944
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { className: "agi-chat__state agi-chat__auth", onSubmit: submit, children: [
1945
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: t("auth", "emailTitle") }),
1946
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: t("auth", "emailHint") }),
1947
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Field, { label: t("auth", "email"), error: error ?? void 0, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1948
+ Input,
1949
+ {
1950
+ type: "email",
1951
+ value: email,
1952
+ onChange: (e) => setEmail(e.target.value),
1953
+ required: true,
1954
+ autoComplete: "email"
1955
+ }
1956
+ ) }),
1957
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { variant: "signal", type: "submit", disabled: pending || !email.trim(), children: t("auth", "sendCode") })
1958
+ ] });
1959
+ }
1960
+
1961
+ // src/observability/index.tsx
1962
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1963
+ function StatTiles({
1964
+ items,
1965
+ className,
1966
+ ...props
1967
+ }) {
1968
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: cx("agi-stats", className), ...props, children: items.map((s) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "agi-panel agi-stats__tile", children: [
1969
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: cx("agi-stat__v", s.tone && s.tone !== "default" && `is-${s.tone}`), children: s.value }),
1970
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "agi-stat__k", children: s.label }),
1971
+ s.delta && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "agi-stats__delta", children: s.delta })
1972
+ ] }, s.label)) });
1973
+ }
1974
+ var pct = (v) => `${(v * 100).toFixed(1)}%`;
1975
+ function SuccessHeatmap({
1976
+ rows,
1977
+ columns,
1978
+ thresholds = { warn: 0.95, bad: 0.85 },
1979
+ format = pct,
1980
+ className,
1981
+ ...props
1982
+ }) {
1983
+ const cols = columns ?? Array.from({ length: rows[0]?.values.length ?? 0 }, (_, i) => String(i + 1));
1984
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: cx("agi-heat", className), ...props, children: [
1985
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("table", { className: "agi-heat__table", children: [
1986
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("tr", { children: [
1987
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { className: "agi-heat__label" }),
1988
+ cols.map((c) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { className: "agi-heat__col", scope: "col", children: c }, c))
1989
+ ] }) }),
1990
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tbody", { children: rows.map((r) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("tr", { children: [
1991
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { className: "agi-heat__label", scope: "row", children: r.label }),
1992
+ r.values.map((v, i) => {
1993
+ const tone = v === null ? "none" : v < thresholds.bad ? "bad" : v < thresholds.warn ? "warn" : "ok";
1994
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { className: "agi-heat__td", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1995
+ "span",
1996
+ {
1997
+ className: cx("agi-heat__cell", `is-${tone}`),
1998
+ title: v === null ? "\u2014" : format(v),
1999
+ style: v === null ? void 0 : { opacity: 0.35 + 0.65 * Math.min(1, Math.max(0, (v - 0.5) / 0.5)) }
2000
+ }
2001
+ ) }, i);
2002
+ })
2003
+ ] }, r.label)) })
2004
+ ] }),
2005
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "agi-heat__legend", children: [
2006
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Tag, { tone: "ok", children: [
2007
+ "\u2265 ",
2008
+ pct(thresholds.warn)
2009
+ ] }),
2010
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Tag, { tone: "warn", children: [
2011
+ "\u2265 ",
2012
+ pct(thresholds.bad)
2013
+ ] }),
2014
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Tag, { tone: "bad", children: [
2015
+ "< ",
2016
+ pct(thresholds.bad)
2017
+ ] })
2018
+ ] })
2019
+ ] });
2020
+ }
2021
+ var GLYPH = {
2022
+ ingest: "\u25E6",
2023
+ plan: "\u2318",
2024
+ retrieve: "\u2315",
2025
+ reason: "\u223F",
2026
+ tool: "\u2699",
2027
+ verify: "\u2713",
2028
+ approval: "\u23F8",
2029
+ write: "\u21E2",
2030
+ notify: "\u27A4"
2031
+ };
2032
+ var fmtMs = (x) => x < 1e3 ? `${Math.round(x)} ms` : `${(x / 1e3).toFixed(1)} s`;
2033
+ function RunTimeline({ steps, totalMs, className, ...props }) {
2034
+ const end = totalMs ?? Math.max(1, ...steps.map((s) => s.startMs + (s.durationMs ?? 0)));
2035
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ol", { className: cx("agi-timeline", className), ...props, children: steps.map((s) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2036
+ "li",
2037
+ {
2038
+ className: cx("agi-timeline__step", `is-${s.status}`, s.kind && `k-${s.kind}`),
2039
+ children: [
2040
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "agi-timeline__glyph", "aria-hidden": "true", children: s.kind ? GLYPH[s.kind] : "\u2022" }),
2041
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "agi-timeline__name", children: [
2042
+ s.name,
2043
+ s.detail && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "agi-timeline__detail", children: s.detail })
2044
+ ] }),
2045
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "agi-timeline__bar", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2046
+ "span",
2047
+ {
2048
+ className: "agi-timeline__fill",
2049
+ style: {
2050
+ left: `${s.startMs / end * 100}%`,
2051
+ width: `${Math.max(1, (s.durationMs ?? 0) / end * 100)}%`
2052
+ }
2053
+ }
2054
+ ) }),
2055
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "agi-timeline__meta", children: [
2056
+ s.durationMs !== void 0 && fmtMs(s.durationMs),
2057
+ s.tokens !== void 0 && ` \xB7 ${s.tokens} tok`,
2058
+ s.costUsd !== void 0 && ` \xB7 $${s.costUsd.toFixed(3)}`
2059
+ ] })
2060
+ ]
2061
+ },
2062
+ s.id
2063
+ )) });
2064
+ }
2065
+ var usd = (v) => `$${v.toFixed(2)}`;
2066
+ function CostBars({ items, format = usd, className, ...props }) {
2067
+ const max = Math.max(1e-9, ...items.map((i) => i.value));
2068
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: cx("agi-bars", className), ...props, children: items.map((i, idx) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "agi-bars__row", children: [
2069
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "agi-bars__label", children: i.label }),
2070
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "agi-bars__track", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2071
+ "span",
2072
+ {
2073
+ className: "agi-bars__fill",
2074
+ style: {
2075
+ width: `${i.value / max * 100}%`,
2076
+ background: `var(--data-${idx % 6 + 1})`
2077
+ }
2078
+ }
2079
+ ) }),
2080
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "agi-bars__value", children: [
2081
+ format(i.value),
2082
+ i.note && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "agi-bars__note", children: i.note })
2083
+ ] })
2084
+ ] }, i.label)) });
2085
+ }
2086
+
2087
+ // src/run/agent-runner.tsx
2088
+ var import_react6 = require("react");
2089
+
2090
+ // src/run/run-client.ts
2091
+ async function* runAgent(client, workflowId, options, signal) {
2092
+ const res = await client.fetchRaw(`/api/workflows/${encodeURIComponent(workflowId)}/execute`, {
2093
+ method: "POST",
2094
+ headers: {
2095
+ "Content-Type": "application/json",
2096
+ "X-API-Key": options.apiKey,
2097
+ "X-Stream-Response": "true"
2098
+ },
2099
+ credentials: "omit",
2100
+ body: JSON.stringify({
2101
+ input: options.input,
2102
+ stream: true,
2103
+ triggerType: "api",
2104
+ selectedOutputs: options.selectedOutputs
2105
+ }),
2106
+ signal
2107
+ });
2108
+ const executionId = res.headers.get("X-Execution-Id") ?? void 0;
2109
+ if (!res.ok) {
2110
+ let message = `HTTP ${res.status}`;
2111
+ try {
2112
+ const body = await res.json();
2113
+ if (body.error) message = body.error;
2114
+ } catch {
2115
+ }
2116
+ throw new AginiesError(message, res.status, res.status === 401 ? "UNAUTHORIZED" : void 0);
2117
+ }
2118
+ yield { type: "started", executionId };
2119
+ const contentType = res.headers.get("content-type") ?? "";
2120
+ if (!contentType.includes("text/event-stream")) {
2121
+ const body = await res.json();
2122
+ if (body.success === false) yield { type: "error", message: body.error ?? "Run failed" };
2123
+ else yield { type: "done", output: body.output ?? body, success: true };
2124
+ return;
2125
+ }
2126
+ yield* parseRunSSE(res.body);
2127
+ }
2128
+ async function* parseRunSSE(stream) {
2129
+ const reader = stream.getReader();
2130
+ const decoder = new TextDecoder();
2131
+ let buffer = "";
2132
+ let finished = false;
2133
+ try {
2134
+ while (true) {
2135
+ const { done, value } = await reader.read();
2136
+ if (done) break;
2137
+ buffer += decoder.decode(value, { stream: true });
2138
+ let sep = buffer.indexOf("\n\n");
2139
+ while (sep !== -1) {
2140
+ const ev = decodeRunFrame(buffer.slice(0, sep));
2141
+ buffer = buffer.slice(sep + 2);
2142
+ if (ev) {
2143
+ if (ev.type === "done" || ev.type === "error") finished = true;
2144
+ yield ev;
2145
+ }
2146
+ sep = buffer.indexOf("\n\n");
2147
+ }
2148
+ }
2149
+ const tail = decodeRunFrame(buffer);
2150
+ if (tail) {
2151
+ if (tail.type === "done" || tail.type === "error") finished = true;
2152
+ yield tail;
2153
+ }
2154
+ } finally {
2155
+ reader.releaseLock();
2156
+ }
2157
+ if (!finished) yield { type: "done", output: null, success: true };
2158
+ }
2159
+ function decodeRunFrame(frame) {
2160
+ const line = frame.split("\n").find((l) => l.startsWith("data:"));
2161
+ if (!line) return null;
2162
+ const data = line.slice(5).trim();
2163
+ if (!data || data === "[DONE]") return null;
2164
+ let json;
2165
+ try {
2166
+ json = JSON.parse(data);
2167
+ } catch {
2168
+ return { type: "chunk", text: data };
2169
+ }
2170
+ const d = json.data ?? {};
2171
+ switch (json.type) {
2172
+ case "stream:chunk":
2173
+ return { type: "chunk", blockId: d.blockId, text: String(d.chunk ?? "") };
2174
+ case "block:started":
2175
+ return {
2176
+ type: "step",
2177
+ blockId: String(d.blockId),
2178
+ name: String(d.blockName ?? d.blockType ?? ""),
2179
+ status: "running"
2180
+ };
2181
+ case "block:completed":
2182
+ return {
2183
+ type: "step",
2184
+ blockId: String(d.blockId),
2185
+ name: String(d.blockName ?? d.blockType ?? ""),
2186
+ status: "done",
2187
+ durationMs: d.durationMs
2188
+ };
2189
+ case "block:error":
2190
+ return {
2191
+ type: "step",
2192
+ blockId: String(d.blockId),
2193
+ name: String(d.blockName ?? d.blockType ?? ""),
2194
+ status: "error",
2195
+ durationMs: d.durationMs
2196
+ };
2197
+ case "execution:completed":
2198
+ return { type: "done", output: d.output, success: d.success !== false };
2199
+ case "execution:error":
2200
+ return { type: "error", message: String(d.error ?? "Run failed") };
2201
+ case "execution:cancelled":
2202
+ return { type: "error", message: "Run cancelled" };
2203
+ case "execution:started":
2204
+ case "stream:done":
2205
+ return null;
2206
+ }
2207
+ if (json.event === "error") return { type: "error", message: String(json.error ?? "Run failed") };
2208
+ if (json.event === "final") {
2209
+ const fd = json.data ?? {};
2210
+ if (fd.success === false) {
2211
+ const err = fd.error;
2212
+ return {
2213
+ type: "error",
2214
+ message: typeof err === "string" ? err : err?.message ?? "Run failed"
2215
+ };
2216
+ }
2217
+ return { type: "done", output: fd.output ?? fd, success: true };
2218
+ }
2219
+ if (typeof json.chunk === "string")
2220
+ return { type: "chunk", blockId: json.blockId, text: json.chunk };
2221
+ return null;
2222
+ }
2223
+
2224
+ // src/run/agent-runner.tsx
2225
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2226
+ function useAgentRun(workflowId, apiKey) {
2227
+ const { client, t } = useAginies();
2228
+ const [status, setStatus] = (0, import_react6.useState)("idle");
2229
+ const [text, setText] = (0, import_react6.useState)("");
2230
+ const [steps, setSteps] = (0, import_react6.useState)([]);
2231
+ const [output, setOutput] = (0, import_react6.useState)(null);
2232
+ const [error, setError] = (0, import_react6.useState)(null);
2233
+ const [executionId, setExecutionId] = (0, import_react6.useState)();
2234
+ const abortRef = (0, import_react6.useRef)(null);
2235
+ const cancel = (0, import_react6.useCallback)(() => {
2236
+ abortRef.current?.abort();
2237
+ abortRef.current = null;
2238
+ setStatus((s) => s === "running" ? "idle" : s);
2239
+ }, []);
2240
+ const run = (0, import_react6.useCallback)(
2241
+ async (input) => {
2242
+ abortRef.current?.abort();
2243
+ const controller = new AbortController();
2244
+ abortRef.current = controller;
2245
+ setStatus("running");
2246
+ setText("");
2247
+ setSteps([]);
2248
+ setOutput(null);
2249
+ setError(null);
2250
+ try {
2251
+ for await (const ev of runAgent(client, workflowId, { apiKey, input }, controller.signal)) {
2252
+ apply(ev);
2253
+ }
2254
+ } catch (err) {
2255
+ if (controller.signal.aborted) return;
2256
+ setError(
2257
+ err instanceof AginiesError && err.code === "UNAUTHORIZED" ? t("run", "unauthorized") : err instanceof Error ? err.message : t("run", "failed")
2258
+ );
2259
+ setStatus("error");
2260
+ } finally {
2261
+ if (abortRef.current === controller) abortRef.current = null;
2262
+ }
2263
+ function apply(ev) {
2264
+ switch (ev.type) {
2265
+ case "started":
2266
+ setExecutionId(ev.executionId);
2267
+ break;
2268
+ case "chunk":
2269
+ setText((s) => s + ev.text);
2270
+ break;
2271
+ case "step":
2272
+ setSteps((prev) => {
2273
+ const i = prev.findIndex((s) => s.blockId === ev.blockId);
2274
+ const next = {
2275
+ blockId: ev.blockId,
2276
+ name: ev.name,
2277
+ status: ev.status,
2278
+ durationMs: ev.durationMs
2279
+ };
2280
+ if (i === -1) return [...prev, next];
2281
+ const copy = [...prev];
2282
+ copy[i] = next;
2283
+ return copy;
2284
+ });
2285
+ break;
2286
+ case "done":
2287
+ setOutput(ev.output);
2288
+ setStatus(ev.success ? "done" : "error");
2289
+ break;
2290
+ case "error":
2291
+ setError(ev.message);
2292
+ setStatus("error");
2293
+ break;
2294
+ }
2295
+ }
2296
+ },
2297
+ [client, workflowId, apiKey, t]
2298
+ );
2299
+ return { status, text, steps, output, error, executionId, run, cancel };
2300
+ }
2301
+ var DEFAULT_FIELDS = [
2302
+ { name: "input", label: "Input", type: "textarea", required: true }
2303
+ ];
2304
+ function AgentRunner({
2305
+ workflowId,
2306
+ apiKey,
2307
+ fields = DEFAULT_FIELDS,
2308
+ title,
2309
+ description,
2310
+ submitLabel,
2311
+ onResult,
2312
+ className
2313
+ }) {
2314
+ const { t } = useAginies();
2315
+ const enabled = useModule("run");
2316
+ const agent = useAgentRun(workflowId, apiKey);
2317
+ const [values, setValues] = (0, import_react6.useState)(
2318
+ () => Object.fromEntries(
2319
+ fields.map((f) => [f.name, f.defaultValue ?? (f.type === "boolean" ? false : "")])
2320
+ )
2321
+ );
2322
+ const set = (name, value) => setValues((v) => ({ ...v, [name]: value }));
2323
+ const submit = async (e) => {
2324
+ e.preventDefault();
2325
+ if (agent.status === "running") return;
2326
+ const input = fields.length === 1 && fields[0]?.name === "input" && fields[0]?.type === "textarea" ? values.input : values;
2327
+ await agent.run(input);
2328
+ };
2329
+ const onResultRef = (0, import_react6.useRef)(onResult);
2330
+ onResultRef.current = onResult;
2331
+ (0, import_react6.useEffect)(() => {
2332
+ if (agent.status === "done") onResultRef.current?.(agent.output);
2333
+ }, [agent.status, agent.output]);
2334
+ if (!enabled) return null;
2335
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Panel, { className: cx("agi-run", className), children: [
2336
+ (title || description) && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("header", { className: "agi-run__head", children: [
2337
+ title && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { className: "agi-run__title", children: title }),
2338
+ description && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "agi-run__desc", children: description })
2339
+ ] }),
2340
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("form", { className: "agi-run__form", onSubmit: submit, children: [
2341
+ fields.map((f) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Field, { label: f.label, children: f.type === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2342
+ Textarea,
2343
+ {
2344
+ required: f.required,
2345
+ placeholder: f.placeholder,
2346
+ value: String(values[f.name] ?? ""),
2347
+ onChange: (e) => set(f.name, e.target.value)
2348
+ }
2349
+ ) : f.type === "select" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2350
+ "select",
2351
+ {
2352
+ className: "agi-input",
2353
+ required: f.required,
2354
+ value: String(values[f.name] ?? ""),
2355
+ onChange: (e) => set(f.name, e.target.value),
2356
+ children: [
2357
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "", children: "\u2014" }),
2358
+ f.options?.map((o) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: o.value, children: o.label }, o.value))
2359
+ ]
2360
+ }
2361
+ ) : f.type === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2362
+ "input",
2363
+ {
2364
+ type: "checkbox",
2365
+ className: "agi-checkbox",
2366
+ checked: Boolean(values[f.name]),
2367
+ onChange: (e) => set(f.name, e.target.checked)
2368
+ }
2369
+ ) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2370
+ Input,
2371
+ {
2372
+ type: f.type === "number" ? "number" : "text",
2373
+ required: f.required,
2374
+ placeholder: f.placeholder,
2375
+ value: String(values[f.name] ?? ""),
2376
+ onChange: (e) => set(f.name, f.type === "number" ? Number(e.target.value) : e.target.value)
2377
+ }
2378
+ ) }, f.name)),
2379
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "agi-run__actions", children: [
2380
+ agent.status === "running" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { variant: "outline", onClick: agent.cancel, children: t("run", "cancel") }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { variant: "signal", type: "submit", children: submitLabel ?? t("run", "submit") }),
2381
+ agent.status === "running" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "agi-run__status", children: [
2382
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Spinner, { label: t("run", "running") }),
2383
+ " ",
2384
+ t("run", "running")
2385
+ ] }),
2386
+ agent.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Tag, { tone: "ok", children: t("run", "done") }),
2387
+ agent.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Tag, { tone: "bad", children: t("run", "error") })
2388
+ ] })
2389
+ ] }),
2390
+ agent.steps.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ol", { className: "agi-run__steps", "aria-label": t("run", "steps"), children: agent.steps.map((s) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { className: `agi-run__step is-${s.status}`, children: [
2391
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "agi-run__step-dot" }),
2392
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "agi-run__step-name", children: s.name }),
2393
+ s.durationMs !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "agi-run__step-meta", children: [
2394
+ s.durationMs,
2395
+ " ms"
2396
+ ] })
2397
+ ] }, s.blockId)) }),
2398
+ (agent.text || agent.output !== null || agent.error) && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "agi-run__result", "aria-live": "polite", children: [
2399
+ agent.error && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "agi-run__error", children: agent.error }),
2400
+ agent.text && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "agi-run__text", children: agent.text }),
2401
+ !agent.text && agent.output !== null && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("pre", { className: "agi-run__output", children: formatOutput(agent.output) }),
2402
+ agent.executionId && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { className: "agi-run__meta", children: [
2403
+ t("run", "execution"),
2404
+ " ",
2405
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("b", { children: agent.executionId })
2406
+ ] })
2407
+ ] })
2408
+ ] });
2409
+ }
2410
+ function formatOutput(output) {
2411
+ if (typeof output === "string") return output;
2412
+ try {
2413
+ return JSON.stringify(output, null, 2);
2414
+ } catch {
2415
+ return String(output);
2416
+ }
2417
+ }
2418
+ // Annotate the CommonJS export names for ESM import in node:
2419
+ 0 && (module.exports = {
2420
+ ATTACHMENT_LIMITS,
2421
+ AgentRunner,
2422
+ AginiesClient,
2423
+ AginiesError,
2424
+ AginiesProvider,
2425
+ ApprovalPanel,
2426
+ Button,
2427
+ ChatWidget,
2428
+ Chip,
2429
+ CostBars,
2430
+ Eyebrow,
2431
+ Field,
2432
+ Input,
2433
+ Markdown,
2434
+ Panel,
2435
+ RunTimeline,
2436
+ Spinner,
2437
+ Stat,
2438
+ StatTiles,
2439
+ StructuredUI,
2440
+ SuccessHeatmap,
2441
+ Tag,
2442
+ Textarea,
2443
+ buildSubmission,
2444
+ cx,
2445
+ fieldsOf,
2446
+ formatFieldValue,
2447
+ getClient,
2448
+ getPauseContext,
2449
+ getPausedExecution,
2450
+ init,
2451
+ initialValues,
2452
+ listPausedExecutions,
2453
+ outputOf,
2454
+ parseFieldValue,
2455
+ parseRunSSE,
2456
+ parseSSE,
2457
+ parseStructured,
2458
+ resumeExecution,
2459
+ runAgent,
2460
+ translator,
2461
+ useAgentRun,
2462
+ useAginies,
2463
+ useApproval,
2464
+ useChat,
2465
+ useModule
2466
+ });
2467
+ //# sourceMappingURL=index.cjs.map