@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.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +441 -100
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +442 -101
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
5
|
|
|
6
6
|
// src/components/Chat/Chat.tsx
|
|
7
|
-
import { useState as
|
|
7
|
+
import { useState as useState10, useEffect as useEffect10, useRef as useRef10, useMemo as useMemo2, useCallback as useCallback5, forwardRef, useImperativeHandle } from "react";
|
|
8
8
|
|
|
9
9
|
// src/components/Chat/MessageList.tsx
|
|
10
10
|
import { useEffect as useEffect7, useRef as useRef6 } from "react";
|
|
@@ -2805,17 +2805,36 @@ function ToolCall({ name, status, isReceiving = false, inputLength = 0, streamOu
|
|
|
2805
2805
|
// src/components/Chat/ToolCallGroup.tsx
|
|
2806
2806
|
import { useState as useState5 } from "react";
|
|
2807
2807
|
import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
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] = useState5(false);
|
|
2816
|
-
const isExpanded =
|
|
2817
|
-
const
|
|
2818
|
-
|
|
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__ */ jsxs13("div", { className: cardClass, children: [
|
|
2821
2840
|
/* @__PURE__ */ jsxs13(
|
|
@@ -2846,18 +2865,20 @@ function ToolCallGroup({ tools }) {
|
|
|
2846
2865
|
]
|
|
2847
2866
|
}
|
|
2848
2867
|
),
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2868
|
+
isExpanded && /* @__PURE__ */ jsx18("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__ */ jsxs13("div", { className: `apteva-tool-group-item ${hasDetail ? "apteva-tool-group-item-has-detail" : ""}`, children: [
|
|
2872
|
+
/* @__PURE__ */ jsxs13("div", { className: "apteva-tool-group-item-row", children: [
|
|
2873
|
+
tool.status === "completed" ? /* @__PURE__ */ jsx18("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__ */ jsx18("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M5 13l4 4L19 7" }) }) : tool.status === "error" ? /* @__PURE__ */ jsx18("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__ */ jsx18("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M6 18L18 6M6 6l12 12" }) }) : /* @__PURE__ */ jsx18("div", { className: "apteva-tool-group-item-icon apteva-tool-group-item-spinner" }),
|
|
2874
|
+
/* @__PURE__ */ jsx18("span", { className: "apteva-tool-group-item-name", children: tool.name }),
|
|
2875
|
+
tool.status === "running" && !tool.streamOutput && /* @__PURE__ */ jsx18("span", { className: "apteva-tool-group-item-running-label", children: "running..." }),
|
|
2876
|
+
tool.status === "preparing" && /* @__PURE__ */ jsx18("span", { className: "apteva-tool-group-item-running-label", children: "preparing..." })
|
|
2877
|
+
] }),
|
|
2878
|
+
tool.status === "running" && tool.streamOutput && /* @__PURE__ */ jsx18("div", { className: "apteva-tool-group-item-detail", children: tool.streamOutput }),
|
|
2879
|
+
resultPreview && /* @__PURE__ */ jsx18("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] = useState6("");
|
|
3375
3397
|
const [showMenu, setShowMenu] = useState6(false);
|
|
3376
3398
|
const [pendingFiles, setPendingFiles] = useState6([]);
|
|
@@ -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__ */ jsx23("div", { className: "px-4 py-3 relative", children: /* @__PURE__ */ jsxs17("div", { className: "apteva-voice-overlay", children: [
|
|
3697
|
+
/* @__PURE__ */ jsx23("div", { className: "apteva-voice-transcript-area", children: voicePartialTranscript ? /* @__PURE__ */ jsx23("span", { className: "apteva-voice-partial", children: voicePartialTranscript }) : voiceState === "connecting" ? /* @__PURE__ */ jsx23("span", { className: "apteva-voice-connecting", children: "Connecting..." }) : /* @__PURE__ */ jsx23("span", { className: "apteva-voice-listening", children: "Listening..." }) }),
|
|
3698
|
+
/* @__PURE__ */ jsxs17("div", { className: "apteva-voice-controls", children: [
|
|
3699
|
+
/* @__PURE__ */ jsx23("span", { className: "apteva-voice-duration", children: formatVoiceDuration(voiceDuration) }),
|
|
3700
|
+
/* @__PURE__ */ jsx23(
|
|
3701
|
+
"button",
|
|
3702
|
+
{
|
|
3703
|
+
onClick: onVoiceStop,
|
|
3704
|
+
className: "apteva-voice-stop-btn",
|
|
3705
|
+
title: "Stop voice mode",
|
|
3706
|
+
children: /* @__PURE__ */ jsx23("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx23("rect", { x: "3", y: "3", width: "10", height: "10", rx: "1", fill: "currentColor" }) })
|
|
3707
|
+
}
|
|
3708
|
+
)
|
|
3709
|
+
] }),
|
|
3710
|
+
/* @__PURE__ */ jsx23("div", { className: "apteva-voice-indicator", children: /* @__PURE__ */ jsx23("div", { className: `apteva-voice-pulse ${voiceState === "active" ? "apteva-voice-pulse-active" : ""}` }) })
|
|
3711
|
+
] }) });
|
|
3712
|
+
}
|
|
3666
3713
|
return /* @__PURE__ */ jsxs17("div", { className: "px-4 py-3 relative", children: [
|
|
3667
3714
|
fileError && /* @__PURE__ */ jsx23("div", { className: "apteva-file-error", children: /* @__PURE__ */ jsxs17("div", { className: "apteva-file-error-content", children: [
|
|
3668
3715
|
/* @__PURE__ */ jsx23("svg", { fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx23("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__ */ jsx23("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx23("rect", { x: "2", y: "2", width: "10", height: "10", rx: "1", fill: "currentColor" }) })
|
|
3808
3855
|
}
|
|
3856
|
+
) : showMicButton ? /* @__PURE__ */ jsx23(
|
|
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__ */ jsxs17("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
3863
|
+
/* @__PURE__ */ jsx23("path", { d: "M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z", fill: "currentColor" }),
|
|
3864
|
+
/* @__PURE__ */ jsx23("path", { d: "M19 10v2a7 7 0 01-14 0v-2", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
3865
|
+
/* @__PURE__ */ jsx23("path", { d: "M12 19v4M8 23h8", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })
|
|
3866
|
+
] })
|
|
3867
|
+
}
|
|
3809
3868
|
) : /* @__PURE__ */ jsx23(
|
|
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
|
+
import { useState as useState9, useRef as useRef9, useCallback as useCallback4, useEffect as useEffect9 } from "react";
|
|
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] = useState9("idle");
|
|
4480
|
+
const [partialTranscript, setPartialTranscript] = useState9("");
|
|
4481
|
+
const [duration, setDuration] = useState9(0);
|
|
4482
|
+
const wsRef = useRef9(null);
|
|
4483
|
+
const captureCtxRef = useRef9(null);
|
|
4484
|
+
const playbackCtxRef = useRef9(null);
|
|
4485
|
+
const mediaStreamRef = useRef9(null);
|
|
4486
|
+
const processorRef = useRef9(null);
|
|
4487
|
+
const nextPlayTimeRef = useRef9(0);
|
|
4488
|
+
const durationIntervalRef = useRef9(null);
|
|
4489
|
+
const startTimeRef = useRef9(0);
|
|
4490
|
+
const configRef = useRef9(config);
|
|
4491
|
+
configRef.current = config;
|
|
4492
|
+
const cleanup = useCallback4(() => {
|
|
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
|
+
useEffect9(() => {
|
|
4531
|
+
return () => {
|
|
4532
|
+
cleanup();
|
|
4533
|
+
};
|
|
4534
|
+
}, [cleanup]);
|
|
4535
|
+
const playAudioChunk = useCallback4((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 = useCallback4((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 (msg.data?.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
|
+
cfg.onTranscript?.({
|
|
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
|
+
cfg.onTranscript?.({
|
|
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
|
+
cfg.onError?.(new Error(msg.data?.message || "Voice session error"));
|
|
4605
|
+
break;
|
|
4606
|
+
}
|
|
4607
|
+
}, [playAudioChunk]);
|
|
4608
|
+
const startCapture = useCallback4(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
|
+
configRef.current.onError?.(new Error("Microphone access denied"));
|
|
4632
|
+
cleanup();
|
|
4633
|
+
setState("idle");
|
|
4634
|
+
}
|
|
4635
|
+
}, [cleanup]);
|
|
4636
|
+
const start = useCallback4(() => {
|
|
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
|
+
configRef.current.onError?.(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 = useCallback4(() => {
|
|
4669
|
+
cleanup();
|
|
4670
|
+
setState("idle");
|
|
4671
|
+
}, [cleanup]);
|
|
4672
|
+
const sendText = useCallback4((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
|
import { Fragment as Fragment6, jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
4371
4685
|
var Chat = forwardRef(function Chat2({
|
|
@@ -4418,28 +4732,49 @@ var Chat = forwardRef(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
|
-
const [messages, setMessages] =
|
|
4424
|
-
const [isLoading, setIsLoading] =
|
|
4425
|
-
const [currentThreadId, setCurrentThreadId] =
|
|
4426
|
-
const [mode, setMode] =
|
|
4427
|
-
const [chatToolName, setChatToolName] =
|
|
4428
|
-
const [commandState, setCommandState] =
|
|
4429
|
-
const [commandResult, setCommandResult] =
|
|
4430
|
-
const [commandError, setCommandError] =
|
|
4431
|
-
const [progress, setProgress] =
|
|
4432
|
-
const [commandInput, setCommandInput] =
|
|
4433
|
-
const [streamedContent, setStreamedContent] =
|
|
4434
|
-
const [currentToolName, setCurrentToolName] =
|
|
4435
|
-
const [currentRequestId, setCurrentRequestId] =
|
|
4436
|
-
const [plan, setPlan] =
|
|
4437
|
-
const [pendingCommand, setPendingCommand] =
|
|
4438
|
-
const [internalPlanMode, setInternalPlanMode] =
|
|
4439
|
-
const [showSettingsMenu, setShowSettingsMenu] =
|
|
4440
|
-
const fileInputRef =
|
|
4441
|
-
const
|
|
4442
|
-
|
|
4741
|
+
const [messages, setMessages] = useState10(initialMessages);
|
|
4742
|
+
const [isLoading, setIsLoading] = useState10(false);
|
|
4743
|
+
const [currentThreadId, setCurrentThreadId] = useState10(threadId || null);
|
|
4744
|
+
const [mode, setMode] = useState10(initialMode);
|
|
4745
|
+
const [chatToolName, setChatToolName] = useState10(null);
|
|
4746
|
+
const [commandState, setCommandState] = useState10("idle");
|
|
4747
|
+
const [commandResult, setCommandResult] = useState10(null);
|
|
4748
|
+
const [commandError, setCommandError] = useState10(null);
|
|
4749
|
+
const [progress, setProgress] = useState10(0);
|
|
4750
|
+
const [commandInput, setCommandInput] = useState10("");
|
|
4751
|
+
const [streamedContent, setStreamedContent] = useState10("");
|
|
4752
|
+
const [currentToolName, setCurrentToolName] = useState10(null);
|
|
4753
|
+
const [currentRequestId, setCurrentRequestId] = useState10(null);
|
|
4754
|
+
const [plan, setPlan] = useState10("");
|
|
4755
|
+
const [pendingCommand, setPendingCommand] = useState10("");
|
|
4756
|
+
const [internalPlanMode, setInternalPlanMode] = useState10(planMode);
|
|
4757
|
+
const [showSettingsMenu, setShowSettingsMenu] = useState10(false);
|
|
4758
|
+
const fileInputRef = useRef10(null);
|
|
4759
|
+
const handleVoiceTranscript = useCallback5((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
|
+
});
|
|
4776
|
+
const [persistentWidgets, setPersistentWidgets] = useState10(/* @__PURE__ */ new Map());
|
|
4777
|
+
const updatePersistentWidgets = useCallback5((msgs) => {
|
|
4443
4778
|
setPersistentWidgets((prev) => {
|
|
4444
4779
|
const next = new Map(prev);
|
|
4445
4780
|
let changed = false;
|
|
@@ -4457,12 +4792,12 @@ var Chat = forwardRef(function Chat2({
|
|
|
4457
4792
|
return changed ? next : prev;
|
|
4458
4793
|
});
|
|
4459
4794
|
}, []);
|
|
4460
|
-
|
|
4795
|
+
useEffect10(() => {
|
|
4461
4796
|
updatePersistentWidgets(messages);
|
|
4462
4797
|
}, [messages, updatePersistentWidgets]);
|
|
4463
4798
|
const persistentWidgetList = useMemo2(() => Array.from(persistentWidgets.values()), [persistentWidgets]);
|
|
4464
4799
|
const persistentWidgetIds = useMemo2(() => new Set(persistentWidgets.keys()), [persistentWidgets]);
|
|
4465
|
-
const handleSendMessageRef =
|
|
4800
|
+
const handleSendMessageRef = useRef10(null);
|
|
4466
4801
|
useImperativeHandle(ref, () => ({
|
|
4467
4802
|
sendMessage: async (text) => {
|
|
4468
4803
|
if (handleSendMessageRef.current) {
|
|
@@ -4483,7 +4818,7 @@ var Chat = forwardRef(function Chat2({
|
|
|
4483
4818
|
return context ? `${context}
|
|
4484
4819
|
${widgetContext}` : widgetContext;
|
|
4485
4820
|
}, [context, enableWidgets, availableWidgets, compactWidgetContext]);
|
|
4486
|
-
|
|
4821
|
+
useEffect10(() => {
|
|
4487
4822
|
if (apiUrl || apiKey) {
|
|
4488
4823
|
aptevaClient.configure({
|
|
4489
4824
|
...apiUrl && { apiUrl },
|
|
@@ -4491,15 +4826,15 @@ ${widgetContext}` : widgetContext;
|
|
|
4491
4826
|
});
|
|
4492
4827
|
}
|
|
4493
4828
|
}, [apiUrl, apiKey]);
|
|
4494
|
-
|
|
4829
|
+
useEffect10(() => {
|
|
4495
4830
|
if (threadId) {
|
|
4496
4831
|
onThreadChange?.(threadId);
|
|
4497
4832
|
}
|
|
4498
4833
|
}, [threadId, onThreadChange]);
|
|
4499
|
-
|
|
4834
|
+
useEffect10(() => {
|
|
4500
4835
|
setInternalPlanMode(planMode);
|
|
4501
4836
|
}, [planMode]);
|
|
4502
|
-
|
|
4837
|
+
useEffect10(() => {
|
|
4503
4838
|
const handleClickOutside = (event) => {
|
|
4504
4839
|
const target = event.target;
|
|
4505
4840
|
if (showSettingsMenu && !target.closest(".settings-menu-container")) {
|
|
@@ -4519,7 +4854,7 @@ ${widgetContext}` : widgetContext;
|
|
|
4519
4854
|
}
|
|
4520
4855
|
};
|
|
4521
4856
|
const defaultPlaceholder = mode === "chat" ? "Type a message..." : "Enter your command...";
|
|
4522
|
-
const handleWidgetAction =
|
|
4857
|
+
const handleWidgetAction = useCallback5((action) => {
|
|
4523
4858
|
onAction?.(action);
|
|
4524
4859
|
if (action.type === "submit" && action.payload?.formData) {
|
|
4525
4860
|
const formData = action.payload.formData;
|
|
@@ -5040,8 +5375,8 @@ ${planToExecute}`;
|
|
|
5040
5375
|
/* @__PURE__ */ jsx26("div", { className: "apteva-chat-title", children: headerTitle }),
|
|
5041
5376
|
/* @__PURE__ */ jsx26("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__ */ jsxs20(Fragment6, { 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
|
] }),
|
|
@@ -5117,11 +5458,11 @@ ${planToExecute}`;
|
|
|
5117
5458
|
});
|
|
5118
5459
|
|
|
5119
5460
|
// src/components/Chat/CommandOutput.tsx
|
|
5120
|
-
import { useState as
|
|
5461
|
+
import { useState as useState11 } from "react";
|
|
5121
5462
|
import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
5122
5463
|
|
|
5123
5464
|
// src/components/Command/Command.tsx
|
|
5124
|
-
import React, { useState as
|
|
5465
|
+
import React, { useState as useState12, useEffect as useEffect11 } from "react";
|
|
5125
5466
|
import { Fragment as Fragment7, jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
5126
5467
|
function Command({
|
|
5127
5468
|
agentId,
|
|
@@ -5149,28 +5490,28 @@ function Command({
|
|
|
5149
5490
|
resultRenderer,
|
|
5150
5491
|
className
|
|
5151
5492
|
}) {
|
|
5152
|
-
const [state, setState] =
|
|
5153
|
-
const [result, setResult] =
|
|
5154
|
-
const [error, setError] =
|
|
5155
|
-
const [progress, setProgress] =
|
|
5156
|
-
const [command, setCommand] =
|
|
5157
|
-
const [streamedContent, setStreamedContent] =
|
|
5158
|
-
const [plan, setPlan] =
|
|
5159
|
-
const [pendingCommand, setPendingCommand] =
|
|
5160
|
-
const [showPlanDetails, setShowPlanDetails] =
|
|
5161
|
-
const [uploadedFiles, setUploadedFiles] =
|
|
5162
|
-
const [showSettingsMenu, setShowSettingsMenu] =
|
|
5163
|
-
const [internalPlanMode, setInternalPlanMode] =
|
|
5493
|
+
const [state, setState] = useState12("idle");
|
|
5494
|
+
const [result, setResult] = useState12(null);
|
|
5495
|
+
const [error, setError] = useState12(null);
|
|
5496
|
+
const [progress, setProgress] = useState12(0);
|
|
5497
|
+
const [command, setCommand] = useState12(initialCommand || "");
|
|
5498
|
+
const [streamedContent, setStreamedContent] = useState12("");
|
|
5499
|
+
const [plan, setPlan] = useState12("");
|
|
5500
|
+
const [pendingCommand, setPendingCommand] = useState12("");
|
|
5501
|
+
const [showPlanDetails, setShowPlanDetails] = useState12(false);
|
|
5502
|
+
const [uploadedFiles, setUploadedFiles] = useState12([]);
|
|
5503
|
+
const [showSettingsMenu, setShowSettingsMenu] = useState12(false);
|
|
5504
|
+
const [internalPlanMode, setInternalPlanMode] = useState12(planMode);
|
|
5164
5505
|
const fileInputRef = React.useRef(null);
|
|
5165
|
-
|
|
5506
|
+
useEffect11(() => {
|
|
5166
5507
|
if (autoExecute && state === "idle" && command) {
|
|
5167
5508
|
executeCommand();
|
|
5168
5509
|
}
|
|
5169
5510
|
}, [autoExecute]);
|
|
5170
|
-
|
|
5511
|
+
useEffect11(() => {
|
|
5171
5512
|
setInternalPlanMode(planMode);
|
|
5172
5513
|
}, [planMode]);
|
|
5173
|
-
|
|
5514
|
+
useEffect11(() => {
|
|
5174
5515
|
const handleClickOutside = (event) => {
|
|
5175
5516
|
const target = event.target;
|
|
5176
5517
|
if (showSettingsMenu && !target.closest(".settings-menu-container")) {
|
|
@@ -6092,7 +6433,7 @@ ${planToExecute}`;
|
|
|
6092
6433
|
}
|
|
6093
6434
|
|
|
6094
6435
|
// src/components/Prompt/Prompt.tsx
|
|
6095
|
-
import { useState as
|
|
6436
|
+
import { useState as useState13 } from "react";
|
|
6096
6437
|
import { jsx as jsx29, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
6097
6438
|
function Prompt({
|
|
6098
6439
|
agentId,
|
|
@@ -6110,9 +6451,9 @@ function Prompt({
|
|
|
6110
6451
|
showSuggestions = false,
|
|
6111
6452
|
className
|
|
6112
6453
|
}) {
|
|
6113
|
-
const [value, setValue] =
|
|
6114
|
-
const [isLoading, setIsLoading] =
|
|
6115
|
-
const [suggestions] =
|
|
6454
|
+
const [value, setValue] = useState13(initialValue);
|
|
6455
|
+
const [isLoading, setIsLoading] = useState13(false);
|
|
6456
|
+
const [suggestions] = useState13(["Plan a trip", "Write a description", "Analyze data"]);
|
|
6116
6457
|
const handleChange = (e) => {
|
|
6117
6458
|
const newValue = e.target.value;
|
|
6118
6459
|
if (!maxLength || newValue.length <= maxLength) {
|
|
@@ -6203,7 +6544,7 @@ function Prompt({
|
|
|
6203
6544
|
}
|
|
6204
6545
|
|
|
6205
6546
|
// src/components/Stream/Stream.tsx
|
|
6206
|
-
import { useState as
|
|
6547
|
+
import { useState as useState14, useEffect as useEffect12 } from "react";
|
|
6207
6548
|
import { jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
6208
6549
|
function Stream({
|
|
6209
6550
|
agentId,
|
|
@@ -6220,10 +6561,10 @@ function Stream({
|
|
|
6220
6561
|
typingSpeed = 30,
|
|
6221
6562
|
className
|
|
6222
6563
|
}) {
|
|
6223
|
-
const [text, setText] =
|
|
6224
|
-
const [isStreaming, setIsStreaming] =
|
|
6225
|
-
const [isComplete, setIsComplete] =
|
|
6226
|
-
|
|
6564
|
+
const [text, setText] = useState14("");
|
|
6565
|
+
const [isStreaming, setIsStreaming] = useState14(false);
|
|
6566
|
+
const [isComplete, setIsComplete] = useState14(false);
|
|
6567
|
+
useEffect12(() => {
|
|
6227
6568
|
if (autoStart && !isStreaming && !isComplete) {
|
|
6228
6569
|
startStreaming();
|
|
6229
6570
|
}
|
|
@@ -6300,7 +6641,7 @@ function Stream({
|
|
|
6300
6641
|
}
|
|
6301
6642
|
|
|
6302
6643
|
// src/components/Threads/ThreadList.tsx
|
|
6303
|
-
import { useState as
|
|
6644
|
+
import { useState as useState15 } from "react";
|
|
6304
6645
|
|
|
6305
6646
|
// src/components/Threads/ThreadItem.tsx
|
|
6306
6647
|
import { jsx as jsx31, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
@@ -6364,7 +6705,7 @@ function ThreadList({
|
|
|
6364
6705
|
showSearch = false,
|
|
6365
6706
|
groupBy = "none"
|
|
6366
6707
|
}) {
|
|
6367
|
-
const [searchQuery, setSearchQuery] =
|
|
6708
|
+
const [searchQuery, setSearchQuery] = useState15("");
|
|
6368
6709
|
const filteredThreads = threads.filter(
|
|
6369
6710
|
(thread) => thread.title.toLowerCase().includes(searchQuery.toLowerCase()) || thread.preview?.toLowerCase().includes(searchQuery.toLowerCase())
|
|
6370
6711
|
);
|
|
@@ -6494,10 +6835,10 @@ function Threads({
|
|
|
6494
6835
|
}
|
|
6495
6836
|
|
|
6496
6837
|
// src/components/AutoInterface/AutoInterface.tsx
|
|
6497
|
-
import { useState as
|
|
6838
|
+
import { useState as useState17, useRef as useRef11, useCallback as useCallback6, useEffect as useEffect13 } from "react";
|
|
6498
6839
|
|
|
6499
6840
|
// src/components/AutoInterface/LayoutRenderer.tsx
|
|
6500
|
-
import { useState as
|
|
6841
|
+
import { useState as useState16 } from "react";
|
|
6501
6842
|
import { Fragment as Fragment8, jsx as jsx34, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
6502
6843
|
var gapClasses = {
|
|
6503
6844
|
none: "gap-0",
|
|
@@ -6613,7 +6954,7 @@ function SidebarLayout({ node, renderNode }) {
|
|
|
6613
6954
|
function TabsLayout({ node, renderNode }) {
|
|
6614
6955
|
const { labels = [], defaultTab = 0 } = node.props || {};
|
|
6615
6956
|
const children = node.children || [];
|
|
6616
|
-
const [activeTab, setActiveTab] =
|
|
6957
|
+
const [activeTab, setActiveTab] = useState16(defaultTab);
|
|
6617
6958
|
return /* @__PURE__ */ jsxs28("div", { children: [
|
|
6618
6959
|
/* @__PURE__ */ jsx34("div", { className: "flex border-b border-neutral-200 dark:border-neutral-700 mb-4", children: labels.map((label, idx) => /* @__PURE__ */ jsx34(
|
|
6619
6960
|
"button",
|
|
@@ -6764,19 +7105,19 @@ function AutoInterface({
|
|
|
6764
7105
|
theme,
|
|
6765
7106
|
className
|
|
6766
7107
|
}) {
|
|
6767
|
-
const [interfaceSpec, setInterfaceSpec] =
|
|
6768
|
-
const [isGenerating, setIsGenerating] =
|
|
6769
|
-
const [chatCollapsed, setChatCollapsed] =
|
|
6770
|
-
const chatRef =
|
|
7108
|
+
const [interfaceSpec, setInterfaceSpec] = useState17(initialInterface || null);
|
|
7109
|
+
const [isGenerating, setIsGenerating] = useState17(false);
|
|
7110
|
+
const [chatCollapsed, setChatCollapsed] = useState17(false);
|
|
7111
|
+
const chatRef = useRef11(null);
|
|
6771
7112
|
const systemContext = [
|
|
6772
7113
|
generateInterfaceContext(),
|
|
6773
7114
|
context || ""
|
|
6774
7115
|
].filter(Boolean).join("\n\n");
|
|
6775
|
-
const updateInterface =
|
|
7116
|
+
const updateInterface = useCallback6((newSpec) => {
|
|
6776
7117
|
setInterfaceSpec(newSpec);
|
|
6777
7118
|
onInterfaceChange?.(newSpec);
|
|
6778
7119
|
}, [onInterfaceChange]);
|
|
6779
|
-
const handleAction =
|
|
7120
|
+
const handleAction = useCallback6((action) => {
|
|
6780
7121
|
onAction?.(action);
|
|
6781
7122
|
if (chatRef.current) {
|
|
6782
7123
|
chatRef.current.sendMessage(
|
|
@@ -6784,7 +7125,7 @@ function AutoInterface({
|
|
|
6784
7125
|
);
|
|
6785
7126
|
}
|
|
6786
7127
|
}, [onAction]);
|
|
6787
|
-
const handleMessageComplete =
|
|
7128
|
+
const handleMessageComplete = useCallback6((result) => {
|
|
6788
7129
|
if (!result?.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));
|
|
@@ -6805,7 +7146,7 @@ function AutoInterface({
|
|
|
6805
7146
|
}
|
|
6806
7147
|
setIsGenerating(false);
|
|
6807
7148
|
}, [interfaceSpec, updateInterface]);
|
|
6808
|
-
|
|
7149
|
+
useEffect13(() => {
|
|
6809
7150
|
if (!initialPrompt || initialInterface || useMock) return;
|
|
6810
7151
|
if (!apiUrl) return;
|
|
6811
7152
|
let cancelled = false;
|
|
@@ -6930,29 +7271,29 @@ function getThemeScript() {
|
|
|
6930
7271
|
}
|
|
6931
7272
|
|
|
6932
7273
|
// src/hooks/useInterfaceState.ts
|
|
6933
|
-
import { useState as
|
|
7274
|
+
import { useState as useState18, useCallback as useCallback7 } from "react";
|
|
6934
7275
|
function useInterfaceState(initialSpec) {
|
|
6935
|
-
const [spec, setSpec] =
|
|
6936
|
-
const [isStreaming, setIsStreaming] =
|
|
6937
|
-
const setInterface =
|
|
7276
|
+
const [spec, setSpec] = useState18(initialSpec || null);
|
|
7277
|
+
const [isStreaming, setIsStreaming] = useState18(false);
|
|
7278
|
+
const setInterface = useCallback7((newSpec) => {
|
|
6938
7279
|
setSpec(newSpec);
|
|
6939
7280
|
}, []);
|
|
6940
|
-
const clearInterface =
|
|
7281
|
+
const clearInterface = useCallback7(() => {
|
|
6941
7282
|
setSpec(null);
|
|
6942
7283
|
}, []);
|
|
6943
|
-
const applyInterfaceUpdate =
|
|
7284
|
+
const applyInterfaceUpdate = useCallback7((update) => {
|
|
6944
7285
|
setSpec((prev) => {
|
|
6945
7286
|
if (!prev) return prev;
|
|
6946
7287
|
return applyUpdate(prev, update);
|
|
6947
7288
|
});
|
|
6948
7289
|
}, []);
|
|
6949
|
-
const applyInterfaceUpdates =
|
|
7290
|
+
const applyInterfaceUpdates = useCallback7((updates) => {
|
|
6950
7291
|
setSpec((prev) => {
|
|
6951
7292
|
if (!prev) return prev;
|
|
6952
7293
|
return applyUpdates(prev, updates);
|
|
6953
7294
|
});
|
|
6954
7295
|
}, []);
|
|
6955
|
-
const getNode =
|
|
7296
|
+
const getNode = useCallback7((id) => {
|
|
6956
7297
|
if (!spec) return null;
|
|
6957
7298
|
return findNode(spec.root, id);
|
|
6958
7299
|
}, [spec]);
|
|
@@ -6969,7 +7310,7 @@ function useInterfaceState(initialSpec) {
|
|
|
6969
7310
|
}
|
|
6970
7311
|
|
|
6971
7312
|
// src/hooks/useInterfaceAI.ts
|
|
6972
|
-
import { useCallback as
|
|
7313
|
+
import { useCallback as useCallback8, useRef as useRef12 } from "react";
|
|
6973
7314
|
function useInterfaceAI({
|
|
6974
7315
|
agentId,
|
|
6975
7316
|
apiUrl,
|
|
@@ -6981,15 +7322,15 @@ function useInterfaceAI({
|
|
|
6981
7322
|
onStreamStart,
|
|
6982
7323
|
onStreamEnd
|
|
6983
7324
|
}) {
|
|
6984
|
-
const threadIdRef =
|
|
6985
|
-
const accumulatedTextRef =
|
|
7325
|
+
const threadIdRef = useRef12(null);
|
|
7326
|
+
const accumulatedTextRef = useRef12("");
|
|
6986
7327
|
if (apiUrl || apiKey) {
|
|
6987
7328
|
aptevaClient.configure({
|
|
6988
7329
|
...apiUrl && { apiUrl },
|
|
6989
7330
|
...apiKey && { apiKey }
|
|
6990
7331
|
});
|
|
6991
7332
|
}
|
|
6992
|
-
const sendMessage =
|
|
7333
|
+
const sendMessage = useCallback8(async (message) => {
|
|
6993
7334
|
accumulatedTextRef.current = "";
|
|
6994
7335
|
onStreamStart?.();
|
|
6995
7336
|
const systemPrompt = [
|