@xopcai/xopc 0.0.242 → 0.0.243
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/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-MU5XrVv8.js → activity-store-CAah-_8h.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B_Wc0wuL.js → agent-avatar-dicebear-DDH4HgP7.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-BDCfJZhh.js +1 -0
- package/dist/gateway/static/root/assets/agents-B0ZWgf-U.js +1 -0
- package/dist/gateway/static/root/assets/{api-DLyc8BQp.js → api-B2tKxbcz.js} +1 -1
- package/dist/gateway/static/root/assets/app-management-settings-panel-Blfwszzn.js +1 -0
- package/dist/gateway/static/root/assets/{appearance-settings-DB5gEQhN.js → appearance-settings-C3V7Na75.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BiEks0-F.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-BOx0EJZs.js → archive-plugin-BmSx7wzY.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-CYnYIyLr.js → attachment-load-BS-S4LJ9.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-ChTflpmA.js → automations-page-C7Y3L30D.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-A3zPkPuo.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-BjbLfNwG.js → binary-plugins-BM9B5kcm.js} +1 -1
- package/dist/gateway/static/root/assets/block-editor-BbnpkYP9.js +185 -0
- package/dist/gateway/static/root/assets/browser-settings-page-Dk4FQ7fY.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-DGQxD0vD.js → browser-workflow-inputs-CRnkgZHI.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-B9gfdd7L.js → browser-workflows-page-B9qGL-it.js} +2 -2
- package/dist/gateway/static/root/assets/{button-CSEbl4zT.js → button-CtTvuElV.js} +1 -1
- package/dist/gateway/static/root/assets/capabilities-settings-panel--tR_El9e.js +7 -0
- package/dist/gateway/static/root/assets/channels-settings-D347vl_J.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-TkU42f-W.js → channels-status-swr-DuY4MGxe.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-CWMPcnoN.js → chat-terminal-dock-DABPvwBT.js} +2 -2
- package/dist/gateway/static/root/assets/connectors-page-B-tvJkRJ.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-3h3rR0cf.js → cron-expression-D3bsKbNd.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-Bz1sLBEx.js → date-picker-BsGM6Yty.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-p9DWR8uU.js → dependency-picker-Dj3g6YXZ.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-D1TDB_gR.js → desktop-pet-C1QT0Sur.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-DWPZpoB7.js → desktop-pet-settings-r6kAOnfY.js} +1 -1
- package/dist/gateway/static/root/assets/dist-CpzYSoz7.js +1 -0
- package/dist/gateway/static/root/assets/{dist-DaxPZj9e.js → dist-DBS3OB8K.js} +1 -1
- package/dist/gateway/static/root/assets/dist-DLmwHyAh.js +1 -0
- package/dist/gateway/static/root/assets/es2015-BvLh9GaE.js +41 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-BrRbK2rJ.js → extension-debug-page-DOkf7nh9.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CD65czfS.js → extension-page-Cq2IA4Ho.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-BRDDKhpi.js → extension-settings-page-DQn4qjDZ.js} +1 -1
- package/dist/gateway/static/root/assets/{files-DQjhZjr2.js → files-D6vf3S30.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-CjbBsr5M.js → gateway-config-api-DM3poL22.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-HT7sLeO9.js → gateway-config-swr-BC3pgb_P.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-BQjmfYD4.js → gateway-settings-DPgH1hnh.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-iBCtaAuT.js → gateway-startup-retry-uMcSfLru.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-BzZxLgrw.js → heartbeat-settings-Bk80-E3b.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-DKo5JiMR.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-dj9TNEn2.js → image-generation-api-D1qlQA-A.js} +1 -1
- package/dist/gateway/static/root/assets/index-B0WJL9N1.js +71 -0
- package/dist/gateway/static/root/assets/index-Dbh5SXyV.css +2 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BEnuEPD3.js → keyboard-shortcuts-settings-BEwvd8ZU.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page--eJ5rmNj.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-DXQtppWq.js → local-apps-page-CgkY9E-r.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-DVzTJSj2.js → locale-store-CMZljTJx.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-Z49Td0J9.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-DIpBMWrA.js → management-settings-Dv8NSJKt.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-BFHyGwNF.js → markdown-split-Cm0RBB-t.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-DR3yVwtV.js → markdown-view-PPCLt7fu.js} +3 -3
- package/dist/gateway/static/root/assets/{media-plugins-BjjMxC5_.js → media-plugins-Bcr5sU1f.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CTSgFlE4.js +3 -0
- package/dist/gateway/static/root/assets/mobile-pairing-wizard-kKDiXofY.js +1 -0
- package/dist/gateway/static/root/assets/models-hub-cache-ZrbGRiGY.js +1 -0
- package/dist/gateway/static/root/assets/{notes-page-BbvtelJa.js → notes-page-CgsaRaGi.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-C1DEE09k.js +4 -0
- package/dist/gateway/static/root/assets/{oauth-api-BB-VYJ5j.js → oauth-api-4VeMbkTJ.js} +1 -1
- package/dist/gateway/static/root/assets/popover-select-C-Hj-nXR.js +1 -0
- package/dist/gateway/static/root/assets/{product-delivery-dUJgmBQZ.js → product-delivery-CV4pDOtG.js} +1 -1
- package/dist/gateway/static/root/assets/product-open-page-BU0HiZtv.js +1 -0
- package/dist/gateway/static/root/assets/project-detail-page-isRapnp5.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-zvsjg0mi.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-DXsR8oGN.js → registry-api-CWOtPFrE.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-C9TGZ9Hc.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DoEfLjPB.js → runtime-tools-settings-panel-2zm9edMA.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-BsqpbBDv.js → schema-form-54A5gzkN.js} +1 -1
- package/dist/gateway/static/root/assets/{schemas-zIBW3wiV.js → schemas-BHS7bo06.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-BP8RyiUn.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-D4EMxWAZ.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-CE7ZcCTK.js → settings-page-DzDhoyxv.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-CGlne9i0.js → setup-status-panel-uDicHU1w.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-Bn0qMX8V.js → share-preview-page-lOmLCWFS.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-T4Yvouvv.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-DVb7nrXz.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-dRkeYh5P.js → skills-page-CnyNH3To.js} +1 -1
- package/dist/gateway/static/root/assets/skills-page.utils-CgDtf2qs.js +1 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-C0ZCuCM4.js → system-settings-panel-C8yWfwtR.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-Tzfjlbf3.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-Cth-eChE.js → theme-store-uxUwr10D.js} +1 -1
- package/dist/gateway/static/root/assets/tunnel-api-Bvg679no.js +1 -0
- package/dist/gateway/static/root/assets/{use-autosave-PSV89QuQ.js → use-autosave-D88VGoyG.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-RijPtyfO.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-DXWdJ8cR.js → voice-api-key-field-CBHLsMcc.js} +1 -1
- package/dist/gateway/static/root/assets/voice-config-api-MqyI6cgq.js +1 -0
- package/dist/gateway/static/root/assets/work-discovery-overlay-GGe2TQ98.js +1 -0
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-C0layUE9.js +3 -0
- package/dist/gateway/static/root/assets/workflows-page-DQXIzBAc.js +5 -0
- package/dist/gateway/static/root/index.html +21 -22
- package/dist/package.js +1 -1
- package/dist/packages/realtime-protocol/src/voice-audio.js +20 -0
- package/dist/packages/realtime-protocol/src/voice.js +208 -0
- package/dist/src/agent/embedded/run-for-session.d.ts +1 -0
- package/dist/src/agent/embedded/run-for-session.js +2 -1
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +1 -0
- package/dist/src/agent/inbound/turn-dispatcher.js +2 -1
- package/dist/src/agent/prompt/voice-presentation.d.ts +2 -0
- package/dist/src/agent/prompt/voice-presentation.js +12 -0
- package/dist/src/agent/service/direct-turn-helpers.d.ts +1 -0
- package/dist/src/agent/service/direct-turn-helpers.js +1 -0
- package/dist/src/agent/service/process-direct-streaming.d.ts +1 -0
- package/dist/src/agent/service/process-direct-streaming.js +2 -1
- package/dist/src/agent/session/session-config-service.js +4 -2
- package/dist/src/automations/draft/automation-draft-service.js +1 -1
- package/dist/src/config/models-json.d.ts +8 -8
- package/dist/src/config/schema.d.ts +60 -0
- package/dist/src/config/schema.js +31 -1
- package/dist/src/files/file-service.d.ts +1 -0
- package/dist/src/files/file-service.js +4 -0
- package/dist/src/gateway/chat-stream/thinking-delta-coalescer.js +8 -3
- package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -11
- package/dist/src/gateway/hono/lib/config-payload.js +2 -2
- package/dist/src/gateway/hono/lib/safe-voice-config.d.ts +14 -0
- package/dist/src/gateway/hono/lib/safe-voice-config.js +29 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -2
- package/dist/src/gateway/hono/routes/files.js +7 -0
- package/dist/src/gateway/hono/routes/lazy-fallback.js +18 -4
- package/dist/src/gateway/hono/routes/session-input-handler.js +14 -0
- package/dist/src/gateway/hono/routes/sessions.js +4 -1
- package/dist/src/gateway/hono/routes/voice.js +139 -2
- package/dist/src/gateway/server.js +1 -0
- package/dist/src/gateway/service/agent-runner.d.ts +1 -0
- package/dist/src/gateway/service/agent-runner.js +1 -6
- package/dist/src/gateway/service/run-gateway-agent.d.ts +1 -0
- package/dist/src/gateway/service/run-gateway-agent.js +19 -1
- package/dist/src/gateway/service.d.ts +2 -0
- package/dist/src/gateway/service.js +73 -0
- package/dist/src/media-understanding/types.d.ts +61 -0
- package/dist/src/session/client-history.js +12 -0
- package/dist/src/session/manager.d.ts +1 -0
- package/dist/src/session/session-context-for-llm.js +8 -0
- package/dist/src/session/store.d.ts +1 -0
- package/dist/src/session/store.js +1 -0
- package/dist/src/session/stored-rows-to-file-entries.js +5 -1
- package/dist/src/session/voice-transcript.d.ts +9 -0
- package/dist/src/session/voice-transcript.js +45 -0
- package/dist/src/storage/sqlite/config-repository.js +9 -0
- package/dist/src/storage/sqlite/remote-context-repository.d.ts +3 -0
- package/dist/src/storage/sqlite/remote-context-repository.js +40 -0
- package/dist/src/storage/sqlite/session-repository.js +13 -0
- package/dist/src/storage/sqlite/user-context-repository.d.ts +3 -1
- package/dist/src/storage/sqlite/user-context-repository.js +50 -4
- package/dist/src/tui/tui.js +2 -1
- package/dist/src/user-context/automatic-context.d.ts +17 -0
- package/dist/src/user-context/automatic-context.js +85 -0
- package/dist/src/user-context/changes.d.ts +7 -0
- package/dist/src/user-context/changes.js +28 -0
- package/dist/src/user-context/planner.js +1 -24
- package/dist/src/user-context/retriever.js +10 -11
- package/dist/src/user-context/selection-policy.d.ts +20 -0
- package/dist/src/user-context/selection-policy.js +33 -0
- package/dist/src/user-context/sources/index.js +2 -2
- package/dist/src/user-context/sources/repository.d.ts +2 -1
- package/dist/src/user-context/sources/repository.js +26 -5
- package/dist/src/voice/dashscope/streaming-stt-session.d.ts +2 -0
- package/dist/src/voice/dashscope/streaming-stt-session.js +249 -0
- package/dist/src/voice/dashscope/streaming-tts-stream.d.ts +12 -0
- package/dist/src/voice/dashscope/streaming-tts-stream.js +153 -0
- package/dist/src/voice/realtime/agentEngine.d.ts +10 -0
- package/dist/src/voice/realtime/agentEngine.js +403 -0
- package/dist/src/voice/realtime/audio-playback-window.d.ts +9 -0
- package/dist/src/voice/realtime/audio-playback-window.js +49 -0
- package/dist/src/voice/realtime/conversation-context.d.ts +11 -0
- package/dist/src/voice/realtime/conversation-context.js +76 -0
- package/dist/src/voice/realtime/engine.d.ts +13 -0
- package/dist/src/voice/realtime/engine.js +1 -0
- package/dist/src/voice/realtime/memory-context.d.ts +17 -0
- package/dist/src/voice/realtime/memory-context.js +100 -0
- package/dist/src/voice/realtime/omniEngine.d.ts +18 -0
- package/dist/src/voice/realtime/omniEngine.js +443 -0
- package/dist/src/voice/realtime/omniRoute.d.ts +10 -0
- package/dist/src/voice/realtime/omniRoute.js +31 -0
- package/dist/src/voice/realtime/runtime.d.ts +99 -0
- package/dist/src/voice/realtime/runtime.js +622 -0
- package/dist/src/voice/realtime/speakable-segmenter.d.ts +10 -0
- package/dist/src/voice/realtime/speakable-segmenter.js +87 -0
- package/dist/src/voice/stt/list-providers.js +2 -1
- package/dist/src/voice/stt/providers/alibaba-transcription.js +13 -1
- package/dist/src/voice/stt/providers/xopc-cloud-transcription.js +23 -0
- package/dist/src/voice/tts/factory.js +1 -0
- package/dist/src/voice/tts/openai-compatible-speech.js +3 -1
- package/dist/src/voice/tts/providers/alibaba-speech.d.ts +1 -5
- package/dist/src/voice/tts/providers/alibaba-speech.js +25 -8
- package/dist/src/voice/tts/providers/edge-speech.js +21 -22
- package/dist/src/voice/tts/providers/minimax-speech.js +6 -3
- package/dist/src/voice/tts/providers/xopc-cloud-speech.js +26 -1
- package/dist/src/voice/tts/speak-core.d.ts +6 -2
- package/dist/src/voice/tts/speak-core.js +46 -34
- package/dist/src/voice/tts/speech-provider-types.d.ts +1 -0
- package/package.json +5 -5
- package/dist/gateway/static/root/assets/Combination-14nmIgxH.js +0 -41
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-Cf7U2aUi.js +0 -1
- package/dist/gateway/static/root/assets/agents-Ce9oOnwE.js +0 -1
- package/dist/gateway/static/root/assets/app-chrome-BeB4KgOf.js +0 -1
- package/dist/gateway/static/root/assets/app-management-settings-panel-CACOOS-a.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-BaTFOCmR.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-DK6EreCr.js +0 -6
- package/dist/gateway/static/root/assets/block-editor-DgAs5aJc.js +0 -184
- package/dist/gateway/static/root/assets/browser-settings-page-CHStw5UW.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-JGH6Kfkr.js +0 -7
- package/dist/gateway/static/root/assets/channels-settings-YkUaaWkY.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-BI0FG3gA.js +0 -2
- package/dist/gateway/static/root/assets/dist-BPoKqzeH.js +0 -1
- package/dist/gateway/static/root/assets/dist-DqPZM2MH.js +0 -1
- package/dist/gateway/static/root/assets/home-page--9fKq0mL.js +0 -1
- package/dist/gateway/static/root/assets/index-D499B1qS.css +0 -2
- package/dist/gateway/static/root/assets/index-J3FsIvTs.js +0 -70
- package/dist/gateway/static/root/assets/local-app-workbench-page-FqG00zS1.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-c6CfZ8PA.js +0 -2
- package/dist/gateway/static/root/assets/messages-_tYhRAHD.js +0 -3
- package/dist/gateway/static/root/assets/mobile-pairing-wizard-CHnXZTwb.js +0 -1
- package/dist/gateway/static/root/assets/models-hub-cache-DiXjKuuY.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-DIR37b-K.js +0 -4
- package/dist/gateway/static/root/assets/popover-select-DrILF6mR.js +0 -1
- package/dist/gateway/static/root/assets/product-open-page-CRm9Q66h.js +0 -1
- package/dist/gateway/static/root/assets/project-detail-page-DHiLTiRW.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-God7NCcI.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-YpF0-mx2.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CP8O1TxR.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-DzdbK3j9.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-B7NeVl4g.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DDTmi4a7.js +0 -1
- package/dist/gateway/static/root/assets/skills-page.utils--q8p7MAn.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-yiMzii2b.js +0 -1
- package/dist/gateway/static/root/assets/tunnel-api-CC3jOB4n.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-Vtwg7fQc.js +0 -1
- package/dist/gateway/static/root/assets/voice-config-api-BDoeXgww.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-overlay-BV_Jj5iD.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-DNHbWGPq.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-BkFIbMrz.js +0 -5
|
@@ -13,7 +13,7 @@ import { GENERIC_MASKED_SECRET, maskSecretLength } from "./mask-secret-length.js
|
|
|
13
13
|
import { safeToolsWebForGet } from "../../config-tools-web.js";
|
|
14
14
|
import { maskTunnelSecretForWeb } from "../../../tunnel/env.js";
|
|
15
15
|
import { buildSafeProvidersConfigForWeb } from "./safe-providers-config.js";
|
|
16
|
-
import { maskSttConfigForWeb, maskTtsConfigForWeb } from "./safe-voice-config.js";
|
|
16
|
+
import { maskRealtimeVoiceConfigForWeb, maskSttConfigForWeb, maskTtsConfigForWeb } from "./safe-voice-config.js";
|
|
17
17
|
//#region src/gateway/hono/lib/config-payload.ts
|
|
18
18
|
init_agent_scope();
|
|
19
19
|
init_channel_catalog_service();
|
|
@@ -195,7 +195,7 @@ async function buildSafeWebConfigPayload(service, options = {}) {
|
|
|
195
195
|
update: { ...resolveUpdateConfigForWeb(config) },
|
|
196
196
|
stt: maskSttConfigForWeb(config.tools?.media?.audio),
|
|
197
197
|
tts: maskTtsConfigForWeb(config.messages?.tts),
|
|
198
|
-
voice: config.voice,
|
|
198
|
+
voice: maskRealtimeVoiceConfigForWeb(config.voice),
|
|
199
199
|
tools: safeToolsWebForGet(config),
|
|
200
200
|
bindings: Array.isArray(config.bindings) ? config.bindings : [],
|
|
201
201
|
mcp: buildSafeMcpConfigForWeb(config)
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
export declare function maskRealtimeVoiceConfigForWeb(voice: {
|
|
2
|
+
realtime?: {
|
|
3
|
+
omni?: {
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
};
|
|
6
|
+
};
|
|
7
|
+
} | undefined): unknown;
|
|
8
|
+
export declare function mergeRealtimeVoiceConfigPatch(previous: {
|
|
9
|
+
realtime?: {
|
|
10
|
+
omni?: {
|
|
11
|
+
apiKey?: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
} | undefined, incoming: unknown): unknown;
|
|
1
15
|
/** Mask STT api keys for GET `/api/config`. */
|
|
2
16
|
export declare function maskSttConfigForWeb(stt: unknown): unknown;
|
|
3
17
|
/** Mask TTS api keys for GET `/api/config`. */
|
|
@@ -1,6 +1,34 @@
|
|
|
1
1
|
import { maskSecretLength } from "./mask-secret-length.js";
|
|
2
2
|
import { isMaskedApiKey } from "../../config-tools-web.js";
|
|
3
3
|
//#region src/gateway/hono/lib/safe-voice-config.ts
|
|
4
|
+
function maskRealtimeVoiceConfigForWeb(voice) {
|
|
5
|
+
if (!voice?.realtime?.omni) return voice;
|
|
6
|
+
return {
|
|
7
|
+
...voice,
|
|
8
|
+
realtime: {
|
|
9
|
+
...voice.realtime,
|
|
10
|
+
omni: maskProviderSlice(voice.realtime.omni)
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function mergeRealtimeVoiceConfigPatch(previous, incoming) {
|
|
15
|
+
if (!incoming || typeof incoming !== "object" || Array.isArray(incoming)) return incoming;
|
|
16
|
+
const patch = incoming;
|
|
17
|
+
const realtime = patch.realtime;
|
|
18
|
+
const omni = realtime?.omni;
|
|
19
|
+
if (!omni || typeof omni !== "object" || Array.isArray(omni)) return incoming;
|
|
20
|
+
const apiKey = omni.apiKey === "" ? void 0 : mergeApiKeyField(omni.apiKey, previous?.realtime?.omni?.apiKey);
|
|
21
|
+
return {
|
|
22
|
+
...patch,
|
|
23
|
+
realtime: {
|
|
24
|
+
...realtime,
|
|
25
|
+
omni: {
|
|
26
|
+
...omni,
|
|
27
|
+
...omni.apiKey !== void 0 ? { apiKey } : {}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
4
32
|
function maskProviderSlice(slice) {
|
|
5
33
|
const next = { ...slice };
|
|
6
34
|
if (typeof next.apiKey === "string" && next.apiKey.trim()) next.apiKey = maskSecretLength(next.apiKey);
|
|
@@ -64,4 +92,4 @@ function mergeTtsConfigPatch(previous, incoming) {
|
|
|
64
92
|
return mergeVoiceConfigPatch(previous, incoming);
|
|
65
93
|
}
|
|
66
94
|
//#endregion
|
|
67
|
-
export { maskSttConfigForWeb, maskTtsConfigForWeb, mergeSttConfigPatch, mergeTtsConfigPatch };
|
|
95
|
+
export { maskRealtimeVoiceConfigForWeb, maskSttConfigForWeb, maskTtsConfigForWeb, mergeRealtimeVoiceConfigPatch, mergeSttConfigPatch, mergeTtsConfigPatch };
|
|
@@ -9,7 +9,7 @@ import { isMaskedSecretPatchValue } from "../../lib/mask-secret-length.js";
|
|
|
9
9
|
import { applyToolsWebPatch } from "../../../config-tools-web.js";
|
|
10
10
|
import { mergeTunnelConfigPatch } from "../../../../tunnel/tunnel-config.js";
|
|
11
11
|
import { assertGatewayRuntimeConfig } from "../../../runtime-config.js";
|
|
12
|
-
import { mergeSttConfigPatch, mergeTtsConfigPatch } from "../../lib/safe-voice-config.js";
|
|
12
|
+
import { mergeRealtimeVoiceConfigPatch, mergeSttConfigPatch, mergeTtsConfigPatch } from "../../lib/safe-voice-config.js";
|
|
13
13
|
import { PATCH_OK, patchError } from "./result.js";
|
|
14
14
|
//#region src/gateway/hono/routes/config-patch/misc.ts
|
|
15
15
|
init_schema();
|
|
@@ -137,7 +137,7 @@ async function applyMiscPatch(config, body) {
|
|
|
137
137
|
config.messages.tts = mergeTtsConfigPatch(config.messages.tts, body.tts);
|
|
138
138
|
}
|
|
139
139
|
if (body.voice !== void 0) {
|
|
140
|
-
const parsed = VoiceConfigSchema.safeParse(body.voice);
|
|
140
|
+
const parsed = VoiceConfigSchema.safeParse(mergeRealtimeVoiceConfigPatch(config.voice, body.voice));
|
|
141
141
|
if (!parsed.success) return patchError(parsed.error.issues.map((i) => i.message).join("; "));
|
|
142
142
|
config.voice = parsed.data;
|
|
143
143
|
}
|
|
@@ -86,6 +86,13 @@ function registerFilesRoutes(authenticated, deps) {
|
|
|
86
86
|
return errorResponse(c, error);
|
|
87
87
|
}
|
|
88
88
|
});
|
|
89
|
+
authenticated.get("/api/files/spaces/:id/root", async (c) => {
|
|
90
|
+
try {
|
|
91
|
+
return c.json({ resource: await files.rootResource(c.req.param("id")) });
|
|
92
|
+
} catch (error) {
|
|
93
|
+
return errorResponse(c, error);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
89
96
|
authenticated.get("/api/files/recent", async (c) => {
|
|
90
97
|
try {
|
|
91
98
|
const limit = Math.min(100, Math.max(1, Number(c.req.query("limit")) || 50));
|
|
@@ -3,6 +3,16 @@ import { APP_LAZY_ROUTE_BUNDLES, AUTHENTICATED_LAZY_ROUTE_BUNDLES, findAuthentic
|
|
|
3
3
|
import { Hono } from "hono";
|
|
4
4
|
//#region src/gateway/hono/routes/lazy-fallback.ts
|
|
5
5
|
const log = createGatewayRouteLogger("LazyRoutes");
|
|
6
|
+
const FORWARDED_VARIABLES = Symbol("gateway.forwardedVariables");
|
|
7
|
+
function createSubApp() {
|
|
8
|
+
const sub = new Hono();
|
|
9
|
+
sub.use(async (c, next) => {
|
|
10
|
+
const variables = c.env?.[FORWARDED_VARIABLES];
|
|
11
|
+
for (const [key, value] of Object.entries(variables ?? {})) c.set(key, value);
|
|
12
|
+
await next();
|
|
13
|
+
});
|
|
14
|
+
return sub;
|
|
15
|
+
}
|
|
6
16
|
const authenticatedSubApps = /* @__PURE__ */ new Map();
|
|
7
17
|
const appSubApps = /* @__PURE__ */ new Map();
|
|
8
18
|
const authenticatedLoadPromises = /* @__PURE__ */ new Map();
|
|
@@ -28,7 +38,7 @@ async function ensureAuthenticatedLazyBundle(bundleId, deps) {
|
|
|
28
38
|
if (!bundle) return null;
|
|
29
39
|
pending = (async () => {
|
|
30
40
|
const mod = await bundle.load();
|
|
31
|
-
const sub =
|
|
41
|
+
const sub = createSubApp();
|
|
32
42
|
mod.register(sub, deps);
|
|
33
43
|
authenticatedSubApps.set(bundleId, sub);
|
|
34
44
|
authenticatedLoadPromises.delete(bundleId);
|
|
@@ -47,7 +57,7 @@ async function ensureAppLazyBundle(bundleId, params) {
|
|
|
47
57
|
if (!bundle) return null;
|
|
48
58
|
pending = (async () => {
|
|
49
59
|
const mod = await bundle.load();
|
|
50
|
-
const sub =
|
|
60
|
+
const sub = createSubApp();
|
|
51
61
|
if (mod.registerOnApp) mod.registerOnApp(sub, params.service);
|
|
52
62
|
appSubApps.set(bundleId, sub);
|
|
53
63
|
appLoadPromises.delete(bundleId);
|
|
@@ -58,10 +68,14 @@ async function ensureAppLazyBundle(bundleId, params) {
|
|
|
58
68
|
return pending;
|
|
59
69
|
}
|
|
60
70
|
async function forwardToSubApp(c, sub) {
|
|
71
|
+
const env = {
|
|
72
|
+
...c.env,
|
|
73
|
+
[FORWARDED_VARIABLES]: { ...c.var }
|
|
74
|
+
};
|
|
61
75
|
try {
|
|
62
|
-
return await sub.fetch(c.req.raw,
|
|
76
|
+
return await sub.fetch(c.req.raw, env, c.executionCtx);
|
|
63
77
|
} catch (error) {
|
|
64
|
-
if (error instanceof Error && error.message.includes("ExecutionContext")) return sub.fetch(c.req.raw,
|
|
78
|
+
if (error instanceof Error && error.message.includes("ExecutionContext")) return sub.fetch(c.req.raw, env);
|
|
65
79
|
logRouteError(log, c, error, "gateway.route.lazy_forward");
|
|
66
80
|
throw error;
|
|
67
81
|
}
|
|
@@ -73,6 +73,13 @@ async function submitSessionInput(c, deps, sessionKey) {
|
|
|
73
73
|
}
|
|
74
74
|
}, 400);
|
|
75
75
|
return withModelConfigLock(sessionKey, async () => {
|
|
76
|
+
if (deps.service.voiceRealtime?.hasConversation(sessionKey)) return c.json({
|
|
77
|
+
ok: false,
|
|
78
|
+
error: {
|
|
79
|
+
code: "SESSION_BUSY",
|
|
80
|
+
message: "End the voice call before sending text"
|
|
81
|
+
}
|
|
82
|
+
}, 409);
|
|
76
83
|
const selection = body.configVersion !== void 0 ? await deps.service.sessions.getAgentConfig(sessionKey) : void 0;
|
|
77
84
|
if (selection) {
|
|
78
85
|
if (!Number.isSafeInteger(body.configVersion) || selection.configVersion !== body.configVersion || !selection.fixedModel) return c.json({
|
|
@@ -181,6 +188,13 @@ async function replaceLatestSessionTurn(c, deps, sessionKey, targetTurnId) {
|
|
|
181
188
|
}
|
|
182
189
|
}, 401);
|
|
183
190
|
return withModelConfigLock(sessionKey, async () => {
|
|
191
|
+
if (deps.service.voiceRealtime?.hasConversation(sessionKey)) return c.json({
|
|
192
|
+
ok: false,
|
|
193
|
+
error: {
|
|
194
|
+
code: "SESSION_BUSY",
|
|
195
|
+
message: "End the voice call before editing a turn"
|
|
196
|
+
}
|
|
197
|
+
}, 409);
|
|
184
198
|
const selection = body.configVersion !== void 0 ? await deps.service.sessions.getAgentConfig(sessionKey) : void 0;
|
|
185
199
|
if (selection) {
|
|
186
200
|
if (!Number.isSafeInteger(body.configVersion) || selection.configVersion !== body.configVersion || !selection.fixedModel) return c.json({
|
|
@@ -3,13 +3,13 @@ import { resolveProjectAgentId } from "../../../projects/project-agent.js";
|
|
|
3
3
|
import "../../../projects/index.js";
|
|
4
4
|
import { evictEmbeddedSessionRunner } from "../../../agent/embedded/session-runner.js";
|
|
5
5
|
import { messagesToClientHistory } from "../../../session/client-history.js";
|
|
6
|
-
import { SessionEnvironmentService } from "../../../execution-environments/session-environment-service.js";
|
|
7
6
|
import { deleteMediaUrisNoLongerReferenced } from "../../../media/session-references.js";
|
|
8
7
|
import { getGatewayPrincipal } from "../../security/gateway-principal.js";
|
|
9
8
|
import { createGatewayRouteLogger, logRouteError } from "../lib/route-logger.js";
|
|
10
9
|
import { patchChatModelConfig } from "./chat-model-config.js";
|
|
11
10
|
import { getSessionContextSummary } from "../../session-context-summary.js";
|
|
12
11
|
import { respondStartupUnavailable } from "../lib/startup-unavailable.js";
|
|
12
|
+
import { SessionEnvironmentService } from "../../../execution-environments/session-environment-service.js";
|
|
13
13
|
import { randomUUID } from "node:crypto";
|
|
14
14
|
//#region src/gateway/hono/routes/sessions.ts
|
|
15
15
|
init_session_key();
|
|
@@ -785,6 +785,7 @@ function registerSessionsRoutes(authenticated, deps) {
|
|
|
785
785
|
});
|
|
786
786
|
authenticated.delete("/api/sessions/:key/messages", async (c) => {
|
|
787
787
|
const key = c.req.param("key");
|
|
788
|
+
if (service.voiceRealtime?.hasConversation(key)) return c.json({ error: "End the voice call before editing its history" }, 409);
|
|
788
789
|
const body = await c.req.json().catch(() => ({}));
|
|
789
790
|
const userRoundIndex = typeof body.userRoundIndex === "number" ? body.userRoundIndex : void 0;
|
|
790
791
|
if (userRoundIndex === void 0 || !Number.isInteger(userRoundIndex) || userRoundIndex < 0) return c.json({ error: "userRoundIndex must be a non-negative integer" }, 400);
|
|
@@ -805,6 +806,7 @@ function registerSessionsRoutes(authenticated, deps) {
|
|
|
805
806
|
const blocked = ensureGatewayReadyForSessions(c, service, "sessions.reset");
|
|
806
807
|
if (blocked) return blocked;
|
|
807
808
|
const key = c.req.param("key");
|
|
809
|
+
if (service.voiceRealtime?.hasConversation(key)) return c.json({ error: "End the voice call before resetting the session" }, 409);
|
|
808
810
|
const result = await service.sessions.reset(key);
|
|
809
811
|
if (result.ok === false) {
|
|
810
812
|
const status = result.error === "Session not found" ? 404 : 400;
|
|
@@ -824,6 +826,7 @@ function registerSessionsRoutes(authenticated, deps) {
|
|
|
824
826
|
});
|
|
825
827
|
authenticated.delete("/api/sessions/:key", async (c) => {
|
|
826
828
|
const key = c.req.param("key");
|
|
829
|
+
if (service.voiceRealtime?.hasConversation(key)) return c.json({ error: "End the voice call before deleting the session" }, 409);
|
|
827
830
|
if (environments.get(key) && service.getActiveWebchatRunId(key)) return c.json({
|
|
828
831
|
ok: false,
|
|
829
832
|
error: "Stop the active session run before deleting its environment"
|
|
@@ -2,7 +2,7 @@ import { getDefaultModelSync, init_providers, resolveModel } from "../../../prov
|
|
|
2
2
|
import { completeWithResolvedCredentials } from "../../../providers/model-call.js";
|
|
3
3
|
import { resolveTtsProviderConfigSlice } from "../../../voice/tts/config-slice.js";
|
|
4
4
|
import { isTTSAvailable, resolveSpeechProvider } from "../../../voice/tts/factory.js";
|
|
5
|
-
import { speak } from "../../../voice/tts/speak-core.js";
|
|
5
|
+
import { speak, speakStream } from "../../../voice/tts/speak-core.js";
|
|
6
6
|
import { mergeTtsConfigFromAppConfig } from "../../../voice/tts/merge-config.js";
|
|
7
7
|
import { getLocalVoiceRuntimeClient } from "../../../voice/local/runtime-client.js";
|
|
8
8
|
import { getAudioDecoderStatus } from "../../../voice/audio/normalize.js";
|
|
@@ -13,6 +13,11 @@ import { mergeSttConfigFromAppConfig } from "../../../voice/stt/config.js";
|
|
|
13
13
|
import "../../../voice/stt/index.js";
|
|
14
14
|
import { listSttProvidersForApi } from "../../../voice/stt/list-providers.js";
|
|
15
15
|
import "../../../voice/tts/index.js";
|
|
16
|
+
import { withModelConfigLock } from "../../../session/model-config-lock.js";
|
|
17
|
+
import { createVoiceSessionRequestSchema } from "../../../../packages/realtime-protocol/src/voice.js";
|
|
18
|
+
import { resolveOmniRoute } from "../../../voice/realtime/omniRoute.js";
|
|
19
|
+
import { VoiceSessionCreationError, resolveStreamingStt, resolveStreamingTts } from "../../../voice/realtime/runtime.js";
|
|
20
|
+
import { getGatewayPrincipal } from "../../security/gateway-principal.js";
|
|
16
21
|
import { createGatewayRouteLogger } from "../lib/route-logger.js";
|
|
17
22
|
import { listLocalVoiceModelStatuses, removeLocalVoiceModel, startLocalVoiceModelInstall } from "../../../voice/local/model-manager.js";
|
|
18
23
|
import { listTtsProvidersForApi } from "../../../voice/tts/list-providers.js";
|
|
@@ -107,6 +112,134 @@ async function refineTranscript(raw, config, signal) {
|
|
|
107
112
|
}
|
|
108
113
|
function registerVoiceRoutes(authenticated, deps) {
|
|
109
114
|
const { service, strictRateLimitMiddleware } = deps;
|
|
115
|
+
authenticated.get("/api/voice/realtime/status", async (c) => {
|
|
116
|
+
const config = service.currentConfig;
|
|
117
|
+
const stt = resolveStreamingStt(config);
|
|
118
|
+
const tts = resolveStreamingTts(config);
|
|
119
|
+
const omni = await resolveOmniRoute(config).catch(() => null);
|
|
120
|
+
const enabled = config.voice?.realtime?.enabled === true;
|
|
121
|
+
const availability = (configured) => ({
|
|
122
|
+
available: enabled && configured,
|
|
123
|
+
...!enabled ? { reasonCode: "VOICE_DISABLED" } : !configured ? { reasonCode: "PROVIDER_UNAVAILABLE" } : {}
|
|
124
|
+
});
|
|
125
|
+
return c.json({
|
|
126
|
+
ok: true,
|
|
127
|
+
payload: {
|
|
128
|
+
enabled,
|
|
129
|
+
capabilities: {
|
|
130
|
+
dictation: availability(Boolean(stt)),
|
|
131
|
+
agent: availability(Boolean(stt && tts)),
|
|
132
|
+
omni: availability(Boolean(omni)),
|
|
133
|
+
languages: ["zh", "en"],
|
|
134
|
+
bargeIn: config.voice?.realtime?.bargeIn ?? true
|
|
135
|
+
},
|
|
136
|
+
defaultEngine: config.voice?.realtime?.defaultEngine ?? "agent",
|
|
137
|
+
omni: omni?.route ?? null,
|
|
138
|
+
stt: stt?.route ?? null,
|
|
139
|
+
tts: tts ? {
|
|
140
|
+
...tts.route,
|
|
141
|
+
voice: tts.config.providers?.[tts.route.provider]?.voice ?? tts.provider.providerConfig.voice
|
|
142
|
+
} : null
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
authenticated.post("/api/voice/realtime/preview", strictRateLimitMiddleware, async (c) => {
|
|
147
|
+
const config = service.currentConfig;
|
|
148
|
+
const route = resolveStreamingTts(config);
|
|
149
|
+
if (!route) return c.json({
|
|
150
|
+
ok: false,
|
|
151
|
+
error: { message: "Realtime voice output is not configured" }
|
|
152
|
+
}, 503);
|
|
153
|
+
const controller = new AbortController();
|
|
154
|
+
const signal = AbortSignal.any([
|
|
155
|
+
c.req.raw.signal,
|
|
156
|
+
controller.signal,
|
|
157
|
+
AbortSignal.timeout(2e4)
|
|
158
|
+
]);
|
|
159
|
+
let result;
|
|
160
|
+
let reader;
|
|
161
|
+
try {
|
|
162
|
+
result = await speakStream(config.voice?.language === "en" ? "Hello, I am your assistant. You can talk to me naturally." : "你好,我是你的助手。现在可以和我自然对话了。", route.config, {
|
|
163
|
+
signal,
|
|
164
|
+
appConfig: config,
|
|
165
|
+
allowFallback: false,
|
|
166
|
+
parseDirectives: false
|
|
167
|
+
});
|
|
168
|
+
if (result.outputFormat !== "pcm") throw new Error("Realtime preview requires PCM audio");
|
|
169
|
+
reader = result.audioStream.getReader();
|
|
170
|
+
const chunks = [];
|
|
171
|
+
let size = 0;
|
|
172
|
+
while (true) {
|
|
173
|
+
signal.throwIfAborted();
|
|
174
|
+
const { value, done } = await reader.read();
|
|
175
|
+
if (done) break;
|
|
176
|
+
size += value.byteLength;
|
|
177
|
+
if (size > 96e4) throw new Error("Realtime preview audio exceeds the limit");
|
|
178
|
+
chunks.push(value);
|
|
179
|
+
}
|
|
180
|
+
if (size === 0 || size % 2 !== 0) throw new Error("Realtime preview returned invalid audio");
|
|
181
|
+
return c.json({
|
|
182
|
+
ok: true,
|
|
183
|
+
payload: {
|
|
184
|
+
audio: Buffer.concat(chunks).toString("base64"),
|
|
185
|
+
sampleRate: 24e3
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
} catch (error) {
|
|
189
|
+
log.warn({
|
|
190
|
+
err: error,
|
|
191
|
+
provider: route.route.provider
|
|
192
|
+
}, "Realtime voice preview failed");
|
|
193
|
+
return c.json({
|
|
194
|
+
ok: false,
|
|
195
|
+
error: { message: "Voice preview failed. Check the provider credentials and try again." }
|
|
196
|
+
}, 502);
|
|
197
|
+
} finally {
|
|
198
|
+
controller.abort();
|
|
199
|
+
await reader?.cancel().catch(() => void 0);
|
|
200
|
+
reader?.releaseLock();
|
|
201
|
+
await result?.release();
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
for (const action of ["preflight", "sessions"]) authenticated.post(`/api/voice/realtime/${action}`, strictRateLimitMiddleware, async (c) => {
|
|
205
|
+
const parsed = createVoiceSessionRequestSchema.safeParse(await c.req.json().catch(() => null));
|
|
206
|
+
if (!parsed.success) return c.json({
|
|
207
|
+
ok: false,
|
|
208
|
+
error: {
|
|
209
|
+
code: "INVALID_REQUEST",
|
|
210
|
+
message: "Invalid realtime voice session request"
|
|
211
|
+
}
|
|
212
|
+
}, 400);
|
|
213
|
+
try {
|
|
214
|
+
if (action === "preflight") {
|
|
215
|
+
await service.voiceRealtime.preflight(parsed.data);
|
|
216
|
+
return c.json({ ok: true });
|
|
217
|
+
}
|
|
218
|
+
const principal = getGatewayPrincipal(c);
|
|
219
|
+
const create = () => service.voiceRealtime.createSession(parsed.data, principal.principalId);
|
|
220
|
+
const payload = parsed.data.sessionKey ? await withModelConfigLock(parsed.data.sessionKey, create) : await create();
|
|
221
|
+
return c.json({
|
|
222
|
+
ok: true,
|
|
223
|
+
payload
|
|
224
|
+
});
|
|
225
|
+
} catch (error) {
|
|
226
|
+
const message = error instanceof Error ? error.message : "Realtime voice is unavailable";
|
|
227
|
+
if (error instanceof VoiceSessionCreationError) return c.json({
|
|
228
|
+
ok: false,
|
|
229
|
+
error: {
|
|
230
|
+
code: error.code,
|
|
231
|
+
message
|
|
232
|
+
}
|
|
233
|
+
}, error.status);
|
|
234
|
+
return c.json({
|
|
235
|
+
ok: false,
|
|
236
|
+
error: {
|
|
237
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
238
|
+
message
|
|
239
|
+
}
|
|
240
|
+
}, 503);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
110
243
|
authenticated.post("/api/voice/language", strictRateLimitMiddleware, async (c) => {
|
|
111
244
|
let body = {};
|
|
112
245
|
try {
|
|
@@ -153,7 +286,11 @@ function registerVoiceRoutes(authenticated, deps) {
|
|
|
153
286
|
error: { message: "provider and model are required" }
|
|
154
287
|
}, 400);
|
|
155
288
|
const config = service.currentConfig;
|
|
156
|
-
const baseConfig = mergeTtsConfigFromAppConfig(config.messages?.tts);
|
|
289
|
+
const baseConfig = c.req.query("purpose") === "realtime" ? resolveStreamingTts(config)?.config : mergeTtsConfigFromAppConfig(config.messages?.tts);
|
|
290
|
+
if (!baseConfig) return c.json({
|
|
291
|
+
ok: true,
|
|
292
|
+
payload: { voices: [] }
|
|
293
|
+
});
|
|
157
294
|
const resolved = resolveSpeechProvider(provider, {
|
|
158
295
|
...baseConfig,
|
|
159
296
|
provider,
|
|
@@ -68,6 +68,7 @@ var GatewayServer = class {
|
|
|
68
68
|
});
|
|
69
69
|
inner.on("upgrade", (req, socket, head) => {
|
|
70
70
|
try {
|
|
71
|
+
if (this.service.voiceRealtime.handleUpgrade(req, socket, head)) return;
|
|
71
72
|
if (this.service.realtime.handleUpgrade(req, socket, head)) return;
|
|
72
73
|
if (handleSiteShareUpgrade(this.service, req, socket, head)) return;
|
|
73
74
|
socket.destroy();
|
|
@@ -128,12 +128,7 @@ var GatewayAgentRunner = class {
|
|
|
128
128
|
completeRealtimeTopic: this.opts.completeRealtimeTopic
|
|
129
129
|
}, message, channel, chatId, origin, attachments, thinking, runOptions);
|
|
130
130
|
try {
|
|
131
|
-
|
|
132
|
-
while (!step.done) {
|
|
133
|
-
yield step.value;
|
|
134
|
-
step = await iter.next();
|
|
135
|
-
}
|
|
136
|
-
return step.value;
|
|
131
|
+
return yield* iter;
|
|
137
132
|
} finally {
|
|
138
133
|
if (trackedRunId) {
|
|
139
134
|
this.resolveRunCompletions.get(trackedRunId)?.();
|
|
@@ -25,6 +25,7 @@ export declare function runGatewayAgent(deps: RunGatewayAgentDeps, message: stri
|
|
|
25
25
|
signal?: AbortSignal;
|
|
26
26
|
runId?: string;
|
|
27
27
|
sourceContexts?: AgentSourceContext[];
|
|
28
|
+
presentation?: 'voice';
|
|
28
29
|
}): AsyncGenerator<RunGatewayAgentYield, {
|
|
29
30
|
status: string;
|
|
30
31
|
summary: string;
|
|
@@ -131,7 +131,8 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
|
|
|
131
131
|
const eventStream = agentService.turnDispatcher.processDirectStreaming(stampedMessage, sessionKey, origin, prepared, thinking, {
|
|
132
132
|
signal: mergedSignal,
|
|
133
133
|
runId,
|
|
134
|
-
sourceContexts: runOptions?.sourceContexts
|
|
134
|
+
sourceContexts: runOptions?.sourceContexts,
|
|
135
|
+
presentation: runOptions?.presentation
|
|
135
136
|
});
|
|
136
137
|
const mappedEvents = (async function* () {
|
|
137
138
|
for await (const event of eventStream) yield* mapper.map(event);
|
|
@@ -150,6 +151,18 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
|
|
|
150
151
|
summary: mergedSignal.aborted ? "Interrupted" : "Message processed successfully"
|
|
151
152
|
};
|
|
152
153
|
} catch (error) {
|
|
154
|
+
if (mergedSignal.aborted) {
|
|
155
|
+
terminalStatus = "cancelled";
|
|
156
|
+
taskRunStatus = "cancelled";
|
|
157
|
+
taskRunSummary = "Interrupted";
|
|
158
|
+
yield* emitAndYield(mapper.end("cancelled", "Interrupted"));
|
|
159
|
+
completeRealtimeTopic(`run:${runId}`);
|
|
160
|
+
runTopicCompleted = true;
|
|
161
|
+
return {
|
|
162
|
+
status: "aborted",
|
|
163
|
+
summary: "Interrupted"
|
|
164
|
+
};
|
|
165
|
+
}
|
|
153
166
|
const em = error instanceof Error ? error.message : String(error);
|
|
154
167
|
log.error({
|
|
155
168
|
err: error,
|
|
@@ -173,6 +186,11 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
|
|
|
173
186
|
summary: streamError
|
|
174
187
|
};
|
|
175
188
|
} finally {
|
|
189
|
+
if (mergedSignal.aborted) {
|
|
190
|
+
terminalStatus = "cancelled";
|
|
191
|
+
taskRunStatus = "cancelled";
|
|
192
|
+
taskRunSummary = "Interrupted";
|
|
193
|
+
}
|
|
176
194
|
if (registeredActiveWebchatRun && activeWebchatRunBySession.get(sessionKey) === runId) {
|
|
177
195
|
activeWebchatRunBySession.delete(sessionKey);
|
|
178
196
|
publishRealtime("sessions", "run.completed", {
|
|
@@ -19,6 +19,7 @@ import { GatewaySessionsApi } from './service/sessions-api.js';
|
|
|
19
19
|
import { GatewayMarketplaceService } from './service/marketplace-service.js';
|
|
20
20
|
import { GatewayAgentRunner } from './service/agent-runner.js';
|
|
21
21
|
import { RealtimeRuntime } from '../realtime/runtime.js';
|
|
22
|
+
import { VoiceRealtimeRuntime } from '../voice/realtime/runtime.js';
|
|
22
23
|
import type { GatewayServiceConfig } from './service/types.js';
|
|
23
24
|
import { type GatewayReadinessSnapshot } from './startup-readiness.js';
|
|
24
25
|
import { type ConnectorLearningCoordinator } from '../connectors/learning-coordinator.js';
|
|
@@ -51,6 +52,7 @@ export declare class GatewayService {
|
|
|
51
52
|
private auth;
|
|
52
53
|
readonly endpointTools: EndpointToolRuntime;
|
|
53
54
|
readonly realtime: RealtimeRuntime;
|
|
55
|
+
readonly voiceRealtime: VoiceRealtimeRuntime;
|
|
54
56
|
getConfig(): Config;
|
|
55
57
|
getModelCatalogSync(): ModelCatalogSyncService;
|
|
56
58
|
get browserRecipes(): BrowserRecipeService;
|
|
@@ -6,6 +6,8 @@ import { getRuntimeLogStats } from "../utils/logger/stats.js";
|
|
|
6
6
|
import { createLogger } from "../utils/logger/index.js";
|
|
7
7
|
import { init_logger } from "../utils/logger.js";
|
|
8
8
|
import { closeXopcDatabase, openXopcDatabase } from "../storage/sqlite/connection.js";
|
|
9
|
+
import { notifyUserContextChange } from "../user-context/changes.js";
|
|
10
|
+
import { getSessionConfig } from "../storage/sqlite/config-repository.js";
|
|
9
11
|
import "../storage/sqlite/index.js";
|
|
10
12
|
import { getAgentDefaultModelRef, init_schema } from "../config/schema.js";
|
|
11
13
|
import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveDefaultAgentId } from "../agent/agent-scope.js";
|
|
@@ -18,6 +20,7 @@ import { loadConfig, saveConfig } from "../config/loader.js";
|
|
|
18
20
|
import { buildSessionKey, init_session_key, sanitizeSegment } from "../routing/session-key.js";
|
|
19
21
|
import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
|
|
20
22
|
import { init_providers, providers_exports } from "../providers/index.js";
|
|
23
|
+
import { resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
|
|
21
24
|
import { TaskRepository } from "../tasks/task-repository.js";
|
|
22
25
|
import { TaskConversationRepository } from "../tasks/task-conversation-repository.js";
|
|
23
26
|
import { disposeAllSessionMcpRuntimes } from "../agent/mcp/bundle-mcp-runtime.js";
|
|
@@ -68,6 +71,8 @@ import { assertGatewayAuthConfigured, extractToken, resolveGatewayAuth, validate
|
|
|
68
71
|
import { prepareAutomationAgentSession } from "./automation-agent-session.js";
|
|
69
72
|
import { stopTailscaleExposure } from "./tailscale-lifecycle.js";
|
|
70
73
|
import { reconcileDreamingAutomations } from "./dreaming-automation-reconciler.js";
|
|
74
|
+
import { buildVoiceMemoryContext } from "../voice/realtime/memory-context.js";
|
|
75
|
+
import { voiceMemoryBudget } from "../voice/realtime/conversation-context.js";
|
|
71
76
|
import { NotesStore } from "../notes/store.js";
|
|
72
77
|
import { buildNoteAgentContext } from "../notes/agent-context.js";
|
|
73
78
|
import { NotesService } from "../notes/service.js";
|
|
@@ -114,6 +119,7 @@ import { GatewayMarketplaceService } from "./service/marketplace-service.js";
|
|
|
114
119
|
import { GatewayConfigCoordinator } from "./service/config-coordinator.js";
|
|
115
120
|
import { GatewayAgentRunner } from "./service/agent-runner.js";
|
|
116
121
|
import { RealtimeRuntime } from "../realtime/runtime.js";
|
|
122
|
+
import { VoiceRealtimeRuntime } from "../voice/realtime/runtime.js";
|
|
117
123
|
import { GatewayReadiness } from "./startup-readiness.js";
|
|
118
124
|
import { createGatewayStartupTrace } from "./startup-trace.js";
|
|
119
125
|
import { applyAutomaticVoiceLanguage, inferProductLanguageFromEnvironment, initializeVoiceDefaults } from "../voice/language-profile.js";
|
|
@@ -158,6 +164,71 @@ var GatewayService = class {
|
|
|
158
164
|
auth;
|
|
159
165
|
endpointTools = new EndpointToolRuntime();
|
|
160
166
|
realtime = new RealtimeRuntime(this.endpointTools);
|
|
167
|
+
voiceRealtime = new VoiceRealtimeRuntime({
|
|
168
|
+
getConversationContext: async (sessionKey, expectedSessionId) => {
|
|
169
|
+
if ((await this.sessionIndex.getSessionMetadata(sessionKey))?.sessionId !== expectedSessionId) throw new Error("Conversation changed before voice connection");
|
|
170
|
+
const messages = await this.sessionIndex.loadMessages(sessionKey);
|
|
171
|
+
const after = await this.sessionIndex.getSessionMetadata(sessionKey);
|
|
172
|
+
if (after?.sessionId !== expectedSessionId) throw new Error("Conversation changed while loading voice context");
|
|
173
|
+
const profile = resolveEffectiveAgentProfileForSession(this.config, sessionKey);
|
|
174
|
+
const context = {
|
|
175
|
+
identity: [`Your name is ${profile.config.profile?.name ?? profile.agentId}.`, profile.customInstructions ?? ""].join("\n"),
|
|
176
|
+
history: messages
|
|
177
|
+
};
|
|
178
|
+
const memory = buildVoiceMemoryContext({
|
|
179
|
+
getConfig: () => this.config,
|
|
180
|
+
sessionKey,
|
|
181
|
+
workspaceId: getSessionConfig(sessionKey)?.workingDirectoryOverride ?? profile.resolvedWorkspacePath,
|
|
182
|
+
projectId: after?.projectId,
|
|
183
|
+
history: messages,
|
|
184
|
+
maxChars: voiceMemoryBudget(this.config.voice.realtime.omni.instructions, context)
|
|
185
|
+
});
|
|
186
|
+
return {
|
|
187
|
+
...context,
|
|
188
|
+
...memory ? { memory } : {}
|
|
189
|
+
};
|
|
190
|
+
},
|
|
191
|
+
getSessionIdentity: async (sessionKey) => (await this.sessionIndex.getSessionMetadata(sessionKey))?.sessionId,
|
|
192
|
+
recordOmniTranscript: async (sessionKey, callId, entry, expectedSessionId) => {
|
|
193
|
+
await this.sessionIndex.appendTranscriptCustomMessageEntry(sessionKey, {
|
|
194
|
+
expectedSessionId,
|
|
195
|
+
customType: "voice_omni_transcript",
|
|
196
|
+
content: entry.text,
|
|
197
|
+
display: true,
|
|
198
|
+
details: {
|
|
199
|
+
callId,
|
|
200
|
+
itemId: entry.itemId,
|
|
201
|
+
role: entry.role,
|
|
202
|
+
interrupted: entry.interrupted,
|
|
203
|
+
engine: "omni"
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
this.emit("session.transcript_updated", { key: sessionKey });
|
|
207
|
+
},
|
|
208
|
+
getConfig: () => this.config,
|
|
209
|
+
sessionExists: async (sessionKey) => Boolean(await this.sessionIndex.getSessionMetadata(sessionKey)),
|
|
210
|
+
sessionBusy: (sessionKey) => Boolean(this.agentRunner.getActiveRunId(sessionKey)) || this.agentRunner.inputs.snapshot(sessionKey).inputs.some((input) => input.status === "queued"),
|
|
211
|
+
recordInterruption: (entry) => this.sessionIndex.appendTranscriptContextEntry(entry.sessionKey, {
|
|
212
|
+
text: "Voice response was interrupted before playback completed.",
|
|
213
|
+
data: {
|
|
214
|
+
type: "voice_response_interrupted",
|
|
215
|
+
responseId: entry.responseId,
|
|
216
|
+
reason: entry.reason,
|
|
217
|
+
generatedCharacters: entry.generatedCharacters,
|
|
218
|
+
interruptedDuring: entry.interruptedDuring
|
|
219
|
+
}
|
|
220
|
+
}),
|
|
221
|
+
runAgent: (text, sessionKey, signal) => {
|
|
222
|
+
if (this.agentRunner.hasActiveRun(sessionKey)) throw new Error("Conversation session already has an active response");
|
|
223
|
+
return this.agentRunner.runAgent(text, "webchat", sessionKey, {
|
|
224
|
+
type: "channel",
|
|
225
|
+
channel: "webchat"
|
|
226
|
+
}, void 0, void 0, {
|
|
227
|
+
signal,
|
|
228
|
+
presentation: "voice"
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
});
|
|
161
232
|
getConfig() {
|
|
162
233
|
return this.config;
|
|
163
234
|
}
|
|
@@ -1097,6 +1168,7 @@ var GatewayService = class {
|
|
|
1097
1168
|
this.endpointTools.close();
|
|
1098
1169
|
await this.sideChats.disposeAll();
|
|
1099
1170
|
this.realtime.close();
|
|
1171
|
+
this.voiceRealtime.close();
|
|
1100
1172
|
await this.proactiveWorker.stop();
|
|
1101
1173
|
await this.discussionWorker.stop();
|
|
1102
1174
|
await this.discussionSealer.stop();
|
|
@@ -1543,6 +1615,7 @@ var GatewayService = class {
|
|
|
1543
1615
|
});
|
|
1544
1616
|
}
|
|
1545
1617
|
emit(type, payload) {
|
|
1618
|
+
if (type === "config.reload") notifyUserContextChange({ kind: "policy" });
|
|
1546
1619
|
this.realtime.broker.publish("gateway", type, payload);
|
|
1547
1620
|
this.createNotificationService().handleGatewayEvent(type, payload);
|
|
1548
1621
|
}
|