@apteva/apteva-kit 0.1.129 → 0.1.131

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2805,17 +2805,36 @@ function ToolCall({ name, status, isReceiving = false, inputLength = 0, streamOu
2805
2805
  // src/components/Chat/ToolCallGroup.tsx
2806
2806
 
2807
2807
 
2808
+ function formatResultPreview(result) {
2809
+ if (result == null) return "";
2810
+ const str = typeof result === "string" ? result : JSON.stringify(result);
2811
+ const oneLine = str.replace(/\s+/g, " ").trim();
2812
+ return oneLine.length > 120 ? oneLine.slice(0, 117) + "..." : oneLine;
2813
+ }
2808
2814
  function ToolCallGroup({ tools }) {
2809
2815
  const completed = tools.filter((t) => t.status === "completed").length;
2810
2816
  const errored = tools.filter((t) => t.status === "error").length;
2811
- const running = tools.filter((t) => t.status === "running").length;
2812
- const preparing = tools.filter((t) => t.status === "preparing").length;
2813
2817
  const total = tools.length;
2814
2818
  const allDone = completed + errored === total;
2815
2819
  const [expanded, setExpanded] = _react.useState.call(void 0, false);
2816
- const isExpanded = allDone ? expanded : true;
2817
- const activeStreamTool = tools.find((t) => t.status === "running" && t.streamOutput);
2818
- const statusText = allDone ? `Used ${total} tools` : `Using ${total} tools${completed > 0 ? ` \xB7 ${completed}/${total} done` : ""}`;
2820
+ const isExpanded = expanded;
2821
+ const activeTool = tools.find((t) => t.status === "running") || tools.find((t) => t.status === "preparing");
2822
+ let statusText;
2823
+ if (allDone) {
2824
+ if (errored > 0) {
2825
+ statusText = `Used ${total} tools \xB7 ${errored} failed`;
2826
+ } else {
2827
+ statusText = `Used ${total} tools`;
2828
+ }
2829
+ } else {
2830
+ const parts = [`Using ${total} tools`];
2831
+ if (completed > 0) parts.push(`${completed} done`);
2832
+ if (activeTool) {
2833
+ const activeLabel = activeTool.streamOutput || (activeTool.status === "preparing" ? "preparing" : "running");
2834
+ parts.push(`${activeTool.name} ${activeLabel === "preparing" || activeLabel === "running" ? activeLabel + "..." : "\xB7 " + activeLabel}`);
2835
+ }
2836
+ statusText = parts.join(" \xB7 ");
2837
+ }
2819
2838
  const cardClass = allDone ? errored > 0 ? "apteva-tool-group apteva-tool-group-error" : "apteva-tool-group apteva-tool-group-completed" : "apteva-tool-group apteva-tool-group-running";
2820
2839
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: cardClass, children: [
2821
2840
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
@@ -2846,18 +2865,20 @@ function ToolCallGroup({ tools }) {
2846
2865
  ]
2847
2866
  }
2848
2867
  ),
2849
- !isExpanded && activeStreamTool && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "apteva-tool-group-stream", children: [
2850
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "apteva-tool-group-stream-name", children: [
2851
- activeStreamTool.name,
2852
- ":"
2853
- ] }),
2854
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "apteva-tool-group-stream-text", children: activeStreamTool.streamOutput })
2855
- ] }),
2856
- isExpanded && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "apteva-tool-group-list", children: tools.map((tool) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "apteva-tool-group-item", children: [
2857
- tool.status === "completed" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { className: "apteva-tool-group-item-icon apteva-tool-group-item-done", width: "12", height: "12", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M5 13l4 4L19 7" }) }) : tool.status === "error" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { className: "apteva-tool-group-item-icon apteva-tool-group-item-error", width: "12", height: "12", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M6 18L18 6M6 6l12 12" }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "apteva-tool-group-item-icon apteva-tool-group-item-spinner" }),
2858
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "apteva-tool-group-item-name", children: tool.name }),
2859
- tool.streamOutput && tool.status === "running" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "apteva-tool-group-item-stream", children: tool.streamOutput })
2860
- ] }, tool.id)) })
2868
+ isExpanded && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "apteva-tool-group-list", children: tools.map((tool) => {
2869
+ const resultPreview = tool.status === "completed" && tool.result ? formatResultPreview(tool.result) : "";
2870
+ const hasDetail = tool.status === "running" && tool.streamOutput || resultPreview;
2871
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: `apteva-tool-group-item ${hasDetail ? "apteva-tool-group-item-has-detail" : ""}`, children: [
2872
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "apteva-tool-group-item-row", children: [
2873
+ tool.status === "completed" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { className: "apteva-tool-group-item-icon apteva-tool-group-item-done", width: "12", height: "12", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M5 13l4 4L19 7" }) }) : tool.status === "error" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { className: "apteva-tool-group-item-icon apteva-tool-group-item-error", width: "12", height: "12", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M6 18L18 6M6 6l12 12" }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "apteva-tool-group-item-icon apteva-tool-group-item-spinner" }),
2874
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "apteva-tool-group-item-name", children: tool.name }),
2875
+ tool.status === "running" && !tool.streamOutput && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "apteva-tool-group-item-running-label", children: "running..." }),
2876
+ tool.status === "preparing" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "apteva-tool-group-item-running-label", children: "preparing..." })
2877
+ ] }),
2878
+ tool.status === "running" && tool.streamOutput && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "apteva-tool-group-item-detail", children: tool.streamOutput }),
2879
+ resultPreview && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "apteva-tool-group-item-detail apteva-tool-group-item-result-text", children: resultPreview })
2880
+ ] }, tool.id);
2881
+ }) })
2861
2882
  ] });
2862
2883
  }
2863
2884
 
@@ -3108,7 +3129,8 @@ function Message({ message, onAction, enableWidgets, onWidgetRender, persistentW
3108
3129
  name: tool.name,
3109
3130
  status: tool.status || (tool.result !== void 0 ? "completed" : "running"),
3110
3131
  isReceiving: tool.isReceiving,
3111
- streamOutput: tool.streamOutput
3132
+ streamOutput: tool.streamOutput,
3133
+ result: tool.result
3112
3134
  };
3113
3135
  });
3114
3136
  elements.push(
@@ -3370,7 +3392,7 @@ var getSpeechRecognition = () => {
3370
3392
  if (typeof window === "undefined") return null;
3371
3393
  return window.SpeechRecognition || window.webkitSpeechRecognition || null;
3372
3394
  };
3373
- function Composer({ onSendMessage, placeholder = "Type a message...", disabled = false, isLoading = false, onStop, onFileUpload, onSwitchMode, speechToText }) {
3395
+ function Composer({ onSendMessage, placeholder = "Type a message...", disabled = false, isLoading = false, onStop, onFileUpload, onSwitchMode, speechToText, enableVoice = false, voiceState = "idle", voicePartialTranscript = "", voiceDuration = 0, onVoiceStart, onVoiceStop }) {
3374
3396
  const [text, setText] = _react.useState.call(void 0, "");
3375
3397
  const [showMenu, setShowMenu] = _react.useState.call(void 0, false);
3376
3398
  const [pendingFiles, setPendingFiles] = _react.useState.call(void 0, []);
@@ -3663,6 +3685,31 @@ function Composer({ onSendMessage, placeholder = "Type a message...", disabled =
3663
3685
  const gridCols = hasMic ? "auto 1fr auto auto" : "auto 1fr auto";
3664
3686
  const gridAreas = isRecording ? '"plus waveform waveform stop"' : isMultiLine ? hasMic ? '"textarea textarea textarea textarea" "plus . mic send"' : '"textarea textarea textarea" "plus . send"' : hasMic ? '"plus textarea mic send"' : '"plus textarea send"';
3665
3687
  const gridColsRecording = "auto 1fr auto";
3688
+ const voiceActive = voiceState === "active" || voiceState === "connecting";
3689
+ const formatVoiceDuration = (s) => {
3690
+ const m = Math.floor(s / 60);
3691
+ const sec = s % 60;
3692
+ return `${m}:${sec.toString().padStart(2, "0")}`;
3693
+ };
3694
+ const showMicButton = enableVoice && !text.trim() && pendingFiles.length === 0 && !isLoading && !voiceActive;
3695
+ if (voiceActive) {
3696
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "px-4 py-3 relative", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "apteva-voice-overlay", children: [
3697
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "apteva-voice-transcript-area", children: voicePartialTranscript ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "apteva-voice-partial", children: voicePartialTranscript }) : voiceState === "connecting" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "apteva-voice-connecting", children: "Connecting..." }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "apteva-voice-listening", children: "Listening..." }) }),
3698
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "apteva-voice-controls", children: [
3699
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "apteva-voice-duration", children: formatVoiceDuration(voiceDuration) }),
3700
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3701
+ "button",
3702
+ {
3703
+ onClick: onVoiceStop,
3704
+ className: "apteva-voice-stop-btn",
3705
+ title: "Stop voice mode",
3706
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "3", y: "3", width: "10", height: "10", rx: "1", fill: "currentColor" }) })
3707
+ }
3708
+ )
3709
+ ] }),
3710
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "apteva-voice-indicator", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: `apteva-voice-pulse ${voiceState === "active" ? "apteva-voice-pulse-active" : ""}` }) })
3711
+ ] }) });
3712
+ }
3666
3713
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "px-4 py-3 relative", children: [
3667
3714
  fileError && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "apteva-file-error", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "apteva-file-error-content", children: [
3668
3715
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
@@ -3806,6 +3853,18 @@ function Composer({ onSendMessage, placeholder = "Type a message...", disabled =
3806
3853
  title: "Stop generation",
3807
3854
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "2", y: "2", width: "10", height: "10", rx: "1", fill: "currentColor" }) })
3808
3855
  }
