@xopcai/xopc 0.0.242 → 0.0.243
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-MU5XrVv8.js → activity-store-CAah-_8h.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B_Wc0wuL.js → agent-avatar-dicebear-DDH4HgP7.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-BDCfJZhh.js +1 -0
- package/dist/gateway/static/root/assets/agents-B0ZWgf-U.js +1 -0
- package/dist/gateway/static/root/assets/{api-DLyc8BQp.js → api-B2tKxbcz.js} +1 -1
- package/dist/gateway/static/root/assets/app-management-settings-panel-Blfwszzn.js +1 -0
- package/dist/gateway/static/root/assets/{appearance-settings-DB5gEQhN.js → appearance-settings-C3V7Na75.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BiEks0-F.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-BOx0EJZs.js → archive-plugin-BmSx7wzY.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-CYnYIyLr.js → attachment-load-BS-S4LJ9.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-ChTflpmA.js → automations-page-C7Y3L30D.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-A3zPkPuo.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-BjbLfNwG.js → binary-plugins-BM9B5kcm.js} +1 -1
- package/dist/gateway/static/root/assets/block-editor-BbnpkYP9.js +185 -0
- package/dist/gateway/static/root/assets/browser-settings-page-Dk4FQ7fY.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-DGQxD0vD.js → browser-workflow-inputs-CRnkgZHI.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-B9gfdd7L.js → browser-workflows-page-B9qGL-it.js} +2 -2
- package/dist/gateway/static/root/assets/{button-CSEbl4zT.js → button-CtTvuElV.js} +1 -1
- package/dist/gateway/static/root/assets/capabilities-settings-panel--tR_El9e.js +7 -0
- package/dist/gateway/static/root/assets/channels-settings-D347vl_J.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-TkU42f-W.js → channels-status-swr-DuY4MGxe.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-CWMPcnoN.js → chat-terminal-dock-DABPvwBT.js} +2 -2
- package/dist/gateway/static/root/assets/connectors-page-B-tvJkRJ.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-3h3rR0cf.js → cron-expression-D3bsKbNd.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-Bz1sLBEx.js → date-picker-BsGM6Yty.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-p9DWR8uU.js → dependency-picker-Dj3g6YXZ.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-D1TDB_gR.js → desktop-pet-C1QT0Sur.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-DWPZpoB7.js → desktop-pet-settings-r6kAOnfY.js} +1 -1
- package/dist/gateway/static/root/assets/dist-CpzYSoz7.js +1 -0
- package/dist/gateway/static/root/assets/{dist-DaxPZj9e.js → dist-DBS3OB8K.js} +1 -1
- package/dist/gateway/static/root/assets/dist-DLmwHyAh.js +1 -0
- package/dist/gateway/static/root/assets/es2015-BvLh9GaE.js +41 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-BrRbK2rJ.js → extension-debug-page-DOkf7nh9.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CD65czfS.js → extension-page-Cq2IA4Ho.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-BRDDKhpi.js → extension-settings-page-DQn4qjDZ.js} +1 -1
- package/dist/gateway/static/root/assets/{files-DQjhZjr2.js → files-D6vf3S30.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-CjbBsr5M.js → gateway-config-api-DM3poL22.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-HT7sLeO9.js → gateway-config-swr-BC3pgb_P.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-BQjmfYD4.js → gateway-settings-DPgH1hnh.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-iBCtaAuT.js → gateway-startup-retry-uMcSfLru.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-BzZxLgrw.js → heartbeat-settings-Bk80-E3b.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-DKo5JiMR.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-dj9TNEn2.js → image-generation-api-D1qlQA-A.js} +1 -1
- package/dist/gateway/static/root/assets/index-B0WJL9N1.js +71 -0
- package/dist/gateway/static/root/assets/index-Dbh5SXyV.css +2 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BEnuEPD3.js → keyboard-shortcuts-settings-BEwvd8ZU.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page--eJ5rmNj.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-DXQtppWq.js → local-apps-page-CgkY9E-r.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-DVzTJSj2.js → locale-store-CMZljTJx.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-Z49Td0J9.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-DIpBMWrA.js → management-settings-Dv8NSJKt.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-BFHyGwNF.js → markdown-split-Cm0RBB-t.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-DR3yVwtV.js → markdown-view-PPCLt7fu.js} +3 -3
- package/dist/gateway/static/root/assets/{media-plugins-BjjMxC5_.js → media-plugins-Bcr5sU1f.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CTSgFlE4.js +3 -0
- package/dist/gateway/static/root/assets/mobile-pairing-wizard-kKDiXofY.js +1 -0
- package/dist/gateway/static/root/assets/models-hub-cache-ZrbGRiGY.js +1 -0
- package/dist/gateway/static/root/assets/{notes-page-BbvtelJa.js → notes-page-CgsaRaGi.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-C1DEE09k.js +4 -0
- package/dist/gateway/static/root/assets/{oauth-api-BB-VYJ5j.js → oauth-api-4VeMbkTJ.js} +1 -1
- package/dist/gateway/static/root/assets/popover-select-C-Hj-nXR.js +1 -0
- package/dist/gateway/static/root/assets/{product-delivery-dUJgmBQZ.js → product-delivery-CV4pDOtG.js} +1 -1
- package/dist/gateway/static/root/assets/product-open-page-BU0HiZtv.js +1 -0
- package/dist/gateway/static/root/assets/project-detail-page-isRapnp5.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-zvsjg0mi.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-DXsR8oGN.js → registry-api-CWOtPFrE.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-C9TGZ9Hc.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DoEfLjPB.js → runtime-tools-settings-panel-2zm9edMA.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-BsqpbBDv.js → schema-form-54A5gzkN.js} +1 -1
- package/dist/gateway/static/root/assets/{schemas-zIBW3wiV.js → schemas-BHS7bo06.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-BP8RyiUn.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-D4EMxWAZ.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-CE7ZcCTK.js → settings-page-DzDhoyxv.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-CGlne9i0.js → setup-status-panel-uDicHU1w.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-Bn0qMX8V.js → share-preview-page-lOmLCWFS.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-T4Yvouvv.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-DVb7nrXz.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-dRkeYh5P.js → skills-page-CnyNH3To.js} +1 -1
- package/dist/gateway/static/root/assets/skills-page.utils-CgDtf2qs.js +1 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-C0ZCuCM4.js → system-settings-panel-C8yWfwtR.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-Tzfjlbf3.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-Cth-eChE.js → theme-store-uxUwr10D.js} +1 -1
- package/dist/gateway/static/root/assets/tunnel-api-Bvg679no.js +1 -0
- package/dist/gateway/static/root/assets/{use-autosave-PSV89QuQ.js → use-autosave-D88VGoyG.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-RijPtyfO.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-DXWdJ8cR.js → voice-api-key-field-CBHLsMcc.js} +1 -1
- package/dist/gateway/static/root/assets/voice-config-api-MqyI6cgq.js +1 -0
- package/dist/gateway/static/root/assets/work-discovery-overlay-GGe2TQ98.js +1 -0
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-C0layUE9.js +3 -0
- package/dist/gateway/static/root/assets/workflows-page-DQXIzBAc.js +5 -0
- package/dist/gateway/static/root/index.html +21 -22
- package/dist/package.js +1 -1
- package/dist/packages/realtime-protocol/src/voice-audio.js +20 -0
- package/dist/packages/realtime-protocol/src/voice.js +208 -0
- package/dist/src/agent/embedded/run-for-session.d.ts +1 -0
- package/dist/src/agent/embedded/run-for-session.js +2 -1
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +1 -0
- package/dist/src/agent/inbound/turn-dispatcher.js +2 -1
- package/dist/src/agent/prompt/voice-presentation.d.ts +2 -0
- package/dist/src/agent/prompt/voice-presentation.js +12 -0
- package/dist/src/agent/service/direct-turn-helpers.d.ts +1 -0
- package/dist/src/agent/service/direct-turn-helpers.js +1 -0
- package/dist/src/agent/service/process-direct-streaming.d.ts +1 -0
- package/dist/src/agent/service/process-direct-streaming.js +2 -1
- package/dist/src/agent/session/session-config-service.js +4 -2
- package/dist/src/automations/draft/automation-draft-service.js +1 -1
- package/dist/src/config/models-json.d.ts +8 -8
- package/dist/src/config/schema.d.ts +60 -0
- package/dist/src/config/schema.js +31 -1
- package/dist/src/files/file-service.d.ts +1 -0
- package/dist/src/files/file-service.js +4 -0
- package/dist/src/gateway/chat-stream/thinking-delta-coalescer.js +8 -3
- package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -11
- package/dist/src/gateway/hono/lib/config-payload.js +2 -2
- package/dist/src/gateway/hono/lib/safe-voice-config.d.ts +14 -0
- package/dist/src/gateway/hono/lib/safe-voice-config.js +29 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -2
- package/dist/src/gateway/hono/routes/files.js +7 -0
- package/dist/src/gateway/hono/routes/lazy-fallback.js +18 -4
- package/dist/src/gateway/hono/routes/session-input-handler.js +14 -0
- package/dist/src/gateway/hono/routes/sessions.js +4 -1
- package/dist/src/gateway/hono/routes/voice.js +139 -2
- package/dist/src/gateway/server.js +1 -0
- package/dist/src/gateway/service/agent-runner.d.ts +1 -0
- package/dist/src/gateway/service/agent-runner.js +1 -6
- package/dist/src/gateway/service/run-gateway-agent.d.ts +1 -0
- package/dist/src/gateway/service/run-gateway-agent.js +19 -1
- package/dist/src/gateway/service.d.ts +2 -0
- package/dist/src/gateway/service.js +73 -0
- package/dist/src/media-understanding/types.d.ts +61 -0
- package/dist/src/session/client-history.js +12 -0
- package/dist/src/session/manager.d.ts +1 -0
- package/dist/src/session/session-context-for-llm.js +8 -0
- package/dist/src/session/store.d.ts +1 -0
- package/dist/src/session/store.js +1 -0
- package/dist/src/session/stored-rows-to-file-entries.js +5 -1
- package/dist/src/session/voice-transcript.d.ts +9 -0
- package/dist/src/session/voice-transcript.js +45 -0
- package/dist/src/storage/sqlite/config-repository.js +9 -0
- package/dist/src/storage/sqlite/remote-context-repository.d.ts +3 -0
- package/dist/src/storage/sqlite/remote-context-repository.js +40 -0
- package/dist/src/storage/sqlite/session-repository.js +13 -0
- package/dist/src/storage/sqlite/user-context-repository.d.ts +3 -1
- package/dist/src/storage/sqlite/user-context-repository.js +50 -4
- package/dist/src/tui/tui.js +2 -1
- package/dist/src/user-context/automatic-context.d.ts +17 -0
- package/dist/src/user-context/automatic-context.js +85 -0
- package/dist/src/user-context/changes.d.ts +7 -0
- package/dist/src/user-context/changes.js +28 -0
- package/dist/src/user-context/planner.js +1 -24
- package/dist/src/user-context/retriever.js +10 -11
- package/dist/src/user-context/selection-policy.d.ts +20 -0
- package/dist/src/user-context/selection-policy.js +33 -0
- package/dist/src/user-context/sources/index.js +2 -2
- package/dist/src/user-context/sources/repository.d.ts +2 -1
- package/dist/src/user-context/sources/repository.js +26 -5
- package/dist/src/voice/dashscope/streaming-stt-session.d.ts +2 -0
- package/dist/src/voice/dashscope/streaming-stt-session.js +249 -0
- package/dist/src/voice/dashscope/streaming-tts-stream.d.ts +12 -0
- package/dist/src/voice/dashscope/streaming-tts-stream.js +153 -0
- package/dist/src/voice/realtime/agentEngine.d.ts +10 -0
- package/dist/src/voice/realtime/agentEngine.js +403 -0
- package/dist/src/voice/realtime/audio-playback-window.d.ts +9 -0
- package/dist/src/voice/realtime/audio-playback-window.js +49 -0
- package/dist/src/voice/realtime/conversation-context.d.ts +11 -0
- package/dist/src/voice/realtime/conversation-context.js +76 -0
- package/dist/src/voice/realtime/engine.d.ts +13 -0
- package/dist/src/voice/realtime/engine.js +1 -0
- package/dist/src/voice/realtime/memory-context.d.ts +17 -0
- package/dist/src/voice/realtime/memory-context.js +100 -0
- package/dist/src/voice/realtime/omniEngine.d.ts +18 -0
- package/dist/src/voice/realtime/omniEngine.js +443 -0
- package/dist/src/voice/realtime/omniRoute.d.ts +10 -0
- package/dist/src/voice/realtime/omniRoute.js +31 -0
- package/dist/src/voice/realtime/runtime.d.ts +99 -0
- package/dist/src/voice/realtime/runtime.js +622 -0
- package/dist/src/voice/realtime/speakable-segmenter.d.ts +10 -0
- package/dist/src/voice/realtime/speakable-segmenter.js +87 -0
- package/dist/src/voice/stt/list-providers.js +2 -1
- package/dist/src/voice/stt/providers/alibaba-transcription.js +13 -1
- package/dist/src/voice/stt/providers/xopc-cloud-transcription.js +23 -0
- package/dist/src/voice/tts/factory.js +1 -0
- package/dist/src/voice/tts/openai-compatible-speech.js +3 -1
- package/dist/src/voice/tts/providers/alibaba-speech.d.ts +1 -5
- package/dist/src/voice/tts/providers/alibaba-speech.js +25 -8
- package/dist/src/voice/tts/providers/edge-speech.js +21 -22
- package/dist/src/voice/tts/providers/minimax-speech.js +6 -3
- package/dist/src/voice/tts/providers/xopc-cloud-speech.js +26 -1
- package/dist/src/voice/tts/speak-core.d.ts +6 -2
- package/dist/src/voice/tts/speak-core.js +46 -34
- package/dist/src/voice/tts/speech-provider-types.d.ts +1 -0
- package/package.json +5 -5
- package/dist/gateway/static/root/assets/Combination-14nmIgxH.js +0 -41
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-Cf7U2aUi.js +0 -1
- package/dist/gateway/static/root/assets/agents-Ce9oOnwE.js +0 -1
- package/dist/gateway/static/root/assets/app-chrome-BeB4KgOf.js +0 -1
- package/dist/gateway/static/root/assets/app-management-settings-panel-CACOOS-a.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-BaTFOCmR.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-DK6EreCr.js +0 -6
- package/dist/gateway/static/root/assets/block-editor-DgAs5aJc.js +0 -184
- package/dist/gateway/static/root/assets/browser-settings-page-CHStw5UW.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-JGH6Kfkr.js +0 -7
- package/dist/gateway/static/root/assets/channels-settings-YkUaaWkY.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-BI0FG3gA.js +0 -2
- package/dist/gateway/static/root/assets/dist-BPoKqzeH.js +0 -1
- package/dist/gateway/static/root/assets/dist-DqPZM2MH.js +0 -1
- package/dist/gateway/static/root/assets/home-page--9fKq0mL.js +0 -1
- package/dist/gateway/static/root/assets/index-D499B1qS.css +0 -2
- package/dist/gateway/static/root/assets/index-J3FsIvTs.js +0 -70
- package/dist/gateway/static/root/assets/local-app-workbench-page-FqG00zS1.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-c6CfZ8PA.js +0 -2
- package/dist/gateway/static/root/assets/messages-_tYhRAHD.js +0 -3
- package/dist/gateway/static/root/assets/mobile-pairing-wizard-CHnXZTwb.js +0 -1
- package/dist/gateway/static/root/assets/models-hub-cache-DiXjKuuY.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-DIR37b-K.js +0 -4
- package/dist/gateway/static/root/assets/popover-select-DrILF6mR.js +0 -1
- package/dist/gateway/static/root/assets/product-open-page-CRm9Q66h.js +0 -1
- package/dist/gateway/static/root/assets/project-detail-page-DHiLTiRW.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-God7NCcI.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-YpF0-mx2.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CP8O1TxR.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-DzdbK3j9.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-B7NeVl4g.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DDTmi4a7.js +0 -1
- package/dist/gateway/static/root/assets/skills-page.utils--q8p7MAn.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-yiMzii2b.js +0 -1
- package/dist/gateway/static/root/assets/tunnel-api-CC3jOB4n.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-Vtwg7fQc.js +0 -1
- package/dist/gateway/static/root/assets/voice-config-api-BDoeXgww.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-overlay-BV_Jj5iD.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-DNHbWGPq.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-BkFIbMrz.js +0 -5
|
@@ -112,6 +112,65 @@ export interface AudioTranscriptionResult {
|
|
|
112
112
|
/** Audio duration in seconds, when reported. */
|
|
113
113
|
durationSeconds?: number;
|
|
114
114
|
}
|
|
115
|
+
export interface PcmAudioFormat {
|
|
116
|
+
encoding: 'pcm_s16le';
|
|
117
|
+
sampleRate: 16_000 | 24_000;
|
|
118
|
+
channels: 1;
|
|
119
|
+
}
|
|
120
|
+
export interface StreamingSttCapabilities {
|
|
121
|
+
inputSampleRates: readonly number[];
|
|
122
|
+
turnDetection: readonly 'server_vad'[];
|
|
123
|
+
defaultModel: string;
|
|
124
|
+
models: readonly string[];
|
|
125
|
+
}
|
|
126
|
+
export type StreamingSttEvent = {
|
|
127
|
+
type: 'ready';
|
|
128
|
+
} | {
|
|
129
|
+
type: 'speech_started';
|
|
130
|
+
utteranceId: string;
|
|
131
|
+
} | {
|
|
132
|
+
type: 'speech_stopped';
|
|
133
|
+
utteranceId: string;
|
|
134
|
+
} | {
|
|
135
|
+
type: 'transcript_delta';
|
|
136
|
+
utteranceId: string;
|
|
137
|
+
revision: number;
|
|
138
|
+
text: string;
|
|
139
|
+
} | {
|
|
140
|
+
type: 'transcript_final';
|
|
141
|
+
utteranceId: string;
|
|
142
|
+
revision: number;
|
|
143
|
+
text: string;
|
|
144
|
+
language?: string;
|
|
145
|
+
} | {
|
|
146
|
+
type: 'usage';
|
|
147
|
+
inputAudioMs: number;
|
|
148
|
+
} | {
|
|
149
|
+
type: 'error';
|
|
150
|
+
error: Error;
|
|
151
|
+
};
|
|
152
|
+
export interface StreamingSttOpenRequest {
|
|
153
|
+
model: string;
|
|
154
|
+
inputFormat: PcmAudioFormat;
|
|
155
|
+
apiKey?: string;
|
|
156
|
+
baseUrl?: string;
|
|
157
|
+
headers?: Record<string, string>;
|
|
158
|
+
language?: string;
|
|
159
|
+
prompt?: string;
|
|
160
|
+
turnDetection: {
|
|
161
|
+
mode: 'server_vad';
|
|
162
|
+
silenceDurationMs: number;
|
|
163
|
+
};
|
|
164
|
+
timeoutMs: number;
|
|
165
|
+
signal: AbortSignal;
|
|
166
|
+
onEvent: (event: StreamingSttEvent) => void;
|
|
167
|
+
}
|
|
168
|
+
export interface StreamingSttSession {
|
|
169
|
+
appendAudio(chunk: Uint8Array): void;
|
|
170
|
+
commit(): Promise<void>;
|
|
171
|
+
close(): Promise<void>;
|
|
172
|
+
abort(reason: string): void;
|
|
173
|
+
}
|
|
115
174
|
export interface ImageDescriptionRequest {
|
|
116
175
|
buffer: Buffer;
|
|
117
176
|
fileName: string;
|
|
@@ -170,6 +229,8 @@ export interface MediaUnderstandingProvider {
|
|
|
170
229
|
/** True when the provider can natively ingest PDF (no OCR pre-step needed). */
|
|
171
230
|
nativeDocumentInputs?: ReadonlyArray<'pdf'>;
|
|
172
231
|
transcribeAudio?: (req: AudioTranscriptionRequest) => Promise<AudioTranscriptionResult>;
|
|
232
|
+
streamingAudio?: StreamingSttCapabilities;
|
|
233
|
+
openAudioStream?: (req: StreamingSttOpenRequest) => Promise<StreamingSttSession>;
|
|
173
234
|
describeImage?: (req: ImageDescriptionRequest) => Promise<ImageDescriptionResult>;
|
|
174
235
|
describeVideo?: (req: VideoDescriptionRequest) => Promise<VideoDescriptionResult>;
|
|
175
236
|
}
|
|
@@ -267,6 +267,18 @@ function customRowToClientHistory(row) {
|
|
|
267
267
|
if (r.role !== "custom" && r.type !== "custom_message") return null;
|
|
268
268
|
const customType = optionalString(r.customType)?.trim();
|
|
269
269
|
if (!customType) return null;
|
|
270
|
+
if (customType === "voice_omni_transcript") {
|
|
271
|
+
const details = r.details;
|
|
272
|
+
if (details?.role !== "user" && details?.role !== "assistant") return null;
|
|
273
|
+
const content = typeof r.content === "string" ? r.content : "";
|
|
274
|
+
return {
|
|
275
|
+
role: details.role,
|
|
276
|
+
kind: "message",
|
|
277
|
+
content,
|
|
278
|
+
rawContent: content,
|
|
279
|
+
timestamp: parseTimestampValue(typeof r.timestamp === "string" || typeof r.timestamp === "number" ? r.timestamp : void 0)
|
|
280
|
+
};
|
|
281
|
+
}
|
|
270
282
|
const content = Array.isArray(r.content) || typeof r.content === "string" ? flattenMessageContent(r.content) : "";
|
|
271
283
|
const timestamp = parseTimestampValue(typeof r.timestamp === "string" || typeof r.timestamp === "number" ? r.timestamp : void 0);
|
|
272
284
|
return {
|
|
@@ -149,6 +149,7 @@ export declare class SessionIndex extends EventEmitter {
|
|
|
149
149
|
data?: unknown;
|
|
150
150
|
}): Promise<void>;
|
|
151
151
|
appendTranscriptCustomMessageEntry(key: string, entry: {
|
|
152
|
+
expectedSessionId?: string;
|
|
152
153
|
customType: string;
|
|
153
154
|
content?: string | unknown[];
|
|
154
155
|
display?: boolean;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { voiceTranscriptMessage } from "./voice-transcript.js";
|
|
1
2
|
import { isCompactionAudit, isCompactionHandover } from "./compaction-types.js";
|
|
2
3
|
//#region src/session/session-context-for-llm.ts
|
|
3
4
|
function isTranscriptContextEntry(x) {
|
|
@@ -245,6 +246,12 @@ function buildSessionContextForLlm(rows) {
|
|
|
245
246
|
continue;
|
|
246
247
|
}
|
|
247
248
|
if (isTranscriptCustomMessageEntry(r)) {
|
|
249
|
+
if (r.customType === "voice_call") continue;
|
|
250
|
+
if (r.customType === "voice_omni_transcript") {
|
|
251
|
+
const message = voiceTranscriptMessage(r);
|
|
252
|
+
if (message) out.push(message);
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
248
255
|
out.push(customMessageRowToLlmMessage(r));
|
|
249
256
|
continue;
|
|
250
257
|
}
|
|
@@ -257,6 +264,7 @@ function buildSessionDisplayMessages(rows) {
|
|
|
257
264
|
const out = [];
|
|
258
265
|
for (const r of rows) {
|
|
259
266
|
if (isTranscriptCustomMessageEntry(r)) {
|
|
267
|
+
if (r.customType === "voice_call") continue;
|
|
260
268
|
if (r.display === false) continue;
|
|
261
269
|
out.push(customMessageRowToLlmMessage(r));
|
|
262
270
|
continue;
|
|
@@ -386,6 +386,7 @@ var SessionStore = class {
|
|
|
386
386
|
async appendTranscriptCustomMessageEntry(key, entry) {
|
|
387
387
|
return this.runStoreMutation(async () => {
|
|
388
388
|
requireXopcDatabase();
|
|
389
|
+
if (entry.expectedSessionId && getSessionMetadata(key)?.sessionId !== entry.expectedSessionId) throw new Error("Voice conversation session changed");
|
|
389
390
|
ensureSessionRecord(key, this.resolveWorkspaceCwd(key));
|
|
390
391
|
appendTranscriptEntry(key, {
|
|
391
392
|
role: "custom",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { voiceTranscriptMessage } from "./voice-transcript.js";
|
|
1
2
|
import { isTranscriptContextEntry, isTranscriptCustomMessageEntry, isTranscriptCustomStateEntry } from "./session-context-for-llm.js";
|
|
2
3
|
import { randomUUID } from "node:crypto";
|
|
3
4
|
import { CURRENT_SESSION_VERSION } from "@earendil-works/pi-coding-agent";
|
|
@@ -100,7 +101,10 @@ function storedRowsToFileEntries(params) {
|
|
|
100
101
|
continue;
|
|
101
102
|
}
|
|
102
103
|
if (isTranscriptCustomMessageEntry(row)) {
|
|
103
|
-
|
|
104
|
+
if (row.customType === "voice_call") continue;
|
|
105
|
+
const voiceMessage = row.customType === "voice_omni_transcript" ? voiceTranscriptMessage(row) : null;
|
|
106
|
+
if (row.customType === "voice_omni_transcript" && !voiceMessage) continue;
|
|
107
|
+
const entry = voiceMessage ? agentMessageToEntry(voiceMessage, parentId, byId) : customMessageRowToEntry(row, parentId, byId);
|
|
104
108
|
byId.add(entry.id);
|
|
105
109
|
entries.push(entry);
|
|
106
110
|
parentId = entry.id;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AgentMessage } from '@earendil-works/pi-agent-core';
|
|
2
|
+
export declare const VOICE_CALL_TYPE = "voice_call";
|
|
3
|
+
export declare const VOICE_TRANSCRIPT_TYPE = "voice_omni_transcript";
|
|
4
|
+
/** One projection for both direct LLM loads and the embedded SessionManager. */
|
|
5
|
+
export declare function voiceTranscriptMessage(row: {
|
|
6
|
+
content?: unknown;
|
|
7
|
+
details?: unknown;
|
|
8
|
+
timestamp?: string | number;
|
|
9
|
+
}): AgentMessage | null;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/session/voice-transcript.ts
|
|
2
|
+
const VOICE_CALL_TYPE = "voice_call";
|
|
3
|
+
const VOICE_TRANSCRIPT_TYPE = "voice_omni_transcript";
|
|
4
|
+
/** One projection for both direct LLM loads and the embedded SessionManager. */
|
|
5
|
+
function voiceTranscriptMessage(row) {
|
|
6
|
+
const details = row.details && typeof row.details === "object" ? row.details : {};
|
|
7
|
+
if (details.role !== "user" && details.role !== "assistant" || typeof row.content !== "string" || !row.content.trim()) return null;
|
|
8
|
+
const text = details.role === "assistant" && details.interrupted === true ? "[Voice reply was interrupted. Its generated text is omitted because the heard portion is unknown.]" : row.content;
|
|
9
|
+
const parsed = typeof row.timestamp === "number" ? row.timestamp : Date.parse(row.timestamp ?? "");
|
|
10
|
+
const timestamp = Number.isFinite(parsed) ? parsed : 0;
|
|
11
|
+
const content = [{
|
|
12
|
+
type: "text",
|
|
13
|
+
text
|
|
14
|
+
}];
|
|
15
|
+
if (details.role === "user") return {
|
|
16
|
+
role: "user",
|
|
17
|
+
content,
|
|
18
|
+
timestamp
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
role: "assistant",
|
|
22
|
+
content,
|
|
23
|
+
timestamp,
|
|
24
|
+
api: "openai-completions",
|
|
25
|
+
provider: "xopc-voice",
|
|
26
|
+
model: "voice-transcript",
|
|
27
|
+
stopReason: "stop",
|
|
28
|
+
usage: {
|
|
29
|
+
input: 0,
|
|
30
|
+
output: 0,
|
|
31
|
+
cacheRead: 0,
|
|
32
|
+
cacheWrite: 0,
|
|
33
|
+
totalTokens: 0,
|
|
34
|
+
cost: {
|
|
35
|
+
input: 0,
|
|
36
|
+
output: 0,
|
|
37
|
+
cacheRead: 0,
|
|
38
|
+
cacheWrite: 0,
|
|
39
|
+
total: 0
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { VOICE_CALL_TYPE, VOICE_TRANSCRIPT_TYPE, voiceTranscriptMessage };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
|
|
2
|
+
import { notifyUserContextChange } from "../../user-context/changes.js";
|
|
2
3
|
import { sessionConfigRowToConfig } from "./row-mappers.js";
|
|
3
4
|
import { ensureSessionInTransaction } from "./session-repository.js";
|
|
4
5
|
//#region src/storage/sqlite/config-repository.ts
|
|
@@ -21,6 +22,10 @@ function listSessionWorkspaceOverrides() {
|
|
|
21
22
|
`).all();
|
|
22
23
|
}
|
|
23
24
|
function setSessionConfig(sessionKey, config, cwd) {
|
|
25
|
+
notifyUserContextChange({
|
|
26
|
+
kind: "session",
|
|
27
|
+
id: sessionKey
|
|
28
|
+
});
|
|
24
29
|
return runSqliteWriteTransaction((db) => {
|
|
25
30
|
ensureSessionInTransaction(db, sessionKey, cwd);
|
|
26
31
|
const updatedAt = Math.max(Date.now(), (readConfigRow(db, sessionKey)?.updated_at ?? 0) + 1);
|
|
@@ -54,6 +59,10 @@ function updateSessionConfig(sessionKey, partial, cwd) {
|
|
|
54
59
|
}, cwd);
|
|
55
60
|
}
|
|
56
61
|
function deleteSessionConfig(sessionKey) {
|
|
62
|
+
notifyUserContextChange({
|
|
63
|
+
kind: "session",
|
|
64
|
+
id: sessionKey
|
|
65
|
+
});
|
|
57
66
|
runSqliteWriteTransaction((db) => {
|
|
58
67
|
db.prepare(`DELETE FROM session_config WHERE session_key = ?`).run(sessionKey);
|
|
59
68
|
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { getSqliteDatabase } from "./transaction.js";
|
|
2
|
+
import { USER_CONTEXT_PRINCIPAL_ID } from "../../user-context/domain.js";
|
|
3
|
+
//#region src/storage/sqlite/remote-context-repository.ts
|
|
4
|
+
/** Check all provenance, including older evidence, without loading private excerpts. */
|
|
5
|
+
function remoteContextEligibleIds(kind, ids) {
|
|
6
|
+
if (!ids.length) return /* @__PURE__ */ new Set();
|
|
7
|
+
if (ids.length > 200) throw new Error("Context candidate limit exceeded");
|
|
8
|
+
const focus = kind === "focus";
|
|
9
|
+
const table = focus ? "user_focuses" : "user_understandings";
|
|
10
|
+
const versions = focus ? "user_focus_versions" : "user_understanding_versions";
|
|
11
|
+
const links = focus ? "user_focus_evidence_links" : "understanding_evidence_links";
|
|
12
|
+
const id = focus ? "focus_id" : "understanding_id";
|
|
13
|
+
const rows = getSqliteDatabase().prepare(`
|
|
14
|
+
SELECT u.${id} AS id, v.created_by, u.explicitness,
|
|
15
|
+
COUNT(e.evidence_id) AS evidence_count,
|
|
16
|
+
MAX(CASE WHEN e.evidence_id IS NOT NULL AND (
|
|
17
|
+
(e.processing_policy IS NOT NULL AND e.processing_policy <> 'remote_allowed')
|
|
18
|
+
OR e.trust_level = 'untrusted' OR e.principal_id <> u.principal_id
|
|
19
|
+
OR (e.source_run_id IS NOT NULL AND (g.grant_id IS NULL OR g.status <> 'active' OR g.processing_policy <> 'remote_allowed'))
|
|
20
|
+
OR (e.source_type = 'connector' AND (e.processing_policy IS NULL OR e.source_run_id IS NULL))
|
|
21
|
+
OR (e.processing_policy IS NULL AND e.source_type <> 'user' AND e.trust_level <> 'owner')
|
|
22
|
+
) THEN 1 ELSE 0 END) AS blocked
|
|
23
|
+
FROM ${table} u
|
|
24
|
+
JOIN ${versions} v ON v.version_id = u.current_version_id
|
|
25
|
+
LEFT JOIN ${versions} history ON history.${id} = u.${id}
|
|
26
|
+
LEFT JOIN ${links} l ON l.version_id = history.version_id
|
|
27
|
+
LEFT JOIN context_evidence e ON e.evidence_id = l.evidence_id
|
|
28
|
+
LEFT JOIN understanding_source_runs r ON r.run_id = e.source_run_id
|
|
29
|
+
LEFT JOIN understanding_source_grants g ON g.grant_id = r.grant_id
|
|
30
|
+
WHERE u.principal_id = ? AND u.${id} IN (${ids.map(() => "?").join(",")})
|
|
31
|
+
${focus ? `AND (u.source_run_id IS NULL OR EXISTS (
|
|
32
|
+
SELECT 1 FROM understanding_source_runs fr JOIN understanding_source_grants fg ON fg.grant_id = fr.grant_id
|
|
33
|
+
WHERE fr.run_id = u.source_run_id AND fg.status = 'active' AND fg.processing_policy = 'remote_allowed'
|
|
34
|
+
))` : ""}
|
|
35
|
+
GROUP BY u.${id}
|
|
36
|
+
`).all(USER_CONTEXT_PRINCIPAL_ID, ...ids);
|
|
37
|
+
return new Set(rows.filter((row) => !row.blocked && (row.evidence_count > 0 || row.explicitness === "explicit" && row.created_by === "user")).map((row) => row.id));
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { remoteContextEligibleIds };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
|
|
2
|
+
import { notifyUserContextChange } from "../../user-context/changes.js";
|
|
2
3
|
import { buildFts5SearchQuery } from "./fts.js";
|
|
3
4
|
import { validateSessionId } from "../../session/session-id.js";
|
|
4
5
|
import { buildDefaultSessionMetadata } from "./session-metadata.js";
|
|
@@ -175,6 +176,10 @@ function sessionSortColumn(sortBy) {
|
|
|
175
176
|
}
|
|
176
177
|
}
|
|
177
178
|
function patchSessionMetadata(sessionKey, updates) {
|
|
179
|
+
if ("projectId" in updates) notifyUserContextChange({
|
|
180
|
+
kind: "session-reset",
|
|
181
|
+
id: sessionKey
|
|
182
|
+
});
|
|
178
183
|
return runSqliteWriteTransaction((db) => {
|
|
179
184
|
const existing = readSessionRow(db, sessionKey);
|
|
180
185
|
if (!existing) throw new Error(`Session not found: ${sessionKey}`);
|
|
@@ -242,6 +247,10 @@ function incrementSessionStatsOnAppend(sessionKey, tokenDelta = 0) {
|
|
|
242
247
|
});
|
|
243
248
|
}
|
|
244
249
|
function resetSessionRecord(sessionKey, cwd) {
|
|
250
|
+
notifyUserContextChange({
|
|
251
|
+
kind: "session-reset",
|
|
252
|
+
id: sessionKey
|
|
253
|
+
});
|
|
245
254
|
return runSqliteWriteTransaction((db) => {
|
|
246
255
|
const existing = readSessionRow(db, sessionKey);
|
|
247
256
|
if (!existing) return null;
|
|
@@ -267,6 +276,10 @@ function resetSessionRecord(sessionKey, cwd) {
|
|
|
267
276
|
});
|
|
268
277
|
}
|
|
269
278
|
function deleteSessionRecord(sessionKey) {
|
|
279
|
+
notifyUserContextChange({
|
|
280
|
+
kind: "session-reset",
|
|
281
|
+
id: sessionKey
|
|
282
|
+
});
|
|
270
283
|
return runSqliteWriteTransaction((db) => {
|
|
271
284
|
const existing = readSessionRow(db, sessionKey);
|
|
272
285
|
if (!existing) return false;
|
|
@@ -18,7 +18,7 @@ export type CreateUnderstandingInput = Omit<UserUnderstanding, 'id' | 'versionId
|
|
|
18
18
|
};
|
|
19
19
|
export declare function createUnderstanding(input: CreateUnderstandingInput, principalId?: string): UserUnderstanding;
|
|
20
20
|
export declare function getUnderstanding(id: string): UserUnderstanding | undefined;
|
|
21
|
-
export declare function listUnderstandings(statuses?: UnderstandingStatus[], principalId?: string): UserUnderstanding[];
|
|
21
|
+
export declare function listUnderstandings(statuses?: UnderstandingStatus[], principalId?: string, limit?: number): UserUnderstanding[];
|
|
22
22
|
export declare function searchActiveUnderstandings(query: string, limit?: number): Array<{
|
|
23
23
|
understanding: UserUnderstanding;
|
|
24
24
|
score: number;
|
|
@@ -52,6 +52,8 @@ export declare function createContextEvidence(input: Omit<ContextEvidence, 'id'
|
|
|
52
52
|
}, principalId?: string): ContextEvidence;
|
|
53
53
|
export declare function linkUnderstandingEvidence(versionId: string, evidenceId: string, relation: 'supports' | 'contradicts' | 'supersedes', confidence: number): void;
|
|
54
54
|
export declare function listUnderstandingEvidence(understandingId: string, relation?: 'supports' | 'contradicts' | 'supersedes'): ContextEvidence[];
|
|
55
|
+
/** Latest source labels for ranking, without fetching evidence bodies per candidate. */
|
|
56
|
+
export declare function understandingSourceBuckets(ids: string[]): Map<string, string>;
|
|
55
57
|
export declare function recordContextRun(input: {
|
|
56
58
|
turnId: string;
|
|
57
59
|
sessionKey: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
|
|
2
2
|
import { USER_CONTEXT_PRINCIPAL_ID } from "../../user-context/domain.js";
|
|
3
|
+
import { notifyUserContextChange } from "../../user-context/changes.js";
|
|
3
4
|
import { retrievalQueryAuditValue } from "../../retrieval/audit.js";
|
|
4
5
|
import { buildFts5SearchQuery, fts5RankToScore } from "./fts.js";
|
|
5
6
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -108,6 +109,10 @@ function getUserProfile(principalId = USER_CONTEXT_PRINCIPAL_ID) {
|
|
|
108
109
|
};
|
|
109
110
|
}
|
|
110
111
|
function updateUserProfile(patch, principalId = USER_CONTEXT_PRINCIPAL_ID) {
|
|
112
|
+
notifyUserContextChange({
|
|
113
|
+
kind: "profile",
|
|
114
|
+
id: "profile"
|
|
115
|
+
});
|
|
111
116
|
const current = getUserProfile(principalId);
|
|
112
117
|
const now = Date.now();
|
|
113
118
|
const next = {
|
|
@@ -163,11 +168,12 @@ function getUnderstanding(id) {
|
|
|
163
168
|
const row = getSqliteDatabase().prepare(`${UNDERSTANDING_SELECT} WHERE u.understanding_id = ?`).get(id);
|
|
164
169
|
return row ? understandingFromRow(row) : void 0;
|
|
165
170
|
}
|
|
166
|
-
function listUnderstandings(statuses, principalId = USER_CONTEXT_PRINCIPAL_ID) {
|
|
171
|
+
function listUnderstandings(statuses, principalId = USER_CONTEXT_PRINCIPAL_ID, limit) {
|
|
167
172
|
const db = getSqliteDatabase();
|
|
168
|
-
|
|
173
|
+
const maxRows = limit === void 0 ? -1 : Math.max(1, Math.min(500, Math.floor(limit)));
|
|
174
|
+
if (!statuses?.length) return db.prepare(`${UNDERSTANDING_SELECT} WHERE u.principal_id = ? ORDER BY u.updated_at DESC LIMIT ?`).all(principalId, maxRows).map(understandingFromRow);
|
|
169
175
|
const placeholders = statuses.map(() => "?").join(", ");
|
|
170
|
-
return db.prepare(`${UNDERSTANDING_SELECT} WHERE u.principal_id = ? AND u.status IN (${placeholders}) ORDER BY u.updated_at DESC
|
|
176
|
+
return db.prepare(`${UNDERSTANDING_SELECT} WHERE u.principal_id = ? AND u.status IN (${placeholders}) ORDER BY u.updated_at DESC LIMIT ?`).all(principalId, ...statuses, maxRows).map(understandingFromRow);
|
|
171
177
|
}
|
|
172
178
|
function searchActiveUnderstandings(query, limit = 50) {
|
|
173
179
|
const ftsQuery = buildFts5SearchQuery(query);
|
|
@@ -193,6 +199,10 @@ function searchActiveUnderstandings(query, limit = 50) {
|
|
|
193
199
|
}));
|
|
194
200
|
}
|
|
195
201
|
function reviseUnderstanding(id, statement, options) {
|
|
202
|
+
notifyUserContextChange({
|
|
203
|
+
kind: "understanding",
|
|
204
|
+
id
|
|
205
|
+
});
|
|
196
206
|
const current = getUnderstanding(id);
|
|
197
207
|
if (!current) throw new Error(`User understanding not found: ${id}`);
|
|
198
208
|
const versionId = randomUUID();
|
|
@@ -210,6 +220,10 @@ function reviseUnderstanding(id, statement, options) {
|
|
|
210
220
|
return getUnderstanding(id);
|
|
211
221
|
}
|
|
212
222
|
function setUnderstandingStatus(id, status, options) {
|
|
223
|
+
notifyUserContextChange({
|
|
224
|
+
kind: "understanding",
|
|
225
|
+
id
|
|
226
|
+
});
|
|
213
227
|
const current = getUnderstanding(id);
|
|
214
228
|
if (!current) throw new Error(`User understanding not found: ${id}`);
|
|
215
229
|
const now = Date.now();
|
|
@@ -237,6 +251,10 @@ function setUnderstandingStatus(id, status, options) {
|
|
|
237
251
|
return result;
|
|
238
252
|
}
|
|
239
253
|
function closeUnderstandingValidity(id, validTo = Date.now()) {
|
|
254
|
+
notifyUserContextChange({
|
|
255
|
+
kind: "understanding",
|
|
256
|
+
id
|
|
257
|
+
});
|
|
240
258
|
getSqliteDatabase().prepare(`UPDATE user_understandings SET valid_to = ?, updated_at = ?
|
|
241
259
|
WHERE understanding_id = ?`).run(validTo, validTo, id);
|
|
242
260
|
const result = getUnderstanding(id);
|
|
@@ -244,6 +262,10 @@ function closeUnderstandingValidity(id, validTo = Date.now()) {
|
|
|
244
262
|
return result;
|
|
245
263
|
}
|
|
246
264
|
function rejectUnderstanding(id, reason, actorType = "runtime") {
|
|
265
|
+
notifyUserContextChange({
|
|
266
|
+
kind: "understanding",
|
|
267
|
+
id
|
|
268
|
+
});
|
|
247
269
|
const current = getUnderstanding(id);
|
|
248
270
|
if (!current) throw new Error(`User understanding not found: ${id}`);
|
|
249
271
|
const now = Date.now();
|
|
@@ -277,6 +299,10 @@ function listUnderstandingStatusEvents(id) {
|
|
|
277
299
|
}));
|
|
278
300
|
}
|
|
279
301
|
function deleteUnderstanding(id) {
|
|
302
|
+
notifyUserContextChange({
|
|
303
|
+
kind: "understanding",
|
|
304
|
+
id
|
|
305
|
+
});
|
|
280
306
|
return runSqliteWriteTransaction((db) => {
|
|
281
307
|
db.prepare("DELETE FROM user_understanding_fts WHERE understanding_id = ?").run(id);
|
|
282
308
|
return Number(db.prepare("DELETE FROM user_understandings WHERE understanding_id = ?").run(id).changes) > 0;
|
|
@@ -342,6 +368,7 @@ function createContextEvidence(input, principalId = USER_CONTEXT_PRINCIPAL_ID) {
|
|
|
342
368
|
AND COALESCE(source_instance_id, '') = COALESCE(?, '') AND source_ref = ?`).get(principalId, input.sourceType, input.sourceInstanceId ?? null, input.sourceRef);
|
|
343
369
|
const derivedHash = input.contentHash ?? (input.redactedExcerpt ? createHash("sha256").update(input.redactedExcerpt).digest("hex") : void 0);
|
|
344
370
|
if (existing) {
|
|
371
|
+
notifyUserContextChange({ kind: "policy" });
|
|
345
372
|
getSqliteDatabase().prepare(`UPDATE context_evidence SET
|
|
346
373
|
source_run_id = COALESCE(source_run_id, ?), source_item_id = COALESCE(source_item_id, ?),
|
|
347
374
|
session_id = COALESCE(session_id, ?), turn_id = COALESCE(turn_id, ?),
|
|
@@ -373,6 +400,11 @@ function createContextEvidence(input, principalId = USER_CONTEXT_PRINCIPAL_ID) {
|
|
|
373
400
|
return evidence;
|
|
374
401
|
}
|
|
375
402
|
function linkUnderstandingEvidence(versionId, evidenceId, relation, confidence) {
|
|
403
|
+
const owner = getSqliteDatabase().prepare("SELECT understanding_id AS id FROM user_understanding_versions WHERE version_id = ?").get(versionId);
|
|
404
|
+
if (owner) notifyUserContextChange({
|
|
405
|
+
kind: "understanding",
|
|
406
|
+
id: owner.id
|
|
407
|
+
});
|
|
376
408
|
getSqliteDatabase().prepare(`INSERT INTO understanding_evidence_links (
|
|
377
409
|
version_id, evidence_id, relation, confidence
|
|
378
410
|
) VALUES (?, ?, ?, ?)
|
|
@@ -385,6 +417,20 @@ function listUnderstandingEvidence(understandingId, relation) {
|
|
|
385
417
|
WHERE v.understanding_id = ? AND (? IS NULL OR l.relation = ?)
|
|
386
418
|
ORDER BY e.observed_at DESC`).all(understandingId, relation ?? null, relation ?? null).map(evidenceFromRow);
|
|
387
419
|
}
|
|
420
|
+
/** Latest source labels for ranking, without fetching evidence bodies per candidate. */
|
|
421
|
+
function understandingSourceBuckets(ids) {
|
|
422
|
+
if (!ids.length) return /* @__PURE__ */ new Map();
|
|
423
|
+
const rows = getSqliteDatabase().prepare(`
|
|
424
|
+
SELECT understanding_id, source_type, source_instance_id, source_ref FROM (
|
|
425
|
+
SELECT v.understanding_id, e.source_type, e.source_instance_id, e.source_ref,
|
|
426
|
+
ROW_NUMBER() OVER (PARTITION BY v.understanding_id ORDER BY e.observed_at DESC) AS rank
|
|
427
|
+
FROM context_evidence e JOIN understanding_evidence_links l ON l.evidence_id = e.evidence_id
|
|
428
|
+
JOIN user_understanding_versions v ON v.version_id = l.version_id
|
|
429
|
+
WHERE v.understanding_id IN (${ids.map(() => "?").join(",")})
|
|
430
|
+
) WHERE rank = 1
|
|
431
|
+
`).all(...ids);
|
|
432
|
+
return new Map(rows.map((row) => [row.understanding_id, `${row.source_type}:${row.source_instance_id ?? row.source_ref.split(":entry:")[0]}`]));
|
|
433
|
+
}
|
|
388
434
|
function recordContextRun(input) {
|
|
389
435
|
const auditedQuery = retrievalQueryAuditValue(input.query);
|
|
390
436
|
const existing = getSqliteDatabase().prepare("SELECT context_run_id FROM context_runs WHERE turn_id = ?").get(input.turnId);
|
|
@@ -486,4 +532,4 @@ function decideContextConsent(id, decision) {
|
|
|
486
532
|
return Number(result.changes) > 0;
|
|
487
533
|
}
|
|
488
534
|
//#endregion
|
|
489
|
-
export { closeUnderstandingValidity, consumeContextConsent, createCollaborationRule, createContextEvidence, createUnderstanding, decideContextConsent, deleteCollaborationRule, deleteUnderstanding, ensureContextConsent, getCollaborationRule, getTurnPersonalization, getUnderstanding, getUserProfile, hasContextConsent, isUnderstandingSuppressed, linkUnderstandingEvidence, listCollaborationRules, listUnderstandingEvidence, listUnderstandingStatusEvents, listUnderstandings, recordContextFeedback, recordContextRun, rejectUnderstanding, reviseCollaborationRule, reviseUnderstanding, searchActiveUnderstandings, setCollaborationRuleStatus, setUnderstandingStatus, updateUserProfile };
|
|
535
|
+
export { closeUnderstandingValidity, consumeContextConsent, createCollaborationRule, createContextEvidence, createUnderstanding, decideContextConsent, deleteCollaborationRule, deleteUnderstanding, ensureContextConsent, getCollaborationRule, getTurnPersonalization, getUnderstanding, getUserProfile, hasContextConsent, isUnderstandingSuppressed, linkUnderstandingEvidence, listCollaborationRules, listUnderstandingEvidence, listUnderstandingStatusEvents, listUnderstandings, recordContextFeedback, recordContextRun, rejectUnderstanding, reviseCollaborationRule, reviseUnderstanding, searchActiveUnderstandings, setCollaborationRuleStatus, setUnderstandingStatus, understandingSourceBuckets, updateUserProfile };
|
package/dist/src/tui/tui.js
CHANGED
|
@@ -477,7 +477,8 @@ async function runTui(opts) {
|
|
|
477
477
|
isHidden: () => hidden,
|
|
478
478
|
focus: () => tui.setFocus(component),
|
|
479
479
|
unfocus: () => tui.setFocus(editor),
|
|
480
|
-
isFocused: () => false
|
|
480
|
+
isFocused: () => false,
|
|
481
|
+
getBounds: () => void 0
|
|
481
482
|
};
|
|
482
483
|
};
|
|
483
484
|
const closeCommandOverlay = () => {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type RemoteContextKind } from '../storage/sqlite/remote-context-repository.js';
|
|
2
|
+
import type { UserContextScopeTarget } from './scope.js';
|
|
3
|
+
export interface AutomaticContextReference {
|
|
4
|
+
kind: RemoteContextKind | 'profile';
|
|
5
|
+
id: string;
|
|
6
|
+
version: string;
|
|
7
|
+
}
|
|
8
|
+
export interface AutomaticContextSelection {
|
|
9
|
+
block: string;
|
|
10
|
+
references: AutomaticContextReference[];
|
|
11
|
+
}
|
|
12
|
+
/** Read-only background selection. Never consumes consent or starts a model turn. */
|
|
13
|
+
export declare function selectAutomaticContext(input: UserContextScopeTarget & {
|
|
14
|
+
query: string;
|
|
15
|
+
maxChars: number;
|
|
16
|
+
deadline: number;
|
|
17
|
+
}): AutomaticContextSelection;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { getUserProfile, listUnderstandings } from "../storage/sqlite/user-context-repository.js";
|
|
2
|
+
import { listUserFocuses } from "./sources/repository.js";
|
|
3
|
+
import { UserUnderstandingRetriever } from "./retriever.js";
|
|
4
|
+
import { allowsAutomaticDisclosure, focusRejectionReason, focusScore, rejectionReason } from "./selection-policy.js";
|
|
5
|
+
import { remoteContextEligibleIds } from "../storage/sqlite/remote-context-repository.js";
|
|
6
|
+
//#region src/user-context/automatic-context.ts
|
|
7
|
+
/** Read-only background selection. Never consumes consent or starts a model turn. */
|
|
8
|
+
function selectAutomaticContext(input) {
|
|
9
|
+
const references = [];
|
|
10
|
+
const facts = [];
|
|
11
|
+
const profile = {};
|
|
12
|
+
const render = () => JSON.stringify({ backgroundMemory: {
|
|
13
|
+
profile,
|
|
14
|
+
facts
|
|
15
|
+
} });
|
|
16
|
+
const withinDeadline = () => performance.now() < input.deadline;
|
|
17
|
+
if (input.maxChars < 128 || !withinDeadline()) return {
|
|
18
|
+
block: "",
|
|
19
|
+
references
|
|
20
|
+
};
|
|
21
|
+
const user = getUserProfile();
|
|
22
|
+
for (const key of [
|
|
23
|
+
"callName",
|
|
24
|
+
"locale",
|
|
25
|
+
"timezone",
|
|
26
|
+
"pronouns",
|
|
27
|
+
"role",
|
|
28
|
+
"primaryGoal"
|
|
29
|
+
]) {
|
|
30
|
+
if (!user[key] || user[key].length > 300) continue;
|
|
31
|
+
profile[key] = user[key];
|
|
32
|
+
if (render().length > input.maxChars) delete profile[key];
|
|
33
|
+
}
|
|
34
|
+
if (Object.keys(profile).length) references.push({
|
|
35
|
+
kind: "profile",
|
|
36
|
+
id: "profile",
|
|
37
|
+
version: JSON.stringify(user)
|
|
38
|
+
});
|
|
39
|
+
const query = input.query.trim();
|
|
40
|
+
const candidates = !withinDeadline() ? [] : query ? new UserUnderstandingRetriever().retrieve({
|
|
41
|
+
...input,
|
|
42
|
+
maxCandidates: 50
|
|
43
|
+
}) : listUnderstandings(["active"], void 0, 200).filter((item) => item.explicitness === "explicit" && ["preference", "boundary"].includes(item.kind) && item.durability === "durable").map((understanding) => ({
|
|
44
|
+
understanding,
|
|
45
|
+
score: 1
|
|
46
|
+
}));
|
|
47
|
+
const now = Date.now();
|
|
48
|
+
const eligible = candidates.filter(({ understanding: item, score }) => item.status === "active" && allowsAutomaticDisclosure(item) && !rejectionReason(item, input, now, []) && score > .25);
|
|
49
|
+
const allowed = withinDeadline() ? remoteContextEligibleIds("understanding", eligible.map(({ understanding }) => understanding.id)) : /* @__PURE__ */ new Set();
|
|
50
|
+
const append = (text, origin, reference) => {
|
|
51
|
+
if (!withinDeadline() || facts.length >= 6 || !text.trim()) return;
|
|
52
|
+
facts.push({
|
|
53
|
+
text,
|
|
54
|
+
origin
|
|
55
|
+
});
|
|
56
|
+
if (render().length > input.maxChars) {
|
|
57
|
+
facts.pop();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
references.push(reference);
|
|
61
|
+
};
|
|
62
|
+
for (const { understanding: item } of eligible) if (allowed.has(item.id)) append(item.statement, item.explicitness, {
|
|
63
|
+
kind: "understanding",
|
|
64
|
+
id: item.id,
|
|
65
|
+
version: item.versionId
|
|
66
|
+
});
|
|
67
|
+
if (query && withinDeadline() && facts.length < 6) {
|
|
68
|
+
const focuses = listUserFocuses(["active"], 50).filter((item) => allowsAutomaticDisclosure(item) && !focusRejectionReason(item, input, now)).map((item) => ({
|
|
69
|
+
item,
|
|
70
|
+
score: focusScore(item, query, input)
|
|
71
|
+
})).filter(({ score }) => score > .25).sort((a, b) => b.score - a.score);
|
|
72
|
+
const allowedFocuses = remoteContextEligibleIds("focus", focuses.map(({ item }) => item.id));
|
|
73
|
+
for (const { item } of focuses) if (allowedFocuses.has(item.id)) append(`${item.title}: ${item.summary}`, item.explicitness, {
|
|
74
|
+
kind: "focus",
|
|
75
|
+
id: item.id,
|
|
76
|
+
version: item.versionId ?? String(item.updatedAt)
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
block: references.length ? render() : "",
|
|
81
|
+
references
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
export { selectAutomaticContext };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface UserContextChange {
|
|
2
|
+
kind: 'profile' | 'understanding' | 'focus' | 'policy' | 'session' | 'session-reset';
|
|
3
|
+
id?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function onUserContextChange(listener: (change: UserContextChange) => void): () => void;
|
|
6
|
+
/** Dispatch after the synchronous write/outer transaction has left the stack. */
|
|
7
|
+
export declare function notifyUserContextChange(change: UserContextChange): void;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../utils/logger.js";
|
|
3
|
+
//#region src/user-context/changes.ts
|
|
4
|
+
init_logger();
|
|
5
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
6
|
+
const log = createLogger("UserContextChanges");
|
|
7
|
+
function onUserContextChange(listener) {
|
|
8
|
+
listeners.add(listener);
|
|
9
|
+
return () => {
|
|
10
|
+
listeners.delete(listener);
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/** Dispatch after the synchronous write/outer transaction has left the stack. */
|
|
14
|
+
function notifyUserContextChange(change) {
|
|
15
|
+
if (!listeners.size) return;
|
|
16
|
+
queueMicrotask(() => {
|
|
17
|
+
for (const listener of listeners) try {
|
|
18
|
+
listener(change);
|
|
19
|
+
} catch (err) {
|
|
20
|
+
log.error({
|
|
21
|
+
err,
|
|
22
|
+
kind: change.kind
|
|
23
|
+
}, "User context change listener failed");
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { notifyUserContextChange, onUserContextChange };
|