@athenaintel/react 0.10.41 → 0.11.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 CHANGED
@@ -42,8 +42,8 @@ var __privateWrapper = (obj, member, setter, getter) => ({
42
42
  var _focused, _cleanup, _setup, _a2, _provider, _providerCalled, _b, _online, _cleanup2, _setup2, _c, _gcTimeout, _d, _initialState, _revertState, _cache, _client, _retryer, _defaultOptions, _abortSignalConsumed, _Query_instances, isInitialPausedFetch_fn, dispatch_fn, _e, _client2, _currentQuery, _currentQueryInitialState, _currentResult, _currentResultState, _currentResultOptions, _currentThenable, _selectError, _selectFn, _selectResult, _lastQueryWithDefinedData, _staleTimeoutId, _refetchIntervalId, _currentRefetchInterval, _trackedProps, _QueryObserver_instances, executeFetch_fn, updateStaleTimeout_fn, computeRefetchInterval_fn, updateRefetchInterval_fn, updateTimers_fn, clearStaleTimeout_fn, clearRefetchInterval_fn, updateQuery_fn, notify_fn, _f, _client3, _observers, _mutationCache, _retryer2, _Mutation_instances, dispatch_fn2, _g, _mutations, _scopes, _mutationId, _h, _queries, _i, _queryCache, _mutationCache2, _defaultOptions2, _queryDefaults, _mutationDefaults, _mountCount, _unsubscribeFocus, _unsubscribeOnline, _j;
43
43
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
44
44
  const jsxRuntime = require("react/jsx-runtime");
45
- const react$1 = require("@assistant-ui/react");
46
45
  const React = require("react");
46
+ const react$1 = require("@assistant-ui/react");
47
47
  const AthenaAuthContext = require("./AthenaAuthContext-B3AwLA5Z.cjs");
48
48
  const localStorage$1 = require("@assistant-ui/react-statewire/local-storage");
49
49
  const tap = require("@assistant-ui/tap");
@@ -52,6 +52,7 @@ require("@assistant-ui/core");
52
52
  const react$2 = require("@assistant-ui/core/react");
53
53
  const reactLanggraph = require("@assistant-ui/react-langgraph");
54
54
  const reactStatewire = require("@assistant-ui/react-statewire");
55
+ const store = require("@assistant-ui/store");
55
56
  const ReactDOM = require("react-dom");
56
57
  function _interopNamespaceDefault(e) {
57
58
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -71,6 +72,909 @@ function _interopNamespaceDefault(e) {
71
72
  }
72
73
  const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
73
74
  const ReactDOM__namespace = /* @__PURE__ */ _interopNamespaceDefault(ReactDOM);
75
+ const version$1 = "0.11.0";
76
+ const packageJson = {
77
+ version: version$1
78
+ };
79
+ const ATHENA_REACT_SDK_VERSION = packageJson.version;
80
+ const DEFAULT_CAPTURE_GATE_CONFIG = {
81
+ globalMaxPerWindow: 50,
82
+ globalWindowMs: 1e4,
83
+ criticalReservePerWindow: 15,
84
+ defaultEventMaxPerWindow: 12,
85
+ defaultEventWindowMs: 6e4,
86
+ defaultDedupeWindowMs: 5e3,
87
+ flushIntervalMs: 3e4,
88
+ flushCoalesceThreshold: 20,
89
+ eventOverrides: {
90
+ memory_profile_sample: { maxPerWindow: 2, windowMs: 3e4, dedupeWindowMs: 15e3 },
91
+ long_task_detected: { maxPerWindow: 3, windowMs: 6e4, dedupeWindowMs: 1e4 },
92
+ collab_connection_status_changed: { maxPerWindow: 6, windowMs: 6e4 },
93
+ collab_first_remote_update: { maxPerWindow: 3, windowMs: 6e4 },
94
+ collab_first_local_update: { maxPerWindow: 3, windowMs: 6e4 },
95
+ collab_render_time_sync_fix: { maxPerWindow: 3, windowMs: 6e4 },
96
+ collab_visibility_recovery: { maxPerWindow: 4, windowMs: 6e4 },
97
+ langgraph_message_validation_error: {
98
+ maxPerWindow: 8,
99
+ windowMs: 6e4,
100
+ dedupeWindowMs: 15e3
101
+ },
102
+ langgraph_messages_validation_error: {
103
+ maxPerWindow: 5,
104
+ windowMs: 6e4,
105
+ dedupeWindowMs: 15e3
106
+ },
107
+ langgraph_interrupt_validation_error: {
108
+ maxPerWindow: 5,
109
+ windowMs: 6e4,
110
+ dedupeWindowMs: 15e3
111
+ },
112
+ langgraph_state_validation_error: {
113
+ maxPerWindow: 5,
114
+ windowMs: 6e4,
115
+ dedupeWindowMs: 15e3
116
+ },
117
+ graphql_error: { maxPerWindow: 12, windowMs: 6e4, dedupeWindowMs: 1e4 },
118
+ chat_error: { maxPerWindow: 8, windowMs: 6e4, dedupeWindowMs: 5e3 },
119
+ memory_critical_threshold: { maxPerWindow: 3, windowMs: 3e5 },
120
+ memory_warning_threshold: { maxPerWindow: 3, windowMs: 3e5 },
121
+ pptx_slide_changed: { maxPerWindow: 8, windowMs: 3e4 }
122
+ }
123
+ };
124
+ const CRITICAL_EVENT_PATTERNS = [
125
+ /(?:^|_)failed$/,
126
+ /(?:^|_)error(?:_|$)/,
127
+ /crash/,
128
+ /^oom_/,
129
+ /aw_snap/,
130
+ /chunk_load/,
131
+ /global_error/,
132
+ /\$exception$/,
133
+ /^404_error$/,
134
+ /^500_error$/,
135
+ /_boundary_/
136
+ ];
137
+ const BYPASS_OPTION_KEY = "__posthog_gate_bypass";
138
+ function isCriticalPosthogEvent(event) {
139
+ return CRITICAL_EVENT_PATTERNS.some((pattern) => pattern.test(event));
140
+ }
141
+ function shouldBypassCaptureGate(options) {
142
+ if (!options || typeof options !== "object") return false;
143
+ return options[BYPASS_OPTION_KEY] === true;
144
+ }
145
+ function withCaptureGateBypass(options) {
146
+ return {
147
+ ...options ?? {},
148
+ [BYPASS_OPTION_KEY]: true
149
+ };
150
+ }
151
+ function pruneWindow(window2, now, windowMs) {
152
+ const cutoff = now - windowMs;
153
+ while (window2.timestamps.length > 0 && window2.timestamps[0] < cutoff) {
154
+ window2.timestamps.shift();
155
+ }
156
+ }
157
+ function countInWindow(window2, now, windowMs) {
158
+ pruneWindow(window2, now, windowMs);
159
+ return window2.timestamps.length;
160
+ }
161
+ function recordInWindow(window2, now) {
162
+ window2.timestamps.push(now);
163
+ }
164
+ function stableStringify(value) {
165
+ if (value == null) return String(value);
166
+ if (typeof value !== "object") return String(value);
167
+ if (Array.isArray(value)) {
168
+ return `[${value.map((item) => stableStringify(item)).join(",")}]`;
169
+ }
170
+ const record2 = value;
171
+ const keys2 = Object.keys(record2).sort();
172
+ return `{${keys2.map((key) => `${key}:${stableStringify(record2[key])}`).join(",")}}`;
173
+ }
174
+ function fingerprintProperties(properties) {
175
+ if (!properties) return "";
176
+ const keys2 = [
177
+ "error",
178
+ "error_message",
179
+ "message",
180
+ "reason",
181
+ "status",
182
+ "code",
183
+ "asset_id",
184
+ "doc_id",
185
+ "thread_id",
186
+ "session_id",
187
+ "operation",
188
+ "path",
189
+ "url",
190
+ "chunk_identifier",
191
+ "validation_path"
192
+ ];
193
+ const subset = {};
194
+ for (const key of keys2) {
195
+ if (key in properties) {
196
+ subset[key] = properties[key];
197
+ }
198
+ }
199
+ return stableStringify(subset);
200
+ }
201
+ function buildCaptureFingerprint(event, properties) {
202
+ return `${event}|${fingerprintProperties(properties)}`;
203
+ }
204
+ function buildCoalescedCaptureProperties(payload) {
205
+ const windowMs = payload.lastAt - payload.firstAt;
206
+ return {
207
+ ...payload.properties,
208
+ coalesced: true,
209
+ coalesced_count: payload.coalescedCount,
210
+ coalesced_first_at: new Date(payload.firstAt).toISOString(),
211
+ coalesced_last_at: new Date(payload.lastAt).toISOString(),
212
+ coalesced_window_ms: windowMs,
213
+ coalesced_suppression_reason: payload.suppressionReason
214
+ };
215
+ }
216
+ class PosthogCaptureGate {
217
+ constructor(config2 = DEFAULT_CAPTURE_GATE_CONFIG) {
218
+ __publicField(this, "config");
219
+ __publicField(this, "globalWindow", { timestamps: [] });
220
+ __publicField(this, "eventWindows", /* @__PURE__ */ new Map());
221
+ __publicField(this, "activeDedupe", /* @__PURE__ */ new Map());
222
+ __publicField(this, "coalesceBuckets", /* @__PURE__ */ new Map());
223
+ __publicField(this, "emittedTotal", 0);
224
+ __publicField(this, "coalescedTotal", 0);
225
+ __publicField(this, "flushedCoalescedTotal", 0);
226
+ this.config = config2;
227
+ }
228
+ resetForTests() {
229
+ this.globalWindow.timestamps.length = 0;
230
+ this.eventWindows.clear();
231
+ this.activeDedupe.clear();
232
+ this.coalesceBuckets.clear();
233
+ this.emittedTotal = 0;
234
+ this.coalescedTotal = 0;
235
+ this.flushedCoalescedTotal = 0;
236
+ }
237
+ getSnapshot() {
238
+ const coalescedPendingByEvent = {};
239
+ let coalescedPending = 0;
240
+ for (const bucket of this.coalesceBuckets.values()) {
241
+ coalescedPending += bucket.count;
242
+ coalescedPendingByEvent[bucket.event] = (coalescedPendingByEvent[bucket.event] ?? 0) + bucket.count;
243
+ }
244
+ return {
245
+ coalescedPending,
246
+ coalescedPendingByEvent,
247
+ emittedTotal: this.emittedTotal,
248
+ coalescedTotal: this.coalescedTotal,
249
+ flushedCoalescedTotal: this.flushedCoalescedTotal
250
+ };
251
+ }
252
+ evaluateCapture(event, properties, options, now = Date.now()) {
253
+ if (shouldBypassCaptureGate(options)) {
254
+ return { action: "emit" };
255
+ }
256
+ const fingerprint = buildCaptureFingerprint(event, properties);
257
+ const bucketKey = fingerprint;
258
+ const override = this.config.eventOverrides[event];
259
+ const dedupeWindowMs = (override == null ? void 0 : override.dedupeWindowMs) ?? this.config.defaultDedupeWindowMs;
260
+ const lastDedupe = this.activeDedupe.get(event);
261
+ if (lastDedupe && lastDedupe.fingerprint === fingerprint && now - lastDedupe.at < dedupeWindowMs) {
262
+ return this.recordCoalesce(event, bucketKey, fingerprint, properties, "dedupe", now);
263
+ }
264
+ const critical = isCriticalPosthogEvent(event);
265
+ const globalCount = countInWindow(this.globalWindow, now, this.config.globalWindowMs);
266
+ const normalBudget = Math.max(
267
+ 0,
268
+ this.config.globalMaxPerWindow - this.config.criticalReservePerWindow
269
+ );
270
+ if (critical) {
271
+ if (globalCount >= this.config.globalMaxPerWindow) {
272
+ return this.recordCoalesce(event, bucketKey, fingerprint, properties, "global_budget", now);
273
+ }
274
+ } else if (globalCount >= normalBudget) {
275
+ return this.recordCoalesce(event, bucketKey, fingerprint, properties, "global_budget", now);
276
+ }
277
+ const eventWindow = this.eventWindows.get(event) ?? { timestamps: [] };
278
+ this.eventWindows.set(event, eventWindow);
279
+ const eventMax = (override == null ? void 0 : override.maxPerWindow) ?? this.config.defaultEventMaxPerWindow;
280
+ const eventWindowMs = (override == null ? void 0 : override.windowMs) ?? this.config.defaultEventWindowMs;
281
+ const eventCount = countInWindow(eventWindow, now, eventWindowMs);
282
+ if (eventCount >= eventMax) {
283
+ return this.recordCoalesce(event, bucketKey, fingerprint, properties, "event_budget", now);
284
+ }
285
+ recordInWindow(this.globalWindow, now);
286
+ recordInWindow(eventWindow, now);
287
+ this.activeDedupe.set(event, { fingerprint, bucketKey, at: now });
288
+ this.emittedTotal += 1;
289
+ return { action: "emit" };
290
+ }
291
+ /** Returns payloads ready to flush (does not mutate buckets until caller confirms). */
292
+ collectFlushCandidates(now = Date.now()) {
293
+ const payloads = [];
294
+ for (const bucket of this.coalesceBuckets.values()) {
295
+ const shouldFlushBySize = bucket.count >= this.config.flushCoalesceThreshold;
296
+ const shouldFlushByAge = now - bucket.firstAt >= this.config.flushIntervalMs;
297
+ if (!shouldFlushBySize && !shouldFlushByAge) {
298
+ continue;
299
+ }
300
+ payloads.push({
301
+ bucketKey: bucket.bucketKey,
302
+ event: bucket.event,
303
+ properties: bucket.sampleProperties,
304
+ coalescedCount: bucket.count,
305
+ firstAt: bucket.firstAt,
306
+ lastAt: bucket.lastAt,
307
+ suppressionReason: bucket.suppressionReason
308
+ });
309
+ }
310
+ return payloads;
311
+ }
312
+ /** Remove flushed bucket keys after successful emit. */
313
+ acknowledgeFlushed(payloads) {
314
+ for (const payload of payloads) {
315
+ this.coalesceBuckets.delete(payload.bucketKey);
316
+ this.flushedCoalescedTotal += payload.coalescedCount;
317
+ }
318
+ }
319
+ /** After coalescing, flush immediately if the bucket crossed the early threshold. */
320
+ takeBucketIfReady(bucketKey, now = Date.now()) {
321
+ const bucket = this.coalesceBuckets.get(bucketKey);
322
+ if (!bucket) return null;
323
+ const shouldFlushBySize = bucket.count >= this.config.flushCoalesceThreshold;
324
+ const shouldFlushByAge = now - bucket.firstAt >= this.config.flushIntervalMs;
325
+ if (!shouldFlushBySize && !shouldFlushByAge) {
326
+ return null;
327
+ }
328
+ this.coalesceBuckets.delete(bucketKey);
329
+ this.flushedCoalescedTotal += bucket.count;
330
+ return {
331
+ bucketKey: bucket.bucketKey,
332
+ event: bucket.event,
333
+ properties: bucket.sampleProperties,
334
+ coalescedCount: bucket.count,
335
+ firstAt: bucket.firstAt,
336
+ lastAt: bucket.lastAt,
337
+ suppressionReason: bucket.suppressionReason
338
+ };
339
+ }
340
+ /** Force-flush every pending bucket (e.g. page hide). */
341
+ collectAllPending() {
342
+ return [...this.coalesceBuckets.values()].map((bucket) => ({
343
+ bucketKey: bucket.bucketKey,
344
+ event: bucket.event,
345
+ properties: bucket.sampleProperties,
346
+ coalescedCount: bucket.count,
347
+ firstAt: bucket.firstAt,
348
+ lastAt: bucket.lastAt,
349
+ suppressionReason: bucket.suppressionReason
350
+ }));
351
+ }
352
+ recordCoalesce(event, bucketKey, fingerprint, properties, reason, now) {
353
+ const existing = this.coalesceBuckets.get(bucketKey);
354
+ if (existing) {
355
+ existing.count += 1;
356
+ existing.lastAt = now;
357
+ existing.sampleProperties = { ...existing.sampleProperties, ...properties ?? {} };
358
+ } else {
359
+ this.coalesceBuckets.set(bucketKey, {
360
+ event,
361
+ bucketKey,
362
+ fingerprint,
363
+ count: 1,
364
+ firstAt: now,
365
+ lastAt: now,
366
+ suppressionReason: reason,
367
+ sampleProperties: { ...properties ?? {} }
368
+ });
369
+ }
370
+ this.coalescedTotal += 1;
371
+ this.activeDedupe.set(event, { fingerprint, bucketKey, at: now });
372
+ return { action: "coalesce", reason, bucketKey };
373
+ }
374
+ }
375
+ const gate = new PosthogCaptureGate(DEFAULT_CAPTURE_GATE_CONFIG);
376
+ let wrappedClient = null;
377
+ let originalCaptureRef = null;
378
+ let flushTimer = null;
379
+ let lifecycleHooksInstalled = false;
380
+ function getPosthogCaptureGate() {
381
+ return gate;
382
+ }
383
+ function emitThroughOriginal(event, properties, options) {
384
+ if (!originalCaptureRef) return void 0;
385
+ return originalCaptureRef(event, properties, withCaptureGateBypass(options));
386
+ }
387
+ function flushCoalescedPayload(payload) {
388
+ emitThroughOriginal(payload.event, buildCoalescedCaptureProperties(payload));
389
+ }
390
+ function flushCoalescedCaptures(options) {
391
+ const payloads = (options == null ? void 0 : options.force) ? gate.collectAllPending() : gate.collectFlushCandidates();
392
+ if (payloads.length === 0) return;
393
+ for (const payload of payloads) {
394
+ flushCoalescedPayload(payload);
395
+ }
396
+ gate.acknowledgeFlushed(payloads);
397
+ }
398
+ function installLifecycleFlushHooks() {
399
+ if (lifecycleHooksInstalled || typeof window === "undefined") return;
400
+ lifecycleHooksInstalled = true;
401
+ const flushOnHide = () => {
402
+ flushCoalescedCaptures({ force: true });
403
+ };
404
+ window.addEventListener("pagehide", flushOnHide);
405
+ document.addEventListener("visibilitychange", () => {
406
+ if (document.visibilityState === "hidden") {
407
+ flushOnHide();
408
+ }
409
+ });
410
+ if (!flushTimer) {
411
+ flushTimer = setInterval(() => {
412
+ flushCoalescedCaptures();
413
+ }, DEFAULT_CAPTURE_GATE_CONFIG.flushIntervalMs);
414
+ }
415
+ }
416
+ function wrapPosthogClient(client) {
417
+ if (wrappedClient === client) {
418
+ return client;
419
+ }
420
+ originalCaptureRef = client.capture.bind(client);
421
+ const originalCaptureException = typeof client.captureException === "function" ? client.captureException.bind(client) : null;
422
+ installLifecycleFlushHooks();
423
+ client.capture = ((event, properties, options) => {
424
+ const outcome = gate.evaluateCapture(event, properties, options);
425
+ if (outcome.action === "coalesce") {
426
+ const readyPayload = gate.takeBucketIfReady(outcome.bucketKey);
427
+ if (readyPayload) {
428
+ flushCoalescedPayload(readyPayload);
429
+ }
430
+ return void 0;
431
+ }
432
+ return emitThroughOriginal(event, properties, options);
433
+ });
434
+ if (originalCaptureException) {
435
+ client.captureException = ((error2, additionalProperties) => {
436
+ const mergedProperties = {
437
+ ...additionalProperties ?? {},
438
+ $exception_message: error2 instanceof Error ? error2.message : String(error2),
439
+ $exception_type: error2 instanceof Error ? error2.name : typeof error2
440
+ };
441
+ const outcome = gate.evaluateCapture("$exception", mergedProperties);
442
+ if (outcome.action === "coalesce") {
443
+ const readyPayload = gate.takeBucketIfReady(outcome.bucketKey);
444
+ if (readyPayload) {
445
+ flushCoalescedPayload(readyPayload);
446
+ }
447
+ return void 0;
448
+ }
449
+ return originalCaptureException(error2, additionalProperties);
450
+ });
451
+ }
452
+ wrappedClient = client;
453
+ return client;
454
+ }
455
+ function capturePosthogEvent(client, event, properties, options) {
456
+ if (!client || typeof client.capture !== "function") return;
457
+ client.capture(event, properties, options);
458
+ }
459
+ function capturePosthogException(client, error2, properties, options) {
460
+ if (!client) return;
461
+ if (typeof client.captureException === "function") {
462
+ client.captureException(error2, properties);
463
+ return;
464
+ }
465
+ capturePosthogEvent(
466
+ client,
467
+ "$exception",
468
+ {
469
+ ...properties ?? {},
470
+ $exception_message: error2.message,
471
+ $exception_type: error2.name,
472
+ $exception_stack: error2.stack
473
+ },
474
+ options
475
+ );
476
+ }
477
+ let posthogInstance = null;
478
+ let initPromise = null;
479
+ const DEFAULT_HOST = "https://us.i.posthog.com";
480
+ async function initializePostHog(apiKey, host, debug) {
481
+ if (posthogInstance) return posthogInstance;
482
+ if (typeof window === "undefined") return null;
483
+ try {
484
+ const posthog = (await import("posthog-js")).default;
485
+ posthog.init(apiKey, {
486
+ api_host: host,
487
+ autocapture: true,
488
+ capture_pageview: false,
489
+ session_recording: {
490
+ recordCrossOriginIframes: true,
491
+ maskAllInputs: true
492
+ },
493
+ loaded: (ph) => {
494
+ wrapPosthogClient(ph);
495
+ if (debug) {
496
+ ph.debug(true);
497
+ }
498
+ }
499
+ });
500
+ wrapPosthogClient(posthog);
501
+ posthogInstance = posthog;
502
+ return posthog;
503
+ } catch {
504
+ initPromise = null;
505
+ return null;
506
+ }
507
+ }
508
+ function getPostHogInstance() {
509
+ return posthogInstance;
510
+ }
511
+ function PostHogProvider({
512
+ children,
513
+ config: config2
514
+ }) {
515
+ const apiKey = (config2 == null ? void 0 : config2.apiKey) ?? "";
516
+ const host = (config2 == null ? void 0 : config2.host) ?? DEFAULT_HOST;
517
+ const debug = (config2 == null ? void 0 : config2.debug) ?? false;
518
+ React.useEffect(() => {
519
+ if (!apiKey || typeof window === "undefined") return;
520
+ if (!initPromise) {
521
+ initPromise = initializePostHog(apiKey, host, debug);
522
+ }
523
+ }, [apiKey, host, debug]);
524
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
525
+ }
526
+ const ATHENA_SDK_ERROR_CODES = {
527
+ /** No token and no API key resolved before a request had to be sent. */
528
+ auth_missing: "auth_missing",
529
+ /** The server refused the credential (401 / statewire `unauthorized` fin). */
530
+ auth_rejected: "auth_rejected",
531
+ /** `/_athena/auth` or the iframe bridge did not answer within the timeout. */
532
+ auth_bridge_timeout: "auth_bridge_timeout",
533
+ /** `/_athena/auth` answered with a non-404 error. */
534
+ auth_bridge_failed: "auth_bridge_failed",
535
+ /** The statewire sync URL could not be derived from the configuration. */
536
+ config_invalid: "config_invalid",
537
+ /** A prop was set that the active transport ignores (e.g. `agent` on statewire). */
538
+ config_ignored: "config_ignored",
539
+ /** The thread list request failed. */
540
+ threads_list_failed: "threads_list_failed",
541
+ /** Loading a thread's history failed. */
542
+ thread_load_failed: "thread_load_failed",
543
+ /** The statewire host rejected a command (structured `{status, detail}`). */
544
+ statewire_rejected: "statewire_rejected",
545
+ /** The statewire connection is gone and will not reconnect on its own. */
546
+ statewire_gone: "statewire_gone",
547
+ /** The legacy `/api/chat` stream failed. */
548
+ stream_failed: "stream_failed",
549
+ /** The selected collab agent / channel was refused by the backend. */
550
+ collab_agent_rejected: "collab_agent_rejected",
551
+ /** Anything else. */
552
+ unknown: "unknown"
553
+ };
554
+ class AthenaSdkError extends Error {
555
+ constructor(options) {
556
+ super(options.message, options.cause === void 0 ? void 0 : { cause: options.cause });
557
+ __publicField(this, "code");
558
+ __publicField(this, "hint");
559
+ __publicField(this, "status");
560
+ __publicField(this, "detail");
561
+ __publicField(this, "context");
562
+ this.name = "AthenaSdkError";
563
+ this.code = options.code;
564
+ this.hint = options.hint;
565
+ this.status = options.status;
566
+ this.detail = options.detail;
567
+ this.context = options.context ?? {};
568
+ }
569
+ /** A log/console-friendly one-liner: `[code] message — hint`. */
570
+ describe() {
571
+ return `[${this.code}] ${this.message}${this.hint ? ` — ${this.hint}` : ""}`;
572
+ }
573
+ toJSON() {
574
+ return {
575
+ name: this.name,
576
+ code: this.code,
577
+ message: this.message,
578
+ hint: this.hint,
579
+ status: this.status,
580
+ detail: this.detail,
581
+ context: this.context
582
+ };
583
+ }
584
+ }
585
+ function isAthenaSdkError(value) {
586
+ return value instanceof AthenaSdkError;
587
+ }
588
+ function toAthenaSdkError(value, fallback) {
589
+ if (isAthenaSdkError(value)) return value;
590
+ const message = value instanceof Error && value.message ? value.message : fallback.message;
591
+ return new AthenaSdkError({ ...fallback, message, cause: value });
592
+ }
593
+ function readRejectionDetail(detail) {
594
+ if (typeof detail === "string") return { code: null, message: detail || null };
595
+ if (!detail || typeof detail !== "object") return { code: null, message: null };
596
+ const record2 = detail;
597
+ return {
598
+ code: typeof record2.code === "string" ? record2.code : null,
599
+ message: typeof record2.message === "string" ? record2.message : null
600
+ };
601
+ }
602
+ const ATHENA_DIAGNOSTIC_LEVELS = ["debug", "info", "warn", "error"];
603
+ const LEVEL_RANK = {
604
+ debug: 0,
605
+ info: 1,
606
+ warn: 2,
607
+ error: 3
608
+ };
609
+ const DEFAULT_CONFIG = {
610
+ console: false,
611
+ posthog: false,
612
+ bufferSize: 300
613
+ };
614
+ const CONSOLE_PREFIX = "[AthenaSDK]";
615
+ const LOCAL_STORAGE_DEBUG_KEY = "athena:debug";
616
+ const GLOBAL_KEY = "__ATHENA_SDK__";
617
+ const REDACT_KEYS = /token|secret|api[-_]?key|authorization|cookie|password/i;
618
+ function redact(data) {
619
+ if (!data) return void 0;
620
+ const out = {};
621
+ for (const [key, value] of Object.entries(data)) {
622
+ if (REDACT_KEYS.test(key)) {
623
+ out[key] = typeof value === "string" && value.length > 0 ? `<redacted:${value.length}>` : "<redacted>";
624
+ } else {
625
+ out[key] = value;
626
+ }
627
+ }
628
+ return out;
629
+ }
630
+ function nowMs() {
631
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
632
+ }
633
+ function readLocalDebugLevel() {
634
+ try {
635
+ if (typeof localStorage === "undefined") return null;
636
+ const raw = localStorage.getItem(LOCAL_STORAGE_DEBUG_KEY);
637
+ if (!raw) return null;
638
+ if (ATHENA_DIAGNOSTIC_LEVELS.includes(raw)) {
639
+ return raw;
640
+ }
641
+ return raw === "1" || raw === "true" ? "debug" : null;
642
+ } catch {
643
+ return null;
644
+ }
645
+ }
646
+ class AthenaDiagnosticsBus {
647
+ constructor() {
648
+ __publicField(this, "config", { ...DEFAULT_CONFIG });
649
+ __publicField(this, "events", []);
650
+ __publicField(this, "listeners", /* @__PURE__ */ new Set());
651
+ __publicField(this, "snapshotListeners", /* @__PURE__ */ new Set());
652
+ __publicField(this, "seq", 0);
653
+ __publicField(this, "gauges", {});
654
+ __publicField(this, "timings", {});
655
+ __publicField(this, "spans", /* @__PURE__ */ new Map());
656
+ __publicField(this, "cachedSnapshot", null);
657
+ }
658
+ configure(partial2) {
659
+ this.config = { ...this.config, ...partial2 };
660
+ if (this.events.length > this.config.bufferSize) {
661
+ this.events = this.events.slice(-this.config.bufferSize);
662
+ }
663
+ this.invalidate();
664
+ }
665
+ getConfig() {
666
+ return this.config;
667
+ }
668
+ /** Effective console level: the configured one, or `localStorage['athena:debug']`. */
669
+ consoleLevel() {
670
+ if (this.config.console !== false) return this.config.console;
671
+ return readLocalDebugLevel() ?? false;
672
+ }
673
+ emit(name, options = {}) {
674
+ const level = options.level ?? (options.error !== void 0 ? "error" : "info");
675
+ const error2 = options.error === void 0 ? void 0 : toAthenaSdkError(options.error, {
676
+ code: "unknown",
677
+ message: `Unexpected error during ${name}`
678
+ });
679
+ const event = {
680
+ seq: ++this.seq,
681
+ t: Math.round(nowMs() * 10) / 10,
682
+ at: (/* @__PURE__ */ new Date()).toISOString(),
683
+ name,
684
+ level,
685
+ ...options.durationMs !== void 0 && { durationMs: Math.round(options.durationMs) },
686
+ ...options.data && { data: redact(options.data) },
687
+ ...error2 && { error: error2 }
688
+ };
689
+ this.events.push(event);
690
+ if (this.events.length > this.config.bufferSize) {
691
+ this.events.splice(0, this.events.length - this.config.bufferSize);
692
+ }
693
+ if (event.durationMs !== void 0) {
694
+ this.timings[name] = event.durationMs;
695
+ }
696
+ this.invalidate();
697
+ this.echoToConsole(event);
698
+ this.forwardToPostHog(event);
699
+ for (const listener of this.listeners) {
700
+ try {
701
+ listener(event);
702
+ } catch (listenerError) {
703
+ console.error(`${CONSOLE_PREFIX} diagnostics listener threw`, listenerError);
704
+ }
705
+ }
706
+ if (this.config.onEvent) {
707
+ try {
708
+ this.config.onEvent(event);
709
+ } catch (callbackError) {
710
+ console.error(`${CONSOLE_PREFIX} onDiagnostic callback threw`, callbackError);
711
+ }
712
+ }
713
+ if (error2 && this.config.onError) {
714
+ try {
715
+ this.config.onError(error2, event);
716
+ } catch (callbackError) {
717
+ console.error(`${CONSOLE_PREFIX} onError callback threw`, callbackError);
718
+ }
719
+ }
720
+ for (const notify of this.snapshotListeners) notify();
721
+ return event;
722
+ }
723
+ /** Record an error-level event. Returns the normalized `AthenaSdkError`. */
724
+ error(name, error2, fallback, data) {
725
+ const normalized = toAthenaSdkError(error2, fallback);
726
+ this.emit(name, { level: "error", error: normalized, data });
727
+ return normalized;
728
+ }
729
+ /**
730
+ * Start a named span. Returns a function that ends it and emits `doneName`
731
+ * with `durationMs` (or `errorName` when passed an error). Also records a
732
+ * `performance.measure` so the span shows in the browser's Performance panel.
733
+ */
734
+ span(spanName, startName, data) {
735
+ const startedAt = nowMs();
736
+ this.spans.set(spanName, startedAt);
737
+ this.mark(`${spanName}:start`);
738
+ this.emit(startName, { level: "debug", data });
739
+ return (doneName, doneOptions = {}) => {
740
+ const durationMs = nowMs() - startedAt;
741
+ this.spans.delete(spanName);
742
+ this.mark(`${spanName}:end`);
743
+ this.measure(spanName);
744
+ this.emit(doneName, {
745
+ level: doneOptions.error !== void 0 ? "error" : "info",
746
+ durationMs,
747
+ data: doneOptions.data,
748
+ error: doneOptions.error
749
+ });
750
+ return durationMs;
751
+ };
752
+ }
753
+ /** Set a gauge (latest-value metric): connection status, transport, auth mode. */
754
+ gauge(name, value) {
755
+ if (this.gauges[name] === value) return;
756
+ this.gauges[name] = value;
757
+ this.invalidate();
758
+ for (const notify of this.snapshotListeners) notify();
759
+ }
760
+ subscribe(listener) {
761
+ this.listeners.add(listener);
762
+ return () => {
763
+ this.listeners.delete(listener);
764
+ };
765
+ }
766
+ /**
767
+ * Additive consumer registration: every registered consumer receives every
768
+ * event (and every error), unlike the single `onEvent`/`onError` config
769
+ * slots which are last-writer-wins. `AthenaProvider` registers through this
770
+ * so two mounted providers never clobber each other's callbacks.
771
+ */
772
+ addConsumer(consumer) {
773
+ return this.subscribe((event) => {
774
+ var _a3, _b2;
775
+ try {
776
+ (_a3 = consumer.onEvent) == null ? void 0 : _a3.call(consumer, event);
777
+ } catch (callbackError) {
778
+ console.error(`${CONSOLE_PREFIX} onDiagnostic consumer threw`, callbackError);
779
+ }
780
+ if (event.error) {
781
+ try {
782
+ (_b2 = consumer.onError) == null ? void 0 : _b2.call(consumer, event.error, event);
783
+ } catch (callbackError) {
784
+ console.error(`${CONSOLE_PREFIX} onError consumer threw`, callbackError);
785
+ }
786
+ }
787
+ });
788
+ }
789
+ /** Subscribe to snapshot changes (for `useSyncExternalStore`). */
790
+ subscribeSnapshot(listener) {
791
+ this.snapshotListeners.add(listener);
792
+ return () => {
793
+ this.snapshotListeners.delete(listener);
794
+ };
795
+ }
796
+ snapshot() {
797
+ if (!this.cachedSnapshot) {
798
+ const { onEvent: _onEvent, onError: _onError, ...config2 } = this.config;
799
+ this.cachedSnapshot = {
800
+ sdkVersion: ATHENA_REACT_SDK_VERSION,
801
+ config: config2,
802
+ events: [...this.events],
803
+ gauges: { ...this.gauges },
804
+ timings: { ...this.timings }
805
+ };
806
+ }
807
+ return this.cachedSnapshot;
808
+ }
809
+ /** Copy-paste-able JSON of the current snapshot (errors serialized). */
810
+ export() {
811
+ return JSON.stringify(
812
+ this.snapshot(),
813
+ (_key, value) => isAthenaSdkError(value) ? value.toJSON() : value,
814
+ 2
815
+ );
816
+ }
817
+ clear() {
818
+ this.events = [];
819
+ this.timings = {};
820
+ this.invalidate();
821
+ for (const notify of this.snapshotListeners) notify();
822
+ }
823
+ invalidate() {
824
+ this.cachedSnapshot = null;
825
+ }
826
+ mark(name) {
827
+ try {
828
+ if (typeof performance !== "undefined" && typeof performance.mark === "function") {
829
+ performance.mark(`athena-sdk:${name}`);
830
+ }
831
+ } catch {
832
+ }
833
+ }
834
+ measure(spanName) {
835
+ try {
836
+ if (typeof performance !== "undefined" && typeof performance.measure === "function") {
837
+ performance.measure(
838
+ `athena-sdk:${spanName}`,
839
+ `athena-sdk:${spanName}:start`,
840
+ `athena-sdk:${spanName}:end`
841
+ );
842
+ }
843
+ } catch {
844
+ }
845
+ }
846
+ echoToConsole(event) {
847
+ const level = this.consoleLevel();
848
+ if (level === false) {
849
+ if (event.level === "error" && event.error) {
850
+ console.error(`${CONSOLE_PREFIX} ${event.name}: ${event.error.describe()}`, event.data ?? "");
851
+ }
852
+ return;
853
+ }
854
+ if (LEVEL_RANK[event.level] < LEVEL_RANK[level]) return;
855
+ const suffix = event.durationMs !== void 0 ? ` (${event.durationMs}ms)` : "";
856
+ const line = `${CONSOLE_PREFIX} ${event.name}${suffix}`;
857
+ const payload = event.error ? { ...event.data, error: event.error.describe() } : event.data;
858
+ const method = event.level === "error" ? console.error : event.level === "warn" ? console.warn : event.level === "debug" ? console.debug : console.info;
859
+ method(line, payload ?? "");
860
+ }
861
+ forwardToPostHog(event) {
862
+ if (!this.config.posthog) return;
863
+ if (event.durationMs === void 0 && event.level !== "error") return;
864
+ try {
865
+ const client = getPostHogInstance();
866
+ capturePosthogEvent(client, `athena_sdk_${event.name.replace(/\./g, "_")}`, {
867
+ sdk_version: ATHENA_REACT_SDK_VERSION,
868
+ level: event.level,
869
+ ...event.durationMs !== void 0 && { duration_ms: event.durationMs },
870
+ ...event.error && {
871
+ error_code: event.error.code,
872
+ error_message: event.error.message,
873
+ error_status: event.error.status
874
+ },
875
+ ...event.data
876
+ });
877
+ } catch {
878
+ }
879
+ }
880
+ }
881
+ const athenaDiagnostics = new AthenaDiagnosticsBus();
882
+ function installAthenaDiagnosticsGlobal() {
883
+ if (typeof window === "undefined") return;
884
+ const globalWindow = window;
885
+ const existing = globalWindow[GLOBAL_KEY] ?? {};
886
+ globalWindow[GLOBAL_KEY] = {
887
+ ...existing,
888
+ version: ATHENA_REACT_SDK_VERSION,
889
+ diagnostics: {
890
+ snapshot: () => athenaDiagnostics.snapshot(),
891
+ export: () => athenaDiagnostics.export(),
892
+ clear: () => athenaDiagnostics.clear(),
893
+ enableConsole: (level = "debug") => {
894
+ try {
895
+ localStorage.setItem(LOCAL_STORAGE_DEBUG_KEY, level);
896
+ } catch {
897
+ }
898
+ athenaDiagnostics.configure({ console: level });
899
+ },
900
+ disableConsole: () => {
901
+ try {
902
+ localStorage.removeItem(LOCAL_STORAGE_DEBUG_KEY);
903
+ } catch {
904
+ }
905
+ athenaDiagnostics.configure({ console: false });
906
+ }
907
+ }
908
+ };
909
+ }
910
+ function debugPropToDiagnosticsConfig(debug) {
911
+ if (debug === void 0) return {};
912
+ if (debug === true) return { console: "debug" };
913
+ if (debug === false) return { console: false };
914
+ if (typeof debug === "string") return { console: debug };
915
+ return debug;
916
+ }
917
+ function useAthenaDiagnostics() {
918
+ const snapshot = React.useSyncExternalStore(
919
+ athenaDiagnostics.subscribeSnapshot.bind(athenaDiagnostics),
920
+ athenaDiagnostics.snapshot.bind(athenaDiagnostics),
921
+ athenaDiagnostics.snapshot.bind(athenaDiagnostics)
922
+ );
923
+ const clear = React.useCallback(() => athenaDiagnostics.clear(), []);
924
+ const exportJson = React.useCallback(() => athenaDiagnostics.export(), []);
925
+ return { ...snapshot, clear, export: exportJson };
926
+ }
927
+ const DEEP_AGENT_RUNTIME_MARKER = "athena_deep_agent";
928
+ const STATEWIRE_START_CHANNEL = "web";
929
+ const STATEWIRE_RUN_LABEL = "Athena SDK";
930
+ const DEFAULT_STATEWIRE_MODEL = "claude-sonnet-5";
931
+ const COLLAB_AGENT_REF_PREFIX = "collab_agent:";
932
+ function parseCollabAgentRef(agent2) {
933
+ if (typeof agent2 !== "string" || !agent2.startsWith(COLLAB_AGENT_REF_PREFIX)) return null;
934
+ const assetId = agent2.slice(COLLAB_AGENT_REF_PREFIX.length).trim();
935
+ return assetId || null;
936
+ }
937
+ function buildStatewireRunConfig(options = {}) {
938
+ var _a3, _b2, _c2, _d2, _e2;
939
+ const collabAgentId = parseCollabAgentRef(options.agent);
940
+ const collabChannelId = collabAgentId && ((_a3 = options.channel) == null ? void 0 : _a3.trim()) ? options.channel.trim() : void 0;
941
+ const model = options.model ?? (collabAgentId ? void 0 : DEFAULT_STATEWIRE_MODEL);
942
+ const panelModel = model ?? DEFAULT_STATEWIRE_MODEL;
943
+ const enabledTools = Array.from(
944
+ /* @__PURE__ */ new Set([...options.tools ?? [], ...options.frontendToolIds ?? []])
945
+ );
946
+ const systemPrompt = ((_b2 = options.systemPrompt) == null ? void 0 : _b2.trim()) ?? "";
947
+ return {
948
+ custom: {
949
+ runtime: DEEP_AGENT_RUNTIME_MARKER,
950
+ // With a collab channel selected, omit the SDK's own 'web' stamp: the
951
+ // request's explicit start_channel would win over the backend overlay's
952
+ // kind-mapped provenance (a custom SMS channel must stamp 'sms').
953
+ ...collabChannelId ? {} : { start_channel: STATEWIRE_START_CHANNEL },
954
+ ...model ? { model } : {},
955
+ // An empty list is behavior-identical to an absent key for the parser
956
+ // (both coerce to []), but the collab-agent overlay merges request keys
957
+ // OVER the agent definition — so an explicit empty list would erase the
958
+ // agent's configured tools. Omit it when empty.
959
+ ...enabledTools.length > 0 ? { enabled_tools: enabledTools } : {},
960
+ panel_config: {
961
+ model: panelModel,
962
+ enabled_tools: enabledTools,
963
+ system_prompt: systemPrompt,
964
+ run_label: STATEWIRE_RUN_LABEL
965
+ },
966
+ ...collabAgentId ? { collab_agent_id: collabAgentId } : {},
967
+ ...collabChannelId ? { collab_channel_id: collabChannelId } : {},
968
+ ...systemPrompt ? { system_prompt: systemPrompt } : {},
969
+ ...((_c2 = options.workbench) == null ? void 0 : _c2.length) ? { workbench: options.workbench } : {},
970
+ ...((_d2 = options.knowledgeBase) == null ? void 0 : _d2.length) ? { knowledge_base: options.knowledgeBase } : {},
971
+ ...options.customToolConfigs ? { custom_tool_configs: options.customToolConfigs } : {},
972
+ ...options.appId ? { app_id: options.appId } : {},
973
+ ...((_e2 = options.clientTools) == null ? void 0 : _e2.length) ? { client_tools: options.clientTools } : {},
974
+ ...options.extraRunConfig ?? {}
975
+ }
976
+ };
977
+ }
74
978
  const ATHENA_ENVIRONMENT_URLS = {
75
979
  production: {
76
980
  apiUrl: "https://iris.prd.athenaintel.com/api/chat",
@@ -274,7 +1178,7 @@ const normalizeOrigin = (value) => {
274
1178
  return null;
275
1179
  }
276
1180
  };
277
- const getTokenRefreshDelay = (expiresAt, nowMs) => {
1181
+ const getTokenRefreshDelay = (expiresAt, nowMs2) => {
278
1182
  if (typeof expiresAt !== "string") {
279
1183
  return DEFAULT_TOKEN_REFRESH_MS;
280
1184
  }
@@ -282,7 +1186,7 @@ const getTokenRefreshDelay = (expiresAt, nowMs) => {
282
1186
  if (!Number.isFinite(expiresAtMs)) {
283
1187
  return DEFAULT_TOKEN_REFRESH_MS;
284
1188
  }
285
- return Math.max(TOKEN_REFRESH_RETRY_BASE_MS, expiresAtMs - nowMs - TOKEN_REFRESH_BUFFER_MS);
1189
+ return Math.max(TOKEN_REFRESH_RETRY_BASE_MS, expiresAtMs - nowMs2 - TOKEN_REFRESH_BUFFER_MS);
286
1190
  };
287
1191
  const getAuthRetryDelay = (retryAttempt) => {
288
1192
  const safeAttempt = Number.isFinite(retryAttempt) ? Math.max(0, Math.floor(retryAttempt)) : 0;
@@ -316,6 +1220,15 @@ function useParentBridge({
316
1220
  const configReceived = React.useRef(false);
317
1221
  React.useEffect(() => {
318
1222
  if (!isInIframe) return;
1223
+ const endBridgeSpan = athenaDiagnostics.span("auth.bridge", "auth.bridge.start", {
1224
+ mode: "iframe"
1225
+ });
1226
+ let spanEnded = false;
1227
+ const endOnce = (name, options) => {
1228
+ if (spanEnded) return 0;
1229
+ spanEnded = true;
1230
+ return endBridgeSpan(name, options);
1231
+ };
319
1232
  const handler = (event) => {
320
1233
  if (!isTrustedOrigin({ origin: event.origin, trustedOrigins: runtimeTrustedOrigins })) {
321
1234
  return;
@@ -334,6 +1247,11 @@ function useParentBridge({
334
1247
  }));
335
1248
  }
336
1249
  if (event.data.type === "athena-auth" && typeof event.data.token === "string") {
1250
+ endOnce("auth.bridge.ready", { data: { mode: "iframe" } });
1251
+ athenaDiagnostics.emit("auth.token.acquired", {
1252
+ level: "debug",
1253
+ data: { source: "iframe-postmessage" }
1254
+ });
337
1255
  setState((prev) => ({
338
1256
  ...prev,
339
1257
  token: event.data.token,
@@ -347,6 +1265,13 @@ function useParentBridge({
347
1265
  readySignalSent.current = true;
348
1266
  }
349
1267
  const timer = setTimeout(() => {
1268
+ endOnce("auth.bridge.timeout", {
1269
+ data: {
1270
+ mode: "iframe",
1271
+ timeout_ms: BRIDGE_TIMEOUT_MS,
1272
+ config_received: configReceived.current
1273
+ }
1274
+ });
350
1275
  setState((prev) => prev.ready ? prev : { ...prev, ready: true });
351
1276
  }, BRIDGE_TIMEOUT_MS);
352
1277
  return () => {
@@ -399,9 +1324,20 @@ function useParentBridge({
399
1324
  }) => {
400
1325
  controller == null ? void 0 : controller.abort();
401
1326
  controller = new AbortController();
1327
+ const isInitial = markReadyOnFailure;
1328
+ const rawEndSpan = isInitial ? athenaDiagnostics.span("auth.bridge", "auth.bridge.start", { mode: "marathon" }) : null;
1329
+ let spanEnded = false;
1330
+ const endBridgeSpan = rawEndSpan ? (name, options) => {
1331
+ if (spanEnded) return 0;
1332
+ spanEnded = true;
1333
+ return rawEndSpan(name, options);
1334
+ } : null;
402
1335
  clearRequestTimer();
403
1336
  requestTimer = setTimeout(() => {
404
1337
  controller == null ? void 0 : controller.abort();
1338
+ endBridgeSpan == null ? void 0 : endBridgeSpan("auth.bridge.timeout", {
1339
+ data: { mode: "marathon", timeout_ms: BRIDGE_TIMEOUT_MS }
1340
+ });
405
1341
  if (markReadyOnFailure) {
406
1342
  markReady();
407
1343
  }
@@ -415,17 +1351,43 @@ function useParentBridge({
415
1351
  if (cancelled) return;
416
1352
  if (!resp.ok) {
417
1353
  if (resp.status === 404) {
1354
+ endBridgeSpan == null ? void 0 : endBridgeSpan("auth.bridge.absent", {
1355
+ data: { mode: "marathon", status: resp.status }
1356
+ });
418
1357
  markReady();
419
- } else if (markReadyOnFailure) {
420
- markReady();
421
- scheduleRetry();
422
1358
  } else {
1359
+ const failure = {
1360
+ level: "warn",
1361
+ data: { mode: "marathon", status: resp.status }
1362
+ };
1363
+ if (endBridgeSpan) {
1364
+ endBridgeSpan("auth.bridge.error", failure);
1365
+ } else {
1366
+ athenaDiagnostics.emit("auth.token.refresh_failed", failure);
1367
+ }
1368
+ if (markReadyOnFailure) {
1369
+ markReady();
1370
+ }
423
1371
  scheduleRetry();
424
1372
  }
425
1373
  return;
426
1374
  }
427
1375
  const data = await resp.json();
428
1376
  if (cancelled) return;
1377
+ if (endBridgeSpan) {
1378
+ endBridgeSpan("auth.bridge.ready", {
1379
+ data: { mode: "marathon", has_token: typeof data.token === "string" }
1380
+ });
1381
+ athenaDiagnostics.emit("auth.token.acquired", {
1382
+ level: "debug",
1383
+ data: { source: "marathon", expires_at: data.expires_at }
1384
+ });
1385
+ } else {
1386
+ athenaDiagnostics.emit("auth.token.refreshed", {
1387
+ level: "debug",
1388
+ data: { source: "marathon", expires_at: data.expires_at }
1389
+ });
1390
+ }
429
1391
  setState({
430
1392
  token: typeof data.token === "string" ? data.token : null,
431
1393
  apiUrl: typeof data.apiUrl === "string" ? data.apiUrl : null,
@@ -434,7 +1396,15 @@ function useParentBridge({
434
1396
  ready: true
435
1397
  });
436
1398
  scheduleRefresh(data.expires_at);
437
- } catch {
1399
+ } catch (error2) {
1400
+ if (!cancelled && !(error2 instanceof DOMException && error2.name === "AbortError")) {
1401
+ const failure = { level: "warn", data: { mode: "marathon" }, error: error2 };
1402
+ if (endBridgeSpan) {
1403
+ endBridgeSpan("auth.bridge.error", failure);
1404
+ } else {
1405
+ athenaDiagnostics.emit("auth.token.refresh_failed", failure);
1406
+ }
1407
+ }
438
1408
  if (markReadyOnFailure) {
439
1409
  markReady();
440
1410
  }
@@ -9880,24 +10850,42 @@ function getAthenaApiBaseUrl(backendUrl) {
9880
10850
  return stripped;
9881
10851
  }
9882
10852
  async function listThreads(backendUrl, auth, opts = {}) {
10853
+ var _a3;
9883
10854
  const base2 = getAthenaApiBaseUrl(backendUrl);
9884
- const res = await fetch(`${base2}/api/conversations/threads/list`, {
9885
- method: "POST",
9886
- headers: { "Content-Type": "application/json", ...getAuthHeaders(auth) },
9887
- body: JSON.stringify({
9888
- limit: opts.limit ?? 50,
9889
- offset: opts.offset ?? 0,
9890
- // Default to the full recent-conversations set unless a caller
9891
- // explicitly asks to hide triggered/background sessions.
9892
- exclude_triggered: opts.exclude_triggered ?? false,
9893
- ...opts.app_id ? { app_id: opts.app_id } : {},
9894
- ...opts.start_channel ? { start_channel: opts.start_channel } : {}
9895
- })
10855
+ const endSpan = athenaDiagnostics.span("threads.list", "threads.list.start", {
10856
+ auth_mode: getAuthMode(auth),
10857
+ app_id: opts.app_id
9896
10858
  });
9897
- if (!res.ok) {
9898
- throw new Error(`[AthenaSDK] Failed to list threads: ${res.status}`);
10859
+ try {
10860
+ const res = await fetch(`${base2}/api/conversations/threads/list`, {
10861
+ method: "POST",
10862
+ headers: { "Content-Type": "application/json", ...getAuthHeaders(auth) },
10863
+ body: JSON.stringify({
10864
+ limit: opts.limit ?? 50,
10865
+ offset: opts.offset ?? 0,
10866
+ // Default to the full recent-conversations set unless a caller
10867
+ // explicitly asks to hide triggered/background sessions.
10868
+ exclude_triggered: opts.exclude_triggered ?? false,
10869
+ ...opts.app_id ? { app_id: opts.app_id } : {},
10870
+ ...opts.start_channel ? { start_channel: opts.start_channel } : {}
10871
+ })
10872
+ });
10873
+ if (!res.ok) {
10874
+ throw new AthenaSdkError({
10875
+ code: res.status === 401 || res.status === 403 ? "auth_rejected" : "threads_list_failed",
10876
+ message: `Failed to list threads: ${res.status}`,
10877
+ status: res.status,
10878
+ hint: res.status === 401 || res.status === 403 ? "The credential was refused. Check the token/API key and that the user belongs to the workspace." : "Check backendUrl points at the Agora API base.",
10879
+ context: { auth_mode: getAuthMode(auth) }
10880
+ });
10881
+ }
10882
+ const data = await res.json();
10883
+ endSpan("threads.list.done", { data: { count: ((_a3 = data.threads) == null ? void 0 : _a3.length) ?? 0 } });
10884
+ return data;
10885
+ } catch (error2) {
10886
+ endSpan("threads.list.error", { error: error2 });
10887
+ throw error2;
9899
10888
  }
9900
- return res.json();
9901
10889
  }
9902
10890
  async function setThreadReadState(backendUrl, auth, opts) {
9903
10891
  const base2 = getAthenaApiBaseUrl(backendUrl);
@@ -9958,31 +10946,49 @@ function getResponseErrorBody(response) {
9958
10946
  return response.text().catch(() => "");
9959
10947
  }
9960
10948
  async function getThreadState(backendUrl, auth, threadId) {
10949
+ var _a3, _b2, _c2, _d2;
9961
10950
  const base2 = getAthenaApiBaseUrl(backendUrl);
9962
10951
  const authMode = getAuthMode(auth);
9963
10952
  const endpoint = `${base2}/api/conversations/threads/get`;
9964
- console.info("[AthenaSDK] Loading thread state from conversations API:", {
9965
- threadId,
9966
- endpoint,
9967
- authMode,
9968
- hasToken: Boolean(auth.token),
9969
- hasApiKey: Boolean(auth.apiKey)
9970
- });
9971
- const res = await fetch(endpoint, {
9972
- method: "POST",
9973
- headers: { "Content-Type": "application/json", ...getAuthHeaders(auth) },
9974
- body: JSON.stringify({
9975
- thread_id: threadId,
9976
- skip_cache: true
9977
- })
10953
+ const endSpan = athenaDiagnostics.span("threads.history", "threads.history.start", {
10954
+ thread_id: threadId,
10955
+ auth_mode: authMode
9978
10956
  });
10957
+ let res;
10958
+ try {
10959
+ res = await fetch(endpoint, {
10960
+ method: "POST",
10961
+ headers: { "Content-Type": "application/json", ...getAuthHeaders(auth) },
10962
+ body: JSON.stringify({
10963
+ thread_id: threadId,
10964
+ skip_cache: true
10965
+ })
10966
+ });
10967
+ } catch (error2) {
10968
+ endSpan("threads.history.error", { error: error2, data: { thread_id: threadId } });
10969
+ throw error2;
10970
+ }
9979
10971
  if (!res.ok) {
9980
10972
  const body = await getResponseErrorBody(res);
9981
- throw new Error(
9982
- `[AthenaSDK] Failed to get thread state: ${res.status} (${authMode})${body ? `: ${body.slice(0, 300)}` : ""}`
9983
- );
10973
+ const error2 = new AthenaSdkError({
10974
+ code: res.status === 401 || res.status === 403 ? "auth_rejected" : "thread_load_failed",
10975
+ message: `Failed to get thread state: ${res.status} (${authMode})${body ? `: ${body.slice(0, 300)}` : ""}`,
10976
+ status: res.status,
10977
+ hint: "A brand-new thread may not be persisted yet; anything else means the credential or backendUrl is wrong.",
10978
+ context: { thread_id: threadId, auth_mode: authMode }
10979
+ });
10980
+ endSpan("threads.history.error", { error: error2, data: { thread_id: threadId } });
10981
+ throw error2;
9984
10982
  }
9985
10983
  const data = await res.json();
10984
+ const channelMessages = (_b2 = (_a3 = data.thread) == null ? void 0 : _a3.channel_values) == null ? void 0 : _b2.messages;
10985
+ endSpan("threads.history.done", {
10986
+ data: {
10987
+ thread_id: threadId,
10988
+ found: data.thread_found !== false,
10989
+ message_count: Array.isArray(channelMessages) ? channelMessages.length : ((_d2 = (_c2 = data.thread) == null ? void 0 : _c2.messages) == null ? void 0 : _d2.length) ?? 0
10990
+ }
10991
+ });
9986
10992
  const thread = data.thread;
9987
10993
  if (data.thread_found === false || !thread) {
9988
10994
  return {
@@ -10264,17 +11270,35 @@ const useAthenaRuntime = (config2) => {
10264
11270
  };
10265
11271
  },
10266
11272
  onResponse: () => {
11273
+ athenaDiagnostics.emit("stream.connected", {
11274
+ level: "debug",
11275
+ data: { transport: "legacy", thread_id: threadIdRef.current }
11276
+ });
10267
11277
  if (IS_DEV) {
10268
11278
  console.log("[AthenaSDK] Stream connected");
10269
11279
  }
10270
11280
  },
10271
11281
  onFinish: () => {
11282
+ athenaDiagnostics.emit("run.done", {
11283
+ level: "debug",
11284
+ data: { transport: "legacy", thread_id: threadIdRef.current }
11285
+ });
10272
11286
  if (IS_DEV) {
10273
11287
  console.log("[AthenaSDK] Stream completed");
10274
11288
  }
10275
11289
  },
10276
11290
  onError: (error2, { commands: commands2, updateState }) => {
10277
11291
  var _a3;
11292
+ athenaDiagnostics.error(
11293
+ "stream.error",
11294
+ error2,
11295
+ {
11296
+ code: /\b401\b|unauthori[sz]ed/i.test(error2.message) ? "auth_rejected" : "stream_failed",
11297
+ message: error2.message || "The chat stream failed",
11298
+ hint: "Check the Iris apiUrl and the credential; the raw error is in `cause`."
11299
+ },
11300
+ { transport: "legacy", thread_id: threadIdRef.current }
11301
+ );
10278
11302
  const pendingCommands = commandsToMessages(commands2);
10279
11303
  const isInvalidStringLength = error2 instanceof RangeError && /Invalid string length/i.test(error2.message);
10280
11304
  const userErrorMessage = isInvalidStringLength ? "The response was too large to process. Try reducing the amount of content in a single request or starting a new chat." : error2.message;
@@ -10396,33 +11420,21 @@ const useAthenaRuntime = (config2) => {
10396
11420
  if (isExistingThread && !hasResumedRef.current) {
10397
11421
  hasResumedRef.current = true;
10398
11422
  (async () => {
10399
- var _a3, _b2;
11423
+ var _a3;
10400
11424
  const currentToken = getTokenRef.current ? await getTokenRef.current() ?? tokenRef.current : tokenRef.current;
10401
11425
  const auth = { apiKey: apiKeyRef.current, token: currentToken };
10402
- console.log("[AthenaSDK] Loading existing thread state:", {
10403
- threadId,
10404
- backendUrl
10405
- });
10406
11426
  try {
10407
11427
  const state = await getThreadState(backendUrl, auth, threadId);
10408
- const messageCount = ((_a3 = state == null ? void 0 : state.messages) == null ? void 0 : _a3.length) ?? 0;
10409
- console.log("[AthenaSDK] Got thread state:", {
10410
- threadId,
10411
- messageCount,
10412
- hasMessages: messageCount > 0
10413
- });
10414
11428
  runtime.thread.importExternalState({
10415
11429
  ...state
10416
11430
  });
10417
- console.log(
10418
- "[AthenaSDK] importExternalState completed, runtime messages:",
10419
- runtime.thread.getState().messages.length
10420
- );
10421
11431
  } catch (err) {
10422
- console.warn(
10423
- "[AthenaSDK] Failed to load thread state (may be a new streaming thread):",
10424
- err
10425
- );
11432
+ if (IS_DEV) {
11433
+ console.warn(
11434
+ "[AthenaSDK] Failed to load thread state (may be a new streaming thread):",
11435
+ err
11436
+ );
11437
+ }
10426
11438
  }
10427
11439
  try {
10428
11440
  const statusRes = await fetch(resolvedStatusApiUrl, {
@@ -10434,7 +11446,7 @@ const useAthenaRuntime = (config2) => {
10434
11446
  const status = await statusRes.json();
10435
11447
  if (status.isRunning) {
10436
11448
  try {
10437
- const lastMessageId = ((_b2 = runtime.thread.getState().messages.at(-1)) == null ? void 0 : _b2.id) ?? null;
11449
+ const lastMessageId = ((_a3 = runtime.thread.getState().messages.at(-1)) == null ? void 0 : _a3.id) ?? null;
10438
11450
  runtime.thread.resumeRun({ parentId: lastMessageId });
10439
11451
  } catch (resumeErr) {
10440
11452
  if (IS_DEV) {
@@ -10582,6 +11594,7 @@ function projectDeepAgentConnection(connection) {
10582
11594
  return {
10583
11595
  status: connection.status,
10584
11596
  cause: connection.cause,
11597
+ attempt: connection.attempt,
10585
11598
  ...message !== void 0 && { message }
10586
11599
  };
10587
11600
  }
@@ -10757,6 +11770,22 @@ function liftAopSourceIntoMetadata(message) {
10757
11770
  }
10758
11771
  };
10759
11772
  }
11773
+ function liftBranchIntoMetadata(message) {
11774
+ if (message.type !== "human" && message.type !== "ai") return message;
11775
+ const branch = message.branch;
11776
+ if (typeof branch !== "object" || branch === null || Array.isArray(branch)) return message;
11777
+ const kwargs = message.additional_kwargs;
11778
+ const existingMetadata = kwargs == null ? void 0 : kwargs.metadata;
11779
+ const metadata = typeof existingMetadata === "object" && existingMetadata !== null ? existingMetadata : {};
11780
+ if (typeof metadata.branch === "object" && metadata.branch !== null) return message;
11781
+ return {
11782
+ ...message,
11783
+ additional_kwargs: {
11784
+ ...kwargs,
11785
+ metadata: { ...metadata, branch }
11786
+ }
11787
+ };
11788
+ }
10760
11789
  const TOOL_MESSAGE_INTERNAL_KWARGS = /* @__PURE__ */ new Set([
10761
11790
  "reasoning",
10762
11791
  "tool_outputs",
@@ -10809,11 +11838,13 @@ function isConvertibleChatMessage(message) {
10809
11838
  }
10810
11839
  function sanitizeLangChainMessages(messages) {
10811
11840
  return messages.filter((message) => isConvertibleChatMessage(message) && !isMessageHiddenFromFrontend(message)).map(
10812
- (message) => liftToolMessageMetadataIntoArtifact(
10813
- liftAopSourceIntoMetadata(
10814
- liftCompactionBoundaryIntoMetadata(
10815
- liftConversationStatsIntoMetadata(
10816
- liftModelIntoMetadata(liftRunMarkerIntoMetadata(message))
11841
+ (message) => liftBranchIntoMetadata(
11842
+ liftToolMessageMetadataIntoArtifact(
11843
+ liftAopSourceIntoMetadata(
11844
+ liftCompactionBoundaryIntoMetadata(
11845
+ liftConversationStatsIntoMetadata(
11846
+ liftModelIntoMetadata(liftRunMarkerIntoMetadata(message))
11847
+ )
10817
11848
  )
10818
11849
  )
10819
11850
  )
@@ -10846,14 +11877,15 @@ function registerDeepAgentRunConfig(aui, getRunConfig) {
10846
11877
  })
10847
11878
  });
10848
11879
  }
10849
- function deepAgentThreadStatus(state) {
10850
- var _a3;
10851
- const runs = state == null ? void 0 : state.runs;
10852
- if (runs === void 0) return "loading";
10853
- return ((_a3 = runs[0]) == null ? void 0 : _a3.status) ?? "ready";
10854
- }
10855
11880
  function useDeepAgentThreadStatus() {
10856
- return reactStatewire.useStatewireState(deepAgentThreadStatus);
11881
+ return store.useAuiState((s) => {
11882
+ var _a3;
11883
+ const status = (_a3 = s.thread.extras) == null ? void 0 : _a3.status;
11884
+ if (status === void 0) {
11885
+ throw new Error("useDeepAgentThreadStatus requires a statewire thread");
11886
+ }
11887
+ return status;
11888
+ });
10857
11889
  }
10858
11890
  function shouldNotifyRunningChange(previous, next) {
10859
11891
  if (previous === null) return next.isRunning;
@@ -11074,7 +12106,7 @@ function useDeepAgentThread({
11074
12106
  }
11075
12107
  const connection = projectDeepAgentConnection(meta.connection);
11076
12108
  const previous = lastConnectionRef.current;
11077
- if ((previous == null ? void 0 : previous.threadId) !== attachId || previous.connection.status !== connection.status || previous.connection.cause !== connection.cause || previous.connection.message !== connection.message) {
12109
+ if ((previous == null ? void 0 : previous.threadId) !== attachId || previous.connection.status !== connection.status || previous.connection.cause !== connection.cause || previous.connection.message !== connection.message || previous.connection.attempt !== connection.attempt) {
11078
12110
  const update = { threadId: attachId, connection };
11079
12111
  lastConnectionRef.current = update;
11080
12112
  queueMicrotask(() => {
@@ -11146,46 +12178,30 @@ function toJSONSchema(schema2) {
11146
12178
  if (isStandardSchema(schema2)) throw new Error("Could not convert schema to JSON Schema. The schema implements Standard Schema but does not support JSON Schema conversion. If you are using Zod, please upgrade to Zod v4 (npm install zod@latest). Alternatively, pass a plain JSON Schema object instead.");
11147
12179
  return schema2;
11148
12180
  }
11149
- function defaultToolFilter(_name, tool) {
11150
- return !tool.disabled && tool.type !== "backend" && (tool.type !== "frontend" || tool.execute !== void 0);
11151
- }
11152
- function toolHasUploadableParameters(tool) {
11153
- var _a3;
11154
- return tool.parameters !== void 0 && !((_a3 = tool.unstable_backendDefault) == null ? void 0 : _a3.parameters);
11155
- }
11156
- function toToolsJSONSchema(tools, options = {}) {
11157
- if (!tools) return {};
11158
- const filter = options.filter ?? defaultToolFilter;
11159
- return Object.fromEntries(Object.entries(tools).filter(([name, tool]) => filter(name, tool)).filter((entry) => toolHasUploadableParameters(entry[1])).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([name, tool]) => [name, {
11160
- ...tool.description && { description: tool.description },
11161
- parameters: toJSONSchema(tool.parameters),
11162
- ...tool.providerOptions && { providerOptions: tool.providerOptions }
11163
- }]));
11164
- }
11165
12181
  function hasCallableExecute(entry) {
11166
12182
  return !!entry && typeof entry === "object" && typeof entry.execute === "function";
11167
12183
  }
11168
12184
  function collectStatewireClientTools(toolkit) {
11169
12185
  const executable = Object.entries(toolkit).filter(([, entry]) => hasCallableExecute(entry));
11170
12186
  if (executable.length === 0) return [];
11171
- let schemas;
11172
- try {
11173
- schemas = toToolsJSONSchema(toolkit, {
11174
- filter: (name) => executable.some(([toolName]) => toolName === name)
11175
- });
11176
- } catch (error2) {
11177
- console.warn("[AthenaSDK] failed to convert frontend tool schemas for statewire:", error2);
11178
- return [];
11179
- }
11180
12187
  return executable.flatMap(([name, entry]) => {
11181
- const schema2 = schemas[name];
11182
- if (!schema2) return [];
12188
+ if (entry.parameters === void 0) return [];
12189
+ let parameters;
12190
+ try {
12191
+ parameters = toJSONSchema(entry.parameters);
12192
+ } catch (error2) {
12193
+ console.warn(
12194
+ `[AthenaSDK] failed to convert frontend tool schema for statewire (${name}):`,
12195
+ error2
12196
+ );
12197
+ return [];
12198
+ }
11183
12199
  const execute = entry.execute;
11184
12200
  return [
11185
12201
  {
11186
12202
  name,
11187
- description: schema2.description,
11188
- parameters: schema2.parameters ?? { type: "object" },
12203
+ description: entry.description,
12204
+ parameters,
11189
12205
  handler: async (args, { toolCallId }) => {
11190
12206
  const controller = new AbortController();
11191
12207
  const output = await execute(args, {
@@ -11209,39 +12225,6 @@ function statewireClientToolWireEntries(tools) {
11209
12225
  requires_write: false
11210
12226
  }));
11211
12227
  }
11212
- const DEEP_AGENT_RUNTIME_MARKER = "athena_deep_agent";
11213
- const STATEWIRE_START_CHANNEL = "web";
11214
- const STATEWIRE_RUN_LABEL = "Athena SDK";
11215
- const DEFAULT_STATEWIRE_MODEL = "claude-sonnet-5";
11216
- function buildStatewireRunConfig(options = {}) {
11217
- var _a3, _b2, _c2, _d2;
11218
- const model = options.model ?? DEFAULT_STATEWIRE_MODEL;
11219
- const enabledTools = Array.from(
11220
- /* @__PURE__ */ new Set([...options.tools ?? [], ...options.frontendToolIds ?? []])
11221
- );
11222
- const systemPrompt = ((_a3 = options.systemPrompt) == null ? void 0 : _a3.trim()) ?? "";
11223
- return {
11224
- custom: {
11225
- runtime: DEEP_AGENT_RUNTIME_MARKER,
11226
- start_channel: STATEWIRE_START_CHANNEL,
11227
- model,
11228
- enabled_tools: enabledTools,
11229
- panel_config: {
11230
- model,
11231
- enabled_tools: enabledTools,
11232
- system_prompt: systemPrompt,
11233
- run_label: STATEWIRE_RUN_LABEL
11234
- },
11235
- ...systemPrompt ? { system_prompt: systemPrompt } : {},
11236
- ...((_b2 = options.workbench) == null ? void 0 : _b2.length) ? { workbench: options.workbench } : {},
11237
- ...((_c2 = options.knowledgeBase) == null ? void 0 : _c2.length) ? { knowledge_base: options.knowledgeBase } : {},
11238
- ...options.customToolConfigs ? { custom_tool_configs: options.customToolConfigs } : {},
11239
- ...options.appId ? { app_id: options.appId } : {},
11240
- ...((_d2 = options.clientTools) == null ? void 0 : _d2.length) ? { client_tools: options.clientTools } : {},
11241
- ...options.extraRunConfig ?? {}
11242
- }
11243
- };
11244
- }
11245
12228
  const EMPTY_TOOLKIT = {};
11246
12229
  const EMPTY_TOOL_IDS = [];
11247
12230
  function useStatewireClientTools(frontendToolkit) {
@@ -11259,6 +12242,8 @@ function useAthenaStatewireRuntime(config2) {
11259
12242
  token,
11260
12243
  getToken,
11261
12244
  model,
12245
+ agent: agent2,
12246
+ channel,
11262
12247
  tools = EMPTY_TOOL_IDS,
11263
12248
  frontendToolIds = EMPTY_TOOL_IDS,
11264
12249
  frontendToolkit = EMPTY_TOOLKIT,
@@ -11286,6 +12271,28 @@ function useAthenaStatewireRuntime(config2) {
11286
12271
  const clientToolsRef = React.useRef(clientTools);
11287
12272
  clientToolsRef.current = clientTools;
11288
12273
  const [canPersistSession] = React.useState(() => typeof localStorage !== "undefined");
12274
+ React.useEffect(() => {
12275
+ if (agent2 && !parseCollabAgentRef(agent2)) {
12276
+ athenaDiagnostics.emit("sdk.config.warning", {
12277
+ level: "warn",
12278
+ data: {
12279
+ prop: "agent",
12280
+ value: agent2,
12281
+ reason: "the statewire transport always runs the Athena deep agent; only 'collab_agent:<asset_id>' refs apply. Use transport='legacy' for named agents."
12282
+ }
12283
+ });
12284
+ }
12285
+ }, [agent2]);
12286
+ const attachSpanRef = React.useRef(null);
12287
+ const attachThreadRef = React.useRef(null);
12288
+ if (attachThreadRef.current !== threadId) {
12289
+ attachThreadRef.current = threadId;
12290
+ attachSpanRef.current = athenaDiagnostics.span(
12291
+ `statewire.attach:${threadId}`,
12292
+ "statewire.attach.start",
12293
+ { thread_id: threadId, is_new_chat: isNewChat }
12294
+ );
12295
+ }
11289
12296
  const thread = useDeepAgentThread({
11290
12297
  threadId,
11291
12298
  baseUrl: syncUrl,
@@ -11315,11 +12322,47 @@ function useAthenaStatewireRuntime(config2) {
11315
12322
  }
11316
12323
  },
11317
12324
  capabilities: { edit: true, reload: true, continue: true },
11318
- onConnectionChange,
12325
+ onStateChange: () => {
12326
+ const endSpan = attachSpanRef.current;
12327
+ if (endSpan) {
12328
+ attachSpanRef.current = null;
12329
+ endSpan("statewire.snapshot", { data: { thread_id: threadId } });
12330
+ }
12331
+ },
12332
+ onConnectionChange: (connection) => {
12333
+ athenaDiagnostics.gauge("statewire.connection", (connection == null ? void 0 : connection.status) ?? null);
12334
+ if ((connection == null ? void 0 : connection.status) === "gone") {
12335
+ athenaDiagnostics.emit("statewire.connection", {
12336
+ level: "warn",
12337
+ data: { status: connection.status, message: connection.message }
12338
+ });
12339
+ }
12340
+ onConnectionChange == null ? void 0 : onConnectionChange(connection);
12341
+ },
11319
12342
  onRawConnectionChange,
11320
- onLegacyReadOnly,
12343
+ onLegacyReadOnly: (legacyReadOnly) => {
12344
+ if (legacyReadOnly) {
12345
+ athenaDiagnostics.emit("statewire.read_only", {
12346
+ level: "warn",
12347
+ data: { thread_id: threadId }
12348
+ });
12349
+ }
12350
+ onLegacyReadOnly == null ? void 0 : onLegacyReadOnly(legacyReadOnly);
12351
+ },
11321
12352
  onRunningChange,
11322
12353
  onError: (error2) => {
12354
+ if (!isStatewireChannelTeardown(error2)) {
12355
+ athenaDiagnostics.error(
12356
+ "statewire.error",
12357
+ error2,
12358
+ {
12359
+ code: "statewire_rejected",
12360
+ message: "The statewire host rejected a command",
12361
+ hint: "Inspect error.detail — agora rejections carry a structured {code, message}."
12362
+ },
12363
+ { thread_id: threadId }
12364
+ );
12365
+ }
11323
12366
  if (onErrorRef.current) {
11324
12367
  onErrorRef.current(error2);
11325
12368
  return;
@@ -11335,6 +12378,8 @@ function useAthenaStatewireRuntime(config2) {
11335
12378
  const aui = react$1.useAui({ thread, tools: auiTools });
11336
12379
  const runConfigInputsRef = React.useRef({
11337
12380
  model,
12381
+ agent: agent2,
12382
+ channel,
11338
12383
  tools,
11339
12384
  frontendToolIds,
11340
12385
  workbench,
@@ -11346,6 +12391,8 @@ function useAthenaStatewireRuntime(config2) {
11346
12391
  });
11347
12392
  runConfigInputsRef.current = {
11348
12393
  model,
12394
+ agent: agent2,
12395
+ channel,
11349
12396
  tools,
11350
12397
  frontendToolIds,
11351
12398
  workbench,
@@ -15914,11 +16961,11 @@ const pickNumber = (...candidates) => {
15914
16961
  return void 0;
15915
16962
  };
15916
16963
  const autoOpen = (assetId, options = {}) => {
15917
- const store = useAssetPanelStore.getState();
15918
- if (!store.markAutoOpened(assetId)) return;
15919
- const existing = store.tabs.find((tab) => tab.id === assetId);
16964
+ const store2 = useAssetPanelStore.getState();
16965
+ if (!store2.markAutoOpened(assetId)) return;
16966
+ const existing = store2.tabs.find((tab) => tab.id === assetId);
15920
16967
  const keepCurrentSlide = options.preserveExistingSlide && existing;
15921
- store.openAsset(assetId, {
16968
+ store2.openAsset(assetId, {
15922
16969
  type: options.type ?? "unknown",
15923
16970
  ...keepCurrentSlide || options.slideNumber === void 0 ? {} : { slideNumber: options.slideNumber }
15924
16971
  });
@@ -19340,452 +20387,6 @@ const themes = {
19340
20387
  radius: "0.625rem"
19341
20388
  }
19342
20389
  };
19343
- const DEFAULT_CAPTURE_GATE_CONFIG = {
19344
- globalMaxPerWindow: 50,
19345
- globalWindowMs: 1e4,
19346
- criticalReservePerWindow: 15,
19347
- defaultEventMaxPerWindow: 12,
19348
- defaultEventWindowMs: 6e4,
19349
- defaultDedupeWindowMs: 5e3,
19350
- flushIntervalMs: 3e4,
19351
- flushCoalesceThreshold: 20,
19352
- eventOverrides: {
19353
- memory_profile_sample: { maxPerWindow: 2, windowMs: 3e4, dedupeWindowMs: 15e3 },
19354
- long_task_detected: { maxPerWindow: 3, windowMs: 6e4, dedupeWindowMs: 1e4 },
19355
- collab_connection_status_changed: { maxPerWindow: 6, windowMs: 6e4 },
19356
- collab_first_remote_update: { maxPerWindow: 3, windowMs: 6e4 },
19357
- collab_first_local_update: { maxPerWindow: 3, windowMs: 6e4 },
19358
- collab_render_time_sync_fix: { maxPerWindow: 3, windowMs: 6e4 },
19359
- collab_visibility_recovery: { maxPerWindow: 4, windowMs: 6e4 },
19360
- langgraph_message_validation_error: {
19361
- maxPerWindow: 8,
19362
- windowMs: 6e4,
19363
- dedupeWindowMs: 15e3
19364
- },
19365
- langgraph_messages_validation_error: {
19366
- maxPerWindow: 5,
19367
- windowMs: 6e4,
19368
- dedupeWindowMs: 15e3
19369
- },
19370
- langgraph_interrupt_validation_error: {
19371
- maxPerWindow: 5,
19372
- windowMs: 6e4,
19373
- dedupeWindowMs: 15e3
19374
- },
19375
- langgraph_state_validation_error: {
19376
- maxPerWindow: 5,
19377
- windowMs: 6e4,
19378
- dedupeWindowMs: 15e3
19379
- },
19380
- graphql_error: { maxPerWindow: 12, windowMs: 6e4, dedupeWindowMs: 1e4 },
19381
- chat_error: { maxPerWindow: 8, windowMs: 6e4, dedupeWindowMs: 5e3 },
19382
- memory_critical_threshold: { maxPerWindow: 3, windowMs: 3e5 },
19383
- memory_warning_threshold: { maxPerWindow: 3, windowMs: 3e5 },
19384
- pptx_slide_changed: { maxPerWindow: 8, windowMs: 3e4 }
19385
- }
19386
- };
19387
- const CRITICAL_EVENT_PATTERNS = [
19388
- /(?:^|_)failed$/,
19389
- /(?:^|_)error(?:_|$)/,
19390
- /crash/,
19391
- /^oom_/,
19392
- /aw_snap/,
19393
- /chunk_load/,
19394
- /global_error/,
19395
- /\$exception$/,
19396
- /^404_error$/,
19397
- /^500_error$/,
19398
- /_boundary_/
19399
- ];
19400
- const BYPASS_OPTION_KEY = "__posthog_gate_bypass";
19401
- function isCriticalPosthogEvent(event) {
19402
- return CRITICAL_EVENT_PATTERNS.some((pattern) => pattern.test(event));
19403
- }
19404
- function shouldBypassCaptureGate(options) {
19405
- if (!options || typeof options !== "object") return false;
19406
- return options[BYPASS_OPTION_KEY] === true;
19407
- }
19408
- function withCaptureGateBypass(options) {
19409
- return {
19410
- ...options ?? {},
19411
- [BYPASS_OPTION_KEY]: true
19412
- };
19413
- }
19414
- function pruneWindow(window2, now, windowMs) {
19415
- const cutoff = now - windowMs;
19416
- while (window2.timestamps.length > 0 && window2.timestamps[0] < cutoff) {
19417
- window2.timestamps.shift();
19418
- }
19419
- }
19420
- function countInWindow(window2, now, windowMs) {
19421
- pruneWindow(window2, now, windowMs);
19422
- return window2.timestamps.length;
19423
- }
19424
- function recordInWindow(window2, now) {
19425
- window2.timestamps.push(now);
19426
- }
19427
- function stableStringify(value) {
19428
- if (value == null) return String(value);
19429
- if (typeof value !== "object") return String(value);
19430
- if (Array.isArray(value)) {
19431
- return `[${value.map((item) => stableStringify(item)).join(",")}]`;
19432
- }
19433
- const record2 = value;
19434
- const keys2 = Object.keys(record2).sort();
19435
- return `{${keys2.map((key) => `${key}:${stableStringify(record2[key])}`).join(",")}}`;
19436
- }
19437
- function fingerprintProperties(properties) {
19438
- if (!properties) return "";
19439
- const keys2 = [
19440
- "error",
19441
- "error_message",
19442
- "message",
19443
- "reason",
19444
- "status",
19445
- "code",
19446
- "asset_id",
19447
- "doc_id",
19448
- "thread_id",
19449
- "session_id",
19450
- "operation",
19451
- "path",
19452
- "url",
19453
- "chunk_identifier",
19454
- "validation_path"
19455
- ];
19456
- const subset = {};
19457
- for (const key of keys2) {
19458
- if (key in properties) {
19459
- subset[key] = properties[key];
19460
- }
19461
- }
19462
- return stableStringify(subset);
19463
- }
19464
- function buildCaptureFingerprint(event, properties) {
19465
- return `${event}|${fingerprintProperties(properties)}`;
19466
- }
19467
- function buildCoalescedCaptureProperties(payload) {
19468
- const windowMs = payload.lastAt - payload.firstAt;
19469
- return {
19470
- ...payload.properties,
19471
- coalesced: true,
19472
- coalesced_count: payload.coalescedCount,
19473
- coalesced_first_at: new Date(payload.firstAt).toISOString(),
19474
- coalesced_last_at: new Date(payload.lastAt).toISOString(),
19475
- coalesced_window_ms: windowMs,
19476
- coalesced_suppression_reason: payload.suppressionReason
19477
- };
19478
- }
19479
- class PosthogCaptureGate {
19480
- constructor(config2 = DEFAULT_CAPTURE_GATE_CONFIG) {
19481
- __publicField(this, "config");
19482
- __publicField(this, "globalWindow", { timestamps: [] });
19483
- __publicField(this, "eventWindows", /* @__PURE__ */ new Map());
19484
- __publicField(this, "activeDedupe", /* @__PURE__ */ new Map());
19485
- __publicField(this, "coalesceBuckets", /* @__PURE__ */ new Map());
19486
- __publicField(this, "emittedTotal", 0);
19487
- __publicField(this, "coalescedTotal", 0);
19488
- __publicField(this, "flushedCoalescedTotal", 0);
19489
- this.config = config2;
19490
- }
19491
- resetForTests() {
19492
- this.globalWindow.timestamps.length = 0;
19493
- this.eventWindows.clear();
19494
- this.activeDedupe.clear();
19495
- this.coalesceBuckets.clear();
19496
- this.emittedTotal = 0;
19497
- this.coalescedTotal = 0;
19498
- this.flushedCoalescedTotal = 0;
19499
- }
19500
- getSnapshot() {
19501
- const coalescedPendingByEvent = {};
19502
- let coalescedPending = 0;
19503
- for (const bucket of this.coalesceBuckets.values()) {
19504
- coalescedPending += bucket.count;
19505
- coalescedPendingByEvent[bucket.event] = (coalescedPendingByEvent[bucket.event] ?? 0) + bucket.count;
19506
- }
19507
- return {
19508
- coalescedPending,
19509
- coalescedPendingByEvent,
19510
- emittedTotal: this.emittedTotal,
19511
- coalescedTotal: this.coalescedTotal,
19512
- flushedCoalescedTotal: this.flushedCoalescedTotal
19513
- };
19514
- }
19515
- evaluateCapture(event, properties, options, now = Date.now()) {
19516
- if (shouldBypassCaptureGate(options)) {
19517
- return { action: "emit" };
19518
- }
19519
- const fingerprint = buildCaptureFingerprint(event, properties);
19520
- const bucketKey = fingerprint;
19521
- const override = this.config.eventOverrides[event];
19522
- const dedupeWindowMs = (override == null ? void 0 : override.dedupeWindowMs) ?? this.config.defaultDedupeWindowMs;
19523
- const lastDedupe = this.activeDedupe.get(event);
19524
- if (lastDedupe && lastDedupe.fingerprint === fingerprint && now - lastDedupe.at < dedupeWindowMs) {
19525
- return this.recordCoalesce(event, bucketKey, fingerprint, properties, "dedupe", now);
19526
- }
19527
- const critical = isCriticalPosthogEvent(event);
19528
- const globalCount = countInWindow(this.globalWindow, now, this.config.globalWindowMs);
19529
- const normalBudget = Math.max(
19530
- 0,
19531
- this.config.globalMaxPerWindow - this.config.criticalReservePerWindow
19532
- );
19533
- if (critical) {
19534
- if (globalCount >= this.config.globalMaxPerWindow) {
19535
- return this.recordCoalesce(event, bucketKey, fingerprint, properties, "global_budget", now);
19536
- }
19537
- } else if (globalCount >= normalBudget) {
19538
- return this.recordCoalesce(event, bucketKey, fingerprint, properties, "global_budget", now);
19539
- }
19540
- const eventWindow = this.eventWindows.get(event) ?? { timestamps: [] };
19541
- this.eventWindows.set(event, eventWindow);
19542
- const eventMax = (override == null ? void 0 : override.maxPerWindow) ?? this.config.defaultEventMaxPerWindow;
19543
- const eventWindowMs = (override == null ? void 0 : override.windowMs) ?? this.config.defaultEventWindowMs;
19544
- const eventCount = countInWindow(eventWindow, now, eventWindowMs);
19545
- if (eventCount >= eventMax) {
19546
- return this.recordCoalesce(event, bucketKey, fingerprint, properties, "event_budget", now);
19547
- }
19548
- recordInWindow(this.globalWindow, now);
19549
- recordInWindow(eventWindow, now);
19550
- this.activeDedupe.set(event, { fingerprint, bucketKey, at: now });
19551
- this.emittedTotal += 1;
19552
- return { action: "emit" };
19553
- }
19554
- /** Returns payloads ready to flush (does not mutate buckets until caller confirms). */
19555
- collectFlushCandidates(now = Date.now()) {
19556
- const payloads = [];
19557
- for (const bucket of this.coalesceBuckets.values()) {
19558
- const shouldFlushBySize = bucket.count >= this.config.flushCoalesceThreshold;
19559
- const shouldFlushByAge = now - bucket.firstAt >= this.config.flushIntervalMs;
19560
- if (!shouldFlushBySize && !shouldFlushByAge) {
19561
- continue;
19562
- }
19563
- payloads.push({
19564
- bucketKey: bucket.bucketKey,
19565
- event: bucket.event,
19566
- properties: bucket.sampleProperties,
19567
- coalescedCount: bucket.count,
19568
- firstAt: bucket.firstAt,
19569
- lastAt: bucket.lastAt,
19570
- suppressionReason: bucket.suppressionReason
19571
- });
19572
- }
19573
- return payloads;
19574
- }
19575
- /** Remove flushed bucket keys after successful emit. */
19576
- acknowledgeFlushed(payloads) {
19577
- for (const payload of payloads) {
19578
- this.coalesceBuckets.delete(payload.bucketKey);
19579
- this.flushedCoalescedTotal += payload.coalescedCount;
19580
- }
19581
- }
19582
- /** After coalescing, flush immediately if the bucket crossed the early threshold. */
19583
- takeBucketIfReady(bucketKey, now = Date.now()) {
19584
- const bucket = this.coalesceBuckets.get(bucketKey);
19585
- if (!bucket) return null;
19586
- const shouldFlushBySize = bucket.count >= this.config.flushCoalesceThreshold;
19587
- const shouldFlushByAge = now - bucket.firstAt >= this.config.flushIntervalMs;
19588
- if (!shouldFlushBySize && !shouldFlushByAge) {
19589
- return null;
19590
- }
19591
- this.coalesceBuckets.delete(bucketKey);
19592
- this.flushedCoalescedTotal += bucket.count;
19593
- return {
19594
- bucketKey: bucket.bucketKey,
19595
- event: bucket.event,
19596
- properties: bucket.sampleProperties,
19597
- coalescedCount: bucket.count,
19598
- firstAt: bucket.firstAt,
19599
- lastAt: bucket.lastAt,
19600
- suppressionReason: bucket.suppressionReason
19601
- };
19602
- }
19603
- /** Force-flush every pending bucket (e.g. page hide). */
19604
- collectAllPending() {
19605
- return [...this.coalesceBuckets.values()].map((bucket) => ({
19606
- bucketKey: bucket.bucketKey,
19607
- event: bucket.event,
19608
- properties: bucket.sampleProperties,
19609
- coalescedCount: bucket.count,
19610
- firstAt: bucket.firstAt,
19611
- lastAt: bucket.lastAt,
19612
- suppressionReason: bucket.suppressionReason
19613
- }));
19614
- }
19615
- recordCoalesce(event, bucketKey, fingerprint, properties, reason, now) {
19616
- const existing = this.coalesceBuckets.get(bucketKey);
19617
- if (existing) {
19618
- existing.count += 1;
19619
- existing.lastAt = now;
19620
- existing.sampleProperties = { ...existing.sampleProperties, ...properties ?? {} };
19621
- } else {
19622
- this.coalesceBuckets.set(bucketKey, {
19623
- event,
19624
- bucketKey,
19625
- fingerprint,
19626
- count: 1,
19627
- firstAt: now,
19628
- lastAt: now,
19629
- suppressionReason: reason,
19630
- sampleProperties: { ...properties ?? {} }
19631
- });
19632
- }
19633
- this.coalescedTotal += 1;
19634
- this.activeDedupe.set(event, { fingerprint, bucketKey, at: now });
19635
- return { action: "coalesce", reason, bucketKey };
19636
- }
19637
- }
19638
- const gate = new PosthogCaptureGate(DEFAULT_CAPTURE_GATE_CONFIG);
19639
- let wrappedClient = null;
19640
- let originalCaptureRef = null;
19641
- let flushTimer = null;
19642
- let lifecycleHooksInstalled = false;
19643
- function getPosthogCaptureGate() {
19644
- return gate;
19645
- }
19646
- function emitThroughOriginal(event, properties, options) {
19647
- if (!originalCaptureRef) return void 0;
19648
- return originalCaptureRef(event, properties, withCaptureGateBypass(options));
19649
- }
19650
- function flushCoalescedPayload(payload) {
19651
- emitThroughOriginal(payload.event, buildCoalescedCaptureProperties(payload));
19652
- }
19653
- function flushCoalescedCaptures(options) {
19654
- const payloads = (options == null ? void 0 : options.force) ? gate.collectAllPending() : gate.collectFlushCandidates();
19655
- if (payloads.length === 0) return;
19656
- for (const payload of payloads) {
19657
- flushCoalescedPayload(payload);
19658
- }
19659
- gate.acknowledgeFlushed(payloads);
19660
- }
19661
- function installLifecycleFlushHooks() {
19662
- if (lifecycleHooksInstalled || typeof window === "undefined") return;
19663
- lifecycleHooksInstalled = true;
19664
- const flushOnHide = () => {
19665
- flushCoalescedCaptures({ force: true });
19666
- };
19667
- window.addEventListener("pagehide", flushOnHide);
19668
- document.addEventListener("visibilitychange", () => {
19669
- if (document.visibilityState === "hidden") {
19670
- flushOnHide();
19671
- }
19672
- });
19673
- if (!flushTimer) {
19674
- flushTimer = setInterval(() => {
19675
- flushCoalescedCaptures();
19676
- }, DEFAULT_CAPTURE_GATE_CONFIG.flushIntervalMs);
19677
- }
19678
- }
19679
- function wrapPosthogClient(client) {
19680
- if (wrappedClient === client) {
19681
- return client;
19682
- }
19683
- originalCaptureRef = client.capture.bind(client);
19684
- const originalCaptureException = typeof client.captureException === "function" ? client.captureException.bind(client) : null;
19685
- installLifecycleFlushHooks();
19686
- client.capture = ((event, properties, options) => {
19687
- const outcome = gate.evaluateCapture(event, properties, options);
19688
- if (outcome.action === "coalesce") {
19689
- const readyPayload = gate.takeBucketIfReady(outcome.bucketKey);
19690
- if (readyPayload) {
19691
- flushCoalescedPayload(readyPayload);
19692
- }
19693
- return void 0;
19694
- }
19695
- return emitThroughOriginal(event, properties, options);
19696
- });
19697
- if (originalCaptureException) {
19698
- client.captureException = ((error2, additionalProperties) => {
19699
- const mergedProperties = {
19700
- ...additionalProperties ?? {},
19701
- $exception_message: error2 instanceof Error ? error2.message : String(error2),
19702
- $exception_type: error2 instanceof Error ? error2.name : typeof error2
19703
- };
19704
- const outcome = gate.evaluateCapture("$exception", mergedProperties);
19705
- if (outcome.action === "coalesce") {
19706
- const readyPayload = gate.takeBucketIfReady(outcome.bucketKey);
19707
- if (readyPayload) {
19708
- flushCoalescedPayload(readyPayload);
19709
- }
19710
- return void 0;
19711
- }
19712
- return originalCaptureException(error2, additionalProperties);
19713
- });
19714
- }
19715
- wrappedClient = client;
19716
- return client;
19717
- }
19718
- function capturePosthogEvent(client, event, properties, options) {
19719
- if (!client || typeof client.capture !== "function") return;
19720
- client.capture(event, properties, options);
19721
- }
19722
- function capturePosthogException(client, error2, properties, options) {
19723
- if (!client) return;
19724
- if (typeof client.captureException === "function") {
19725
- client.captureException(error2, properties);
19726
- return;
19727
- }
19728
- capturePosthogEvent(
19729
- client,
19730
- "$exception",
19731
- {
19732
- ...properties ?? {},
19733
- $exception_message: error2.message,
19734
- $exception_type: error2.name,
19735
- $exception_stack: error2.stack
19736
- },
19737
- options
19738
- );
19739
- }
19740
- let posthogInstance = null;
19741
- let initPromise = null;
19742
- const DEFAULT_HOST = "https://us.i.posthog.com";
19743
- async function initializePostHog(apiKey, host, debug) {
19744
- if (posthogInstance) return posthogInstance;
19745
- if (typeof window === "undefined") return null;
19746
- try {
19747
- const posthog = (await import("posthog-js")).default;
19748
- posthog.init(apiKey, {
19749
- api_host: host,
19750
- autocapture: true,
19751
- capture_pageview: false,
19752
- session_recording: {
19753
- recordCrossOriginIframes: true,
19754
- maskAllInputs: true
19755
- },
19756
- loaded: (ph) => {
19757
- wrapPosthogClient(ph);
19758
- if (debug) {
19759
- ph.debug(true);
19760
- }
19761
- }
19762
- });
19763
- wrapPosthogClient(posthog);
19764
- posthogInstance = posthog;
19765
- return posthog;
19766
- } catch {
19767
- initPromise = null;
19768
- return null;
19769
- }
19770
- }
19771
- function getPostHogInstance() {
19772
- return posthogInstance;
19773
- }
19774
- function PostHogProvider({
19775
- children,
19776
- config: config2
19777
- }) {
19778
- const apiKey = (config2 == null ? void 0 : config2.apiKey) ?? "";
19779
- const host = (config2 == null ? void 0 : config2.host) ?? DEFAULT_HOST;
19780
- const debug = (config2 == null ? void 0 : config2.debug) ?? false;
19781
- React.useEffect(() => {
19782
- if (!apiKey || typeof window === "undefined") return;
19783
- if (!initPromise) {
19784
- initPromise = initializePostHog(apiKey, host, debug);
19785
- }
19786
- }, [apiKey, host, debug]);
19787
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
19788
- }
19789
20390
  const resolveTokenOverride = ({
19790
20391
  config: config2,
19791
20392
  token
@@ -19915,6 +20516,8 @@ function AthenaStatewireStandalone({
19915
20516
  token,
19916
20517
  getToken,
19917
20518
  model,
20519
+ agent: agent2,
20520
+ channel,
19918
20521
  tools,
19919
20522
  frontendToolIds,
19920
20523
  frontendTools,
@@ -19946,6 +20549,8 @@ function AthenaStatewireStandalone({
19946
20549
  token,
19947
20550
  getToken,
19948
20551
  model,
20552
+ agent: agent2,
20553
+ channel,
19949
20554
  tools,
19950
20555
  frontendToolIds,
19951
20556
  frontendToolkit: frontendTools,
@@ -20221,6 +20826,7 @@ function AthenaProvider({
20221
20826
  apiKey,
20222
20827
  token: tokenProp,
20223
20828
  agent: agent2,
20829
+ channel,
20224
20830
  model,
20225
20831
  tools = [],
20226
20832
  frontendTools = {},
@@ -20243,8 +20849,32 @@ function AthenaProvider({
20243
20849
  theme,
20244
20850
  linkClicks,
20245
20851
  citationLinks,
20246
- posthog: posthogProp
20852
+ posthog: posthogProp,
20853
+ debug,
20854
+ onDiagnostic,
20855
+ onError
20247
20856
  }) {
20857
+ const onDiagnosticRef = React.useRef(onDiagnostic);
20858
+ onDiagnosticRef.current = onDiagnostic;
20859
+ const onErrorRef = React.useRef(onError);
20860
+ onErrorRef.current = onError;
20861
+ React.useEffect(() => {
20862
+ installAthenaDiagnosticsGlobal();
20863
+ return athenaDiagnostics.addConsumer({
20864
+ onEvent: (event) => {
20865
+ var _a3;
20866
+ return (_a3 = onDiagnosticRef.current) == null ? void 0 : _a3.call(onDiagnosticRef, event);
20867
+ },
20868
+ onError: (error2, event) => {
20869
+ var _a3;
20870
+ return (_a3 = onErrorRef.current) == null ? void 0 : _a3.call(onErrorRef, error2, event);
20871
+ }
20872
+ });
20873
+ }, []);
20874
+ const debugKey = JSON.stringify(debugPropToDiagnosticsConfig(debug));
20875
+ React.useEffect(() => {
20876
+ athenaDiagnostics.configure(debugPropToDiagnosticsConfig(debug));
20877
+ }, [debugKey]);
20248
20878
  const frontendToolNames = React.useMemo(() => Object.keys(frontendTools), [frontendTools]);
20249
20879
  const effectiveFrontendTools = React.useMemo(
20250
20880
  () => disableAutoOpen ? frontendTools : { ...DEFAULT_AUTO_OPEN_TOOLS, ...frontendTools },
@@ -20271,10 +20901,31 @@ function AthenaProvider({
20271
20901
  transport: configuredTransport
20272
20902
  });
20273
20903
  React.useEffect(() => {
20904
+ athenaDiagnostics.gauge("sdk.transport", effectiveTransport);
20905
+ athenaDiagnostics.emit("sdk.transport", {
20906
+ level: "debug",
20907
+ data: { transport: effectiveTransport, thread_list: enableThreadList }
20908
+ });
20274
20909
  if (transportFallbackReason) {
20910
+ athenaDiagnostics.emit("sdk.config.warning", {
20911
+ level: "warn",
20912
+ data: { prop: "transport", reason: transportFallbackReason }
20913
+ });
20275
20914
  console.warn(`[AthenaSDK] ${transportFallbackReason}`);
20276
20915
  }
20277
- }, [transportFallbackReason]);
20916
+ }, [effectiveTransport, enableThreadList, transportFallbackReason]);
20917
+ React.useEffect(() => {
20918
+ if (channel && effectiveTransport !== "statewire") {
20919
+ athenaDiagnostics.emit("sdk.config.warning", {
20920
+ level: "warn",
20921
+ data: {
20922
+ prop: "channel",
20923
+ value: channel,
20924
+ reason: "the 'channel' prop requires transport='statewire'; the legacy transport ignores it."
20925
+ }
20926
+ });
20927
+ }
20928
+ }, [channel, effectiveTransport]);
20278
20929
  const bridge = useParentBridge({
20279
20930
  trustedOrigins: configuredTrustedParentOrigins
20280
20931
  });
@@ -20301,6 +20952,8 @@ function AthenaProvider({
20301
20952
  token: effectiveToken,
20302
20953
  getToken: configuredGetToken,
20303
20954
  model,
20955
+ agent: agent2,
20956
+ channel,
20304
20957
  tools,
20305
20958
  frontendToolIds: frontendToolNames,
20306
20959
  frontendTools: effectiveFrontendTools,
@@ -54652,13 +55305,13 @@ function getEmptyMessage(scope, query) {
54652
55305
  function MentionIcon({ item }) {
54653
55306
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-7 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(MentionIconGlyph, { icon: item.fallbackIcon }) });
54654
55307
  }
54655
- const MentionSuggestionList = React.forwardRef(({ store, query, command: command2, closeMenu }, ref) => {
55308
+ const MentionSuggestionList = React.forwardRef(({ store: store2, query, command: command2, closeMenu }, ref) => {
54656
55309
  const [selectedIndex, setSelectedIndex] = React.useState(0);
54657
55310
  const [currentScope, setCurrentScope] = React.useState("root");
54658
55311
  const scrollContainerRef = React.useRef(null);
54659
- const hasGlobalSearch = store.state.registry.entries.has(GLOBAL_SEARCH_SCOPE$1);
55312
+ const hasGlobalSearch = store2.state.registry.entries.has(GLOBAL_SEARCH_SCOPE$1);
54660
55313
  const effectiveScope = currentScope === "root" && query.trim() && hasGlobalSearch ? GLOBAL_SEARCH_SCOPE$1 : currentScope;
54661
- const { items, isFetching } = useStore(store, (state) => ({
55314
+ const { items, isFetching } = useStore(store2, (state) => ({
54662
55315
  items: getFilteredItems(state.cache, effectiveScope, query),
54663
55316
  isFetching: false
54664
55317
  }));
@@ -54777,7 +55430,7 @@ const MentionSuggestionList = React.forwardRef(({ store, query, command: command
54777
55430
  ] });
54778
55431
  });
54779
55432
  MentionSuggestionList.displayName = "MentionSuggestionList";
54780
- const MentionSuggestionPopup = React.forwardRef(({ store, query, command: command2, clientRect: clientRect2, closeMenu, isHidden: isHidden3 = false }, ref) => {
55433
+ const MentionSuggestionPopup = React.forwardRef(({ store: store2, query, command: command2, clientRect: clientRect2, closeMenu, isHidden: isHidden3 = false }, ref) => {
54781
55434
  const listRef = React.useRef(null);
54782
55435
  const virtualRef = React.useRef({
54783
55436
  getBoundingClientRect: () => clientRect2 ? clientRect2() : new DOMRect()
@@ -54824,7 +55477,7 @@ const MentionSuggestionPopup = React.forwardRef(({ store, query, command: comman
54824
55477
  MentionSuggestionList,
54825
55478
  {
54826
55479
  ref: listRef,
54827
- store,
55480
+ store: store2,
54828
55481
  query,
54829
55482
  command: command2,
54830
55483
  closeMenu
@@ -55051,9 +55704,9 @@ function useMentionSuggestions(tools, options = {}) {
55051
55704
  populateMentionCache({ cache, tools, rootCategories });
55052
55705
  storeRef.current = new Store({ registry: registry2, cache });
55053
55706
  }
55054
- const store = storeRef.current;
55707
+ const store2 = storeRef.current;
55055
55708
  React.useEffect(() => {
55056
- store.setState((prev) => {
55709
+ store2.setState((prev) => {
55057
55710
  const newCache = createItemCache();
55058
55711
  if (rootCategories) {
55059
55712
  registerStaticSource(prev.registry, "toolkits");
@@ -55063,8 +55716,8 @@ function useMentionSuggestions(tools, options = {}) {
55063
55716
  populateMentionCache({ cache: newCache, tools, rootCategories });
55064
55717
  return { ...prev, cache: newCache };
55065
55718
  });
55066
- }, [tools, store, rootCategories, rootCategoriesKey]);
55067
- return store;
55719
+ }, [tools, store2, rootCategories, rootCategoriesKey]);
55720
+ return store2;
55068
55721
  }
55069
55722
  const AttachmentCtx = React.createContext(null);
55070
55723
  function AttachmentProvider({ children }) {
@@ -57489,10 +58142,10 @@ function openStudioAsset({
57489
58142
  slideNumber,
57490
58143
  preserveExistingSlide
57491
58144
  }) {
57492
- const store = useAssetPanelStore.getState();
57493
- const existing = store.tabs.find((tab) => tab.id === assetId);
58145
+ const store2 = useAssetPanelStore.getState();
58146
+ const existing = store2.tabs.find((tab) => tab.id === assetId);
57494
58147
  const shouldKeepCurrentSlide = preserveExistingSlide && existing;
57495
- store.openAsset(assetId, {
58148
+ store2.openAsset(assetId, {
57496
58149
  type: assetType,
57497
58150
  ...!shouldKeepCurrentSlide && slideNumber !== void 0 ? { slideNumber } : {}
57498
58151
  });
@@ -62457,6 +63110,8 @@ function useComposerAttachment() {
62457
63110
  }, [aui]);
62458
63111
  return { addFile, addContent, clear };
62459
63112
  }
63113
+ exports.ATHENA_REACT_SDK_VERSION = ATHENA_REACT_SDK_VERSION;
63114
+ exports.ATHENA_SDK_ERROR_CODES = ATHENA_SDK_ERROR_CODES;
62460
63115
  exports.ATHENA_TRANSPORTS = ATHENA_TRANSPORTS;
62461
63116
  exports.AppendDocumentToolUI = AppendDocumentToolUI;
62462
63117
  exports.AssetPanel = AssetPanel;
@@ -62467,10 +63122,12 @@ exports.AthenaChat = AthenaChat;
62467
63122
  exports.AthenaLayout = AthenaLayout;
62468
63123
  exports.AthenaProvider = AthenaProvider;
62469
63124
  exports.AthenaReasoningPart = AthenaReasoningPart;
63125
+ exports.AthenaSdkError = AthenaSdkError;
62470
63126
  exports.AthenaThreadIdContext = AthenaThreadIdContext;
62471
63127
  exports.AthenaUserMessage = AthenaUserMessage;
62472
63128
  exports.BrowseToolUI = BrowseToolUI;
62473
63129
  exports.Button = Button;
63130
+ exports.COLLAB_AGENT_REF_PREFIX = COLLAB_AGENT_REF_PREFIX;
62474
63131
  exports.Collapsible = Collapsible;
62475
63132
  exports.CollapsibleContent = CollapsibleContent;
62476
63133
  exports.CollapsibleTrigger = CollapsibleTrigger;
@@ -62530,6 +63187,7 @@ exports.WebSearchToolUI = WebSearchToolUI;
62530
63187
  exports.allowsMidRunSend = allowsMidRunSend;
62531
63188
  exports.archiveThread = archiveThread;
62532
63189
  exports.asHitlApproval = asHitlApproval;
63190
+ exports.athenaDiagnostics = athenaDiagnostics;
62533
63191
  exports.athenaStatewireErrorNotice = athenaStatewireErrorNotice;
62534
63192
  exports.autoCloseInFlightSubgraphMessages = autoCloseInFlightSubgraphMessages;
62535
63193
  exports.buildCoalescedCaptureProperties = buildCoalescedCaptureProperties;
@@ -62553,13 +63211,17 @@ exports.getPostHogInstance = getPostHogInstance;
62553
63211
  exports.getPosthogCaptureGate = getPosthogCaptureGate;
62554
63212
  exports.getThreadState = getThreadState;
62555
63213
  exports.hasStatewireThreadExtras = hasStatewireThreadExtras;
63214
+ exports.installAthenaDiagnosticsGlobal = installAthenaDiagnosticsGlobal;
62556
63215
  exports.isAthenaCitationUrl = isAthenaCitationUrl;
63216
+ exports.isAthenaSdkError = isAthenaSdkError;
62557
63217
  exports.isCriticalPosthogEvent = isCriticalPosthogEvent;
62558
63218
  exports.isPendingInterrupt = isPendingInterrupt;
62559
63219
  exports.listThreads = listThreads;
62560
63220
  exports.normalizeResult = normalizeResult;
62561
63221
  exports.parseAthenaCitationLink = parseAthenaCitationLink;
63222
+ exports.parseCollabAgentRef = parseCollabAgentRef;
62562
63223
  exports.readInterruptMessage = readInterruptMessage;
63224
+ exports.readRejectionDetail = readRejectionDetail;
62563
63225
  exports.resetAssetAutoOpen = resetAssetAutoOpen;
62564
63226
  exports.resolveAthenaTransport = resolveAthenaTransport;
62565
63227
  exports.resolveStatewireSyncUrl = resolveStatewireSyncUrl;
@@ -62567,6 +63229,7 @@ exports.setThreadReadState = setThreadReadState;
62567
63229
  exports.statewireClientToolWireEntries = statewireClientToolWireEntries;
62568
63230
  exports.themeToStyleVars = themeToStyleVars;
62569
63231
  exports.themes = themes;
63232
+ exports.toAthenaSdkError = toAthenaSdkError;
62570
63233
  exports.truncate = truncate;
62571
63234
  exports.tryParseJson = tryParseJson$2;
62572
63235
  exports.useAppendToComposer = useAppendToComposer;
@@ -62574,6 +63237,7 @@ exports.useAssetEmbed = useAssetEmbed;
62574
63237
  exports.useAssetPanelStore = useAssetPanelStore;
62575
63238
  exports.useAthenaCitationLinkHandler = useAthenaCitationLinkHandler;
62576
63239
  exports.useAthenaConfig = useAthenaConfig;
63240
+ exports.useAthenaDiagnostics = useAthenaDiagnostics;
62577
63241
  exports.useAthenaLinkClickHandler = useAthenaLinkClickHandler;
62578
63242
  exports.useAthenaRuntime = useAthenaRuntime;
62579
63243
  exports.useAthenaStatewireLifecycle = useAthenaStatewireLifecycle;