3856
+ ) : showMicButton ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3857
+ "button",
3858
+ {
3859
+ onClick: onVoiceStart,
3860
+ className: "apteva-composer-voice-btn w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0",
3861
+ title: "Start voice mode",
3862
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
3863
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z", fill: "currentColor" }),
3864
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M19 10v2a7 7 0 01-14 0v-2", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
3865
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M12 19v4M8 23h8", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })
3866
+ ] })
3867
+ }
3809
3868
  ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3810
3869
  "button",
3811
3870
  {
@@ -4366,6 +4425,261 @@ function PersistentWidgetPanel({ widgets, onAction }) {
4366
4425
  ] });
4367
4426
  }
4368
4427
 
4428
+ // src/hooks/useVoiceSession.ts
4429
+
4430
+
4431
+ // src/utils/audio-utils.ts
4432
+ function float32ToInt16(float32Array) {
4433
+ const int16Array = new Int16Array(float32Array.length);
4434
+ for (let i = 0; i < float32Array.length; i++) {
4435
+ const s = Math.max(-1, Math.min(1, float32Array[i]));
4436
+ int16Array[i] = s < 0 ? s * 32768 : s * 32767;
4437
+ }
4438
+ return int16Array;
4439
+ }
4440
+ function int16ToBase64(int16Array) {
4441
+ const uint8Array = new Uint8Array(int16Array.buffer);
4442
+ let binary = "";
4443
+ for (let i = 0; i < uint8Array.length; i++) {
4444
+ binary += String.fromCharCode(uint8Array[i]);
4445
+ }
4446
+ return btoa(binary);
4447
+ }
4448
+ function base64ToFloat32(base64) {
4449
+ const binaryString = atob(base64);
4450
+ const int16Array = new Int16Array(binaryString.length / 2);
4451
+ for (let i = 0; i < int16Array.length; i++) {
4452
+ int16Array[i] = binaryString.charCodeAt(i * 2 + 1) << 8 | binaryString.charCodeAt(i * 2);
4453
+ }
4454
+ const float32Array = new Float32Array(int16Array.length);
4455
+ for (let i = 0; i < int16Array.length; i++) {
4456
+ float32Array[i] = int16Array[i] / (int16Array[i] < 0 ? 32768 : 32767);
4457
+ }
4458
+ return float32Array;
4459
+ }
4460
+ function resampleAudio(inputData, inputSampleRate, outputSampleRate) {
4461
+ if (inputSampleRate === outputSampleRate) {
4462
+ return inputData;
4463
+ }
4464
+ const ratio = inputSampleRate / outputSampleRate;
4465
+ const outputLength = Math.floor(inputData.length / ratio);
4466
+ const output = new Float32Array(outputLength);
4467
+ for (let i = 0; i < outputLength; i++) {
4468
+ const srcIndex = i * ratio;
4469
+ const srcIndexFloor = Math.floor(srcIndex);
4470
+ const srcIndexCeil = Math.min(srcIndexFloor + 1, inputData.length - 1);
4471
+ const t = srcIndex - srcIndexFloor;
4472
+ output[i] = inputData[srcIndexFloor] * (1 - t) + inputData[srcIndexCeil] * t;
4473
+ }
4474
+ return output;
4475
+ }
4476
+
4477
+ // src/hooks/useVoiceSession.ts
4478
+ function useVoiceSession(config) {
4479
+ const [state, setState] = _react.useState.call(void 0, "idle");
4480
+ const [partialTranscript, setPartialTranscript] = _react.useState.call(void 0, "");
4481
+ const [duration, setDuration] = _react.useState.call(void 0, 0);
4482
+ const wsRef = _react.useRef.call(void 0, null);
4483
+ const captureCtxRef = _react.useRef.call(void 0, null);
4484
+ const playbackCtxRef = _react.useRef.call(void 0, null);
4485
+ const mediaStreamRef = _react.useRef.call(void 0, null);
4486
+ const processorRef = _react.useRef.call(void 0, null);
4487
+ const nextPlayTimeRef = _react.useRef.call(void 0, 0);
4488
+ const durationIntervalRef = _react.useRef.call(void 0, null);
4489
+ const startTimeRef = _react.useRef.call(void 0, 0);
4490
+ const configRef = _react.useRef.call(void 0, config);
4491
+ configRef.current = config;
4492
+ const cleanup = _react.useCallback.call(void 0, () => {
4493
+ if (durationIntervalRef.current) {
4494
+ clearInterval(durationIntervalRef.current);
4495
+ durationIntervalRef.current = null;
4496
+ }
4497
+ if (processorRef.current) {
4498
+ processorRef.current.disconnect();
4499
+ processorRef.current = null;
4500
+ }
4501
+ if (mediaStreamRef.current) {
4502
+ mediaStreamRef.current.getTracks().forEach((t) => t.stop());
4503
+ mediaStreamRef.current = null;
4504
+ }
4505
+ if (captureCtxRef.current) {
4506
+ try {
4507
+ captureCtxRef.current.close();
4508
+ } catch (_) {
4509
+ }
4510
+ captureCtxRef.current = null;
4511
+ }
4512
+ if (playbackCtxRef.current) {
4513
+ try {
4514
+ playbackCtxRef.current.close();
4515
+ } catch (_) {
4516
+ }
4517
+ playbackCtxRef.current = null;
4518
+ }
4519
+ if (wsRef.current) {
4520
+ try {
4521
+ wsRef.current.close();
4522
+ } catch (_) {
4523
+ }
4524
+ wsRef.current = null;
4525
+ }
4526
+ nextPlayTimeRef.current = 0;
4527
+ setPartialTranscript("");
4528
+ setDuration(0);
4529
+ }, []);
4530
+ _react.useEffect.call(void 0, () => {
4531
+ return () => {
4532
+ cleanup();
4533
+ };
4534
+ }, [cleanup]);
4535
+ const playAudioChunk = _react.useCallback.call(void 0, (base64Audio) => {
4536
+ if (!playbackCtxRef.current) {
4537
+ playbackCtxRef.current = new AudioContext({ sampleRate: 24e3 });
4538
+ }
4539
+ const ctx = playbackCtxRef.current;
4540
+ if (ctx.state === "suspended") {
4541
+ ctx.resume();
4542
+ }
4543
+ const float32Data = base64ToFloat32(base64Audio);
4544
+ const audioBuffer = ctx.createBuffer(1, float32Data.length, 24e3);
4545
+ audioBuffer.getChannelData(0).set(float32Data);
4546
+ const source = ctx.createBufferSource();
4547
+ source.buffer = audioBuffer;
4548
+ source.connect(ctx.destination);
4549
+ const currentTime = ctx.currentTime;
4550
+ const startTime = Math.max(currentTime, nextPlayTimeRef.current);
4551
+ source.start(startTime);
4552
+ nextPlayTimeRef.current = startTime + audioBuffer.duration;
4553
+ }, []);
4554
+ const handleMessage = _react.useCallback.call(void 0, (msg) => {
4555
+ const cfg = configRef.current;
4556
+ switch (msg.type) {
4557
+ case "session_created":
4558
+ setState("active");
4559
+ startTimeRef.current = Date.now();
4560
+ durationIntervalRef.current = setInterval(() => {
4561
+ setDuration(Math.floor((Date.now() - startTimeRef.current) / 1e3));
4562
+ }, 1e3);
4563
+ break;
4564
+ case "audio_delta":
4565
+ if (_optionalChain([msg, 'access', _93 => _93.data, 'optionalAccess', _94 => _94.chunk])) {
4566
+ playAudioChunk(msg.data.chunk);
4567
+ }
4568
+ break;
4569
+ case "transcript":
4570
+ if (msg.data) {
4571
+ if (msg.data.partial) {
4572
+ setPartialTranscript(msg.data.content);
4573
+ } else {
4574
+ setPartialTranscript("");
4575
+ _optionalChain([cfg, 'access', _95 => _95.onTranscript, 'optionalCall', _96 => _96({
4576
+ id: `vt-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
4577
+ role: msg.data.role,
4578
+ content: msg.data.content,
4579
+ partial: false,
4580
+ timestamp: /* @__PURE__ */ new Date()
4581
+ })]);
4582
+ }
4583
+ }
4584
+ break;
4585
+ case "tool_call":
4586
+ if (msg.data) {
4587
+ nextPlayTimeRef.current = 0;
4588
+ _optionalChain([cfg, 'access', _97 => _97.onTranscript, 'optionalCall', _98 => _98({
4589
+ id: `vt-tool-${Date.now()}`,
4590
+ role: "system",
4591
+ content: `Using ${msg.data.name}...`,
4592
+ partial: false,
4593
+ timestamp: /* @__PURE__ */ new Date()
4594
+ })]);
4595
+ }
4596
+ break;
4597
+ case "tool_result":
4598
+ if (msg.data) {
4599
+ nextPlayTimeRef.current = 0;
4600
+ }
4601
+ break;
4602
+ case "error":
4603
+ setState("error");
4604
+ _optionalChain([cfg, 'access', _99 => _99.onError, 'optionalCall', _100 => _100(new Error(_optionalChain([msg, 'access', _101 => _101.data, 'optionalAccess', _102 => _102.message]) || "Voice session error"))]);
4605
+ break;
4606
+ }
4607
+ }, [playAudioChunk]);
4608
+ const startCapture = _react.useCallback.call(void 0, async () => {
4609
+ const ws = wsRef.current;
4610
+ if (!ws) return;
4611
+ try {
4612
+ captureCtxRef.current = new AudioContext();
4613
+ const nativeSampleRate = captureCtxRef.current.sampleRate;
4614
+ mediaStreamRef.current = await navigator.mediaDevices.getUserMedia({ audio: true });
4615
+ const source = captureCtxRef.current.createMediaStreamSource(mediaStreamRef.current);
4616
+ processorRef.current = captureCtxRef.current.createScriptProcessor(2048, 1, 1);
4617
+ processorRef.current.onaudioprocess = (e) => {
4618
+ if (!ws || ws.readyState !== WebSocket.OPEN) return;
4619
+ const inputData = e.inputBuffer.getChannelData(0);
4620
+ const resampledData = resampleAudio(inputData, nativeSampleRate, 16e3);
4621
+ const int16Data = float32ToInt16(resampledData);
4622
+ const base64Data = int16ToBase64(int16Data);
4623
+ ws.send(JSON.stringify({
4624
+ type: "audio",
4625
+ data: { chunk: base64Data }
4626
+ }));
4627
+ };
4628
+ source.connect(processorRef.current);
4629
+ processorRef.current.connect(captureCtxRef.current.destination);
4630
+ } catch (e) {
4631
+ _optionalChain([configRef, 'access', _103 => _103.current, 'access', _104 => _104.onError, 'optionalCall', _105 => _105(new Error("Microphone access denied"))]);
4632
+ cleanup();
4633
+ setState("idle");
4634
+ }
4635
+ }, [cleanup]);
4636
+ const start = _react.useCallback.call(void 0, () => {
4637
+ if (state !== "idle") return;
4638
+ setState("connecting");
4639
+ const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
4640
+ const wsUrl = `${protocol}//${window.location.host}${config.apiUrl}/voice`;
4641
+ const ws = new WebSocket(wsUrl);
4642
+ wsRef.current = ws;
4643
+ ws.onopen = () => {
4644
+ const provider = configRef.current.provider || "openai";
4645
+ const voice = configRef.current.voice || "ash";
4646
+ ws.send(JSON.stringify({
4647
+ type: "start",
4648
+ data: { provider, voice }
4649
+ }));
4650
+ startCapture();
4651
+ };
4652
+ ws.onmessage = (event) => {
4653
+ try {
4654
+ const msg = JSON.parse(event.data);
4655
+ handleMessage(msg);
4656
+ } catch (_) {
4657
+ }
4658
+ };
4659
+ ws.onerror = () => {
4660
+ setState("error");
4661
+ _optionalChain([configRef, 'access', _106 => _106.current, 'access', _107 => _107.onError, 'optionalCall', _108 => _108(new Error("WebSocket connection failed"))]);
4662
+ };
4663
+ ws.onclose = () => {
4664
+ cleanup();
4665
+ setState("idle");
4666
+ };
4667
+ }, [state, config.apiUrl, startCapture, handleMessage, cleanup]);
4668
+ const stop = _react.useCallback.call(void 0, () => {
4669
+ cleanup();
4670
+ setState("idle");
4671
+ }, [cleanup]);
4672
+ const sendText = _react.useCallback.call(void 0, (text) => {
4673
+ const ws = wsRef.current;
4674
+ if (!ws || ws.readyState !== WebSocket.OPEN) return;
4675
+ ws.send(JSON.stringify({
4676
+ type: "text",
4677
+ data: { content: text }
4678
+ }));
4679
+ }, []);
4680
+ return { state, partialTranscript, duration, start, stop, sendText };
4681
+ }
4682
+
4369
4683
  // src/components/Chat/Chat.tsx
4370
4684
 
4371
4685
  var Chat = _react.forwardRef.call(void 0, function Chat2({
@@ -4418,6 +4732,10 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
4418
4732
  onWidgetRender,
4419
4733
  // Speech to text
4420
4734
  speechToText,
4735
+ // Realtime voice
4736
+ enableVoice = false,
4737
+ voiceProvider,
4738
+ voiceId,
4421
4739
  className
4422
4740
  }, ref) {
4423
4741
  const [messages, setMessages] = _react.useState.call(void 0, initialMessages);
@@ -4438,6 +4756,23 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
4438
4756
  const [internalPlanMode, setInternalPlanMode] = _react.useState.call(void 0, planMode);
4439
4757
  const [showSettingsMenu, setShowSettingsMenu] = _react.useState.call(void 0, false);
4440
4758
  const fileInputRef = _react.useRef.call(void 0, null);
4759
+ const handleVoiceTranscript = _react.useCallback.call(void 0, (entry) => {
4760
+ const msg = {
4761
+ id: entry.id,
4762
+ role: entry.role === "system" ? "assistant" : entry.role,
4763
+ content: entry.content,
4764
+ timestamp: entry.timestamp,
4765
+ metadata: entry.role === "system" ? { isVoiceSystem: true } : { isVoice: true }
4766
+ };
4767
+ setMessages((prev) => [...prev, msg]);
4768
+ }, []);
4769
+ const voice = useVoiceSession({
4770
+ apiUrl: apiUrl || "",
4771
+ provider: voiceProvider,
4772
+ voice: voiceId,
4773
+ onTranscript: handleVoiceTranscript,
4774
+ onError
4775
+ });
4441
4776
  const [persistentWidgets, setPersistentWidgets] = _react.useState.call(void 0, /* @__PURE__ */ new Map());
4442
4777
  const updatePersistentWidgets = _react.useCallback.call(void 0, (msgs) => {
4443
4778
  setPersistentWidgets((prev) => {
@@ -4493,7 +4828,7 @@ ${widgetContext}` : widgetContext;
4493
4828
  }, [apiUrl, apiKey]);
4494
4829
  _react.useEffect.call(void 0, () => {
4495
4830
  if (threadId) {
4496
- _optionalChain([onThreadChange, 'optionalCall', _93 => _93(threadId)]);
4831
+ _optionalChain([onThreadChange, 'optionalCall', _109 => _109(threadId)]);
4497
4832
  }
4498
4833
  }, [threadId, onThreadChange]);
4499
4834
  _react.useEffect.call(void 0, () => {
@@ -4511,7 +4846,7 @@ ${widgetContext}` : widgetContext;
4511
4846
  }, [showSettingsMenu]);
4512
4847
  const handleModeChange = (newMode) => {
4513
4848
  setMode(newMode);
4514
- _optionalChain([onModeChange, 'optionalCall', _94 => _94(newMode)]);
4849
+ _optionalChain([onModeChange, 'optionalCall', _110 => _110(newMode)]);
4515
4850
  if (newMode === "command") {
4516
4851
  setCommandState("idle");
4517
4852
  setCommandResult(null);
@@ -4520,8 +4855,8 @@ ${widgetContext}` : widgetContext;
4520
4855
  };
4521
4856
  const defaultPlaceholder = mode === "chat" ? "Type a message..." : "Enter your command...";
4522
4857
  const handleWidgetAction = _react.useCallback.call(void 0, (action) => {
4523
- _optionalChain([onAction, 'optionalCall', _95 => _95(action)]);
4524
- if (action.type === "submit" && _optionalChain([action, 'access', _96 => _96.payload, 'optionalAccess', _97 => _97.formData])) {
4858
+ _optionalChain([onAction, 'optionalCall', _111 => _111(action)]);
4859
+ if (action.type === "submit" && _optionalChain([action, 'access', _112 => _112.payload, 'optionalAccess', _113 => _113.formData])) {
4525
4860
  const formData = action.payload.formData;
4526
4861
  const lines = [];
4527
4862
  for (const [key, value] of Object.entries(formData)) {
@@ -4560,7 +4895,7 @@ ${widgetContext}` : widgetContext;
4560
4895
  metadata: hasFiles ? { attachments } : void 0
4561
4896
  };
4562
4897
  setMessages((prev) => [...prev, userMessage]);
4563
- _optionalChain([onMessageSent, 'optionalCall', _98 => _98(userMessage)]);
4898
+ _optionalChain([onMessageSent, 'optionalCall', _114 => _114(userMessage)]);
4564
4899
  }
4565
4900
  setIsLoading(true);
4566
4901
  try {
@@ -4628,7 +4963,7 @@ ${widgetContext}` : widgetContext;
4628
4963
  responseThreadId = chunk.thread_id;
4629
4964
  if (!currentThreadId) {
4630
4965
  setCurrentThreadId(chunk.thread_id);
4631
- _optionalChain([onThreadChange, 'optionalCall', _99 => _99(chunk.thread_id)]);
4966
+ _optionalChain([onThreadChange, 'optionalCall', _115 => _115(chunk.thread_id)]);
4632
4967
  }
4633
4968
  }
4634
4969
  break;
@@ -4660,7 +4995,7 @@ ${widgetContext}` : widgetContext;
4660
4995
  contentSegments.push({ type: "tool", id: chunk.tool_id, name: displayName, status: "preparing" });
4661
4996
  toolInputBuffers[chunk.tool_id] = "";
4662
4997
  setChatToolName(displayName);
4663
- _optionalChain([onToolCall, 'optionalCall', _100 => _100(chunk.tool_name, chunk.tool_id)]);
4998
+ _optionalChain([onToolCall, 'optionalCall', _116 => _116(chunk.tool_name, chunk.tool_id)]);
4664
4999
  updateMessage();
4665
5000
  }
4666
5001
  break;
@@ -4720,7 +5055,7 @@ ${widgetContext}` : widgetContext;
4720
5055
  toolSegment.result = chunk.content;
4721
5056
  toolSegment.status = "completed";
4722
5057
  toolSegment.isReceiving = false;
4723
- _optionalChain([onToolResult, 'optionalCall', _101 => _101(toolSegment.name, chunk.content)]);
5058
+ _optionalChain([onToolResult, 'optionalCall', _117 => _117(toolSegment.name, chunk.content)]);
4724
5059
  }
4725
5060
  setChatToolName(null);
4726
5061
  updateMessage();
@@ -4764,7 +5099,7 @@ ${widgetContext}` : widgetContext;
4764
5099
  });
4765
5100
  if (threadId2 && threadId2 !== currentThreadId) {
4766
5101
  setCurrentThreadId(threadId2);
4767
- _optionalChain([onThreadChange, 'optionalCall', _102 => _102(threadId2)]);
5102
+ _optionalChain([onThreadChange, 'optionalCall', _118 => _118(threadId2)]);
4768
5103
  }
4769
5104
  setIsLoading(false);
4770
5105
  setCurrentRequestId(null);
@@ -4788,7 +5123,7 @@ ${widgetContext}` : widgetContext;
4788
5123
  setIsLoading(false);
4789
5124
  setCurrentRequestId(null);
4790
5125
  setChatToolName(null);
4791
- _optionalChain([onError, 'optionalCall', _103 => _103(error)]);
5126
+ _optionalChain([onError, 'optionalCall', _119 => _119(error)]);
4792
5127
  }
4793
5128
  );
4794
5129
  }
@@ -4801,7 +5136,7 @@ ${widgetContext}` : widgetContext;
4801
5136
  metadata: { error: true }
4802
5137
  };
4803
5138
  setMessages((prev) => [...prev, errorMessage]);
4804
- _optionalChain([onError, 'optionalCall', _104 => _104(error instanceof Error ? error : new Error("Unknown error"))]);
5139
+ _optionalChain([onError, 'optionalCall', _120 => _120(error instanceof Error ? error : new Error("Unknown error"))]);
4805
5140
  } finally {
4806
5141
  setIsLoading(false);
4807
5142
  }
@@ -4847,7 +5182,7 @@ ${planningInstruction}` : planningInstruction;
4847
5182
  const error = err instanceof Error ? err : new Error("Failed to generate plan");
4848
5183
  setCommandError(error);
4849
5184
  setCommandState("error");
4850
- _optionalChain([onError, 'optionalCall', _105 => _105(error)]);
5185
+ _optionalChain([onError, 'optionalCall', _121 => _121(error)]);
4851
5186
  }
4852
5187
  }
4853
5188
  return;
@@ -4880,12 +5215,12 @@ ${planningInstruction}` : planningInstruction;
4880
5215
  setCommandResult(result);
4881
5216
  setCommandState("success");
4882
5217
  setProgress(100);
4883
- _optionalChain([onComplete, 'optionalCall', _106 => _106(result)]);
5218
+ _optionalChain([onComplete, 'optionalCall', _122 => _122(result)]);
4884
5219
  },
4885
5220
  (error) => {
4886
5221
  setCommandError(error);
4887
5222
  setCommandState("error");
4888
- _optionalChain([onError, 'optionalCall', _107 => _107(error)]);
5223
+ _optionalChain([onError, 'optionalCall', _123 => _123(error)]);
4889
5224
  }
4890
5225
  );
4891
5226
  } else {
@@ -4898,7 +5233,7 @@ ${planningInstruction}` : planningInstruction;
4898
5233
  setCommandResult(result);
4899
5234
  setCommandState("success");
4900
5235
  setProgress(100);
4901
- _optionalChain([onComplete, 'optionalCall', _108 => _108(result)]);
5236
+ _optionalChain([onComplete, 'optionalCall', _124 => _124(result)]);
4902
5237
  }
4903
5238
  } else {
4904
5239
  const commandInstruction = `CRITICAL COMMAND MODE: Maximum 10 words per response. Execute the command immediately. Make reasonable assumptions based on context. Use sensible defaults for missing details. DO NOT ask questions unless something is truly impossible without user input (e.g., missing required password). State what you're doing or the result. Examples: "Analyzing customer data from last quarter..." or "Created 5 new database entries successfully" or "Search complete: found 12 matching results". NO greetings, NO filler words, NO clarification requests. Action/result only.`;
@@ -4928,16 +5263,16 @@ ${commandInstruction}` : commandInstruction;
4928
5263
  const displayName = chunk.tool_display_name || chunk.tool_name;
4929
5264
  lastToolName = chunk.tool_name;
4930
5265
  setCurrentToolName(displayName);
4931
- _optionalChain([onToolCall, 'optionalCall', _109 => _109(chunk.tool_name, chunk.tool_id || "")]);
5266
+ _optionalChain([onToolCall, 'optionalCall', _125 => _125(chunk.tool_name, chunk.tool_id || "")]);
4932
5267
  accumulatedContent = "";
4933
5268
  setStreamedContent("");
4934
5269
  } else if (chunk.type === "tool_result") {
4935
- _optionalChain([onToolResult, 'optionalCall', _110 => _110(lastToolName, chunk.content)]);
5270
+ _optionalChain([onToolResult, 'optionalCall', _126 => _126(lastToolName, chunk.content)]);
4936
5271
  setCurrentToolName(null);
4937
5272
  } else if (chunk.type === "thread_id" && chunk.thread_id) {
4938
5273
  if (!currentThreadId) {
4939
5274
  setCurrentThreadId(chunk.thread_id);
4940
- _optionalChain([onThreadChange, 'optionalCall', _111 => _111(chunk.thread_id)]);
5275
+ _optionalChain([onThreadChange, 'optionalCall', _127 => _127(chunk.thread_id)]);
4941
5276
  }
4942
5277
  } else if (chunk.type === "request_id" && chunk.request_id) {
4943
5278
  setCurrentRequestId(chunk.request_id);
@@ -4953,13 +5288,13 @@ ${commandInstruction}` : commandInstruction;
4953
5288
  setCommandState("success");
4954
5289
  setProgress(100);
4955
5290
  setCurrentRequestId(null);
4956
- _optionalChain([onComplete, 'optionalCall', _112 => _112(result)]);
5291
+ _optionalChain([onComplete, 'optionalCall', _128 => _128(result)]);
4957
5292
  },
4958
5293
  (error) => {
4959
5294
  setCommandError(error);
4960
5295
  setCommandState("error");
4961
5296
  setCurrentRequestId(null);
4962
- _optionalChain([onError, 'optionalCall', _113 => _113(error)]);
5297
+ _optionalChain([onError, 'optionalCall', _129 => _129(error)]);
4963
5298
  }
4964
5299
  );
4965
5300
  } else {
@@ -4979,14 +5314,14 @@ ${commandInstruction}` : commandInstruction;
4979
5314
  setCommandResult(result);
4980
5315
  setCommandState("success");
4981
5316
  setProgress(100);
4982
- _optionalChain([onComplete, 'optionalCall', _114 => _114(result)]);
5317
+ _optionalChain([onComplete, 'optionalCall', _130 => _130(result)]);
4983
5318
  }
4984
5319
  }
4985
5320
  } catch (err) {
4986
5321
  const error = err instanceof Error ? err : new Error("Unknown error");
4987
5322
  setCommandError(error);
4988
5323
  setCommandState("error");
4989
- _optionalChain([onError, 'optionalCall', _115 => _115(error)]);
5324
+ _optionalChain([onError, 'optionalCall', _131 => _131(error)]);
4990
5325
  }
4991
5326
  };
4992
5327
  const resetCommand = () => {
@@ -5040,8 +5375,8 @@ ${planToExecute}`;
5040
5375
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "apteva-chat-title", children: headerTitle }),
5041
5376
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: cn(
5042
5377
  "apteva-chat-status",
5043
- isLoading ? chatToolName ? "apteva-chat-status-tool" : "apteva-chat-status-thinking" : "apteva-chat-status-ready"
5044
- ), children: isLoading ? chatToolName ? `Using ${chatToolName}...` : "Thinking..." : "Ready" })
5378
+ voice.state === "active" ? "apteva-chat-status-voice" : voice.state === "connecting" ? "apteva-chat-status-thinking" : isLoading ? chatToolName ? "apteva-chat-status-tool" : "apteva-chat-status-thinking" : "apteva-chat-status-ready"
5379
+ ), children: voice.state === "active" ? "Voice active" : voice.state === "connecting" ? "Connecting voice..." : isLoading ? chatToolName ? `Using ${chatToolName}...` : "Thinking..." : "Ready" })
5045
5380
  ] })
