@xopcai/xopc 0.0.210 → 0.0.211
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-JLmEb1p0.js → activity-store-BzjFoSr0.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CI1zQfzY.js → agent-avatar-dicebear-DTfjhfVE.js} +1 -1
- package/dist/gateway/static/root/assets/agents-CjhgfuVJ.js +68 -0
- package/dist/gateway/static/root/assets/{api-C6MmWfcb.js → api-D269PnU9.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-Cd02GGpV.js → app-management-settings-panel-BFpfQDWc.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-Db-h2I3G.js → appearance-settings-DLxFdqhY.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-BT7F4WBI.js → apps-page-CjmlGB5V.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-CMHzJT2a.js → archive-plugin-DPlH4dnc.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-BzhI2LoH.js → attachment-load-xqfLLd0I.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-4m6Ey6wG.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-DsUeHvZO.js → binary-plugins-C0tuoPXk.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CFfsIeZ4.js → block-editor-Deyphj1o.js} +47 -47
- package/dist/gateway/static/root/assets/browser-settings-page-CAGCYx8U.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-BiWghvJ0.js → browser-workflow-inputs-CYEbXyRF.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-DPLdT6Zn.js → browser-workflows-page-Bf0tPbGi.js} +2 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-CKfLsxTI.js +7 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-CTxGFvsS.js → capability-presets-api-DPkFA_-R.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-CpipKNqX.js +3 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-BklVUOxC.js → channel-recipient-api-DqKaAcnZ.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-Bvq-O4pt.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-CrMld2l7.js +1 -0
- package/dist/gateway/static/root/assets/{chat-terminal-dock-0F4Jmma2.js → chat-terminal-dock-CTDRZa7e.js} +2 -2
- package/dist/gateway/static/root/assets/{connectors-api-BvIZ51ty.js → connectors-api-Buu8fif8.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-CSQRzaVn.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-BHmwaMbO.js → cron-expression-DTLR82NB.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-fj_pPCv5.js → date-picker-DyNogHQH.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-DsWvwOv-.js → dependency-picker-BpnCuo7B.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-mjkF0Xxh.js → desktop-pet-CDKI4gVB.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-ClwUpRYu.js → desktop-pet-settings-DjT5C2a3.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-OkqRFyRL.js → directory-picker-path-field-DlJY90TM.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DC69wplH.js → extension-debug-page-DWf2z7q5.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DCtk6zdJ.js → extension-page-Dorx0kf9.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-Bkm4zzv-.js → extension-settings-page-B1wU9ZOB.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-Dr_NQt7v.js → gateway-config-api-B1lG4dNr.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-CEfv8N1J.js → gateway-config-swr-BIxuwPQi.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-DqIOqJjM.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-B8hebJ7s.js → gateway-startup-retry-BpZgd4U-.js} +1 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-DG4Kmgkc.js +1 -0
- package/dist/gateway/static/root/assets/home-page-BhqItS_s.js +1 -0
- package/dist/gateway/static/root/assets/image-generation-api-PkhYohDa.js +1 -0
- package/dist/gateway/static/root/assets/index-DLhvsU9B.css +2 -0
- package/dist/gateway/static/root/assets/{index-DJ7HSgKs.js → index-_cuTcWjB.js} +78 -56
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-DCQvf05d.js → keyboard-shortcuts-settings-6OQT3gQF.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-DWjTmzxw.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-B3Ugd0my.js → local-apps-page-DfruRAmE.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-hDBVeG3G.js → locale-store-C5MK9WcP.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-BA5efZ8B.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-C-S5Llq3.js → management-settings-L1VYkywO.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-DuVq37Uh.js → markdown-split-oqgHbqt-.js} +1 -1
- package/dist/gateway/static/root/assets/markdown-view-DD_PgVue.css +1 -0
- package/dist/gateway/static/root/assets/{markdown-view-D8eO_6h3.js → markdown-view-V4rcPPH0.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-C1V6pkX3.js → media-plugins-Bb6gSX2o.js} +1 -1
- package/dist/gateway/static/root/assets/messages-ctG2e-ix.js +3 -0
- package/dist/gateway/static/root/assets/{notes-page-Dn71ZV8c.js → notes-page-B1rOXjpT.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-CkHXVmKP.js +4 -0
- package/dist/gateway/static/root/assets/{page-tabs-B5a5aSoS.js → page-tabs-CBuCKeyy.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-5041AIBX.js → preview-open-alternatives-BQ0tLfPO.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-7UkouFQU.js → product-open-page-DPeFn7Hu.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DCqet9-L.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-D0t_AjzG.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-BUWPoBvw.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DvaXzHYS.js → runtime-tools-settings-panel-BCfQNzjG.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-Dlxl_5X0.js → schema-form-Bo7YbHYN.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-vLhrrM3m.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-OP1y0Y8M.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-CSaiuuer.js → settings-form-section-B9dnKr3M.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-H3mJwt3r.js → settings-loading-skeleton-CYDV2JtY.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-Cs7zA4BS.js → settings-page-DbrIYfS9.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-CwgMODfJ.js → setup-status-panel-Cxc-Ejl5.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-Bdpw5m7M.js → share-preview-page-olgr7LLN.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-ZOqC6-aA.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-DwvC3Iuf.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-Bup3Lg1Z.js → skills-page-PE16CNw5.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-D22ORR21.js → skills-page.utils-nXmBcBxt.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-GmtWsfjB.js → system-settings-panel-C3qPwAdY.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-DCRB-5q-.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-CtY8RwMX.js → theme-store-KR5Otp5w.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-C2aOdlEA.js → typed-models-lib-lMZodtDF.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-DOj5i8d_.js → use-autosave-CKpatP3S.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-CoiedRuA.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-5WfurWYa.js → voice-api-key-field-CDcv0Wbh.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-D5_MH3n3.js → work-discovery-overlay-CGdT22un.js} +1 -1
- package/dist/gateway/static/root/assets/work-discovery-page-BwaU1RqI.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-bBA8LinI.js → workflow-run-setup-panel-BAHYNlQt.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-DHYmh9G7.js +5 -0
- package/dist/gateway/static/root/index.html +10 -10
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +1 -1
- package/dist/src/agent/image/generation/providers/xopc-cloud.js +2 -1
- package/dist/src/agent/image/tool-model-config.js +15 -9
- package/dist/src/agent/memory/builtin-provider.js +0 -1
- package/dist/src/agent/memory/create-memory-manager.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +23 -7
- package/dist/src/agent-runtime/index.js +1 -1
- package/dist/src/agent-runtime/runtime-profile.js +1 -1
- package/dist/src/capabilities/readiness/from-config.d.ts +10 -0
- package/dist/src/capabilities/readiness/from-config.js +128 -0
- package/dist/src/capabilities/readiness/index.d.ts +3 -0
- package/dist/src/capabilities/readiness/index.js +3 -0
- package/dist/src/capabilities/readiness/planner.d.ts +3 -0
- package/dist/src/capabilities/readiness/planner.js +56 -0
- package/dist/src/capabilities/readiness/types.d.ts +35 -0
- package/dist/src/capabilities/readiness/types.js +1 -0
- package/dist/src/cli/commands/agent.js +9 -0
- package/dist/src/cli/commands/auth.js +4 -3
- package/dist/src/cli/commands/connectors.js +1 -1
- package/dist/src/cli/commands/models.js +2 -1
- package/dist/src/cli/commands/onboard/model.d.ts +3 -21
- package/dist/src/cli/commands/onboard/model.js +10 -86
- package/dist/src/cli/utils/oauth-login.d.ts +2 -0
- package/dist/src/cli/utils/oauth-login.js +9 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/index.js +2 -2
- package/dist/src/config/paths-state.d.ts +2 -0
- package/dist/src/config/paths-state.js +5 -1
- package/dist/src/config/paths.d.ts +1 -1
- package/dist/src/config/paths.js +2 -2
- package/dist/src/config/schema.js +1 -1
- package/dist/src/connectors/composio-sessions.d.ts +1 -0
- package/dist/src/connectors/composio-sessions.js +2 -1
- package/dist/src/connectors/composio.js +8 -3
- package/dist/src/connectors/connected-source-cursor.d.ts +9 -0
- package/dist/src/connectors/connected-source-cursor.js +30 -0
- package/dist/src/connectors/connected-source-ingestion.js +67 -46
- package/dist/src/connectors/connected-source-normalizers.d.ts +1 -0
- package/dist/src/connectors/connected-source-normalizers.js +33 -2
- package/dist/src/connectors/connected-source-sanitization.d.ts +1 -0
- package/dist/src/connectors/connected-source-sanitization.js +21 -0
- package/dist/src/connectors/connector-identity.js +10 -2
- package/dist/src/connectors/content-enrichment.d.ts +29 -0
- package/dist/src/connectors/content-enrichment.js +273 -0
- package/dist/src/connectors/health.js +1 -1
- package/dist/src/connectors/learning-coordinator.js +1 -2
- package/dist/src/connectors/learning-recipes.js +28 -33
- package/dist/src/discussions/live-worker.d.ts +1 -0
- package/dist/src/discussions/live-worker.js +7 -1
- package/dist/src/discussions/repository.js +11 -1
- package/dist/src/discussions/sealer.d.ts +1 -1
- package/dist/src/discussions/sealer.js +16 -7
- package/dist/src/discussions/transcript.js +27 -1
- package/dist/src/discussions/types.d.ts +4 -0
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/app.js +8 -3
- package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +4 -0
- package/dist/src/gateway/hono/middleware/strict-rate-limit.js +8 -1
- package/dist/src/gateway/hono/oauth-async.d.ts +11 -5
- package/dist/src/gateway/hono/oauth-async.js +29 -16
- package/dist/src/gateway/hono/oauth.d.ts +1 -3
- package/dist/src/gateway/hono/oauth.js +22 -22
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/connectors.js +1 -1
- package/dist/src/gateway/hono/routes/deps.d.ts +1 -0
- package/dist/src/gateway/hono/routes/discussions.js +2 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +2 -1
- package/dist/src/gateway/hono/routes/mcp.js +1 -1
- package/dist/src/gateway/hono/routes/models.js +59 -5
- package/dist/src/gateway/hono/routes/understanding-sources.js +29 -0
- package/dist/src/gateway/hono/routes/voice.d.ts +1 -2
- package/dist/src/gateway/hono/routes/voice.js +16 -35
- package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
- package/dist/src/gateway/rate-limit/buckets.js +12 -0
- package/dist/src/gateway/service/session-input-coordinator.js +1 -2
- package/dist/src/gateway/service.js +20 -5
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/knowledge/connected-understanding-pipeline.d.ts +1 -1
- package/dist/src/knowledge/connected-understanding-pipeline.js +74 -25
- package/dist/src/knowledge/ingestion-service.js +33 -15
- package/dist/src/knowledge/types.d.ts +2 -0
- package/dist/src/media-understanding/audio-transcription-runner.d.ts +2 -0
- package/dist/src/media-understanding/audio-transcription-runner.js +3 -1
- package/dist/src/media-understanding/runner.js +3 -1
- package/dist/src/media-understanding/types.d.ts +2 -0
- package/dist/src/providers/model-catalog-persistence.d.ts +9 -0
- package/dist/src/providers/model-catalog-persistence.js +172 -0
- package/dist/src/providers/model-catalog-ranking.d.ts +2 -0
- package/dist/src/providers/model-catalog-ranking.js +17 -0
- package/dist/src/providers/model-catalog-store.d.ts +13 -3
- package/dist/src/providers/model-catalog-store.js +24 -5
- package/dist/src/providers/model-catalog-sync-service.d.ts +3 -3
- package/dist/src/providers/model-catalog-sync-service.js +12 -7
- package/dist/src/providers/provider-auth-service.d.ts +1 -0
- package/dist/src/providers/provider-auth-service.js +3 -0
- package/dist/src/providers/provider-disconnect.d.ts +11 -0
- package/dist/src/providers/provider-disconnect.js +33 -0
- package/dist/src/providers/xopc-cloud-catalog-coordinator.d.ts +56 -0
- package/dist/src/providers/xopc-cloud-catalog-coordinator.js +182 -0
- package/dist/src/providers/xopc-cloud-model-source.d.ts +6 -10
- package/dist/src/providers/xopc-cloud-model-source.js +49 -27
- package/dist/src/storage/sqlite/knowledge-repository.d.ts +1 -0
- package/dist/src/storage/sqlite/knowledge-repository.js +4 -0
- package/dist/src/storage/sqlite/user-context-quality-repository.d.ts +8 -0
- package/dist/src/storage/sqlite/user-context-quality-repository.js +21 -1
- package/dist/src/tui/backends/embedded-backend.js +11 -3
- package/dist/src/tui/tui-oauth-login.js +5 -0
- package/dist/src/tui/tui-startup-resources.js +1 -1
- package/dist/src/user-context/sources/activity-clustering.js +30 -117
- package/dist/src/user-context/sources/index.d.ts +1 -0
- package/dist/src/user-context/sources/index.js +2 -1
- package/dist/src/user-context/sources/signal-clustering.d.ts +18 -0
- package/dist/src/user-context/sources/signal-clustering.js +131 -0
- package/dist/src/voice/audio/normalize.d.ts +17 -0
- package/dist/src/voice/audio/normalize.js +155 -0
- package/dist/src/voice/language-profile.d.ts +1 -4
- package/dist/src/voice/language-profile.js +2 -25
- package/dist/src/voice/local/runtime-client.d.ts +2 -0
- package/dist/src/voice/local/runtime-client.js +20 -1
- package/dist/src/voice/local/runtime-worker.js +7 -13
- package/dist/src/voice/local/wav.js +1 -1
- package/dist/src/voice/stt/availability.d.ts +1 -4
- package/dist/src/voice/stt/availability.js +3 -15
- package/dist/src/voice/stt/config.js +1 -0
- package/dist/src/voice/stt/factory.js +23 -0
- package/dist/src/voice/stt/index.d.ts +1 -0
- package/dist/src/voice/stt/index.js +2 -2
- package/dist/src/voice/stt/list-providers.js +1 -1
- package/dist/src/voice/stt/providers/local-transcription.js +7 -3
- package/dist/src/voice/stt/providers/xopc-cloud-transcription.js +3 -1
- package/dist/src/voice/stt/transcribe-core.d.ts +5 -1
- package/dist/src/voice/stt/transcribe-core.js +13 -5
- package/dist/src/voice/stt/types.d.ts +2 -0
- package/dist/src/voice/tts/factory.d.ts +1 -1
- package/dist/src/voice/tts/factory.js +23 -1
- package/dist/src/voice/tts/merge-config.js +5 -3
- package/dist/src/voice/tts/providers/xopc-cloud-speech.js +3 -1
- package/dist/src/voice/tts/types.d.ts +2 -0
- package/dist/src/voice/tts/types.js +4 -2
- package/dist/src/work-discovery/evaluation.d.ts +23 -0
- package/dist/src/work-discovery/evaluation.js +18 -1
- package/dist/src/work-discovery/index.js +2 -2
- package/package.json +4 -3
- package/dist/gateway/static/root/assets/agents-DqGMj3QJ.js +0 -68
- package/dist/gateway/static/root/assets/automations-page-CwOXGV9z.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-CyRLhCod.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-jRKcS7lZ.js +0 -7
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-B3bKdtwU.js +0 -3
- package/dist/gateway/static/root/assets/channels-settings-yZBWH02s.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-C3zlimZd.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-OX4KvUkA.js +0 -2
- package/dist/gateway/static/root/assets/gateway-settings-V1XVxjHa.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-CWUBAQrE.js +0 -1
- package/dist/gateway/static/root/assets/home-page-D57cYRd3.js +0 -1
- package/dist/gateway/static/root/assets/index-PNBFdxHb.css +0 -2
- package/dist/gateway/static/root/assets/local-app-workbench-page-BbAiMZE1.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-nXdF3wOT.js +0 -2
- package/dist/gateway/static/root/assets/markdown-view-B12xeflb.css +0 -1
- package/dist/gateway/static/root/assets/messages-1qg_hOOd.js +0 -3
- package/dist/gateway/static/root/assets/notes-workbench-BYPoZeRw.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-D27nOKbo.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-CdB5cJJ-.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DFoZ3UNS.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-C1cbIcJ7.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-DnXRlQXS.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-hlUgIkrp.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DR31B_Gz.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-CTKDpxhf.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-keJJYpix.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-BcvBiebt.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-Cz2VpWdj.js +0 -5
- package/dist/src/voice/local/runtime-dispatcher.d.ts +0 -9
- package/dist/src/voice/local/runtime-dispatcher.js +0 -20
|
@@ -2,6 +2,7 @@ import { createLogger } from "../utils/logger/index.js";
|
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
3
|
import { CredentialResolver, init_credentials } from "../auth/credentials.js";
|
|
4
4
|
import { getProviderDisplayName, init_providers } from "../providers/index.js";
|
|
5
|
+
import { getXopcCloudCatalogCoordinator } from "../providers/xopc-cloud-catalog-coordinator.js";
|
|
5
6
|
import { selectListTheme, theme } from "./theme.js";
|
|
6
7
|
import { formatKeyIds } from "./format-tui-hotkeys.js";
|
|
7
8
|
import { getOAuthProvider, getSupportedOAuthProviders } from "../cli/utils/oauth-providers.js";
|
|
@@ -170,6 +171,10 @@ async function runTuiOAuthLogin(provider, deps) {
|
|
|
170
171
|
activeCleanups
|
|
171
172
|
}));
|
|
172
173
|
await new CredentialResolver().saveOAuthCredentials(selectedProvider, credentials);
|
|
174
|
+
if (selectedProvider === "xopc-cloud") {
|
|
175
|
+
const catalog = await getXopcCloudCatalogCoordinator().refresh("oauth");
|
|
176
|
+
if (catalog.error) deps.chatLog.addSystem(`Authorization succeeded, but model catalog sync failed: ${catalog.error.message}`);
|
|
177
|
+
}
|
|
173
178
|
deps.chatLog.addSystem(`OAuth login completed for ${selectedProvider}.`);
|
|
174
179
|
} finally {
|
|
175
180
|
for (const cleanup of [...activeCleanups]) cleanup();
|
|
@@ -5,9 +5,9 @@ import { resolveBootstrapFilesSync } from "../agent/bootstrap/bootstrap-files.js
|
|
|
5
5
|
import { createSkillConfigManager, isSkillEnabled } from "../agent/skills/config.js";
|
|
6
6
|
import { loadSkills } from "../agent/skills/index.js";
|
|
7
7
|
import { createWorkflowCatalog } from "../agent/workflow/catalog.js";
|
|
8
|
-
import { listConnectorInstances } from "../connectors/instances.js";
|
|
9
8
|
import { getWorkspacePath } from "../config/workspace-path-helpers.js";
|
|
10
9
|
import "../config/index.js";
|
|
10
|
+
import { listConnectorInstances } from "../connectors/instances.js";
|
|
11
11
|
import { basename } from "node:path";
|
|
12
12
|
//#region src/tui/tui-startup-resources.ts
|
|
13
13
|
init_paths();
|
|
@@ -1,130 +1,43 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { clusterUnderstandingSignals } from "./signal-clustering.js";
|
|
2
2
|
//#region src/user-context/sources/activity-clustering.ts
|
|
3
|
-
const STOP_WORDS = new Set([
|
|
4
|
-
"about",
|
|
5
|
-
"and",
|
|
6
|
-
"bookmark",
|
|
7
|
-
"bookmarks",
|
|
8
|
-
"desktop",
|
|
9
|
-
"document",
|
|
10
|
-
"documents",
|
|
11
|
-
"download",
|
|
12
|
-
"downloads",
|
|
13
|
-
"file",
|
|
14
|
-
"files",
|
|
15
|
-
"from",
|
|
16
|
-
"guide",
|
|
17
|
-
"home",
|
|
18
|
-
"index",
|
|
19
|
-
"into",
|
|
20
|
-
"latest",
|
|
21
|
-
"new",
|
|
22
|
-
"notes",
|
|
23
|
-
"official",
|
|
24
|
-
"overview",
|
|
25
|
-
"page",
|
|
26
|
-
"plan",
|
|
27
|
-
"profile",
|
|
28
|
-
"project",
|
|
29
|
-
"recent",
|
|
30
|
-
"roadmap",
|
|
31
|
-
"the",
|
|
32
|
-
"this",
|
|
33
|
-
"with",
|
|
34
|
-
"www"
|
|
35
|
-
]);
|
|
36
3
|
function activityTimestamp(item) {
|
|
37
4
|
return item.modifiedAt ?? item.occurredAt ?? item.startsAt ?? 0;
|
|
38
5
|
}
|
|
39
|
-
function
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
else for (let index = 0; index < token.length - 1; index += 1) tokens.add(token.slice(index, index + 2));
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
const clean = token.replace(/^-+|-+$/g, "");
|
|
49
|
-
if (clean.length >= 3 && !STOP_WORDS.has(clean) && !/^\d+$/.test(clean)) tokens.add(clean);
|
|
6
|
+
function resourceHost(item) {
|
|
7
|
+
if (!item.resourceUri) return void 0;
|
|
8
|
+
try {
|
|
9
|
+
return new URL(item.resourceUri).hostname.replace(/^www\./, "") || void 0;
|
|
10
|
+
} catch {
|
|
11
|
+
return;
|
|
50
12
|
}
|
|
51
|
-
return tokens;
|
|
52
|
-
}
|
|
53
|
-
function itemTokens(item) {
|
|
54
|
-
let host = "";
|
|
55
|
-
if (item.resourceUri) try {
|
|
56
|
-
host = new URL(item.resourceUri).hostname.replace(/^www\./, "");
|
|
57
|
-
} catch {}
|
|
58
|
-
return tokenize([
|
|
59
|
-
item.title,
|
|
60
|
-
item.group ?? "",
|
|
61
|
-
host
|
|
62
|
-
].join(" "));
|
|
63
|
-
}
|
|
64
|
-
function overlap(left, right) {
|
|
65
|
-
let count = 0;
|
|
66
|
-
for (const token of left) if (right.has(token)) count += 1;
|
|
67
|
-
return count;
|
|
68
|
-
}
|
|
69
|
-
function related(left, right) {
|
|
70
|
-
const shared = overlap(left.tokens, right.tokens);
|
|
71
|
-
if (shared >= 2) return true;
|
|
72
|
-
const smallest = Math.min(left.tokens.size, right.tokens.size);
|
|
73
|
-
if (shared === 1 && smallest <= 2) return true;
|
|
74
|
-
return Boolean(shared === 1 && left.item.group && left.item.group === right.item.group);
|
|
75
|
-
}
|
|
76
|
-
function displayTitle(cluster) {
|
|
77
|
-
const frequency = /* @__PURE__ */ new Map();
|
|
78
|
-
for (const entry of cluster) for (const token of entry.tokens) frequency.set(token, (frequency.get(token) ?? 0) + 1);
|
|
79
|
-
const shared = [...frequency.entries()].filter(([, count]) => count >= 2).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, 3).map(([token]) => token);
|
|
80
|
-
if (shared.length && shared.every((token) => /^[\p{Script=Han}]+$/u.test(token))) return cluster[0].item.title.replace(/\.[a-z0-9]{1,8}$/i, "").slice(0, 80);
|
|
81
|
-
if (shared.length) return shared.map((token) => token.charAt(0).toUpperCase() + token.slice(1)).join(" ");
|
|
82
|
-
return cluster[0].item.title.replace(/\.[a-z0-9]{1,8}$/i, "").slice(0, 80);
|
|
83
13
|
}
|
|
84
14
|
function clusterActivityTopics(items, now = Date.now()) {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (cluster.length < 2) return [];
|
|
102
|
-
const sourceIds = [...new Set(cluster.map(({ item }) => item.sourceId))];
|
|
103
|
-
const types = new Set(cluster.map(({ item }) => item.type));
|
|
104
|
-
if (types.size === 1 && types.has("bookmark") && cluster.length < 3) return [];
|
|
105
|
-
const newestAt = Math.max(...cluster.map(({ timestamp }) => timestamp));
|
|
106
|
-
const ageDays = newestAt ? Math.max(0, (now - newestAt) / 864e5) : 90;
|
|
107
|
-
const recency = Math.max(0, 1 - ageDays / 90);
|
|
108
|
-
const confidence = Math.min(.92, .48 + Math.min(cluster.length, 5) * .06 + Math.min(sourceIds.length, 3) * .09 + recency * .08);
|
|
109
|
-
const title = displayTitle(cluster);
|
|
110
|
-
const fileCount = cluster.filter(({ item }) => item.type === "document").length;
|
|
111
|
-
const bookmarkCount = cluster.length - fileCount;
|
|
112
|
-
const evidenceRefs = cluster.map(({ item }) => item.evidenceRef);
|
|
113
|
-
const sharedTokens = /* @__PURE__ */ new Map();
|
|
114
|
-
for (const entry of cluster) for (const token of entry.tokens) sharedTokens.set(token, (sharedTokens.get(token) ?? 0) + 1);
|
|
115
|
-
const stableTopicTokens = [...sharedTokens.entries()].filter(([, count]) => count >= 2).map(([token]) => token).sort();
|
|
116
|
-
const key = createHash("sha256").update(stableTopicTokens.join("|")).digest("hex").slice(0, 16);
|
|
117
|
-
const signals = [fileCount ? `${fileCount} recent file${fileCount === 1 ? "" : "s"}` : "", bookmarkCount ? `${bookmarkCount} bookmark${bookmarkCount === 1 ? "" : "s"}` : ""].filter(Boolean).join(" and ");
|
|
15
|
+
const eligible = items.filter((item) => item.type === "document" || item.type === "bookmark");
|
|
16
|
+
const byEvidenceRef = new Map(eligible.map((item) => [item.evidenceRef, item]));
|
|
17
|
+
return clusterUnderstandingSignals(eligible.map((item) => ({
|
|
18
|
+
evidenceRef: item.evidenceRef,
|
|
19
|
+
sourceId: item.sourceId,
|
|
20
|
+
title: item.title,
|
|
21
|
+
group: [item.group, resourceHost(item)].filter(Boolean).join(" ") || void 0,
|
|
22
|
+
occurredAt: activityTimestamp(item)
|
|
23
|
+
})), now).flatMap((cluster) => {
|
|
24
|
+
const sourceItems = cluster.signals.map((signal) => byEvidenceRef.get(signal.evidenceRef)).filter((item) => Boolean(item));
|
|
25
|
+
const types = new Set(sourceItems.map((item) => item.type));
|
|
26
|
+
if (types.size === 1 && types.has("bookmark") && sourceItems.length < 3) return [];
|
|
27
|
+
const fileCount = sourceItems.filter((item) => item.type === "document").length;
|
|
28
|
+
const bookmarkCount = sourceItems.length - fileCount;
|
|
29
|
+
const evidenceRefs = cluster.signals.map((signal) => signal.evidenceRef);
|
|
30
|
+
const evidenceSummary = [fileCount ? `${fileCount} recent file${fileCount === 1 ? "" : "s"}` : "", bookmarkCount ? `${bookmarkCount} bookmark${bookmarkCount === 1 ? "" : "s"}` : ""].filter(Boolean).join(" and ");
|
|
118
31
|
return [{
|
|
119
|
-
canonicalKey: `activity-focus:${key}`,
|
|
120
|
-
title,
|
|
121
|
-
summary: `${
|
|
122
|
-
horizon:
|
|
123
|
-
confidence,
|
|
32
|
+
canonicalKey: `activity-focus:${cluster.key}`,
|
|
33
|
+
title: cluster.title,
|
|
34
|
+
summary: `${evidenceSummary} suggest sustained attention to ${cluster.title}.`,
|
|
35
|
+
horizon: cluster.horizon,
|
|
36
|
+
confidence: cluster.confidence,
|
|
124
37
|
evidenceRefs,
|
|
125
|
-
sourceIds
|
|
38
|
+
sourceIds: cluster.sourceIds
|
|
126
39
|
}];
|
|
127
|
-
})
|
|
40
|
+
});
|
|
128
41
|
}
|
|
129
42
|
//#endregion
|
|
130
43
|
export { clusterActivityTopics };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { createUnderstandingSourceRun, deleteUserFocus, getUnderstandingSourceGrant, getUnderstandingSourceRun, listUnderstandingSourceGrants, listUnderstandingSourceRuns, listUserFocuses, revokeUnderstandingSourceGrant, setUserFocusStatus, updateUnderstandingSourceGrantCheckpoint, updateUnderstandingSourceRun, upsertUnderstandingSourceGrant, upsertUserFocus } from "./repository.js";
|
|
2
|
+
import { clusterUnderstandingSignals, tokenizeUnderstandingSignal } from "./signal-clustering.js";
|
|
2
3
|
import { listUnderstandingSourceDefinitions } from "./catalog.js";
|
|
3
|
-
export { createUnderstandingSourceRun, deleteUserFocus, getUnderstandingSourceGrant, getUnderstandingSourceRun, listUnderstandingSourceDefinitions, listUnderstandingSourceGrants, listUnderstandingSourceRuns, listUserFocuses, revokeUnderstandingSourceGrant, setUserFocusStatus, updateUnderstandingSourceGrantCheckpoint, updateUnderstandingSourceRun, upsertUnderstandingSourceGrant, upsertUserFocus };
|
|
4
|
+
export { clusterUnderstandingSignals, createUnderstandingSourceRun, deleteUserFocus, getUnderstandingSourceGrant, getUnderstandingSourceRun, listUnderstandingSourceDefinitions, listUnderstandingSourceGrants, listUnderstandingSourceRuns, listUserFocuses, revokeUnderstandingSourceGrant, setUserFocusStatus, tokenizeUnderstandingSignal, updateUnderstandingSourceGrantCheckpoint, updateUnderstandingSourceRun, upsertUnderstandingSourceGrant, upsertUserFocus };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type UnderstandingSignal = {
|
|
2
|
+
evidenceRef: string;
|
|
3
|
+
sourceId: string;
|
|
4
|
+
title: string;
|
|
5
|
+
group?: string;
|
|
6
|
+
subjectKey?: string;
|
|
7
|
+
occurredAt?: number;
|
|
8
|
+
};
|
|
9
|
+
export type UnderstandingSignalCluster = {
|
|
10
|
+
key: string;
|
|
11
|
+
title: string;
|
|
12
|
+
confidence: number;
|
|
13
|
+
horizon: 'current' | 'ongoing';
|
|
14
|
+
signals: UnderstandingSignal[];
|
|
15
|
+
sourceIds: string[];
|
|
16
|
+
};
|
|
17
|
+
export declare function tokenizeUnderstandingSignal(value: string): Set<string>;
|
|
18
|
+
export declare function clusterUnderstandingSignals(signals: UnderstandingSignal[], now?: number): UnderstandingSignalCluster[];
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
//#region src/user-context/sources/signal-clustering.ts
|
|
3
|
+
const STOP_WORDS = new Set([
|
|
4
|
+
"about",
|
|
5
|
+
"and",
|
|
6
|
+
"bookmark",
|
|
7
|
+
"bookmarks",
|
|
8
|
+
"desktop",
|
|
9
|
+
"document",
|
|
10
|
+
"documents",
|
|
11
|
+
"download",
|
|
12
|
+
"downloads",
|
|
13
|
+
"file",
|
|
14
|
+
"files",
|
|
15
|
+
"from",
|
|
16
|
+
"fwd",
|
|
17
|
+
"guide",
|
|
18
|
+
"home",
|
|
19
|
+
"index",
|
|
20
|
+
"into",
|
|
21
|
+
"latest",
|
|
22
|
+
"new",
|
|
23
|
+
"notes",
|
|
24
|
+
"official",
|
|
25
|
+
"overview",
|
|
26
|
+
"page",
|
|
27
|
+
"plan",
|
|
28
|
+
"profile",
|
|
29
|
+
"project",
|
|
30
|
+
"recent",
|
|
31
|
+
"reply",
|
|
32
|
+
"roadmap",
|
|
33
|
+
"the",
|
|
34
|
+
"this",
|
|
35
|
+
"with",
|
|
36
|
+
"www"
|
|
37
|
+
]);
|
|
38
|
+
function normalizeKey(value) {
|
|
39
|
+
return value?.trim().toLocaleLowerCase() || void 0;
|
|
40
|
+
}
|
|
41
|
+
function tokenizeUnderstandingSignal(value) {
|
|
42
|
+
const normalized = value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLocaleLowerCase().replace(/\.[a-z0-9]{1,8}$/i, "").replace(/https?:\/\//g, " ");
|
|
43
|
+
const tokens = /* @__PURE__ */ new Set();
|
|
44
|
+
for (const token of normalized.match(/[a-z0-9][a-z0-9-]{2,}|[\p{Script=Han}]{2,}/gu) ?? []) {
|
|
45
|
+
if (/^[\p{Script=Han}]+$/u.test(token)) {
|
|
46
|
+
if (token.length <= 4) tokens.add(token);
|
|
47
|
+
else for (let index = 0; index < token.length - 1; index += 1) tokens.add(token.slice(index, index + 2));
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
const clean = token.replace(/^-+|-+$/g, "");
|
|
51
|
+
if (clean.length >= 3 && !STOP_WORDS.has(clean) && !/^\d+$/.test(clean)) tokens.add(clean);
|
|
52
|
+
}
|
|
53
|
+
return tokens;
|
|
54
|
+
}
|
|
55
|
+
function signalTokens(signal) {
|
|
56
|
+
return tokenizeUnderstandingSignal([signal.title, signal.group ?? ""].join(" "));
|
|
57
|
+
}
|
|
58
|
+
function overlap(left, right) {
|
|
59
|
+
let count = 0;
|
|
60
|
+
for (const token of left) if (right.has(token)) count += 1;
|
|
61
|
+
return count;
|
|
62
|
+
}
|
|
63
|
+
function related(left, right) {
|
|
64
|
+
const leftSubject = normalizeKey(left.signal.subjectKey);
|
|
65
|
+
const rightSubject = normalizeKey(right.signal.subjectKey);
|
|
66
|
+
if (leftSubject && leftSubject === rightSubject) return true;
|
|
67
|
+
const shared = overlap(left.tokens, right.tokens);
|
|
68
|
+
if (shared >= 2) return true;
|
|
69
|
+
const smallest = Math.min(left.tokens.size, right.tokens.size);
|
|
70
|
+
if (shared === 1 && smallest <= 2) return true;
|
|
71
|
+
return Boolean(shared === 1 && left.signal.group && normalizeKey(left.signal.group) === normalizeKey(right.signal.group));
|
|
72
|
+
}
|
|
73
|
+
function displayTitle(cluster) {
|
|
74
|
+
const subjects = /* @__PURE__ */ new Map();
|
|
75
|
+
for (const { signal } of cluster) {
|
|
76
|
+
const key = normalizeKey(signal.subjectKey);
|
|
77
|
+
if (!key) continue;
|
|
78
|
+
const current = subjects.get(key);
|
|
79
|
+
subjects.set(key, {
|
|
80
|
+
count: (current?.count ?? 0) + 1,
|
|
81
|
+
label: signal.subjectKey
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
const repeatedSubject = [...subjects.values()].sort((left, right) => right.count - left.count)[0];
|
|
85
|
+
if (repeatedSubject && repeatedSubject.count >= 2) return repeatedSubject.label.slice(0, 80);
|
|
86
|
+
const frequency = /* @__PURE__ */ new Map();
|
|
87
|
+
for (const entry of cluster) for (const token of entry.tokens) frequency.set(token, (frequency.get(token) ?? 0) + 1);
|
|
88
|
+
const shared = [...frequency.entries()].filter(([, count]) => count >= 2).sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0])).slice(0, 3).map(([token]) => token);
|
|
89
|
+
if (shared.length && !shared.every((token) => /^[\p{Script=Han}]+$/u.test(token))) return shared.map((token) => token.charAt(0).toUpperCase() + token.slice(1)).join(" ");
|
|
90
|
+
return cluster[0].signal.title.replace(/\.[a-z0-9]{1,8}$/i, "").slice(0, 80);
|
|
91
|
+
}
|
|
92
|
+
function clusterUnderstandingSignals(signals, now = Date.now()) {
|
|
93
|
+
const prepared = signals.map((signal) => ({
|
|
94
|
+
signal,
|
|
95
|
+
tokens: signalTokens(signal)
|
|
96
|
+
})).filter((entry) => entry.tokens.size > 0 || entry.signal.subjectKey);
|
|
97
|
+
const parent = prepared.map((_, index) => index);
|
|
98
|
+
const find = (index) => parent[index] === index ? index : parent[index] = find(parent[index]);
|
|
99
|
+
const union = (left, right) => {
|
|
100
|
+
const leftRoot = find(left);
|
|
101
|
+
const rightRoot = find(right);
|
|
102
|
+
if (leftRoot !== rightRoot) parent[rightRoot] = leftRoot;
|
|
103
|
+
};
|
|
104
|
+
for (let left = 0; left < prepared.length; left += 1) for (let right = left + 1; right < prepared.length; right += 1) if (related(prepared[left], prepared[right])) union(left, right);
|
|
105
|
+
const clusters = /* @__PURE__ */ new Map();
|
|
106
|
+
prepared.forEach((entry, index) => clusters.set(find(index), [...clusters.get(find(index)) ?? [], entry]));
|
|
107
|
+
return [...clusters.values()].flatMap((cluster) => {
|
|
108
|
+
if (cluster.length < 2) return [];
|
|
109
|
+
const sourceIds = [...new Set(cluster.map(({ signal }) => signal.sourceId))];
|
|
110
|
+
const timestamps = cluster.map(({ signal }) => signal.occurredAt ?? 0).filter(Boolean);
|
|
111
|
+
const newestAt = timestamps.length ? Math.max(...timestamps) : 0;
|
|
112
|
+
const ageDays = newestAt ? Math.max(0, (now - newestAt) / 864e5) : 90;
|
|
113
|
+
const recency = Math.max(0, 1 - ageDays / 90);
|
|
114
|
+
const confidence = Math.min(.92, .48 + Math.min(cluster.length, 5) * .06 + Math.min(sourceIds.length, 3) * .09 + recency * .08);
|
|
115
|
+
const tokenFrequency = /* @__PURE__ */ new Map();
|
|
116
|
+
for (const entry of cluster) for (const token of entry.tokens) tokenFrequency.set(token, (tokenFrequency.get(token) ?? 0) + 1);
|
|
117
|
+
const stableTokens = [...tokenFrequency.entries()].filter(([, count]) => count >= 2).map(([token]) => token).sort();
|
|
118
|
+
const stableSubjects = cluster.map(({ signal }) => normalizeKey(signal.subjectKey)).filter((value) => Boolean(value)).sort();
|
|
119
|
+
const keyMaterial = stableTokens.length ? stableTokens : stableSubjects;
|
|
120
|
+
return [{
|
|
121
|
+
key: createHash("sha256").update((keyMaterial.length ? keyMaterial : cluster.map(({ signal }) => signal.evidenceRef).sort()).join("|")).digest("hex").slice(0, 16),
|
|
122
|
+
title: displayTitle(cluster),
|
|
123
|
+
confidence,
|
|
124
|
+
horizon: ageDays <= 14 ? "current" : "ongoing",
|
|
125
|
+
signals: cluster.map(({ signal }) => signal),
|
|
126
|
+
sourceIds
|
|
127
|
+
}];
|
|
128
|
+
}).sort((left, right) => right.confidence - left.confidence);
|
|
129
|
+
}
|
|
130
|
+
//#endregion
|
|
131
|
+
export { clusterUnderstandingSignals, tokenizeUnderstandingSignal };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type DecodedPcmAudio } from '../local/wav.js';
|
|
2
|
+
export type AudioFormat = 'wav' | 'webm' | 'ogg' | 'mp3' | 'mp4' | 'unknown';
|
|
3
|
+
export declare class AudioNormalizationError extends Error {
|
|
4
|
+
readonly code = "unsupported_audio_codec";
|
|
5
|
+
constructor(message: string, options?: ErrorOptions);
|
|
6
|
+
}
|
|
7
|
+
export declare function detectAudioFormat(buffer: Buffer): AudioFormat;
|
|
8
|
+
export declare function decodeAudioToMonoFloat32(input: {
|
|
9
|
+
buffer: Buffer;
|
|
10
|
+
signal?: AbortSignal;
|
|
11
|
+
}): Promise<DecodedPcmAudio>;
|
|
12
|
+
/** Decodes a recording into bounded PCM WAV files and removes all temporary files afterwards. */
|
|
13
|
+
export declare function forEachNormalizedAudioSegment(input: {
|
|
14
|
+
filePath: string;
|
|
15
|
+
segmentSeconds?: number;
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
}, consume: (buffer: Buffer, index: number) => Promise<void>): Promise<number>;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { decodeWavToMonoFloat32 } from "../local/wav.js";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
import { mkdtemp, readFile, readdir, rm } from "node:fs/promises";
|
|
6
|
+
//#region src/voice/audio/normalize.ts
|
|
7
|
+
const TARGET_SAMPLE_RATE = 16e3;
|
|
8
|
+
const MAX_DECODED_BYTES = TARGET_SAMPLE_RATE * 4 * 15 * 60;
|
|
9
|
+
var AudioNormalizationError = class extends Error {
|
|
10
|
+
code = "unsupported_audio_codec";
|
|
11
|
+
constructor(message, options) {
|
|
12
|
+
super(message, options);
|
|
13
|
+
this.name = "AudioNormalizationError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
function detectAudioFormat(buffer) {
|
|
17
|
+
if (buffer.length >= 12 && buffer.toString("ascii", 0, 4) === "RIFF" && buffer.toString("ascii", 8, 12) === "WAVE") return "wav";
|
|
18
|
+
if (buffer.length >= 4 && buffer.subarray(0, 4).equals(Buffer.from([
|
|
19
|
+
26,
|
|
20
|
+
69,
|
|
21
|
+
223,
|
|
22
|
+
163
|
|
23
|
+
]))) return "webm";
|
|
24
|
+
if (buffer.length >= 4 && buffer.toString("ascii", 0, 4) === "OggS") return "ogg";
|
|
25
|
+
if (buffer.length >= 3 && buffer.toString("ascii", 0, 3) === "ID3") return "mp3";
|
|
26
|
+
if (buffer.length >= 2 && buffer[0] === 255 && (buffer[1] & 224) === 224) return "mp3";
|
|
27
|
+
if (buffer.length >= 12 && buffer.toString("ascii", 4, 8) === "ftyp") return "mp4";
|
|
28
|
+
return "unknown";
|
|
29
|
+
}
|
|
30
|
+
function runFfmpeg(args, options = {}) {
|
|
31
|
+
options.signal?.throwIfAborted();
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const child = spawn("ffmpeg", [
|
|
34
|
+
"-hide_banner",
|
|
35
|
+
"-loglevel",
|
|
36
|
+
"error",
|
|
37
|
+
...args
|
|
38
|
+
], { stdio: [
|
|
39
|
+
options.input ? "pipe" : "ignore",
|
|
40
|
+
"pipe",
|
|
41
|
+
"pipe"
|
|
42
|
+
] });
|
|
43
|
+
const stdout = [];
|
|
44
|
+
const stderr = [];
|
|
45
|
+
let outputBytes = 0;
|
|
46
|
+
let errorBytes = 0;
|
|
47
|
+
let settled = false;
|
|
48
|
+
const finish = (error) => {
|
|
49
|
+
if (settled) return;
|
|
50
|
+
settled = true;
|
|
51
|
+
options.signal?.removeEventListener("abort", abort);
|
|
52
|
+
if (error) reject(error);
|
|
53
|
+
else resolve(Buffer.concat(stdout));
|
|
54
|
+
};
|
|
55
|
+
const abort = () => {
|
|
56
|
+
child.kill("SIGTERM");
|
|
57
|
+
finish(new AudioNormalizationError("Audio decoding was cancelled"));
|
|
58
|
+
};
|
|
59
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
60
|
+
child.stdout.on("data", (chunk) => {
|
|
61
|
+
outputBytes += chunk.length;
|
|
62
|
+
if (options.maxOutputBytes != null && outputBytes > options.maxOutputBytes) {
|
|
63
|
+
child.kill("SIGTERM");
|
|
64
|
+
finish(new AudioNormalizationError("Decoded audio exceeds the supported duration"));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
stdout.push(chunk);
|
|
68
|
+
});
|
|
69
|
+
child.stderr.on("data", (chunk) => {
|
|
70
|
+
if (errorBytes >= 8192) return;
|
|
71
|
+
const bounded = chunk.subarray(0, 8192 - errorBytes);
|
|
72
|
+
stderr.push(bounded);
|
|
73
|
+
errorBytes += bounded.length;
|
|
74
|
+
});
|
|
75
|
+
child.once("error", (error) => {
|
|
76
|
+
finish(new AudioNormalizationError(error.code === "ENOENT" ? "Audio decoder is unavailable; install ffmpeg to transcribe this format" : `Audio decoder failed to start: ${error.message}`, { cause: error }));
|
|
77
|
+
});
|
|
78
|
+
child.once("close", (code) => {
|
|
79
|
+
if (settled) return;
|
|
80
|
+
if (code === 0) finish();
|
|
81
|
+
else finish(new AudioNormalizationError(Buffer.concat(stderr).toString("utf8").trim() || `Unsupported or corrupt audio (decoder exit ${code})`));
|
|
82
|
+
});
|
|
83
|
+
if (options.input) {
|
|
84
|
+
child.stdin.on("error", () => void 0);
|
|
85
|
+
child.stdin.end(options.input);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async function decodeAudioToMonoFloat32(input) {
|
|
90
|
+
if (detectAudioFormat(input.buffer) === "wav") return decodeWavToMonoFloat32(input.buffer);
|
|
91
|
+
const bytes = await runFfmpeg([
|
|
92
|
+
"-i",
|
|
93
|
+
"pipe:0",
|
|
94
|
+
"-map",
|
|
95
|
+
"0:a:0",
|
|
96
|
+
"-vn",
|
|
97
|
+
"-ac",
|
|
98
|
+
"1",
|
|
99
|
+
"-ar",
|
|
100
|
+
String(TARGET_SAMPLE_RATE),
|
|
101
|
+
"-f",
|
|
102
|
+
"f32le",
|
|
103
|
+
"pipe:1"
|
|
104
|
+
], {
|
|
105
|
+
input: input.buffer,
|
|
106
|
+
signal: input.signal,
|
|
107
|
+
maxOutputBytes: MAX_DECODED_BYTES
|
|
108
|
+
});
|
|
109
|
+
if (bytes.length === 0 || bytes.length % 4 !== 0) throw new AudioNormalizationError("Audio decoder produced no usable samples");
|
|
110
|
+
const copied = Uint8Array.from(bytes);
|
|
111
|
+
const samples = new Float32Array(copied.buffer);
|
|
112
|
+
return {
|
|
113
|
+
samples,
|
|
114
|
+
sampleRate: TARGET_SAMPLE_RATE,
|
|
115
|
+
durationSeconds: samples.length / TARGET_SAMPLE_RATE
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** Decodes a recording into bounded PCM WAV files and removes all temporary files afterwards. */
|
|
119
|
+
async function forEachNormalizedAudioSegment(input, consume) {
|
|
120
|
+
const directory = await mkdtemp(join(tmpdir(), "xopc-audio-"));
|
|
121
|
+
const outputPattern = join(directory, "segment-%05d.wav");
|
|
122
|
+
try {
|
|
123
|
+
await runFfmpeg([
|
|
124
|
+
"-i",
|
|
125
|
+
input.filePath,
|
|
126
|
+
"-map",
|
|
127
|
+
"0:a:0",
|
|
128
|
+
"-vn",
|
|
129
|
+
"-ac",
|
|
130
|
+
"1",
|
|
131
|
+
"-ar",
|
|
132
|
+
String(TARGET_SAMPLE_RATE),
|
|
133
|
+
"-c:a",
|
|
134
|
+
"pcm_s16le",
|
|
135
|
+
"-f",
|
|
136
|
+
"segment",
|
|
137
|
+
"-segment_time",
|
|
138
|
+
String(input.segmentSeconds ?? 20),
|
|
139
|
+
"-reset_timestamps",
|
|
140
|
+
"1",
|
|
141
|
+
outputPattern
|
|
142
|
+
], { signal: input.signal });
|
|
143
|
+
const files = (await readdir(directory)).filter((name) => name.endsWith(".wav")).sort();
|
|
144
|
+
if (files.length === 0) throw new AudioNormalizationError("Audio decoder produced no segments");
|
|
145
|
+
for (let index = 0; index < files.length; index += 1) await consume(await readFile(join(directory, files[index])), index);
|
|
146
|
+
return files.length;
|
|
147
|
+
} finally {
|
|
148
|
+
await rm(directory, {
|
|
149
|
+
recursive: true,
|
|
150
|
+
force: true
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
export { AudioNormalizationError, decodeAudioToMonoFloat32, detectAudioFormat, forEachNormalizedAudioSegment };
|
|
@@ -9,10 +9,7 @@ export interface VoiceLanguageProfile {
|
|
|
9
9
|
}
|
|
10
10
|
export declare function resolveVoiceLanguageProfile(language: ProductLanguage): VoiceLanguageProfile;
|
|
11
11
|
export declare function inferProductLanguageFromEnvironment(): ProductLanguage;
|
|
12
|
-
/**
|
|
13
|
-
* Install safe product defaults while preserving every explicit on/off choice.
|
|
14
|
-
* Older configs with a persisted language or Edge voice are treated as manual.
|
|
15
|
-
*/
|
|
12
|
+
/** Install safe product defaults while preserving every explicit on/off choice. */
|
|
16
13
|
export declare function initializeVoiceDefaults(config: Config, language?: ProductLanguage): boolean;
|
|
17
14
|
/** Apply product language only to providers whose language mapping is known. */
|
|
18
15
|
export declare function applyAutomaticVoiceLanguage(config: Config, language: ProductLanguage): boolean;
|
|
@@ -26,22 +26,14 @@ function inferProductLanguageFromEnvironment() {
|
|
|
26
26
|
Intl.DateTimeFormat().resolvedOptions().locale
|
|
27
27
|
].find((value) => typeof value === "string" && value.trim())?.trim().toLowerCase().startsWith("zh") ? "zh" : "en";
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
const local = config.tools?.media?.audio?.providers?.["xopc-local"];
|
|
31
|
-
const edge = config.messages?.tts?.providers?.edge;
|
|
32
|
-
return typeof local?.language === "string" && local.language.trim().length > 0 || typeof edge?.voice === "string" && edge.voice.trim().length > 0 || typeof edge?.lang === "string" && edge.lang.trim().length > 0;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Install safe product defaults while preserving every explicit on/off choice.
|
|
36
|
-
* Older configs with a persisted language or Edge voice are treated as manual.
|
|
37
|
-
*/
|
|
29
|
+
/** Install safe product defaults while preserving every explicit on/off choice. */
|
|
38
30
|
function initializeVoiceDefaults(config, language = inferProductLanguageFromEnvironment()) {
|
|
39
31
|
const before = JSON.stringify({
|
|
40
32
|
voice: config.voice,
|
|
41
33
|
tools: config.tools?.media?.audio,
|
|
42
34
|
tts: config.messages?.tts
|
|
43
35
|
});
|
|
44
|
-
const languageMode = config.voice?.languageMode ??
|
|
36
|
+
const languageMode = config.voice?.languageMode ?? "auto";
|
|
45
37
|
config.voice = {
|
|
46
38
|
...config.voice,
|
|
47
39
|
languageMode,
|
|
@@ -66,21 +58,6 @@ function initializeVoiceDefaults(config, language = inferProductLanguageFromEnvi
|
|
|
66
58
|
}
|
|
67
59
|
}
|
|
68
60
|
};
|
|
69
|
-
config.messages = config.messages ?? {};
|
|
70
|
-
const tts = config.messages.tts;
|
|
71
|
-
config.messages.tts = {
|
|
72
|
-
...tts,
|
|
73
|
-
enabled: tts?.enabled ?? true,
|
|
74
|
-
provider: tts?.provider ?? "edge",
|
|
75
|
-
trigger: tts?.trigger ?? "inbound",
|
|
76
|
-
providers: {
|
|
77
|
-
...tts?.providers ?? {},
|
|
78
|
-
edge: {
|
|
79
|
-
enabled: true,
|
|
80
|
-
...tts?.providers?.edge ?? {}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
61
|
if (languageMode === "auto") applyAutomaticVoiceLanguage(config, language);
|
|
85
62
|
return before !== JSON.stringify({
|
|
86
63
|
voice: config.voice,
|
|
@@ -9,6 +9,7 @@ export declare class LocalVoiceRuntimeClient {
|
|
|
9
9
|
private child;
|
|
10
10
|
private nextId;
|
|
11
11
|
private pending;
|
|
12
|
+
private requestTail;
|
|
12
13
|
request<T>(method: string, params?: Record<string, unknown>, options?: {
|
|
13
14
|
signal?: AbortSignal;
|
|
14
15
|
timeoutMs?: number;
|
|
@@ -16,6 +17,7 @@ export declare class LocalVoiceRuntimeClient {
|
|
|
16
17
|
stopOnTimeout?: boolean;
|
|
17
18
|
onProgress?: (progress: LocalVoiceRuntimeProgress) => void;
|
|
18
19
|
}): Promise<T>;
|
|
20
|
+
private executeRequest;
|
|
19
21
|
stop(): void;
|
|
20
22
|
private ensureStarted;
|
|
21
23
|
private handleLine;
|
|
@@ -35,7 +35,26 @@ var LocalVoiceRuntimeClient = class {
|
|
|
35
35
|
child = null;
|
|
36
36
|
nextId = 1;
|
|
37
37
|
pending = /* @__PURE__ */ new Map();
|
|
38
|
+
requestTail = Promise.resolve();
|
|
38
39
|
async request(method, params = {}, options = {}) {
|
|
40
|
+
options.signal?.throwIfAborted();
|
|
41
|
+
if (method === "health") return this.executeRequest(method, params, options);
|
|
42
|
+
const queued = this.requestTail.then(() => this.executeRequest(method, params, options));
|
|
43
|
+
this.requestTail = queued.then(() => void 0, () => void 0);
|
|
44
|
+
if (!options.signal) return queued;
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
const abort = () => reject(/* @__PURE__ */ new Error("Local voice runtime request aborted"));
|
|
47
|
+
options.signal.addEventListener("abort", abort, { once: true });
|
|
48
|
+
queued.then((value) => {
|
|
49
|
+
options.signal.removeEventListener("abort", abort);
|
|
50
|
+
resolve(value);
|
|
51
|
+
}, (error) => {
|
|
52
|
+
options.signal.removeEventListener("abort", abort);
|
|
53
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async executeRequest(method, params, options) {
|
|
39
58
|
options.signal?.throwIfAborted();
|
|
40
59
|
const child = this.ensureStarted();
|
|
41
60
|
const id = this.nextId++;
|
|
@@ -56,7 +75,7 @@ var LocalVoiceRuntimeClient = class {
|
|
|
56
75
|
const pending = this.pending.get(id);
|
|
57
76
|
if (!pending) return;
|
|
58
77
|
this.deletePending(id);
|
|
59
|
-
pending.reject(/* @__PURE__ */ new Error("Local voice
|
|
78
|
+
pending.reject(/* @__PURE__ */ new Error("Local voice runtime request aborted"));
|
|
60
79
|
this.stop();
|
|
61
80
|
};
|
|
62
81
|
const pending = this.pending.get(id);
|