@xopcai/xopc 0.0.99 → 0.0.101
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/src/account-manager.d.ts +3 -3
- package/dist/extensions/telegram/src/account-manager.js +8 -8
- package/dist/extensions/telegram/src/account-manager.js.map +1 -1
- package/dist/extensions/telegram/src/actions/message-actions.d.ts +4 -0
- package/dist/extensions/telegram/src/actions/message-actions.js +71 -0
- package/dist/extensions/telegram/src/actions/message-actions.js.map +1 -0
- package/dist/extensions/telegram/src/adapters/config-adapter.js +9 -1
- package/dist/extensions/telegram/src/adapters/config-adapter.js.map +1 -1
- package/dist/extensions/telegram/src/adapters/config-surface.js +1 -1
- package/dist/extensions/telegram/src/adapters/config-surface.js.map +1 -1
- package/dist/extensions/telegram/src/adapters/outbound-adapter.d.ts +2 -1
- package/dist/extensions/telegram/src/adapters/outbound-adapter.js +18 -4
- package/dist/extensions/telegram/src/adapters/outbound-adapter.js.map +1 -1
- package/dist/extensions/telegram/src/adapters/security-adapter.js +2 -1
- package/dist/extensions/telegram/src/adapters/security-adapter.js.map +1 -1
- package/dist/extensions/telegram/src/adapters/streaming-adapter.js +90 -6
- package/dist/extensions/telegram/src/adapters/streaming-adapter.js.map +1 -1
- package/dist/extensions/telegram/src/adapters/types.d.ts +9 -1
- package/dist/extensions/telegram/src/api-root.d.ts +4 -0
- package/dist/extensions/telegram/src/api-root.js +42 -0
- package/dist/extensions/telegram/src/api-root.js.map +1 -0
- package/dist/extensions/telegram/src/approval-delivery.d.ts +9 -0
- package/dist/extensions/telegram/src/approval-delivery.js +36 -0
- package/dist/extensions/telegram/src/approval-delivery.js.map +1 -0
- package/dist/extensions/telegram/src/approval-store.d.ts +25 -0
- package/dist/extensions/telegram/src/approval-store.js +61 -0
- package/dist/extensions/telegram/src/approval-store.js.map +1 -0
- package/dist/extensions/telegram/src/config-schema.d.ts +185 -35
- package/dist/extensions/telegram/src/config-schema.js +67 -45
- package/dist/extensions/telegram/src/config-schema.js.map +1 -1
- package/dist/extensions/telegram/src/conversation-id.d.ts +6 -0
- package/dist/extensions/telegram/src/conversation-id.js +18 -0
- package/dist/extensions/telegram/src/conversation-id.js.map +1 -0
- package/dist/extensions/telegram/src/doctor.d.ts +5 -0
- package/dist/extensions/telegram/src/doctor.js +80 -0
- package/dist/extensions/telegram/src/doctor.js.map +1 -0
- package/dist/extensions/telegram/src/exec-approval-handler.d.ts +7 -0
- package/dist/extensions/telegram/src/exec-approval-handler.js +36 -0
- package/dist/extensions/telegram/src/exec-approval-handler.js.map +1 -0
- package/dist/extensions/telegram/src/exec-approvals.d.ts +8 -0
- package/dist/extensions/telegram/src/exec-approvals.js +20 -0
- package/dist/extensions/telegram/src/exec-approvals.js.map +1 -0
- package/dist/extensions/telegram/src/focus-handler.d.ts +12 -0
- package/dist/extensions/telegram/src/focus-handler.js +55 -0
- package/dist/extensions/telegram/src/focus-handler.js.map +1 -0
- package/dist/extensions/telegram/src/group-config-resolver.d.ts +12 -0
- package/dist/extensions/telegram/src/group-config-resolver.js +17 -0
- package/dist/extensions/telegram/src/group-config-resolver.js.map +1 -0
- package/dist/extensions/telegram/src/inbound-coalescer.d.ts +15 -0
- package/dist/extensions/telegram/src/inbound-coalescer.js +107 -0
- package/dist/extensions/telegram/src/inbound-coalescer.js.map +1 -0
- package/dist/extensions/telegram/src/inbound-processor.d.ts +1 -0
- package/dist/extensions/telegram/src/inbound-processor.js +41 -4
- package/dist/extensions/telegram/src/inbound-processor.js.map +1 -1
- package/dist/extensions/telegram/src/network-errors.d.ts +2 -0
- package/dist/extensions/telegram/src/network-errors.js +23 -0
- package/dist/extensions/telegram/src/network-errors.js.map +1 -0
- package/dist/extensions/telegram/src/plugin.d.ts +11 -0
- package/dist/extensions/telegram/src/plugin.js +191 -57
- package/dist/extensions/telegram/src/plugin.js.map +1 -1
- package/dist/extensions/telegram/src/polling-session.d.ts +17 -0
- package/dist/extensions/telegram/src/polling-session.js +112 -0
- package/dist/extensions/telegram/src/polling-session.js.map +1 -0
- package/dist/extensions/telegram/src/proxy-fetch.d.ts +2 -0
- package/dist/extensions/telegram/src/proxy-fetch.js +14 -0
- package/dist/extensions/telegram/src/proxy-fetch.js.map +1 -0
- package/dist/extensions/telegram/src/reactions.d.ts +14 -0
- package/dist/extensions/telegram/src/reactions.js +48 -0
- package/dist/extensions/telegram/src/reactions.js.map +1 -0
- package/dist/extensions/telegram/src/reply-params.d.ts +15 -0
- package/dist/extensions/telegram/src/reply-params.js +28 -0
- package/dist/extensions/telegram/src/reply-params.js.map +1 -0
- package/dist/extensions/telegram/src/startup-errors.d.ts +3 -0
- package/dist/extensions/telegram/src/startup-errors.js +27 -0
- package/dist/extensions/telegram/src/startup-errors.js.map +1 -0
- package/dist/extensions/telegram/src/telegram-actions.d.ts +25 -0
- package/dist/extensions/telegram/src/telegram-actions.js +65 -0
- package/dist/extensions/telegram/src/telegram-actions.js.map +1 -0
- package/dist/extensions/telegram/src/thread-bindings.d.ts +15 -0
- package/dist/extensions/telegram/src/thread-bindings.js +22 -0
- package/dist/extensions/telegram/src/thread-bindings.js.map +1 -0
- package/dist/extensions/telegram/src/token-resolver.d.ts +8 -0
- package/dist/extensions/telegram/src/token-resolver.js +34 -0
- package/dist/extensions/telegram/src/token-resolver.js.map +1 -0
- package/dist/extensions/telegram/src/update-offset-store.d.ts +9 -0
- package/dist/extensions/telegram/src/update-offset-store.js +66 -0
- package/dist/extensions/telegram/src/update-offset-store.js.map +1 -0
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +5 -3
- package/dist/extensions/weixin/src/api/api.js.map +1 -1
- package/dist/gateway/static/root/assets/{agents-4KTK-Ku7.js → agents-u8cmUfGQ.js} +2 -2
- package/dist/gateway/static/root/assets/{apps-page-DkgInY2w.js → apps-page-DF8m9cUE.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-preview-renderer-DBAxQXb-.js → attachment-preview-renderer-CybMSIoS.js} +2 -2
- package/dist/gateway/static/root/assets/{attachment-process-heavy-Csq3TrrP.js → attachment-process-heavy-RnGYy9bC.js} +2 -2
- package/dist/gateway/static/root/assets/channels-settings-BM3doRvi.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-ah4zWEIP.js +8 -0
- package/dist/gateway/static/root/assets/{cron-api-BRDli2Mm.js → cron-api-DgMuL_2b.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-BzEr5Za8.js → cron-page-COfUPKfq.js} +1 -1
- package/dist/gateway/static/root/assets/{dist-BsHh1vX0.js → dist-Dzy3Q0ZH.js} +1 -1
- package/dist/gateway/static/root/assets/{docx-preview-Dxj1EkCO.js → docx-preview-CajIk2FR.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-TWt5q_ef.js → extension-debug-page-kyxxefKh.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-C3kV8ZvZ.js → extension-page-BVbCBHoI.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-Csy9LNC6.js → extension-settings-page-t1lb2A7v.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-BLLOP2CM.js → fetch-drJUxxKP.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-MXbM8HvY.js → field-primitives-6Vo1Yga4.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-CkoyqfRx.js → heartbeat-config-api-BF3psu4O.js} +1 -1
- package/dist/gateway/static/root/assets/index-DjNDHzwG.css +1 -0
- package/dist/gateway/static/root/assets/index-WAyKAilR.js +4840 -0
- package/dist/gateway/static/root/assets/{logs-page-B2vY41ph.js → logs-page-BTVPXcHV.js} +1 -1
- package/dist/gateway/static/root/assets/{note-detail-page-B7qE5pkO.js → note-detail-page-DqSAg_5Z.js} +1 -1
- package/dist/gateway/static/root/assets/{note-time-NBBReVR4.js → note-time-FSOjchic.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-CsWYaqYM.js → notes-page-DkRX7BE2.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-BPGY3SCT.js → sessions-page-Khdw35Zk.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-advanced-gate-DtA451RM.js → settings-advanced-gate-DspC8oEm.js} +2 -2
- package/dist/gateway/static/root/assets/{settings-form-section-DYR_SPlX.js → settings-form-section-DuxvUuur.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-BJUgZQzN.js → settings-page-DN8JBZ8F.js} +2 -2
- package/dist/gateway/static/root/assets/{share-preview-page-3u8VFmdo.js → share-preview-page-UNAcbiMb.js} +2 -2
- package/dist/gateway/static/root/assets/{skills-page-DuyhcH4U.js → skills-page-ByYT0fXZ.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-e2q2yjs4.js → theme-store-B6KXPHgK.js} +1 -1
- package/dist/gateway/static/root/assets/url-q28QhI7l.js +3 -0
- package/dist/gateway/static/root/assets/{utils-B4Vw3fnc.js → utils-DK_1H47k.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-BFY67Hhp.js → voice-api-key-field-BYN2EIMs.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-page.utils-yUJ5jexd.js → workflow-page.utils-Bi19YNTr.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-DIMHCpNt.js → workflows-page-DP57FEKW.js} +1 -1
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +4 -0
- package/dist/src/agent/agent-manager.js +84 -4
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/child-agent-factory.d.ts +1 -0
- package/dist/src/agent/child-agent-factory.js +13 -10
- package/dist/src/agent/child-agent-factory.js.map +1 -1
- package/dist/src/agent/embedded/run-for-session.d.ts +1 -0
- package/dist/src/agent/embedded/run-for-session.js +2 -0
- package/dist/src/agent/embedded/run-for-session.js.map +1 -1
- package/dist/src/agent/embedded/run-turn.js +1 -17
- package/dist/src/agent/embedded/run-turn.js.map +1 -1
- package/dist/src/agent/embedded/session-runner.js +3 -1
- package/dist/src/agent/embedded/session-runner.js.map +1 -1
- package/dist/src/agent/embedded/session-tool-result-guard.d.ts +1 -0
- package/dist/src/agent/embedded/session-tool-result-guard.js +1 -0
- package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
- package/dist/src/agent/inbound/attachment-pipeline.d.ts +37 -0
- package/dist/src/agent/inbound/attachment-pipeline.js +169 -0
- package/dist/src/agent/inbound/attachment-pipeline.js.map +1 -0
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +3 -5
- package/dist/src/agent/inbound/turn-dispatcher.js +1 -2
- package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
- package/dist/src/agent/memory/index.d.ts +2 -0
- package/dist/src/agent/memory/index.js +2 -1
- package/dist/src/agent/memory/memory-flush.d.ts +27 -0
- package/dist/src/agent/memory/memory-flush.js +124 -0
- package/dist/src/agent/memory/memory-flush.js.map +1 -0
- package/dist/src/agent/messaging/outbound-coordinator.js +2 -1
- package/dist/src/agent/messaging/outbound-coordinator.js.map +1 -1
- package/dist/src/agent/messaging/stream-manager.d.ts +2 -0
- package/dist/src/agent/messaging/stream-manager.js +3 -0
- package/dist/src/agent/messaging/stream-manager.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.d.ts +0 -4
- package/dist/src/agent/orchestration/agent-orchestrator.js +40 -107
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/prompt/contribution.d.ts +9 -0
- package/dist/src/agent/prompt/contribution.js +1 -0
- package/dist/src/agent/prompt/safety.js +0 -10
- package/dist/src/agent/prompt/safety.js.map +1 -1
- package/dist/src/agent/prompt/sanitize-for-prompt.d.ts +6 -0
- package/dist/src/agent/prompt/sanitize-for-prompt.js +13 -0
- package/dist/src/agent/prompt/sanitize-for-prompt.js.map +1 -0
- package/dist/src/agent/prompt/sections/behavior.d.ts +5 -0
- package/dist/src/agent/prompt/sections/behavior.js +50 -0
- package/dist/src/agent/prompt/sections/behavior.js.map +1 -0
- package/dist/src/agent/prompt/sections/memory-skills.d.ts +9 -0
- package/dist/src/agent/prompt/sections/memory-skills.js +59 -0
- package/dist/src/agent/prompt/sections/memory-skills.js.map +1 -0
- package/dist/src/agent/prompt/sections/messaging-runtime.d.ts +16 -0
- package/dist/src/agent/prompt/sections/messaging-runtime.js +69 -0
- package/dist/src/agent/prompt/sections/messaging-runtime.js.map +1 -0
- package/dist/src/agent/prompt/sections/project-context.d.ts +16 -0
- package/dist/src/agent/prompt/sections/project-context.js +58 -0
- package/dist/src/agent/prompt/sections/project-context.js.map +1 -0
- package/dist/src/agent/prompt/sections/tooling.d.ts +5 -0
- package/dist/src/agent/prompt/sections/tooling.js +119 -0
- package/dist/src/agent/prompt/sections/tooling.js.map +1 -0
- package/dist/src/agent/prompt/sections/workspace-runtime.d.ts +11 -0
- package/dist/src/agent/prompt/sections/workspace-runtime.js +32 -0
- package/dist/src/agent/prompt/sections/workspace-runtime.js.map +1 -0
- package/dist/src/agent/prompt/service-prompt-builder.d.ts +13 -0
- package/dist/src/agent/prompt/service-prompt-builder.js +54 -13
- package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
- package/dist/src/agent/prompt/subagent-context.d.ts +15 -0
- package/dist/src/agent/prompt/subagent-context.js +68 -0
- package/dist/src/agent/prompt/subagent-context.js.map +1 -0
- package/dist/src/agent/prompt/system-prompt-params.d.ts +53 -0
- package/dist/src/agent/prompt/system-prompt-params.js +74 -0
- package/dist/src/agent/prompt/system-prompt-params.js.map +1 -0
- package/dist/src/agent/prompt/system-prompt.d.ts +22 -11
- package/dist/src/agent/prompt/system-prompt.js +79 -193
- package/dist/src/agent/prompt/system-prompt.js.map +1 -1
- package/dist/src/agent/prompt/types.d.ts +3 -0
- package/dist/src/agent/service/build-direct-message-content.d.ts +5 -21
- package/dist/src/agent/service/build-direct-message-content.js +11 -64
- package/dist/src/agent/service/build-direct-message-content.js.map +1 -1
- package/dist/src/agent/service/direct-turn-helpers.d.ts +1 -1
- package/dist/src/agent/service/direct-turn-helpers.js +7 -0
- package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
- package/dist/src/agent/service/process-direct-one-shot.d.ts +3 -3
- package/dist/src/agent/service/process-direct-one-shot.js +22 -17
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.d.ts +6 -20
- package/dist/src/agent/service/process-direct-streaming.js +39 -40
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service/webchat-tts.d.ts +4 -9
- package/dist/src/agent/service/webchat-tts.js +9 -20
- package/dist/src/agent/service/webchat-tts.js.map +1 -1
- package/dist/src/agent/service.d.ts +8 -19
- package/dist/src/agent/service.js +53 -11
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/tools/factory.js +2 -0
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +1 -0
- package/dist/src/agent/tools/index.js +2 -1
- package/dist/src/agent/tools/media-read-tool.d.ts +2 -0
- package/dist/src/agent/tools/media-read-tool.js +89 -0
- package/dist/src/agent/tools/media-read-tool.js.map +1 -0
- package/dist/src/auth/credentials.js +0 -1
- package/dist/src/auth/credentials.js.map +1 -1
- package/dist/src/channels/attachments/attachment-classifiers.d.ts +8 -0
- package/dist/src/channels/attachments/attachment-classifiers.js +11 -0
- package/dist/src/channels/attachments/attachment-classifiers.js.map +1 -0
- package/dist/src/channels/attachments/inbound-persist.d.ts +13 -34
- package/dist/src/channels/attachments/inbound-persist.js +34 -102
- package/dist/src/channels/attachments/inbound-persist.js.map +1 -1
- package/dist/src/channels/attachments/inbound-types.d.ts +13 -0
- package/dist/src/channels/attachments/inbound-types.js +30 -0
- package/dist/src/channels/attachments/inbound-types.js.map +1 -0
- package/dist/src/channels/attachments/outbound-tts-persist.d.ts +3 -12
- package/dist/src/channels/attachments/outbound-tts-persist.js +28 -48
- package/dist/src/channels/attachments/outbound-tts-persist.js.map +1 -1
- package/dist/src/channels/attachments/voice-stt-webchat.d.ts +3 -3
- package/dist/src/channels/attachments/voice-stt-webchat.js +8 -14
- package/dist/src/channels/attachments/voice-stt-webchat.js.map +1 -1
- package/dist/src/channels/channel-domain.d.ts +30 -2
- package/dist/src/channels/exec-approval-runtime.d.ts +29 -0
- package/dist/src/channels/exec-approval-runtime.js +30 -0
- package/dist/src/channels/exec-approval-runtime.js.map +1 -0
- package/dist/src/channels/index.js +1 -1
- package/dist/src/channels/plugin-types.d.ts +1 -0
- package/dist/src/channels/transport-types.d.ts +2 -2
- package/dist/src/cli/bin.d.ts +1 -0
- package/dist/src/cli/bin.js +1 -0
- package/dist/src/cli/bin.js.map +1 -1
- package/dist/src/cli/commands/channels.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/database-schema.js +62 -0
- package/dist/src/cli/commands/doctor/checks/database-schema.js.map +1 -0
- package/dist/src/cli/commands/doctor/flow.js +2 -0
- package/dist/src/cli/commands/doctor/flow.js.map +1 -1
- package/dist/src/cli/commands/init.js +2 -57
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/onboard/channels/registry.js +1 -1
- package/dist/src/cli/commands/setup.js +6 -5
- package/dist/src/cli/commands/setup.js.map +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +1 -2
- package/dist/src/cli/utils/init-workspace-core.js.map +1 -1
- package/dist/src/config/index.js +2 -2
- package/dist/src/config/paths.d.ts +0 -13
- package/dist/src/config/paths.js +1 -20
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/rules.js +1 -1
- package/dist/src/config/schema.d.ts +24 -0
- package/dist/src/config/schema.js +33 -2
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/oauth-async.js +36 -3
- package/dist/src/gateway/hono/oauth-async.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/channels.js +3 -3
- package/dist/src/gateway/hono/routes/config-patch/channels.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/media.d.ts +3 -0
- package/dist/src/gateway/hono/routes/media.js +50 -0
- package/dist/src/gateway/hono/routes/media.js.map +1 -0
- package/dist/src/gateway/hono/routes/sessions.js +6 -0
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +1 -87
- package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
- package/dist/src/gateway/service/sessions-api.js +3 -0
- package/dist/src/gateway/service/sessions-api.js.map +1 -1
- package/dist/src/infra/http-proxy-env.d.ts +4 -0
- package/dist/src/infra/http-proxy-env.js +23 -0
- package/dist/src/infra/http-proxy-env.js.map +1 -0
- package/dist/src/media/index.d.ts +5 -0
- package/dist/src/media/index.js +5 -0
- package/dist/src/media/media-reference.d.ts +23 -0
- package/dist/src/media/media-reference.js +34 -0
- package/dist/src/media/media-reference.js.map +1 -0
- package/dist/src/media/paths.d.ts +5 -0
- package/dist/src/media/paths.js +20 -0
- package/dist/src/media/paths.js.map +1 -0
- package/dist/src/media/session-references.d.ts +8 -0
- package/dist/src/media/session-references.js +45 -0
- package/dist/src/media/session-references.js.map +1 -0
- package/dist/src/media/store.d.ts +19 -0
- package/dist/src/media/store.js +131 -0
- package/dist/src/media/store.js.map +1 -0
- package/dist/src/media/types.d.ts +34 -0
- package/dist/src/media/types.js +1 -0
- package/dist/src/media/uri.d.ts +15 -0
- package/dist/src/media/uri.js +51 -0
- package/dist/src/media/uri.js.map +1 -0
- package/dist/src/session/session-title.js +6 -3
- package/dist/src/session/session-title.js.map +1 -1
- package/dist/src/session/store.js +1 -1
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/types.d.ts +12 -7
- package/dist/src/session/types.js.map +1 -1
- package/dist/src/storage/sqlite/index.d.ts +4 -1
- package/dist/src/storage/sqlite/index.js +6 -2
- package/dist/src/storage/sqlite/migrations/002_add_flush_columns.sql +3 -0
- package/dist/src/storage/sqlite/migrations/discover.d.ts +4 -0
- package/dist/src/storage/sqlite/migrations/discover.js +38 -0
- package/dist/src/storage/sqlite/migrations/discover.js.map +1 -0
- package/dist/src/storage/sqlite/migrations/discover.ts +52 -0
- package/dist/src/storage/sqlite/migrations/errors.d.ts +11 -0
- package/dist/src/storage/sqlite/migrations/errors.js +27 -0
- package/dist/src/storage/sqlite/migrations/errors.js.map +1 -0
- package/dist/src/storage/sqlite/migrations/errors.ts +32 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +22 -0
- package/dist/src/storage/sqlite/migrations/runner.js +97 -0
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -0
- package/dist/src/storage/sqlite/migrations/runner.ts +153 -0
- package/dist/src/storage/sqlite/migrations/types.d.ts +12 -0
- package/dist/src/storage/sqlite/migrations/types.js +1 -0
- package/dist/src/storage/sqlite/migrations/types.ts +13 -0
- package/dist/src/storage/sqlite/row-mappers.d.ts +4 -0
- package/dist/src/storage/sqlite/row-mappers.js +4 -0
- package/dist/src/storage/sqlite/row-mappers.js.map +1 -1
- package/dist/src/storage/sqlite/schema-version.d.ts +6 -0
- package/dist/src/storage/sqlite/schema-version.js +29 -0
- package/dist/src/storage/sqlite/schema-version.js.map +1 -0
- package/dist/src/storage/sqlite/schema.d.ts +5 -3
- package/dist/src/storage/sqlite/schema.js +24 -28
- package/dist/src/storage/sqlite/schema.js.map +1 -1
- package/dist/src/storage/sqlite/schema.sql +2 -0
- package/dist/src/storage/sqlite/session-metadata.js +1 -0
- package/dist/src/storage/sqlite/session-metadata.js.map +1 -1
- package/dist/src/storage/sqlite/session-repository.js +7 -3
- package/dist/src/storage/sqlite/session-repository.js.map +1 -1
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/channels-settings-BxW1Xio4.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-Cxm6AvQO.js +0 -8
- package/dist/gateway/static/root/assets/index-BJDmBCSl.css +0 -1
- package/dist/gateway/static/root/assets/index-Cbg5TS5m.js +0 -4707
- package/dist/gateway/static/root/assets/url-DpFBIyN9.js +0 -3
- package/dist/src/cli/commands/onboard/workspace.d.ts +0 -14
- package/dist/src/cli/commands/onboard/workspace.js +0 -33
- package/dist/src/cli/commands/onboard/workspace.js.map +0 -1
- package/dist/src/cli/utils/workspace.d.ts +0 -35
- package/dist/src/cli/utils/workspace.js +0 -72
- package/dist/src/cli/utils/workspace.js.map +0 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CompactionResult } from './compaction.js';
|
|
2
|
+
export interface MemoryFlushConfig {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
threshold: number;
|
|
5
|
+
softThresholdTokens: number;
|
|
6
|
+
afterCompactions: number;
|
|
7
|
+
maxEntryChars: number;
|
|
8
|
+
includeToolHistory: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface MemoryFlushOptions {
|
|
11
|
+
workspaceDir: string;
|
|
12
|
+
sessionKey: string;
|
|
13
|
+
compactionResult: CompactionResult;
|
|
14
|
+
config: MemoryFlushConfig;
|
|
15
|
+
}
|
|
16
|
+
export interface MemoryFlushResult {
|
|
17
|
+
flushed: boolean;
|
|
18
|
+
entryPath: string;
|
|
19
|
+
entryLength: number;
|
|
20
|
+
reason?: string;
|
|
21
|
+
}
|
|
22
|
+
export declare class MemoryFlushService {
|
|
23
|
+
flush(options: MemoryFlushOptions): Promise<MemoryFlushResult>;
|
|
24
|
+
private buildEntry;
|
|
25
|
+
/** YYYY-MM-DD in local time (for daily `memory/YYYY-MM-DD.md` names). */
|
|
26
|
+
private isoDay;
|
|
27
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { createLogger } from "../../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../../utils/logger.js";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
6
|
+
//#region src/agent/memory/memory-flush.ts
|
|
7
|
+
init_logger();
|
|
8
|
+
const log = createLogger("MemoryFlush");
|
|
9
|
+
var MemoryFlushService = class {
|
|
10
|
+
async flush(options) {
|
|
11
|
+
const { workspaceDir, sessionKey, compactionResult, config } = options;
|
|
12
|
+
if (!config.enabled) return {
|
|
13
|
+
flushed: false,
|
|
14
|
+
entryPath: "",
|
|
15
|
+
entryLength: 0,
|
|
16
|
+
reason: "disabled"
|
|
17
|
+
};
|
|
18
|
+
const now = /* @__PURE__ */ new Date();
|
|
19
|
+
const day = this.isoDay(now);
|
|
20
|
+
const memoryDir = join(workspaceDir, "memory");
|
|
21
|
+
const filePath = join(memoryDir, `${day}.md`);
|
|
22
|
+
const entryPath = `memory/${day}.md`;
|
|
23
|
+
await mkdir(memoryDir, { recursive: true });
|
|
24
|
+
const entryText = this.buildEntry(sessionKey, compactionResult, now, config).text;
|
|
25
|
+
const entryLength = entryText.length;
|
|
26
|
+
if (entryLength > config.maxEntryChars) log.warn({
|
|
27
|
+
sessionKey,
|
|
28
|
+
entryLength,
|
|
29
|
+
maxEntryChars: config.maxEntryChars
|
|
30
|
+
}, "Flush entry exceeds maxEntryChars; truncating");
|
|
31
|
+
try {
|
|
32
|
+
if (!existsSync(filePath)) await writeFile(filePath, `# Daily Notes — ${day}\n\n` + entryText, "utf-8");
|
|
33
|
+
else {
|
|
34
|
+
const existing = await readFile(filePath, "utf-8");
|
|
35
|
+
if (existing.length > 5e4) log.warn({
|
|
36
|
+
sessionKey,
|
|
37
|
+
filePath,
|
|
38
|
+
size: existing.length
|
|
39
|
+
}, "Daily notes file is large; continuing append");
|
|
40
|
+
await appendFile(filePath, "\n" + entryText, "utf-8");
|
|
41
|
+
}
|
|
42
|
+
log.info({
|
|
43
|
+
sessionKey,
|
|
44
|
+
entryPath,
|
|
45
|
+
entryLength
|
|
46
|
+
}, "Memory flushed to daily notes");
|
|
47
|
+
return {
|
|
48
|
+
flushed: true,
|
|
49
|
+
entryPath,
|
|
50
|
+
entryLength
|
|
51
|
+
};
|
|
52
|
+
} catch (err) {
|
|
53
|
+
const em = err instanceof Error ? err.message : String(err);
|
|
54
|
+
log.error({
|
|
55
|
+
sessionKey,
|
|
56
|
+
err,
|
|
57
|
+
filePath
|
|
58
|
+
}, `Memory flush failed: ${em}`);
|
|
59
|
+
return {
|
|
60
|
+
flushed: false,
|
|
61
|
+
entryPath,
|
|
62
|
+
entryLength: 0,
|
|
63
|
+
reason: `write_error: ${em}`
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
buildEntry(sessionKey, result, now, config) {
|
|
68
|
+
const iso = now.toISOString();
|
|
69
|
+
const lines = [];
|
|
70
|
+
lines.push(`## Session Flush [${sessionKey}] ${iso}`);
|
|
71
|
+
lines.push("");
|
|
72
|
+
const summary = result.summary || "";
|
|
73
|
+
lines.push(`**Summary:** ${summary}`);
|
|
74
|
+
lines.push("");
|
|
75
|
+
const structured = result.structuredSummary;
|
|
76
|
+
if (structured) {
|
|
77
|
+
if (structured.userRequests && structured.userRequests.length > 0) {
|
|
78
|
+
lines.push("**User Requests:**");
|
|
79
|
+
for (const req of structured.userRequests) lines.push(`- ${req}`);
|
|
80
|
+
lines.push("");
|
|
81
|
+
}
|
|
82
|
+
if (structured.keyDecisions && structured.keyDecisions.length > 0) {
|
|
83
|
+
lines.push("**Key Decisions:**");
|
|
84
|
+
for (const decision of structured.keyDecisions) lines.push(`- ${decision}`);
|
|
85
|
+
lines.push("");
|
|
86
|
+
}
|
|
87
|
+
if (structured.filesModified && structured.filesModified.length > 0) {
|
|
88
|
+
lines.push("**Files Modified:**");
|
|
89
|
+
for (const file of structured.filesModified) lines.push(`- ${file}`);
|
|
90
|
+
lines.push("");
|
|
91
|
+
}
|
|
92
|
+
if (config.includeToolHistory && structured.toolCalls && structured.toolCalls.length > 0) {
|
|
93
|
+
lines.push("**Tool Calls:**");
|
|
94
|
+
for (const call of structured.toolCalls) {
|
|
95
|
+
const filePart = call.filePath ? ` (${call.filePath})` : "";
|
|
96
|
+
const status = call.success ? "success" : "failed";
|
|
97
|
+
lines.push(`- \`${call.toolName}\`${filePart} — ${status}`);
|
|
98
|
+
}
|
|
99
|
+
lines.push("");
|
|
100
|
+
}
|
|
101
|
+
} else if (summary) {
|
|
102
|
+
lines.push("**Summary (text only):**");
|
|
103
|
+
lines.push(summary);
|
|
104
|
+
lines.push("");
|
|
105
|
+
}
|
|
106
|
+
lines.push("---");
|
|
107
|
+
let text = lines.join("\n");
|
|
108
|
+
if (text.length > config.maxEntryChars) {
|
|
109
|
+
const headerEnd = text.indexOf("\n\n") + 2;
|
|
110
|
+
const header = text.slice(0, headerEnd);
|
|
111
|
+
const remainingBudget = config.maxEntryChars - header.length - 60;
|
|
112
|
+
text = header + text.slice(headerEnd).slice(0, Math.max(0, remainingBudget)) + "\n\n*(Entry truncated due to length limit)*\n---";
|
|
113
|
+
}
|
|
114
|
+
return { text };
|
|
115
|
+
}
|
|
116
|
+
/** YYYY-MM-DD in local time (for daily `memory/YYYY-MM-DD.md` names). */
|
|
117
|
+
isoDay(d) {
|
|
118
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
//#endregion
|
|
122
|
+
export { MemoryFlushService };
|
|
123
|
+
|
|
124
|
+
//# sourceMappingURL=memory-flush.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-flush.js","names":[],"sources":["../../../../src/agent/memory/memory-flush.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile, appendFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { createLogger } from '../../utils/logger.js';\nimport type { CompactionResult } from './compaction.js';\n\nconst log = createLogger('MemoryFlush');\n\nexport interface MemoryFlushConfig {\n enabled: boolean;\n threshold: number;\n softThresholdTokens: number;\n afterCompactions: number;\n maxEntryChars: number;\n includeToolHistory: boolean;\n}\n\nexport interface MemoryFlushOptions {\n workspaceDir: string;\n sessionKey: string;\n compactionResult: CompactionResult;\n config: MemoryFlushConfig;\n}\n\nexport interface MemoryFlushResult {\n flushed: boolean;\n entryPath: string;\n entryLength: number;\n reason?: string;\n}\n\nexport class MemoryFlushService {\n async flush(options: MemoryFlushOptions): Promise<MemoryFlushResult> {\n const { workspaceDir, sessionKey, compactionResult, config } = options;\n\n if (!config.enabled) {\n return { flushed: false, entryPath: '', entryLength: 0, reason: 'disabled' };\n }\n\n const now = new Date();\n const day = this.isoDay(now);\n const memoryDir = join(workspaceDir, 'memory');\n const filePath = join(memoryDir, `${day}.md`);\n const entryPath = `memory/${day}.md`;\n\n await mkdir(memoryDir, { recursive: true });\n\n const entry = this.buildEntry(sessionKey, compactionResult, now, config);\n const entryText = entry.text;\n const entryLength = entryText.length;\n\n if (entryLength > config.maxEntryChars) {\n log.warn({ sessionKey, entryLength, maxEntryChars: config.maxEntryChars }, 'Flush entry exceeds maxEntryChars; truncating');\n }\n\n try {\n const fileExists = existsSync(filePath);\n if (!fileExists) {\n const frontmatter = `# Daily Notes — ${day}\\n\\n`;\n await writeFile(filePath, frontmatter + entryText, 'utf-8');\n } else {\n const existing = await readFile(filePath, 'utf-8');\n // Warn if file is getting large (>50KB) but still append\n if (existing.length > 50_000) {\n log.warn({ sessionKey, filePath, size: existing.length }, 'Daily notes file is large; continuing append');\n }\n await appendFile(filePath, '\\n' + entryText, 'utf-8');\n }\n\n log.info({ sessionKey, entryPath, entryLength }, 'Memory flushed to daily notes');\n return { flushed: true, entryPath, entryLength };\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ sessionKey, err, filePath }, `Memory flush failed: ${em}`);\n return { flushed: false, entryPath, entryLength: 0, reason: `write_error: ${em}` };\n }\n }\n\n private buildEntry(\n sessionKey: string,\n result: CompactionResult,\n now: Date,\n config: MemoryFlushConfig,\n ): { text: string } {\n const iso = now.toISOString();\n const lines: string[] = [];\n\n lines.push(`## Session Flush [${sessionKey}] ${iso}`);\n lines.push('');\n\n const summary = result.summary || '';\n lines.push(`**Summary:** ${summary}`);\n lines.push('');\n\n const structured = result.structuredSummary;\n if (structured) {\n if (structured.userRequests && structured.userRequests.length > 0) {\n lines.push('**User Requests:**');\n for (const req of structured.userRequests) {\n lines.push(`- ${req}`);\n }\n lines.push('');\n }\n\n if (structured.keyDecisions && structured.keyDecisions.length > 0) {\n lines.push('**Key Decisions:**');\n for (const decision of structured.keyDecisions) {\n lines.push(`- ${decision}`);\n }\n lines.push('');\n }\n\n if (structured.filesModified && structured.filesModified.length > 0) {\n lines.push('**Files Modified:**');\n for (const file of structured.filesModified) {\n lines.push(`- ${file}`);\n }\n lines.push('');\n }\n\n if (config.includeToolHistory && structured.toolCalls && structured.toolCalls.length > 0) {\n lines.push('**Tool Calls:**');\n for (const call of structured.toolCalls) {\n const filePart = call.filePath ? ` (${call.filePath})` : '';\n const status = call.success ? 'success' : 'failed';\n lines.push(`- \\`${call.toolName}\\`${filePart} — ${status}`);\n }\n lines.push('');\n }\n } else if (summary) {\n // Fallback when structuredSummary is absent\n lines.push('**Summary (text only):**');\n lines.push(summary);\n lines.push('');\n }\n\n lines.push('---');\n\n let text = lines.join('\\n');\n\n // Respect maxEntryChars by truncating from the end if needed\n if (text.length > config.maxEntryChars) {\n // Keep the header and a truncation notice\n const headerEnd = text.indexOf('\\n\\n') + 2;\n const header = text.slice(0, headerEnd);\n const remainingBudget = config.maxEntryChars - header.length - 60;\n const body = text.slice(headerEnd);\n const truncatedBody = body.slice(0, Math.max(0, remainingBudget));\n text = header + truncatedBody + '\\n\\n*(Entry truncated due to length limit)*\\n---';\n }\n\n return { text };\n }\n\n /** YYYY-MM-DD in local time (for daily `memory/YYYY-MM-DD.md` names). */\n private isoDay(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, '0');\n const day = String(d.getDate()).padStart(2, '0');\n return `${y}-${m}-${day}`;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
-
import { createTypingController } from "../lifecycle/typing.js";
|
|
4
3
|
import { shouldSilence } from "../../heartbeat/tokens.js";
|
|
4
|
+
import { createTypingController } from "../lifecycle/typing.js";
|
|
5
5
|
//#region src/agent/messaging/outbound-coordinator.ts
|
|
6
6
|
init_logger();
|
|
7
7
|
const log = createLogger("OutboundCoordinator");
|
|
@@ -84,6 +84,7 @@ var OutboundCoordinator = class {
|
|
|
84
84
|
metadata: {
|
|
85
85
|
accountId: msg.metadata?.accountId,
|
|
86
86
|
threadId: msg.metadata?.threadId,
|
|
87
|
+
inboundMessageId: msg.metadata?.messageId,
|
|
87
88
|
transcribedVoice: sessionContext.metadata?.transcribedVoice,
|
|
88
89
|
sessionWebhook: msg.metadata?.sessionWebhook,
|
|
89
90
|
conversationId: msg.metadata?.conversationId
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbound-coordinator.js","names":[],"sources":["../../../../src/agent/messaging/outbound-coordinator.ts"],"sourcesContent":["/**\n * OutboundCoordinator — owns the post-turn outbound pipeline.\n *\n * Concentrates the responsibilities that used to be scattered across\n * `AgentService`:\n * - typing-on / typing-off lifecycle for channels that surface \"is typing…\"\n * - final assistant response delivery (silence guard + hook + bus publish)\n * - cross-cutting `webchat_turn_complete` hook + `/goal` post-turn\n * - thin pass-through for extension `message_sending` / `message_sent` hooks\n *\n * The class is intentionally framework-agnostic: it pulls everything it needs\n * via the constructor config (no direct AgentService reference), so it is\n * unit-testable and lets the parent `AgentService` shrink to a coordinator.\n */\n\nimport type { MessageBus, InboundMessage } from '../../infra/bus/index.js';\nimport type { Config } from '../../config/schema.js';\nimport type { HookHandler } from '../lifecycle/hook-handler.js';\nimport type { SessionContext } from '../session/index.js';\nimport { createTypingController, type TypingController } from '../lifecycle/typing.js';\nimport { DEFAULT_ACK_MAX_CHARS, NO_REPLY, shouldSilence } from '../../heartbeat/tokens.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type { StreamManager } from './stream-manager.js';\n\nconst log = createLogger('OutboundCoordinator');\n\nexport interface OutboundCoordinatorConfig {\n bus: MessageBus;\n hookHandler: HookHandler;\n streamManager: StreamManager;\n /** Reads the effective config snapshot (honours runtime overrides). */\n getConfig: () => Config | undefined;\n /** Resolves the last visible assistant text for a session (in-memory + agent fallback). */\n getLastAssistantPlainText: (sessionKey: string) => string;\n /**\n * Run the `/goal` post-turn verdict for a completed user turn. Owned by\n * `PersistentGoalService`; OutboundCoordinator only forwards.\n */\n runPersistentGoalPostTurn: (payload: SessionTurnCompletePayload) => Promise<void>;\n}\n\nexport interface SessionTurnCompletePayload {\n sessionKey: string;\n channel: string;\n chatId: string;\n inboundUserText: string;\n assistantPlainText: string;\n aborted: boolean;\n streamError?: string;\n skipPersistentGoalPostTurn?: boolean;\n outboundMetadata?: Record<string, unknown>;\n}\n\nexport class OutboundCoordinator {\n private readonly bus: MessageBus;\n private readonly hookHandler: HookHandler;\n private readonly streamManager: StreamManager;\n private readonly getConfig: () => Config | undefined;\n private readonly getLastAssistantPlainText: (sessionKey: string) => string;\n private readonly runPersistentGoalPostTurn: OutboundCoordinatorConfig['runPersistentGoalPostTurn'];\n\n constructor(config: OutboundCoordinatorConfig) {\n this.bus = config.bus;\n this.hookHandler = config.hookHandler;\n this.streamManager = config.streamManager;\n this.getConfig = config.getConfig;\n this.getLastAssistantPlainText = config.getLastAssistantPlainText;\n this.runPersistentGoalPostTurn = config.runPersistentGoalPostTurn;\n }\n\n /**\n * Build the typing indicator controller for an inbound message. Returns\n * `null` for the CLI channel (no typing UI). Caller is responsible for\n * `start()` and `stop()` (`stop()` should run AFTER the final outbound so\n * Telegram/Weixin see `typing_off` only once the message is delivered).\n */\n createTypingControllerForInbound(msg: InboundMessage): TypingController | null {\n if (msg.channel === 'cli') {\n return null;\n }\n const meta = msg.metadata as Record<string, unknown> | undefined;\n return createTypingController({\n intervalSeconds: 5,\n onStart: async () => {\n await this.bus.publishOutbound({\n channel: msg.channel,\n chat_id: msg.chat_id,\n content: '',\n type: 'typing_on',\n metadata: {\n accountId: meta?.accountId,\n threadId: meta?.threadId,\n sessionWebhook: meta?.sessionWebhook,\n conversationId: meta?.conversationId,\n },\n });\n },\n onStop: async () => {\n await this.bus.publishOutbound({\n channel: msg.channel,\n chat_id: msg.chat_id,\n content: '',\n type: 'typing_off',\n metadata: {\n accountId: meta?.accountId,\n threadId: meta?.threadId,\n sessionWebhook: meta?.sessionWebhook,\n conversationId: meta?.conversationId,\n },\n });\n },\n });\n }\n\n /**\n * Publish the assistant's visible text as the final bus message. Honours the\n * stream-manager \"channel already streamed the final text\" hint, the heartbeat\n * silence guard, and the extension `message_sending` hook.\n */\n async sendFinalResponse(msg: InboundMessage, sessionContext: SessionContext): Promise<void> {\n if (this.streamManager.consumeSkipFinalOutbound()) {\n return;\n }\n\n const finalContent = this.getLastAssistantPlainText(sessionContext.sessionKey);\n if (!finalContent?.trim()) {\n return;\n }\n\n const ackMax = this.getConfig()?.gateway?.heartbeat?.ackMaxChars ?? DEFAULT_ACK_MAX_CHARS;\n if (shouldSilence(finalContent, ackMax) || finalContent.trim() === NO_REPLY) {\n log.debug({ sessionKey: sessionContext.sessionKey }, 'Silent reply — skipping outbound');\n return;\n }\n\n const hookResult = await this.hookHandler.runMessageSending(\n sessionContext.chatId,\n finalContent,\n sessionContext.channel,\n );\n if (!hookResult.send) {\n return;\n }\n\n await this.bus.publishOutbound({\n channel: sessionContext.channel,\n chat_id: sessionContext.chatId,\n content: hookResult.content || finalContent,\n type: 'message',\n metadata: {\n accountId: msg.metadata?.accountId,\n threadId: msg.metadata?.threadId,\n transcribedVoice: sessionContext.metadata?.transcribedVoice,\n sessionWebhook: msg.metadata?.sessionWebhook,\n conversationId: msg.metadata?.conversationId,\n },\n });\n }\n\n /**\n * Post-turn hook + `/goal` checklist evaluation. Wired into both the bus-driven\n * inbound finally block and the webchat direct-stream finally. The goal verdict\n * itself lives in `PersistentGoalService`; we just trigger the extension hook\n * here and delegate the `/goal` work.\n */\n async emitSessionTurnComplete(payload: SessionTurnCompletePayload): Promise<void> {\n await this.hookHandler.triggerWithSessionKey(payload.sessionKey, 'webchat_turn_complete', {\n sessionKey: payload.sessionKey,\n channel: payload.channel,\n chatId: payload.chatId,\n inboundUserText: payload.inboundUserText,\n assistantPlainText: payload.assistantPlainText,\n aborted: payload.aborted,\n ...(payload.streamError !== undefined ? { streamError: payload.streamError } : {}),\n });\n\n await this.runPersistentGoalPostTurn(payload);\n }\n\n /** Extension hook pass-through (Gateway ChannelManager). */\n invokeOutboundMessageSending(\n to: string,\n content: string,\n channel: string,\n ): Promise<{ send: boolean; content?: string; reason?: string }> {\n return this.hookHandler.runMessageSending(to, content, channel);\n }\n\n /** Extension hook pass-through (Gateway ChannelManager). */\n invokeOutboundMessageSent(\n to: string,\n content: string,\n success: boolean,\n error: string | undefined,\n channel: string,\n ): Promise<void> {\n return this.hookHandler.runMessageSent(to, content, success, error, channel);\n }\n}\n"],"mappings":";;;;;aAqBqD;AAGrD,MAAM,MAAM,aAAa,sBAAsB;AA6B/C,IAAa,sBAAb,MAAiC;CAC/B;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,QAAmC;AAC7C,OAAK,MAAM,OAAO;AAClB,OAAK,cAAc,OAAO;AAC1B,OAAK,gBAAgB,OAAO;AAC5B,OAAK,YAAY,OAAO;AACxB,OAAK,4BAA4B,OAAO;AACxC,OAAK,4BAA4B,OAAO;;;;;;;;CAS1C,iCAAiC,KAA8C;AAC7E,MAAI,IAAI,YAAY,MAClB,QAAO;EAET,MAAM,OAAO,IAAI;AACjB,SAAO,uBAAuB;GAC5B,iBAAiB;GACjB,SAAS,YAAY;AACnB,UAAM,KAAK,IAAI,gBAAgB;KAC7B,SAAS,IAAI;KACb,SAAS,IAAI;KACb,SAAS;KACT,MAAM;KACN,UAAU;MACR,WAAW,MAAM;MACjB,UAAU,MAAM;MAChB,gBAAgB,MAAM;MACtB,gBAAgB,MAAM;MACvB;KACF,CAAC;;GAEJ,QAAQ,YAAY;AAClB,UAAM,KAAK,IAAI,gBAAgB;KAC7B,SAAS,IAAI;KACb,SAAS,IAAI;KACb,SAAS;KACT,MAAM;KACN,UAAU;MACR,WAAW,MAAM;MACjB,UAAU,MAAM;MAChB,gBAAgB,MAAM;MACtB,gBAAgB,MAAM;MACvB;KACF,CAAC;;GAEL,CAAC;;;;;;;CAQJ,MAAM,kBAAkB,KAAqB,gBAA+C;AAC1F,MAAI,KAAK,cAAc,0BAA0B,CAC/C;EAGF,MAAM,eAAe,KAAK,0BAA0B,eAAe,WAAW;AAC9E,MAAI,CAAC,cAAc,MAAM,CACvB;AAIF,MAAI,cAAc,cADH,KAAK,WAAW,EAAE,SAAS,WAAW,eAAA,IACd,IAAI,aAAa,MAAM,KAAA,YAAe;AAC3E,OAAI,MAAM,EAAE,YAAY,eAAe,YAAY,EAAE,mCAAmC;AACxF;;EAGF,MAAM,aAAa,MAAM,KAAK,YAAY,kBACxC,eAAe,QACf,cACA,eAAe,QAChB;AACD,MAAI,CAAC,WAAW,KACd;AAGF,QAAM,KAAK,IAAI,gBAAgB;GAC7B,SAAS,eAAe;GACxB,SAAS,eAAe;GACxB,SAAS,WAAW,WAAW;GAC/B,MAAM;GACN,UAAU;IACR,WAAW,IAAI,UAAU;IACzB,UAAU,IAAI,UAAU;IACxB,kBAAkB,eAAe,UAAU;IAC3C,gBAAgB,IAAI,UAAU;IAC9B,gBAAgB,IAAI,UAAU;IAC/B;GACF,CAAC;;;;;;;;CASJ,MAAM,wBAAwB,SAAoD;AAChF,QAAM,KAAK,YAAY,sBAAsB,QAAQ,YAAY,yBAAyB;GACxF,YAAY,QAAQ;GACpB,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GAChB,iBAAiB,QAAQ;GACzB,oBAAoB,QAAQ;GAC5B,SAAS,QAAQ;GACjB,GAAI,QAAQ,gBAAgB,KAAA,IAAY,EAAE,aAAa,QAAQ,aAAa,GAAG,EAAE;GAClF,CAAC;AAEF,QAAM,KAAK,0BAA0B,QAAQ;;;CAI/C,6BACE,IACA,SACA,SAC+D;AAC/D,SAAO,KAAK,YAAY,kBAAkB,IAAI,SAAS,QAAQ;;;CAIjE,0BACE,IACA,SACA,SACA,OACA,SACe;AACf,SAAO,KAAK,YAAY,eAAe,IAAI,SAAS,SAAS,OAAO,QAAQ"}
|
|
1
|
+
{"version":3,"file":"outbound-coordinator.js","names":[],"sources":["../../../../src/agent/messaging/outbound-coordinator.ts"],"sourcesContent":["/**\n * OutboundCoordinator — owns the post-turn outbound pipeline.\n *\n * Concentrates the responsibilities that used to be scattered across\n * `AgentService`:\n * - typing-on / typing-off lifecycle for channels that surface \"is typing…\"\n * - final assistant response delivery (silence guard + hook + bus publish)\n * - cross-cutting `webchat_turn_complete` hook + `/goal` post-turn\n * - thin pass-through for extension `message_sending` / `message_sent` hooks\n *\n * The class is intentionally framework-agnostic: it pulls everything it needs\n * via the constructor config (no direct AgentService reference), so it is\n * unit-testable and lets the parent `AgentService` shrink to a coordinator.\n */\n\nimport type { MessageBus, InboundMessage } from '../../infra/bus/index.js';\nimport type { Config } from '../../config/schema.js';\nimport type { HookHandler } from '../lifecycle/hook-handler.js';\nimport type { SessionContext } from '../session/index.js';\nimport { createTypingController, type TypingController } from '../lifecycle/typing.js';\nimport { DEFAULT_ACK_MAX_CHARS, NO_REPLY, shouldSilence } from '../../heartbeat/tokens.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type { StreamManager } from './stream-manager.js';\n\nconst log = createLogger('OutboundCoordinator');\n\nexport interface OutboundCoordinatorConfig {\n bus: MessageBus;\n hookHandler: HookHandler;\n streamManager: StreamManager;\n /** Reads the effective config snapshot (honours runtime overrides). */\n getConfig: () => Config | undefined;\n /** Resolves the last visible assistant text for a session (in-memory + agent fallback). */\n getLastAssistantPlainText: (sessionKey: string) => string;\n /**\n * Run the `/goal` post-turn verdict for a completed user turn. Owned by\n * `PersistentGoalService`; OutboundCoordinator only forwards.\n */\n runPersistentGoalPostTurn: (payload: SessionTurnCompletePayload) => Promise<void>;\n}\n\nexport interface SessionTurnCompletePayload {\n sessionKey: string;\n channel: string;\n chatId: string;\n inboundUserText: string;\n assistantPlainText: string;\n aborted: boolean;\n streamError?: string;\n skipPersistentGoalPostTurn?: boolean;\n outboundMetadata?: Record<string, unknown>;\n}\n\nexport class OutboundCoordinator {\n private readonly bus: MessageBus;\n private readonly hookHandler: HookHandler;\n private readonly streamManager: StreamManager;\n private readonly getConfig: () => Config | undefined;\n private readonly getLastAssistantPlainText: (sessionKey: string) => string;\n private readonly runPersistentGoalPostTurn: OutboundCoordinatorConfig['runPersistentGoalPostTurn'];\n\n constructor(config: OutboundCoordinatorConfig) {\n this.bus = config.bus;\n this.hookHandler = config.hookHandler;\n this.streamManager = config.streamManager;\n this.getConfig = config.getConfig;\n this.getLastAssistantPlainText = config.getLastAssistantPlainText;\n this.runPersistentGoalPostTurn = config.runPersistentGoalPostTurn;\n }\n\n /**\n * Build the typing indicator controller for an inbound message. Returns\n * `null` for the CLI channel (no typing UI). Caller is responsible for\n * `start()` and `stop()` (`stop()` should run AFTER the final outbound so\n * Telegram/Weixin see `typing_off` only once the message is delivered).\n */\n createTypingControllerForInbound(msg: InboundMessage): TypingController | null {\n if (msg.channel === 'cli') {\n return null;\n }\n const meta = msg.metadata as Record<string, unknown> | undefined;\n return createTypingController({\n intervalSeconds: 5,\n onStart: async () => {\n await this.bus.publishOutbound({\n channel: msg.channel,\n chat_id: msg.chat_id,\n content: '',\n type: 'typing_on',\n metadata: {\n accountId: meta?.accountId,\n threadId: meta?.threadId,\n sessionWebhook: meta?.sessionWebhook,\n conversationId: meta?.conversationId,\n },\n });\n },\n onStop: async () => {\n await this.bus.publishOutbound({\n channel: msg.channel,\n chat_id: msg.chat_id,\n content: '',\n type: 'typing_off',\n metadata: {\n accountId: meta?.accountId,\n threadId: meta?.threadId,\n sessionWebhook: meta?.sessionWebhook,\n conversationId: meta?.conversationId,\n },\n });\n },\n });\n }\n\n /**\n * Publish the assistant's visible text as the final bus message. Honours the\n * stream-manager \"channel already streamed the final text\" hint, the heartbeat\n * silence guard, and the extension `message_sending` hook.\n */\n async sendFinalResponse(msg: InboundMessage, sessionContext: SessionContext): Promise<void> {\n if (this.streamManager.consumeSkipFinalOutbound()) {\n return;\n }\n\n const finalContent = this.getLastAssistantPlainText(sessionContext.sessionKey);\n if (!finalContent?.trim()) {\n return;\n }\n\n const ackMax = this.getConfig()?.gateway?.heartbeat?.ackMaxChars ?? DEFAULT_ACK_MAX_CHARS;\n if (shouldSilence(finalContent, ackMax) || finalContent.trim() === NO_REPLY) {\n log.debug({ sessionKey: sessionContext.sessionKey }, 'Silent reply — skipping outbound');\n return;\n }\n\n const hookResult = await this.hookHandler.runMessageSending(\n sessionContext.chatId,\n finalContent,\n sessionContext.channel,\n );\n if (!hookResult.send) {\n return;\n }\n\n await this.bus.publishOutbound({\n channel: sessionContext.channel,\n chat_id: sessionContext.chatId,\n content: hookResult.content || finalContent,\n type: 'message',\n metadata: {\n accountId: msg.metadata?.accountId,\n threadId: msg.metadata?.threadId,\n inboundMessageId: msg.metadata?.messageId,\n transcribedVoice: sessionContext.metadata?.transcribedVoice,\n sessionWebhook: msg.metadata?.sessionWebhook,\n conversationId: msg.metadata?.conversationId,\n },\n });\n }\n\n /**\n * Post-turn hook + `/goal` checklist evaluation. Wired into both the bus-driven\n * inbound finally block and the webchat direct-stream finally. The goal verdict\n * itself lives in `PersistentGoalService`; we just trigger the extension hook\n * here and delegate the `/goal` work.\n */\n async emitSessionTurnComplete(payload: SessionTurnCompletePayload): Promise<void> {\n await this.hookHandler.triggerWithSessionKey(payload.sessionKey, 'webchat_turn_complete', {\n sessionKey: payload.sessionKey,\n channel: payload.channel,\n chatId: payload.chatId,\n inboundUserText: payload.inboundUserText,\n assistantPlainText: payload.assistantPlainText,\n aborted: payload.aborted,\n ...(payload.streamError !== undefined ? { streamError: payload.streamError } : {}),\n });\n\n await this.runPersistentGoalPostTurn(payload);\n }\n\n /** Extension hook pass-through (Gateway ChannelManager). */\n invokeOutboundMessageSending(\n to: string,\n content: string,\n channel: string,\n ): Promise<{ send: boolean; content?: string; reason?: string }> {\n return this.hookHandler.runMessageSending(to, content, channel);\n }\n\n /** Extension hook pass-through (Gateway ChannelManager). */\n invokeOutboundMessageSent(\n to: string,\n content: string,\n success: boolean,\n error: string | undefined,\n channel: string,\n ): Promise<void> {\n return this.hookHandler.runMessageSent(to, content, success, error, channel);\n }\n}\n"],"mappings":";;;;;aAqBqD;AAGrD,MAAM,MAAM,aAAa,sBAAsB;AA6B/C,IAAa,sBAAb,MAAiC;CAC/B;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,QAAmC;AAC7C,OAAK,MAAM,OAAO;AAClB,OAAK,cAAc,OAAO;AAC1B,OAAK,gBAAgB,OAAO;AAC5B,OAAK,YAAY,OAAO;AACxB,OAAK,4BAA4B,OAAO;AACxC,OAAK,4BAA4B,OAAO;;;;;;;;CAS1C,iCAAiC,KAA8C;AAC7E,MAAI,IAAI,YAAY,MAClB,QAAO;EAET,MAAM,OAAO,IAAI;AACjB,SAAO,uBAAuB;GAC5B,iBAAiB;GACjB,SAAS,YAAY;AACnB,UAAM,KAAK,IAAI,gBAAgB;KAC7B,SAAS,IAAI;KACb,SAAS,IAAI;KACb,SAAS;KACT,MAAM;KACN,UAAU;MACR,WAAW,MAAM;MACjB,UAAU,MAAM;MAChB,gBAAgB,MAAM;MACtB,gBAAgB,MAAM;MACvB;KACF,CAAC;;GAEJ,QAAQ,YAAY;AAClB,UAAM,KAAK,IAAI,gBAAgB;KAC7B,SAAS,IAAI;KACb,SAAS,IAAI;KACb,SAAS;KACT,MAAM;KACN,UAAU;MACR,WAAW,MAAM;MACjB,UAAU,MAAM;MAChB,gBAAgB,MAAM;MACtB,gBAAgB,MAAM;MACvB;KACF,CAAC;;GAEL,CAAC;;;;;;;CAQJ,MAAM,kBAAkB,KAAqB,gBAA+C;AAC1F,MAAI,KAAK,cAAc,0BAA0B,CAC/C;EAGF,MAAM,eAAe,KAAK,0BAA0B,eAAe,WAAW;AAC9E,MAAI,CAAC,cAAc,MAAM,CACvB;AAIF,MAAI,cAAc,cADH,KAAK,WAAW,EAAE,SAAS,WAAW,eAAA,IACd,IAAI,aAAa,MAAM,KAAA,YAAe;AAC3E,OAAI,MAAM,EAAE,YAAY,eAAe,YAAY,EAAE,mCAAmC;AACxF;;EAGF,MAAM,aAAa,MAAM,KAAK,YAAY,kBACxC,eAAe,QACf,cACA,eAAe,QAChB;AACD,MAAI,CAAC,WAAW,KACd;AAGF,QAAM,KAAK,IAAI,gBAAgB;GAC7B,SAAS,eAAe;GACxB,SAAS,eAAe;GACxB,SAAS,WAAW,WAAW;GAC/B,MAAM;GACN,UAAU;IACR,WAAW,IAAI,UAAU;IACzB,UAAU,IAAI,UAAU;IACxB,kBAAkB,IAAI,UAAU;IAChC,kBAAkB,eAAe,UAAU;IAC3C,gBAAgB,IAAI,UAAU;IAC9B,gBAAgB,IAAI,UAAU;IAC/B;GACF,CAAC;;;;;;;;CASJ,MAAM,wBAAwB,SAAoD;AAChF,QAAM,KAAK,YAAY,sBAAsB,QAAQ,YAAY,yBAAyB;GACxF,YAAY,QAAQ;GACpB,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GAChB,iBAAiB,QAAQ;GACzB,oBAAoB,QAAQ;GAC5B,SAAS,QAAQ;GACjB,GAAI,QAAQ,gBAAgB,KAAA,IAAY,EAAE,aAAa,QAAQ,aAAa,GAAG,EAAE;GAClF,CAAC;AAEF,QAAM,KAAK,0BAA0B,QAAQ;;;CAI/C,6BACE,IACA,SACA,SAC+D;AAC/D,SAAO,KAAK,YAAY,kBAAkB,IAAI,SAAS,QAAQ;;;CAIjE,0BACE,IACA,SACA,SACA,OACA,SACe;AACf,SAAO,KAAK,YAAY,eAAe,IAAI,SAAS,SAAS,OAAO,QAAQ"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import type { ProgressStage } from '../lifecycle/progress.js';
|
|
8
8
|
export interface StreamHandle {
|
|
9
9
|
update: (text: string) => void;
|
|
10
|
+
updateReasoning?: (text: string) => void;
|
|
10
11
|
updateProgress?: (text: string, stage: ProgressStage, detail?: string) => void;
|
|
11
12
|
setProgress?: (stage: ProgressStage, detail?: string) => void;
|
|
12
13
|
end: () => Promise<void>;
|
|
@@ -37,6 +38,7 @@ export declare class StreamManager {
|
|
|
37
38
|
* Update the stream with text content
|
|
38
39
|
*/
|
|
39
40
|
update(text: string): void;
|
|
41
|
+
updateReasoning(text: string): void;
|
|
40
42
|
/**
|
|
41
43
|
* End the stream and clear the handle
|
|
42
44
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-manager.js","names":[],"sources":["../../../../src/agent/messaging/stream-manager.ts"],"sourcesContent":["/**\n * Stream Manager - Manages stream handles for progress updates\n *\n * Handles creation and lifecycle of stream handles for sending progress updates\n * and streaming responses.\n */\n\nimport type { ProgressStage } from '../lifecycle/progress.js';\n\nexport interface StreamHandle {\n update: (text: string) => void;\n updateProgress?: (text: string, stage: ProgressStage, detail?: string) => void;\n setProgress?: (stage: ProgressStage, detail?: string) => void;\n end: () => Promise<void>;\n abort: () => Promise<void>;\n messageId: () => number | undefined;\n skipFinalOutbound?: () => boolean;\n}\n\nexport class StreamManager {\n private currentHandle: StreamHandle | null = null;\n private skipFinalOutboundPending = false;\n\n /**\n * Set the current stream handle\n */\n setHandle(handle: StreamHandle): void {\n this.currentHandle = handle;\n }\n\n /**\n * Get the current stream handle\n */\n getHandle(): StreamHandle | null {\n return this.currentHandle;\n }\n\n /**\n * Clear the current stream handle\n */\n clearHandle(): void {\n this.currentHandle = null;\n }\n\n /**\n * Check if a stream handle is currently active\n */\n hasActiveHandle(): boolean {\n return this.currentHandle !== null;\n }\n\n /**\n * Update the stream with text content\n */\n update(text: string): void {\n this.currentHandle?.update(text);\n }\n\n /**\n * End the stream and clear the handle\n */\n async end(): Promise<void> {\n if (this.currentHandle) {\n const handle = this.currentHandle;\n await handle.end();\n this.skipFinalOutboundPending = handle.skipFinalOutbound?.() ?? false;\n this.clearHandle();\n } else {\n this.skipFinalOutboundPending = false;\n }\n }\n\n /**\n * Abort the stream and clear the handle\n */\n async abort(): Promise<void> {\n if (this.currentHandle) {\n await this.currentHandle.abort();\n this.skipFinalOutboundPending = false;\n this.clearHandle();\n }\n }\n\n /**\n * Whether the channel already delivered the final assistant text (e.g. Telegram streaming).\n * Consumes the flag for one outbound decision.\n */\n consumeSkipFinalOutbound(): boolean {\n const v = this.skipFinalOutboundPending;\n this.skipFinalOutboundPending = false;\n return v;\n }\n\n /**\n * Get the current message ID from the stream handle\n */\n getMessageId(): number | undefined {\n return this.currentHandle?.messageId();\n }\n\n /**\n * Update progress via the stream handle\n */\n updateProgress(text: string, stage: ProgressStage, detail?: string): void {\n if (this.currentHandle?.updateProgress) {\n this.currentHandle.updateProgress(text, stage, detail);\n }\n }\n\n /**\n * Set progress stage via the stream handle\n */\n setProgress(stage: ProgressStage, detail?: string): void {\n if (this.currentHandle?.setProgress) {\n this.currentHandle.setProgress(stage, detail);\n }\n }\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"file":"stream-manager.js","names":[],"sources":["../../../../src/agent/messaging/stream-manager.ts"],"sourcesContent":["/**\n * Stream Manager - Manages stream handles for progress updates\n *\n * Handles creation and lifecycle of stream handles for sending progress updates\n * and streaming responses.\n */\n\nimport type { ProgressStage } from '../lifecycle/progress.js';\n\nexport interface StreamHandle {\n update: (text: string) => void;\n updateReasoning?: (text: string) => void;\n updateProgress?: (text: string, stage: ProgressStage, detail?: string) => void;\n setProgress?: (stage: ProgressStage, detail?: string) => void;\n end: () => Promise<void>;\n abort: () => Promise<void>;\n messageId: () => number | undefined;\n skipFinalOutbound?: () => boolean;\n}\n\nexport class StreamManager {\n private currentHandle: StreamHandle | null = null;\n private skipFinalOutboundPending = false;\n\n /**\n * Set the current stream handle\n */\n setHandle(handle: StreamHandle): void {\n this.currentHandle = handle;\n }\n\n /**\n * Get the current stream handle\n */\n getHandle(): StreamHandle | null {\n return this.currentHandle;\n }\n\n /**\n * Clear the current stream handle\n */\n clearHandle(): void {\n this.currentHandle = null;\n }\n\n /**\n * Check if a stream handle is currently active\n */\n hasActiveHandle(): boolean {\n return this.currentHandle !== null;\n }\n\n /**\n * Update the stream with text content\n */\n update(text: string): void {\n this.currentHandle?.update(text);\n }\n\n updateReasoning(text: string): void {\n this.currentHandle?.updateReasoning?.(text);\n }\n\n /**\n * End the stream and clear the handle\n */\n async end(): Promise<void> {\n if (this.currentHandle) {\n const handle = this.currentHandle;\n await handle.end();\n this.skipFinalOutboundPending = handle.skipFinalOutbound?.() ?? false;\n this.clearHandle();\n } else {\n this.skipFinalOutboundPending = false;\n }\n }\n\n /**\n * Abort the stream and clear the handle\n */\n async abort(): Promise<void> {\n if (this.currentHandle) {\n await this.currentHandle.abort();\n this.skipFinalOutboundPending = false;\n this.clearHandle();\n }\n }\n\n /**\n * Whether the channel already delivered the final assistant text (e.g. Telegram streaming).\n * Consumes the flag for one outbound decision.\n */\n consumeSkipFinalOutbound(): boolean {\n const v = this.skipFinalOutboundPending;\n this.skipFinalOutboundPending = false;\n return v;\n }\n\n /**\n * Get the current message ID from the stream handle\n */\n getMessageId(): number | undefined {\n return this.currentHandle?.messageId();\n }\n\n /**\n * Update progress via the stream handle\n */\n updateProgress(text: string, stage: ProgressStage, detail?: string): void {\n if (this.currentHandle?.updateProgress) {\n this.currentHandle.updateProgress(text, stage, detail);\n }\n }\n\n /**\n * Set progress stage via the stream handle\n */\n setProgress(stage: ProgressStage, detail?: string): void {\n if (this.currentHandle?.setProgress) {\n this.currentHandle.setProgress(stage, detail);\n }\n }\n}\n"],"mappings":";AAoBA,IAAa,gBAAb,MAA2B;CACzB,gBAA6C;CAC7C,2BAAmC;;;;CAKnC,UAAU,QAA4B;AACpC,OAAK,gBAAgB;;;;;CAMvB,YAAiC;AAC/B,SAAO,KAAK;;;;;CAMd,cAAoB;AAClB,OAAK,gBAAgB;;;;;CAMvB,kBAA2B;AACzB,SAAO,KAAK,kBAAkB;;;;;CAMhC,OAAO,MAAoB;AACzB,OAAK,eAAe,OAAO,KAAK;;CAGlC,gBAAgB,MAAoB;AAClC,OAAK,eAAe,kBAAkB,KAAK;;;;;CAM7C,MAAM,MAAqB;AACzB,MAAI,KAAK,eAAe;GACtB,MAAM,SAAS,KAAK;AACpB,SAAM,OAAO,KAAK;AAClB,QAAK,2BAA2B,OAAO,qBAAqB,IAAI;AAChE,QAAK,aAAa;QAElB,MAAK,2BAA2B;;;;;CAOpC,MAAM,QAAuB;AAC3B,MAAI,KAAK,eAAe;AACtB,SAAM,KAAK,cAAc,OAAO;AAChC,QAAK,2BAA2B;AAChC,QAAK,aAAa;;;;;;;CAQtB,2BAAoC;EAClC,MAAM,IAAI,KAAK;AACf,OAAK,2BAA2B;AAChC,SAAO;;;;;CAMT,eAAmC;AACjC,SAAO,KAAK,eAAe,WAAW;;;;;CAMxC,eAAe,MAAc,OAAsB,QAAuB;AACxE,MAAI,KAAK,eAAe,eACtB,MAAK,cAAc,eAAe,MAAM,OAAO,OAAO;;;;;CAO1D,YAAY,OAAsB,QAAuB;AACvD,MAAI,KAAK,eAAe,YACtB,MAAK,cAAc,YAAY,OAAO,OAAO"}
|
|
@@ -64,10 +64,6 @@ export declare class AgentOrchestrator {
|
|
|
64
64
|
* Process a message through the agent orchestration pipeline
|
|
65
65
|
*/
|
|
66
66
|
process(msg: InboundMessage, context: SessionContext): Promise<void>;
|
|
67
|
-
/**
|
|
68
|
-
* Build an agent message from an inbound message
|
|
69
|
-
*/
|
|
70
|
-
private buildUserMessage;
|
|
71
67
|
/**
|
|
72
68
|
* Get the current agent model ID
|
|
73
69
|
*/
|
|
@@ -2,13 +2,12 @@ import { createLogger } from "../../utils/logger/index.js";
|
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import "../memory/dreaming/constants.js";
|
|
4
4
|
import { resolveDreamingConfig } from "../memory/dreaming/config.js";
|
|
5
|
+
import { persistInboundAttachments } from "../../channels/attachments/inbound-persist.js";
|
|
6
|
+
import { buildTranscriptUserMessage, clearPendingTranscriptUserMessage, hydrateUserTurnForLlm, setPendingTranscriptUserMessage } from "../inbound/attachment-pipeline.js";
|
|
5
7
|
import { extractAgentUserPlainText } from "../memory/user-message-text.js";
|
|
6
|
-
import { formatInboundFileTextBlock, persistInboundAttachmentsToWorkspace } from "../../channels/attachments/inbound-persist.js";
|
|
7
8
|
import { resolveEffectiveThinkingLevel } from "../../session/thinking-resolve.js";
|
|
8
9
|
import { abortEmbeddedRun } from "../embedded/runs.js";
|
|
9
10
|
import { runEmbeddedTurnForSession } from "../embedded/run-for-session.js";
|
|
10
|
-
import { expandAtFileMentionsInPlainText } from "../context/expand-at-file-mentions.js";
|
|
11
|
-
import { resolveInboundImageContentParts } from "../image/inbound-image-handling.js";
|
|
12
11
|
import { runDreamingDeepPromotion } from "../memory/dreaming/deep-promotion.js";
|
|
13
12
|
import { appendDreamingEvent } from "../memory/dreaming/events.js";
|
|
14
13
|
import { runLightSweep } from "../memory/dreaming/light-sweep.js";
|
|
@@ -113,28 +112,50 @@ var AgentOrchestrator = class {
|
|
|
113
112
|
}
|
|
114
113
|
try {
|
|
115
114
|
await this.sessionHydrator.model(sessionKey);
|
|
115
|
+
const channelSystemPrompt = typeof context.metadata?.channelSystemPrompt === "string" ? context.metadata.channelSystemPrompt.trim() : "";
|
|
116
|
+
if (channelSystemPrompt) {
|
|
117
|
+
this.agentManager.getOrCreateAgent(sessionKey);
|
|
118
|
+
this.agentManager.applyTurnChannelSystemPrompt(sessionKey, channelSystemPrompt);
|
|
119
|
+
}
|
|
116
120
|
const thinkingDefault = this.getThinkingDefaultForSession?.(sessionKey) ?? this.getThinkingDefault();
|
|
117
121
|
const thinkingLevel = await resolveEffectiveThinkingLevel(this.sessionConfigStore, sessionKey, null, thinkingDefault);
|
|
118
122
|
this.agentManager.setThinkingLevel(sessionKey, thinkingLevel);
|
|
119
|
-
const persistedAttachments = await
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
const persistedAttachments = await persistInboundAttachments(msg.attachments);
|
|
124
|
+
const modelRef = this.modelManager.getModelForSession(sessionKey);
|
|
125
|
+
const userMessage = await buildTranscriptUserMessage({
|
|
126
|
+
text: msg.content,
|
|
127
|
+
prepared: persistedAttachments,
|
|
128
|
+
sessionKey,
|
|
129
|
+
modelRef,
|
|
130
|
+
config: this.getConfig?.(),
|
|
131
|
+
agentManager: this.agentManager
|
|
132
|
+
});
|
|
133
|
+
setPendingTranscriptUserMessage(sessionKey, userMessage);
|
|
124
134
|
const userPlainForMemory = extractAgentUserPlainText(userMessage);
|
|
125
135
|
const userMessageForModel = await this.agentManager.applyMemoryPrefetchToUserMessage(userMessage, sessionKey);
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
userMessage: userMessageForModel,
|
|
130
|
-
sessionStore: this.sessionStore,
|
|
131
|
-
agentManager: this.agentManager,
|
|
132
|
-
modelManager: this.modelManager,
|
|
133
|
-
thinkingOverride: thinkingLevel,
|
|
134
|
-
getConfig: this.getConfig,
|
|
135
|
-
beforeTurn: () => this.agentManager.beginBackgroundReviewUserTurn(sessionKey),
|
|
136
|
-
onEvent: (event) => this.onEmbeddedStreamEvent?.(sessionKey, event)
|
|
136
|
+
const llmTurn = await hydrateUserTurnForLlm({
|
|
137
|
+
message: userMessage,
|
|
138
|
+
modelRef
|
|
137
139
|
});
|
|
140
|
+
this.feedbackCoordinator.startTask();
|
|
141
|
+
const turnResult = await (async () => {
|
|
142
|
+
try {
|
|
143
|
+
return await runEmbeddedTurnForSession({
|
|
144
|
+
sessionKey,
|
|
145
|
+
userMessage: userMessageForModel,
|
|
146
|
+
llmImages: llmTurn.images,
|
|
147
|
+
sessionStore: this.sessionStore,
|
|
148
|
+
agentManager: this.agentManager,
|
|
149
|
+
modelManager: this.modelManager,
|
|
150
|
+
thinkingOverride: thinkingLevel,
|
|
151
|
+
getConfig: this.getConfig,
|
|
152
|
+
beforeTurn: () => this.agentManager.beginBackgroundReviewUserTurn(sessionKey),
|
|
153
|
+
onEvent: (event) => this.onEmbeddedStreamEvent?.(sessionKey, event)
|
|
154
|
+
});
|
|
155
|
+
} finally {
|
|
156
|
+
clearPendingTranscriptUserMessage(sessionKey, userMessage);
|
|
157
|
+
}
|
|
158
|
+
})();
|
|
138
159
|
this.agentManager.afterAgentTurn(sessionKey, userPlainForMemory);
|
|
139
160
|
this.agentManager.scheduleBackgroundReviewAfterUserTurn(sessionKey);
|
|
140
161
|
if (turnResult.ok) {
|
|
@@ -155,94 +176,6 @@ var AgentOrchestrator = class {
|
|
|
155
176
|
}
|
|
156
177
|
}
|
|
157
178
|
/**
|
|
158
|
-
* Build an agent message from an inbound message
|
|
159
|
-
*/
|
|
160
|
-
async buildUserMessage(msg, sessionKey) {
|
|
161
|
-
const storageRootAbs = this.getAgentInternalStorageRootForSession(sessionKey);
|
|
162
|
-
let textBody = msg.content.trimStart().startsWith("/skill:") ? this.agentManager.expandSkillUserText(msg.content) : msg.content;
|
|
163
|
-
if (/@file:/.test(textBody)) {
|
|
164
|
-
const root = this.agentManager.getResolvedWorkspaceForSession(sessionKey);
|
|
165
|
-
textBody = await expandAtFileMentionsInPlainText(textBody, root);
|
|
166
|
-
}
|
|
167
|
-
if (!msg.attachments || msg.attachments.length === 0) return {
|
|
168
|
-
role: "user",
|
|
169
|
-
content: textBody,
|
|
170
|
-
timestamp: Date.now()
|
|
171
|
-
};
|
|
172
|
-
const modelRef = this.modelManager.getModelForSession(sessionKey);
|
|
173
|
-
const cfg = this.getConfig?.();
|
|
174
|
-
const messageContent = [];
|
|
175
|
-
if (msg.content.trim()) messageContent.push({
|
|
176
|
-
type: "text",
|
|
177
|
-
text: textBody
|
|
178
|
-
});
|
|
179
|
-
const attachments = msg.attachments;
|
|
180
|
-
let i = 0;
|
|
181
|
-
while (i < attachments.length) {
|
|
182
|
-
const att = attachments[i];
|
|
183
|
-
if (att.type === "image" || att.type === "photo" || Boolean(att.mimeType?.startsWith("image/"))) {
|
|
184
|
-
const group = [];
|
|
185
|
-
while (i < attachments.length) {
|
|
186
|
-
const a = attachments[i];
|
|
187
|
-
if (!(a.type === "image" || a.type === "photo" || Boolean(a.mimeType?.startsWith("image/")))) break;
|
|
188
|
-
if (!a.data || a.data.length === 0) {
|
|
189
|
-
log.warn({
|
|
190
|
-
type: a.type,
|
|
191
|
-
name: a.name
|
|
192
|
-
}, "Empty image data, skipping");
|
|
193
|
-
i += 1;
|
|
194
|
-
continue;
|
|
195
|
-
}
|
|
196
|
-
group.push({
|
|
197
|
-
data: a.data,
|
|
198
|
-
mimeType: a.mimeType || "image/jpeg"
|
|
199
|
-
});
|
|
200
|
-
i += 1;
|
|
201
|
-
}
|
|
202
|
-
if (group.length > 0) {
|
|
203
|
-
const parts = await resolveInboundImageContentParts({
|
|
204
|
-
modelRef,
|
|
205
|
-
cfg,
|
|
206
|
-
userTextForContext: msg.content.trim() ? textBody : "",
|
|
207
|
-
images: group
|
|
208
|
-
});
|
|
209
|
-
messageContent.push(...parts);
|
|
210
|
-
}
|
|
211
|
-
} else {
|
|
212
|
-
const fileBlock = formatInboundFileTextBlock({
|
|
213
|
-
type: att.type,
|
|
214
|
-
mimeType: att.mimeType,
|
|
215
|
-
name: att.name,
|
|
216
|
-
size: att.size,
|
|
217
|
-
workspaceRelativePath: att.workspaceRelativePath
|
|
218
|
-
}, storageRootAbs);
|
|
219
|
-
messageContent.push({
|
|
220
|
-
type: "text",
|
|
221
|
-
text: fileBlock
|
|
222
|
-
});
|
|
223
|
-
i += 1;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
const hasText = messageContent.some((item) => item.type === "text");
|
|
227
|
-
if (messageContent.some((item) => item.type === "image") && !hasText) messageContent.unshift({
|
|
228
|
-
type: "text",
|
|
229
|
-
text: "Please analyze the image(s) I sent."
|
|
230
|
-
});
|
|
231
|
-
if (messageContent.length === 0) {
|
|
232
|
-
log.warn({ attachmentCount: msg.attachments.length }, "All attachments were skipped, falling back to text message");
|
|
233
|
-
return {
|
|
234
|
-
role: "user",
|
|
235
|
-
content: textBody || "[Image attachment could not be processed]",
|
|
236
|
-
timestamp: Date.now()
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
return {
|
|
240
|
-
role: "user",
|
|
241
|
-
content: messageContent,
|
|
242
|
-
timestamp: Date.now()
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
179
|
* Get the current agent model ID
|
|
247
180
|
*/
|
|
248
181
|
getCurrentModel() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-orchestrator.js","names":[],"sources":["../../../../src/agent/orchestration/agent-orchestrator.ts"],"sourcesContent":["/**\n * Agent Orchestrator - Coordinates Agent execution flow\n *\n * Manages the complete agent execution pipeline from message processing\n * to response generation.\n */\n\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\nimport type { Config } from '../../config/schema.js';\nimport type { InboundMessage } from '../../infra/bus/index.js';\nimport type { SessionConfigStore, SessionStore } from '../../session/index.js';\nimport type { SessionHydrator } from '../session/index.js';\nimport { resolveEffectiveThinkingLevel } from '../../session/thinking-resolve.js';\nimport type { ThinkLevel } from '../transcript/thinking-types.js';\nimport type { ModelManager } from '../models/index.js';\nimport type { SessionContext } from '../session/session-context.js';\nimport type { AgentEventHandler } from './agent-event-handler.js';\nimport type { FeedbackCoordinator } from '../feedback/feedback-coordinator.js';\nimport type { AgentManager } from '../agent-manager.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { extractAgentUserPlainText } from '../memory/user-message-text.js';\nimport { abortEmbeddedRun } from '../embedded/runs.js';\nimport { runEmbeddedTurnForSession } from '../embedded/run-for-session.js';\nimport type { EmbeddedStreamEvent } from '../embedded/types.js';\nimport {\n persistInboundAttachmentsToWorkspace,\n formatInboundFileTextBlock,\n} from '../../channels/attachments/inbound-persist.js';\nimport { expandAtFileMentionsInPlainText } from '../context/expand-at-file-mentions.js';\nimport { resolveInboundImageContentParts } from '../image/inbound-image-handling.js';\nimport {\n DREAMING_SWEEP_TOKEN,\n DREAMING_LIGHT_SWEEP_TOKEN,\n DREAMING_REM_SWEEP_TOKEN,\n} from '../memory/dreaming/constants.js';\nimport { resolveDreamingConfig } from '../memory/dreaming/config.js';\nimport { runDreamingDeepPromotion } from '../memory/dreaming/deep-promotion.js';\nimport { appendDreamingEvent, type DreamingEvent } from '../memory/dreaming/events.js';\nimport { runLightSweep } from '../memory/dreaming/light-sweep.js';\nimport { runRemPatterns } from '../memory/dreaming/rem-patterns.js';\n\nconst log = createLogger('AgentOrchestrator');\n\nexport interface AgentOrchestratorConfig {\n agentManager: AgentManager;\n sessionStore: SessionStore;\n modelManager: ModelManager;\n eventHandler: AgentEventHandler;\n feedbackCoordinator: FeedbackCoordinator;\n sessionConfigStore: SessionConfigStore;\n /** Per-session hydration (workspace override + model override) before the agent runs. */\n sessionHydrator: SessionHydrator;\n getThinkingDefault: () => ThinkLevel | undefined;\n /** Per-session default from merged `agents.list` / defaults (optional). */\n getThinkingDefaultForSession?: (sessionKey: string) => ThinkLevel | undefined;\n /** Default workspace root when no per-session resolver is set. */\n workspaceRoot: string;\n /** Per-agent workspace root for attachments (optional; defaults to `workspaceRoot`). */\n getWorkspaceRootForSession?: (sessionKey: string) => string;\n /** Agent home (`…/agents/<id>/`) for inbound/TTS files — keeps internal state out of the markdown workspace. */\n getAgentInternalStorageRootForSession?: (sessionKey: string) => string;\n /** Fire-and-forget after full session persist (e.g. LLM session title); not called from mid-turn snapshots. */\n enqueueAutoTitle?: (sessionKey: string) => void;\n /** For per-turn timeout via `agents.defaults.maxTaskDurationMs`. */\n getConfig?: () => Config | undefined;\n /** Channel streaming: token/tool events from pi embedded session. */\n onEmbeddedStreamEvent?: (sessionKey: string, event: EmbeddedStreamEvent) => void;\n /** Called after a successful embedded turn with assistant plain text. */\n onEmbeddedTurnComplete?: (sessionKey: string, lastAssistantText?: string) => void;\n}\n\nexport class AgentOrchestrator {\n private agentManager: AgentManager;\n private sessionStore: SessionStore;\n private modelManager: ModelManager;\n private eventHandler: AgentEventHandler;\n private feedbackCoordinator: FeedbackCoordinator;\n private sessionConfigStore: SessionConfigStore;\n private sessionHydrator: SessionHydrator;\n private getThinkingDefault: () => ThinkLevel | undefined;\n private getThinkingDefaultForSession?: (sessionKey: string) => ThinkLevel | undefined;\n private workspaceRoot: string;\n private getWorkspaceRootForSession?: (sessionKey: string) => string;\n private getAgentInternalStorageRootForSession: (sessionKey: string) => string;\n private enqueueAutoTitle?: (sessionKey: string) => void;\n private getConfig?: () => Config | undefined;\n private onEmbeddedStreamEvent?: (sessionKey: string, event: EmbeddedStreamEvent) => void;\n private onEmbeddedTurnComplete?: (sessionKey: string, lastAssistantText?: string) => void;\n\n constructor(config: AgentOrchestratorConfig) {\n this.agentManager = config.agentManager;\n this.sessionStore = config.sessionStore;\n this.modelManager = config.modelManager;\n this.eventHandler = config.eventHandler;\n this.feedbackCoordinator = config.feedbackCoordinator;\n this.sessionConfigStore = config.sessionConfigStore;\n this.sessionHydrator = config.sessionHydrator;\n this.getThinkingDefault = config.getThinkingDefault;\n this.getThinkingDefaultForSession = config.getThinkingDefaultForSession;\n this.workspaceRoot = config.workspaceRoot;\n this.getWorkspaceRootForSession = config.getWorkspaceRootForSession;\n this.getAgentInternalStorageRootForSession =\n config.getAgentInternalStorageRootForSession ??\n ((sk) => this.getWorkspaceRootForSession?.(sk) ?? this.workspaceRoot);\n this.enqueueAutoTitle = config.enqueueAutoTitle;\n this.getConfig = config.getConfig;\n this.onEmbeddedStreamEvent = config.onEmbeddedStreamEvent;\n this.onEmbeddedTurnComplete = config.onEmbeddedTurnComplete;\n }\n\n /**\n * Process a message through the agent orchestration pipeline\n */\n async process(msg: InboundMessage, context: SessionContext): Promise<void> {\n const { sessionKey } = context;\n\n log.debug({ sessionKey }, 'Processing message through agent orchestrator');\n\n await this.sessionHydrator.workspace(sessionKey);\n\n // Dreaming: short-circuit cron-triggered sweep tokens into maintenance runs.\n // This avoids spending LLM tokens for scheduled memory consolidation.\n if (\n typeof msg.content === 'string' &&\n (sessionKey.startsWith('cron:') || context.channel === 'cron')\n ) {\n const content = msg.content;\n const isDreamingSweep =\n content.includes(DREAMING_SWEEP_TOKEN) ||\n content.includes(DREAMING_LIGHT_SWEEP_TOKEN) ||\n content.includes(DREAMING_REM_SWEEP_TOKEN);\n\n if (isDreamingSweep) {\n const workspaceDir = this.agentManager.getResolvedWorkspaceForSession(sessionKey);\n const resolved = resolveDreamingConfig(this.getConfig?.());\n const t0 = Date.now();\n\n if (content.includes(DREAMING_LIGHT_SWEEP_TOKEN)) {\n const result = await runLightSweep({ workspaceDir, config: resolved.phases.light });\n const event: DreamingEvent = {\n timestamp: new Date().toISOString(), phase: 'light',\n ok: result.ok, reason: result.reason, durationMs: Date.now() - t0,\n scannedEntries: result.scannedEntries, newSignals: result.newSignals, deduped: result.deduped,\n };\n await appendDreamingEvent(workspaceDir, event);\n } else if (content.includes(DREAMING_REM_SWEEP_TOKEN)) {\n const result = await runRemPatterns({ workspaceDir, config: resolved.phases.rem });\n const event: DreamingEvent = {\n timestamp: new Date().toISOString(), phase: 'rem',\n ok: result.ok, reason: result.reason, durationMs: Date.now() - t0,\n patternsDiscovered: result.patternsDiscovered, entriesAnalyzed: result.entriesAnalyzed,\n };\n await appendDreamingEvent(workspaceDir, event);\n } else {\n const result = await runDreamingDeepPromotion({ workspaceDir, config: resolved.phases.deep });\n const event: DreamingEvent = {\n timestamp: new Date().toISOString(), phase: 'deep',\n ok: result.ok, reason: result.reason, durationMs: Date.now() - t0,\n candidates: result.candidates, applied: result.applied,\n };\n await appendDreamingEvent(workspaceDir, event);\n }\n return;\n }\n }\n\n try {\n await this.sessionHydrator.model(sessionKey);\n\n const thinkingDefault =\n this.getThinkingDefaultForSession?.(sessionKey) ?? this.getThinkingDefault();\n const thinkingLevel = await resolveEffectiveThinkingLevel(\n this.sessionConfigStore,\n sessionKey,\n null,\n thinkingDefault,\n );\n this.agentManager.setThinkingLevel(sessionKey, thinkingLevel);\n\n // Persist inbound files (Telegram, etc.) under agent home, then build user message\n const storageRoot = this.getAgentInternalStorageRootForSession(sessionKey);\n const persistedAttachments = await persistInboundAttachmentsToWorkspace(\n storageRoot,\n sessionKey,\n msg.attachments,\n );\n const userMessage = await this.buildUserMessage(\n {\n ...msg,\n attachments: persistedAttachments ?? msg.attachments,\n },\n sessionKey,\n );\n const userPlainForMemory = extractAgentUserPlainText(userMessage);\n const userMessageForModel = await this.agentManager.applyMemoryPrefetchToUserMessage(\n userMessage,\n sessionKey,\n );\n\n this.feedbackCoordinator.startTask();\n\n const turnResult = await runEmbeddedTurnForSession({\n sessionKey,\n userMessage: userMessageForModel,\n sessionStore: this.sessionStore,\n agentManager: this.agentManager,\n modelManager: this.modelManager,\n thinkingOverride: thinkingLevel,\n getConfig: this.getConfig,\n beforeTurn: () => this.agentManager.beginBackgroundReviewUserTurn(sessionKey),\n onEvent: (event) => this.onEmbeddedStreamEvent?.(sessionKey, event),\n });\n\n this.agentManager.afterAgentTurn(sessionKey, userPlainForMemory);\n this.agentManager.scheduleBackgroundReviewAfterUserTurn(sessionKey);\n\n if (turnResult.ok) {\n this.onEmbeddedTurnComplete?.(sessionKey, turnResult.lastAssistantText);\n this.enqueueAutoTitle?.(sessionKey);\n } else if (turnResult.errorMessage) {\n log.warn({ sessionKey, errorMessage: turnResult.errorMessage }, 'Embedded inbound turn failed');\n }\n\n this.feedbackCoordinator.endTask();\n\n } catch (error) {\n log.error({ err: error, sessionKey }, 'Error in agent orchestration');\n this.feedbackCoordinator.endTask();\n throw error;\n }\n }\n\n /**\n * Build an agent message from an inbound message\n */\n private async buildUserMessage(msg: InboundMessage, sessionKey: string): Promise<AgentMessage> {\n const storageRootAbs = this.getAgentInternalStorageRootForSession(sessionKey);\n let textBody = msg.content.trimStart().startsWith('/skill:')\n ? this.agentManager.expandSkillUserText(msg.content)\n : msg.content;\n\n if (/@file:/.test(textBody)) {\n const root = this.agentManager.getResolvedWorkspaceForSession(sessionKey);\n textBody = await expandAtFileMentionsInPlainText(textBody, root);\n }\n\n if (!msg.attachments || msg.attachments.length === 0) {\n return {\n role: 'user',\n content: textBody,\n timestamp: Date.now(),\n };\n }\n\n const modelRef = this.modelManager.getModelForSession(sessionKey);\n const cfg = this.getConfig?.();\n\n const messageContent: Array<\n { type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string }\n > = [];\n\n if (msg.content.trim()) {\n messageContent.push({ type: 'text', text: textBody });\n }\n\n const attachments = msg.attachments;\n let i = 0;\n while (i < attachments.length) {\n const att = attachments[i]!;\n const isImage =\n att.type === 'image' || att.type === 'photo' || Boolean(att.mimeType?.startsWith('image/'));\n\n if (isImage) {\n const group: Array<{ data: string; mimeType: string }> = [];\n while (i < attachments.length) {\n const a = attachments[i]!;\n const img =\n a.type === 'image' || a.type === 'photo' || Boolean(a.mimeType?.startsWith('image/'));\n if (!img) {\n break;\n }\n if (!a.data || a.data.length === 0) {\n log.warn({ type: a.type, name: a.name }, 'Empty image data, skipping');\n i += 1;\n continue;\n }\n group.push({ data: a.data, mimeType: a.mimeType || 'image/jpeg' });\n i += 1;\n }\n if (group.length > 0) {\n const parts = await resolveInboundImageContentParts({\n modelRef,\n cfg,\n userTextForContext: msg.content.trim() ? textBody : '',\n images: group,\n });\n messageContent.push(...parts);\n }\n } else {\n const fileBlock = formatInboundFileTextBlock(\n {\n type: att.type,\n mimeType: att.mimeType,\n name: att.name,\n size: att.size,\n workspaceRelativePath: att.workspaceRelativePath,\n },\n storageRootAbs,\n );\n messageContent.push({ type: 'text', text: fileBlock });\n i += 1;\n }\n }\n\n const hasText = messageContent.some((item) => item.type === 'text');\n const hasImage = messageContent.some((item) => item.type === 'image');\n if (hasImage && !hasText) {\n messageContent.unshift({ type: 'text', text: 'Please analyze the image(s) I sent.' });\n }\n\n if (messageContent.length === 0) {\n log.warn(\n { attachmentCount: msg.attachments.length },\n 'All attachments were skipped, falling back to text message',\n );\n return {\n role: 'user',\n content: textBody || '[Image attachment could not be processed]',\n timestamp: Date.now(),\n };\n }\n\n return {\n role: 'user',\n content: messageContent,\n timestamp: Date.now(),\n };\n }\n\n /**\n * Get the current agent model ID\n */\n getCurrentModel(): string {\n return this.modelManager.getCurrentModel();\n }\n\n /**\n * Check if agent is currently processing for a session\n */\n isProcessing(sessionKey: string): boolean {\n const agent = this.agentManager.getAgent(sessionKey);\n if (!agent) {\n return false;\n }\n return agent.state.messages.length > 0;\n }\n\n /**\n * Abort current agent execution for a session\n */\n abort(sessionKey: string): void {\n void abortEmbeddedRun(sessionKey);\n const agent = this.agentManager.getAgent(sessionKey);\n agent?.abort();\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agent-orchestrator.js","names":[],"sources":["../../../../src/agent/orchestration/agent-orchestrator.ts"],"sourcesContent":["/**\n * Agent Orchestrator - Coordinates Agent execution flow\n *\n * Manages the complete agent execution pipeline from message processing\n * to response generation.\n */\n\nimport type { Config } from '../../config/schema.js';\nimport type { InboundMessage } from '../../infra/bus/index.js';\nimport type { SessionConfigStore, SessionStore } from '../../session/index.js';\nimport type { SessionHydrator } from '../session/index.js';\nimport { resolveEffectiveThinkingLevel } from '../../session/thinking-resolve.js';\nimport type { ThinkLevel } from '../transcript/thinking-types.js';\nimport type { ModelManager } from '../models/index.js';\nimport type { SessionContext } from '../session/session-context.js';\nimport type { AgentEventHandler } from './agent-event-handler.js';\nimport type { FeedbackCoordinator } from '../feedback/feedback-coordinator.js';\nimport type { AgentManager } from '../agent-manager.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { extractAgentUserPlainText } from '../memory/user-message-text.js';\nimport { abortEmbeddedRun } from '../embedded/runs.js';\nimport { runEmbeddedTurnForSession } from '../embedded/run-for-session.js';\nimport type { EmbeddedStreamEvent } from '../embedded/types.js';\nimport { persistInboundAttachments } from '../../channels/attachments/inbound-persist.js';\nimport {\n buildTranscriptUserMessage,\n clearPendingTranscriptUserMessage,\n hydrateUserTurnForLlm,\n setPendingTranscriptUserMessage,\n} from '../inbound/attachment-pipeline.js';\nimport {\n DREAMING_SWEEP_TOKEN,\n DREAMING_LIGHT_SWEEP_TOKEN,\n DREAMING_REM_SWEEP_TOKEN,\n} from '../memory/dreaming/constants.js';\nimport { resolveDreamingConfig } from '../memory/dreaming/config.js';\nimport { runDreamingDeepPromotion } from '../memory/dreaming/deep-promotion.js';\nimport { appendDreamingEvent, type DreamingEvent } from '../memory/dreaming/events.js';\nimport { runLightSweep } from '../memory/dreaming/light-sweep.js';\nimport { runRemPatterns } from '../memory/dreaming/rem-patterns.js';\n\nconst log = createLogger('AgentOrchestrator');\n\nexport interface AgentOrchestratorConfig {\n agentManager: AgentManager;\n sessionStore: SessionStore;\n modelManager: ModelManager;\n eventHandler: AgentEventHandler;\n feedbackCoordinator: FeedbackCoordinator;\n sessionConfigStore: SessionConfigStore;\n /** Per-session hydration (workspace override + model override) before the agent runs. */\n sessionHydrator: SessionHydrator;\n getThinkingDefault: () => ThinkLevel | undefined;\n /** Per-session default from merged `agents.list` / defaults (optional). */\n getThinkingDefaultForSession?: (sessionKey: string) => ThinkLevel | undefined;\n /** Default workspace root when no per-session resolver is set. */\n workspaceRoot: string;\n /** Per-agent workspace root for attachments (optional; defaults to `workspaceRoot`). */\n getWorkspaceRootForSession?: (sessionKey: string) => string;\n /** Agent home (`…/agents/<id>/`) for inbound/TTS files — keeps internal state out of the markdown workspace. */\n getAgentInternalStorageRootForSession?: (sessionKey: string) => string;\n /** Fire-and-forget after full session persist (e.g. LLM session title); not called from mid-turn snapshots. */\n enqueueAutoTitle?: (sessionKey: string) => void;\n /** For per-turn timeout via `agents.defaults.maxTaskDurationMs`. */\n getConfig?: () => Config | undefined;\n /** Channel streaming: token/tool events from pi embedded session. */\n onEmbeddedStreamEvent?: (sessionKey: string, event: EmbeddedStreamEvent) => void;\n /** Called after a successful embedded turn with assistant plain text. */\n onEmbeddedTurnComplete?: (sessionKey: string, lastAssistantText?: string) => void;\n}\n\nexport class AgentOrchestrator {\n private agentManager: AgentManager;\n private sessionStore: SessionStore;\n private modelManager: ModelManager;\n private eventHandler: AgentEventHandler;\n private feedbackCoordinator: FeedbackCoordinator;\n private sessionConfigStore: SessionConfigStore;\n private sessionHydrator: SessionHydrator;\n private getThinkingDefault: () => ThinkLevel | undefined;\n private getThinkingDefaultForSession?: (sessionKey: string) => ThinkLevel | undefined;\n private workspaceRoot: string;\n private getWorkspaceRootForSession?: (sessionKey: string) => string;\n private getAgentInternalStorageRootForSession: (sessionKey: string) => string;\n private enqueueAutoTitle?: (sessionKey: string) => void;\n private getConfig?: () => Config | undefined;\n private onEmbeddedStreamEvent?: (sessionKey: string, event: EmbeddedStreamEvent) => void;\n private onEmbeddedTurnComplete?: (sessionKey: string, lastAssistantText?: string) => void;\n\n constructor(config: AgentOrchestratorConfig) {\n this.agentManager = config.agentManager;\n this.sessionStore = config.sessionStore;\n this.modelManager = config.modelManager;\n this.eventHandler = config.eventHandler;\n this.feedbackCoordinator = config.feedbackCoordinator;\n this.sessionConfigStore = config.sessionConfigStore;\n this.sessionHydrator = config.sessionHydrator;\n this.getThinkingDefault = config.getThinkingDefault;\n this.getThinkingDefaultForSession = config.getThinkingDefaultForSession;\n this.workspaceRoot = config.workspaceRoot;\n this.getWorkspaceRootForSession = config.getWorkspaceRootForSession;\n this.getAgentInternalStorageRootForSession =\n config.getAgentInternalStorageRootForSession ??\n ((sk) => this.getWorkspaceRootForSession?.(sk) ?? this.workspaceRoot);\n this.enqueueAutoTitle = config.enqueueAutoTitle;\n this.getConfig = config.getConfig;\n this.onEmbeddedStreamEvent = config.onEmbeddedStreamEvent;\n this.onEmbeddedTurnComplete = config.onEmbeddedTurnComplete;\n }\n\n /**\n * Process a message through the agent orchestration pipeline\n */\n async process(msg: InboundMessage, context: SessionContext): Promise<void> {\n const { sessionKey } = context;\n\n log.debug({ sessionKey }, 'Processing message through agent orchestrator');\n\n await this.sessionHydrator.workspace(sessionKey);\n\n // Dreaming: short-circuit cron-triggered sweep tokens into maintenance runs.\n // This avoids spending LLM tokens for scheduled memory consolidation.\n if (\n typeof msg.content === 'string' &&\n (sessionKey.startsWith('cron:') || context.channel === 'cron')\n ) {\n const content = msg.content;\n const isDreamingSweep =\n content.includes(DREAMING_SWEEP_TOKEN) ||\n content.includes(DREAMING_LIGHT_SWEEP_TOKEN) ||\n content.includes(DREAMING_REM_SWEEP_TOKEN);\n\n if (isDreamingSweep) {\n const workspaceDir = this.agentManager.getResolvedWorkspaceForSession(sessionKey);\n const resolved = resolveDreamingConfig(this.getConfig?.());\n const t0 = Date.now();\n\n if (content.includes(DREAMING_LIGHT_SWEEP_TOKEN)) {\n const result = await runLightSweep({ workspaceDir, config: resolved.phases.light });\n const event: DreamingEvent = {\n timestamp: new Date().toISOString(), phase: 'light',\n ok: result.ok, reason: result.reason, durationMs: Date.now() - t0,\n scannedEntries: result.scannedEntries, newSignals: result.newSignals, deduped: result.deduped,\n };\n await appendDreamingEvent(workspaceDir, event);\n } else if (content.includes(DREAMING_REM_SWEEP_TOKEN)) {\n const result = await runRemPatterns({ workspaceDir, config: resolved.phases.rem });\n const event: DreamingEvent = {\n timestamp: new Date().toISOString(), phase: 'rem',\n ok: result.ok, reason: result.reason, durationMs: Date.now() - t0,\n patternsDiscovered: result.patternsDiscovered, entriesAnalyzed: result.entriesAnalyzed,\n };\n await appendDreamingEvent(workspaceDir, event);\n } else {\n const result = await runDreamingDeepPromotion({ workspaceDir, config: resolved.phases.deep });\n const event: DreamingEvent = {\n timestamp: new Date().toISOString(), phase: 'deep',\n ok: result.ok, reason: result.reason, durationMs: Date.now() - t0,\n candidates: result.candidates, applied: result.applied,\n };\n await appendDreamingEvent(workspaceDir, event);\n }\n return;\n }\n }\n\n try {\n await this.sessionHydrator.model(sessionKey);\n\n const channelSystemPrompt =\n typeof context.metadata?.channelSystemPrompt === 'string'\n ? context.metadata.channelSystemPrompt.trim()\n : '';\n if (channelSystemPrompt) {\n this.agentManager.getOrCreateAgent(sessionKey);\n this.agentManager.applyTurnChannelSystemPrompt(sessionKey, channelSystemPrompt);\n }\n\n const thinkingDefault =\n this.getThinkingDefaultForSession?.(sessionKey) ?? this.getThinkingDefault();\n const thinkingLevel = await resolveEffectiveThinkingLevel(\n this.sessionConfigStore,\n sessionKey,\n null,\n thinkingDefault,\n );\n this.agentManager.setThinkingLevel(sessionKey, thinkingLevel);\n\n const persistedAttachments = await persistInboundAttachments(msg.attachments);\n const modelRef = this.modelManager.getModelForSession(sessionKey);\n const userMessage = await buildTranscriptUserMessage({\n text: msg.content,\n prepared: persistedAttachments,\n sessionKey,\n modelRef,\n config: this.getConfig?.(),\n agentManager: this.agentManager,\n });\n setPendingTranscriptUserMessage(sessionKey, userMessage);\n\n const userPlainForMemory = extractAgentUserPlainText(userMessage);\n const userMessageForModel = await this.agentManager.applyMemoryPrefetchToUserMessage(\n userMessage,\n sessionKey,\n );\n\n const llmTurn = await hydrateUserTurnForLlm({\n message: userMessage,\n modelRef,\n });\n\n this.feedbackCoordinator.startTask();\n\n const turnResult = await (async () => {\n try {\n return await runEmbeddedTurnForSession({\n sessionKey,\n userMessage: userMessageForModel,\n llmImages: llmTurn.images,\n sessionStore: this.sessionStore,\n agentManager: this.agentManager,\n modelManager: this.modelManager,\n thinkingOverride: thinkingLevel,\n getConfig: this.getConfig,\n beforeTurn: () => this.agentManager.beginBackgroundReviewUserTurn(sessionKey),\n onEvent: (event) => this.onEmbeddedStreamEvent?.(sessionKey, event),\n });\n } finally {\n clearPendingTranscriptUserMessage(sessionKey, userMessage);\n }\n })();\n\n this.agentManager.afterAgentTurn(sessionKey, userPlainForMemory);\n this.agentManager.scheduleBackgroundReviewAfterUserTurn(sessionKey);\n\n if (turnResult.ok) {\n this.onEmbeddedTurnComplete?.(sessionKey, turnResult.lastAssistantText);\n this.enqueueAutoTitle?.(sessionKey);\n } else if (turnResult.errorMessage) {\n log.warn({ sessionKey, errorMessage: turnResult.errorMessage }, 'Embedded inbound turn failed');\n }\n\n this.feedbackCoordinator.endTask();\n\n } catch (error) {\n log.error({ err: error, sessionKey }, 'Error in agent orchestration');\n this.feedbackCoordinator.endTask();\n throw error;\n }\n }\n\n /**\n * Get the current agent model ID\n */\n getCurrentModel(): string {\n return this.modelManager.getCurrentModel();\n }\n\n /**\n * Check if agent is currently processing for a session\n */\n isProcessing(sessionKey: string): boolean {\n const agent = this.agentManager.getAgent(sessionKey);\n if (!agent) {\n return false;\n }\n return agent.state.messages.length > 0;\n }\n\n /**\n * Abort current agent execution for a session\n */\n abort(sessionKey: string): void {\n void abortEmbeddedRun(sessionKey);\n const agent = this.agentManager.getAgent(sessionKey);\n agent?.abort();\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ProviderSystemPromptSectionId = 'interaction_style' | 'tool_call_style' | 'execution_bias';
|
|
2
|
+
export type ProviderSystemPromptContribution = {
|
|
3
|
+
/** Cache-stable provider guidance inserted above the prompt cache boundary. */
|
|
4
|
+
stablePrefix?: string;
|
|
5
|
+
/** Provider guidance inserted below the cache boundary. */
|
|
6
|
+
dynamicSuffix?: string;
|
|
7
|
+
/** Whole-section replacements for selected core prompt sections. */
|
|
8
|
+
sectionOverrides?: Partial<Record<ProviderSystemPromptSectionId, string>>;
|
|
9
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
import { Type } from "@sinclair/typebox";
|
|
2
1
|
//#region src/agent/prompt/safety.ts
|
|
3
|
-
Type.Object({
|
|
4
|
-
allowExternalActions: Type.Optional(Type.Boolean({ default: false })),
|
|
5
|
-
allowDangerousOperations: Type.Optional(Type.Boolean({ default: false })),
|
|
6
|
-
requireConfirmationForDestructive: Type.Optional(Type.Boolean({ default: true })),
|
|
7
|
-
allowedChannels: Type.Optional(Type.Array(Type.String())),
|
|
8
|
-
blockedCommands: Type.Optional(Type.Array(Type.String())),
|
|
9
|
-
maxFileSize: Type.Optional(Type.Number({ default: 10 * 1024 * 1024 })),
|
|
10
|
-
maxShellTimeout: Type.Optional(Type.Number({ default: 300 }))
|
|
11
|
-
});
|
|
12
2
|
/**
|
|
13
3
|
* Quick safety check for file operations
|
|
14
4
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safety.js","names":[],"sources":["../../../../src/agent/prompt/safety.ts"],"sourcesContent":["// Safety System -
|
|
1
|
+
{"version":3,"file":"safety.js","names":[],"sources":["../../../../src/agent/prompt/safety.ts"],"sourcesContent":["// Safety System - Quick safety check for file operations\n\n/**\n * Quick safety check for file operations\n */\nexport function checkFileSafety(\n operation: 'read' | 'write' | 'delete',\n path: string\n): { allowed: boolean; message?: string } {\n // Check for sensitive paths\n const sensitivePaths = [\n '/etc/passwd',\n '/etc/shadow',\n '/root/.ssh',\n '/home/*/.ssh',\n '~/.aws',\n '~/.bashrc',\n '~/.profile',\n ];\n\n for (const sp of sensitivePaths) {\n if (path.includes(sp)) {\n return {\n allowed: false,\n message: `Cannot ${operation} sensitive path: ${path}`,\n };\n }\n }\n\n return { allowed: true };\n}\n\n"],"mappings":";;;;AAKA,SAAgB,gBACd,WACA,MACwC;AAYxC,MAAK,MAAM,MAAM;EATf;EACA;EACA;EACA;EACA;EACA;EACA;EAG6B,CAC7B,KAAI,KAAK,SAAS,GAAG,CACnB,QAAO;EACL,SAAS;EACT,SAAS,UAAU,UAAU,mBAAmB;EACjD;AAIL,QAAO,EAAE,SAAS,MAAM"}
|