5046
5381
  ] }) }),
5047
5382
  mode === "chat" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
@@ -5074,7 +5409,13 @@ ${planToExecute}`;
5074
5409
  onStop: handleStop,
5075
5410
  onFileUpload,
5076
5411
  onSwitchMode: showModeToggle ? () => handleModeChange("command") : void 0,
5077
- speechToText
5412
+ speechToText,
5413
+ enableVoice,
5414
+ voiceState: voice.state,
5415
+ voicePartialTranscript: voice.partialTranscript,
5416
+ voiceDuration: voice.duration,
5417
+ onVoiceStart: voice.start,
5418
+ onVoiceStop: voice.stop
5078
5419
  }
5079
5420
  )
5080
5421
  ] }),
@@ -5086,8 +5427,8 @@ ${planToExecute}`;
5086
5427
  executeCommand(text, files);
5087
5428
  },
5088
5429
  state: commandState,
5089
- response: _optionalChain([commandResult, 'optionalAccess', _116 => _116.data, 'optionalAccess', _117 => _117.summary]) || _optionalChain([commandResult, 'optionalAccess', _118 => _118.message]),
5090
- error: _optionalChain([commandError, 'optionalAccess', _119 => _119.message]),
5430
+ response: _optionalChain([commandResult, 'optionalAccess', _132 => _132.data, 'optionalAccess', _133 => _133.summary]) || _optionalChain([commandResult, 'optionalAccess', _134 => _134.message]),
5431
+ error: _optionalChain([commandError, 'optionalAccess', _135 => _135.message]),
5091
5432
  plan,
