@xopcai/xopc 0.0.86 → 0.0.87
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/feishu/src/adapters/cli-login.js +3 -3
- package/dist/extensions/feishu/src/adapters/cli-login.js.map +1 -1
- package/dist/extensions/telegram/src/delivery-chat-id.d.ts +1 -1
- package/dist/extensions/telegram/src/delivery-chat-id.js +1 -1
- package/dist/extensions/telegram/src/delivery-chat-id.js.map +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +1 -0
- package/dist/extensions/telegram/src/routing-integration.js.map +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js +2 -2
- package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js.map +1 -1
- package/dist/extensions/weixin/src/api/api.js +2 -2
- package/dist/extensions/weixin/src/api/api.js.map +1 -1
- package/dist/extensions/weixin/src/auth/accounts.js +12 -12
- package/dist/extensions/weixin/src/auth/accounts.js.map +1 -1
- package/dist/extensions/weixin/src/delivery-to.js +2 -2
- package/dist/extensions/weixin/src/delivery-to.js.map +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +5 -5
- package/dist/extensions/weixin/src/messaging/debug-mode.js.map +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +11 -11
- package/dist/extensions/weixin/src/messaging/inbound.js.map +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +4 -4
- package/dist/extensions/weixin/src/storage/sync-buf.js.map +1 -1
- package/dist/extensions/weixin/src/workflow-progress.d.ts +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js.map +1 -1
- package/dist/gateway/static/root/assets/{agents-mS3_HpRI.js → agents-BEAbXpuP.js} +6 -6
- package/dist/gateway/static/root/assets/{apps-page-DrfytjOb.js → apps-page-Dg8R-Szf.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-BG6b9KrW.js → channels-settings-yohw9YSu.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-status-swr-Bs5kMCMI.js → channels-status-swr-BSHqqCF1.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-api-BuVcZ5zR.js → cron-api-0h_QT8U3.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-BMrloeFH.js → cron-page-BkfKFfFk.js} +1 -1
- package/dist/gateway/static/root/assets/{dist-CKU1OOTf.js → dist-Cmjp2APP.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-BdW_46sN.js → extension-debug-page-CFa9z_1N.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DW47KI82.js → extension-page-BI8eaTPq.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-B-W4x2xP.js → extension-settings-page-x4BB7q1X.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-B2MYHbWg.js → fetch-DRqwef_Q.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-DPG-oJmx.js → field-primitives-BiNHBo2Y.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-C8dNts9i.js → heartbeat-config-api-ZRb8qhuz.js} +1 -1
- package/dist/gateway/static/root/assets/{index-BmVYculr.js → index-Cu7bKuUi.js} +96 -94
- package/dist/gateway/static/root/assets/index-a5gWIdZQ.css +1 -0
- package/dist/gateway/static/root/assets/{logs-page-sTsVWz0X.js → logs-page-BFZ8GgCv.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-FaG_Vlkb.js → sessions-page-CD7AfB-2.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-DuvRQW--.js → settings-form-section-DiqqVs6m.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-Bet1OerL.js → settings-page-BBOjEQW3.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-BtG2kLDh.js → share-preview-page-n1Gprylk.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-DhUO235y.js → skills-page-CcN_gj--.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-DryYl3qD.js → theme-store-CZOh1nT3.js} +1 -1
- package/dist/gateway/static/root/assets/url-Dd8Q7kZZ.js +3 -0
- package/dist/gateway/static/root/assets/{utils-BY7bU1DT.js → utils-CkWBfxs4.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-CGEydndO.js → voice-api-key-field-O6awz9hi.js} +1 -1
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-scope.d.ts +4 -0
- package/dist/src/agent/agent-scope.js +53 -10
- package/dist/src/agent/agent-scope.js.map +1 -1
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js +2 -1
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
- package/dist/src/agent/embedded/session-tool-result-guard.js +2 -1
- package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
- package/dist/src/agent/embedded/tool-result-truncation.js +2 -1
- package/dist/src/agent/embedded/tool-result-truncation.js.map +1 -1
- package/dist/src/agent/fallback/candidates.js +2 -2
- package/dist/src/agent/fallback/candidates.js.map +1 -1
- package/dist/src/agent/goals/persistent-goal-apis.d.ts +0 -2
- package/dist/src/agent/goals/persistent-goal-service.js +0 -1
- package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
- package/dist/src/agent/image/generation/normalization.js +2 -12
- package/dist/src/agent/image/generation/normalization.js.map +1 -1
- package/dist/src/agent/image/generation/provider-registry.d.ts +4 -8
- package/dist/src/agent/image/generation/provider-registry.js.map +1 -1
- package/dist/src/agent/image/generation/runtime.d.ts +2 -2
- package/dist/src/agent/image/generation/runtime.js.map +1 -1
- package/dist/src/agent/image/generation/types.d.ts +0 -18
- package/dist/src/agent/image/image-helpers.js +6 -1
- package/dist/src/agent/image/image-helpers.js.map +1 -1
- package/dist/src/agent/image/index.d.ts +1 -1
- package/dist/src/agent/inbound/inbound-loop.d.ts +5 -0
- package/dist/src/agent/inbound/inbound-loop.js +41 -10
- package/dist/src/agent/inbound/inbound-loop.js.map +1 -1
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +4 -0
- package/dist/src/agent/inbound/turn-dispatcher.js +6 -4
- package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +2 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-names.js +2 -1
- package/dist/src/agent/mcp/bundle-mcp-names.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +2 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
- package/dist/src/agent/mcp/mcp-transport-config.js +2 -1
- package/dist/src/agent/mcp/mcp-transport-config.js.map +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +2 -1
- package/dist/src/agent/mcp/mcp-transport.js.map +1 -1
- package/dist/src/agent/media-generation/runtime-shared.js +2 -9
- package/dist/src/agent/media-generation/runtime-shared.js.map +1 -1
- package/dist/src/agent/messaging/command-handler.d.ts +6 -0
- package/dist/src/agent/messaging/command-handler.js +5 -0
- package/dist/src/agent/messaging/command-handler.js.map +1 -1
- package/dist/src/agent/prompt/safety.d.ts +0 -7
- package/dist/src/agent/prompt/safety.js +1 -20
- package/dist/src/agent/prompt/safety.js.map +1 -1
- package/dist/src/agent/service/build-direct-message-content.js +1 -1
- package/dist/src/agent/service/build-direct-message-content.js.map +1 -1
- package/dist/src/agent/service/direct-turn-helpers.d.ts +3 -1
- package/dist/src/agent/service/direct-turn-helpers.js +6 -1
- package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
- package/dist/src/agent/service/process-direct-one-shot.d.ts +4 -0
- package/dist/src/agent/service/process-direct-one-shot.js +15 -2
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.d.ts +4 -0
- package/dist/src/agent/service/process-direct-streaming.js +34 -4
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service/webchat-tts.js +1 -1
- package/dist/src/agent/service/webchat-tts.js.map +1 -1
- package/dist/src/agent/service.d.ts +8 -0
- package/dist/src/agent/service.js +21 -1
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/tools/create-share-tool.js +27 -20
- package/dist/src/agent/tools/create-share-tool.js.map +1 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/index.d.ts +0 -1
- package/dist/src/agent/tools/index.js +4 -5
- package/dist/src/agent/tools/shell.js +0 -13
- package/dist/src/agent/tools/shell.js.map +1 -1
- package/dist/src/agent/tools/workflow-tool.js +7 -1
- package/dist/src/agent/tools/workflow-tool.js.map +1 -1
- package/dist/src/agent/workflow/channel-capability.d.ts +3 -3
- package/dist/src/agent/workflow/lint.d.ts +38 -0
- package/dist/src/agent/workflow/lint.js +74 -0
- package/dist/src/agent/workflow/lint.js.map +1 -0
- package/dist/src/agent/workflow/parser.js +4 -1
- package/dist/src/agent/workflow/parser.js.map +1 -1
- package/dist/src/agent/workflow/runtime.d.ts +3 -0
- package/dist/src/agent/workflow/runtime.js +76 -3
- package/dist/src/agent/workflow/runtime.js.map +1 -1
- package/dist/src/agent/workflow/types.d.ts +3 -1
- package/dist/src/browser/index.js +4 -4
- package/dist/src/browser/manager.d.ts +1 -3
- package/dist/src/browser/manager.js +0 -6
- package/dist/src/browser/manager.js.map +1 -1
- package/dist/src/browser/providers/browser-ext-install.d.ts +4 -4
- package/dist/src/browser/providers/browser-ext-install.js +38 -85
- package/dist/src/browser/providers/browser-ext-install.js.map +1 -1
- package/dist/src/browser/providers/cloakbrowser.d.ts +0 -5
- package/dist/src/browser/providers/cloakbrowser.js +2 -55
- package/dist/src/browser/providers/cloakbrowser.js.map +1 -1
- package/dist/src/channels/attachments/voice-stt-webchat.js +10 -8
- package/dist/src/channels/attachments/voice-stt-webchat.js.map +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +9 -9
- package/dist/src/channels/pairing/allow-from-file.js.map +1 -1
- package/dist/src/channels/pairing/pairing-store.js +6 -6
- package/dist/src/channels/pairing/pairing-store.js.map +1 -1
- package/dist/src/chat-commands/builtins/session.js +1 -1
- package/dist/src/chat-commands/builtins/session.js.map +1 -1
- package/dist/src/chat-commands/builtins/tts.js +2 -2
- package/dist/src/chat-commands/builtins/tts.js.map +1 -1
- package/dist/src/chat-commands/context.d.ts +3 -0
- package/dist/src/chat-commands/context.js +21 -3
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/chat-commands/session-key.d.ts +4 -37
- package/dist/src/chat-commands/session-key.js +49 -85
- package/dist/src/chat-commands/session-key.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +2 -0
- package/dist/src/cli/commands/agent/interactive.js +2 -2
- package/dist/src/cli/commands/agent/interactive.js.map +1 -1
- package/dist/src/cli/commands/agent/sessions.js +2 -2
- package/dist/src/cli/commands/agent/sessions.js.map +1 -1
- package/dist/src/cli/commands/agent.js +4 -5
- package/dist/src/cli/commands/agent.js.map +1 -1
- package/dist/src/cli/commands/channels.js +1 -5
- package/dist/src/cli/commands/channels.js.map +1 -1
- package/dist/src/cli/commands/gateway/lifecycle-core.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle-core.js.map +1 -1
- package/dist/src/cli/commands/gateway/logs.d.ts +9 -0
- package/dist/src/cli/commands/gateway/logs.js +50 -17
- package/dist/src/cli/commands/gateway/logs.js.map +1 -1
- package/dist/src/cli/commands/image.js +22 -21
- package/dist/src/cli/commands/image.js.map +1 -1
- package/dist/src/cli/commands/session/utils.js +2 -2
- package/dist/src/cli/commands/session/utils.js.map +1 -1
- package/dist/src/cli/commands/update.js +26 -46
- package/dist/src/cli/commands/update.js.map +1 -1
- package/dist/src/cli/utils/session.d.ts +0 -5
- package/dist/src/cli/utils/session.js +1 -6
- package/dist/src/cli/utils/session.js.map +1 -1
- package/dist/src/commands/agents.config.js +1 -1
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/agent-profile.js +5 -27
- package/dist/src/config/agent-profile.js.map +1 -1
- package/dist/src/config/index.js +2 -2
- package/dist/src/config/model-input.js +2 -5
- package/dist/src/config/model-input.js.map +1 -1
- package/dist/src/config/schema.d.ts +201 -217
- package/dist/src/config/schema.js +54 -39
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/workspace-path-helpers.d.ts +1 -2
- package/dist/src/config/workspace-path-helpers.js.map +1 -1
- package/dist/src/daemon/install-plan.js +25 -1
- package/dist/src/daemon/install-plan.js.map +1 -1
- package/dist/src/daemon/launchd.d.ts +8 -0
- package/dist/src/daemon/launchd.js +5 -12
- package/dist/src/daemon/launchd.js.map +1 -1
- package/dist/src/daemon/schtasks.d.ts +25 -0
- package/dist/src/daemon/schtasks.js +166 -46
- package/dist/src/daemon/schtasks.js.map +1 -1
- package/dist/src/daemon/service.js +5 -4
- package/dist/src/daemon/service.js.map +1 -1
- package/dist/src/daemon/systemd.d.ts +6 -0
- package/dist/src/daemon/systemd.js +18 -3
- package/dist/src/daemon/systemd.js.map +1 -1
- package/dist/src/extensions/activation-context.js +0 -1
- package/dist/src/extensions/activation-context.js.map +1 -1
- package/dist/src/extensions/normalize-manifest.js +0 -1
- package/dist/src/extensions/normalize-manifest.js.map +1 -1
- package/dist/src/extensions/types/manifest.d.ts +0 -2
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/agent-builtin-tools.js +1 -0
- package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
- package/dist/src/gateway/agents-admin.js +10 -2
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/heartbeat/service.js +2 -2
- package/dist/src/gateway/heartbeat/service.js.map +1 -1
- package/dist/src/gateway/hono/app.js +1 -1
- package/dist/src/gateway/hono/lib/agent-model.d.ts +18 -10
- package/dist/src/gateway/hono/lib/agent-model.js +24 -35
- package/dist/src/gateway/hono/lib/agent-model.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/lib/safe-voice-config.js +14 -53
- package/dist/src/gateway/hono/lib/safe-voice-config.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/agents.js +17 -5
- package/dist/src/gateway/hono/routes/config-patch/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/channels.js +0 -11
- package/dist/src/gateway/hono/routes/config-patch/channels.js.map +1 -1
- package/dist/src/gateway/hono/routes/goals.js +1 -1
- package/dist/src/gateway/hono/routes/goals.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +28 -7
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/shares.js +14 -12
- package/dist/src/gateway/hono/routes/shares.js.map +1 -1
- package/dist/src/gateway/hono/routes/tunnel.js +1 -1
- package/dist/src/gateway/hono/routes/update.js +4 -2
- package/dist/src/gateway/hono/routes/update.js.map +1 -1
- package/dist/src/gateway/hono/sse.js +16 -33
- package/dist/src/gateway/hono/sse.js.map +1 -1
- package/dist/src/gateway/lock.js +10 -10
- package/dist/src/gateway/lock.js.map +1 -1
- package/dist/src/gateway/ports.js +6 -6
- package/dist/src/gateway/ports.js.map +1 -1
- package/dist/src/gateway/resolve-webchat-session-key.d.ts +19 -0
- package/dist/src/gateway/resolve-webchat-session-key.js +46 -0
- package/dist/src/gateway/resolve-webchat-session-key.js.map +1 -0
- package/dist/src/gateway/service/run-gateway-agent.js +27 -11
- package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
- package/dist/src/gateway/service/sessions-api.d.ts +3 -0
- package/dist/src/gateway/service/sessions-api.js +8 -0
- package/dist/src/gateway/service/sessions-api.js.map +1 -1
- package/dist/src/gateway/service.d.ts +0 -2
- package/dist/src/gateway/service.js +2 -7
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/session-reset-service.d.ts +20 -0
- package/dist/src/gateway/session-reset-service.js +54 -0
- package/dist/src/gateway/session-reset-service.js.map +1 -0
- package/dist/src/gateway/startup-readiness.d.ts +1 -1
- package/dist/src/gateway/startup-readiness.js +1 -0
- package/dist/src/gateway/startup-readiness.js.map +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/gateway-processes.js +2 -2
- package/dist/src/infra/gateway-processes.js.map +1 -1
- package/dist/src/infra/run-command.d.ts +16 -0
- package/dist/src/infra/run-command.js +67 -0
- package/dist/src/infra/run-command.js.map +1 -0
- package/dist/src/infra/update-global.d.ts +45 -0
- package/dist/src/infra/update-global.js +224 -0
- package/dist/src/infra/update-global.js.map +1 -0
- package/dist/src/mcp/channel-bridge.js +1 -1
- package/dist/src/mcp/channel-shared.js +2 -1
- package/dist/src/mcp/channel-shared.js.map +1 -1
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/auth-runtime/auth-profile-store.js.map +1 -1
- package/dist/src/providers/auth-runtime/resolve-auth.js +1 -12
- package/dist/src/providers/auth-runtime/resolve-auth.js.map +1 -1
- package/dist/src/providers/auth-runtime/types.d.ts +6 -12
- package/dist/src/routing/agent-session-key.d.ts +58 -0
- package/dist/src/routing/agent-session-key.js +164 -0
- package/dist/src/routing/agent-session-key.js.map +1 -0
- package/dist/src/routing/index.d.ts +1 -1
- package/dist/src/routing/index.js +4 -2
- package/dist/src/routing/index.js.map +1 -1
- package/dist/src/routing/resolve-route.d.ts +15 -0
- package/dist/src/routing/resolve-route.js +41 -20
- package/dist/src/routing/resolve-route.js.map +1 -1
- package/dist/src/routing/resolve-tui-session-key.d.ts +25 -0
- package/dist/src/routing/resolve-tui-session-key.js +54 -0
- package/dist/src/routing/resolve-tui-session-key.js.map +1 -0
- package/dist/src/routing/session-key-utils.d.ts +24 -0
- package/dist/src/routing/session-key-utils.js +92 -0
- package/dist/src/routing/session-key-utils.js.map +1 -0
- package/dist/src/routing/session-key.d.ts +19 -49
- package/dist/src/routing/session-key.js +143 -116
- package/dist/src/routing/session-key.js.map +1 -1
- package/dist/src/session/index.d.ts +6 -0
- package/dist/src/session/index.js +7 -1
- package/dist/src/session/init-session-turn.d.ts +30 -0
- package/dist/src/session/init-session-turn.js +102 -0
- package/dist/src/session/init-session-turn.js.map +1 -0
- package/dist/src/session/lifecycle-timestamps.d.ts +8 -0
- package/dist/src/session/lifecycle-timestamps.js +16 -0
- package/dist/src/session/lifecycle-timestamps.js.map +1 -0
- package/dist/src/session/manager.d.ts +7 -1
- package/dist/src/session/manager.js +8 -1
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/parity/transcript-paths.js +2 -2
- package/dist/src/session/parity/transcript-paths.js.map +1 -1
- package/dist/src/session/parity/xopc-session-disk-entry.d.ts +6 -0
- package/dist/src/session/reset-policy.d.ts +32 -0
- package/dist/src/session/reset-policy.js +65 -0
- package/dist/src/session/reset-policy.js.map +1 -0
- package/dist/src/session/reset-triggers.d.ts +20 -0
- package/dist/src/session/reset-triggers.js +63 -0
- package/dist/src/session/reset-triggers.js.map +1 -0
- package/dist/src/session/reset-type.d.ts +12 -0
- package/dist/src/session/reset-type.js +25 -0
- package/dist/src/session/reset-type.js.map +1 -0
- package/dist/src/session/resolve-session.d.ts +30 -0
- package/dist/src/session/resolve-session.js +93 -0
- package/dist/src/session/resolve-session.js.map +1 -0
- package/dist/src/session/session-title.js +3 -2
- package/dist/src/session/session-title.js.map +1 -1
- package/dist/src/session/store.d.ts +11 -4
- package/dist/src/session/store.js +57 -6
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/transcript-events.js +2 -1
- package/dist/src/session/transcript-events.js.map +1 -1
- package/dist/src/share/share-url.d.ts +33 -0
- package/dist/src/share/share-url.js +56 -14
- package/dist/src/share/share-url.js.map +1 -1
- package/dist/src/tui/backends/embedded-backend.js +4 -9
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.js +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/components/chat-log.js +3 -3
- package/dist/src/tui/components/chat-log.js.map +1 -1
- package/dist/src/tui/theme.d.ts +0 -2
- package/dist/src/tui/theme.js +1 -3
- package/dist/src/tui/theme.js.map +1 -1
- package/dist/src/tui/tui-commands.d.ts +3 -0
- package/dist/src/tui/tui-commands.js +45 -10
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-keybindings-file.js +1 -21
- package/dist/src/tui/tui-keybindings-file.js.map +1 -1
- package/dist/src/tui/tui-session-actions.d.ts +28 -0
- package/dist/src/tui/tui-session-actions.js +88 -0
- package/dist/src/tui/tui-session-actions.js.map +1 -0
- package/dist/src/tui/tui.js +52 -47
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/utils/string-coerce.d.ts +2 -0
- package/dist/src/utils/string-coerce.js +10 -1
- package/dist/src/utils/string-coerce.js.map +1 -1
- package/dist/src/voice/stt/config-slice.d.ts +2 -5
- package/dist/src/voice/stt/config-slice.js +5 -26
- package/dist/src/voice/stt/config-slice.js.map +1 -1
- package/dist/src/voice/stt/types.d.ts +1 -18
- package/dist/src/voice/stt/types.js +4 -2
- package/dist/src/voice/stt/types.js.map +1 -1
- package/dist/src/voice/tts/config-slice.d.ts +3 -7
- package/dist/src/voice/tts/config-slice.js +7 -38
- package/dist/src/voice/tts/config-slice.js.map +1 -1
- package/dist/src/voice/tts/merge-config.js +2 -48
- package/dist/src/voice/tts/merge-config.js.map +1 -1
- package/dist/src/voice/tts/providers/alibaba-speech.js +1 -1
- package/dist/src/voice/tts/providers/alibaba-speech.js.map +1 -1
- package/dist/src/voice/tts/types.d.ts +1 -29
- package/dist/src/voice/tts/types.js +19 -17
- package/dist/src/voice/tts/types.js.map +1 -1
- package/package.json +1 -4
- package/dist/gateway/static/root/assets/index-ew_2L2We.css +0 -1
- package/dist/gateway/static/root/assets/url-BwNL6Rgk.js +0 -3
- package/dist/src/agent/tools/browser-legacy-tools.d.ts +0 -17
- package/dist/src/agent/tools/browser-legacy-tools.js +0 -766
- package/dist/src/agent/tools/browser-legacy-tools.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-slice.js","names":[],"sources":["../../../../src/voice/stt/config-slice.ts"],"sourcesContent":["/**\n * STT config slice resolution — maps persisted config to per-provider raw config.\n *\n *
|
|
1
|
+
{"version":3,"file":"config-slice.js","names":[],"sources":["../../../../src/voice/stt/config-slice.ts"],"sourcesContent":["/**\n * STT config slice resolution — maps persisted config to per-provider raw config.\n *\n * Reads `tools.media.audio.providers.<id>` only — there is no legacy flat-key form.\n */\n\nimport type { STTConfig } from './types.js';\n\n/** Built-in env fallbacks when config slice has no apiKey. */\nexport const STT_LEGACY_ENV_KEYS: Record<string, string> = {\n openai: 'OPENAI_API_KEY',\n alibaba: 'DASHSCOPE_API_KEY',\n};\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** Collect provider-id → raw config entries from the `providers` map. */\nexport function collectSttProviderConfigEntries(\n config: Partial<STTConfig> | Record<string, unknown> | undefined,\n): Record<string, Record<string, unknown>> {\n const raw = (config ?? {}) as Record<string, unknown>;\n const providers = asRecord(raw.providers);\n if (!providers) return {};\n const entries: Record<string, Record<string, unknown>> = {};\n for (const [providerId, value] of Object.entries(providers)) {\n entries[providerId] = { ...(asRecord(value) ?? {}) };\n }\n return entries;\n}\n\n/** Resolve the raw config slice for one provider id. */\nexport function resolveSttProviderConfigSlice(\n providerId: string,\n config: Partial<STTConfig> | Record<string, unknown> | undefined,\n): Record<string, unknown> {\n return collectSttProviderConfigEntries(config)[providerId] ?? {};\n}\n\nfunction trimToUndefined(value: unknown): string | undefined {\n if (typeof value !== 'string') {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction readStringRecord(value: unknown): Record<string, string> | undefined {\n const record = asRecord(value);\n if (!record) {\n return undefined;\n }\n const out: Record<string, string> = {};\n for (const [key, entry] of Object.entries(record)) {\n const text = trimToUndefined(entry);\n if (text) {\n out[key] = text;\n }\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\n/** Read normalized provider fields from a config slice or model entry override. */\nexport function readSttProviderFields(\n slice: Record<string, unknown>,\n entryOverride?: Record<string, unknown>,\n): {\n apiKey?: string;\n model?: string;\n baseUrl?: string;\n headers?: Record<string, string>;\n language?: string;\n prompt?: string;\n} {\n const merged = { ...slice, ...(entryOverride ?? {}) };\n return {\n apiKey: trimToUndefined(merged.apiKey),\n model: trimToUndefined(merged.model),\n baseUrl: trimToUndefined(merged.baseUrl),\n headers: readStringRecord(merged.headers),\n language: trimToUndefined(merged.language),\n prompt: trimToUndefined(merged.prompt),\n };\n}\n"],"mappings":";;AASA,MAAa,sBAA8C;CACzD,QAAQ;CACR,SAAS;CACV;AAED,SAAS,SAAS,OAAqD;AACrE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM,GACtE,QACD,KAAA;;;AAIN,SAAgB,gCACd,QACyC;CAEzC,MAAM,YAAY,UADL,UAAU,EAAE,EACM,UAAU;AACzC,KAAI,CAAC,UAAW,QAAO,EAAE;CACzB,MAAM,UAAmD,EAAE;AAC3D,MAAK,MAAM,CAAC,YAAY,UAAU,OAAO,QAAQ,UAAU,CACzD,SAAQ,cAAc,EAAE,GAAI,SAAS,MAAM,IAAI,EAAE,EAAG;AAEtD,QAAO;;;AAIT,SAAgB,8BACd,YACA,QACyB;AACzB,QAAO,gCAAgC,OAAO,CAAC,eAAe,EAAE;;AAGlE,SAAS,gBAAgB,OAAoC;AAC3D,KAAI,OAAO,UAAU,SACnB;CAEF,MAAM,UAAU,MAAM,MAAM;AAC5B,QAAO,QAAQ,SAAS,IAAI,UAAU,KAAA;;AAGxC,SAAS,iBAAiB,OAAoD;CAC5E,MAAM,SAAS,SAAS,MAAM;AAC9B,KAAI,CAAC,OACH;CAEF,MAAM,MAA8B,EAAE;AACtC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,EAAE;EACjD,MAAM,OAAO,gBAAgB,MAAM;AACnC,MAAI,KACF,KAAI,OAAO;;AAGf,QAAO,OAAO,KAAK,IAAI,CAAC,SAAS,IAAI,MAAM,KAAA;;;AAI7C,SAAgB,sBACd,OACA,eAQA;CACA,MAAM,SAAS;EAAE,GAAG;EAAO,GAAI,iBAAiB,EAAE;EAAG;AACrD,QAAO;EACL,QAAQ,gBAAgB,OAAO,OAAO;EACtC,OAAO,gBAAgB,OAAO,MAAM;EACpC,SAAS,gBAAgB,OAAO,QAAQ;EACxC,SAAS,iBAAiB,OAAO,QAAQ;EACzC,UAAU,gBAAgB,OAAO,SAAS;EAC1C,QAAQ,gBAAgB,OAAO,OAAO;EACvC"}
|
|
@@ -27,27 +27,11 @@ import type { MediaUnderstandingModelEntry } from '../../media-understanding/typ
|
|
|
27
27
|
export interface STTConfig {
|
|
28
28
|
enabled: boolean;
|
|
29
29
|
provider: string;
|
|
30
|
-
alibaba?: {
|
|
31
|
-
apiKey?: string;
|
|
32
|
-
model?: string;
|
|
33
|
-
baseUrl?: string;
|
|
34
|
-
headers?: Record<string, string>;
|
|
35
|
-
language?: string;
|
|
36
|
-
prompt?: string;
|
|
37
|
-
};
|
|
38
|
-
openai?: {
|
|
39
|
-
apiKey?: string;
|
|
40
|
-
model?: string;
|
|
41
|
-
baseUrl?: string;
|
|
42
|
-
headers?: Record<string, string>;
|
|
43
|
-
language?: string;
|
|
44
|
-
prompt?: string;
|
|
45
|
-
};
|
|
46
30
|
/** Capability-local model chain (`tools.media.audio.models`). */
|
|
47
31
|
models?: MediaUnderstandingModelEntry[];
|
|
48
32
|
/** Shared model entries merged from `tools.media.models` at runtime. */
|
|
49
33
|
sharedModels?: MediaUnderstandingModelEntry[];
|
|
50
|
-
/**
|
|
34
|
+
/** Provider settings map (`tools.media.audio.providers.<id>`). */
|
|
51
35
|
providers?: Record<string, Record<string, unknown>>;
|
|
52
36
|
fallback?: {
|
|
53
37
|
enabled: boolean;
|
|
@@ -55,7 +39,6 @@ export interface STTConfig {
|
|
|
55
39
|
};
|
|
56
40
|
/** Hard timeout per provider call (ms). Default 60s. */
|
|
57
41
|
timeoutMs?: number;
|
|
58
|
-
[key: string]: unknown;
|
|
59
42
|
}
|
|
60
43
|
export type STTProviderAttemptOutcome = 'success' | 'skipped' | 'failed';
|
|
61
44
|
export type STTProviderFailureReason = 'success' | 'not_configured' | 'timeout' | 'provider_error' | 'unsupported_format' | 'unknown';
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
const DEFAULT_STT_CONFIG = {
|
|
3
3
|
enabled: false,
|
|
4
4
|
provider: "alibaba",
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
providers: {
|
|
6
|
+
alibaba: { model: "paraformer-v2" },
|
|
7
|
+
openai: { model: "whisper-1" }
|
|
8
|
+
},
|
|
7
9
|
fallback: {
|
|
8
10
|
enabled: true,
|
|
9
11
|
order: ["alibaba", "openai"]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../../../src/voice/stt/types.ts"],"sourcesContent":["/**\n * STT public types — data shapes consumed by downstream code (channels,\n * schema validation, gateway payloads).\n *\n * Provider implementations live behind `MediaUnderstandingProvider.transcribeAudio`\n * (see src/media-understanding/types.ts).\n */\n\nexport interface STTResult {\n /** Transcribed text. */\n text: string;\n /** Provider that performed the transcription (e.g. \"alibaba\", \"openai\"). */\n provider: string;\n /** Audio duration in seconds (if reported). */\n duration?: number;\n /** Detected language (if reported). */\n language?: string;\n}\n\nexport interface STTOptions {\n /** Language hint (e.g. 'zh', 'en'). */\n language?: string;\n /** Model id (provider-specific). */\n model?: string;\n}\n\nexport type { MediaUnderstandingModelEntry } from '../../media-understanding/types.js';\nimport type { MediaUnderstandingModelEntry } from '../../media-understanding/types.js';\n\n/** STTConfig consumed by the schema and downstream wiring. */\nexport interface STTConfig {\n enabled: boolean;\n provider: string;\n
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../../../src/voice/stt/types.ts"],"sourcesContent":["/**\n * STT public types — data shapes consumed by downstream code (channels,\n * schema validation, gateway payloads).\n *\n * Provider implementations live behind `MediaUnderstandingProvider.transcribeAudio`\n * (see src/media-understanding/types.ts).\n */\n\nexport interface STTResult {\n /** Transcribed text. */\n text: string;\n /** Provider that performed the transcription (e.g. \"alibaba\", \"openai\"). */\n provider: string;\n /** Audio duration in seconds (if reported). */\n duration?: number;\n /** Detected language (if reported). */\n language?: string;\n}\n\nexport interface STTOptions {\n /** Language hint (e.g. 'zh', 'en'). */\n language?: string;\n /** Model id (provider-specific). */\n model?: string;\n}\n\nexport type { MediaUnderstandingModelEntry } from '../../media-understanding/types.js';\nimport type { MediaUnderstandingModelEntry } from '../../media-understanding/types.js';\n\n/** STTConfig consumed by the schema and downstream wiring. */\nexport interface STTConfig {\n enabled: boolean;\n provider: string;\n /** Capability-local model chain (`tools.media.audio.models`). */\n models?: MediaUnderstandingModelEntry[];\n /** Shared model entries merged from `tools.media.models` at runtime. */\n sharedModels?: MediaUnderstandingModelEntry[];\n /** Provider settings map (`tools.media.audio.providers.<id>`). */\n providers?: Record<string, Record<string, unknown>>;\n fallback?: {\n enabled: boolean;\n order: string[];\n };\n /** Hard timeout per provider call (ms). Default 60s. */\n timeoutMs?: number;\n}\n\nexport type STTProviderAttemptOutcome = 'success' | 'skipped' | 'failed';\n\nexport type STTProviderFailureReason =\n | 'success'\n | 'not_configured'\n | 'timeout'\n | 'provider_error'\n | 'unsupported_format'\n | 'unknown';\n\nexport interface STTProviderAttempt {\n provider: string;\n outcome: STTProviderAttemptOutcome;\n reasonCode: STTProviderFailureReason;\n latencyMs: number;\n error?: string;\n}\n\nexport interface STTResultWithTracking extends STTResult {\n attempts: STTProviderAttempt[];\n fallbackFrom?: string;\n attemptedProviders: string[];\n}\n\nexport const DEFAULT_STT_CONFIG: STTConfig = {\n enabled: false,\n provider: 'alibaba',\n providers: {\n alibaba: { model: 'paraformer-v2' },\n openai: { model: 'whisper-1' },\n },\n fallback: {\n enabled: true,\n order: ['alibaba', 'openai'],\n },\n timeoutMs: 60_000,\n};\n"],"mappings":";AAuEA,MAAa,qBAAgC;CAC3C,SAAS;CACT,UAAU;CACV,WAAW;EACT,SAAS,EAAE,OAAO,iBAAiB;EACnC,QAAQ,EAAE,OAAO,aAAa;EAC/B;CACD,UAAU;EACR,SAAS;EACT,OAAO,CAAC,WAAW,SAAS;EAC7B;CACD,WAAW;CACZ"}
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TTS config slice resolution — maps persisted config to per-provider raw config.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* (`messages.tts.openai`, `messages.tts.tts-local-cli`, …).
|
|
4
|
+
* Reads `messages.tts.providers.<id>` only — there is no legacy flat-key form.
|
|
6
5
|
*/
|
|
7
6
|
import type { TTSConfig } from './types.js';
|
|
8
|
-
/**
|
|
9
|
-
export declare const TTS_CONFIG_RESERVED_KEYS: Set<string>;
|
|
10
|
-
/** Collect provider-id → raw config entries from providers map + legacy flat keys. */
|
|
7
|
+
/** Collect provider-id → raw config entries from the `providers` map. */
|
|
11
8
|
export declare function collectTtsProviderConfigEntries(config: Partial<TTSConfig> | Record<string, unknown> | undefined): Record<string, Record<string, unknown>>;
|
|
12
9
|
/** Resolve the raw config slice for one provider id. */
|
|
13
10
|
export declare function resolveTtsProviderConfigSlice(providerId: string, config: Partial<TTSConfig> | Record<string, unknown> | undefined): Record<string, unknown>;
|
|
14
11
|
/**
|
|
15
12
|
* Build the `rawConfig` object passed into `SpeechProviderPlugin.resolveConfig`.
|
|
16
|
-
* Includes the full TTS block
|
|
17
|
-
* for the active provider (matches built-in `rawConfig[id] ?? rawConfig` reads).
|
|
13
|
+
* Includes the full TTS block plus a normalized `providers` map.
|
|
18
14
|
*/
|
|
19
15
|
export declare function buildTtsResolveRawConfig(providerId: string, config: Partial<TTSConfig> | Record<string, unknown>): Record<string, unknown>;
|
|
@@ -1,42 +1,13 @@
|
|
|
1
1
|
//#region src/voice/tts/config-slice.ts
|
|
2
|
-
/** Top-level `messages.tts` keys that are not provider config buckets. */
|
|
3
|
-
const TTS_CONFIG_RESERVED_KEYS = new Set([
|
|
4
|
-
"auto",
|
|
5
|
-
"enabled",
|
|
6
|
-
"maxTextLength",
|
|
7
|
-
"mode",
|
|
8
|
-
"modelOverrides",
|
|
9
|
-
"persona",
|
|
10
|
-
"personas",
|
|
11
|
-
"prefsPath",
|
|
12
|
-
"provider",
|
|
13
|
-
"providers",
|
|
14
|
-
"summaryModel",
|
|
15
|
-
"timeoutMs",
|
|
16
|
-
"trigger",
|
|
17
|
-
"fallback",
|
|
18
|
-
"summarization"
|
|
19
|
-
]);
|
|
20
2
|
function asRecord(value) {
|
|
21
3
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
22
4
|
}
|
|
23
|
-
|
|
24
|
-
return asRecord(value) ?? {};
|
|
25
|
-
}
|
|
26
|
-
/** Collect provider-id → raw config entries from providers map + legacy flat keys. */
|
|
5
|
+
/** Collect provider-id → raw config entries from the `providers` map. */
|
|
27
6
|
function collectTtsProviderConfigEntries(config) {
|
|
28
|
-
const
|
|
7
|
+
const providers = asRecord((config ?? {}).providers);
|
|
8
|
+
if (!providers) return {};
|
|
29
9
|
const entries = {};
|
|
30
|
-
const providers = asRecord(
|
|
31
|
-
if (providers) for (const [providerId, value] of Object.entries(providers)) entries[providerId] = {
|
|
32
|
-
...entries[providerId],
|
|
33
|
-
...asProviderConfig(value)
|
|
34
|
-
};
|
|
35
|
-
for (const [key, value] of Object.entries(raw)) {
|
|
36
|
-
if (TTS_CONFIG_RESERVED_KEYS.has(key)) continue;
|
|
37
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) continue;
|
|
38
|
-
if (entries[key] === void 0) entries[key] = asProviderConfig(value);
|
|
39
|
-
}
|
|
10
|
+
for (const [providerId, value] of Object.entries(providers)) entries[providerId] = { ...asRecord(value) ?? {} };
|
|
40
11
|
return entries;
|
|
41
12
|
}
|
|
42
13
|
/** Resolve the raw config slice for one provider id. */
|
|
@@ -45,19 +16,17 @@ function resolveTtsProviderConfigSlice(providerId, config) {
|
|
|
45
16
|
}
|
|
46
17
|
/**
|
|
47
18
|
* Build the `rawConfig` object passed into `SpeechProviderPlugin.resolveConfig`.
|
|
48
|
-
* Includes the full TTS block
|
|
49
|
-
* for the active provider (matches built-in `rawConfig[id] ?? rawConfig` reads).
|
|
19
|
+
* Includes the full TTS block plus a normalized `providers` map.
|
|
50
20
|
*/
|
|
51
21
|
function buildTtsResolveRawConfig(providerId, config) {
|
|
52
22
|
const entries = collectTtsProviderConfigEntries(config);
|
|
53
|
-
const slice = entries[providerId] ?? {};
|
|
54
23
|
return {
|
|
55
24
|
...config,
|
|
56
25
|
providers: entries,
|
|
57
|
-
[providerId]:
|
|
26
|
+
[providerId]: entries[providerId] ?? {}
|
|
58
27
|
};
|
|
59
28
|
}
|
|
60
29
|
//#endregion
|
|
61
|
-
export {
|
|
30
|
+
export { buildTtsResolveRawConfig, collectTtsProviderConfigEntries, resolveTtsProviderConfigSlice };
|
|
62
31
|
|
|
63
32
|
//# sourceMappingURL=config-slice.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-slice.js","names":[],"sources":["../../../../src/voice/tts/config-slice.ts"],"sourcesContent":["/**\n * TTS config slice resolution — maps persisted config to per-provider raw config.\n *\n *
|
|
1
|
+
{"version":3,"file":"config-slice.js","names":[],"sources":["../../../../src/voice/tts/config-slice.ts"],"sourcesContent":["/**\n * TTS config slice resolution — maps persisted config to per-provider raw config.\n *\n * Reads `messages.tts.providers.<id>` only — there is no legacy flat-key form.\n */\n\nimport type { TTSConfig } from './types.js';\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** Collect provider-id → raw config entries from the `providers` map. */\nexport function collectTtsProviderConfigEntries(\n config: Partial<TTSConfig> | Record<string, unknown> | undefined,\n): Record<string, Record<string, unknown>> {\n const raw = (config ?? {}) as Record<string, unknown>;\n const providers = asRecord(raw.providers);\n if (!providers) return {};\n const entries: Record<string, Record<string, unknown>> = {};\n for (const [providerId, value] of Object.entries(providers)) {\n entries[providerId] = { ...(asRecord(value) ?? {}) };\n }\n return entries;\n}\n\n/** Resolve the raw config slice for one provider id. */\nexport function resolveTtsProviderConfigSlice(\n providerId: string,\n config: Partial<TTSConfig> | Record<string, unknown> | undefined,\n): Record<string, unknown> {\n return collectTtsProviderConfigEntries(config)[providerId] ?? {};\n}\n\n/**\n * Build the `rawConfig` object passed into `SpeechProviderPlugin.resolveConfig`.\n * Includes the full TTS block plus a normalized `providers` map.\n */\nexport function buildTtsResolveRawConfig(\n providerId: string,\n config: Partial<TTSConfig> | Record<string, unknown>,\n): Record<string, unknown> {\n const entries = collectTtsProviderConfigEntries(config);\n return {\n ...(config as Record<string, unknown>),\n providers: entries,\n [providerId]: entries[providerId] ?? {},\n };\n}\n"],"mappings":";AAQA,SAAS,SAAS,OAAqD;AACrE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM,GACtE,QACD,KAAA;;;AAIN,SAAgB,gCACd,QACyC;CAEzC,MAAM,YAAY,UADL,UAAU,EAAE,EACM,UAAU;AACzC,KAAI,CAAC,UAAW,QAAO,EAAE;CACzB,MAAM,UAAmD,EAAE;AAC3D,MAAK,MAAM,CAAC,YAAY,UAAU,OAAO,QAAQ,UAAU,CACzD,SAAQ,cAAc,EAAE,GAAI,SAAS,MAAM,IAAI,EAAE,EAAG;AAEtD,QAAO;;;AAIT,SAAgB,8BACd,YACA,QACyB;AACzB,QAAO,gCAAgC,OAAO,CAAC,eAAe,EAAE;;;;;;AAOlE,SAAgB,yBACd,YACA,QACyB;CACzB,MAAM,UAAU,gCAAgC,OAAO;AACvD,QAAO;EACL,GAAI;EACJ,WAAW;GACV,aAAa,QAAQ,eAAe,EAAE;EACxC"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { TTS_CONFIG_RESERVED_KEYS, collectTtsProviderConfigEntries } from "./config-slice.js";
|
|
2
1
|
import { isTTSAvailable } from "./factory.js";
|
|
3
2
|
import { DEFAULT_TTS_CONFIG } from "./types.js";
|
|
4
3
|
//#region src/voice/tts/merge-config.ts
|
|
@@ -23,51 +22,9 @@ function mergeProviderEntries(base, patch) {
|
|
|
23
22
|
};
|
|
24
23
|
return merged;
|
|
25
24
|
}
|
|
26
|
-
function mergeKnownFlatProviderSlices(merged, patch) {
|
|
27
|
-
return {
|
|
28
|
-
...merged,
|
|
29
|
-
alibaba: {
|
|
30
|
-
...DEFAULT_TTS_CONFIG.alibaba,
|
|
31
|
-
...patch.alibaba
|
|
32
|
-
},
|
|
33
|
-
openai: {
|
|
34
|
-
...DEFAULT_TTS_CONFIG.openai,
|
|
35
|
-
...patch.openai
|
|
36
|
-
},
|
|
37
|
-
edge: {
|
|
38
|
-
...DEFAULT_TTS_CONFIG.edge,
|
|
39
|
-
...patch.edge
|
|
40
|
-
},
|
|
41
|
-
minimax: {
|
|
42
|
-
...DEFAULT_TTS_CONFIG.minimax,
|
|
43
|
-
...patch.minimax
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
function mergeExtensionFlatProviderSlices(merged, patch) {
|
|
48
|
-
const next = { ...merged };
|
|
49
|
-
for (const [key, value] of Object.entries(patch)) {
|
|
50
|
-
if (TTS_CONFIG_RESERVED_KEYS.has(key)) continue;
|
|
51
|
-
if ([
|
|
52
|
-
"alibaba",
|
|
53
|
-
"openai",
|
|
54
|
-
"edge",
|
|
55
|
-
"minimax"
|
|
56
|
-
].includes(key)) continue;
|
|
57
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) continue;
|
|
58
|
-
const existing = next[key];
|
|
59
|
-
next[key] = typeof existing === "object" && existing !== null && !Array.isArray(existing) ? {
|
|
60
|
-
...existing,
|
|
61
|
-
...value
|
|
62
|
-
} : value;
|
|
63
|
-
}
|
|
64
|
-
return next;
|
|
65
|
-
}
|
|
66
25
|
function mergeTtsConfigFromAppConfig(tts) {
|
|
67
26
|
const p = tts ?? {};
|
|
68
|
-
|
|
69
|
-
const patchEntries = collectTtsProviderConfigEntries(p);
|
|
70
|
-
let merged = {
|
|
27
|
+
return {
|
|
71
28
|
...DEFAULT_TTS_CONFIG,
|
|
72
29
|
...p,
|
|
73
30
|
enabled: p.enabled ?? DEFAULT_TTS_CONFIG.enabled,
|
|
@@ -81,15 +38,12 @@ function mergeTtsConfigFromAppConfig(tts) {
|
|
|
81
38
|
...DEFAULT_TTS_CONFIG.modelOverrides,
|
|
82
39
|
...p.modelOverrides
|
|
83
40
|
},
|
|
84
|
-
providers: mergeProviderEntries(
|
|
41
|
+
providers: mergeProviderEntries(DEFAULT_TTS_CONFIG.providers, p.providers),
|
|
85
42
|
summarization: {
|
|
86
43
|
...DEFAULT_TTS_CONFIG.summarization,
|
|
87
44
|
...p.summarization
|
|
88
45
|
}
|
|
89
46
|
};
|
|
90
|
-
merged = mergeKnownFlatProviderSlices(merged, p);
|
|
91
|
-
merged = mergeExtensionFlatProviderSlices(merged, p);
|
|
92
|
-
return merged;
|
|
93
47
|
}
|
|
94
48
|
/**
|
|
95
49
|
* User-facing hint when TTS is enabled in settings but no provider can run.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge-config.js","names":[],"sources":["../../../../src/voice/tts/merge-config.ts"],"sourcesContent":["import type { Config } from '../../config/schema.js';\nimport {
|
|
1
|
+
{"version":3,"file":"merge-config.js","names":[],"sources":["../../../../src/voice/tts/merge-config.ts"],"sourcesContent":["import type { Config } from '../../config/schema.js';\nimport { DEFAULT_TTS_CONFIG, type TTSConfig } from './types.js';\nimport { isTTSAvailable } from './factory.js';\n\n/**\n * Merge persisted app config `tts` with defaults to a full {@link TTSConfig}\n * for validation (provider chain, env-based keys, etc.).\n */\nfunction normalizeTtsTrigger(raw: unknown): TTSConfig['trigger'] {\n const t = typeof raw === 'string' ? raw.toLowerCase() : '';\n if (t === 'off' || t === 'always' || t === 'inbound' || t === 'tagged') return t;\n return DEFAULT_TTS_CONFIG.trigger;\n}\n\nfunction normalizeTtsProvider(raw: unknown): string {\n return typeof raw === 'string' && raw.trim().length > 0 ? raw.trim() : DEFAULT_TTS_CONFIG.provider;\n}\n\nfunction mergeProviderEntries(\n base: Record<string, Record<string, unknown>> | undefined,\n patch: Record<string, Record<string, unknown>> | undefined,\n): Record<string, Record<string, unknown>> | undefined {\n if (!base && !patch) {\n return undefined;\n }\n const merged: Record<string, Record<string, unknown>> = { ...(base ?? {}) };\n for (const [providerId, slice] of Object.entries(patch ?? {})) {\n merged[providerId] = { ...(merged[providerId] ?? {}), ...slice };\n }\n return merged;\n}\n\nexport function mergeTtsConfigFromAppConfig(tts: Partial<TTSConfig> | undefined): TTSConfig {\n const p = (tts ?? {}) as Partial<TTSConfig>;\n return {\n ...DEFAULT_TTS_CONFIG,\n ...p,\n enabled: p.enabled ?? DEFAULT_TTS_CONFIG.enabled,\n provider: normalizeTtsProvider(p.provider),\n trigger: normalizeTtsTrigger(p.trigger ?? DEFAULT_TTS_CONFIG.trigger),\n fallback: {\n ...DEFAULT_TTS_CONFIG.fallback!,\n ...p.fallback,\n },\n modelOverrides: {\n ...DEFAULT_TTS_CONFIG.modelOverrides!,\n ...p.modelOverrides,\n },\n providers: mergeProviderEntries(DEFAULT_TTS_CONFIG.providers, p.providers),\n summarization: {\n ...DEFAULT_TTS_CONFIG.summarization,\n ...p.summarization,\n },\n };\n}\n\n/**\n * User-facing hint when TTS is enabled in settings but no provider can run.\n */\nexport function formatTtsSetupHint(): string {\n return (\n `⚠️ *TTS is on, but no provider can run yet.*\\n\\n` +\n `Configure one of the following in \\`~/.xopc/xopc.json\\` (or env):\\n` +\n `• *OpenAI*: \\`OPENAI_API_KEY\\` or \\`messages.tts.providers.openai.apiKey\\`\\n` +\n `• *Alibaba*: \\`DASHSCOPE_API_KEY\\` or \\`messages.tts.providers.alibaba.apiKey\\`\\n` +\n `• *MiniMax*: \\`MINIMAX_API_KEY\\` or \\`messages.tts.providers.minimax.apiKey\\`\\n` +\n `• *Edge* (no key): ensure \\`messages.tts.providers.edge.enabled\\` is not \\`false\\`\\n` +\n `• *Local CLI*: \\`messages.tts.providers.tts-local-cli.command\\`\\n\\n` +\n `You can also use the gateway Web UI → Settings → Voice.`\n );\n}\n\n/**\n * Append readiness / setup guidance when TTS is enabled but unavailable.\n */\nexport function appendTtsReadinessNote(content: string, appConfig: Config | undefined): string {\n const effective = mergeTtsConfigFromAppConfig(appConfig?.messages?.tts);\n if (!effective.enabled) {\n return content;\n }\n if (isTTSAvailable(effective)) {\n return content;\n }\n return `${content}\\n\\n${formatTtsSetupHint()}`;\n}\n"],"mappings":";;;;;;;AAQA,SAAS,oBAAoB,KAAoC;CAC/D,MAAM,IAAI,OAAO,QAAQ,WAAW,IAAI,aAAa,GAAG;AACxD,KAAI,MAAM,SAAS,MAAM,YAAY,MAAM,aAAa,MAAM,SAAU,QAAO;AAC/E,QAAO,mBAAmB;;AAG5B,SAAS,qBAAqB,KAAsB;AAClD,QAAO,OAAO,QAAQ,YAAY,IAAI,MAAM,CAAC,SAAS,IAAI,IAAI,MAAM,GAAG,mBAAmB;;AAG5F,SAAS,qBACP,MACA,OACqD;AACrD,KAAI,CAAC,QAAQ,CAAC,MACZ;CAEF,MAAM,SAAkD,EAAE,GAAI,QAAQ,EAAE,EAAG;AAC3E,MAAK,MAAM,CAAC,YAAY,UAAU,OAAO,QAAQ,SAAS,EAAE,CAAC,CAC3D,QAAO,cAAc;EAAE,GAAI,OAAO,eAAe,EAAE;EAAG,GAAG;EAAO;AAElE,QAAO;;AAGT,SAAgB,4BAA4B,KAAgD;CAC1F,MAAM,IAAK,OAAO,EAAE;AACpB,QAAO;EACL,GAAG;EACH,GAAG;EACH,SAAS,EAAE,WAAW,mBAAmB;EACzC,UAAU,qBAAqB,EAAE,SAAS;EAC1C,SAAS,oBAAoB,EAAE,WAAW,mBAAmB,QAAQ;EACrE,UAAU;GACR,GAAG,mBAAmB;GACtB,GAAG,EAAE;GACN;EACD,gBAAgB;GACd,GAAG,mBAAmB;GACtB,GAAG,EAAE;GACN;EACD,WAAW,qBAAqB,mBAAmB,WAAW,EAAE,UAAU;EAC1E,eAAe;GACb,GAAG,mBAAmB;GACtB,GAAG,EAAE;GACN;EACF;;;;;AAMH,SAAgB,qBAA6B;AAC3C,QACE;;;;;AAcJ,SAAgB,uBAAuB,SAAiB,WAAuC;CAC7F,MAAM,YAAY,4BAA4B,WAAW,UAAU,IAAI;AACvE,KAAI,CAAC,UAAU,QACb,QAAO;AAET,KAAI,eAAe,UAAU,CAC3B,QAAO;AAET,QAAO,GAAG,QAAQ,MAAM,oBAAoB"}
|
|
@@ -56,7 +56,7 @@ function trimToUndefined(value) {
|
|
|
56
56
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
57
57
|
}
|
|
58
58
|
function normalizeConfig(rawConfig) {
|
|
59
|
-
const raw = asObject(rawConfig.alibaba) ??
|
|
59
|
+
const raw = asObject(rawConfig.alibaba) ?? {};
|
|
60
60
|
return {
|
|
61
61
|
apiKey: trimToUndefined(raw.apiKey),
|
|
62
62
|
baseUrl: trimToUndefined(raw.baseUrl) ?? DEFAULT_BASE_URL,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alibaba-speech.js","names":[],"sources":["../../../../../src/voice/tts/providers/alibaba-speech.ts"],"sourcesContent":["/**\n * Alibaba DashScope TTS provider (qwen-tts model).\n *\n * Implements the SpeechProviderPlugin contract directly because DashScope's\n * response shape (output.audio.url for the audio binary, no direct stream)\n * doesn't fit the OpenAI-compatible factory.\n *\n * Implementation notes (per docs/voice-rearchitecture.md §8.4.1):\n * - `synthesizeStream` is intentionally not implemented. Native qwen-tts\n * streaming uses a WebSocket protocol\n * (wss://dashscope.aliyuncs.com/api-ws/v1/inference); speak-core's stream\n * fallback wraps `synthesize` output as a single-chunk ReadableStream so\n * callers see the same shape.\n * - `maxTextLength = 512` (DashScope qwen-tts hard limit). Enforced upstream\n * via `truncateAtSentenceBoundary` before this provider sees the text.\n * - The audio URL returned by DashScope is hosted on Alibaba's CDN (variable\n * hostname). We do not SSRF-guard the audio fetch because:\n * (a) the URL is provided by the same provider we already trust for the\n * initial synthesis call,\n * (b) it's HTTPS-only and short-lived (~5 min TTL),\n * (c) maintaining a hostname allowlist breaks every time Alibaba rotates\n * CDN domains.\n * A dedicated `assertSafeUrl` for trusted-CDN responses can be added later\n * as a hardening pass.\n */\n\nimport {\n ProviderHttpError,\n fetchWithTimeoutGuarded,\n postJsonRequest,\n} from '../../../media-shared/http/index.js';\nimport { createLogger } from '../../../utils/logger.js';\nimport { registerSpeechProvider } from '../speech-registry.js';\nimport type {\n SpeechDirectiveTokenParseContext,\n SpeechDirectiveTokenParseResult,\n SpeechProviderConfig,\n SpeechProviderConfiguredContext,\n SpeechProviderPlugin,\n SpeechProviderResolveConfigContext,\n SpeechSynthesisRequest,\n SpeechSynthesisResult,\n} from '../speech-provider-types.js';\n\nconst log = createLogger('SpeechProvider:Alibaba');\n\nconst DEFAULT_BASE_URL =\n 'https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation';\nconst DEFAULT_MODEL = 'qwen-tts';\nconst DEFAULT_VOICE = 'longxiaochun';\nconst ENV_KEY = 'DASHSCOPE_API_KEY';\nconst MAX_TEXT_LENGTH = 512;\nconst ALIBABA_VOICES = [\n 'Cherry',\n 'Ethan',\n 'Serena',\n 'Chelsie',\n 'longxiaochun',\n 'longxiaobai',\n 'longwan',\n 'longcheng',\n] as const;\n\ninterface AlibabaTtsConfig extends Record<string, unknown> {\n apiKey?: string;\n baseUrl: string;\n model: string;\n voice: string;\n}\n\ninterface CosyVoiceResponse {\n output: {\n audio?: { url?: string; data?: string };\n speech?: string;\n speech_url?: string;\n finish_reason?: string;\n };\n usage?: { characters?: number };\n request_id?: string;\n}\n\nfunction asObject(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction trimToUndefined(value: unknown): string | undefined {\n if (typeof value !== 'string') {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction normalizeConfig(rawConfig: Record<string, unknown>): AlibabaTtsConfig {\n const raw = asObject(rawConfig.alibaba) ?? rawConfig;\n return {\n apiKey: trimToUndefined(raw.apiKey),\n baseUrl: trimToUndefined(raw.baseUrl) ?? DEFAULT_BASE_URL,\n model: trimToUndefined(raw.model ?? raw.modelId) ?? DEFAULT_MODEL,\n voice: trimToUndefined(raw.voice ?? raw.voiceId) ?? DEFAULT_VOICE,\n };\n}\n\nfunction readProviderConfig(config: SpeechProviderConfig): AlibabaTtsConfig {\n return {\n apiKey: trimToUndefined(config.apiKey),\n baseUrl: trimToUndefined(config.baseUrl) ?? DEFAULT_BASE_URL,\n model: trimToUndefined(config.model ?? config.modelId) ?? DEFAULT_MODEL,\n voice: trimToUndefined(config.voice ?? config.voiceId) ?? DEFAULT_VOICE,\n };\n}\n\nfunction resolveApiKey(config: AlibabaTtsConfig): string | undefined {\n return config.apiKey ?? trimToUndefined(process.env[ENV_KEY]);\n}\n\nfunction parseDirectiveTokenInternal(\n ctx: SpeechDirectiveTokenParseContext,\n): SpeechDirectiveTokenParseResult {\n switch (ctx.key) {\n case 'voice':\n case 'voice_id':\n case 'voiceid':\n case 'alibaba_voice':\n case 'alibabavoice':\n if (!ctx.policy.allowVoice) {\n return { handled: true };\n }\n return { handled: true, overrides: { voice: ctx.value } };\n case 'model':\n case 'model_id':\n case 'modelid':\n case 'alibaba_model':\n case 'alibabamodel':\n if (!ctx.policy.allowModelId) {\n return { handled: true };\n }\n return { handled: true, overrides: { model: ctx.value } };\n default:\n return { handled: false };\n }\n}\n\nexport const alibabaSpeechProvider: SpeechProviderPlugin = {\n id: 'alibaba',\n aliases: ['dashscope', 'qwen-tts'],\n autoSelectOrder: 25,\n\n resolveConfig: (ctx: SpeechProviderResolveConfigContext) => normalizeConfig(ctx.rawConfig),\n\n isConfigured: (ctx: SpeechProviderConfiguredContext) =>\n Boolean(resolveApiKey(readProviderConfig(ctx.providerConfig))),\n\n parseDirectiveToken: parseDirectiveTokenInternal,\n\n listVoices: async () => ALIBABA_VOICES.map((id) => ({ id, name: id })),\n\n synthesize: async (req: SpeechSynthesisRequest): Promise<SpeechSynthesisResult> => {\n const config = readProviderConfig(req.providerConfig);\n const apiKey = resolveApiKey(config);\n if (!apiKey) {\n throw new Error(\n `Alibaba TTS API key missing (set ${ENV_KEY} or messages.tts.providers.alibaba.apiKey)`,\n );\n }\n if (req.text.length > MAX_TEXT_LENGTH) {\n throw new Error(\n `Alibaba TTS text exceeds ${MAX_TEXT_LENGTH} char limit (got ${req.text.length})`,\n );\n }\n\n const overrides = req.providerOverrides ?? {};\n const model = trimToUndefined(overrides.model ?? overrides.modelId) ?? config.model;\n const voice = trimToUndefined(overrides.voice ?? overrides.voiceId) ?? config.voice;\n\n log.debug({ model, voice, textLength: req.text.length }, 'Calling Alibaba TTS');\n\n const response = await postJsonRequest(config.baseUrl, {\n timeoutMs: req.timeoutMs,\n label: 'Alibaba TTS',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'X-DashScope-DataInspection': 'disable',\n },\n body: {\n model,\n input: { text: req.text },\n parameters: { voice },\n },\n });\n\n const data = (await response.json()) as CosyVoiceResponse;\n\n // DashScope occasionally returns `finish_reason: \"null\"` (string) on failure.\n if (data.output?.finish_reason === 'null' && !data.output?.audio?.url) {\n throw new Error(`Alibaba TTS API error: ${JSON.stringify(data)}`);\n }\n\n let audioBuffer: Buffer;\n const audioUrl = data.output?.audio?.url ?? data.output?.speech_url;\n if (audioUrl) {\n // CDN URL — see file-level DECISION on why we skip SSRF here.\n const audioResponse = await fetchWithTimeoutGuarded(audioUrl, {\n timeoutMs: req.timeoutMs,\n label: 'Alibaba TTS audio download',\n allowPrivateNetwork: false,\n });\n if (!audioResponse.ok) {\n throw new ProviderHttpError({\n label: 'Alibaba TTS audio download',\n status: audioResponse.status,\n detail: audioResponse.statusText,\n });\n }\n audioBuffer = Buffer.from(await audioResponse.arrayBuffer());\n } else if (data.output?.speech) {\n audioBuffer = Buffer.from(data.output.speech, 'base64');\n } else if (data.output?.audio?.data) {\n audioBuffer = Buffer.from(data.output.audio.data, 'base64');\n } else {\n throw new Error('No audio returned from Alibaba TTS');\n }\n\n log.debug(\n { size: audioBuffer.length, characters: data.usage?.characters, requestId: data.request_id },\n 'Alibaba TTS completed',\n );\n\n return {\n audioBuffer,\n outputFormat: 'wav',\n fileExtension: 'wav',\n // wav is NOT a Telegram voice-note format → ffmpeg compresses downstream.\n voiceCompatible: false,\n };\n },\n\n // synthesizeStream intentionally omitted — see file-level DECISION.\n};\n\nregisterSpeechProvider(alibabaSpeechProvider);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"alibaba-speech.js","names":[],"sources":["../../../../../src/voice/tts/providers/alibaba-speech.ts"],"sourcesContent":["/**\n * Alibaba DashScope TTS provider (qwen-tts model).\n *\n * Implements the SpeechProviderPlugin contract directly because DashScope's\n * response shape (output.audio.url for the audio binary, no direct stream)\n * doesn't fit the OpenAI-compatible factory.\n *\n * Implementation notes (per docs/voice-rearchitecture.md §8.4.1):\n * - `synthesizeStream` is intentionally not implemented. Native qwen-tts\n * streaming uses a WebSocket protocol\n * (wss://dashscope.aliyuncs.com/api-ws/v1/inference); speak-core's stream\n * fallback wraps `synthesize` output as a single-chunk ReadableStream so\n * callers see the same shape.\n * - `maxTextLength = 512` (DashScope qwen-tts hard limit). Enforced upstream\n * via `truncateAtSentenceBoundary` before this provider sees the text.\n * - The audio URL returned by DashScope is hosted on Alibaba's CDN (variable\n * hostname). We do not SSRF-guard the audio fetch because:\n * (a) the URL is provided by the same provider we already trust for the\n * initial synthesis call,\n * (b) it's HTTPS-only and short-lived (~5 min TTL),\n * (c) maintaining a hostname allowlist breaks every time Alibaba rotates\n * CDN domains.\n * A dedicated `assertSafeUrl` for trusted-CDN responses can be added later\n * as a hardening pass.\n */\n\nimport {\n ProviderHttpError,\n fetchWithTimeoutGuarded,\n postJsonRequest,\n} from '../../../media-shared/http/index.js';\nimport { createLogger } from '../../../utils/logger.js';\nimport { registerSpeechProvider } from '../speech-registry.js';\nimport type {\n SpeechDirectiveTokenParseContext,\n SpeechDirectiveTokenParseResult,\n SpeechProviderConfig,\n SpeechProviderConfiguredContext,\n SpeechProviderPlugin,\n SpeechProviderResolveConfigContext,\n SpeechSynthesisRequest,\n SpeechSynthesisResult,\n} from '../speech-provider-types.js';\n\nconst log = createLogger('SpeechProvider:Alibaba');\n\nconst DEFAULT_BASE_URL =\n 'https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation';\nconst DEFAULT_MODEL = 'qwen-tts';\nconst DEFAULT_VOICE = 'longxiaochun';\nconst ENV_KEY = 'DASHSCOPE_API_KEY';\nconst MAX_TEXT_LENGTH = 512;\nconst ALIBABA_VOICES = [\n 'Cherry',\n 'Ethan',\n 'Serena',\n 'Chelsie',\n 'longxiaochun',\n 'longxiaobai',\n 'longwan',\n 'longcheng',\n] as const;\n\ninterface AlibabaTtsConfig extends Record<string, unknown> {\n apiKey?: string;\n baseUrl: string;\n model: string;\n voice: string;\n}\n\ninterface CosyVoiceResponse {\n output: {\n audio?: { url?: string; data?: string };\n speech?: string;\n speech_url?: string;\n finish_reason?: string;\n };\n usage?: { characters?: number };\n request_id?: string;\n}\n\nfunction asObject(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction trimToUndefined(value: unknown): string | undefined {\n if (typeof value !== 'string') {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction normalizeConfig(rawConfig: Record<string, unknown>): AlibabaTtsConfig {\n const raw = asObject(rawConfig.alibaba) ?? {};\n return {\n apiKey: trimToUndefined(raw.apiKey),\n baseUrl: trimToUndefined(raw.baseUrl) ?? DEFAULT_BASE_URL,\n model: trimToUndefined(raw.model ?? raw.modelId) ?? DEFAULT_MODEL,\n voice: trimToUndefined(raw.voice ?? raw.voiceId) ?? DEFAULT_VOICE,\n };\n}\n\nfunction readProviderConfig(config: SpeechProviderConfig): AlibabaTtsConfig {\n return {\n apiKey: trimToUndefined(config.apiKey),\n baseUrl: trimToUndefined(config.baseUrl) ?? DEFAULT_BASE_URL,\n model: trimToUndefined(config.model ?? config.modelId) ?? DEFAULT_MODEL,\n voice: trimToUndefined(config.voice ?? config.voiceId) ?? DEFAULT_VOICE,\n };\n}\n\nfunction resolveApiKey(config: AlibabaTtsConfig): string | undefined {\n return config.apiKey ?? trimToUndefined(process.env[ENV_KEY]);\n}\n\nfunction parseDirectiveTokenInternal(\n ctx: SpeechDirectiveTokenParseContext,\n): SpeechDirectiveTokenParseResult {\n switch (ctx.key) {\n case 'voice':\n case 'voice_id':\n case 'voiceid':\n case 'alibaba_voice':\n case 'alibabavoice':\n if (!ctx.policy.allowVoice) {\n return { handled: true };\n }\n return { handled: true, overrides: { voice: ctx.value } };\n case 'model':\n case 'model_id':\n case 'modelid':\n case 'alibaba_model':\n case 'alibabamodel':\n if (!ctx.policy.allowModelId) {\n return { handled: true };\n }\n return { handled: true, overrides: { model: ctx.value } };\n default:\n return { handled: false };\n }\n}\n\nexport const alibabaSpeechProvider: SpeechProviderPlugin = {\n id: 'alibaba',\n aliases: ['dashscope', 'qwen-tts'],\n autoSelectOrder: 25,\n\n resolveConfig: (ctx: SpeechProviderResolveConfigContext) => normalizeConfig(ctx.rawConfig),\n\n isConfigured: (ctx: SpeechProviderConfiguredContext) =>\n Boolean(resolveApiKey(readProviderConfig(ctx.providerConfig))),\n\n parseDirectiveToken: parseDirectiveTokenInternal,\n\n listVoices: async () => ALIBABA_VOICES.map((id) => ({ id, name: id })),\n\n synthesize: async (req: SpeechSynthesisRequest): Promise<SpeechSynthesisResult> => {\n const config = readProviderConfig(req.providerConfig);\n const apiKey = resolveApiKey(config);\n if (!apiKey) {\n throw new Error(\n `Alibaba TTS API key missing (set ${ENV_KEY} or messages.tts.providers.alibaba.apiKey)`,\n );\n }\n if (req.text.length > MAX_TEXT_LENGTH) {\n throw new Error(\n `Alibaba TTS text exceeds ${MAX_TEXT_LENGTH} char limit (got ${req.text.length})`,\n );\n }\n\n const overrides = req.providerOverrides ?? {};\n const model = trimToUndefined(overrides.model ?? overrides.modelId) ?? config.model;\n const voice = trimToUndefined(overrides.voice ?? overrides.voiceId) ?? config.voice;\n\n log.debug({ model, voice, textLength: req.text.length }, 'Calling Alibaba TTS');\n\n const response = await postJsonRequest(config.baseUrl, {\n timeoutMs: req.timeoutMs,\n label: 'Alibaba TTS',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'X-DashScope-DataInspection': 'disable',\n },\n body: {\n model,\n input: { text: req.text },\n parameters: { voice },\n },\n });\n\n const data = (await response.json()) as CosyVoiceResponse;\n\n // DashScope occasionally returns `finish_reason: \"null\"` (string) on failure.\n if (data.output?.finish_reason === 'null' && !data.output?.audio?.url) {\n throw new Error(`Alibaba TTS API error: ${JSON.stringify(data)}`);\n }\n\n let audioBuffer: Buffer;\n const audioUrl = data.output?.audio?.url ?? data.output?.speech_url;\n if (audioUrl) {\n // CDN URL — see file-level DECISION on why we skip SSRF here.\n const audioResponse = await fetchWithTimeoutGuarded(audioUrl, {\n timeoutMs: req.timeoutMs,\n label: 'Alibaba TTS audio download',\n allowPrivateNetwork: false,\n });\n if (!audioResponse.ok) {\n throw new ProviderHttpError({\n label: 'Alibaba TTS audio download',\n status: audioResponse.status,\n detail: audioResponse.statusText,\n });\n }\n audioBuffer = Buffer.from(await audioResponse.arrayBuffer());\n } else if (data.output?.speech) {\n audioBuffer = Buffer.from(data.output.speech, 'base64');\n } else if (data.output?.audio?.data) {\n audioBuffer = Buffer.from(data.output.audio.data, 'base64');\n } else {\n throw new Error('No audio returned from Alibaba TTS');\n }\n\n log.debug(\n { size: audioBuffer.length, characters: data.usage?.characters, requestId: data.request_id },\n 'Alibaba TTS completed',\n );\n\n return {\n audioBuffer,\n outputFormat: 'wav',\n fileExtension: 'wav',\n // wav is NOT a Telegram voice-note format → ffmpeg compresses downstream.\n voiceCompatible: false,\n };\n },\n\n // synthesizeStream intentionally omitted — see file-level DECISION.\n};\n\nregisterSpeechProvider(alibabaSpeechProvider);\n"],"mappings":"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"}
|
|
@@ -72,36 +72,8 @@ export interface TTSConfig {
|
|
|
72
72
|
summarization?: TTSSummarizationConfig;
|
|
73
73
|
/** Allow model to override TTS parameters */
|
|
74
74
|
modelOverrides?: TTSModelOverrideConfig;
|
|
75
|
-
/**
|
|
75
|
+
/** Provider settings map (`messages.tts.providers.<id>`). */
|
|
76
76
|
providers?: Record<string, Record<string, unknown>>;
|
|
77
|
-
alibaba?: {
|
|
78
|
-
apiKey?: string;
|
|
79
|
-
model?: string;
|
|
80
|
-
voice?: string;
|
|
81
|
-
};
|
|
82
|
-
openai?: {
|
|
83
|
-
apiKey?: string;
|
|
84
|
-
model?: string;
|
|
85
|
-
voice?: string;
|
|
86
|
-
};
|
|
87
|
-
edge?: {
|
|
88
|
-
enabled?: boolean;
|
|
89
|
-
voice?: string;
|
|
90
|
-
lang?: string;
|
|
91
|
-
outputFormat?: string;
|
|
92
|
-
pitch?: string;
|
|
93
|
-
rate?: string;
|
|
94
|
-
volume?: string;
|
|
95
|
-
proxy?: string;
|
|
96
|
-
timeoutMs?: number;
|
|
97
|
-
};
|
|
98
|
-
minimax?: {
|
|
99
|
-
apiKey?: string;
|
|
100
|
-
model?: string;
|
|
101
|
-
voice?: string;
|
|
102
|
-
};
|
|
103
|
-
/** Extension / legacy flat provider config (e.g. `tts-local-cli`). */
|
|
104
|
-
[providerId: string]: unknown;
|
|
105
77
|
}
|
|
106
78
|
export interface TTSSummarizationConfig {
|
|
107
79
|
/** When true (default), long text is summarized via LLM before TTS */
|
|
@@ -25,23 +25,25 @@ const DEFAULT_TTS_CONFIG = {
|
|
|
25
25
|
allowNormalization: false,
|
|
26
26
|
allowSeed: false
|
|
27
27
|
},
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
28
|
+
providers: {
|
|
29
|
+
alibaba: {
|
|
30
|
+
model: "qwen-tts",
|
|
31
|
+
voice: "Cherry"
|
|
32
|
+
},
|
|
33
|
+
openai: {
|
|
34
|
+
model: "tts-1",
|
|
35
|
+
voice: "alloy"
|
|
36
|
+
},
|
|
37
|
+
edge: {
|
|
38
|
+
enabled: true,
|
|
39
|
+
voice: "en-US-MichelleNeural",
|
|
40
|
+
lang: "en-US",
|
|
41
|
+
outputFormat: "audio-24khz-48kbitrate-mono-mp3"
|
|
42
|
+
},
|
|
43
|
+
minimax: {
|
|
44
|
+
model: "speech-2.8-hd",
|
|
45
|
+
voice: "male-qn-qingse"
|
|
46
|
+
}
|
|
45
47
|
}
|
|
46
48
|
};
|
|
47
49
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../../../src/voice/tts/types.ts"],"sourcesContent":["/**\n * TTS (Text-to-Speech) Types\n */\n\n/** Built-in provider ids shipped in core. Extensions add more at runtime. */\nexport type BuiltinTTSProvider = 'openai' | 'alibaba' | 'edge' | 'minimax' | 'tts-local-cli';\n\n/** Any registered SpeechProviderPlugin id (built-in or extension). */\nexport type TTSProvider = string;\n\nexport type TTSAutoMode = 'off' | 'always' | 'inbound' | 'tagged';\n\nexport interface TTSOptions {\n /** Voice ID */\n voice?: string;\n /** Speed (0.25 - 4.0) */\n speed?: number;\n /** Output format */\n format?: 'opus' | 'mp3' | 'wav';\n /** Model ID (for provider-specific model selection) */\n model?: string;\n /** Request timeout in milliseconds */\n timeoutMs?: number;\n}\n\nexport interface TTSResult {\n /** Audio buffer */\n audio: Buffer;\n /** Format */\n format: string;\n /** Duration in seconds (if available) */\n duration?: number;\n /** Provider that generated the speech */\n provider: string;\n}\n\nexport interface TTSProviderInterface {\n /** Provider name */\n name: string;\n /** Convert text to speech */\n speak(text: string, options?: TTSOptions): Promise<TTSResult>;\n /** Check if provider is configured */\n isConfigured(): boolean;\n}\n\nexport interface TTSModelOverrideConfig {\n /** Enable model-provided overrides for TTS */\n enabled?: boolean;\n /** Allow model-provided TTS text blocks */\n allowText?: boolean;\n /** Allow model-provided provider override (default: false) */\n allowProvider?: boolean;\n /** Allow model-provided voice/voiceId override */\n allowVoice?: boolean;\n /** Allow model-provided modelId override */\n allowModelId?: boolean;\n /** Allow model-provided voice settings override */\n allowVoiceSettings?: boolean;\n /** Allow model-provided normalization or language overrides */\n allowNormalization?: boolean;\n /** Allow model-provided seed override */\n allowSeed?: boolean;\n}\n\nexport interface TTSConfig {\n enabled: boolean;\n provider: TTSProvider;\n /** Trigger mode: auto = reply with voice when user sends voice */\n trigger: TTSAutoMode;\n /** Fallback configuration */\n fallback?: {\n enabled: boolean;\n order: TTSProvider[];\n };\n /** Maximum text length for TTS */\n maxTextLength?: number;\n /** API request timeout (ms) */\n timeoutMs?: number;\n /** Long-text summarization before TTS */\n summarization?: TTSSummarizationConfig;\n /** Allow model to override TTS parameters */\n modelOverrides?: TTSModelOverrideConfig;\n /**
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../../../src/voice/tts/types.ts"],"sourcesContent":["/**\n * TTS (Text-to-Speech) Types\n */\n\n/** Built-in provider ids shipped in core. Extensions add more at runtime. */\nexport type BuiltinTTSProvider = 'openai' | 'alibaba' | 'edge' | 'minimax' | 'tts-local-cli';\n\n/** Any registered SpeechProviderPlugin id (built-in or extension). */\nexport type TTSProvider = string;\n\nexport type TTSAutoMode = 'off' | 'always' | 'inbound' | 'tagged';\n\nexport interface TTSOptions {\n /** Voice ID */\n voice?: string;\n /** Speed (0.25 - 4.0) */\n speed?: number;\n /** Output format */\n format?: 'opus' | 'mp3' | 'wav';\n /** Model ID (for provider-specific model selection) */\n model?: string;\n /** Request timeout in milliseconds */\n timeoutMs?: number;\n}\n\nexport interface TTSResult {\n /** Audio buffer */\n audio: Buffer;\n /** Format */\n format: string;\n /** Duration in seconds (if available) */\n duration?: number;\n /** Provider that generated the speech */\n provider: string;\n}\n\nexport interface TTSProviderInterface {\n /** Provider name */\n name: string;\n /** Convert text to speech */\n speak(text: string, options?: TTSOptions): Promise<TTSResult>;\n /** Check if provider is configured */\n isConfigured(): boolean;\n}\n\nexport interface TTSModelOverrideConfig {\n /** Enable model-provided overrides for TTS */\n enabled?: boolean;\n /** Allow model-provided TTS text blocks */\n allowText?: boolean;\n /** Allow model-provided provider override (default: false) */\n allowProvider?: boolean;\n /** Allow model-provided voice/voiceId override */\n allowVoice?: boolean;\n /** Allow model-provided modelId override */\n allowModelId?: boolean;\n /** Allow model-provided voice settings override */\n allowVoiceSettings?: boolean;\n /** Allow model-provided normalization or language overrides */\n allowNormalization?: boolean;\n /** Allow model-provided seed override */\n allowSeed?: boolean;\n}\n\nexport interface TTSConfig {\n enabled: boolean;\n provider: TTSProvider;\n /** Trigger mode: auto = reply with voice when user sends voice */\n trigger: TTSAutoMode;\n /** Fallback configuration */\n fallback?: {\n enabled: boolean;\n order: TTSProvider[];\n };\n /** Maximum text length for TTS */\n maxTextLength?: number;\n /** API request timeout (ms) */\n timeoutMs?: number;\n /** Long-text summarization before TTS */\n summarization?: TTSSummarizationConfig;\n /** Allow model to override TTS parameters */\n modelOverrides?: TTSModelOverrideConfig;\n /** Provider settings map (`messages.tts.providers.<id>`). */\n providers?: Record<string, Record<string, unknown>>;\n}\n\nexport interface TTSSummarizationConfig {\n /** When true (default), long text is summarized via LLM before TTS */\n enabled?: boolean;\n targetLength?: number;\n threshold?: number;\n model?: string;\n}\n\nexport const DEFAULT_TTS_CONFIG: TTSConfig = {\n enabled: false,\n provider: 'openai',\n trigger: 'always',\n fallback: {\n enabled: true,\n order: ['openai', 'alibaba', 'minimax', 'edge'],\n },\n maxTextLength: 512, // Conservative default to accommodate all providers (Alibaba limit is 512)\n timeoutMs: 30000,\n summarization: {\n enabled: true,\n },\n modelOverrides: {\n enabled: true,\n allowText: true,\n allowProvider: false,\n allowVoice: true,\n allowModelId: true,\n allowVoiceSettings: false,\n allowNormalization: false,\n allowSeed: false,\n },\n providers: {\n alibaba: { model: 'qwen-tts', voice: 'Cherry' },\n openai: { model: 'tts-1', voice: 'alloy' },\n edge: {\n enabled: true,\n voice: 'en-US-MichelleNeural',\n lang: 'en-US',\n outputFormat: 'audio-24khz-48kbitrate-mono-mp3',\n },\n minimax: { model: 'speech-2.8-hd', voice: 'male-qn-qingse' },\n },\n};\n\n/** TTS directive parse result */\nexport interface TtsDirectiveParseResult {\n cleanedText: string;\n ttsText?: string;\n hasDirective: boolean;\n overrides: TtsDirectiveOverrides;\n warnings: string[];\n}\n\n/** TTS directive overrides */\nexport interface TtsDirectiveOverrides {\n ttsText?: string;\n provider?: TTSProvider;\n openai?: {\n voice?: string;\n model?: string;\n };\n alibaba?: {\n voice?: string;\n model?: string;\n };\n edge?: {\n voice?: string;\n };\n minimax?: {\n voice?: string;\n model?: string;\n };\n}\n\n/** Provider attempt result (TTS fallback chain) */\nexport type ProviderAttemptOutcome = 'success' | 'skipped' | 'failed';\n\n/** Provider failure reason classification */\nexport type ProviderFailureReason =\n | 'success'\n | 'not_configured'\n | 'timeout'\n | 'provider_error'\n | 'text_too_long'\n | 'unknown';\n\n/** Single provider attempt in a TTS fallback chain */\nexport interface ProviderAttempt {\n provider: string;\n outcome: ProviderAttemptOutcome;\n reasonCode: ProviderFailureReason;\n latencyMs: number;\n error?: string;\n}\n\n/** TTS result including fallback / preprocessing metadata */\nexport interface TTSResultWithTracking extends TTSResult {\n attempts: ProviderAttempt[];\n fallbackFrom?: string;\n attemptedProviders: string[];\n wasPreprocessed?: boolean;\n ttsText?: string;\n wasSummarized?: boolean;\n}\n\n/** Last TTS call diagnostics (memory-only) */\nexport interface TtsStatusEntry {\n timestamp: number;\n success: boolean;\n provider?: string;\n latencyMs?: number;\n error?: string;\n textLength?: number;\n audioSize?: number;\n audioFormat?: string;\n usedFallback?: boolean;\n wasSummarized?: boolean;\n}\n\nexport interface TtsRuntimeStatus {\n lastAttempt?: TtsStatusEntry;\n recentSuccessRate?: number;\n totalCalls: number;\n totalSuccesses: number;\n totalFailures: number;\n}\n"],"mappings":";AA8FA,MAAa,qBAAgC;CAC3C,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;EACR,SAAS;EACT,OAAO;GAAC;GAAU;GAAW;GAAW;GAAO;EAChD;CACD,eAAe;CACf,WAAW;CACX,eAAe,EACb,SAAS,MACV;CACD,gBAAgB;EACd,SAAS;EACT,WAAW;EACX,eAAe;EACf,YAAY;EACZ,cAAc;EACd,oBAAoB;EACpB,oBAAoB;EACpB,WAAW;EACZ;CACD,WAAW;EACT,SAAS;GAAE,OAAO;GAAY,OAAO;GAAU;EAC/C,QAAQ;GAAE,OAAO;GAAS,OAAO;GAAS;EAC1C,MAAM;GACJ,SAAS;GACT,OAAO;GACP,MAAM;GACN,cAAc;GACf;EACD,SAAS;GAAE,OAAO;GAAiB,OAAO;GAAkB;EAC7D;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xopcai/xopc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.87",
|
|
4
4
|
"description": "The OPC workstation that grows with you: AI assistant for One Person Companies — CLI, gateway, multi-channel (Telegram/WeChat), 20+ LLM providers via pi-ai, extensions and skills.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -71,7 +71,6 @@
|
|
|
71
71
|
"adm-zip": "^0.5.17",
|
|
72
72
|
"ajv": "^8.20.0",
|
|
73
73
|
"chalk": "^5.6.2",
|
|
74
|
-
"chromium-bidi": "15.0.0",
|
|
75
74
|
"cli-table3": "^0.6.5",
|
|
76
75
|
"commander": "^14.0.3",
|
|
77
76
|
"cron-parser": "^5.5.0",
|
|
@@ -88,10 +87,8 @@
|
|
|
88
87
|
"node-edge-tts": "^1.2.10",
|
|
89
88
|
"openai": "^6.39.1",
|
|
90
89
|
"pino": "^10.3.1",
|
|
91
|
-
"pino-pretty": "^13.1.3",
|
|
92
90
|
"playwright-core": "^1.60.0",
|
|
93
91
|
"proper-lockfile": "^4.1.2",
|
|
94
|
-
"qrcode-terminal": "^0.12.0",
|
|
95
92
|
"semver": "^7.8.1",
|
|
96
93
|
"silk-wasm": "^3.7.1",
|
|
97
94
|
"thread-stream": "^4.2.0",
|