@xopcai/xopc 0.0.225 → 0.0.228
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-CtTYnku4.js → activity-store-M0nAY5XB.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-dizuqu_4.js → agent-avatar-dicebear-CjGZBs4C.js} +1 -1
- package/dist/gateway/static/root/assets/agents-B0NI4_NI.js +68 -0
- package/dist/gateway/static/root/assets/{api-CLRMz2BT.js → api-BywYxpaS.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-Cnk-DtQh.js → app-management-settings-panel--SjycrXk.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-wP0rogVI.js → appearance-settings-8G-TVUtg.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-2NiqD-YP.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-Cpzsm-DM.js → archive-plugin-7_DXaMTP.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-Bd2OOoEK.js → attachment-load-Bx44zSpz.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-DNqhguyk.js → automations-page-CrKAHqc0.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-Q3g9cf0h.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-Dcma5HdI.js → binary-plugins-DjDwnHAQ.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-D-B8ThwK.js → block-editor-7aMOKoZM.js} +3 -3
- package/dist/gateway/static/root/assets/browser-settings-page-DTwPkmAC.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-BAPZIXrs.js → browser-workflow-inputs-8NC2qDRF.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-DHtaSKEh.js → browser-workflows-page-DVLrWKz_.js} +2 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-YcP4FbN7.js +7 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-zsZQ7im3.js → capability-presets-api-o0y9WgAI.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-AcPjHHia.js +3 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-Cp8iaaXp.js → channel-recipient-api-C5ABr73b.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-Ca94Q1D-.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-38FsOnR0.js +1 -0
- package/dist/gateway/static/root/assets/{chat-terminal-dock-Dr6Rq2ln.js → chat-terminal-dock-BR-_7KC0.js} +2 -2
- package/dist/gateway/static/root/assets/connectors-page-SGxfLTd6.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-BiXrpzmo.js → cron-expression-D8-c-Tkw.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-BPuRtwKt.js → date-picker-kV-Jyl9J.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-BNC_W7wI.js → dependency-picker-CwKcrfGj.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-DzOpt5nI.js → desktop-pet-D9rnchu3.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-BW0brCvH.js → desktop-pet-settings-CTs5WGzk.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-Baml0uTS.js → directory-picker-path-field-CCl0aaDm.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-CBXyKmfS.js → extension-debug-page-Cau40SvC.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BBhcr_SZ.js → extension-page-BsJXdvIL.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-4rwWpN9_.js → extension-settings-page-qWqJyF7-.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-Dg-BlBe4.js → gateway-config-api-BI0SELXm.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-Du0MvK9s.js → gateway-config-swr-BWGjnmDl.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-BOuYZOYe.js → gateway-settings-6ZdOIC7F.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-JbjcHCaN.js → gateway-startup-retry-B_zrtccP.js} +1 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-KBwhXeFD.js +1 -0
- package/dist/gateway/static/root/assets/home-page-BA2M4CLi.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-G2tfPvKP.js → image-generation-api-YKP2me5Z.js} +1 -1
- package/dist/gateway/static/root/assets/index-BX0dz1JK.js +70 -0
- package/dist/gateway/static/root/assets/index-D_hrEKXM.css +2 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-L1Vtxgp9.js → keyboard-shortcuts-settings-kHtpnyEm.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-D2nkn09R.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page--thlkBLS.js → local-apps-page-BCXa0oUa.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-DqJz-cOR.js → locale-store-CXhjfe4q.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-D3sNst0K.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-p55fR4XO.js → management-settings-tHnlfOAQ.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-DwMcRlBR.js → markdown-split-BMLqHHr5.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-DD_PgVue.css → markdown-view-CLzTdVLW.css} +1 -1
- package/dist/gateway/static/root/assets/markdown-view-DvM5PWEH.js +201 -0
- package/dist/gateway/static/root/assets/{media-plugins-O6H3GZn7.js → media-plugins-DybwqTgv.js} +1 -1
- package/dist/gateway/static/root/assets/messages-BMdD0LWk.js +3 -0
- package/dist/gateway/static/root/assets/{notes-api-CrjQbmk1.js → notes-api-BFsOGYkd.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-miO9ig9C.js → notes-page-C24SfF6r.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-CTdZc3ov.js +4 -0
- package/dist/gateway/static/root/assets/{product-open-page-BOu07nXf.js → product-open-page-DBfCVlJq.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-COHaEpbA.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-lMnST7D_.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-Bf_HDLUJ.js → registry-api-BFZrVYfy.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BIRKBvO_.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DthuRqUH.js → runtime-tools-settings-panel-BPEGTip5.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-8W8PhXxa.js → schema-form-Dxlu60Td.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-CATO9G3y.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-Cco_W41x.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-CrsKGYiG.js → settings-form-section-ChXh3Bwk.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-WJtI0AAq.js → settings-loading-skeleton-BCAUqIe2.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-PCjwRF47.js → settings-page-D25W9Okr.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-D65CwlNC.js → setup-status-panel-DsN7Z4Fl.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-BGtvLLeZ.js → share-preview-page-CRFnUaNb.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-CAX0eNaP.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-Doy1gghe.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-C_npyryI.js → skills-page-Cl7jjTK7.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-C46Sd78k.js → skills-page.utils-BiCl4nb5.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-DomTLwki.js → system-settings-panel-BuESR7ZT.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-BRiy8NL3.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-Ce7wq__X.js → theme-store-DOdCjyuw.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-Do9mCRcY.js → use-autosave-Dg1mgJ_l.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-CqoADNKu.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-Bc5p-0tX.js → voice-api-key-field-BDNexlVR.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-BieqsmT1.js → work-discovery-overlay-BHTfeaWL.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DVj8iYvm.js → workflow-run-setup-panel-Cf_w-NZy.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-j0P-uECz.js +5 -0
- package/dist/gateway/static/root/index.html +12 -12
- package/dist/gateway/static/root/notification-sw.js +1 -1
- package/dist/package.js +1 -1
- package/dist/packages/gateway-contract/src/notifications.js +56 -0
- package/dist/packages/gateway-contract/src/turn-outcome.js +114 -0
- package/dist/src/agent/agent-manager.d.ts +3 -1
- package/dist/src/agent/agent-manager.js +22 -5
- package/dist/src/agent/lifecycle/timeout-wrapper.d.ts +1 -0
- package/dist/src/agent/lifecycle/timeout-wrapper.js +7 -6
- package/dist/src/agent/mcp/mcp-transport-config.d.ts +1 -1
- package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
- package/dist/src/agent/memory/understanding/service.js +1 -0
- package/dist/src/agent/memory/understanding/types.d.ts +1 -0
- package/dist/src/agent/orchestration/run-agent-turn-with-timeout.d.ts +2 -2
- package/dist/src/agent/orchestration/run-agent-turn-with-timeout.js +4 -4
- package/dist/src/agent/service.d.ts +2 -0
- package/dist/src/agent/service.js +6 -0
- package/dist/src/agent/skills/index.d.ts +22 -2
- package/dist/src/agent/skills/index.js +74 -32
- package/dist/src/agent/skills/skill-sources.d.ts +0 -1
- package/dist/src/agent/skills/skill-sources.js +1 -11
- package/dist/src/agent/tools/create-share-tool.js +14 -1
- package/dist/src/agent/tools/exec-command.js +3 -3
- package/dist/src/agent/tools/execute-code-tool.js +1 -1
- package/dist/src/agent/tools/executor.js +2 -2
- package/dist/src/agent/tools/image-generate-tool.js +12 -0
- package/dist/src/agent/tools/send-media.js +11 -0
- package/dist/src/agent/tools/xopc-use-tool.js +1 -1
- package/dist/src/cli/command-loaders.js +1 -0
- package/dist/src/cli/command-manifest.js +4 -0
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/cli/commands/history.d.ts +1 -0
- package/dist/src/cli/commands/history.js +50 -0
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/connectors/connected-source-understanding.js +1 -1
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/chat-stream/protocol.d.ts +3 -2
- package/dist/src/gateway/chat-stream/turn-outcome-collector.d.ts +16 -0
- package/dist/src/gateway/chat-stream/turn-outcome-collector.js +111 -0
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/lib/static-ui.js +7 -5
- package/dist/src/gateway/hono/routes/connectors.js +18 -16
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/mobile.js +18 -40
- package/dist/src/gateway/hono/routes/notifications.d.ts +3 -0
- package/dist/src/gateway/hono/routes/notifications.js +45 -0
- package/dist/src/gateway/hono/routes/project-skills.js +30 -2
- package/dist/src/gateway/hono/routes/sessions.js +31 -0
- package/dist/src/gateway/hono/routes/tasks.js +1 -1
- package/dist/src/gateway/hono/routes/voice.js +1 -1
- package/dist/src/gateway/hono/routes/you.js +52 -0
- package/dist/src/gateway/service/agent-runner.js +6 -2
- package/dist/src/gateway/service/run-gateway-agent.js +53 -1
- package/dist/src/gateway/service/sessions-api.d.ts +6 -0
- package/dist/src/gateway/service/sessions-api.js +60 -3
- package/dist/src/gateway/service.d.ts +2 -2
- package/dist/src/gateway/service.js +8 -7
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/history/ctx/exporter.d.ts +14 -0
- package/dist/src/history/ctx/exporter.js +99 -0
- package/dist/src/history/ctx/format.d.ts +25 -0
- package/dist/src/history/ctx/format.js +282 -0
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/knowledge/connected-understanding-pipeline.js +12 -3
- package/dist/src/knowledge/index.d.ts +0 -1
- package/dist/src/knowledge/index.js +1 -2
- package/dist/src/media/session-references.d.ts +6 -0
- package/dist/src/media/session-references.js +24 -3
- package/dist/src/notifications/device-store.d.ts +16 -0
- package/dist/src/notifications/device-store.js +96 -0
- package/dist/src/notifications/planner.d.ts +6 -0
- package/dist/src/notifications/planner.js +156 -0
- package/dist/src/notifications/service.d.ts +18 -0
- package/dist/src/notifications/service.js +184 -0
- package/dist/src/notifications/store.d.ts +53 -0
- package/dist/src/notifications/store.js +184 -0
- package/dist/src/notifications/types.d.ts +29 -0
- package/dist/src/notifications/types.js +14 -0
- package/dist/src/projects/project-skill-service.d.ts +28 -6
- package/dist/src/projects/project-skill-service.js +76 -29
- package/dist/src/session/client-history.d.ts +3 -1
- package/dist/src/session/client-history.js +13 -0
- package/dist/src/session/index.d.ts +1 -1
- package/dist/src/session/manager.d.ts +1 -0
- package/dist/src/session/manager.js +6 -0
- package/dist/src/session/store.d.ts +15 -0
- package/dist/src/session/store.js +58 -0
- package/dist/src/storage/sqlite/index.d.ts +2 -1
- package/dist/src/storage/sqlite/index.js +3 -2
- package/dist/src/storage/sqlite/migrations/135_user_people.sql +59 -0
- package/dist/src/storage/sqlite/migrations/136_product_notifications.sql +79 -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/session-input-repository.d.ts +5 -0
- package/dist/src/storage/sqlite/session-input-repository.js +9 -1
- package/dist/src/storage/sqlite/user-people-repository.d.ts +32 -0
- package/dist/src/storage/sqlite/user-people-repository.js +246 -0
- package/dist/src/tasks/index.js +2 -2
- package/dist/src/tasks/task-application-service.js +42 -6
- package/dist/src/tasks/task-change-events.d.ts +9 -0
- package/dist/src/tasks/task-change-events.js +17 -1
- package/dist/src/tasks/task-outbox-dispatcher.js +5 -1
- package/dist/src/tasks/task-run-dispatcher.js +4 -2
- package/dist/src/tasks/task-run-repository.js +13 -0
- package/dist/src/user-context/relationships/indexer.d.ts +13 -0
- package/dist/src/user-context/relationships/indexer.js +185 -0
- package/dist/src/user-context/relationships/service.d.ts +22 -0
- package/dist/src/user-context/relationships/service.js +50 -0
- package/dist/src/user-context/relationships/types.d.ts +55 -0
- package/dist/src/user-context/relationships/types.js +10 -0
- package/dist/src/user-context/sources/repository.d.ts +1 -1
- package/dist/src/user-context/sources/repository.js +8 -2
- package/dist/src/work-discovery/service.js +1 -1
- package/package.json +2 -2
- package/dist/gateway/static/root/assets/agents-DeEEFZJ4.js +0 -68
- package/dist/gateway/static/root/assets/apps-page-Db5YNHVM.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-CNT05YTb.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-UbDj3LIq.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-CiO152QS.js +0 -7
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-Bc_hRwfL.js +0 -3
- package/dist/gateway/static/root/assets/channels-settings-CFW7zBoT.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-5rNVq7iI.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-DLBr5nre.js +0 -2
- package/dist/gateway/static/root/assets/heartbeat-settings-Dq4YAlSx.js +0 -1
- package/dist/gateway/static/root/assets/home-page-BIXkO0Ck.js +0 -1
- package/dist/gateway/static/root/assets/index-Csccu8sa.js +0 -74
- package/dist/gateway/static/root/assets/index-D3_xSYKd.css +0 -2
- package/dist/gateway/static/root/assets/local-app-workbench-page-D-eacBcO.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-BRCglHvd.js +0 -2
- package/dist/gateway/static/root/assets/markdown-view-CTB9u15e.js +0 -69
- package/dist/gateway/static/root/assets/mermaid-render-BbqDc_LQ.js +0 -134
- package/dist/gateway/static/root/assets/messages-CeydamsI.js +0 -3
- package/dist/gateway/static/root/assets/notes-workbench-_13lmvmF.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-BStRkOQr.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-CY03RxVr.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-B19llkld.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BDA2qbTd.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-BONIDX4v.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-CdzVKrBl.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-CsRWid5h.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-B6YFX7kK.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-CiCQA40E.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-AG04TTuH.js +0 -5
- package/dist/src/knowledge/people-graph.d.ts +0 -25
- package/dist/src/knowledge/people-graph.js +0 -92
- package/dist/src/mobile/notification-service.d.ts +0 -9
- package/dist/src/mobile/notification-service.js +0 -156
- package/dist/src/mobile/notification-store.d.ts +0 -28
- package/dist/src/mobile/notification-store.js +0 -132
- package/dist/src/mobile/notification-types.d.ts +0 -37
- package/dist/src/mobile/notification-types.js +0 -9
|
@@ -60,6 +60,14 @@ function buildDirectSessionMetadata(params) {
|
|
|
60
60
|
}
|
|
61
61
|
function registerSessionsRoutes(authenticated, deps) {
|
|
62
62
|
const { service } = deps;
|
|
63
|
+
authenticated.get("/api/session-runs", (c) => {
|
|
64
|
+
const blocked = ensureGatewayReadyForSessions(c, service, "sessions.list");
|
|
65
|
+
if (blocked) return blocked;
|
|
66
|
+
return c.json({
|
|
67
|
+
ok: true,
|
|
68
|
+
payload: { runs: service.sessions.listActiveRuns() }
|
|
69
|
+
});
|
|
70
|
+
});
|
|
63
71
|
authenticated.get("/api/sidebar/chat-list", async (c) => {
|
|
64
72
|
const blocked = ensureGatewayReadyForSessions(c, service, "sessions.list");
|
|
65
73
|
if (blocked) return blocked;
|
|
@@ -648,6 +656,29 @@ function registerSessionsRoutes(authenticated, deps) {
|
|
|
648
656
|
}, 400);
|
|
649
657
|
}
|
|
650
658
|
});
|
|
659
|
+
authenticated.post("/api/sessions/:key/fork-at-turn", async (c) => {
|
|
660
|
+
const key = c.req.param("key");
|
|
661
|
+
const body = await c.req.json().catch(() => ({}));
|
|
662
|
+
const lastTurnId = typeof body.lastTurnId === "string" ? body.lastTurnId.trim() : "";
|
|
663
|
+
if (!lastTurnId) return c.json({
|
|
664
|
+
ok: false,
|
|
665
|
+
error: "lastTurnId is required"
|
|
666
|
+
}, 400);
|
|
667
|
+
try {
|
|
668
|
+
const result = await service.sessions.forkAtTurn(key, lastTurnId);
|
|
669
|
+
return c.json({
|
|
670
|
+
ok: true,
|
|
671
|
+
...result
|
|
672
|
+
}, 201);
|
|
673
|
+
} catch (err) {
|
|
674
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
675
|
+
const status = errorMessage.startsWith("Session not found:") ? 404 : 409;
|
|
676
|
+
return c.json({
|
|
677
|
+
ok: false,
|
|
678
|
+
error: errorMessage
|
|
679
|
+
}, status);
|
|
680
|
+
}
|
|
681
|
+
});
|
|
651
682
|
authenticated.post("/api/sessions/:key/fork-row", async (c) => {
|
|
652
683
|
const key = c.req.param("key");
|
|
653
684
|
const body = await c.req.json().catch(() => ({}));
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { runSqliteWriteTransaction } from "../../../storage/sqlite/transaction.js";
|
|
2
2
|
import { TaskRepository } from "../../../tasks/task-repository.js";
|
|
3
3
|
import { TaskConversationRepository } from "../../../tasks/task-conversation-repository.js";
|
|
4
|
+
import { enqueueTaskChangedEvent } from "../../../tasks/task-change-events.js";
|
|
4
5
|
import { TaskRunRepository } from "../../../tasks/task-run-repository.js";
|
|
5
6
|
import { TaskReadModelProjector } from "../../../tasks/task-read-model-projector.js";
|
|
6
7
|
import { TaskPhaseSchema } from "../../../../packages/gateway-contract/src/task-lifecycle.js";
|
|
@@ -8,7 +9,6 @@ import { TaskBoardPositionRequestSchema, TaskCommandRequestSchema, TaskContextIn
|
|
|
8
9
|
import { ProjectMonitoringUpdateSchema } from "../../../../packages/gateway-contract/src/project-monitoring.js";
|
|
9
10
|
import { resolveProjectAgentId } from "../../../projects/project-agent.js";
|
|
10
11
|
import { TaskContextRepository } from "../../../tasks/task-context-repository.js";
|
|
11
|
-
import { enqueueTaskChangedEvent } from "../../../tasks/task-change-events.js";
|
|
12
12
|
import { TaskDependencyError, TaskDependencyService } from "../../../tasks/task-dependency-service.js";
|
|
13
13
|
import { TaskApplicationService } from "../../../tasks/task-application-service.js";
|
|
14
14
|
import { ProjectMonitoringService } from "../../../tasks/project-monitoring-service.js";
|
|
@@ -14,8 +14,8 @@ import "../../../voice/stt/index.js";
|
|
|
14
14
|
import { listSttProvidersForApi } from "../../../voice/stt/list-providers.js";
|
|
15
15
|
import "../../../voice/tts/index.js";
|
|
16
16
|
import { createGatewayRouteLogger } from "../lib/route-logger.js";
|
|
17
|
-
import { listTtsProvidersForApi } from "../../../voice/tts/list-providers.js";
|
|
18
17
|
import { listLocalVoiceModelStatuses, removeLocalVoiceModel, startLocalVoiceModelInstall } from "../../../voice/local/model-manager.js";
|
|
18
|
+
import { listTtsProvidersForApi } from "../../../voice/tts/list-providers.js";
|
|
19
19
|
//#region src/gateway/hono/routes/voice.ts
|
|
20
20
|
init_providers();
|
|
21
21
|
const log = createGatewayRouteLogger("Voice");
|
|
@@ -7,6 +7,8 @@ import { listUserFocuses, updateUserFocus } from "../../../user-context/sources/
|
|
|
7
7
|
import { canonicalUnderstandingKey, findDuplicateUnderstanding } from "../../../user-context/understanding.js";
|
|
8
8
|
import { listContextObjects } from "../../../user-context/context-objects.js";
|
|
9
9
|
import { repairExtractedContext } from "../../../user-context/extraction/repair.js";
|
|
10
|
+
import { getUserRelationship, listUserRelationships, mergeUserRelationships, patchUserRelationship } from "../../../user-context/relationships/service.js";
|
|
11
|
+
import { USER_PERSON_KINDS } from "../../../user-context/relationships/types.js";
|
|
10
12
|
import { userInfo } from "node:os";
|
|
11
13
|
//#region src/gateway/hono/routes/you.ts
|
|
12
14
|
const UNDERSTANDING_KIND_SET = new Set(UNDERSTANDING_KINDS);
|
|
@@ -42,6 +44,7 @@ const CONTEXT_OBJECT_VIEWS = new Set([
|
|
|
42
44
|
"review",
|
|
43
45
|
"history"
|
|
44
46
|
]);
|
|
47
|
+
const USER_PERSON_KIND_SET = new Set(USER_PERSON_KINDS);
|
|
45
48
|
function asRecord(value) {
|
|
46
49
|
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
47
50
|
}
|
|
@@ -99,6 +102,55 @@ function registerYouRoutes(authenticated, deps) {
|
|
|
99
102
|
rules: listCollaborationRules(),
|
|
100
103
|
consolidation: { lastRun: listContextConsolidationRuns(1)[0] ?? null }
|
|
101
104
|
}));
|
|
105
|
+
authenticated.get("/api/you/relationships", (c) => {
|
|
106
|
+
const kind = c.req.query("kind");
|
|
107
|
+
if (kind && !USER_PERSON_KIND_SET.has(kind)) return c.json({ error: "Invalid relationship kind" }, 400);
|
|
108
|
+
const requestedLimit = Number(c.req.query("limit") ?? "30");
|
|
109
|
+
if (!Number.isInteger(requestedLimit) || requestedLimit < 1 || requestedLimit > 100) return c.json({ error: "limit must be an integer from 1 to 100" }, 400);
|
|
110
|
+
const cursor = c.req.query("cursor");
|
|
111
|
+
if (cursor && !/^\d+$/.test(cursor)) return c.json({ error: "Invalid cursor" }, 400);
|
|
112
|
+
return c.json(listUserRelationships({
|
|
113
|
+
query: c.req.query("q") ?? "",
|
|
114
|
+
...kind ? { kind } : {},
|
|
115
|
+
...c.req.query("source") ? { sourceInstanceId: c.req.query("source") } : {},
|
|
116
|
+
includeHidden: c.req.query("includeHidden") === "true",
|
|
117
|
+
hiddenOnly: c.req.query("hidden") === "true",
|
|
118
|
+
...cursor ? { cursor } : {},
|
|
119
|
+
limit: requestedLimit
|
|
120
|
+
}));
|
|
121
|
+
});
|
|
122
|
+
authenticated.get("/api/you/relationships/:id", (c) => {
|
|
123
|
+
const person = getUserRelationship(c.req.param("id"));
|
|
124
|
+
return person ? c.json({ person }) : c.json({ error: "Relationship not found" }, 404);
|
|
125
|
+
});
|
|
126
|
+
authenticated.patch("/api/you/relationships/:id", write, async (c) => {
|
|
127
|
+
const body = await readBody(c);
|
|
128
|
+
if (!body) return c.json({ error: "Invalid JSON" }, 400);
|
|
129
|
+
const patch = {};
|
|
130
|
+
if (body.displayName !== void 0) {
|
|
131
|
+
if (body.displayName !== null && (typeof body.displayName !== "string" || body.displayName.trim().length > 160)) return c.json({ error: "displayName must be null or a string of at most 160 characters" }, 400);
|
|
132
|
+
patch.displayName = typeof body.displayName === "string" && body.displayName.trim() ? body.displayName.trim() : null;
|
|
133
|
+
}
|
|
134
|
+
if (body.kind !== void 0) {
|
|
135
|
+
if (body.kind !== null && !USER_PERSON_KIND_SET.has(body.kind)) return c.json({ error: "Invalid relationship kind" }, 400);
|
|
136
|
+
patch.kind = body.kind;
|
|
137
|
+
}
|
|
138
|
+
if (body.hidden !== void 0) {
|
|
139
|
+
if (typeof body.hidden !== "boolean") return c.json({ error: "hidden must be a boolean" }, 400);
|
|
140
|
+
patch.hidden = body.hidden;
|
|
141
|
+
}
|
|
142
|
+
if (!Object.keys(patch).length) return c.json({ error: "No relationship fields provided" }, 400);
|
|
143
|
+
const person = patchUserRelationship(c.req.param("id"), patch);
|
|
144
|
+
return person ? c.json({ person }) : c.json({ error: "Relationship not found" }, 404);
|
|
145
|
+
});
|
|
146
|
+
authenticated.post("/api/you/relationships/merge", write, async (c) => {
|
|
147
|
+
const body = await readBody(c);
|
|
148
|
+
const sourcePersonId = nonEmptyString(body?.sourcePersonId, 200);
|
|
149
|
+
const targetPersonId = nonEmptyString(body?.targetPersonId, 200);
|
|
150
|
+
if (!sourcePersonId || !targetPersonId || sourcePersonId === targetPersonId) return c.json({ error: "Distinct sourcePersonId and targetPersonId are required" }, 400);
|
|
151
|
+
const person = mergeUserRelationships(sourcePersonId, targetPersonId);
|
|
152
|
+
return person ? c.json({ person }) : c.json({ error: "Relationship not found" }, 404);
|
|
153
|
+
});
|
|
102
154
|
authenticated.get("/api/you/context-objects", (c) => {
|
|
103
155
|
const view = c.req.query("view") ?? "current";
|
|
104
156
|
if (!CONTEXT_OBJECT_VIEWS.has(view)) return c.json({ error: "Invalid context object view" }, 400);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
+
import { listActiveSessionInputRuns } from "../../storage/sqlite/session-input-repository.js";
|
|
4
|
+
import "../../storage/sqlite/index.js";
|
|
3
5
|
import { ClarifyBridge } from "../clarify-bridge.js";
|
|
4
6
|
import { runGatewayAgent } from "./run-gateway-agent.js";
|
|
5
7
|
import { fitSourceContextsToBudget } from "../../agent/source-context/budget.js";
|
|
@@ -75,10 +77,12 @@ var GatewayAgentRunner = class {
|
|
|
75
77
|
return this.activeWebchatRunBySession.has(sessionKey);
|
|
76
78
|
}
|
|
77
79
|
getActiveRunId(sessionKey) {
|
|
78
|
-
return this.activeWebchatRunBySession.get(sessionKey);
|
|
80
|
+
return this.activeWebchatRunBySession.get(sessionKey) ?? this.inputs.snapshot(sessionKey).activeRunId;
|
|
79
81
|
}
|
|
80
82
|
listActiveRuns() {
|
|
81
|
-
|
|
83
|
+
const runs = new Map(listActiveSessionInputRuns().map(({ sessionKey, runId }) => [sessionKey, runId]));
|
|
84
|
+
for (const [sessionKey, runId] of this.activeWebchatRunBySession) runs.set(sessionKey, runId);
|
|
85
|
+
return [...runs].map(([sessionKey, runId]) => ({
|
|
82
86
|
sessionKey,
|
|
83
87
|
runId
|
|
84
88
|
}));
|
|
@@ -13,6 +13,7 @@ import { ChatStreamMapper } from "../chat-stream/mapper.js";
|
|
|
13
13
|
import { resolveWebchatSessionKey } from "../resolve-webchat-session-key.js";
|
|
14
14
|
import { recordExplicitRelationshipFollowUp } from "../../user-context/relationship-continuity.js";
|
|
15
15
|
import { coalesceThinkingDeltas } from "../chat-stream/thinking-delta-coalescer.js";
|
|
16
|
+
import { TurnOutcomeCollector } from "../chat-stream/turn-outcome-collector.js";
|
|
16
17
|
import crypto from "crypto";
|
|
17
18
|
//#region src/gateway/service/run-gateway-agent.ts
|
|
18
19
|
init_logger();
|
|
@@ -34,9 +35,11 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
|
|
|
34
35
|
let taskRunStatus = "failed";
|
|
35
36
|
let taskRunSummary = "Agent run ended unexpectedly";
|
|
36
37
|
let terminalStatus = "error";
|
|
38
|
+
let runTopicCompleted = false;
|
|
37
39
|
let webchatSessionKey;
|
|
38
40
|
let webchatSessionId;
|
|
39
41
|
let webchatMetadata;
|
|
42
|
+
let outcomeEnvironment = "workspace";
|
|
40
43
|
if (channel === "webchat") {
|
|
41
44
|
const resolved = resolveWebchatSessionKey({ sessionKey: chatId });
|
|
42
45
|
if (resolved.ok === false) throw new Error(resolved.error);
|
|
@@ -65,6 +68,8 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
|
|
|
65
68
|
channel,
|
|
66
69
|
metadata: webchatMetadata
|
|
67
70
|
});
|
|
71
|
+
if (/remote/i.test(executionContext.strategy ?? "")) outcomeEnvironment = "remote_runtime";
|
|
72
|
+
else if (/worktree/i.test(executionContext.strategy ?? "")) outcomeEnvironment = "worktree";
|
|
68
73
|
taskRun = TaskRunCoordinator.start({
|
|
69
74
|
runId,
|
|
70
75
|
context: executionContext,
|
|
@@ -76,8 +81,11 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
|
|
|
76
81
|
sessionKey: streamSessionKey,
|
|
77
82
|
channel
|
|
78
83
|
});
|
|
84
|
+
const outcomeCollector = new TurnOutcomeCollector(runId, outcomeEnvironment);
|
|
85
|
+
let outcomeFinalized = false;
|
|
79
86
|
let registeredActiveWebchatRun = false;
|
|
80
87
|
const captureTaskEvent = (event) => {
|
|
88
|
+
outcomeCollector.capture(event);
|
|
81
89
|
if (event.type === "task_plan_updated") {
|
|
82
90
|
taskRun?.capturePlan(event.payload.items);
|
|
83
91
|
return;
|
|
@@ -102,6 +110,30 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
|
|
|
102
110
|
yield event;
|
|
103
111
|
}
|
|
104
112
|
};
|
|
113
|
+
const finalizeOutcome = async (status, summary) => {
|
|
114
|
+
if (outcomeFinalized) return [];
|
|
115
|
+
outcomeFinalized = true;
|
|
116
|
+
const outcome = outcomeCollector.finalize(status, summary);
|
|
117
|
+
if (webchatSessionKey) try {
|
|
118
|
+
await sessionIndex.appendTranscriptCustomEntry(webchatSessionKey, {
|
|
119
|
+
customType: "turn_outcome",
|
|
120
|
+
data: outcome
|
|
121
|
+
});
|
|
122
|
+
} catch (err) {
|
|
123
|
+
log.warn({
|
|
124
|
+
err,
|
|
125
|
+
runId,
|
|
126
|
+
sessionKey: webchatSessionKey
|
|
127
|
+
}, `Turn outcome persistence failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
128
|
+
}
|
|
129
|
+
return [{
|
|
130
|
+
type: "turn_outcome",
|
|
131
|
+
runId,
|
|
132
|
+
sessionKey: streamSessionKey,
|
|
133
|
+
timestamp: Date.now(),
|
|
134
|
+
payload: outcome
|
|
135
|
+
}];
|
|
136
|
+
};
|
|
105
137
|
try {
|
|
106
138
|
yield* emitAndYield(mapper.start());
|
|
107
139
|
if (channel === "webchat" && webchatSessionKey) {
|
|
@@ -141,8 +173,10 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
|
|
|
141
173
|
taskRunStatus = mergedSignal.aborted ? "cancelled" : "succeeded";
|
|
142
174
|
terminalStatus = endStatus;
|
|
143
175
|
taskRunSummary = endSummary;
|
|
176
|
+
yield* emitAndYield(await finalizeOutcome(endStatus, endSummary));
|
|
144
177
|
yield* emitAndYield(mapper.end(endStatus, endSummary));
|
|
145
178
|
completeRealtimeTopic(`run:${runId}`);
|
|
179
|
+
runTopicCompleted = true;
|
|
146
180
|
return {
|
|
147
181
|
status: mergedSignal.aborted ? "aborted" : "ok",
|
|
148
182
|
summary: mergedSignal.aborted ? "Interrupted" : "Message processed successfully"
|
|
@@ -163,8 +197,10 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
|
|
|
163
197
|
taskRunSummary = em;
|
|
164
198
|
const errorContent = formatAgentRunErrorForClient(streamError);
|
|
165
199
|
yield* emitAndYield(mapper.error(errorContent));
|
|
200
|
+
yield* emitAndYield(await finalizeOutcome("error", streamError));
|
|
166
201
|
yield* emitAndYield(mapper.end("error", streamError));
|
|
167
202
|
completeRealtimeTopic(`run:${runId}`);
|
|
203
|
+
runTopicCompleted = true;
|
|
168
204
|
return {
|
|
169
205
|
status: "error",
|
|
170
206
|
summary: streamError
|
|
@@ -247,6 +283,7 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
|
|
|
247
283
|
presentation: "answer"
|
|
248
284
|
}
|
|
249
285
|
}]);
|
|
286
|
+
yield* emitAndYield(await finalizeOutcome("success", "Message processed"));
|
|
250
287
|
yield* emitAndYield(mapper.end("success", "Message processed"));
|
|
251
288
|
taskRunStatus = "succeeded";
|
|
252
289
|
taskRunSummary = "Message processed";
|
|
@@ -257,6 +294,7 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
|
|
|
257
294
|
} catch (error) {
|
|
258
295
|
const em = error instanceof Error ? error.message : String(error);
|
|
259
296
|
taskRunStatus = "failed";
|
|
297
|
+
terminalStatus = "error";
|
|
260
298
|
taskRunSummary = em;
|
|
261
299
|
log.error({
|
|
262
300
|
err: error,
|
|
@@ -266,6 +304,17 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
|
|
|
266
304
|
channel,
|
|
267
305
|
chatId
|
|
268
306
|
}, `Agent run failed: ${em}`);
|
|
307
|
+
if (channel === "webchat" && !runTopicCompleted) {
|
|
308
|
+
yield* emitAndYield(mapper.error(formatAgentRunErrorForClient(em)));
|
|
309
|
+
yield* emitAndYield(await finalizeOutcome("error", em));
|
|
310
|
+
yield* emitAndYield(mapper.end("error", em));
|
|
311
|
+
completeRealtimeTopic(`run:${runId}`);
|
|
312
|
+
runTopicCompleted = true;
|
|
313
|
+
return {
|
|
314
|
+
status: "error",
|
|
315
|
+
summary: em
|
|
316
|
+
};
|
|
317
|
+
}
|
|
269
318
|
throw error;
|
|
270
319
|
} finally {
|
|
271
320
|
if (taskRun) try {
|
|
@@ -292,7 +341,10 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
|
|
|
292
341
|
sessionKey: webchatSessionKey,
|
|
293
342
|
status: terminalStatus,
|
|
294
343
|
completedAtMs: Date.now(),
|
|
295
|
-
|
|
344
|
+
target: {
|
|
345
|
+
kind: "chat",
|
|
346
|
+
sessionKey: webchatSessionKey
|
|
347
|
+
},
|
|
296
348
|
source: "webchat",
|
|
297
349
|
...metaAfter?.name?.trim() ? { sessionTitle: metaAfter.name.trim().slice(0, 100) } : {}
|
|
298
350
|
});
|
|
@@ -159,6 +159,12 @@ export declare class GatewaySessionsApi {
|
|
|
159
159
|
sessionKey: string;
|
|
160
160
|
rowCount: number;
|
|
161
161
|
}>;
|
|
162
|
+
forkAtTurn(sourceKey: string, lastTurnId: string): Promise<{
|
|
163
|
+
sessionKey: string;
|
|
164
|
+
rowCount: number;
|
|
165
|
+
lastTurnId: string;
|
|
166
|
+
session: NonNullable<Awaited<ReturnType<GatewaySessionsApi['getSession']>>>;
|
|
167
|
+
}>;
|
|
162
168
|
btwQuery(sessionKey: string, question: string): Promise<{
|
|
163
169
|
text: string;
|
|
164
170
|
error?: string;
|
|
@@ -1,11 +1,28 @@
|
|
|
1
|
+
import { init_agent_session_key, resolveAgentIdFromSessionKey } from "../../routing/agent-session-key.js";
|
|
2
|
+
import { buildSessionKey, init_session_key } from "../../routing/session-key.js";
|
|
1
3
|
import { retireSessionMcpRuntimeForSessionKey } from "../../agent/mcp/bundle-mcp-runtime.js";
|
|
2
4
|
import "../../agent/mcp/bundle-mcp-tools.js";
|
|
3
5
|
import { buildSessionTimeline } from "../../session/transcript-outline.js";
|
|
4
6
|
import { transcriptRowsToClientHistory } from "../../session/client-history.js";
|
|
5
|
-
import {
|
|
7
|
+
import { collectMediaUrisFromValues, deleteMediaUris } from "../../media/session-references.js";
|
|
6
8
|
import { getDistinctSessionChatIds } from "./session-chat-ids.js";
|
|
7
9
|
import { performSessionReset } from "../session-reset-service.js";
|
|
10
|
+
import { randomUUID } from "node:crypto";
|
|
8
11
|
//#region src/gateway/service/sessions-api.ts
|
|
12
|
+
/**
|
|
13
|
+
* GatewaySessionsApi — session CRUD, search, compaction, tag/pin/archive,
|
|
14
|
+
* stats, and chat-id grouping for the gateway REST surface.
|
|
15
|
+
*
|
|
16
|
+
* Twenty-four methods, previously sitting on `GatewayService` as a mix of
|
|
17
|
+
* one-line `sessionIndex.*` delegations and small composite operations (e.g.
|
|
18
|
+
* `restoreCheckpoint` also evicts the in-memory agent, `runCompaction` also
|
|
19
|
+
* appends a transcript context entry). Centralising them here lets routes
|
|
20
|
+
* depend on the narrow `GatewaySessionsApi` surface instead of the full
|
|
21
|
+
* `GatewayService`, and keeps the gateway composition root focused on
|
|
22
|
+
* lifecycle + wiring.
|
|
23
|
+
*/
|
|
24
|
+
init_session_key();
|
|
25
|
+
init_agent_session_key();
|
|
9
26
|
function clampWindowSpan(value, fallback) {
|
|
10
27
|
const parsed = Math.trunc(value ?? fallback);
|
|
11
28
|
if (!Number.isFinite(parsed)) return fallback;
|
|
@@ -117,10 +134,10 @@ var GatewaySessionsApi = class {
|
|
|
117
134
|
return result;
|
|
118
135
|
}
|
|
119
136
|
async delete(key) {
|
|
120
|
-
const
|
|
137
|
+
const transcriptRows = await this.opts.sessionIndex.getStore().loadTranscriptHistoryRows(key).catch(() => []);
|
|
121
138
|
const result = await this.opts.sessionIndex.deleteSession(key);
|
|
122
139
|
if (result) {
|
|
123
|
-
await deleteMediaUris(
|
|
140
|
+
await deleteMediaUris(collectMediaUrisFromValues(transcriptRows));
|
|
124
141
|
this.opts.getAgentService().evictSessionAgent(key);
|
|
125
142
|
await retireSessionMcpRuntimeForSessionKey({
|
|
126
143
|
sessionKey: key,
|
|
@@ -185,6 +202,46 @@ var GatewaySessionsApi = class {
|
|
|
185
202
|
forkRows(key, targetKey, options = {}) {
|
|
186
203
|
return this.opts.sessionIndex.forkSessionRows(key, targetKey, options);
|
|
187
204
|
}
|
|
205
|
+
async forkAtTurn(sourceKey, lastTurnId) {
|
|
206
|
+
const source = await this.opts.sessionIndex.getSessionMetadata(sourceKey);
|
|
207
|
+
if (!source) throw new Error(`Session not found: ${sourceKey}`);
|
|
208
|
+
if (source.sessionType !== "chat") throw new Error("Only chat sessions can be forked");
|
|
209
|
+
const normalizedTurnId = lastTurnId.trim();
|
|
210
|
+
if (!normalizedTurnId) throw new Error("lastTurnId is required");
|
|
211
|
+
if (this.opts.getActiveWebchatRunId(sourceKey)?.trim() === normalizedTurnId) throw new Error("Cannot fork a turn that is still running");
|
|
212
|
+
const agentId = source.routing?.agentId?.trim() || resolveAgentIdFromSessionKey(sourceKey);
|
|
213
|
+
const chatId = `chat_${randomUUID()}`;
|
|
214
|
+
const targetKey = buildSessionKey({
|
|
215
|
+
agentId,
|
|
216
|
+
source: "webchat",
|
|
217
|
+
accountId: "default",
|
|
218
|
+
peerKind: "direct",
|
|
219
|
+
peerId: chatId
|
|
220
|
+
});
|
|
221
|
+
const result = await this.opts.sessionIndex.forkSessionAtTurn(sourceKey, {
|
|
222
|
+
targetKey,
|
|
223
|
+
lastTurnId: normalizedTurnId,
|
|
224
|
+
targetMetadata: {
|
|
225
|
+
sourceChannel: "webchat",
|
|
226
|
+
sourceChatId: `default:direct:${chatId}`,
|
|
227
|
+
sessionType: "chat",
|
|
228
|
+
routing: {
|
|
229
|
+
agentId,
|
|
230
|
+
source: "webchat",
|
|
231
|
+
accountId: "default",
|
|
232
|
+
peerKind: "direct",
|
|
233
|
+
peerId: chatId
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
const session = await this.getSession(result.sessionKey);
|
|
238
|
+
if (!session) throw new Error(`Forked session not found: ${result.sessionKey}`);
|
|
239
|
+
return {
|
|
240
|
+
...result,
|
|
241
|
+
lastTurnId: normalizedTurnId,
|
|
242
|
+
session
|
|
243
|
+
};
|
|
244
|
+
}
|
|
188
245
|
btwQuery(sessionKey, question) {
|
|
189
246
|
return this.opts.getAgentService().sessionInspector.btwQuery(sessionKey, question);
|
|
190
247
|
}
|
|
@@ -68,7 +68,7 @@ export declare class GatewayService {
|
|
|
68
68
|
private taskRunDispatcher;
|
|
69
69
|
private taskRunDispatchTimer;
|
|
70
70
|
private managedComposioEventPoller?;
|
|
71
|
-
private
|
|
71
|
+
private notificationService;
|
|
72
72
|
private connectorSupervisor;
|
|
73
73
|
private connectorLearningCoordinator;
|
|
74
74
|
private connectedSourceChangePublisher;
|
|
@@ -120,7 +120,7 @@ export declare class GatewayService {
|
|
|
120
120
|
private ensureAgentService;
|
|
121
121
|
private ensureHeartbeatService;
|
|
122
122
|
private createTaskRunDispatcher;
|
|
123
|
-
private
|
|
123
|
+
private createNotificationService;
|
|
124
124
|
dispatchTaskRuns(): void;
|
|
125
125
|
ensureTaskConversation(taskId: string, options?: {
|
|
126
126
|
runId?: string;
|
|
@@ -92,7 +92,7 @@ import { auditGatewayConfig } from "./security/audit.js";
|
|
|
92
92
|
import { getXopcCloudCatalogCoordinator } from "../providers/xopc-cloud-catalog-coordinator.js";
|
|
93
93
|
import { ModelCatalogSyncService } from "../providers/model-catalog-sync-service.js";
|
|
94
94
|
import { runBootstrapMigrationsSync } from "../migrations/runner.js";
|
|
95
|
-
import {
|
|
95
|
+
import { NotificationService } from "../notifications/service.js";
|
|
96
96
|
import { LocalAppService } from "../local-apps/service.js";
|
|
97
97
|
import "../local-apps/index.js";
|
|
98
98
|
import { createRuntimeBrowserRecipeService } from "../browser/recipes/runtime-service.js";
|
|
@@ -185,7 +185,7 @@ var GatewayService = class {
|
|
|
185
185
|
taskRunDispatcher = null;
|
|
186
186
|
taskRunDispatchTimer = null;
|
|
187
187
|
managedComposioEventPoller;
|
|
188
|
-
|
|
188
|
+
notificationService = null;
|
|
189
189
|
connectorSupervisor = null;
|
|
190
190
|
connectorLearningCoordinator = null;
|
|
191
191
|
connectedSourceChangePublisher = null;
|
|
@@ -239,7 +239,6 @@ var GatewayService = class {
|
|
|
239
239
|
this.proactiveTemporalWorker = new ProactiveTemporalWorker(this.proactive);
|
|
240
240
|
this.proactiveInboxWorker = new ProactiveInboxWorker({ deliver: async ({ inboxItem }) => {
|
|
241
241
|
this.emit("proactive.inbox.created", inboxItem);
|
|
242
|
-
await this.createMobileNotificationService().deliverGatewayEvent("proactive.inbox.created", inboxItem);
|
|
243
242
|
} });
|
|
244
243
|
let bootstrapConfigChanged = initializeVoiceDefaults(this.config, inferProductLanguageFromEnvironment());
|
|
245
244
|
const starterResult = ensureStarterAgentsInitialized(this.config);
|
|
@@ -574,9 +573,9 @@ var GatewayService = class {
|
|
|
574
573
|
});
|
|
575
574
|
return this.taskRunDispatcher;
|
|
576
575
|
}
|
|
577
|
-
|
|
578
|
-
if (!this.
|
|
579
|
-
return this.
|
|
576
|
+
createNotificationService() {
|
|
577
|
+
if (!this.notificationService) this.notificationService = new NotificationService({ publish: (type, payload) => this.realtime.broker.publish("gateway", type, payload) });
|
|
578
|
+
return this.notificationService;
|
|
580
579
|
}
|
|
581
580
|
dispatchTaskRuns() {
|
|
582
581
|
new TaskSignalService().tick();
|
|
@@ -798,6 +797,7 @@ var GatewayService = class {
|
|
|
798
797
|
});
|
|
799
798
|
log.debug("Starting gateway service...");
|
|
800
799
|
openXopcDatabase();
|
|
800
|
+
this.createNotificationService().start();
|
|
801
801
|
this.startTime = Date.now();
|
|
802
802
|
this.running = true;
|
|
803
803
|
this.taskRunDispatchTimer = setInterval(() => this.dispatchTaskRuns(), 1e3);
|
|
@@ -1103,6 +1103,7 @@ var GatewayService = class {
|
|
|
1103
1103
|
await this.discussionLiveWorker.stop();
|
|
1104
1104
|
this.proactiveTemporalWorker.stop();
|
|
1105
1105
|
await this.proactiveInboxWorker.stop();
|
|
1106
|
+
this.notificationService?.stop();
|
|
1106
1107
|
if (this.taskRunDispatchTimer) {
|
|
1107
1108
|
clearInterval(this.taskRunDispatchTimer);
|
|
1108
1109
|
this.taskRunDispatchTimer = null;
|
|
@@ -1543,7 +1544,7 @@ var GatewayService = class {
|
|
|
1543
1544
|
}
|
|
1544
1545
|
emit(type, payload) {
|
|
1545
1546
|
this.realtime.broker.publish("gateway", type, payload);
|
|
1546
|
-
this.
|
|
1547
|
+
this.createNotificationService().handleGatewayEvent(type, payload);
|
|
1547
1548
|
}
|
|
1548
1549
|
handleAutomationRunCompleted(run) {
|
|
1549
1550
|
this.automationService.get(run.automationId).then((automation) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_ACK_MAX_CHARS, HEARTBEAT_OK, NO_REPLY, shouldSilence, stripHeartbeatToken } from "./tokens.js";
|
|
2
|
-
import { appendCronEventLines } from "./event-prompt.js";
|
|
3
2
|
import { isWithinActiveHours } from "./active-hours.js";
|
|
4
3
|
import { isHeartbeatContentEmpty } from "./content-check.js";
|
|
4
|
+
import { appendCronEventLines } from "./event-prompt.js";
|
|
5
5
|
import { createHeartbeatWake } from "./wake.js";
|
|
6
6
|
export { DEFAULT_ACK_MAX_CHARS, HEARTBEAT_OK, NO_REPLY, appendCronEventLines, createHeartbeatWake, isHeartbeatContentEmpty, isWithinActiveHours, shouldSilence, stripHeartbeatToken };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
export interface CtxHistoryExportResult {
|
|
3
|
+
outputDir: string;
|
|
4
|
+
historyPath: string;
|
|
5
|
+
manifestPath: string;
|
|
6
|
+
sessionCount: number;
|
|
7
|
+
eventCount: number;
|
|
8
|
+
changed: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function resolveDefaultCtxHistoryExportDir(env?: NodeJS.ProcessEnv): string;
|
|
11
|
+
export declare function exportCtxHistory(db: DatabaseSync, options?: {
|
|
12
|
+
outputDir?: string;
|
|
13
|
+
env?: NodeJS.ProcessEnv;
|
|
14
|
+
}): Promise<CtxHistoryExportResult>;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { init_paths_state, resolveStateDir } from "../../config/paths-state.js";
|
|
2
|
+
import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
|
|
3
|
+
import { buildCtxHistoryJsonl, buildCtxPluginManifest } from "./format.js";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { mkdir, readFile } from "node:fs/promises";
|
|
6
|
+
//#region src/history/ctx/exporter.ts
|
|
7
|
+
init_paths_state();
|
|
8
|
+
init_write_file_atomic();
|
|
9
|
+
function readSnapshot(db) {
|
|
10
|
+
db.exec("BEGIN");
|
|
11
|
+
try {
|
|
12
|
+
const transcripts = db.prepare(`SELECT
|
|
13
|
+
t.session_id,
|
|
14
|
+
t.status,
|
|
15
|
+
t.created_at,
|
|
16
|
+
t.archived_at,
|
|
17
|
+
t.cwd,
|
|
18
|
+
s.agent_id,
|
|
19
|
+
s.session_type
|
|
20
|
+
FROM transcripts t
|
|
21
|
+
JOIN sessions s ON s.session_key = t.session_key
|
|
22
|
+
WHERE t.status = 'active' OR t.archive_reason IN ('reset', 'stale')
|
|
23
|
+
ORDER BY t.created_at ASC, t.session_id ASC`).all();
|
|
24
|
+
const entries = db.prepare(`SELECT e.entry_id, e.session_id, e.seq, e.payload_json, e.created_at
|
|
25
|
+
FROM transcript_entries e
|
|
26
|
+
JOIN transcripts t ON t.session_id = e.session_id
|
|
27
|
+
JOIN sessions s ON s.session_key = t.session_key
|
|
28
|
+
WHERE t.status = 'active' OR t.archive_reason IN ('reset', 'stale')
|
|
29
|
+
ORDER BY t.created_at ASC, t.session_id ASC, e.seq ASC, e.entry_id ASC`).all();
|
|
30
|
+
db.exec("COMMIT");
|
|
31
|
+
const entriesBySession = /* @__PURE__ */ new Map();
|
|
32
|
+
for (const entry of entries) {
|
|
33
|
+
const bucket = entriesBySession.get(entry.session_id) ?? [];
|
|
34
|
+
bucket.push({
|
|
35
|
+
entryId: entry.entry_id,
|
|
36
|
+
seq: entry.seq,
|
|
37
|
+
createdAt: entry.created_at,
|
|
38
|
+
payloadJson: entry.payload_json
|
|
39
|
+
});
|
|
40
|
+
entriesBySession.set(entry.session_id, bucket);
|
|
41
|
+
}
|
|
42
|
+
return transcripts.map((transcript) => ({
|
|
43
|
+
sessionId: transcript.session_id,
|
|
44
|
+
status: transcript.status,
|
|
45
|
+
createdAt: transcript.created_at,
|
|
46
|
+
archivedAt: transcript.archived_at,
|
|
47
|
+
cwd: transcript.cwd,
|
|
48
|
+
agentId: transcript.agent_id,
|
|
49
|
+
sessionType: transcript.session_type,
|
|
50
|
+
entries: entriesBySession.get(transcript.session_id) ?? []
|
|
51
|
+
}));
|
|
52
|
+
} catch (error) {
|
|
53
|
+
try {
|
|
54
|
+
db.exec("ROLLBACK");
|
|
55
|
+
} catch {}
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function writeIfChanged(path, contents) {
|
|
60
|
+
let existing = null;
|
|
61
|
+
try {
|
|
62
|
+
existing = await readFile(path, "utf8");
|
|
63
|
+
} catch (error) {
|
|
64
|
+
if (error.code !== "ENOENT") throw error;
|
|
65
|
+
}
|
|
66
|
+
if (existing === contents) return false;
|
|
67
|
+
await writeTextAtomic(path, contents, {
|
|
68
|
+
mode: 384,
|
|
69
|
+
ensureDirMode: 448
|
|
70
|
+
});
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
function resolveDefaultCtxHistoryExportDir(env = process.env) {
|
|
74
|
+
return join(resolveStateDir(env), "exports", "ctx");
|
|
75
|
+
}
|
|
76
|
+
async function exportCtxHistory(db, options = {}) {
|
|
77
|
+
const outputDir = resolve(options.outputDir ?? resolveDefaultCtxHistoryExportDir(options.env));
|
|
78
|
+
const historyPath = join(outputDir, "history.jsonl");
|
|
79
|
+
const manifestPath = join(outputDir, "ctx-history-plugin.json");
|
|
80
|
+
const sessions = readSnapshot(db);
|
|
81
|
+
const history = buildCtxHistoryJsonl(sessions);
|
|
82
|
+
const manifest = buildCtxPluginManifest();
|
|
83
|
+
await mkdir(outputDir, {
|
|
84
|
+
recursive: true,
|
|
85
|
+
mode: 448
|
|
86
|
+
});
|
|
87
|
+
const historyChanged = await writeIfChanged(historyPath, history.contents);
|
|
88
|
+
const manifestChanged = await writeIfChanged(manifestPath, manifest);
|
|
89
|
+
return {
|
|
90
|
+
outputDir,
|
|
91
|
+
historyPath,
|
|
92
|
+
manifestPath,
|
|
93
|
+
sessionCount: sessions.length,
|
|
94
|
+
eventCount: history.eventCount,
|
|
95
|
+
changed: historyChanged || manifestChanged
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
//#endregion
|
|
99
|
+
export { exportCtxHistory, resolveDefaultCtxHistoryExportDir };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare const CTX_HISTORY_SCHEMA_VERSION = "ctx-history-jsonl-v2";
|
|
2
|
+
export declare const CTX_PROVIDER_KEY = "xopc";
|
|
3
|
+
export declare const CTX_SOURCE_ID = "default";
|
|
4
|
+
export declare const CTX_SOURCE_FORMAT = "xopc-session-history-v1";
|
|
5
|
+
export interface XopcHistorySession {
|
|
6
|
+
sessionId: string;
|
|
7
|
+
status: string;
|
|
8
|
+
createdAt: number;
|
|
9
|
+
archivedAt: number | null;
|
|
10
|
+
cwd: string;
|
|
11
|
+
agentId: string;
|
|
12
|
+
sessionType: string | null;
|
|
13
|
+
entries: XopcHistoryEntry[];
|
|
14
|
+
}
|
|
15
|
+
export interface XopcHistoryEntry {
|
|
16
|
+
entryId: string;
|
|
17
|
+
seq: number;
|
|
18
|
+
createdAt: number;
|
|
19
|
+
payloadJson: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function buildCtxHistoryJsonl(sessions: XopcHistorySession[]): {
|
|
22
|
+
contents: string;
|
|
23
|
+
eventCount: number;
|
|
24
|
+
};
|
|
25
|
+
export declare function buildCtxPluginManifest(): string;
|