@xopcai/xopc 0.0.124 → 0.0.126
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/README.md +56 -102
- package/README.zh-CN.md +51 -98
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/schema/config-schema.d.ts +6 -6
- package/dist/extensions/feishu/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
- package/dist/extensions/telegram/src/config-schema.d.ts +8 -8
- package/dist/extensions/telegram/src/inbound-processor.js +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +1 -1
- package/dist/extensions/weixin/src/config-schema.d.ts +3 -3
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/gateway/static/root/assets/Combination-BzaXOLd9.js +41 -0
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B5uSVAyJ.js → agent-avatar-dicebear-C70vgt60.js} +1 -1
- package/dist/gateway/static/root/assets/agents-DRYVahI-.js +2 -0
- package/dist/gateway/static/root/assets/app-management-settings-panel-D9-HW6cy.js +1 -0
- package/dist/gateway/static/root/assets/appearance-settings-BHlahIDL.js +1 -0
- package/dist/gateway/static/root/assets/apps-page-BdJ1eQg3.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-CXUGRp2i.js → archive-plugin-B-aoIt0w.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-Cmiub3Wg.js → attachment-load-BD0G0FD5.js} +1 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-iJRVI7aZ.js +1 -0
- package/dist/gateway/static/root/assets/automations-page-D8hYQbkl.js +4 -0
- package/dist/gateway/static/root/assets/{binary-plugins-0Izz-N3p.js → binary-plugins-B0mNlVSz.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-C1Kv0IkJ.js → block-editor-CJY9Lu5G.js} +3 -3
- package/dist/gateway/static/root/assets/browser-settings-page-CiWEO-Iy.js +8 -0
- package/dist/gateway/static/root/assets/capability-presets-api-Bgc8ag55.js +1 -0
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-B1nIi0TC.js +1 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-BeA2aVor.js → channel-recipient-api-0sauApoC.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-BddPdqVo.js +1 -0
- package/dist/gateway/static/root/assets/code-editor-gbRgS14t.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-Ba2GDhSE.js +2 -0
- package/dist/gateway/static/root/assets/{directory-picker-path-field-2rjzUu57.js → directory-picker-path-field-CiEc4KmY.js} +1 -1
- package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +1 -0
- package/dist/gateway/static/root/assets/dist-CkobR7mk.js +1 -0
- package/dist/gateway/static/root/assets/dist-DokQNVMQ.js +1 -0
- package/dist/gateway/static/root/assets/dreaming-settings-4bvpk5wr.js +3 -0
- package/dist/gateway/static/root/assets/extension-debug-page-BbyczVZ3.js +1 -0
- package/dist/gateway/static/root/assets/extension-page-DLN1I3DR.js +1 -0
- package/dist/gateway/static/root/assets/extension-settings-page-D9VGHmYJ.js +1 -0
- package/dist/gateway/static/root/assets/{fetch-BU5S0Sn7.js → fetch-5V96dUz3.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-BIPGwrl1.js → gateway-config-api-BtIzObwp.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-KFsGGDhg.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-Cd0Zz30N.js → gateway-startup-retry-DEMad2wt.js} +1 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-4PcF6Sh6.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-B482PSaG.js +1 -0
- package/dist/gateway/static/root/assets/{goals-config-api-B95KdGMj.js → goals-config-api-CVN7-pdM.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-CUdgJuDn.js +2 -0
- package/dist/gateway/static/root/assets/goals-settings-IYCH3-Pi.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-Cf_a2Bmz.js +1 -0
- package/dist/gateway/static/root/assets/{html-workspace-editor-CQLWDiwE.js → html-workspace-editor-DV90ddkE.js} +1 -1
- package/dist/gateway/static/root/assets/index-CA2tR2vm.js +256 -0
- package/dist/gateway/static/root/assets/index-Ds3u0LOk.css +1 -0
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-lKTg6St7.js +1 -0
- package/dist/gateway/static/root/assets/logs-page-BCporcNH.js +2 -0
- package/dist/gateway/static/root/assets/{markdown-editor-AssmZFx4.js → markdown-editor-BFOjBBla.js} +2 -2
- package/dist/gateway/static/root/assets/markdown-split-Bv4k6iGJ.js +1 -0
- package/dist/gateway/static/root/assets/{media-plugins-BhIQU5yS.js → media-plugins-Bbi8g3N8.js} +1 -1
- package/dist/gateway/static/root/assets/messages-C22hxE1N.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-D68Pyow7.js +2 -0
- package/dist/gateway/static/root/assets/notes-page-CuUMOiyv.js +1 -0
- package/dist/gateway/static/root/assets/notes-workbench-Dx2N5zTk.js +2 -0
- package/dist/gateway/static/root/assets/page-tabs-Cp395RYD.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-DGzet1d7.js → preview-open-alternatives-DqV5OM4m.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-sB8AzZi3.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-LBnJqWK2.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-Dbj0o6SC.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-Cqgb-jqa.js → save-bar-controls-BItmzAzI.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-DVZcI8Yt.js → schedule-field-BQ8IjjCn.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-Bj7sOxC8.js → schema-form-BRpD6x3d.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-DhDZKspB.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BvXLMNL6.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-BmXn-8N6.js → settings-collapsible-section-BKSPQM4R.js} +1 -1
- package/dist/gateway/static/root/assets/settings-form-section-BmyfthNQ.js +1 -0
- package/dist/gateway/static/root/assets/settings-page-Cfm9UxAr.js +1 -0
- package/dist/gateway/static/root/assets/settings-page-layout-Bls5tfbH.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-kQEsTGAs.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-IB1v8i86.js → share-preview-page-DbYZNAPb.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-BtR4B0kn.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-CJNVOWoK.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-DcWDHrt3.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-BxQ384RC.js → system-settings-panel-DKDAojWM.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-BkcpvFYO.js → typed-models-lib-BCCV4Kkp.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-Cd0FaEQ4.js → use-channel-catalog-NBqg3iFY.js} +1 -1
- package/dist/gateway/static/root/assets/{user-profile-settings-panel-DQ7NnRSY.js → user-profile-settings-panel-suQ2x-LB.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-YKhVf7Ka.js → utils-DPGVr3tS.js} +1 -1
- package/dist/gateway/static/root/assets/{vendor-codemirror-CNP1wPe7.js → vendor-codemirror-BvNgyE1Q.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-DaJASKFP.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-BrCZpAWh.js +1 -0
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-BTkRVNAh.js +3 -0
- package/dist/gateway/static/root/assets/{workflow-start-dialog-BNJVCWoS.js → workflow-start-dialog-DAImVtdO.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-vyJ8wSXm.js +18 -0
- package/dist/gateway/static/root/index.html +8 -7
- package/dist/package.js +1 -1
- package/dist/src/activity/context.d.ts +11 -0
- package/dist/src/activity/context.js +36 -0
- package/dist/src/activity/context.js.map +1 -0
- package/dist/src/activity/emitter.d.ts +6 -0
- package/dist/src/activity/emitter.js +43 -0
- package/dist/src/activity/emitter.js.map +1 -0
- package/dist/src/activity/index.d.ts +3 -0
- package/dist/src/activity/index.js +3 -0
- package/dist/src/activity/service.d.ts +12 -0
- package/dist/src/activity/service.js +59 -0
- package/dist/src/activity/service.js.map +1 -0
- package/dist/src/activity/types.d.ts +109 -0
- package/dist/src/activity/types.js +1 -0
- package/dist/src/agent/agent-manager.d.ts +7 -0
- package/dist/src/agent/agent-manager.js +12 -5
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/child-agent-factory.d.ts +2 -0
- package/dist/src/agent/child-agent-factory.js +2 -0
- package/dist/src/agent/child-agent-factory.js.map +1 -1
- package/dist/src/agent/coding/index.d.ts +1 -0
- package/dist/src/agent/coding/index.js +2 -0
- package/dist/src/agent/coding/turn-diff-tracker.d.ts +67 -0
- package/dist/src/agent/coding/turn-diff-tracker.js +233 -0
- package/dist/src/agent/coding/turn-diff-tracker.js.map +1 -0
- package/dist/src/agent/context/project-context.js +2 -2
- package/dist/src/agent/context/workspace-seed.js +2 -2
- package/dist/src/agent/embedded/run-for-session.js +1 -1
- package/dist/src/agent/goals/post-turn.js +2 -2
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
- package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +1 -1
- package/dist/src/agent/memory/dreaming/config.d.ts +2 -2
- package/dist/src/agent/memory/dreaming/config.js +3 -3
- package/dist/src/agent/memory/dreaming/config.js.map +1 -1
- package/dist/src/agent/memory/dreaming/constants.d.ts +1 -1
- package/dist/src/agent/memory/dreaming/constants.js +1 -1
- package/dist/src/agent/memory/dreaming/constants.js.map +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.d.ts +1 -0
- package/dist/src/agent/memory/dreaming/deep-promotion.js +11 -20
- package/dist/src/agent/memory/dreaming/deep-promotion.js.map +1 -1
- package/dist/src/agent/memory/dreaming/events.d.ts +3 -3
- package/dist/src/agent/memory/dreaming/events.js +6 -6
- package/dist/src/agent/memory/dreaming/events.js.map +1 -1
- package/dist/src/agent/memory/dreaming/last-run.d.ts +2 -2
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js.map +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.d.ts +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +3 -3
- package/dist/src/agent/memory/dreaming/light-sweep.js.map +1 -1
- package/dist/src/agent/memory/dreaming/preview.d.ts +1 -0
- package/dist/src/agent/memory/dreaming/preview.js +2 -2
- package/dist/src/agent/memory/dreaming/preview.js.map +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.d.ts +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +13 -13
- package/dist/src/agent/memory/dreaming/rem-patterns.js.map +1 -1
- package/dist/src/agent/memory/dreaming/scope.d.ts +14 -0
- package/dist/src/agent/memory/dreaming/scope.js +27 -0
- package/dist/src/agent/memory/dreaming/scope.js.map +1 -0
- package/dist/src/agent/memory/dreaming/short-term-store.d.ts +4 -4
- package/dist/src/agent/memory/dreaming/short-term-store.js +17 -17
- package/dist/src/agent/memory/dreaming/short-term-store.js.map +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/orchestration/agent-event-handler.d.ts +2 -0
- package/dist/src/agent/orchestration/agent-event-handler.js +13 -0
- package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js +22 -12
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/sandbox/command-validator.js +12 -0
- package/dist/src/agent/sandbox/command-validator.js.map +1 -1
- package/dist/src/agent/service.d.ts +2 -1
- package/dist/src/agent/service.js +24 -9
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +7 -0
- package/dist/src/agent/session/session-inspector.d.ts +5 -3
- package/dist/src/agent/session/session-inspector.js +17 -8
- package/dist/src/agent/session/session-inspector.js.map +1 -1
- package/dist/src/agent/skills/hub-pull.js +1 -1
- package/dist/src/agent/source-context/types.d.ts +1 -1
- package/dist/src/agent/source-context/types.js +1 -1
- package/dist/src/agent/source-context/types.js.map +1 -1
- package/dist/src/agent/tool-manuals/index.js +15 -6
- package/dist/src/agent/tool-manuals/index.js.map +1 -1
- package/dist/src/agent/tool-manuals/xopc-use.d.ts +1 -0
- package/dist/src/agent/tool-manuals/xopc-use.js +204 -0
- package/dist/src/agent/tool-manuals/xopc-use.js.map +1 -0
- package/dist/src/agent/tools/apply-patch.js +116 -62
- package/dist/src/agent/tools/apply-patch.js.map +1 -1
- package/dist/src/agent/tools/concurrency.d.ts +8 -0
- package/dist/src/agent/tools/concurrency.js +31 -0
- package/dist/src/agent/tools/concurrency.js.map +1 -0
- package/dist/src/agent/tools/dreaming-tool.d.ts +2 -0
- package/dist/src/agent/tools/dreaming-tool.js +13 -10
- package/dist/src/agent/tools/dreaming-tool.js.map +1 -1
- package/dist/src/agent/tools/exec-command.js +4 -0
- package/dist/src/agent/tools/exec-command.js.map +1 -1
- package/dist/src/agent/tools/executor.d.ts +6 -4
- package/dist/src/agent/tools/executor.js +7 -4
- package/dist/src/agent/tools/executor.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +10 -0
- package/dist/src/agent/tools/factory.js +16 -1
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/find.js +2 -0
- package/dist/src/agent/tools/find.js.map +1 -1
- package/dist/src/agent/tools/goal-tool.js +2 -2
- package/dist/src/agent/tools/grep.js +2 -0
- package/dist/src/agent/tools/grep.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +3 -0
- package/dist/src/agent/tools/index.js +4 -1
- package/dist/src/agent/tools/list-dir.js +2 -0
- package/dist/src/agent/tools/list-dir.js.map +1 -1
- package/dist/src/agent/tools/memory-tool.d.ts +1 -0
- package/dist/src/agent/tools/memory-tool.js +2 -2
- package/dist/src/agent/tools/memory-tool.js.map +1 -1
- package/dist/src/agent/tools/metadata.d.ts +15 -0
- package/dist/src/agent/tools/metadata.js +26 -0
- package/dist/src/agent/tools/metadata.js.map +1 -0
- package/dist/src/agent/tools/read.js +2 -0
- package/dist/src/agent/tools/read.js.map +1 -1
- package/dist/src/agent/tools/workflow-tool.js +1 -1
- package/dist/src/agent/tools/write.js +6 -0
- package/dist/src/agent/tools/write.js.map +1 -1
- package/dist/src/agent/tools/xopc-use-tool.d.ts +34 -0
- package/dist/src/agent/tools/xopc-use-tool.js +636 -0
- package/dist/src/agent/tools/xopc-use-tool.js.map +1 -0
- package/dist/src/agent/workflow/subagent-runner.d.ts +1 -0
- package/dist/src/agent/workflow/subagent-runner.js +5 -1
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
- package/dist/src/agent/workflow/workflow-child-tools.js +5 -0
- package/dist/src/agent/workflow/workflow-child-tools.js.map +1 -1
- package/dist/src/agent-manifest/schema.d.ts +27 -27
- package/dist/src/automations/api/routes.js +1 -1
- package/dist/src/automations/domain/validation.d.ts +55 -55
- package/dist/src/automations/draft/automation-draft-validator.d.ts +25 -25
- package/dist/src/automations/service/action-executor.js +2 -2
- package/dist/src/browser/cdp-local-launcher.js +1 -1
- package/dist/src/browser/providers/browser-ext-install.js +3 -3
- package/dist/src/browser/providers/cloakbrowser.js +2 -2
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/chat-commands/agent-edit.js +1 -1
- package/dist/src/chat-commands/builtins/config.js +1 -1
- package/dist/src/chat-commands/builtins/goal.js +2 -2
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/cli/commands/agent.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +2 -2
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/extension-pack.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/cli/commands/goal.js +3 -3
- package/dist/src/cli/commands/init.js +1 -1
- package/dist/src/cli/commands/project.js +4 -4
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +1 -1
- package/dist/src/config/loader.js +1 -1
- package/dist/src/config/models-json.d.ts +14 -14
- package/dist/src/config/models-json.js +1 -1
- package/dist/src/config/schema.d.ts +60 -60
- package/dist/src/connectors/health.d.ts +2 -1
- package/dist/src/connectors/health.js +59 -1
- package/dist/src/connectors/health.js.map +1 -1
- package/dist/src/connectors/install.d.ts +1 -0
- package/dist/src/connectors/install.js +28 -1
- package/dist/src/connectors/install.js.map +1 -1
- package/dist/src/connectors/instances.js +7 -0
- package/dist/src/connectors/instances.js.map +1 -1
- package/dist/src/connectors/materialize.js +2 -1
- package/dist/src/connectors/materialize.js.map +1 -1
- package/dist/src/connectors/registries/modelscope.js +38 -13
- package/dist/src/connectors/registries/modelscope.js.map +1 -1
- package/dist/src/connectors/types.d.ts +2 -0
- package/dist/src/daemon/launchd.js +1 -1
- package/dist/src/daemon/systemd.js +1 -1
- package/dist/src/extensions/discover-extensions.js +1 -1
- package/dist/src/extensions/loader.js +2 -2
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/dreaming-automation-reconciler.d.ts +1 -0
- package/dist/src/gateway/dreaming-automation-reconciler.js +62 -42
- package/dist/src/gateway/dreaming-automation-reconciler.js.map +1 -1
- package/dist/src/gateway/hono/app.js +7 -1
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +14 -14
- package/dist/src/gateway/hono/lib/static-ui.js +1 -1
- package/dist/src/gateway/hono/middleware/log-context.js +8 -1
- package/dist/src/gateway/hono/middleware/log-context.js.map +1 -1
- package/dist/src/gateway/hono/routes/activity.d.ts +14 -0
- package/dist/src/gateway/hono/routes/activity.js +72 -0
- package/dist/src/gateway/hono/routes/activity.js.map +1 -0
- package/dist/src/gateway/hono/routes/connectors.js +46 -2
- package/dist/src/gateway/hono/routes/connectors.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +111 -66
- package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
- package/dist/src/gateway/hono/routes/goals.js +1 -1
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/index.js.map +1 -1
- package/dist/src/gateway/hono/routes/memory.js +2 -2
- package/dist/src/gateway/hono/routes/projects.js +903 -50
- package/dist/src/gateway/hono/routes/projects.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +102 -2
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +2 -2
- package/dist/src/gateway/lock.js +1 -1
- package/dist/src/gateway/ports.js +1 -1
- package/dist/src/gateway/service/sessions-api.d.ts +10 -0
- package/dist/src/gateway/service/sessions-api.js +31 -0
- package/dist/src/gateway/service/sessions-api.js.map +1 -1
- package/dist/src/gateway/service.js +28 -16
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/goals/goal-store.js +1 -1
- package/dist/src/goals/goal-store.js.map +1 -1
- package/dist/src/goals/goal-workflow-judge.js +1 -1
- package/dist/src/infra/ports.js +1 -1
- package/dist/src/infra/ssh-tunnel.js +1 -1
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/mcp/channel-bridge.js +1 -1
- package/dist/src/media/store.js +1 -1
- package/dist/src/media/store.js.map +1 -1
- package/dist/src/media/types.d.ts +1 -1
- package/dist/src/media/uri.js +2 -1
- package/dist/src/media/uri.js.map +1 -1
- package/dist/src/migrations/runner.js +1 -1
- package/dist/src/notes/service.js +65 -6
- package/dist/src/notes/service.js.map +1 -1
- package/dist/src/notes/store.js +1 -1
- package/dist/src/projects/project-service.d.ts +2 -1
- package/dist/src/projects/project-service.js +59 -2
- package/dist/src/projects/project-service.js.map +1 -1
- package/dist/src/projects/project-store.d.ts +2 -1
- package/dist/src/projects/project-store.js +43 -0
- package/dist/src/projects/project-store.js.map +1 -1
- package/dist/src/projects/types.d.ts +10 -0
- package/dist/src/projects/workspace.js +1 -1
- package/dist/src/routing/agent-session-key.js +1 -1
- package/dist/src/routing/resolve-route.js +1 -1
- package/dist/src/routing/resolve-tui-session-key.js +1 -1
- package/dist/src/session/client-history.d.ts +3 -0
- package/dist/src/session/client-history.js +24 -9
- package/dist/src/session/client-history.js.map +1 -1
- package/dist/src/session/init-session-turn.js +1 -1
- package/dist/src/session/resolve-session.js +1 -1
- package/dist/src/session/session-context-for-llm.d.ts +2 -0
- package/dist/src/session/session-context-for-llm.js +14 -1
- package/dist/src/session/session-context-for-llm.js.map +1 -1
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/store.js +3 -3
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/types.d.ts +4 -0
- package/dist/src/session/types.js.map +1 -1
- package/dist/src/storage/sqlite/activity-repository.d.ts +8 -0
- package/dist/src/storage/sqlite/activity-repository.js +208 -0
- package/dist/src/storage/sqlite/activity-repository.js.map +1 -0
- package/dist/src/storage/sqlite/connection.js +1 -1
- package/dist/src/storage/sqlite/index.d.ts +1 -0
- package/dist/src/storage/sqlite/index.js +2 -1
- package/dist/src/storage/sqlite/migrations/022_work_items.sql +61 -0
- package/dist/src/storage/sqlite/migrations/023_work_item_attachments.sql +15 -0
- package/dist/src/storage/sqlite/migrations/024_activity_events.sql +62 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/row-mappers.js +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/schema.sql +141 -0
- package/dist/src/storage/sqlite/session-repository.js +11 -0
- package/dist/src/storage/sqlite/session-repository.js.map +1 -1
- package/dist/src/tui/backends/embedded-backend.d.ts +13 -0
- package/dist/src/tui/backends/embedded-backend.js +76 -7
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +13 -0
- package/dist/src/tui/backends/gateway-sse-backend.js +53 -0
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/chat-history.js +16 -3
- package/dist/src/tui/chat-history.js.map +1 -1
- package/dist/src/tui/clipboard-image.js +1 -1
- package/dist/src/tui/components/assistant-message.js +12 -2
- package/dist/src/tui/components/assistant-message.js.map +1 -1
- package/dist/src/tui/components/chat-log.d.ts +23 -3
- package/dist/src/tui/components/chat-log.js +68 -9
- package/dist/src/tui/components/chat-log.js.map +1 -1
- package/dist/src/tui/components/tool-execution.d.ts +8 -0
- package/dist/src/tui/components/tool-execution.js +87 -77
- package/dist/src/tui/components/tool-execution.js.map +1 -1
- package/dist/src/tui/components/tui-bottom-bar.js +9 -5
- package/dist/src/tui/components/tui-bottom-bar.js.map +1 -1
- package/dist/src/tui/components/visual-truncate.d.ts +1 -0
- package/dist/src/tui/components/visual-truncate.js +28 -1
- package/dist/src/tui/components/visual-truncate.js.map +1 -1
- package/dist/src/tui/tool-summary.d.ts +22 -0
- package/dist/src/tui/tool-summary.js +212 -0
- package/dist/src/tui/tool-summary.js.map +1 -0
- package/dist/src/tui/tui-backend.d.ts +16 -0
- package/dist/src/tui/tui-command-formatters.js +2 -2
- package/dist/src/tui/tui-commands.d.ts +9 -0
- package/dist/src/tui/tui-commands.js +95 -6
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-picker-overlay.d.ts +1 -0
- package/dist/src/tui/tui-picker-overlay.js +36 -1
- package/dist/src/tui/tui-picker-overlay.js.map +1 -1
- package/dist/src/tui/tui-picker-services.d.ts +13 -0
- package/dist/src/tui/tui-run-state.js +11 -0
- package/dist/src/tui/tui-run-state.js.map +1 -1
- package/dist/src/tui/tui-run-status-format.d.ts +3 -0
- package/dist/src/tui/tui-run-status-format.js +33 -0
- package/dist/src/tui/tui-run-status-format.js.map +1 -0
- package/dist/src/tui/tui-session-actions.d.ts +5 -0
- package/dist/src/tui/tui-session-actions.js +24 -0
- package/dist/src/tui/tui-session-actions.js.map +1 -1
- package/dist/src/tui/tui-timeline-picker.d.ts +19 -0
- package/dist/src/tui/tui-timeline-picker.js +81 -0
- package/dist/src/tui/tui-timeline-picker.js.map +1 -0
- package/dist/src/tui/tui-timeline.d.ts +15 -0
- package/dist/src/tui/tui-timeline.js +65 -0
- package/dist/src/tui/tui-timeline.js.map +1 -0
- package/dist/src/tui/tui-tool-diff.d.ts +15 -0
- package/dist/src/tui/tui-tool-diff.js +178 -7
- package/dist/src/tui/tui-tool-diff.js.map +1 -1
- package/dist/src/tui/tui-types.d.ts +1 -0
- package/dist/src/tui/tui-types.js +1 -0
- package/dist/src/tui/tui-types.js.map +1 -1
- package/dist/src/tui/tui.js +31 -25
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/utils/index.js +1 -1
- package/dist/src/utils/logger/index.js +1 -1
- package/dist/src/utils/logger/stats.d.ts +3 -3
- package/dist/src/utils/logger.js +1 -1
- package/dist/src/work-items/agent-context.d.ts +7 -0
- package/dist/src/work-items/agent-context.js +75 -0
- package/dist/src/work-items/agent-context.js.map +1 -0
- package/dist/src/work-items/index.d.ts +4 -0
- package/dist/src/work-items/index.js +4 -0
- package/dist/src/work-items/types.d.ts +112 -0
- package/dist/src/work-items/types.js +1 -0
- package/dist/src/work-items/work-item-service.d.ts +35 -0
- package/dist/src/work-items/work-item-service.js +277 -0
- package/dist/src/work-items/work-item-service.js.map +1 -0
- package/dist/src/work-items/work-item-store.d.ts +21 -0
- package/dist/src/work-items/work-item-store.js +302 -0
- package/dist/src/work-items/work-item-store.js.map +1 -0
- package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
- package/dist/src/workflows/service/workflow-run-service.js +4 -3
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-session-bridge.js +4 -1
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
- package/package.json +5 -5
- package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +0 -41
- package/dist/gateway/static/root/assets/agents-BjIxt67Z.js +0 -2
- package/dist/gateway/static/root/assets/app-management-settings-panel-CYCONLIL.js +0 -1
- package/dist/gateway/static/root/assets/appearance-settings-Clw3ryKg.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-QICTeGjX.js +0 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-CU0-4nQ-.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-Car-jtiz.js +0 -1
- package/dist/gateway/static/root/assets/browser-settings-page-CMeBJzlS.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-api-BmQTM9Il.js +0 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-DZEJEoCF.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-kkW-xFau.js +0 -1
- package/dist/gateway/static/root/assets/code-editor-dZTY2dRW.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-BvaQvO5F.js +0 -2
- package/dist/gateway/static/root/assets/dist-Mys7eFJ5.js +0 -1
- package/dist/gateway/static/root/assets/dist-wO9a2_ID.js +0 -1
- package/dist/gateway/static/root/assets/dreaming-settings-DnHO686d.js +0 -1
- package/dist/gateway/static/root/assets/extension-debug-page-BGLRuWVN.js +0 -1
- package/dist/gateway/static/root/assets/extension-page-D978ePp9.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-B6Ih4Swx.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-CMEA3r5u.js +0 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-B-KHKeXN.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-BxrSoWdj.js +0 -1
- package/dist/gateway/static/root/assets/goals-page-BTJzIl28.js +0 -2
- package/dist/gateway/static/root/assets/goals-settings-BJyEuLLm.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-wkOjYNQT.js +0 -1
- package/dist/gateway/static/root/assets/index-BLaXr6Ev.css +0 -1
- package/dist/gateway/static/root/assets/index-c_9TVr_C.js +0 -191
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-BT8T4DyC.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-CrxBJUgI.js +0 -2
- package/dist/gateway/static/root/assets/markdown-split-Dv66bO2b.js +0 -1
- package/dist/gateway/static/root/assets/messages-O6TAtdFC.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-DOOpz6y1.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-Br16pK9v.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-PSJAi0ZC.js +0 -2
- package/dist/gateway/static/root/assets/project-detail-page-CIGGgKuw.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-B2grhsBt.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CXMORxBD.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-Bi2wkBzU.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-B1L3G4IA.js +0 -1
- package/dist/gateway/static/root/assets/settings-form-section-BnqYMWHR.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-BfRSHJmO.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-layout-CdWZU1hd.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-CWtPM7RK.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-ngbsBgij.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BIe442Gv.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-BfchZRVa.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-C5Ov8Uk_.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-BYD9BtOq.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-BYF29ANm.js +0 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rem-patterns.js","names":[],"sources":["../../../../../src/agent/memory/dreaming/rem-patterns.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { createLogger } from '../../../utils/logger.js';\nimport { DREAMING_DIR_RELATIVE, DREAMS_MD_FILENAME, MS_PER_DAY } from './constants.js';\nimport type { DreamingRemConfig } from './config.js';\nimport {\n bumpEntryPhaseSignal,\n loadDreamingStore,\n saveDreamingStore,\n type DreamingStoreEntry,\n} from './short-term-store.js';\nimport { isoDay } from './utils.js';\nimport {\n DREAMING_LAST_RUN_FORMAT_VERSION,\n type DreamingRemLastRun,\n} from './last-run.js';\n\nconst log = createLogger('Dreaming:REM');\n\n// ── Pattern types ──────────────────────────────────────────────────────\n\ntype PatternCluster = {\n representative: DreamingStoreEntry;\n members: DreamingStoreEntry[];\n strength: number;\n /** Shared query hashes across members. */\n sharedQueries: string[];\n /** Distinct source files involved. */\n distinctPaths: string[];\n};\n\n// ── Config defaults ────────────────────────────────────────────────────\n\nfunction resolveConfig(overrides?: Partial<DreamingRemConfig>): DreamingRemConfig {\n return {\n enabled: overrides?.enabled === true,\n cron: typeof overrides?.cron === 'string' ? overrides.cron : '0 5 * * 0',\n lookbackDays: Math.max(1, Math.floor(Number(overrides?.lookbackDays) || 7)),\n limit: Math.max(0, Math.floor(Number(overrides?.limit) || 10)),\n minPatternStrength: Math.max(0, Math.min(1, Number(overrides?.minPatternStrength) || 0.75)),\n };\n}\n\n// ── Core REM pattern discovery ─────────────────────────────────────────\n\n/**\n * REM phase: cross-session pattern discovery.\n *\n * Scans the short-term store for entries that share query hashes or\n * appear across multiple indexed memory sources, then clusters them to identify\n * recurring themes/patterns. Bumps `remHits` on touched entries and\n * optionally writes a pattern summary to DREAMS.md.\n *\n * Runs weekly; expensive but insightful.\n */\nexport async function runRemPatterns(params: {\n workspaceDir: string;\n config?: Partial<DreamingRemConfig>;\n now?: Date;\n}): Promise<{\n ok: boolean;\n reason: string;\n patternsDiscovered: number;\n entriesAnalyzed: number;\n}> {\n const cfg = resolveConfig(params.config);\n const now = params.now ?? new Date();\n const startedAt = now.toISOString();\n const runId = `rem:${startedAt}:${process.pid}`;\n const startMs = Date.now();\n const nowMs = now.getTime();\n\n if (!cfg.enabled) {\n await writeLastRun(params.workspaceDir, {\n runId, startedAt, cfg, ok: true, reason: 'REM patterns disabled', startMs,\n rem: { patternsDiscovered: 0, entriesAnalyzed: 0 },\n });\n return { ok: true, reason: 'REM patterns disabled', patternsDiscovered: 0, entriesAnalyzed: 0 };\n }\n\n try {\n const { store } = await loadDreamingStore({ workspaceDir: params.workspaceDir });\n\n // Filter entries within the lookback window.\n const cutoffMs = nowMs - cfg.lookbackDays * MS_PER_DAY;\n const recentEntries = Object.values(store.entries ?? {}).filter(\n (entry): entry is DreamingStoreEntry => {\n if (!entry || typeof entry !== 'object') return false;\n if (!entry.lastRecalledAt) return false;\n const lastMs = Date.parse(entry.lastRecalledAt);\n return Number.isFinite(lastMs) && lastMs >= cutoffMs;\n },\n );\n\n if (recentEntries.length < 2) {\n await writeLastRun(params.workspaceDir, {\n runId, startedAt, cfg, ok: true, reason: 'not enough recent entries for pattern analysis', startMs,\n rem: { patternsDiscovered: 0, entriesAnalyzed: recentEntries.length },\n });\n return {\n ok: true,\n reason: 'not enough recent entries for pattern analysis',\n patternsDiscovered: 0,\n entriesAnalyzed: recentEntries.length,\n };\n }\n\n // Discover patterns by clustering entries that share query hashes.\n const clusters = discoverPatternClusters(recentEntries, cfg.minPatternStrength);\n const topClusters = clusters.slice(0, cfg.limit);\n\n // Bump remHits on all entries that belong to a discovered pattern.\n const touchedKeys = new Set<string>();\n for (const cluster of topClusters) {\n for (const member of cluster.members) {\n if (!touchedKeys.has(member.key)) {\n touchedKeys.add(member.key);\n const storeEntry = store.entries[member.key];\n if (storeEntry) {\n bumpEntryPhaseSignal(storeEntry, 'remHits');\n }\n }\n }\n }\n\n store.updatedAt = now.toISOString();\n await saveDreamingStore({ workspaceDir: params.workspaceDir, store });\n\n // Write pattern summary to DREAMS.md (append).\n if (topClusters.length > 0) {\n await appendPatternSummary(params.workspaceDir, topClusters, now);\n }\n\n log.info(\n {\n workspaceDir: params.workspaceDir,\n patterns: topClusters.length,\n entriesAnalyzed: recentEntries.length,\n touched: touchedKeys.size,\n },\n 'REM pattern discovery complete',\n );\n\n await writeLastRun(params.workspaceDir, {\n runId, startedAt, cfg, ok: true, reason: 'REM patterns complete', startMs,\n rem: { patternsDiscovered: topClusters.length, entriesAnalyzed: recentEntries.length },\n });\n\n return {\n ok: true,\n reason: 'REM patterns complete',\n patternsDiscovered: topClusters.length,\n entriesAnalyzed: recentEntries.length,\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n log.error({ err, errorMessage, workspaceDir: params.workspaceDir }, `REM pattern discovery failed: ${errorMessage}`);\n await writeLastRun(params.workspaceDir, {\n runId, startedAt, cfg, ok: false, reason: `REM error: ${errorMessage}`, startMs,\n rem: { patternsDiscovered: 0, entriesAnalyzed: 0 }, errorMessage,\n }).catch(() => undefined);\n return { ok: false, reason: errorMessage, patternsDiscovered: 0, entriesAnalyzed: 0 };\n }\n}\n\n// ── Pattern clustering ─────────────────────────────────────────────────\n\n/**\n * Build an inverted index of queryHash → entries, then form clusters\n * where multiple entries share overlapping query hashes. Each cluster's\n * \"strength\" is the ratio of shared queries to total unique queries.\n */\nfunction discoverPatternClusters(\n entries: DreamingStoreEntry[],\n minStrength: number,\n): PatternCluster[] {\n // Build inverted index: queryHash → entry keys.\n const hashToEntries = new Map<string, DreamingStoreEntry[]>();\n for (const entry of entries) {\n for (const queryHash of entry.queryHashes ?? []) {\n const group = hashToEntries.get(queryHash);\n if (group) {\n group.push(entry);\n } else {\n hashToEntries.set(queryHash, [entry]);\n }\n }\n }\n\n // Find query hashes that appear in 2+ distinct entries from different paths.\n const significantHashes: Array<{ hash: string; entries: DreamingStoreEntry[] }> = [];\n for (const [hash, group] of hashToEntries) {\n const uniquePaths = new Set(group.map((e) => e.path));\n if (group.length >= 2 && uniquePaths.size >= 2) {\n significantHashes.push({ hash, entries: group });\n }\n }\n\n if (significantHashes.length === 0) return [];\n\n // Merge overlapping groups into clusters using union-find.\n const keyToCluster = new Map<string, Set<string>>();\n const keyToEntry = new Map<string, DreamingStoreEntry>();\n\n for (const entry of entries) {\n keyToEntry.set(entry.key, entry);\n }\n\n for (const { entries: groupEntries } of significantHashes) {\n const keys = groupEntries.map((e) => e.key);\n // Find or create the cluster for the first key.\n let mergedCluster = keyToCluster.get(keys[0]!);\n if (!mergedCluster) {\n mergedCluster = new Set<string>();\n mergedCluster.add(keys[0]!);\n keyToCluster.set(keys[0]!, mergedCluster);\n }\n // Merge all other keys into this cluster.\n for (const key of keys.slice(1)) {\n const existingCluster = keyToCluster.get(key);\n if (existingCluster && existingCluster !== mergedCluster) {\n for (const existingKey of existingCluster) {\n mergedCluster.add(existingKey);\n keyToCluster.set(existingKey, mergedCluster);\n }\n } else {\n mergedCluster.add(key);\n keyToCluster.set(key, mergedCluster);\n }\n }\n }\n\n // Deduplicate cluster sets.\n const seenClusters = new Set<Set<string>>();\n const rawClusters: Set<string>[] = [];\n for (const cluster of keyToCluster.values()) {\n if (!seenClusters.has(cluster) && cluster.size >= 2) {\n seenClusters.add(cluster);\n rawClusters.push(cluster);\n }\n }\n\n // Score each cluster.\n const scoredClusters: PatternCluster[] = [];\n for (const clusterKeys of rawClusters) {\n const members: DreamingStoreEntry[] = [];\n for (const key of clusterKeys) {\n const entry = keyToEntry.get(key);\n if (entry) members.push(entry);\n }\n if (members.length < 2) continue;\n\n // Shared queries: hashes that appear in 2+ members.\n const hashCounts = new Map<string, number>();\n for (const member of members) {\n for (const hash of member.queryHashes ?? []) {\n hashCounts.set(hash, (hashCounts.get(hash) ?? 0) + 1);\n }\n }\n const sharedQueries = [...hashCounts.entries()]\n .filter(([, count]) => count >= 2)\n .map(([hash]) => hash);\n\n const allUniqueHashes = new Set<string>();\n for (const member of members) {\n for (const hash of member.queryHashes ?? []) allUniqueHashes.add(hash);\n }\n\n const strength = allUniqueHashes.size > 0 ? sharedQueries.length / allUniqueHashes.size : 0;\n if (strength < minStrength) continue;\n\n const distinctPaths = [...new Set(members.map((m) => m.path))];\n\n // Representative: the member with the highest totalSignalCount.\n const representative = members.reduce((best, current) =>\n (current.totalSignalCount ?? 0) > (best.totalSignalCount ?? 0) ? current : best,\n );\n\n scoredClusters.push({\n representative,\n members,\n strength,\n sharedQueries,\n distinctPaths,\n });\n }\n\n // Sort by strength descending, then by member count.\n scoredClusters.sort((a, b) => {\n if (b.strength !== a.strength) return b.strength - a.strength;\n return b.members.length - a.members.length;\n });\n\n return scoredClusters;\n}\n\n// ── DREAMS.md writer ───────────────────────────────────────────────────\n\nasync function appendPatternSummary(\n workspaceDir: string,\n clusters: PatternCluster[],\n now: Date,\n): Promise<void> {\n const dreamsPath = path.join(workspaceDir, DREAMS_MD_FILENAME);\n const existing = await fs.readFile(dreamsPath, 'utf-8').catch((err: unknown) => {\n if ((err as NodeJS.ErrnoException)?.code === 'ENOENT') return '';\n throw err;\n });\n\n const day = isoDay(now);\n const lines: string[] = [];\n\n if (existing.trim().length === 0) {\n lines.push('# Dream Diary', '');\n }\n\n lines.push(`## REM Pattern Discovery — ${day}`, '');\n lines.push(`*${now.toISOString()}*`, '');\n\n for (let i = 0; i < clusters.length; i++) {\n const cluster = clusters[i]!;\n lines.push(\n `### Pattern ${i + 1}: ${cluster.distinctPaths.length} files, strength=${cluster.strength.toFixed(2)}`,\n );\n lines.push('');\n lines.push(`**Files involved:** ${cluster.distinctPaths.join(', ')}`);\n lines.push(`**Shared query themes:** ${cluster.sharedQueries.length} overlapping queries`);\n lines.push(`**Members:** ${cluster.members.length} snippets`);\n lines.push('');\n // Include the representative snippet.\n const rep = cluster.representative;\n lines.push(`> ${rep.snippet?.slice(0, 200) ?? '(no snippet)'}`);\n lines.push(`> — ${rep.path}:${rep.startLine}-${rep.endLine}`);\n lines.push('');\n }\n\n lines.push('---', '');\n\n const separator = existing.trim().length > 0 && !existing.endsWith('\\n') ? '\\n' : '';\n const next = `${existing}${separator}${lines.join('\\n')}`;\n await fs.writeFile(dreamsPath, next, 'utf-8');\n}\n\n// ── Last-run writer ────────────────────────────────────────────────────\n\nasync function writeLastRun(\n workspaceDir: string,\n params: {\n runId: string;\n startedAt: string;\n cfg: DreamingRemConfig;\n ok: boolean;\n reason: string;\n startMs: number;\n rem: DreamingRemLastRun['rem'];\n errorMessage?: string;\n },\n): Promise<void> {\n const finishedAt = new Date().toISOString();\n const durationMs = Math.max(0, Date.now() - params.startMs);\n\n const lastRun: DreamingRemLastRun = {\n version: DREAMING_LAST_RUN_FORMAT_VERSION,\n phase: 'rem',\n runId: params.runId,\n startedAt: params.startedAt,\n finishedAt,\n durationMs,\n ok: params.ok,\n reason: params.reason,\n config: params.cfg,\n rem: params.rem,\n ...(params.errorMessage ? { errorMessage: params.errorMessage } : {}),\n };\n\n const lastRunPath = path.join(workspaceDir, DREAMING_DIR_RELATIVE, 'last-run-rem.json');\n await fs.mkdir(path.dirname(lastRunPath), { recursive: true });\n const tmp = `${lastRunPath}.${process.pid}.${Date.now()}.tmp`;\n await fs.writeFile(tmp, `${JSON.stringify(lastRun, null, 2)}\\n`, 'utf-8');\n await fs.rename(tmp, lastRunPath);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rem-patterns.js","names":[],"sources":["../../../../../src/agent/memory/dreaming/rem-patterns.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { createLogger } from '../../../utils/logger.js';\nimport { DREAMING_DIR_RELATIVE, DREAMS_MD_FILENAME, MS_PER_DAY } from './constants.js';\nimport type { DreamingRemConfig } from './config.js';\nimport {\n bumpEntryPhaseSignal,\n loadDreamingStore,\n saveDreamingStore,\n type DreamingStoreEntry,\n} from './short-term-store.js';\nimport { isoDay } from './utils.js';\nimport {\n DREAMING_LAST_RUN_FORMAT_VERSION,\n type DreamingRemLastRun,\n} from './last-run.js';\n\nconst log = createLogger('Dreaming:REM');\n\n// ── Pattern types ──────────────────────────────────────────────────────\n\ntype PatternCluster = {\n representative: DreamingStoreEntry;\n members: DreamingStoreEntry[];\n strength: number;\n /** Shared query hashes across members. */\n sharedQueries: string[];\n /** Distinct source files involved. */\n distinctPaths: string[];\n};\n\n// ── Config defaults ────────────────────────────────────────────────────\n\nfunction resolveConfig(overrides?: Partial<DreamingRemConfig>): DreamingRemConfig {\n return {\n enabled: overrides?.enabled === true,\n cron: typeof overrides?.cron === 'string' ? overrides.cron : '0 5 * * 0',\n lookbackDays: Math.max(1, Math.floor(Number(overrides?.lookbackDays) || 7)),\n limit: Math.max(0, Math.floor(Number(overrides?.limit) || 10)),\n minPatternStrength: Math.max(0, Math.min(1, Number(overrides?.minPatternStrength) || 0.75)),\n };\n}\n\n// ── Core REM pattern discovery ─────────────────────────────────────────\n\n/**\n * REM phase: cross-session pattern discovery.\n *\n * Scans the short-term store for entries that share query hashes or\n * appear across multiple indexed memory sources, then clusters them to identify\n * recurring themes/patterns. Bumps `remHits` on touched entries and\n * optionally writes a pattern summary to DREAMS.md.\n *\n * Runs weekly; expensive but insightful.\n */\nexport async function runRemPatterns(params: {\n dreamingRoot: string;\n config?: Partial<DreamingRemConfig>;\n now?: Date;\n}): Promise<{\n ok: boolean;\n reason: string;\n patternsDiscovered: number;\n entriesAnalyzed: number;\n}> {\n const cfg = resolveConfig(params.config);\n const now = params.now ?? new Date();\n const startedAt = now.toISOString();\n const runId = `rem:${startedAt}:${process.pid}`;\n const startMs = Date.now();\n const nowMs = now.getTime();\n\n if (!cfg.enabled) {\n await writeLastRun(params.dreamingRoot, {\n runId, startedAt, cfg, ok: true, reason: 'REM patterns disabled', startMs,\n rem: { patternsDiscovered: 0, entriesAnalyzed: 0 },\n });\n return { ok: true, reason: 'REM patterns disabled', patternsDiscovered: 0, entriesAnalyzed: 0 };\n }\n\n try {\n const { store } = await loadDreamingStore({ dreamingRoot: params.dreamingRoot });\n\n // Filter entries within the lookback window.\n const cutoffMs = nowMs - cfg.lookbackDays * MS_PER_DAY;\n const recentEntries = Object.values(store.entries ?? {}).filter(\n (entry): entry is DreamingStoreEntry => {\n if (!entry || typeof entry !== 'object') return false;\n if (!entry.lastRecalledAt) return false;\n const lastMs = Date.parse(entry.lastRecalledAt);\n return Number.isFinite(lastMs) && lastMs >= cutoffMs;\n },\n );\n\n if (recentEntries.length < 2) {\n await writeLastRun(params.dreamingRoot, {\n runId, startedAt, cfg, ok: true, reason: 'not enough recent entries for pattern analysis', startMs,\n rem: { patternsDiscovered: 0, entriesAnalyzed: recentEntries.length },\n });\n return {\n ok: true,\n reason: 'not enough recent entries for pattern analysis',\n patternsDiscovered: 0,\n entriesAnalyzed: recentEntries.length,\n };\n }\n\n // Discover patterns by clustering entries that share query hashes.\n const clusters = discoverPatternClusters(recentEntries, cfg.minPatternStrength);\n const topClusters = clusters.slice(0, cfg.limit);\n\n // Bump remHits on all entries that belong to a discovered pattern.\n const touchedKeys = new Set<string>();\n for (const cluster of topClusters) {\n for (const member of cluster.members) {\n if (!touchedKeys.has(member.key)) {\n touchedKeys.add(member.key);\n const storeEntry = store.entries[member.key];\n if (storeEntry) {\n bumpEntryPhaseSignal(storeEntry, 'remHits');\n }\n }\n }\n }\n\n store.updatedAt = now.toISOString();\n await saveDreamingStore({ dreamingRoot: params.dreamingRoot, store });\n\n // Write pattern summary to DREAMS.md (append).\n if (topClusters.length > 0) {\n await appendPatternSummary(params.dreamingRoot, topClusters, now);\n }\n\n log.info(\n {\n dreamingRoot: params.dreamingRoot,\n patterns: topClusters.length,\n entriesAnalyzed: recentEntries.length,\n touched: touchedKeys.size,\n },\n 'REM pattern discovery complete',\n );\n\n await writeLastRun(params.dreamingRoot, {\n runId, startedAt, cfg, ok: true, reason: 'REM patterns complete', startMs,\n rem: { patternsDiscovered: topClusters.length, entriesAnalyzed: recentEntries.length },\n });\n\n return {\n ok: true,\n reason: 'REM patterns complete',\n patternsDiscovered: topClusters.length,\n entriesAnalyzed: recentEntries.length,\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n log.error({ err, errorMessage, dreamingRoot: params.dreamingRoot }, `REM pattern discovery failed: ${errorMessage}`);\n await writeLastRun(params.dreamingRoot, {\n runId, startedAt, cfg, ok: false, reason: `REM error: ${errorMessage}`, startMs,\n rem: { patternsDiscovered: 0, entriesAnalyzed: 0 }, errorMessage,\n }).catch(() => undefined);\n return { ok: false, reason: errorMessage, patternsDiscovered: 0, entriesAnalyzed: 0 };\n }\n}\n\n// ── Pattern clustering ─────────────────────────────────────────────────\n\n/**\n * Build an inverted index of queryHash → entries, then form clusters\n * where multiple entries share overlapping query hashes. Each cluster's\n * \"strength\" is the ratio of shared queries to total unique queries.\n */\nfunction discoverPatternClusters(\n entries: DreamingStoreEntry[],\n minStrength: number,\n): PatternCluster[] {\n // Build inverted index: queryHash → entry keys.\n const hashToEntries = new Map<string, DreamingStoreEntry[]>();\n for (const entry of entries) {\n for (const queryHash of entry.queryHashes ?? []) {\n const group = hashToEntries.get(queryHash);\n if (group) {\n group.push(entry);\n } else {\n hashToEntries.set(queryHash, [entry]);\n }\n }\n }\n\n // Find query hashes that appear in 2+ distinct entries from different paths.\n const significantHashes: Array<{ hash: string; entries: DreamingStoreEntry[] }> = [];\n for (const [hash, group] of hashToEntries) {\n const uniquePaths = new Set(group.map((e) => e.path));\n if (group.length >= 2 && uniquePaths.size >= 2) {\n significantHashes.push({ hash, entries: group });\n }\n }\n\n if (significantHashes.length === 0) return [];\n\n // Merge overlapping groups into clusters using union-find.\n const keyToCluster = new Map<string, Set<string>>();\n const keyToEntry = new Map<string, DreamingStoreEntry>();\n\n for (const entry of entries) {\n keyToEntry.set(entry.key, entry);\n }\n\n for (const { entries: groupEntries } of significantHashes) {\n const keys = groupEntries.map((e) => e.key);\n // Find or create the cluster for the first key.\n let mergedCluster = keyToCluster.get(keys[0]!);\n if (!mergedCluster) {\n mergedCluster = new Set<string>();\n mergedCluster.add(keys[0]!);\n keyToCluster.set(keys[0]!, mergedCluster);\n }\n // Merge all other keys into this cluster.\n for (const key of keys.slice(1)) {\n const existingCluster = keyToCluster.get(key);\n if (existingCluster && existingCluster !== mergedCluster) {\n for (const existingKey of existingCluster) {\n mergedCluster.add(existingKey);\n keyToCluster.set(existingKey, mergedCluster);\n }\n } else {\n mergedCluster.add(key);\n keyToCluster.set(key, mergedCluster);\n }\n }\n }\n\n // Deduplicate cluster sets.\n const seenClusters = new Set<Set<string>>();\n const rawClusters: Set<string>[] = [];\n for (const cluster of keyToCluster.values()) {\n if (!seenClusters.has(cluster) && cluster.size >= 2) {\n seenClusters.add(cluster);\n rawClusters.push(cluster);\n }\n }\n\n // Score each cluster.\n const scoredClusters: PatternCluster[] = [];\n for (const clusterKeys of rawClusters) {\n const members: DreamingStoreEntry[] = [];\n for (const key of clusterKeys) {\n const entry = keyToEntry.get(key);\n if (entry) members.push(entry);\n }\n if (members.length < 2) continue;\n\n // Shared queries: hashes that appear in 2+ members.\n const hashCounts = new Map<string, number>();\n for (const member of members) {\n for (const hash of member.queryHashes ?? []) {\n hashCounts.set(hash, (hashCounts.get(hash) ?? 0) + 1);\n }\n }\n const sharedQueries = [...hashCounts.entries()]\n .filter(([, count]) => count >= 2)\n .map(([hash]) => hash);\n\n const allUniqueHashes = new Set<string>();\n for (const member of members) {\n for (const hash of member.queryHashes ?? []) allUniqueHashes.add(hash);\n }\n\n const strength = allUniqueHashes.size > 0 ? sharedQueries.length / allUniqueHashes.size : 0;\n if (strength < minStrength) continue;\n\n const distinctPaths = [...new Set(members.map((m) => m.path))];\n\n // Representative: the member with the highest totalSignalCount.\n const representative = members.reduce((best, current) =>\n (current.totalSignalCount ?? 0) > (best.totalSignalCount ?? 0) ? current : best,\n );\n\n scoredClusters.push({\n representative,\n members,\n strength,\n sharedQueries,\n distinctPaths,\n });\n }\n\n // Sort by strength descending, then by member count.\n scoredClusters.sort((a, b) => {\n if (b.strength !== a.strength) return b.strength - a.strength;\n return b.members.length - a.members.length;\n });\n\n return scoredClusters;\n}\n\n// ── DREAMS.md writer ───────────────────────────────────────────────────\n\nasync function appendPatternSummary(\n dreamingRoot: string,\n clusters: PatternCluster[],\n now: Date,\n): Promise<void> {\n const dreamsPath = path.join(dreamingRoot, DREAMS_MD_FILENAME);\n const existing = await fs.readFile(dreamsPath, 'utf-8').catch((err: unknown) => {\n if ((err as NodeJS.ErrnoException)?.code === 'ENOENT') return '';\n throw err;\n });\n\n const day = isoDay(now);\n const lines: string[] = [];\n\n if (existing.trim().length === 0) {\n lines.push('# Dream Diary', '');\n }\n\n lines.push(`## REM Pattern Discovery — ${day}`, '');\n lines.push(`*${now.toISOString()}*`, '');\n\n for (let i = 0; i < clusters.length; i++) {\n const cluster = clusters[i]!;\n lines.push(\n `### Pattern ${i + 1}: ${cluster.distinctPaths.length} files, strength=${cluster.strength.toFixed(2)}`,\n );\n lines.push('');\n lines.push(`**Files involved:** ${cluster.distinctPaths.join(', ')}`);\n lines.push(`**Shared query themes:** ${cluster.sharedQueries.length} overlapping queries`);\n lines.push(`**Members:** ${cluster.members.length} snippets`);\n lines.push('');\n // Include the representative snippet.\n const rep = cluster.representative;\n lines.push(`> ${rep.snippet?.slice(0, 200) ?? '(no snippet)'}`);\n lines.push(`> — ${rep.path}:${rep.startLine}-${rep.endLine}`);\n lines.push('');\n }\n\n lines.push('---', '');\n\n const separator = existing.trim().length > 0 && !existing.endsWith('\\n') ? '\\n' : '';\n const next = `${existing}${separator}${lines.join('\\n')}`;\n await fs.writeFile(dreamsPath, next, 'utf-8');\n}\n\n// ── Last-run writer ────────────────────────────────────────────────────\n\nasync function writeLastRun(\n dreamingRoot: string,\n params: {\n runId: string;\n startedAt: string;\n cfg: DreamingRemConfig;\n ok: boolean;\n reason: string;\n startMs: number;\n rem: DreamingRemLastRun['rem'];\n errorMessage?: string;\n },\n): Promise<void> {\n const finishedAt = new Date().toISOString();\n const durationMs = Math.max(0, Date.now() - params.startMs);\n\n const lastRun: DreamingRemLastRun = {\n version: DREAMING_LAST_RUN_FORMAT_VERSION,\n phase: 'rem',\n runId: params.runId,\n startedAt: params.startedAt,\n finishedAt,\n durationMs,\n ok: params.ok,\n reason: params.reason,\n config: params.cfg,\n rem: params.rem,\n ...(params.errorMessage ? { errorMessage: params.errorMessage } : {}),\n };\n\n const lastRunPath = path.join(dreamingRoot, DREAMING_DIR_RELATIVE, 'last-run-rem.json');\n await fs.mkdir(path.dirname(lastRunPath), { recursive: true });\n const tmp = `${lastRunPath}.${process.pid}.${Date.now()}.tmp`;\n await fs.writeFile(tmp, `${JSON.stringify(lastRun, null, 2)}\\n`, 'utf-8');\n await fs.rename(tmp, lastRunPath);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Config } from '../../../config/schema.js';
|
|
2
|
+
import { resolveEffectiveAgentManifestForAgent } from '../../../config/agent-profile.js';
|
|
3
|
+
import type { DreamingResolvedConfig } from './config.js';
|
|
4
|
+
export type DreamingAgentScope = {
|
|
5
|
+
agentId: string;
|
|
6
|
+
workspaceDir: string;
|
|
7
|
+
memoriesDir: string;
|
|
8
|
+
memoryPath: string;
|
|
9
|
+
dreamsPath: string;
|
|
10
|
+
config: DreamingResolvedConfig;
|
|
11
|
+
memory: ReturnType<typeof resolveEffectiveAgentManifestForAgent>['memory'];
|
|
12
|
+
};
|
|
13
|
+
export declare function resolveDreamingRootForAgent(config: Config, agentId: string): string;
|
|
14
|
+
export declare function resolveDreamingAgentScope(config: Config, requestedAgentId?: string | null): DreamingAgentScope;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { init_agent_scope, normalizeAgentId, resolveAgentHomeDir, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../agent-scope.js";
|
|
2
|
+
import { resolveEffectiveAgentManifestForAgent } from "../../../config/agent-profile.js";
|
|
3
|
+
import { resolveDreamingConfig } from "./config.js";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
//#region src/agent/memory/dreaming/scope.ts
|
|
6
|
+
init_agent_scope();
|
|
7
|
+
function resolveDreamingRootForAgent(config, agentId) {
|
|
8
|
+
return path.join(resolveAgentHomeDir(config, agentId), "memories");
|
|
9
|
+
}
|
|
10
|
+
function resolveDreamingAgentScope(config, requestedAgentId) {
|
|
11
|
+
const agentId = normalizeAgentId(requestedAgentId || resolveDefaultAgentId(config));
|
|
12
|
+
const manifest = resolveEffectiveAgentManifestForAgent(config, agentId);
|
|
13
|
+
const memoriesDir = resolveDreamingRootForAgent(config, agentId);
|
|
14
|
+
return {
|
|
15
|
+
agentId,
|
|
16
|
+
workspaceDir: resolveAgentWorkspaceDir(config, agentId),
|
|
17
|
+
memoriesDir,
|
|
18
|
+
memoryPath: path.join(memoriesDir, "MEMORY.md"),
|
|
19
|
+
dreamsPath: path.join(memoriesDir, "DREAMS.md"),
|
|
20
|
+
config: resolveDreamingConfig(config, agentId),
|
|
21
|
+
memory: manifest.memory
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { resolveDreamingAgentScope, resolveDreamingRootForAgent };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.js","names":[],"sources":["../../../../../src/agent/memory/dreaming/scope.ts"],"sourcesContent":["import path from 'node:path';\n\nimport type { Config } from '../../../config/schema.js';\nimport {\n normalizeAgentId,\n resolveAgentHomeDir,\n resolveAgentWorkspaceDir,\n resolveDefaultAgentId,\n} from '../../agent-scope.js';\nimport { resolveEffectiveAgentManifestForAgent } from '../../../config/agent-profile.js';\nimport type { DreamingResolvedConfig } from './config.js';\nimport { resolveDreamingConfig } from './config.js';\n\nexport type DreamingAgentScope = {\n agentId: string;\n workspaceDir: string;\n memoriesDir: string;\n memoryPath: string;\n dreamsPath: string;\n config: DreamingResolvedConfig;\n memory: ReturnType<typeof resolveEffectiveAgentManifestForAgent>['memory'];\n};\n\nexport function resolveDreamingRootForAgent(config: Config, agentId: string): string {\n return path.join(resolveAgentHomeDir(config, agentId), 'memories');\n}\n\nexport function resolveDreamingAgentScope(config: Config, requestedAgentId?: string | null): DreamingAgentScope {\n const agentId = normalizeAgentId(requestedAgentId || resolveDefaultAgentId(config));\n const manifest = resolveEffectiveAgentManifestForAgent(config, agentId);\n const memoriesDir = resolveDreamingRootForAgent(config, agentId);\n return {\n agentId,\n workspaceDir: resolveAgentWorkspaceDir(config, agentId),\n memoriesDir,\n memoryPath: path.join(memoriesDir, 'MEMORY.md'),\n dreamsPath: path.join(memoriesDir, 'DREAMS.md'),\n config: resolveDreamingConfig(config, agentId),\n memory: manifest.memory,\n };\n}\n"],"mappings":";;;;;kBAQ8B;AAe9B,SAAgB,4BAA4B,QAAgB,SAAyB;AACnF,QAAO,KAAK,KAAK,oBAAoB,QAAQ,QAAQ,EAAE,WAAW;;AAGpE,SAAgB,0BAA0B,QAAgB,kBAAsD;CAC9G,MAAM,UAAU,iBAAiB,oBAAoB,sBAAsB,OAAO,CAAC;CACnF,MAAM,WAAW,sCAAsC,QAAQ,QAAQ;CACvE,MAAM,cAAc,4BAA4B,QAAQ,QAAQ;AAChE,QAAO;EACL;EACA,cAAc,yBAAyB,QAAQ,QAAQ;EACvD;EACA,YAAY,KAAK,KAAK,aAAa,YAAY;EAC/C,YAAY,KAAK,KAAK,aAAa,YAAY;EAC/C,QAAQ,sBAAsB,QAAQ,QAAQ;EAC9C,QAAQ,SAAS;EAClB"}
|
|
@@ -34,7 +34,7 @@ export type DreamingStore = {
|
|
|
34
34
|
};
|
|
35
35
|
type MemoryMatch = Awaited<ReturnType<typeof import('../../prompt/memory/index.js').memorySearch>>[number];
|
|
36
36
|
export declare function recordDreamingRecalls(params: {
|
|
37
|
-
|
|
37
|
+
dreamingRoot: string;
|
|
38
38
|
query: string;
|
|
39
39
|
matches: MemoryMatch[];
|
|
40
40
|
options?: MemorySearchOptions;
|
|
@@ -44,15 +44,15 @@ export declare function recordDreamingRecalls(params: {
|
|
|
44
44
|
skipped: number;
|
|
45
45
|
storePath: string;
|
|
46
46
|
}>;
|
|
47
|
-
export declare function withDreamingPromotionLock<T>(
|
|
47
|
+
export declare function withDreamingPromotionLock<T>(dreamingRoot: string, task: () => Promise<T>): Promise<T>;
|
|
48
48
|
export declare function loadDreamingStore(params: {
|
|
49
|
-
|
|
49
|
+
dreamingRoot: string;
|
|
50
50
|
}): Promise<{
|
|
51
51
|
store: DreamingStore;
|
|
52
52
|
storePath: string;
|
|
53
53
|
}>;
|
|
54
54
|
export declare function saveDreamingStore(params: {
|
|
55
|
-
|
|
55
|
+
dreamingRoot: string;
|
|
56
56
|
store: DreamingStore;
|
|
57
57
|
}): Promise<void>;
|
|
58
58
|
type PhaseSignalField = 'sourceCount' | 'groundedCount' | 'lightHits' | 'remHits';
|
|
@@ -31,13 +31,13 @@ function emptyStore(nowIso) {
|
|
|
31
31
|
entries: {}
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
-
async function ensureDreamDir(
|
|
35
|
-
const dir = path.join(
|
|
34
|
+
async function ensureDreamDir(dreamingRoot) {
|
|
35
|
+
const dir = path.join(dreamingRoot, path.dirname(SHORT_TERM_RECALL_STORE_RELATIVE));
|
|
36
36
|
await fs.mkdir(dir, { recursive: true });
|
|
37
37
|
return dir;
|
|
38
38
|
}
|
|
39
|
-
async function readStore(
|
|
40
|
-
const storePath = path.join(
|
|
39
|
+
async function readStore(dreamingRoot, nowIso) {
|
|
40
|
+
const storePath = path.join(dreamingRoot, SHORT_TERM_RECALL_STORE_RELATIVE);
|
|
41
41
|
try {
|
|
42
42
|
const raw = await fs.readFile(storePath, "utf-8");
|
|
43
43
|
const parsed = JSON.parse(raw);
|
|
@@ -53,22 +53,22 @@ async function readStore(workspaceDir, nowIso) {
|
|
|
53
53
|
if (err?.code === "ENOENT") return emptyStore(nowIso);
|
|
54
54
|
log.warn({
|
|
55
55
|
err,
|
|
56
|
-
|
|
56
|
+
dreamingRoot
|
|
57
57
|
}, "Failed to read dreaming store; resetting");
|
|
58
58
|
return emptyStore(nowIso);
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
async function writeStore(
|
|
62
|
-
await ensureDreamDir(
|
|
63
|
-
const storePath = path.join(
|
|
61
|
+
async function writeStore(dreamingRoot, store) {
|
|
62
|
+
await ensureDreamDir(dreamingRoot);
|
|
63
|
+
const storePath = path.join(dreamingRoot, SHORT_TERM_RECALL_STORE_RELATIVE);
|
|
64
64
|
const tmp = `${storePath}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`;
|
|
65
65
|
await fs.writeFile(tmp, `${JSON.stringify(store, null, 2)}\n`, "utf-8");
|
|
66
66
|
await fs.rename(tmp, storePath);
|
|
67
67
|
}
|
|
68
68
|
async function recordDreamingRecalls(params) {
|
|
69
|
-
const
|
|
69
|
+
const dreamingRoot = params.dreamingRoot.trim();
|
|
70
70
|
const query = params.query.trim();
|
|
71
|
-
if (!
|
|
71
|
+
if (!dreamingRoot || !query) return {
|
|
72
72
|
recorded: 0,
|
|
73
73
|
skipped: params.matches.length,
|
|
74
74
|
storePath: SHORT_TERM_RECALL_STORE_RELATIVE
|
|
@@ -77,7 +77,7 @@ async function recordDreamingRecalls(params) {
|
|
|
77
77
|
const nowIso = now.toISOString();
|
|
78
78
|
const dayBucket = isoDay(now);
|
|
79
79
|
const qHash = hashQuery(query);
|
|
80
|
-
const store = await readStore(
|
|
80
|
+
const store = await readStore(dreamingRoot, nowIso);
|
|
81
81
|
let recorded = 0;
|
|
82
82
|
let skipped = 0;
|
|
83
83
|
for (const match of params.matches) {
|
|
@@ -142,7 +142,7 @@ async function recordDreamingRecalls(params) {
|
|
|
142
142
|
}
|
|
143
143
|
if (recorded > 0) {
|
|
144
144
|
store.updatedAt = nowIso;
|
|
145
|
-
await writeStore(
|
|
145
|
+
await writeStore(dreamingRoot, store);
|
|
146
146
|
}
|
|
147
147
|
return {
|
|
148
148
|
recorded,
|
|
@@ -150,9 +150,9 @@ async function recordDreamingRecalls(params) {
|
|
|
150
150
|
storePath: SHORT_TERM_RECALL_STORE_RELATIVE
|
|
151
151
|
};
|
|
152
152
|
}
|
|
153
|
-
async function withDreamingPromotionLock(
|
|
154
|
-
const lockPath = path.join(
|
|
155
|
-
await ensureDreamDir(
|
|
153
|
+
async function withDreamingPromotionLock(dreamingRoot, task) {
|
|
154
|
+
const lockPath = path.join(dreamingRoot, SHORT_TERM_PROMOTION_LOCK_RELATIVE);
|
|
155
|
+
await ensureDreamDir(dreamingRoot);
|
|
156
156
|
const startedAt = Date.now();
|
|
157
157
|
const timeoutMs = 1e4;
|
|
158
158
|
const retryDelayMs = 50;
|
|
@@ -174,12 +174,12 @@ async function withDreamingPromotionLock(workspaceDir, task) {
|
|
|
174
174
|
async function loadDreamingStore(params) {
|
|
175
175
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
176
176
|
return {
|
|
177
|
-
store: await readStore(params.
|
|
177
|
+
store: await readStore(params.dreamingRoot, nowIso),
|
|
178
178
|
storePath: SHORT_TERM_RECALL_STORE_RELATIVE
|
|
179
179
|
};
|
|
180
180
|
}
|
|
181
181
|
async function saveDreamingStore(params) {
|
|
182
|
-
await writeStore(params.
|
|
182
|
+
await writeStore(params.dreamingRoot, params.store);
|
|
183
183
|
}
|
|
184
184
|
/**
|
|
185
185
|
* Increment a phase-specific signal counter on an existing store entry.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"short-term-store.js","names":[],"sources":["../../../../../src/agent/memory/dreaming/short-term-store.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { createHash, randomUUID } from 'node:crypto';\n\nimport type { MemorySearchOptions } from '../../prompt/memory/index.js';\nimport { createLogger } from '../../../utils/logger.js';\nimport {\n SHORT_TERM_PROMOTION_LOCK_RELATIVE,\n SHORT_TERM_RECALL_STORE_RELATIVE,\n} from './constants.js';\nimport { buildEntryKey, clamp01, isoDay, normalizeMemoryPath } from './utils.js';\n\nconst log = createLogger('Dreaming:Store');\n\nexport type DreamingStoreEntry = {\n key: string;\n path: string;\n startLine: number;\n endLine: number;\n snippet: string;\n\n // ── Signal dimensions ────────────────────────────────────────────────\n /** Number of times this snippet was returned by a memory recall query. */\n recallCount: number;\n /** Number of times recorded from source-side sweep phases. */\n sourceCount: number;\n /** Number of times replayed from grounded context (agent-initiated). */\n groundedCount: number;\n /** Number of times the light phase touched this entry. */\n lightHits: number;\n /** Number of times the REM phase touched this entry. */\n remHits: number;\n /** Cross-phase hit count (light + deep + rem combined touches). */\n phaseHitCount: number;\n /** Weighted aggregate of all signal dimensions. */\n totalSignalCount: number;\n\n // ── Score tracking ───────────────────────────────────────────────────\n totalScore: number;\n maxScore: number;\n queryHashes: string[];\n recallDays: string[];\n\n // ── Timestamps ───────────────────────────────────────────────────────\n firstRecalledAt: string;\n lastRecalledAt: string;\n promotedAt?: string;\n};\n\nexport type DreamingStore = {\n version: 1;\n updatedAt: string;\n entries: Record<string, DreamingStoreEntry>;\n};\n\ntype MemoryMatch = Awaited<ReturnType<typeof import('../../prompt/memory/index.js').memorySearch>>[number];\n\nfunction isRecordableMemoryPath(rel: string): boolean {\n const p = normalizeMemoryPath(rel);\n return p.length > 0 && !p.startsWith('../') && !path.isAbsolute(p);\n}\n\nfunction hashQuery(query: string): string {\n return createHash('sha1').update(query.trim().toLowerCase()).digest('hex').slice(0, 12);\n}\n\nfunction mergeRecentDistinct(existing: string[], nextValue: string, limit: number): string[] {\n const seen = new Set<string>();\n const normalized = existing\n .filter((v): v is string => typeof v === 'string')\n .map((v) => v.trim())\n .filter((v) => v.length > 0 && !seen.has(v) && (seen.add(v), true));\n if (nextValue && !normalized.includes(nextValue)) {\n normalized.push(nextValue);\n }\n return normalized.length <= limit ? normalized : normalized.slice(-limit);\n}\n\nfunction mergeQueryHashes(existing: string[], nextHash: string): string[] {\n const out = mergeRecentDistinct(existing, nextHash, 32);\n return out;\n}\n\nfunction emptyStore(nowIso: string): DreamingStore {\n return { version: 1, updatedAt: nowIso, entries: {} };\n}\n\nasync function ensureDreamDir(workspaceDir: string): Promise<string> {\n const dir = path.join(workspaceDir, path.dirname(SHORT_TERM_RECALL_STORE_RELATIVE));\n await fs.mkdir(dir, { recursive: true });\n return dir;\n}\n\nasync function readStore(workspaceDir: string, nowIso: string): Promise<DreamingStore> {\n const storePath = path.join(workspaceDir, SHORT_TERM_RECALL_STORE_RELATIVE);\n try {\n const raw = await fs.readFile(storePath, 'utf-8');\n const parsed = JSON.parse(raw) as unknown;\n if (!parsed || typeof parsed !== 'object') return emptyStore(nowIso);\n const rec = parsed as Partial<DreamingStore>;\n if (rec.version !== 1 || !rec.entries || typeof rec.entries !== 'object') {\n return emptyStore(nowIso);\n }\n return {\n version: 1,\n updatedAt: typeof rec.updatedAt === 'string' ? rec.updatedAt : nowIso,\n entries: rec.entries as Record<string, DreamingStoreEntry>,\n };\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | undefined)?.code;\n if (code === 'ENOENT') return emptyStore(nowIso);\n log.warn({ err, workspaceDir }, 'Failed to read dreaming store; resetting');\n return emptyStore(nowIso);\n }\n}\n\nasync function writeStore(workspaceDir: string, store: DreamingStore): Promise<void> {\n await ensureDreamDir(workspaceDir);\n const storePath = path.join(workspaceDir, SHORT_TERM_RECALL_STORE_RELATIVE);\n const tmp = `${storePath}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`;\n await fs.writeFile(tmp, `${JSON.stringify(store, null, 2)}\\n`, 'utf-8');\n await fs.rename(tmp, storePath);\n}\n\nexport async function recordDreamingRecalls(params: {\n workspaceDir: string;\n query: string;\n matches: MemoryMatch[];\n options?: MemorySearchOptions;\n now?: Date;\n}): Promise<{ recorded: number; skipped: number; storePath: string }> {\n const workspaceDir = params.workspaceDir.trim();\n const query = params.query.trim();\n if (!workspaceDir || !query) {\n return { recorded: 0, skipped: params.matches.length, storePath: SHORT_TERM_RECALL_STORE_RELATIVE };\n }\n const now = params.now ?? new Date();\n const nowIso = now.toISOString();\n const dayBucket = isoDay(now);\n const qHash = hashQuery(query);\n\n const store = await readStore(workspaceDir, nowIso);\n\n let recorded = 0;\n let skipped = 0;\n for (const match of params.matches) {\n const file = typeof match?.file === \"string\" ? match.file : \"\";\n if (!file || !isRecordableMemoryPath(file)) {\n skipped += 1;\n continue;\n }\n const lines = typeof match?.lines === \"string\" ? match.lines.trim() : \"\";\n const lineNumbers = Array.isArray(match?.lineNumbers) ? match.lineNumbers : [];\n const startLine = Math.max(1, Math.min(...lineNumbers.filter((n) => Number.isFinite(n) && n > 0)));\n const endLine = Math.max(startLine, Math.max(...lineNumbers.filter((n) => Number.isFinite(n) && n > 0)));\n if (!Number.isFinite(startLine) || !Number.isFinite(endLine)) {\n skipped += 1;\n continue;\n }\n const score = clamp01(Number(match.score));\n const key = buildEntryKey({ path: file, startLine, endLine });\n const existing = store.entries[key];\n const snippet = lines.length > 0 ? lines.slice(0, 360) : file;\n\n const next: DreamingStoreEntry = existing\n ? {\n ...existing,\n snippet,\n recallCount: Math.max(0, Math.floor(existing.recallCount + 1)),\n sourceCount: existing.sourceCount ?? 0,\n groundedCount: existing.groundedCount ?? 0,\n lightHits: existing.lightHits ?? 0,\n remHits: existing.remHits ?? 0,\n phaseHitCount: existing.phaseHitCount ?? 0,\n totalSignalCount: Math.max(0, (existing.totalSignalCount ?? existing.recallCount ?? 0) + 1),\n totalScore: Math.max(0, existing.totalScore + score),\n maxScore: Math.max(existing.maxScore, score),\n queryHashes: mergeQueryHashes(existing.queryHashes ?? [], qHash),\n recallDays: mergeRecentDistinct(existing.recallDays ?? [], dayBucket, 16),\n lastRecalledAt: nowIso,\n }\n : {\n key,\n path: normalizeMemoryPath(file),\n startLine,\n endLine,\n snippet,\n recallCount: 1,\n sourceCount: 0,\n groundedCount: 0,\n lightHits: 0,\n remHits: 0,\n phaseHitCount: 0,\n totalSignalCount: 1,\n totalScore: score,\n maxScore: score,\n queryHashes: [qHash],\n recallDays: [dayBucket],\n firstRecalledAt: nowIso,\n lastRecalledAt: nowIso,\n };\n\n store.entries[key] = next;\n recorded += 1;\n }\n\n if (recorded > 0) {\n store.updatedAt = nowIso;\n await writeStore(workspaceDir, store);\n }\n\n return {\n recorded,\n skipped,\n storePath: SHORT_TERM_RECALL_STORE_RELATIVE,\n };\n}\n\nexport async function withDreamingPromotionLock<T>(\n workspaceDir: string,\n task: () => Promise<T>,\n): Promise<T> {\n const lockPath = path.join(workspaceDir, SHORT_TERM_PROMOTION_LOCK_RELATIVE);\n await ensureDreamDir(workspaceDir);\n\n const startedAt = Date.now();\n const timeoutMs = 10_000;\n const retryDelayMs = 50;\n\n while (true) {\n try {\n const handle = await fs.open(lockPath, 'wx');\n await handle.writeFile(`${process.pid}:${Date.now()}\\n`, 'utf-8').catch(() => undefined);\n try {\n return await task();\n } finally {\n await handle.close().catch(() => undefined);\n await fs.unlink(lockPath).catch(() => undefined);\n }\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | undefined)?.code;\n if (code !== 'EEXIST') {\n throw err;\n }\n if (Date.now() - startedAt >= timeoutMs) {\n throw new Error(`Timed out waiting for dreaming promotion lock at ${lockPath}`);\n }\n await new Promise((r) => setTimeout(r, retryDelayMs));\n }\n }\n}\n\nexport async function loadDreamingStore(params: {\n workspaceDir: string;\n}): Promise<{ store: DreamingStore; storePath: string }> {\n const nowIso = new Date().toISOString();\n const store = await readStore(params.workspaceDir, nowIso);\n return { store, storePath: SHORT_TERM_RECALL_STORE_RELATIVE };\n}\n\nexport async function saveDreamingStore(params: {\n workspaceDir: string;\n store: DreamingStore;\n}): Promise<void> {\n await writeStore(params.workspaceDir, params.store);\n}\n\n// ── Phase-level signal helpers ─────────────────────────────────────────\n\ntype PhaseSignalField = 'sourceCount' | 'groundedCount' | 'lightHits' | 'remHits';\n\n/**\n * Increment a phase-specific signal counter on an existing store entry.\n * Also bumps `phaseHitCount` and `totalSignalCount`.\n * Returns `true` if the entry existed and was updated.\n */\nexport function bumpEntryPhaseSignal(\n entry: DreamingStoreEntry,\n field: PhaseSignalField,\n increment = 1,\n): void {\n entry[field] = (entry[field] ?? 0) + increment;\n entry.phaseHitCount = (entry.phaseHitCount ?? 0) + increment;\n entry.totalSignalCount = (entry.totalSignalCount ?? 0) + increment;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"short-term-store.js","names":[],"sources":["../../../../../src/agent/memory/dreaming/short-term-store.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { createHash, randomUUID } from 'node:crypto';\n\nimport type { MemorySearchOptions } from '../../prompt/memory/index.js';\nimport { createLogger } from '../../../utils/logger.js';\nimport {\n SHORT_TERM_PROMOTION_LOCK_RELATIVE,\n SHORT_TERM_RECALL_STORE_RELATIVE,\n} from './constants.js';\nimport { buildEntryKey, clamp01, isoDay, normalizeMemoryPath } from './utils.js';\n\nconst log = createLogger('Dreaming:Store');\n\nexport type DreamingStoreEntry = {\n key: string;\n path: string;\n startLine: number;\n endLine: number;\n snippet: string;\n\n // ── Signal dimensions ────────────────────────────────────────────────\n /** Number of times this snippet was returned by a memory recall query. */\n recallCount: number;\n /** Number of times recorded from source-side sweep phases. */\n sourceCount: number;\n /** Number of times replayed from grounded context (agent-initiated). */\n groundedCount: number;\n /** Number of times the light phase touched this entry. */\n lightHits: number;\n /** Number of times the REM phase touched this entry. */\n remHits: number;\n /** Cross-phase hit count (light + deep + rem combined touches). */\n phaseHitCount: number;\n /** Weighted aggregate of all signal dimensions. */\n totalSignalCount: number;\n\n // ── Score tracking ───────────────────────────────────────────────────\n totalScore: number;\n maxScore: number;\n queryHashes: string[];\n recallDays: string[];\n\n // ── Timestamps ───────────────────────────────────────────────────────\n firstRecalledAt: string;\n lastRecalledAt: string;\n promotedAt?: string;\n};\n\nexport type DreamingStore = {\n version: 1;\n updatedAt: string;\n entries: Record<string, DreamingStoreEntry>;\n};\n\ntype MemoryMatch = Awaited<ReturnType<typeof import('../../prompt/memory/index.js').memorySearch>>[number];\n\nfunction isRecordableMemoryPath(rel: string): boolean {\n const p = normalizeMemoryPath(rel);\n return p.length > 0 && !p.startsWith('../') && !path.isAbsolute(p);\n}\n\nfunction hashQuery(query: string): string {\n return createHash('sha1').update(query.trim().toLowerCase()).digest('hex').slice(0, 12);\n}\n\nfunction mergeRecentDistinct(existing: string[], nextValue: string, limit: number): string[] {\n const seen = new Set<string>();\n const normalized = existing\n .filter((v): v is string => typeof v === 'string')\n .map((v) => v.trim())\n .filter((v) => v.length > 0 && !seen.has(v) && (seen.add(v), true));\n if (nextValue && !normalized.includes(nextValue)) {\n normalized.push(nextValue);\n }\n return normalized.length <= limit ? normalized : normalized.slice(-limit);\n}\n\nfunction mergeQueryHashes(existing: string[], nextHash: string): string[] {\n const out = mergeRecentDistinct(existing, nextHash, 32);\n return out;\n}\n\nfunction emptyStore(nowIso: string): DreamingStore {\n return { version: 1, updatedAt: nowIso, entries: {} };\n}\n\nasync function ensureDreamDir(dreamingRoot: string): Promise<string> {\n const dir = path.join(dreamingRoot, path.dirname(SHORT_TERM_RECALL_STORE_RELATIVE));\n await fs.mkdir(dir, { recursive: true });\n return dir;\n}\n\nasync function readStore(dreamingRoot: string, nowIso: string): Promise<DreamingStore> {\n const storePath = path.join(dreamingRoot, SHORT_TERM_RECALL_STORE_RELATIVE);\n try {\n const raw = await fs.readFile(storePath, 'utf-8');\n const parsed = JSON.parse(raw) as unknown;\n if (!parsed || typeof parsed !== 'object') return emptyStore(nowIso);\n const rec = parsed as Partial<DreamingStore>;\n if (rec.version !== 1 || !rec.entries || typeof rec.entries !== 'object') {\n return emptyStore(nowIso);\n }\n return {\n version: 1,\n updatedAt: typeof rec.updatedAt === 'string' ? rec.updatedAt : nowIso,\n entries: rec.entries as Record<string, DreamingStoreEntry>,\n };\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | undefined)?.code;\n if (code === 'ENOENT') return emptyStore(nowIso);\n log.warn({ err, dreamingRoot }, 'Failed to read dreaming store; resetting');\n return emptyStore(nowIso);\n }\n}\n\nasync function writeStore(dreamingRoot: string, store: DreamingStore): Promise<void> {\n await ensureDreamDir(dreamingRoot);\n const storePath = path.join(dreamingRoot, SHORT_TERM_RECALL_STORE_RELATIVE);\n const tmp = `${storePath}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`;\n await fs.writeFile(tmp, `${JSON.stringify(store, null, 2)}\\n`, 'utf-8');\n await fs.rename(tmp, storePath);\n}\n\nexport async function recordDreamingRecalls(params: {\n dreamingRoot: string;\n query: string;\n matches: MemoryMatch[];\n options?: MemorySearchOptions;\n now?: Date;\n}): Promise<{ recorded: number; skipped: number; storePath: string }> {\n const dreamingRoot = params.dreamingRoot.trim();\n const query = params.query.trim();\n if (!dreamingRoot || !query) {\n return { recorded: 0, skipped: params.matches.length, storePath: SHORT_TERM_RECALL_STORE_RELATIVE };\n }\n const now = params.now ?? new Date();\n const nowIso = now.toISOString();\n const dayBucket = isoDay(now);\n const qHash = hashQuery(query);\n\n const store = await readStore(dreamingRoot, nowIso);\n\n let recorded = 0;\n let skipped = 0;\n for (const match of params.matches) {\n const file = typeof match?.file === \"string\" ? match.file : \"\";\n if (!file || !isRecordableMemoryPath(file)) {\n skipped += 1;\n continue;\n }\n const lines = typeof match?.lines === \"string\" ? match.lines.trim() : \"\";\n const lineNumbers = Array.isArray(match?.lineNumbers) ? match.lineNumbers : [];\n const startLine = Math.max(1, Math.min(...lineNumbers.filter((n) => Number.isFinite(n) && n > 0)));\n const endLine = Math.max(startLine, Math.max(...lineNumbers.filter((n) => Number.isFinite(n) && n > 0)));\n if (!Number.isFinite(startLine) || !Number.isFinite(endLine)) {\n skipped += 1;\n continue;\n }\n const score = clamp01(Number(match.score));\n const key = buildEntryKey({ path: file, startLine, endLine });\n const existing = store.entries[key];\n const snippet = lines.length > 0 ? lines.slice(0, 360) : file;\n\n const next: DreamingStoreEntry = existing\n ? {\n ...existing,\n snippet,\n recallCount: Math.max(0, Math.floor(existing.recallCount + 1)),\n sourceCount: existing.sourceCount ?? 0,\n groundedCount: existing.groundedCount ?? 0,\n lightHits: existing.lightHits ?? 0,\n remHits: existing.remHits ?? 0,\n phaseHitCount: existing.phaseHitCount ?? 0,\n totalSignalCount: Math.max(0, (existing.totalSignalCount ?? existing.recallCount ?? 0) + 1),\n totalScore: Math.max(0, existing.totalScore + score),\n maxScore: Math.max(existing.maxScore, score),\n queryHashes: mergeQueryHashes(existing.queryHashes ?? [], qHash),\n recallDays: mergeRecentDistinct(existing.recallDays ?? [], dayBucket, 16),\n lastRecalledAt: nowIso,\n }\n : {\n key,\n path: normalizeMemoryPath(file),\n startLine,\n endLine,\n snippet,\n recallCount: 1,\n sourceCount: 0,\n groundedCount: 0,\n lightHits: 0,\n remHits: 0,\n phaseHitCount: 0,\n totalSignalCount: 1,\n totalScore: score,\n maxScore: score,\n queryHashes: [qHash],\n recallDays: [dayBucket],\n firstRecalledAt: nowIso,\n lastRecalledAt: nowIso,\n };\n\n store.entries[key] = next;\n recorded += 1;\n }\n\n if (recorded > 0) {\n store.updatedAt = nowIso;\n await writeStore(dreamingRoot, store);\n }\n\n return {\n recorded,\n skipped,\n storePath: SHORT_TERM_RECALL_STORE_RELATIVE,\n };\n}\n\nexport async function withDreamingPromotionLock<T>(\n dreamingRoot: string,\n task: () => Promise<T>,\n): Promise<T> {\n const lockPath = path.join(dreamingRoot, SHORT_TERM_PROMOTION_LOCK_RELATIVE);\n await ensureDreamDir(dreamingRoot);\n\n const startedAt = Date.now();\n const timeoutMs = 10_000;\n const retryDelayMs = 50;\n\n while (true) {\n try {\n const handle = await fs.open(lockPath, 'wx');\n await handle.writeFile(`${process.pid}:${Date.now()}\\n`, 'utf-8').catch(() => undefined);\n try {\n return await task();\n } finally {\n await handle.close().catch(() => undefined);\n await fs.unlink(lockPath).catch(() => undefined);\n }\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | undefined)?.code;\n if (code !== 'EEXIST') {\n throw err;\n }\n if (Date.now() - startedAt >= timeoutMs) {\n throw new Error(`Timed out waiting for dreaming promotion lock at ${lockPath}`);\n }\n await new Promise((r) => setTimeout(r, retryDelayMs));\n }\n }\n}\n\nexport async function loadDreamingStore(params: {\n dreamingRoot: string;\n}): Promise<{ store: DreamingStore; storePath: string }> {\n const nowIso = new Date().toISOString();\n const store = await readStore(params.dreamingRoot, nowIso);\n return { store, storePath: SHORT_TERM_RECALL_STORE_RELATIVE };\n}\n\nexport async function saveDreamingStore(params: {\n dreamingRoot: string;\n store: DreamingStore;\n}): Promise<void> {\n await writeStore(params.dreamingRoot, params.store);\n}\n\n// ── Phase-level signal helpers ─────────────────────────────────────────\n\ntype PhaseSignalField = 'sourceCount' | 'groundedCount' | 'lightHits' | 'remHits';\n\n/**\n * Increment a phase-specific signal counter on an existing store entry.\n * Also bumps `phaseHitCount` and `totalSignalCount`.\n * Returns `true` if the entry existed and was updated.\n */\nexport function bumpEntryPhaseSignal(\n entry: DreamingStoreEntry,\n field: PhaseSignalField,\n increment = 1,\n): void {\n entry[field] = (entry[field] ?? 0) + increment;\n entry.phaseHitCount = (entry.phaseHitCount ?? 0) + increment;\n entry.totalSignalCount = (entry.totalSignalCount ?? 0) + increment;\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { discoverExtensionsFromDisk, init_discover_extensions } from "../../extensions/discover-extensions.js";
|
|
2
2
|
import { isAbsolute, join } from "node:path";
|
|
3
|
-
import { stat } from "node:fs/promises";
|
|
4
3
|
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { stat } from "node:fs/promises";
|
|
5
5
|
//#region src/agent/memory/plugin-discovery.ts
|
|
6
6
|
init_discover_extensions();
|
|
7
7
|
async function discoverMemoryPlugins(config) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { getAgentDefaultModelRef, init_schema } from "../../config/schema.js";
|
|
2
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
3
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
+
import { getAgentDefaultModelRef, init_schema } from "../../config/schema.js";
|
|
4
4
|
import { getAllModels, getDefaultModelSync, init_providers, resolveModel } from "../../providers/index.js";
|
|
5
5
|
import { parseModelRef } from "./selection.js";
|
|
6
6
|
import { resolveFallbackCandidates } from "../fallback/candidates.js";
|
|
@@ -23,6 +23,7 @@ import type { SelfVerifyMiddleware } from '../middleware/index.js';
|
|
|
23
23
|
import type { SystemReminder } from '../prompt/system-reminder.js';
|
|
24
24
|
import type { ToolUsageAnalyzer } from '../tools/usage-analyzer.js';
|
|
25
25
|
import type { ErrorPatternMatcher } from '../tools/error-pattern-matcher.js';
|
|
26
|
+
import type { TurnDiffTracker } from '../coding/index.js';
|
|
26
27
|
export type SessionEventListener = (event: AgentEvent, context: SessionContext) => void;
|
|
27
28
|
export type SessionEventTypeFilter = AgentEvent['type'] | 'all';
|
|
28
29
|
/**
|
|
@@ -45,6 +46,7 @@ export interface AgentEventHandlerConfig {
|
|
|
45
46
|
systemReminder: SystemReminder;
|
|
46
47
|
toolUsageAnalyzer: ToolUsageAnalyzer;
|
|
47
48
|
errorPatternMatcher: ErrorPatternMatcher;
|
|
49
|
+
turnDiffTracker?: TurnDiffTracker;
|
|
48
50
|
}
|
|
49
51
|
/**
|
|
50
52
|
* Thin façade over {@link SessionEventBus} that pre-registers all built-in
|
|
@@ -294,6 +294,18 @@ function installSelfVerifyListener(bus, selfVerifyMiddleware) {
|
|
|
294
294
|
selfVerifyMiddleware.onTurnStart(context.sessionKey);
|
|
295
295
|
});
|
|
296
296
|
}
|
|
297
|
+
function installTurnDiffTrackerListener(bus, turnDiffTracker) {
|
|
298
|
+
bus.on("tool_execution_end", (event, context) => {
|
|
299
|
+
const e = event;
|
|
300
|
+
turnDiffTracker.recordToolResult({
|
|
301
|
+
sessionKey: context.sessionKey,
|
|
302
|
+
toolName: e.toolName,
|
|
303
|
+
args: e.args,
|
|
304
|
+
result: e.result,
|
|
305
|
+
isError: e.isError
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
}
|
|
297
309
|
/**
|
|
298
310
|
* Thin façade over {@link SessionEventBus} that pre-registers all built-in
|
|
299
311
|
* listeners in their required order. `handle(event, ctx)` is the entry point
|
|
@@ -312,6 +324,7 @@ var AgentEventHandler = class {
|
|
|
312
324
|
});
|
|
313
325
|
installLifecycleHookListener(this.bus, config.lifecycleManager);
|
|
314
326
|
installSystemReminderListener(this.bus, config.systemReminder);
|
|
327
|
+
if (config.turnDiffTracker) installTurnDiffTrackerListener(this.bus, config.turnDiffTracker);
|
|
315
328
|
installSelfVerifyListener(this.bus, config.selfVerifyMiddleware);
|
|
316
329
|
installToolUsageListener(this.bus, config.toolUsageAnalyzer);
|
|
317
330
|
installToolChainListener(this.bus, config.toolChainTracker);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-event-handler.js","names":[],"sources":["../../../../src/agent/orchestration/agent-event-handler.ts"],"sourcesContent":["/**\n * Agent Event Handler — coordinates listeners on pi-agent events.\n *\n * Previously a single god-handler with ten manager fields and one `switch`. Now a\n * thin façade around {@link SessionEventBus}: each concern (progress, lifecycle\n * hooks, tool-chain recording, error tracking, self-verify, etc.) registers its\n * own listener at construction time, and external code can add new listeners via\n * {@link AgentEventHandler.registerListener} without modifying this file (OCP).\n *\n * Ordering note: a few listeners are order-sensitive (notably the\n * `tool_execution_end` chain — `SystemReminder` mutates `event.result` in place\n * and downstream listeners read the mutated value). The `installX` calls below\n * preserve the exact order from the previous implementation.\n */\n\nimport type { AgentEvent } from '@earendil-works/pi-agent-core';\nimport type { SessionContext } from '../session/session-context.js';\nimport type { ProgressFeedbackManager } from '../lifecycle/progress.js';\nimport type { ToolErrorTracker } from '../tools/error-tracker.js';\nimport type { RequestLimiter } from '../models/request-limiter.js';\nimport type { LifecycleManager } from '../lifecycle/index.js';\nimport type { ToolChainTracker } from '../tools/chain-tracker.js';\nimport type { SelfVerifyMiddleware } from '../middleware/index.js';\nimport type { SystemReminder } from '../prompt/system-reminder.js';\nimport type { ToolUsageAnalyzer } from '../tools/usage-analyzer.js';\nimport type { ErrorPatternMatcher } from '../tools/error-pattern-matcher.js';\nimport { extractTextContent } from '../context/workspace.js';\nimport { createLogger } from '../../utils/logger.js';\n\nconst log = createLogger('AgentEventHandler');\n\n// ── Event bus ──────────────────────────────────────────────────────────────\n\nexport type SessionEventListener = (event: AgentEvent, context: SessionContext) => void;\nexport type SessionEventTypeFilter = AgentEvent['type'] | 'all';\n\n/**\n * Typed pub/sub for agent events. Listeners run in registration order; the bus\n * itself is synchronous — listeners that need async work must dispatch their own\n * promises (typically by awaiting and logging on error, like the lifecycle hooks).\n */\nexport class SessionEventBus {\n private readonly listeners = new Map<SessionEventTypeFilter, SessionEventListener[]>();\n\n on(type: SessionEventTypeFilter, listener: SessionEventListener): () => void {\n const bucket = this.listeners.get(type) ?? [];\n bucket.push(listener);\n this.listeners.set(type, bucket);\n return () => {\n const current = this.listeners.get(type);\n if (!current) return;\n const idx = current.indexOf(listener);\n if (idx >= 0) current.splice(idx, 1);\n };\n }\n\n dispatch(event: AgentEvent, context: SessionContext | null): void {\n if (!context) {\n if (event.type !== 'message_update') {\n log.warn(\n { eventType: event.type },\n `Agent event ignored (no SessionContext): ${event.type}`,\n );\n }\n return;\n }\n const exact = this.listeners.get(event.type);\n if (exact) {\n for (const listener of exact) {\n listener(event, context);\n }\n }\n const all = this.listeners.get('all');\n if (all) {\n for (const listener of all) {\n listener(event, context);\n }\n }\n }\n}\n\n// ── Built-in listener installers ───────────────────────────────────────────\n\nfunction installProgressListener(bus: SessionEventBus, progressManager: ProgressFeedbackManager): void {\n bus.on('agent_start', () => {\n log.debug('Agent turn started');\n progressManager.startTask();\n });\n bus.on('turn_start', () => {\n log.debug('Turn started');\n progressManager.onTurnStart();\n });\n bus.on('tool_execution_start', (event) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_start' }>;\n log.debug({ tool: e.toolName, args: e.args }, 'Tool execution started');\n progressManager.onToolStart(e.toolName, e.args || {});\n });\n bus.on('tool_execution_update', (event) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_update' }>;\n progressManager.onToolUpdate(e.toolName, e.partialResult);\n });\n bus.on('tool_execution_end', (event) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }>;\n log.debug({ tool: e.toolName, isError: e.isError }, 'Tool execution complete');\n progressManager.onToolEnd(e.toolName, e.result, e.isError);\n });\n bus.on('agent_end', () => {\n progressManager.endTask();\n });\n}\n\nfunction installRequestLimitListener(\n bus: SessionEventBus,\n deps: {\n requestLimiter: RequestLimiter;\n progressManager: ProgressFeedbackManager;\n lifecycleManager: LifecycleManager;\n },\n): void {\n bus.on('agent_start', (_event, context) => {\n const result = deps.requestLimiter.recordRequest();\n\n deps.lifecycleManager\n .emit(\n 'llm_request',\n context.sessionKey,\n { requestNumber: result.count, maxRequests: result.limit },\n context,\n )\n .catch((err) => {\n const em = err instanceof Error ? err.message : String(err);\n log.warn(\n {\n err,\n errorMessage: em,\n sessionKey: context.sessionKey,\n requestNumber: result.count,\n maxRequests: result.limit,\n },\n `Lifecycle emit llm_request failed: ${em}`,\n );\n });\n\n deps.progressManager.onRequestLimitStatus(\n result.count,\n result.limit,\n result.remaining,\n result.isWarning,\n result.shouldStop,\n );\n\n if (result.shouldStop) {\n log.error(\n { count: result.count, limit: result.limit, sessionKey: context.sessionKey },\n `Request limit reached (${result.count}/${result.limit}) for session`,\n );\n }\n });\n\n bus.on('turn_end', () => {\n deps.requestLimiter.reset();\n });\n}\n\nfunction installLifecycleHookListener(bus: SessionEventBus, lifecycleManager: LifecycleManager): void {\n bus.on('message_end', (event, context) => {\n const e = event as Extract<AgentEvent, { type: 'message_end' }>;\n if (e.message?.role !== 'assistant') return;\n const content = e.message.content;\n const text = Array.isArray(content)\n ? extractTextContent(content as Array<{ type: string; text?: string }>)\n : String(content);\n log.debug({ contentLength: text.length }, 'Assistant response complete');\n\n lifecycleManager\n .emit(\n 'llm_response',\n context.sessionKey,\n { response: text, usage: (e.message as { usage?: unknown }).usage },\n context,\n )\n .catch((err) => {\n const em = err instanceof Error ? err.message : String(err);\n log.warn(\n { err, errorMessage: em, sessionKey: context.sessionKey, responseChars: text.length },\n `Lifecycle emit llm_response failed: ${em}`,\n );\n });\n });\n\n bus.on('tool_execution_start', (event, context) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_start' }>;\n lifecycleManager\n .emit(\n 'tool_call_start',\n context.sessionKey,\n {\n toolName: e.toolName,\n arguments: e.args || {},\n attemptNumber: 1,\n maxAttempts: 3,\n },\n context,\n )\n .catch((err) => {\n const em = err instanceof Error ? err.message : String(err);\n log.warn(\n { err, errorMessage: em, sessionKey: context.sessionKey, tool: e.toolName },\n `Lifecycle emit tool_call_start failed: ${em}`,\n );\n });\n });\n\n bus.on('tool_execution_end', (event, context) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }>;\n const durationMs = (e as { durationMs?: number }).durationMs || 0;\n lifecycleManager\n .emit(\n 'tool_call_end',\n context.sessionKey,\n {\n toolName: e.toolName,\n success: !e.isError,\n result: e.result,\n error: e.isError ? String(e.result) : undefined,\n durationMs,\n },\n context,\n )\n .catch((err) => {\n const em = err instanceof Error ? err.message : String(err);\n log.warn(\n { err, errorMessage: em, sessionKey: context.sessionKey, tool: e.toolName },\n `Lifecycle hook tool_call_end failed: ${em}`,\n );\n });\n });\n}\n\nfunction installSystemReminderListener(bus: SessionEventBus, systemReminder: SystemReminder): void {\n // MUTATES `event.result` so downstream listeners (tool-chain, error-tracking) see\n // the decorated text. Must run AFTER progress + lifecycle hooks (they consume the\n // original) and BEFORE tool-chain + error-tracking.\n bus.on('tool_execution_end', (event) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }> & { result: unknown };\n e.result = systemReminder.appendToResult(e.result, e.toolName);\n });\n}\n\nfunction appendTextToToolResult(result: unknown, text: string): unknown {\n if (!text.trim()) {\n return result;\n }\n if (result && typeof result === 'object') {\n const res = result as Record<string, unknown>;\n if (Array.isArray(res.content)) {\n res.content = [\n ...res.content,\n { type: 'text', text: `\\n${text}` },\n ];\n return res;\n }\n if (typeof res.content === 'string') {\n res.content = `${res.content}\\n${text}`;\n return res;\n }\n }\n return result;\n}\n\nfunction readRecord(value: unknown): Record<string, unknown> | null {\n return value && typeof value === 'object' ? (value as Record<string, unknown>) : null;\n}\n\nfunction readToolResultDetails(result: unknown): Record<string, unknown> | null {\n const rec = readRecord(result);\n if (!rec) return null;\n return readRecord(rec.details);\n}\n\nfunction readStringArray(value: unknown): string[] {\n return Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : [];\n}\n\nfunction readChangedPathsFromToolEnd(toolName: string, args: unknown, result: unknown): string[] {\n const name = toolName.toLowerCase();\n const details = readToolResultDetails(result);\n\n if (name === 'apply_patch') {\n const files = readStringArray(details?.files);\n if (files.length > 0) return files;\n\n const changes = Array.isArray(details?.changes) ? details.changes : [];\n return changes.flatMap((change) => {\n const rec = readRecord(change);\n if (!rec) return [];\n return readStringArray([rec.moveTo, rec.path]);\n });\n }\n\n if (name === 'write_file') {\n if (typeof details?.size !== 'number') return [];\n const rec = readRecord(args);\n return typeof rec?.path === 'string' ? [rec.path] : [];\n }\n\n if (name.includes('write') || name.includes('edit')) {\n const rec = readRecord(args);\n return typeof rec?.path === 'string' ? [rec.path] : [];\n }\n\n return [];\n}\n\nfunction installToolChainListener(bus: SessionEventBus, toolChainTracker: ToolChainTracker): void {\n bus.on('turn_start', (_event, context) => {\n // One chain per LLM turn (pi-agent emits turn_start each round; turn_end clears the chain).\n toolChainTracker.startChain(context.sessionKey);\n });\n bus.on('tool_execution_start', (event, context) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_start' }>;\n toolChainTracker.recordCall(context.sessionKey, e.toolName, e.args || {}, 0);\n });\n bus.on('tool_execution_end', (event, context) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }>;\n const durationMs = (e as { durationMs?: number }).durationMs || 0;\n const chain = toolChainTracker.getCurrentChain(context.sessionKey);\n if (!chain) return;\n const lastNode = chain.nodes[chain.nodes.length - 1];\n if (lastNode && lastNode.toolName === e.toolName) {\n toolChainTracker.recordResult(\n context.sessionKey,\n lastNode.id,\n e.result,\n e.isError ? 'Tool execution failed' : undefined,\n durationMs,\n );\n }\n });\n bus.on('turn_end', (_event, context) => {\n toolChainTracker.endChain(context.sessionKey);\n });\n}\n\nfunction installToolUsageListener(bus: SessionEventBus, toolUsageAnalyzer: ToolUsageAnalyzer): void {\n bus.on('tool_execution_end', (event) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }>;\n const durationMs = (e as { durationMs?: number }).durationMs || 0;\n toolUsageAnalyzer.recordUsage(e.toolName, !e.isError, durationMs);\n });\n}\n\nfunction extractErrorText(result: unknown): string {\n if (typeof result === 'string') return result;\n if (result && typeof result === 'object') {\n const obj = result as Record<string, unknown>;\n if (typeof obj.error === 'string') return obj.error;\n if (typeof obj.message === 'string') return obj.message;\n return JSON.stringify(result);\n }\n return String(result);\n}\n\nfunction installErrorTrackingListener(\n bus: SessionEventBus,\n deps: { errorTracker: ToolErrorTracker; errorPatternMatcher: ErrorPatternMatcher },\n): void {\n bus.on('tool_execution_end', (event) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }>;\n if (!e.isError) return;\n const errorText = extractErrorText(e.result);\n deps.errorTracker.recordFailure(e.toolName, errorText);\n\n const errorMatch = deps.errorPatternMatcher.matchError(errorText);\n if (errorMatch.matched && errorMatch.pattern) {\n const preview = errorText.length > 120 ? `${errorText.slice(0, 120)}…` : errorText;\n log.warn(\n { tool: e.toolName, pattern: errorMatch.pattern.name, errorPreview: preview },\n `Tool error matched pattern \"${errorMatch.pattern.name}\" (${e.toolName}): ${preview}`,\n );\n }\n });\n bus.on('turn_end', () => {\n deps.errorTracker.reset();\n });\n}\n\nfunction installSelfVerifyListener(bus: SessionEventBus, selfVerifyMiddleware: SelfVerifyMiddleware): void {\n bus.on('tool_execution_end', (event, context) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }> & { result: unknown };\n const name = e.toolName?.toLowerCase() ?? '';\n const args = (e as { args?: unknown }).args;\n\n if (name === 'exec_command') {\n selfVerifyMiddleware.recordVerification(e.toolName, args, {\n isError: e.isError,\n result: e.result,\n }, context.sessionKey);\n return;\n }\n\n if (!e.isError) {\n const changedPaths = readChangedPathsFromToolEnd(e.toolName, args, e.result);\n for (const path of changedPaths) {\n selfVerifyMiddleware.recordEdit(\n path,\n name.includes('write') ? 'write' : 'edit',\n context.sessionKey,\n );\n }\n if (changedPaths.length > 0) {\n e.result = appendTextToToolResult(\n e.result,\n selfVerifyMiddleware.consumePostEditReminder(context.sessionKey),\n );\n return;\n }\n selfVerifyMiddleware.recordVerification(e.toolName, args, {\n isError: e.isError,\n result: e.result,\n }, context.sessionKey);\n }\n });\n bus.on('turn_start', (_event, context) => {\n selfVerifyMiddleware.onTurnStart(context.sessionKey);\n });\n}\n\n// ── Public façade ───────────────────────────────────────────────────────────\n\nexport interface AgentEventHandlerConfig {\n progressManager: ProgressFeedbackManager;\n errorTracker: ToolErrorTracker;\n requestLimiter: RequestLimiter;\n lifecycleManager: LifecycleManager;\n toolChainTracker: ToolChainTracker;\n selfVerifyMiddleware: SelfVerifyMiddleware;\n systemReminder: SystemReminder;\n toolUsageAnalyzer: ToolUsageAnalyzer;\n errorPatternMatcher: ErrorPatternMatcher;\n}\n\n/**\n * Thin façade over {@link SessionEventBus} that pre-registers all built-in\n * listeners in their required order. `handle(event, ctx)` is the entry point\n * used by `AgentService.handleSessionEvent`; extensions can hook in via\n * {@link registerListener} without touching this class.\n */\nexport class AgentEventHandler {\n private readonly bus: SessionEventBus;\n\n constructor(config: AgentEventHandlerConfig) {\n this.bus = new SessionEventBus();\n\n // Order matters for `tool_execution_end`: SystemReminder mutates `event.result`\n // and ToolChain + ErrorTracking depend on the mutated value. Keep these in this\n // exact sequence.\n installProgressListener(this.bus, config.progressManager);\n installRequestLimitListener(this.bus, {\n requestLimiter: config.requestLimiter,\n progressManager: config.progressManager,\n lifecycleManager: config.lifecycleManager,\n });\n installLifecycleHookListener(this.bus, config.lifecycleManager);\n installSystemReminderListener(this.bus, config.systemReminder);\n installSelfVerifyListener(this.bus, config.selfVerifyMiddleware);\n installToolUsageListener(this.bus, config.toolUsageAnalyzer);\n installToolChainListener(this.bus, config.toolChainTracker);\n installErrorTrackingListener(this.bus, {\n errorTracker: config.errorTracker,\n errorPatternMatcher: config.errorPatternMatcher,\n });\n }\n\n /** Dispatch a pi-agent event to all registered listeners. */\n handle(event: AgentEvent, context: SessionContext | null): void {\n this.bus.dispatch(event, context);\n }\n\n /**\n * Register an additional listener (e.g. from an extension). Returns an\n * unsubscribe function. Listeners run after the built-ins in registration\n * order; if you need to run before a built-in, you must create your own\n * {@link SessionEventBus} instance.\n */\n registerListener(type: SessionEventTypeFilter, listener: SessionEventListener): () => void {\n return this.bus.on(type, listener);\n }\n}\n"],"mappings":";;;;aA2BqD;AAErD,MAAM,MAAM,aAAa,oBAAoB;;;;;;AAY7C,IAAa,kBAAb,MAA6B;CAC3B,4BAA6B,IAAI,KAAqD;CAEtF,GAAG,MAA8B,UAA4C;EAC3E,MAAM,SAAS,KAAK,UAAU,IAAI,KAAK,IAAI,EAAE;AAC7C,SAAO,KAAK,SAAS;AACrB,OAAK,UAAU,IAAI,MAAM,OAAO;AAChC,eAAa;GACX,MAAM,UAAU,KAAK,UAAU,IAAI,KAAK;AACxC,OAAI,CAAC,QAAS;GACd,MAAM,MAAM,QAAQ,QAAQ,SAAS;AACrC,OAAI,OAAO,EAAG,SAAQ,OAAO,KAAK,EAAE;;;CAIxC,SAAS,OAAmB,SAAsC;AAChE,MAAI,CAAC,SAAS;AACZ,OAAI,MAAM,SAAS,iBACjB,KAAI,KACF,EAAE,WAAW,MAAM,MAAM,EACzB,4CAA4C,MAAM,OACnD;AAEH;;EAEF,MAAM,QAAQ,KAAK,UAAU,IAAI,MAAM,KAAK;AAC5C,MAAI,MACF,MAAK,MAAM,YAAY,MACrB,UAAS,OAAO,QAAQ;EAG5B,MAAM,MAAM,KAAK,UAAU,IAAI,MAAM;AACrC,MAAI,IACF,MAAK,MAAM,YAAY,IACrB,UAAS,OAAO,QAAQ;;;AAQhC,SAAS,wBAAwB,KAAsB,iBAAgD;AACrG,KAAI,GAAG,qBAAqB;AAC1B,MAAI,MAAM,qBAAqB;AAC/B,kBAAgB,WAAW;GAC3B;AACF,KAAI,GAAG,oBAAoB;AACzB,MAAI,MAAM,eAAe;AACzB,kBAAgB,aAAa;GAC7B;AACF,KAAI,GAAG,yBAAyB,UAAU;EACxC,MAAM,IAAI;AACV,MAAI,MAAM;GAAE,MAAM,EAAE;GAAU,MAAM,EAAE;GAAM,EAAE,yBAAyB;AACvE,kBAAgB,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;GACrD;AACF,KAAI,GAAG,0BAA0B,UAAU;EACzC,MAAM,IAAI;AACV,kBAAgB,aAAa,EAAE,UAAU,EAAE,cAAc;GACzD;AACF,KAAI,GAAG,uBAAuB,UAAU;EACtC,MAAM,IAAI;AACV,MAAI,MAAM;GAAE,MAAM,EAAE;GAAU,SAAS,EAAE;GAAS,EAAE,0BAA0B;AAC9E,kBAAgB,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ;GAC1D;AACF,KAAI,GAAG,mBAAmB;AACxB,kBAAgB,SAAS;GACzB;;AAGJ,SAAS,4BACP,KACA,MAKM;AACN,KAAI,GAAG,gBAAgB,QAAQ,YAAY;EACzC,MAAM,SAAS,KAAK,eAAe,eAAe;AAElD,OAAK,iBACF,KACC,eACA,QAAQ,YACR;GAAE,eAAe,OAAO;GAAO,aAAa,OAAO;GAAO,EAC1D,QACD,CACA,OAAO,QAAQ;GACd,MAAM,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC3D,OAAI,KACF;IACE;IACA,cAAc;IACd,YAAY,QAAQ;IACpB,eAAe,OAAO;IACtB,aAAa,OAAO;IACrB,EACD,sCAAsC,KACvC;IACD;AAEJ,OAAK,gBAAgB,qBACnB,OAAO,OACP,OAAO,OACP,OAAO,WACP,OAAO,WACP,OAAO,WACR;AAED,MAAI,OAAO,WACT,KAAI,MACF;GAAE,OAAO,OAAO;GAAO,OAAO,OAAO;GAAO,YAAY,QAAQ;GAAY,EAC5E,0BAA0B,OAAO,MAAM,GAAG,OAAO,MAAM,eACxD;GAEH;AAEF,KAAI,GAAG,kBAAkB;AACvB,OAAK,eAAe,OAAO;GAC3B;;AAGJ,SAAS,6BAA6B,KAAsB,kBAA0C;AACpG,KAAI,GAAG,gBAAgB,OAAO,YAAY;EACxC,MAAM,IAAI;AACV,MAAI,EAAE,SAAS,SAAS,YAAa;EACrC,MAAM,UAAU,EAAE,QAAQ;EAC1B,MAAM,OAAO,MAAM,QAAQ,QAAQ,GAC/B,mBAAmB,QAAkD,GACrE,OAAO,QAAQ;AACnB,MAAI,MAAM,EAAE,eAAe,KAAK,QAAQ,EAAE,8BAA8B;AAExE,mBACG,KACC,gBACA,QAAQ,YACR;GAAE,UAAU;GAAM,OAAQ,EAAE,QAAgC;GAAO,EACnE,QACD,CACA,OAAO,QAAQ;GACd,MAAM,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC3D,OAAI,KACF;IAAE;IAAK,cAAc;IAAI,YAAY,QAAQ;IAAY,eAAe,KAAK;IAAQ,EACrF,uCAAuC,KACxC;IACD;GACJ;AAEF,KAAI,GAAG,yBAAyB,OAAO,YAAY;EACjD,MAAM,IAAI;AACV,mBACG,KACC,mBACA,QAAQ,YACR;GACE,UAAU,EAAE;GACZ,WAAW,EAAE,QAAQ,EAAE;GACvB,eAAe;GACf,aAAa;GACd,EACD,QACD,CACA,OAAO,QAAQ;GACd,MAAM,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC3D,OAAI,KACF;IAAE;IAAK,cAAc;IAAI,YAAY,QAAQ;IAAY,MAAM,EAAE;IAAU,EAC3E,0CAA0C,KAC3C;IACD;GACJ;AAEF,KAAI,GAAG,uBAAuB,OAAO,YAAY;EAC/C,MAAM,IAAI;EACV,MAAM,aAAc,EAA8B,cAAc;AAChE,mBACG,KACC,iBACA,QAAQ,YACR;GACE,UAAU,EAAE;GACZ,SAAS,CAAC,EAAE;GACZ,QAAQ,EAAE;GACV,OAAO,EAAE,UAAU,OAAO,EAAE,OAAO,GAAG,KAAA;GACtC;GACD,EACD,QACD,CACA,OAAO,QAAQ;GACd,MAAM,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC3D,OAAI,KACF;IAAE;IAAK,cAAc;IAAI,YAAY,QAAQ;IAAY,MAAM,EAAE;IAAU,EAC3E,wCAAwC,KACzC;IACD;GACJ;;AAGJ,SAAS,8BAA8B,KAAsB,gBAAsC;AAIjG,KAAI,GAAG,uBAAuB,UAAU;EACtC,MAAM,IAAI;AACV,IAAE,SAAS,eAAe,eAAe,EAAE,QAAQ,EAAE,SAAS;GAC9D;;AAGJ,SAAS,uBAAuB,QAAiB,MAAuB;AACtE,KAAI,CAAC,KAAK,MAAM,CACd,QAAO;AAET,KAAI,UAAU,OAAO,WAAW,UAAU;EACxC,MAAM,MAAM;AACZ,MAAI,MAAM,QAAQ,IAAI,QAAQ,EAAE;AAC9B,OAAI,UAAU,CACZ,GAAG,IAAI,SACP;IAAE,MAAM;IAAQ,MAAM,KAAK;IAAQ,CACpC;AACD,UAAO;;AAET,MAAI,OAAO,IAAI,YAAY,UAAU;AACnC,OAAI,UAAU,GAAG,IAAI,QAAQ,IAAI;AACjC,UAAO;;;AAGX,QAAO;;AAGT,SAAS,WAAW,OAAgD;AAClE,QAAO,SAAS,OAAO,UAAU,WAAY,QAAoC;;AAGnF,SAAS,sBAAsB,QAAiD;CAC9E,MAAM,MAAM,WAAW,OAAO;AAC9B,KAAI,CAAC,IAAK,QAAO;AACjB,QAAO,WAAW,IAAI,QAAQ;;AAGhC,SAAS,gBAAgB,OAA0B;AACjD,QAAO,MAAM,QAAQ,MAAM,GAAG,MAAM,QAAQ,SAAyB,OAAO,SAAS,SAAS,GAAG,EAAE;;AAGrG,SAAS,4BAA4B,UAAkB,MAAe,QAA2B;CAC/F,MAAM,OAAO,SAAS,aAAa;CACnC,MAAM,UAAU,sBAAsB,OAAO;AAE7C,KAAI,SAAS,eAAe;EAC1B,MAAM,QAAQ,gBAAgB,SAAS,MAAM;AAC7C,MAAI,MAAM,SAAS,EAAG,QAAO;AAG7B,UADgB,MAAM,QAAQ,SAAS,QAAQ,GAAG,QAAQ,UAAU,EAAE,EACvD,SAAS,WAAW;GACjC,MAAM,MAAM,WAAW,OAAO;AAC9B,OAAI,CAAC,IAAK,QAAO,EAAE;AACnB,UAAO,gBAAgB,CAAC,IAAI,QAAQ,IAAI,KAAK,CAAC;IAC9C;;AAGJ,KAAI,SAAS,cAAc;AACzB,MAAI,OAAO,SAAS,SAAS,SAAU,QAAO,EAAE;EAChD,MAAM,MAAM,WAAW,KAAK;AAC5B,SAAO,OAAO,KAAK,SAAS,WAAW,CAAC,IAAI,KAAK,GAAG,EAAE;;AAGxD,KAAI,KAAK,SAAS,QAAQ,IAAI,KAAK,SAAS,OAAO,EAAE;EACnD,MAAM,MAAM,WAAW,KAAK;AAC5B,SAAO,OAAO,KAAK,SAAS,WAAW,CAAC,IAAI,KAAK,GAAG,EAAE;;AAGxD,QAAO,EAAE;;AAGX,SAAS,yBAAyB,KAAsB,kBAA0C;AAChG,KAAI,GAAG,eAAe,QAAQ,YAAY;AAExC,mBAAiB,WAAW,QAAQ,WAAW;GAC/C;AACF,KAAI,GAAG,yBAAyB,OAAO,YAAY;EACjD,MAAM,IAAI;AACV,mBAAiB,WAAW,QAAQ,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE;GAC5E;AACF,KAAI,GAAG,uBAAuB,OAAO,YAAY;EAC/C,MAAM,IAAI;EACV,MAAM,aAAc,EAA8B,cAAc;EAChE,MAAM,QAAQ,iBAAiB,gBAAgB,QAAQ,WAAW;AAClE,MAAI,CAAC,MAAO;EACZ,MAAM,WAAW,MAAM,MAAM,MAAM,MAAM,SAAS;AAClD,MAAI,YAAY,SAAS,aAAa,EAAE,SACtC,kBAAiB,aACf,QAAQ,YACR,SAAS,IACT,EAAE,QACF,EAAE,UAAU,0BAA0B,KAAA,GACtC,WACD;GAEH;AACF,KAAI,GAAG,aAAa,QAAQ,YAAY;AACtC,mBAAiB,SAAS,QAAQ,WAAW;GAC7C;;AAGJ,SAAS,yBAAyB,KAAsB,mBAA4C;AAClG,KAAI,GAAG,uBAAuB,UAAU;EACtC,MAAM,IAAI;EACV,MAAM,aAAc,EAA8B,cAAc;AAChE,oBAAkB,YAAY,EAAE,UAAU,CAAC,EAAE,SAAS,WAAW;GACjE;;AAGJ,SAAS,iBAAiB,QAAyB;AACjD,KAAI,OAAO,WAAW,SAAU,QAAO;AACvC,KAAI,UAAU,OAAO,WAAW,UAAU;EACxC,MAAM,MAAM;AACZ,MAAI,OAAO,IAAI,UAAU,SAAU,QAAO,IAAI;AAC9C,MAAI,OAAO,IAAI,YAAY,SAAU,QAAO,IAAI;AAChD,SAAO,KAAK,UAAU,OAAO;;AAE/B,QAAO,OAAO,OAAO;;AAGvB,SAAS,6BACP,KACA,MACM;AACN,KAAI,GAAG,uBAAuB,UAAU;EACtC,MAAM,IAAI;AACV,MAAI,CAAC,EAAE,QAAS;EAChB,MAAM,YAAY,iBAAiB,EAAE,OAAO;AAC5C,OAAK,aAAa,cAAc,EAAE,UAAU,UAAU;EAEtD,MAAM,aAAa,KAAK,oBAAoB,WAAW,UAAU;AACjE,MAAI,WAAW,WAAW,WAAW,SAAS;GAC5C,MAAM,UAAU,UAAU,SAAS,MAAM,GAAG,UAAU,MAAM,GAAG,IAAI,CAAC,KAAK;AACzE,OAAI,KACF;IAAE,MAAM,EAAE;IAAU,SAAS,WAAW,QAAQ;IAAM,cAAc;IAAS,EAC7E,+BAA+B,WAAW,QAAQ,KAAK,KAAK,EAAE,SAAS,KAAK,UAC7E;;GAEH;AACF,KAAI,GAAG,kBAAkB;AACvB,OAAK,aAAa,OAAO;GACzB;;AAGJ,SAAS,0BAA0B,KAAsB,sBAAkD;AACzG,KAAI,GAAG,uBAAuB,OAAO,YAAY;EAC/C,MAAM,IAAI;EACV,MAAM,OAAO,EAAE,UAAU,aAAa,IAAI;EAC1C,MAAM,OAAQ,EAAyB;AAEvC,MAAI,SAAS,gBAAgB;AAC3B,wBAAqB,mBAAmB,EAAE,UAAU,MAAM;IACxD,SAAS,EAAE;IACX,QAAQ,EAAE;IACX,EAAE,QAAQ,WAAW;AACtB;;AAGF,MAAI,CAAC,EAAE,SAAS;GACd,MAAM,eAAe,4BAA4B,EAAE,UAAU,MAAM,EAAE,OAAO;AAC5E,QAAK,MAAM,QAAQ,aACjB,sBAAqB,WACnB,MACA,KAAK,SAAS,QAAQ,GAAG,UAAU,QACnC,QAAQ,WACT;AAEH,OAAI,aAAa,SAAS,GAAG;AAC3B,MAAE,SAAS,uBACT,EAAE,QACF,qBAAqB,wBAAwB,QAAQ,WAAW,CACjE;AACD;;AAEF,wBAAqB,mBAAmB,EAAE,UAAU,MAAM;IACxD,SAAS,EAAE;IACX,QAAQ,EAAE;IACX,EAAE,QAAQ,WAAW;;GAExB;AACF,KAAI,GAAG,eAAe,QAAQ,YAAY;AACxC,uBAAqB,YAAY,QAAQ,WAAW;GACpD;;;;;;;;AAuBJ,IAAa,oBAAb,MAA+B;CAC7B;CAEA,YAAY,QAAiC;AAC3C,OAAK,MAAM,IAAI,iBAAiB;AAKhC,0BAAwB,KAAK,KAAK,OAAO,gBAAgB;AACzD,8BAA4B,KAAK,KAAK;GACpC,gBAAgB,OAAO;GACvB,iBAAiB,OAAO;GACxB,kBAAkB,OAAO;GAC1B,CAAC;AACF,+BAA6B,KAAK,KAAK,OAAO,iBAAiB;AAC/D,gCAA8B,KAAK,KAAK,OAAO,eAAe;AAC9D,4BAA0B,KAAK,KAAK,OAAO,qBAAqB;AAChE,2BAAyB,KAAK,KAAK,OAAO,kBAAkB;AAC5D,2BAAyB,KAAK,KAAK,OAAO,iBAAiB;AAC3D,+BAA6B,KAAK,KAAK;GACrC,cAAc,OAAO;GACrB,qBAAqB,OAAO;GAC7B,CAAC;;;CAIJ,OAAO,OAAmB,SAAsC;AAC9D,OAAK,IAAI,SAAS,OAAO,QAAQ;;;;;;;;CASnC,iBAAiB,MAA8B,UAA4C;AACzF,SAAO,KAAK,IAAI,GAAG,MAAM,SAAS"}
|
|
1
|
+
{"version":3,"file":"agent-event-handler.js","names":[],"sources":["../../../../src/agent/orchestration/agent-event-handler.ts"],"sourcesContent":["/**\n * Agent Event Handler — coordinates listeners on pi-agent events.\n *\n * Previously a single god-handler with ten manager fields and one `switch`. Now a\n * thin façade around {@link SessionEventBus}: each concern (progress, lifecycle\n * hooks, tool-chain recording, error tracking, self-verify, etc.) registers its\n * own listener at construction time, and external code can add new listeners via\n * {@link AgentEventHandler.registerListener} without modifying this file (OCP).\n *\n * Ordering note: a few listeners are order-sensitive (notably the\n * `tool_execution_end` chain — `SystemReminder` mutates `event.result` in place\n * and downstream listeners read the mutated value). The `installX` calls below\n * preserve the exact order from the previous implementation.\n */\n\nimport type { AgentEvent } from '@earendil-works/pi-agent-core';\nimport type { SessionContext } from '../session/session-context.js';\nimport type { ProgressFeedbackManager } from '../lifecycle/progress.js';\nimport type { ToolErrorTracker } from '../tools/error-tracker.js';\nimport type { RequestLimiter } from '../models/request-limiter.js';\nimport type { LifecycleManager } from '../lifecycle/index.js';\nimport type { ToolChainTracker } from '../tools/chain-tracker.js';\nimport type { SelfVerifyMiddleware } from '../middleware/index.js';\nimport type { SystemReminder } from '../prompt/system-reminder.js';\nimport type { ToolUsageAnalyzer } from '../tools/usage-analyzer.js';\nimport type { ErrorPatternMatcher } from '../tools/error-pattern-matcher.js';\nimport type { TurnDiffTracker } from '../coding/index.js';\nimport { extractTextContent } from '../context/workspace.js';\nimport { createLogger } from '../../utils/logger.js';\n\nconst log = createLogger('AgentEventHandler');\n\n// ── Event bus ──────────────────────────────────────────────────────────────\n\nexport type SessionEventListener = (event: AgentEvent, context: SessionContext) => void;\nexport type SessionEventTypeFilter = AgentEvent['type'] | 'all';\n\n/**\n * Typed pub/sub for agent events. Listeners run in registration order; the bus\n * itself is synchronous — listeners that need async work must dispatch their own\n * promises (typically by awaiting and logging on error, like the lifecycle hooks).\n */\nexport class SessionEventBus {\n private readonly listeners = new Map<SessionEventTypeFilter, SessionEventListener[]>();\n\n on(type: SessionEventTypeFilter, listener: SessionEventListener): () => void {\n const bucket = this.listeners.get(type) ?? [];\n bucket.push(listener);\n this.listeners.set(type, bucket);\n return () => {\n const current = this.listeners.get(type);\n if (!current) return;\n const idx = current.indexOf(listener);\n if (idx >= 0) current.splice(idx, 1);\n };\n }\n\n dispatch(event: AgentEvent, context: SessionContext | null): void {\n if (!context) {\n if (event.type !== 'message_update') {\n log.warn(\n { eventType: event.type },\n `Agent event ignored (no SessionContext): ${event.type}`,\n );\n }\n return;\n }\n const exact = this.listeners.get(event.type);\n if (exact) {\n for (const listener of exact) {\n listener(event, context);\n }\n }\n const all = this.listeners.get('all');\n if (all) {\n for (const listener of all) {\n listener(event, context);\n }\n }\n }\n}\n\n// ── Built-in listener installers ───────────────────────────────────────────\n\nfunction installProgressListener(bus: SessionEventBus, progressManager: ProgressFeedbackManager): void {\n bus.on('agent_start', () => {\n log.debug('Agent turn started');\n progressManager.startTask();\n });\n bus.on('turn_start', () => {\n log.debug('Turn started');\n progressManager.onTurnStart();\n });\n bus.on('tool_execution_start', (event) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_start' }>;\n log.debug({ tool: e.toolName, args: e.args }, 'Tool execution started');\n progressManager.onToolStart(e.toolName, e.args || {});\n });\n bus.on('tool_execution_update', (event) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_update' }>;\n progressManager.onToolUpdate(e.toolName, e.partialResult);\n });\n bus.on('tool_execution_end', (event) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }>;\n log.debug({ tool: e.toolName, isError: e.isError }, 'Tool execution complete');\n progressManager.onToolEnd(e.toolName, e.result, e.isError);\n });\n bus.on('agent_end', () => {\n progressManager.endTask();\n });\n}\n\nfunction installRequestLimitListener(\n bus: SessionEventBus,\n deps: {\n requestLimiter: RequestLimiter;\n progressManager: ProgressFeedbackManager;\n lifecycleManager: LifecycleManager;\n },\n): void {\n bus.on('agent_start', (_event, context) => {\n const result = deps.requestLimiter.recordRequest();\n\n deps.lifecycleManager\n .emit(\n 'llm_request',\n context.sessionKey,\n { requestNumber: result.count, maxRequests: result.limit },\n context,\n )\n .catch((err) => {\n const em = err instanceof Error ? err.message : String(err);\n log.warn(\n {\n err,\n errorMessage: em,\n sessionKey: context.sessionKey,\n requestNumber: result.count,\n maxRequests: result.limit,\n },\n `Lifecycle emit llm_request failed: ${em}`,\n );\n });\n\n deps.progressManager.onRequestLimitStatus(\n result.count,\n result.limit,\n result.remaining,\n result.isWarning,\n result.shouldStop,\n );\n\n if (result.shouldStop) {\n log.error(\n { count: result.count, limit: result.limit, sessionKey: context.sessionKey },\n `Request limit reached (${result.count}/${result.limit}) for session`,\n );\n }\n });\n\n bus.on('turn_end', () => {\n deps.requestLimiter.reset();\n });\n}\n\nfunction installLifecycleHookListener(bus: SessionEventBus, lifecycleManager: LifecycleManager): void {\n bus.on('message_end', (event, context) => {\n const e = event as Extract<AgentEvent, { type: 'message_end' }>;\n if (e.message?.role !== 'assistant') return;\n const content = e.message.content;\n const text = Array.isArray(content)\n ? extractTextContent(content as Array<{ type: string; text?: string }>)\n : String(content);\n log.debug({ contentLength: text.length }, 'Assistant response complete');\n\n lifecycleManager\n .emit(\n 'llm_response',\n context.sessionKey,\n { response: text, usage: (e.message as { usage?: unknown }).usage },\n context,\n )\n .catch((err) => {\n const em = err instanceof Error ? err.message : String(err);\n log.warn(\n { err, errorMessage: em, sessionKey: context.sessionKey, responseChars: text.length },\n `Lifecycle emit llm_response failed: ${em}`,\n );\n });\n });\n\n bus.on('tool_execution_start', (event, context) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_start' }>;\n lifecycleManager\n .emit(\n 'tool_call_start',\n context.sessionKey,\n {\n toolName: e.toolName,\n arguments: e.args || {},\n attemptNumber: 1,\n maxAttempts: 3,\n },\n context,\n )\n .catch((err) => {\n const em = err instanceof Error ? err.message : String(err);\n log.warn(\n { err, errorMessage: em, sessionKey: context.sessionKey, tool: e.toolName },\n `Lifecycle emit tool_call_start failed: ${em}`,\n );\n });\n });\n\n bus.on('tool_execution_end', (event, context) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }>;\n const durationMs = (e as { durationMs?: number }).durationMs || 0;\n lifecycleManager\n .emit(\n 'tool_call_end',\n context.sessionKey,\n {\n toolName: e.toolName,\n success: !e.isError,\n result: e.result,\n error: e.isError ? String(e.result) : undefined,\n durationMs,\n },\n context,\n )\n .catch((err) => {\n const em = err instanceof Error ? err.message : String(err);\n log.warn(\n { err, errorMessage: em, sessionKey: context.sessionKey, tool: e.toolName },\n `Lifecycle hook tool_call_end failed: ${em}`,\n );\n });\n });\n}\n\nfunction installSystemReminderListener(bus: SessionEventBus, systemReminder: SystemReminder): void {\n // MUTATES `event.result` so downstream listeners (tool-chain, error-tracking) see\n // the decorated text. Must run AFTER progress + lifecycle hooks (they consume the\n // original) and BEFORE tool-chain + error-tracking.\n bus.on('tool_execution_end', (event) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }> & { result: unknown };\n e.result = systemReminder.appendToResult(e.result, e.toolName);\n });\n}\n\nfunction appendTextToToolResult(result: unknown, text: string): unknown {\n if (!text.trim()) {\n return result;\n }\n if (result && typeof result === 'object') {\n const res = result as Record<string, unknown>;\n if (Array.isArray(res.content)) {\n res.content = [\n ...res.content,\n { type: 'text', text: `\\n${text}` },\n ];\n return res;\n }\n if (typeof res.content === 'string') {\n res.content = `${res.content}\\n${text}`;\n return res;\n }\n }\n return result;\n}\n\nfunction readRecord(value: unknown): Record<string, unknown> | null {\n return value && typeof value === 'object' ? (value as Record<string, unknown>) : null;\n}\n\nfunction readToolResultDetails(result: unknown): Record<string, unknown> | null {\n const rec = readRecord(result);\n if (!rec) return null;\n return readRecord(rec.details);\n}\n\nfunction readStringArray(value: unknown): string[] {\n return Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : [];\n}\n\nfunction readChangedPathsFromToolEnd(toolName: string, args: unknown, result: unknown): string[] {\n const name = toolName.toLowerCase();\n const details = readToolResultDetails(result);\n\n if (name === 'apply_patch') {\n const files = readStringArray(details?.files);\n if (files.length > 0) return files;\n\n const changes = Array.isArray(details?.changes) ? details.changes : [];\n return changes.flatMap((change) => {\n const rec = readRecord(change);\n if (!rec) return [];\n return readStringArray([rec.moveTo, rec.path]);\n });\n }\n\n if (name === 'write_file') {\n if (typeof details?.size !== 'number') return [];\n const rec = readRecord(args);\n return typeof rec?.path === 'string' ? [rec.path] : [];\n }\n\n if (name.includes('write') || name.includes('edit')) {\n const rec = readRecord(args);\n return typeof rec?.path === 'string' ? [rec.path] : [];\n }\n\n return [];\n}\n\nfunction installToolChainListener(bus: SessionEventBus, toolChainTracker: ToolChainTracker): void {\n bus.on('turn_start', (_event, context) => {\n // One chain per LLM turn (pi-agent emits turn_start each round; turn_end clears the chain).\n toolChainTracker.startChain(context.sessionKey);\n });\n bus.on('tool_execution_start', (event, context) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_start' }>;\n toolChainTracker.recordCall(context.sessionKey, e.toolName, e.args || {}, 0);\n });\n bus.on('tool_execution_end', (event, context) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }>;\n const durationMs = (e as { durationMs?: number }).durationMs || 0;\n const chain = toolChainTracker.getCurrentChain(context.sessionKey);\n if (!chain) return;\n const lastNode = chain.nodes[chain.nodes.length - 1];\n if (lastNode && lastNode.toolName === e.toolName) {\n toolChainTracker.recordResult(\n context.sessionKey,\n lastNode.id,\n e.result,\n e.isError ? 'Tool execution failed' : undefined,\n durationMs,\n );\n }\n });\n bus.on('turn_end', (_event, context) => {\n toolChainTracker.endChain(context.sessionKey);\n });\n}\n\nfunction installToolUsageListener(bus: SessionEventBus, toolUsageAnalyzer: ToolUsageAnalyzer): void {\n bus.on('tool_execution_end', (event) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }>;\n const durationMs = (e as { durationMs?: number }).durationMs || 0;\n toolUsageAnalyzer.recordUsage(e.toolName, !e.isError, durationMs);\n });\n}\n\nfunction extractErrorText(result: unknown): string {\n if (typeof result === 'string') return result;\n if (result && typeof result === 'object') {\n const obj = result as Record<string, unknown>;\n if (typeof obj.error === 'string') return obj.error;\n if (typeof obj.message === 'string') return obj.message;\n return JSON.stringify(result);\n }\n return String(result);\n}\n\nfunction installErrorTrackingListener(\n bus: SessionEventBus,\n deps: { errorTracker: ToolErrorTracker; errorPatternMatcher: ErrorPatternMatcher },\n): void {\n bus.on('tool_execution_end', (event) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }>;\n if (!e.isError) return;\n const errorText = extractErrorText(e.result);\n deps.errorTracker.recordFailure(e.toolName, errorText);\n\n const errorMatch = deps.errorPatternMatcher.matchError(errorText);\n if (errorMatch.matched && errorMatch.pattern) {\n const preview = errorText.length > 120 ? `${errorText.slice(0, 120)}…` : errorText;\n log.warn(\n { tool: e.toolName, pattern: errorMatch.pattern.name, errorPreview: preview },\n `Tool error matched pattern \"${errorMatch.pattern.name}\" (${e.toolName}): ${preview}`,\n );\n }\n });\n bus.on('turn_end', () => {\n deps.errorTracker.reset();\n });\n}\n\nfunction installSelfVerifyListener(bus: SessionEventBus, selfVerifyMiddleware: SelfVerifyMiddleware): void {\n bus.on('tool_execution_end', (event, context) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }> & { result: unknown };\n const name = e.toolName?.toLowerCase() ?? '';\n const args = (e as { args?: unknown }).args;\n\n if (name === 'exec_command') {\n selfVerifyMiddleware.recordVerification(e.toolName, args, {\n isError: e.isError,\n result: e.result,\n }, context.sessionKey);\n return;\n }\n\n if (!e.isError) {\n const changedPaths = readChangedPathsFromToolEnd(e.toolName, args, e.result);\n for (const path of changedPaths) {\n selfVerifyMiddleware.recordEdit(\n path,\n name.includes('write') ? 'write' : 'edit',\n context.sessionKey,\n );\n }\n if (changedPaths.length > 0) {\n e.result = appendTextToToolResult(\n e.result,\n selfVerifyMiddleware.consumePostEditReminder(context.sessionKey),\n );\n return;\n }\n selfVerifyMiddleware.recordVerification(e.toolName, args, {\n isError: e.isError,\n result: e.result,\n }, context.sessionKey);\n }\n });\n bus.on('turn_start', (_event, context) => {\n selfVerifyMiddleware.onTurnStart(context.sessionKey);\n });\n}\n\nfunction installTurnDiffTrackerListener(bus: SessionEventBus, turnDiffTracker: TurnDiffTracker): void {\n bus.on('tool_execution_end', (event, context) => {\n const e = event as Extract<AgentEvent, { type: 'tool_execution_end' }> & {\n args?: unknown;\n result: unknown;\n };\n turnDiffTracker.recordToolResult({\n sessionKey: context.sessionKey,\n toolName: e.toolName,\n args: e.args,\n result: e.result,\n isError: e.isError,\n });\n });\n}\n\n// ── Public façade ───────────────────────────────────────────────────────────\n\nexport interface AgentEventHandlerConfig {\n progressManager: ProgressFeedbackManager;\n errorTracker: ToolErrorTracker;\n requestLimiter: RequestLimiter;\n lifecycleManager: LifecycleManager;\n toolChainTracker: ToolChainTracker;\n selfVerifyMiddleware: SelfVerifyMiddleware;\n systemReminder: SystemReminder;\n toolUsageAnalyzer: ToolUsageAnalyzer;\n errorPatternMatcher: ErrorPatternMatcher;\n turnDiffTracker?: TurnDiffTracker;\n}\n\n/**\n * Thin façade over {@link SessionEventBus} that pre-registers all built-in\n * listeners in their required order. `handle(event, ctx)` is the entry point\n * used by `AgentService.handleSessionEvent`; extensions can hook in via\n * {@link registerListener} without touching this class.\n */\nexport class AgentEventHandler {\n private readonly bus: SessionEventBus;\n\n constructor(config: AgentEventHandlerConfig) {\n this.bus = new SessionEventBus();\n\n // Order matters for `tool_execution_end`: SystemReminder mutates `event.result`\n // and ToolChain + ErrorTracking depend on the mutated value. Keep these in this\n // exact sequence.\n installProgressListener(this.bus, config.progressManager);\n installRequestLimitListener(this.bus, {\n requestLimiter: config.requestLimiter,\n progressManager: config.progressManager,\n lifecycleManager: config.lifecycleManager,\n });\n installLifecycleHookListener(this.bus, config.lifecycleManager);\n installSystemReminderListener(this.bus, config.systemReminder);\n if (config.turnDiffTracker) {\n installTurnDiffTrackerListener(this.bus, config.turnDiffTracker);\n }\n installSelfVerifyListener(this.bus, config.selfVerifyMiddleware);\n installToolUsageListener(this.bus, config.toolUsageAnalyzer);\n installToolChainListener(this.bus, config.toolChainTracker);\n installErrorTrackingListener(this.bus, {\n errorTracker: config.errorTracker,\n errorPatternMatcher: config.errorPatternMatcher,\n });\n }\n\n /** Dispatch a pi-agent event to all registered listeners. */\n handle(event: AgentEvent, context: SessionContext | null): void {\n this.bus.dispatch(event, context);\n }\n\n /**\n * Register an additional listener (e.g. from an extension). Returns an\n * unsubscribe function. Listeners run after the built-ins in registration\n * order; if you need to run before a built-in, you must create your own\n * {@link SessionEventBus} instance.\n */\n registerListener(type: SessionEventTypeFilter, listener: SessionEventListener): () => void {\n return this.bus.on(type, listener);\n }\n}\n"],"mappings":"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"}
|