5092
5433
  streamedContent,
5093
5434
  toolName: currentToolName,
@@ -5255,13 +5596,13 @@ ${planningInstruction}` : planningInstruction;
5255
5596
  const error2 = err instanceof Error ? err : new Error("Failed to generate plan");
5256
5597
  setError(error2);
5257
5598
  setState("error");
5258
- _optionalChain([onError, 'optionalCall', _120 => _120(error2)]);
5599
+ _optionalChain([onError, 'optionalCall', _136 => _136(error2)]);
5259
5600
  });
5260
5601
  } catch (err) {
5261
5602
  const error2 = err instanceof Error ? err : new Error("Failed to generate plan");
5262
5603
  setError(error2);
5263
5604
  setState("error");
5264
- _optionalChain([onError, 'optionalCall', _121 => _121(error2)]);
5605
+ _optionalChain([onError, 'optionalCall', _137 => _137(error2)]);
5265
5606
  }
5266
5607
  }
5267
5608
  return;
@@ -5272,7 +5613,7 @@ ${planningInstruction}` : planningInstruction;
5272
5613
  setStreamedContent("");
5273
5614
  setCommand("");
5274
5615
  setUploadedFiles([]);
5275
- _optionalChain([onStart, 'optionalCall', _122 => _122()]);
5616
+ _optionalChain([onStart, 'optionalCall', _138 => _138()]);
5276
5617
  try {
5277
5618
  if (useMock) {
5278
5619
  if (enableStreaming) {
@@ -5283,16 +5624,16 @@ ${planningInstruction}` : planningInstruction;
5283
5624
  if (chunk.type === "token" && chunk.content) {
5284
5625
  accumulatedContent += chunk.content;
5285
5626
  setStreamedContent(accumulatedContent);
5286
- _optionalChain([onChunk, 'optionalCall', _123 => _123(chunk.content)]);
5627
+ _optionalChain([onChunk, 'optionalCall', _139 => _139(chunk.content)]);
5287
5628
  const estimatedProgress = Math.min(Math.round(accumulatedContent.length / 10), 90);
5288
5629
  setProgress(estimatedProgress);
5289
- _optionalChain([onProgress, 'optionalCall', _124 => _124(estimatedProgress)]);
5630
+ _optionalChain([onProgress, 'optionalCall', _140 => _140(estimatedProgress)]);
5290
5631
  } else if (chunk.type === "widget" && chunk.widget) {
5291
5632
  const widget = chunk.widget;
5292
5633
  setResult((prev) => ({
5293
5634
  success: true,
5294
- data: _optionalChain([prev, 'optionalAccess', _125 => _125.data]) || {},
5295
- widgets: [..._optionalChain([prev, 'optionalAccess', _126 => _126.widgets]) || [], widget],
5635
+ data: _optionalChain([prev, 'optionalAccess', _141 => _141.data]) || {},
5636
+ widgets: [..._optionalChain([prev, 'optionalAccess', _142 => _142.widgets]) || [], widget],
5296
5637
  message: accumulatedContent || "Command executed successfully"
5297
5638
  }));
5298
5639
  }
@@ -5312,19 +5653,19 @@ ${planningInstruction}` : planningInstruction;
5312
5653
  setResult(result2);
5313
5654
  setState("success");
5314
5655
  setProgress(100);
5315
- _optionalChain([onComplete, 'optionalCall', _127 => _127(result2)]);
5656
+ _optionalChain([onComplete, 'optionalCall', _143 => _143(result2)]);
5316
5657
  },
5317
5658
  (error2) => {
5318
5659
  setError(error2);
5319
5660
  setState("error");
5320
- _optionalChain([onError, 'optionalCall', _128 => _128(error2)]);
5661
+ _optionalChain([onError, 'optionalCall', _144 => _144(error2)]);
5321
5662
  }
5322
5663
  );
5323
5664
  } else {
5324
5665
  const progressInterval = setInterval(() => {
5325
5666
  setProgress((prev) => {
5326
5667
  const next = Math.min(prev + 10, 90);
5327
- _optionalChain([onProgress, 'optionalCall', _129 => _129(next)]);
5668
+ _optionalChain([onProgress, 'optionalCall', _145 => _145(next)]);
5328
5669
  return next;
5329
5670
  });
5330
5671
  }, 200);
@@ -5348,7 +5689,7 @@ ${planningInstruction}` : planningInstruction;
5348
5689
  setResult(result2);
5349
5690
  setState("success");
5350
5691
  setProgress(100);
5351
- _optionalChain([onComplete, 'optionalCall', _130 => _130(result2)]);
5692
+ _optionalChain([onComplete, 'optionalCall', _146 => _146(result2)]);
5352
5693
  }
5353
5694
  } else {
5354
5695
  if (enableStreaming) {
@@ -5394,16 +5735,16 @@ ${commandInstruction}` : commandInstruction;
5394
5735
  if (chunk.type === "token" && chunk.content) {
5395
5736
  accumulatedContent += chunk.content;
5396
5737
  setStreamedContent(accumulatedContent);
5397
- _optionalChain([onChunk, 'optionalCall', _131 => _131(chunk.content)]);
5738
+ _optionalChain([onChunk, 'optionalCall', _147 => _147(chunk.content)]);
5398
5739
  const estimatedProgress = Math.min(Math.round(accumulatedContent.length / 10), 90);
5399
5740
  setProgress(estimatedProgress);
5400
- _optionalChain([onProgress, 'optionalCall', _132 => _132(estimatedProgress)]);
5741
+ _optionalChain([onProgress, 'optionalCall', _148 => _148(estimatedProgress)]);
5401
5742
  } else if (chunk.type === "widget" && chunk.widget) {
5402
5743
  const widget = chunk.widget;
5403
5744
  setResult((prev) => ({
5404
5745
  success: true,
5405
- data: _optionalChain([prev, 'optionalAccess', _133 => _133.data]) || {},
5406
- widgets: [..._optionalChain([prev, 'optionalAccess', _134 => _134.widgets]) || [], widget],
5746
+ data: _optionalChain([prev, 'optionalAccess', _149 => _149.data]) || {},
5747
+ widgets: [..._optionalChain([prev, 'optionalAccess', _150 => _150.widgets]) || [], widget],
5407
5748
  message: accumulatedContent || "Command executed successfully"
5408
5749
  }));
5409
5750
  }
@@ -5423,20 +5764,20 @@ ${commandInstruction}` : commandInstruction;
5423
5764
  setResult(result2);
5424
5765
  setState("success");
5425
5766
  setProgress(100);
5426
- _optionalChain([onComplete, 'optionalCall', _135 => _135(result2)]);
5767
+ _optionalChain([onComplete, 'optionalCall', _151 => _151(result2)]);
5427
5768
  },
5428
5769
  (error2) => {
5429
5770
  const err = error2 instanceof Error ? error2 : new Error("Unknown error");
5430
5771
  setError(err);
5431
5772
  setState("error");
5432
- _optionalChain([onError, 'optionalCall', _136 => _136(err)]);
5773
+ _optionalChain([onError, 'optionalCall', _152 => _152(err)]);
5433
5774
  }
5434
5775
  );
5435
5776
  } else {
5436
5777
  const progressInterval = setInterval(() => {
5437
5778
  setProgress((prev) => {
5438
5779
  const next = Math.min(prev + 10, 90);
5439
- _optionalChain([onProgress, 'optionalCall', _137 => _137(next)]);
5780
+ _optionalChain([onProgress, 'optionalCall', _153 => _153(next)]);
5440
5781
  return next;
5441
5782
  });
5442
5783
  }, 200);
@@ -5492,14 +5833,14 @@ ${commandInstruction}` : commandInstruction;
5492
5833
  setResult(result2);
5493
5834
  setState("success");
5494
5835
  setProgress(100);
5495
- _optionalChain([onComplete, 'optionalCall', _138 => _138(result2)]);
5836
+ _optionalChain([onComplete, 'optionalCall', _154 => _154(result2)]);
5496
5837
  }
