@xopcai/xopc 0.0.123 → 0.0.125
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 +28 -11
- package/README.zh-CN.md +28 -11
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/Combination-BzaXOLd9.js +41 -0
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-Bicr3ZBg.js → agent-avatar-dicebear-BKDKICZV.js} +1 -1
- package/dist/gateway/static/root/assets/agents-BnTB7-c5.js +2 -0
- package/dist/gateway/static/root/assets/app-management-settings-panel-DI4BqHKW.js +1 -0
- package/dist/gateway/static/root/assets/appearance-settings-6_ie3NQ4.js +1 -0
- package/dist/gateway/static/root/assets/apps-page-B6bG65SW.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-Bpy64GjU.js → archive-plugin-kUHEJ1HK.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DMkp4xSb.js → attachment-load-Dm-9prpU.js} +1 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-OTxQTPnC.js +1 -0
- package/dist/gateway/static/root/assets/automations-page-1lVbo0dS.js +1 -0
- package/dist/gateway/static/root/assets/{binary-plugins-DA9C5mCw.js → binary-plugins-DllA_jQ0.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CiSXk_YC.js → block-editor-Cm6CWNj1.js} +5 -5
- package/dist/gateway/static/root/assets/browser-settings-page-CzDBlOK0.js +8 -0
- package/dist/gateway/static/root/assets/capability-presets-api-VJ89b6I2.js +1 -0
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-BaPj8wC2.js +1 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-CDhrhfhN.js → channel-recipient-api-B5PwBEUx.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-Df4m7p1k.js +1 -0
- package/dist/gateway/static/root/assets/code-editor-gbRgS14t.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-BMTphmHS.js +2 -0
- package/dist/gateway/static/root/assets/{directory-picker-path-field-7jKfbH0J.js → directory-picker-path-field-DySMzOF6.js} +1 -1
- package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +1 -0
- package/dist/gateway/static/root/assets/dist-CkobR7mk.js +1 -0
- package/dist/gateway/static/root/assets/dist-DokQNVMQ.js +1 -0
- package/dist/gateway/static/root/assets/dreaming-settings-D_AjSnV_.js +3 -0
- package/dist/gateway/static/root/assets/extension-debug-page-BaM0FpW7.js +1 -0
- package/dist/gateway/static/root/assets/extension-page-DuZWVOGA.js +1 -0
- package/dist/gateway/static/root/assets/extension-settings-page-DarVtbmJ.js +1 -0
- package/dist/gateway/static/root/assets/{fetch-Dtpbbe0s.js → fetch-NFKfkqrd.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-BN6pyX2c.js → gateway-config-api-CFEm9rgy.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-BMk2S5td.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-BIET2x3y.js → gateway-startup-retry-Dtwh_yGg.js} +1 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-BKP7ylcG.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-C2cTxf71.js +1 -0
- package/dist/gateway/static/root/assets/{goals-config-api-CQm2r1Ty.js → goals-config-api-DTWZNA_Y.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-CTmA3hWK.js +2 -0
- package/dist/gateway/static/root/assets/goals-settings-Bhct0ZT-.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-C-UxSU4a.js +1 -0
- package/dist/gateway/static/root/assets/{html-workspace-editor-CQLWDiwE.js → html-workspace-editor-DV90ddkE.js} +1 -1
- package/dist/gateway/static/root/assets/index-BNHDd2j1.css +1 -0
- package/dist/gateway/static/root/assets/index-BPXLPMuY.js +193 -0
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-DCjy2y4d.js +1 -0
- package/dist/gateway/static/root/assets/logs-page-CGc3_CQU.js +2 -0
- package/dist/gateway/static/root/assets/{markdown-editor-AssmZFx4.js → markdown-editor-BFOjBBla.js} +2 -2
- package/dist/gateway/static/root/assets/markdown-split-BaqxP-GQ.js +1 -0
- package/dist/gateway/static/root/assets/{media-plugins-DS44pJzr.js → media-plugins-DQ_EXloK.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CjuIJcZl.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-Drz4UQMb.js +2 -0
- package/dist/gateway/static/root/assets/notes-page-CY1ylng1.js +1 -0
- package/dist/gateway/static/root/assets/notes-workbench-X7IaD--t.js +2 -0
- package/dist/gateway/static/root/assets/page-tabs-EIZhLppK.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-Dej6zHnr.js → preview-open-alternatives-r_uB4Epr.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DE5adRBE.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-CuOb1k6F.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-BOxNrUVA.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-Zu1FzH6z.js → save-bar-controls-B132Uf-2.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-BW78mKc0.js → schedule-field-B5qshALm.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-Cc-IOydE.js → schema-form-CvLmkdS9.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-CY0IQcGW.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-D4NBNVCB.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-DIpIYht_.js → settings-collapsible-section-pRlvqsAf.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-BFxBNxOG.js → settings-form-section-BBYUDLVd.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-C4fivemT.js → settings-page-DaO7zYZM.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-CLx4o2PN.js → settings-page-layout-D8g9PAek.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Bks0CLLT.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-ZswWCrDu.js → share-preview-page-v6-IOp8t.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-CEZsKm9r.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-oTkHbb9W.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-DigsbZ6K.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-3ZNcGRhS.js → system-settings-panel-HUU2FFjM.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-bpzZjiVF.js → typed-models-lib-AH160QHh.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-BCjZLZ3O.js → use-channel-catalog-BXzDmjCQ.js} +1 -1
- package/dist/gateway/static/root/assets/{user-profile-settings-panel-CIXafITi.js → user-profile-settings-panel-DxwnQvQ3.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-DXMtz5j_.js → utils-i5POEtqd.js} +1 -1
- package/dist/gateway/static/root/assets/{vendor-codemirror-CNP1wPe7.js → vendor-codemirror-BvNgyE1Q.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-CEJklEgb.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-CD6FL_Rs.js +1 -0
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-ClVVMgN-.js +3 -0
- package/dist/gateway/static/root/assets/{workflow-start-dialog-B4sZpTDQ.js → workflow-start-dialog-Dv4ZA1T0.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-OLQiUpoW.js +18 -0
- package/dist/gateway/static/root/index.html +8 -7
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +6 -1
- package/dist/src/agent/agent-manager.js +34 -14
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/child-agent-factory.d.ts +2 -0
- package/dist/src/agent/child-agent-factory.js +2 -0
- package/dist/src/agent/child-agent-factory.js.map +1 -1
- package/dist/src/agent/coding/index.d.ts +1 -0
- package/dist/src/agent/coding/index.js +2 -0
- package/dist/src/agent/coding/turn-diff-tracker.d.ts +67 -0
- package/dist/src/agent/coding/turn-diff-tracker.js +233 -0
- package/dist/src/agent/coding/turn-diff-tracker.js.map +1 -0
- package/dist/src/agent/context/workspace-templates/AGENTS.md +1 -1
- package/dist/src/agent/embedded/xopc-tools-bridge.js +11 -7
- package/dist/src/agent/embedded/xopc-tools-bridge.js.map +1 -1
- package/dist/src/agent/lifecycle/progress.js +3 -1
- package/dist/src/agent/lifecycle/progress.js.map +1 -1
- package/dist/src/agent/lifecycle/timeout-wrapper.d.ts +2 -2
- package/dist/src/agent/lifecycle/timeout-wrapper.js +4 -4
- package/dist/src/agent/lifecycle/timeout-wrapper.js.map +1 -1
- package/dist/src/agent/memory/dreaming/config.d.ts +2 -2
- package/dist/src/agent/memory/dreaming/config.js +3 -3
- package/dist/src/agent/memory/dreaming/config.js.map +1 -1
- package/dist/src/agent/memory/dreaming/constants.d.ts +1 -1
- package/dist/src/agent/memory/dreaming/constants.js +1 -1
- package/dist/src/agent/memory/dreaming/constants.js.map +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.d.ts +1 -0
- package/dist/src/agent/memory/dreaming/deep-promotion.js +11 -20
- package/dist/src/agent/memory/dreaming/deep-promotion.js.map +1 -1
- package/dist/src/agent/memory/dreaming/events.d.ts +3 -3
- package/dist/src/agent/memory/dreaming/events.js +6 -6
- package/dist/src/agent/memory/dreaming/events.js.map +1 -1
- package/dist/src/agent/memory/dreaming/last-run.d.ts +2 -2
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js.map +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.d.ts +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +3 -3
- package/dist/src/agent/memory/dreaming/light-sweep.js.map +1 -1
- package/dist/src/agent/memory/dreaming/preview.d.ts +1 -0
- package/dist/src/agent/memory/dreaming/preview.js +2 -2
- package/dist/src/agent/memory/dreaming/preview.js.map +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.d.ts +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +13 -13
- package/dist/src/agent/memory/dreaming/rem-patterns.js.map +1 -1
- package/dist/src/agent/memory/dreaming/scope.d.ts +14 -0
- package/dist/src/agent/memory/dreaming/scope.js +27 -0
- package/dist/src/agent/memory/dreaming/scope.js.map +1 -0
- package/dist/src/agent/memory/dreaming/short-term-store.d.ts +4 -4
- package/dist/src/agent/memory/dreaming/short-term-store.js +17 -17
- package/dist/src/agent/memory/dreaming/short-term-store.js.map +1 -1
- package/dist/src/agent/memory/summary-generator.d.ts +1 -1
- package/dist/src/agent/memory/summary-generator.js +1 -2
- package/dist/src/agent/memory/summary-generator.js.map +1 -1
- package/dist/src/agent/middleware/index.d.ts +1 -1
- package/dist/src/agent/middleware/self-verify.d.ts +44 -14
- package/dist/src/agent/middleware/self-verify.js +214 -44
- package/dist/src/agent/middleware/self-verify.js.map +1 -1
- package/dist/src/agent/orchestration/agent-event-handler.d.ts +2 -0
- package/dist/src/agent/orchestration/agent-event-handler.js +69 -14
- package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js +22 -12
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/prompt/sections/tooling.js +18 -13
- package/dist/src/agent/prompt/sections/tooling.js.map +1 -1
- package/dist/src/agent/prompt/system-reminder.js +2 -2
- package/dist/src/agent/prompt/system-reminder.js.map +1 -1
- package/dist/src/agent/sandbox/command-validator.js +12 -0
- package/dist/src/agent/sandbox/command-validator.js.map +1 -1
- package/dist/src/agent/sandbox/sanitize-env-vars.d.ts +2 -2
- package/dist/src/agent/sandbox/sanitize-env-vars.js +2 -2
- package/dist/src/agent/sandbox/sanitize-env-vars.js.map +1 -1
- package/dist/src/agent/sandbox/types.d.ts +2 -2
- package/dist/src/agent/sandbox/types.js.map +1 -1
- package/dist/src/agent/service/btw-query.js +1 -1
- package/dist/src/agent/service/btw-query.js.map +1 -1
- package/dist/src/agent/service/process-direct-one-shot.js +6 -2
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.js +12 -7
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service.d.ts +2 -1
- package/dist/src/agent/service.js +19 -6
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/session/session-inspector.d.ts +5 -3
- package/dist/src/agent/session/session-inspector.js +16 -7
- package/dist/src/agent/session/session-inspector.js.map +1 -1
- package/dist/src/agent/skills/skill-tool-gating.js +1 -1
- package/dist/src/agent/skills/skill-tool-gating.js.map +1 -1
- package/dist/src/agent/source-context/types.d.ts +1 -1
- package/dist/src/agent/source-context/types.js +1 -1
- package/dist/src/agent/source-context/types.js.map +1 -1
- package/dist/src/agent/starter-agents.js +9 -9
- package/dist/src/agent/starter-agents.js.map +1 -1
- package/dist/src/agent/tools/apply-patch.d.ts +25 -0
- package/dist/src/agent/tools/apply-patch.js +310 -0
- package/dist/src/agent/tools/apply-patch.js.map +1 -0
- package/dist/src/agent/tools/concurrency.d.ts +8 -0
- package/dist/src/agent/tools/concurrency.js +31 -0
- package/dist/src/agent/tools/concurrency.js.map +1 -0
- package/dist/src/agent/tools/delegate-tool.d.ts +1 -1
- package/dist/src/agent/tools/delegate-tool.js +3 -3
- package/dist/src/agent/tools/delegate-tool.js.map +1 -1
- package/dist/src/agent/tools/dreaming-tool.d.ts +2 -0
- package/dist/src/agent/tools/dreaming-tool.js +13 -10
- package/dist/src/agent/tools/dreaming-tool.js.map +1 -1
- package/dist/src/agent/tools/exec-command.d.ts +30 -0
- package/dist/src/agent/tools/exec-command.js +228 -0
- package/dist/src/agent/tools/exec-command.js.map +1 -0
- package/dist/src/agent/tools/execute-code-tool.js +7 -4
- package/dist/src/agent/tools/execute-code-tool.js.map +1 -1
- package/dist/src/agent/tools/executor.d.ts +6 -4
- package/dist/src/agent/tools/executor.js +7 -4
- package/dist/src/agent/tools/executor.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +6 -3
- package/dist/src/agent/tools/factory.js +14 -9
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/find.js +2 -0
- package/dist/src/agent/tools/find.js.map +1 -1
- package/dist/src/agent/tools/grep.js +2 -0
- package/dist/src/agent/tools/grep.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +5 -2
- package/dist/src/agent/tools/index.js +7 -4
- package/dist/src/agent/tools/list-dir.js +2 -0
- package/dist/src/agent/tools/list-dir.js.map +1 -1
- package/dist/src/agent/tools/memory-tool.d.ts +1 -0
- package/dist/src/agent/tools/memory-tool.js +2 -2
- package/dist/src/agent/tools/memory-tool.js.map +1 -1
- package/dist/src/agent/tools/metadata.d.ts +15 -0
- package/dist/src/agent/tools/metadata.js +26 -0
- package/dist/src/agent/tools/metadata.js.map +1 -0
- package/dist/src/agent/tools/read.js +2 -0
- package/dist/src/agent/tools/read.js.map +1 -1
- package/dist/src/agent/tools/skills-tools.d.ts +1 -1
- package/dist/src/agent/tools/skills-tools.js.map +1 -1
- package/dist/src/agent/tools/update-plan-tool.d.ts +11 -0
- package/dist/src/agent/tools/update-plan-tool.js +72 -0
- package/dist/src/agent/tools/update-plan-tool.js.map +1 -0
- package/dist/src/agent/tools/write.js +6 -0
- package/dist/src/agent/tools/write.js.map +1 -1
- package/dist/src/agent/workflow/builtins/debug-incident.d.ts +1 -1
- package/dist/src/agent/workflow/builtins/debug-incident.js +1 -1
- package/dist/src/agent/workflow/builtins/debug-incident.js.map +1 -1
- package/dist/src/agent/workflow/builtins/pr-review.d.ts +1 -1
- package/dist/src/agent/workflow/builtins/pr-review.js +1 -1
- package/dist/src/agent/workflow/builtins/pr-review.js.map +1 -1
- package/dist/src/agent/workflow/builtins/release-check.d.ts +1 -1
- package/dist/src/agent/workflow/builtins/release-check.js +1 -1
- package/dist/src/agent/workflow/builtins/release-check.js.map +1 -1
- package/dist/src/agent/workflow/step-labels.js +7 -3
- package/dist/src/agent/workflow/step-labels.js.map +1 -1
- package/dist/src/agent/workflow/subagent-runner.d.ts +1 -0
- package/dist/src/agent/workflow/subagent-runner.js +5 -1
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
- package/dist/src/agent/workflow/workflow-child-tools.js +5 -0
- package/dist/src/agent/workflow/workflow-child-tools.js.map +1 -1
- package/dist/src/chat-commands/agent-edit.js +1 -1
- package/dist/src/chat-commands/agent-edit.js.map +1 -1
- package/dist/src/chat-commands/builtins/review.d.ts +1 -0
- package/dist/src/chat-commands/builtins/review.js +167 -0
- package/dist/src/chat-commands/builtins/review.js.map +1 -0
- package/dist/src/chat-commands/index.d.ts +1 -0
- package/dist/src/chat-commands/index.js +3 -1
- package/dist/src/chat-commands/index.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/connectors/health.d.ts +2 -1
- package/dist/src/connectors/health.js +59 -1
- package/dist/src/connectors/health.js.map +1 -1
- package/dist/src/connectors/install.d.ts +1 -0
- package/dist/src/connectors/install.js +28 -1
- package/dist/src/connectors/install.js.map +1 -1
- package/dist/src/connectors/instances.js +7 -0
- package/dist/src/connectors/instances.js.map +1 -1
- package/dist/src/connectors/materialize.js +2 -1
- package/dist/src/connectors/materialize.js.map +1 -1
- package/dist/src/connectors/registries/modelscope.js +38 -13
- package/dist/src/connectors/registries/modelscope.js.map +1 -1
- package/dist/src/connectors/types.d.ts +2 -0
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/agent-builtin-tools.js +3 -2
- package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
- package/dist/src/gateway/chat-stream/mapper.d.ts +6 -0
- package/dist/src/gateway/chat-stream/mapper.js +149 -6
- package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
- package/dist/src/gateway/chat-stream/protocol.d.ts +51 -1
- package/dist/src/gateway/dreaming-automation-reconciler.d.ts +1 -0
- package/dist/src/gateway/dreaming-automation-reconciler.js +62 -42
- package/dist/src/gateway/dreaming-automation-reconciler.js.map +1 -1
- package/dist/src/gateway/hono/app.js +7 -1
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/routes/commands-skills.js +21 -0
- package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
- package/dist/src/gateway/hono/routes/connectors.js +46 -2
- package/dist/src/gateway/hono/routes/connectors.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +111 -66
- package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/index.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +1 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/projects.js +886 -45
- package/dist/src/gateway/hono/routes/projects.js.map +1 -1
- package/dist/src/gateway/hono/routes/search.d.ts +3 -0
- package/dist/src/gateway/hono/routes/search.js +47 -0
- package/dist/src/gateway/hono/routes/search.js.map +1 -0
- package/dist/src/gateway/hono/routes/sessions.js +1 -0
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/security/dangerous-tools.js +1 -1
- package/dist/src/gateway/security/dangerous-tools.js.map +1 -1
- package/dist/src/gateway/service.js +17 -8
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/mcp/channel-bridge.js +1 -1
- package/dist/src/media/store.js +1 -1
- package/dist/src/media/store.js.map +1 -1
- package/dist/src/media/types.d.ts +1 -1
- package/dist/src/media/uri.js +2 -1
- package/dist/src/media/uri.js.map +1 -1
- package/dist/src/projects/index.d.ts +2 -0
- package/dist/src/projects/index.js +3 -1
- package/dist/src/projects/project-agent-suggestion.d.ts +14 -0
- package/dist/src/projects/project-agent-suggestion.js +19 -0
- package/dist/src/projects/project-agent-suggestion.js.map +1 -0
- package/dist/src/projects/project-kind.d.ts +13 -0
- package/dist/src/projects/project-kind.js +147 -0
- package/dist/src/projects/project-kind.js.map +1 -0
- package/dist/src/projects/project-service.d.ts +1 -0
- package/dist/src/projects/project-service.js +1 -1
- package/dist/src/projects/project-service.js.map +1 -1
- package/dist/src/projects/project-store.js +32 -8
- package/dist/src/projects/project-store.js.map +1 -1
- package/dist/src/projects/types.d.ts +1 -0
- package/dist/src/review/review-git.d.ts +48 -0
- package/dist/src/review/review-git.js +333 -0
- package/dist/src/review/review-git.js.map +1 -0
- package/dist/src/review/review-types.d.ts +22 -0
- package/dist/src/review/review-types.js +29 -0
- package/dist/src/review/review-types.js.map +1 -0
- package/dist/src/session/session-context-for-llm.d.ts +2 -0
- package/dist/src/session/session-context-for-llm.js +165 -1
- package/dist/src/session/session-context-for-llm.js.map +1 -1
- package/dist/src/session/store.js +2 -2
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/021_projects_fts.sql +21 -0
- package/dist/src/storage/sqlite/migrations/022_work_items.sql +61 -0
- package/dist/src/storage/sqlite/migrations/023_work_item_attachments.sql +15 -0
- package/dist/src/storage/sqlite/migrations/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/schema.js +1 -1
- package/dist/src/storage/sqlite/schema.sql +78 -0
- package/dist/src/tui/backends/embedded-backend.d.ts +1 -0
- package/dist/src/tui/backends/embedded-backend.js +20 -0
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +2 -0
- package/dist/src/tui/backends/gateway-sse-backend.js +7 -0
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/components/assistant-message.js +47 -2
- package/dist/src/tui/components/assistant-message.js.map +1 -1
- package/dist/src/tui/components/tool-execution.d.ts +8 -0
- package/dist/src/tui/components/tool-execution.js +87 -77
- package/dist/src/tui/components/tool-execution.js.map +1 -1
- package/dist/src/tui/components/visual-truncate.d.ts +1 -0
- package/dist/src/tui/components/visual-truncate.js +28 -1
- package/dist/src/tui/components/visual-truncate.js.map +1 -1
- package/dist/src/tui/tool-summary.d.ts +22 -0
- package/dist/src/tui/tool-summary.js +212 -0
- package/dist/src/tui/tool-summary.js.map +1 -0
- package/dist/src/tui/tui-agent-events.js +25 -0
- package/dist/src/tui/tui-agent-events.js.map +1 -1
- package/dist/src/tui/tui-backend.d.ts +4 -0
- package/dist/src/tui/tui-commands.d.ts +1 -0
- package/dist/src/tui/tui-commands.js +110 -4
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-picker-overlay.d.ts +2 -0
- package/dist/src/tui/tui-picker-overlay.js +153 -1
- package/dist/src/tui/tui-picker-overlay.js.map +1 -1
- package/dist/src/tui/tui-tool-diff.d.ts +15 -0
- package/dist/src/tui/tui-tool-diff.js +178 -7
- package/dist/src/tui/tui-tool-diff.js.map +1 -1
- package/dist/src/tui/tui.js +16 -3
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/work-items/agent-context.d.ts +3 -0
- package/dist/src/work-items/agent-context.js +39 -0
- package/dist/src/work-items/agent-context.js.map +1 -0
- package/dist/src/work-items/index.d.ts +4 -0
- package/dist/src/work-items/index.js +4 -0
- package/dist/src/work-items/types.d.ts +112 -0
- package/dist/src/work-items/types.js +1 -0
- package/dist/src/work-items/work-item-service.d.ts +33 -0
- package/dist/src/work-items/work-item-service.js +180 -0
- package/dist/src/work-items/work-item-service.js.map +1 -0
- package/dist/src/work-items/work-item-store.d.ts +21 -0
- package/dist/src/work-items/work-item-store.js +302 -0
- package/dist/src/work-items/work-item-store.js.map +1 -0
- package/dist/src/workflows/service/workflow-run-service.js +4 -3
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-session-bridge.js +3 -0
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +0 -41
- package/dist/gateway/static/root/assets/agents-CxDSFHGx.js +0 -2
- package/dist/gateway/static/root/assets/app-management-settings-panel-CbEy9sR1.js +0 -1
- package/dist/gateway/static/root/assets/appearance-settings-CTHja6n9.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-CyZdgqvm.js +0 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-KnYaP7NT.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-8VLKM4au.js +0 -1
- package/dist/gateway/static/root/assets/browser-settings-page-5tPg0DcP.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-api-CEJ44WCU.js +0 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-BJW3aVST.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-CorUCTrs.js +0 -1
- package/dist/gateway/static/root/assets/code-editor-dZTY2dRW.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-VKstC3sP.js +0 -2
- package/dist/gateway/static/root/assets/dist-Mys7eFJ5.js +0 -1
- package/dist/gateway/static/root/assets/dist-wO9a2_ID.js +0 -1
- package/dist/gateway/static/root/assets/dreaming-settings-m1-wmz4o.js +0 -1
- package/dist/gateway/static/root/assets/extension-debug-page-C9qQQrBS.js +0 -1
- package/dist/gateway/static/root/assets/extension-page-DcBBMEGl.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-BQ-jMMP9.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-hQtgVmSR.js +0 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-BuIMDx6C.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-FEypCq74.js +0 -1
- package/dist/gateway/static/root/assets/goals-page-C4-2_MLG.js +0 -2
- package/dist/gateway/static/root/assets/goals-settings-DDrdRMxB.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-BJVok3Sl.js +0 -1
- package/dist/gateway/static/root/assets/index-CBDr5xjB.css +0 -1
- package/dist/gateway/static/root/assets/index-T0SaNd5a.js +0 -191
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-C2TuQppb.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-DwkwPgid.js +0 -2
- package/dist/gateway/static/root/assets/markdown-split-DhONQ81k.js +0 -1
- package/dist/gateway/static/root/assets/messages-avfvyZuQ.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-huNY4A1G.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-DdfGuEZ1.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-B0bT9Hqa.js +0 -2
- package/dist/gateway/static/root/assets/project-detail-page-CjxhPorG.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-C4Z5OJMF.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CVCOPUVd.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-B4qExXHC.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-Ce8yLTBi.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Kyc4eUf0.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-Bu76CMiC.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-D-CFg86j.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-CUU4f6Ss.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-C1MrQD8R.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-DqizIcY5.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-B3sVNPFk.js +0 -18
- package/dist/src/agent/tools/edit.d.ts +0 -14
- package/dist/src/agent/tools/edit.js +0 -132
- package/dist/src/agent/tools/edit.js.map +0 -1
- package/dist/src/agent/tools/shell.d.ts +0 -15
- package/dist/src/agent/tools/shell.js +0 -158
- package/dist/src/agent/tools/shell.js.map +0 -1
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
//#region src/agent/coding/turn-diff-tracker.ts
|
|
2
|
+
const DEFAULT_TURN_ID = "default";
|
|
3
|
+
function createState(sessionKey, turnId = DEFAULT_TURN_ID) {
|
|
4
|
+
return {
|
|
5
|
+
sessionKey,
|
|
6
|
+
turnId,
|
|
7
|
+
changedFiles: [],
|
|
8
|
+
changes: [],
|
|
9
|
+
cumulativeDiff: "",
|
|
10
|
+
added: 0,
|
|
11
|
+
removed: 0,
|
|
12
|
+
dirty: false,
|
|
13
|
+
diffReviewed: false,
|
|
14
|
+
verificationAttempted: false
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function readRecord(value) {
|
|
18
|
+
return value && typeof value === "object" ? value : null;
|
|
19
|
+
}
|
|
20
|
+
function readDetails(result) {
|
|
21
|
+
return readRecord(readRecord(result)?.details);
|
|
22
|
+
}
|
|
23
|
+
function readString(value) {
|
|
24
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
25
|
+
}
|
|
26
|
+
function readNumber(value) {
|
|
27
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
28
|
+
}
|
|
29
|
+
function readExitCode(value) {
|
|
30
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
31
|
+
if (value === null) return null;
|
|
32
|
+
}
|
|
33
|
+
function readStringArray(value) {
|
|
34
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.trim().length > 0) : [];
|
|
35
|
+
}
|
|
36
|
+
function uniqueSorted(values) {
|
|
37
|
+
return Array.from(new Set(Array.from(values).filter(Boolean))).sort();
|
|
38
|
+
}
|
|
39
|
+
function extractExecCommand(args, result) {
|
|
40
|
+
const argRec = readRecord(args);
|
|
41
|
+
const fromArgs = readString(argRec?.cmd) ?? readString(argRec?.command);
|
|
42
|
+
if (fromArgs) return fromArgs;
|
|
43
|
+
return readString(readDetails(result)?.command) ?? "";
|
|
44
|
+
}
|
|
45
|
+
function isDiffReviewCommand(command) {
|
|
46
|
+
return /\bgit\s+(diff|status)\b/i.test(command);
|
|
47
|
+
}
|
|
48
|
+
function isVerificationCommand(command) {
|
|
49
|
+
return /\b(test|vitest|jest|mocha|ava|playwright|typecheck|type-check|tsc|build|lint)\b/i.test(command);
|
|
50
|
+
}
|
|
51
|
+
function commandMayMutateWorkspace(command) {
|
|
52
|
+
return /\b(sed\s+-i|perl\s+-pi|rm\s+|mv\s+|cp\s+|git\s+(checkout|reset|clean|apply|merge|rebase)|writeFile|write\(|open\([^)]*['"]w['"])/i.test(command);
|
|
53
|
+
}
|
|
54
|
+
function execSuccess(isError, result) {
|
|
55
|
+
if (isError) return false;
|
|
56
|
+
const details = readDetails(result);
|
|
57
|
+
if (!details) return false;
|
|
58
|
+
if (details.timedOut === true) return false;
|
|
59
|
+
if (details.status === "success") return true;
|
|
60
|
+
return details.exitCode === 0;
|
|
61
|
+
}
|
|
62
|
+
function appendSection(lines, title, body) {
|
|
63
|
+
if (body.length === 0) return;
|
|
64
|
+
lines.push(title, ...body);
|
|
65
|
+
}
|
|
66
|
+
var TurnDiffTracker = class {
|
|
67
|
+
states = /* @__PURE__ */ new Map();
|
|
68
|
+
beginTurn(sessionKey, turnId = `${Date.now()}`) {
|
|
69
|
+
this.states.set(sessionKey, createState(sessionKey, turnId));
|
|
70
|
+
}
|
|
71
|
+
getState(sessionKey) {
|
|
72
|
+
const state = this.states.get(sessionKey) ?? createState(sessionKey);
|
|
73
|
+
return {
|
|
74
|
+
...state,
|
|
75
|
+
changedFiles: [...state.changedFiles],
|
|
76
|
+
changes: state.changes.map((change) => ({ ...change })),
|
|
77
|
+
lastVerification: state.lastVerification ? { ...state.lastVerification } : void 0
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
reset(sessionKey) {
|
|
81
|
+
this.states.delete(sessionKey);
|
|
82
|
+
}
|
|
83
|
+
recordToolResult(input) {
|
|
84
|
+
if (input.isError) return;
|
|
85
|
+
const name = input.toolName.toLowerCase();
|
|
86
|
+
if (name === "apply_patch") {
|
|
87
|
+
this.recordApplyPatch(input.sessionKey, input.toolName, input.result);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (name === "write_file") {
|
|
91
|
+
this.recordWriteFile(input.sessionKey, input.toolName, input.args, input.result);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (name === "exec_command") this.recordExecCommand(input.sessionKey, input.toolName, input.args, input.result, input.isError);
|
|
95
|
+
}
|
|
96
|
+
recordMutation(input) {
|
|
97
|
+
const state = this.mutableState(input.sessionKey);
|
|
98
|
+
for (const change of input.changes) {
|
|
99
|
+
state.changes.push({
|
|
100
|
+
...change,
|
|
101
|
+
toolName: input.toolName
|
|
102
|
+
});
|
|
103
|
+
state.added += change.added ?? 0;
|
|
104
|
+
state.removed += change.removed ?? 0;
|
|
105
|
+
if (change.diff) state.cumulativeDiff = [state.cumulativeDiff.trimEnd(), change.diff.trimEnd()].filter(Boolean).join("\n");
|
|
106
|
+
}
|
|
107
|
+
state.changedFiles = uniqueSorted([...state.changedFiles, ...input.changes.flatMap((change) => [change.path, change.moveTo].filter(Boolean))]);
|
|
108
|
+
}
|
|
109
|
+
recordDiffReviewed(sessionKey) {
|
|
110
|
+
this.mutableState(sessionKey).diffReviewed = true;
|
|
111
|
+
}
|
|
112
|
+
recordVerification(input) {
|
|
113
|
+
const state = this.mutableState(input.sessionKey);
|
|
114
|
+
state.verificationAttempted = true;
|
|
115
|
+
state.lastVerification = {
|
|
116
|
+
toolName: input.toolName,
|
|
117
|
+
command: input.command,
|
|
118
|
+
success: input.success,
|
|
119
|
+
status: input.status,
|
|
120
|
+
exitCode: input.exitCode,
|
|
121
|
+
timedOut: input.timedOut
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
markDirty(sessionKey, reason) {
|
|
125
|
+
const state = this.mutableState(sessionKey);
|
|
126
|
+
state.dirty = true;
|
|
127
|
+
state.dirtyReason = reason;
|
|
128
|
+
}
|
|
129
|
+
buildFinalGuardContext(sessionKey) {
|
|
130
|
+
const state = this.states.get(sessionKey);
|
|
131
|
+
if (!state) return "";
|
|
132
|
+
if (!(state.changedFiles.length > 0 || state.changes.length > 0 || state.dirty)) return "";
|
|
133
|
+
const needsDiff = !state.diffReviewed;
|
|
134
|
+
const needsVerification = !state.verificationAttempted;
|
|
135
|
+
const failedVerification = state.lastVerification && !state.lastVerification.success;
|
|
136
|
+
if (!needsDiff && !needsVerification && !failedVerification) return "";
|
|
137
|
+
const lines = ["## Coding final check reminder"];
|
|
138
|
+
if (state.changedFiles.length > 0) appendSection(lines, "This turn changed workspace files:", state.changedFiles.map((file) => `- ${file}`));
|
|
139
|
+
if (state.dirty && needsDiff) lines.push(`A command may have modified the workspace${state.dirtyReason ? `: ${state.dirtyReason}` : "."}`);
|
|
140
|
+
const actions = [];
|
|
141
|
+
if (needsDiff) actions.push("- Inspect the diff/status with `git_status` before final response.");
|
|
142
|
+
if (needsVerification) actions.push("- Run the smallest meaningful verification command if feasible.");
|
|
143
|
+
if (failedVerification) {
|
|
144
|
+
const v = state.lastVerification;
|
|
145
|
+
actions.push(`- Last verification failed${v.command ? `: ${v.command}` : ""}. Do not claim success until fixed or clearly report the blocker.`);
|
|
146
|
+
}
|
|
147
|
+
actions.push("- If skipping verification, say why in the final answer.");
|
|
148
|
+
appendSection(lines, "Before final response:", actions);
|
|
149
|
+
return lines.join("\n");
|
|
150
|
+
}
|
|
151
|
+
mutableState(sessionKey) {
|
|
152
|
+
let state = this.states.get(sessionKey);
|
|
153
|
+
if (!state) {
|
|
154
|
+
state = createState(sessionKey);
|
|
155
|
+
this.states.set(sessionKey, state);
|
|
156
|
+
}
|
|
157
|
+
return state;
|
|
158
|
+
}
|
|
159
|
+
recordApplyPatch(sessionKey, toolName, result) {
|
|
160
|
+
const details = readDetails(result);
|
|
161
|
+
if (!details) return;
|
|
162
|
+
const now = Date.now();
|
|
163
|
+
const changes = (Array.isArray(details.changes) ? details.changes : []).flatMap((raw) => {
|
|
164
|
+
const rec = readRecord(raw);
|
|
165
|
+
const path = readString(rec?.path);
|
|
166
|
+
if (!path) return [];
|
|
167
|
+
return [{
|
|
168
|
+
kind: readString(rec?.kind) ?? "update",
|
|
169
|
+
path,
|
|
170
|
+
moveTo: readString(rec?.moveTo),
|
|
171
|
+
added: readNumber(rec?.added),
|
|
172
|
+
removed: readNumber(rec?.removed),
|
|
173
|
+
diff: readString(rec?.diff),
|
|
174
|
+
toolName,
|
|
175
|
+
at: now
|
|
176
|
+
}];
|
|
177
|
+
});
|
|
178
|
+
if (changes.length === 0) {
|
|
179
|
+
const files = readStringArray(details.files);
|
|
180
|
+
for (const file of files) changes.push({
|
|
181
|
+
kind: "unknown",
|
|
182
|
+
path: file,
|
|
183
|
+
toolName,
|
|
184
|
+
at: now
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
this.recordMutation({
|
|
188
|
+
sessionKey,
|
|
189
|
+
toolName,
|
|
190
|
+
changes
|
|
191
|
+
});
|
|
192
|
+
const state = this.mutableState(sessionKey);
|
|
193
|
+
state.added = readNumber(details.added) ?? state.added;
|
|
194
|
+
state.removed = readNumber(details.removed) ?? state.removed;
|
|
195
|
+
const diff = readString(details.diff);
|
|
196
|
+
if (diff && !state.cumulativeDiff.includes(diff.trim())) state.cumulativeDiff = [state.cumulativeDiff.trimEnd(), diff.trimEnd()].filter(Boolean).join("\n");
|
|
197
|
+
}
|
|
198
|
+
recordWriteFile(sessionKey, toolName, args, result) {
|
|
199
|
+
if (typeof readDetails(result)?.size !== "number") return;
|
|
200
|
+
const path = readString(readRecord(args)?.path);
|
|
201
|
+
if (!path) return;
|
|
202
|
+
this.recordMutation({
|
|
203
|
+
sessionKey,
|
|
204
|
+
toolName,
|
|
205
|
+
changes: [{
|
|
206
|
+
kind: "rewrite",
|
|
207
|
+
path,
|
|
208
|
+
toolName,
|
|
209
|
+
at: Date.now()
|
|
210
|
+
}]
|
|
211
|
+
});
|
|
212
|
+
this.markDirty(sessionKey, "`write_file` rewrote file content without a captured unified diff");
|
|
213
|
+
}
|
|
214
|
+
recordExecCommand(sessionKey, toolName, args, result, isError) {
|
|
215
|
+
const command = extractExecCommand(args, result);
|
|
216
|
+
const details = readDetails(result);
|
|
217
|
+
if (command && isDiffReviewCommand(command)) this.recordDiffReviewed(sessionKey);
|
|
218
|
+
if (command && isVerificationCommand(command)) this.recordVerification({
|
|
219
|
+
sessionKey,
|
|
220
|
+
toolName,
|
|
221
|
+
command,
|
|
222
|
+
success: execSuccess(isError, result),
|
|
223
|
+
status: readString(details?.status),
|
|
224
|
+
exitCode: readExitCode(details?.exitCode),
|
|
225
|
+
timedOut: details?.timedOut === true
|
|
226
|
+
});
|
|
227
|
+
if (command && commandMayMutateWorkspace(command)) this.markDirty(sessionKey, `exec_command may have changed files: ${command.slice(0, 120)}`);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
//#endregion
|
|
231
|
+
export { TurnDiffTracker };
|
|
232
|
+
|
|
233
|
+
//# sourceMappingURL=turn-diff-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turn-diff-tracker.js","names":[],"sources":["../../../../src/agent/coding/turn-diff-tracker.ts"],"sourcesContent":["export type WorkspaceMutationKind = 'add' | 'update' | 'delete' | 'move' | 'rewrite' | 'unknown';\n\nexport interface TurnFileChange {\n kind: WorkspaceMutationKind;\n path: string;\n moveTo?: string;\n added?: number;\n removed?: number;\n diff?: string;\n toolName: string;\n at: number;\n}\n\nexport interface TurnVerificationRecord {\n toolName: string;\n command?: string;\n success: boolean;\n status?: string;\n exitCode?: number | null;\n timedOut?: boolean;\n}\n\nexport interface TurnDiffState {\n sessionKey: string;\n turnId: string;\n changedFiles: string[];\n changes: TurnFileChange[];\n cumulativeDiff: string;\n added: number;\n removed: number;\n dirty: boolean;\n dirtyReason?: string;\n diffReviewed: boolean;\n verificationAttempted: boolean;\n lastVerification?: TurnVerificationRecord;\n}\n\nconst DEFAULT_TURN_ID = 'default';\n\nfunction createState(sessionKey: string, turnId = DEFAULT_TURN_ID): TurnDiffState {\n return {\n sessionKey,\n turnId,\n changedFiles: [],\n changes: [],\n cumulativeDiff: '',\n added: 0,\n removed: 0,\n dirty: false,\n diffReviewed: false,\n verificationAttempted: false,\n };\n}\n\nfunction readRecord(value: unknown): Record<string, unknown> | null {\n return value && typeof value === 'object' ? (value as Record<string, unknown>) : null;\n}\n\nfunction readDetails(result: unknown): Record<string, unknown> | null {\n const rec = readRecord(result);\n return readRecord(rec?.details);\n}\n\nfunction readString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value : undefined;\n}\n\nfunction readNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction readExitCode(value: unknown): number | null | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (value === null) return null;\n return undefined;\n}\n\nfunction readStringArray(value: unknown): string[] {\n return Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string' && item.trim().length > 0) : [];\n}\n\nfunction uniqueSorted(values: Iterable<string>): string[] {\n return Array.from(new Set(Array.from(values).filter(Boolean))).sort();\n}\n\nfunction extractExecCommand(args?: unknown, result?: unknown): string {\n const argRec = readRecord(args);\n const fromArgs = readString(argRec?.cmd) ?? readString(argRec?.command);\n if (fromArgs) return fromArgs;\n const details = readDetails(result);\n return readString(details?.command) ?? '';\n}\n\nfunction isDiffReviewCommand(command: string): boolean {\n return /\\bgit\\s+(diff|status)\\b/i.test(command);\n}\n\nfunction isVerificationCommand(command: string): boolean {\n return /\\b(test|vitest|jest|mocha|ava|playwright|typecheck|type-check|tsc|build|lint)\\b/i.test(command);\n}\n\nfunction commandMayMutateWorkspace(command: string): boolean {\n return /\\b(sed\\s+-i|perl\\s+-pi|rm\\s+|mv\\s+|cp\\s+|git\\s+(checkout|reset|clean|apply|merge|rebase)|writeFile|write\\(|open\\([^)]*['\"]w['\"])/i.test(command);\n}\n\nfunction execSuccess(isError: boolean | undefined, result: unknown): boolean {\n if (isError) return false;\n const details = readDetails(result);\n if (!details) return false;\n if (details.timedOut === true) return false;\n if (details.status === 'success') return true;\n return details.exitCode === 0;\n}\n\nfunction appendSection(lines: string[], title: string, body: string[]): void {\n if (body.length === 0) return;\n lines.push(title, ...body);\n}\n\nexport class TurnDiffTracker {\n private readonly states = new Map<string, TurnDiffState>();\n\n beginTurn(sessionKey: string, turnId = `${Date.now()}`): void {\n this.states.set(sessionKey, createState(sessionKey, turnId));\n }\n\n getState(sessionKey: string): TurnDiffState {\n const state = this.states.get(sessionKey) ?? createState(sessionKey);\n return {\n ...state,\n changedFiles: [...state.changedFiles],\n changes: state.changes.map((change) => ({ ...change })),\n lastVerification: state.lastVerification ? { ...state.lastVerification } : undefined,\n };\n }\n\n reset(sessionKey: string): void {\n this.states.delete(sessionKey);\n }\n\n recordToolResult(input: {\n sessionKey: string;\n toolName: string;\n args?: unknown;\n result?: unknown;\n isError?: boolean;\n }): void {\n if (input.isError) return;\n const name = input.toolName.toLowerCase();\n if (name === 'apply_patch') {\n this.recordApplyPatch(input.sessionKey, input.toolName, input.result);\n return;\n }\n if (name === 'write_file') {\n this.recordWriteFile(input.sessionKey, input.toolName, input.args, input.result);\n return;\n }\n if (name === 'exec_command') {\n this.recordExecCommand(input.sessionKey, input.toolName, input.args, input.result, input.isError);\n }\n }\n\n recordMutation(input: { sessionKey: string; toolName: string; changes: TurnFileChange[] }): void {\n const state = this.mutableState(input.sessionKey);\n for (const change of input.changes) {\n state.changes.push({ ...change, toolName: input.toolName });\n state.added += change.added ?? 0;\n state.removed += change.removed ?? 0;\n if (change.diff) {\n state.cumulativeDiff = [state.cumulativeDiff.trimEnd(), change.diff.trimEnd()]\n .filter(Boolean)\n .join('\\n');\n }\n }\n state.changedFiles = uniqueSorted([\n ...state.changedFiles,\n ...input.changes.flatMap((change) => [change.path, change.moveTo].filter(Boolean) as string[]),\n ]);\n }\n\n recordDiffReviewed(sessionKey: string): void {\n this.mutableState(sessionKey).diffReviewed = true;\n }\n\n recordVerification(input: {\n sessionKey: string;\n toolName: string;\n command?: string;\n success: boolean;\n status?: string;\n exitCode?: number | null;\n timedOut?: boolean;\n }): void {\n const state = this.mutableState(input.sessionKey);\n state.verificationAttempted = true;\n state.lastVerification = {\n toolName: input.toolName,\n command: input.command,\n success: input.success,\n status: input.status,\n exitCode: input.exitCode,\n timedOut: input.timedOut,\n };\n }\n\n markDirty(sessionKey: string, reason: string): void {\n const state = this.mutableState(sessionKey);\n state.dirty = true;\n state.dirtyReason = reason;\n }\n\n buildFinalGuardContext(sessionKey: string): string {\n const state = this.states.get(sessionKey);\n if (!state) return '';\n const hasChanges = state.changedFiles.length > 0 || state.changes.length > 0 || state.dirty;\n if (!hasChanges) return '';\n\n const needsDiff = !state.diffReviewed;\n const needsVerification = !state.verificationAttempted;\n const failedVerification = state.lastVerification && !state.lastVerification.success;\n if (!needsDiff && !needsVerification && !failedVerification) return '';\n\n const lines: string[] = ['## Coding final check reminder'];\n if (state.changedFiles.length > 0) {\n appendSection(lines, 'This turn changed workspace files:', state.changedFiles.map((file) => `- ${file}`));\n }\n if (state.dirty && needsDiff) {\n lines.push(`A command may have modified the workspace${state.dirtyReason ? `: ${state.dirtyReason}` : '.'}`);\n }\n const actions: string[] = [];\n if (needsDiff) actions.push('- Inspect the diff/status with `git_status` before final response.');\n if (needsVerification) actions.push('- Run the smallest meaningful verification command if feasible.');\n if (failedVerification) {\n const v = state.lastVerification!;\n actions.push(`- Last verification failed${v.command ? `: ${v.command}` : ''}. Do not claim success until fixed or clearly report the blocker.`);\n }\n actions.push('- If skipping verification, say why in the final answer.');\n appendSection(lines, 'Before final response:', actions);\n return lines.join('\\n');\n }\n\n private mutableState(sessionKey: string): TurnDiffState {\n let state = this.states.get(sessionKey);\n if (!state) {\n state = createState(sessionKey);\n this.states.set(sessionKey, state);\n }\n return state;\n }\n\n private recordApplyPatch(sessionKey: string, toolName: string, result: unknown): void {\n const details = readDetails(result);\n if (!details) return;\n const now = Date.now();\n const rawChanges = Array.isArray(details.changes) ? details.changes : [];\n const changes: TurnFileChange[] = rawChanges.flatMap((raw) => {\n const rec = readRecord(raw);\n const path = readString(rec?.path);\n if (!path) return [];\n return [{\n kind: (readString(rec?.kind) as WorkspaceMutationKind | undefined) ?? 'update',\n path,\n moveTo: readString(rec?.moveTo),\n added: readNumber(rec?.added),\n removed: readNumber(rec?.removed),\n diff: readString(rec?.diff),\n toolName,\n at: now,\n }];\n });\n if (changes.length === 0) {\n const files = readStringArray(details.files);\n for (const file of files) {\n changes.push({ kind: 'unknown', path: file, toolName, at: now });\n }\n }\n this.recordMutation({ sessionKey, toolName, changes });\n const state = this.mutableState(sessionKey);\n state.added = readNumber(details.added) ?? state.added;\n state.removed = readNumber(details.removed) ?? state.removed;\n const diff = readString(details.diff);\n if (diff && !state.cumulativeDiff.includes(diff.trim())) {\n state.cumulativeDiff = [state.cumulativeDiff.trimEnd(), diff.trimEnd()].filter(Boolean).join('\\n');\n }\n }\n\n private recordWriteFile(sessionKey: string, toolName: string, args: unknown, result: unknown): void {\n const details = readDetails(result);\n if (typeof details?.size !== 'number') return;\n const path = readString(readRecord(args)?.path);\n if (!path) return;\n this.recordMutation({\n sessionKey,\n toolName,\n changes: [{ kind: 'rewrite', path, toolName, at: Date.now() }],\n });\n this.markDirty(sessionKey, '`write_file` rewrote file content without a captured unified diff');\n }\n\n private recordExecCommand(sessionKey: string, toolName: string, args: unknown, result: unknown, isError?: boolean): void {\n const command = extractExecCommand(args, result);\n const details = readDetails(result);\n if (command && isDiffReviewCommand(command)) {\n this.recordDiffReviewed(sessionKey);\n }\n if (command && isVerificationCommand(command)) {\n this.recordVerification({\n sessionKey,\n toolName,\n command,\n success: execSuccess(isError, result),\n status: readString(details?.status),\n exitCode: readExitCode(details?.exitCode),\n timedOut: details?.timedOut === true,\n });\n }\n if (command && commandMayMutateWorkspace(command)) {\n this.markDirty(sessionKey, `exec_command may have changed files: ${command.slice(0, 120)}`);\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -31,7 +31,7 @@ Do not manually reread startup files unless:
|
|
|
31
31
|
|
|
32
32
|
- Read before writing.
|
|
33
33
|
- Prefer narrow file edits over broad rewrites.
|
|
34
|
-
- Use
|
|
34
|
+
- Use exec_command only when commands are necessary and safe.
|
|
35
35
|
- Ask before destructive operations, external actions, or changes that are difficult to undo.
|
|
36
36
|
- Keep local environment notes in `TOOLS.md`.
|
|
37
37
|
|
|
@@ -4,17 +4,21 @@ const TOOL_PROMPT_HINTS = {
|
|
|
4
4
|
promptSnippet: "Read targeted file contents",
|
|
5
5
|
promptGuidelines: ["Use read_file to inspect source files before editing."]
|
|
6
6
|
},
|
|
7
|
-
edit_file: {
|
|
8
|
-
promptSnippet: "Make precise, minimal edits to existing files",
|
|
9
|
-
promptGuidelines: ["Use edit_file for small source changes instead of rewriting whole files."]
|
|
10
|
-
},
|
|
11
7
|
write_file: {
|
|
12
8
|
promptSnippet: "Create new files or intentional complete rewrites",
|
|
13
|
-
promptGuidelines: ["Use write_file only for
|
|
9
|
+
promptGuidelines: ["Prefer apply_patch for code changes. Use write_file only for non-code artifacts or deliberate full-file rewrites."]
|
|
10
|
+
},
|
|
11
|
+
apply_patch: {
|
|
12
|
+
promptSnippet: "Apply strict multi-file patches for code edits",
|
|
13
|
+
promptGuidelines: ["Use apply_patch for all source edits. Keep patches small and verify with exec_command."]
|
|
14
14
|
},
|
|
15
|
-
|
|
15
|
+
exec_command: {
|
|
16
16
|
promptSnippet: "Run tests, type checks, builds, package scripts, and safe inspection commands",
|
|
17
|
-
promptGuidelines: ["Use
|
|
17
|
+
promptGuidelines: ["Use exec_command for verification and safe inspection, not routine file editing."]
|
|
18
|
+
},
|
|
19
|
+
update_plan: {
|
|
20
|
+
promptSnippet: "Update the visible multi-step coding plan",
|
|
21
|
+
promptGuidelines: ["Use update_plan for multi-step coding work and keep the active step current."]
|
|
18
22
|
},
|
|
19
23
|
grep: { promptSnippet: "Search file contents for literals, errors, config values, and docs" },
|
|
20
24
|
find: { promptSnippet: "Find files by glob pattern" }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xopc-tools-bridge.js","names":[],"sources":["../../../../src/agent/embedded/xopc-tools-bridge.ts"],"sourcesContent":["import type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { ToolDefinition } from '@earendil-works/pi-coding-agent';\n\nconst TOOL_PROMPT_HINTS: Record<string, { promptSnippet?: string; promptGuidelines?: string[] }> = {\n read_file: {\n promptSnippet: 'Read targeted file contents',\n promptGuidelines: ['Use read_file to inspect source files before editing.'],\n },\n
|
|
1
|
+
{"version":3,"file":"xopc-tools-bridge.js","names":[],"sources":["../../../../src/agent/embedded/xopc-tools-bridge.ts"],"sourcesContent":["import type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { ToolDefinition } from '@earendil-works/pi-coding-agent';\n\nconst TOOL_PROMPT_HINTS: Record<string, { promptSnippet?: string; promptGuidelines?: string[] }> = {\n read_file: {\n promptSnippet: 'Read targeted file contents',\n promptGuidelines: ['Use read_file to inspect source files before editing.'],\n },\n write_file: {\n promptSnippet: 'Create new files or intentional complete rewrites',\n promptGuidelines: ['Prefer apply_patch for code changes. Use write_file only for non-code artifacts or deliberate full-file rewrites.'],\n },\n apply_patch: {\n promptSnippet: 'Apply strict multi-file patches for code edits',\n promptGuidelines: ['Use apply_patch for all source edits. Keep patches small and verify with exec_command.'],\n },\n exec_command: {\n promptSnippet: 'Run tests, type checks, builds, package scripts, and safe inspection commands',\n promptGuidelines: ['Use exec_command for verification and safe inspection, not routine file editing.'],\n },\n update_plan: {\n promptSnippet: 'Update the visible multi-step coding plan',\n promptGuidelines: ['Use update_plan for multi-step coding work and keep the active step current.'],\n },\n grep: {\n promptSnippet: 'Search file contents for literals, errors, config values, and docs',\n },\n find: {\n promptSnippet: 'Find files by glob pattern',\n },\n};\n\n/** Map xopc {@link AgentTool} instances to pi-coding-agent {@link ToolDefinition}s for `createAgentSession`. */\nexport function xopcToolsToDefinitions(tools: AgentTool[]): ToolDefinition[] {\n return tools.map((tool) => {\n const promptHints = TOOL_PROMPT_HINTS[tool.name];\n const def = {\n name: tool.name,\n label: tool.label ?? tool.name,\n description: tool.description ?? tool.name,\n ...(promptHints?.promptSnippet ? { promptSnippet: promptHints.promptSnippet } : {}),\n ...(promptHints?.promptGuidelines ? { promptGuidelines: promptHints.promptGuidelines } : {}),\n parameters: tool.parameters,\n async execute(\n toolCallId: string,\n params: unknown,\n signal: AbortSignal | undefined,\n onUpdate: unknown,\n ) {\n return (tool as { execute: (...a: never[]) => unknown }).execute(\n toolCallId as never,\n params as never,\n signal as never,\n onUpdate as never,\n ) as never;\n },\n };\n return def as unknown as ToolDefinition;\n });\n}\n"],"mappings":";AAGA,MAAM,oBAA6F;CACjG,WAAW;EACT,eAAe;EACf,kBAAkB,CAAC,wDAAwD;EAC5E;CACD,YAAY;EACV,eAAe;EACf,kBAAkB,CAAC,oHAAoH;EACxI;CACD,aAAa;EACX,eAAe;EACf,kBAAkB,CAAC,yFAAyF;EAC7G;CACD,cAAc;EACZ,eAAe;EACf,kBAAkB,CAAC,mFAAmF;EACvG;CACD,aAAa;EACX,eAAe;EACf,kBAAkB,CAAC,+EAA+E;EACnG;CACD,MAAM,EACJ,eAAe,sEAChB;CACD,MAAM,EACJ,eAAe,8BAChB;CACF;;AAGD,SAAgB,uBAAuB,OAAsC;AAC3E,QAAO,MAAM,KAAK,SAAS;EACzB,MAAM,cAAc,kBAAkB,KAAK;AAsB3C,SAAO;GApBL,MAAM,KAAK;GACX,OAAO,KAAK,SAAS,KAAK;GAC1B,aAAa,KAAK,eAAe,KAAK;GACtC,GAAI,aAAa,gBAAgB,EAAE,eAAe,YAAY,eAAe,GAAG,EAAE;GAClF,GAAI,aAAa,mBAAmB,EAAE,kBAAkB,YAAY,kBAAkB,GAAG,EAAE;GAC3F,YAAY,KAAK;GACjB,MAAM,QACJ,YACA,QACA,QACA,UACA;AACA,WAAQ,KAAiD,QACvD,YACA,QACA,QACA,SACD;;GAGK;GACV"}
|
|
@@ -37,13 +37,15 @@ const TOOL_STAGE_MAP = {
|
|
|
37
37
|
"write_file": "writing",
|
|
38
38
|
"write_multiple": "writing",
|
|
39
39
|
"edit": "writing",
|
|
40
|
+
"apply_patch": "writing",
|
|
40
41
|
"patch": "writing",
|
|
41
42
|
"create": "writing",
|
|
42
43
|
"mkdir": "writing",
|
|
43
44
|
"delete": "writing",
|
|
44
45
|
"remove": "writing",
|
|
45
46
|
"bash": "executing",
|
|
46
|
-
"
|
|
47
|
+
"exec_command": "executing",
|
|
48
|
+
"update_plan": "thinking",
|
|
47
49
|
"exec": "executing",
|
|
48
50
|
"run": "executing",
|
|
49
51
|
"command": "executing",
|
|
@@ -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 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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"}
|
|
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 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 'apply_patch': 'writing',\n 'patch': 'writing',\n 'create': 'writing',\n 'mkdir': 'writing',\n 'delete': 'writing',\n 'remove': 'writing',\n \n // Executing tools\n 'bash': 'executing',\n 'exec_command': 'executing',\n 'update_plan': 'thinking',\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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"}
|
|
@@ -33,8 +33,8 @@ export interface ToolTimeoutConfig {
|
|
|
33
33
|
* @example
|
|
34
34
|
* ```typescript
|
|
35
35
|
* const result = await executeWithTimeout(
|
|
36
|
-
* () =>
|
|
37
|
-
* { toolName: '
|
|
36
|
+
* () => execCommand('long-running-command'),
|
|
37
|
+
* { toolName: 'exec_command', timeoutMs: 60000 }
|
|
38
38
|
* );
|
|
39
39
|
* ```
|
|
40
40
|
*/
|
|
@@ -16,7 +16,7 @@ const DEFAULT_CONFIG = {
|
|
|
16
16
|
*/
|
|
17
17
|
function getTimeoutForTool(toolName, config) {
|
|
18
18
|
const toolLower = toolName.toLowerCase();
|
|
19
|
-
if (toolLower.includes("
|
|
19
|
+
if (toolLower.includes("exec") || toolLower.includes("command")) return config.shellTimeoutMs;
|
|
20
20
|
if (toolLower.includes("read") || toolLower.includes("view")) return config.readTimeoutMs;
|
|
21
21
|
if (toolLower.includes("write") || toolLower.includes("edit")) return config.writeTimeoutMs;
|
|
22
22
|
if (toolLower.includes("web") || toolLower.includes("http") || toolLower.includes("fetch")) return config.networkTimeoutMs;
|
|
@@ -28,8 +28,8 @@ function getTimeoutForTool(toolName, config) {
|
|
|
28
28
|
* @example
|
|
29
29
|
* ```typescript
|
|
30
30
|
* const result = await executeWithTimeout(
|
|
31
|
-
* () =>
|
|
32
|
-
* { toolName: '
|
|
31
|
+
* () => execCommand('long-running-command'),
|
|
32
|
+
* { toolName: 'exec_command', timeoutMs: 60000 }
|
|
33
33
|
* );
|
|
34
34
|
* ```
|
|
35
35
|
*/
|
|
@@ -123,7 +123,7 @@ var TimeoutError = class TimeoutError extends Error {
|
|
|
123
123
|
*/
|
|
124
124
|
getUserMessage() {
|
|
125
125
|
const suggestions = [];
|
|
126
|
-
if (this.toolName.toLowerCase().includes("
|
|
126
|
+
if (this.toolName.toLowerCase().includes("exec") || this.toolName.toLowerCase().includes("command")) {
|
|
127
127
|
suggestions.push("Break the command into smaller steps");
|
|
128
128
|
suggestions.push("Add timeouts to individual commands");
|
|
129
129
|
suggestions.push("Check for infinite loops or waiting for input");
|
|
@@ -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 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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"}
|
|
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('exec') || toolLower.includes('command')) {\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 * () => execCommand('long-running-command'),\n * { toolName: 'exec_command', 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('exec') || this.toolName.toLowerCase().includes('command')) {\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":";;;aASqD;AAErD,MAAM,MAAM,aAAa,iBAAiB;AAW1C,MAAM,iBAAgC;CACpC,kBAAkB,MAAS;CAC3B,gBAAgB,MAAS;CACzB,eAAe,KAAK;CACpB,gBAAgB,KAAK;CACrB,kBAAkB,KAAK;CACvB,oBAAoB;CACrB;;;;AAmBD,SAAS,kBAAkB,UAAkB,QAA+B;CAC1E,MAAM,YAAY,SAAS,aAAa;AAExC,KAAI,UAAU,SAAS,OAAO,IAAI,UAAU,SAAS,UAAU,CAC7D,QAAO,OAAO;AAEhB,KAAI,UAAU,SAAS,OAAO,IAAI,UAAU,SAAS,OAAO,CAC1D,QAAO,OAAO;AAEhB,KAAI,UAAU,SAAS,QAAQ,IAAI,UAAU,SAAS,OAAO,CAC3D,QAAO,OAAO;AAEhB,KAAI,UAAU,SAAS,MAAM,IAAI,UAAU,SAAS,OAAO,IAAI,UAAU,SAAS,QAAQ,CACxF,QAAO,OAAO;AAGhB,QAAO,OAAO;;;;;;;;;;;;;AAchB,eAAsB,mBACpB,WACA,QACY;CACZ,MAAM,aAAa,EAAE,GAAG,gBAAgB;CACxC,MAAM,YAAY,OAAO,aAAa,kBAAkB,OAAO,UAAU,WAAW;CAEpF,MAAM,YAAY,KAAK,KAAK;CAC5B,IAAI,YAAmC;CACvC,IAAI,YAAY;AAEhB,QAAO,IAAI,SAAS,SAAS,WAAW;AAEtC,cAAY,iBAAiB;AAC3B,OAAI,UAAW;AACf,eAAY;GAEZ,MAAM,gBAAgB,KAAK,KAAK,GAAG;GACnC,MAAM,OAAO,OAAO,cAAc,KAAK,OAAO,YAAY,KAAK;AAC/D,OAAI,MACF;IACE,UAAU,OAAO;IACjB;IACA,iBAAiB;IACjB,aAAa,OAAO;IACrB,EACD,SAAS,OAAO,SAAS,oBAAoB,UAAU,cAAc,cAAc,KAAK,OACzF;AAED,UACE,IAAI,aACF,OAAO,UACP,WACA,OAAO,aACP,cACD,CACF;KACA,UAAU;AAGb,aAAW,CACR,MAAK,WAAU;AACd,OAAI,UAAW;AACf,eAAY;AAEZ,OAAI,WAAW;AACb,iBAAa,UAAU;AACvB,gBAAY;;GAEd,MAAM,gBAAgB,KAAK,KAAK,GAAG;AAEnC,OAAI,MACF;IACE,UAAU,OAAO;IACjB,iBAAiB;IAClB,EACD,0CACD;AAED,WAAQ,OAAO;IACf,CACD,OAAM,UAAS;AACd,OAAI,UAAW;AACf,eAAY;AAEZ,OAAI,WAAW;AACb,iBAAa,UAAU;AACvB,gBAAY;;AAEd,UAAO,MAAM;IACb;GACJ;;;;;AAMJ,eAAsB,yBACpB,WACA,QAC2B;CAC3B,MAAM,YAAY,KAAK,KAAK;AAE5B,KAAI;AAEF,SAAO;GACL,SAAS;GACT,QAAA,MAHmB,mBAAmB,WAAW,OAAO;GAIxD,UAAU;GACV,iBAAiB,KAAK,KAAK,GAAG;GAC/B;UACM,OAAO;EACd,MAAM,YAAY,iBAAiB;AACnC,SAAO;GACL,SAAS;GACT,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;GAChE,UAAU;GACV,iBAAiB,KAAK,KAAK,GAAG;GAC/B;;;;;;AAOL,IAAa,eAAb,MAAa,qBAAqB,MAAM;CACtC;CACA;CACA;CACA;CAEA,YACE,UACA,WACA,aACA,kBAA0B,WAC1B;EACA,MAAM,aAAa,KAAK,MAAM,YAAY,IAAK;EAC/C,MAAM,UAAU,cACZ,SAAS,SAAS,oBAAoB,WAAW,KAAK,gBACtD,SAAS,SAAS,oBAAoB,WAAW;AAErD,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,WAAW;AAChB,OAAK,YAAY;AACjB,OAAK,cAAc;AACnB,OAAK,kBAAkB;AAGvB,MAAI,MAAM,kBACR,OAAM,kBAAkB,MAAM,aAAa;;;;;CAO/C,iBAAyB;EACvB,MAAM,cAAwB,EAAE;AAEhC,MAAI,KAAK,SAAS,aAAa,CAAC,SAAS,OAAO,IAAI,KAAK,SAAS,aAAa,CAAC,SAAS,UAAU,EAAE;AACnG,eAAY,KAAK,uCAAuC;AACxD,eAAY,KAAK,sCAAsC;AACvD,eAAY,KAAK,gDAAgD;aACxD,KAAK,SAAS,aAAa,CAAC,SAAS,OAAO,EAAE;AACvD,eAAY,KAAK,kCAAkC;AACnD,eAAY,KAAK,0CAA0C;aAClD,KAAK,SAAS,aAAa,CAAC,SAAS,QAAQ,CACtD,aAAY,KAAK,mCAAmC;WAC3C,KAAK,SAAS,aAAa,CAAC,SAAS,MAAM,EAAE;AACtD,eAAY,KAAK,6BAA6B;AAC9C,eAAY,KAAK,kBAAkB;;EAGrC,IAAI,UAAU,MAAM,KAAK;AACzB,MAAI,YAAY,SAAS,EACvB,YAAW,uBAAuB,YAAY,KAAI,MAAK,KAAK,IAAI,CAAC,KAAK,KAAK;AAG7E,SAAO;;;;;;AAOX,SAAgB,YACd,IACA,QACoD;AACpD,QAAO,OAAO,GAAG,SAAgD;EAC/D,MAAM,cAAc,OAAO,OAAO,gBAAgB,aAC9C,OAAO,YAAY,GAAG,KAAK,GAC3B,OAAO;AAEX,SAAO,yBAAyB,GAAG,GAAG,KAAK,EAAE;GAC3C,UAAU,OAAO;GACjB,WAAW,OAAO;GAClB;GACD,CAAC;;;;;;AAON,IAAa,iBAAb,MAA4B;CAC1B,aAKK,EAAE;CAEP,YAAY,UAAkC,EAAE,EAAE;;;;CAKlD,MAAM,QACJ,WACA,YACY;EACZ,MAAM,YAAY,KAAK,KAAK;EAC5B,IAAI,WAAW;AAEf,MAAI;GACF,MAAM,SAAS,MAAM,mBAAmB,WAAW,WAAW;AAC9D,QAAK,WAAW,KAAK;IACnB,UAAU,WAAW;IACrB,iBAAiB,KAAK,KAAK,GAAG;IAC9B,UAAU;IACV,WAAW,KAAK,KAAK;IACtB,CAAC;AACF,UAAO;WACA,OAAO;AACd,OAAI,iBAAiB,aACnB,YAAW;AAEb,QAAK,WAAW,KAAK;IACnB,UAAU,WAAW;IACrB,iBAAiB,KAAK,KAAK,GAAG;IAC9B;IACA,WAAW,KAAK,KAAK;IACtB,CAAC;AACF,SAAM;;;;;;CAOV,WAUE;EACA,MAAM,SAAiF,EAAE;AAEzF,OAAK,MAAM,QAAQ,KAAK,YAAY;AAClC,OAAI,CAAC,OAAO,KAAK,UACf,QAAO,KAAK,YAAY;IAAE,OAAO;IAAG,UAAU;IAAG,WAAW;IAAG;AAEjE,UAAO,KAAK,UAAU;AACtB,OAAI,KAAK,SACP,QAAO,KAAK,UAAU;AAExB,UAAO,KAAK,UAAU,aAAa,KAAK;;EAG1C,MAAM,kBAAkB,KAAK,WAAW;EACxC,MAAM,eAAe,KAAK,WAAW,QAAO,MAAK,EAAE,SAAS,CAAC;EAC7D,MAAM,YAAY,KAAK,WAAW,QAAQ,KAAK,MAAM,MAAM,EAAE,iBAAiB,EAAE;AAEhF,SAAO;GACL;GACA;GACA,aAAa,kBAAkB,IAAI,eAAe,kBAAkB;GACpE,wBAAwB,kBAAkB,IAAI,YAAY,kBAAkB;GAC5E,QAAQ,OAAO,YACb,OAAO,QAAQ,OAAO,CAAC,KAAK,CAAC,MAAM,WAAW,CAC5C,MACA;IACE,OAAO,MAAM;IACb,UAAU,MAAM;IAChB,oBAAoB,MAAM,QAAQ,IAAI,MAAM,YAAY,MAAM,QAAQ;IACvE,CACF,CAAC,CACH;GACF;;;;;CAMH,QAAQ,WAAmB,OAAU,KAAK,KAAY;EACpD,MAAM,SAAS,KAAK,KAAK,GAAG;AAC5B,OAAK,aAAa,KAAK,WAAW,QAAO,MAAK,EAAE,YAAY,OAAO"}
|
|
@@ -35,8 +35,8 @@ export type DreamingResolvedConfig = {
|
|
|
35
35
|
};
|
|
36
36
|
deep: DreamingDeepConfig;
|
|
37
37
|
};
|
|
38
|
-
/** Resolve the full three-phase dreaming config from
|
|
39
|
-
export declare function resolveDreamingConfig(cfg: Config | undefined): DreamingResolvedConfig;
|
|
38
|
+
/** Resolve the full three-phase dreaming config from an agent manifest. */
|
|
39
|
+
export declare function resolveDreamingConfig(cfg: Config | undefined, requestedAgentId?: string | null): DreamingResolvedConfig;
|
|
40
40
|
/** Get the cron expression for a specific phase from resolved config. */
|
|
41
41
|
export declare function getPhaseCron(config: DreamingResolvedConfig, phase: DreamingPhaseId): string;
|
|
42
42
|
/** Check if a specific phase is enabled (global + phase-level). */
|
|
@@ -25,9 +25,9 @@ function trimmedStringOr(value, fallback) {
|
|
|
25
25
|
function optionalTrimmedString(value) {
|
|
26
26
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
27
27
|
}
|
|
28
|
-
/** Resolve the full three-phase dreaming config from
|
|
29
|
-
function resolveDreamingConfig(cfg) {
|
|
30
|
-
const agentId = cfg ? resolveDefaultAgentId(cfg) : void 0;
|
|
28
|
+
/** Resolve the full three-phase dreaming config from an agent manifest. */
|
|
29
|
+
function resolveDreamingConfig(cfg, requestedAgentId) {
|
|
30
|
+
const agentId = cfg ? requestedAgentId?.trim() || resolveDefaultAgentId(cfg) : void 0;
|
|
31
31
|
const manifest = cfg && agentId ? resolveEffectiveAgentManifestForAgent(cfg, agentId) : void 0;
|
|
32
32
|
const dreaming = manifest?.memory.dreaming;
|
|
33
33
|
const enabled = dreaming?.enabled === true && manifest?.memory.mode !== "off";
|