@xopcai/xopc 0.0.247 → 0.0.248
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/src/update-offset-store.js +17 -54
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/auth/accounts.js +3 -5
- package/dist/extensions/weixin/src/monitor/monitor.js +3 -5
- package/dist/extensions/weixin/src/storage/sync-buf.d.ts +3 -6
- package/dist/extensions/weixin/src/storage/sync-buf.js +9 -22
- package/dist/gateway/static/root/assets/{activity-store-BlxqErph.js → activity-store-etpmyV7S.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DmaFeojS.js → agent-avatar-dicebear-BmKxSM1k.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CUXApfcE.js +1 -0
- package/dist/gateway/static/root/assets/{agents-CZwf1mgZ.js → agents-DNq_GKuc.js} +1 -1
- package/dist/gateway/static/root/assets/{api-BbXzyQMj.js → api-B0-hLuZ1.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-BODskFTb.js → app-management-settings-panel-qfwAgyhQ.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DeaVvaYZ.js → appearance-settings-DqQVUpCC.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-dwIqYmXk.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-DD2SweEH.js → archive-plugin-BnMSgZvR.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-BG82bNBQ.js → attachment-load-CejsQMev.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-CqBZ89He.js → automations-page-RC8EyoAf.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-SkdcSZ0i.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-B6LKm5Zv.js → binary-plugins-DGjppLSG.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-BJKvGVXd.js → block-editor-CWdP4bUc.js} +44 -44
- package/dist/gateway/static/root/assets/browser-settings-page-CKCa6TvG.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-BAAc151l.js → browser-workflow-inputs-BQ1Ilw_o.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-DoE4Uuns.js → browser-workflows-page-CJh4NyxT.js} +2 -2
- package/dist/gateway/static/root/assets/{capabilities-settings-panel-Cg7zCxEH.js → capabilities-settings-panel-DSp--zIZ.js} +5 -5
- package/dist/gateway/static/root/assets/channels-settings-CMd2dDrI.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-CCBCtLDg.js → channels-status-swr-Ohhee4vm.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-BsRWnz7M.js → chat-terminal-dock-BOtoKTK3.js} +2 -2
- package/dist/gateway/static/root/assets/connectors-page-udWs5Kdm.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-DdCgsH2c.js → cron-expression-DTj1V3Sw.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-dt37Lt8e.js → date-picker-Yr6OCvGL.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-oi7cdv2C.js → dependency-picker-DpN3XZg9.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-Nw_Pgkk3.js → desktop-pet-DbGzggPF.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-D9OO-exo.js → desktop-pet-settings-DinCToZh.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-BHSst0WN.js → extension-debug-page-DgTtk4KC.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DXbL4cQZ.js → extension-page-DtQeiP6f.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-FTD7nE8v.js → extension-settings-page-DcguCgsH.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-c-8ENciH.js → gateway-config-api-Br7lSf6H.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-826dipyU.js → gateway-config-swr-DXuXtU1w.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-BxvyTRl0.js → gateway-settings-CdPoDMuj.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-DyvcAIMm.js → gateway-startup-retry-CzBzglzQ.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-C1S2Ccui.js → heartbeat-settings-DHk1hawP.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-YGipe_W6.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-D7cyfks6.js → image-generation-api-TIgsn04n.js} +1 -1
- package/dist/gateway/static/root/assets/{index-Cif1_3Jx.js → index-D5TQQpeb.js} +44 -44
- package/dist/gateway/static/root/assets/index-DReBaaTX.css +2 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-EY4cu-6W.js → keyboard-shortcuts-settings-wsWuoa8p.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-CpyvYyrb.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-Dh7OxX0S.js → local-apps-page-CXrbrGo8.js} +1 -1
- package/dist/gateway/static/root/assets/local-context-graph-BjUf7fQ9.js +1 -0
- package/dist/gateway/static/root/assets/{locale-store-CBoCuIMx.js → locale-store-BJFLQY8O.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-DUsxXdDp.js → logs-page-CXKy6E_l.js} +2 -2
- package/dist/gateway/static/root/assets/{management-settings-ZjiL3A-S.js → management-settings-BdJZFR7U.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-B4BxkTpU.js → markdown-split-NK3ACVG2.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-BXsHghJd.js → markdown-view-DTF9v1gg.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-D15XBiEo.js → media-plugins-F0jcUxyl.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CHNYp8EQ.js +3 -0
- package/dist/gateway/static/root/assets/{mobile-pairing-wizard-Dv87XewB.js → mobile-pairing-wizard-3NKCniSp.js} +1 -1
- package/dist/gateway/static/root/assets/models-hub-cache-nCfkBN8M.js +1 -0
- package/dist/gateway/static/root/assets/{notes-page-DOe0lOcQ.js → notes-page-DuqLahi6.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-C7j9EdQk.js +5 -0
- package/dist/gateway/static/root/assets/{oauth-api-BjSUDIgq.js → oauth-api-8lP_qJpq.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-CAJeUXeU.js → product-open-page-CxGGlWA8.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-CfebYVX0.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-48GvzSVa.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-BhGKnvLP.js → registry-api-CIsNlSBi.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-64xj_s2m.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BhKcyEId.js → runtime-tools-settings-panel-YkjhiQfA.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-L0s7RWCi.js → schema-form-oFGf3G3s.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-CcwcdRN8.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BaN84CyW.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-CTKoztlF.js → settings-page-C7VWs0IT.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-DVVOCNbr.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-CiiLLz5A.js → share-preview-page-t5oz18rh.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-DUYbYLi7.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-BGyD0gB9.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-cBT9jCof.js → skills-page-CjF8DTsN.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-CwRekJSJ.js → skills-page.utils-DEDTYs2W.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-Byrk4DQy.js → system-settings-panel-BSYuRgFI.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-YZYSTJH7.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-hybK3oC9.js → theme-store-O597U8q_.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-jKzujxFU.js → tunnel-api-FKUi9wDL.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-DX5YZ3Nn.js → use-autosave-B5eUJ6Zq.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-BCyiduKd.js +2 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-ocnZbAyi.js → voice-api-key-field-CMKSwz4C.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-CBbiF1T3.js → voice-config-api-q7B6fOFB.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-DE4_YpDn.js → work-discovery-overlay-jhT2EzeH.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DaErGvxO.js → workflow-run-setup-panel-DZmvLZjb.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-DQC0TpMa.js +5 -0
- package/dist/gateway/static/root/index.html +12 -12
- package/dist/package.js +1 -1
- package/dist/src/agent/commands/command-registry.d.ts +1 -0
- package/dist/src/agent/commands/command-registry.js +12 -22
- package/dist/src/agent/ipc/inbox.d.ts +8 -31
- package/dist/src/agent/ipc/inbox.js +64 -133
- package/dist/src/agent/service/process-direct-one-shot.js +15 -10
- package/dist/src/agent/workflow/catalog.d.ts +1 -8
- package/dist/src/agent/workflow/catalog.js +44 -102
- package/dist/src/agent/workflow/index.d.ts +1 -1
- package/dist/src/agent/workflow/index.js +2 -2
- package/dist/src/automations/domain/types.d.ts +1 -0
- package/dist/src/automations/service/action-executor.js +2 -2
- package/dist/src/automations/service/automation-service.js +2 -2
- package/dist/src/channels/manager.d.ts +1 -1
- package/dist/src/channels/manager.js +2 -2
- package/dist/src/channels/outbound/persist-store.d.ts +2 -8
- package/dist/src/channels/outbound/persist-store.js +11 -38
- package/dist/src/channels/outbound-sender.d.ts +1 -1
- package/dist/src/channels/outbound-sender.js +2 -2
- package/dist/src/cli/commands/connectors.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/config/schema.js +2 -2
- package/dist/src/connectors/auth-provider-registry.js +1 -1
- package/dist/src/connectors/composio-triggers.d.ts +2 -2
- package/dist/src/connectors/composio-triggers.js +8 -15
- package/dist/src/connectors/connected-source-ingestion.js +1 -1
- package/dist/src/connectors/health.js +1 -1
- package/dist/src/gateway/automation-agent-session.js +3 -0
- package/dist/src/gateway/hono/lib/extension-store.js +8 -25
- package/dist/src/gateway/hono/routes/capabilities.js +1 -1
- package/dist/src/gateway/hono/routes/connectors.js +3 -3
- package/dist/src/gateway/hono/routes/mcp.js +1 -1
- package/dist/src/gateway/hono/routes/projects.js +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +2 -2
- package/dist/src/gateway/hono/routes/you.js +16 -2
- package/dist/src/gateway/service.js +4 -5
- package/dist/src/notes/index.d.ts +1 -1
- package/dist/src/notes/index.js +2 -2
- package/dist/src/notes/paths.d.ts +0 -3
- package/dist/src/notes/paths.js +1 -10
- package/dist/src/notes/service.d.ts +0 -1
- package/dist/src/notes/service.js +0 -3
- package/dist/src/notes/store.d.ts +0 -2
- package/dist/src/notes/store.js +33 -80
- package/dist/src/share/hosted-session-share.d.ts +1 -4
- package/dist/src/share/hosted-session-share.js +14 -47
- package/dist/src/share/share-auto.d.ts +1 -1
- package/dist/src/share/share-auto.js +2 -2
- package/dist/src/share/share-store.d.ts +2 -7
- package/dist/src/share/share-store.js +153 -195
- package/dist/src/share/share-types.d.ts +0 -4
- package/dist/src/share/site-share-store.d.ts +3 -8
- package/dist/src/share/site-share-store.js +94 -153
- package/dist/src/share/site-share-types.d.ts +0 -4
- package/dist/src/storage/sqlite/connection.d.ts +1 -2
- package/dist/src/storage/sqlite/connection.js +50 -47
- package/dist/src/storage/sqlite/durable-queue.d.ts +16 -0
- package/dist/src/storage/sqlite/durable-queue.js +52 -0
- package/dist/src/storage/sqlite/durable-state.d.ts +16 -0
- package/dist/src/storage/sqlite/durable-state.js +43 -0
- package/dist/src/storage/sqlite/migrations/146_understanding_focus_exclusions.sql +9 -0
- package/dist/src/storage/sqlite/migrations/147_durable_application_state.sql +39 -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/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/understanding-focus-exclusions.d.ts +2 -0
- package/dist/src/storage/sqlite/understanding-focus-exclusions.js +24 -0
- package/dist/src/tui/tui-scoped-models.js +9 -6
- package/dist/src/tui/tui-startup-resources.js +1 -1
- package/dist/src/voice/realtime/agentEngine.js +63 -18
- package/dist/src/voice/realtime/conversationTurn.d.ts +20 -0
- package/dist/src/voice/realtime/conversationTurn.js +83 -0
- package/dist/src/voice/realtime/omniEngine.js +72 -18
- package/dist/src/workflows/authoring/workflow-draft-store.d.ts +1 -5
- package/dist/src/workflows/authoring/workflow-draft-store.js +23 -43
- package/dist/src/workflows/index.js +2 -2
- package/dist/src/workflows/store/event-store.d.ts +1 -2
- package/dist/src/workflows/store/event-store.js +19 -64
- package/dist/src/workflows/store/paths.d.ts +0 -2
- package/dist/src/workflows/store/paths.js +1 -7
- package/dist/src/workflows/store/run-store.d.ts +0 -1
- package/dist/src/workflows/store/run-store.js +1 -24
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-eG49pM-z.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-BZG3BK7f.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-CB7Yl2_B.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-Bu42Ljfw.js +0 -8
- package/dist/gateway/static/root/assets/channels-settings-EDTZ8P3y.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-kh7PEkSS.js +0 -2
- package/dist/gateway/static/root/assets/home-page-Bqx-SMWV.js +0 -1
- package/dist/gateway/static/root/assets/index-Dbh5SXyV.css +0 -2
- package/dist/gateway/static/root/assets/local-app-workbench-page-sDdw7Y3Q.js +0 -2
- package/dist/gateway/static/root/assets/messages-BbdwoxVo.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-cache-88f4fzYS.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-Cy0oYbWP.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-fgD1xc4O.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-CiTiEcOc.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-Dc0GrNSp.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BPOW3yaM.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-Bz4s9BBY.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-rllj-j7k.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-DMj7onCX.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DRB366nS.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-CheX3zmK.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-CWy3Pqtk.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-y4O9-BTf.js +0 -5
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
CREATE TABLE durable_state (
|
|
2
|
+
namespace TEXT NOT NULL,
|
|
3
|
+
scope TEXT NOT NULL,
|
|
4
|
+
key TEXT NOT NULL,
|
|
5
|
+
payload TEXT NOT NULL CHECK(json_valid(payload)),
|
|
6
|
+
UNIQUE(namespace, scope, key)
|
|
7
|
+
);
|
|
8
|
+
CREATE TABLE workflow_events (
|
|
9
|
+
agent_id TEXT NOT NULL,
|
|
10
|
+
run_id TEXT NOT NULL,
|
|
11
|
+
sequence INTEGER NOT NULL CHECK(sequence > 0),
|
|
12
|
+
id TEXT NOT NULL UNIQUE,
|
|
13
|
+
payload TEXT NOT NULL CHECK(json_valid(payload)),
|
|
14
|
+
PRIMARY KEY(agent_id, run_id, sequence)
|
|
15
|
+
);
|
|
16
|
+
CREATE TABLE note_snapshots (
|
|
17
|
+
note_id TEXT NOT NULL REFERENCES notes(note_id) ON DELETE CASCADE,
|
|
18
|
+
timestamp INTEGER NOT NULL,
|
|
19
|
+
payload TEXT NOT NULL CHECK(json_valid(payload)),
|
|
20
|
+
PRIMARY KEY(note_id, timestamp)
|
|
21
|
+
);
|
|
22
|
+
CREATE TABLE durable_messages (
|
|
23
|
+
sequence INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
24
|
+
queue TEXT NOT NULL,
|
|
25
|
+
scope TEXT NOT NULL,
|
|
26
|
+
id TEXT NOT NULL,
|
|
27
|
+
payload TEXT NOT NULL CHECK(json_valid(payload)),
|
|
28
|
+
enqueued_at INTEGER NOT NULL,
|
|
29
|
+
processed_at INTEGER,
|
|
30
|
+
lease_token TEXT,
|
|
31
|
+
lease_until INTEGER,
|
|
32
|
+
UNIQUE(queue, scope, id)
|
|
33
|
+
);
|
|
34
|
+
CREATE INDEX durable_messages_pending ON durable_messages(queue, scope, processed_at, sequence);
|
|
35
|
+
|
|
36
|
+
CREATE UNIQUE INDEX durable_share_token ON durable_state(namespace, json_extract(payload, '$.token'))
|
|
37
|
+
WHERE namespace IN ('shares', 'site-shares');
|
|
38
|
+
CREATE UNIQUE INDEX durable_site_subdomain ON durable_state(json_extract(payload, '$.subdomain'))
|
|
39
|
+
WHERE namespace = 'site-shares' AND json_extract(payload, '$.subdomain') IS NOT NULL;
|
|
@@ -3,7 +3,7 @@ import type { ApplyMigrationsOptions } from './types.js';
|
|
|
3
3
|
/** Baseline schema version applied from schema.sql on first open. */
|
|
4
4
|
export declare const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
|
|
5
5
|
/** Latest schema version this release supports (increment when adding migrations). */
|
|
6
|
-
export declare const XOPC_DB_SCHEMA_VERSION =
|
|
6
|
+
export declare const XOPC_DB_SCHEMA_VERSION = 147;
|
|
7
7
|
export declare function resolveMigrationsDir(override?: string): string;
|
|
8
8
|
/**
|
|
9
9
|
* Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.
|
|
@@ -12,7 +12,7 @@ const log = createLogger("Sqlite:Migrations");
|
|
|
12
12
|
/** Baseline schema version applied from schema.sql on first open. */
|
|
13
13
|
const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
|
|
14
14
|
/** Latest schema version this release supports (increment when adding migrations). */
|
|
15
|
-
const XOPC_DB_SCHEMA_VERSION =
|
|
15
|
+
const XOPC_DB_SCHEMA_VERSION = 147;
|
|
16
16
|
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
17
17
|
function backupBeforeTaskCutover(db, databasePath) {
|
|
18
18
|
db.exec("PRAGMA wal_checkpoint(FULL)");
|
|
@@ -57,7 +57,7 @@ function applySingleMigration(db, migration) {
|
|
|
57
57
|
* Each step runs in its own transaction and updates schema_meta on success.
|
|
58
58
|
*/
|
|
59
59
|
function applyPendingMigrations(db, options = {}) {
|
|
60
|
-
const targetVersion = options.targetVersion ??
|
|
60
|
+
const targetVersion = options.targetVersion ?? 147;
|
|
61
61
|
let currentVersion = readSchemaVersion(db);
|
|
62
62
|
if (currentVersion > targetVersion) throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);
|
|
63
63
|
if (currentVersion >= targetVersion) return currentVersion;
|
|
@@ -94,7 +94,7 @@ function applyPendingMigrations(db, options = {}) {
|
|
|
94
94
|
}
|
|
95
95
|
/** Inspect schema version without mutating the database. */
|
|
96
96
|
function inspectSchemaMigrationStatus(db, options = {}) {
|
|
97
|
-
const appVersion = options.targetVersion ??
|
|
97
|
+
const appVersion = options.targetVersion ?? 147;
|
|
98
98
|
const dbVersion = readSchemaVersion(db);
|
|
99
99
|
if (dbVersion > appVersion) return {
|
|
100
100
|
dbVersion,
|
|
@@ -19,7 +19,7 @@ const log = createLogger('Sqlite:Migrations');
|
|
|
19
19
|
export const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
|
|
20
20
|
|
|
21
21
|
/** Latest schema version this release supports (increment when adding migrations). */
|
|
22
|
-
export const XOPC_DB_SCHEMA_VERSION =
|
|
22
|
+
export const XOPC_DB_SCHEMA_VERSION = 147;
|
|
23
23
|
|
|
24
24
|
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
25
25
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { getSqliteDatabase } from "./transaction.js";
|
|
2
|
+
import { notifyUserContextChange } from "../../user-context/changes.js";
|
|
3
|
+
//#region src/storage/sqlite/understanding-focus-exclusions.ts
|
|
4
|
+
function listUnderstandingFocusExclusions() {
|
|
5
|
+
const rows = getSqliteDatabase().prepare("SELECT understanding_id, focus_id FROM understanding_focus_exclusions").all();
|
|
6
|
+
const result = /* @__PURE__ */ new Map();
|
|
7
|
+
for (const row of rows) {
|
|
8
|
+
const ids = result.get(row.understanding_id) ?? [];
|
|
9
|
+
ids.push(row.focus_id);
|
|
10
|
+
result.set(row.understanding_id, ids);
|
|
11
|
+
}
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
function setUnderstandingFocusExclusion(understandingId, focusId, excluded) {
|
|
15
|
+
const db = getSqliteDatabase();
|
|
16
|
+
if (excluded) db.prepare("INSERT OR IGNORE INTO understanding_focus_exclusions (understanding_id, focus_id, created_at) VALUES (?, ?, ?)").run(understandingId, focusId, Date.now());
|
|
17
|
+
else db.prepare("DELETE FROM understanding_focus_exclusions WHERE understanding_id = ? AND focus_id = ?").run(understandingId, focusId);
|
|
18
|
+
notifyUserContextChange({
|
|
19
|
+
kind: "understanding",
|
|
20
|
+
id: understandingId
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { listUnderstandingFocusExclusions, setUnderstandingFocusExclusion };
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { init_paths_state, resolveStateDir } from "../config/paths-state.js";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
//#region src/tui/tui-scoped-models.ts
|
|
5
|
-
|
|
5
|
+
init_paths_state();
|
|
6
|
+
function storePath() {
|
|
7
|
+
return join(resolveStateDir(), "tui-scoped-models.json");
|
|
8
|
+
}
|
|
6
9
|
function normalizeWorkspaceKey(cwd) {
|
|
7
10
|
return cwd.replace(/\\/g, "/").replace(/\/+$/, "") || "/";
|
|
8
11
|
}
|
|
9
12
|
function readStore() {
|
|
10
13
|
try {
|
|
11
|
-
if (!existsSync(
|
|
12
|
-
const raw = readFileSync(
|
|
14
|
+
if (!existsSync(storePath())) return {};
|
|
15
|
+
const raw = readFileSync(storePath(), "utf8");
|
|
13
16
|
const parsed = JSON.parse(raw);
|
|
14
17
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
15
18
|
} catch {
|
|
@@ -17,9 +20,9 @@ function readStore() {
|
|
|
17
20
|
}
|
|
18
21
|
}
|
|
19
22
|
function writeStore(data) {
|
|
20
|
-
const dir =
|
|
23
|
+
const dir = resolveStateDir();
|
|
21
24
|
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
22
|
-
writeFileSync(
|
|
25
|
+
writeFileSync(storePath(), `${JSON.stringify(data, null, 2)}\n`, "utf8");
|
|
23
26
|
}
|
|
24
27
|
/** Load scoped model refs for Ctrl+P cycling (`null` = all models). */
|
|
25
28
|
function loadScopedModelRefs(cwd = process.cwd()) {
|
|
@@ -5,9 +5,9 @@ import { resolveBootstrapFilesSync } from "../agent/bootstrap/bootstrap-files.js
|
|
|
5
5
|
import { createSkillConfigManager, isSkillEnabled } from "../agent/skills/config.js";
|
|
6
6
|
import { loadSkills } from "../agent/skills/index.js";
|
|
7
7
|
import { createWorkflowCatalog } from "../agent/workflow/catalog.js";
|
|
8
|
-
import { listConnectorInstances } from "../connectors/instances.js";
|
|
9
8
|
import { getWorkspacePath } from "../config/workspace-path-helpers.js";
|
|
10
9
|
import "../config/index.js";
|
|
10
|
+
import { listConnectorInstances } from "../connectors/instances.js";
|
|
11
11
|
import { basename } from "node:path";
|
|
12
12
|
//#region src/tui/tui-startup-resources.ts
|
|
13
13
|
init_paths();
|
|
@@ -2,6 +2,7 @@ import { createLogger } from "../../utils/logger/index.js";
|
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { speakStream } from "../tts/speak-core.js";
|
|
4
4
|
import { AudioPlaybackWindow } from "./audio-playback-window.js";
|
|
5
|
+
import { ConversationTurn } from "./conversationTurn.js";
|
|
5
6
|
import { SpeakableSegmenter } from "./speakable-segmenter.js";
|
|
6
7
|
import crypto from "node:crypto";
|
|
7
8
|
//#region src/voice/realtime/agentEngine.ts
|
|
@@ -29,6 +30,32 @@ function createAgentVoiceEngine(options) {
|
|
|
29
30
|
let finalCount = 0;
|
|
30
31
|
let committing = false;
|
|
31
32
|
const finalizedUtterances = /* @__PURE__ */ new Set();
|
|
33
|
+
let pendingTurn;
|
|
34
|
+
const turn = new ConversationTurn(claim.silenceDurationMs, (text) => {
|
|
35
|
+
if (closed || muted) return;
|
|
36
|
+
if (queuedTurns >= 8) {
|
|
37
|
+
send("session.error", {
|
|
38
|
+
code: "INPUT_BACKPRESSURE",
|
|
39
|
+
message: "Too many queued voice turns",
|
|
40
|
+
recoverable: false
|
|
41
|
+
});
|
|
42
|
+
options.onClose("input_backpressure", true);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
queuedTurns += 1;
|
|
46
|
+
const generation = inputGeneration;
|
|
47
|
+
const pending = {
|
|
48
|
+
text,
|
|
49
|
+
cancelled: false
|
|
50
|
+
};
|
|
51
|
+
pendingTurn = pending;
|
|
52
|
+
conversationTail = conversationTail.then(() => {
|
|
53
|
+
if (pendingTurn === pending) pendingTurn = void 0;
|
|
54
|
+
if (generation === inputGeneration && !pending.cancelled) return runConversationTurn(text);
|
|
55
|
+
}).finally(() => {
|
|
56
|
+
if (generation === inputGeneration) queuedTurns -= 1;
|
|
57
|
+
});
|
|
58
|
+
});
|
|
32
59
|
function cancelActiveResponse(reason) {
|
|
33
60
|
const response = activeResponse;
|
|
34
61
|
if (!response) return false;
|
|
@@ -238,10 +265,23 @@ function createAgentVoiceEngine(options) {
|
|
|
238
265
|
}
|
|
239
266
|
});
|
|
240
267
|
}
|
|
268
|
+
function bufferFinal(utteranceId, text) {
|
|
269
|
+
try {
|
|
270
|
+
turn.final(utteranceId, text);
|
|
271
|
+
} catch {
|
|
272
|
+
send("session.error", {
|
|
273
|
+
code: "INPUT_BACKPRESSURE",
|
|
274
|
+
message: "Voice turn input limit reached",
|
|
275
|
+
recoverable: false
|
|
276
|
+
});
|
|
277
|
+
options.onClose("input_backpressure", true);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
241
280
|
function onSttEvent(event) {
|
|
242
281
|
if (closed) return;
|
|
243
282
|
if (event.type === "ready" || event.type === "usage") return;
|
|
244
283
|
if (event.type === "error") {
|
|
284
|
+
turn.reset();
|
|
245
285
|
log.warn({
|
|
246
286
|
err: event.error,
|
|
247
287
|
sessionId: claim.sessionId,
|
|
@@ -257,10 +297,21 @@ function createAgentVoiceEngine(options) {
|
|
|
257
297
|
}
|
|
258
298
|
if (muted || finalizedUtterances.has(event.utteranceId)) return;
|
|
259
299
|
if (event.type === "speech_started") {
|
|
300
|
+
if (claim.request.purpose === "conversation") {
|
|
301
|
+
if (pendingTurn) {
|
|
302
|
+
pendingTurn.cancelled = true;
|
|
303
|
+
turn.restore(pendingTurn.text);
|
|
304
|
+
pendingTurn = void 0;
|
|
305
|
+
}
|
|
306
|
+
turn.start(event.utteranceId);
|
|
307
|
+
}
|
|
260
308
|
if (claim.request.purpose === "conversation" && claim.config.voice?.realtime?.bargeIn && !activeResponse?.awaitingClarification) cancelActiveResponse("barge_in");
|
|
261
309
|
send("input.speech_started", { utteranceId: event.utteranceId });
|
|
262
310
|
}
|
|
263
|
-
if (event.type === "speech_stopped")
|
|
311
|
+
if (event.type === "speech_stopped") {
|
|
312
|
+
if (claim.request.purpose === "conversation") turn.stop(event.utteranceId);
|
|
313
|
+
send("input.speech_stopped", { utteranceId: event.utteranceId });
|
|
314
|
+
}
|
|
264
315
|
if (event.type === "transcript_delta") send("input.transcript.delta", {
|
|
265
316
|
utteranceId: event.utteranceId,
|
|
266
317
|
revision: event.revision,
|
|
@@ -268,7 +319,10 @@ function createAgentVoiceEngine(options) {
|
|
|
268
319
|
});
|
|
269
320
|
if (event.type === "transcript_final") {
|
|
270
321
|
const text = event.text.trim();
|
|
271
|
-
if (!text)
|
|
322
|
+
if (!text) {
|
|
323
|
+
if (claim.request.purpose === "conversation") bufferFinal(event.utteranceId, "");
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
272
326
|
if (finalizedUtterances.size >= 1e4) {
|
|
273
327
|
options.onClose("utterance_limit", true);
|
|
274
328
|
return;
|
|
@@ -282,28 +336,18 @@ function createAgentVoiceEngine(options) {
|
|
|
282
336
|
...event.language === "zh" || event.language === "en" ? { language: event.language } : {}
|
|
283
337
|
});
|
|
284
338
|
if (claim.request.purpose === "conversation") {
|
|
285
|
-
if (activeResponse?.awaitingClarification)
|
|
286
|
-
|
|
287
|
-
if (queuedTurns >= 8) {
|
|
288
|
-
send("session.error", {
|
|
289
|
-
code: "INPUT_BACKPRESSURE",
|
|
290
|
-
message: "Too many queued voice turns",
|
|
291
|
-
recoverable: false
|
|
292
|
-
});
|
|
293
|
-
options.onClose("input_backpressure", true);
|
|
339
|
+
if (activeResponse?.awaitingClarification) {
|
|
340
|
+
turn.reset();
|
|
294
341
|
return;
|
|
295
342
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
conversationTail = conversationTail.then(() => {
|
|
299
|
-
if (generation === inputGeneration) return runConversationTurn(text);
|
|
300
|
-
}).finally(() => {
|
|
301
|
-
if (generation === inputGeneration) queuedTurns -= 1;
|
|
302
|
-
});
|
|
343
|
+
if (claim.config.voice?.realtime?.bargeIn) cancelActiveResponse("barge_in");
|
|
344
|
+
bufferFinal(event.utteranceId, text);
|
|
303
345
|
}
|
|
304
346
|
}
|
|
305
347
|
}
|
|
306
348
|
function discardInput() {
|
|
349
|
+
turn.reset();
|
|
350
|
+
pendingTurn = void 0;
|
|
307
351
|
inputGeneration += 1;
|
|
308
352
|
queuedTurns = 0;
|
|
309
353
|
bufferedAudio = [];
|
|
@@ -387,6 +431,7 @@ function createAgentVoiceEngine(options) {
|
|
|
387
431
|
close() {
|
|
388
432
|
if (closing) return closing;
|
|
389
433
|
closed = true;
|
|
434
|
+
turn.reset();
|
|
390
435
|
cancelActiveResponse("session_closed");
|
|
391
436
|
sttAbort.abort("session_closed");
|
|
392
437
|
sttSession?.abort("session_closed");
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Conservative continuation hints, not a semantic model or punctuation-based endpoint detector. */
|
|
2
|
+
export declare function needsContinuation(text: string): boolean;
|
|
3
|
+
/** Joins provider utterances until both transcription and the continuation window have settled. */
|
|
4
|
+
export declare class ConversationTurn {
|
|
5
|
+
private readonly silenceDurationMs;
|
|
6
|
+
private readonly onTurn;
|
|
7
|
+
private readonly parts;
|
|
8
|
+
private timer;
|
|
9
|
+
private stoppedAt;
|
|
10
|
+
constructor(silenceDurationMs: number, onTurn: (text: string) => void);
|
|
11
|
+
start(id: string): void;
|
|
12
|
+
stop(id: string): void;
|
|
13
|
+
final(id: string, text: string): void;
|
|
14
|
+
reset(): void;
|
|
15
|
+
/** Restore a settled turn if generation was still queued when the user resumed. */
|
|
16
|
+
restore(text: string): void;
|
|
17
|
+
private text;
|
|
18
|
+
private clearTimer;
|
|
19
|
+
private schedule;
|
|
20
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
//#region src/voice/realtime/conversationTurn.ts
|
|
2
|
+
const MIN_TURN_SILENCE_MS = 1200;
|
|
3
|
+
const FINAL_SETTLE_MS = 350;
|
|
4
|
+
const INCOMPLETE_HOLD_MS = 1800;
|
|
5
|
+
/** Conservative continuation hints, not a semantic model or punctuation-based endpoint detector. */
|
|
6
|
+
function needsContinuation(text) {
|
|
7
|
+
const tail = text.trim().replace(/[\s,。!?、;:,.!?;:]+$/u, "");
|
|
8
|
+
return /(?:…|\.\.\.)[\s,。!?,.!?]*$/u.test(text) || /(?:因为|但是|然后|而且|如果|所以|比如|或者|还有|我想|我要|我觉得|帮我|帮我查一下|帮我查查|请帮我|就是说|那个|这个|呃|嗯)$/u.test(tail) || /\b(?:because|but|and|or|if|so|then|um|uh|i want to|i would like to|can you|could you|let me)\s*$/iu.test(tail);
|
|
9
|
+
}
|
|
10
|
+
/** Joins provider utterances until both transcription and the continuation window have settled. */
|
|
11
|
+
var ConversationTurn = class {
|
|
12
|
+
parts = /* @__PURE__ */ new Map();
|
|
13
|
+
timer;
|
|
14
|
+
stoppedAt = 0;
|
|
15
|
+
constructor(silenceDurationMs, onTurn) {
|
|
16
|
+
this.silenceDurationMs = silenceDurationMs;
|
|
17
|
+
this.onTurn = onTurn;
|
|
18
|
+
}
|
|
19
|
+
start(id) {
|
|
20
|
+
if (this.parts.has(id)) return;
|
|
21
|
+
this.clearTimer();
|
|
22
|
+
this.parts.set(id, { stopped: false });
|
|
23
|
+
}
|
|
24
|
+
stop(id) {
|
|
25
|
+
const part = this.parts.get(id);
|
|
26
|
+
if (part?.stopped) return;
|
|
27
|
+
this.parts.set(id, {
|
|
28
|
+
...part,
|
|
29
|
+
stopped: true
|
|
30
|
+
});
|
|
31
|
+
this.stoppedAt = Date.now();
|
|
32
|
+
this.schedule();
|
|
33
|
+
}
|
|
34
|
+
final(id, text) {
|
|
35
|
+
const part = this.parts.get(id);
|
|
36
|
+
if (part?.text !== void 0) return;
|
|
37
|
+
if (!part?.stopped) this.stoppedAt = Date.now();
|
|
38
|
+
this.parts.set(id, {
|
|
39
|
+
text: text.trim(),
|
|
40
|
+
stopped: true
|
|
41
|
+
});
|
|
42
|
+
if (this.parts.size > 256 || this.text().length > 32e3) {
|
|
43
|
+
this.reset();
|
|
44
|
+
throw new Error("Voice turn input limit reached");
|
|
45
|
+
}
|
|
46
|
+
this.schedule();
|
|
47
|
+
}
|
|
48
|
+
reset() {
|
|
49
|
+
this.clearTimer();
|
|
50
|
+
this.parts.clear();
|
|
51
|
+
}
|
|
52
|
+
/** Restore a settled turn if generation was still queued when the user resumed. */
|
|
53
|
+
restore(text) {
|
|
54
|
+
this.parts.set("queued-turn", {
|
|
55
|
+
text,
|
|
56
|
+
stopped: true
|
|
57
|
+
});
|
|
58
|
+
this.clearTimer();
|
|
59
|
+
}
|
|
60
|
+
text() {
|
|
61
|
+
return [...this.parts.values()].map((part) => part.text ?? "").filter(Boolean).join(" ");
|
|
62
|
+
}
|
|
63
|
+
clearTimer() {
|
|
64
|
+
clearTimeout(this.timer);
|
|
65
|
+
this.timer = void 0;
|
|
66
|
+
}
|
|
67
|
+
schedule() {
|
|
68
|
+
this.clearTimer();
|
|
69
|
+
if ([...this.parts.values()].some((part) => !part.stopped || part.text === void 0)) return;
|
|
70
|
+
const text = this.text();
|
|
71
|
+
if (!text) {
|
|
72
|
+
this.reset();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const holdMs = Math.max(FINAL_SETTLE_MS, MIN_TURN_SILENCE_MS - this.silenceDurationMs, needsContinuation(text) ? INCOMPLETE_HOLD_MS : 0);
|
|
76
|
+
this.timer = setTimeout(() => {
|
|
77
|
+
this.reset();
|
|
78
|
+
this.onTurn(text);
|
|
79
|
+
}, Math.max(FINAL_SETTLE_MS, this.stoppedAt + holdMs - Date.now()));
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
//#endregion
|
|
83
|
+
export { ConversationTurn, needsContinuation };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { AudioPlaybackWindow } from "./audio-playback-window.js";
|
|
4
|
+
import { ConversationTurn } from "./conversationTurn.js";
|
|
4
5
|
import crypto from "node:crypto";
|
|
5
6
|
import WebSocket from "ws";
|
|
6
7
|
//#region src/voice/realtime/omniEngine.ts
|
|
@@ -47,6 +48,23 @@ function createOmniVoiceEngine(options) {
|
|
|
47
48
|
let queuedInputBytes = 0;
|
|
48
49
|
let uploadingBytes = 0;
|
|
49
50
|
let uploadTimer;
|
|
51
|
+
let turnSettled = false;
|
|
52
|
+
const speaking = /* @__PURE__ */ new Set();
|
|
53
|
+
const turn = new ConversationTurn(options.silenceDurationMs, () => {
|
|
54
|
+
if (closed || failed || muted || inputBlocked) return;
|
|
55
|
+
turnSettled = true;
|
|
56
|
+
if (active) publish(active);
|
|
57
|
+
});
|
|
58
|
+
function publish(response) {
|
|
59
|
+
if (response.published || active !== response) return;
|
|
60
|
+
response.published = true;
|
|
61
|
+
options.send("response.created", { responseId: response.id });
|
|
62
|
+
if (response.text) options.send("response.text.delta", {
|
|
63
|
+
responseId: response.id,
|
|
64
|
+
delta: response.text
|
|
65
|
+
});
|
|
66
|
+
response.release();
|
|
67
|
+
}
|
|
50
68
|
const send = (type, fields = {}) => {
|
|
51
69
|
if (closed || socket?.readyState !== WebSocket.OPEN) throw new Error("Omni connection is closed");
|
|
52
70
|
socket.send(JSON.stringify({
|
|
@@ -103,23 +121,29 @@ function createOmniVoiceEngine(options) {
|
|
|
103
121
|
if (!response) return false;
|
|
104
122
|
active = void 0;
|
|
105
123
|
response.abort.abort(reason);
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
124
|
+
response.release();
|
|
125
|
+
if (response.published) {
|
|
126
|
+
save({
|
|
127
|
+
itemId: response.id,
|
|
128
|
+
role: "assistant",
|
|
129
|
+
text: response.text,
|
|
130
|
+
interrupted: true
|
|
131
|
+
});
|
|
132
|
+
options.send("response.cancelled", {
|
|
133
|
+
responseId: response.id,
|
|
134
|
+
reason
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if ((reason === "client_cancelled" || reason === "barge_in" && !options.bargeIn) && response.generating && socket?.readyState === WebSocket.OPEN) {
|
|
117
138
|
cancellationPending = true;
|
|
118
139
|
send("response.cancel");
|
|
119
140
|
}
|
|
120
141
|
return true;
|
|
121
142
|
};
|
|
122
143
|
const finish = async (response) => {
|
|
144
|
+
await response.settled;
|
|
145
|
+
if (active !== response || closed) return;
|
|
146
|
+
options.send("response.text.done", { responseId: response.id });
|
|
123
147
|
await response.tail;
|
|
124
148
|
if (active !== response || closed) return;
|
|
125
149
|
await response.playback.drain(response.abort.signal);
|
|
@@ -157,6 +181,7 @@ function createOmniVoiceEngine(options) {
|
|
|
157
181
|
function fail(code, details = {}) {
|
|
158
182
|
if (closed || failed) return;
|
|
159
183
|
failed = true;
|
|
184
|
+
turn.reset();
|
|
160
185
|
log.warn({
|
|
161
186
|
sessionId: options.callId,
|
|
162
187
|
platformRequestId,
|
|
@@ -179,6 +204,10 @@ function createOmniVoiceEngine(options) {
|
|
|
179
204
|
options.onClose("omni_error", true);
|
|
180
205
|
}
|
|
181
206
|
function discardInput() {
|
|
207
|
+
turn.reset();
|
|
208
|
+
speaking.clear();
|
|
209
|
+
turnSettled = false;
|
|
210
|
+
if (active && !active.published) cancel("client_cancelled");
|
|
182
211
|
inputQueue = [];
|
|
183
212
|
queuedInputBytes = 0;
|
|
184
213
|
inputBlocked = true;
|
|
@@ -266,12 +295,18 @@ function createOmniVoiceEngine(options) {
|
|
|
266
295
|
discardedInputs.add(String(event.item_id));
|
|
267
296
|
return;
|
|
268
297
|
}
|
|
298
|
+
if (recorded.has(String(event.item_id)) || pendingInputs.has(String(event.item_id))) return;
|
|
269
299
|
inputBlocked = false;
|
|
270
300
|
pendingInputs.add(String(event.item_id));
|
|
271
|
-
|
|
301
|
+
turnSettled = false;
|
|
302
|
+
speaking.add(String(event.item_id));
|
|
303
|
+
turn.start(String(event.item_id));
|
|
304
|
+
if (options.bargeIn || active && !active.published) cancel("barge_in");
|
|
272
305
|
options.send("input.speech_started", { utteranceId: String(event.item_id) });
|
|
273
306
|
} else if (event.type === "input_audio_buffer.speech_stopped") {
|
|
274
|
-
if (muted || inputBlocked || discardedInputs.has(String(event.item_id))) return;
|
|
307
|
+
if (muted || inputBlocked || discardedInputs.has(String(event.item_id)) || recorded.has(String(event.item_id))) return;
|
|
308
|
+
speaking.delete(String(event.item_id));
|
|
309
|
+
turn.stop(String(event.item_id));
|
|
275
310
|
options.send("input.speech_stopped", { utteranceId: String(event.item_id) });
|
|
276
311
|
} else if (event.type === "conversation.item.input_audio_transcription.completed") {
|
|
277
312
|
if (typeof event.transcript !== "string" || event.transcript.length > 32e3 || typeof event.item_id !== "string") {
|
|
@@ -280,6 +315,8 @@ function createOmniVoiceEngine(options) {
|
|
|
280
315
|
}
|
|
281
316
|
if (muted || inputBlocked || discardedInputs.has(event.item_id) || recorded.has(event.item_id)) return;
|
|
282
317
|
pendingInputs.delete(event.item_id);
|
|
318
|
+
speaking.delete(event.item_id);
|
|
319
|
+
turn.final(event.item_id, event.transcript);
|
|
283
320
|
save({
|
|
284
321
|
itemId: event.item_id,
|
|
285
322
|
role: "user",
|
|
@@ -291,8 +328,16 @@ function createOmniVoiceEngine(options) {
|
|
|
291
328
|
revision: 1,
|
|
292
329
|
text: event.transcript
|
|
293
330
|
});
|
|
331
|
+
} else if (event.type === "conversation.item.input_audio_transcription.failed") {
|
|
332
|
+
if (muted || inputBlocked || discardedInputs.has(String(event.item_id))) return;
|
|
333
|
+
discardInput();
|
|
334
|
+
options.send("session.error", {
|
|
335
|
+
code: "INPUT_DROPPED",
|
|
336
|
+
message: "Could not transcribe this voice turn. Please repeat it.",
|
|
337
|
+
recoverable: true
|
|
338
|
+
});
|
|
294
339
|
} else if (event.type === "response.created") {
|
|
295
|
-
if (muted || inputBlocked) {
|
|
340
|
+
if (muted || inputBlocked || speaking.size > 0) {
|
|
296
341
|
cancellationPending = true;
|
|
297
342
|
send("response.cancel");
|
|
298
343
|
return;
|
|
@@ -301,6 +346,10 @@ function createOmniVoiceEngine(options) {
|
|
|
301
346
|
if (active) cancel("barge_in");
|
|
302
347
|
const id = event.response?.id;
|
|
303
348
|
if (typeof id !== "string" || !id.length || id.length > 160) throw new Error("Invalid response ID");
|
|
349
|
+
let release;
|
|
350
|
+
const settled = new Promise((resolve) => {
|
|
351
|
+
release = resolve;
|
|
352
|
+
});
|
|
304
353
|
active = {
|
|
305
354
|
id,
|
|
306
355
|
text: "",
|
|
@@ -309,16 +358,19 @@ function createOmniVoiceEngine(options) {
|
|
|
309
358
|
queuedBytes: 0,
|
|
310
359
|
abort: new AbortController(),
|
|
311
360
|
playback: new AudioPlaybackWindow(),
|
|
312
|
-
tail: Promise.resolve()
|
|
361
|
+
tail: Promise.resolve(),
|
|
362
|
+
published: false,
|
|
363
|
+
settled,
|
|
364
|
+
release
|
|
313
365
|
};
|
|
314
|
-
|
|
366
|
+
if (turnSettled) publish(active);
|
|
315
367
|
} else if (active && event.response_id === active.id && event.type === "response.audio_transcript.delta") {
|
|
316
368
|
if (typeof event.delta !== "string" || active.text.length + event.delta.length > 32e3) {
|
|
317
369
|
fail("OMNI_TRANSCRIPT_LIMIT");
|
|
318
370
|
return;
|
|
319
371
|
}
|
|
320
372
|
active.text += event.delta;
|
|
321
|
-
options.send("response.text.delta", {
|
|
373
|
+
if (active.published) options.send("response.text.delta", {
|
|
322
374
|
responseId: active.id,
|
|
323
375
|
delta: event.delta
|
|
324
376
|
});
|
|
@@ -339,6 +391,7 @@ function createOmniVoiceEngine(options) {
|
|
|
339
391
|
}
|
|
340
392
|
response.queuedBytes += audio.length;
|
|
341
393
|
response.tail = response.tail.then(async () => {
|
|
394
|
+
await response.settled;
|
|
342
395
|
for (let offset = 0; offset < audio.length; offset += 24e3) {
|
|
343
396
|
if (closed || active !== response) return;
|
|
344
397
|
const chunk = audio.subarray(offset, offset + 24e3);
|
|
@@ -368,7 +421,6 @@ function createOmniVoiceEngine(options) {
|
|
|
368
421
|
else if (event.response.status !== "completed") fail("OMNI_RESPONSE_FAILED");
|
|
369
422
|
else {
|
|
370
423
|
const response = active;
|
|
371
|
-
options.send("response.text.done", { responseId: response.id });
|
|
372
424
|
finish(response).catch(() => {
|
|
373
425
|
if (!response.abort.signal.aborted) stopReply(response, "OMNI_PLAYBACK_FAILED");
|
|
374
426
|
});
|
|
@@ -429,6 +481,8 @@ function createOmniVoiceEngine(options) {
|
|
|
429
481
|
clearTimeout(timer);
|
|
430
482
|
clearTimeout(clearTimer);
|
|
431
483
|
clearTimeout(uploadTimer);
|
|
484
|
+
turn.reset();
|
|
485
|
+
speaking.clear();
|
|
432
486
|
inputQueue = [];
|
|
433
487
|
queuedInputBytes = 0;
|
|
434
488
|
rejectStart?.(/* @__PURE__ */ new Error("Omni connection closed"));
|
|
@@ -17,15 +17,11 @@ export interface SaveWorkflowAuthoringDraftInput {
|
|
|
17
17
|
expectedUpdatedAtMs?: number;
|
|
18
18
|
}
|
|
19
19
|
export declare class WorkflowDraftStore {
|
|
20
|
-
private readonly
|
|
21
|
-
constructor(options?: {
|
|
22
|
-
userDir?: string;
|
|
23
|
-
});
|
|
20
|
+
private readonly state;
|
|
24
21
|
list(workflowName?: string): WorkflowAuthoringDraft[];
|
|
25
22
|
get(id: string): WorkflowAuthoringDraft | null;
|
|
26
23
|
save(input: SaveWorkflowAuthoringDraftInput): WorkflowAuthoringDraft;
|
|
27
24
|
remove(id: string): boolean;
|
|
28
|
-
private readFile;
|
|
29
25
|
}
|
|
30
26
|
export declare class WorkflowDraftConflictError extends Error {
|
|
31
27
|
readonly currentUpdatedAtMs?: number;
|