@xopcai/xopc 0.0.344 → 0.0.346
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/dist/assets/{auth-BsvblhQz.js → auth-CFiOJ_rf.js} +1 -1
- package/dist/browser-ext/dist/background.js +1 -1
- package/dist/browser-ext/dist/sidepanel.html +1 -1
- package/dist/browser-ext/dist/sidepanel.js +1 -1
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DRFs0Jjv.js → agent-avatar-dicebear-M2vuj6W3.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-C9J-ILd0.js → agent-defaults-settings-panel-B_d0WGFm.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-plugin-dialog-CGstiK5S.js → agent-plugin-dialog-egTQDEeV.js} +1 -1
- package/dist/gateway/static/root/assets/{agents-DS-CV-xB.js → agents-BbwmG8Kl.js} +6 -6
- package/dist/gateway/static/root/assets/{agents-admin-api-BTYHoqlW.js → agents-admin-api-Dlw9XxYa.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-znCRRKVF.js → app-management-settings-panel-IxWZDAeT.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DSUujN-S.js → appearance-settings-C56szwjn.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-7uOjQp30.js → apps-page-Cqoc4xoi.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-DV01jcWu.js → archive-plugin-Ce3TNO-R.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-D_Ts5PDI.js → automations-page-4so9_Bya.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-workspace-Dg7IuWeB.js → automations-workspace-CP3GH1iA.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-CEoIySYJ.js → binary-plugins-l6tKp21u.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-4bv_tjfg.js → block-editor-cj2RNjQs.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automation-inputs-UYRx7nE_.js → browser-automation-inputs-C9W2EklQ.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automations-page-EtXgro_V.js → browser-automations-page-CbTkFxIX.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-settings-page-Bf45sjmd.js → browser-settings-page-KMfDs9dO.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-B-2wxCUQ.js → capabilities-Co9ZxHHB.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-page-YjIv97Sw.js → capabilities-page-cm2Q7EfF.js} +2 -2
- package/dist/gateway/static/root/assets/{capabilities-settings-panel-Ch2iNnfI.js → capabilities-settings-panel-CIe5qsxW.js} +1 -1
- package/dist/gateway/static/root/assets/{capability-header-actions-DJKC0sss.js → capability-header-actions-D2ASOs4Z.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-BWZmepe_.js → channels-D-DnLz_c.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-DLBqdgS-.js → chat-terminal-dock-DaQrqzCz.js} +1 -1
- package/dist/gateway/static/root/assets/computer-settings-page-C-59NTyH.js +1 -0
- package/dist/gateway/static/root/assets/{connector-service-page-CYE4gX1g.js → connector-service-page-Cq7t7AJq.js} +1 -1
- package/dist/gateway/static/root/assets/{connectors-page-dJDZx96_.js → connectors-page-BH53KX8Y.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-BM9HDlUj.js → date-picker-CcfRQKmj.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-BybqITjG.js → dependency-picker-b9Tif8dg.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-CYoJiTna.js → desktop-pet-BHe6Cb51.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-CXcTdFHs.js → desktop-pet-settings-wgA6yOo1.js} +1 -1
- package/dist/gateway/static/root/assets/{device-pairing-wizard-DnkRc3SQ.js → device-pairing-wizard-fv8c6u1o.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-BNC2UnEM.js → directory-picker-path-field-DM2YpM4N.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-CHU0dr2j.js → extension-debug-page-B-Y_Zk8L.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DXjPSQIh.js → extension-page-BC1m3MlB.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DqFNPQsx.js → extension-settings-page-Cu3cfeJj.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-DcE8n_ZS.js → gateway-config-swr-ukBQYwfH.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-realtime-DvNfXjan.js +1 -0
- package/dist/gateway/static/root/assets/gateway-realtime-store-DGQMXjfI.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-settings-BJVKTwIx.js → gateway-settings-pxmn3b8n.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-CCPlq9Lk.js → gateway-startup-retry-CVpOj205.js} +1 -1
- package/dist/gateway/static/root/assets/{home-page-B2imtrmi.js → home-page-DOsvv2rU.js} +1 -1
- package/dist/gateway/static/root/assets/{image-generation-api-D1Uh-05P.js → image-generation-api-zxx0qG9z.js} +1 -1
- package/dist/gateway/static/root/assets/{imports-page-CsypWC3J.js → imports-page-CWYDLeqJ.js} +1 -1
- package/dist/gateway/static/root/assets/index-DsIQD44S.js +106 -0
- package/dist/gateway/static/root/assets/index-y6kxoLV2.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CSzm05SM.js → keyboard-shortcuts-settings-BEkTI6mv.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-BulzWHzC.js → local-app-workbench-page-aSXZL05r.js} +1 -1
- package/dist/gateway/static/root/assets/{local-apps-page-BQ2QlJNH.js → local-apps-page-BJThsekO.js} +1 -1
- package/dist/gateway/static/root/assets/{local-session-drafts-D9DeB55u.js → local-session-drafts-Dt_Yx7kq.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-B0WmWiCo.js → locale-store-B008NR-f.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-harzpOPJ.js → logs-page-WlqqTmpk.js} +1 -1
- package/dist/gateway/static/root/assets/{management-settings-BXKeyT_O.js → management-settings-j_npowOA.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-CSADmLmZ.js → markdown-view-BjDzimRP.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-CMe8YQ8l.js → media-plugins-DhYWGP6O.js} +1 -1
- package/dist/gateway/static/root/assets/messages-aVTaD9Mj.js +3 -0
- package/dist/gateway/static/root/assets/{note-detail-panel-DD9n9tnf.js → note-detail-panel-CYcNB2Pf.js} +3 -3
- package/dist/gateway/static/root/assets/{notes-page-B5NcvMau.js → notes-page-4D1-mt6Y.js} +1 -1
- package/dist/gateway/static/root/assets/{page-context-capture-button-BwFIuZqk.js → page-context-capture-button-BfmOqRGN.js} +1 -1
- package/dist/gateway/static/root/assets/{page-tabs-DH4JI3t_.js → page-tabs-aFGUXE53.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-D3Wsh5jh.js → preview-open-alternatives-BCEnqJTC.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-iigCUM2g.js → product-open-page-DHcx6kDT.js} +1 -1
- package/dist/gateway/static/root/assets/{project-detail-page-C19aDnSV.js → project-detail-page-ChKkovsq.js} +1 -1
- package/dist/gateway/static/root/assets/{projects-page-aWOL4_py.js → projects-page-Lt3HXMRm.js} +1 -1
- package/dist/gateway/static/root/assets/{registry-api-Bw0ZkSav.js → registry-api-EPj5O77m.js} +1 -1
- package/dist/gateway/static/root/assets/{remote-access-hub-CGLJFrLG.js → remote-access-hub-B94Vc-fj.js} +1 -1
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-ArGdQMYT.js → runtime-tools-settings-panel-DNU19xEH.js} +1 -1
- package/dist/gateway/static/root/assets/{scenes-page-WB5cZttQ.js → scenes-page-BgzfnfOB.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-Bzga2Tq0.js → schema-form-MKBLqh8C.js} +1 -1
- package/dist/gateway/static/root/assets/session-api-D5BlAIge.js +1 -0
- package/dist/gateway/static/root/assets/session-manager-DcFS0yfO.js +16 -0
- package/dist/gateway/static/root/assets/{sessions-page-DCs83Gg-.js → sessions-page-sYWhgEMH.js} +1 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-alf3atpI.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-DMchToFl.js → settings-form-section-C2gcfyxy.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-Dh-S9_GO.js → settings-page-CYd6_yBb.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-kFPkdt3z.js → setup-status-panel-CUbH_YtB.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-CrVC0BzQ.js → share-preview-page-Dxwq4fx1.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-settings-ZesbsEGA.js → shares-settings-CqwHm0Mf.js} +1 -1
- package/dist/gateway/static/root/assets/{skill-api-Deb8HqtR.js → skill-api-C9k6G-tI.js} +1 -1
- package/dist/gateway/static/root/assets/skill-reload-api-D9bB-ANm.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-Bgs9jaCc.js → skills-page-CFiCgbAs.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-CwD47-_i.js → system-settings-panel-1tXKr0cJ.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-BBQ3sk4y.js +1 -0
- package/dist/gateway/static/root/assets/{tasks-QQJXsiER.js → tasks-BH8_WMUF.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-DtL__Vgg.js → tunnel-api-COo0rSrc.js} +1 -1
- package/dist/gateway/static/root/assets/{usage-page-DZ01CsLl.js → usage-page-DHXG-2Rr.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-XBFnwLd0.js → use-autosave-CJfX4SWk.js} +1 -1
- package/dist/gateway/static/root/assets/{user-model-page-ByACaDBG.js → user-model-page-d-Gjs-EX.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-NaIj9rQC.js → voice-api-key-field-D0gWz3iO.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-st1q4lqP.js → voice-config-api-BnnUzr07.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-D418eqa5.js → work-discovery-overlay-CDAZKFVO.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-CSXIidqw.js → workflow-run-setup-panel-Db0lk_9G.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-nGttfQ1r.js → workflows-page-Dj89Gagd.js} +1 -1
- package/dist/gateway/static/root/index.html +16 -16
- package/dist/package.js +1 -1
- package/dist/packages/endpoint-tools-protocol/src/index.js +2 -1
- package/dist/packages/gateway-contract/src/sessions.js +11 -0
- package/dist/packages/gateway-contract/src/tasks.js +1 -0
- package/dist/src/agent/memory/context-budget.d.ts +2 -0
- package/dist/src/agent/memory/context-budget.js +23 -2
- package/dist/src/agent/memory/context-recovery.js +2 -2
- package/dist/src/agent/service/direct-turn-helpers.js +2 -2
- package/dist/src/agent/service/process-direct-streaming.js +16 -2
- package/dist/src/agent/tasks/task-judge-service.d.ts +1 -0
- package/dist/src/agent/tasks/task-judge-service.js +55 -33
- package/dist/src/agent/tool-manuals/computer.d.ts +1 -1
- package/dist/src/agent/tool-manuals/computer.js +2 -2
- package/dist/src/agent/tool-manuals/xopc-use.d.ts +1 -1
- package/dist/src/agent/tool-manuals/xopc-use.js +28 -2
- package/dist/src/agent/tools/computer-use-tool.d.ts +0 -2
- package/dist/src/agent/tools/computer-use-tool.js +31 -19
- package/dist/src/agent/tools/factory.js +2 -3
- package/dist/src/agent/tools/xopc-use-tool.js +179 -8
- package/dist/src/capabilities/runtime/dispatcher.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/computer/broker.d.ts +6 -0
- package/dist/src/computer/broker.js +14 -0
- package/dist/src/computer/errors.js +2 -1
- package/dist/src/computer/model-adapter.js +3 -3
- package/dist/src/gateway/chat-stream/mapper.d.ts +3 -0
- package/dist/src/gateway/chat-stream/mapper.js +5 -1
- package/dist/src/gateway/chat-stream/protocol.d.ts +3 -0
- package/dist/src/gateway/hono/routes/session-input-handler.d.ts +2 -2
- package/dist/src/gateway/hono/routes/sessions.js +19 -2
- package/dist/src/gateway/hono/routes/tasks.js +93 -0
- package/dist/src/gateway/service/active-execution.js +1 -1
- package/dist/src/gateway/service/run-gateway-agent.js +5 -1
- package/dist/src/gateway/service/session-input-coordinator.d.ts +1 -1
- package/dist/src/gateway/service.d.ts +2 -1
- package/dist/src/gateway/service.js +70 -6
- package/dist/src/gateway/session-context-summary.js +17 -0
- package/dist/src/home-intelligence/host.js +2 -2
- package/dist/src/session/client-history.d.ts +7 -1
- package/dist/src/session/client-history.js +51 -1
- package/dist/src/session/store.js +10 -2
- package/dist/src/session/types.d.ts +1 -0
- package/dist/src/storage/sqlite/index.d.ts +1 -1
- package/dist/src/storage/sqlite/index.js +2 -2
- package/dist/src/storage/sqlite/migrations/224_task_origin_links.sql +8 -0
- package/dist/src/storage/sqlite/migrations/225_task_collaboration.sql +32 -0
- package/dist/src/storage/sqlite/migrations/226_task_main_updates.sql +9 -0
- package/dist/src/storage/sqlite/migrations/227_task_main_update_decisions.sql +8 -0
- package/dist/src/storage/sqlite/migrations/228_task_main_agent_links.sql +14 -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/storage/sqlite/session-input-repository.d.ts +9 -0
- package/dist/src/storage/sqlite/session-input-repository.js +28 -1
- package/dist/src/storage/sqlite/session-repository.js +11 -0
- package/dist/src/tasks/capabilities/write.js +2 -0
- package/dist/src/tasks/index.js +2 -2
- package/dist/src/tasks/task-application-service.js +19 -1
- package/dist/src/tasks/task-collaboration-delivery.d.ts +9 -0
- package/dist/src/tasks/task-collaboration-delivery.js +100 -0
- package/dist/src/tasks/task-collaboration-repository.d.ts +52 -0
- package/dist/src/tasks/task-collaboration-repository.js +151 -0
- package/dist/src/tasks/task-context-assembler.d.ts +2 -0
- package/dist/src/tasks/task-context-assembler.js +23 -1
- package/dist/src/tasks/task-main-agent-repository.d.ts +10 -0
- package/dist/src/tasks/task-main-agent-repository.js +30 -0
- package/dist/src/tasks/task-main-update-decision-service.d.ts +21 -0
- package/dist/src/tasks/task-main-update-decision-service.js +118 -0
- package/dist/src/tasks/task-main-update-delivery.d.ts +16 -0
- package/dist/src/tasks/task-main-update-delivery.js +64 -0
- package/dist/src/tasks/task-main-update-input.d.ts +20 -0
- package/dist/src/tasks/task-main-update-input.js +37 -0
- package/dist/src/tasks/task-orchestration-metrics.d.ts +17 -0
- package/dist/src/tasks/task-orchestration-metrics.js +61 -0
- package/dist/src/tasks/task-origin-repository.d.ts +14 -0
- package/dist/src/tasks/task-origin-repository.js +29 -0
- package/dist/src/tasks/task-run-dispatcher.d.ts +3 -0
- package/dist/src/tasks/task-run-dispatcher.js +65 -7
- package/dist/src/tasks/task-run-repository.d.ts +2 -0
- package/dist/src/tasks/task-run-repository.js +12 -1
- package/dist/src/tasks/task-sidebar-hierarchy.d.ts +14 -0
- package/dist/src/tasks/task-sidebar-hierarchy.js +49 -0
- package/dist/src/tui/chat-history.js +8 -0
- package/dist/src/tui/tui-session-snapshot.js +4 -3
- package/dist/src/tui/tui.js +1 -1
- package/dist/src/voice/realtime/agentBroker.d.ts +4 -0
- package/dist/src/voice/realtime/agentBroker.js +9 -3
- package/dist/src/voice/realtime/agentEngine.js +47 -13
- package/dist/src/voice/realtime/engine.d.ts +5 -0
- package/dist/src/voice/realtime/omniEngine.js +66 -12
- package/dist/src/voice/realtime/playback-echo.js +2 -0
- package/dist/src/voice/realtime/runtime.d.ts +6 -0
- package/dist/src/voice/realtime/runtime.js +12 -0
- package/dist/src/voice/realtime/turnPolicy.d.ts +1 -0
- package/dist/src/voice/realtime/turnPolicy.js +3 -0
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/computer-settings-page-CciQtKpz.js +0 -1
- package/dist/gateway/static/root/assets/gateway-realtime-BeUJkjA3.js +0 -1
- package/dist/gateway/static/root/assets/gateway-realtime-store-C-8wwbt_.js +0 -1
- package/dist/gateway/static/root/assets/index-Ca6iqaCn.css +0 -1
- package/dist/gateway/static/root/assets/index-DqQgdJHd.js +0 -106
- package/dist/gateway/static/root/assets/messages-CTKYRqR-.js +0 -3
- package/dist/gateway/static/root/assets/session-api-BY3dAGBn.js +0 -1
- package/dist/gateway/static/root/assets/session-manager-D10sD8IN.js +0 -16
- package/dist/gateway/static/root/assets/settings-advanced-gate-yIwyFL-A.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DvWOrc3C.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-DFEM3Xbj.js +0 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { getSqliteDatabase, init_transaction } from "../storage/sqlite/transaction.js";
|
|
2
|
+
//#region src/tasks/task-sidebar-hierarchy.ts
|
|
3
|
+
init_transaction();
|
|
4
|
+
/** Fetch task children for a page of conversations without one query per parent. */
|
|
5
|
+
function listSidebarTaskGroups(conversationIds) {
|
|
6
|
+
const ids = [...new Set(conversationIds.filter(Boolean))];
|
|
7
|
+
const groups = {};
|
|
8
|
+
for (const id of ids) groups[id] = {
|
|
9
|
+
total: 0,
|
|
10
|
+
activeCount: 0,
|
|
11
|
+
items: []
|
|
12
|
+
};
|
|
13
|
+
const db = getSqliteDatabase();
|
|
14
|
+
for (let offset = 0; offset < ids.length; offset += 200) {
|
|
15
|
+
const batch = ids.slice(offset, offset + 200);
|
|
16
|
+
const rows = db.prepare(`SELECT origin.conversation_id AS parent_id, task.task_id, task.title, task.phase,
|
|
17
|
+
state.active_conversation_id,
|
|
18
|
+
worker_session.name AS conversation_title,
|
|
19
|
+
(SELECT run.status FROM task_runs run WHERE run.task_id = task.task_id
|
|
20
|
+
AND run.parent_run_id IS NULL ORDER BY run.queued_at DESC LIMIT 1) AS run_status
|
|
21
|
+
FROM task_origin_links origin
|
|
22
|
+
JOIN tasks task ON task.task_id = origin.task_id
|
|
23
|
+
LEFT JOIN task_conversation_state state ON state.task_id = task.task_id
|
|
24
|
+
LEFT JOIN sessions worker_session ON worker_session.conversation_id = state.active_conversation_id
|
|
25
|
+
WHERE origin.conversation_id IN (${batch.map(() => "?").join(", ")})
|
|
26
|
+
ORDER BY CASE WHEN task.phase = 'closed' THEN 1 ELSE 0 END,
|
|
27
|
+
task.updated_at DESC, task.task_id DESC`).all(...batch);
|
|
28
|
+
for (const row of rows) {
|
|
29
|
+
const group = groups[row.parent_id];
|
|
30
|
+
group.total++;
|
|
31
|
+
if (row.run_status ? [
|
|
32
|
+
"queued",
|
|
33
|
+
"running",
|
|
34
|
+
"waiting",
|
|
35
|
+
"verifying"
|
|
36
|
+
].includes(row.run_status) : row.phase === "active") group.activeCount++;
|
|
37
|
+
group.items.push({
|
|
38
|
+
taskId: row.task_id,
|
|
39
|
+
title: row.conversation_title?.trim() || row.title,
|
|
40
|
+
phase: row.phase,
|
|
41
|
+
...row.run_status ? { runStatus: row.run_status } : {},
|
|
42
|
+
...row.active_conversation_id ? { activeConversationId: row.active_conversation_id } : {}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return groups;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { listSidebarTaskGroups };
|
|
@@ -93,6 +93,14 @@ function appendHistoryToChatLog(chatLog, messages, toolsExpanded, showThinking =
|
|
|
93
93
|
});
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
96
|
+
if (hm.role === "task" && hm.taskTrigger) {
|
|
97
|
+
chatLog.addSystem(`Task update · ${hm.taskTrigger.taskTitle} (${hm.taskTrigger.kind})`, {
|
|
98
|
+
displayIndex,
|
|
99
|
+
historyIndex,
|
|
100
|
+
role: "system"
|
|
101
|
+
});
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
96
104
|
chatLog.finalizeAssistant(assistantHistoryMessage(hm.content), runId, {
|
|
97
105
|
displayIndex,
|
|
98
106
|
historyIndex,
|
|
@@ -103,7 +103,8 @@ var TuiSessionSnapshot = class {
|
|
|
103
103
|
}
|
|
104
104
|
entryFromHistory(message, parentId) {
|
|
105
105
|
const type = message.kind ?? "message";
|
|
106
|
-
const role = message.role;
|
|
106
|
+
const role = message.role === "task" ? "system" : message.role;
|
|
107
|
+
const content = message.taskTrigger ? `Task update · ${message.taskTrigger.taskTitle} (${message.taskTrigger.kind})` : message.content;
|
|
107
108
|
const base = {
|
|
108
109
|
id: message.id,
|
|
109
110
|
parentId,
|
|
@@ -112,7 +113,7 @@ var TuiSessionSnapshot = class {
|
|
|
112
113
|
data: message.custom?.details,
|
|
113
114
|
display: message.custom?.display,
|
|
114
115
|
role,
|
|
115
|
-
content
|
|
116
|
+
content,
|
|
116
117
|
timestamp: message.timestamp,
|
|
117
118
|
raw: message
|
|
118
119
|
};
|
|
@@ -120,7 +121,7 @@ var TuiSessionSnapshot = class {
|
|
|
120
121
|
...base,
|
|
121
122
|
message: {
|
|
122
123
|
role,
|
|
123
|
-
content
|
|
124
|
+
content,
|
|
124
125
|
usage: {
|
|
125
126
|
input: 0,
|
|
126
127
|
output: 0,
|
package/dist/src/tui/tui.js
CHANGED
|
@@ -13,7 +13,6 @@ import { renderWorkflowFinalSummary, renderWorkflowPanel } from "../agent/workfl
|
|
|
13
13
|
import { ensureStarterAgentsInitialized } from "../agent/starter-agents.js";
|
|
14
14
|
import "../config/index.js";
|
|
15
15
|
import { runViewToSnapshot } from "../workflows/service/run-view-to-snapshot.js";
|
|
16
|
-
import { resolveTuiConversationId, resolveTuiStartupConversationId } from "../routing/resolve-tui-session-key.js";
|
|
17
16
|
import { applyThemeById, getBashExcludeBorderColor, getBashModeBorderColor, getCustomThemesDir, getThemeExports, getThinkingBorderColor, initTuiTheme, listAvailableThemeIds, resolveThemePalette } from "./theme-manager.js";
|
|
18
17
|
import { editorTheme, theme } from "./theme.js";
|
|
19
18
|
import { extensionForImageMimeType, readClipboardImage } from "./clipboard-image.js";
|
|
@@ -45,6 +44,7 @@ import { createEditorSubmitHandler, createSubmitBurstCoalescer, shouldEnableWind
|
|
|
45
44
|
import { withTuiSuspended } from "./tui-suspend.js";
|
|
46
45
|
import { createInitialState } from "./tui-types.js";
|
|
47
46
|
import { TuiDraftFileStore } from "./backends/embedded-drafts.js";
|
|
47
|
+
import { resolveTuiConversationId, resolveTuiStartupConversationId } from "../routing/resolve-tui-session-key.js";
|
|
48
48
|
import { EmbeddedBackend } from "./backends/embedded-backend.js";
|
|
49
49
|
import { GatewayRealtimeBackend } from "./backends/gateway-realtime-backend.js";
|
|
50
50
|
import { ChatLog } from "./components/chat-log.js";
|
|
@@ -17,6 +17,8 @@ export interface VoiceAgentBroker {
|
|
|
17
17
|
turnId: string;
|
|
18
18
|
text: string;
|
|
19
19
|
signal: AbortSignal;
|
|
20
|
+
clientMessageId?: string;
|
|
21
|
+
origin?: SubmitSessionInput['origin'];
|
|
20
22
|
}): Promise<VoiceAgentTask>;
|
|
21
23
|
cancel(taskId: string): Promise<boolean>;
|
|
22
24
|
}
|
|
@@ -47,6 +49,8 @@ export declare class DurableVoiceAgentBroker implements VoiceAgentBroker {
|
|
|
47
49
|
turnId: string;
|
|
48
50
|
text: string;
|
|
49
51
|
signal: AbortSignal;
|
|
52
|
+
clientMessageId?: string;
|
|
53
|
+
origin?: SubmitSessionInput['origin'];
|
|
50
54
|
}): Promise<VoiceAgentTask>;
|
|
51
55
|
cancel(taskId: string): Promise<boolean>;
|
|
52
56
|
private events;
|
|
@@ -29,8 +29,14 @@ var DurableVoiceAgentBroker = class {
|
|
|
29
29
|
this.deps = deps;
|
|
30
30
|
}
|
|
31
31
|
async delegate(input) {
|
|
32
|
-
const clientMessageId = `voice:${input.expectedTranscriptId}:${input.turnId}`;
|
|
33
|
-
const
|
|
32
|
+
const clientMessageId = input.clientMessageId ?? `voice:${input.expectedTranscriptId}:${input.turnId}`;
|
|
33
|
+
const state = this.deps.snapshot(input.conversationId);
|
|
34
|
+
const activeRunId = state.activeRunId;
|
|
35
|
+
if (input.origin?.type === "system" && input.origin.source === "task_update" && (activeRunId || state.inputs.some((item) => [
|
|
36
|
+
"queued",
|
|
37
|
+
"running",
|
|
38
|
+
"injecting"
|
|
39
|
+
].includes(item.status)))) throw new Error("Task update cannot overtake an active or queued voice turn");
|
|
34
40
|
const activeRunCursor = activeRunId ? this.deps.currentSequence(`run:${activeRunId}`) : 0;
|
|
35
41
|
const result = await this.deps.submit({
|
|
36
42
|
conversationId: input.conversationId,
|
|
@@ -38,7 +44,7 @@ var DurableVoiceAgentBroker = class {
|
|
|
38
44
|
clientMessageId,
|
|
39
45
|
delivery: activeRunId ? "steer" : "next",
|
|
40
46
|
content: input.text,
|
|
41
|
-
origin: {
|
|
47
|
+
origin: input.origin ?? {
|
|
42
48
|
type: "channel",
|
|
43
49
|
channel: "voice"
|
|
44
50
|
}
|
|
@@ -13,6 +13,7 @@ const log = createLogger("Voice:Agent");
|
|
|
13
13
|
const AGENT_TTS_MAX_SEGMENT_CHARACTERS = 180;
|
|
14
14
|
const AGENT_TTS_MIN_SEGMENT_CHARACTERS = 24;
|
|
15
15
|
const PLAYBACK_ECHO_TAIL_MS = 3e3;
|
|
16
|
+
const TASK_UPDATE_QUIET_MS = 1500;
|
|
16
17
|
function createAgentVoiceEngine(options) {
|
|
17
18
|
const claim = options.claim;
|
|
18
19
|
const stt = claim.stt;
|
|
@@ -37,6 +38,8 @@ function createAgentVoiceEngine(options) {
|
|
|
37
38
|
let recentPlayback;
|
|
38
39
|
const finalizedUtterances = /* @__PURE__ */ new Set();
|
|
39
40
|
let pendingTurn;
|
|
41
|
+
let taskUpdateQueued = false;
|
|
42
|
+
let lastUserSpeechAt = 0;
|
|
40
43
|
const turn = new TurnCoordinator(claim.silenceDurationMs, (text, decision, turnId) => {
|
|
41
44
|
if (closed || muted) return;
|
|
42
45
|
log.info({
|
|
@@ -74,7 +77,7 @@ function createAgentVoiceEngine(options) {
|
|
|
74
77
|
pendingTurn = pending;
|
|
75
78
|
conversationTail = conversationTail.then(() => {
|
|
76
79
|
if (pendingTurn === pending) pendingTurn = void 0;
|
|
77
|
-
if (generation === inputGeneration && !pending.cancelled) return runAssistantTurn(text, turnId);
|
|
80
|
+
if (generation === inputGeneration && !pending.cancelled) return runAssistantTurn(text, turnId).then(() => {});
|
|
78
81
|
}).finally(() => {
|
|
79
82
|
if (generation === inputGeneration) queuedTurns -= 1;
|
|
80
83
|
});
|
|
@@ -228,8 +231,8 @@ function createAgentVoiceEngine(options) {
|
|
|
228
231
|
if (response.speechWorker) prefetchNextSpeech(response);
|
|
229
232
|
else startSpeechWorker(response);
|
|
230
233
|
}
|
|
231
|
-
async function runAssistantTurn(text, turnId) {
|
|
232
|
-
if (!claim.tts || !claim.request.conversationId || !text.trim() || closed) return;
|
|
234
|
+
async function runAssistantTurn(text, turnId, updateClientMessageId) {
|
|
235
|
+
if (!claim.tts || !claim.request.conversationId || !text.trim() || closed) return false;
|
|
233
236
|
cancelActiveResponse("barge_in");
|
|
234
237
|
const response = {
|
|
235
238
|
id: `resp_${crypto.randomUUID()}`,
|
|
@@ -246,18 +249,26 @@ function createAgentVoiceEngine(options) {
|
|
|
246
249
|
awaitingClarification: false,
|
|
247
250
|
pcm: new PcmFrameBuffer()
|
|
248
251
|
};
|
|
252
|
+
const taskUpdateExposed = () => Boolean(updateClientMessageId && response.text.trim());
|
|
249
253
|
activeResponse = response;
|
|
250
254
|
send("response.created", { responseId: response.id });
|
|
251
255
|
try {
|
|
252
256
|
await interruptionWrites;
|
|
253
|
-
if (response.abortController.signal.aborted || closed) return;
|
|
257
|
+
if (response.abortController.signal.aborted || closed) return taskUpdateExposed();
|
|
254
258
|
if (!claim.conversationSessionId) throw new Error("Conversation identity is unavailable");
|
|
255
259
|
const task = await options.runtime.agentBroker.delegate({
|
|
256
260
|
text,
|
|
257
261
|
turnId,
|
|
258
262
|
conversationId: claim.request.conversationId,
|
|
259
263
|
expectedTranscriptId: claim.conversationSessionId,
|
|
260
|
-
signal: response.abortController.signal
|
|
264
|
+
signal: response.abortController.signal,
|
|
265
|
+
...updateClientMessageId ? {
|
|
266
|
+
clientMessageId: updateClientMessageId,
|
|
267
|
+
origin: {
|
|
268
|
+
type: "system",
|
|
269
|
+
source: "task_update"
|
|
270
|
+
}
|
|
271
|
+
} : {}
|
|
261
272
|
});
|
|
262
273
|
response.taskId = task.taskId;
|
|
263
274
|
send("task.created", {
|
|
@@ -265,7 +276,7 @@ function createAgentVoiceEngine(options) {
|
|
|
265
276
|
taskId: task.taskId
|
|
266
277
|
});
|
|
267
278
|
for await (const event of task.events) {
|
|
268
|
-
if (activeResponse !== response || response.abortController.signal.aborted) return;
|
|
279
|
+
if (activeResponse !== response || response.abortController.signal.aborted) return taskUpdateExposed();
|
|
269
280
|
if (event.type === "assistant_delta" || event.type === "tool_end" && event.payload?.toolName !== "clarify") response.awaitingClarification = false;
|
|
270
281
|
if (event.type === "assistant_delta" && typeof event.payload?.delta === "string") {
|
|
271
282
|
if (response.text.length + event.payload.delta.length > 32e3) throw new Error("Voice response text limit reached");
|
|
@@ -314,7 +325,7 @@ function createAgentVoiceEngine(options) {
|
|
|
314
325
|
}
|
|
315
326
|
if (event.type === "error") throw new Error(typeof event.payload?.message === "string" ? event.payload.message : "Agent response failed");
|
|
316
327
|
}
|
|
317
|
-
if (activeResponse !== response || response.abortController.signal.aborted || closed) return;
|
|
328
|
+
if (activeResponse !== response || response.abortController.signal.aborted || closed) return taskUpdateExposed();
|
|
318
329
|
queuePhrases(response, response.segmenter.flush());
|
|
319
330
|
send("response.text.done", { responseId: response.id });
|
|
320
331
|
await waitForSpeech(response);
|
|
@@ -322,11 +333,11 @@ function createAgentVoiceEngine(options) {
|
|
|
322
333
|
const finalFrame = response.pcm.finish();
|
|
323
334
|
if (finalFrame) {
|
|
324
335
|
await response.playback.reserve(finalFrame.byteLength, response.abortController.signal);
|
|
325
|
-
if (activeResponse !== response || closed) return;
|
|
336
|
+
if (activeResponse !== response || closed) return taskUpdateExposed();
|
|
326
337
|
options.sendAudio(response.id, finalFrame);
|
|
327
338
|
}
|
|
328
339
|
await response.playback.drain(response.abortController.signal);
|
|
329
|
-
if (activeResponse !== response || response.abortController.signal.aborted) return;
|
|
340
|
+
if (activeResponse !== response || response.abortController.signal.aborted) return taskUpdateExposed();
|
|
330
341
|
if (response.audioStarted && response.audibleText) recentPlayback = {
|
|
331
342
|
responseId: response.id,
|
|
332
343
|
text: response.audibleText,
|
|
@@ -339,14 +350,16 @@ function createAgentVoiceEngine(options) {
|
|
|
339
350
|
audio: response.audioStarted
|
|
340
351
|
});
|
|
341
352
|
activeResponse = void 0;
|
|
353
|
+
return !updateClientMessageId || taskUpdateExposed();
|
|
342
354
|
} catch (error) {
|
|
343
|
-
if (response.abortController.signal.aborted || closed) return;
|
|
355
|
+
if (response.abortController.signal.aborted || closed) return taskUpdateExposed();
|
|
344
356
|
log.warn({
|
|
345
357
|
err: error,
|
|
346
358
|
sessionId: claim.sessionId,
|
|
347
|
-
responseId: response.id
|
|
348
|
-
|
|
349
|
-
|
|
359
|
+
responseId: response.id,
|
|
360
|
+
...updateClientMessageId ? { clientMessageId: updateClientMessageId } : {}
|
|
361
|
+
}, updateClientMessageId ? "Proactive voice task update deferred" : "Realtime voice response failed");
|
|
362
|
+
if (!updateClientMessageId) send("session.error", {
|
|
350
363
|
code: "RESPONSE_FAILED",
|
|
351
364
|
message: "Voice response failed",
|
|
352
365
|
recoverable: true
|
|
@@ -359,6 +372,7 @@ function createAgentVoiceEngine(options) {
|
|
|
359
372
|
});
|
|
360
373
|
response.abortController.abort("provider_error");
|
|
361
374
|
if (activeResponse === response) activeResponse = void 0;
|
|
375
|
+
return taskUpdateExposed();
|
|
362
376
|
} finally {
|
|
363
377
|
await waitForSpeech(response);
|
|
364
378
|
}
|
|
@@ -420,6 +434,7 @@ function createAgentVoiceEngine(options) {
|
|
|
420
434
|
}
|
|
421
435
|
if (muted || finalizedUtterances.has(event.utteranceId)) return;
|
|
422
436
|
if (event.type === "speech_started") {
|
|
437
|
+
lastUserSpeechAt = Date.now();
|
|
423
438
|
if (claim.request.purpose === "conversation") {
|
|
424
439
|
if (pendingTurn) {
|
|
425
440
|
pendingTurn.cancelled = true;
|
|
@@ -440,6 +455,7 @@ function createAgentVoiceEngine(options) {
|
|
|
440
455
|
text: event.text
|
|
441
456
|
});
|
|
442
457
|
if (event.type === "transcript_final") {
|
|
458
|
+
lastUserSpeechAt = Date.now();
|
|
443
459
|
const text = event.text.trim();
|
|
444
460
|
if (!text) {
|
|
445
461
|
if (claim.request.purpose === "conversation") bufferFinal(event.utteranceId, "");
|
|
@@ -506,7 +522,25 @@ function createAgentVoiceEngine(options) {
|
|
|
506
522
|
});
|
|
507
523
|
return inputReset;
|
|
508
524
|
}
|
|
525
|
+
function canOfferTaskUpdateInput() {
|
|
526
|
+
return claim.request.purpose === "conversation" && Boolean(claim.tts) && !closed && Boolean(sttSession) && !committing && !activeResponse && !pendingTurn && queuedTurns === 0 && turn.isIdle() && Date.now() - lastUserSpeechAt >= TASK_UPDATE_QUIET_MS;
|
|
527
|
+
}
|
|
509
528
|
return {
|
|
529
|
+
canOfferTaskUpdate() {
|
|
530
|
+
return !taskUpdateQueued && canOfferTaskUpdateInput();
|
|
531
|
+
},
|
|
532
|
+
offerTaskUpdate(input) {
|
|
533
|
+
if (taskUpdateQueued || !canOfferTaskUpdateInput()) return Promise.resolve(false);
|
|
534
|
+
taskUpdateQueued = true;
|
|
535
|
+
const attempt = conversationTail.then(() => {
|
|
536
|
+
if (!canOfferTaskUpdateInput()) return false;
|
|
537
|
+
return runAssistantTurn(input.content, input.clientMessageId, input.clientMessageId);
|
|
538
|
+
});
|
|
539
|
+
conversationTail = attempt.then(() => {}, () => {});
|
|
540
|
+
return attempt.finally(() => {
|
|
541
|
+
taskUpdateQueued = false;
|
|
542
|
+
});
|
|
543
|
+
},
|
|
510
544
|
async start() {
|
|
511
545
|
const opened = await openSttSession(claim);
|
|
512
546
|
if (closed || options.signal.aborted) {
|
|
@@ -10,5 +10,10 @@ export interface VoiceEngine {
|
|
|
10
10
|
cancel(responseId: string, reason: 'client_cancelled' | 'barge_in'): boolean;
|
|
11
11
|
cancelTask(taskId: string): Promise<boolean>;
|
|
12
12
|
acknowledge(responseId: string, playedDurationMs: number): void;
|
|
13
|
+
canOfferTaskUpdate?(): boolean;
|
|
14
|
+
offerTaskUpdate?(input: {
|
|
15
|
+
clientMessageId: string;
|
|
16
|
+
content: string;
|
|
17
|
+
}): Promise<boolean>;
|
|
13
18
|
close(): void | Promise<void>;
|
|
14
19
|
}
|
|
@@ -2,6 +2,7 @@ import { createLogger } from "../../utils/logger/index.js";
|
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { AudioPlaybackWindow } from "./audio-playback-window.js";
|
|
4
4
|
import { TurnCoordinator } from "./turnPolicy.js";
|
|
5
|
+
import { isLikelyPlaybackEcho } from "./playback-echo.js";
|
|
5
6
|
import { PcmFrameBuffer } from "./pcmFrameBuffer.js";
|
|
6
7
|
import crypto from "node:crypto";
|
|
7
8
|
import WebSocket from "ws";
|
|
@@ -13,6 +14,7 @@ const MAX_PENDING_INPUT_BYTES = 64 * 1024;
|
|
|
13
14
|
const UPLOAD_TIMEOUT_MS = 1e4;
|
|
14
15
|
const RESPONSE_START_TIMEOUT_MS = 3e4;
|
|
15
16
|
const CANCELLATION_ERROR_GRACE_MS = 5e3;
|
|
17
|
+
const PLAYBACK_ECHO_TAIL_MS = 3e3;
|
|
16
18
|
const FAILURE_MESSAGES = {
|
|
17
19
|
OMNI_UPLOAD_TIMEOUT: "The connection to the voice service stopped uploading audio. Check the network to your configured endpoint and reconnect.",
|
|
18
20
|
OMNI_INPUT_RESET_TIMEOUT: "The voice service did not acknowledge clearing microphone input. Reconnect to continue.",
|
|
@@ -43,6 +45,9 @@ function createOmniVoiceEngine(options) {
|
|
|
43
45
|
let failed = false;
|
|
44
46
|
let platformRequestId;
|
|
45
47
|
let active;
|
|
48
|
+
let recentPlayback;
|
|
49
|
+
let waitingForCancellation;
|
|
50
|
+
let responseCreateQueued = false;
|
|
46
51
|
let rejectStart;
|
|
47
52
|
let timer;
|
|
48
53
|
const recorded = /* @__PURE__ */ new Set();
|
|
@@ -55,6 +60,13 @@ function createOmniVoiceEngine(options) {
|
|
|
55
60
|
let turnSettled = false;
|
|
56
61
|
let responseStartTimer;
|
|
57
62
|
const speaking = /* @__PURE__ */ new Set();
|
|
63
|
+
function maybeCreateResponse() {
|
|
64
|
+
if (!responseCreateQueued || active || waitingForCancellation || closed || failed || muted || inputBlocked) return;
|
|
65
|
+
responseCreateQueued = false;
|
|
66
|
+
clearTimeout(responseStartTimer);
|
|
67
|
+
responseStartTimer = setTimeout(() => fail("OMNI_RESPONSE_START_TIMEOUT"), RESPONSE_START_TIMEOUT_MS);
|
|
68
|
+
send("response.create");
|
|
69
|
+
}
|
|
58
70
|
const turn = new TurnCoordinator(options.silenceDurationMs, (_text, decision, turnId) => {
|
|
59
71
|
if (closed || failed || muted || inputBlocked) return;
|
|
60
72
|
options.send("turn.decision", {
|
|
@@ -66,11 +78,10 @@ function createOmniVoiceEngine(options) {
|
|
|
66
78
|
});
|
|
67
79
|
options.send("turn.committed", { turnId });
|
|
68
80
|
turnSettled = true;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
81
|
+
const preparedReply = Boolean(active && !active.published);
|
|
82
|
+
if (active && !active.published) publish(active);
|
|
83
|
+
responseCreateQueued = !preparedReply;
|
|
84
|
+
maybeCreateResponse();
|
|
74
85
|
});
|
|
75
86
|
function publish(response) {
|
|
76
87
|
if (response.published || active !== response) return;
|
|
@@ -151,7 +162,8 @@ function createOmniVoiceEngine(options) {
|
|
|
151
162
|
reason
|
|
152
163
|
});
|
|
153
164
|
}
|
|
154
|
-
if (
|
|
165
|
+
if (reason !== "session_closed" && response.generating && socket?.readyState === WebSocket.OPEN) {
|
|
166
|
+
waitingForCancellation = response.id;
|
|
155
167
|
cancellationPendingUntil = Date.now() + CANCELLATION_ERROR_GRACE_MS;
|
|
156
168
|
send("response.cancel");
|
|
157
169
|
}
|
|
@@ -188,6 +200,10 @@ function createOmniVoiceEngine(options) {
|
|
|
188
200
|
text: response.text,
|
|
189
201
|
interrupted: false
|
|
190
202
|
});
|
|
203
|
+
if (response.audio && response.text) recentPlayback = {
|
|
204
|
+
text: response.text,
|
|
205
|
+
expiresAt: Date.now() + PLAYBACK_ECHO_TAIL_MS
|
|
206
|
+
};
|
|
191
207
|
options.send("response.audio.done", { responseId: response.id });
|
|
192
208
|
options.send("response.done", {
|
|
193
209
|
responseId: response.id,
|
|
@@ -195,6 +211,7 @@ function createOmniVoiceEngine(options) {
|
|
|
195
211
|
finishReason: response.audio ? "completed" : "text_only"
|
|
196
212
|
});
|
|
197
213
|
active = void 0;
|
|
214
|
+
maybeCreateResponse();
|
|
198
215
|
};
|
|
199
216
|
const stopReply = (response, code) => {
|
|
200
217
|
if (closed || active !== response) return;
|
|
@@ -217,6 +234,7 @@ function createOmniVoiceEngine(options) {
|
|
|
217
234
|
failed = true;
|
|
218
235
|
clearTimeout(responseStartTimer);
|
|
219
236
|
turn.reset();
|
|
237
|
+
responseCreateQueued = false;
|
|
220
238
|
log.warn({
|
|
221
239
|
sessionId: options.callId,
|
|
222
240
|
platformRequestId,
|
|
@@ -241,6 +259,7 @@ function createOmniVoiceEngine(options) {
|
|
|
241
259
|
function discardInput() {
|
|
242
260
|
clearTimeout(responseStartTimer);
|
|
243
261
|
turn.reset();
|
|
262
|
+
responseCreateQueued = false;
|
|
244
263
|
speaking.clear();
|
|
245
264
|
turnSettled = false;
|
|
246
265
|
if (active && !active.published) cancel("client_cancelled");
|
|
@@ -300,6 +319,8 @@ function createOmniVoiceEngine(options) {
|
|
|
300
319
|
const managedLateCancellation = options.route.route.managed && event.error?.code === "invalid_request_error" && event.error?.message === "The voice provider rejected the request.";
|
|
301
320
|
if (Date.now() <= cancellationPendingUntil && (lateCancellation || managedLateCancellation)) {
|
|
302
321
|
cancellationPendingUntil = 0;
|
|
322
|
+
waitingForCancellation = void 0;
|
|
323
|
+
maybeCreateResponse();
|
|
303
324
|
return;
|
|
304
325
|
}
|
|
305
326
|
fail("OMNI_PROVIDER_ERROR");
|
|
@@ -318,8 +339,8 @@ function createOmniVoiceEngine(options) {
|
|
|
318
339
|
type: "server_vad",
|
|
319
340
|
threshold: .5,
|
|
320
341
|
silence_duration_ms: options.silenceDurationMs,
|
|
321
|
-
create_response:
|
|
322
|
-
interrupt_response:
|
|
342
|
+
create_response: false,
|
|
343
|
+
interrupt_response: false
|
|
323
344
|
}
|
|
324
345
|
} });
|
|
325
346
|
else if (event.type === "session.updated" && !ready) {
|
|
@@ -343,7 +364,7 @@ function createOmniVoiceEngine(options) {
|
|
|
343
364
|
turnSettled = false;
|
|
344
365
|
speaking.add(String(event.item_id));
|
|
345
366
|
turn.start(String(event.item_id));
|
|
346
|
-
if (
|
|
367
|
+
if (active && !active.published) cancel("barge_in");
|
|
347
368
|
options.send("input.speech_started", { utteranceId: String(event.item_id) });
|
|
348
369
|
} else if (event.type === "input_audio_buffer.speech_stopped") {
|
|
349
370
|
if (muted || inputBlocked || discardedInputs.has(String(event.item_id)) || recorded.has(String(event.item_id))) return;
|
|
@@ -358,7 +379,27 @@ function createOmniVoiceEngine(options) {
|
|
|
358
379
|
if (muted || inputBlocked || discardedInputs.has(event.item_id) || recorded.has(event.item_id)) return;
|
|
359
380
|
pendingInputs.delete(event.item_id);
|
|
360
381
|
speaking.delete(event.item_id);
|
|
361
|
-
|
|
382
|
+
const text = event.transcript.trim();
|
|
383
|
+
const playbackText = active?.audio ? active.text : recentPlayback && recentPlayback.expiresAt >= Date.now() ? recentPlayback.text : void 0;
|
|
384
|
+
if (playbackText && isLikelyPlaybackEcho(text, playbackText)) {
|
|
385
|
+
turn.final(event.item_id, "");
|
|
386
|
+
log.debug({
|
|
387
|
+
sessionId: options.callId,
|
|
388
|
+
responseId: active?.id,
|
|
389
|
+
transcriptCharacters: text.length
|
|
390
|
+
}, "Ignored native voice playback echo");
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
if (text && active?.published && options.bargeIn) {
|
|
394
|
+
log.info({
|
|
395
|
+
sessionId: options.callId,
|
|
396
|
+
responseId: active.id,
|
|
397
|
+
utteranceId: event.item_id,
|
|
398
|
+
transcriptCharacters: text.length
|
|
399
|
+
}, "Confirmed user speech interrupted native voice playback");
|
|
400
|
+
cancel("barge_in");
|
|
401
|
+
}
|
|
402
|
+
turn.final(event.item_id, text);
|
|
362
403
|
save({
|
|
363
404
|
itemId: event.item_id,
|
|
364
405
|
role: "user",
|
|
@@ -379,15 +420,25 @@ function createOmniVoiceEngine(options) {
|
|
|
379
420
|
recoverable: true
|
|
380
421
|
});
|
|
381
422
|
} else if (event.type === "response.created") {
|
|
382
|
-
clearTimeout(responseStartTimer);
|
|
383
423
|
if (muted || inputBlocked) {
|
|
384
424
|
cancellationPendingUntil = Date.now() + CANCELLATION_ERROR_GRACE_MS;
|
|
385
425
|
send("response.cancel");
|
|
386
426
|
return;
|
|
387
427
|
}
|
|
388
|
-
if (active)
|
|
428
|
+
if (active) {
|
|
429
|
+
log.warn({
|
|
430
|
+
sessionId: options.callId,
|
|
431
|
+
responseId: active.id
|
|
432
|
+
}, "Ignored overlapping native voice reply");
|
|
433
|
+
cancellationPendingUntil = Date.now() + CANCELLATION_ERROR_GRACE_MS;
|
|
434
|
+
send("response.cancel");
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
clearTimeout(responseStartTimer);
|
|
389
438
|
const id = event.response?.id;
|
|
390
439
|
if (typeof id !== "string" || !id.length || id.length > 160) throw new Error("Invalid response ID");
|
|
440
|
+
responseCreateQueued = false;
|
|
441
|
+
waitingForCancellation = void 0;
|
|
391
442
|
let release;
|
|
392
443
|
const settled = new Promise((resolve) => {
|
|
393
444
|
release = resolve;
|
|
@@ -467,6 +518,9 @@ function createOmniVoiceEngine(options) {
|
|
|
467
518
|
if (!response.abort.signal.aborted) stopReply(response, "OMNI_PLAYBACK_FAILED");
|
|
468
519
|
});
|
|
469
520
|
}
|
|
521
|
+
} else if (event.type === "response.done" && event.response?.id === waitingForCancellation) {
|
|
522
|
+
waitingForCancellation = void 0;
|
|
523
|
+
maybeCreateResponse();
|
|
470
524
|
}
|
|
471
525
|
} catch {
|
|
472
526
|
fail("OMNI_PROTOCOL_ERROR");
|
|
@@ -23,6 +23,8 @@ function isLikelyPlaybackEcho(transcript, assistantText) {
|
|
|
23
23
|
const containsCjk = /\p{Script=Han}/u.test(heard);
|
|
24
24
|
if (heard.length < (containsCjk ? 3 : 6)) return false;
|
|
25
25
|
if (spoken.includes(heard)) return true;
|
|
26
|
+
if (heard.length > 200 || spoken.length > 8e3) return false;
|
|
27
|
+
if (containsCjk && heard.length >= 4 && heard.length <= 5) return closestSubstringEditDistance(heard, spoken) <= 1;
|
|
26
28
|
if (heard.length < (containsCjk ? 6 : 10)) return false;
|
|
27
29
|
return closestSubstringEditDistance(heard, spoken) / Array.from(heard).length <= .22;
|
|
28
30
|
}
|
|
@@ -27,6 +27,12 @@ export declare class VoiceRealtimeRuntime {
|
|
|
27
27
|
createSession(request: CreateVoiceSessionRequest, principalId: string, now?: number): Promise<CreateVoiceSessionResponse>;
|
|
28
28
|
handleUpgrade(req: IncomingMessage, socket: Socket, head: Buffer): boolean;
|
|
29
29
|
hasConversation(conversationId: string): boolean;
|
|
30
|
+
canOfferTaskUpdate(conversationId: string): boolean;
|
|
31
|
+
offerTaskUpdate(input: {
|
|
32
|
+
conversationId: string;
|
|
33
|
+
clientMessageId: string;
|
|
34
|
+
content: string;
|
|
35
|
+
}): Promise<boolean>;
|
|
30
36
|
cancelSession(sessionId: string, ticket: string, principalId: string): Promise<boolean>;
|
|
31
37
|
disconnectPrincipal(principalId: string): void;
|
|
32
38
|
close(): void;
|
|
@@ -298,6 +298,16 @@ var VoiceRealtimeRuntime = class {
|
|
|
298
298
|
this.pruneTickets(Date.now());
|
|
299
299
|
return this.conversationReservations.has(conversationId);
|
|
300
300
|
}
|
|
301
|
+
canOfferTaskUpdate(conversationId) {
|
|
302
|
+
const sessionId = this.conversationReservations.get(conversationId);
|
|
303
|
+
return (sessionId ? this.activeSessions.get(sessionId) : void 0)?.engine?.canOfferTaskUpdate?.() === true;
|
|
304
|
+
}
|
|
305
|
+
async offerTaskUpdate(input) {
|
|
306
|
+
const sessionId = this.conversationReservations.get(input.conversationId);
|
|
307
|
+
const session = sessionId ? this.activeSessions.get(sessionId) : void 0;
|
|
308
|
+
if (!session?.engine?.canOfferTaskUpdate?.()) return false;
|
|
309
|
+
return session.engine.offerTaskUpdate?.(input) ?? false;
|
|
310
|
+
}
|
|
301
311
|
async cancelSession(sessionId, ticket, principalId) {
|
|
302
312
|
const key = ticketKey(ticket);
|
|
303
313
|
const claim = this.tickets.get(key);
|
|
@@ -526,6 +536,8 @@ var VoiceRealtimeRuntime = class {
|
|
|
526
536
|
});
|
|
527
537
|
await engine.start();
|
|
528
538
|
if (closed) return;
|
|
539
|
+
const active = this.activeSessions.get(consumed.sessionId);
|
|
540
|
+
if (active?.socket === socket) active.engine = engine;
|
|
529
541
|
ready = true;
|
|
530
542
|
log.info({
|
|
531
543
|
sessionId: consumed.sessionId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xopcai/xopc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.346",
|
|
4
4
|
"description": "Local-first personal AI for the one-person company, with durable context, tasks, workflows, automations, and local or cloud models.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -159,11 +159,11 @@
|
|
|
159
159
|
"vitest": "4.1.5",
|
|
160
160
|
"vue": "^3.5.35",
|
|
161
161
|
"@xopcai/browser-control-contract": "0.1.0",
|
|
162
|
-
"@xopcai/computer-control-contract": "0.1.0",
|
|
163
162
|
"@xopcai/endpoint-tools-client": "0.0.0",
|
|
163
|
+
"@xopcai/computer-control-contract": "0.1.0",
|
|
164
164
|
"@xopcai/endpoint-tools-protocol": "0.0.0",
|
|
165
|
-
"@xopcai/gateway-contract": "0.0.0",
|
|
166
165
|
"@xopcai/realtime-client": "0.0.0",
|
|
166
|
+
"@xopcai/gateway-contract": "0.0.0",
|
|
167
167
|
"@xopcai/realtime-protocol": "0.0.0"
|
|
168
168
|
},
|
|
169
169
|
"scripts": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{i as e}from"./rolldown-runtime-aKtaBQYM.js";import{a as t,n,t as r}from"./vendor-react-BOUWij0V.js";import{t as i}from"./chunk-KS7C4IRE-BMYIfy9x.js";import{t as a}from"./globe-DSSGFWFn.js";import{t as o}from"./messages-CTKYRqR-.js";import{a as s,n as c,r as l}from"./locale-store-B0WmWiCo.js";import{i as u}from"./vendor-swr-BIWyz7Rc.js";import{t as d}from"./button-CS04eWY9.js";import{r as f}from"./gateway-config-swr-DcE8n_ZS.js";import{n as p,t as m}from"./registry-api-Bw0ZkSav.js";import{t as h}from"./skeleton-BwbyijEw.js";import{t as g}from"./electron-env-Dit0bHgy.js";import{Lc as _,Mi as v,Oc as y,Sn as b,gl as x,hl as S,xn as C}from"./index-DqQgdJHd.js";import{n as w,r as T}from"./settings-page-layout-X1x-2Cp9.js";var E=n(),D=e(t(),1),O=r();function k({zh:e}){let t=o(e?`zh`:`en`).computerSettings,n=u(`settings-agent-defaults`,C),r=u(m,p),a=n.data?.defaults.models.computerUse?.primary??``,[s,c]=(0,D.useState)(a),[l,f]=(0,D.useState)(!1),[g,_]=(0,D.useState)(``),[y,x]=(0,D.useState)(!1);(0,D.useEffect)(()=>{c(a)},[a]);let S=!s||r.data?.some(e=>e.id===s&&e.computerUse),w=async()=>{f(!0),_(``),x(!1);try{if(!S)throw Error(t.modelUnavailable);let e=await C(),r={...e.defaults.models};s?r.computerUse={primary:s,fallbacks:[]}:delete r.computerUse;let i=await b({...e.defaults,models:r});await n.mutate(i,!1),x(!0)}catch(e){_(e instanceof Error?e.message:String(e))}finally{f(!1)}};return(0,O.jsxs)(`section`,{"aria-label":t.model,className:`space-y-3`,children:[(0,O.jsx)(`h2`,{className:`text-sm font-semibold text-fg`,children:t.model}),!n.data&&!n.error?(0,O.jsx)(h,{className:`h-52 w-full rounded-xl`}):n.error?(0,O.jsxs)(`div`,{role:`alert`,className:`text-sm text-danger`,children:[String(n.error),(0,O.jsx)(d,{onClick:()=>{n.mutate().catch(()=>{})},children:t.retry})]}):(0,O.jsxs)(`div`,{className:`space-y-4 rounded-xl bg-surface-hover/25 p-4 sm:p-5`,children:[(0,O.jsx)(`p`,{className:`text-sm text-fg-muted`,children:t.modelDescription}),(0,O.jsx)(`p`,{className:`text-xs leading-relaxed text-fg-muted`,children:t.modelScope}),r.isLoading?(0,O.jsx)(h,{className:`h-10 w-full rounded-lg`}):(0,O.jsx)(v,{value:s,onChange:e=>{c(e),x(!1)},disabled:l,capabilitiesFilter:`computer-use`,models:r.data??[],modelsError:r.error,placeholder:t.selectModel,searchPlaceholder:t.searchModel,noMatches:t.noModels,registryEmptyHint:t.noModels,allowEmpty:!0,emptyLabel:t.noModel,ariaLabel:t.modelLabel,className:`w-full`,contentAlign:`start`}),!S&&!r.isLoading&&!r.error&&(0,O.jsx)(`p`,{role:`status`,className:`text-sm text-warning`,children:t.modelUnavailable}),r.error&&(0,O.jsxs)(`p`,{role:`alert`,className:`text-sm text-danger`,children:[String(r.error),(0,O.jsx)(d,{onClick:()=>{r.mutate().catch(()=>{})},children:t.retry})]}),(0,O.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,O.jsx)(d,{variant:`primary`,disabled:l||s===a||!S||!!r.error||r.isLoading,onClick:()=>{w()},children:t.saveModel}),(0,O.jsx)(d,{asChild:!0,variant:`ghost`,children:(0,O.jsx)(i,{to:`/settings/capabilities/models?add=1`,children:t.manageModels})}),y&&(0,O.jsx)(`span`,{role:`status`,className:`text-xs text-fg-muted`,children:t.modelSaved})]}),g&&(0,O.jsx)(`p`,{role:`alert`,className:`text-sm text-danger`,children:g})]}),(0,O.jsx)(`p`,{className:`text-xs leading-relaxed text-fg-muted`,children:t.modelPrivacy})]})}function A(e){let t=(0,E.c)(15),{icon:n,title:r,description:i,children:a}=e,o;t[0]===n?o=t[1]:(o=n&&(0,O.jsx)(`div`,{className:`flex size-10 shrink-0 items-center justify-center rounded-xl bg-surface-base/70 text-fg-muted`,"aria-hidden":!0,children:n}),t[0]=n,t[1]=o);let s;t[2]===r?s=t[3]:(s=(0,O.jsx)(`h3`,{className:`text-sm font-medium text-fg`,children:r}),t[2]=r,t[3]=s);let c;t[4]===i?c=t[5]:(c=i&&(0,O.jsx)(`div`,{className:`mt-1 text-sm leading-relaxed text-fg-muted`,children:i}),t[4]=i,t[5]=c);let l;t[6]!==s||t[7]!==c?(l=(0,O.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[s,c]}),t[6]=s,t[7]=c,t[8]=l):l=t[8];let u;t[9]===a?u=t[10]:(u=a&&(0,O.jsx)(`div`,{className:`flex shrink-0 items-center gap-3`,children:a}),t[9]=a,t[10]=u);let d;return t[11]!==o||t[12]!==l||t[13]!==u?(d=(0,O.jsxs)(`div`,{className:`flex flex-wrap items-center gap-4 p-4 sm:flex-nowrap sm:p-5`,children:[o,l,u]}),t[11]=o,t[12]=l,t[13]=u,t[14]=d):d=t[14],d}function j(){let e=(0,E.c)(2),t=c(M)===`zh`,n;return e[0]===t?n=e[1]:(n=(0,O.jsx)(N,{zh:t}),e[0]=t,e[1]=n),n}function M(e){return e.language}function N({zh:e}){let t=o(e?`zh`:`en`).computerSettings,{data:n,mutate:r,error:c}=f(!0),u=n?.payload?.config,[p,m]=(0,D.useState)(!1),[v,b]=(0,D.useState)(``),[C,E]=(0,D.useState)(!1),[j,M]=(0,D.useState)(null),[N,P]=(0,D.useState)(!1),F=window.electronAPI?.platform===`darwin`?window.electronAPI.computer:void 0,I=window.electronAPI?.platform===`darwin`?window.electronAPI.system:void 0;(0,D.useEffect)(()=>{if(!F)return;let e=!1,t=!1,n=async()=>{if(!t){t=!0;try{let t=await F.status();e||(M(t),P(!1))}catch{e||(M(null),P(!0))}finally{t=!1}}};n();let r=window.setInterval(()=>{n()},2e3);return()=>{e=!0,window.clearInterval(r)}},[F]);let L=async e=>{m(!0),b(``);try{await e()}catch(e){b(e instanceof Error?e.message:String(e))}finally{m(!1)}},R=e=>L(async()=>{g()&&(await s(l(`/api/config`),{method:`PATCH`,headers:{"Content-Type":`application/json`},body:JSON.stringify({computer:{enabled:e}})}),await r())}),z=async()=>{b(``),E(!1);try{await F?.stop(),E(!0),F&&M(await F.status())}catch(e){b(e instanceof Error?e.message:String(e))}},B=j?.session?.status??`idle`,V=t.states[B]??B,H=g()&&u?.computer?.enabled===!0;return(0,O.jsxs)(T,{gap:`gap-7`,children:[(0,O.jsx)(w,{title:t.title,subtitle:t.subtitle,meta:(0,O.jsxs)(`div`,{className:`mt-3 space-y-3`,children:[(0,O.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,O.jsx)(`span`,{className:`inline-flex rounded-md border border-edge px-2 py-1 text-xs text-fg-muted`,children:t.experimental}),(0,O.jsx)(`span`,{className:`inline-flex rounded-md border border-edge px-2 py-1 text-xs text-fg-muted`,children:t.preview})]}),(0,O.jsx)(`p`,{className:`text-sm leading-relaxed text-fg-muted`,children:t.experimentalDescription})]}),actions:F&&(0,O.jsxs)(d,{onClick:()=>{z()},children:[(0,O.jsx)(y,{className:`size-3.5`}),t.stop]})}),v&&(0,O.jsx)(`p`,{role:`alert`,className:`text-sm text-red-600`,children:v}),C&&(0,O.jsx)(`p`,{role:`status`,className:`text-sm text-fg-muted`,children:t.stoppedNotice}),j?.controlPaused&&(0,O.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3 rounded-xl bg-warning-soft p-4`,children:[(0,O.jsx)(`p`,{className:`text-sm text-fg-muted`,children:t.pausedNotice}),(0,O.jsx)(d,{disabled:p,onClick:()=>{L(async()=>{F&&M(await F.resume()),E(!1)})},children:t.resume})]}),(0,O.jsx)(k,{zh:e}),(0,O.jsxs)(`section`,{"aria-labelledby":`computer-control-title`,className:`space-y-3`,children:[(0,O.jsx)(`h2`,{id:`computer-control-title`,className:`text-sm font-semibold text-fg`,children:t.control}),!u&&!c?(0,O.jsx)(h,{className:`h-40 w-full rounded-xl`}):c?(0,O.jsxs)(`div`,{role:`alert`,className:`text-sm text-fg-muted`,children:[String(c),` `,(0,O.jsx)(d,{onClick:()=>{L(()=>r())},children:t.retry})]}):(0,O.jsxs)(`div`,{className:`flex flex-col gap-1 rounded-xl bg-surface-hover/20 p-1 [&>*]:rounded-lg [&>*]:bg-surface-base/45`,children:[(0,O.jsx)(A,{icon:(0,O.jsx)(S,{className:`size-5`}),title:t.desktop,description:t.desktopDescription,children:(0,O.jsx)(`button`,{type:`button`,role:`switch`,"aria-label":t.desktop,"aria-checked":H,disabled:p||!g(),onClick:()=>{R(u?.computer?.enabled!==!0)},className:`touch-target flex items-center rounded-lg px-1 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent disabled:opacity-50`,children:(0,O.jsx)(`span`,{className:`flex h-6 w-11 items-center rounded-full p-0.5 transition-colors ${H?`bg-accent`:`bg-fg-muted/30`}`,children:(0,O.jsx)(`span`,{className:`size-5 rounded-full bg-white transition-transform ${H?`translate-x-5`:`translate-x-0`}`})})})}),(0,O.jsx)(A,{icon:(0,O.jsx)(_,{className:`size-5`}),title:t.approvals,description:t.approvalsDescription,children:(0,O.jsx)(`span`,{className:`rounded-md border border-edge px-2 py-1 text-xs text-fg-muted`,children:t.approvalsRequired})}),(0,O.jsx)(A,{icon:(0,O.jsx)(a,{className:`size-5`}),title:t.browser,description:(0,O.jsxs)(O.Fragment,{children:[t.browserDescription,(0,O.jsx)(`span`,{className:`mt-1 block text-xs`,children:u?.browser?.enabled?t.browserEnabled:t.browserDisabled})]}),children:(0,O.jsx)(d,{asChild:!0,children:(0,O.jsx)(i,{to:`/settings/agent-browser`,children:t.manage})})})]}),(0,O.jsxs)(`p`,{className:`text-xs leading-relaxed text-fg-muted`,children:[t.safety,` `,t.lockedDescription]})]}),(0,O.jsxs)(`section`,{"aria-labelledby":`computer-permissions-title`,className:`space-y-3`,children:[(0,O.jsx)(`h2`,{id:`computer-permissions-title`,className:`text-sm font-semibold text-fg`,children:t.permissions}),F?N?(0,O.jsx)(`p`,{role:`alert`,className:`rounded-xl bg-danger-soft p-5 text-sm text-danger`,children:t.nativeError}):j?(0,O.jsxs)(`div`,{className:`flex flex-col gap-1 rounded-xl bg-surface-hover/20 p-1 [&>*]:rounded-lg [&>*]:bg-surface-base/45`,children:[(0,O.jsx)(A,{icon:(0,O.jsx)(x,{className:`size-5`}),title:t.device,description:(0,O.jsxs)(O.Fragment,{children:[(0,O.jsxs)(`span`,{"aria-live":`polite`,children:[j.connected?t.connected:t.disconnected,` · `,V]}),j.reenrollmentRequired&&(0,O.jsx)(`p`,{className:`mt-1`,children:t.revoked})]}),children:j.reenrollmentRequired&&(0,O.jsx)(d,{disabled:p,onClick:()=>{L(async()=>{M(await F.reenroll())})},children:t.reenroll})}),I&&(0,O.jsxs)(O.Fragment,{children:[(0,O.jsxs)(A,{icon:(0,O.jsx)(_,{className:`size-5`}),title:t.accessibility,description:t.accessibilityDescription,children:[(0,O.jsx)(`span`,{className:`text-xs text-fg-muted`,children:j.permissions.accessibility?t.granted:t.notGranted}),!j.permissions.accessibility&&(0,O.jsx)(d,{disabled:p,"aria-label":`${t.openSettings}: ${t.accessibility}`,onClick:()=>{L(()=>I.requestAccessibility())},children:t.openSettings})]}),(0,O.jsxs)(A,{icon:(0,O.jsx)(x,{className:`size-5`}),title:t.screen,description:t.screenDescription,children:[(0,O.jsx)(`span`,{className:`text-xs text-fg-muted`,children:j.permissions.screenRecording===`granted`?t.granted:t.notGranted}),j.permissions.screenRecording!==`granted`&&(0,O.jsx)(d,{disabled:p,"aria-label":`${t.openSettings}: ${t.screen}`,onClick:()=>{L(()=>I.requestScreen())},children:t.openSettings})]})]})]}):(0,O.jsx)(`div`,{"aria-label":t.checking,children:(0,O.jsx)(h,{className:`h-52 w-full rounded-xl`})}):(0,O.jsx)(`p`,{className:`rounded-xl bg-surface-hover/20 p-5 text-sm leading-relaxed text-fg-muted`,children:window.electronAPI&&window.electronAPI.platform!==`darwin`?t.unsupportedPlatform:t.desktopRequired}),(j?.error||j?.session?.errorCode)&&(0,O.jsx)(`p`,{role:`alert`,className:`break-words text-sm text-red-600`,children:j.error||j.session?.errorCode})]})]})}export{j as ComputerSettingsPage,N as ComputerSettingsPanel};
|