@xopcai/xopc 0.0.118 → 0.0.120
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 +2 -1
- package/README.zh-CN.md +2 -1
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-dzUrQoeZ.js → agent-avatar-dicebear-APTlX9Sq.js} +1 -1
- package/dist/gateway/static/root/assets/agents-CFW_FS_V.js +2 -0
- package/dist/gateway/static/root/assets/app-management-settings-panel-DTKc5HHT.js +1 -0
- package/dist/gateway/static/root/assets/appearance-settings-BTciFrE9.js +1 -0
- package/dist/gateway/static/root/assets/{apps-page--wMEL00f.js → apps-page-DT52OrbM.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-Cki4SfU2.js → archive-plugin-CiHaUMII.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-D-KnS2Do.js → attachment-load-t4gSrNjL.js} +1 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-CtysjSoQ.js +1 -0
- package/dist/gateway/static/root/assets/automations-page-B2YvT3ES.js +1 -0
- package/dist/gateway/static/root/assets/{binary-plugins-D2sgvJja.js → binary-plugins-BAbSldW5.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-DIq-4Gvb.js → block-editor-BNr_82xl.js} +28 -28
- package/dist/gateway/static/root/assets/browser-settings-page-BQEXPhDU.js +8 -0
- package/dist/gateway/static/root/assets/capability-presets-api-tzD702Gg.js +1 -0
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-AGhTueAc.js +1 -0
- package/dist/gateway/static/root/assets/channel-recipient-api-DL_KzwGE.js +1 -0
- package/dist/gateway/static/root/assets/channels-settings-DRTutLlN.js +1 -0
- package/dist/gateway/static/root/assets/cn-BQ_8x0bT.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-DneJVuge.js +2 -0
- package/dist/gateway/static/root/assets/cron-expression-B3B1eqnr.js +2 -0
- package/dist/gateway/static/root/assets/dreaming-settings-BEwWA1yf.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-DYu1KaFQ.js → extension-debug-page-Dl2kO0Sf.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-B3W6QwlZ.js → extension-page-DmbLPsx_.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-D7VQ-cxE.js → extension-settings-page-BS2rx40e.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-B7xDPu-R.js → fetch-B3ME5Eri.js} +1 -1
- package/dist/gateway/static/root/assets/format-cron-label-arqgGlVV.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-config-api-BTBLSeUu.js → gateway-config-api-DI9_BBTo.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-DAFI_T0W.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-CYj9FWCp.js → gateway-startup-retry-CSZQTz6K.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-DLuz4jC9.js +1 -0
- package/dist/gateway/static/root/assets/{goals-config-api-CQQgzPr3.js → goals-config-api-Bhzqrp2w.js} +1 -1
- package/dist/gateway/static/root/assets/{goals-page-BHitvJAv.js → goals-page-DTAfv9Ft.js} +2 -2
- package/dist/gateway/static/root/assets/goals-settings-CWN2iirQ.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-CkkkHvOi.js +1 -0
- package/dist/gateway/static/root/assets/index-CnjzMw5i.js +191 -0
- package/dist/gateway/static/root/assets/index-E1QinYKp.css +1 -0
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-kMp08SlX.js +1 -0
- package/dist/gateway/static/root/assets/{locale-store-DjbfSsfA.js → locale-store-Ba72bFmP.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-C2Uqvae9.js → logs-page-CDXDlS_W.js} +2 -2
- package/dist/gateway/static/root/assets/{markdown-split-BwOFrJ2E.js → markdown-split-Bc0w40vz.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-Cnz6Q5G6.js → media-plugins-DJ_HvgIy.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CISb1HLv.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-BTwxMIgZ.js +2 -0
- package/dist/gateway/static/root/assets/note-detail-page-BBfOeB0m.js +2 -0
- package/dist/gateway/static/root/assets/{note-image-lightbox-B-Svpmza.js → note-image-lightbox-4zntqpZq.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-VocWOjoK.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-Bss4TiwP.js → preview-open-alternatives-BbA7sRd_.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CXwjuD_Q.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-BRNjdgKq.js → save-bar-controls-Dividh61.js} +1 -1
- package/dist/gateway/static/root/assets/schedule-field-pRheF2CO.js +1 -0
- package/dist/gateway/static/root/assets/{schema-form-Dub9sy8r.js → schema-form-D6PiPxfr.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-CpcVySQK.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BVy_TawT.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-BeFLavGi.js → settings-collapsible-section-BMCOfuE_.js} +1 -1
- package/dist/gateway/static/root/assets/settings-form-section-DBkGwpIN.js +1 -0
- package/dist/gateway/static/root/assets/settings-page-CZpNyCWn.js +1 -0
- package/dist/gateway/static/root/assets/settings-page-layout-NxoW5Y57.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-MVHLLu_a.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-C8glrdqe.js → share-preview-page-B0suFCfj.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-C6DBbQGo.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-6hJmhwSn.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-Im1MA0Iw.js +2 -0
- package/dist/gateway/static/root/assets/system-settings-panel-CrmEnyX4.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-CD2wtgZV.js → theme-store-Bt6vAkSB.js} +1 -1
- package/dist/gateway/static/root/assets/typed-models-lib-BAsGn25g.js +1 -0
- package/dist/gateway/static/root/assets/{use-channel-catalog-DqlWTsDb.js → use-channel-catalog-C7vcAoGb.js} +1 -1
- package/dist/gateway/static/root/assets/user-profile-settings-panel-QAQWGelF.js +1 -0
- package/dist/gateway/static/root/assets/utils-Dl9efgnV.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-C73IVZeC.js → voice-api-key-field-D-6XueTv.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-player-store-C_ArLJPM.js → voice-player-store-CMC5NOJp.js} +1 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-DVPllR4k.js +3 -0
- package/dist/gateway/static/root/assets/workflows-page-B94WISTW.js +18 -0
- package/dist/gateway/static/root/index.html +8 -9
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +4 -5
- package/dist/src/agent/agent-manager.js +4 -8
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/context/workspace-templates/AGENTS.md +3 -2
- package/dist/src/agent/embedded/run-for-session.js +102 -14
- package/dist/src/agent/embedded/run-for-session.js.map +1 -1
- package/dist/src/agent/fallback/candidates.d.ts +0 -8
- package/dist/src/agent/fallback/candidates.js.map +1 -1
- package/dist/src/agent/index.js +1 -1
- package/dist/src/agent/lifecycle/handlers/compaction.d.ts +1 -3
- package/dist/src/agent/lifecycle/handlers/compaction.js +1 -16
- package/dist/src/agent/lifecycle/handlers/compaction.js.map +1 -1
- package/dist/src/agent/lifecycle/progress.d.ts +0 -1
- package/dist/src/agent/lifecycle/progress.js +1 -6
- package/dist/src/agent/lifecycle/progress.js.map +1 -1
- package/dist/src/agent/lifecycle/timeout-wrapper.d.ts +1 -2
- package/dist/src/agent/lifecycle/timeout-wrapper.js +1 -7
- package/dist/src/agent/lifecycle/timeout-wrapper.js.map +1 -1
- package/dist/src/agent/memory/builtin-memory-store.d.ts +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
- package/dist/src/agent/memory/builtin-provider.d.ts +2 -2
- package/dist/src/agent/memory/builtin-provider.js +2 -2
- package/dist/src/agent/memory/builtin-provider.js.map +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.d.ts +0 -7
- package/dist/src/agent/memory/dreaming/light-sweep.js +16 -277
- package/dist/src/agent/memory/dreaming/light-sweep.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 +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js.map +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.d.ts +3 -3
- package/dist/src/agent/memory/dreaming/short-term-store.js +5 -5
- package/dist/src/agent/memory/dreaming/short-term-store.js.map +1 -1
- package/dist/src/agent/memory/dreaming/utils.d.ts +2 -2
- package/dist/src/agent/memory/dreaming/utils.js +2 -2
- package/dist/src/agent/memory/dreaming/utils.js.map +1 -1
- package/dist/src/agent/memory/index.d.ts +0 -2
- package/dist/src/agent/memory/index.js +1 -2
- package/dist/src/agent/middleware/self-verify.d.ts +0 -1
- package/dist/src/agent/middleware/self-verify.js +0 -2
- package/dist/src/agent/middleware/self-verify.js.map +1 -1
- package/dist/src/agent/models/index.d.ts +1 -1
- package/dist/src/agent/models/manager.d.ts +4 -20
- package/dist/src/agent/models/manager.js +9 -126
- package/dist/src/agent/models/manager.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.d.ts +0 -4
- package/dist/src/agent/orchestration/agent-orchestrator.js +1 -9
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/prompt/sections/memory-skills.js +11 -10
- package/dist/src/agent/prompt/sections/memory-skills.js.map +1 -1
- package/dist/src/agent/prompt/sections/tooling.js +4 -4
- package/dist/src/agent/prompt/sections/tooling.js.map +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.d.ts +0 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +0 -12
- package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
- package/dist/src/agent/prompt/subagent-context.js +1 -1
- package/dist/src/agent/prompt/subagent-context.js.map +1 -1
- package/dist/src/agent/prompt/types.d.ts +1 -1
- package/dist/src/agent/reply/startup-context.js +6 -105
- package/dist/src/agent/reply/startup-context.js.map +1 -1
- package/dist/src/agent/service.d.ts +1 -12
- package/dist/src/agent/service.js +3 -81
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +2 -2
- package/dist/src/agent/session/session-config-service.d.ts +11 -11
- package/dist/src/agent/session/session-config-service.js +14 -14
- package/dist/src/agent/session/session-config-service.js.map +1 -1
- package/dist/src/agent/session/session-inspector.js +3 -2
- package/dist/src/agent/session/session-inspector.js.map +1 -1
- package/dist/src/agent/starter-agents.js +12 -12
- package/dist/src/agent/starter-agents.js.map +1 -1
- package/dist/src/agent/tools/automation-tool.d.ts +14 -0
- package/dist/src/agent/tools/automation-tool.js +102 -0
- package/dist/src/agent/tools/automation-tool.js.map +1 -0
- package/dist/src/agent/tools/delegate-tool.js +1 -1
- package/dist/src/agent/tools/delegate-tool.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +3 -3
- package/dist/src/agent/tools/factory.js +2 -2
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +1 -1
- package/dist/src/agent/tools/index.js +2 -2
- 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-manifest/resolver.d.ts +1 -0
- package/dist/src/agent-manifest/resolver.js +1 -0
- package/dist/src/agent-manifest/resolver.js.map +1 -1
- package/dist/src/agent-manifest/schema.d.ts +6 -0
- package/dist/src/agent-manifest/schema.js +12 -3
- package/dist/src/agent-manifest/schema.js.map +1 -1
- package/dist/src/ai-assist/text-assist.d.ts +1 -1
- package/dist/src/ai-assist/text-assist.js +56 -0
- package/dist/src/ai-assist/text-assist.js.map +1 -1
- package/dist/src/auth/profiles/store.js.map +1 -1
- package/dist/src/automations/api/routes.d.ts +3 -0
- package/dist/src/automations/api/routes.js +193 -0
- package/dist/src/automations/api/routes.js.map +1 -0
- package/dist/src/automations/domain/index.d.ts +3 -0
- package/dist/src/automations/domain/index.js +3 -0
- package/dist/src/automations/domain/schedule.d.ts +4 -0
- package/dist/src/automations/domain/schedule.js +37 -0
- package/dist/src/automations/domain/schedule.js.map +1 -0
- package/dist/src/automations/domain/types.d.ts +160 -0
- package/dist/src/automations/domain/validation.d.ts +370 -0
- package/dist/src/automations/domain/validation.js +149 -0
- package/dist/src/automations/domain/validation.js.map +1 -0
- package/dist/src/automations/draft/automation-draft-prompt.d.ts +26 -0
- package/dist/src/automations/draft/automation-draft-prompt.js +127 -0
- package/dist/src/automations/draft/automation-draft-prompt.js.map +1 -0
- package/dist/src/automations/draft/automation-draft-service.d.ts +12 -0
- package/dist/src/automations/draft/automation-draft-service.js +135 -0
- package/dist/src/automations/draft/automation-draft-service.js.map +1 -0
- package/dist/src/automations/draft/automation-draft-validator.d.ts +99 -0
- package/dist/src/automations/draft/automation-draft-validator.js +105 -0
- package/dist/src/automations/draft/automation-draft-validator.js.map +1 -0
- package/dist/src/automations/draft/automation-draft.types.d.ts +40 -0
- package/dist/src/automations/draft/index.d.ts +3 -0
- package/dist/src/automations/draft/index.js +3 -0
- package/dist/src/automations/index.d.ts +3 -0
- package/dist/src/automations/index.js +8 -0
- package/dist/src/automations/product-events.d.ts +5 -0
- package/dist/src/automations/product-events.js +21 -0
- package/dist/src/automations/product-events.js.map +1 -0
- package/dist/src/automations/service/action-executor.d.ts +9 -0
- package/dist/src/automations/service/action-executor.js +157 -0
- package/dist/src/automations/service/action-executor.js.map +1 -0
- package/dist/src/automations/service/automation-service.d.ts +54 -0
- package/dist/src/automations/service/automation-service.js +404 -0
- package/dist/src/automations/service/automation-service.js.map +1 -0
- package/dist/src/automations/service/index.d.ts +2 -0
- package/dist/src/automations/service/index.js +3 -0
- package/dist/src/automations/storage/automation-repository.d.ts +6 -0
- package/dist/src/automations/storage/automation-repository.js +61 -0
- package/dist/src/automations/storage/automation-repository.js.map +1 -0
- package/dist/src/automations/storage/automation-run-repository.d.ts +17 -0
- package/dist/src/automations/storage/automation-run-repository.js +130 -0
- package/dist/src/automations/storage/automation-run-repository.js.map +1 -0
- package/dist/src/automations/storage/index.d.ts +2 -0
- package/dist/src/automations/storage/index.js +3 -0
- package/dist/src/channels/plugin-types.d.ts +3 -0
- package/dist/src/chat-commands/builtins/thinking.js.map +1 -1
- package/dist/src/cli/command-catalog.js +0 -39
- package/dist/src/cli/command-catalog.js.map +1 -1
- package/dist/src/cli/command-loaders.js +0 -1
- package/dist/src/cli/command-loaders.js.map +1 -1
- package/dist/src/cli/command-manifest.js +0 -4
- package/dist/src/cli/command-manifest.js.map +1 -1
- package/dist/src/cli/commands/agents.js +7 -6
- package/dist/src/cli/commands/agents.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/{cron-health.d.ts → migrations.d.ts} +1 -1
- package/dist/src/cli/commands/doctor/checks/migrations.js +40 -0
- package/dist/src/cli/commands/doctor/checks/migrations.js.map +1 -0
- package/dist/src/cli/commands/doctor/flow.js +2 -2
- package/dist/src/cli/commands/doctor/flow.js.map +1 -1
- package/dist/src/cli/commands/gateway/call.js +2 -2
- package/dist/src/cli/commands/gateway/call.js.map +1 -1
- package/dist/src/cli/commands/gateway/run-foreground.js +4 -2
- package/dist/src/cli/commands/gateway/run-foreground.js.map +1 -1
- package/dist/src/cli/commands/init.js +27 -9
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/tui.js +24 -2
- package/dist/src/cli/commands/tui.js.map +1 -1
- package/dist/src/cli/templates.js +3 -2
- package/dist/src/cli/templates.js.map +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -0
- package/dist/src/cli/utils/init-workspace-core.js.map +1 -1
- package/dist/src/commands/agents.config.d.ts +9 -0
- package/dist/src/commands/agents.config.js +40 -2
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/agent-profile.js +4 -3
- package/dist/src/config/agent-profile.js.map +1 -1
- package/dist/src/config/agent-typed-models.js.map +1 -1
- package/dist/src/config/config-surface.d.ts +3 -0
- package/dist/src/config/index.d.ts +0 -1
- package/dist/src/config/index.js +3 -3
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/config/paths.d.ts +0 -9
- package/dist/src/config/paths.js +1 -14
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/profile.js +0 -1
- package/dist/src/config/profile.js.map +1 -1
- package/dist/src/config/rules.js +0 -5
- package/dist/src/config/rules.js.map +1 -1
- package/dist/src/config/schema.d.ts +13 -12
- package/dist/src/config/schema.js +22 -26
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/web-patch.d.ts +0 -12
- package/dist/src/config/web-patch.js +2 -29
- package/dist/src/config/web-patch.js.map +1 -1
- package/dist/src/extensions/api.d.ts +2 -0
- package/dist/src/extensions/api.js +10 -0
- package/dist/src/extensions/api.js.map +1 -1
- package/dist/src/extensions/extension-registry-impl.d.ts +4 -1
- package/dist/src/extensions/extension-registry-impl.js +8 -0
- package/dist/src/extensions/extension-registry-impl.js.map +1 -1
- package/dist/src/extensions/loader.d.ts +3 -3
- package/dist/src/extensions/loader.js +3 -3
- package/dist/src/extensions/loader.js.map +1 -1
- package/dist/src/extensions/sdk/testing.d.ts +2 -0
- package/dist/src/extensions/sdk/testing.js +7 -0
- package/dist/src/extensions/sdk/testing.js.map +1 -1
- package/dist/src/extensions/types/core.d.ts +10 -1
- package/dist/src/extensions/types/index.d.ts +1 -1
- package/dist/src/extensions/types/{phase4.d.ts → registration.d.ts} +2 -2
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/agent-builtin-tools.js +1 -1
- package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
- package/dist/src/gateway/agents-admin.d.ts +1 -0
- package/dist/src/gateway/agents-admin.js +13 -15
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/capability-presets-admin.d.ts +1 -0
- package/dist/src/gateway/capability-presets-admin.js +19 -10
- package/dist/src/gateway/capability-presets-admin.js.map +1 -1
- package/dist/src/gateway/dreaming-automation-reconciler.d.ts +11 -0
- package/dist/src/gateway/dreaming-automation-reconciler.js +105 -0
- package/dist/src/gateway/dreaming-automation-reconciler.js.map +1 -0
- package/dist/src/gateway/heartbeat/service.d.ts +0 -2
- package/dist/src/gateway/heartbeat/service.js +0 -7
- package/dist/src/gateway/heartbeat/service.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +5 -6
- package/dist/src/gateway/hono/lib/config-payload.js +2 -2
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.d.ts +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +15 -6
- package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +27 -37
- package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
- package/dist/src/gateway/hono/routes/home.d.ts +2 -2
- package/dist/src/gateway/hono/routes/home.js +34 -25
- package/dist/src/gateway/hono/routes/home.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +10 -6
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/migrations.d.ts +3 -0
- package/dist/src/gateway/hono/routes/migrations.js +35 -0
- package/dist/src/gateway/hono/routes/migrations.js.map +1 -0
- package/dist/src/gateway/hono/routes/public-gateway.js +2 -1
- package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +14 -0
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/run-loop.js +2 -0
- package/dist/src/gateway/run-loop.js.map +1 -1
- package/dist/src/gateway/security/operator-scopes.js +5 -1
- package/dist/src/gateway/security/operator-scopes.js.map +1 -1
- package/dist/src/gateway/service/config-coordinator.d.ts +4 -4
- package/dist/src/gateway/service/config-coordinator.js +14 -8
- package/dist/src/gateway/service/config-coordinator.js.map +1 -1
- package/dist/src/gateway/service/sessions-api.d.ts +2 -1
- package/dist/src/gateway/service/sessions-api.js +6 -1
- package/dist/src/gateway/service/sessions-api.js.map +1 -1
- package/dist/src/gateway/service.d.ts +7 -3
- package/dist/src/gateway/service.js +61 -27
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/goals/goal-service.js +45 -4
- package/dist/src/goals/goal-service.js.map +1 -1
- package/dist/src/migrations/config/default-capability-preset.d.ts +10 -0
- package/dist/src/migrations/config/default-capability-preset.js +135 -0
- package/dist/src/migrations/config/default-capability-preset.js.map +1 -0
- package/dist/src/migrations/index.d.ts +4 -0
- package/dist/src/migrations/index.js +4 -0
- package/dist/src/migrations/registry.d.ts +8 -0
- package/dist/src/migrations/registry.js +18 -0
- package/dist/src/migrations/registry.js.map +1 -0
- package/dist/src/migrations/runner.d.ts +17 -0
- package/dist/src/migrations/runner.js +191 -0
- package/dist/src/migrations/runner.js.map +1 -0
- package/dist/src/migrations/types.d.ts +34 -0
- package/dist/src/notes/service.js +24 -1
- package/dist/src/notes/service.js.map +1 -1
- package/dist/src/providers/model-registry.d.ts +0 -1
- package/dist/src/providers/model-registry.js +0 -3
- package/dist/src/providers/model-registry.js.map +1 -1
- package/dist/src/routing/resolve-tui-session-key.d.ts +3 -0
- package/dist/src/routing/resolve-tui-session-key.js +14 -3
- package/dist/src/routing/resolve-tui-session-key.js.map +1 -1
- package/dist/src/session/transcript-outline.d.ts +47 -0
- package/dist/src/session/transcript-outline.js +481 -0
- package/dist/src/session/transcript-outline.js.map +1 -0
- package/dist/src/storage/sqlite/index.d.ts +0 -2
- package/dist/src/storage/sqlite/index.js +1 -3
- package/dist/src/storage/sqlite/migrations/016_automations.sql +47 -0
- package/dist/src/storage/sqlite/migrations/017_automation_run_events.sql +14 -0
- package/dist/src/storage/sqlite/migrations/018_automation_safety.sql +1 -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 +3 -1
- package/dist/src/storage/sqlite/row-mappers.js.map +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/schema.sql +56 -46
- package/dist/src/tui/backends/embedded-backend.d.ts +6 -0
- package/dist/src/tui/backends/embedded-backend.js +19 -9
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +3 -0
- package/dist/src/tui/backends/gateway-sse-backend.js +14 -0
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/tui-backend.d.ts +4 -0
- package/dist/src/tui/tui-commands.d.ts +5 -0
- package/dist/src/tui/tui-commands.js +43 -0
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-transcript-tree.d.ts +1 -1
- package/dist/src/tui/tui-transcript-tree.js +17 -257
- package/dist/src/tui/tui-transcript-tree.js.map +1 -1
- package/dist/src/tui/tui-types.d.ts +2 -0
- package/dist/src/tui/tui-types.js.map +1 -1
- package/dist/src/tui/tui.js +7 -2
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/workflows/domain/index.js +1 -1
- package/dist/src/workflows/domain/run.d.ts +7 -7
- package/dist/src/workflows/domain/run.js.map +1 -1
- package/dist/src/workflows/index.js +2 -2
- package/dist/src/workflows/service/workflow-run-service.d.ts +2 -0
- package/dist/src/workflows/service/workflow-run-service.js +31 -9
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-run-service.types.d.ts +1 -1
- package/package.json +4 -2
- package/dist/gateway/static/root/assets/agents-BCxZbkOw.js +0 -2
- package/dist/gateway/static/root/assets/app-management-settings-panel-bxYJVJpx.js +0 -1
- package/dist/gateway/static/root/assets/appearance-settings-BCIykXlI.js +0 -1
- package/dist/gateway/static/root/assets/browser-settings-page-DRhKdn81.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-api-CorhiHlg.js +0 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-qFx9Jtce.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BAwAkqIA.js +0 -1
- package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-BQLcfitM.js +0 -2
- package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +0 -1
- package/dist/gateway/static/root/assets/cron-api-qGwmL-24.js +0 -1
- package/dist/gateway/static/root/assets/cron-dreaming-jobs-nCMWCf0p.js +0 -1
- package/dist/gateway/static/root/assets/cron-page-BBWMAj8-.js +0 -3
- package/dist/gateway/static/root/assets/dreaming-settings-Dw89Obml.js +0 -1
- package/dist/gateway/static/root/assets/format-cron-label-BsotZDO5.js +0 -2
- package/dist/gateway/static/root/assets/format-interval-label-BzxafKxR.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-Cmwy58rS.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-l7mu5GWX.js +0 -1
- package/dist/gateway/static/root/assets/goals-settings-CYVY4NGp.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-config-api-DriO_CN9.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-CUQTKxg7.js +0 -1
- package/dist/gateway/static/root/assets/index-C17Tsd_b.css +0 -1
- package/dist/gateway/static/root/assets/index-Cc41r16l.js +0 -191
- package/dist/gateway/static/root/assets/interval-presets-DFPCKW_W.js +0 -1
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-CcVcqstx.js +0 -1
- package/dist/gateway/static/root/assets/messages-B1iSKjiw.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-BfLfcta8.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-BjwOQBfT.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-DktdBiwB.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-rfVx96fq.js +0 -1
- package/dist/gateway/static/root/assets/schedule-field-CUCKODde.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-DbtMFuuH.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-5re5gAnP.js +0 -1
- package/dist/gateway/static/root/assets/settings-form-section-dmyaPOTG.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-D-WMyLlj.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Cl-DEJAU.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-CyPVvbLt.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-CleTH1oz.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-Ck8hdXqR.js +0 -2
- package/dist/gateway/static/root/assets/system-settings-panel-DI-LN_8G.js +0 -1
- package/dist/gateway/static/root/assets/typed-models-lib-kX9duch4.js +0 -1
- package/dist/gateway/static/root/assets/user-profile-settings-panel-B-UFPMXy.js +0 -1
- package/dist/gateway/static/root/assets/utils-Dm0hKalR.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-BtFGp2y_.js +0 -18
- package/dist/src/agent/fallback/error.d.ts +0 -22
- package/dist/src/agent/fallback/error.js +0 -32
- package/dist/src/agent/fallback/error.js.map +0 -1
- package/dist/src/agent/fallback/index.d.ts +0 -5
- package/dist/src/agent/fallback/index.js +0 -9
- package/dist/src/agent/fallback/index.js.map +0 -1
- package/dist/src/agent/memory/memory-flush.d.ts +0 -27
- package/dist/src/agent/memory/memory-flush.js +0 -124
- package/dist/src/agent/memory/memory-flush.js.map +0 -1
- package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.d.ts +0 -29
- package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js +0 -76
- package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js.map +0 -1
- package/dist/src/agent/service/reconcile-dreaming-cron.d.ts +0 -6
- package/dist/src/agent/service/reconcile-dreaming-cron.js +0 -84
- package/dist/src/agent/service/reconcile-dreaming-cron.js.map +0 -1
- package/dist/src/agent/tools/cronjob-tool.d.ts +0 -29
- package/dist/src/agent/tools/cronjob-tool.js +0 -274
- package/dist/src/agent/tools/cronjob-tool.js.map +0 -1
- package/dist/src/cli/commands/cron-cli.d.ts +0 -2
- package/dist/src/cli/commands/cron-cli.js +0 -15
- package/dist/src/cli/commands/cron-cli.js.map +0 -1
- package/dist/src/cli/commands/cron.d.ts +0 -4
- package/dist/src/cli/commands/cron.js +0 -188
- package/dist/src/cli/commands/cron.js.map +0 -1
- package/dist/src/cli/commands/doctor/checks/cron-health.js +0 -35
- package/dist/src/cli/commands/doctor/checks/cron-health.js.map +0 -1
- package/dist/src/cron/execution-types.d.ts +0 -42
- package/dist/src/cron/executor.d.ts +0 -67
- package/dist/src/cron/executor.js +0 -669
- package/dist/src/cron/executor.js.map +0 -1
- package/dist/src/cron/index.d.ts +0 -7
- package/dist/src/cron/index.js +0 -7
- package/dist/src/cron/job-content.d.ts +0 -5
- package/dist/src/cron/job-content.js +0 -15
- package/dist/src/cron/job-content.js.map +0 -1
- package/dist/src/cron/run-log-store.d.ts +0 -12
- package/dist/src/cron/run-log-store.js +0 -58
- package/dist/src/cron/run-log-store.js.map +0 -1
- package/dist/src/cron/schedule.d.ts +0 -10
- package/dist/src/cron/schedule.js +0 -85
- package/dist/src/cron/schedule.js.map +0 -1
- package/dist/src/cron/service.d.ts +0 -58
- package/dist/src/cron/service.js +0 -419
- package/dist/src/cron/service.js.map +0 -1
- package/dist/src/cron/types.d.ts +0 -183
- package/dist/src/cron/validation.d.ts +0 -500
- package/dist/src/cron/validation.js +0 -192
- package/dist/src/cron/validation.js.map +0 -1
- package/dist/src/cron/workflow-run-completion.d.ts +0 -23
- package/dist/src/cron/workflow-run-completion.js +0 -72
- package/dist/src/cron/workflow-run-completion.js.map +0 -1
- package/dist/src/extensions/types/phase4.js +0 -1
- package/dist/src/gateway/hono/routes/cron.d.ts +0 -3
- package/dist/src/gateway/hono/routes/cron.js +0 -109
- package/dist/src/gateway/hono/routes/cron.js.map +0 -1
- package/dist/src/storage/sqlite/cron-job-repository.d.ts +0 -6
- package/dist/src/storage/sqlite/cron-job-repository.js +0 -70
- package/dist/src/storage/sqlite/cron-job-repository.js.map +0 -1
- package/dist/src/storage/sqlite/cron-run-repository.d.ts +0 -5
- package/dist/src/storage/sqlite/cron-run-repository.js +0 -96
- package/dist/src/storage/sqlite/cron-run-repository.js.map +0 -1
- /package/dist/src/{cron → automations/domain}/types.js +0 -0
- /package/dist/src/{config/defaults.d.ts → automations/draft/automation-draft.types.js} +0 -0
- /package/dist/src/{config/defaults.js → extensions/types/registration.js} +0 -0
- /package/dist/src/{cron/execution-types.js → migrations/types.js} +0 -0
|
@@ -48,7 +48,6 @@ export declare class ProgressFeedbackManager {
|
|
|
48
48
|
private currentStage;
|
|
49
49
|
private currentTool;
|
|
50
50
|
private taskStartTime;
|
|
51
|
-
private lastHeartbeatTime;
|
|
52
51
|
private heartbeatTimer?;
|
|
53
52
|
private streamActive;
|
|
54
53
|
constructor(config?: Partial<ProgressFeedbackConfig>);
|
|
@@ -86,7 +86,6 @@ var ProgressFeedbackManager = class {
|
|
|
86
86
|
currentStage = "idle";
|
|
87
87
|
currentTool = null;
|
|
88
88
|
taskStartTime = 0;
|
|
89
|
-
lastHeartbeatTime = 0;
|
|
90
89
|
heartbeatTimer;
|
|
91
90
|
streamActive = false;
|
|
92
91
|
constructor(config = {}) {
|
|
@@ -103,7 +102,6 @@ var ProgressFeedbackManager = class {
|
|
|
103
102
|
}
|
|
104
103
|
startTask() {
|
|
105
104
|
this.taskStartTime = Date.now();
|
|
106
|
-
this.lastHeartbeatTime = Date.now();
|
|
107
105
|
if (this.config.heartbeatEnabled) this.startHeartbeat();
|
|
108
106
|
}
|
|
109
107
|
endTask() {
|
|
@@ -117,10 +115,7 @@ var ProgressFeedbackManager = class {
|
|
|
117
115
|
this.stopHeartbeat();
|
|
118
116
|
this.heartbeatTimer = setInterval(() => {
|
|
119
117
|
const elapsed = Date.now() - this.taskStartTime;
|
|
120
|
-
if (elapsed >= this.config.longTaskThresholdMs)
|
|
121
|
-
this.callbacks.onHeartbeat?.(elapsed, this.currentStage);
|
|
122
|
-
this.lastHeartbeatTime = Date.now();
|
|
123
|
-
}
|
|
118
|
+
if (elapsed >= this.config.longTaskThresholdMs) this.callbacks.onHeartbeat?.(elapsed, this.currentStage);
|
|
124
119
|
}, this.config.heartbeatIntervalMs);
|
|
125
120
|
}
|
|
126
121
|
stopHeartbeat() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"progress.js","names":[],"sources":["../../../../src/agent/lifecycle/progress.ts"],"sourcesContent":["/**\n * Progress Feedback Manager\n * \n * Manages real-time progress feedback for long-running agent tasks.\n * Provides:\n * - Tool/end notifications execution start\n * - Thinking indicators\n * - Progress stage updates\n * - Stream integration for real-time display\n */\n\nimport { createLogger } from '../../utils/logger.js';\n\nconst log = createLogger('ProgressFeedback');\n\n// Progress stages for different operations\nexport type ProgressStage = \n | 'thinking' // AI is thinking/reasoning\n | 'searching' // Web search\n | 'reading' // Reading files\n | 'writing' // Writing files \n | 'executing' // Running shell commands\n | 'analyzing' // Analyzing data\n | 'idle'; // No active operation\n\nexport interface ProgressUpdate {\n stage: ProgressStage;\n detail?: string;\n toolName?: string;\n toolArgs?: Record<string, unknown>;\n timestamp: number;\n}\n\nexport interface ProgressFeedbackConfig {\n // Feedback level: minimal (errors only), normal (key events), verbose (all updates)\n level: 'minimal' | 'normal' | 'verbose';\n // Whether to show thinking indicators\n showThinking: boolean;\n // Whether to stream tool progress updates\n streamToolProgress: boolean;\n // Whether to send periodic heartbeats for long tasks\n heartbeatEnabled: boolean;\n // Heartbeat interval in ms\n heartbeatIntervalMs: number;\n // Threshold for long-running task in ms\n longTaskThresholdMs: number;\n // Enhanced feedback options\n showErrorAccumulation: boolean; // Show tool error accumulation (default: true)\n showRequestLimitWarning: boolean; // Show request limit warnings (default: true)\n}\n\nconst DEFAULT_CONFIG: ProgressFeedbackConfig = {\n level: 'normal',\n showThinking: true,\n streamToolProgress: true,\n heartbeatEnabled: true,\n heartbeatIntervalMs: 20000, // 20 seconds\n longTaskThresholdMs: 30000, // 30 seconds\n showErrorAccumulation: true,\n showRequestLimitWarning: true,\n};\n\n// Tool category mapping for better feedback\nconst TOOL_STAGE_MAP: Record<string, ProgressStage> = {\n // Reading tools\n 'read': 'reading',\n 'read_file': 'reading',\n 'read_multiple': 'reading',\n 'glob': 'reading',\n 'find': 'reading',\n 'list_dir': 'reading',\n 'ls': 'reading',\n 'memory_get': 'reading',\n 'curated_memory': 'writing',\n\n // Searching tools\n 'grep': 'searching',\n 'web_search': 'searching',\n 'search': 'searching',\n 'memory_search': 'searching',\n 'session_search': 'searching',\n 'find_files': 'searching',\n \n // Web fetching\n 'web_fetch': 'reading',\n 'fetch': 'reading',\n 'curl': 'reading',\n 'wget': 'reading',\n \n // Writing tools\n 'write': 'writing',\n 'write_file': 'writing',\n 'write_multiple': 'writing',\n 'edit': 'writing',\n 'patch': 'writing',\n 'create': 'writing',\n 'mkdir': 'writing',\n 'delete': 'writing',\n 'remove': 'writing',\n \n // Executing tools\n 'bash': 'executing',\n 'shell': 'executing',\n 'exec': 'executing',\n 'run': 'executing',\n 'command': 'executing',\n 'node': 'executing',\n 'python': 'executing',\n 'npm': 'executing',\n 'pnpm': 'executing',\n 'git': 'executing',\n 'docker': 'executing',\n 'kubectl': 'executing',\n \n // Message/communication\n 'message': 'idle',\n 'send': 'idle',\n 'reply': 'idle',\n \n // Analysis tools\n 'analyze': 'analyzing',\n 'compare': 'analyzing',\n 'diff': 'analyzing',\n 'summarize': 'analyzing',\n};\n\n// Emoji mapping for stages\nconst STAGE_EMOJI: Record<ProgressStage, string> = {\n 'thinking': '🤔',\n 'searching': '🔍',\n 'reading': '📖',\n 'writing': '✍️',\n 'executing': '⚙️',\n 'analyzing': '📊',\n 'idle': '💬',\n};\n\n// Stage labels in English\nconst STAGE_LABEL: Record<ProgressStage, string> = {\n 'thinking': 'Thinking',\n 'searching': 'Searching',\n 'reading': 'Reading',\n 'writing': 'Writing',\n 'executing': 'Executing',\n 'analyzing': 'Analyzing',\n 'idle': 'Ready',\n};\n\nexport interface ProgressMessage {\n type: 'start' | 'update' | 'complete' | 'error' | 'warning' | 'thinking';\n stage: ProgressStage;\n message: string;\n detail?: string;\n toolName?: string;\n toolArgs?: Record<string, unknown>;\n}\n\nexport interface ProgressCallbacks {\n onProgress?: (msg: ProgressMessage) => void;\n onStreamStart?: (toolName: string, toolArgs: Record<string, unknown>) => void;\n onStreamUpdate?: (toolName: string, partialResult: string) => void;\n onStreamEnd?: (toolName: string, result: string, isError: boolean) => void;\n onThinking?: (thinking: string) => void;\n onHeartbeat?: (elapsedMs: number, currentStage: ProgressStage) => void;\n}\n\nexport class ProgressFeedbackManager {\n private config: ProgressFeedbackConfig;\n private callbacks: ProgressCallbacks = {};\n private currentStage: ProgressStage = 'idle';\n private currentTool: string | null = null;\n private taskStartTime: number = 0;\n private lastHeartbeatTime: number = 0;\n private heartbeatTimer?: ReturnType<typeof setInterval>;\n private streamActive: boolean = false;\n\n constructor(config: Partial<ProgressFeedbackConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n setCallbacks(callbacks: ProgressCallbacks): void {\n this.callbacks = { ...this.callbacks, ...callbacks };\n }\n\n startTask(): void {\n this.taskStartTime = Date.now();\n this.lastHeartbeatTime = Date.now();\n \n if (this.config.heartbeatEnabled) {\n this.startHeartbeat();\n }\n }\n\n endTask(): void {\n this.stopHeartbeat();\n this.currentStage = 'idle';\n this.currentTool = null;\n this.taskStartTime = 0;\n this.streamActive = false;\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n const elapsed = Date.now() - this.taskStartTime;\n if (elapsed >= this.config.longTaskThresholdMs) {\n this.callbacks.onHeartbeat?.(elapsed, this.currentStage);\n this.lastHeartbeatTime = Date.now();\n }\n }, this.config.heartbeatIntervalMs);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = undefined;\n }\n }\n\n private mapToolToStage(toolName: string): ProgressStage {\n const normalizedName = toolName.toLowerCase();\n const normalizedNoUnderscore = normalizedName.replace(/_/g, '');\n \n // Try both versions: with and without underscores\n const toCheck = [normalizedName, normalizedNoUnderscore];\n \n // Sort keys by length (longest first) to match more specific keys first\n const sortedKeys = Object.keys(TOOL_STAGE_MAP).sort((a, b) => b.length - a.length);\n \n for (const name of toCheck) {\n for (const key of sortedKeys) {\n if (name.includes(key)) {\n return TOOL_STAGE_MAP[key];\n }\n }\n }\n return 'executing';\n }\n\n private formatToolName(toolName: string): string {\n // Convert snake_case to Title Case\n return toolName\n .replace(/_/g, ' ')\n .replace(/\\b\\w/g, c => c.toUpperCase());\n }\n\n // Handle tool execution start\n onToolStart(toolName: string, toolArgs: Record<string, unknown> = {}): void {\n if (this.config.level === 'minimal') return;\n\n this.currentTool = toolName;\n this.currentStage = this.mapToolToStage(toolName);\n this.streamActive = true;\n\n const formattedName = this.formatToolName(toolName);\n const emoji = STAGE_EMOJI[this.currentStage];\n const label = STAGE_LABEL[this.currentStage];\n\n // Build detail message\n let detail = '';\n if (toolArgs.path) {\n detail = `📁 ${toolArgs.path}`;\n } else if (toolArgs.query) {\n detail = `🔎 ${toolArgs.query}`;\n } else if (toolArgs.command) {\n const cmd = String(toolArgs.command);\n detail = `⚡ ${cmd.length > 50 ? cmd.slice(0, 50) + '...' : cmd}`;\n }\n\n const message: ProgressMessage = {\n type: 'start',\n stage: this.currentStage,\n message: `${emoji} ${label}: ${formattedName}`,\n detail: detail || undefined,\n toolName,\n toolArgs,\n };\n\n if (this.config.level === 'verbose' || this.config.streamToolProgress) {\n this.callbacks.onProgress?.(message);\n }\n this.callbacks.onStreamStart?.(toolName, toolArgs);\n\n log.debug({ toolName, stage: this.currentStage }, 'Tool execution started');\n }\n\n // Handle tool execution update (streaming)\n onToolUpdate(toolName: string, partialResult: unknown): void {\n if (this.config.level === 'minimal') return;\n if (!this.streamActive || !this.config.streamToolProgress) return;\n\n // Format partial result for display\n let displayResult = '';\n if (typeof partialResult === 'string') {\n displayResult = partialResult.slice(0, 200); // Truncate for display\n } else if (partialResult && typeof partialResult === 'object') {\n const result = partialResult as Record<string, unknown>;\n if (result.output) {\n displayResult = String(result.output).slice(0, 200);\n } else if (result.content) {\n displayResult = String(result.content).slice(0, 200);\n } else if (result.text) {\n displayResult = String(result.text).slice(0, 200);\n }\n }\n\n this.callbacks.onStreamUpdate?.(toolName, displayResult);\n }\n\n // Handle tool execution end\n onToolEnd(toolName: string, result: unknown, isError: boolean = false): void {\n if (this.config.level === 'minimal' && !isError) return;\n\n const wasActive = this.streamActive;\n this.streamActive = false;\n\n // Extract result summary\n let resultSummary = '';\n if (result && typeof result === 'object') {\n const res = result as Record<string, unknown>;\n if (res.content && Array.isArray(res.content)) {\n const textContent = res.content.find((c: unknown) => \n typeof c === 'object' && c !== null && (c as Record<string, unknown>).type === 'text'\n );\n if (textContent) {\n resultSummary = String((textContent as Record<string, unknown>).text || '').slice(0, 100);\n }\n }\n }\n\n const message: ProgressMessage = {\n type: isError ? 'error' : 'complete',\n stage: this.currentStage,\n message: isError \n ? `❌ Tool failed: ${this.formatToolName(toolName)}`\n : `✅ Done: ${this.formatToolName(toolName)}`,\n toolName,\n };\n\n if (wasActive) {\n this.callbacks.onStreamEnd?.(toolName, resultSummary, isError);\n }\n \n if (isError || this.config.level !== 'minimal') {\n this.callbacks.onProgress?.(message);\n }\n\n // Reset current tool if it matches\n if (this.currentTool === toolName) {\n this.currentTool = null;\n this.currentStage = 'idle';\n }\n\n log.debug({ toolName, isError }, 'Tool execution ended');\n }\n\n // Handle thinking/reasoning\n onThinking(thinking: string): void {\n if (!this.config.showThinking || this.config.level === 'minimal') return;\n\n const displayThinking = thinking.length > 100 \n ? thinking.slice(0, 100) + '...'\n : thinking;\n\n this.callbacks.onThinking?.(displayThinking);\n }\n\n // Handle turn start\n onTurnStart(): void {\n if (this.config.level === 'minimal') return;\n \n this.currentStage = 'thinking';\n this.taskStartTime = Date.now();\n \n if (this.config.heartbeatEnabled && !this.heartbeatTimer) {\n this.startHeartbeat();\n }\n }\n\n // Handle message/response start\n onMessageStart(): void {\n // Could be used to show \"AI is typing...\" indicator\n }\n\n // Handle message/response update (streaming tokens)\n onMessageUpdate(_content: string): void {\n // Could be used to show live response\n }\n\n // Handle agent end\n onAgentEnd(): void {\n this.endTask();\n }\n\n // Get current state\n getCurrentState(): { stage: ProgressStage; tool: string | null; elapsedMs: number } {\n return {\n stage: this.currentStage,\n tool: this.currentTool,\n elapsedMs: this.taskStartTime ? Date.now() - this.taskStartTime : 0,\n };\n }\n\n // Update config\n setConfig(config: Partial<ProgressFeedbackConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n // Get stage emoji\n getStageEmoji(stage: ProgressStage): string {\n return STAGE_EMOJI[stage] || '💬';\n }\n\n // Get stage label\n getStageLabel(stage: ProgressStage): string {\n return STAGE_LABEL[stage] || 'Unknown';\n }\n\n /**\n * Notify about accumulated tool errors\n * Enhanced feedback for tool failures\n */\n onToolErrorAccumulated(\n toolName: string,\n failureCount: number,\n maxFailures: number,\n remainingAttempts?: number\n ): void {\n if (!this.config.showErrorAccumulation) return;\n if (this.config.level === 'minimal') return;\n\n const remaining = remainingAttempts ?? (maxFailures - failureCount);\n const percentage = (failureCount / maxFailures) * 100;\n \n let message: string;\n let type: 'warning' | 'error' = percentage >= 100 ? 'error' : 'warning';\n\n if (percentage >= 100) {\n message = `❌ ${this.formatToolName(toolName)} has reached maximum failures (${maxFailures}/${maxFailures})`;\n } else if (percentage >= 50) {\n message = `⚠️ ${this.formatToolName(toolName)} failed ${failureCount}/${maxFailures} times`;\n } else {\n message = `⚠️ ${this.formatToolName(toolName)} failed ${failureCount} time${failureCount > 1 ? 's' : ''}`;\n }\n\n const progressMsg: ProgressMessage = {\n type,\n stage: 'executing',\n message,\n detail: remaining > 0 \n ? `Remaining attempts: ${remaining}` \n : 'Stopping tool execution',\n toolName,\n };\n\n this.callbacks.onProgress?.(progressMsg);\n\n const atCap = maxFailures > 0 && failureCount >= maxFailures;\n const summary = atCap\n ? `Tool \"${toolName}\" reached max failures (${failureCount}/${maxFailures})`\n : `Tool \"${toolName}\" failures ${failureCount}/${maxFailures} (${remaining} attempt(s) left)`;\n if (atCap) {\n log.error({ toolName, failureCount, maxFailures, remaining }, summary);\n } else {\n log.warn({ toolName, failureCount, maxFailures, remaining }, summary);\n }\n }\n\n /**\n * Notify about request limit status\n * Enhanced feedback for approaching/ reaching request limits\n */\n onRequestLimitStatus(\n count: number,\n limit: number,\n remaining: number,\n isWarning: boolean,\n shouldStop: boolean\n ): void {\n if (!this.config.showRequestLimitWarning) return;\n if (this.config.level === 'minimal') return;\n if (!isWarning && !shouldStop) return;\n\n const percentage = (count / limit) * 100;\n \n let message: string;\n let type: 'warning' | 'error' = shouldStop ? 'error' : 'warning';\n\n if (shouldStop) {\n message = `❌ Request limit reached (${count}/${limit})`;\n } else if (percentage >= 90) {\n message = `⚠️ Request limit warning (${count}/${limit})`;\n } else {\n message = `⚠️ Approaching request limit (${count}/${limit})`;\n }\n\n const progressMsg: ProgressMessage = {\n type,\n stage: 'thinking',\n message,\n detail: remaining > 0 \n ? `Remaining requests: ${remaining}` \n : 'Stopping execution',\n };\n\n this.callbacks.onProgress?.(progressMsg);\n\n const summary = shouldStop\n ? `LLM request limit reached (${count}/${limit}); stopping turn`\n : `LLM request budget ${count}/${limit} (${remaining} left)`;\n if (shouldStop) {\n log.error({ count, limit, remaining, shouldStop }, summary);\n } else {\n log.warn({ count, limit, remaining, shouldStop }, summary);\n }\n }\n}\n\n// Singleton instance with default config\nexport const progressFeedbackManager = new ProgressFeedbackManager();\n\n// Utility function to format progress messages for Telegram\nexport function formatProgressMessage(msg: ProgressMessage, parseMode: 'Markdown' | 'HTML' = 'HTML'): string {\n const emoji = STAGE_EMOJI[msg.stage];\n \n if (parseMode === 'HTML') {\n let html = `<b>${emoji} ${msg.message}</b>`;\n if (msg.detail) {\n html += `\\n${msg.detail}`;\n }\n return html;\n } else {\n let md = `**${emoji} ${msg.message}**`;\n if (msg.detail) {\n md += `\\n${msg.detail}`;\n }\n return md;\n }\n}\n\n// Utility function to format heartbeat message\nexport function formatHeartbeatMessage(elapsedMs: number, stage: ProgressStage, detail?: string): string {\n const seconds = Math.floor(elapsedMs / 1000);\n const emoji = STAGE_EMOJI[stage];\n const label = STAGE_LABEL[stage];\n \n let message = `${emoji} Still ${label.toLowerCase()}...`;\n if (detail) {\n message += `\\n${detail}`;\n }\n message += `\\n⏱️ ${seconds}s elapsed`;\n \n return message;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"progress.js","names":[],"sources":["../../../../src/agent/lifecycle/progress.ts"],"sourcesContent":["/**\n * Progress Feedback Manager\n * \n * Manages real-time progress feedback for long-running agent tasks.\n * Provides:\n * - Tool/end notifications execution start\n * - Thinking indicators\n * - Progress stage updates\n * - Stream integration for real-time display\n */\n\nimport { createLogger } from '../../utils/logger.js';\n\nconst log = createLogger('ProgressFeedback');\n\n// Progress stages for different operations\nexport type ProgressStage = \n | 'thinking' // AI is thinking/reasoning\n | 'searching' // Web search\n | 'reading' // Reading files\n | 'writing' // Writing files \n | 'executing' // Running shell commands\n | 'analyzing' // Analyzing data\n | 'idle'; // No active operation\n\nexport interface ProgressUpdate {\n stage: ProgressStage;\n detail?: string;\n toolName?: string;\n toolArgs?: Record<string, unknown>;\n timestamp: number;\n}\n\nexport interface ProgressFeedbackConfig {\n // Feedback level: minimal (errors only), normal (key events), verbose (all updates)\n level: 'minimal' | 'normal' | 'verbose';\n // Whether to show thinking indicators\n showThinking: boolean;\n // Whether to stream tool progress updates\n streamToolProgress: boolean;\n // Whether to send periodic heartbeats for long tasks\n heartbeatEnabled: boolean;\n // Heartbeat interval in ms\n heartbeatIntervalMs: number;\n // Threshold for long-running task in ms\n longTaskThresholdMs: number;\n // Enhanced feedback options\n showErrorAccumulation: boolean; // Show tool error accumulation (default: true)\n showRequestLimitWarning: boolean; // Show request limit warnings (default: true)\n}\n\nconst DEFAULT_CONFIG: ProgressFeedbackConfig = {\n level: 'normal',\n showThinking: true,\n streamToolProgress: true,\n heartbeatEnabled: true,\n heartbeatIntervalMs: 20000, // 20 seconds\n longTaskThresholdMs: 30000, // 30 seconds\n showErrorAccumulation: true,\n showRequestLimitWarning: true,\n};\n\n// Tool category mapping for better feedback\nconst TOOL_STAGE_MAP: Record<string, ProgressStage> = {\n // Reading tools\n 'read': 'reading',\n 'read_file': 'reading',\n 'read_multiple': 'reading',\n 'glob': 'reading',\n 'find': 'reading',\n 'list_dir': 'reading',\n 'ls': 'reading',\n 'memory_get': 'reading',\n 'curated_memory': 'writing',\n\n // Searching tools\n 'grep': 'searching',\n 'web_search': 'searching',\n 'search': 'searching',\n 'memory_search': 'searching',\n 'session_search': 'searching',\n 'find_files': 'searching',\n \n // Web fetching\n 'web_fetch': 'reading',\n 'fetch': 'reading',\n 'curl': 'reading',\n 'wget': 'reading',\n \n // Writing tools\n 'write': 'writing',\n 'write_file': 'writing',\n 'write_multiple': 'writing',\n 'edit': 'writing',\n 'patch': 'writing',\n 'create': 'writing',\n 'mkdir': 'writing',\n 'delete': 'writing',\n 'remove': 'writing',\n \n // Executing tools\n 'bash': 'executing',\n 'shell': 'executing',\n 'exec': 'executing',\n 'run': 'executing',\n 'command': 'executing',\n 'node': 'executing',\n 'python': 'executing',\n 'npm': 'executing',\n 'pnpm': 'executing',\n 'git': 'executing',\n 'docker': 'executing',\n 'kubectl': 'executing',\n \n // Message/communication\n 'message': 'idle',\n 'send': 'idle',\n 'reply': 'idle',\n \n // Analysis tools\n 'analyze': 'analyzing',\n 'compare': 'analyzing',\n 'diff': 'analyzing',\n 'summarize': 'analyzing',\n};\n\n// Emoji mapping for stages\nconst STAGE_EMOJI: Record<ProgressStage, string> = {\n 'thinking': '🤔',\n 'searching': '🔍',\n 'reading': '📖',\n 'writing': '✍️',\n 'executing': '⚙️',\n 'analyzing': '📊',\n 'idle': '💬',\n};\n\n// Stage labels in English\nconst STAGE_LABEL: Record<ProgressStage, string> = {\n 'thinking': 'Thinking',\n 'searching': 'Searching',\n 'reading': 'Reading',\n 'writing': 'Writing',\n 'executing': 'Executing',\n 'analyzing': 'Analyzing',\n 'idle': 'Ready',\n};\n\nexport interface ProgressMessage {\n type: 'start' | 'update' | 'complete' | 'error' | 'warning' | 'thinking';\n stage: ProgressStage;\n message: string;\n detail?: string;\n toolName?: string;\n toolArgs?: Record<string, unknown>;\n}\n\nexport interface ProgressCallbacks {\n onProgress?: (msg: ProgressMessage) => void;\n onStreamStart?: (toolName: string, toolArgs: Record<string, unknown>) => void;\n onStreamUpdate?: (toolName: string, partialResult: string) => void;\n onStreamEnd?: (toolName: string, result: string, isError: boolean) => void;\n onThinking?: (thinking: string) => void;\n onHeartbeat?: (elapsedMs: number, currentStage: ProgressStage) => void;\n}\n\nexport class ProgressFeedbackManager {\n private config: ProgressFeedbackConfig;\n private callbacks: ProgressCallbacks = {};\n private currentStage: ProgressStage = 'idle';\n private currentTool: string | null = null;\n private taskStartTime: number = 0;\n private heartbeatTimer?: ReturnType<typeof setInterval>;\n private streamActive: boolean = false;\n\n constructor(config: Partial<ProgressFeedbackConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n setCallbacks(callbacks: ProgressCallbacks): void {\n this.callbacks = { ...this.callbacks, ...callbacks };\n }\n\n startTask(): void {\n this.taskStartTime = Date.now();\n \n if (this.config.heartbeatEnabled) {\n this.startHeartbeat();\n }\n }\n\n endTask(): void {\n this.stopHeartbeat();\n this.currentStage = 'idle';\n this.currentTool = null;\n this.taskStartTime = 0;\n this.streamActive = false;\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n const elapsed = Date.now() - this.taskStartTime;\n if (elapsed >= this.config.longTaskThresholdMs) {\n this.callbacks.onHeartbeat?.(elapsed, this.currentStage);\n }\n }, this.config.heartbeatIntervalMs);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = undefined;\n }\n }\n\n private mapToolToStage(toolName: string): ProgressStage {\n const normalizedName = toolName.toLowerCase();\n const normalizedNoUnderscore = normalizedName.replace(/_/g, '');\n \n // Try both versions: with and without underscores\n const toCheck = [normalizedName, normalizedNoUnderscore];\n \n // Sort keys by length (longest first) to match more specific keys first\n const sortedKeys = Object.keys(TOOL_STAGE_MAP).sort((a, b) => b.length - a.length);\n \n for (const name of toCheck) {\n for (const key of sortedKeys) {\n if (name.includes(key)) {\n return TOOL_STAGE_MAP[key];\n }\n }\n }\n return 'executing';\n }\n\n private formatToolName(toolName: string): string {\n // Convert snake_case to Title Case\n return toolName\n .replace(/_/g, ' ')\n .replace(/\\b\\w/g, c => c.toUpperCase());\n }\n\n // Handle tool execution start\n onToolStart(toolName: string, toolArgs: Record<string, unknown> = {}): void {\n if (this.config.level === 'minimal') return;\n\n this.currentTool = toolName;\n this.currentStage = this.mapToolToStage(toolName);\n this.streamActive = true;\n\n const formattedName = this.formatToolName(toolName);\n const emoji = STAGE_EMOJI[this.currentStage];\n const label = STAGE_LABEL[this.currentStage];\n\n // Build detail message\n let detail = '';\n if (toolArgs.path) {\n detail = `📁 ${toolArgs.path}`;\n } else if (toolArgs.query) {\n detail = `🔎 ${toolArgs.query}`;\n } else if (toolArgs.command) {\n const cmd = String(toolArgs.command);\n detail = `⚡ ${cmd.length > 50 ? cmd.slice(0, 50) + '...' : cmd}`;\n }\n\n const message: ProgressMessage = {\n type: 'start',\n stage: this.currentStage,\n message: `${emoji} ${label}: ${formattedName}`,\n detail: detail || undefined,\n toolName,\n toolArgs,\n };\n\n if (this.config.level === 'verbose' || this.config.streamToolProgress) {\n this.callbacks.onProgress?.(message);\n }\n this.callbacks.onStreamStart?.(toolName, toolArgs);\n\n log.debug({ toolName, stage: this.currentStage }, 'Tool execution started');\n }\n\n // Handle tool execution update (streaming)\n onToolUpdate(toolName: string, partialResult: unknown): void {\n if (this.config.level === 'minimal') return;\n if (!this.streamActive || !this.config.streamToolProgress) return;\n\n // Format partial result for display\n let displayResult = '';\n if (typeof partialResult === 'string') {\n displayResult = partialResult.slice(0, 200); // Truncate for display\n } else if (partialResult && typeof partialResult === 'object') {\n const result = partialResult as Record<string, unknown>;\n if (result.output) {\n displayResult = String(result.output).slice(0, 200);\n } else if (result.content) {\n displayResult = String(result.content).slice(0, 200);\n } else if (result.text) {\n displayResult = String(result.text).slice(0, 200);\n }\n }\n\n this.callbacks.onStreamUpdate?.(toolName, displayResult);\n }\n\n // Handle tool execution end\n onToolEnd(toolName: string, result: unknown, isError: boolean = false): void {\n if (this.config.level === 'minimal' && !isError) return;\n\n const wasActive = this.streamActive;\n this.streamActive = false;\n\n // Extract result summary\n let resultSummary = '';\n if (result && typeof result === 'object') {\n const res = result as Record<string, unknown>;\n if (res.content && Array.isArray(res.content)) {\n const textContent = res.content.find((c: unknown) => \n typeof c === 'object' && c !== null && (c as Record<string, unknown>).type === 'text'\n );\n if (textContent) {\n resultSummary = String((textContent as Record<string, unknown>).text || '').slice(0, 100);\n }\n }\n }\n\n const message: ProgressMessage = {\n type: isError ? 'error' : 'complete',\n stage: this.currentStage,\n message: isError \n ? `❌ Tool failed: ${this.formatToolName(toolName)}`\n : `✅ Done: ${this.formatToolName(toolName)}`,\n toolName,\n };\n\n if (wasActive) {\n this.callbacks.onStreamEnd?.(toolName, resultSummary, isError);\n }\n \n if (isError || this.config.level !== 'minimal') {\n this.callbacks.onProgress?.(message);\n }\n\n // Reset current tool if it matches\n if (this.currentTool === toolName) {\n this.currentTool = null;\n this.currentStage = 'idle';\n }\n\n log.debug({ toolName, isError }, 'Tool execution ended');\n }\n\n // Handle thinking/reasoning\n onThinking(thinking: string): void {\n if (!this.config.showThinking || this.config.level === 'minimal') return;\n\n const displayThinking = thinking.length > 100 \n ? thinking.slice(0, 100) + '...'\n : thinking;\n\n this.callbacks.onThinking?.(displayThinking);\n }\n\n // Handle turn start\n onTurnStart(): void {\n if (this.config.level === 'minimal') return;\n \n this.currentStage = 'thinking';\n this.taskStartTime = Date.now();\n \n if (this.config.heartbeatEnabled && !this.heartbeatTimer) {\n this.startHeartbeat();\n }\n }\n\n // Handle message/response start\n onMessageStart(): void {\n // Could be used to show \"AI is typing...\" indicator\n }\n\n // Handle message/response update (streaming tokens)\n onMessageUpdate(_content: string): void {\n // Could be used to show live response\n }\n\n // Handle agent end\n onAgentEnd(): void {\n this.endTask();\n }\n\n // Get current state\n getCurrentState(): { stage: ProgressStage; tool: string | null; elapsedMs: number } {\n return {\n stage: this.currentStage,\n tool: this.currentTool,\n elapsedMs: this.taskStartTime ? Date.now() - this.taskStartTime : 0,\n };\n }\n\n // Update config\n setConfig(config: Partial<ProgressFeedbackConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n // Get stage emoji\n getStageEmoji(stage: ProgressStage): string {\n return STAGE_EMOJI[stage] || '💬';\n }\n\n // Get stage label\n getStageLabel(stage: ProgressStage): string {\n return STAGE_LABEL[stage] || 'Unknown';\n }\n\n /**\n * Notify about accumulated tool errors\n * Enhanced feedback for tool failures\n */\n onToolErrorAccumulated(\n toolName: string,\n failureCount: number,\n maxFailures: number,\n remainingAttempts?: number\n ): void {\n if (!this.config.showErrorAccumulation) return;\n if (this.config.level === 'minimal') return;\n\n const remaining = remainingAttempts ?? (maxFailures - failureCount);\n const percentage = (failureCount / maxFailures) * 100;\n \n let message: string;\n let type: 'warning' | 'error' = percentage >= 100 ? 'error' : 'warning';\n\n if (percentage >= 100) {\n message = `❌ ${this.formatToolName(toolName)} has reached maximum failures (${maxFailures}/${maxFailures})`;\n } else if (percentage >= 50) {\n message = `⚠️ ${this.formatToolName(toolName)} failed ${failureCount}/${maxFailures} times`;\n } else {\n message = `⚠️ ${this.formatToolName(toolName)} failed ${failureCount} time${failureCount > 1 ? 's' : ''}`;\n }\n\n const progressMsg: ProgressMessage = {\n type,\n stage: 'executing',\n message,\n detail: remaining > 0 \n ? `Remaining attempts: ${remaining}` \n : 'Stopping tool execution',\n toolName,\n };\n\n this.callbacks.onProgress?.(progressMsg);\n\n const atCap = maxFailures > 0 && failureCount >= maxFailures;\n const summary = atCap\n ? `Tool \"${toolName}\" reached max failures (${failureCount}/${maxFailures})`\n : `Tool \"${toolName}\" failures ${failureCount}/${maxFailures} (${remaining} attempt(s) left)`;\n if (atCap) {\n log.error({ toolName, failureCount, maxFailures, remaining }, summary);\n } else {\n log.warn({ toolName, failureCount, maxFailures, remaining }, summary);\n }\n }\n\n /**\n * Notify about request limit status\n * Enhanced feedback for approaching/ reaching request limits\n */\n onRequestLimitStatus(\n count: number,\n limit: number,\n remaining: number,\n isWarning: boolean,\n shouldStop: boolean\n ): void {\n if (!this.config.showRequestLimitWarning) return;\n if (this.config.level === 'minimal') return;\n if (!isWarning && !shouldStop) return;\n\n const percentage = (count / limit) * 100;\n \n let message: string;\n let type: 'warning' | 'error' = shouldStop ? 'error' : 'warning';\n\n if (shouldStop) {\n message = `❌ Request limit reached (${count}/${limit})`;\n } else if (percentage >= 90) {\n message = `⚠️ Request limit warning (${count}/${limit})`;\n } else {\n message = `⚠️ Approaching request limit (${count}/${limit})`;\n }\n\n const progressMsg: ProgressMessage = {\n type,\n stage: 'thinking',\n message,\n detail: remaining > 0 \n ? `Remaining requests: ${remaining}` \n : 'Stopping execution',\n };\n\n this.callbacks.onProgress?.(progressMsg);\n\n const summary = shouldStop\n ? `LLM request limit reached (${count}/${limit}); stopping turn`\n : `LLM request budget ${count}/${limit} (${remaining} left)`;\n if (shouldStop) {\n log.error({ count, limit, remaining, shouldStop }, summary);\n } else {\n log.warn({ count, limit, remaining, shouldStop }, summary);\n }\n }\n}\n\n// Singleton instance with default config\nexport const progressFeedbackManager = new ProgressFeedbackManager();\n\n// Utility function to format progress messages for Telegram\nexport function formatProgressMessage(msg: ProgressMessage, parseMode: 'Markdown' | 'HTML' = 'HTML'): string {\n const emoji = STAGE_EMOJI[msg.stage];\n \n if (parseMode === 'HTML') {\n let html = `<b>${emoji} ${msg.message}</b>`;\n if (msg.detail) {\n html += `\\n${msg.detail}`;\n }\n return html;\n } else {\n let md = `**${emoji} ${msg.message}**`;\n if (msg.detail) {\n md += `\\n${msg.detail}`;\n }\n return md;\n }\n}\n\n// Utility function to format heartbeat message\nexport function formatHeartbeatMessage(elapsedMs: number, stage: ProgressStage, detail?: string): string {\n const seconds = Math.floor(elapsedMs / 1000);\n const emoji = STAGE_EMOJI[stage];\n const label = STAGE_LABEL[stage];\n \n let message = `${emoji} Still ${label.toLowerCase()}...`;\n if (detail) {\n message += `\\n${detail}`;\n }\n message += `\\n⏱️ ${seconds}s elapsed`;\n \n return message;\n}\n"],"mappings":"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"}
|
|
@@ -67,9 +67,8 @@ export declare function withTimeout<T extends (...args: any[]) => Promise<any>>(
|
|
|
67
67
|
* Timeout manager for tracking execution statistics
|
|
68
68
|
*/
|
|
69
69
|
export declare class TimeoutManager {
|
|
70
|
-
private config;
|
|
71
70
|
private executions;
|
|
72
|
-
constructor(
|
|
71
|
+
constructor(_config?: Partial<TimeoutConfig>);
|
|
73
72
|
/**
|
|
74
73
|
* Execute with timeout and track statistics
|
|
75
74
|
*/
|
|
@@ -157,14 +157,8 @@ function withTimeout(fn, config) {
|
|
|
157
157
|
* Timeout manager for tracking execution statistics
|
|
158
158
|
*/
|
|
159
159
|
var TimeoutManager = class {
|
|
160
|
-
config;
|
|
161
160
|
executions = [];
|
|
162
|
-
constructor(
|
|
163
|
-
this.config = {
|
|
164
|
-
...DEFAULT_CONFIG,
|
|
165
|
-
...config
|
|
166
|
-
};
|
|
167
|
-
}
|
|
161
|
+
constructor(_config = {}) {}
|
|
168
162
|
/**
|
|
169
163
|
* Execute with timeout and track statistics
|
|
170
164
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeout-wrapper.js","names":[],"sources":["../../../../src/agent/lifecycle/timeout-wrapper.ts"],"sourcesContent":["/**\n * Timeout Wrapper - Protects tool execution from hanging\n *\n * Wraps tool execution with timeout protection to prevent:\n * - Infinite loops in shell commands\n * - Network requests hanging forever\n * - Resource exhaustion\n */\n\nimport { createLogger } from '../../utils/logger.js';\n\nconst log = createLogger('TimeoutWrapper');\n\nexport interface TimeoutConfig {\n defaultTimeoutMs: number; // Default timeout in ms (default: 300000 = 5 min)\n shellTimeoutMs: number; // Shell command timeout (default: 300000 = 5 min)\n readTimeoutMs: number; // File read timeout (default: 30000 = 30 sec)\n writeTimeoutMs: number; // File write timeout (default: 60000 = 1 min)\n networkTimeoutMs: number; // Network request timeout (default: 60000 = 1 min)\n gracefulShutdownMs: number; // Time to wait for graceful shutdown (default: 5000)\n}\n\nconst DEFAULT_CONFIG: TimeoutConfig = {\n defaultTimeoutMs: 5 * 60 * 1000, // 5 minutes\n shellTimeoutMs: 5 * 60 * 1000, // 5 minutes\n readTimeoutMs: 30 * 1000, // 30 seconds\n writeTimeoutMs: 60 * 1000, // 1 minute\n networkTimeoutMs: 60 * 1000, // 1 minute\n gracefulShutdownMs: 5000, // 5 seconds\n};\n\nexport interface TimeoutResult<T> {\n success: boolean;\n result?: T;\n error?: Error;\n timedOut: boolean;\n executionTimeMs: number;\n}\n\nexport interface ToolTimeoutConfig {\n toolName: string;\n timeoutMs?: number;\n description?: string;\n}\n\n/**\n * Get timeout for specific tool type\n */\nfunction getTimeoutForTool(toolName: string, config: TimeoutConfig): number {\n const toolLower = toolName.toLowerCase();\n\n if (toolLower.includes('shell') || toolLower.includes('exec')) {\n return config.shellTimeoutMs;\n }\n if (toolLower.includes('read') || toolLower.includes('view')) {\n return config.readTimeoutMs;\n }\n if (toolLower.includes('write') || toolLower.includes('edit')) {\n return config.writeTimeoutMs;\n }\n if (toolLower.includes('web') || toolLower.includes('http') || toolLower.includes('fetch')) {\n return config.networkTimeoutMs;\n }\n\n return config.defaultTimeoutMs;\n}\n\n/**\n * Execute function with timeout protection\n *\n * @example\n * ```typescript\n * const result = await executeWithTimeout(\n * () => shell.exec('long-running-command'),\n * { toolName: 'shell', timeoutMs: 60000 }\n * );\n * ```\n */\nexport async function executeWithTimeout<T>(\n operation: () => Promise<T>,\n config: ToolTimeoutConfig\n): Promise<T> {\n const fullConfig = { ...DEFAULT_CONFIG };\n const timeoutMs = config.timeoutMs || getTimeoutForTool(config.toolName, fullConfig);\n\n const startTime = Date.now();\n let timeoutId: NodeJS.Timeout | null = null;\n let isSettled = false;\n\n return new Promise((resolve, reject) => {\n // Set up timeout\n timeoutId = setTimeout(() => {\n if (isSettled) return;\n isSettled = true;\n \n const executionTime = Date.now() - startTime;\n const desc = config.description ? ` (${config.description})` : '';\n log.error(\n {\n toolName: config.toolName,\n timeoutMs,\n executionTimeMs: executionTime,\n description: config.description,\n },\n `Tool \"${config.toolName}\" timed out after ${timeoutMs}ms (elapsed ${executionTime}ms)${desc}`,\n );\n\n reject(\n new TimeoutError(\n config.toolName,\n timeoutMs,\n config.description,\n executionTime\n )\n );\n }, timeoutMs);\n\n // Execute operation\n operation()\n .then(result => {\n if (isSettled) return;\n isSettled = true;\n \n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n const executionTime = Date.now() - startTime;\n\n log.debug(\n {\n toolName: config.toolName,\n executionTimeMs: executionTime,\n },\n 'Tool execution completed within timeout'\n );\n\n resolve(result);\n })\n .catch(error => {\n if (isSettled) return;\n isSettled = true;\n \n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n reject(error);\n });\n });\n}\n\n/**\n * Execute with timeout and return detailed result\n */\nexport async function executeWithTimeoutResult<T>(\n operation: () => Promise<T>,\n config: ToolTimeoutConfig\n): Promise<TimeoutResult<T>> {\n const startTime = Date.now();\n\n try {\n const result = await executeWithTimeout(operation, config);\n return {\n success: true,\n result,\n timedOut: false,\n executionTimeMs: Date.now() - startTime,\n };\n } catch (error) {\n const isTimeout = error instanceof TimeoutError;\n return {\n success: false,\n error: error instanceof Error ? error : new Error(String(error)),\n timedOut: isTimeout,\n executionTimeMs: Date.now() - startTime,\n };\n }\n}\n\n/**\n * Custom timeout error\n */\nexport class TimeoutError extends Error {\n public readonly toolName: string;\n public readonly timeoutMs: number;\n public readonly executionTimeMs: number;\n public readonly description?: string;\n\n constructor(\n toolName: string,\n timeoutMs: number,\n description?: string,\n executionTimeMs: number = timeoutMs\n ) {\n const timeoutSec = Math.round(timeoutMs / 1000);\n const message = description\n ? `Tool '${toolName}' timed out after ${timeoutSec}s: ${description}`\n : `Tool '${toolName}' timed out after ${timeoutSec}s. Consider breaking the operation into smaller steps.`;\n\n super(message);\n this.name = 'TimeoutError';\n this.toolName = toolName;\n this.timeoutMs = timeoutMs;\n this.description = description;\n this.executionTimeMs = executionTimeMs;\n\n // Maintain proper stack trace\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, TimeoutError);\n }\n }\n\n /**\n * Get user-friendly error message with suggestions\n */\n getUserMessage(): string {\n const suggestions: string[] = [];\n\n if (this.toolName.toLowerCase().includes('shell')) {\n suggestions.push('Break the command into smaller steps');\n suggestions.push('Add timeouts to individual commands');\n suggestions.push('Check for infinite loops or waiting for input');\n } else if (this.toolName.toLowerCase().includes('read')) {\n suggestions.push('Read the file in smaller chunks');\n suggestions.push('Use grep to find specific content first');\n } else if (this.toolName.toLowerCase().includes('write')) {\n suggestions.push('Write content in smaller batches');\n } else if (this.toolName.toLowerCase().includes('web')) {\n suggestions.push('Check network connectivity');\n suggestions.push('Try again later');\n }\n\n let message = `⚠️ ${this.message}`;\n if (suggestions.length > 0) {\n message += '\\n\\nSuggestions:\\n' + suggestions.map(s => `• ${s}`).join('\\n');\n }\n\n return message;\n }\n}\n\n/**\n * Wrap a function with timeout protection\n */\nexport function withTimeout<T extends (...args: any[]) => Promise<any>>(\n fn: T,\n config: Omit<ToolTimeoutConfig, 'description'> & { description?: string | ((...args: Parameters<T>) => string) }\n): (...args: Parameters<T>) => Promise<ReturnType<T>> {\n return async (...args: Parameters<T>): Promise<ReturnType<T>> => {\n const description = typeof config.description === 'function'\n ? config.description(...args)\n : config.description;\n\n return executeWithTimeout(() => fn(...args), {\n toolName: config.toolName,\n timeoutMs: config.timeoutMs,\n description,\n });\n };\n}\n\n/**\n * Timeout manager for tracking execution statistics\n */\nexport class TimeoutManager {\n private config: TimeoutConfig;\n private executions: Array<{\n toolName: string;\n executionTimeMs: number;\n timedOut: boolean;\n timestamp: number;\n }> = [];\n\n constructor(config: Partial<TimeoutConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n /**\n * Execute with timeout and track statistics\n */\n async execute<T>(\n operation: () => Promise<T>,\n toolConfig: ToolTimeoutConfig\n ): Promise<T> {\n const startTime = Date.now();\n let timedOut = false;\n\n try {\n const result = await executeWithTimeout(operation, toolConfig);\n this.executions.push({\n toolName: toolConfig.toolName,\n executionTimeMs: Date.now() - startTime,\n timedOut: false,\n timestamp: Date.now(),\n });\n return result;\n } catch (error) {\n if (error instanceof TimeoutError) {\n timedOut = true;\n }\n this.executions.push({\n toolName: toolConfig.toolName,\n executionTimeMs: Date.now() - startTime,\n timedOut,\n timestamp: Date.now(),\n });\n throw error;\n }\n }\n\n /**\n * Get execution statistics\n */\n getStats(): {\n totalExecutions: number;\n timeoutCount: number;\n timeoutRate: number;\n averageExecutionTimeMs: number;\n byTool: Record<string, {\n count: number;\n timeouts: number;\n avgExecutionTimeMs: number;\n }>;\n } {\n const byTool: Record<string, { count: number; timeouts: number; totalTime: number }> = {};\n\n for (const exec of this.executions) {\n if (!byTool[exec.toolName]) {\n byTool[exec.toolName] = { count: 0, timeouts: 0, totalTime: 0 };\n }\n byTool[exec.toolName].count++;\n if (exec.timedOut) {\n byTool[exec.toolName].timeouts++;\n }\n byTool[exec.toolName].totalTime += exec.executionTimeMs;\n }\n\n const totalExecutions = this.executions.length;\n const timeoutCount = this.executions.filter(e => e.timedOut).length;\n const totalTime = this.executions.reduce((sum, e) => sum + e.executionTimeMs, 0);\n\n return {\n totalExecutions,\n timeoutCount,\n timeoutRate: totalExecutions > 0 ? timeoutCount / totalExecutions : 0,\n averageExecutionTimeMs: totalExecutions > 0 ? totalTime / totalExecutions : 0,\n byTool: Object.fromEntries(\n Object.entries(byTool).map(([name, stats]) => [\n name,\n {\n count: stats.count,\n timeouts: stats.timeouts,\n avgExecutionTimeMs: stats.count > 0 ? stats.totalTime / stats.count : 0,\n },\n ])\n ),\n };\n }\n\n /**\n * Clean up old execution records\n */\n cleanup(maxAgeMs: number = 24 * 60 * 60 * 1000): void {\n const cutoff = Date.now() - maxAgeMs;\n this.executions = this.executions.filter(e => e.timestamp > cutoff);\n }\n}\n\n// Convenience exports\nexport { DEFAULT_CONFIG as DEFAULT_TIMEOUT_CONFIG };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"timeout-wrapper.js","names":[],"sources":["../../../../src/agent/lifecycle/timeout-wrapper.ts"],"sourcesContent":["/**\n * Timeout Wrapper - Protects tool execution from hanging\n *\n * Wraps tool execution with timeout protection to prevent:\n * - Infinite loops in shell commands\n * - Network requests hanging forever\n * - Resource exhaustion\n */\n\nimport { createLogger } from '../../utils/logger.js';\n\nconst log = createLogger('TimeoutWrapper');\n\nexport interface TimeoutConfig {\n defaultTimeoutMs: number; // Default timeout in ms (default: 300000 = 5 min)\n shellTimeoutMs: number; // Shell command timeout (default: 300000 = 5 min)\n readTimeoutMs: number; // File read timeout (default: 30000 = 30 sec)\n writeTimeoutMs: number; // File write timeout (default: 60000 = 1 min)\n networkTimeoutMs: number; // Network request timeout (default: 60000 = 1 min)\n gracefulShutdownMs: number; // Time to wait for graceful shutdown (default: 5000)\n}\n\nconst DEFAULT_CONFIG: TimeoutConfig = {\n defaultTimeoutMs: 5 * 60 * 1000, // 5 minutes\n shellTimeoutMs: 5 * 60 * 1000, // 5 minutes\n readTimeoutMs: 30 * 1000, // 30 seconds\n writeTimeoutMs: 60 * 1000, // 1 minute\n networkTimeoutMs: 60 * 1000, // 1 minute\n gracefulShutdownMs: 5000, // 5 seconds\n};\n\nexport interface TimeoutResult<T> {\n success: boolean;\n result?: T;\n error?: Error;\n timedOut: boolean;\n executionTimeMs: number;\n}\n\nexport interface ToolTimeoutConfig {\n toolName: string;\n timeoutMs?: number;\n description?: string;\n}\n\n/**\n * Get timeout for specific tool type\n */\nfunction getTimeoutForTool(toolName: string, config: TimeoutConfig): number {\n const toolLower = toolName.toLowerCase();\n\n if (toolLower.includes('shell') || toolLower.includes('exec')) {\n return config.shellTimeoutMs;\n }\n if (toolLower.includes('read') || toolLower.includes('view')) {\n return config.readTimeoutMs;\n }\n if (toolLower.includes('write') || toolLower.includes('edit')) {\n return config.writeTimeoutMs;\n }\n if (toolLower.includes('web') || toolLower.includes('http') || toolLower.includes('fetch')) {\n return config.networkTimeoutMs;\n }\n\n return config.defaultTimeoutMs;\n}\n\n/**\n * Execute function with timeout protection\n *\n * @example\n * ```typescript\n * const result = await executeWithTimeout(\n * () => shell.exec('long-running-command'),\n * { toolName: 'shell', timeoutMs: 60000 }\n * );\n * ```\n */\nexport async function executeWithTimeout<T>(\n operation: () => Promise<T>,\n config: ToolTimeoutConfig\n): Promise<T> {\n const fullConfig = { ...DEFAULT_CONFIG };\n const timeoutMs = config.timeoutMs || getTimeoutForTool(config.toolName, fullConfig);\n\n const startTime = Date.now();\n let timeoutId: NodeJS.Timeout | null = null;\n let isSettled = false;\n\n return new Promise((resolve, reject) => {\n // Set up timeout\n timeoutId = setTimeout(() => {\n if (isSettled) return;\n isSettled = true;\n \n const executionTime = Date.now() - startTime;\n const desc = config.description ? ` (${config.description})` : '';\n log.error(\n {\n toolName: config.toolName,\n timeoutMs,\n executionTimeMs: executionTime,\n description: config.description,\n },\n `Tool \"${config.toolName}\" timed out after ${timeoutMs}ms (elapsed ${executionTime}ms)${desc}`,\n );\n\n reject(\n new TimeoutError(\n config.toolName,\n timeoutMs,\n config.description,\n executionTime\n )\n );\n }, timeoutMs);\n\n // Execute operation\n operation()\n .then(result => {\n if (isSettled) return;\n isSettled = true;\n \n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n const executionTime = Date.now() - startTime;\n\n log.debug(\n {\n toolName: config.toolName,\n executionTimeMs: executionTime,\n },\n 'Tool execution completed within timeout'\n );\n\n resolve(result);\n })\n .catch(error => {\n if (isSettled) return;\n isSettled = true;\n \n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n reject(error);\n });\n });\n}\n\n/**\n * Execute with timeout and return detailed result\n */\nexport async function executeWithTimeoutResult<T>(\n operation: () => Promise<T>,\n config: ToolTimeoutConfig\n): Promise<TimeoutResult<T>> {\n const startTime = Date.now();\n\n try {\n const result = await executeWithTimeout(operation, config);\n return {\n success: true,\n result,\n timedOut: false,\n executionTimeMs: Date.now() - startTime,\n };\n } catch (error) {\n const isTimeout = error instanceof TimeoutError;\n return {\n success: false,\n error: error instanceof Error ? error : new Error(String(error)),\n timedOut: isTimeout,\n executionTimeMs: Date.now() - startTime,\n };\n }\n}\n\n/**\n * Custom timeout error\n */\nexport class TimeoutError extends Error {\n public readonly toolName: string;\n public readonly timeoutMs: number;\n public readonly executionTimeMs: number;\n public readonly description?: string;\n\n constructor(\n toolName: string,\n timeoutMs: number,\n description?: string,\n executionTimeMs: number = timeoutMs\n ) {\n const timeoutSec = Math.round(timeoutMs / 1000);\n const message = description\n ? `Tool '${toolName}' timed out after ${timeoutSec}s: ${description}`\n : `Tool '${toolName}' timed out after ${timeoutSec}s. Consider breaking the operation into smaller steps.`;\n\n super(message);\n this.name = 'TimeoutError';\n this.toolName = toolName;\n this.timeoutMs = timeoutMs;\n this.description = description;\n this.executionTimeMs = executionTimeMs;\n\n // Maintain proper stack trace\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, TimeoutError);\n }\n }\n\n /**\n * Get user-friendly error message with suggestions\n */\n getUserMessage(): string {\n const suggestions: string[] = [];\n\n if (this.toolName.toLowerCase().includes('shell')) {\n suggestions.push('Break the command into smaller steps');\n suggestions.push('Add timeouts to individual commands');\n suggestions.push('Check for infinite loops or waiting for input');\n } else if (this.toolName.toLowerCase().includes('read')) {\n suggestions.push('Read the file in smaller chunks');\n suggestions.push('Use grep to find specific content first');\n } else if (this.toolName.toLowerCase().includes('write')) {\n suggestions.push('Write content in smaller batches');\n } else if (this.toolName.toLowerCase().includes('web')) {\n suggestions.push('Check network connectivity');\n suggestions.push('Try again later');\n }\n\n let message = `⚠️ ${this.message}`;\n if (suggestions.length > 0) {\n message += '\\n\\nSuggestions:\\n' + suggestions.map(s => `• ${s}`).join('\\n');\n }\n\n return message;\n }\n}\n\n/**\n * Wrap a function with timeout protection\n */\nexport function withTimeout<T extends (...args: any[]) => Promise<any>>(\n fn: T,\n config: Omit<ToolTimeoutConfig, 'description'> & { description?: string | ((...args: Parameters<T>) => string) }\n): (...args: Parameters<T>) => Promise<ReturnType<T>> {\n return async (...args: Parameters<T>): Promise<ReturnType<T>> => {\n const description = typeof config.description === 'function'\n ? config.description(...args)\n : config.description;\n\n return executeWithTimeout(() => fn(...args), {\n toolName: config.toolName,\n timeoutMs: config.timeoutMs,\n description,\n });\n };\n}\n\n/**\n * Timeout manager for tracking execution statistics\n */\nexport class TimeoutManager {\n private executions: Array<{\n toolName: string;\n executionTimeMs: number;\n timedOut: boolean;\n timestamp: number;\n }> = [];\n\n constructor(_config: Partial<TimeoutConfig> = {}) {}\n\n /**\n * Execute with timeout and track statistics\n */\n async execute<T>(\n operation: () => Promise<T>,\n toolConfig: ToolTimeoutConfig\n ): Promise<T> {\n const startTime = Date.now();\n let timedOut = false;\n\n try {\n const result = await executeWithTimeout(operation, toolConfig);\n this.executions.push({\n toolName: toolConfig.toolName,\n executionTimeMs: Date.now() - startTime,\n timedOut: false,\n timestamp: Date.now(),\n });\n return result;\n } catch (error) {\n if (error instanceof TimeoutError) {\n timedOut = true;\n }\n this.executions.push({\n toolName: toolConfig.toolName,\n executionTimeMs: Date.now() - startTime,\n timedOut,\n timestamp: Date.now(),\n });\n throw error;\n }\n }\n\n /**\n * Get execution statistics\n */\n getStats(): {\n totalExecutions: number;\n timeoutCount: number;\n timeoutRate: number;\n averageExecutionTimeMs: number;\n byTool: Record<string, {\n count: number;\n timeouts: number;\n avgExecutionTimeMs: number;\n }>;\n } {\n const byTool: Record<string, { count: number; timeouts: number; totalTime: number }> = {};\n\n for (const exec of this.executions) {\n if (!byTool[exec.toolName]) {\n byTool[exec.toolName] = { count: 0, timeouts: 0, totalTime: 0 };\n }\n byTool[exec.toolName].count++;\n if (exec.timedOut) {\n byTool[exec.toolName].timeouts++;\n }\n byTool[exec.toolName].totalTime += exec.executionTimeMs;\n }\n\n const totalExecutions = this.executions.length;\n const timeoutCount = this.executions.filter(e => e.timedOut).length;\n const totalTime = this.executions.reduce((sum, e) => sum + e.executionTimeMs, 0);\n\n return {\n totalExecutions,\n timeoutCount,\n timeoutRate: totalExecutions > 0 ? timeoutCount / totalExecutions : 0,\n averageExecutionTimeMs: totalExecutions > 0 ? totalTime / totalExecutions : 0,\n byTool: Object.fromEntries(\n Object.entries(byTool).map(([name, stats]) => [\n name,\n {\n count: stats.count,\n timeouts: stats.timeouts,\n avgExecutionTimeMs: stats.count > 0 ? stats.totalTime / stats.count : 0,\n },\n ])\n ),\n };\n }\n\n /**\n * Clean up old execution records\n */\n cleanup(maxAgeMs: number = 24 * 60 * 60 * 1000): void {\n const cutoff = Date.now() - maxAgeMs;\n this.executions = this.executions.filter(e => e.timestamp > cutoff);\n }\n}\n\n// Convenience exports\nexport { DEFAULT_CONFIG as DEFAULT_TIMEOUT_CONFIG };\n"],"mappings":"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"}
|
|
@@ -16,7 +16,7 @@ export declare class BuiltinMemoryStore {
|
|
|
16
16
|
get memoriesDir(): string;
|
|
17
17
|
/** Global user memory file (`~/.xopc/user/MEMORY.md`). */
|
|
18
18
|
get userMemoryPath(): string;
|
|
19
|
-
/** Workspace whose
|
|
19
|
+
/** Workspace whose profile and curated files participate in local memory search. */
|
|
20
20
|
get workspaceDir(): string;
|
|
21
21
|
pathFor(target: 'memory' | 'user'): string;
|
|
22
22
|
/**
|
|
@@ -32,7 +32,7 @@ var BuiltinMemoryStore = class {
|
|
|
32
32
|
get userMemoryPath() {
|
|
33
33
|
return this.config.userMemoryPath;
|
|
34
34
|
}
|
|
35
|
-
/** Workspace whose
|
|
35
|
+
/** Workspace whose profile and curated files participate in local memory search. */
|
|
36
36
|
get workspaceDir() {
|
|
37
37
|
return this.config.workspaceDir;
|
|
38
38
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtin-memory-store.js","names":[],"sources":["../../../../src/agent/memory/builtin-memory-store.ts"],"sourcesContent":["/**\n * Bounded curated memory: agent home `memories/MEMORY.md` + global `user/MEMORY.md`, §-delimited entries.\n * Snapshot for system prompt is captured at load time and not mutated until next load.\n */\n\nimport { existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport { mkdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport lockfile from 'proper-lockfile';\n\nimport type { MemorySnapshot, MemoryStoreConfig } from './types.js';\n\nexport const MEMORY_ENTRY_DELIMITER = '\\n§\\n';\n\nconst DEFAULT_MEMORY_LIMIT = 2200;\nconst DEFAULT_USER_LIMIT = 1375;\n\nexport class BuiltinMemoryStore {\n private memoryEntries: string[] = [];\n private userEntries: string[] = [];\n private snapshot: MemorySnapshot = { memory: '', user: '' };\n\n constructor(private readonly config: MemoryStoreConfig) {}\n\n /** When false, global user memory is omitted from the snapshot and should not be edited via `curated_memory`. */\n isUserProfileEnabled(): boolean {\n return this.config.userProfileEnabled !== false;\n }\n\n /** Agent-scoped curated memory directory (`~/.xopc/agents/<id>/memories/`). */\n get memoriesDir(): string {\n return this.config.memoriesDir;\n }\n\n /** Global user memory file (`~/.xopc/user/MEMORY.md`). */\n get userMemoryPath(): string {\n return this.config.userMemoryPath;\n }\n\n /** Workspace whose MEMORY.md and daily notes participate in local memory search. */\n get workspaceDir(): string {\n return this.config.workspaceDir;\n }\n\n pathFor(target: 'memory' | 'user'): string {\n return target === 'memory' ? join(this.memoriesDir, 'MEMORY.md') : this.userMemoryPath;\n }\n\n /**\n * Load from disk and freeze {@link getSnapshot}. Sync for agent creation (prefix cache stability).\n */\n loadFromDiskSync(): void {\n mkdirSync(this.memoriesDir, { recursive: true });\n this.memoryEntries = this.parseFileContent(\n this.readPathSync(join(this.memoriesDir, 'MEMORY.md')),\n );\n this.userEntries =\n this.config.userProfileEnabled === false\n ? []\n : this.parseFileContent(this.readPathSync(this.userMemoryPath));\n this.memoryEntries = dedupePreserveOrder(this.memoryEntries);\n this.userEntries = dedupePreserveOrder(this.userEntries);\n this.snapshot = {\n memory: this.renderBlock('memory', this.memoryEntries),\n user: this.renderBlock('user', this.userEntries),\n };\n }\n\n private readPathSync(path: string): string {\n try {\n if (!existsSync(path)) return '';\n return readFileSync(path, { encoding: 'utf-8' });\n } catch {\n return '';\n }\n }\n\n private parseFileContent(raw: string): string[] {\n if (!raw.trim()) return [];\n return raw\n .split(MEMORY_ENTRY_DELIMITER)\n .map((e) => e.trim())\n .filter(Boolean);\n }\n\n getSnapshot(): MemorySnapshot {\n return this.snapshot;\n }\n\n /**\n * Live entries for read/debug (may differ from snapshot after mutations).\n */\n getLiveEntries(target: 'memory' | 'user'): string[] {\n return target === 'memory' ? [...this.memoryEntries] : [...this.userEntries];\n }\n\n async add(\n target: 'memory' | 'user',\n content: string,\n ): Promise<{ success: boolean; error?: string; message?: string }> {\n const trimmed = content.trim();\n if (!trimmed) {\n return { success: false, error: 'Content cannot be empty.' };\n }\n const scanError = scanForThreats(trimmed);\n if (scanError) {\n return { success: false, error: scanError };\n }\n\n return this.withFileLock(target, async () => {\n await this.reloadTargetFromDisk(target);\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const limit = this.charLimit(target);\n\n if (entries.includes(trimmed)) {\n return { success: false, error: 'Entry already exists' };\n }\n\n const newTotal = calculateTotal([...entries, trimmed]);\n if (newTotal > limit) {\n return {\n success: false,\n error: `Memory at ${calculateTotal(entries)}/${limit} chars. Adding would exceed limit.`,\n };\n }\n\n entries.push(trimmed);\n await this.flushTargetToDisk(target);\n return { success: true, message: 'Entry added.' };\n });\n }\n\n async replace(\n target: 'memory' | 'user',\n oldText: string,\n newContent: string,\n ): Promise<{ success: boolean; error?: string; message?: string }> {\n const ot = oldText.trim();\n const nc = newContent.trim();\n if (!ot) {\n return { success: false, error: 'old_text cannot be empty.' };\n }\n if (!nc) {\n return { success: false, error: 'new_content cannot be empty. Use remove to delete entries.' };\n }\n const scanError = scanForThreats(nc);\n if (scanError) {\n return { success: false, error: scanError };\n }\n\n return this.withFileLock(target, async () => {\n await this.reloadTargetFromDisk(target);\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const matches: Array<{ index: number; entry: string }> = [];\n for (let i = 0; i < entries.length; i++) {\n if (entries[i].includes(ot)) {\n matches.push({ index: i, entry: entries[i] });\n }\n }\n\n if (matches.length === 0) {\n return { success: false, error: `No entry matched '${ot}'.` };\n }\n\n if (matches.length > 1) {\n const uniqueTexts = new Set(matches.map((m) => m.entry));\n if (uniqueTexts.size > 1) {\n const previews = matches.map((m) =>\n m.entry.length > 80 ? `${m.entry.slice(0, 80)}...` : m.entry,\n );\n return {\n success: false,\n error: `Multiple entries matched '${ot}'. Be more specific. Previews: ${previews.join(' | ')}`,\n };\n }\n }\n\n const idx = matches[0].index;\n const limit = this.charLimit(target);\n const testEntries = [...entries];\n testEntries[idx] = nc;\n\n if (calculateTotal(testEntries) > limit) {\n return {\n success: false,\n error: `Replacement would put memory at ${calculateTotal(testEntries)}/${limit} chars.`,\n };\n }\n\n entries[idx] = nc;\n await this.flushTargetToDisk(target);\n return { success: true, message: 'Entry replaced.' };\n });\n }\n\n async remove(\n target: 'memory' | 'user',\n oldText: string,\n ): Promise<{ success: boolean; error?: string; message?: string }> {\n const ot = oldText.trim();\n if (!ot) {\n return { success: false, error: 'old_text cannot be empty.' };\n }\n\n return this.withFileLock(target, async () => {\n await this.reloadTargetFromDisk(target);\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const matches: number[] = [];\n for (let i = 0; i < entries.length; i++) {\n if (entries[i].includes(ot)) {\n matches.push(i);\n }\n }\n\n if (matches.length === 0) {\n return { success: false, error: `No entry matched '${ot}'.` };\n }\n\n if (matches.length > 1) {\n const uniqueTexts = new Set(matches.map((i) => entries[i]));\n if (uniqueTexts.size > 1) {\n const previews = matches.map((i) => {\n const e = entries[i];\n return e.length > 80 ? `${e.slice(0, 80)}...` : e;\n });\n return {\n success: false,\n error: `Multiple entries matched '${ot}'. Be more specific. Previews: ${previews.join(' | ')}`,\n };\n }\n }\n\n entries.splice(matches[0], 1);\n await this.flushTargetToDisk(target);\n return { success: true, message: 'Entry removed.' };\n });\n }\n\n private async withFileLock<T>(\n target: 'memory' | 'user',\n fn: () => Promise<T>,\n ): Promise<T> {\n const filePath = this.pathFor(target);\n await mkdir(dirname(filePath), { recursive: true });\n if (!existsSync(filePath)) {\n await writeFile(filePath, '', 'utf-8');\n }\n await lockfile.lock(filePath, { retries: 3, stale: 10_000 });\n try {\n return await fn();\n } finally {\n await lockfile.unlock(filePath);\n }\n }\n\n private async reloadTargetFromDisk(target: 'memory' | 'user'): Promise<void> {\n const path = this.pathFor(target);\n let raw = '';\n try {\n raw = await readFile(path, 'utf-8');\n } catch {\n raw = '';\n }\n const parsed = dedupePreserveOrder(this.parseFileContent(raw));\n if (target === 'memory') {\n this.memoryEntries = parsed;\n } else {\n this.userEntries = parsed;\n }\n }\n\n private async flushTargetToDisk(target: 'memory' | 'user'): Promise<void> {\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const filePath = this.pathFor(target);\n const content = entries.join(MEMORY_ENTRY_DELIMITER);\n const tmpPath = `${filePath}.tmp.${Date.now()}`;\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(tmpPath, content, 'utf-8');\n await rename(tmpPath, filePath);\n }\n\n private charLimit(target: 'memory' | 'user'): number {\n return target === 'memory'\n ? (this.config.memoryCharLimit ?? DEFAULT_MEMORY_LIMIT)\n : (this.config.userCharLimit ?? DEFAULT_USER_LIMIT);\n }\n\n private renderBlock(target: 'memory' | 'user', entries: string[]): string {\n if (entries.length === 0) {\n return '';\n }\n\n const limit = this.charLimit(target);\n const content = entries.join(MEMORY_ENTRY_DELIMITER);\n const current = content.length;\n const pct = Math.min(100, Math.round((current / limit) * 100));\n\n const header =\n target === 'user'\n ? `USER PROFILE (who the user is) [${pct}% — ${current.toLocaleString()}/${limit.toLocaleString()} chars]`\n : `MEMORY (your personal notes) [${pct}% — ${current.toLocaleString()}/${limit.toLocaleString()} chars]`;\n\n const separator = '═'.repeat(46);\n return `${separator}\\n${header}\\n${separator}\\n${content}`;\n }\n}\n\nfunction dedupePreserveOrder(entries: string[]): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const e of entries) {\n if (seen.has(e)) {\n continue;\n }\n seen.add(e);\n out.push(e);\n }\n return out;\n}\n\nfunction calculateTotal(entries: string[]): number {\n if (entries.length === 0) {\n return 0;\n }\n return entries.join(MEMORY_ENTRY_DELIMITER).length;\n}\n\nexport function scanForThreats(content: string): string | null {\n const patterns: Array<{ regex: RegExp; id: string }> = [\n { regex: /ignore\\s+(previous|all|above|prior)\\s+instructions/i, id: 'prompt_injection' },\n { regex: /you\\s+are\\s+now\\s+/i, id: 'role_hijack' },\n { regex: /do\\s+not\\s+tell\\s+the\\s+user/i, id: 'deception_hide' },\n { regex: /system\\s+prompt\\s+override/i, id: 'sys_prompt_override' },\n {\n regex: /disregard\\s+(your|all|any)\\s+(instructions|rules|guidelines)/i,\n id: 'disregard_rules',\n },\n {\n regex: /act\\s+as\\s+(if|though)\\s+you\\s+(have\\s+no|don't\\s+have)\\s+(restrictions|limits|rules)/i,\n id: 'bypass_restrictions',\n },\n { regex: /curl\\s+[^\\n]*\\$\\{?\\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)/i, id: 'exfil_curl' },\n { regex: /wget\\s+[^\\n]*\\$\\{?\\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)/i, id: 'exfil_wget' },\n {\n regex: /cat\\s+[^\\n]*(\\.env|credentials|\\.netrc|\\.pgpass|\\.npmrc|\\.pypirc)/i,\n id: 'read_secrets',\n },\n { regex: /authorized_keys/i, id: 'ssh_backdoor' },\n { regex: /\\$HOME\\/\\.ssh|\\~\\/\\.ssh/i, id: 'ssh_access' },\n ];\n\n for (const { regex, id } of patterns) {\n if (regex.test(content)) {\n return `Blocked: content matches threat pattern '${id}'. Memory entries are injected into the system prompt and must not contain injection payloads.`;\n }\n }\n\n const invisibleChars = [\n '\\u200b',\n '\\u200c',\n '\\u200d',\n '\\u2060',\n '\\ufeff',\n '\\u202a',\n '\\u202b',\n '\\u202c',\n '\\u202d',\n '\\u202e',\n ];\n for (const char of invisibleChars) {\n if (content.includes(char)) {\n const code = char.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0');\n return `Blocked: content contains invisible unicode character U+${code} (possible injection).`;\n }\n }\n\n return null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"builtin-memory-store.js","names":[],"sources":["../../../../src/agent/memory/builtin-memory-store.ts"],"sourcesContent":["/**\n * Bounded curated memory: agent home `memories/MEMORY.md` + global `user/MEMORY.md`, §-delimited entries.\n * Snapshot for system prompt is captured at load time and not mutated until next load.\n */\n\nimport { existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport { mkdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport lockfile from 'proper-lockfile';\n\nimport type { MemorySnapshot, MemoryStoreConfig } from './types.js';\n\nexport const MEMORY_ENTRY_DELIMITER = '\\n§\\n';\n\nconst DEFAULT_MEMORY_LIMIT = 2200;\nconst DEFAULT_USER_LIMIT = 1375;\n\nexport class BuiltinMemoryStore {\n private memoryEntries: string[] = [];\n private userEntries: string[] = [];\n private snapshot: MemorySnapshot = { memory: '', user: '' };\n\n constructor(private readonly config: MemoryStoreConfig) {}\n\n /** When false, global user memory is omitted from the snapshot and should not be edited via `curated_memory`. */\n isUserProfileEnabled(): boolean {\n return this.config.userProfileEnabled !== false;\n }\n\n /** Agent-scoped curated memory directory (`~/.xopc/agents/<id>/memories/`). */\n get memoriesDir(): string {\n return this.config.memoriesDir;\n }\n\n /** Global user memory file (`~/.xopc/user/MEMORY.md`). */\n get userMemoryPath(): string {\n return this.config.userMemoryPath;\n }\n\n /** Workspace whose profile and curated files participate in local memory search. */\n get workspaceDir(): string {\n return this.config.workspaceDir;\n }\n\n pathFor(target: 'memory' | 'user'): string {\n return target === 'memory' ? join(this.memoriesDir, 'MEMORY.md') : this.userMemoryPath;\n }\n\n /**\n * Load from disk and freeze {@link getSnapshot}. Sync for agent creation (prefix cache stability).\n */\n loadFromDiskSync(): void {\n mkdirSync(this.memoriesDir, { recursive: true });\n this.memoryEntries = this.parseFileContent(\n this.readPathSync(join(this.memoriesDir, 'MEMORY.md')),\n );\n this.userEntries =\n this.config.userProfileEnabled === false\n ? []\n : this.parseFileContent(this.readPathSync(this.userMemoryPath));\n this.memoryEntries = dedupePreserveOrder(this.memoryEntries);\n this.userEntries = dedupePreserveOrder(this.userEntries);\n this.snapshot = {\n memory: this.renderBlock('memory', this.memoryEntries),\n user: this.renderBlock('user', this.userEntries),\n };\n }\n\n private readPathSync(path: string): string {\n try {\n if (!existsSync(path)) return '';\n return readFileSync(path, { encoding: 'utf-8' });\n } catch {\n return '';\n }\n }\n\n private parseFileContent(raw: string): string[] {\n if (!raw.trim()) return [];\n return raw\n .split(MEMORY_ENTRY_DELIMITER)\n .map((e) => e.trim())\n .filter(Boolean);\n }\n\n getSnapshot(): MemorySnapshot {\n return this.snapshot;\n }\n\n /**\n * Live entries for read/debug (may differ from snapshot after mutations).\n */\n getLiveEntries(target: 'memory' | 'user'): string[] {\n return target === 'memory' ? [...this.memoryEntries] : [...this.userEntries];\n }\n\n async add(\n target: 'memory' | 'user',\n content: string,\n ): Promise<{ success: boolean; error?: string; message?: string }> {\n const trimmed = content.trim();\n if (!trimmed) {\n return { success: false, error: 'Content cannot be empty.' };\n }\n const scanError = scanForThreats(trimmed);\n if (scanError) {\n return { success: false, error: scanError };\n }\n\n return this.withFileLock(target, async () => {\n await this.reloadTargetFromDisk(target);\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const limit = this.charLimit(target);\n\n if (entries.includes(trimmed)) {\n return { success: false, error: 'Entry already exists' };\n }\n\n const newTotal = calculateTotal([...entries, trimmed]);\n if (newTotal > limit) {\n return {\n success: false,\n error: `Memory at ${calculateTotal(entries)}/${limit} chars. Adding would exceed limit.`,\n };\n }\n\n entries.push(trimmed);\n await this.flushTargetToDisk(target);\n return { success: true, message: 'Entry added.' };\n });\n }\n\n async replace(\n target: 'memory' | 'user',\n oldText: string,\n newContent: string,\n ): Promise<{ success: boolean; error?: string; message?: string }> {\n const ot = oldText.trim();\n const nc = newContent.trim();\n if (!ot) {\n return { success: false, error: 'old_text cannot be empty.' };\n }\n if (!nc) {\n return { success: false, error: 'new_content cannot be empty. Use remove to delete entries.' };\n }\n const scanError = scanForThreats(nc);\n if (scanError) {\n return { success: false, error: scanError };\n }\n\n return this.withFileLock(target, async () => {\n await this.reloadTargetFromDisk(target);\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const matches: Array<{ index: number; entry: string }> = [];\n for (let i = 0; i < entries.length; i++) {\n if (entries[i].includes(ot)) {\n matches.push({ index: i, entry: entries[i] });\n }\n }\n\n if (matches.length === 0) {\n return { success: false, error: `No entry matched '${ot}'.` };\n }\n\n if (matches.length > 1) {\n const uniqueTexts = new Set(matches.map((m) => m.entry));\n if (uniqueTexts.size > 1) {\n const previews = matches.map((m) =>\n m.entry.length > 80 ? `${m.entry.slice(0, 80)}...` : m.entry,\n );\n return {\n success: false,\n error: `Multiple entries matched '${ot}'. Be more specific. Previews: ${previews.join(' | ')}`,\n };\n }\n }\n\n const idx = matches[0].index;\n const limit = this.charLimit(target);\n const testEntries = [...entries];\n testEntries[idx] = nc;\n\n if (calculateTotal(testEntries) > limit) {\n return {\n success: false,\n error: `Replacement would put memory at ${calculateTotal(testEntries)}/${limit} chars.`,\n };\n }\n\n entries[idx] = nc;\n await this.flushTargetToDisk(target);\n return { success: true, message: 'Entry replaced.' };\n });\n }\n\n async remove(\n target: 'memory' | 'user',\n oldText: string,\n ): Promise<{ success: boolean; error?: string; message?: string }> {\n const ot = oldText.trim();\n if (!ot) {\n return { success: false, error: 'old_text cannot be empty.' };\n }\n\n return this.withFileLock(target, async () => {\n await this.reloadTargetFromDisk(target);\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const matches: number[] = [];\n for (let i = 0; i < entries.length; i++) {\n if (entries[i].includes(ot)) {\n matches.push(i);\n }\n }\n\n if (matches.length === 0) {\n return { success: false, error: `No entry matched '${ot}'.` };\n }\n\n if (matches.length > 1) {\n const uniqueTexts = new Set(matches.map((i) => entries[i]));\n if (uniqueTexts.size > 1) {\n const previews = matches.map((i) => {\n const e = entries[i];\n return e.length > 80 ? `${e.slice(0, 80)}...` : e;\n });\n return {\n success: false,\n error: `Multiple entries matched '${ot}'. Be more specific. Previews: ${previews.join(' | ')}`,\n };\n }\n }\n\n entries.splice(matches[0], 1);\n await this.flushTargetToDisk(target);\n return { success: true, message: 'Entry removed.' };\n });\n }\n\n private async withFileLock<T>(\n target: 'memory' | 'user',\n fn: () => Promise<T>,\n ): Promise<T> {\n const filePath = this.pathFor(target);\n await mkdir(dirname(filePath), { recursive: true });\n if (!existsSync(filePath)) {\n await writeFile(filePath, '', 'utf-8');\n }\n await lockfile.lock(filePath, { retries: 3, stale: 10_000 });\n try {\n return await fn();\n } finally {\n await lockfile.unlock(filePath);\n }\n }\n\n private async reloadTargetFromDisk(target: 'memory' | 'user'): Promise<void> {\n const path = this.pathFor(target);\n let raw = '';\n try {\n raw = await readFile(path, 'utf-8');\n } catch {\n raw = '';\n }\n const parsed = dedupePreserveOrder(this.parseFileContent(raw));\n if (target === 'memory') {\n this.memoryEntries = parsed;\n } else {\n this.userEntries = parsed;\n }\n }\n\n private async flushTargetToDisk(target: 'memory' | 'user'): Promise<void> {\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const filePath = this.pathFor(target);\n const content = entries.join(MEMORY_ENTRY_DELIMITER);\n const tmpPath = `${filePath}.tmp.${Date.now()}`;\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(tmpPath, content, 'utf-8');\n await rename(tmpPath, filePath);\n }\n\n private charLimit(target: 'memory' | 'user'): number {\n return target === 'memory'\n ? (this.config.memoryCharLimit ?? DEFAULT_MEMORY_LIMIT)\n : (this.config.userCharLimit ?? DEFAULT_USER_LIMIT);\n }\n\n private renderBlock(target: 'memory' | 'user', entries: string[]): string {\n if (entries.length === 0) {\n return '';\n }\n\n const limit = this.charLimit(target);\n const content = entries.join(MEMORY_ENTRY_DELIMITER);\n const current = content.length;\n const pct = Math.min(100, Math.round((current / limit) * 100));\n\n const header =\n target === 'user'\n ? `USER PROFILE (who the user is) [${pct}% — ${current.toLocaleString()}/${limit.toLocaleString()} chars]`\n : `MEMORY (your personal notes) [${pct}% — ${current.toLocaleString()}/${limit.toLocaleString()} chars]`;\n\n const separator = '═'.repeat(46);\n return `${separator}\\n${header}\\n${separator}\\n${content}`;\n }\n}\n\nfunction dedupePreserveOrder(entries: string[]): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const e of entries) {\n if (seen.has(e)) {\n continue;\n }\n seen.add(e);\n out.push(e);\n }\n return out;\n}\n\nfunction calculateTotal(entries: string[]): number {\n if (entries.length === 0) {\n return 0;\n }\n return entries.join(MEMORY_ENTRY_DELIMITER).length;\n}\n\nexport function scanForThreats(content: string): string | null {\n const patterns: Array<{ regex: RegExp; id: string }> = [\n { regex: /ignore\\s+(previous|all|above|prior)\\s+instructions/i, id: 'prompt_injection' },\n { regex: /you\\s+are\\s+now\\s+/i, id: 'role_hijack' },\n { regex: /do\\s+not\\s+tell\\s+the\\s+user/i, id: 'deception_hide' },\n { regex: /system\\s+prompt\\s+override/i, id: 'sys_prompt_override' },\n {\n regex: /disregard\\s+(your|all|any)\\s+(instructions|rules|guidelines)/i,\n id: 'disregard_rules',\n },\n {\n regex: /act\\s+as\\s+(if|though)\\s+you\\s+(have\\s+no|don't\\s+have)\\s+(restrictions|limits|rules)/i,\n id: 'bypass_restrictions',\n },\n { regex: /curl\\s+[^\\n]*\\$\\{?\\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)/i, id: 'exfil_curl' },\n { regex: /wget\\s+[^\\n]*\\$\\{?\\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)/i, id: 'exfil_wget' },\n {\n regex: /cat\\s+[^\\n]*(\\.env|credentials|\\.netrc|\\.pgpass|\\.npmrc|\\.pypirc)/i,\n id: 'read_secrets',\n },\n { regex: /authorized_keys/i, id: 'ssh_backdoor' },\n { regex: /\\$HOME\\/\\.ssh|\\~\\/\\.ssh/i, id: 'ssh_access' },\n ];\n\n for (const { regex, id } of patterns) {\n if (regex.test(content)) {\n return `Blocked: content matches threat pattern '${id}'. Memory entries are injected into the system prompt and must not contain injection payloads.`;\n }\n }\n\n const invisibleChars = [\n '\\u200b',\n '\\u200c',\n '\\u200d',\n '\\u2060',\n '\\ufeff',\n '\\u202a',\n '\\u202b',\n '\\u202c',\n '\\u202d',\n '\\u202e',\n ];\n for (const char of invisibleChars) {\n if (content.includes(char)) {\n const code = char.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0');\n return `Blocked: content contains invisible unicode character U+${code} (possible injection).`;\n }\n }\n\n return null;\n}\n"],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@ import type { BuiltinMemoryStore } from './builtin-memory-store.js';
|
|
|
2
2
|
import type { MemoryProvider, MemoryProviderInitOptions } from './provider.js';
|
|
3
3
|
import type { MemoryDeleteRequest, MemoryListRequest, MemoryReadRequest, MemoryReadResult, MemoryRecord, MemorySearchRequest, MemorySearchResult, MemoryUpdateRequest, MemoryWriteRequest, MemoryWriteResult, MemorySyncEvent } from './types.js';
|
|
4
4
|
/**
|
|
5
|
-
* Builtin local memory provider backed by agent-home curated files,
|
|
6
|
-
*
|
|
5
|
+
* Builtin local memory provider backed by profile memory, agent-home curated files,
|
|
6
|
+
* and the local SQLite FTS index.
|
|
7
7
|
*/
|
|
8
8
|
export declare class BuiltinMemoryProvider implements MemoryProvider {
|
|
9
9
|
private readonly store;
|
|
@@ -3,8 +3,8 @@ import "../../storage/sqlite/index.js";
|
|
|
3
3
|
import { memoryGet, memorySearch } from "../prompt/memory/index.js";
|
|
4
4
|
//#region src/agent/memory/builtin-provider.ts
|
|
5
5
|
/**
|
|
6
|
-
* Builtin local memory provider backed by agent-home curated files,
|
|
7
|
-
*
|
|
6
|
+
* Builtin local memory provider backed by profile memory, agent-home curated files,
|
|
7
|
+
* and the local SQLite FTS index.
|
|
8
8
|
*/
|
|
9
9
|
var BuiltinMemoryProvider = class {
|
|
10
10
|
id = "local";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtin-provider.js","names":[],"sources":["../../../../src/agent/memory/builtin-provider.ts"],"sourcesContent":["import type { BuiltinMemoryStore } from './builtin-memory-store.js';\nimport type { MemoryProvider, MemoryProviderInitOptions } from './provider.js';\nimport { memoryGet, memorySearch } from '../prompt/memory/index.js';\nimport {\n appendMemorySignal,\n deleteMemoryRecord,\n getMemoryRecord,\n listMemoryRecords,\n searchMemoryRecords,\n upsertMemoryRecord,\n} from '../../storage/sqlite/index.js';\nimport type {\n MemoryDeleteRequest,\n MemoryListRequest,\n MemoryReadRequest,\n MemoryReadResult,\n MemoryRecord,\n MemorySearchRequest,\n MemorySearchResult,\n MemoryUpdateRequest,\n MemoryWriteRequest,\n MemoryWriteResult,\n MemorySyncEvent,\n} from './types.js';\n\n/**\n * Builtin local memory provider backed by agent-home curated files, workspace MEMORY.md,\n * daily notes, and the local SQLite FTS index.\n */\nexport class BuiltinMemoryProvider implements MemoryProvider {\n readonly id = 'local';\n readonly displayName = 'Local Markdown Memory';\n readonly capabilities = {\n search: true,\n read: true,\n write: true,\n update: true,\n delete: true,\n keywordSearch: true,\n semanticSearch: false,\n hybridSearch: false,\n citations: true,\n sync: false,\n local: true,\n };\n\n private workspaceDir = '';\n private agentId = 'main';\n\n constructor(private readonly store: BuiltinMemoryStore) {}\n\n isAvailable(): boolean {\n return true;\n }\n\n async initialize(_sessionId: string, options?: MemoryProviderInitOptions): Promise<void> {\n this.workspaceDir = options?.workspace ?? options?.agentWorkspace ?? this.store.workspaceDir;\n this.agentId = String(options?.agentId ?? this.agentId);\n }\n\n systemPromptBlock(): string {\n return '';\n }\n\n async prefetch(): Promise<string> {\n return '';\n }\n\n queuePrefetch(): void {}\n\n getToolSchemas() {\n return [];\n }\n\n async search(request: MemorySearchRequest): Promise<MemorySearchResult[]> {\n const agentId = request.scope?.agentId ?? this.agentId;\n const workspaceId = request.scope?.workspaceId ?? this.workspaceDir;\n const recordHits = searchMemoryRecords({\n query: request.query,\n agentId,\n workspaceId,\n providerId: this.id,\n kinds: request.kinds,\n maxResults: request.maxResults,\n minScore: request.minScore,\n });\n if (recordHits.length > 0) {\n return recordHits;\n }\n\n const results = await memorySearch(this.workspaceDir, request.query, {\n maxResults: request.maxResults,\n minScore: request.minScore,\n memoriesDir: this.store.memoriesDir,\n userMemoryPath: this.store.userMemoryPath,\n agentId,\n });\n return results.map((entry) => {\n const start = entry.lineNumbers[0] ?? 1;\n const end = entry.lineNumbers[entry.lineNumbers.length - 1] ?? start;\n const id = `${entry.file}#L${start}-L${end}`;\n const kind = inferKindFromPath(entry.file);\n const record = upsertMemoryRecord({\n id,\n providerId: this.id,\n kind,\n agentId,\n workspaceId,\n content: entry.lines,\n source: {\n provider: this.id,\n path: entry.file,\n lineStart: start,\n lineEnd: end,\n },\n confidence: entry.score,\n });\n return {\n record,\n score: entry.score,\n snippet: entry.lines,\n citation: {\n providerId: this.id,\n recordId: id,\n path: entry.file,\n lineStart: start,\n lineEnd: end,\n },\n };\n });\n }\n\n async read(request: MemoryReadRequest): Promise<MemoryReadResult | null> {\n if (request.id && !request.path) {\n const existing = getMemoryRecord(request.id);\n if (existing) {\n return { record: existing };\n }\n }\n const result = memoryGet(\n this.workspaceDir,\n request.path ?? request.id ?? '',\n request.from,\n request.lines,\n this.store.memoriesDir,\n this.store.userMemoryPath,\n );\n if (!result) return null;\n const path = request.path ?? request.id ?? '';\n const record = upsertMemoryRecord({\n id: `${path}#L${result.lineNumbers.start}-L${result.lineNumbers.end}`,\n providerId: this.id,\n kind: inferKindFromPath(path),\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n content: result.content,\n source: {\n provider: this.id,\n path,\n lineStart: result.lineNumbers.start,\n lineEnd: result.lineNumbers.end,\n },\n });\n return {\n record,\n lineNumbers: result.lineNumbers,\n };\n }\n\n async get(id: string): Promise<MemoryRecord | null> {\n const parsed = parseLineAddress(id);\n const result = await this.read({\n path: parsed.path,\n from: parsed.lineStart,\n lines: parsed.lineEnd != null ? parsed.lineEnd - parsed.lineStart + 1 : undefined,\n });\n return result?.record ?? null;\n }\n\n async list(request: MemoryListRequest): Promise<MemoryRecord[]> {\n const records = listMemoryRecords({\n providerId: this.id,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n kind: request.kind,\n limit: 200,\n });\n if (records.length > 0 || request.kind) {\n return request.target\n ? records.filter((record) => targetForKind(record.kind) === request.target)\n : records;\n }\n\n const target = request.target ?? (request.kind === 'user_profile' ? 'user' : 'memory');\n return this.store.getLiveEntries(target).map((content, index) =>\n upsertMemoryRecord({\n id: `curated:${target}:${index + 1}`,\n providerId: this.id,\n kind: target === 'user' ? 'user_profile' : 'agent_note',\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n content,\n source: {\n provider: this.id,\n path: sourcePathForTarget(target),\n },\n }),\n );\n }\n\n async write(request: MemoryWriteRequest): Promise<MemoryWriteResult> {\n const target = request.target ?? (request.kind === 'user_profile' ? 'user' : 'memory');\n if (request.status === 'candidate') {\n const record = upsertMemoryRecord({\n providerId: this.id,\n kind: target === 'user' ? 'user_profile' : request.kind,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n sessionKey: request.scope?.sessionKey,\n content: request.content,\n source: {\n ...(request.source ?? {}),\n provider: this.id,\n path: sourcePathForTarget(target),\n },\n confidence: request.confidence,\n tags: request.tags,\n status: 'candidate',\n sensitivity: request.sensitivity,\n evidence: request.evidence,\n reviewAfter: request.reviewAfter,\n expiresAt: request.expiresAt,\n });\n return {\n success: true,\n message: 'Memory candidate added to inbox',\n record,\n };\n }\n const result = await this.store.add(target, request.content);\n if (!result.success) return { success: false, error: result.error };\n return {\n success: true,\n message: result.message,\n record: upsertMemoryRecord({\n id: `curated:${target}:${Date.now()}`,\n providerId: this.id,\n kind: target === 'user' ? 'user_profile' : request.kind,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n sessionKey: request.scope?.sessionKey,\n content: request.content,\n source: {\n ...(request.source ?? {}),\n provider: this.id,\n path: sourcePathForTarget(target),\n },\n tags: request.tags,\n }),\n };\n }\n\n async update(request: MemoryUpdateRequest): Promise<MemoryWriteResult> {\n const target = request.target ?? 'memory';\n const result = await this.store.replace(target, request.matchText ?? request.id ?? '', request.content);\n if (!result.success) return { success: false, error: result.error };\n if (request.id) {\n const existing = getMemoryRecord(request.id);\n upsertMemoryRecord({\n id: request.id,\n providerId: this.id,\n kind: existing?.kind ?? (target === 'user' ? 'user_profile' : 'agent_note'),\n agentId: existing?.scope.agentId ?? request.scope?.agentId ?? this.agentId,\n workspaceId: existing?.scope.workspaceId ?? request.scope?.workspaceId ?? this.workspaceDir,\n sessionKey: existing?.scope.sessionKey ?? request.scope?.sessionKey,\n content: request.content,\n source: existing?.source ?? { provider: this.id, path: sourcePathForTarget(target) },\n tags: existing?.tags,\n });\n } else if (request.matchText) {\n for (const existing of listMemoryRecords({\n providerId: this.id,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n kind: target === 'user' ? 'user_profile' : 'agent_note',\n limit: 200,\n })) {\n if (!existing.content.includes(request.matchText)) continue;\n upsertMemoryRecord({\n id: existing.id,\n providerId: this.id,\n kind: existing.kind,\n agentId: existing.scope.agentId,\n workspaceId: existing.scope.workspaceId,\n sessionKey: existing.scope.sessionKey,\n content: request.content,\n source: existing.source,\n tags: existing.tags,\n });\n }\n }\n return { success: true, message: result.message };\n }\n\n async delete(request: MemoryDeleteRequest): Promise<MemoryWriteResult> {\n const target = request.target ?? 'memory';\n const result = await this.store.remove(target, request.matchText ?? request.id ?? '');\n if (!result.success) return { success: false, error: result.error };\n if (request.id) {\n deleteMemoryRecord(request.id);\n } else if (request.matchText) {\n for (const existing of listMemoryRecords({\n providerId: this.id,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n kind: target === 'user' ? 'user_profile' : 'agent_note',\n limit: 200,\n })) {\n if (existing.content.includes(request.matchText)) {\n deleteMemoryRecord(existing.id);\n }\n }\n }\n return { success: true, message: result.message };\n }\n\n sync(event: MemorySyncEvent): void {\n if (event.type !== 'signal') return;\n appendMemorySignal({\n signal: event.signal,\n providerId: this.id,\n agentId: this.agentId,\n workspaceId: this.workspaceDir,\n sessionKey:\n typeof event.signal.metadata?.sessionKey === 'string'\n ? event.signal.metadata.sessionKey\n : undefined,\n });\n }\n\n async shutdown(): Promise<void> {}\n}\n\nfunction inferKindFromPath(path: string): MemoryRecord['kind'] {\n const normalized = path.replace(/\\\\/g, '/');\n if (normalized === 'user/MEMORY.md' || normalized.endsWith('/user/MEMORY.md')) return 'user_profile';\n if (/^memory\\/\\d{4}-\\d{2}-\\d{2}\\.md$/.test(normalized)) return 'daily_note';\n if (normalized.endsWith('MEMORY.md')) return 'agent_note';\n return 'workspace_fact';\n}\n\nfunction targetForKind(kind: MemoryRecord['kind']): 'memory' | 'user' {\n return kind === 'user_profile' ? 'user' : 'memory';\n}\n\nfunction sourcePathForTarget(target: 'memory' | 'user'): string {\n return target === 'user' ? 'user/MEMORY.md' : 'MEMORY.md';\n}\n\nfunction parseLineAddress(id: string): { path: string; lineStart?: number; lineEnd?: number } {\n const match = /^(.*)#L(\\d+)(?:-L(\\d+))?$/.exec(id);\n if (!match) return { path: id };\n const lineStart = Number.parseInt(match[2] ?? '1', 10);\n const lineEnd = Number.parseInt(match[3] ?? match[2] ?? '1', 10);\n return {\n path: match[1] ?? id,\n lineStart: Number.isFinite(lineStart) ? lineStart : undefined,\n lineEnd: Number.isFinite(lineEnd) ? lineEnd : undefined,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"builtin-provider.js","names":[],"sources":["../../../../src/agent/memory/builtin-provider.ts"],"sourcesContent":["import type { BuiltinMemoryStore } from './builtin-memory-store.js';\nimport type { MemoryProvider, MemoryProviderInitOptions } from './provider.js';\nimport { memoryGet, memorySearch } from '../prompt/memory/index.js';\nimport {\n appendMemorySignal,\n deleteMemoryRecord,\n getMemoryRecord,\n listMemoryRecords,\n searchMemoryRecords,\n upsertMemoryRecord,\n} from '../../storage/sqlite/index.js';\nimport type {\n MemoryDeleteRequest,\n MemoryListRequest,\n MemoryReadRequest,\n MemoryReadResult,\n MemoryRecord,\n MemorySearchRequest,\n MemorySearchResult,\n MemoryUpdateRequest,\n MemoryWriteRequest,\n MemoryWriteResult,\n MemorySyncEvent,\n} from './types.js';\n\n/**\n * Builtin local memory provider backed by profile memory, agent-home curated files,\n * and the local SQLite FTS index.\n */\nexport class BuiltinMemoryProvider implements MemoryProvider {\n readonly id = 'local';\n readonly displayName = 'Local Markdown Memory';\n readonly capabilities = {\n search: true,\n read: true,\n write: true,\n update: true,\n delete: true,\n keywordSearch: true,\n semanticSearch: false,\n hybridSearch: false,\n citations: true,\n sync: false,\n local: true,\n };\n\n private workspaceDir = '';\n private agentId = 'main';\n\n constructor(private readonly store: BuiltinMemoryStore) {}\n\n isAvailable(): boolean {\n return true;\n }\n\n async initialize(_sessionId: string, options?: MemoryProviderInitOptions): Promise<void> {\n this.workspaceDir = options?.workspace ?? options?.agentWorkspace ?? this.store.workspaceDir;\n this.agentId = String(options?.agentId ?? this.agentId);\n }\n\n systemPromptBlock(): string {\n return '';\n }\n\n async prefetch(): Promise<string> {\n return '';\n }\n\n queuePrefetch(): void {}\n\n getToolSchemas() {\n return [];\n }\n\n async search(request: MemorySearchRequest): Promise<MemorySearchResult[]> {\n const agentId = request.scope?.agentId ?? this.agentId;\n const workspaceId = request.scope?.workspaceId ?? this.workspaceDir;\n const recordHits = searchMemoryRecords({\n query: request.query,\n agentId,\n workspaceId,\n providerId: this.id,\n kinds: request.kinds,\n maxResults: request.maxResults,\n minScore: request.minScore,\n });\n if (recordHits.length > 0) {\n return recordHits;\n }\n\n const results = await memorySearch(this.workspaceDir, request.query, {\n maxResults: request.maxResults,\n minScore: request.minScore,\n memoriesDir: this.store.memoriesDir,\n userMemoryPath: this.store.userMemoryPath,\n agentId,\n });\n return results.map((entry) => {\n const start = entry.lineNumbers[0] ?? 1;\n const end = entry.lineNumbers[entry.lineNumbers.length - 1] ?? start;\n const id = `${entry.file}#L${start}-L${end}`;\n const kind = inferKindFromPath(entry.file);\n const record = upsertMemoryRecord({\n id,\n providerId: this.id,\n kind,\n agentId,\n workspaceId,\n content: entry.lines,\n source: {\n provider: this.id,\n path: entry.file,\n lineStart: start,\n lineEnd: end,\n },\n confidence: entry.score,\n });\n return {\n record,\n score: entry.score,\n snippet: entry.lines,\n citation: {\n providerId: this.id,\n recordId: id,\n path: entry.file,\n lineStart: start,\n lineEnd: end,\n },\n };\n });\n }\n\n async read(request: MemoryReadRequest): Promise<MemoryReadResult | null> {\n if (request.id && !request.path) {\n const existing = getMemoryRecord(request.id);\n if (existing) {\n return { record: existing };\n }\n }\n const result = memoryGet(\n this.workspaceDir,\n request.path ?? request.id ?? '',\n request.from,\n request.lines,\n this.store.memoriesDir,\n this.store.userMemoryPath,\n );\n if (!result) return null;\n const path = request.path ?? request.id ?? '';\n const record = upsertMemoryRecord({\n id: `${path}#L${result.lineNumbers.start}-L${result.lineNumbers.end}`,\n providerId: this.id,\n kind: inferKindFromPath(path),\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n content: result.content,\n source: {\n provider: this.id,\n path,\n lineStart: result.lineNumbers.start,\n lineEnd: result.lineNumbers.end,\n },\n });\n return {\n record,\n lineNumbers: result.lineNumbers,\n };\n }\n\n async get(id: string): Promise<MemoryRecord | null> {\n const parsed = parseLineAddress(id);\n const result = await this.read({\n path: parsed.path,\n from: parsed.lineStart,\n lines: parsed.lineEnd != null ? parsed.lineEnd - parsed.lineStart + 1 : undefined,\n });\n return result?.record ?? null;\n }\n\n async list(request: MemoryListRequest): Promise<MemoryRecord[]> {\n const records = listMemoryRecords({\n providerId: this.id,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n kind: request.kind,\n limit: 200,\n });\n if (records.length > 0 || request.kind) {\n return request.target\n ? records.filter((record) => targetForKind(record.kind) === request.target)\n : records;\n }\n\n const target = request.target ?? (request.kind === 'user_profile' ? 'user' : 'memory');\n return this.store.getLiveEntries(target).map((content, index) =>\n upsertMemoryRecord({\n id: `curated:${target}:${index + 1}`,\n providerId: this.id,\n kind: target === 'user' ? 'user_profile' : 'agent_note',\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n content,\n source: {\n provider: this.id,\n path: sourcePathForTarget(target),\n },\n }),\n );\n }\n\n async write(request: MemoryWriteRequest): Promise<MemoryWriteResult> {\n const target = request.target ?? (request.kind === 'user_profile' ? 'user' : 'memory');\n if (request.status === 'candidate') {\n const record = upsertMemoryRecord({\n providerId: this.id,\n kind: target === 'user' ? 'user_profile' : request.kind,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n sessionKey: request.scope?.sessionKey,\n content: request.content,\n source: {\n ...(request.source ?? {}),\n provider: this.id,\n path: sourcePathForTarget(target),\n },\n confidence: request.confidence,\n tags: request.tags,\n status: 'candidate',\n sensitivity: request.sensitivity,\n evidence: request.evidence,\n reviewAfter: request.reviewAfter,\n expiresAt: request.expiresAt,\n });\n return {\n success: true,\n message: 'Memory candidate added to inbox',\n record,\n };\n }\n const result = await this.store.add(target, request.content);\n if (!result.success) return { success: false, error: result.error };\n return {\n success: true,\n message: result.message,\n record: upsertMemoryRecord({\n id: `curated:${target}:${Date.now()}`,\n providerId: this.id,\n kind: target === 'user' ? 'user_profile' : request.kind,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n sessionKey: request.scope?.sessionKey,\n content: request.content,\n source: {\n ...(request.source ?? {}),\n provider: this.id,\n path: sourcePathForTarget(target),\n },\n tags: request.tags,\n }),\n };\n }\n\n async update(request: MemoryUpdateRequest): Promise<MemoryWriteResult> {\n const target = request.target ?? 'memory';\n const result = await this.store.replace(target, request.matchText ?? request.id ?? '', request.content);\n if (!result.success) return { success: false, error: result.error };\n if (request.id) {\n const existing = getMemoryRecord(request.id);\n upsertMemoryRecord({\n id: request.id,\n providerId: this.id,\n kind: existing?.kind ?? (target === 'user' ? 'user_profile' : 'agent_note'),\n agentId: existing?.scope.agentId ?? request.scope?.agentId ?? this.agentId,\n workspaceId: existing?.scope.workspaceId ?? request.scope?.workspaceId ?? this.workspaceDir,\n sessionKey: existing?.scope.sessionKey ?? request.scope?.sessionKey,\n content: request.content,\n source: existing?.source ?? { provider: this.id, path: sourcePathForTarget(target) },\n tags: existing?.tags,\n });\n } else if (request.matchText) {\n for (const existing of listMemoryRecords({\n providerId: this.id,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n kind: target === 'user' ? 'user_profile' : 'agent_note',\n limit: 200,\n })) {\n if (!existing.content.includes(request.matchText)) continue;\n upsertMemoryRecord({\n id: existing.id,\n providerId: this.id,\n kind: existing.kind,\n agentId: existing.scope.agentId,\n workspaceId: existing.scope.workspaceId,\n sessionKey: existing.scope.sessionKey,\n content: request.content,\n source: existing.source,\n tags: existing.tags,\n });\n }\n }\n return { success: true, message: result.message };\n }\n\n async delete(request: MemoryDeleteRequest): Promise<MemoryWriteResult> {\n const target = request.target ?? 'memory';\n const result = await this.store.remove(target, request.matchText ?? request.id ?? '');\n if (!result.success) return { success: false, error: result.error };\n if (request.id) {\n deleteMemoryRecord(request.id);\n } else if (request.matchText) {\n for (const existing of listMemoryRecords({\n providerId: this.id,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n kind: target === 'user' ? 'user_profile' : 'agent_note',\n limit: 200,\n })) {\n if (existing.content.includes(request.matchText)) {\n deleteMemoryRecord(existing.id);\n }\n }\n }\n return { success: true, message: result.message };\n }\n\n sync(event: MemorySyncEvent): void {\n if (event.type !== 'signal') return;\n appendMemorySignal({\n signal: event.signal,\n providerId: this.id,\n agentId: this.agentId,\n workspaceId: this.workspaceDir,\n sessionKey:\n typeof event.signal.metadata?.sessionKey === 'string'\n ? event.signal.metadata.sessionKey\n : undefined,\n });\n }\n\n async shutdown(): Promise<void> {}\n}\n\nfunction inferKindFromPath(path: string): MemoryRecord['kind'] {\n const normalized = path.replace(/\\\\/g, '/');\n if (normalized === 'user/MEMORY.md' || normalized.endsWith('/user/MEMORY.md')) return 'user_profile';\n if (/^memory\\/\\d{4}-\\d{2}-\\d{2}\\.md$/.test(normalized)) return 'daily_note';\n if (normalized.endsWith('MEMORY.md')) return 'agent_note';\n return 'workspace_fact';\n}\n\nfunction targetForKind(kind: MemoryRecord['kind']): 'memory' | 'user' {\n return kind === 'user_profile' ? 'user' : 'memory';\n}\n\nfunction sourcePathForTarget(target: 'memory' | 'user'): string {\n return target === 'user' ? 'user/MEMORY.md' : 'MEMORY.md';\n}\n\nfunction parseLineAddress(id: string): { path: string; lineStart?: number; lineEnd?: number } {\n const match = /^(.*)#L(\\d+)(?:-L(\\d+))?$/.exec(id);\n if (!match) return { path: id };\n const lineStart = Number.parseInt(match[2] ?? '1', 10);\n const lineEnd = Number.parseInt(match[3] ?? match[2] ?? '1', 10);\n return {\n path: match[1] ?? id,\n lineStart: Number.isFinite(lineStart) ? lineStart : undefined,\n lineEnd: Number.isFinite(lineEnd) ? lineEnd : undefined,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
import type { DreamingLightConfig } from './config.js';
|
|
2
|
-
/**
|
|
3
|
-
* Scan recent daily memory files (memory/YYYY-MM-DD.md) and collect signal
|
|
4
|
-
* entries into the short-term store. Deduplicates near-identical snippets
|
|
5
|
-
* using trigram similarity.
|
|
6
|
-
*
|
|
7
|
-
* This is the "light sleep" phase: fast, frequent, cheap.
|
|
8
|
-
*/
|
|
9
2
|
export declare function runLightSweep(params: {
|
|
10
3
|
workspaceDir: string;
|
|
11
4
|
config?: Partial<DreamingLightConfig>;
|