5497
5838
  }
5498
5839
  } catch (err) {
5499
5840
  const error2 = err instanceof Error ? err : new Error("Unknown error");
5500
5841
  setError(error2);
5501
5842
  setState("error");
5502
- _optionalChain([onError, 'optionalCall', _139 => _139(error2)]);
5843
+ _optionalChain([onError, 'optionalCall', _155 => _155(error2)]);
5503
5844
  }
5504
5845
  };
5505
5846
  const resetCommand = () => {
@@ -5532,14 +5873,14 @@ ${planToExecute}`;
5532
5873
  };
5533
5874
  const handleFileSelect = async (e) => {
5534
5875
  if (e.target.files && e.target.files.length > 0) {
5535
- _optionalChain([onFileUpload, 'optionalCall', _140 => _140(e.target.files)]);
5876
+ _optionalChain([onFileUpload, 'optionalCall', _156 => _156(e.target.files)]);
5536
5877
  const files = [];
5537
5878
  for (let i = 0; i < e.target.files.length; i++) {
5538
5879
  const file = e.target.files[i];
5539
5880
  const reader = new FileReader();
5540
5881
  await new Promise((resolve) => {
5541
5882
  reader.onload = (event) => {
5542
- if (_optionalChain([event, 'access', _141 => _141.target, 'optionalAccess', _142 => _142.result])) {
5883
+ if (_optionalChain([event, 'access', _157 => _157.target, 'optionalAccess', _158 => _158.result])) {
5543
5884
  const fullDataUrl = event.target.result;
5544
5885
  const base64Data = fullDataUrl.split(",")[1];
5545
5886
  if (file.type.startsWith("image/")) {
@@ -5633,7 +5974,7 @@ ${planToExecute}`;
5633
5974
  enableFileUpload && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5634
5975
  "button",
5635
5976
  {
5636
- onClick: () => _optionalChain([fileInputRef, 'access', _143 => _143.current, 'optionalAccess', _144 => _144.click, 'call', _145 => _145()]),
5977
+ onClick: () => _optionalChain([fileInputRef, 'access', _159 => _159.current, 'optionalAccess', _160 => _160.click, 'call', _161 => _161()]),
5637
5978
  className: "w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0 !text-neutral-500 dark:!text-neutral-500 hover:bg-neutral-100 dark:hover:bg-neutral-800",
5638
5979
  title: "Attach file",
5639
5980
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M8.4 2.8L4.4 6.8C3.736 7.464 3.736 8.536 4.4 9.2C5.064 9.864 6.136 9.864 6.8 9.2L11.6 4.4C12.704 3.296 12.704 1.504 11.6 0.4C10.496 -0.704 8.704 -0.704 7.6 0.4L2.8 5.2C1.256 6.744 1.256 9.256 2.8 10.8C4.344 12.344 6.856 12.344 8.4 10.8L12.4 6.8", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round", transform: "translate(1.6, 2.4)" }) })
@@ -5852,7 +6193,7 @@ ${planToExecute}`;
5852
6193
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { className: "w-5 h-5 text-red-600 mt-0.5 flex-shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
5853
6194
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
5854
6195
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "text-sm font-semibold text-red-800 dark:text-red-400", children: "Error" }),
5855
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-red-700 dark:text-red-300 text-sm mt-1", children: _optionalChain([error, 'optionalAccess', _146 => _146.message]) })
6196
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-red-700 dark:text-red-300 text-sm mt-1", children: _optionalChain([error, 'optionalAccess', _162 => _162.message]) })
5856
6197
  ] })
5857
6198
  ] }) }),
5858
6199
  allowInput && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -5880,7 +6221,7 @@ ${planToExecute}`;
