@xopcai/xopc 0.0.208 → 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-D0mYZqhc.js → activity-store-BzjFoSr0.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-MWLQWL_i.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-DZA1yVzM.js → api-D269PnU9.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-B2X6quAF.js → app-management-settings-panel-BFpfQDWc.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-BZW-c38q.js → appearance-settings-DLxFdqhY.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-CjmlGB5V.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-CK-gsjsJ.js → archive-plugin-DPlH4dnc.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-EJGP4rCw.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-Tbss_4P-.js → binary-plugins-C0tuoPXk.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-C-dOWigw.js → block-editor-Deyphj1o.js} +6 -6
- package/dist/gateway/static/root/assets/browser-settings-page-CAGCYx8U.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-DW06Zo1N.js → browser-workflow-inputs-CYEbXyRF.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-B6RnRGwm.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-Cc3BtQar.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-BvZO5FaO.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-CTDRZa7e.js +36 -0
- package/dist/gateway/static/root/assets/{connectors-api-CUl6_EQJ.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-BD9MgoE_.js → cron-expression-DTLR82NB.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-ChqNmoxw.js → date-picker-DyNogHQH.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-CDUmFs6H.js → dependency-picker-BpnCuo7B.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-D61gqxaD.js → desktop-pet-CDKI4gVB.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-QvuJvIX_.js → desktop-pet-settings-DjT5C2a3.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-DvXMvDNY.js → directory-picker-path-field-DlJY90TM.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DMdVTAQ3.js → extension-debug-page-DWf2z7q5.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BNzxZtaK.js → extension-page-Dorx0kf9.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DoEfyizU.js → extension-settings-page-B1wU9ZOB.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-o7AKvthC.js → gateway-config-api-B1lG4dNr.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-BQbkUP5X.js → gateway-config-swr-BIxuwPQi.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-TO5YYZ9a.js → gateway-settings-DqIOqJjM.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-DIgdpHgk.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-_cuTcWjB.js +107 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-4xaM3jjU.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-C1xDicdr.js → local-apps-page-DfruRAmE.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-pByvK12G.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-D1XdHm7v.js → management-settings-L1VYkywO.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-B_Ijq1Fr.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-CyJlGUxB.js → markdown-view-V4rcPPH0.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-CXXNRROJ.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-rkePB4CB.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-gw-RMQCV.js → page-tabs-CBuCKeyy.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-B8aMScJ2.js → preview-open-alternatives-BQ0tLfPO.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-CjcpkWAz.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-Ch5qq86o.js → runtime-tools-settings-panel-BCfQNzjG.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-DHYWYUFt.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-DlzZx0-i.js → settings-form-section-B9dnKr3M.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-BVLhreQi.js → settings-loading-skeleton-CYDV2JtY.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-BJU-kUnN.js → settings-page-DbrIYfS9.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Cxc-Ejl5.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-hvIuZXMe.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-Dlvuh7D-.js → skills-page-PE16CNw5.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-B6ddOpnf.js → skills-page.utils-nXmBcBxt.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-BdbCAyoA.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-BtdGacMI.js → theme-store-KR5Otp5w.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-CL6qHYJA.js → typed-models-lib-lMZodtDF.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-DysNnqCS.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-UEsO9Jr-.js → voice-api-key-field-CDcv0Wbh.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-B9disASf.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-A0zTQHFQ.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/background-review/coordinator.d.ts +1 -1
- package/dist/src/agent/background-review/coordinator.js +4 -5
- package/dist/src/agent/background-review/run-background-review.js +0 -1
- package/dist/src/agent/background-review/settings.d.ts +1 -2
- package/dist/src/agent/background-review/settings.js +3 -4
- package/dist/src/agent/external-tools/composio-provider.js +8 -4
- 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 +1 -2
- package/dist/src/agent/memory/manager.js +2 -0
- package/dist/src/agent/memory/sensitivity.js +1 -1
- package/dist/src/agent/memory/understanding/service.js +43 -19
- package/dist/src/agent/memory/user-context-coordinator.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +23 -7
- package/dist/src/automations/domain/validation.d.ts +7 -7
- package/dist/src/automations/draft/automation-draft-validator.d.ts +2 -2
- 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/auth-provider-registry.d.ts +2 -1
- package/dist/src/connectors/auth-provider-registry.js +5 -2
- package/dist/src/connectors/composio-sessions.d.ts +39 -0
- package/dist/src/connectors/composio-sessions.js +66 -7
- package/dist/src/connectors/composio.d.ts +4 -1
- package/dist/src/connectors/composio.js +34 -7
- 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/connectors/runtime-adapter-registry.js +14 -1
- 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/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/agent-stream.js +4 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/connectors.js +16 -3
- 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/session-input-handler.d.ts +60 -0
- package/dist/src/gateway/hono/routes/session-input-handler.js +75 -1
- 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/agent-runner.d.ts +9 -1
- package/dist/src/gateway/service/agent-runner.js +9 -0
- package/dist/src/gateway/service/session-input-coordinator.d.ts +12 -0
- package/dist/src/gateway/service/session-input-coordinator.js +63 -6
- package/dist/src/gateway/service.d.ts +8 -0
- package/dist/src/gateway/service.js +18 -0
- 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/retrieval/audit.d.ts +1 -0
- package/dist/src/retrieval/audit.js +8 -0
- package/dist/src/retrieval/candidateFusion.d.ts +5 -0
- package/dist/src/retrieval/candidateFusion.js +20 -0
- package/dist/src/retrieval/queryProfile.d.ts +16 -0
- package/dist/src/retrieval/queryProfile.js +66 -0
- package/dist/src/retrieval/textFeatures.d.ts +5 -0
- package/dist/src/retrieval/textFeatures.js +71 -0
- package/dist/src/session/client-history.d.ts +1 -0
- package/dist/src/session/client-history.js +4 -0
- package/dist/src/session/index.js +1 -1
- package/dist/src/session/store.js +1 -1
- package/dist/src/storage/sqlite/fts.d.ts +0 -4
- package/dist/src/storage/sqlite/fts.js +2 -49
- package/dist/src/storage/sqlite/index.d.ts +3 -2
- package/dist/src/storage/sqlite/index.js +6 -5
- 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/memory-records-repository.js +60 -38
- package/dist/src/storage/sqlite/row-mappers.js +2 -2
- package/dist/src/storage/sqlite/session-repository.js +2 -2
- package/dist/src/storage/sqlite/session-turn-replace-repository.d.ts +34 -0
- package/dist/src/storage/sqlite/session-turn-replace-repository.js +110 -0
- package/dist/src/storage/sqlite/transcript-repository.js +1 -1
- package/dist/src/storage/sqlite/user-context-quality-repository.d.ts +15 -0
- package/dist/src/storage/sqlite/user-context-quality-repository.js +46 -2
- package/dist/src/storage/sqlite/user-context-repository.d.ts +4 -0
- package/dist/src/storage/sqlite/user-context-repository.js +29 -3
- package/dist/src/tasks/home-query-service.d.ts +3 -1
- package/dist/src/tasks/home-query-service.js +73 -70
- package/dist/src/tui/backends/embedded-backend.js +12 -4
- 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/planner.d.ts +1 -0
- package/dist/src/user-context/planner.js +16 -29
- package/dist/src/user-context/retriever.d.ts +15 -0
- package/dist/src/user-context/retriever.js +65 -0
- package/dist/src/user-context/scope.d.ts +7 -0
- package/dist/src/user-context/scope.js +9 -0
- 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-Bl8FQZxW.js +0 -68
- package/dist/gateway/static/root/assets/apps-page-CRUgTO10.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-DrSwolhG.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-NlvDyMwD.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-BWXUznw5.js +0 -7
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-D0loEbzq.js +0 -3
- package/dist/gateway/static/root/assets/channels-settings-CcivCw8U.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-DkHAD2Zn.js +0 -1
- package/dist/gateway/static/root/assets/chat-terminal-dock-DVedGAeX.js +0 -36
- package/dist/gateway/static/root/assets/connectors-page-DlBSlfkv.js +0 -2
- package/dist/gateway/static/root/assets/heartbeat-settings-UZAn1aAQ.js +0 -1
- package/dist/gateway/static/root/assets/home-page-CRJDpy5E.js +0 -3
- package/dist/gateway/static/root/assets/index-BSjP0Wsx.css +0 -2
- package/dist/gateway/static/root/assets/index-C2ZYFBGL.js +0 -85
- package/dist/gateway/static/root/assets/local-app-workbench-page-D9bguWRo.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-Gr-nE4nW.js +0 -2
- package/dist/gateway/static/root/assets/markdown-view-B12xeflb.css +0 -1
- package/dist/gateway/static/root/assets/messages-yG5P43Q9.js +0 -3
- package/dist/gateway/static/root/assets/notes-workbench-CpbD4XG2.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-GvSYDbjR.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-DPRxKGbs.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-WIzeu-gB.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-2XEJM0YE.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-g1GThZ0O.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-C6qj2L-q.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-BBpE1bep.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DXORBJNk.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-DC0hc8hp.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-Bwg4KV8B.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-CmPfOfHl.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-DhQNh7W6.js +0 -5
- package/dist/src/voice/local/runtime-dispatcher.d.ts +0 -9
- package/dist/src/voice/local/runtime-dispatcher.js +0 -20
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { summarizeUnderstandingFeedback } from "../storage/sqlite/user-context-quality-repository.js";
|
|
2
|
+
import { listUnderstandings, searchActiveUnderstandings } from "../storage/sqlite/user-context-repository.js";
|
|
3
|
+
import { normalizeRetrievalText, retrievalLexicalSimilarity } from "../retrieval/textFeatures.js";
|
|
4
|
+
import { buildRetrievalQueryProfile } from "../retrieval/queryProfile.js";
|
|
5
|
+
import "../storage/sqlite/index.js";
|
|
6
|
+
import { matchesUserContextScope } from "./scope.js";
|
|
7
|
+
//#region src/user-context/retriever.ts
|
|
8
|
+
function authorityBonus(item) {
|
|
9
|
+
if (item.explicitness === "explicit") return .1;
|
|
10
|
+
if (item.explicitness === "observed") return .05;
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
function baseline(item) {
|
|
14
|
+
if (item.kind === "boundary" && item.explicitness === "explicit") return .8;
|
|
15
|
+
if (item.kind === "preference" && item.explicitness === "explicit") return .35;
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
function feedbackAdjustment(summary) {
|
|
19
|
+
if (!summary || summary.total < 3) return 0;
|
|
20
|
+
const helpfulRate = (summary.helpful + 1) / (summary.total + 2);
|
|
21
|
+
const relevancePenalty = summary.irrelevant >= 3 ? .05 : 0;
|
|
22
|
+
return Math.max(-.1, Math.min(.05, (helpfulRate - .5) * .1 - relevancePenalty));
|
|
23
|
+
}
|
|
24
|
+
var UserUnderstandingRetriever = class {
|
|
25
|
+
retrieve(params) {
|
|
26
|
+
const profile = buildRetrievalQueryProfile(params.query, {
|
|
27
|
+
sessionKey: params.sessionKey,
|
|
28
|
+
workspaceId: params.workspaceId,
|
|
29
|
+
...params.projectId ? { projectId: params.projectId } : {}
|
|
30
|
+
});
|
|
31
|
+
if (!profile.normalized) return [];
|
|
32
|
+
const maxCandidates = Math.max(1, Math.min(200, Math.floor(params.maxCandidates)));
|
|
33
|
+
const fts = searchActiveUnderstandings(profile.normalized, Math.max(50, maxCandidates));
|
|
34
|
+
const ftsScores = new Map(fts.map((result) => [result.understanding.id, result.score]));
|
|
35
|
+
const recentLimit = Math.max(200, Math.min(500, maxCandidates * 5));
|
|
36
|
+
const recent = listUnderstandings(["active"]).slice(0, recentLimit);
|
|
37
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
38
|
+
for (const result of fts) candidates.set(result.understanding.id, result.understanding);
|
|
39
|
+
for (const item of recent) candidates.set(item.id, item);
|
|
40
|
+
const feedback = new Map(summarizeUnderstandingFeedback([...candidates.keys()]).map((summary) => [summary.understandingId, summary]));
|
|
41
|
+
return [...candidates.values()].map((item) => {
|
|
42
|
+
const lexical = retrievalLexicalSimilarity(profile.normalized, item.statement);
|
|
43
|
+
const ftsScore = ftsScores.get(item.id) ?? 0;
|
|
44
|
+
const textScore = Math.max(lexical, ftsScore);
|
|
45
|
+
const kindMatched = profile.intentKinds.includes(item.kind);
|
|
46
|
+
const normalizedStatement = normalizeRetrievalText(item.statement);
|
|
47
|
+
const identifierMatched = profile.identifiers.some((identifier) => normalizedStatement.includes(identifier));
|
|
48
|
+
const feedbackScore = feedbackAdjustment(feedback.get(item.id));
|
|
49
|
+
return {
|
|
50
|
+
understanding: item,
|
|
51
|
+
score: Math.min(1, Math.max(0, Math.max(baseline(item), textScore * .7 + lexical * .1 + item.confidence * .1 + authorityBonus(item) + (kindMatched ? .08 : 0) + (identifierMatched ? .12 : 0) + (matchesUserContextScope(item.scope, params) && item.scope.type !== "global" ? .05 : 0)) + feedbackScore)),
|
|
52
|
+
reasons: [
|
|
53
|
+
ftsScore > 0 ? "fts" : "",
|
|
54
|
+
lexical > 0 ? "lexical" : "",
|
|
55
|
+
identifierMatched ? "identifier" : "",
|
|
56
|
+
kindMatched ? "kind" : "",
|
|
57
|
+
item.explicitness === "explicit" ? "explicit" : "",
|
|
58
|
+
feedbackScore !== 0 ? "feedback" : ""
|
|
59
|
+
].filter(Boolean)
|
|
60
|
+
};
|
|
61
|
+
}).sort((left, right) => Number(matchesUserContextScope(right.understanding.scope, params)) - Number(matchesUserContextScope(left.understanding.scope, params)) || right.score - left.score || right.understanding.updatedAt - left.understanding.updatedAt).slice(0, maxCandidates);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
//#endregion
|
|
65
|
+
export { UserUnderstandingRetriever };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { UserContextScope } from './domain.js';
|
|
2
|
+
export interface UserContextScopeTarget {
|
|
3
|
+
sessionKey: string;
|
|
4
|
+
workspaceId: string;
|
|
5
|
+
projectId?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function matchesUserContextScope(scope: UserContextScope, target: UserContextScopeTarget): boolean;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/user-context/scope.ts
|
|
2
|
+
function matchesUserContextScope(scope, target) {
|
|
3
|
+
if (scope.type === "global") return true;
|
|
4
|
+
if (scope.type === "session") return scope.id === target.sessionKey;
|
|
5
|
+
if (scope.type === "workspace") return scope.id === target.workspaceId;
|
|
6
|
+
return Boolean(target.projectId && scope.id === target.projectId);
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { matchesUserContextScope };
|
|
@@ -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;
|