@xopcai/xopc 0.0.389 → 0.0.391
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-dvik6t7Z.js → activity-store-DWQCDi8M.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-bWMd5TDC.js → agent-avatar-dicebear-CzS0TUv9.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-DE910MyU.js +1 -0
- package/dist/gateway/static/root/assets/{agent-plugin-dialog-UunIxc1q.js → agent-plugin-dialog-0SlvsYl7.js} +1 -1
- package/dist/gateway/static/root/assets/agents-BZh28Qn1.js +77 -0
- package/dist/gateway/static/root/assets/{agents-admin-api-BlNGyXpm.js → agents-admin-api-Bb3Kvz3X.js} +1 -1
- package/dist/gateway/static/root/assets/app-management-settings-panel-9A7JN5V5.js +1 -0
- package/dist/gateway/static/root/assets/{appearance-settings-CUAdx44v.js → appearance-settings-BPdLEo6L.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-D5zDB6gp.js → apps-page-Cz7LypV9.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-Du6dJNcl.js → archive-plugin-DFnHPNie.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-BO8Ig5Z4.js → automations-page-CnBLPVNh.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-BBjS-sk-.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-D7VJjwnr.js → binary-plugins-BQC0Tzoi.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CaJlWTAn.js → block-editor-DSh5019z.js} +4 -4
- package/dist/gateway/static/root/assets/{browser-automation-inputs-iyMBJmQX.js → browser-automation-inputs-C5tIrIRL.js} +1 -1
- package/dist/gateway/static/root/assets/browser-automations-page-CFCMNfJN.js +3 -0
- package/dist/gateway/static/root/assets/browser-settings-page-C__tyPwu.js +3 -0
- package/dist/gateway/static/root/assets/{capabilities-CEH1AnXc.js → capabilities-D6RJG4QY.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-MCKRMZDK.js → capabilities-DGEmBQnF.js} +1 -1
- package/dist/gateway/static/root/assets/capabilities-page-B5AZa7ir.js +2 -0
- package/dist/gateway/static/root/assets/capabilities-settings-panel-Dskz2_bh.js +8 -0
- package/dist/gateway/static/root/assets/{capability-header-actions-BIA0Lwt5.js → capability-header-actions-xzjWZVbg.js} +1 -1
- package/dist/gateway/static/root/assets/channels-DRse_dD3.js +1 -0
- package/dist/gateway/static/root/assets/chat-terminal-dock-CQF0M4kE.js +36 -0
- package/dist/gateway/static/root/assets/{computer-settings-page-DvY3zgyY.js → computer-settings-page-ZfzCTS0N.js} +1 -1
- package/dist/gateway/static/root/assets/{connector-service-page-St2-Fj3y.js → connector-service-page-CwAeWVLK.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-CanakKaj.js +1 -0
- package/dist/gateway/static/root/assets/{date-picker-C0-D80ny.js → date-picker-hmJlEAQZ.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-CNd7mwMU.js → dependency-picker-Us_Juz6I.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-C-2wDANn.js → desktop-pet-CvOTI4uw.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-DyhxLrdJ.js → desktop-pet-settings-DYg-Gb8t.js} +1 -1
- package/dist/gateway/static/root/assets/device-pairing-wizard-B1FbZ8C1.js +1 -0
- package/dist/gateway/static/root/assets/{directory-picker-path-field-CNivVIPT.js → directory-picker-path-field-DZN9EDvM.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-CGYO3JPw.js → extension-debug-page-YIibp6Kk.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-Dc51ALAg.js → extension-page-DkcGyb28.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-provider-BXPILdlw.js → extension-provider-B1PQGTtY.js} +1 -1
- package/dist/gateway/static/root/assets/extension-settings-page-C_rJiSKo.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-config-swr-Bc2MytsF.js → gateway-config-swr-Dv_A5FMu.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-realtime-BFK-vlME.js → gateway-realtime-DghCGfY_.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-realtime-store-CMJVSnvi.js +1 -0
- package/dist/gateway/static/root/assets/gateway-settings-CjCWPHNJ.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-BDPMttPx.js → gateway-startup-retry-CkTVSESs.js} +1 -1
- package/dist/gateway/static/root/assets/{highlighted-body-KQOG7T2V-DAlRGMge.js → highlighted-body-KQOG7T2V-DV2wNqBn.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-fAYsd7kG.js +2 -0
- package/dist/gateway/static/root/assets/image-generation-api-B98iXt6A.js +1 -0
- package/dist/gateway/static/root/assets/imports-page-DoBCBN8G.js +1 -0
- package/dist/gateway/static/root/assets/index-DFgXwLsv.js +260 -0
- package/dist/gateway/static/root/assets/index-a6ZvhclR.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BYYC9Qmw.js → keyboard-shortcuts-settings-DXVu4lqV.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-B3fz6uRi.js +1 -0
- package/dist/gateway/static/root/assets/{local-apps-page-BU8pUsVM.js → local-apps-page-BC6xhmUh.js} +1 -1
- package/dist/gateway/static/root/assets/{local-session-drafts-kFc_MAA9.js → local-session-drafts-DFnZQu9A.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-Dr43FCty.js → locale-store-BpK9AiDq.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-CSqSFDRU.js +2 -0
- package/dist/gateway/static/root/assets/management-settings-gq5L0THs.js +1 -0
- package/dist/gateway/static/root/assets/{markdown-view-CdKlPjJM.js → markdown-view-IsYTotu6.js} +18 -18
- package/dist/gateway/static/root/assets/{media-plugins-DE9zt88i.js → media-plugins-oSChWbcP.js} +1 -1
- package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-C_QKwqDN.js +1 -0
- package/dist/gateway/static/root/assets/messages-CKTo_sIF.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-cache-TjpL7hZ5.js +1 -0
- package/dist/gateway/static/root/assets/note-detail-panel-CdpNXre-.js +5 -0
- package/dist/gateway/static/root/assets/{notes-api-BHouNL6-.js → notes-api-CBb944yw.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-EGvGw8MN.js +8 -0
- package/dist/gateway/static/root/assets/{page-context-capture-button-TQr8NnSc.js → page-context-capture-button-CoWb7BYP.js} +1 -1
- package/dist/gateway/static/root/assets/personal-page-DYzbNTyN.js +1 -0
- package/dist/gateway/static/root/assets/{product-open-page-BEl6syFp.js → product-open-page-CTyy7H7-.js} +1 -1
- package/dist/gateway/static/root/assets/{product-preview-content-BxSHnbqz.js → product-preview-content-D4xqTaEy.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DIVCw0QQ.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-B4L9VnBN.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-BD5IgDOA.js → registry-api-Dsa2LvRt.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-B8PvgLVz.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-api-CjTRoQWT.js → runtime-tools-api-C2Uw89eY.js} +1 -1
- package/dist/gateway/static/root/assets/runtime-tools-settings-panel-Bqnp3tyt.js +1 -0
- package/dist/gateway/static/root/assets/scenes-page-D50g4GM2.js +2 -0
- package/dist/gateway/static/root/assets/{schema-form-ByG-R6N2.js → schema-form-h_RCNfiO.js} +1 -1
- package/dist/gateway/static/root/assets/{send-session-input-UAVStisp.js → send-session-input-DypbVTT7.js} +1 -1
- package/dist/gateway/static/root/assets/{session-api-DvgEiNRS.js → session-api-ga-SUOq_.js} +1 -1
- package/dist/gateway/static/root/assets/{session-manager-BOb1tC_Z.js → session-manager-C_OiKblh.js} +8 -8
- package/dist/gateway/static/root/assets/sessions-page-BsqDIbIr.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-D3zJAW4p.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-C1e9m23j.js → settings-page-DPCgrICd.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-jjSYJpDd.js +1 -0
- package/dist/gateway/static/root/assets/{share-link-dialog-kE_6v5Dp.js → share-link-dialog-BGicglAS.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-BT-_yR1h.js → share-preview-page-BORe9rLB.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-api-Dg_SqHQE.js → shares-api-Dbx3z6-1.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-C13FgfWk.js +1 -0
- package/dist/gateway/static/root/assets/{skill-api-BslUYMnX.js → skill-api-Cq6O1DZK.js} +1 -1
- package/dist/gateway/static/root/assets/{skill-reload-api-BQ2rTOP1.js → skill-reload-api-Cq7QDjMA.js} +1 -1
- package/dist/gateway/static/root/assets/skills-page-BM1ShEjx.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-GpbPfWwo.js → system-settings-panel-BNCGFO1e.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-4VG82wcF.js +2 -0
- package/dist/gateway/static/root/assets/{task-expandable-content-DJrrEBB4.js → task-expandable-content-DAZGz5YC.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-BKpYnggg.js → theme-store-Db7hDESt.js} +1 -1
- package/dist/gateway/static/root/assets/{tracing-settings-page-D71w7dwV.js → tracing-settings-page-C6p2Mu92.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-BV46CvS8.js → tunnel-api-Dw15EJp0.js} +1 -1
- package/dist/gateway/static/root/assets/usage-page-DDrIqgGe.js +1 -0
- package/dist/gateway/static/root/assets/{use-autosave-CzyqRffr.js → use-autosave-DDjIdW4U.js} +1 -1
- package/dist/gateway/static/root/assets/{use-composer-attachments-Dviq-1f6.js → use-composer-attachments-DNl7O3Vb.js} +1 -1
- package/dist/gateway/static/root/assets/{use-file-preview-expanded-D5Kk7Hon.js → use-file-preview-expanded-DMHehhwG.js} +2 -2
- package/dist/gateway/static/root/assets/user-model-page-CaS9dOIr.js +2 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-DWtbmacd.js → voice-api-key-field-ByAxHE4P.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-DnIjZm_9.js → voice-config-api-Dl39b27p.js} +1 -1
- package/dist/gateway/static/root/assets/voice-transcribe-api-CVaU83Jc.js +1 -0
- package/dist/gateway/static/root/assets/{work-discovery-overlay-ChEG71hz.js → work-discovery-overlay-BvVvPA1T.js} +1 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-BcFm9QcC.js +3 -0
- package/dist/gateway/static/root/assets/workflows-page-DMec_XZB.js +6 -0
- package/dist/gateway/static/root/assets/{workspace-api-CZDvu7uA.js → workspace-api-BpfKsrtP.js} +2 -2
- package/dist/gateway/static/root/assets/{xopc-cloud-account-card-CbUgg1SK.js → xopc-cloud-account-card-CU5lzzE9.js} +1 -1
- package/dist/gateway/static/root/index.html +28 -35
- package/dist/package.js +1 -1
- package/dist/packages/gateway-contract/src/discussions.js +3 -2
- package/dist/packages/gateway-contract/src/index.js +4 -0
- package/dist/packages/gateway-contract/src/provider-setup.js +6 -0
- package/dist/packages/gateway-contract/src/recording-outcome.js +6 -0
- package/dist/packages/image-providers/src/catalog.js +10 -0
- package/dist/packages/image-providers/src/execute.js +5 -1
- package/dist/packages/image-providers/src/validation.js +19 -1
- package/dist/src/agent/agent-manager.d.ts +1 -0
- package/dist/src/agent/agent-manager.js +4 -1
- package/dist/src/agent/background-review/run-background-review.d.ts +0 -1
- package/dist/src/agent/background-review/run-background-review.js +10 -2
- package/dist/src/agent/context/execution-scope.js +1 -1
- package/dist/src/agent/embedded/execution-tool-policy.d.ts +2 -0
- package/dist/src/agent/embedded/execution-tool-policy.js +8 -3
- package/dist/src/agent/embedded/run-for-session.js +26 -3
- package/dist/src/agent/embedded/run-turn.js +14 -1
- package/dist/src/agent/embedded/session-runner.js +1 -1
- package/dist/src/agent/embedded/xopc-stream-bridge.js +3 -0
- package/dist/src/agent/image/generation/runtime.js +12 -14
- package/dist/src/agent/image/understanding/runtime.js +5 -0
- package/dist/src/agent/inbound/inbound-loop.d.ts +1 -15
- package/dist/src/agent/inbound/inbound-loop.js +5 -0
- package/dist/src/agent/mcp/connection-errors.d.ts +3 -0
- package/dist/src/agent/mcp/connection-errors.js +32 -0
- package/dist/src/agent/mcp/connection-setup.d.ts +2 -0
- package/dist/src/agent/mcp/connection-setup.js +38 -18
- package/dist/src/agent/memory/compaction.js +5 -1
- package/dist/src/agent/memory/idle-compaction-scheduler.js +3 -1
- package/dist/src/agent/models/manager.d.ts +1 -0
- package/dist/src/agent/models/manager.js +4 -2
- package/dist/src/agent/orchestration/agent-orchestrator.d.ts +1 -6
- package/dist/src/agent/orchestration/agent-orchestrator.js +5 -0
- package/dist/src/agent/service/process-direct-one-shot.js +5 -0
- package/dist/src/agent/service/process-direct-streaming.d.ts +1 -0
- package/dist/src/agent/service/process-direct-streaming.js +17 -1
- package/dist/src/agent/tools/factory.js +14 -12
- package/dist/src/agent/tools/image-generate-tool.js +5 -1
- package/dist/src/agent/tools/personal-read-tool.js +4 -0
- package/dist/src/agent/tools/task-collaboration-tool.js +1 -1
- package/dist/src/agent-config/resolver.js +5 -0
- package/dist/src/agent-config/schema.d.ts +26 -6
- package/dist/src/agent-config/schema.js +2 -0
- package/dist/src/ai-assist/text-assist.js +5 -16
- package/dist/src/automations/service/action-executor.js +3 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/config/agent-model-intents.js +4 -1
- package/dist/src/config/schema.d.ts +11 -5
- package/dist/src/config/schema.js +11 -3
- package/dist/src/discussions/analyzer.d.ts +2 -0
- package/dist/src/discussions/analyzer.js +38 -9
- package/dist/src/discussions/audio-clip.d.ts +3 -0
- package/dist/src/discussions/audio-clip.js +72 -0
- package/dist/src/discussions/live-worker.js +3 -1
- package/dist/src/discussions/long-review.d.ts +17 -0
- package/dist/src/discussions/long-review.js +278 -0
- package/dist/src/discussions/media-timeline.d.ts +21 -0
- package/dist/src/discussions/media-timeline.js +134 -0
- package/dist/src/discussions/organizer-worker.d.ts +4 -1
- package/dist/src/discussions/organizer-worker.js +17 -12
- package/dist/src/discussions/organizer.js +2 -0
- package/dist/src/discussions/processing.d.ts +43 -0
- package/dist/src/discussions/processing.js +125 -0
- package/dist/src/discussions/recording.js +202 -42
- package/dist/src/discussions/recordingJobs.js +2 -0
- package/dist/src/discussions/repository.js +4 -2
- package/dist/src/discussions/review.d.ts +8 -0
- package/dist/src/discussions/review.js +183 -0
- package/dist/src/discussions/sealer.d.ts +7 -1
- package/dist/src/discussions/sealer.js +163 -87
- package/dist/src/discussions/service.d.ts +7 -1
- package/dist/src/discussions/service.js +51 -15
- package/dist/src/discussions/types.d.ts +2 -1
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/global-defaults-admin.d.ts +3 -1
- package/dist/src/gateway/global-defaults-admin.js +14 -2
- package/dist/src/gateway/hono/lib/config-payload.d.ts +11 -2
- package/dist/src/gateway/hono/lib/config-payload.js +2 -0
- package/dist/src/gateway/hono/lib/voice-settings-revisions.d.ts +5 -0
- package/dist/src/gateway/hono/lib/voice-settings-revisions.js +24 -0
- package/dist/src/gateway/hono/routes/commands-skills.js +15 -0
- package/dist/src/gateway/hono/routes/config-patch/misc.js +8 -1
- package/dist/src/gateway/hono/routes/config.js +12 -0
- package/dist/src/gateway/hono/routes/discussions.js +63 -1
- package/dist/src/gateway/hono/routes/global-defaults.js +8 -1
- package/dist/src/gateway/hono/routes/models.js +12 -4
- package/dist/src/gateway/hono/routes/provider-setup.d.ts +3 -0
- package/dist/src/gateway/hono/routes/provider-setup.js +106 -0
- package/dist/src/gateway/hono/routes/status.js +2 -0
- package/dist/src/gateway/hono/routes/voice.js +23 -10
- package/dist/src/gateway/provider-model-setup.d.ts +4 -0
- package/dist/src/gateway/provider-model-setup.js +56 -0
- package/dist/src/gateway/service/config-coordinator.d.ts +2 -2
- package/dist/src/gateway/service.js +2 -0
- package/dist/src/media-shared/http/provider-http.d.ts +0 -6
- package/dist/src/media-shared/http/provider-http.js +5 -4
- package/dist/src/media-understanding/runner.d.ts +0 -28
- package/dist/src/media-understanding/runner.js +4 -0
- package/dist/src/platform/client.d.ts +1 -1
- package/dist/src/platform/contracts.d.ts +1 -1
- package/dist/src/providers/env-keys.js +3 -0
- package/dist/src/providers/extension-stream-bridge.js +3 -0
- package/dist/src/providers/index.js +15 -0
- package/dist/src/providers/model-call.d.ts +5 -2
- package/dist/src/providers/model-call.js +13 -2
- package/dist/src/providers/model-reference-auditor.js +1 -0
- package/dist/src/providers/model-response.js +1 -1
- package/dist/src/providers/model-usage.d.ts +15 -0
- package/dist/src/providers/model-usage.js +50 -0
- package/dist/src/providers/presentation.js +8 -0
- package/dist/src/providers/setup/engine.d.ts +37 -0
- package/dist/src/providers/setup/engine.js +177 -0
- package/dist/src/providers/setup/profiles.d.ts +4 -0
- package/dist/src/providers/setup/profiles.js +78 -0
- package/dist/src/providers/setup/voice.d.ts +23 -0
- package/dist/src/providers/setup/voice.js +234 -0
- package/dist/src/scenes/agentExecutor.d.ts +1 -0
- package/dist/src/scenes/agentExecutor.js +5 -0
- package/dist/src/storage/sqlite/migrations/253_discussion_processing_recovery.sql +20 -0
- package/dist/src/storage/sqlite/migrations/254_discussion_annotations.sql +17 -0
- package/dist/src/storage/sqlite/migrations/255_discussion_chapter_progress.sql +10 -0
- package/dist/src/storage/sqlite/migrations/256_task_main_update_retries.sql +21 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/tasks/task-collaboration-repository.d.ts +2 -0
- package/dist/src/tasks/task-collaboration-repository.js +7 -1
- package/dist/src/tasks/task-main-update-delivery.js +11 -4
- package/dist/src/tasks/task-main-update-input.js +2 -1
- package/dist/src/tasks/task-main-update-retry.d.ts +5 -0
- package/dist/src/tasks/task-main-update-retry.js +15 -0
- package/dist/src/usage/recorder.js +2 -1
- package/dist/src/usage/scenario-registry.js +128 -123
- package/dist/src/voice/dashscope/streaming-stt-session.js +3 -0
- package/dist/src/voice/dashscope/streaming-tts-stream.js +3 -0
- package/dist/src/voice/dictation.d.ts +12 -0
- package/dist/src/voice/dictation.js +22 -0
- package/dist/src/voice/metadata/builtin.js +54 -0
- package/dist/src/voice/platform-streams.js +3 -0
- package/dist/src/voice/realtime/omniEngine.js +3 -0
- package/dist/src/voice/realtime/omniRoute.js +3 -2
- package/dist/src/voice/realtime/runtime.js +4 -2
- package/dist/src/voice/stt/factory.js +9 -3
- package/dist/src/voice/stt/providers/bailian-plan-transcription.d.ts +2 -0
- package/dist/src/voice/stt/providers/bailian-plan-transcription.js +32 -0
- package/dist/src/voice/stt/providers/index.d.ts +1 -0
- package/dist/src/voice/stt/providers/index.js +2 -1
- package/dist/src/voice/token-plan.d.ts +8 -0
- package/dist/src/voice/token-plan.js +11 -0
- package/dist/src/voice/tts/factory.js +4 -1
- package/dist/src/voice/tts/providers/bailian-plan-speech.d.ts +2 -0
- package/dist/src/voice/tts/providers/bailian-plan-speech.js +84 -0
- package/dist/src/voice/tts/providers/index.d.ts +1 -0
- package/dist/src/voice/tts/providers/index.js +2 -1
- package/dist/src/voice/tts/speak-core.js +10 -1
- package/package.json +2 -2
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-Ds0Ue2FB.js +0 -1
- package/dist/gateway/static/root/assets/agents-BLRM4o-U.js +0 -77
- package/dist/gateway/static/root/assets/app-management-settings-panel-Dmy828Pe.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-UcCneEs3.js +0 -6
- package/dist/gateway/static/root/assets/bot-DjLkhyZL.js +0 -1
- package/dist/gateway/static/root/assets/browser-automations-page-BjvQnYfO.js +0 -3
- package/dist/gateway/static/root/assets/browser-settings-page-D5ZghI28.js +0 -3
- package/dist/gateway/static/root/assets/capabilities-page-MC8qIrXo.js +0 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-Blz3hEzp.js +0 -8
- package/dist/gateway/static/root/assets/channels-DSg_iCVC.js +0 -1
- package/dist/gateway/static/root/assets/chat-terminal-dock-C97SJEwd.js +0 -36
- package/dist/gateway/static/root/assets/circle-pause-CN9jYH2s.js +0 -1
- package/dist/gateway/static/root/assets/clock-3-DnrAnuyZ.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-DXk-GAsd.js +0 -1
- package/dist/gateway/static/root/assets/device-pairing-wizard-BeSuq__I.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-jYu6qpY2.js +0 -1
- package/dist/gateway/static/root/assets/fallback-models-CoyzvDo7.js +0 -1
- package/dist/gateway/static/root/assets/gateway-realtime-store-C3vH-Iup.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-JlT1dlSj.js +0 -1
- package/dist/gateway/static/root/assets/git-branch-Dh9uxTot.js +0 -1
- package/dist/gateway/static/root/assets/home-page-DOVl8s-1.js +0 -2
- package/dist/gateway/static/root/assets/image-generation-api-BZBiYDmV.js +0 -1
- package/dist/gateway/static/root/assets/imports-page-DgdBTp_0.js +0 -1
- package/dist/gateway/static/root/assets/index-CmC8JkSM.js +0 -260
- package/dist/gateway/static/root/assets/index-Dgzc0oBu.css +0 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-BKZfn-MS.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-BSepiACn.js +0 -2
- package/dist/gateway/static/root/assets/management-settings-dE_ykPNY.js +0 -1
- package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-65SE6j-_.js +0 -1
- package/dist/gateway/static/root/assets/message-square-fVE7Ghj1.js +0 -1
- package/dist/gateway/static/root/assets/messages-DlTNQI92.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-cache-C7FAsEe_.js +0 -1
- package/dist/gateway/static/root/assets/note-detail-panel-D9oqhdyk.js +0 -5
- package/dist/gateway/static/root/assets/notes-page-Bd4_7ph8.js +0 -8
- package/dist/gateway/static/root/assets/pause-DuPxgSxk.js +0 -1
- package/dist/gateway/static/root/assets/personal-page-BvWzq4Wp.js +0 -1
- package/dist/gateway/static/root/assets/play-kxZvpBg8.js +0 -1
- package/dist/gateway/static/root/assets/project-detail-page-D-qkIXVT.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-BQtw1Dfn.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CYFNz0Jc.js +0 -1
- package/dist/gateway/static/root/assets/runtime-tools-settings-panel-Qq_NyYx_.js +0 -1
- package/dist/gateway/static/root/assets/scenes-page-hGr-ppYk.js +0 -2
- package/dist/gateway/static/root/assets/sessions-page-CpX1Rluw.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-D2s_MlxR.js +0 -1
- package/dist/gateway/static/root/assets/settings-loading-skeleton-BTqvr_Fw.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-BiHRYDHq.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-DfcAu08T.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-CvKc5nBN.js +0 -2
- package/dist/gateway/static/root/assets/sparkles-DHlfQFAF.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-5B5ZVAu0.js +0 -2
- package/dist/gateway/static/root/assets/usage-page-rMuwNpJi.js +0 -1
- package/dist/gateway/static/root/assets/user-model-page-Dhqw3v_u.js +0 -2
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-pdiRKLxP.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-D9LMxINt.js +0 -6
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { spawnProcess } from "../process/run-process.js";
|
|
2
|
+
import { DiscussionServiceError } from "./errors.js";
|
|
3
|
+
import { getDiscussionCapture } from "./repository.js";
|
|
4
|
+
//#region src/discussions/audio-clip.ts
|
|
5
|
+
let active = 0;
|
|
6
|
+
/** A bounded playback derivative for native clients that require per-request device proofs. */
|
|
7
|
+
async function discussionAudioClip(id, startMs, endMs, notes, signal) {
|
|
8
|
+
if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || startMs < 0 || endMs <= startMs || endMs - startMs > 12e4) throw new DiscussionServiceError("invalid_input", "Audio clip must be at most 120 seconds");
|
|
9
|
+
const capture = getDiscussionCapture(id);
|
|
10
|
+
if (!capture || !capture.audioAttachmentId || capture.audioDeletedAt) throw new DiscussionServiceError("not_found", "Original audio unavailable");
|
|
11
|
+
const source = await notes.getAttachmentPath(capture.noteId, capture.audioAttachmentId);
|
|
12
|
+
if (!source) throw new DiscussionServiceError("not_found", "Original audio unavailable");
|
|
13
|
+
if (active >= 2) throw new DiscussionServiceError("conflict", "Audio playback is busy; retry shortly");
|
|
14
|
+
active++;
|
|
15
|
+
try {
|
|
16
|
+
return await new Promise((resolve, reject) => {
|
|
17
|
+
signal.throwIfAborted();
|
|
18
|
+
const handle = spawnProcess({
|
|
19
|
+
program: process.env.XOPC_FFMPEG_PATH || "ffmpeg",
|
|
20
|
+
args: [
|
|
21
|
+
"-v",
|
|
22
|
+
"error",
|
|
23
|
+
"-protocol_whitelist",
|
|
24
|
+
"file,pipe",
|
|
25
|
+
"-ss",
|
|
26
|
+
String(startMs / 1e3),
|
|
27
|
+
"-i",
|
|
28
|
+
source.filePath,
|
|
29
|
+
"-t",
|
|
30
|
+
String((endMs - startMs) / 1e3),
|
|
31
|
+
"-map",
|
|
32
|
+
"0:a:0",
|
|
33
|
+
"-vn",
|
|
34
|
+
"-ar",
|
|
35
|
+
"16000",
|
|
36
|
+
"-ac",
|
|
37
|
+
"1",
|
|
38
|
+
"-f",
|
|
39
|
+
"wav",
|
|
40
|
+
"pipe:1"
|
|
41
|
+
],
|
|
42
|
+
maxOutputBytes: 0
|
|
43
|
+
});
|
|
44
|
+
const child = handle.child;
|
|
45
|
+
const chunks = [];
|
|
46
|
+
let bytes = 0;
|
|
47
|
+
const abort = () => {
|
|
48
|
+
handle.terminate();
|
|
49
|
+
reject(/* @__PURE__ */ new Error("Audio clip interrupted"));
|
|
50
|
+
};
|
|
51
|
+
const timer = setTimeout(abort, 3e4);
|
|
52
|
+
timer.unref();
|
|
53
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
54
|
+
child.stdout?.on("data", (chunk) => {
|
|
55
|
+
bytes += chunk.length;
|
|
56
|
+
if (bytes > 4 * 1024 * 1024) abort();
|
|
57
|
+
else chunks.push(chunk);
|
|
58
|
+
});
|
|
59
|
+
child.once("error", reject);
|
|
60
|
+
child.once("close", (code) => {
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
signal.removeEventListener("abort", abort);
|
|
63
|
+
if (code || bytes <= 44) reject(/* @__PURE__ */ new Error("Audio clip unavailable"));
|
|
64
|
+
else resolve(Buffer.concat(chunks));
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
} finally {
|
|
68
|
+
active--;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
export { discussionAudioClip };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
3
|
import { ObjectLinkService } from "../activity/service.js";
|
|
4
|
+
import { init_model_usage, withModelUsageOrigin } from "../providers/model-usage.js";
|
|
4
5
|
import { transcribe } from "../voice/stt/transcribe-core.js";
|
|
5
6
|
import { isSTTAvailable } from "../voice/stt/availability.js";
|
|
6
7
|
import { mergeSttConfigFromAppConfig } from "../voice/stt/config.js";
|
|
@@ -11,6 +12,7 @@ import { enrichLiveDiscussion } from "./analyzer.js";
|
|
|
11
12
|
import { acceptRankedProject, findExactProjectMention } from "./project-inference.js";
|
|
12
13
|
import { randomUUID } from "node:crypto";
|
|
13
14
|
//#region src/discussions/live-worker.ts
|
|
15
|
+
init_model_usage();
|
|
14
16
|
init_logger();
|
|
15
17
|
const log = createLogger("DiscussionLiveWorker");
|
|
16
18
|
const MAX_ATTEMPTS = 3;
|
|
@@ -58,7 +60,7 @@ var DiscussionLiveWorker = class {
|
|
|
58
60
|
if (!segment) return;
|
|
59
61
|
try {
|
|
60
62
|
try {
|
|
61
|
-
const result = this.deps.transcribeSegment ?
|
|
63
|
+
const result = await withModelUsageOrigin("interactive", () => this.deps.transcribeSegment ? this.deps.transcribeSegment(segment.audioBuffer) : this.transcribeSegment(segment.audioBuffer));
|
|
62
64
|
const completed = completeDiscussionTranscriptSegment(segment.discussionId, segment.sequence, this.owner, result.text.trim(), result.provider);
|
|
63
65
|
if (!completed) return;
|
|
64
66
|
this.deps.onTranscriptUpdated?.(completed);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DiscussionOrganization, DiscussionReview, DiscussionPlaybackRange } from '@xopcai/gateway-contract';
|
|
2
|
+
import type { NotesService } from '../notes/service.js';
|
|
3
|
+
export type ChapterScope = {
|
|
4
|
+
source: string;
|
|
5
|
+
revision: number;
|
|
6
|
+
transcript: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function chapterScope(id: string): ChapterScope;
|
|
9
|
+
export declare function saveReviewChapter(id: string, hash: string, position: number, chapter: DiscussionOrganization, scope: ChapterScope): void;
|
|
10
|
+
/** Union, rather than the latest timestamp or sum, describes verified coverage. */
|
|
11
|
+
export declare function unionReviewRanges(ranges: DiscussionPlaybackRange[], duration: number): DiscussionPlaybackRange[];
|
|
12
|
+
export declare function longRecordingReview(id: string, notes: NotesService, options?: {
|
|
13
|
+
query?: string;
|
|
14
|
+
offset?: number;
|
|
15
|
+
limit?: number;
|
|
16
|
+
version?: string;
|
|
17
|
+
}): Promise<DiscussionReview>;
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { getSqliteDatabase, init_transaction, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
2
|
+
import { DiscussionServiceError } from "./errors.js";
|
|
3
|
+
import { getDiscussionCapture, getLatestDiscussionOrganization, listDiscussionTranscriptSegments } from "./repository.js";
|
|
4
|
+
import { readTranscriptRevision } from "./revisions.js";
|
|
5
|
+
import { getProcessingRun } from "./processing.js";
|
|
6
|
+
import { playbackRanges, pointToPcm } from "./media-timeline.js";
|
|
7
|
+
import { listAnnotations, recordingTimeline } from "./review.js";
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
//#region src/discussions/long-review.ts
|
|
10
|
+
init_transaction();
|
|
11
|
+
function chapterScope(id) {
|
|
12
|
+
const capture = getDiscussionCapture(id);
|
|
13
|
+
return {
|
|
14
|
+
source: capture.audioSha256 ?? "",
|
|
15
|
+
revision: capture.transcriptRevision,
|
|
16
|
+
transcript: capture.canonicalTranscriptSha256 ?? ""
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function saveReviewChapter(id, hash, position, chapter, scope) {
|
|
20
|
+
runSqliteWriteTransaction((db) => {
|
|
21
|
+
if (JSON.stringify(chapterScope(id)) !== JSON.stringify(scope)) return;
|
|
22
|
+
db.prepare(`DELETE FROM discussion_chapter_progress WHERE discussion_id=? AND source_sha256=? AND transcript_revision=? AND transcript_sha256=? AND position=?`).run(id, scope.source, scope.revision, scope.transcript, position);
|
|
23
|
+
db.prepare("INSERT OR REPLACE INTO discussion_chapter_progress VALUES (?,?,?,?,?,?,?)").run(id, scope.source, scope.revision, scope.transcript, hash, position, JSON.stringify(chapter));
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/** Union, rather than the latest timestamp or sum, describes verified coverage. */
|
|
27
|
+
function unionReviewRanges(ranges, duration) {
|
|
28
|
+
const sorted = ranges.filter((r) => Number.isFinite(r.startedAtMs) && Number.isFinite(r.endedAtMs) && r.endedAtMs > r.startedAtMs).map((r) => ({
|
|
29
|
+
startedAtMs: Math.max(0, r.startedAtMs),
|
|
30
|
+
endedAtMs: Math.min(duration, r.endedAtMs)
|
|
31
|
+
})).filter((r) => r.endedAtMs > r.startedAtMs).sort((a, b) => a.startedAtMs - b.startedAtMs);
|
|
32
|
+
const output = [];
|
|
33
|
+
for (const range of sorted) {
|
|
34
|
+
const last = output.at(-1);
|
|
35
|
+
if (last && range.startedAtMs <= last.endedAtMs) last.endedAtMs = Math.max(last.endedAtMs, range.endedAtMs);
|
|
36
|
+
else output.push({ ...range });
|
|
37
|
+
}
|
|
38
|
+
return output;
|
|
39
|
+
}
|
|
40
|
+
const fold = (value) => value.normalize("NFKC").toLocaleLowerCase();
|
|
41
|
+
function excerpt(text, query) {
|
|
42
|
+
if (text.length <= 700) return text;
|
|
43
|
+
const at = query ? Math.max(0, fold(text).indexOf(query) - 180) : 0;
|
|
44
|
+
return `${at ? "…" : ""}${text.slice(at, at + 700)}${at + 700 < text.length ? "…" : ""}`;
|
|
45
|
+
}
|
|
46
|
+
async function longRecordingReview(id, notes, options = {}) {
|
|
47
|
+
const capture = getDiscussionCapture(id);
|
|
48
|
+
if (!capture) throw new DiscussionServiceError("not_found", "Discussion not found");
|
|
49
|
+
const query = (options.query ?? "").trim();
|
|
50
|
+
const offset = options.offset ?? 0;
|
|
51
|
+
const limit = options.limit ?? 20;
|
|
52
|
+
if (query.length > 200 || !Number.isSafeInteger(offset) || offset < 0 || offset > 1e5 || !Number.isSafeInteger(limit) || limit < 1 || limit > 50) throw new DiscussionServiceError("invalid_input", "Invalid review query or pagination");
|
|
53
|
+
const sourceSegments = listDiscussionTranscriptSegments(id).filter((s) => s.status === "confirmed");
|
|
54
|
+
const record = getLatestDiscussionOrganization(id);
|
|
55
|
+
const organization = record?.organization;
|
|
56
|
+
const duration = capture.durationMs ?? Math.max(0, ...sourceSegments.map((s) => s.endedAtMs));
|
|
57
|
+
const run = getProcessingRun(id);
|
|
58
|
+
const checkpoints = run && run.audio_sha256 === (capture.audioSha256 ?? null) ? getSqliteDatabase().prepare("SELECT started_at_ms,ended_at_ms,result_json FROM discussion_transcription_checkpoints WHERE run_id=? ORDER BY started_at_ms").all(run.run_id) : [];
|
|
59
|
+
const scope = chapterScope(id);
|
|
60
|
+
const partialChapters = getSqliteDatabase().prepare(`SELECT chapter_json FROM discussion_chapter_progress WHERE discussion_id=? AND source_sha256=? AND transcript_revision=? AND transcript_sha256=? ORDER BY position`).all(id, scope.source, scope.revision, scope.transcript).map((row) => JSON.parse(row.chapter_json));
|
|
61
|
+
const timeline = await recordingTimeline(id, notes);
|
|
62
|
+
const attachment = capture.audioAttachmentId && !capture.audioDeletedAt ? await notes.getAttachmentPath(capture.noteId, capture.audioAttachmentId) : null;
|
|
63
|
+
const playable = (start, end) => attachment && timeline ? playbackRanges(timeline, start, end) : [];
|
|
64
|
+
const segment = (s) => ({
|
|
65
|
+
sequence: s.sequence,
|
|
66
|
+
startedAtMs: s.startedAtMs,
|
|
67
|
+
endedAtMs: s.endedAtMs,
|
|
68
|
+
text: s.displayText ?? s.rawText ?? "",
|
|
69
|
+
speakerLabel: s.speakerLabel,
|
|
70
|
+
playback: playable(s.startedAtMs, s.endedAtMs)
|
|
71
|
+
});
|
|
72
|
+
const entries = sourceSegments.map((s, index) => ({
|
|
73
|
+
id: `transcript:${capture.transcriptRevision}:${s.sequence}`,
|
|
74
|
+
kind: "transcript",
|
|
75
|
+
title: s.speakerLabel ?? "",
|
|
76
|
+
text: s.displayText ?? s.rawText ?? "",
|
|
77
|
+
transcriptRevision: capture.transcriptRevision,
|
|
78
|
+
provisional: false,
|
|
79
|
+
stale: false,
|
|
80
|
+
startedAtMs: s.startedAtMs,
|
|
81
|
+
endedAtMs: s.endedAtMs,
|
|
82
|
+
segments: sourceSegments.slice(Math.max(0, index - 1), index + 2).map(segment),
|
|
83
|
+
playback: playable(Math.max(0, s.startedAtMs - 3e3), Math.min(duration, s.endedAtMs + 5e3))
|
|
84
|
+
}));
|
|
85
|
+
if (capture.status === "sealing" || capture.status === "needs_attention" && capture.failureStage === "transcript_sealing") for (const row of checkpoints) {
|
|
86
|
+
const checkpoint = JSON.parse(row.result_json);
|
|
87
|
+
for (const [index, s] of checkpoint.segments.entries()) entries.push({
|
|
88
|
+
id: `checkpoint:${run.run_id}:${row.started_at_ms}:${index}`,
|
|
89
|
+
kind: "transcript",
|
|
90
|
+
title: "",
|
|
91
|
+
text: s.text,
|
|
92
|
+
provisional: true,
|
|
93
|
+
stale: false,
|
|
94
|
+
startedAtMs: s.startedAtMs,
|
|
95
|
+
endedAtMs: s.endedAtMs,
|
|
96
|
+
segments: [{
|
|
97
|
+
sequence: index,
|
|
98
|
+
startedAtMs: s.startedAtMs,
|
|
99
|
+
endedAtMs: s.endedAtMs,
|
|
100
|
+
text: s.text,
|
|
101
|
+
playback: playable(s.startedAtMs, s.endedAtMs)
|
|
102
|
+
}],
|
|
103
|
+
playback: playable(Math.max(0, s.startedAtMs - 3e3), Math.min(duration, s.endedAtMs + 5e3))
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
const revisions = new Map([[capture.transcriptRevision, sourceSegments]]);
|
|
107
|
+
const revisionSegments = (revision) => {
|
|
108
|
+
if (!revisions.has(revision)) revisions.set(revision, (readTranscriptRevision(id, revision) ?? []).filter((s) => s.status === "confirmed"));
|
|
109
|
+
return revisions.get(revision);
|
|
110
|
+
};
|
|
111
|
+
const annotations = listAnnotations(id).map((annotation) => {
|
|
112
|
+
const anchor = annotation.anchor;
|
|
113
|
+
const epoch = timeline?.epochs[anchor.epoch ?? 0];
|
|
114
|
+
const position = anchor.positionMs ?? (epoch && anchor.offsetMs !== void 0 ? anchor.coordinate === "pcm" ? anchor.offsetMs < epoch.durationMs ? epoch.baseMs + anchor.offsetMs : void 0 : pointToPcm(epoch, anchor.offsetMs) : void 0);
|
|
115
|
+
const durable = !!attachment && position !== void 0 && position >= 0 && position < duration;
|
|
116
|
+
const revision = anchor.transcriptRevision ?? capture.transcriptRevision;
|
|
117
|
+
const refs = anchor.type === "transcript" ? revisionSegments(revision).filter((s) => anchor.segmentIds?.includes(s.sequence)) : durable ? sourceSegments.filter((s) => s.startedAtMs <= position && s.endedAtMs > position) : [];
|
|
118
|
+
const valid = anchor.type === "transcript" ? refs.length === anchor.segmentIds?.length : durable;
|
|
119
|
+
const evidence = refs.length && valid ? {
|
|
120
|
+
transcriptRevision: revision,
|
|
121
|
+
stale: revision !== capture.transcriptRevision,
|
|
122
|
+
segments: refs.map(segment)
|
|
123
|
+
} : void 0;
|
|
124
|
+
return {
|
|
125
|
+
annotation,
|
|
126
|
+
positionMs: durable ? position : void 0,
|
|
127
|
+
evidence,
|
|
128
|
+
state: valid ? "located" : !capture.audioAttachmentId && !capture.audioDeletedAt ? "pending" : "unavailable",
|
|
129
|
+
playback: anchor.type === "transcript" ? evidence?.segments.flatMap((s) => s.playback) ?? [] : durable ? playable(Math.max(0, position - 2e3), Math.min(duration, position + 8e3)) : []
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
const chapters = [];
|
|
133
|
+
const appendChapters = (org, revision, provisional, prefix) => {
|
|
134
|
+
const historical = revisionSegments(revision);
|
|
135
|
+
org.chapters.forEach((c, index) => {
|
|
136
|
+
if (!Number.isFinite(c.startedAtMs) || !Number.isFinite(c.endedAtMs) || c.startedAtMs < 0 || c.endedAtMs <= c.startedAtMs || c.endedAtMs > duration) return;
|
|
137
|
+
const within = historical.filter((s) => s.status === "confirmed" && s.endedAtMs > c.startedAtMs && s.startedAtMs < c.endedAtMs);
|
|
138
|
+
chapters.push({
|
|
139
|
+
id: `${prefix}:${index}`,
|
|
140
|
+
kind: "chapter",
|
|
141
|
+
title: c.title,
|
|
142
|
+
text: c.summary,
|
|
143
|
+
transcriptRevision: revision,
|
|
144
|
+
provisional,
|
|
145
|
+
stale: revision !== capture.transcriptRevision,
|
|
146
|
+
startedAtMs: c.startedAtMs,
|
|
147
|
+
endedAtMs: c.endedAtMs,
|
|
148
|
+
segments: within.slice(0, 3).map(segment),
|
|
149
|
+
playback: playable(c.startedAtMs, Math.min(c.endedAtMs, c.startedAtMs + 12e4)),
|
|
150
|
+
highlightCount: annotations.filter((a) => !a.annotation.deleted && (a.positionMs ?? a.evidence?.segments[0]?.startedAtMs ?? -1) >= c.startedAtMs && (a.positionMs ?? a.evidence?.segments[0]?.startedAtMs ?? -1) < c.endedAtMs).length,
|
|
151
|
+
actionCount: org.actionItems.filter((a) => !a.ignored && a.evidenceSegmentIds.some((seq) => within.some((s) => s.sequence === seq))).length
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
if (organization) appendChapters(organization, record.transcriptRevision, false, `chapter:${record.revision}`);
|
|
156
|
+
if (capture.status !== "completed") partialChapters.forEach((org, index) => appendChapters(org, capture.transcriptRevision, true, `partial:${index}`));
|
|
157
|
+
entries.push(...chapters);
|
|
158
|
+
if (organization) {
|
|
159
|
+
const revision = record.transcriptRevision;
|
|
160
|
+
const historical = revisionSegments(revision);
|
|
161
|
+
const facts = [
|
|
162
|
+
{
|
|
163
|
+
id: "summary",
|
|
164
|
+
text: organization.summary,
|
|
165
|
+
evidenceSegmentIds: organization.summaryEvidenceSegmentIds ?? []
|
|
166
|
+
},
|
|
167
|
+
...organization.keyPointEvidence ?? [],
|
|
168
|
+
...organization.decisions,
|
|
169
|
+
...organization.risks,
|
|
170
|
+
...organization.openQuestions,
|
|
171
|
+
...organization.actionItems.map((a) => ({
|
|
172
|
+
...a,
|
|
173
|
+
text: a.title
|
|
174
|
+
}))
|
|
175
|
+
];
|
|
176
|
+
for (const fact of facts) {
|
|
177
|
+
if ("ignored" in fact && fact.ignored) continue;
|
|
178
|
+
const rev = "evidenceRevision" in fact ? fact.evidenceRevision ?? revision : revision;
|
|
179
|
+
const referenced = (rev === revision ? historical : revisionSegments(rev)).filter((s) => s.status === "confirmed" && fact.evidenceSegmentIds.includes(s.sequence));
|
|
180
|
+
entries.push({
|
|
181
|
+
id: `analysis:${record.revision}:${fact.id}`,
|
|
182
|
+
kind: "analysis",
|
|
183
|
+
title: "",
|
|
184
|
+
text: fact.text,
|
|
185
|
+
transcriptRevision: rev,
|
|
186
|
+
provisional: false,
|
|
187
|
+
stale: rev !== capture.transcriptRevision,
|
|
188
|
+
startedAtMs: referenced[0]?.startedAtMs,
|
|
189
|
+
endedAtMs: referenced.at(-1)?.endedAtMs,
|
|
190
|
+
segments: referenced.slice(0, 3).map(segment),
|
|
191
|
+
playback: referenced.slice(0, 3).flatMap((s) => playable(s.startedAtMs, s.endedAtMs))
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
if (!organization.keyPointEvidence?.length) organization.keyPoints.forEach((text, index) => entries.push({
|
|
195
|
+
id: `keypoint:${index}`,
|
|
196
|
+
kind: "analysis",
|
|
197
|
+
title: "",
|
|
198
|
+
text,
|
|
199
|
+
provisional: false,
|
|
200
|
+
stale: revision !== capture.transcriptRevision,
|
|
201
|
+
transcriptRevision: revision,
|
|
202
|
+
segments: [],
|
|
203
|
+
playback: []
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
206
|
+
for (const a of annotations.filter((a) => !a.annotation.deleted)) entries.push({
|
|
207
|
+
id: `annotation:${a.annotation.id}`,
|
|
208
|
+
kind: "annotation",
|
|
209
|
+
title: a.annotation.kind,
|
|
210
|
+
text: a.annotation.text,
|
|
211
|
+
transcriptRevision: a.evidence?.transcriptRevision,
|
|
212
|
+
provisional: a.state === "pending",
|
|
213
|
+
stale: a.evidence?.stale ?? false,
|
|
214
|
+
startedAtMs: a.positionMs ?? a.evidence?.segments[0]?.startedAtMs,
|
|
215
|
+
segments: a.evidence?.segments.slice(0, 3) ?? [],
|
|
216
|
+
playback: a.playback
|
|
217
|
+
});
|
|
218
|
+
const processedRanges = unionReviewRanges((capture.status === "organizing" || capture.status === "completed") && capture.canonicalTranscript && duration > 0 ? [{
|
|
219
|
+
startedAtMs: 0,
|
|
220
|
+
endedAtMs: duration
|
|
221
|
+
}] : [...run?.force_audio ? [] : sourceSegments, ...checkpoints.map((r) => ({
|
|
222
|
+
startedAtMs: r.started_at_ms,
|
|
223
|
+
endedAtMs: r.ended_at_ms
|
|
224
|
+
}))], duration);
|
|
225
|
+
const analysisRanges = unionReviewRanges(chapters.filter((c) => c.provisional || !c.stale).map((c) => ({
|
|
226
|
+
startedAtMs: c.startedAtMs,
|
|
227
|
+
endedAtMs: c.endedAtMs
|
|
228
|
+
})), duration);
|
|
229
|
+
const needle = fold(query);
|
|
230
|
+
const matches = entries.filter((e) => needle ? fold(`${e.title}\n${e.text}\n${e.kind === "annotation" ? e.segments.map((s) => s.text).join("\n") : ""}`).includes(needle) : e.provisional && e.kind === "transcript");
|
|
231
|
+
const version = createHash("sha256").update(JSON.stringify([
|
|
232
|
+
capture.audioSha256,
|
|
233
|
+
capture.audioDeletedAt,
|
|
234
|
+
capture.status,
|
|
235
|
+
capture.transcriptRevision,
|
|
236
|
+
record?.revision,
|
|
237
|
+
processedRanges,
|
|
238
|
+
analysisRanges,
|
|
239
|
+
entries.map((e) => [
|
|
240
|
+
e.id,
|
|
241
|
+
e.title,
|
|
242
|
+
e.text,
|
|
243
|
+
e.startedAtMs,
|
|
244
|
+
e.endedAtMs,
|
|
245
|
+
e.stale,
|
|
246
|
+
e.provisional
|
|
247
|
+
])
|
|
248
|
+
])).digest("hex").slice(0, 24);
|
|
249
|
+
if (options.version && options.version !== version) throw new DiscussionServiceError("conflict", "Review updated; restart search");
|
|
250
|
+
const fresh = getDiscussionCapture(id);
|
|
251
|
+
if (fresh?.audioSha256 !== capture.audioSha256 || fresh?.transcriptRevision !== capture.transcriptRevision || fresh?.audioDeletedAt !== capture.audioDeletedAt) throw new DiscussionServiceError("conflict", "Review updated; retry");
|
|
252
|
+
return {
|
|
253
|
+
version,
|
|
254
|
+
query,
|
|
255
|
+
offset,
|
|
256
|
+
total: matches.length,
|
|
257
|
+
hasMore: offset + limit < matches.length,
|
|
258
|
+
hits: matches.slice(offset, offset + limit).map((e) => ({
|
|
259
|
+
...e,
|
|
260
|
+
text: excerpt(e.text, needle)
|
|
261
|
+
})),
|
|
262
|
+
chapters,
|
|
263
|
+
coverage: {
|
|
264
|
+
durationMs: duration,
|
|
265
|
+
audioAvailable: !!attachment,
|
|
266
|
+
transcriptRanges: unionReviewRanges(sourceSegments, duration),
|
|
267
|
+
processedRanges,
|
|
268
|
+
processedMs: processedRanges.reduce((sum, r) => sum + r.endedAtMs - r.startedAtMs, 0),
|
|
269
|
+
continuousThroughMs: processedRanges[0]?.startedAtMs === 0 ? processedRanges[0].endedAtMs : 0,
|
|
270
|
+
analysisRanges,
|
|
271
|
+
analysisRevision: record?.transcriptRevision,
|
|
272
|
+
analysisStale: !!record && record.transcriptRevision !== capture.transcriptRevision,
|
|
273
|
+
complete: capture.status === "completed"
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
//#endregion
|
|
278
|
+
export { chapterScope, longRecordingReview, saveReviewChapter, unionReviewRanges };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { DiscussionPlaybackRange } from '@xopcai/gateway-contract';
|
|
2
|
+
export interface MediaSpan {
|
|
3
|
+
sourceMs: number;
|
|
4
|
+
pcmMs: number;
|
|
5
|
+
durationMs: number;
|
|
6
|
+
}
|
|
7
|
+
export interface MediaEpoch {
|
|
8
|
+
baseMs: number;
|
|
9
|
+
durationMs: number;
|
|
10
|
+
spans: MediaSpan[];
|
|
11
|
+
verified: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface RecordingTimeline {
|
|
14
|
+
primary: 'encoded' | 'pcm';
|
|
15
|
+
epochs: MediaEpoch[];
|
|
16
|
+
}
|
|
17
|
+
export declare const pcmEpoch: (durationMs: number, baseMs?: number) => MediaEpoch;
|
|
18
|
+
/** Packet timestamps expose pauses without decoding the recording into memory. */
|
|
19
|
+
export declare function probeMediaEpoch(path: string, durationMs: number, baseMs: number, signal: AbortSignal): Promise<MediaEpoch>;
|
|
20
|
+
export declare function pointToPcm(epoch: MediaEpoch, sourceMs: number): number | undefined;
|
|
21
|
+
export declare function playbackRanges(timeline: RecordingTimeline, start: number, end: number): DiscussionPlaybackRange[];
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { spawnProcess } from "../process/run-process.js";
|
|
2
|
+
//#region src/discussions/media-timeline.ts
|
|
3
|
+
const pcmEpoch = (durationMs, baseMs = 0) => ({
|
|
4
|
+
baseMs,
|
|
5
|
+
durationMs,
|
|
6
|
+
verified: true,
|
|
7
|
+
spans: [{
|
|
8
|
+
sourceMs: 0,
|
|
9
|
+
pcmMs: 0,
|
|
10
|
+
durationMs
|
|
11
|
+
}]
|
|
12
|
+
});
|
|
13
|
+
/** Packet timestamps expose pauses without decoding the recording into memory. */
|
|
14
|
+
async function probeMediaEpoch(path, durationMs, baseMs, signal) {
|
|
15
|
+
const result = {
|
|
16
|
+
baseMs,
|
|
17
|
+
durationMs,
|
|
18
|
+
spans: [],
|
|
19
|
+
verified: false
|
|
20
|
+
};
|
|
21
|
+
try {
|
|
22
|
+
await new Promise((resolve, reject) => {
|
|
23
|
+
signal.throwIfAborted();
|
|
24
|
+
const handle = spawnProcess({
|
|
25
|
+
program: process.env.XOPC_FFPROBE_PATH || "ffprobe",
|
|
26
|
+
args: [
|
|
27
|
+
"-v",
|
|
28
|
+
"error",
|
|
29
|
+
"-select_streams",
|
|
30
|
+
"a:0",
|
|
31
|
+
"-show_packets",
|
|
32
|
+
"-show_entries",
|
|
33
|
+
"packet=pts_time,duration_time:packet_side_data=skip_samples,discard_padding",
|
|
34
|
+
"-of",
|
|
35
|
+
"compact=p=0",
|
|
36
|
+
path
|
|
37
|
+
],
|
|
38
|
+
maxOutputBytes: 0
|
|
39
|
+
});
|
|
40
|
+
const child = handle.child;
|
|
41
|
+
let pending = "";
|
|
42
|
+
let pcm = 0;
|
|
43
|
+
let packets = 0;
|
|
44
|
+
let lastStart = -Infinity;
|
|
45
|
+
const abort = () => {
|
|
46
|
+
handle.terminate();
|
|
47
|
+
reject(/* @__PURE__ */ new Error("Timing inspection cancelled"));
|
|
48
|
+
};
|
|
49
|
+
const timer = setTimeout(abort, 3e4);
|
|
50
|
+
timer.unref();
|
|
51
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
52
|
+
child.stdout?.setEncoding("utf8");
|
|
53
|
+
child.stdout?.on("data", (text) => {
|
|
54
|
+
pending += text;
|
|
55
|
+
const lines = pending.split("\n");
|
|
56
|
+
pending = lines.pop();
|
|
57
|
+
if (pending.length > 8192) {
|
|
58
|
+
abort();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
for (const line of lines) {
|
|
62
|
+
if (!line.trim()) continue;
|
|
63
|
+
const fields = Object.fromEntries(line.split("|").map((part) => part.split("=")));
|
|
64
|
+
const pts = Number(fields.pts_time) * 1e3;
|
|
65
|
+
const duration = Number(fields.duration_time) * 1e3;
|
|
66
|
+
if (++packets > 1e6 || !Number.isFinite(pts) || !Number.isFinite(duration) || duration <= 0 || Number(fields.skip_samples ?? 0) !== 0 || Number(fields.discard_padding ?? 0) !== 0) {
|
|
67
|
+
abort();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const start = Math.max(0, pts);
|
|
71
|
+
const length = duration - (start - pts);
|
|
72
|
+
if (length <= 0) continue;
|
|
73
|
+
const previous = result.spans.at(-1);
|
|
74
|
+
if (start <= lastStart) {
|
|
75
|
+
abort();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
lastStart = start;
|
|
79
|
+
if (previous && Math.abs(start - previous.sourceMs - previous.durationMs) <= 2) previous.durationMs += length;
|
|
80
|
+
else result.spans.push({
|
|
81
|
+
sourceMs: start,
|
|
82
|
+
pcmMs: pcm,
|
|
83
|
+
durationMs: length
|
|
84
|
+
});
|
|
85
|
+
pcm += length;
|
|
86
|
+
if (result.spans.length > 1e4) {
|
|
87
|
+
abort();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
child.once("error", reject);
|
|
93
|
+
child.once("close", (code) => {
|
|
94
|
+
clearTimeout(timer);
|
|
95
|
+
signal.removeEventListener("abort", abort);
|
|
96
|
+
if (code !== 0 || !result.spans.length || Math.abs(pcm - durationMs) > 100) {
|
|
97
|
+
reject(/* @__PURE__ */ new Error("Unverified media timing"));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
result.spans.at(-1).durationMs += durationMs - pcm;
|
|
101
|
+
result.verified = result.spans.at(-1).durationMs > 0;
|
|
102
|
+
resolve();
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
} catch {
|
|
106
|
+
result.verified = false;
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
function pointToPcm(epoch, sourceMs) {
|
|
111
|
+
if (!epoch.verified || !Number.isFinite(sourceMs)) return;
|
|
112
|
+
const matches = epoch.spans.filter((span) => sourceMs >= span.sourceMs && sourceMs < span.sourceMs + span.durationMs);
|
|
113
|
+
const span = matches.length === 1 ? matches[0] : void 0;
|
|
114
|
+
return span ? epoch.baseMs + span.pcmMs + sourceMs - span.sourceMs : void 0;
|
|
115
|
+
}
|
|
116
|
+
function playbackRanges(timeline, start, end) {
|
|
117
|
+
const total = timeline.epochs.reduce((sum, epoch) => sum + epoch.durationMs, 0);
|
|
118
|
+
if (!Number.isFinite(start) || !Number.isFinite(end) || start < 0 || end <= start || end > total + 1) return [];
|
|
119
|
+
if (timeline.primary === "pcm") return [{
|
|
120
|
+
startedAtMs: start,
|
|
121
|
+
endedAtMs: end
|
|
122
|
+
}];
|
|
123
|
+
if (!timeline.epochs.every((epoch) => epoch.verified)) return [];
|
|
124
|
+
return timeline.epochs[0].spans.flatMap((span) => {
|
|
125
|
+
const left = Math.max(start, span.pcmMs);
|
|
126
|
+
const right = Math.min(end, span.pcmMs + span.durationMs);
|
|
127
|
+
return right > left ? [{
|
|
128
|
+
startedAtMs: span.sourceMs + left - span.pcmMs,
|
|
129
|
+
endedAtMs: span.sourceMs + right - span.pcmMs
|
|
130
|
+
}] : [];
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
//#endregion
|
|
134
|
+
export { pcmEpoch, playbackRanges, pointToPcm, probeMediaEpoch };
|
|
@@ -6,10 +6,13 @@ export declare class DiscussionOrganizerWorker {
|
|
|
6
6
|
private readonly processor;
|
|
7
7
|
private readonly onUpdated?;
|
|
8
8
|
private readonly intervalMs;
|
|
9
|
+
private readonly requestTimeoutMs;
|
|
9
10
|
private readonly owner;
|
|
10
11
|
private timer?;
|
|
11
12
|
private running;
|
|
12
|
-
|
|
13
|
+
private stopping;
|
|
14
|
+
private controller?;
|
|
15
|
+
constructor(processor: DiscussionOrganizerProcessor, onUpdated?: (capture: DiscussionCapture) => void, intervalMs?: number, requestTimeoutMs?: number);
|
|
13
16
|
start(): void;
|
|
14
17
|
stop(): Promise<void>;
|
|
15
18
|
tick(): Promise<void>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
|
-
import { claimNextDiscussionCapture, getDiscussionCapture, releaseDiscussionWorkLease, renewDiscussionWorkLease
|
|
3
|
+
import { claimNextDiscussionCapture, getDiscussionCapture, releaseDiscussionWorkLease, renewDiscussionWorkLease } from "./repository.js";
|
|
4
|
+
import { failOrRetryProcessing, resetProcessingRetry, withProcessingDeadline } from "./processing.js";
|
|
4
5
|
import { randomUUID } from "node:crypto";
|
|
5
6
|
//#region src/discussions/organizer-worker.ts
|
|
6
7
|
init_logger();
|
|
@@ -9,47 +10,50 @@ var DiscussionOrganizerWorker = class {
|
|
|
9
10
|
owner = randomUUID();
|
|
10
11
|
timer;
|
|
11
12
|
running = false;
|
|
12
|
-
|
|
13
|
+
stopping = false;
|
|
14
|
+
controller;
|
|
15
|
+
constructor(processor, onUpdated, intervalMs = 1e3, requestTimeoutMs = 10 * 6e4) {
|
|
13
16
|
this.processor = processor;
|
|
14
17
|
this.onUpdated = onUpdated;
|
|
15
18
|
this.intervalMs = intervalMs;
|
|
19
|
+
this.requestTimeoutMs = requestTimeoutMs;
|
|
16
20
|
}
|
|
17
21
|
start() {
|
|
18
22
|
if (this.timer) return;
|
|
19
|
-
this.
|
|
23
|
+
this.stopping = false;
|
|
24
|
+
this.timer = setInterval(() => void this.tick().catch((error) => log.error({ err: error }, "Discussion organizer tick failed")), this.intervalMs);
|
|
20
25
|
this.timer.unref();
|
|
21
|
-
this.tick();
|
|
26
|
+
this.tick().catch((error) => log.error({ err: error }, "Discussion organizer tick failed"));
|
|
22
27
|
}
|
|
23
28
|
async stop() {
|
|
29
|
+
this.stopping = true;
|
|
30
|
+
this.controller?.abort(/* @__PURE__ */ new Error("Discussion processing stopped"));
|
|
24
31
|
if (this.timer) clearInterval(this.timer);
|
|
25
32
|
this.timer = void 0;
|
|
26
33
|
while (this.running) await new Promise((resolve) => setTimeout(resolve, 10));
|
|
27
34
|
}
|
|
28
35
|
async tick() {
|
|
29
|
-
if (this.running) return;
|
|
36
|
+
if (this.running || this.stopping) return;
|
|
30
37
|
this.running = true;
|
|
31
38
|
try {
|
|
32
39
|
const capture = claimNextDiscussionCapture(this.owner);
|
|
33
40
|
if (!capture) return;
|
|
34
41
|
const controller = new AbortController();
|
|
42
|
+
this.controller = controller;
|
|
35
43
|
const renewal = setInterval(() => {
|
|
36
44
|
if (!renewDiscussionWorkLease(capture.id, this.owner)) controller.abort();
|
|
37
45
|
}, 3e4);
|
|
38
46
|
renewal.unref();
|
|
39
47
|
try {
|
|
40
|
-
await this.processor.process(capture, this.owner, controller.signal);
|
|
48
|
+
await withProcessingDeadline((signal) => this.processor.process(capture, this.owner, signal), controller.signal, this.requestTimeoutMs);
|
|
49
|
+
resetProcessingRetry(capture.id);
|
|
41
50
|
releaseDiscussionWorkLease(capture.id, this.owner);
|
|
42
51
|
} catch (error) {
|
|
43
52
|
const message = error instanceof Error ? error.message : String(error);
|
|
44
53
|
const ownsLease = renewDiscussionWorkLease(capture.id, this.owner);
|
|
45
54
|
releaseDiscussionWorkLease(capture.id, this.owner);
|
|
46
55
|
const current = getDiscussionCapture(capture.id);
|
|
47
|
-
const updated = ownsLease &&
|
|
48
|
-
status: "needs_attention",
|
|
49
|
-
failureStage: "organization",
|
|
50
|
-
failureCode: "organization_failed",
|
|
51
|
-
failureMessage: message.slice(0, 1e3)
|
|
52
|
-
}, ["organizing"]);
|
|
56
|
+
const updated = ownsLease && !controller.signal.aborted && current ? failOrRetryProcessing(current, "organization", error) : null;
|
|
53
57
|
if (updated) this.onUpdated?.(updated);
|
|
54
58
|
log.warn({
|
|
55
59
|
err: error,
|
|
@@ -57,6 +61,7 @@ var DiscussionOrganizerWorker = class {
|
|
|
57
61
|
}, `Discussion organization failed: ${message}`);
|
|
58
62
|
} finally {
|
|
59
63
|
clearInterval(renewal);
|
|
64
|
+
this.controller = void 0;
|
|
60
65
|
}
|
|
61
66
|
} finally {
|
|
62
67
|
this.running = false;
|
|
@@ -2,6 +2,7 @@ import { init_transaction, runSqliteWriteTransaction } from "../storage/sqlite/t
|
|
|
2
2
|
import { ObjectLinkService } from "../activity/service.js";
|
|
3
3
|
import { completeDiscussionOrganization, createDiscussionOrganization, getDiscussionCapture, getLatestDiscussionOrganization, listDiscussionTranscriptSegments, renewDiscussionWorkLease, updateDiscussionCapture } from "./repository.js";
|
|
4
4
|
import { saveTranscriptRevision } from "./revisions.js";
|
|
5
|
+
import { chapterScope } from "./long-review.js";
|
|
5
6
|
import { analyzeDiscussion } from "./analyzer.js";
|
|
6
7
|
import { applyMeetingEdits } from "./edits.js";
|
|
7
8
|
import { acceptRankedProject, findExactProjectMention } from "./project-inference.js";
|
|
@@ -27,6 +28,7 @@ var DiscussionOrganizer = class {
|
|
|
27
28
|
transcript,
|
|
28
29
|
segments: listDiscussionTranscriptSegments(capture.id),
|
|
29
30
|
discussionId: capture.id,
|
|
31
|
+
reviewScope: chapterScope(capture.id),
|
|
30
32
|
template: capture.template,
|
|
31
33
|
projects: projects.map(({ id, name }) => ({
|
|
32
34
|
id,
|