@xopcai/xopc 0.0.112 → 0.0.114
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/icons/icon-128.png +0 -0
- package/dist/browser-ext/icons/icon-16.png +0 -0
- package/dist/browser-ext/icons/icon-32.png +0 -0
- package/dist/browser-ext/icons/icon-48.png +0 -0
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/delivery-to.d.ts +3 -3
- package/dist/extensions/weixin/src/delivery-to.js.map +1 -1
- package/dist/gateway/static/root/apple-touch-icon.png +0 -0
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-EhRp-ZMa.js → agent-avatar-dicebear-Fp-p7bP1.js} +1 -1
- package/dist/gateway/static/root/assets/agent-browser-settings-page-CWh7trjd.js +6 -0
- package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-kC8OuLoj.js +1 -0
- package/dist/gateway/static/root/assets/agents-DJWG26Si.js +71 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-BIy7KEsM.js → app-management-settings-panel-v24i25Oj.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DGQG8NwA.js → appearance-settings-ycbdJRuZ.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-0V3DXZ7J.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-uuQPupqx.js → archive-plugin-CJzSADJo.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DBkv0cAv.js → attachment-load-BTAB4zGS.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-DxxN_VAR.js → binary-plugins-DXR1-mct.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CwnUlRmO.js → block-editor-CzQri9h2.js} +44 -44
- package/dist/gateway/static/root/assets/channels-settings-CIKOkYdO.js +1 -0
- package/dist/gateway/static/root/assets/{config-api-BD-NcD5d.js → config-api-DRqjEvAx.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-settings-ClrDS5jH.js +2 -0
- package/dist/gateway/static/root/assets/{cron-api-C5DoipZA.js → cron-api-BXaZXv1o.js} +1 -1
- package/dist/gateway/static/root/assets/cron-page-Chi_4u4P.js +3 -0
- package/dist/gateway/static/root/assets/dreaming-settings-B0_rs2tj.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-BDHA9o_e.js → extension-debug-page-DSkqMYo7.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DmDLVSPE.js → extension-page-h2dGDbMN.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-1124aHw_.js → extension-settings-page-hN99RhOi.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-DOe56Wmy.js → fetch-D9QqUtzZ.js} +1 -1
- package/dist/gateway/static/root/assets/{format-interval-label-tsMSvBSR.js → format-interval-label-D6E687rG.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-CsD4FC9D.js → gateway-config-api-CLt_SKTC.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-HQ8FBhY2.js → gateway-settings-1PDi4lI0.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-C1zg7pH3.js → gateway-startup-retry-N7Z_sz7p.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-D_wwXL-t.js +1 -0
- package/dist/gateway/static/root/assets/goals-page-DZ2toZ8y.js +2 -0
- package/dist/gateway/static/root/assets/{goals-settings-B5nI6lgz.js → goals-settings-LFlwtIKE.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-CIv42nJD.js → heartbeat-config-api-DGPadTw-.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-DFcVuJ3M.js → heartbeat-settings-BHHAs8ZX.js} +1 -1
- package/dist/gateway/static/root/assets/index-DefIdW9q.js +122 -0
- package/dist/gateway/static/root/assets/index-DzmWBkq-.css +1 -0
- package/dist/gateway/static/root/assets/{interval-presets-DGP3S7OB.js → interval-presets-CEklPQ_r.js} +1 -1
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-fETaDYQP.js → keyboard-shortcuts-settings-Ce_aQ8Iv.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-j_D2QTuQ.js +2 -0
- package/dist/gateway/static/root/assets/{markdown-split-CgeBJMOD.js → markdown-split-BMz3xPXO.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-C30GzlV2.js → media-plugins-BalOSoz9.js} +1 -1
- package/dist/gateway/static/root/assets/messages-BN_WiUg0.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-CMH_TmZz.js +2 -0
- package/dist/gateway/static/root/assets/note-detail-page-O18BrQPq.js +2 -0
- package/dist/gateway/static/root/assets/{note-image-lightbox-t1g0qZYh.js → note-image-lightbox-C5D1Q5mY.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-B_ZYCmY9.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-DeWp9x5g.js → preview-open-alternatives-CYFR5U9l.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CwKgWixY.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-BOaAOJI3.js → save-bar-controls-BQ79Z5IP.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-BLWLKqgw.js → schedule-field-Bgk6Emue.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-plqRFYT8.js → schema-form-DzS36TMa.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-C4fcD-7B.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-Ad2OJ86w.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-BP5zRrDI.js → settings-collapsible-section-CdjFnSAy.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-Bv8MZplG.js → settings-form-section-DZLy_exu.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-D2BMY5wo.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-aWwxl_E1.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-4OX1YCgp.js → share-preview-page-_qRDr4g_.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-DUE83uIf.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-mWKJcrog.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-0Sx1Q58n.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-CGy4f_s2.js → system-settings-panel-hqaBF5aG.js} +1 -1
- package/dist/gateway/static/root/assets/use-agent-defaults-form-zbVIQLOA.js +1 -0
- package/dist/gateway/static/root/assets/{use-channel-catalog-CjGHnDvN.js → use-channel-catalog-CbXq97rT.js} +1 -1
- package/dist/gateway/static/root/assets/{use-settings-tab-guard-BMMFa0oA.js → use-settings-tab-guard-DwS3drWK.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-D6HR0hR2.js +1 -0
- package/dist/gateway/static/root/assets/{voice-player-store-D5vzWwls.js → voice-player-store-DSuOd9zy.js} +1 -1
- package/dist/gateway/static/root/assets/workflow-page.utils-C0Uq3xyq.js +1 -0
- package/dist/gateway/static/root/assets/workflows-page-DW0fmWhQ.js +18 -0
- package/dist/gateway/static/root/favicon-16x16.png +0 -0
- package/dist/gateway/static/root/favicon-32x32.png +0 -0
- package/dist/gateway/static/root/favicon-icon.svg +1 -0
- package/dist/gateway/static/root/favicon.ico +0 -0
- package/dist/gateway/static/root/favicon.png +0 -0
- package/dist/gateway/static/root/favicon.svg +24 -17
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/gateway/static/root/logo-dark.svg +23 -15
- package/dist/gateway/static/root/logo.svg +23 -16
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +8 -0
- package/dist/src/agent/agent-manager.js +57 -22
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/bootstrap/project-agents-context.d.ts +2 -0
- package/dist/src/agent/bootstrap/project-agents-context.js +32 -0
- package/dist/src/agent/bootstrap/project-agents-context.js.map +1 -0
- package/dist/src/agent/goals/persistent-goal-service.js +2 -4
- package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
- package/dist/src/agent/inbound/inbound-loop.js +5 -1
- package/dist/src/agent/inbound/inbound-loop.js.map +1 -1
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +2 -2
- package/dist/src/agent/inbound/turn-dispatcher.js +2 -2
- package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.d.ts +27 -0
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +49 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +78 -3
- package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-types.d.ts +19 -0
- package/dist/src/agent/service/btw-query.js +11 -3
- package/dist/src/agent/service/btw-query.js.map +1 -1
- package/dist/src/agent/service/parse-outbound-session-key.js +13 -8
- package/dist/src/agent/service/parse-outbound-session-key.js.map +1 -1
- package/dist/src/agent/service/process-direct-one-shot.d.ts +2 -2
- package/dist/src/agent/service/process-direct-one-shot.js +1 -1
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.d.ts +2 -2
- package/dist/src/agent/service/process-direct-streaming.js +10 -5
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service.d.ts +1 -1
- package/dist/src/agent/service.js +9 -5
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +5 -0
- package/dist/src/agent/skills/filesystem-watcher.js +4 -3
- package/dist/src/agent/skills/filesystem-watcher.js.map +1 -1
- package/dist/src/agent/skills/index.js +2 -1
- package/dist/src/agent/skills/index.js.map +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +2 -1
- package/dist/src/agent/skills/skill-manage-ops.js.map +1 -1
- package/dist/src/agent/skills/types.d.ts +1 -1
- package/dist/src/agent/skills/watcher.js +2 -5
- package/dist/src/agent/skills/watcher.js.map +1 -1
- package/dist/src/agent/skills/workspace-skills-dir.d.ts +1 -0
- package/dist/src/agent/skills/workspace-skills-dir.js +11 -0
- package/dist/src/agent/skills/workspace-skills-dir.js.map +1 -0
- package/dist/src/agent/tool-manuals/browser.d.ts +1 -1
- package/dist/src/agent/tool-manuals/browser.js +62 -3
- package/dist/src/agent/tool-manuals/browser.js.map +1 -1
- package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +4 -1
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js +13 -4
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
- package/dist/src/agent/tools/browser/tool/schemas.d.ts +0 -2
- package/dist/src/agent/tools/browser/tool/schemas.js +1 -2
- package/dist/src/agent/tools/browser/tool/schemas.js.map +1 -1
- package/dist/src/agent/tools/factory.js +1 -10
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js.map +1 -1
- package/dist/src/agent/workflow/subagent-runner.js +18 -1
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
- package/dist/src/ai-assist/text-assist.d.ts +3 -0
- package/dist/src/ai-assist/text-assist.js +25 -7
- package/dist/src/ai-assist/text-assist.js.map +1 -1
- package/dist/src/browser/actions/extension-registry-bridge.js +91 -7
- package/dist/src/browser/actions/extension-registry-bridge.js.map +1 -1
- package/dist/src/browser/actions/registry.js +383 -7
- package/dist/src/browser/actions/registry.js.map +1 -1
- package/dist/src/browser/actions/types.d.ts +11 -3
- package/dist/src/browser/index.js +2 -2
- package/dist/src/browser/pipeline/output.d.ts +18 -16
- package/dist/src/browser/pipeline/output.js +28 -20
- package/dist/src/browser/pipeline/output.js.map +1 -1
- package/dist/src/browser/pipeline/runner.d.ts +7 -14
- package/dist/src/browser/pipeline/runner.js +349 -102
- package/dist/src/browser/pipeline/runner.js.map +1 -1
- package/dist/src/browser/pipeline/schema.d.ts +1 -0
- package/dist/src/browser/pipeline/schema.js +35 -58
- package/dist/src/browser/pipeline/schema.js.map +1 -1
- package/dist/src/browser/pipeline/source.d.ts +2 -0
- package/dist/src/browser/pipeline/source.js +10 -1
- package/dist/src/browser/pipeline/source.js.map +1 -1
- package/dist/src/browser/pipeline/template.d.ts +10 -2
- package/dist/src/browser/pipeline/template.js +50 -8
- package/dist/src/browser/pipeline/template.js.map +1 -1
- package/dist/src/channels/plugins/types.adapters.d.ts +2 -2
- package/dist/src/chat-commands/builtins/config.js +3 -5
- package/dist/src/chat-commands/builtins/config.js.map +1 -1
- package/dist/src/chat-commands/context.d.ts +5 -0
- package/dist/src/chat-commands/context.js +18 -9
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/chat-commands/index.d.ts +1 -1
- package/dist/src/chat-commands/index.js +2 -2
- package/dist/src/chat-commands/index.js.map +1 -1
- package/dist/src/chat-commands/processor.js +22 -21
- package/dist/src/chat-commands/processor.js.map +1 -1
- package/dist/src/chat-commands/session-key.d.ts +3 -15
- package/dist/src/chat-commands/session-key.js +3 -49
- package/dist/src/chat-commands/session-key.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +4 -0
- package/dist/src/cli/commands/browser-cli-helpers.js +11 -5
- package/dist/src/cli/commands/browser-cli-helpers.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +8 -8
- package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
- package/dist/src/config/rules.js +5 -0
- package/dist/src/config/rules.js.map +1 -1
- package/dist/src/connectors/builtin-catalog.js +180 -1
- package/dist/src/connectors/builtin-catalog.js.map +1 -1
- package/dist/src/connectors/health.js +18 -9
- package/dist/src/connectors/health.js.map +1 -1
- package/dist/src/connectors/types.d.ts +19 -0
- package/dist/src/connectors/usage.js +12 -4
- package/dist/src/connectors/usage.js.map +1 -1
- package/dist/src/cron/executor.js.map +1 -1
- package/dist/src/cron/types.d.ts +2 -2
- package/dist/src/extensions/types/tui.d.ts +2 -0
- package/dist/src/gateway/heartbeat/service.js +13 -1
- package/dist/src/gateway/heartbeat/service.js.map +1 -1
- package/dist/src/gateway/hono/app.js +13 -4
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/oauth-async.js +1 -1
- package/dist/src/gateway/hono/routes/agent-stream.js +6 -6
- package/dist/src/gateway/hono/routes/agent-stream.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +1 -1
- package/dist/src/gateway/hono/routes/config-patch/gateway.js +6 -0
- package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/goals.js +16 -3
- package/dist/src/gateway/hono/routes/goals.js.map +1 -1
- package/dist/src/gateway/hono/routes/logs.js +1 -0
- package/dist/src/gateway/hono/routes/logs.js.map +1 -1
- package/dist/src/gateway/hono/routes/mcp.js +27 -8
- package/dist/src/gateway/hono/routes/mcp.js.map +1 -1
- package/dist/src/gateway/hono/routes/notes.js +14 -2
- package/dist/src/gateway/hono/routes/notes.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +62 -4
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +3 -66
- package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
- package/dist/src/gateway/hono/sse.d.ts +2 -2
- package/dist/src/gateway/hono/sse.js +7 -15
- package/dist/src/gateway/hono/sse.js.map +1 -1
- package/dist/src/gateway/resolve-webchat-session-key.d.ts +2 -6
- package/dist/src/gateway/resolve-webchat-session-key.js +5 -31
- package/dist/src/gateway/resolve-webchat-session-key.js.map +1 -1
- package/dist/src/gateway/service/agent-runner.d.ts +2 -3
- package/dist/src/gateway/service/agent-runner.js +9 -22
- package/dist/src/gateway/service/agent-runner.js.map +1 -1
- package/dist/src/gateway/service/run-gateway-agent.js +9 -7
- package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
- package/dist/src/gateway/service/sessions-api.d.ts +9 -0
- package/dist/src/gateway/service/sessions-api.js +11 -0
- package/dist/src/gateway/service/sessions-api.js.map +1 -1
- package/dist/src/gateway/service.d.ts +1 -1
- package/dist/src/gateway/service.js +19 -5
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-file-search.d.ts +9 -0
- package/dist/src/gateway/workspace-file-search.js +76 -0
- package/dist/src/gateway/workspace-file-search.js.map +1 -0
- package/dist/src/goals/goal-notifications.d.ts +2 -0
- package/dist/src/goals/goal-notifications.js +16 -11
- package/dist/src/goals/goal-notifications.js.map +1 -1
- package/dist/src/goals/goal-service.js +1 -6
- package/dist/src/goals/goal-service.js.map +1 -1
- package/dist/src/project-trust/trust-store.js +2 -0
- package/dist/src/project-trust/trust-store.js.map +1 -1
- package/dist/src/session/index.d.ts +1 -1
- package/dist/src/session/index.js +2 -2
- package/dist/src/session/init-session-turn.js +6 -9
- package/dist/src/session/init-session-turn.js.map +1 -1
- package/dist/src/session/manager.d.ts +5 -1
- package/dist/src/session/manager.js +5 -2
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/reset-type.d.ts +0 -2
- package/dist/src/session/reset-type.js +3 -9
- package/dist/src/session/reset-type.js.map +1 -1
- package/dist/src/session/resolve-session.js +9 -20
- package/dist/src/session/resolve-session.js.map +1 -1
- package/dist/src/session/store-reader.d.ts +5 -0
- package/dist/src/session/store-reader.js +1 -0
- package/dist/src/session/store.d.ts +11 -3
- package/dist/src/session/store.js +29 -13
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/types.d.ts +2 -4
- package/dist/src/session/types.js.map +1 -1
- package/dist/src/storage/sqlite/index.d.ts +2 -2
- package/dist/src/storage/sqlite/index.js +3 -3
- package/dist/src/storage/sqlite/migrations/010_session_id_identity.sql +30 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +2 -2
- package/dist/src/storage/sqlite/migrations/runner.js +4 -4
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +2 -2
- package/dist/src/storage/sqlite/row-mappers.d.ts +4 -4
- package/dist/src/storage/sqlite/row-mappers.js +11 -14
- package/dist/src/storage/sqlite/row-mappers.js.map +1 -1
- package/dist/src/storage/sqlite/schema.js +3 -3
- package/dist/src/storage/sqlite/schema.js.map +1 -1
- package/dist/src/storage/sqlite/schema.sql +37 -10
- package/dist/src/storage/sqlite/session-metadata.d.ts +2 -7
- package/dist/src/storage/sqlite/session-metadata.js +18 -72
- package/dist/src/storage/sqlite/session-metadata.js.map +1 -1
- package/dist/src/storage/sqlite/session-repository.d.ts +6 -5
- package/dist/src/storage/sqlite/session-repository.js +34 -40
- package/dist/src/storage/sqlite/session-repository.js.map +1 -1
- package/dist/src/storage/sqlite/transcript-repository.d.ts +2 -2
- package/dist/src/storage/sqlite/transcript-repository.js +52 -52
- package/dist/src/storage/sqlite/transcript-repository.js.map +1 -1
- package/dist/src/tui/backends/embedded-backend.d.ts +11 -4
- package/dist/src/tui/backends/embedded-backend.js +27 -1
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +4 -1
- package/dist/src/tui/backends/gateway-sse-backend.js +21 -2
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/extension-host/autocomplete.js +13 -10
- package/dist/src/tui/extension-host/autocomplete.js.map +1 -1
- package/dist/src/tui/extension-host/runtime.d.ts +7 -0
- package/dist/src/tui/extension-host/runtime.js +6 -4
- package/dist/src/tui/extension-host/runtime.js.map +1 -1
- package/dist/src/tui/tui-backend.d.ts +9 -0
- package/dist/src/tui/tui-commands.js +85 -6
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-file-autocomplete.d.ts +5 -0
- package/dist/src/tui/tui-file-autocomplete.js +26 -0
- package/dist/src/tui/tui-file-autocomplete.js.map +1 -0
- package/dist/src/tui/tui-picker-overlay.js +1 -1
- package/dist/src/tui/tui.js +29 -11
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/utils/logger/context.d.ts +2 -2
- package/dist/src/utils/logger/context.js +2 -1
- package/dist/src/utils/logger/context.js.map +1 -1
- package/dist/src/utils/logger/log-store.js +1 -0
- package/dist/src/utils/logger/log-store.js.map +1 -1
- package/dist/src/utils/logger/pino-record.js +3 -0
- package/dist/src/utils/logger/pino-record.js.map +1 -1
- package/dist/src/utils/logger/types.d.ts +5 -0
- package/dist/src/utils/logger/types.js.map +1 -1
- package/dist/src/workflows/service/workflow-session-bridge.js +13 -1
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agent-browser-settings-page-H4foVCiS.js +0 -6
- package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-DDNw2oNU.js +0 -1
- package/dist/gateway/static/root/assets/agents-E_X2kzS1.js +0 -71
- package/dist/gateway/static/root/assets/apps-page-BZLvInLr.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BHvUKlzw.js +0 -1
- package/dist/gateway/static/root/assets/connectors-settings-VBzXcEXL.js +0 -2
- package/dist/gateway/static/root/assets/cron-page-BLTpdm34.js +0 -3
- package/dist/gateway/static/root/assets/dreaming-settings-DSVhXTPq.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-BG3Onph0.js +0 -1
- package/dist/gateway/static/root/assets/goals-page-DgeKn8zL.js +0 -2
- package/dist/gateway/static/root/assets/index-5A_ZaABy.css +0 -1
- package/dist/gateway/static/root/assets/index-BTmbp2AU.js +0 -121
- package/dist/gateway/static/root/assets/logs-page-B1-b27lK.js +0 -2
- package/dist/gateway/static/root/assets/messages-BUUfPaZ9.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-DPcTS1-u.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-xeGb4owe.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-C_TdnKBe.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BtkPmJIN.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-DOUjxzJm.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-qK_bnTrw.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-DmDfE1ww.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-BEFwNcIZ.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-CbKmJZot.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-YdtnUHtK.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-DwW1IzQ0.js +0 -2
- package/dist/gateway/static/root/assets/use-agent-defaults-form-BMuMvzl_.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-DnRbhMNq.js +0 -1
- package/dist/gateway/static/root/assets/workflow-page.utils-tjGpRVnw.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-DqqHKGj2.js +0 -18
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
-
import { buildSessionKey, init_session_key, parseSessionKey } from "../../routing/session-key.js";
|
|
4
|
-
import { getDefaultAgentId, init_resolve_route } from "../../routing/resolve-route.js";
|
|
5
3
|
import { AgentRunRelay } from "../agent-run-relay.js";
|
|
6
4
|
import { ClarifyBridge } from "../clarify-bridge.js";
|
|
7
5
|
import { runGatewayAgent } from "./run-gateway-agent.js";
|
|
8
6
|
//#region src/gateway/service/agent-runner.ts
|
|
9
|
-
init_session_key();
|
|
10
|
-
init_resolve_route();
|
|
11
7
|
init_logger();
|
|
12
8
|
const log = createLogger("Gateway:AgentRunner");
|
|
13
9
|
var GatewayAgentRunner = class {
|
|
@@ -80,23 +76,14 @@ var GatewayAgentRunner = class {
|
|
|
80
76
|
}
|
|
81
77
|
/**
|
|
82
78
|
* Queue steering text for an active webchat run (`Agent.steer` /
|
|
83
|
-
* tool-boundary injection).
|
|
84
|
-
* (`sessionKey` or legacy peer id).
|
|
79
|
+
* tool-boundary injection). The caller must pass the session key.
|
|
85
80
|
*/
|
|
86
|
-
async steerWebchatAgent(
|
|
81
|
+
async steerWebchatAgent(sessionKey, message) {
|
|
87
82
|
const trimmed = message.trim();
|
|
88
83
|
if (!trimmed) return {
|
|
89
84
|
ok: false,
|
|
90
85
|
code: "BAD_REQUEST"
|
|
91
86
|
};
|
|
92
|
-
const cfg = this.opts.getConfig();
|
|
93
|
-
const sessionKey = parseSessionKey(chatId) ? chatId : buildSessionKey({
|
|
94
|
-
agentId: getDefaultAgentId(cfg),
|
|
95
|
-
source: "webchat",
|
|
96
|
-
accountId: "default",
|
|
97
|
-
peerKind: "direct",
|
|
98
|
-
peerId: chatId
|
|
99
|
-
});
|
|
100
87
|
if (!this.activeWebchatRunBySession.has(sessionKey)) return {
|
|
101
88
|
ok: false,
|
|
102
89
|
code: "NO_ACTIVE_RUN"
|
|
@@ -142,11 +129,11 @@ var GatewayAgentRunner = class {
|
|
|
142
129
|
* `turnDispatcher.enqueueWebchatSseEvent`. We take it as a callback so the
|
|
143
130
|
* runner does not import AgentService statically.
|
|
144
131
|
*/
|
|
145
|
-
requestClarification(opts) {
|
|
132
|
+
async requestClarification(opts) {
|
|
146
133
|
const { sessionKey, request, publishSseFor } = opts;
|
|
147
134
|
const runId = this.activeWebchatRunBySession.get(sessionKey);
|
|
148
135
|
const publishSse = runId ? publishSseFor(runId) : void 0;
|
|
149
|
-
const deliver =
|
|
136
|
+
const deliver = ((await this.opts.sessionIndex.getSessionMetadata(sessionKey).catch(() => null))?.routing)?.source === "telegram" ? async (ctx) => {
|
|
150
137
|
await this.deliverTelegramClarify(ctx);
|
|
151
138
|
} : void 0;
|
|
152
139
|
if (!runId && !deliver) return Promise.reject(/* @__PURE__ */ new Error("Clarify is not available for this session (use webchat, Telegram, or CLI)"));
|
|
@@ -160,8 +147,8 @@ var GatewayAgentRunner = class {
|
|
|
160
147
|
});
|
|
161
148
|
}
|
|
162
149
|
async deliverTelegramClarify(ctx) {
|
|
163
|
-
const
|
|
164
|
-
if (!
|
|
150
|
+
const routing = (await this.opts.sessionIndex.getSessionMetadata(ctx.sessionKey).catch(() => null))?.routing;
|
|
151
|
+
if (!routing || routing.source !== "telegram") return;
|
|
165
152
|
let body = ctx.request.question;
|
|
166
153
|
if (ctx.request.default) body += `\n\nDefault if unsure: ${ctx.request.default}`;
|
|
167
154
|
const choices = ctx.request.choices;
|
|
@@ -172,11 +159,11 @@ var GatewayAgentRunner = class {
|
|
|
172
159
|
if (!buttonRows) body += "\n\nReply with your answer in this chat.";
|
|
173
160
|
await this.opts.getChannelManager().send({
|
|
174
161
|
channel: "telegram",
|
|
175
|
-
chat_id:
|
|
162
|
+
chat_id: routing.peerId,
|
|
176
163
|
content: body,
|
|
177
164
|
metadata: {
|
|
178
|
-
accountId:
|
|
179
|
-
...
|
|
165
|
+
accountId: routing.accountId,
|
|
166
|
+
...routing.threadId ? { threadId: routing.threadId } : {}
|
|
180
167
|
},
|
|
181
168
|
buttons: buttonRows
|
|
182
169
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-runner.js","names":[],"sources":["../../../../src/gateway/service/agent-runner.ts"],"sourcesContent":["/**\n * GatewayAgentRunner — webchat agent invocation and the surrounding control\n * surface (abort, steer, clarify-bridge plumbing, scheduled continuations).\n *\n * Was 200 lines of `GatewayService` covering seven concerns that all hung off\n * the same handful of fields (`activeWebchatRunBySession`, `runAbortControllers`,\n * `clarifyBridge`, `runRelay`):\n *\n * - `runAgent(message, channel, chatId, ...)` — wraps {@link runGatewayAgent}\n * - `abortAgentRun(runId)` — POST /api/agent/abort + cleanup\n * - `steerWebchatAgent(chatId, message)` — Agent.steer queue at tool boundary\n * - `submitClarifyResponse(requestId, answer)` — UI answers a `clarify` call\n * - `enqueueWebchatPersistentGoalKickoff(sessionKey, goalText)` — initial\n * `/goal` kickoff posts the goal text as the next user turn\n * - `drainScheduledWebchatContinuation(sk, msg)` — background continuation\n * (extension scheduler + persistent-goal flow)\n * - `clarifyForSession({ sessionKey, request })` — clarify-bridge dispatch\n * used by `gatewayClarify.requestClarification` in AgentService\n *\n * Owns the two state maps (`activeWebchatRunBySession`, `runAbortControllers`)\n * directly so peer coordinators (sessions-api, marketplace, config) cannot\n * accidentally mutate them.\n */\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport type { AgentService } from '../../agent/service.js';\nimport type { ChannelManager } from '../../channels/manager.js';\nimport type { SessionIndex } from '../../session/index.js';\nimport { AgentRunRelay, type RelayEvent } from '../agent-run-relay.js';\nimport { ClarifyBridge, type ClarifyBridgeRequest } from '../clarify-bridge.js';\nimport { buildSessionKey, parseSessionKey } from '../../routing/session-key.js';\nimport { getDefaultAgentId } from '../../routing/resolve-route.js';\nimport { runGatewayAgent } from './run-gateway-agent.js';\nimport { createLogger } from '../../utils/logger.js';\n\nconst log = createLogger('Gateway:AgentRunner');\n\nexport interface GatewayAgentRunnerOptions {\n bus: MessageBus;\n sessionIndex: SessionIndex;\n /** Resolved lazily — the runner is constructed before AgentService exists. */\n getAgentService: () => AgentService;\n getChannelManager: () => ChannelManager;\n getConfig: () => Config;\n /** SSE emit (re-used so `runAgent` events broadcast to subscribers). */\n emit: (type: string, payload: unknown) => void;\n}\n\nexport class GatewayAgentRunner {\n private readonly opts: GatewayAgentRunnerOptions;\n readonly runRelay = new AgentRunRelay();\n /** Per-run abort for webchat (POST /api/agent/abort or client disconnect). */\n private readonly runAbortControllers = new Map<string, AbortController>();\n private readonly clarifyBridge = new ClarifyBridge();\n /** Maps webchat session key → active `runId` for `clarify` tool routing. */\n private readonly activeWebchatRunBySession = new Map<string, string>();\n\n constructor(opts: GatewayAgentRunnerOptions) {\n this.opts = opts;\n }\n\n // ── Read-only accessors (so peers don't get a Map ref) ────────────────\n\n /** True when a webchat agent run is currently in-flight for `sessionKey`. */\n hasActiveRun(sessionKey: string): boolean {\n return this.activeWebchatRunBySession.has(sessionKey);\n }\n\n getActiveRunId(sessionKey: string): string | undefined {\n return this.activeWebchatRunBySession.get(sessionKey);\n }\n\n getClarifyBridge(): ClarifyBridge {\n return this.clarifyBridge;\n }\n\n /** Called from `GatewayService.stop()` so the bridge gets cleaned up. */\n disposeClarifyBridge(): void {\n this.clarifyBridge.dispose();\n }\n\n // ── runAgent (webchat HTTP POST) ──────────────────────────────────────\n\n async *runAgent(\n message: string,\n channel: string,\n chatId: string,\n attachments?: Array<{\n type: string;\n mimeType?: string;\n data?: string;\n name?: string;\n size?: number;\n }>,\n thinking?: string,\n runOptions?: { signal?: AbortSignal; clientCreatedAtMs?: number },\n ): AsyncGenerator<\n { type: string; [key: string]: unknown },\n { status: string; summary: string },\n unknown\n > {\n const iter = runGatewayAgent(\n {\n config: this.opts.getConfig(),\n agentService: this.opts.getAgentService(),\n bus: this.opts.bus,\n runRelay: this.runRelay,\n runAbortControllers: this.runAbortControllers,\n activeWebchatRunBySession: this.activeWebchatRunBySession,\n sessionIndex: this.opts.sessionIndex,\n emit: this.opts.emit,\n },\n message,\n channel,\n chatId,\n attachments,\n thinking,\n runOptions,\n );\n\n let step = await iter.next();\n while (!step.done) {\n yield step.value as unknown as { type: string; [key: string]: unknown };\n step = await iter.next();\n }\n return step.value;\n }\n\n /** Abort an in-flight webchat agent run (matches `runId` from SSE `run_start`). */\n abortAgentRun(runId: string): boolean {\n this.clarifyBridge.cancelForRun(runId);\n const keysToMark: string[] = [];\n for (const [sk, id] of this.activeWebchatRunBySession) {\n if (id === runId) {\n keysToMark.push(sk);\n }\n }\n for (const sk of keysToMark) {\n this.activeWebchatRunBySession.delete(sk);\n }\n const relaySk = this.runRelay.getSessionKey(runId);\n if (relaySk && !keysToMark.includes(relaySk)) {\n keysToMark.push(relaySk);\n }\n const c = this.runAbortControllers.get(runId);\n if (!c) {\n return false;\n }\n const cutoffTs = Date.now();\n for (const sk of keysToMark) {\n void this.opts.sessionIndex\n .updateSessionMetadata(sk, { abortCutoffTimestamp: cutoffTs })\n .catch(() => {});\n void this.opts.sessionIndex\n .appendTranscriptContextEntry(sk, {\n text: 'Webchat agent run aborted',\n data: { runId, abortCutoffTimestamp: cutoffTs },\n })\n .catch(() => {});\n }\n c.abort();\n for (const sk of keysToMark) {\n void import('../../agent/embedded/runs.js').then(({ abortEmbeddedRun }) =>\n abortEmbeddedRun(sk),\n );\n }\n return true;\n }\n\n /**\n * Queue steering text for an active webchat run (`Agent.steer` /\n * tool-boundary injection). `chatId` is the same as `POST /api/agent` body\n * (`sessionKey` or legacy peer id).\n */\n async steerWebchatAgent(\n chatId: string,\n message: string,\n ): Promise<\n { ok: true } | { ok: false; code: 'BAD_REQUEST' | 'NO_ACTIVE_RUN' | 'STEER_FAILED' }\n > {\n const trimmed = message.trim();\n if (!trimmed) {\n return { ok: false, code: 'BAD_REQUEST' };\n }\n const cfg = this.opts.getConfig();\n const parsedKey = parseSessionKey(chatId);\n const sessionKey = parsedKey\n ? chatId\n : buildSessionKey({\n agentId: getDefaultAgentId(cfg),\n source: 'webchat',\n accountId: 'default',\n peerKind: 'direct',\n peerId: chatId,\n });\n if (!this.activeWebchatRunBySession.has(sessionKey)) {\n return { ok: false, code: 'NO_ACTIVE_RUN' };\n }\n const steered = await this.opts\n .getAgentService()\n .turnDispatcher.steerWebchatSession(sessionKey, trimmed);\n if (!steered) {\n return { ok: false, code: 'STEER_FAILED' };\n }\n return { ok: true };\n }\n\n /** Deliver a user's answer to a pending `clarify` tool call. */\n submitClarifyResponse(requestId: string, answer: string): boolean {\n return this.clarifyBridge.handleResponse(requestId, answer);\n }\n\n /** Hermes-style: after HTTP sets a goal, enqueue the goal text as the next user turn. */\n enqueueWebchatPersistentGoalKickoff(sessionKey: string, goalText: string): void {\n queueMicrotask(() => {\n void this.drainScheduledWebchatContinuation(sessionKey, goalText);\n });\n }\n\n /** Same execution path as scheduled continuation, but lets callers observe failures. */\n async runScheduledWebchatContinuation(sessionKey: string, message: string): Promise<void> {\n const gen = this.runAgent(message, 'webchat', sessionKey, undefined, undefined, {\n clientCreatedAtMs: Date.now(),\n });\n for await (const _ of gen) {\n // Relay + `agent.stream` broadcast; UI attaches via pending runId + resume.\n }\n }\n\n /** Background drain for extension-initiated webchat turns (`scheduleWebchatContinuation`). */\n async drainScheduledWebchatContinuation(sessionKey: string, message: string): Promise<void> {\n try {\n await this.runScheduledWebchatContinuation(sessionKey, message);\n } catch (err) {\n log.warn({ err, sessionKey }, 'Scheduled webchat continuation failed');\n }\n }\n\n // ── Clarify dispatch (called from AgentService.gatewayClarify) ────────\n\n /**\n * Resolve clarify-bridge config for `sessionKey`: who delivers the question\n * (webchat SSE, Telegram message, or both), then start the bridge request.\n * Rejects when neither path is available (e.g. CLI without webchat or TG).\n *\n * `publishSseFor(runId)` is the bridge into AgentService's\n * `turnDispatcher.enqueueWebchatSseEvent`. We take it as a callback so the\n * runner does not import AgentService statically.\n */\n requestClarification(opts: {\n sessionKey: string;\n request: ClarifyBridgeRequest;\n publishSseFor: (runId: string) => (e: RelayEvent) => void;\n }): Promise<string> {\n const { sessionKey, request, publishSseFor } = opts;\n const runId = this.activeWebchatRunBySession.get(sessionKey);\n const publishSse = runId ? publishSseFor(runId) : undefined;\n const parsed = parseSessionKey(sessionKey);\n const deliver =\n parsed?.source === 'telegram'\n ? async (ctx: {\n sessionKey: string;\n requestId: string;\n request: ClarifyBridgeRequest;\n }) => {\n await this.deliverTelegramClarify(ctx);\n }\n : undefined;\n if (!runId && !deliver) {\n return Promise.reject(\n new Error('Clarify is not available for this session (use webchat, Telegram, or CLI)'),\n );\n }\n return this.clarifyBridge.startRequest({\n sessionKey,\n runId,\n relay: this.runRelay,\n publishSse,\n request,\n deliver,\n });\n }\n\n private async deliverTelegramClarify(ctx: {\n sessionKey: string;\n requestId: string;\n request: ClarifyBridgeRequest;\n }): Promise<void> {\n const parsed = parseSessionKey(ctx.sessionKey);\n if (!parsed || parsed.source !== 'telegram') {\n return;\n }\n\n let body = ctx.request.question;\n if (ctx.request.default) {\n body += `\\n\\nDefault if unsure: ${ctx.request.default}`;\n }\n\n const choices = ctx.request.choices;\n const buttonRows =\n choices && choices.length >= 2\n ? choices.map((c, i) => [\n {\n text: c.length > 64 ? `${c.slice(0, 61)}…` : c,\n callback_data: `clarify:${ctx.requestId}:${i}`,\n },\n ])\n : undefined;\n\n if (!buttonRows) {\n body += '\\n\\nReply with your answer in this chat.';\n }\n\n await this.opts.getChannelManager().send({\n channel: 'telegram',\n chat_id: parsed.peerId,\n content: body,\n metadata: {\n accountId: parsed.accountId,\n ...(parsed.threadId ? { threadId: parsed.threadId } : {}),\n },\n buttons: buttonRows,\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agent-runner.js","names":[],"sources":["../../../../src/gateway/service/agent-runner.ts"],"sourcesContent":["/**\n * GatewayAgentRunner — webchat agent invocation and the surrounding control\n * surface (abort, steer, clarify-bridge plumbing, scheduled continuations).\n *\n * Was 200 lines of `GatewayService` covering seven concerns that all hung off\n * the same handful of fields (`activeWebchatRunBySession`, `runAbortControllers`,\n * `clarifyBridge`, `runRelay`):\n *\n * - `runAgent(message, channel, chatId, ...)` — wraps {@link runGatewayAgent}\n * - `abortAgentRun(runId)` — POST /api/agent/abort + cleanup\n * - `steerWebchatAgent(chatId, message)` — Agent.steer queue at tool boundary\n * - `submitClarifyResponse(requestId, answer)` — UI answers a `clarify` call\n * - `enqueueWebchatPersistentGoalKickoff(sessionKey, goalText)` — initial\n * `/goal` kickoff posts the goal text as the next user turn\n * - `drainScheduledWebchatContinuation(sk, msg)` — background continuation\n * (extension scheduler + persistent-goal flow)\n * - `clarifyForSession({ sessionKey, request })` — clarify-bridge dispatch\n * used by `gatewayClarify.requestClarification` in AgentService\n *\n * Owns the two state maps (`activeWebchatRunBySession`, `runAbortControllers`)\n * directly so peer coordinators (sessions-api, marketplace, config) cannot\n * accidentally mutate them.\n */\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport type { AgentService } from '../../agent/service.js';\nimport type { ChannelManager } from '../../channels/manager.js';\nimport type { SessionIndex } from '../../session/index.js';\nimport { AgentRunRelay, type RelayEvent } from '../agent-run-relay.js';\nimport { ClarifyBridge, type ClarifyBridgeRequest } from '../clarify-bridge.js';\nimport { runGatewayAgent } from './run-gateway-agent.js';\nimport { createLogger } from '../../utils/logger.js';\n\nconst log = createLogger('Gateway:AgentRunner');\n\nexport interface GatewayAgentRunnerOptions {\n bus: MessageBus;\n sessionIndex: SessionIndex;\n /** Resolved lazily — the runner is constructed before AgentService exists. */\n getAgentService: () => AgentService;\n getChannelManager: () => ChannelManager;\n getConfig: () => Config;\n /** SSE emit (re-used so `runAgent` events broadcast to subscribers). */\n emit: (type: string, payload: unknown) => void;\n}\n\nexport class GatewayAgentRunner {\n private readonly opts: GatewayAgentRunnerOptions;\n readonly runRelay = new AgentRunRelay();\n /** Per-run abort for webchat (POST /api/agent/abort or client disconnect). */\n private readonly runAbortControllers = new Map<string, AbortController>();\n private readonly clarifyBridge = new ClarifyBridge();\n /** Maps webchat session key → active `runId` for `clarify` tool routing. */\n private readonly activeWebchatRunBySession = new Map<string, string>();\n\n constructor(opts: GatewayAgentRunnerOptions) {\n this.opts = opts;\n }\n\n // ── Read-only accessors (so peers don't get a Map ref) ────────────────\n\n /** True when a webchat agent run is currently in-flight for `sessionKey`. */\n hasActiveRun(sessionKey: string): boolean {\n return this.activeWebchatRunBySession.has(sessionKey);\n }\n\n getActiveRunId(sessionKey: string): string | undefined {\n return this.activeWebchatRunBySession.get(sessionKey);\n }\n\n getClarifyBridge(): ClarifyBridge {\n return this.clarifyBridge;\n }\n\n /** Called from `GatewayService.stop()` so the bridge gets cleaned up. */\n disposeClarifyBridge(): void {\n this.clarifyBridge.dispose();\n }\n\n // ── runAgent (webchat HTTP POST) ──────────────────────────────────────\n\n async *runAgent(\n message: string,\n channel: string,\n chatId: string,\n attachments?: Array<{\n type: string;\n mimeType?: string;\n data?: string;\n name?: string;\n size?: number;\n }>,\n thinking?: string,\n runOptions?: { signal?: AbortSignal; clientCreatedAtMs?: number },\n ): AsyncGenerator<\n { type: string; [key: string]: unknown },\n { status: string; summary: string },\n unknown\n > {\n const iter = runGatewayAgent(\n {\n config: this.opts.getConfig(),\n agentService: this.opts.getAgentService(),\n bus: this.opts.bus,\n runRelay: this.runRelay,\n runAbortControllers: this.runAbortControllers,\n activeWebchatRunBySession: this.activeWebchatRunBySession,\n sessionIndex: this.opts.sessionIndex,\n emit: this.opts.emit,\n },\n message,\n channel,\n chatId,\n attachments,\n thinking,\n runOptions,\n );\n\n let step = await iter.next();\n while (!step.done) {\n yield step.value as unknown as { type: string; [key: string]: unknown };\n step = await iter.next();\n }\n return step.value;\n }\n\n /** Abort an in-flight webchat agent run (matches `runId` from SSE `run_start`). */\n abortAgentRun(runId: string): boolean {\n this.clarifyBridge.cancelForRun(runId);\n const keysToMark: string[] = [];\n for (const [sk, id] of this.activeWebchatRunBySession) {\n if (id === runId) {\n keysToMark.push(sk);\n }\n }\n for (const sk of keysToMark) {\n this.activeWebchatRunBySession.delete(sk);\n }\n const relaySk = this.runRelay.getSessionKey(runId);\n if (relaySk && !keysToMark.includes(relaySk)) {\n keysToMark.push(relaySk);\n }\n const c = this.runAbortControllers.get(runId);\n if (!c) {\n return false;\n }\n const cutoffTs = Date.now();\n for (const sk of keysToMark) {\n void this.opts.sessionIndex\n .updateSessionMetadata(sk, { abortCutoffTimestamp: cutoffTs })\n .catch(() => {});\n void this.opts.sessionIndex\n .appendTranscriptContextEntry(sk, {\n text: 'Webchat agent run aborted',\n data: { runId, abortCutoffTimestamp: cutoffTs },\n })\n .catch(() => {});\n }\n c.abort();\n for (const sk of keysToMark) {\n void import('../../agent/embedded/runs.js').then(({ abortEmbeddedRun }) =>\n abortEmbeddedRun(sk),\n );\n }\n return true;\n }\n\n /**\n * Queue steering text for an active webchat run (`Agent.steer` /\n * tool-boundary injection). The caller must pass the session key.\n */\n async steerWebchatAgent(\n sessionKey: string,\n message: string,\n ): Promise<\n { ok: true } | { ok: false; code: 'BAD_REQUEST' | 'NO_ACTIVE_RUN' | 'STEER_FAILED' }\n > {\n const trimmed = message.trim();\n if (!trimmed) {\n return { ok: false, code: 'BAD_REQUEST' };\n }\n if (!this.activeWebchatRunBySession.has(sessionKey)) {\n return { ok: false, code: 'NO_ACTIVE_RUN' };\n }\n const steered = await this.opts\n .getAgentService()\n .turnDispatcher.steerWebchatSession(sessionKey, trimmed);\n if (!steered) {\n return { ok: false, code: 'STEER_FAILED' };\n }\n return { ok: true };\n }\n\n /** Deliver a user's answer to a pending `clarify` tool call. */\n submitClarifyResponse(requestId: string, answer: string): boolean {\n return this.clarifyBridge.handleResponse(requestId, answer);\n }\n\n /** Hermes-style: after HTTP sets a goal, enqueue the goal text as the next user turn. */\n enqueueWebchatPersistentGoalKickoff(sessionKey: string, goalText: string): void {\n queueMicrotask(() => {\n void this.drainScheduledWebchatContinuation(sessionKey, goalText);\n });\n }\n\n /** Same execution path as scheduled continuation, but lets callers observe failures. */\n async runScheduledWebchatContinuation(sessionKey: string, message: string): Promise<void> {\n const gen = this.runAgent(message, 'webchat', sessionKey, undefined, undefined, {\n clientCreatedAtMs: Date.now(),\n });\n for await (const _ of gen) {\n // Relay + `agent.stream` broadcast; UI attaches via pending runId + resume.\n }\n }\n\n /** Background drain for extension-initiated webchat turns (`scheduleWebchatContinuation`). */\n async drainScheduledWebchatContinuation(sessionKey: string, message: string): Promise<void> {\n try {\n await this.runScheduledWebchatContinuation(sessionKey, message);\n } catch (err) {\n log.warn({ err, sessionKey }, 'Scheduled webchat continuation failed');\n }\n }\n\n // ── Clarify dispatch (called from AgentService.gatewayClarify) ────────\n\n /**\n * Resolve clarify-bridge config for `sessionKey`: who delivers the question\n * (webchat SSE, Telegram message, or both), then start the bridge request.\n * Rejects when neither path is available (e.g. CLI without webchat or TG).\n *\n * `publishSseFor(runId)` is the bridge into AgentService's\n * `turnDispatcher.enqueueWebchatSseEvent`. We take it as a callback so the\n * runner does not import AgentService statically.\n */\n async requestClarification(opts: {\n sessionKey: string;\n request: ClarifyBridgeRequest;\n publishSseFor: (runId: string) => (e: RelayEvent) => void;\n }): Promise<string> {\n const { sessionKey, request, publishSseFor } = opts;\n const runId = this.activeWebchatRunBySession.get(sessionKey);\n const publishSse = runId ? publishSseFor(runId) : undefined;\n const metadata = await this.opts.sessionIndex.getSessionMetadata(sessionKey).catch(() => null);\n const routing = metadata?.routing;\n const deliver =\n routing?.source === 'telegram'\n ? async (ctx: {\n sessionKey: string;\n requestId: string;\n request: ClarifyBridgeRequest;\n }) => {\n await this.deliverTelegramClarify(ctx);\n }\n : undefined;\n if (!runId && !deliver) {\n return Promise.reject(\n new Error('Clarify is not available for this session (use webchat, Telegram, or CLI)'),\n );\n }\n return this.clarifyBridge.startRequest({\n sessionKey,\n runId,\n relay: this.runRelay,\n publishSse,\n request,\n deliver,\n });\n }\n\n private async deliverTelegramClarify(ctx: {\n sessionKey: string;\n requestId: string;\n request: ClarifyBridgeRequest;\n }): Promise<void> {\n const metadata = await this.opts.sessionIndex.getSessionMetadata(ctx.sessionKey).catch(() => null);\n const routing = metadata?.routing;\n if (!routing || routing.source !== 'telegram') {\n return;\n }\n\n let body = ctx.request.question;\n if (ctx.request.default) {\n body += `\\n\\nDefault if unsure: ${ctx.request.default}`;\n }\n\n const choices = ctx.request.choices;\n const buttonRows =\n choices && choices.length >= 2\n ? choices.map((c, i) => [\n {\n text: c.length > 64 ? `${c.slice(0, 61)}…` : c,\n callback_data: `clarify:${ctx.requestId}:${i}`,\n },\n ])\n : undefined;\n\n if (!buttonRows) {\n body += '\\n\\nReply with your answer in this chat.';\n }\n\n await this.opts.getChannelManager().send({\n channel: 'telegram',\n chat_id: routing.peerId,\n content: body,\n metadata: {\n accountId: routing.accountId,\n ...(routing.threadId ? { threadId: routing.threadId } : {}),\n },\n buttons: buttonRows,\n });\n }\n}\n"],"mappings":";;;;;;aA+BqD;AAErD,MAAM,MAAM,aAAa,sBAAsB;AAa/C,IAAa,qBAAb,MAAgC;CAC9B;CACA,WAAoB,IAAI,eAAe;;CAEvC,sCAAuC,IAAI,KAA8B;CACzE,gBAAiC,IAAI,eAAe;;CAEpD,4CAA6C,IAAI,KAAqB;CAEtE,YAAY,MAAiC;AAC3C,OAAK,OAAO;;;CAMd,aAAa,YAA6B;AACxC,SAAO,KAAK,0BAA0B,IAAI,WAAW;;CAGvD,eAAe,YAAwC;AACrD,SAAO,KAAK,0BAA0B,IAAI,WAAW;;CAGvD,mBAAkC;AAChC,SAAO,KAAK;;;CAId,uBAA6B;AAC3B,OAAK,cAAc,SAAS;;CAK9B,OAAO,SACL,SACA,SACA,QACA,aAOA,UACA,YAKA;EACA,MAAM,OAAO,gBACX;GACE,QAAQ,KAAK,KAAK,WAAW;GAC7B,cAAc,KAAK,KAAK,iBAAiB;GACzC,KAAK,KAAK,KAAK;GACf,UAAU,KAAK;GACf,qBAAqB,KAAK;GAC1B,2BAA2B,KAAK;GAChC,cAAc,KAAK,KAAK;GACxB,MAAM,KAAK,KAAK;GACjB,EACD,SACA,SACA,QACA,aACA,UACA,WACD;EAED,IAAI,OAAO,MAAM,KAAK,MAAM;AAC5B,SAAO,CAAC,KAAK,MAAM;AACjB,SAAM,KAAK;AACX,UAAO,MAAM,KAAK,MAAM;;AAE1B,SAAO,KAAK;;;CAId,cAAc,OAAwB;AACpC,OAAK,cAAc,aAAa,MAAM;EACtC,MAAM,aAAuB,EAAE;AAC/B,OAAK,MAAM,CAAC,IAAI,OAAO,KAAK,0BAC1B,KAAI,OAAO,MACT,YAAW,KAAK,GAAG;AAGvB,OAAK,MAAM,MAAM,WACf,MAAK,0BAA0B,OAAO,GAAG;EAE3C,MAAM,UAAU,KAAK,SAAS,cAAc,MAAM;AAClD,MAAI,WAAW,CAAC,WAAW,SAAS,QAAQ,CAC1C,YAAW,KAAK,QAAQ;EAE1B,MAAM,IAAI,KAAK,oBAAoB,IAAI,MAAM;AAC7C,MAAI,CAAC,EACH,QAAO;EAET,MAAM,WAAW,KAAK,KAAK;AAC3B,OAAK,MAAM,MAAM,YAAY;AACtB,QAAK,KAAK,aACZ,sBAAsB,IAAI,EAAE,sBAAsB,UAAU,CAAC,CAC7D,YAAY,GAAG;AACb,QAAK,KAAK,aACZ,6BAA6B,IAAI;IAChC,MAAM;IACN,MAAM;KAAE;KAAO,sBAAsB;KAAU;IAChD,CAAC,CACD,YAAY,GAAG;;AAEpB,IAAE,OAAO;AACT,OAAK,MAAM,MAAM,WACV,QAAO,gCAAgC,MAAM,EAAE,uBAClD,iBAAiB,GAAG,CACrB;AAEH,SAAO;;;;;;CAOT,MAAM,kBACJ,YACA,SAGA;EACA,MAAM,UAAU,QAAQ,MAAM;AAC9B,MAAI,CAAC,QACH,QAAO;GAAE,IAAI;GAAO,MAAM;GAAe;AAE3C,MAAI,CAAC,KAAK,0BAA0B,IAAI,WAAW,CACjD,QAAO;GAAE,IAAI;GAAO,MAAM;GAAiB;AAK7C,MAAI,CAAC,MAHiB,KAAK,KACxB,iBAAiB,CACjB,eAAe,oBAAoB,YAAY,QAAQ,CAExD,QAAO;GAAE,IAAI;GAAO,MAAM;GAAgB;AAE5C,SAAO,EAAE,IAAI,MAAM;;;CAIrB,sBAAsB,WAAmB,QAAyB;AAChE,SAAO,KAAK,cAAc,eAAe,WAAW,OAAO;;;CAI7D,oCAAoC,YAAoB,UAAwB;AAC9E,uBAAqB;AACd,QAAK,kCAAkC,YAAY,SAAS;IACjE;;;CAIJ,MAAM,gCAAgC,YAAoB,SAAgC;EACxF,MAAM,MAAM,KAAK,SAAS,SAAS,WAAW,YAAY,KAAA,GAAW,KAAA,GAAW,EAC9E,mBAAmB,KAAK,KAAK,EAC9B,CAAC;AACF,aAAW,MAAM,KAAK;;;CAMxB,MAAM,kCAAkC,YAAoB,SAAgC;AAC1F,MAAI;AACF,SAAM,KAAK,gCAAgC,YAAY,QAAQ;WACxD,KAAK;AACZ,OAAI,KAAK;IAAE;IAAK;IAAY,EAAE,wCAAwC;;;;;;;;;;;;CAe1E,MAAM,qBAAqB,MAIP;EAClB,MAAM,EAAE,YAAY,SAAS,kBAAkB;EAC/C,MAAM,QAAQ,KAAK,0BAA0B,IAAI,WAAW;EAC5D,MAAM,aAAa,QAAQ,cAAc,MAAM,GAAG,KAAA;EAGlD,MAAM,YADU,MADO,KAAK,KAAK,aAAa,mBAAmB,WAAW,CAAC,YAAY,KAAK,GACpE,UAEf,WAAW,aAChB,OAAO,QAID;AACJ,SAAM,KAAK,uBAAuB,IAAI;MAExC,KAAA;AACN,MAAI,CAAC,SAAS,CAAC,QACb,QAAO,QAAQ,uBACb,IAAI,MAAM,4EAA4E,CACvF;AAEH,SAAO,KAAK,cAAc,aAAa;GACrC;GACA;GACA,OAAO,KAAK;GACZ;GACA;GACA;GACD,CAAC;;CAGJ,MAAc,uBAAuB,KAInB;EAEhB,MAAM,WAAU,MADO,KAAK,KAAK,aAAa,mBAAmB,IAAI,WAAW,CAAC,YAAY,KAAK,GACxE;AAC1B,MAAI,CAAC,WAAW,QAAQ,WAAW,WACjC;EAGF,IAAI,OAAO,IAAI,QAAQ;AACvB,MAAI,IAAI,QAAQ,QACd,SAAQ,0BAA0B,IAAI,QAAQ;EAGhD,MAAM,UAAU,IAAI,QAAQ;EAC5B,MAAM,aACJ,WAAW,QAAQ,UAAU,IACzB,QAAQ,KAAK,GAAG,MAAM,CACpB;GACE,MAAM,EAAE,SAAS,KAAK,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,KAAK;GAC7C,eAAe,WAAW,IAAI,UAAU,GAAG;GAC5C,CACF,CAAC,GACF,KAAA;AAEN,MAAI,CAAC,WACH,SAAQ;AAGV,QAAM,KAAK,KAAK,mBAAmB,CAAC,KAAK;GACvC,SAAS;GACT,SAAS,QAAQ;GACjB,SAAS;GACT,UAAU;IACR,WAAW,QAAQ;IACnB,GAAI,QAAQ,WAAW,EAAE,UAAU,QAAQ,UAAU,GAAG,EAAE;IAC3D;GACD,SAAS;GACV,CAAC"}
|
|
@@ -21,19 +21,18 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
|
|
|
21
21
|
max: 10
|
|
22
22
|
}, "Attachments capped for webchat");
|
|
23
23
|
const runId = crypto.randomUUID();
|
|
24
|
-
const {
|
|
24
|
+
const { agentService, bus, runRelay, runAbortControllers, activeWebchatRunBySession, sessionIndex: sessionIndexFromDeps, emit } = deps;
|
|
25
25
|
const sessionIndex = sessionIndexFromDeps;
|
|
26
26
|
let webchatSessionKey;
|
|
27
|
+
let webchatSessionId;
|
|
27
28
|
let webchatStaleSkip = false;
|
|
28
29
|
if (channel === "webchat") {
|
|
29
|
-
const resolved = resolveWebchatSessionKey({
|
|
30
|
-
cfg: config,
|
|
31
|
-
chatId,
|
|
32
|
-
newSession: false
|
|
33
|
-
});
|
|
30
|
+
const resolved = resolveWebchatSessionKey({ sessionKey: chatId });
|
|
34
31
|
if (resolved.ok === false) throw new Error(resolved.error);
|
|
35
32
|
webchatSessionKey = resolved.sessionKey;
|
|
36
33
|
const meta = await sessionIndex.getSessionMetadata(webchatSessionKey);
|
|
34
|
+
if (!meta) throw new Error("Session not found; create sessions via POST /api/sessions");
|
|
35
|
+
webchatSessionId = meta?.sessionId;
|
|
37
36
|
webchatStaleSkip = shouldSkipWebchatInboundByAbortCutoff(meta, runOptions?.clientCreatedAtMs);
|
|
38
37
|
if (!webchatStaleSkip && meta?.abortCutoffTimestamp !== void 0) await sessionIndex.updateSessionMetadata(webchatSessionKey, { abortCutoffTimestamp: void 0 }).catch(() => {});
|
|
39
38
|
runRelay.ensureRun(runId, webchatSessionKey);
|
|
@@ -69,7 +68,10 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
|
|
|
69
68
|
};
|
|
70
69
|
}
|
|
71
70
|
const sessionKey = webchatSessionKey;
|
|
72
|
-
updateAsyncLogContext({
|
|
71
|
+
updateAsyncLogContext({
|
|
72
|
+
sessionKey,
|
|
73
|
+
...webchatSessionId ? { sessionId: webchatSessionId } : {}
|
|
74
|
+
});
|
|
73
75
|
const timezone = agentService.resolveUserTimezoneForSession(sessionKey);
|
|
74
76
|
const stampedMessage = message.trimStart().startsWith("/") ? message : prependEnvelopeTimestamp(message, timezone);
|
|
75
77
|
const prepared = await agentService.prepareInboundAttachments(sessionKey, cappedAttachments);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-gateway-agent.js","names":[],"sources":["../../../../src/gateway/service/run-gateway-agent.ts"],"sourcesContent":["import crypto from 'crypto';\n\nimport type { AgentService } from '../../agent/service.js';\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport { prependEnvelopeTimestamp } from '../../channels/envelope-timestamp.js';\nimport { resolveWebchatSessionKey } from '../resolve-webchat-session-key.js';\nimport type { SessionIndex } from '../../session/index.js';\nimport {\n createLogger,\n inboundCorrelationMetadataFromAsyncLogContext,\n updateAsyncLogContext,\n} from '../../utils/logger.js';\nimport { shouldSkipWebchatInboundByAbortCutoff } from '../../session/abort-cutoff.js';\n\nimport { formatAgentRunErrorForClient } from '../../agent/client-error-format.js';\n\nimport { ChatStreamMapper } from '../chat-stream/mapper.js';\nimport type { ChatStreamEvent } from '../chat-stream/protocol.js';\nimport type { AgentRunRelay } from '../agent-run-relay.js';\nimport { MAX_CHAT_ATTACHMENTS } from '../chat-limits.js';\nconst log = createLogger('Gateway:Service');\n\nexport type RunGatewayAgentYield = ChatStreamEvent;\n\nexport type RunGatewayAgentDeps = {\n config: Config;\n agentService: AgentService;\n bus: MessageBus;\n runRelay: AgentRunRelay;\n runAbortControllers: Map<string, AbortController>;\n activeWebchatRunBySession: Map<string, string>;\n sessionIndex: SessionIndex;\n emit: (type: string, payload: unknown) => void;\n};\n\n/**\n * @param runOptions.signal — When set (e.g. client disconnect), aborts in-flight generation and persists partial output.\n */\nexport async function *runGatewayAgent(\n deps: RunGatewayAgentDeps,\n message: string,\n channel: string,\n chatId: string,\n attachments?: Array<{\n type: string;\n mimeType?: string;\n data?: string;\n uri?: string;\n name?: string;\n size?: number;\n workspaceRelativePath?: string;\n durationSeconds?: number;\n }>,\n thinking?: string,\n runOptions?: { signal?: AbortSignal; clientCreatedAtMs?: number },\n): AsyncGenerator<RunGatewayAgentYield, { status: string; summary: string }, unknown> {\n const cappedAttachments =\n attachments && attachments.length > MAX_CHAT_ATTACHMENTS\n ? attachments.slice(0, MAX_CHAT_ATTACHMENTS)\n : attachments;\n if (attachments && cappedAttachments && attachments.length > cappedAttachments.length) {\n log.debug(\n { dropped: attachments.length - cappedAttachments.length, max: MAX_CHAT_ATTACHMENTS },\n 'Attachments capped for webchat',\n );\n }\n\n const runId = crypto.randomUUID();\n const {\n config,\n agentService,\n bus,\n runRelay,\n runAbortControllers,\n activeWebchatRunBySession,\n sessionIndex: sessionIndexFromDeps,\n emit,\n } = deps;\n const sessionIndex = sessionIndexFromDeps;\n\n let webchatSessionKey: string | undefined;\n let webchatStaleSkip = false;\n if (channel === 'webchat') {\n const resolved = resolveWebchatSessionKey({ cfg: config, chatId, newSession: false });\n if (resolved.ok === false) {\n throw new Error(resolved.error);\n }\n webchatSessionKey = resolved.sessionKey;\n const meta = await sessionIndex.getSessionMetadata(webchatSessionKey);\n webchatStaleSkip = shouldSkipWebchatInboundByAbortCutoff(meta, runOptions?.clientCreatedAtMs);\n if (!webchatStaleSkip && meta?.abortCutoffTimestamp !== undefined) {\n await sessionIndex\n .updateSessionMetadata(webchatSessionKey, { abortCutoffTimestamp: undefined })\n .catch(() => {});\n }\n runRelay.ensureRun(runId, webchatSessionKey);\n runAbortControllers.set(runId, new AbortController());\n }\n\n const streamSessionKey = webchatSessionKey ?? chatId;\n const mapper = new ChatStreamMapper({ runId, sessionKey: streamSessionKey, channel });\n const publishStreamEvent = (event: ChatStreamEvent): ChatStreamEvent =>\n channel === 'webchat'\n ? ((runRelay.publish(runId, event as unknown as import('../agent-run-relay.js').RelayEvent) as unknown as ChatStreamEvent | undefined) ?? event)\n : event;\n const emitAndYield = function *(events: ChatStreamEvent[]): Generator<ChatStreamEvent> {\n for (const event of events) {\n const relayedEvent = publishStreamEvent(event);\n if (channel === 'webchat') emit('agent.stream', { sessionKey: streamSessionKey, event: relayedEvent });\n yield relayedEvent;\n }\n };\n\n yield* emitAndYield(mapper.start());\n\n try {\n if (channel === 'webchat' && webchatSessionKey) {\n if (webchatStaleSkip) {\n yield* emitAndYield(mapper.end('cancelled', 'Stale inbound after abort (clientCreatedAtMs before cutoff)'));\n runRelay.complete(runId);\n runAbortControllers.delete(runId);\n return {\n status: 'skipped',\n summary: 'Stale inbound after abort (clientCreatedAtMs before cutoff)',\n };\n }\n\n const sessionKey = webchatSessionKey;\n updateAsyncLogContext({ sessionId: sessionKey });\n\n const timezone = agentService.resolveUserTimezoneForSession(sessionKey);\n const stampedMessage = message.trimStart().startsWith('/')\n ? message\n : prependEnvelopeTimestamp(message, timezone);\n const prepared = await agentService.prepareInboundAttachments(sessionKey, cappedAttachments);\n\n const runAbort = runAbortControllers.get(runId);\n if (!runAbort) {\n throw new Error('run abort controller missing for webchat');\n }\n const mergedSignal = runOptions?.signal\n ? AbortSignal.any([runOptions.signal, runAbort.signal])\n : runAbort.signal;\n\n agentService.beginInboundTurn(sessionKey);\n activeWebchatRunBySession.set(sessionKey, runId);\n let streamError: string | undefined;\n try {\n const eventStream = agentService.turnDispatcher.processDirectStreaming(\n stampedMessage,\n sessionKey,\n prepared,\n thinking,\n { signal: mergedSignal, runId },\n );\n\n for await (const event of eventStream) {\n yield* emitAndYield(mapper.map(event));\n }\n\n const endStatus = mergedSignal.aborted ? 'cancelled' : 'success';\n const endSummary = mergedSignal.aborted ? 'Interrupted' : 'Message processed successfully';\n yield* emitAndYield(mapper.end(endStatus, endSummary));\n runRelay.complete(runId);\n try {\n const metaAfter = await sessionIndex.getSessionMetadata(sessionKey);\n if (metaAfter?.name) {\n emit('session.updated', { key: sessionKey, name: metaAfter.name });\n }\n } catch {\n /* ignore */\n }\n return {\n status: mergedSignal.aborted ? 'aborted' : 'ok',\n summary: mergedSignal.aborted ? 'Interrupted' : 'Message processed successfully',\n };\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n log.error(\n {\n err: error,\n errorMessage: em,\n phase: 'gateway.agent_run',\n sessionKey,\n runId,\n channel: 'webchat',\n },\n `Agent processing failed: ${em}`,\n );\n streamError = em;\n const errorContent = formatAgentRunErrorForClient(streamError);\n yield* emitAndYield(mapper.error(errorContent));\n yield* emitAndYield(mapper.end('error', streamError));\n runRelay.complete(runId);\n return { status: 'error', summary: streamError };\n } finally {\n activeWebchatRunBySession.delete(sessionKey);\n runAbortControllers.delete(runId);\n const assistantPlainText = agentService.getLastAssistantPlainText(sessionKey);\n const streamOutcome = agentService.persistentGoals.takeStreamOutcome(sessionKey);\n try {\n await agentService.outboundCoordinator.emitSessionTurnComplete({\n sessionKey,\n channel: 'webchat',\n chatId: sessionKey,\n inboundUserText: message,\n assistantPlainText,\n aborted: mergedSignal.aborted,\n ...(streamError !== undefined ? { streamError } : {}),\n skipPersistentGoalPostTurn: streamOutcome?.skipPersistentGoalPostTurn ?? false,\n outboundMetadata: {},\n });\n } catch (goalErr) {\n log.warn(\n { err: goalErr, sessionKey },\n `Session turn complete failed: ${goalErr instanceof Error ? goalErr.message : String(goalErr)}`,\n );\n }\n agentService.endInboundTurn(sessionKey);\n }\n }\n\n const correlationMeta = inboundCorrelationMetadataFromAsyncLogContext();\n await bus.publishInbound({\n channel,\n sender_id: 'gateway',\n chat_id: chatId,\n content: message,\n ...(correlationMeta ? { metadata: correlationMeta } : {}),\n });\n\n const messageId = `msg_${runId.replace(/[^a-zA-Z0-9_-]/g, '_')}_1`;\n yield* emitAndYield([\n {\n type: 'assistant_message_start',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId },\n },\n {\n type: 'assistant_delta',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId, delta: 'Processing...\\n' },\n },\n ]);\n await new Promise((resolve) => setTimeout(resolve, 1000));\n yield* emitAndYield([\n {\n type: 'assistant_delta',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId, delta: 'Done\\n' },\n },\n {\n type: 'assistant_message_end',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId },\n },\n ]);\n yield* emitAndYield(mapper.end('success', 'Message processed'));\n return { status: 'ok', summary: 'Message processed' };\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n log.error(\n {\n err: error,\n errorMessage: em,\n phase: 'gateway.agent_run',\n runId,\n channel,\n chatId,\n },\n `Agent run failed: ${em}`,\n );\n throw error;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"run-gateway-agent.js","names":[],"sources":["../../../../src/gateway/service/run-gateway-agent.ts"],"sourcesContent":["import crypto from 'crypto';\n\nimport type { AgentService } from '../../agent/service.js';\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport { prependEnvelopeTimestamp } from '../../channels/envelope-timestamp.js';\nimport { resolveWebchatSessionKey } from '../resolve-webchat-session-key.js';\nimport type { SessionIndex } from '../../session/index.js';\nimport {\n createLogger,\n inboundCorrelationMetadataFromAsyncLogContext,\n updateAsyncLogContext,\n} from '../../utils/logger.js';\nimport { shouldSkipWebchatInboundByAbortCutoff } from '../../session/abort-cutoff.js';\n\nimport { formatAgentRunErrorForClient } from '../../agent/client-error-format.js';\n\nimport { ChatStreamMapper } from '../chat-stream/mapper.js';\nimport type { ChatStreamEvent } from '../chat-stream/protocol.js';\nimport type { AgentRunRelay } from '../agent-run-relay.js';\nimport { MAX_CHAT_ATTACHMENTS } from '../chat-limits.js';\nconst log = createLogger('Gateway:Service');\n\nexport type RunGatewayAgentYield = ChatStreamEvent;\n\nexport type RunGatewayAgentDeps = {\n config: Config;\n agentService: AgentService;\n bus: MessageBus;\n runRelay: AgentRunRelay;\n runAbortControllers: Map<string, AbortController>;\n activeWebchatRunBySession: Map<string, string>;\n sessionIndex: SessionIndex;\n emit: (type: string, payload: unknown) => void;\n};\n\n/**\n * @param runOptions.signal — When set (e.g. client disconnect), aborts in-flight generation and persists partial output.\n */\nexport async function *runGatewayAgent(\n deps: RunGatewayAgentDeps,\n message: string,\n channel: string,\n chatId: string,\n attachments?: Array<{\n type: string;\n mimeType?: string;\n data?: string;\n uri?: string;\n name?: string;\n size?: number;\n workspaceRelativePath?: string;\n durationSeconds?: number;\n }>,\n thinking?: string,\n runOptions?: { signal?: AbortSignal; clientCreatedAtMs?: number },\n): AsyncGenerator<RunGatewayAgentYield, { status: string; summary: string }, unknown> {\n const cappedAttachments =\n attachments && attachments.length > MAX_CHAT_ATTACHMENTS\n ? attachments.slice(0, MAX_CHAT_ATTACHMENTS)\n : attachments;\n if (attachments && cappedAttachments && attachments.length > cappedAttachments.length) {\n log.debug(\n { dropped: attachments.length - cappedAttachments.length, max: MAX_CHAT_ATTACHMENTS },\n 'Attachments capped for webchat',\n );\n }\n\n const runId = crypto.randomUUID();\n const {\n agentService,\n bus,\n runRelay,\n runAbortControllers,\n activeWebchatRunBySession,\n sessionIndex: sessionIndexFromDeps,\n emit,\n } = deps;\n const sessionIndex = sessionIndexFromDeps;\n\n let webchatSessionKey: string | undefined;\n let webchatSessionId: string | undefined;\n let webchatStaleSkip = false;\n if (channel === 'webchat') {\n const resolved = resolveWebchatSessionKey({ sessionKey: chatId });\n if (resolved.ok === false) {\n throw new Error(resolved.error);\n }\n webchatSessionKey = resolved.sessionKey;\n const meta = await sessionIndex.getSessionMetadata(webchatSessionKey);\n if (!meta) {\n throw new Error('Session not found; create sessions via POST /api/sessions');\n }\n webchatSessionId = meta?.sessionId;\n webchatStaleSkip = shouldSkipWebchatInboundByAbortCutoff(meta, runOptions?.clientCreatedAtMs);\n if (!webchatStaleSkip && meta?.abortCutoffTimestamp !== undefined) {\n await sessionIndex\n .updateSessionMetadata(webchatSessionKey, { abortCutoffTimestamp: undefined })\n .catch(() => {});\n }\n runRelay.ensureRun(runId, webchatSessionKey);\n runAbortControllers.set(runId, new AbortController());\n }\n\n const streamSessionKey = webchatSessionKey ?? chatId;\n const mapper = new ChatStreamMapper({ runId, sessionKey: streamSessionKey, channel });\n const publishStreamEvent = (event: ChatStreamEvent): ChatStreamEvent =>\n channel === 'webchat'\n ? ((runRelay.publish(runId, event as unknown as import('../agent-run-relay.js').RelayEvent) as unknown as ChatStreamEvent | undefined) ?? event)\n : event;\n const emitAndYield = function *(events: ChatStreamEvent[]): Generator<ChatStreamEvent> {\n for (const event of events) {\n const relayedEvent = publishStreamEvent(event);\n if (channel === 'webchat') emit('agent.stream', { sessionKey: streamSessionKey, event: relayedEvent });\n yield relayedEvent;\n }\n };\n\n yield* emitAndYield(mapper.start());\n\n try {\n if (channel === 'webchat' && webchatSessionKey) {\n if (webchatStaleSkip) {\n yield* emitAndYield(mapper.end('cancelled', 'Stale inbound after abort (clientCreatedAtMs before cutoff)'));\n runRelay.complete(runId);\n runAbortControllers.delete(runId);\n return {\n status: 'skipped',\n summary: 'Stale inbound after abort (clientCreatedAtMs before cutoff)',\n };\n }\n\n const sessionKey = webchatSessionKey;\n updateAsyncLogContext({\n sessionKey,\n ...(webchatSessionId ? { sessionId: webchatSessionId } : {}),\n });\n\n const timezone = agentService.resolveUserTimezoneForSession(sessionKey);\n const stampedMessage = message.trimStart().startsWith('/')\n ? message\n : prependEnvelopeTimestamp(message, timezone);\n const prepared = await agentService.prepareInboundAttachments(sessionKey, cappedAttachments);\n\n const runAbort = runAbortControllers.get(runId);\n if (!runAbort) {\n throw new Error('run abort controller missing for webchat');\n }\n const mergedSignal = runOptions?.signal\n ? AbortSignal.any([runOptions.signal, runAbort.signal])\n : runAbort.signal;\n\n agentService.beginInboundTurn(sessionKey);\n activeWebchatRunBySession.set(sessionKey, runId);\n let streamError: string | undefined;\n try {\n const eventStream = agentService.turnDispatcher.processDirectStreaming(\n stampedMessage,\n sessionKey,\n prepared,\n thinking,\n { signal: mergedSignal, runId },\n );\n\n for await (const event of eventStream) {\n yield* emitAndYield(mapper.map(event));\n }\n\n const endStatus = mergedSignal.aborted ? 'cancelled' : 'success';\n const endSummary = mergedSignal.aborted ? 'Interrupted' : 'Message processed successfully';\n yield* emitAndYield(mapper.end(endStatus, endSummary));\n runRelay.complete(runId);\n try {\n const metaAfter = await sessionIndex.getSessionMetadata(sessionKey);\n if (metaAfter?.name) {\n emit('session.updated', { key: sessionKey, name: metaAfter.name });\n }\n } catch {\n /* ignore */\n }\n return {\n status: mergedSignal.aborted ? 'aborted' : 'ok',\n summary: mergedSignal.aborted ? 'Interrupted' : 'Message processed successfully',\n };\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n log.error(\n {\n err: error,\n errorMessage: em,\n phase: 'gateway.agent_run',\n sessionKey,\n runId,\n channel: 'webchat',\n },\n `Agent processing failed: ${em}`,\n );\n streamError = em;\n const errorContent = formatAgentRunErrorForClient(streamError);\n yield* emitAndYield(mapper.error(errorContent));\n yield* emitAndYield(mapper.end('error', streamError));\n runRelay.complete(runId);\n return { status: 'error', summary: streamError };\n } finally {\n activeWebchatRunBySession.delete(sessionKey);\n runAbortControllers.delete(runId);\n const assistantPlainText = agentService.getLastAssistantPlainText(sessionKey);\n const streamOutcome = agentService.persistentGoals.takeStreamOutcome(sessionKey);\n try {\n await agentService.outboundCoordinator.emitSessionTurnComplete({\n sessionKey,\n channel: 'webchat',\n chatId: sessionKey,\n inboundUserText: message,\n assistantPlainText,\n aborted: mergedSignal.aborted,\n ...(streamError !== undefined ? { streamError } : {}),\n skipPersistentGoalPostTurn: streamOutcome?.skipPersistentGoalPostTurn ?? false,\n outboundMetadata: {},\n });\n } catch (goalErr) {\n log.warn(\n { err: goalErr, sessionKey },\n `Session turn complete failed: ${goalErr instanceof Error ? goalErr.message : String(goalErr)}`,\n );\n }\n agentService.endInboundTurn(sessionKey);\n }\n }\n\n const correlationMeta = inboundCorrelationMetadataFromAsyncLogContext();\n await bus.publishInbound({\n channel,\n sender_id: 'gateway',\n chat_id: chatId,\n content: message,\n ...(correlationMeta ? { metadata: correlationMeta } : {}),\n });\n\n const messageId = `msg_${runId.replace(/[^a-zA-Z0-9_-]/g, '_')}_1`;\n yield* emitAndYield([\n {\n type: 'assistant_message_start',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId },\n },\n {\n type: 'assistant_delta',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId, delta: 'Processing...\\n' },\n },\n ]);\n await new Promise((resolve) => setTimeout(resolve, 1000));\n yield* emitAndYield([\n {\n type: 'assistant_delta',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId, delta: 'Done\\n' },\n },\n {\n type: 'assistant_message_end',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId },\n },\n ]);\n yield* emitAndYield(mapper.end('success', 'Message processed'));\n return { status: 'ok', summary: 'Message processed' };\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n log.error(\n {\n err: error,\n errorMessage: em,\n phase: 'gateway.agent_run',\n runId,\n channel,\n chatId,\n },\n `Agent run failed: ${em}`,\n );\n throw error;\n }\n}\n"],"mappings":"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"}
|
|
@@ -33,6 +33,15 @@ export declare class GatewaySessionsApi {
|
|
|
33
33
|
includeTranscriptSummary?: boolean;
|
|
34
34
|
includeTranscriptRows?: boolean;
|
|
35
35
|
}): Promise<import("../../session/types.js").SessionDetail>;
|
|
36
|
+
resolveSession(input: {
|
|
37
|
+
key?: string;
|
|
38
|
+
sessionKey?: string;
|
|
39
|
+
sessionId?: string;
|
|
40
|
+
}): Promise<{
|
|
41
|
+
sessionKey: string;
|
|
42
|
+
sessionId: string;
|
|
43
|
+
session: Awaited<ReturnType<GatewaySessionsApi['getSession']>>;
|
|
44
|
+
} | null>;
|
|
36
45
|
/** Read-only: in-flight webchat agent run for this session key, if any. */
|
|
37
46
|
getActiveRun(sessionKey: string): {
|
|
38
47
|
active: boolean;
|
|
@@ -19,6 +19,17 @@ var GatewaySessionsApi = class {
|
|
|
19
19
|
getSession(key, options) {
|
|
20
20
|
return this.opts.sessionIndex.getSession(key, options);
|
|
21
21
|
}
|
|
22
|
+
async resolveSession(input) {
|
|
23
|
+
const resolvedKey = input.sessionKey?.trim() || input.key?.trim() || (input.sessionId?.trim() ? await this.opts.sessionIndex.resolveSessionKeyBySessionId(input.sessionId.trim()) : null);
|
|
24
|
+
if (!resolvedKey) return null;
|
|
25
|
+
const session = await this.getSession(resolvedKey);
|
|
26
|
+
if (!session?.sessionId) return null;
|
|
27
|
+
return {
|
|
28
|
+
sessionKey: resolvedKey,
|
|
29
|
+
sessionId: session.sessionId,
|
|
30
|
+
session
|
|
31
|
+
};
|
|
32
|
+
}
|
|
22
33
|
/** Read-only: in-flight webchat agent run for this session key, if any. */
|
|
23
34
|
getActiveRun(sessionKey) {
|
|
24
35
|
const key = sessionKey.trim();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions-api.js","names":[],"sources":["../../../../src/gateway/service/sessions-api.ts"],"sourcesContent":["/**\n * GatewaySessionsApi — session CRUD, search, compaction, tag/pin/archive,\n * stats, and chat-id grouping for the gateway REST surface.\n *\n * Twenty-four methods, previously sitting on `GatewayService` as a mix of\n * one-line `sessionIndex.*` delegations and small composite operations (e.g.\n * `restoreCheckpoint` also evicts the in-memory agent, `runCompaction` also\n * appends a transcript context entry). Centralising them here lets routes\n * depend on the narrow `GatewaySessionsApi` surface instead of the full\n * `GatewayService`, and keeps the gateway composition root focused on\n * lifecycle + wiring.\n */\n\nimport type { AgentService } from '../../agent/service.js';\nimport type { CompactionResult } from '../../agent/memory/compaction.js';\nimport { retireSessionMcpRuntimeForSessionKey } from '../../agent/mcp/bundle-mcp-tools.js';\nimport { SessionIndex } from '../../session/index.js';\nimport type { ExportFormat, SessionListQuery } from '../../session/types.js';\nimport type { SessionPatchBody } from '../../session/patch-metadata.js';\nimport { collectMediaUrisFromMessages, deleteMediaUris } from '../../media/session-references.js';\nimport { getDistinctSessionChatIds } from './session-chat-ids.js';\nimport { performSessionReset, type SessionResetResult } from '../session-reset-service.js';\n\nexport interface GatewaySessionsApiOptions {\n sessionIndex: SessionIndex;\n /** Resolves the live agent service (created lazily; throws if gateway is starting). */\n getAgentService: () => AgentService;\n /** Read-only view of in-flight webchat runs (per session key → run id). */\n getActiveWebchatRunId: (sessionKey: string) => string | undefined;\n}\n\nexport class GatewaySessionsApi {\n private readonly opts: GatewaySessionsApiOptions;\n\n constructor(opts: GatewaySessionsApiOptions) {\n this.opts = opts;\n }\n\n // ── List / get ─────────────────────────────────────────────────────────\n\n listSessions(query?: SessionListQuery) {\n return this.opts.sessionIndex.listSessions(query);\n }\n\n /** Subagent sessions have keys starting with `subagent:`. */\n listSubagents(query?: SessionListQuery) {\n return this.opts.sessionIndex.listSubagents(query);\n }\n\n getSession(\n key: string,\n options?: { includeTranscriptSummary?: boolean; includeTranscriptRows?: boolean },\n ) {\n return this.opts.sessionIndex.getSession(key, options);\n }\n\n /** Read-only: in-flight webchat agent run for this session key, if any. */\n getActiveRun(sessionKey: string): { active: boolean; runId?: string } {\n const key = sessionKey.trim();\n if (!key) return { active: false };\n const runId = this.opts.getActiveWebchatRunId(key)?.trim();\n if (!runId) return { active: false };\n return { active: true, runId };\n }\n\n getMessagePage(\n key: string,\n options?: {\n offset?: number;\n limit?: number;\n before?: string;\n includeTranscriptSummary?: boolean;\n includeTranscriptRows?: boolean;\n },\n ) {\n return this.opts.sessionIndex.getSessionMessagePage(key, options);\n }\n\n // ── Metadata patches ──────────────────────────────────────────────────\n\n patch(key: string, body: SessionPatchBody): Promise<{ ok: true } | { ok: false; error: string }> {\n return this.opts.sessionIndex.patchSession(key, body);\n }\n\n async getAgentConfig(sessionKey: string) {\n return this.opts.getAgentService().sessionInspector.agentConfig(sessionKey);\n }\n\n /** Resolved markdown workspace for a session (after hydration / mkdir). */\n getEffectiveWorkspacePath(sessionKey: string): Promise<string> {\n return this.opts.getAgentService().getEffectiveWorkspacePathForSession(sessionKey);\n }\n\n patchAgentConfig(\n sessionKey: string,\n body: {\n thinkingLevel?: string;\n model?: string | null;\n reasoningLevel?: string;\n verboseLevel?: string;\n workingDirectory?: string;\n },\n ) {\n return this.opts.getAgentService().sessionConfig.patch(sessionKey, body);\n }\n\n // ── Compaction checkpoints ────────────────────────────────────────────\n\n listCompactionCheckpoints(key: string) {\n return this.opts.sessionIndex.listCompactionCheckpoints(key);\n }\n\n getCompactionCheckpoint(key: string, checkpointId: string) {\n return this.opts.sessionIndex.getCompactionCheckpointDetail(key, checkpointId);\n }\n\n async restoreCompactionCheckpoint(key: string, checkpointId: string): Promise<void> {\n await this.opts.sessionIndex.restoreCompactionCheckpoint(key, checkpointId);\n this.opts.getAgentService().evictSessionAgent(key);\n }\n\n async runCompaction(\n key: string,\n options?: { instructions?: string; force?: boolean },\n ): Promise<CompactionResult> {\n const result = await this.opts.getAgentService().sessionInspector.compact(key, options);\n if (result.compacted) {\n void this.opts.sessionIndex\n .appendTranscriptContextEntry(key, {\n text: 'Session transcript compacted',\n data: {\n firstKeptIndex: result.firstKeptIndex,\n tokensBefore: result.tokensBefore,\n tokensAfter: result.tokensAfter,\n summaryPreview: result.summary.slice(0, 500),\n },\n })\n .catch(() => {});\n }\n return result;\n }\n\n // ── Lifecycle (delete / rename / tag / pin / archive) ─────────────────\n\n async delete(key: string): Promise<{ deleted: boolean }> {\n const messages = await this.opts.sessionIndex.loadMessages(key).catch(() => []);\n const result = await this.opts.sessionIndex.deleteSession(key);\n if (result) {\n await deleteMediaUris(collectMediaUrisFromMessages(messages));\n this.opts.getAgentService().evictSessionAgent(key);\n await retireSessionMcpRuntimeForSessionKey({ sessionKey: key, reason: 'session-delete' });\n }\n return { deleted: result };\n }\n\n /** Reset transcript in place (archive + new session id); preserves session key and overrides. */\n reset(key: string): Promise<SessionResetResult> {\n return performSessionReset(key, {\n sessionIndex: this.opts.sessionIndex,\n getAgentService: this.opts.getAgentService,\n });\n }\n\n deleteMany(keys: string[]): Promise<{ success: string[]; failed: string[] }> {\n return this.opts.sessionIndex.deleteSessions(keys);\n }\n\n async rename(key: string, name: string): Promise<{ renamed: boolean }> {\n await this.opts.sessionIndex.renameSession(key, name);\n return { renamed: true };\n }\n\n async tag(key: string, tags: string[]): Promise<{ tagged: boolean }> {\n await this.opts.sessionIndex.tagSession(key, tags);\n return { tagged: true };\n }\n\n async untag(key: string, tags: string[]): Promise<{ untagged: boolean }> {\n await this.opts.sessionIndex.untagSession(key, tags);\n return { untagged: true };\n }\n\n async archive(key: string): Promise<{ archived: boolean }> {\n await this.opts.sessionIndex.archiveSession(key);\n return { archived: true };\n }\n\n async unarchive(key: string): Promise<{ unarchived: boolean }> {\n await this.opts.sessionIndex.unarchiveSession(key);\n return { unarchived: true };\n }\n\n async pin(key: string): Promise<{ pinned: boolean }> {\n await this.opts.sessionIndex.pinSession(key);\n return { pinned: true };\n }\n\n async unpin(key: string): Promise<{ unpinned: boolean }> {\n await this.opts.sessionIndex.unpinSession(key);\n return { unpinned: true };\n }\n\n // ── Search + export + stats ───────────────────────────────────────────\n\n search(query: string) {\n return this.opts.sessionIndex.searchSessions(query);\n }\n\n searchIn(key: string, keyword: string) {\n return this.opts.sessionIndex.searchInSession(key, keyword);\n }\n\n async export(key: string, format: ExportFormat): Promise<{ content: string }> {\n const content = await this.opts.sessionIndex.exportSession(key, format);\n return { content };\n }\n\n importExport(\n targetKey: string,\n jsonContent: string,\n ): Promise<{ sessionKey: string; rowCount: number }> {\n return this.opts.sessionIndex.importSessionExport(targetKey, jsonContent);\n }\n\n fork(\n key: string,\n targetKey: string,\n ): Promise<{ sessionKey: string; rowCount: number }> {\n return this.opts.sessionIndex.forkSession(key, targetKey);\n }\n\n forkRows(\n key: string,\n targetKey: string,\n options: { throughRow?: number } = {},\n ): Promise<{ sessionKey: string; rowCount: number }> {\n return this.opts.sessionIndex.forkSessionRows(key, targetKey, options);\n }\n\n btwQuery(sessionKey: string, question: string): Promise<{ text: string; error?: string }> {\n return this.opts.getAgentService().sessionInspector.btwQuery(sessionKey, question);\n }\n\n stats() {\n return this.opts.sessionIndex.getStats();\n }\n\n /**\n * Distinct chat-id pairs from sessions, grouped by channel. Used by cron job\n * configuration UI to seed the \"send to existing chat\" picker.\n */\n chatIds(channel?: string): Promise<\n Array<{\n channel: string;\n chatId: string;\n lastActive: string;\n accountId?: string;\n peerKind?: string;\n peerId?: string;\n }>\n > {\n return getDistinctSessionChatIds(this.opts.sessionIndex, channel);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sessions-api.js","names":[],"sources":["../../../../src/gateway/service/sessions-api.ts"],"sourcesContent":["/**\n * GatewaySessionsApi — session CRUD, search, compaction, tag/pin/archive,\n * stats, and chat-id grouping for the gateway REST surface.\n *\n * Twenty-four methods, previously sitting on `GatewayService` as a mix of\n * one-line `sessionIndex.*` delegations and small composite operations (e.g.\n * `restoreCheckpoint` also evicts the in-memory agent, `runCompaction` also\n * appends a transcript context entry). Centralising them here lets routes\n * depend on the narrow `GatewaySessionsApi` surface instead of the full\n * `GatewayService`, and keeps the gateway composition root focused on\n * lifecycle + wiring.\n */\n\nimport type { AgentService } from '../../agent/service.js';\nimport type { CompactionResult } from '../../agent/memory/compaction.js';\nimport { retireSessionMcpRuntimeForSessionKey } from '../../agent/mcp/bundle-mcp-tools.js';\nimport { SessionIndex } from '../../session/index.js';\nimport type { ExportFormat, SessionListQuery } from '../../session/types.js';\nimport type { SessionPatchBody } from '../../session/patch-metadata.js';\nimport { collectMediaUrisFromMessages, deleteMediaUris } from '../../media/session-references.js';\nimport { getDistinctSessionChatIds } from './session-chat-ids.js';\nimport { performSessionReset, type SessionResetResult } from '../session-reset-service.js';\n\nexport interface GatewaySessionsApiOptions {\n sessionIndex: SessionIndex;\n /** Resolves the live agent service (created lazily; throws if gateway is starting). */\n getAgentService: () => AgentService;\n /** Read-only view of in-flight webchat runs (per session key → run id). */\n getActiveWebchatRunId: (sessionKey: string) => string | undefined;\n}\n\nexport class GatewaySessionsApi {\n private readonly opts: GatewaySessionsApiOptions;\n\n constructor(opts: GatewaySessionsApiOptions) {\n this.opts = opts;\n }\n\n // ── List / get ─────────────────────────────────────────────────────────\n\n listSessions(query?: SessionListQuery) {\n return this.opts.sessionIndex.listSessions(query);\n }\n\n /** Subagent sessions have keys starting with `subagent:`. */\n listSubagents(query?: SessionListQuery) {\n return this.opts.sessionIndex.listSubagents(query);\n }\n\n getSession(\n key: string,\n options?: { includeTranscriptSummary?: boolean; includeTranscriptRows?: boolean },\n ) {\n return this.opts.sessionIndex.getSession(key, options);\n }\n\n async resolveSession(input: {\n key?: string;\n sessionKey?: string;\n sessionId?: string;\n }): Promise<\n | {\n sessionKey: string;\n sessionId: string;\n session: Awaited<ReturnType<GatewaySessionsApi['getSession']>>;\n }\n | null\n > {\n const explicitKey = input.sessionKey?.trim() || input.key?.trim();\n const resolvedKey =\n explicitKey ||\n (input.sessionId?.trim()\n ? await this.opts.sessionIndex.resolveSessionKeyBySessionId(input.sessionId.trim())\n : null);\n if (!resolvedKey) {\n return null;\n }\n const session = await this.getSession(resolvedKey);\n if (!session?.sessionId) {\n return null;\n }\n return { sessionKey: resolvedKey, sessionId: session.sessionId, session };\n }\n\n /** Read-only: in-flight webchat agent run for this session key, if any. */\n getActiveRun(sessionKey: string): { active: boolean; runId?: string } {\n const key = sessionKey.trim();\n if (!key) return { active: false };\n const runId = this.opts.getActiveWebchatRunId(key)?.trim();\n if (!runId) return { active: false };\n return { active: true, runId };\n }\n\n getMessagePage(\n key: string,\n options?: {\n offset?: number;\n limit?: number;\n before?: string;\n includeTranscriptSummary?: boolean;\n includeTranscriptRows?: boolean;\n },\n ) {\n return this.opts.sessionIndex.getSessionMessagePage(key, options);\n }\n\n // ── Metadata patches ──────────────────────────────────────────────────\n\n patch(key: string, body: SessionPatchBody): Promise<{ ok: true } | { ok: false; error: string }> {\n return this.opts.sessionIndex.patchSession(key, body);\n }\n\n async getAgentConfig(sessionKey: string) {\n return this.opts.getAgentService().sessionInspector.agentConfig(sessionKey);\n }\n\n /** Resolved markdown workspace for a session (after hydration / mkdir). */\n getEffectiveWorkspacePath(sessionKey: string): Promise<string> {\n return this.opts.getAgentService().getEffectiveWorkspacePathForSession(sessionKey);\n }\n\n patchAgentConfig(\n sessionKey: string,\n body: {\n thinkingLevel?: string;\n model?: string | null;\n reasoningLevel?: string;\n verboseLevel?: string;\n workingDirectory?: string;\n },\n ) {\n return this.opts.getAgentService().sessionConfig.patch(sessionKey, body);\n }\n\n // ── Compaction checkpoints ────────────────────────────────────────────\n\n listCompactionCheckpoints(key: string) {\n return this.opts.sessionIndex.listCompactionCheckpoints(key);\n }\n\n getCompactionCheckpoint(key: string, checkpointId: string) {\n return this.opts.sessionIndex.getCompactionCheckpointDetail(key, checkpointId);\n }\n\n async restoreCompactionCheckpoint(key: string, checkpointId: string): Promise<void> {\n await this.opts.sessionIndex.restoreCompactionCheckpoint(key, checkpointId);\n this.opts.getAgentService().evictSessionAgent(key);\n }\n\n async runCompaction(\n key: string,\n options?: { instructions?: string; force?: boolean },\n ): Promise<CompactionResult> {\n const result = await this.opts.getAgentService().sessionInspector.compact(key, options);\n if (result.compacted) {\n void this.opts.sessionIndex\n .appendTranscriptContextEntry(key, {\n text: 'Session transcript compacted',\n data: {\n firstKeptIndex: result.firstKeptIndex,\n tokensBefore: result.tokensBefore,\n tokensAfter: result.tokensAfter,\n summaryPreview: result.summary.slice(0, 500),\n },\n })\n .catch(() => {});\n }\n return result;\n }\n\n // ── Lifecycle (delete / rename / tag / pin / archive) ─────────────────\n\n async delete(key: string): Promise<{ deleted: boolean }> {\n const messages = await this.opts.sessionIndex.loadMessages(key).catch(() => []);\n const result = await this.opts.sessionIndex.deleteSession(key);\n if (result) {\n await deleteMediaUris(collectMediaUrisFromMessages(messages));\n this.opts.getAgentService().evictSessionAgent(key);\n await retireSessionMcpRuntimeForSessionKey({ sessionKey: key, reason: 'session-delete' });\n }\n return { deleted: result };\n }\n\n /** Reset transcript in place (archive + new session id); preserves session key and overrides. */\n reset(key: string): Promise<SessionResetResult> {\n return performSessionReset(key, {\n sessionIndex: this.opts.sessionIndex,\n getAgentService: this.opts.getAgentService,\n });\n }\n\n deleteMany(keys: string[]): Promise<{ success: string[]; failed: string[] }> {\n return this.opts.sessionIndex.deleteSessions(keys);\n }\n\n async rename(key: string, name: string): Promise<{ renamed: boolean }> {\n await this.opts.sessionIndex.renameSession(key, name);\n return { renamed: true };\n }\n\n async tag(key: string, tags: string[]): Promise<{ tagged: boolean }> {\n await this.opts.sessionIndex.tagSession(key, tags);\n return { tagged: true };\n }\n\n async untag(key: string, tags: string[]): Promise<{ untagged: boolean }> {\n await this.opts.sessionIndex.untagSession(key, tags);\n return { untagged: true };\n }\n\n async archive(key: string): Promise<{ archived: boolean }> {\n await this.opts.sessionIndex.archiveSession(key);\n return { archived: true };\n }\n\n async unarchive(key: string): Promise<{ unarchived: boolean }> {\n await this.opts.sessionIndex.unarchiveSession(key);\n return { unarchived: true };\n }\n\n async pin(key: string): Promise<{ pinned: boolean }> {\n await this.opts.sessionIndex.pinSession(key);\n return { pinned: true };\n }\n\n async unpin(key: string): Promise<{ unpinned: boolean }> {\n await this.opts.sessionIndex.unpinSession(key);\n return { unpinned: true };\n }\n\n // ── Search + export + stats ───────────────────────────────────────────\n\n search(query: string) {\n return this.opts.sessionIndex.searchSessions(query);\n }\n\n searchIn(key: string, keyword: string) {\n return this.opts.sessionIndex.searchInSession(key, keyword);\n }\n\n async export(key: string, format: ExportFormat): Promise<{ content: string }> {\n const content = await this.opts.sessionIndex.exportSession(key, format);\n return { content };\n }\n\n importExport(\n targetKey: string,\n jsonContent: string,\n ): Promise<{ sessionKey: string; rowCount: number }> {\n return this.opts.sessionIndex.importSessionExport(targetKey, jsonContent);\n }\n\n fork(\n key: string,\n targetKey: string,\n ): Promise<{ sessionKey: string; rowCount: number }> {\n return this.opts.sessionIndex.forkSession(key, targetKey);\n }\n\n forkRows(\n key: string,\n targetKey: string,\n options: { throughRow?: number } = {},\n ): Promise<{ sessionKey: string; rowCount: number }> {\n return this.opts.sessionIndex.forkSessionRows(key, targetKey, options);\n }\n\n btwQuery(sessionKey: string, question: string): Promise<{ text: string; error?: string }> {\n return this.opts.getAgentService().sessionInspector.btwQuery(sessionKey, question);\n }\n\n stats() {\n return this.opts.sessionIndex.getStats();\n }\n\n /**\n * Distinct chat-id pairs from sessions, grouped by channel. Used by cron job\n * configuration UI to seed the \"send to existing chat\" picker.\n */\n chatIds(channel?: string): Promise<\n Array<{\n channel: string;\n chatId: string;\n lastActive: string;\n accountId?: string;\n peerKind?: string;\n peerId?: string;\n }>\n > {\n return getDistinctSessionChatIds(this.opts.sessionIndex, channel);\n }\n}\n"],"mappings":"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"}
|
|
@@ -84,7 +84,7 @@ export declare class GatewayService {
|
|
|
84
84
|
runAgent(...args: Parameters<GatewayAgentRunner['runAgent']>): ReturnType<GatewayAgentRunner['runAgent']>;
|
|
85
85
|
abortAgentRun(runId: string): boolean;
|
|
86
86
|
getActiveWebchatRunId(sessionKey: string): string | undefined;
|
|
87
|
-
steerWebchatAgent(
|
|
87
|
+
steerWebchatAgent(sessionKey: string, message: string): ReturnType<GatewayAgentRunner['steerWebchatAgent']>;
|
|
88
88
|
submitClarifyResponse(requestId: string, answer: string): boolean;
|
|
89
89
|
private initializeExtensionLoader;
|
|
90
90
|
private registerExtensionChannelPlugins;
|
|
@@ -345,14 +345,27 @@ var GatewayService = class {
|
|
|
345
345
|
ensureSession: async (goal) => {
|
|
346
346
|
const existing = goal.activeSessionKey?.trim();
|
|
347
347
|
if (existing) return existing;
|
|
348
|
+
const agentId = goal.agentId || getDefaultAgentId(this.config);
|
|
349
|
+
const peerId = `goal-${sanitizeSegment(goal.id) || Date.now()}`;
|
|
348
350
|
const sessionKey = buildSessionKey({
|
|
349
|
-
agentId
|
|
351
|
+
agentId,
|
|
350
352
|
source: "webchat",
|
|
351
353
|
accountId: "default",
|
|
352
354
|
peerKind: "direct",
|
|
353
|
-
peerId
|
|
355
|
+
peerId
|
|
354
356
|
});
|
|
355
|
-
await this.sessionIndex.saveMessages(sessionKey, []
|
|
357
|
+
await this.sessionIndex.saveMessages(sessionKey, [], { metadata: {
|
|
358
|
+
sourceChannel: "webchat",
|
|
359
|
+
sourceChatId: `default:direct:${peerId}`,
|
|
360
|
+
sessionType: "chat",
|
|
361
|
+
routing: {
|
|
362
|
+
agentId,
|
|
363
|
+
source: "webchat",
|
|
364
|
+
accountId: "default",
|
|
365
|
+
peerKind: "direct",
|
|
366
|
+
peerId
|
|
367
|
+
}
|
|
368
|
+
} });
|
|
356
369
|
const { GoalService } = await import("../goals/index.js");
|
|
357
370
|
new GoalService().attachSession(goal.id, sessionKey);
|
|
358
371
|
return sessionKey;
|
|
@@ -366,6 +379,7 @@ var GatewayService = class {
|
|
|
366
379
|
createGoalNotificationService() {
|
|
367
380
|
if (!this.goalNotifications) this.goalNotifications = new GoalNotificationService({
|
|
368
381
|
getConfig: () => this.config,
|
|
382
|
+
getSessionMetadata: (sessionKey) => this.sessionIndex.getSessionMetadata(sessionKey),
|
|
369
383
|
send: async (target) => {
|
|
370
384
|
await this.channelManager.send({
|
|
371
385
|
channel: target.channel,
|
|
@@ -401,8 +415,8 @@ var GatewayService = class {
|
|
|
401
415
|
getActiveWebchatRunId(sessionKey) {
|
|
402
416
|
return this.agentRunner.getActiveRunId(sessionKey);
|
|
403
417
|
}
|
|
404
|
-
steerWebchatAgent(
|
|
405
|
-
return this.agentRunner.steerWebchatAgent(
|
|
418
|
+
steerWebchatAgent(sessionKey, message) {
|
|
419
|
+
return this.agentRunner.steerWebchatAgent(sessionKey, message);
|
|
406
420
|
}
|
|
407
421
|
submitClarifyResponse(requestId, answer) {
|
|
408
422
|
return this.agentRunner.submitClarifyResponse(requestId, answer);
|