5880
6221
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-green-700 dark:text-green-300 text-sm", children: "Command executed successfully" })
5881
6222
  ] })
5882
6223
  ] }),
5883
- _optionalChain([result, 'access', _147 => _147.data, 'optionalAccess', _148 => _148.summary]) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "text-neutral-700 dark:text-neutral-300 text-sm leading-relaxed whitespace-pre-line", children: result.data.summary }),
6224
+ _optionalChain([result, 'access', _163 => _163.data, 'optionalAccess', _164 => _164.summary]) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "text-neutral-700 dark:text-neutral-300 text-sm leading-relaxed whitespace-pre-line", children: result.data.summary }),
5884
6225
  result.widgets && result.widgets.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "space-y-3", children: result.widgets.map((widget) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5885
6226
  WidgetRenderer,
5886
6227
  {
@@ -5931,7 +6272,7 @@ ${planToExecute}`;
5931
6272
  enableFileUpload && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5932
6273
  "button",
5933
6274
  {
5934
- onClick: () => _optionalChain([fileInputRef, 'access', _149 => _149.current, 'optionalAccess', _150 => _150.click, 'call', _151 => _151()]),
6275
+ onClick: () => _optionalChain([fileInputRef, 'access', _165 => _165.current, 'optionalAccess', _166 => _166.click, 'call', _167 => _167()]),
5935
6276
  className: "w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0 !text-neutral-500 dark:!text-neutral-500 hover:bg-neutral-100 dark:hover:bg-neutral-800",
5936
6277
  title: "Attach file",
5937
6278
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M8.4 2.8L4.4 6.8C3.736 7.464 3.736 8.536 4.4 9.2C5.064 9.864 6.136 9.864 6.8 9.2L11.6 4.4C12.704 3.296 12.704 1.504 11.6 0.4C10.496 -0.704 8.704 -0.704 7.6 0.4L2.8 5.2C1.256 6.744 1.256 9.256 2.8 10.8C4.344 12.344 6.856 12.344 8.4 10.8L12.4 6.8", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round", transform: "translate(1.6, 2.4)" }) })
@@ -6117,25 +6458,25 @@ function Prompt({
6117
6458
  const newValue = e.target.value;
6118
6459
  if (!maxLength || newValue.length <= maxLength) {
6119
6460
  setValue(newValue);
6120
- _optionalChain([onChange, 'optionalCall', _152 => _152(newValue)]);
6461
+ _optionalChain([onChange, 'optionalCall', _168 => _168(newValue)]);
6121
6462
  }
6122
6463
  };
6123
6464
  const handleSubmit = async () => {
6124
6465
  if (value.length < minLength) return;
6125
- _optionalChain([onSubmit, 'optionalCall', _153 => _153(value)]);
6466
+ _optionalChain([onSubmit, 'optionalCall', _169 => _169(value)]);
6126
6467
  setIsLoading(true);
6127
6468
  try {
6128
6469
  if (useMock) {
6129
6470
  await new Promise((resolve) => setTimeout(resolve, 1500));
6130
6471
  const mockResult = `Enhanced version: ${value} [AI-generated content]`;
6131
- _optionalChain([onResult, 'optionalCall', _154 => _154(mockResult)]);
6472
+ _optionalChain([onResult, 'optionalCall', _170 => _170(mockResult)]);
6132
6473
  setValue("");
6133
6474
  } else {
6134
6475
  const response = await aptevaClient.chat({
6135
6476
  agent_id: agentId,
6136
6477
  message: value
6137
6478
  });
6138
- _optionalChain([onResult, 'optionalCall', _155 => _155(response.message)]);
6479
+ _optionalChain([onResult, 'optionalCall', _171 => _171(response.message)]);
6139
6480
  setValue("");
6140
6481
  }
6141
6482
  } catch (error) {
@@ -6230,7 +6571,7 @@ function Stream({
6230
6571
  }, [autoStart]);
6231
6572
  const startStreaming = async () => {
6232
6573
  setIsStreaming(true);
6233
- _optionalChain([onStart, 'optionalCall', _156 => _156()]);
6574
+ _optionalChain([onStart, 'optionalCall', _172 => _172()]);
6234
6575
  try {
6235
6576
  if (useMock) {
6236
6577
  const mockText = "This is a simulated streaming response from the AI agent. In a real implementation, this would stream data from your backend API. The text appears word by word to simulate the streaming effect. You can customize the typing speed and styling based on your needs.";
@@ -6238,13 +6579,13 @@ function Stream({
6238
6579
  mockText,
6239
6580
  (chunk) => {
6240
6581
  setText((prev) => prev + chunk);
6241
- _optionalChain([onChunk, 'optionalCall', _157 => _157(chunk)]);
6582
+ _optionalChain([onChunk, 'optionalCall', _173 => _173(chunk)]);
6242
6583
  },
6243
6584
  typingSpeed
6244
6585
  );
6245
6586
  setIsComplete(true);
6246
6587
  setIsStreaming(false);
6247
- _optionalChain([onComplete, 'optionalCall', _158 => _158(text + mockText)]);
6588
+ _optionalChain([onComplete, 'optionalCall', _174 => _174(text + mockText)]);
6248
6589
  } else {
6249
6590
  let accumulatedText = "";
6250
6591
  await aptevaClient.chatStream(
@@ -6257,24 +6598,24 @@ function Stream({
6257
6598
  if (chunk.type === "token" && chunk.content) {
6258
6599
  accumulatedText += chunk.content;
6259
6600
  setText(accumulatedText);
6260
- _optionalChain([onChunk, 'optionalCall', _159 => _159(chunk.content)]);
6601
+ _optionalChain([onChunk, 'optionalCall', _175 => _175(chunk.content)]);
6261
6602
  }
6262
6603
  },
6263
6604
  () => {
6264
6605
  setIsComplete(true);
6265
6606
  setIsStreaming(false);
6266
- _optionalChain([onComplete, 'optionalCall', _160 => _160(accumulatedText)]);
6607
+ _optionalChain([onComplete, 'optionalCall', _176 => _176(accumulatedText)]);
6267
6608
  },
6268
6609
  (error) => {
6269
6610
  const err = error instanceof Error ? error : new Error("Streaming error");
6270
- _optionalChain([onError, 'optionalCall', _161 => _161(err)]);
6611
+ _optionalChain([onError, 'optionalCall', _177 => _177(err)]);
6271
6612
  setIsStreaming(false);
6272
6613
  }
6273
6614
  );
6274
6615
  }
6275
6616
  } catch (error) {
6276
6617
  const err = error instanceof Error ? error : new Error("Streaming error");
6277
- _optionalChain([onError, 'optionalCall', _162 => _162(err)]);
6618
+ _optionalChain([onError, 'optionalCall', _178 => _178(err)]);
6278
6619
  setIsStreaming(false);
6279
6620
  }
6280
6621
  };
@@ -6366,7 +6707,7 @@ function ThreadList({
6366
6707
  }) {
6367
6708
  const [searchQuery, setSearchQuery] = _react.useState.call(void 0, "");
6368
6709
  const filteredThreads = threads.filter(
6369
- (thread) => thread.title.toLowerCase().includes(searchQuery.toLowerCase()) || _optionalChain([thread, 'access', _163 => _163.preview, 'optionalAccess', _164 => _164.toLowerCase, 'call', _165 => _165(), 'access', _166 => _166.includes, 'call', _167 => _167(searchQuery.toLowerCase())])
6710
+ (thread) => thread.title.toLowerCase().includes(searchQuery.toLowerCase()) || _optionalChain([thread, 'access', _179 => _179.preview, 'optionalAccess', _180 => _180.toLowerCase, 'call', _181 => _181(), 'access', _182 => _182.includes, 'call', _183 => _183(searchQuery.toLowerCase())])
6370
6711
  );
6371
6712
  const groupedThreads = groupBy === "date" ? groupThreadsByDate(filteredThreads) : { All: filteredThreads };
6372
6713
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col h-full", children: [
@@ -6388,8 +6729,8 @@ function ThreadList({
6388
6729
  {
6389
6730
  thread,
6390
6731
  isActive: thread.id === currentThreadId,
6391
- onSelect: () => _optionalChain([onThreadSelect, 'optionalCall', _168 => _168(thread.id)]),
6392
- onDelete: () => _optionalChain([onThreadDelete, 'optionalCall', _169 => _169(thread.id)])
6732
+ onSelect: () => _optionalChain([onThreadSelect, 'optionalCall', _184 => _184(thread.id)]),
6733
+ onDelete: () => _optionalChain([onThreadDelete, 'optionalCall', _185 => _185(thread.id)])
6393
6734
  },
6394
6735
  thread.id
6395
6736
  ))
@@ -6451,7 +6792,7 @@ function Threads({
6451
6792
  threads.slice(0, 5).map((thread) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6452
6793
  "button",
6453
6794
  {
6454
- onClick: () => _optionalChain([onThreadSelect, 'optionalCall', _170 => _170(thread.id)]),
6795
+ onClick: () => _optionalChain([onThreadSelect, 'optionalCall', _186 => _186(thread.id)]),
6455
6796
  className: cn(
6456
6797
  "px-4 py-2 whitespace-nowrap font-medium transition-colors",
6457
6798
  thread.id === currentThreadId ? "border-b-2 border-apteva-500 text-apteva-500" : "text-neutral-600 hover:text-neutral-900"
@@ -6636,7 +6977,7 @@ function TabsLayout({ node, renderNode }) {
6636
6977
  var STRUCTURAL_KEYS = /* @__PURE__ */ new Set(["type", "id", "layout", "props", "children", "actions", "metadata", "isStreaming"]);
6637
6978
  function normalizeNode(n) {
6638
6979
  let node = { ...n };
6639
- if (node.type === "widget" && _optionalChain([node, 'access', _171 => _171.props, 'optionalAccess', _172 => _172.widget])) {
6980
+ if (node.type === "widget" && _optionalChain([node, 'access', _187 => _187.props, 'optionalAccess', _188 => _188.widget])) {
6640
6981
  node.type = node.props.widget;
6641
6982
  const { widget: _, ...rest } = node.props;
6642
6983
  node.props = rest;
@@ -6774,10 +7115,10 @@ function AutoInterface({
6774
7115
  ].filter(Boolean).join("\n\n");
6775
7116
  const updateInterface = _react.useCallback.call(void 0, (newSpec) => {
6776
7117
  setInterfaceSpec(newSpec);
6777
- _optionalChain([onInterfaceChange, 'optionalCall', _173 => _173(newSpec)]);
7118
+ _optionalChain([onInterfaceChange, 'optionalCall', _189 => _189(newSpec)]);
6778
7119
  }, [onInterfaceChange]);
6779
7120
  const handleAction = _react.useCallback.call(void 0, (action) => {
6780
- _optionalChain([onAction, 'optionalCall', _174 => _174(action)]);
7121
+ _optionalChain([onAction, 'optionalCall', _190 => _190(action)]);
6781
7122
  if (chatRef.current) {
6782
7123
  chatRef.current.sendMessage(
6783
7124
  `[Action: ${action.type} on widget ${action.widgetId || "unknown"}. Payload: ${JSON.stringify(action.payload)}]`
@@ -6785,7 +7126,7 @@ function AutoInterface({
6785
7126
  }
6786
7127
  }, [onAction]);
6787
7128
  const handleMessageComplete = _react.useCallback.call(void 0, (result) => {
6788
- if (!_optionalChain([result, 'optionalAccess', _175 => _175.data])) return;
7129
+ if (!_optionalChain([result, 'optionalAccess', _191 => _191.data])) return;
6789
7130
  const text = typeof result.data === "string" ? result.data : result.data.message || "";
6790
7131
  console.log("[AutoInterface] Chat message complete, text (" + text.length + " chars):", text.substring(0, 300));
6791
7132
  const parsed = parseInterfaceFromText(text);
@@ -6825,7 +7166,7 @@ function AutoInterface({
6825
7166
  }).catch((err) => {
6826
7167
  if (cancelled) return;
6827
7168
  console.error("[AutoInterface] Initial generation failed:", err);
6828
- _optionalChain([onError, 'optionalCall', _176 => _176(err instanceof Error ? err : new Error(String(err)))]);
7169
+ _optionalChain([onError, 'optionalCall', _192 => _192(err instanceof Error ? err : new Error(String(err)))]);
6829
7170
  setIsGenerating(false);
6830
7171
  });
6831
7172
  return () => {
@@ -6991,7 +7332,7 @@ function useInterfaceAI({
6991
7332
  }
6992
7333
  const sendMessage = _react.useCallback.call(void 0, async (message) => {
6993
7334
  accumulatedTextRef.current = "";
6994
- _optionalChain([onStreamStart, 'optionalCall', _177 => _177()]);
7335
+ _optionalChain([onStreamStart, 'optionalCall', _193 => _193()]);
6995
7336
  const systemPrompt = [
6996
7337
  generateInterfaceContext(),
6997
7338
  context || ""
@@ -7014,27 +7355,27 @@ function useInterfaceAI({
7014
7355
  accumulatedTextRef.current += chunk.content || "";
7015
7356
  const parsed = parseInterfaceFromText(accumulatedTextRef.current);
7016
7357
  if (parsed) {
7017
- _optionalChain([onInterface, 'optionalCall', _178 => _178(parsed)]);
7358
+ _optionalChain([onInterface, 'optionalCall', _194 => _194(parsed)]);
7018
7359
  }
7019
7360
  const updates = parseUpdatesFromText(accumulatedTextRef.current);
7020
7361
  if (updates.length > 0) {
7021
- _optionalChain([onUpdates, 'optionalCall', _179 => _179(updates)]);
7362
+ _optionalChain([onUpdates, 'optionalCall', _195 => _195(updates)]);
7022
7363
  }
7023
7364
  }
7024
7365
  },
7025
7366
  // onComplete
7026
7367
  () => {
7027
- _optionalChain([onStreamEnd, 'optionalCall', _180 => _180()]);
7368
+ _optionalChain([onStreamEnd, 'optionalCall', _196 => _196()]);
7028
7369
  },
7029
7370
  // onError
7030
7371
  (error) => {
7031
- _optionalChain([onError, 'optionalCall', _181 => _181(error)]);
7032
- _optionalChain([onStreamEnd, 'optionalCall', _182 => _182()]);
7372
+ _optionalChain([onError, 'optionalCall', _197 => _197(error)]);
7373
+ _optionalChain([onStreamEnd, 'optionalCall', _198 => _198()]);
7033
7374
  }
7034
7375
  );
7035
7376
  } catch (error) {
7036
- _optionalChain([onError, 'optionalCall', _183 => _183(error instanceof Error ? error : new Error("Unknown error"))]);
7037
- _optionalChain([onStreamEnd, 'optionalCall', _184 => _184()]);
7377
+ _optionalChain([onError, 'optionalCall', _199 => _199(error instanceof Error ? error : new Error("Unknown error"))]);
7378
+ _optionalChain([onStreamEnd, 'optionalCall', _200 => _200()]);
7038
7379
  }
7039
7380
  }, [agentId, context, onInterface, onUpdates, onError, onStreamStart, onStreamEnd]);
7040
7381
  return {