@xopcai/xopc 0.0.124 → 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/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-B5uSVAyJ.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-CXUGRp2i.js → archive-plugin-kUHEJ1HK.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-Cmiub3Wg.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-0Izz-N3p.js → binary-plugins-DllA_jQ0.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-C1Kv0IkJ.js → block-editor-Cm6CWNj1.js} +6 -6
- 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-BeA2aVor.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-2rjzUu57.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-BU5S0Sn7.js → fetch-NFKfkqrd.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-BIPGwrl1.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-Cd0Zz30N.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-B95KdGMj.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-BhIQU5yS.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-DGzet1d7.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-Cqgb-jqa.js → save-bar-controls-B132Uf-2.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-DVZcI8Yt.js → schedule-field-B5qshALm.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-Bj7sOxC8.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-BmXn-8N6.js → settings-collapsible-section-pRlvqsAf.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-BnqYMWHR.js → settings-form-section-BBYUDLVd.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-DaO7zYZM.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-layout-CdWZU1hd.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-IB1v8i86.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-BxQ384RC.js → system-settings-panel-HUU2FFjM.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-BkcpvFYO.js → typed-models-lib-AH160QHh.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-Cd0FaEQ4.js → use-channel-catalog-BXzDmjCQ.js} +1 -1
- package/dist/gateway/static/root/assets/{user-profile-settings-panel-DQ7NnRSY.js → user-profile-settings-panel-DxwnQvQ3.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-YKhVf7Ka.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-BNJVCWoS.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.js +6 -2
- 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/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/orchestration/agent-event-handler.d.ts +2 -0
- package/dist/src/agent/orchestration/agent-event-handler.js +13 -0
- package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js +22 -12
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/sandbox/command-validator.js +12 -0
- package/dist/src/agent/sandbox/command-validator.js.map +1 -1
- package/dist/src/agent/service.d.ts +2 -1
- package/dist/src/agent/service.js +18 -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/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/tools/apply-patch.js +116 -62
- package/dist/src/agent/tools/apply-patch.js.map +1 -1
- package/dist/src/agent/tools/concurrency.d.ts +8 -0
- package/dist/src/agent/tools/concurrency.js +31 -0
- package/dist/src/agent/tools/concurrency.js.map +1 -0
- package/dist/src/agent/tools/dreaming-tool.d.ts +2 -0
- package/dist/src/agent/tools/dreaming-tool.js +13 -10
- package/dist/src/agent/tools/dreaming-tool.js.map +1 -1
- package/dist/src/agent/tools/exec-command.js +4 -0
- package/dist/src/agent/tools/exec-command.js.map +1 -1
- package/dist/src/agent/tools/executor.d.ts +6 -4
- package/dist/src/agent/tools/executor.js +7 -4
- package/dist/src/agent/tools/executor.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +3 -0
- package/dist/src/agent/tools/factory.js +7 -1
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/find.js +2 -0
- package/dist/src/agent/tools/find.js.map +1 -1
- package/dist/src/agent/tools/grep.js +2 -0
- package/dist/src/agent/tools/grep.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +2 -0
- package/dist/src/agent/tools/index.js +3 -1
- package/dist/src/agent/tools/list-dir.js +2 -0
- package/dist/src/agent/tools/list-dir.js.map +1 -1
- package/dist/src/agent/tools/memory-tool.d.ts +1 -0
- package/dist/src/agent/tools/memory-tool.js +2 -2
- package/dist/src/agent/tools/memory-tool.js.map +1 -1
- package/dist/src/agent/tools/metadata.d.ts +15 -0
- package/dist/src/agent/tools/metadata.js +26 -0
- package/dist/src/agent/tools/metadata.js.map +1 -0
- package/dist/src/agent/tools/read.js +2 -0
- package/dist/src/agent/tools/read.js.map +1 -1
- package/dist/src/agent/tools/write.js +6 -0
- package/dist/src/agent/tools/write.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/cli/commands/doctor/checks/database-schema.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/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/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/projects.js +846 -43
- package/dist/src/gateway/hono/routes/projects.js.map +1 -1
- 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/service.js +17 -8
- package/dist/src/gateway/service.js.map +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/session/session-context-for-llm.d.ts +2 -0
- package/dist/src/session/session-context-for-llm.js +14 -1
- package/dist/src/session/session-context-for-llm.js.map +1 -1
- package/dist/src/session/store.js +2 -2
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/022_work_items.sql +61 -0
- package/dist/src/storage/sqlite/migrations/023_work_item_attachments.sql +15 -0
- package/dist/src/storage/sqlite/migrations/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/components/assistant-message.js +12 -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-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/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-BjIxt67Z.js +0 -2
- package/dist/gateway/static/root/assets/app-management-settings-panel-CYCONLIL.js +0 -1
- package/dist/gateway/static/root/assets/appearance-settings-Clw3ryKg.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-QICTeGjX.js +0 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-CU0-4nQ-.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-Car-jtiz.js +0 -1
- package/dist/gateway/static/root/assets/browser-settings-page-CMeBJzlS.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-api-BmQTM9Il.js +0 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-DZEJEoCF.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-kkW-xFau.js +0 -1
- package/dist/gateway/static/root/assets/code-editor-dZTY2dRW.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-BvaQvO5F.js +0 -2
- package/dist/gateway/static/root/assets/dist-Mys7eFJ5.js +0 -1
- package/dist/gateway/static/root/assets/dist-wO9a2_ID.js +0 -1
- package/dist/gateway/static/root/assets/dreaming-settings-DnHO686d.js +0 -1
- package/dist/gateway/static/root/assets/extension-debug-page-BGLRuWVN.js +0 -1
- package/dist/gateway/static/root/assets/extension-page-D978ePp9.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-B6Ih4Swx.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-CMEA3r5u.js +0 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-B-KHKeXN.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-BxrSoWdj.js +0 -1
- package/dist/gateway/static/root/assets/goals-page-BTJzIl28.js +0 -2
- package/dist/gateway/static/root/assets/goals-settings-BJyEuLLm.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-wkOjYNQT.js +0 -1
- package/dist/gateway/static/root/assets/index-BLaXr6Ev.css +0 -1
- package/dist/gateway/static/root/assets/index-c_9TVr_C.js +0 -191
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-BT8T4DyC.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-CrxBJUgI.js +0 -2
- package/dist/gateway/static/root/assets/markdown-split-Dv66bO2b.js +0 -1
- package/dist/gateway/static/root/assets/messages-O6TAtdFC.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-DOOpz6y1.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-Br16pK9v.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-PSJAi0ZC.js +0 -2
- package/dist/gateway/static/root/assets/project-detail-page-CIGGgKuw.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-B2grhsBt.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CXMORxBD.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-Bi2wkBzU.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-B1L3G4IA.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-BfRSHJmO.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-CWtPM7RK.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-ngbsBgij.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BIe442Gv.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-BfchZRVa.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-C5Ov8Uk_.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-BYD9BtOq.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-BYF29ANm.js +0 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.js","names":[],"sources":["../../../../src/agent/tools/factory.ts"],"sourcesContent":["/**\n * Agent Tools Factory - Creates and configures agent tools\n *\n * Centralizes tool creation logic to keep service.ts focused on orchestration.\n *\n * TTS: auto TTS is applied at the ChannelManager via maybeApplyTtsToPayload().\n * Optional \\`text_to_speech\\` tool sends explicit voice when TTS is enabled.\n */\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { Model, Api } from '@earendil-works/pi-ai';\nimport type { Page } from 'playwright-core';\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport {\n createReadFileTool,\n createWriteFileTool,\n createApplyPatchTool,\n createListDirTool,\n createGrepTool,\n createFindTool,\n createExecCommandTool,\n createWebSearchTool,\n createWebFetchTool,\n createWebExtractTool,\n createMessageTool,\n createComposioExecuteTool,\n createSendMediaTool,\n createReadMediaTool,\n createCreateShareTool,\n isShareToolAvailable,\n createMemorySearchTool,\n createMemoryGetTool,\n createTodoTool,\n createUpdatePlanTool,\n createSessionStatusTool,\n createDreamingTool,\n createClarifyTool,\n createToolManualTool,\n createGoalTool,\n createAutomationTool,\n} from './index.js';\nimport { createCuratedMemoryTool } from './curated-memory-tool.js';\nimport { createSessionSearchTool } from './session-search-tool.js';\nimport type { MemoryManager } from '../memory/manager.js';\nimport { shouldRegisterCuratedMemoryTool } from '../memory/memory-config.js';\nimport type { SessionStore } from '../../session/store.js';\nimport type { GatewayClarifyRequestFn } from './clarify-tool.js';\nimport { createImageTool } from './image-tool.js';\nimport { createImageGenerateTool } from './image-generate-tool.js';\nimport {\n BrowserManager,\n BrowserNotReadyError,\n CdpSupervisor,\n checkBrowserReadiness,\n resolveBrowserBackendFromConfig,\n} from '../../browser/index.js';\nimport { createBrowserUseTool } from './browser/tool/browser-use-tool.js';\nimport { createDelegateTool } from './delegate-tool.js';\nimport { createWorkflowTool } from './workflow-tool.js';\nimport { createWorkflowCatalog } from '../workflow/catalog.js';\nimport { buildSandboxToolMap, createExecuteCodeTool } from './execute-code-tool.js';\nimport type { AutomationService } from '../../automations/index.js';\nimport type { WorkflowRunServiceLike } from '../../workflows/service/workflow-run-service.types.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type { SkillManager } from '../skills/skill-manager.js';\nimport { wrapToolsWithProtection, type ToolExecutorConfig } from './executor.js';\nimport { createSkillsListTool, createSkillViewTool } from './skills-tools.js';\nimport { createSkillManageTool } from './skill-manage-tool.js';\nimport { createTextToSpeechTool } from './tts-tool.js';\nimport { mergeTtsConfigFromAppConfig } from '../../voice/tts/merge-config.js';\nimport { createGoalEvidenceRecorder } from './goal-evidence-recorder.js';\n\nconst log = createLogger('AgentToolsFactory');\n\n/** Channels where `clarify` can block for a user answer (web UI, Telegram, CLI readline). */\nconst CLARIFY_SUPPORTED_CHANNELS = new Set(['webchat', 'telegram', 'cli']);\n\nexport interface ToolFactoryDeps {\n workspace: string;\n extensionRegistry?: any;\n getCurrentContext: () => { channel: string; chatId: string; sessionKey: string } | null;\n hookRunner?: import('../../extensions/index.js').ExtensionHookRunner;\n bus: MessageBus;\n toolExecutorConfig?: Partial<ToolExecutorConfig>;\n /** Agent defaults (image tools, etc.); use getter so hot-reloaded config applies. */\n getConfig?: () => Config | undefined;\n /** Session / default chat model for vision tool description. */\n getPrimaryModel?: () => Model<Api>;\n /** Memory orchestration (prefetch/sync + external tools). */\n getMemoryManager?: () => MemoryManager;\n /** Session store for `session_search`. */\n getSessionStore?: () => SessionStore;\n /** When set (gateway webchat), enables the `clarify` tool. */\n gatewayClarify?: { requestClarification: GatewayClarifyRequestFn };\n /** Gateway: enables the `automation` tool. */\n getAutomationService?: () => AutomationService | undefined;\n /** Gateway: starts persisted workflow runs (dedicated chat session per run). */\n getWorkflowRunService?: () => WorkflowRunServiceLike | undefined;\n /** Current session skill indexing (tool gating + allowlist); used by skills_list / skill_view. */\n getSkillIndexingContext?: () =>\n | { registeredToolNames: string[]; skillAllowlist?: string[] }\n | undefined;\n /** After skill_manage mutates disk, reload skills + refresh agent prompts (optional). */\n onSkillsFilesystemMutate?: () => void;\n /** Names registered via skill_view for command env passthrough. */\n getSkillPassthroughEnvVarNames?: () => string[];\n /** Add declared env names for the current session (no values stored). */\n registerSkillEnvPassthrough?: (names: string[]) => void;\n}\n\nexport interface CreateCoreToolsOptions {\n /** Workspace root for file/command tools (defaults to factory workspace). */\n workspace?: string;\n /** Canonical `agents/<id>/profile/`: bare SOUL.md / IDENTITY.md resolve here after the workspace. */\n profileMarkdownRoot?: string;\n /** Tool `name` values to omit (e.g. `exec_command`, `extensions` for extension tools). */\n disabledTools?: Set<string>;\n /** Optional primary model for image tool heuristics. */\n getPrimaryModel?: () => Model<Api>;\n getMemoryManager?: () => MemoryManager;\n /** When set, registers `skills_list` and `skill_view` bound to this workspace\\'s skills. */\n getSkillManager?: () => SkillManager;\n}\n\nexport class AgentToolsFactory {\n private browserManager: BrowserManager | null = null;\n /** One dialog/console supervisor per chat session (browser tab). */\n private readonly browserTaskSupervisors = new Map<string, CdpSupervisor>();\n /** Cached readiness probe — keyed by backend mode + extension host:port. */\n private browserReadinessCache: {\n key: string;\n expiresAt: number;\n inflight?: Promise<BrowserNotReadyError | null>;\n result?: BrowserNotReadyError | null;\n } | null = null;\n\n constructor(private deps: ToolFactoryDeps) {}\n\n private browserReadinessKey(): string {\n const cfg = this.deps.getConfig?.();\n const backend = resolveBrowserBackendFromConfig(cfg);\n const host = '127.0.0.1';\n const port = 19820;\n const cdpUrl = backend.mode === 'cdp' ? backend.config.wsEndpoint : '';\n const cloudKind = backend.mode === 'cloud' ? backend.config.type : '';\n return `${backend.mode}@${host}:${port}|${cdpUrl}|${cloudKind}`;\n }\n\n private async checkBrowserReadinessCached(): Promise<BrowserNotReadyError | null> {\n const key = this.browserReadinessKey();\n const now = Date.now();\n const cached = this.browserReadinessCache;\n if (cached && cached.key === key && cached.expiresAt > now && cached.inflight === undefined) {\n return cached.result ?? null;\n }\n if (cached && cached.key === key && cached.inflight) {\n return cached.inflight;\n }\n const inflight = checkBrowserReadiness(this.deps.getConfig?.());\n this.browserReadinessCache = { key, expiresAt: now + 30_000, inflight };\n try {\n const result = await inflight;\n this.browserReadinessCache = { key, expiresAt: Date.now() + 30_000, result };\n return result;\n } catch (e) {\n // Probe should never throw, but if it does we just bypass the cache.\n this.browserReadinessCache = null;\n log.warn({ err: e }, 'browserReadiness probe failed');\n return null;\n }\n }\n\n /** Invalidate the readiness cache (config hot-reload, settings-page save, etc.). */\n invalidateBrowserReadinessCache(): void {\n this.browserReadinessCache = null;\n }\n\n private browserSupervisorForTask(taskId: string): CdpSupervisor {\n let s = this.browserTaskSupervisors.get(taskId);\n if (!s) {\n s = new CdpSupervisor({ dialogPolicy: 'auto_dismiss', dialogTimeoutSeconds: 300 });\n this.browserTaskSupervisors.set(taskId, s);\n }\n return s;\n }\n\n private async acquireBrowserPage(): Promise<Page> {\n const taskId = this.deps.getCurrentContext()?.sessionKey ?? 'default';\n const mgr = this.ensureBrowserManager();\n await mgr.ensureConnected();\n if (mgr.getExtensionProvider()) {\n return null as unknown as Page;\n }\n const page = await mgr.getPage(taskId);\n this.browserSupervisorForTask(taskId).attach(page);\n return page;\n }\n\n private ensureBrowserManager(): BrowserManager {\n if (!this.browserManager) {\n this.browserManager = new BrowserManager({\n getHeadless: () => false,\n getBackend: () => resolveBrowserBackendFromConfig(this.deps.getConfig?.()),\n });\n }\n return this.browserManager;\n }\n\n /** Close Playwright and all pages (gateway stop, agent manager dispose, or config hot-reload). */\n async shutdownBrowser(): Promise<void> {\n this.browserReadinessCache = null;\n if (!this.browserManager) {\n return;\n }\n await this.browserManager.shutdown();\n this.browserManager = null;\n this.browserTaskSupervisors.clear();\n }\n\n /** Drop the tab for a session when its agent instance is removed. */\n async closeBrowserPageForSession(sessionKey: string): Promise<void> {\n this.browserTaskSupervisors.delete(sessionKey);\n await this.browserManager?.closePage(sessionKey);\n }\n\n createCoreTools(options?: CreateCoreToolsOptions): AgentTool<any, any>[] {\n const workspace = options?.workspace ?? this.deps.workspace;\n const { bus } = this.deps;\n const getPrimary = options?.getPrimaryModel ?? this.deps.getPrimaryModel;\n const getMemMgr = options?.getMemoryManager ?? this.deps.getMemoryManager;\n const getSkillMgr = options?.getSkillManager;\n const disabled = options?.disabledTools;\n\n const primary = getPrimary?.();\n const modelHasVision = primary?.input?.includes('image') ?? false;\n const cfg = this.deps.getConfig?.();\n const browserEnabled = cfg?.browser?.enabled !== false;\n const recordGoalEvidence = createGoalEvidenceRecorder({\n getSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n });\n const imageTool = createImageTool({\n config: cfg,\n workspace,\n modelHasVision,\n });\n const imageGenerateTool = createImageGenerateTool({\n config: cfg,\n workspace,\n });\n\n const composioTool = createComposioExecuteTool(() => this.deps.getConfig?.());\n const optionalTools = [imageTool, imageGenerateTool, composioTool].filter((t) => t != null) as any[];\n\n const readTool = createReadFileTool(workspace, {\n profileMarkdownRoot: options?.profileMarkdownRoot,\n });\n const writeTool = createWriteFileTool(workspace, {\n profileMarkdownRoot: options?.profileMarkdownRoot,\n recordGoalEvidence,\n });\n const applyPatchTool = createApplyPatchTool(workspace, { recordGoalEvidence });\n const listDir = createListDirTool(workspace);\n const grep = createGrepTool(workspace);\n const find = createFindTool(workspace);\n\n const core: AgentTool<any, any>[] = [\n createSessionStatusTool(),\n createDreamingTool({\n getWorkspace: () => workspace,\n getConfig: () => this.deps.getConfig?.(),\n }),\n createToolManualTool(),\n createClarifyTool({\n resolveAskUser: () => {\n const req = this.deps.gatewayClarify?.requestClarification;\n if (!req) return null;\n const ctx = this.deps.getCurrentContext();\n if (!ctx?.sessionKey) return null;\n if (!CLARIFY_SUPPORTED_CHANNELS.has(ctx.channel)) return null;\n return (r) => req(ctx.sessionKey, r);\n },\n }),\n createTodoTool({\n getSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n }),\n createUpdatePlanTool(),\n ...(getSkillMgr\n ? [\n createSkillsListTool({\n getSkillManager: getSkillMgr,\n getSkillIndexingContext: this.deps.getSkillIndexingContext,\n }),\n createSkillViewTool({\n getSkillManager: getSkillMgr,\n getSkillIndexingContext: this.deps.getSkillIndexingContext,\n registerSkillEnvPassthrough: this.deps.registerSkillEnvPassthrough,\n }),\n createSkillManageTool({\n getSkillManager: getSkillMgr,\n getWorkspace: () => workspace,\n onSkillsFilesystemMutate: this.deps.onSkillsFilesystemMutate,\n }),\n ]\n : []),\n readTool,\n writeTool,\n applyPatchTool,\n listDir,\n grep,\n find,\n createExecCommandTool(workspace, {\n getSkillPassthroughEnvVarNames: this.deps.getSkillPassthroughEnvVarNames,\n recordGoalEvidence,\n }),\n createWebSearchTool(() => this.deps.getConfig?.()),\n createWebFetchTool(() => this.deps.getConfig?.()),\n createWebExtractTool({ getConfig: () => this.deps.getConfig?.() }),\n // Note: TTS is NOT handled by send_message tool anymore\n // TTS is applied at the ChannelManager dispatch layer\n createMessageTool(bus, () => this.deps.getCurrentContext()),\n ...(mergeTtsConfigFromAppConfig(cfg?.messages?.tts).enabled\n ? [\n createTextToSpeechTool({\n bus,\n getContext: () => this.deps.getCurrentContext(),\n getConfig: () => this.deps.getConfig?.(),\n }),\n ]\n : []),\n createSendMediaTool(workspace, bus, () => this.deps.getCurrentContext()),\n createReadMediaTool(),\n ...(isShareToolAvailable(cfg)\n ? [\n createCreateShareTool({\n workspace,\n getConfig: () => this.deps.getConfig?.(),\n }),\n ]\n : []),\n ...(getMemMgr\n ? [\n createMemorySearchTool({ workspaceDir: workspace, getMemoryManager: () => getMemMgr() }),\n createMemoryGetTool({ workspaceDir: workspace, getMemoryManager: () => getMemMgr() }),\n ]\n : []),\n ...(getMemMgr && shouldRegisterCuratedMemoryTool(this.deps.getConfig?.())\n ? [\n createCuratedMemoryTool(() => getMemMgr()),\n ]\n : []),\n ...(getMemMgr?.().getAdditionalTools() ?? []),\n ...(this.deps.getSessionStore\n ? [\n createSessionSearchTool({\n getSessionStore: this.deps.getSessionStore,\n getConfig: this.deps.getConfig,\n getCurrentSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n }),\n ]\n : []),\n ...(this.deps.getAutomationService\n ? [\n createAutomationTool({\n getAutomationService: this.deps.getAutomationService,\n }),\n ]\n : []),\n createGoalTool({\n getCurrentSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n }),\n ...(browserEnabled\n ? [\n createBrowserUseTool({\n getManager: () => this.ensureBrowserManager(),\n getPageForTask: () => this.acquireBrowserPage(),\n getTaskId: () => this.deps.getCurrentContext()?.sessionKey ?? 'default',\n getConfig: () => this.deps.getConfig?.(),\n getReadiness: () => this.checkBrowserReadinessCached(),\n getSupervisor: () =>\n this.browserSupervisorForTask(this.deps.getCurrentContext()?.sessionKey ?? 'default'),\n notifyBrowserPageClosed: (taskId) => {\n this.browserTaskSupervisors.delete(taskId);\n },\n }),\n ]\n : []),\n ...(primary\n ? [\n createWorkflowTool({\n catalog: createWorkflowCatalog(),\n getCurrentSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n getConfig: () => this.deps.getConfig?.(),\n startWorkflowRun: this.deps.getWorkflowRunService\n ? (params) => this.deps.getWorkflowRunService!().startWorkflowRun(params)\n : undefined,\n }),\n ]\n : []),\n ...(false && primary\n ? [\n createDelegateTool({\n workspace,\n getSubagentModel: () => {\n const gp = options?.getPrimaryModel ?? this.deps.getPrimaryModel;\n const m = gp?.();\n if (!m) {\n throw new Error('No primary model configured for delegate_task');\n }\n return m;\n },\n bus: this.deps.bus,\n getConfig: () => this.deps.getConfig?.(),\n getCurrentContext: () => this.deps.getCurrentContext?.() ?? null,\n hookRunner: this.deps.hookRunner,\n toolExecutorConfig: this.deps.toolExecutorConfig,\n // Injected so `child-agent-factory.ts` does not need to import\n // `AgentToolsFactory` directly (which would form a cycle).\n buildChildTools: (childOpts) => {\n const childFactory = new AgentToolsFactory({\n workspace: childOpts.workspace,\n bus: childOpts.bus,\n getCurrentContext: () => null,\n getConfig: childOpts.getConfig,\n getPrimaryModel: () => childOpts.model,\n toolExecutorConfig: childOpts.toolExecutorConfig,\n });\n return childFactory.createAllTools({\n workspace: childOpts.workspace,\n getPrimaryModel: () => childOpts.model,\n disabledTools: new Set(['extensions']),\n });\n },\n }),\n ]\n : []),\n ...optionalTools,\n ];\n\n return filterToolsByDisabledSet(core, disabled);\n }\n\n createAllTools(coreOptions?: CreateCoreToolsOptions): AgentTool<any, any>[] {\n const coreTools = this.createCoreTools(coreOptions);\n const disableExtensions = coreOptions?.disabledTools?.has('extensions');\n\n let bundled: AgentTool<any, any>[];\n if (!this.deps.extensionRegistry || disableExtensions) {\n bundled = coreTools;\n } else {\n const extensionTools = this.deps.extensionRegistry.getAllTools();\n log.info({ count: extensionTools.length }, 'Loaded extension tools');\n bundled = [...coreTools, ...extensionTools];\n }\n\n const wrapped = wrapToolsWithProtection(bundled, this.deps.toolExecutorConfig);\n\n const executeEnabled = false && !coreOptions?.disabledTools?.has('execute_code');\n\n if (executeEnabled) {\n const sandboxMap = buildSandboxToolMap(wrapped);\n const executeTool = createExecuteCodeTool({ getSandboxToolMap: () => sandboxMap });\n const wrappedExecute = wrapToolsWithProtection([executeTool as any], this.deps.toolExecutorConfig);\n return [...wrapped, ...wrappedExecute];\n }\n\n return wrapped;\n }\n}\n\nfunction filterToolsByDisabledSet(\n tools: any[],\n disabled: Set<string> | undefined,\n): any[] {\n if (!disabled || disabled.size === 0) {\n return tools;\n }\n return tools.filter((t) => !disabled.has(t.name));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"factory.js","names":[],"sources":["../../../../src/agent/tools/factory.ts"],"sourcesContent":["/**\n * Agent Tools Factory - Creates and configures agent tools\n *\n * Centralizes tool creation logic to keep service.ts focused on orchestration.\n *\n * TTS: auto TTS is applied at the ChannelManager via maybeApplyTtsToPayload().\n * Optional \\`text_to_speech\\` tool sends explicit voice when TTS is enabled.\n */\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { Model, Api } from '@earendil-works/pi-ai';\nimport type { Page } from 'playwright-core';\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport {\n createReadFileTool,\n createWriteFileTool,\n createApplyPatchTool,\n createListDirTool,\n createGrepTool,\n createFindTool,\n createExecCommandTool,\n createWebSearchTool,\n createWebFetchTool,\n createWebExtractTool,\n createMessageTool,\n createComposioExecuteTool,\n createSendMediaTool,\n createReadMediaTool,\n createCreateShareTool,\n isShareToolAvailable,\n createMemorySearchTool,\n createMemoryGetTool,\n createTodoTool,\n createUpdatePlanTool,\n createSessionStatusTool,\n createDreamingTool,\n createClarifyTool,\n createToolManualTool,\n createGoalTool,\n createAutomationTool,\n} from './index.js';\nimport { createCuratedMemoryTool } from './curated-memory-tool.js';\nimport { createSessionSearchTool } from './session-search-tool.js';\nimport type { MemoryManager } from '../memory/manager.js';\nimport { shouldRegisterCuratedMemoryTool } from '../memory/memory-config.js';\nimport type { SessionStore } from '../../session/store.js';\nimport type { GatewayClarifyRequestFn } from './clarify-tool.js';\nimport { createImageTool } from './image-tool.js';\nimport { createImageGenerateTool } from './image-generate-tool.js';\nimport {\n BrowserManager,\n BrowserNotReadyError,\n CdpSupervisor,\n checkBrowserReadiness,\n resolveBrowserBackendFromConfig,\n} from '../../browser/index.js';\nimport { createBrowserUseTool } from './browser/tool/browser-use-tool.js';\nimport { createDelegateTool } from './delegate-tool.js';\nimport { createWorkflowTool } from './workflow-tool.js';\nimport { createWorkflowCatalog } from '../workflow/catalog.js';\nimport { resolveDreamingRootForAgent } from '../memory/dreaming/scope.js';\nimport { buildSandboxToolMap, createExecuteCodeTool } from './execute-code-tool.js';\nimport type { AutomationService } from '../../automations/index.js';\nimport type { WorkflowRunServiceLike } from '../../workflows/service/workflow-run-service.types.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type { SkillManager } from '../skills/skill-manager.js';\nimport { wrapToolsWithProtection, type ToolExecutorConfig } from './executor.js';\nimport { createSkillsListTool, createSkillViewTool } from './skills-tools.js';\nimport { createSkillManageTool } from './skill-manage-tool.js';\nimport { createTextToSpeechTool } from './tts-tool.js';\nimport { mergeTtsConfigFromAppConfig } from '../../voice/tts/merge-config.js';\nimport { createGoalEvidenceRecorder } from './goal-evidence-recorder.js';\n\nconst log = createLogger('AgentToolsFactory');\n\n/** Channels where `clarify` can block for a user answer (web UI, Telegram, CLI readline). */\nconst CLARIFY_SUPPORTED_CHANNELS = new Set(['webchat', 'telegram', 'cli']);\n\nexport interface ToolFactoryDeps {\n workspace: string;\n extensionRegistry?: any;\n getCurrentContext: () => { channel: string; chatId: string; sessionKey: string } | null;\n hookRunner?: import('../../extensions/index.js').ExtensionHookRunner;\n bus: MessageBus;\n toolExecutorConfig?: Partial<ToolExecutorConfig>;\n /** Agent defaults (image tools, etc.); use getter so hot-reloaded config applies. */\n getConfig?: () => Config | undefined;\n /** Session / default chat model for vision tool description. */\n getPrimaryModel?: () => Model<Api>;\n /** Memory orchestration (prefetch/sync + external tools). */\n getMemoryManager?: () => MemoryManager;\n /** Session store for `session_search`. */\n getSessionStore?: () => SessionStore;\n /** When set (gateway webchat), enables the `clarify` tool. */\n gatewayClarify?: { requestClarification: GatewayClarifyRequestFn };\n /** Gateway: enables the `automation` tool. */\n getAutomationService?: () => AutomationService | undefined;\n /** Gateway: starts persisted workflow runs (dedicated chat session per run). */\n getWorkflowRunService?: () => WorkflowRunServiceLike | undefined;\n /** Current session skill indexing (tool gating + allowlist); used by skills_list / skill_view. */\n getSkillIndexingContext?: () =>\n | { registeredToolNames: string[]; skillAllowlist?: string[] }\n | undefined;\n /** After skill_manage mutates disk, reload skills + refresh agent prompts (optional). */\n onSkillsFilesystemMutate?: () => void;\n /** Names registered via skill_view for command env passthrough. */\n getSkillPassthroughEnvVarNames?: () => string[];\n /** Add declared env names for the current session (no values stored). */\n registerSkillEnvPassthrough?: (names: string[]) => void;\n}\n\nexport interface CreateCoreToolsOptions {\n /** Workspace root for file/command tools (defaults to factory workspace). */\n workspace?: string;\n /** Canonical `agents/<id>/profile/`: bare SOUL.md / IDENTITY.md resolve here after the workspace. */\n profileMarkdownRoot?: string;\n /** Tool `name` values to omit (e.g. `exec_command`, `extensions` for extension tools). */\n disabledTools?: Set<string>;\n /** Optional primary model for image tool heuristics. */\n getPrimaryModel?: () => Model<Api>;\n getMemoryManager?: () => MemoryManager;\n /** Agent-scoped memories directory used for dreaming state (`agents/<id>/memories`). */\n dreamingRoot?: string;\n agentId?: string;\n /** When set, registers `skills_list` and `skill_view` bound to this workspace\\'s skills. */\n getSkillManager?: () => SkillManager;\n}\n\nexport class AgentToolsFactory {\n private browserManager: BrowserManager | null = null;\n /** One dialog/console supervisor per chat session (browser tab). */\n private readonly browserTaskSupervisors = new Map<string, CdpSupervisor>();\n /** Cached readiness probe — keyed by backend mode + extension host:port. */\n private browserReadinessCache: {\n key: string;\n expiresAt: number;\n inflight?: Promise<BrowserNotReadyError | null>;\n result?: BrowserNotReadyError | null;\n } | null = null;\n\n constructor(private deps: ToolFactoryDeps) {}\n\n private browserReadinessKey(): string {\n const cfg = this.deps.getConfig?.();\n const backend = resolveBrowserBackendFromConfig(cfg);\n const host = '127.0.0.1';\n const port = 19820;\n const cdpUrl = backend.mode === 'cdp' ? backend.config.wsEndpoint : '';\n const cloudKind = backend.mode === 'cloud' ? backend.config.type : '';\n return `${backend.mode}@${host}:${port}|${cdpUrl}|${cloudKind}`;\n }\n\n private async checkBrowserReadinessCached(): Promise<BrowserNotReadyError | null> {\n const key = this.browserReadinessKey();\n const now = Date.now();\n const cached = this.browserReadinessCache;\n if (cached && cached.key === key && cached.expiresAt > now && cached.inflight === undefined) {\n return cached.result ?? null;\n }\n if (cached && cached.key === key && cached.inflight) {\n return cached.inflight;\n }\n const inflight = checkBrowserReadiness(this.deps.getConfig?.());\n this.browserReadinessCache = { key, expiresAt: now + 30_000, inflight };\n try {\n const result = await inflight;\n this.browserReadinessCache = { key, expiresAt: Date.now() + 30_000, result };\n return result;\n } catch (e) {\n // Probe should never throw, but if it does we just bypass the cache.\n this.browserReadinessCache = null;\n log.warn({ err: e }, 'browserReadiness probe failed');\n return null;\n }\n }\n\n /** Invalidate the readiness cache (config hot-reload, settings-page save, etc.). */\n invalidateBrowserReadinessCache(): void {\n this.browserReadinessCache = null;\n }\n\n private browserSupervisorForTask(taskId: string): CdpSupervisor {\n let s = this.browserTaskSupervisors.get(taskId);\n if (!s) {\n s = new CdpSupervisor({ dialogPolicy: 'auto_dismiss', dialogTimeoutSeconds: 300 });\n this.browserTaskSupervisors.set(taskId, s);\n }\n return s;\n }\n\n private async acquireBrowserPage(): Promise<Page> {\n const taskId = this.deps.getCurrentContext()?.sessionKey ?? 'default';\n const mgr = this.ensureBrowserManager();\n await mgr.ensureConnected();\n if (mgr.getExtensionProvider()) {\n return null as unknown as Page;\n }\n const page = await mgr.getPage(taskId);\n this.browserSupervisorForTask(taskId).attach(page);\n return page;\n }\n\n private ensureBrowserManager(): BrowserManager {\n if (!this.browserManager) {\n this.browserManager = new BrowserManager({\n getHeadless: () => false,\n getBackend: () => resolveBrowserBackendFromConfig(this.deps.getConfig?.()),\n });\n }\n return this.browserManager;\n }\n\n /** Close Playwright and all pages (gateway stop, agent manager dispose, or config hot-reload). */\n async shutdownBrowser(): Promise<void> {\n this.browserReadinessCache = null;\n if (!this.browserManager) {\n return;\n }\n await this.browserManager.shutdown();\n this.browserManager = null;\n this.browserTaskSupervisors.clear();\n }\n\n /** Drop the tab for a session when its agent instance is removed. */\n async closeBrowserPageForSession(sessionKey: string): Promise<void> {\n this.browserTaskSupervisors.delete(sessionKey);\n await this.browserManager?.closePage(sessionKey);\n }\n\n createCoreTools(options?: CreateCoreToolsOptions): AgentTool<any, any>[] {\n const workspace = options?.workspace ?? this.deps.workspace;\n const { bus } = this.deps;\n const getPrimary = options?.getPrimaryModel ?? this.deps.getPrimaryModel;\n const getMemMgr = options?.getMemoryManager ?? this.deps.getMemoryManager;\n const getSkillMgr = options?.getSkillManager;\n const disabled = options?.disabledTools;\n\n const primary = getPrimary?.();\n const modelHasVision = primary?.input?.includes('image') ?? false;\n const cfg = this.deps.getConfig?.();\n const dreamingRoot = options?.dreamingRoot ?? (cfg ? resolveDreamingRootForAgent(cfg, options?.agentId) : workspace);\n const browserEnabled = cfg?.browser?.enabled !== false;\n const recordGoalEvidence = createGoalEvidenceRecorder({\n getSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n });\n const imageTool = createImageTool({\n config: cfg,\n workspace,\n modelHasVision,\n });\n const imageGenerateTool = createImageGenerateTool({\n config: cfg,\n workspace,\n });\n\n const composioTool = createComposioExecuteTool(() => this.deps.getConfig?.());\n const optionalTools = [imageTool, imageGenerateTool, composioTool].filter((t) => t != null) as any[];\n\n const readTool = createReadFileTool(workspace, {\n profileMarkdownRoot: options?.profileMarkdownRoot,\n });\n const writeTool = createWriteFileTool(workspace, {\n profileMarkdownRoot: options?.profileMarkdownRoot,\n recordGoalEvidence,\n });\n const applyPatchTool = createApplyPatchTool(workspace, { recordGoalEvidence });\n const listDir = createListDirTool(workspace);\n const grep = createGrepTool(workspace);\n const find = createFindTool(workspace);\n\n const core: AgentTool<any, any>[] = [\n createSessionStatusTool(),\n createDreamingTool({\n getWorkspace: () => workspace,\n getDreamingRoot: () => dreamingRoot,\n getConfig: () => this.deps.getConfig?.(),\n getAgentId: () => options?.agentId,\n }),\n createToolManualTool(),\n createClarifyTool({\n resolveAskUser: () => {\n const req = this.deps.gatewayClarify?.requestClarification;\n if (!req) return null;\n const ctx = this.deps.getCurrentContext();\n if (!ctx?.sessionKey) return null;\n if (!CLARIFY_SUPPORTED_CHANNELS.has(ctx.channel)) return null;\n return (r) => req(ctx.sessionKey, r);\n },\n }),\n createTodoTool({\n getSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n }),\n createUpdatePlanTool(),\n ...(getSkillMgr\n ? [\n createSkillsListTool({\n getSkillManager: getSkillMgr,\n getSkillIndexingContext: this.deps.getSkillIndexingContext,\n }),\n createSkillViewTool({\n getSkillManager: getSkillMgr,\n getSkillIndexingContext: this.deps.getSkillIndexingContext,\n registerSkillEnvPassthrough: this.deps.registerSkillEnvPassthrough,\n }),\n createSkillManageTool({\n getSkillManager: getSkillMgr,\n getWorkspace: () => workspace,\n onSkillsFilesystemMutate: this.deps.onSkillsFilesystemMutate,\n }),\n ]\n : []),\n readTool,\n writeTool,\n applyPatchTool,\n listDir,\n grep,\n find,\n createExecCommandTool(workspace, {\n getSkillPassthroughEnvVarNames: this.deps.getSkillPassthroughEnvVarNames,\n recordGoalEvidence,\n }),\n createWebSearchTool(() => this.deps.getConfig?.()),\n createWebFetchTool(() => this.deps.getConfig?.()),\n createWebExtractTool({ getConfig: () => this.deps.getConfig?.() }),\n // Note: TTS is NOT handled by send_message tool anymore\n // TTS is applied at the ChannelManager dispatch layer\n createMessageTool(bus, () => this.deps.getCurrentContext()),\n ...(mergeTtsConfigFromAppConfig(cfg?.messages?.tts).enabled\n ? [\n createTextToSpeechTool({\n bus,\n getContext: () => this.deps.getCurrentContext(),\n getConfig: () => this.deps.getConfig?.(),\n }),\n ]\n : []),\n createSendMediaTool(workspace, bus, () => this.deps.getCurrentContext()),\n createReadMediaTool(),\n ...(isShareToolAvailable(cfg)\n ? [\n createCreateShareTool({\n workspace,\n getConfig: () => this.deps.getConfig?.(),\n }),\n ]\n : []),\n ...(getMemMgr\n ? [\n createMemorySearchTool({ workspaceDir: workspace, dreamingRoot, getMemoryManager: () => getMemMgr() }),\n createMemoryGetTool({ workspaceDir: workspace, dreamingRoot, getMemoryManager: () => getMemMgr() }),\n ]\n : []),\n ...(getMemMgr && shouldRegisterCuratedMemoryTool(this.deps.getConfig?.())\n ? [\n createCuratedMemoryTool(() => getMemMgr()),\n ]\n : []),\n ...(getMemMgr?.().getAdditionalTools() ?? []),\n ...(this.deps.getSessionStore\n ? [\n createSessionSearchTool({\n getSessionStore: this.deps.getSessionStore,\n getConfig: this.deps.getConfig,\n getCurrentSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n }),\n ]\n : []),\n ...(this.deps.getAutomationService\n ? [\n createAutomationTool({\n getAutomationService: this.deps.getAutomationService,\n }),\n ]\n : []),\n createGoalTool({\n getCurrentSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n }),\n ...(browserEnabled\n ? [\n createBrowserUseTool({\n getManager: () => this.ensureBrowserManager(),\n getPageForTask: () => this.acquireBrowserPage(),\n getTaskId: () => this.deps.getCurrentContext()?.sessionKey ?? 'default',\n getConfig: () => this.deps.getConfig?.(),\n getReadiness: () => this.checkBrowserReadinessCached(),\n getSupervisor: () =>\n this.browserSupervisorForTask(this.deps.getCurrentContext()?.sessionKey ?? 'default'),\n notifyBrowserPageClosed: (taskId) => {\n this.browserTaskSupervisors.delete(taskId);\n },\n }),\n ]\n : []),\n ...(primary\n ? [\n createWorkflowTool({\n catalog: createWorkflowCatalog(),\n getCurrentSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n getConfig: () => this.deps.getConfig?.(),\n startWorkflowRun: this.deps.getWorkflowRunService\n ? (params) => this.deps.getWorkflowRunService!().startWorkflowRun(params)\n : undefined,\n }),\n ]\n : []),\n ...(false && primary\n ? [\n createDelegateTool({\n workspace,\n getSubagentModel: () => {\n const gp = options?.getPrimaryModel ?? this.deps.getPrimaryModel;\n const m = gp?.();\n if (!m) {\n throw new Error('No primary model configured for delegate_task');\n }\n return m;\n },\n bus: this.deps.bus,\n getConfig: () => this.deps.getConfig?.(),\n getCurrentContext: () => this.deps.getCurrentContext?.() ?? null,\n hookRunner: this.deps.hookRunner,\n toolExecutorConfig: this.deps.toolExecutorConfig,\n // Injected so `child-agent-factory.ts` does not need to import\n // `AgentToolsFactory` directly (which would form a cycle).\n buildChildTools: (childOpts) => {\n const childFactory = new AgentToolsFactory({\n workspace: childOpts.workspace,\n bus: childOpts.bus,\n getCurrentContext: () => null,\n getConfig: childOpts.getConfig,\n getPrimaryModel: () => childOpts.model,\n toolExecutorConfig: childOpts.toolExecutorConfig,\n });\n return childFactory.createAllTools({\n workspace: childOpts.workspace,\n getPrimaryModel: () => childOpts.model,\n agentId: options?.agentId ?? childOpts.agentId,\n dreamingRoot: options?.dreamingRoot,\n disabledTools: new Set(['extensions']),\n });\n },\n }),\n ]\n : []),\n ...optionalTools,\n ];\n\n return filterToolsByDisabledSet(core, disabled);\n }\n\n createAllTools(coreOptions?: CreateCoreToolsOptions): AgentTool<any, any>[] {\n const coreTools = this.createCoreTools(coreOptions);\n const disableExtensions = coreOptions?.disabledTools?.has('extensions');\n\n let bundled: AgentTool<any, any>[];\n if (!this.deps.extensionRegistry || disableExtensions) {\n bundled = coreTools;\n } else {\n const extensionTools = this.deps.extensionRegistry.getAllTools();\n log.info({ count: extensionTools.length }, 'Loaded extension tools');\n bundled = [...coreTools, ...extensionTools];\n }\n\n const wrapped = wrapToolsWithProtection(bundled, this.deps.toolExecutorConfig);\n\n const executeEnabled = false && !coreOptions?.disabledTools?.has('execute_code');\n\n if (executeEnabled) {\n const sandboxMap = buildSandboxToolMap(wrapped);\n const executeTool = createExecuteCodeTool({ getSandboxToolMap: () => sandboxMap });\n const wrappedExecute = wrapToolsWithProtection([executeTool as any], this.deps.toolExecutorConfig);\n return [...wrapped, ...wrappedExecute];\n }\n\n return wrapped;\n }\n}\n\nfunction filterToolsByDisabledSet(\n tools: any[],\n disabled: Set<string> | undefined,\n): any[] {\n if (!disabled || disabled.size === 0) {\n return tools;\n }\n return tools.filter((t) => !disabled.has(t.name));\n}\n"],"mappings":"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"}
|
|
@@ -20,6 +20,8 @@ function createFindTool(cwd) {
|
|
|
20
20
|
label: "📁 find",
|
|
21
21
|
description: "Find files by glob pattern (e.g., *.ts, **/*.json).",
|
|
22
22
|
parameters: findSchema,
|
|
23
|
+
supportsParallel: true,
|
|
24
|
+
idempotent: true,
|
|
23
25
|
execute: async (_toolCallId, params, signal) => {
|
|
24
26
|
try {
|
|
25
27
|
const p = params;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find.js","names":[],"sources":["../../../../src/agent/tools/find.ts"],"sourcesContent":["import { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { existsSync } from 'fs';\nimport { globSync } from 'glob';\nimport path from 'path';\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from './truncate.js';\nimport { resolveToCwd } from '../../utils/helpers.js';\n\nconst findSchema = Type.Object({\n\tpattern: Type.String({\n\t\tdescription: \"Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'\",\n\t}),\n\tpath: Type.Optional(Type.String({ description: 'Directory to search in (default: current directory)' })),\n\tlimit: Type.Optional(Type.Number({ description: 'Maximum number of results (default: 1000)' })),\n});\n\nexport type FindToolInput = { pattern: string; path?: string; limit?: number };\n\nconst DEFAULT_LIMIT = 1000;\n\nexport interface FindToolDetails {\n\ttruncation?: TruncationResult;\n\tresultLimitReached?: number;\n}\n\n/**\n * Find tool - Search for files by glob pattern\n */\nexport function createFindTool(cwd: string): AgentTool {\n\treturn {\n\t\tname: 'find',\n\t\tlabel: '📁 find',\n\t\tdescription: 'Find files by glob pattern (e.g., *.ts, **/*.json).',\n\t\tparameters: findSchema,\n\t\texecute: async (\n\t\t\t_toolCallId: string,\n\t\t\tparams: any,\n\t\t\tsignal?: AbortSignal\n\t\t): Promise<AgentToolResult<FindToolDetails>> => {\n\t\t\ttry {\n\t\t\t\tconst p = params as FindToolInput;\n\t\t\t\tconst searchPath = resolveToCwd(p.path || '.', cwd);\n\t\t\t\tconst effectiveLimit = p.limit || DEFAULT_LIMIT;\n\n\t\t\t\tif (!existsSync(searchPath)) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: 'text', text: `Error: Path not found: ${searchPath}` }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: 'text', text: 'Operation aborted' }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst filePaths = globSync(p.pattern, {\n\t\t\t\t\tcwd: searchPath,\n\t\t\t\t\tdot: true,\n\t\t\t\t\tignore: ['**/node_modules/**', '**/.git/**'],\n\t\t\t\t});\n\n\t\t\t\tif (filePaths.length === 0) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: 'text', text: 'No files found matching pattern' }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Relativize paths\n\t\t\t\tconst relativized = filePaths.map((p) => {\n\t\t\t\t\tif (p.startsWith(searchPath)) {\n\t\t\t\t\t\treturn p.slice(searchPath.length + 1);\n\t\t\t\t\t}\n\t\t\t\t\treturn path.relative(searchPath, p);\n\t\t\t\t});\n\n\t\t\t\t// Sort results\n\t\t\t\trelativized.sort();\n\n\t\t\t\tconst resultLimitReached = relativized.length >= effectiveLimit;\n\t\t\t\tconst outputLines = resultLimitReached ? relativized.slice(0, effectiveLimit) : relativized;\n\t\t\t\tconst rawOutput = outputLines.join('\\n');\n\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\n\t\t\t\tlet resultOutput = truncation.content;\n\t\t\t\tconst details: FindToolDetails = {};\n\t\t\t\tconst notices: string[] = [];\n\n\t\t\t\tif (resultLimitReached) {\n\t\t\t\t\tnotices.push(`${effectiveLimit} results limit reached`);\n\t\t\t\t\tdetails.resultLimitReached = effectiveLimit;\n\t\t\t\t}\n\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t}\n\n\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\tresultOutput += `\\n\\n[${notices.join('. ')}]`;\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: 'text', text: resultOutput }],\n\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\t\ttext: `Error during find: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: {},\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t} as any;\n}\n\n/** Default find tool using process.cwd() */\nexport const findTool: AgentTool = createFindTool(process.cwd());\n"],"mappings":";;;;;;;AAQA,MAAM,aAAa,KAAK,OAAO;CAC9B,SAAS,KAAK,OAAO,EACpB,aAAa,gFACb,CAAC;CACF,MAAM,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,uDAAuD,CAAC,CAAC;CACxG,OAAO,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,6CAA6C,CAAC,CAAC;CAC/F,CAAC;AAIF,MAAM,gBAAgB;;;;AAUtB,SAAgB,eAAe,KAAwB;AACtD,QAAO;EACN,MAAM;EACN,OAAO;EACP,aAAa;EACb,YAAY;EACZ,SAAS,OACR,aACA,QACA,WAC+C;AAC/C,OAAI;IACH,MAAM,IAAI;IACV,MAAM,aAAa,aAAa,EAAE,QAAQ,KAAK,IAAI;IACnD,MAAM,iBAAiB,EAAE,SAAS;AAElC,QAAI,CAAC,WAAW,WAAW,CAC1B,QAAO;KACN,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,0BAA0B;MAAc,CAAC;KACzE,SAAS,EAAE;KACX;AAGF,QAAI,QAAQ,QACX,QAAO;KACN,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;MAAqB,CAAC;KACtD,SAAS,EAAE;KACX;IAGF,MAAM,YAAY,SAAS,EAAE,SAAS;KACrC,KAAK;KACL,KAAK;KACL,QAAQ,CAAC,sBAAsB,aAAa;KAC5C,CAAC;AAEF,QAAI,UAAU,WAAW,EACxB,QAAO;KACN,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;MAAmC,CAAC;KACpE,SAAS,EAAE;KACX;IAIF,MAAM,cAAc,UAAU,KAAK,MAAM;AACxC,SAAI,EAAE,WAAW,WAAW,CAC3B,QAAO,EAAE,MAAM,WAAW,SAAS,EAAE;AAEtC,YAAO,KAAK,SAAS,YAAY,EAAE;MAClC;AAGF,gBAAY,MAAM;IAElB,MAAM,qBAAqB,YAAY,UAAU;IAGjD,MAAM,aAAa,cAFC,qBAAqB,YAAY,MAAM,GAAG,eAAe,GAAG,aAClD,KAAK,KACM,EAAE,EAAE,UAAU,OAAO,kBAAkB,CAAC;IAEjF,IAAI,eAAe,WAAW;IAC9B,MAAM,UAA2B,EAAE;IACnC,MAAM,UAAoB,EAAE;AAE5B,QAAI,oBAAoB;AACvB,aAAQ,KAAK,GAAG,eAAe,wBAAwB;AACvD,aAAQ,qBAAqB;;AAG9B,QAAI,WAAW,WAAW;AACzB,aAAQ,KAAK,GAAG,WAAW,kBAAkB,CAAC,gBAAgB;AAC9D,aAAQ,aAAa;;AAGtB,QAAI,QAAQ,SAAS,EACpB,iBAAgB,QAAQ,QAAQ,KAAK,KAAK,CAAC;AAG5C,WAAO;KACN,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;MAAc,CAAC;KAC/C,SAAS,OAAO,KAAK,QAAQ,CAAC,SAAS,IAAI,UAAU,KAAA;KACrD;YACO,OAAO;AACf,WAAO;KACN,SAAS,CACR;MACC,MAAM;MACN,MAAM,sBAAsB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;MAClF,CACD;KACD,SAAS,EAAE;KACX;;;EAGH;;;AAIF,MAAa,WAAsB,eAAe,QAAQ,KAAK,CAAC"}
|
|
1
|
+
{"version":3,"file":"find.js","names":[],"sources":["../../../../src/agent/tools/find.ts"],"sourcesContent":["import { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { existsSync } from 'fs';\nimport { globSync } from 'glob';\nimport path from 'path';\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from './truncate.js';\nimport { resolveToCwd } from '../../utils/helpers.js';\n\nconst findSchema = Type.Object({\n\tpattern: Type.String({\n\t\tdescription: \"Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'\",\n\t}),\n\tpath: Type.Optional(Type.String({ description: 'Directory to search in (default: current directory)' })),\n\tlimit: Type.Optional(Type.Number({ description: 'Maximum number of results (default: 1000)' })),\n});\n\nexport type FindToolInput = { pattern: string; path?: string; limit?: number };\n\nconst DEFAULT_LIMIT = 1000;\n\nexport interface FindToolDetails {\n\ttruncation?: TruncationResult;\n\tresultLimitReached?: number;\n}\n\n/**\n * Find tool - Search for files by glob pattern\n */\nexport function createFindTool(cwd: string): AgentTool {\n\treturn {\n\t\tname: 'find',\n\t\tlabel: '📁 find',\n\t\tdescription: 'Find files by glob pattern (e.g., *.ts, **/*.json).',\n\t\tparameters: findSchema,\n\t\tsupportsParallel: true,\n\t\tidempotent: true,\n\t\texecute: async (\n\t\t\t_toolCallId: string,\n\t\t\tparams: any,\n\t\t\tsignal?: AbortSignal\n\t\t): Promise<AgentToolResult<FindToolDetails>> => {\n\t\t\ttry {\n\t\t\t\tconst p = params as FindToolInput;\n\t\t\t\tconst searchPath = resolveToCwd(p.path || '.', cwd);\n\t\t\t\tconst effectiveLimit = p.limit || DEFAULT_LIMIT;\n\n\t\t\t\tif (!existsSync(searchPath)) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: 'text', text: `Error: Path not found: ${searchPath}` }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: 'text', text: 'Operation aborted' }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst filePaths = globSync(p.pattern, {\n\t\t\t\t\tcwd: searchPath,\n\t\t\t\t\tdot: true,\n\t\t\t\t\tignore: ['**/node_modules/**', '**/.git/**'],\n\t\t\t\t});\n\n\t\t\t\tif (filePaths.length === 0) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: 'text', text: 'No files found matching pattern' }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Relativize paths\n\t\t\t\tconst relativized = filePaths.map((p) => {\n\t\t\t\t\tif (p.startsWith(searchPath)) {\n\t\t\t\t\t\treturn p.slice(searchPath.length + 1);\n\t\t\t\t\t}\n\t\t\t\t\treturn path.relative(searchPath, p);\n\t\t\t\t});\n\n\t\t\t\t// Sort results\n\t\t\t\trelativized.sort();\n\n\t\t\t\tconst resultLimitReached = relativized.length >= effectiveLimit;\n\t\t\t\tconst outputLines = resultLimitReached ? relativized.slice(0, effectiveLimit) : relativized;\n\t\t\t\tconst rawOutput = outputLines.join('\\n');\n\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\n\t\t\t\tlet resultOutput = truncation.content;\n\t\t\t\tconst details: FindToolDetails = {};\n\t\t\t\tconst notices: string[] = [];\n\n\t\t\t\tif (resultLimitReached) {\n\t\t\t\t\tnotices.push(`${effectiveLimit} results limit reached`);\n\t\t\t\t\tdetails.resultLimitReached = effectiveLimit;\n\t\t\t\t}\n\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t}\n\n\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\tresultOutput += `\\n\\n[${notices.join('. ')}]`;\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: 'text', text: resultOutput }],\n\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\t\ttext: `Error during find: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: {},\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t} as any;\n}\n\n/** Default find tool using process.cwd() */\nexport const findTool: AgentTool = createFindTool(process.cwd());\n"],"mappings":";;;;;;;AAQA,MAAM,aAAa,KAAK,OAAO;CAC9B,SAAS,KAAK,OAAO,EACpB,aAAa,gFACb,CAAC;CACF,MAAM,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,uDAAuD,CAAC,CAAC;CACxG,OAAO,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,6CAA6C,CAAC,CAAC;CAC/F,CAAC;AAIF,MAAM,gBAAgB;;;;AAUtB,SAAgB,eAAe,KAAwB;AACtD,QAAO;EACN,MAAM;EACN,OAAO;EACP,aAAa;EACb,YAAY;EACZ,kBAAkB;EAClB,YAAY;EACZ,SAAS,OACR,aACA,QACA,WAC+C;AAC/C,OAAI;IACH,MAAM,IAAI;IACV,MAAM,aAAa,aAAa,EAAE,QAAQ,KAAK,IAAI;IACnD,MAAM,iBAAiB,EAAE,SAAS;AAElC,QAAI,CAAC,WAAW,WAAW,CAC1B,QAAO;KACN,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,0BAA0B;MAAc,CAAC;KACzE,SAAS,EAAE;KACX;AAGF,QAAI,QAAQ,QACX,QAAO;KACN,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;MAAqB,CAAC;KACtD,SAAS,EAAE;KACX;IAGF,MAAM,YAAY,SAAS,EAAE,SAAS;KACrC,KAAK;KACL,KAAK;KACL,QAAQ,CAAC,sBAAsB,aAAa;KAC5C,CAAC;AAEF,QAAI,UAAU,WAAW,EACxB,QAAO;KACN,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;MAAmC,CAAC;KACpE,SAAS,EAAE;KACX;IAIF,MAAM,cAAc,UAAU,KAAK,MAAM;AACxC,SAAI,EAAE,WAAW,WAAW,CAC3B,QAAO,EAAE,MAAM,WAAW,SAAS,EAAE;AAEtC,YAAO,KAAK,SAAS,YAAY,EAAE;MAClC;AAGF,gBAAY,MAAM;IAElB,MAAM,qBAAqB,YAAY,UAAU;IAGjD,MAAM,aAAa,cAFC,qBAAqB,YAAY,MAAM,GAAG,eAAe,GAAG,aAClD,KAAK,KACM,EAAE,EAAE,UAAU,OAAO,kBAAkB,CAAC;IAEjF,IAAI,eAAe,WAAW;IAC9B,MAAM,UAA2B,EAAE;IACnC,MAAM,UAAoB,EAAE;AAE5B,QAAI,oBAAoB;AACvB,aAAQ,KAAK,GAAG,eAAe,wBAAwB;AACvD,aAAQ,qBAAqB;;AAG9B,QAAI,WAAW,WAAW;AACzB,aAAQ,KAAK,GAAG,WAAW,kBAAkB,CAAC,gBAAgB;AAC9D,aAAQ,aAAa;;AAGtB,QAAI,QAAQ,SAAS,EACpB,iBAAgB,QAAQ,QAAQ,KAAK,KAAK,CAAC;AAG5C,WAAO;KACN,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;MAAc,CAAC;KAC/C,SAAS,OAAO,KAAK,QAAQ,CAAC,SAAS,IAAI,UAAU,KAAA;KACrD;YACO,OAAO;AACf,WAAO;KACN,SAAS,CACR;MACC,MAAM;MACN,MAAM,sBAAsB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;MAClF,CACD;KACD,SAAS,EAAE;KACX;;;EAGH;;;AAIF,MAAa,WAAsB,eAAe,QAAQ,KAAK,CAAC"}
|
|
@@ -39,6 +39,8 @@ function createGrepTool(cwd) {
|
|
|
39
39
|
label: "🔍 grep",
|
|
40
40
|
description: "Search file contents for a pattern (regex or literal).",
|
|
41
41
|
parameters: grepSchema,
|
|
42
|
+
supportsParallel: true,
|
|
43
|
+
idempotent: true,
|
|
42
44
|
execute: async (_toolCallId, params, signal) => {
|
|
43
45
|
try {
|
|
44
46
|
const p = params;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grep.js","names":[],"sources":["../../../../src/agent/tools/grep.ts"],"sourcesContent":["import { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { readFileSync, existsSync, statSync } from 'fs';\nimport { globSync } from 'glob';\nimport path from 'path';\nimport {\n\tDEFAULT_MAX_BYTES,\n\tformatSize,\n\tGREP_MAX_LINE_LENGTH,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n} from './truncate.js';\nimport { resolveToCwd } from '../../utils/helpers.js';\n\nconst grepSchema = Type.Object({\n\tpattern: Type.String({ description: 'Search pattern (regex or literal string)' }),\n\tpath: Type.Optional(Type.String({ description: 'Directory or file to search (default: current directory)' })),\n\tglob: Type.Optional(Type.String({ description: \"Filter files by glob pattern, e.g. '*.ts'\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: 'Case-insensitive search (default: false)' })),\n\tliteral: Type.Optional(Type.Boolean({ description: 'Treat pattern as literal string instead of regex (default: false)' })),\n\tcontext: Type.Optional(Type.Number({ description: 'Number of lines to show before and after each match (default: 0)' })),\n\tlimit: Type.Optional(Type.Number({ description: 'Maximum number of matches to return (default: 100)' })),\n});\n\nexport type GrepToolInput = {\n\tpattern: string;\n\tpath?: string;\n\tglob?: string;\n\tignoreCase?: boolean;\n\tliteral?: boolean;\n\tcontext?: number;\n\tlimit?: number;\n};\n\nconst DEFAULT_LIMIT = 100;\n\nexport interface GrepToolDetails {\n\ttruncation?: TruncationResult;\n\tmatchLimitReached?: number;\n\tlinesTruncated?: boolean;\n}\n\n/**\n * Simple grep implementation using Node.js regex\n */\nfunction simpleGrep(\n\tcontent: string,\n\tpattern: string,\n\toptions: { ignoreCase: boolean; literal: boolean }\n): Array<{ lineNumber: number; line: string }> {\n\tconst matches: Array<{ lineNumber: number; line: string }> = [];\n\tconst lines = content.split('\\n');\n\tconst regexPattern = options.literal\n\t\t? pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n\t\t: pattern;\n\tconst flags = options.ignoreCase ? 'i' : '';\n\tconst regex = new RegExp(regexPattern, flags);\n\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tif (regex.test(lines[i])) {\n\t\t\tmatches.push({ lineNumber: i + 1, line: lines[i] });\n\t\t}\n\t}\n\n\treturn matches;\n}\n\n/**\n * Grep tool - Search file contents for a pattern\n */\nexport function createGrepTool(cwd: string): AgentTool {\n\treturn {\n\t\tname: 'grep',\n\t\tlabel: '🔍 grep',\n\t\tdescription: 'Search file contents for a pattern (regex or literal).',\n\t\tparameters: grepSchema,\n\t\texecute: async (\n\t\t\t_toolCallId: string,\n\t\t\tparams: any,\n\t\t\tsignal?: AbortSignal\n\t\t): Promise<AgentToolResult<GrepToolDetails>> => {\n\t\t\ttry {\n\t\t\t\tconst p = params as GrepToolInput;\n\t\t\t\tconst searchPath = resolveToCwd(p.path || '.', cwd);\n\t\t\t\t\n\t\t\t\tif (!existsSync(searchPath)) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: 'text', text: `Error: Path not found: ${searchPath}` }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst isDirectory = statSync(searchPath).isDirectory();\n\t\t\t\tconst context = p.context || 0;\n\t\t\t\tconst effectiveLimit = p.limit || DEFAULT_LIMIT;\n\t\t\t\tconst files: string[] = [];\n\n\t\t\t\t// Collect files to search\n\t\t\t\tif (isDirectory) {\n\t\t\t\t\tconst globPattern = p.glob || '**/*';\n\t\t\t\t\tconst filePaths = globSync(globPattern, {\n\t\t\t\t\t\tcwd: searchPath,\n\t\t\t\t\t\tdot: true,\n\t\t\t\t\t\tignore: ['**/node_modules/**', '**/.git/**'],\n\t\t\t\t\t});\n\t\t\t\t\tfiles.push(...filePaths.map(f => path.join(searchPath, f)));\n\t\t\t\t} else {\n\t\t\t\t\tfiles.push(searchPath);\n\t\t\t\t}\n\n\t\t\t\tconst matches: Array<{ file: string; lineNumber: number; line: string }> = [];\n\t\t\t\tlet matchCount = 0;\n\t\t\t\tlet linesTruncated = false;\n\n\t\t\t\t// Search each file\n\t\t\t\tfor (const filePath of files) {\n\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [{ type: 'text', text: 'Operation aborted' }],\n\t\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (!existsSync(filePath)) continue;\n\t\t\t\t\t\tconst content = readFileSync(filePath, 'utf-8');\n\t\t\t\t\t\tconst fileMatches = simpleGrep(content, p.pattern, {\n\t\t\t\t\t\t\tignoreCase: p.ignoreCase || false,\n\t\t\t\t\t\t\tliteral: p.literal || false,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tfor (const match of fileMatches) {\n\t\t\t\t\t\t\tif (matchCount >= effectiveLimit) break;\n\t\t\t\t\t\t\tmatches.push({ file: filePath, ...match });\n\t\t\t\t\t\t\tmatchCount++;\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Skip files that can't be read\n\t\t\t\t\t}\n\n\t\t\t\t\tif (matchCount >= effectiveLimit) break;\n\t\t\t\t}\n\n\t\t\t\tif (matches.length === 0) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: 'text', text: 'No matches found' }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Format output\n\t\t\t\tconst outputLines: string[] = [];\n\t\t\t\tconst basePath = isDirectory ? searchPath : path.dirname(searchPath);\n\n\t\t\t\tfor (const match of matches) {\n\t\t\t\t\tconst relativePath = path.relative(basePath, match.file);\n\t\t\t\t\tconst { text: truncatedLine, wasTruncated } = truncateLine(match.line);\n\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\n\t\t\t\t\tif (context > 0) {\n\t\t\t\t\t\t// Add context lines\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst content = readFileSync(match.file, 'utf-8');\n\t\t\t\t\t\t\tconst allLines = content.split('\\n');\n\t\t\t\t\t\t\tconst start = Math.max(1, match.lineNumber - context);\n\t\t\t\t\t\t\tconst end = Math.min(allLines.length, match.lineNumber + context);\n\n\t\t\t\t\t\t\tfor (let i = start; i <= end; i++) {\n\t\t\t\t\t\t\t\tconst lineText = allLines[i - 1] || '';\n\t\t\t\t\t\t\t\tconst { text: truncatedContextLine } = truncateLine(lineText);\n\t\t\t\t\t\t\t\tif (i === match.lineNumber) {\n\t\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}:${i}: ${truncatedContextLine}`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}-${i}- ${truncatedContextLine}`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\toutputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedLine}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\toutputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedLine}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst rawOutput = outputLines.join('\\n');\n\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\n\t\t\t\tlet output = truncation.content;\n\t\t\t\tconst details: GrepToolDetails = {};\n\t\t\t\tconst notices: string[] = [];\n\n\t\t\t\tif (matches.length >= effectiveLimit) {\n\t\t\t\t\tnotices.push(`${effectiveLimit} matches limit reached`);\n\t\t\t\t\tdetails.matchLimitReached = effectiveLimit;\n\t\t\t\t}\n\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t}\n\n\t\t\t\tif (linesTruncated) {\n\t\t\t\t\tnotices.push(`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars`);\n\t\t\t\t\tdetails.linesTruncated = true;\n\t\t\t\t}\n\n\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\toutput += `\\n\\n[${notices.join('. ')}]`;\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: 'text', text: output }],\n\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\t\ttext: `Error during grep: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: {},\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t} as any;\n}\n\n/** Default grep tool using process.cwd() */\nexport const grepTool: AgentTool = createGrepTool(process.cwd());\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"grep.js","names":[],"sources":["../../../../src/agent/tools/grep.ts"],"sourcesContent":["import { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { readFileSync, existsSync, statSync } from 'fs';\nimport { globSync } from 'glob';\nimport path from 'path';\nimport {\n\tDEFAULT_MAX_BYTES,\n\tformatSize,\n\tGREP_MAX_LINE_LENGTH,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n} from './truncate.js';\nimport { resolveToCwd } from '../../utils/helpers.js';\n\nconst grepSchema = Type.Object({\n\tpattern: Type.String({ description: 'Search pattern (regex or literal string)' }),\n\tpath: Type.Optional(Type.String({ description: 'Directory or file to search (default: current directory)' })),\n\tglob: Type.Optional(Type.String({ description: \"Filter files by glob pattern, e.g. '*.ts'\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: 'Case-insensitive search (default: false)' })),\n\tliteral: Type.Optional(Type.Boolean({ description: 'Treat pattern as literal string instead of regex (default: false)' })),\n\tcontext: Type.Optional(Type.Number({ description: 'Number of lines to show before and after each match (default: 0)' })),\n\tlimit: Type.Optional(Type.Number({ description: 'Maximum number of matches to return (default: 100)' })),\n});\n\nexport type GrepToolInput = {\n\tpattern: string;\n\tpath?: string;\n\tglob?: string;\n\tignoreCase?: boolean;\n\tliteral?: boolean;\n\tcontext?: number;\n\tlimit?: number;\n};\n\nconst DEFAULT_LIMIT = 100;\n\nexport interface GrepToolDetails {\n\ttruncation?: TruncationResult;\n\tmatchLimitReached?: number;\n\tlinesTruncated?: boolean;\n}\n\n/**\n * Simple grep implementation using Node.js regex\n */\nfunction simpleGrep(\n\tcontent: string,\n\tpattern: string,\n\toptions: { ignoreCase: boolean; literal: boolean }\n): Array<{ lineNumber: number; line: string }> {\n\tconst matches: Array<{ lineNumber: number; line: string }> = [];\n\tconst lines = content.split('\\n');\n\tconst regexPattern = options.literal\n\t\t? pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n\t\t: pattern;\n\tconst flags = options.ignoreCase ? 'i' : '';\n\tconst regex = new RegExp(regexPattern, flags);\n\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tif (regex.test(lines[i])) {\n\t\t\tmatches.push({ lineNumber: i + 1, line: lines[i] });\n\t\t}\n\t}\n\n\treturn matches;\n}\n\n/**\n * Grep tool - Search file contents for a pattern\n */\nexport function createGrepTool(cwd: string): AgentTool {\n\treturn {\n\t\tname: 'grep',\n\t\tlabel: '🔍 grep',\n\t\tdescription: 'Search file contents for a pattern (regex or literal).',\n\t\tparameters: grepSchema,\n\t\tsupportsParallel: true,\n\t\tidempotent: true,\n\t\texecute: async (\n\t\t\t_toolCallId: string,\n\t\t\tparams: any,\n\t\t\tsignal?: AbortSignal\n\t\t): Promise<AgentToolResult<GrepToolDetails>> => {\n\t\t\ttry {\n\t\t\t\tconst p = params as GrepToolInput;\n\t\t\t\tconst searchPath = resolveToCwd(p.path || '.', cwd);\n\t\t\t\t\n\t\t\t\tif (!existsSync(searchPath)) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: 'text', text: `Error: Path not found: ${searchPath}` }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst isDirectory = statSync(searchPath).isDirectory();\n\t\t\t\tconst context = p.context || 0;\n\t\t\t\tconst effectiveLimit = p.limit || DEFAULT_LIMIT;\n\t\t\t\tconst files: string[] = [];\n\n\t\t\t\t// Collect files to search\n\t\t\t\tif (isDirectory) {\n\t\t\t\t\tconst globPattern = p.glob || '**/*';\n\t\t\t\t\tconst filePaths = globSync(globPattern, {\n\t\t\t\t\t\tcwd: searchPath,\n\t\t\t\t\t\tdot: true,\n\t\t\t\t\t\tignore: ['**/node_modules/**', '**/.git/**'],\n\t\t\t\t\t});\n\t\t\t\t\tfiles.push(...filePaths.map(f => path.join(searchPath, f)));\n\t\t\t\t} else {\n\t\t\t\t\tfiles.push(searchPath);\n\t\t\t\t}\n\n\t\t\t\tconst matches: Array<{ file: string; lineNumber: number; line: string }> = [];\n\t\t\t\tlet matchCount = 0;\n\t\t\t\tlet linesTruncated = false;\n\n\t\t\t\t// Search each file\n\t\t\t\tfor (const filePath of files) {\n\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [{ type: 'text', text: 'Operation aborted' }],\n\t\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (!existsSync(filePath)) continue;\n\t\t\t\t\t\tconst content = readFileSync(filePath, 'utf-8');\n\t\t\t\t\t\tconst fileMatches = simpleGrep(content, p.pattern, {\n\t\t\t\t\t\t\tignoreCase: p.ignoreCase || false,\n\t\t\t\t\t\t\tliteral: p.literal || false,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tfor (const match of fileMatches) {\n\t\t\t\t\t\t\tif (matchCount >= effectiveLimit) break;\n\t\t\t\t\t\t\tmatches.push({ file: filePath, ...match });\n\t\t\t\t\t\t\tmatchCount++;\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Skip files that can't be read\n\t\t\t\t\t}\n\n\t\t\t\t\tif (matchCount >= effectiveLimit) break;\n\t\t\t\t}\n\n\t\t\t\tif (matches.length === 0) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: 'text', text: 'No matches found' }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Format output\n\t\t\t\tconst outputLines: string[] = [];\n\t\t\t\tconst basePath = isDirectory ? searchPath : path.dirname(searchPath);\n\n\t\t\t\tfor (const match of matches) {\n\t\t\t\t\tconst relativePath = path.relative(basePath, match.file);\n\t\t\t\t\tconst { text: truncatedLine, wasTruncated } = truncateLine(match.line);\n\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\n\t\t\t\t\tif (context > 0) {\n\t\t\t\t\t\t// Add context lines\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst content = readFileSync(match.file, 'utf-8');\n\t\t\t\t\t\t\tconst allLines = content.split('\\n');\n\t\t\t\t\t\t\tconst start = Math.max(1, match.lineNumber - context);\n\t\t\t\t\t\t\tconst end = Math.min(allLines.length, match.lineNumber + context);\n\n\t\t\t\t\t\t\tfor (let i = start; i <= end; i++) {\n\t\t\t\t\t\t\t\tconst lineText = allLines[i - 1] || '';\n\t\t\t\t\t\t\t\tconst { text: truncatedContextLine } = truncateLine(lineText);\n\t\t\t\t\t\t\t\tif (i === match.lineNumber) {\n\t\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}:${i}: ${truncatedContextLine}`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}-${i}- ${truncatedContextLine}`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\toutputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedLine}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\toutputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedLine}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst rawOutput = outputLines.join('\\n');\n\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\n\t\t\t\tlet output = truncation.content;\n\t\t\t\tconst details: GrepToolDetails = {};\n\t\t\t\tconst notices: string[] = [];\n\n\t\t\t\tif (matches.length >= effectiveLimit) {\n\t\t\t\t\tnotices.push(`${effectiveLimit} matches limit reached`);\n\t\t\t\t\tdetails.matchLimitReached = effectiveLimit;\n\t\t\t\t}\n\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t}\n\n\t\t\t\tif (linesTruncated) {\n\t\t\t\t\tnotices.push(`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars`);\n\t\t\t\t\tdetails.linesTruncated = true;\n\t\t\t\t}\n\n\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\toutput += `\\n\\n[${notices.join('. ')}]`;\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: 'text', text: output }],\n\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\t\ttext: `Error during grep: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: {},\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t} as any;\n}\n\n/** Default grep tool using process.cwd() */\nexport const grepTool: AgentTool = createGrepTool(process.cwd());\n"],"mappings":"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"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { getToolMetadata, DEFAULT_TOOL_METADATA, type AgentToolWithMetadata, type ToolMutationScope, type ToolVerificationKind, type XopcToolMetadata, } from './metadata.js';
|
|
2
|
+
export { ToolConcurrencyController, resolveToolLockMode, type ToolLockMode, } from './concurrency.js';
|
|
1
3
|
export { createReadFileTool, type CreateReadFileToolOptions } from './read.js';
|
|
2
4
|
export { createWriteFileTool, writeFileTool } from './write.js';
|
|
3
5
|
export { createListDirTool, listDirTool } from './list-dir.js';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { DEFAULT_TOOL_METADATA, getToolMetadata } from "./metadata.js";
|
|
2
|
+
import { ToolConcurrencyController, resolveToolLockMode } from "./concurrency.js";
|
|
1
3
|
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, GREP_MAX_LINE_LENGTH, formatSize, truncateHead, truncateLine, truncateTail } from "./truncate.js";
|
|
2
4
|
import { createReadFileTool } from "./read.js";
|
|
3
5
|
import { createWriteFileTool, writeFileTool } from "./write.js";
|
|
@@ -36,4 +38,4 @@ import { createToolManualTool } from "./tool-manual-tool.js";
|
|
|
36
38
|
import { resolveImageModelConfigForTool } from "../image/tool-model-config.js";
|
|
37
39
|
import { createImageTool } from "./image-tool.js";
|
|
38
40
|
import { createImageGenerateTool, resolveImageGenerationModelConfigForTool } from "./image-generate-tool.js";
|
|
39
|
-
export { BrowserManager, DEFAULT_DELEGATE_TOOLS, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, DEFAULT_WEB_EXTRACT_MAX_LENGTH, DELEGATE_BLOCKED_TOOLS, GREP_MAX_LINE_LENGTH, MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT, SANDBOX_ALLOWED_TOOLS, TodoStore, assertBrowserUrlAllowed, buildSandboxToolMap, createApplyPatchTool, createAutomationTool, createClarifyTool, createComposioExecuteTool, createCreateShareTool, createCuratedMemoryTool, createDelegateTool, createDreamingTool, createExecCommandTool, createExecuteCodeTool, createFindTool, createGoalTool, createGrepTool, createImageGenerateTool, createImageTool, createListDirTool, createMemoryGetTool, createMemorySearchTool, createMessageTool, createReadFileTool, createReadMediaTool, createSendMediaTool, createSessionSearchTool, createSessionStatusTool, createSkillManageTool, createSkillViewTool, createSkillsListTool, createTodoTool, createToolManualTool, createUpdatePlanTool, createWebExtractTool, createWebFetchTool, createWebSearchTool, createWorkflowTool, createWriteFileTool, findTool, formatSize, fuzzyFindText, generateDiffString, grepTool, isShareToolAvailable, listDirTool, normalizeForFuzzyMatch, normalizeToLF, resolveImageGenerationModelConfigForTool, resolveImageModelConfigForTool, restoreLineEndings, stripBom, stripHtmlBoilerplate, truncateHead, truncateLine, truncateTail, writeFileTool };
|
|
41
|
+
export { BrowserManager, DEFAULT_DELEGATE_TOOLS, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, DEFAULT_TOOL_METADATA, DEFAULT_WEB_EXTRACT_MAX_LENGTH, DELEGATE_BLOCKED_TOOLS, GREP_MAX_LINE_LENGTH, MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT, SANDBOX_ALLOWED_TOOLS, TodoStore, ToolConcurrencyController, assertBrowserUrlAllowed, buildSandboxToolMap, createApplyPatchTool, createAutomationTool, createClarifyTool, createComposioExecuteTool, createCreateShareTool, createCuratedMemoryTool, createDelegateTool, createDreamingTool, createExecCommandTool, createExecuteCodeTool, createFindTool, createGoalTool, createGrepTool, createImageGenerateTool, createImageTool, createListDirTool, createMemoryGetTool, createMemorySearchTool, createMessageTool, createReadFileTool, createReadMediaTool, createSendMediaTool, createSessionSearchTool, createSessionStatusTool, createSkillManageTool, createSkillViewTool, createSkillsListTool, createTodoTool, createToolManualTool, createUpdatePlanTool, createWebExtractTool, createWebFetchTool, createWebSearchTool, createWorkflowTool, createWriteFileTool, findTool, formatSize, fuzzyFindText, generateDiffString, getToolMetadata, grepTool, isShareToolAvailable, listDirTool, normalizeForFuzzyMatch, normalizeToLF, resolveImageGenerationModelConfigForTool, resolveImageModelConfigForTool, resolveToolLockMode, restoreLineEndings, stripBom, stripHtmlBoilerplate, truncateHead, truncateLine, truncateTail, writeFileTool };
|
|
@@ -9,6 +9,8 @@ function createListDirTool(workspace) {
|
|
|
9
9
|
description: "List the contents of a directory. Relative paths are under the current agent workspace.",
|
|
10
10
|
parameters: ListDirSchema,
|
|
11
11
|
label: "📁 List Directory",
|
|
12
|
+
supportsParallel: true,
|
|
13
|
+
idempotent: true,
|
|
12
14
|
async execute(_toolCallId, params, _signal) {
|
|
13
15
|
try {
|
|
14
16
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-dir.js","names":["p"],"sources":["../../../../src/agent/tools/list-dir.ts"],"sourcesContent":["// List Directory Tool\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { readdir } from 'fs/promises';\nimport { resolvePathUnderWorkspace } from './tool-paths.js';\n\nconst ListDirSchema = Type.Object({\n path: Type.String({ description: 'The directory path to list' }),\n});\n\ntype ListDirParams = { path: string };\n\nexport function createListDirTool(workspace: string): AgentTool {\n return {\n name: 'list_dir',\n description: 'List the contents of a directory. Relative paths are under the current agent workspace.',\n parameters: ListDirSchema,\n label: '📁 List Directory',\n\n async execute(\n _toolCallId: string,\n params: any,\n _signal?: AbortSignal,\n ): Promise<AgentToolResult<{}>> {\n try {\n const p = params as ListDirParams;\n const target = resolvePathUnderWorkspace(p.path, workspace);\n const entries = await readdir(target, { withFileTypes: true });\n const lines = entries.map((e) => {\n const type = e.isDirectory() ? 'd' : e.isFile() ? 'f' : '?';\n return `${type} ${e.name}`;\n });\n return {\n content: [{ type: 'text', text: lines.join('\\n') || '(empty)' }],\n details: {},\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text',\n text: `Error listing directory: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n details: {},\n };\n }\n },\n } as any;\n}\n\nexport const listDirTool: AgentTool = createListDirTool(process.cwd());\n"],"mappings":";;;;AAMA,MAAM,gBAAgB,KAAK,OAAO,EAChC,MAAM,KAAK,OAAO,EAAE,aAAa,8BAA8B,CAAC,EACjE,CAAC;AAIF,SAAgB,kBAAkB,WAA8B;AAC9D,QAAO;EACL,MAAM;EACN,aAAa;EACb,YAAY;EACZ,OAAO;
|
|
1
|
+
{"version":3,"file":"list-dir.js","names":["p"],"sources":["../../../../src/agent/tools/list-dir.ts"],"sourcesContent":["// List Directory Tool\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { readdir } from 'fs/promises';\nimport { resolvePathUnderWorkspace } from './tool-paths.js';\n\nconst ListDirSchema = Type.Object({\n path: Type.String({ description: 'The directory path to list' }),\n});\n\ntype ListDirParams = { path: string };\n\nexport function createListDirTool(workspace: string): AgentTool {\n return {\n name: 'list_dir',\n description: 'List the contents of a directory. Relative paths are under the current agent workspace.',\n parameters: ListDirSchema,\n label: '📁 List Directory',\n supportsParallel: true,\n idempotent: true,\n\n async execute(\n _toolCallId: string,\n params: any,\n _signal?: AbortSignal,\n ): Promise<AgentToolResult<{}>> {\n try {\n const p = params as ListDirParams;\n const target = resolvePathUnderWorkspace(p.path, workspace);\n const entries = await readdir(target, { withFileTypes: true });\n const lines = entries.map((e) => {\n const type = e.isDirectory() ? 'd' : e.isFile() ? 'f' : '?';\n return `${type} ${e.name}`;\n });\n return {\n content: [{ type: 'text', text: lines.join('\\n') || '(empty)' }],\n details: {},\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text',\n text: `Error listing directory: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n details: {},\n };\n }\n },\n } as any;\n}\n\nexport const listDirTool: AgentTool = createListDirTool(process.cwd());\n"],"mappings":";;;;AAMA,MAAM,gBAAgB,KAAK,OAAO,EAChC,MAAM,KAAK,OAAO,EAAE,aAAa,8BAA8B,CAAC,EACjE,CAAC;AAIF,SAAgB,kBAAkB,WAA8B;AAC9D,QAAO;EACL,MAAM;EACN,aAAa;EACb,YAAY;EACZ,OAAO;EACP,kBAAkB;EAClB,YAAY;EAEZ,MAAM,QACJ,aACA,QACA,SAC8B;AAC9B,OAAI;AAQF,WAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,OALd,MADQ,QADP,0BAA0BA,OAAE,MAAM,UACb,EAAE,EAAE,eAAe,MAAM,CAAC,EACxC,KAAK,MAAM;AAE/B,cAAO,GADM,EAAE,aAAa,GAAG,MAAM,EAAE,QAAQ,GAAG,MAAM,IACzC,GAAG,EAAE;QAGiB,CAAC,KAAK,KAAK,IAAI;MAAW,CAAC;KAChE,SAAS,EAAE;KACZ;YACM,OAAO;AACd,WAAO;KACL,SAAS,CACP;MACE,MAAM;MACN,MAAM,4BAA4B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;MACzF,CACF;KACD,SAAS,EAAE;KACZ;;;EAGN;;AAGH,MAAa,cAAyB,kBAAkB,QAAQ,KAAK,CAAC"}
|
|
@@ -2,6 +2,7 @@ import type { AgentTool } from '@earendil-works/pi-agent-core';
|
|
|
2
2
|
import type { MemoryManager } from '../memory/manager.js';
|
|
3
3
|
export interface MemoryToolOptions {
|
|
4
4
|
workspaceDir: string;
|
|
5
|
+
dreamingRoot: string;
|
|
5
6
|
getMemoryManager: () => MemoryManager;
|
|
6
7
|
}
|
|
7
8
|
export declare function createMemorySearchTool(options: MemoryToolOptions): AgentTool;
|
|
@@ -7,7 +7,7 @@ const MemorySearchSchema = Type.Object({
|
|
|
7
7
|
minScore: Type.Optional(Type.Number())
|
|
8
8
|
});
|
|
9
9
|
function createMemorySearchTool(options) {
|
|
10
|
-
const {
|
|
10
|
+
const { dreamingRoot, getMemoryManager } = options;
|
|
11
11
|
return {
|
|
12
12
|
name: "memory_search",
|
|
13
13
|
label: "🔍 Memory Search",
|
|
@@ -34,7 +34,7 @@ function createMemorySearchTool(options) {
|
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
36
|
recordDreamingRecalls({
|
|
37
|
-
|
|
37
|
+
dreamingRoot,
|
|
38
38
|
query,
|
|
39
39
|
matches: results.map((entry) => ({
|
|
40
40
|
file: entry.citation.path ?? entry.record.source.path ?? entry.record.id,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-tool.js","names":[],"sources":["../../../../src/agent/tools/memory-tool.ts"],"sourcesContent":["// Memory search tools for xopc agent\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { recordDreamingRecalls } from '../memory/dreaming/short-term-store.js';\nimport type { MemoryManager } from '../memory/manager.js';\n\n// =============================================================================\n// Memory Search Tool\n// =============================================================================\nconst MemorySearchSchema = Type.Object({\n query: Type.String(),\n maxResults: Type.Optional(Type.Number()),\n minScore: Type.Optional(Type.Number()),\n});\n\ntype MemorySearchParams = { query: string; maxResults?: number; minScore?: number };\n\nexport interface MemoryToolOptions {\n workspaceDir: string;\n getMemoryManager: () => MemoryManager;\n}\n\nexport function createMemorySearchTool(options: MemoryToolOptions): AgentTool {\n const {
|
|
1
|
+
{"version":3,"file":"memory-tool.js","names":[],"sources":["../../../../src/agent/tools/memory-tool.ts"],"sourcesContent":["// Memory search tools for xopc agent\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { recordDreamingRecalls } from '../memory/dreaming/short-term-store.js';\nimport type { MemoryManager } from '../memory/manager.js';\n\n// =============================================================================\n// Memory Search Tool\n// =============================================================================\nconst MemorySearchSchema = Type.Object({\n query: Type.String(),\n maxResults: Type.Optional(Type.Number()),\n minScore: Type.Optional(Type.Number()),\n});\n\ntype MemorySearchParams = { query: string; maxResults?: number; minScore?: number };\n\nexport interface MemoryToolOptions {\n workspaceDir: string;\n dreamingRoot: string;\n getMemoryManager: () => MemoryManager;\n}\n\nexport function createMemorySearchTool(options: MemoryToolOptions): AgentTool {\n const { dreamingRoot, getMemoryManager } = options;\n return {\n name: 'memory_search',\n label: '🔍 Memory Search',\n description:\n 'Mandatory recall step: search indexed profile, curated, and session memory sources before answering questions about prior work, decisions, dates, people, preferences, or todos; returns top snippets with source path + lines.',\n parameters: MemorySearchSchema,\n\n async execute(\n _toolCallId: string,\n params: any,\n _signal?: AbortSignal,\n ): Promise<AgentToolResult<{}>> {\n const { query, maxResults, minScore } = params as MemorySearchParams;\n\n try {\n const results = await getMemoryManager().search({ query, maxResults, minScore });\n for (const result of results) {\n getMemoryManager().recordSignal({\n source: 'search_recall',\n recordId: result.record.id,\n score: result.score,\n content: result.snippet,\n metadata: {\n providerId: result.citation.providerId,\n path: result.citation.path,\n lineStart: result.citation.lineStart,\n lineEnd: result.citation.lineEnd,\n },\n });\n }\n // Dreaming: record short-term recall evidence from memory_search.\n void recordDreamingRecalls({\n dreamingRoot,\n query,\n matches: results.map((entry) => ({\n file: entry.citation.path ?? entry.record.source.path ?? entry.record.id,\n lines: entry.snippet,\n score: entry.score,\n lineNumbers:\n entry.citation.lineStart != null\n ? [entry.citation.lineStart, entry.citation.lineEnd ?? entry.citation.lineStart]\n : [],\n })),\n }).catch(() => {});\n const withCitations = results.map((entry) => ({\n id: entry.record.id,\n kind: entry.record.kind,\n file: entry.citation.path ?? entry.record.source.path,\n lines: entry.snippet,\n score: entry.score,\n lineNumbers:\n entry.citation.lineStart != null\n ? [entry.citation.lineStart, entry.citation.lineEnd ?? entry.citation.lineStart]\n : [],\n citation: `${entry.citation.path ?? entry.record.id}${entry.citation.lineStart != null ? `#L${entry.citation.lineStart}${entry.citation.lineEnd && entry.citation.lineEnd !== entry.citation.lineStart ? `-L${entry.citation.lineEnd}` : ''}` : ''}`,\n snippet: `${entry.snippet.trim()}\\n\\nSource: ${entry.citation.path ?? entry.record.id}${entry.citation.lineStart != null ? `#L${entry.citation.lineStart}${entry.citation.lineEnd && entry.citation.lineEnd !== entry.citation.lineStart ? `-L${entry.citation.lineEnd}` : ''}` : ''}`,\n }));\n\n return {\n content: [{ type: 'text', text: JSON.stringify({ results: withCitations, provider: 'memory-manager' }, null, 2) }],\n details: { results: withCitations },\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n content: [{ type: 'text', text: `Search error: ${message}` }],\n details: { error: message },\n };\n }\n },\n } as any;\n}\n\n// =============================================================================\n// Memory Get Tool\n// =============================================================================\nconst MemoryGetSchema = Type.Object({\n path: Type.String(),\n from: Type.Optional(Type.Number()),\n lines: Type.Optional(Type.Number()),\n});\n\ntype MemoryGetParams = { path: string; from?: number; lines?: number };\n\nexport function createMemoryGetTool(options: MemoryToolOptions): AgentTool {\n const { getMemoryManager } = options;\n return {\n name: 'memory_get',\n label: '📄 Memory Get',\n description: 'Safe snippet read from a source path returned by memory_search, with optional from/lines; pull only the needed lines and keep context small.',\n parameters: MemoryGetSchema,\n\n async execute(\n _toolCallId: string,\n params: any,\n _signal?: AbortSignal,\n ): Promise<AgentToolResult<{}>> {\n const { path, from, lines } = params as MemoryGetParams;\n\n try {\n const result = await getMemoryManager().read({ path, from, lines });\n if (!result) {\n return {\n content: [{ type: 'text', text: `File not found: ${path}` }],\n details: { path, text: '' },\n };\n }\n return {\n content: [{ type: 'text', text: result.record.content }],\n details: { path, text: result.record.content, lineNumbers: result.lineNumbers },\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n content: [{ type: 'text', text: `Read error: ${message}` }],\n details: { error: message },\n };\n }\n },\n } as any;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AgentTool } from '@earendil-works/pi-agent-core';
|
|
2
|
+
export type ToolMutationScope = 'none' | 'workspace' | 'external' | 'unknown';
|
|
3
|
+
export type ToolVerificationKind = 'none' | 'diff-review' | 'test' | 'build' | 'lint' | 'typecheck';
|
|
4
|
+
export interface XopcToolMetadata {
|
|
5
|
+
mutatesWorkspace?: boolean;
|
|
6
|
+
mutationScope?: ToolMutationScope;
|
|
7
|
+
supportsParallel?: boolean;
|
|
8
|
+
idempotent?: boolean;
|
|
9
|
+
verificationKind?: ToolVerificationKind;
|
|
10
|
+
requiresExclusiveWorkspaceLock?: boolean;
|
|
11
|
+
finalGuardRelevant?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export type AgentToolWithMetadata<TParams = any, TDetails = any> = AgentTool<TParams, TDetails> & XopcToolMetadata;
|
|
14
|
+
export declare const DEFAULT_TOOL_METADATA: Required<XopcToolMetadata>;
|
|
15
|
+
export declare function getToolMetadata(tool: AgentTool<any, any>): Required<XopcToolMetadata>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/agent/tools/metadata.ts
|
|
2
|
+
const DEFAULT_TOOL_METADATA = {
|
|
3
|
+
mutatesWorkspace: false,
|
|
4
|
+
mutationScope: "none",
|
|
5
|
+
supportsParallel: false,
|
|
6
|
+
idempotent: false,
|
|
7
|
+
verificationKind: "none",
|
|
8
|
+
requiresExclusiveWorkspaceLock: false,
|
|
9
|
+
finalGuardRelevant: false
|
|
10
|
+
};
|
|
11
|
+
function getToolMetadata(tool) {
|
|
12
|
+
const t = tool;
|
|
13
|
+
return {
|
|
14
|
+
mutatesWorkspace: t.mutatesWorkspace === true,
|
|
15
|
+
mutationScope: t.mutationScope ?? DEFAULT_TOOL_METADATA.mutationScope,
|
|
16
|
+
supportsParallel: t.supportsParallel === true,
|
|
17
|
+
idempotent: t.idempotent === true,
|
|
18
|
+
verificationKind: t.verificationKind ?? DEFAULT_TOOL_METADATA.verificationKind,
|
|
19
|
+
requiresExclusiveWorkspaceLock: t.requiresExclusiveWorkspaceLock === true,
|
|
20
|
+
finalGuardRelevant: t.finalGuardRelevant === true
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { DEFAULT_TOOL_METADATA, getToolMetadata };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","names":[],"sources":["../../../../src/agent/tools/metadata.ts"],"sourcesContent":["import type { AgentTool } from '@earendil-works/pi-agent-core';\n\nexport type ToolMutationScope = 'none' | 'workspace' | 'external' | 'unknown';\n\nexport type ToolVerificationKind = 'none' | 'diff-review' | 'test' | 'build' | 'lint' | 'typecheck';\n\nexport interface XopcToolMetadata {\n mutatesWorkspace?: boolean;\n mutationScope?: ToolMutationScope;\n supportsParallel?: boolean;\n idempotent?: boolean;\n verificationKind?: ToolVerificationKind;\n requiresExclusiveWorkspaceLock?: boolean;\n finalGuardRelevant?: boolean;\n}\n\nexport type AgentToolWithMetadata<TParams = any, TDetails = any> = AgentTool<TParams, TDetails> & XopcToolMetadata;\n\nexport const DEFAULT_TOOL_METADATA: Required<XopcToolMetadata> = {\n mutatesWorkspace: false,\n mutationScope: 'none',\n supportsParallel: false,\n idempotent: false,\n verificationKind: 'none',\n requiresExclusiveWorkspaceLock: false,\n finalGuardRelevant: false,\n};\n\nexport function getToolMetadata(tool: AgentTool<any, any>): Required<XopcToolMetadata> {\n const t = tool as AgentToolWithMetadata;\n return {\n mutatesWorkspace: t.mutatesWorkspace === true,\n mutationScope: t.mutationScope ?? DEFAULT_TOOL_METADATA.mutationScope,\n supportsParallel: t.supportsParallel === true,\n idempotent: t.idempotent === true,\n verificationKind: t.verificationKind ?? DEFAULT_TOOL_METADATA.verificationKind,\n requiresExclusiveWorkspaceLock: t.requiresExclusiveWorkspaceLock === true,\n finalGuardRelevant: t.finalGuardRelevant === true,\n };\n}\n"],"mappings":";AAkBA,MAAa,wBAAoD;CAC/D,kBAAkB;CAClB,eAAe;CACf,kBAAkB;CAClB,YAAY;CACZ,kBAAkB;CAClB,gCAAgC;CAChC,oBAAoB;CACrB;AAED,SAAgB,gBAAgB,MAAuD;CACrF,MAAM,IAAI;AACV,QAAO;EACL,kBAAkB,EAAE,qBAAqB;EACzC,eAAe,EAAE,iBAAiB,sBAAsB;EACxD,kBAAkB,EAAE,qBAAqB;EACzC,YAAY,EAAE,eAAe;EAC7B,kBAAkB,EAAE,oBAAoB,sBAAsB;EAC9D,gCAAgC,EAAE,mCAAmC;EACrE,oBAAoB,EAAE,uBAAuB;EAC9C"}
|
|
@@ -16,6 +16,8 @@ function createReadFileTool(workspace, options) {
|
|
|
16
16
|
description: "Read file contents. Relative paths are from the current agent workspace; profile Markdown (SOUL.md, etc.) is found automatically when given by filename.",
|
|
17
17
|
parameters: ReadFileSchema,
|
|
18
18
|
label: "📄 Read",
|
|
19
|
+
supportsParallel: true,
|
|
20
|
+
idempotent: true,
|
|
19
21
|
async execute(_toolCallId, params, _signal) {
|
|
20
22
|
return executeReadFile(workspace, options?.profileMarkdownRoot, params);
|
|
21
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read.js","names":[],"sources":["../../../../src/agent/tools/read.ts"],"sourcesContent":["// Read file tool\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { readFile, stat } from 'fs/promises';\nimport { checkFileSafety } from '../prompt/safety.js';\nimport { truncateHead, formatSize, DEFAULT_MAX_BYTES } from './truncate.js';\nimport {\n isBareProfileMarkdownFileName,\n resolveProfileMarkdownPathIfBareName,\n resolvePathUnderWorkspace,\n} from './tool-paths.js';\n\nconst MAX_FILE_SIZE = 10 * 1024 * 1024;\nconst DEFAULT_MAX_LINES = 500;\n\nconst ReadFileSchema = Type.Object({\n path: Type.String({ description: 'File path to read' }),\n limit: Type.Optional(Type.Number({ description: 'Max lines (default: 500)' })),\n});\n\nexport interface CreateReadFileToolOptions {\n /** When set and the path is a bare profile filename (e.g. SOUL.md), try this root if not in workspace. */\n profileMarkdownRoot?: string;\n}\n\ntype ReadFileParams = {\n path: string;\n limit?: number;\n};\n\nexport function createReadFileTool(\n workspace: string,\n options?: CreateReadFileToolOptions,\n): AgentTool {\n return {\n name: 'read_file',\n description:\n 'Read file contents. Relative paths are from the current agent workspace; profile Markdown (SOUL.md, etc.) is found automatically when given by filename.',\n parameters: ReadFileSchema,\n label: '📄 Read',\n\n async execute(\n _toolCallId: string,\n params: any,\n _signal?: AbortSignal,\n ): Promise<AgentToolResult<{}>> {\n return executeReadFile(workspace, options?.profileMarkdownRoot, params as ReadFileParams);\n },\n } as any;\n}\n\nasync function executeReadFile(\n workspace: string,\n profileMarkdownRoot: string | undefined,\n params: ReadFileParams,\n): Promise<AgentToolResult<{}>> {\n try {\n const safety = checkFileSafety('read', params.path);\n if (!safety.allowed) {\n return { content: [{ type: 'text', text: `🚫 ${safety.message}` }], details: {} };\n }\n\n let normalized = resolvePathUnderWorkspace(params.path, workspace);\n let stats;\n try {\n stats = await stat(normalized);\n } catch (e) {\n const code = (e as NodeJS.ErrnoException)?.code;\n if (\n code === 'ENOENT' &&\n profileMarkdownRoot &&\n isBareProfileMarkdownFileName(params.path)\n ) {\n const alt = resolveProfileMarkdownPathIfBareName(params.path, profileMarkdownRoot);\n try {\n stats = await stat(alt);\n normalized = alt;\n } catch {\n throw e;\n }\n } else {\n throw e;\n }\n }\n\n if (stats.size > MAX_FILE_SIZE) {\n return { content: [{ type: 'text', text: `🚫 File too large: ${formatSize(stats.size)}` }], details: {} };\n }\n\n const content = await readFile(normalized, 'utf-8');\n const truncation = truncateHead(content, { maxLines: params.limit || DEFAULT_MAX_LINES, maxBytes: DEFAULT_MAX_BYTES });\n\n let outputText = truncation.content;\n if (truncation.truncated) {\n if (truncation.firstLineExceedsLimit) {\n outputText = `(Line exceeds ${formatSize(DEFAULT_MAX_BYTES)})`;\n } else {\n outputText += `\\n\\n[${truncation.outputLines}/${truncation.totalLines} lines]`;\n }\n }\n\n return { content: [{ type: 'text', text: outputText }], details: {} };\n } catch (error) {\n return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], details: {} };\n }\n}\n"],"mappings":";;;;;;AAYA,MAAM,gBAAgB,KAAK,OAAO;AAClC,MAAM,oBAAoB;AAE1B,MAAM,iBAAiB,KAAK,OAAO;CACjC,MAAM,KAAK,OAAO,EAAE,aAAa,qBAAqB,CAAC;CACvD,OAAO,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,4BAA4B,CAAC,CAAC;CAC/E,CAAC;AAYF,SAAgB,mBACd,WACA,SACW;AACX,QAAO;EACL,MAAM;EACN,aACE;EACF,YAAY;EACZ,OAAO;
|
|
1
|
+
{"version":3,"file":"read.js","names":[],"sources":["../../../../src/agent/tools/read.ts"],"sourcesContent":["// Read file tool\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { readFile, stat } from 'fs/promises';\nimport { checkFileSafety } from '../prompt/safety.js';\nimport { truncateHead, formatSize, DEFAULT_MAX_BYTES } from './truncate.js';\nimport {\n isBareProfileMarkdownFileName,\n resolveProfileMarkdownPathIfBareName,\n resolvePathUnderWorkspace,\n} from './tool-paths.js';\n\nconst MAX_FILE_SIZE = 10 * 1024 * 1024;\nconst DEFAULT_MAX_LINES = 500;\n\nconst ReadFileSchema = Type.Object({\n path: Type.String({ description: 'File path to read' }),\n limit: Type.Optional(Type.Number({ description: 'Max lines (default: 500)' })),\n});\n\nexport interface CreateReadFileToolOptions {\n /** When set and the path is a bare profile filename (e.g. SOUL.md), try this root if not in workspace. */\n profileMarkdownRoot?: string;\n}\n\ntype ReadFileParams = {\n path: string;\n limit?: number;\n};\n\nexport function createReadFileTool(\n workspace: string,\n options?: CreateReadFileToolOptions,\n): AgentTool {\n return {\n name: 'read_file',\n description:\n 'Read file contents. Relative paths are from the current agent workspace; profile Markdown (SOUL.md, etc.) is found automatically when given by filename.',\n parameters: ReadFileSchema,\n label: '📄 Read',\n supportsParallel: true,\n idempotent: true,\n\n async execute(\n _toolCallId: string,\n params: any,\n _signal?: AbortSignal,\n ): Promise<AgentToolResult<{}>> {\n return executeReadFile(workspace, options?.profileMarkdownRoot, params as ReadFileParams);\n },\n } as any;\n}\n\nasync function executeReadFile(\n workspace: string,\n profileMarkdownRoot: string | undefined,\n params: ReadFileParams,\n): Promise<AgentToolResult<{}>> {\n try {\n const safety = checkFileSafety('read', params.path);\n if (!safety.allowed) {\n return { content: [{ type: 'text', text: `🚫 ${safety.message}` }], details: {} };\n }\n\n let normalized = resolvePathUnderWorkspace(params.path, workspace);\n let stats;\n try {\n stats = await stat(normalized);\n } catch (e) {\n const code = (e as NodeJS.ErrnoException)?.code;\n if (\n code === 'ENOENT' &&\n profileMarkdownRoot &&\n isBareProfileMarkdownFileName(params.path)\n ) {\n const alt = resolveProfileMarkdownPathIfBareName(params.path, profileMarkdownRoot);\n try {\n stats = await stat(alt);\n normalized = alt;\n } catch {\n throw e;\n }\n } else {\n throw e;\n }\n }\n\n if (stats.size > MAX_FILE_SIZE) {\n return { content: [{ type: 'text', text: `🚫 File too large: ${formatSize(stats.size)}` }], details: {} };\n }\n\n const content = await readFile(normalized, 'utf-8');\n const truncation = truncateHead(content, { maxLines: params.limit || DEFAULT_MAX_LINES, maxBytes: DEFAULT_MAX_BYTES });\n\n let outputText = truncation.content;\n if (truncation.truncated) {\n if (truncation.firstLineExceedsLimit) {\n outputText = `(Line exceeds ${formatSize(DEFAULT_MAX_BYTES)})`;\n } else {\n outputText += `\\n\\n[${truncation.outputLines}/${truncation.totalLines} lines]`;\n }\n }\n\n return { content: [{ type: 'text', text: outputText }], details: {} };\n } catch (error) {\n return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], details: {} };\n }\n}\n"],"mappings":";;;;;;AAYA,MAAM,gBAAgB,KAAK,OAAO;AAClC,MAAM,oBAAoB;AAE1B,MAAM,iBAAiB,KAAK,OAAO;CACjC,MAAM,KAAK,OAAO,EAAE,aAAa,qBAAqB,CAAC;CACvD,OAAO,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,4BAA4B,CAAC,CAAC;CAC/E,CAAC;AAYF,SAAgB,mBACd,WACA,SACW;AACX,QAAO;EACL,MAAM;EACN,aACE;EACF,YAAY;EACZ,OAAO;EACP,kBAAkB;EAClB,YAAY;EAEZ,MAAM,QACJ,aACA,QACA,SAC8B;AAC9B,UAAO,gBAAgB,WAAW,SAAS,qBAAqB,OAAyB;;EAE5F;;AAGH,eAAe,gBACb,WACA,qBACA,QAC8B;AAC9B,KAAI;EACF,MAAM,SAAS,gBAAgB,QAAQ,OAAO,KAAK;AACnD,MAAI,CAAC,OAAO,QACV,QAAO;GAAE,SAAS,CAAC;IAAE,MAAM;IAAQ,MAAM,MAAM,OAAO;IAAW,CAAC;GAAE,SAAS,EAAE;GAAE;EAGnF,IAAI,aAAa,0BAA0B,OAAO,MAAM,UAAU;EAClE,IAAI;AACJ,MAAI;AACF,WAAQ,MAAM,KAAK,WAAW;WACvB,GAAG;AAEV,OADc,GAA6B,SAEhC,YACT,uBACA,8BAA8B,OAAO,KAAK,EAC1C;IACA,MAAM,MAAM,qCAAqC,OAAO,MAAM,oBAAoB;AAClF,QAAI;AACF,aAAQ,MAAM,KAAK,IAAI;AACvB,kBAAa;YACP;AACN,WAAM;;SAGR,OAAM;;AAIV,MAAI,MAAM,OAAO,cACf,QAAO;GAAE,SAAS,CAAC;IAAE,MAAM;IAAQ,MAAM,sBAAsB,WAAW,MAAM,KAAK;IAAI,CAAC;GAAE,SAAS,EAAE;GAAE;EAI3G,MAAM,aAAa,aAAa,MADV,SAAS,YAAY,QAAQ,EACV;GAAE,UAAU,OAAO,SAAS;GAAmB,UAAU;GAAmB,CAAC;EAEtH,IAAI,aAAa,WAAW;AAC5B,MAAI,WAAW,UACb,KAAI,WAAW,sBACb,cAAa,iBAAiB,WAAW,kBAAkB,CAAC;MAE5D,eAAc,QAAQ,WAAW,YAAY,GAAG,WAAW,WAAW;AAI1E,SAAO;GAAE,SAAS,CAAC;IAAE,MAAM;IAAQ,MAAM;IAAY,CAAC;GAAE,SAAS,EAAE;GAAE;UAC9D,OAAO;AACd,SAAO;GAAE,SAAS,CAAC;IAAE,MAAM;IAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAI,CAAC;GAAE,SAAS,EAAE;GAAE"}
|
|
@@ -16,6 +16,12 @@ function createWriteFileTool(workspace, options) {
|
|
|
16
16
|
description: "Create or overwrite a file. Relative paths are under the current agent workspace; profile Markdown (SOUL.md, etc.) is written automatically when given by filename.",
|
|
17
17
|
parameters: WriteFileSchema,
|
|
18
18
|
label: "📝 Write",
|
|
19
|
+
mutatesWorkspace: true,
|
|
20
|
+
mutationScope: "workspace",
|
|
21
|
+
supportsParallel: false,
|
|
22
|
+
idempotent: false,
|
|
23
|
+
requiresExclusiveWorkspaceLock: true,
|
|
24
|
+
finalGuardRelevant: true,
|
|
19
25
|
async execute(_toolCallId, params, _signal) {
|
|
20
26
|
try {
|
|
21
27
|
const p = params;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.js","names":[],"sources":["../../../../src/agent/tools/write.ts"],"sourcesContent":["// Write file tool\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { writeFile, mkdir } from 'fs/promises';\nimport { dirname } from 'path';\nimport { checkFileSafety } from '../prompt/safety.js';\nimport {\n isBareProfileMarkdownFileName,\n resolveProfileMarkdownPathIfBareName,\n resolvePathUnderWorkspace,\n} from './tool-paths.js';\nimport { evaluateFilePolicy } from '../sandbox/exec-policy.js';\nimport type { GoalEvidenceRecordInput } from './goal-evidence-recorder.js';\n\nconst MAX_FILE_SIZE = 10 * 1024 * 1024;\n\nconst WriteFileSchema = Type.Object({\n path: Type.String({ description: 'File path to write' }),\n content: Type.String({ description: 'Content to write' }),\n});\n\ntype WriteFileParams = { path: string; content: string };\n\nexport interface CreateWriteFileToolOptions {\n /** When set and the path is a bare profile filename (e.g. SOUL.md), write to this root. */\n profileMarkdownRoot?: string;\n recordGoalEvidence?: (input: GoalEvidenceRecordInput) => Promise<void> | void;\n}\n\nexport function createWriteFileTool(\n workspace: string,\n options?: CreateWriteFileToolOptions,\n): AgentTool {\n return {\n name: 'write_file',\n description:\n 'Create or overwrite a file. Relative paths are under the current agent workspace; profile Markdown (SOUL.md, etc.) is written automatically when given by filename.',\n parameters: WriteFileSchema,\n label: '📝 Write',\n\n async execute(\n _toolCallId: string,\n params: any,\n _signal?: AbortSignal,\n ): Promise<AgentToolResult<{}>> {\n try {\n const p = params as WriteFileParams;\n const safety = checkFileSafety('write', p.path);\n if (!safety.allowed) {\n return { content: [{ type: 'text', text: `🚫 ${safety.message}` }], details: {} };\n }\n\n const writesProfileFile = Boolean(\n options?.profileMarkdownRoot && isBareProfileMarkdownFileName(p.path),\n );\n const workspaceRoot = writesProfileFile ? options!.profileMarkdownRoot! : workspace;\n\n // Sandbox path-policy check (blocked dirs, symlink escape, config protection)\n const pathPolicy = evaluateFilePolicy({\n operation: 'write',\n path: p.path,\n workspaceRoot,\n });\n if (!pathPolicy.allowed) {\n return { content: [{ type: 'text', text: `🚫 Sandbox: ${pathPolicy.reason}` }], details: {} };\n }\n\n const contentBytes = Buffer.byteLength(p.content, 'utf-8');\n if (contentBytes > MAX_FILE_SIZE) {\n return { content: [{ type: 'text', text: `🚫 File too large: ${contentBytes} bytes` }], details: {} };\n }\n\n const target = writesProfileFile\n ? resolveProfileMarkdownPathIfBareName(p.path, options!.profileMarkdownRoot!)\n : resolvePathUnderWorkspace(p.path, workspace);\n await mkdir(dirname(target), { recursive: true });\n await writeFile(target, p.content, 'utf-8');\n await options?.recordGoalEvidence?.({\n kind: 'file',\n title: `File written: ${target}`,\n summary: `${contentBytes} bytes written`,\n uri: target,\n data: { path: target, size: contentBytes, operation: 'write' },\n });\n return { content: [{ type: 'text', text: `File written: ${target}` }], details: { size: contentBytes } };\n } catch (error) {\n return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], details: {} };\n }\n },\n } as any;\n}\n\nexport const writeFileTool: AgentTool = createWriteFileTool(process.cwd());\n"],"mappings":";;;;;;;AAcA,MAAM,gBAAgB,KAAK,OAAO;AAElC,MAAM,kBAAkB,KAAK,OAAO;CAClC,MAAM,KAAK,OAAO,EAAE,aAAa,sBAAsB,CAAC;CACxD,SAAS,KAAK,OAAO,EAAE,aAAa,oBAAoB,CAAC;CAC1D,CAAC;AAUF,SAAgB,oBACd,WACA,SACW;AACX,QAAO;EACL,MAAM;EACN,aACE;EACF,YAAY;EACZ,OAAO;
|
|
1
|
+
{"version":3,"file":"write.js","names":[],"sources":["../../../../src/agent/tools/write.ts"],"sourcesContent":["// Write file tool\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { writeFile, mkdir } from 'fs/promises';\nimport { dirname } from 'path';\nimport { checkFileSafety } from '../prompt/safety.js';\nimport {\n isBareProfileMarkdownFileName,\n resolveProfileMarkdownPathIfBareName,\n resolvePathUnderWorkspace,\n} from './tool-paths.js';\nimport { evaluateFilePolicy } from '../sandbox/exec-policy.js';\nimport type { GoalEvidenceRecordInput } from './goal-evidence-recorder.js';\n\nconst MAX_FILE_SIZE = 10 * 1024 * 1024;\n\nconst WriteFileSchema = Type.Object({\n path: Type.String({ description: 'File path to write' }),\n content: Type.String({ description: 'Content to write' }),\n});\n\ntype WriteFileParams = { path: string; content: string };\n\nexport interface CreateWriteFileToolOptions {\n /** When set and the path is a bare profile filename (e.g. SOUL.md), write to this root. */\n profileMarkdownRoot?: string;\n recordGoalEvidence?: (input: GoalEvidenceRecordInput) => Promise<void> | void;\n}\n\nexport function createWriteFileTool(\n workspace: string,\n options?: CreateWriteFileToolOptions,\n): AgentTool {\n return {\n name: 'write_file',\n description:\n 'Create or overwrite a file. Relative paths are under the current agent workspace; profile Markdown (SOUL.md, etc.) is written automatically when given by filename.',\n parameters: WriteFileSchema,\n label: '📝 Write',\n mutatesWorkspace: true,\n mutationScope: 'workspace',\n supportsParallel: false,\n idempotent: false,\n requiresExclusiveWorkspaceLock: true,\n finalGuardRelevant: true,\n\n async execute(\n _toolCallId: string,\n params: any,\n _signal?: AbortSignal,\n ): Promise<AgentToolResult<{}>> {\n try {\n const p = params as WriteFileParams;\n const safety = checkFileSafety('write', p.path);\n if (!safety.allowed) {\n return { content: [{ type: 'text', text: `🚫 ${safety.message}` }], details: {} };\n }\n\n const writesProfileFile = Boolean(\n options?.profileMarkdownRoot && isBareProfileMarkdownFileName(p.path),\n );\n const workspaceRoot = writesProfileFile ? options!.profileMarkdownRoot! : workspace;\n\n // Sandbox path-policy check (blocked dirs, symlink escape, config protection)\n const pathPolicy = evaluateFilePolicy({\n operation: 'write',\n path: p.path,\n workspaceRoot,\n });\n if (!pathPolicy.allowed) {\n return { content: [{ type: 'text', text: `🚫 Sandbox: ${pathPolicy.reason}` }], details: {} };\n }\n\n const contentBytes = Buffer.byteLength(p.content, 'utf-8');\n if (contentBytes > MAX_FILE_SIZE) {\n return { content: [{ type: 'text', text: `🚫 File too large: ${contentBytes} bytes` }], details: {} };\n }\n\n const target = writesProfileFile\n ? resolveProfileMarkdownPathIfBareName(p.path, options!.profileMarkdownRoot!)\n : resolvePathUnderWorkspace(p.path, workspace);\n await mkdir(dirname(target), { recursive: true });\n await writeFile(target, p.content, 'utf-8');\n await options?.recordGoalEvidence?.({\n kind: 'file',\n title: `File written: ${target}`,\n summary: `${contentBytes} bytes written`,\n uri: target,\n data: { path: target, size: contentBytes, operation: 'write' },\n });\n return { content: [{ type: 'text', text: `File written: ${target}` }], details: { size: contentBytes } };\n } catch (error) {\n return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], details: {} };\n }\n },\n } as any;\n}\n\nexport const writeFileTool: AgentTool = createWriteFileTool(process.cwd());\n"],"mappings":";;;;;;;AAcA,MAAM,gBAAgB,KAAK,OAAO;AAElC,MAAM,kBAAkB,KAAK,OAAO;CAClC,MAAM,KAAK,OAAO,EAAE,aAAa,sBAAsB,CAAC;CACxD,SAAS,KAAK,OAAO,EAAE,aAAa,oBAAoB,CAAC;CAC1D,CAAC;AAUF,SAAgB,oBACd,WACA,SACW;AACX,QAAO;EACL,MAAM;EACN,aACE;EACF,YAAY;EACZ,OAAO;EACP,kBAAkB;EAClB,eAAe;EACf,kBAAkB;EAClB,YAAY;EACZ,gCAAgC;EAChC,oBAAoB;EAEpB,MAAM,QACJ,aACA,QACA,SAC8B;AAC9B,OAAI;IACF,MAAM,IAAI;IACV,MAAM,SAAS,gBAAgB,SAAS,EAAE,KAAK;AAC/C,QAAI,CAAC,OAAO,QACV,QAAO;KAAE,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,MAAM,OAAO;MAAW,CAAC;KAAE,SAAS,EAAE;KAAE;IAGnF,MAAM,oBAAoB,QACxB,SAAS,uBAAuB,8BAA8B,EAAE,KAAK,CACtE;IACD,MAAM,gBAAgB,oBAAoB,QAAS,sBAAuB;IAG1E,MAAM,aAAa,mBAAmB;KACpC,WAAW;KACX,MAAM,EAAE;KACR;KACD,CAAC;AACF,QAAI,CAAC,WAAW,QACd,QAAO;KAAE,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,eAAe,WAAW;MAAU,CAAC;KAAE,SAAS,EAAE;KAAE;IAG/F,MAAM,eAAe,OAAO,WAAW,EAAE,SAAS,QAAQ;AAC1D,QAAI,eAAe,cACjB,QAAO;KAAE,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,sBAAsB,aAAa;MAAS,CAAC;KAAE,SAAS,EAAE;KAAE;IAGvG,MAAM,SAAS,oBACX,qCAAqC,EAAE,MAAM,QAAS,oBAAqB,GAC3E,0BAA0B,EAAE,MAAM,UAAU;AAChD,UAAM,MAAM,QAAQ,OAAO,EAAE,EAAE,WAAW,MAAM,CAAC;AACjD,UAAM,UAAU,QAAQ,EAAE,SAAS,QAAQ;AAC3C,UAAM,SAAS,qBAAqB;KAClC,MAAM;KACN,OAAO,iBAAiB;KACxB,SAAS,GAAG,aAAa;KACzB,KAAK;KACL,MAAM;MAAE,MAAM;MAAQ,MAAM;MAAc,WAAW;MAAS;KAC/D,CAAC;AACF,WAAO;KAAE,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,iBAAiB;MAAU,CAAC;KAAE,SAAS,EAAE,MAAM,cAAc;KAAE;YACjG,OAAO;AACd,WAAO;KAAE,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;MAAI,CAAC;KAAE,SAAS,EAAE;KAAE;;;EAGlI;;AAGH,MAAa,gBAA2B,oBAAoB,QAAQ,KAAK,CAAC"}
|
|
@@ -24,6 +24,7 @@ import type { SubagentRunOptions, SubagentRunner } from './types.js';
|
|
|
24
24
|
export interface DelegateSubagentRunnerDeps {
|
|
25
25
|
workspace: string;
|
|
26
26
|
bus: MessageBus;
|
|
27
|
+
agentId?: string;
|
|
27
28
|
/** Resolves the default subagent model (typically the parent agent's primary model). */
|
|
28
29
|
getDefaultModel: () => Model<Api>;
|
|
29
30
|
getConfig: () => Config | undefined;
|
|
@@ -52,10 +52,14 @@ var DelegateSubagentRunner = class {
|
|
|
52
52
|
maxIterations: opts.maxIterations ?? DEFAULT_MAX_ITERATIONS,
|
|
53
53
|
model,
|
|
54
54
|
bus: this.deps.bus,
|
|
55
|
+
agentId: this.deps.agentId,
|
|
55
56
|
getConfig: this.deps.getConfig,
|
|
56
57
|
toolExecutorConfig: this.deps.toolExecutorConfig,
|
|
57
58
|
buildChildTools: (childOpts) => {
|
|
58
|
-
const base = this.deps.buildChildTools(
|
|
59
|
+
const base = this.deps.buildChildTools({
|
|
60
|
+
...childOpts,
|
|
61
|
+
agentId: this.deps.agentId ?? childOpts.agentId
|
|
62
|
+
});
|
|
59
63
|
if (!wantStructured || !opts.schema) return base;
|
|
60
64
|
return [...base.filter((t) => t.name !== STRUCTURED_OUTPUT_TOOL_NAME), createStructuredOutputTool({
|
|
61
65
|
schema: opts.schema,
|