@xopcai/xopc 0.0.122 → 0.0.124
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -11
- package/README.zh-CN.md +28 -11
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CK3s5cJo.js → agent-avatar-dicebear-B5uSVAyJ.js} +1 -1
- package/dist/gateway/static/root/assets/agents-BjIxt67Z.js +2 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-CWsNHtTs.js → app-management-settings-panel-CYCONLIL.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-C4b8y6iZ.js → appearance-settings-Clw3ryKg.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-QICTeGjX.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-DAtNW3Ia.js → archive-plugin-CXUGRp2i.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-Dm-RY54y.js → attachment-load-Cmiub3Wg.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-BKHewSVT.js → automation-suggestion-card-CU0-4nQ-.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-Car-jtiz.js +1 -0
- package/dist/gateway/static/root/assets/{binary-plugins-BG6Xnk71.js → binary-plugins-0Izz-N3p.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-DfndiO3h.js → block-editor-C1Kv0IkJ.js} +28 -28
- package/dist/gateway/static/root/assets/browser-settings-page-CMeBJzlS.js +8 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-Cx93GLdw.js → capability-presets-api-BmQTM9Il.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-DZEJEoCF.js +1 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-DdPTtEs8.js → channel-recipient-api-BeA2aVor.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-kkW-xFau.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-BvaQvO5F.js +2 -0
- package/dist/gateway/static/root/assets/{directory-picker-path-field-D835EHJd.js → directory-picker-path-field-2rjzUu57.js} +1 -1
- package/dist/gateway/static/root/assets/{dreaming-settings-CCa1F7Fg.js → dreaming-settings-DnHO686d.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-W2ITCPSA.js → extension-debug-page-BGLRuWVN.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DrvUytvn.js → extension-page-D978ePp9.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-qM8aLT5u.js → extension-settings-page-B6Ih4Swx.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-ovkvM8KQ.js → fetch-BU5S0Sn7.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-BB3biuD0.js → gateway-config-api-BIPGwrl1.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-CMEA3r5u.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-CanQ8UcR.js → gateway-startup-retry-Cd0Zz30N.js} +1 -1
- package/dist/gateway/static/root/assets/{goal-create-dialog-CNqNdEkQ.js → goal-create-dialog-B-KHKeXN.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-BxrSoWdj.js +1 -0
- package/dist/gateway/static/root/assets/{goals-config-api-BBOX6mUl.js → goals-config-api-B95KdGMj.js} +1 -1
- package/dist/gateway/static/root/assets/{goals-page-BP1kfvWv.js → goals-page-BTJzIl28.js} +2 -2
- package/dist/gateway/static/root/assets/{goals-settings-Bh3A7OZV.js → goals-settings-BJyEuLLm.js} +1 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-wkOjYNQT.js +1 -0
- package/dist/gateway/static/root/assets/index-BLaXr6Ev.css +1 -0
- package/dist/gateway/static/root/assets/index-c_9TVr_C.js +191 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-B4TKJHla.js → keyboard-shortcuts-settings-BT8T4DyC.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-CrxBJUgI.js +2 -0
- package/dist/gateway/static/root/assets/{markdown-split-DcFtdLci.js → markdown-split-Dv66bO2b.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-B6SmeLVB.js → media-plugins-BhIQU5yS.js} +1 -1
- package/dist/gateway/static/root/assets/messages-O6TAtdFC.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-DOOpz6y1.js +2 -0
- package/dist/gateway/static/root/assets/notes-page-Br16pK9v.js +1 -0
- package/dist/gateway/static/root/assets/notes-workbench-PSJAi0ZC.js +2 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-C29O19s7.js → preview-open-alternatives-DGzet1d7.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-CIGGgKuw.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-B2grhsBt.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-CXMORxBD.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-B4ad9GfB.js → save-bar-controls-Cqgb-jqa.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-DdYncfLR.js → schedule-field-DVZcI8Yt.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-BMTrDE-7.js → schema-form-Bj7sOxC8.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-Bi2wkBzU.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-B1L3G4IA.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-MwTW2eK4.js → settings-collapsible-section-BmXn-8N6.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-Dg6LBbcr.js → settings-form-section-BnqYMWHR.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-BfRSHJmO.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-layout-BX4T-OLF.js → settings-page-layout-CdWZU1hd.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-Ce1pcFtR.js → setup-status-panel-CWtPM7RK.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-DWE-dUFh.js → share-preview-page-IB1v8i86.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-ngbsBgij.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-BIe442Gv.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-BfchZRVa.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-Dd6Y35Cm.js → system-settings-panel-BxQ384RC.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-Cx6XV5A2.js → typed-models-lib-BkcpvFYO.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-D4sMbmy7.js → use-channel-catalog-Cd0FaEQ4.js} +1 -1
- package/dist/gateway/static/root/assets/{user-profile-settings-panel-Bx-hjMQc.js → user-profile-settings-panel-DQ7NnRSY.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-D7b_vZnv.js → utils-YKhVf7Ka.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-C5Ov8Uk_.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel--TdohF5N.js → workflow-run-setup-panel-BYD9BtOq.js} +2 -2
- package/dist/gateway/static/root/assets/{workflow-start-dialog-B0lavx_o.js → workflow-start-dialog-BNJVCWoS.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-BYF29ANm.js +18 -0
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +6 -1
- package/dist/src/agent/agent-manager.js +28 -12
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/context/workspace-templates/AGENTS.md +1 -1
- package/dist/src/agent/embedded/xopc-tools-bridge.js +11 -7
- package/dist/src/agent/embedded/xopc-tools-bridge.js.map +1 -1
- package/dist/src/agent/lifecycle/progress.js +3 -1
- package/dist/src/agent/lifecycle/progress.js.map +1 -1
- package/dist/src/agent/lifecycle/timeout-wrapper.d.ts +2 -2
- package/dist/src/agent/lifecycle/timeout-wrapper.js +4 -4
- package/dist/src/agent/lifecycle/timeout-wrapper.js.map +1 -1
- package/dist/src/agent/memory/summary-generator.d.ts +1 -1
- package/dist/src/agent/memory/summary-generator.js +1 -2
- package/dist/src/agent/memory/summary-generator.js.map +1 -1
- package/dist/src/agent/middleware/index.d.ts +1 -1
- package/dist/src/agent/middleware/self-verify.d.ts +44 -14
- package/dist/src/agent/middleware/self-verify.js +214 -44
- package/dist/src/agent/middleware/self-verify.js.map +1 -1
- package/dist/src/agent/orchestration/agent-event-handler.js +57 -15
- package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
- package/dist/src/agent/prompt/sections/tooling.js +18 -13
- package/dist/src/agent/prompt/sections/tooling.js.map +1 -1
- package/dist/src/agent/prompt/system-reminder.js +2 -2
- package/dist/src/agent/prompt/system-reminder.js.map +1 -1
- package/dist/src/agent/sandbox/sanitize-env-vars.d.ts +2 -2
- package/dist/src/agent/sandbox/sanitize-env-vars.js +2 -2
- package/dist/src/agent/sandbox/sanitize-env-vars.js.map +1 -1
- package/dist/src/agent/sandbox/types.d.ts +2 -2
- package/dist/src/agent/sandbox/types.js.map +1 -1
- package/dist/src/agent/service/btw-query.js +1 -1
- package/dist/src/agent/service/btw-query.js.map +1 -1
- package/dist/src/agent/service/process-direct-one-shot.js +6 -2
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.js +12 -7
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service.js +2 -1
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/skills/skill-tool-gating.js +1 -1
- package/dist/src/agent/skills/skill-tool-gating.js.map +1 -1
- package/dist/src/agent/starter-agents.js +9 -9
- package/dist/src/agent/starter-agents.js.map +1 -1
- package/dist/src/agent/tools/apply-patch.d.ts +25 -0
- package/dist/src/agent/tools/apply-patch.js +256 -0
- package/dist/src/agent/tools/apply-patch.js.map +1 -0
- package/dist/src/agent/tools/delegate-tool.d.ts +1 -1
- package/dist/src/agent/tools/delegate-tool.js +3 -3
- package/dist/src/agent/tools/delegate-tool.js.map +1 -1
- package/dist/src/agent/tools/exec-command.d.ts +30 -0
- package/dist/src/agent/tools/exec-command.js +224 -0
- package/dist/src/agent/tools/exec-command.js.map +1 -0
- package/dist/src/agent/tools/execute-code-tool.js +7 -4
- package/dist/src/agent/tools/execute-code-tool.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +3 -3
- package/dist/src/agent/tools/factory.js +8 -9
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/goal-tool.d.ts +5 -1
- package/dist/src/agent/tools/goal-tool.js +8 -2
- package/dist/src/agent/tools/goal-tool.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +4 -3
- package/dist/src/agent/tools/index.js +5 -4
- package/dist/src/agent/tools/skills-tools.d.ts +1 -1
- package/dist/src/agent/tools/skills-tools.js.map +1 -1
- package/dist/src/agent/tools/update-plan-tool.d.ts +11 -0
- package/dist/src/agent/tools/update-plan-tool.js +72 -0
- package/dist/src/agent/tools/update-plan-tool.js.map +1 -0
- package/dist/src/agent/workflow/builtins/debug-incident.d.ts +1 -1
- package/dist/src/agent/workflow/builtins/debug-incident.js +1 -1
- package/dist/src/agent/workflow/builtins/debug-incident.js.map +1 -1
- package/dist/src/agent/workflow/builtins/pr-review.d.ts +1 -1
- package/dist/src/agent/workflow/builtins/pr-review.js +1 -1
- package/dist/src/agent/workflow/builtins/pr-review.js.map +1 -1
- package/dist/src/agent/workflow/builtins/release-check.d.ts +1 -1
- package/dist/src/agent/workflow/builtins/release-check.js +1 -1
- package/dist/src/agent/workflow/builtins/release-check.js.map +1 -1
- package/dist/src/agent/workflow/step-labels.js +7 -3
- package/dist/src/agent/workflow/step-labels.js.map +1 -1
- package/dist/src/chat-commands/agent-edit.js +1 -1
- package/dist/src/chat-commands/agent-edit.js.map +1 -1
- package/dist/src/chat-commands/builtins/goal.js +4 -1
- package/dist/src/chat-commands/builtins/goal.js.map +1 -1
- package/dist/src/chat-commands/builtins/review.d.ts +1 -0
- package/dist/src/chat-commands/builtins/review.js +167 -0
- package/dist/src/chat-commands/builtins/review.js.map +1 -0
- package/dist/src/chat-commands/index.d.ts +1 -0
- package/dist/src/chat-commands/index.js +3 -1
- package/dist/src/chat-commands/index.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/agent-builtin-tools.js +3 -2
- package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/chat-stream/mapper.d.ts +6 -0
- package/dist/src/gateway/chat-stream/mapper.js +149 -6
- package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
- package/dist/src/gateway/chat-stream/protocol.d.ts +51 -1
- package/dist/src/gateway/hono/routes/commands-skills.js +21 -0
- package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/index.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +1 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/projects.js +136 -14
- package/dist/src/gateway/hono/routes/projects.js.map +1 -1
- package/dist/src/gateway/hono/routes/search.d.ts +3 -0
- package/dist/src/gateway/hono/routes/search.js +47 -0
- package/dist/src/gateway/hono/routes/search.js.map +1 -0
- package/dist/src/gateway/security/dangerous-tools.js +1 -1
- package/dist/src/gateway/security/dangerous-tools.js.map +1 -1
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/projects/index.d.ts +3 -0
- package/dist/src/projects/index.js +4 -1
- package/dist/src/projects/project-agent-suggestion.d.ts +14 -0
- package/dist/src/projects/project-agent-suggestion.js +19 -0
- package/dist/src/projects/project-agent-suggestion.js.map +1 -0
- package/dist/src/projects/project-kind.d.ts +13 -0
- package/dist/src/projects/project-kind.js +147 -0
- package/dist/src/projects/project-kind.js.map +1 -0
- package/dist/src/projects/project-service.d.ts +15 -0
- package/dist/src/projects/project-service.js +96 -3
- package/dist/src/projects/project-service.js.map +1 -1
- package/dist/src/projects/project-store.js +32 -8
- package/dist/src/projects/project-store.js.map +1 -1
- package/dist/src/projects/types.d.ts +4 -1
- package/dist/src/projects/workspace-project.d.ts +22 -0
- package/dist/src/projects/workspace-project.js +143 -0
- package/dist/src/projects/workspace-project.js.map +1 -0
- package/dist/src/review/review-git.d.ts +48 -0
- package/dist/src/review/review-git.js +333 -0
- package/dist/src/review/review-git.js.map +1 -0
- package/dist/src/review/review-types.d.ts +22 -0
- package/dist/src/review/review-types.js +29 -0
- package/dist/src/review/review-types.js.map +1 -0
- package/dist/src/session/session-context-for-llm.js +151 -0
- package/dist/src/session/session-context-for-llm.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/021_projects_fts.sql +21 -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/tui/backends/embedded-backend.d.ts +8 -1
- package/dist/src/tui/backends/embedded-backend.js +60 -1
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +9 -1
- package/dist/src/tui/backends/gateway-sse-backend.js +29 -0
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/components/assistant-message.js +35 -0
- package/dist/src/tui/components/assistant-message.js.map +1 -1
- package/dist/src/tui/tui-agent-events.js +25 -0
- package/dist/src/tui/tui-agent-events.js.map +1 -1
- package/dist/src/tui/tui-backend.d.ts +20 -0
- package/dist/src/tui/tui-commands.d.ts +1 -0
- package/dist/src/tui/tui-commands.js +110 -4
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-picker-overlay.d.ts +2 -0
- package/dist/src/tui/tui-picker-overlay.js +153 -1
- package/dist/src/tui/tui-picker-overlay.js.map +1 -1
- package/dist/src/tui/tui.js +36 -2
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/workflows/service/workflow-run-service.js +1 -1
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agents-SsQrj9B-.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-CYb6fame.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-DpOOq1nk.js +0 -1
- package/dist/gateway/static/root/assets/browser-settings-page-9nXxgh4u.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-D528_YFy.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-Ck-3h5lI.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-DL-fAqE_.js +0 -2
- package/dist/gateway/static/root/assets/gateway-settings-mmmnIH27.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-Ceu5zrN6.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-YoYgKlfX.js +0 -1
- package/dist/gateway/static/root/assets/index-DdqSO9R2.js +0 -191
- package/dist/gateway/static/root/assets/index-jGB-2nI-.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-BgVk5DvZ.js +0 -2
- package/dist/gateway/static/root/assets/messages-B5O4OIEo.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-BU0x8PGP.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-D6JYVP4I.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-mqRJYnJS.js +0 -2
- package/dist/gateway/static/root/assets/project-detail-page-DOTgzoeh.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-DGUIb4y5.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DVKKUj3u.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BVbzUWxW.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-DrNNoSqE.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-CMDqgeMR.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-aKSraR8l.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-CS-FU_B-.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-BaF3u0LA.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-CkhbRt1q.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-CZR05Bu_.js +0 -18
- package/dist/src/agent/tools/edit.d.ts +0 -14
- package/dist/src/agent/tools/edit.js +0 -132
- package/dist/src/agent/tools/edit.js.map +0 -1
- package/dist/src/agent/tools/shell.d.ts +0 -15
- package/dist/src/agent/tools/shell.js +0 -158
- package/dist/src/agent/tools/shell.js.map +0 -1
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { formatSize, truncateTail } from "./truncate.js";
|
|
2
|
+
import { evaluateExecPolicy } from "../sandbox/exec-policy.js";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
import { Type } from "@sinclair/typebox";
|
|
6
|
+
//#region src/agent/tools/exec-command.ts
|
|
7
|
+
const MAX_COMMAND_TIMEOUT_MS = 3e5;
|
|
8
|
+
const DEFAULT_TIMEOUT_MS = 12e4;
|
|
9
|
+
const DEFAULT_MAX_OUTPUT_CHARS = 5e4;
|
|
10
|
+
const STREAM_DELTA_MAX_CHARS = 16e3;
|
|
11
|
+
const ExecCommandSchema = Type.Object({
|
|
12
|
+
cmd: Type.String({ description: "Shell command to execute." }),
|
|
13
|
+
cwd: Type.Optional(Type.String({ description: "Working directory. Relative paths are resolved under the agent workspace." })),
|
|
14
|
+
timeoutMs: Type.Optional(Type.Number({ description: "Command timeout in milliseconds. Defaults to 120000 and is capped at 300000." })),
|
|
15
|
+
maxOutputChars: Type.Optional(Type.Number({ description: "Maximum characters returned to the model. UI streaming still receives output deltas." }))
|
|
16
|
+
});
|
|
17
|
+
function clampTimeoutMs(raw) {
|
|
18
|
+
return Math.min(MAX_COMMAND_TIMEOUT_MS, Math.max(1e3, Math.floor(typeof raw === "number" && Number.isFinite(raw) ? raw : DEFAULT_TIMEOUT_MS)));
|
|
19
|
+
}
|
|
20
|
+
function clampMaxOutputChars(raw) {
|
|
21
|
+
return Math.max(1e3, Math.min(5e5, Math.floor(typeof raw === "number" && Number.isFinite(raw) ? raw : DEFAULT_MAX_OUTPUT_CHARS)));
|
|
22
|
+
}
|
|
23
|
+
function isLikelyTestCommand(command) {
|
|
24
|
+
return /\b(test|vitest|jest|pytest|go test|cargo test|npm test|pnpm test|yarn test|typecheck|type-check|lint)\b/i.test(command);
|
|
25
|
+
}
|
|
26
|
+
function commandStatus(exitCode, timedOut) {
|
|
27
|
+
if (timedOut) return "timed_out";
|
|
28
|
+
if (exitCode === 0) return "success";
|
|
29
|
+
return "failed";
|
|
30
|
+
}
|
|
31
|
+
function commandFailureHint(details) {
|
|
32
|
+
if (details.status === "success") return void 0;
|
|
33
|
+
if (details.status === "timed_out") return "The command timed out. Re-run a narrower command, increase timeoutMs if the long run is expected, or inspect partial output before retrying.";
|
|
34
|
+
if (details.exitCode !== 0 && details.stderr.trim()) return "The command failed. Inspect stderr first, fix the underlying issue, then re-run the narrowest relevant verification command.";
|
|
35
|
+
if (details.exitCode !== 0 && details.stdout.trim()) return "The command failed. Inspect stdout for the failure location, then re-run the narrowest relevant verification command.";
|
|
36
|
+
return "The command failed without output. Verify the command, cwd, and required dependencies before retrying.";
|
|
37
|
+
}
|
|
38
|
+
function formatOutputForModel(details, maxOutputChars) {
|
|
39
|
+
let prefix = "";
|
|
40
|
+
if (details.timedOut) prefix += `Command timed out after ${Math.round(details.durationMs / 1e3)}s\n`;
|
|
41
|
+
if (details.exitCode !== 0 && details.exitCode != null) prefix += `Command exited with code ${details.exitCode}\n`;
|
|
42
|
+
const truncation = truncateTail(details.aggregatedOutput, { maxBytes: Math.min(maxOutputChars, DEFAULT_MAX_OUTPUT_CHARS) });
|
|
43
|
+
let text = `${prefix}${truncation.content}`.trimEnd();
|
|
44
|
+
if (!text) text = "(no output)";
|
|
45
|
+
if (truncation.truncated) text += `\n\n[Output truncated: ${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)}]`;
|
|
46
|
+
if (details.failureHint) text += `\n\nNext action: ${details.failureHint}`;
|
|
47
|
+
return {
|
|
48
|
+
text,
|
|
49
|
+
truncated: truncation.truncated,
|
|
50
|
+
truncatedBy: truncation.truncatedBy,
|
|
51
|
+
outputBytes: truncation.outputBytes
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function createExecCommandTool(workspaceCwd, options) {
|
|
55
|
+
return {
|
|
56
|
+
name: "exec_command",
|
|
57
|
+
description: [
|
|
58
|
+
"Run shell commands for code inspection, builds, tests, type checks, and verification.",
|
|
59
|
+
"Use apply_patch for file edits; do not edit files by shell redirection unless explicitly necessary.",
|
|
60
|
+
"Relative cwd values resolve under the current agent workspace."
|
|
61
|
+
].join(" "),
|
|
62
|
+
parameters: ExecCommandSchema,
|
|
63
|
+
label: "Run Command",
|
|
64
|
+
async execute(_toolCallId, params, signal, onUpdate) {
|
|
65
|
+
const command = (params.cmd ?? params.command ?? "").trim();
|
|
66
|
+
if (!command) return {
|
|
67
|
+
content: [{
|
|
68
|
+
type: "text",
|
|
69
|
+
text: "Error: cmd is required"
|
|
70
|
+
}],
|
|
71
|
+
details: {
|
|
72
|
+
command,
|
|
73
|
+
cwd: workspaceCwd,
|
|
74
|
+
status: "failed",
|
|
75
|
+
exitCode: null,
|
|
76
|
+
durationMs: 0,
|
|
77
|
+
timedOut: false,
|
|
78
|
+
truncated: false,
|
|
79
|
+
outputBytes: 0,
|
|
80
|
+
stdout: "",
|
|
81
|
+
stderr: "cmd is required",
|
|
82
|
+
aggregatedOutput: "cmd is required",
|
|
83
|
+
failureHint: "Provide a non-empty cmd value."
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const requestedCwd = params.cwd?.trim() ? resolve(workspaceCwd, params.cwd.trim()) : workspaceCwd;
|
|
87
|
+
const policy = evaluateExecPolicy({
|
|
88
|
+
command,
|
|
89
|
+
cwd: requestedCwd,
|
|
90
|
+
allowedEnvVars: options?.getSkillPassthroughEnvVarNames?.() ?? []
|
|
91
|
+
});
|
|
92
|
+
if (!policy.allowed) {
|
|
93
|
+
const text = `Sandbox blocked command: ${policy.reason}`;
|
|
94
|
+
return {
|
|
95
|
+
content: [{
|
|
96
|
+
type: "text",
|
|
97
|
+
text
|
|
98
|
+
}],
|
|
99
|
+
details: {
|
|
100
|
+
command,
|
|
101
|
+
cwd: requestedCwd,
|
|
102
|
+
status: "blocked",
|
|
103
|
+
exitCode: null,
|
|
104
|
+
durationMs: 0,
|
|
105
|
+
timedOut: false,
|
|
106
|
+
truncated: false,
|
|
107
|
+
outputBytes: Buffer.byteLength(text),
|
|
108
|
+
stdout: "",
|
|
109
|
+
stderr: text,
|
|
110
|
+
aggregatedOutput: text,
|
|
111
|
+
failureHint: "Use a narrower workspace-safe command or inspect files with read/search tools instead."
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const timeoutMs = Math.min(clampTimeoutMs(params.timeoutMs), policy.timeoutMs);
|
|
116
|
+
const maxOutputChars = clampMaxOutputChars(params.maxOutputChars);
|
|
117
|
+
const startTime = Date.now();
|
|
118
|
+
let stdout = "";
|
|
119
|
+
let stderr = "";
|
|
120
|
+
let aggregatedOutput = "";
|
|
121
|
+
let timedOut = false;
|
|
122
|
+
let settled = false;
|
|
123
|
+
return new Promise((resolveTool) => {
|
|
124
|
+
const proc = spawn(command, [], {
|
|
125
|
+
shell: true,
|
|
126
|
+
cwd: policy.effectiveCwd,
|
|
127
|
+
env: {
|
|
128
|
+
...policy.sanitizedEnv,
|
|
129
|
+
COLUMNS: "200"
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
const publishDelta = (stream, raw) => {
|
|
133
|
+
const text = raw.toString();
|
|
134
|
+
if (!text) return;
|
|
135
|
+
if (stream === "stdout") stdout += text;
|
|
136
|
+
else stderr += text;
|
|
137
|
+
aggregatedOutput += text;
|
|
138
|
+
const delta = text.length > STREAM_DELTA_MAX_CHARS ? `${text.slice(0, STREAM_DELTA_MAX_CHARS)}\n[stream delta truncated]` : text;
|
|
139
|
+
onUpdate?.({
|
|
140
|
+
content: [],
|
|
141
|
+
details: {
|
|
142
|
+
kind: "command_output_delta",
|
|
143
|
+
command,
|
|
144
|
+
cwd: policy.effectiveCwd,
|
|
145
|
+
stream,
|
|
146
|
+
delta
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
const finish = (exitCode, errorText) => {
|
|
151
|
+
if (settled) return;
|
|
152
|
+
settled = true;
|
|
153
|
+
clearTimeout(timeout);
|
|
154
|
+
signal?.removeEventListener("abort", abort);
|
|
155
|
+
if (errorText) {
|
|
156
|
+
stderr += errorText;
|
|
157
|
+
aggregatedOutput += errorText;
|
|
158
|
+
}
|
|
159
|
+
const durationMs = Date.now() - startTime;
|
|
160
|
+
const baseDetails = {
|
|
161
|
+
command,
|
|
162
|
+
cwd: policy.effectiveCwd,
|
|
163
|
+
status: commandStatus(exitCode, timedOut),
|
|
164
|
+
exitCode,
|
|
165
|
+
durationMs,
|
|
166
|
+
timedOut,
|
|
167
|
+
truncated: false,
|
|
168
|
+
outputBytes: Buffer.byteLength(aggregatedOutput),
|
|
169
|
+
stdout,
|
|
170
|
+
stderr,
|
|
171
|
+
aggregatedOutput
|
|
172
|
+
};
|
|
173
|
+
baseDetails.failureHint = commandFailureHint(baseDetails);
|
|
174
|
+
const formatted = formatOutputForModel(baseDetails, maxOutputChars);
|
|
175
|
+
const details = {
|
|
176
|
+
...baseDetails,
|
|
177
|
+
truncated: formatted.truncated,
|
|
178
|
+
truncatedBy: formatted.truncatedBy,
|
|
179
|
+
outputBytes: formatted.outputBytes
|
|
180
|
+
};
|
|
181
|
+
const result = {
|
|
182
|
+
content: [{
|
|
183
|
+
type: "text",
|
|
184
|
+
text: formatted.text
|
|
185
|
+
}],
|
|
186
|
+
details
|
|
187
|
+
};
|
|
188
|
+
Promise.resolve(options?.recordGoalEvidence?.({
|
|
189
|
+
kind: timedOut || exitCode !== 0 ? "command" : isLikelyTestCommand(command) ? "test" : "command",
|
|
190
|
+
title: `Command: ${command.slice(0, 120)}`,
|
|
191
|
+
summary: formatted.text.slice(0, 2e3),
|
|
192
|
+
data: {
|
|
193
|
+
command,
|
|
194
|
+
cwd: policy.effectiveCwd,
|
|
195
|
+
exitCode,
|
|
196
|
+
durationMs,
|
|
197
|
+
timedOut,
|
|
198
|
+
truncated: details.truncated,
|
|
199
|
+
outputBytes: details.outputBytes
|
|
200
|
+
}
|
|
201
|
+
})).finally(() => resolveTool(result));
|
|
202
|
+
};
|
|
203
|
+
const abort = () => {
|
|
204
|
+
timedOut = true;
|
|
205
|
+
proc.kill("SIGKILL");
|
|
206
|
+
};
|
|
207
|
+
const timeout = setTimeout(() => {
|
|
208
|
+
timedOut = true;
|
|
209
|
+
proc.kill("SIGKILL");
|
|
210
|
+
}, timeoutMs);
|
|
211
|
+
if (signal?.aborted) abort();
|
|
212
|
+
else signal?.addEventListener("abort", abort, { once: true });
|
|
213
|
+
proc.stdout?.on("data", (data) => publishDelta("stdout", data));
|
|
214
|
+
proc.stderr?.on("data", (data) => publishDelta("stderr", data));
|
|
215
|
+
proc.on("error", (err) => finish(null, `Error: ${err.message}`));
|
|
216
|
+
proc.on("close", (code) => finish(code));
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
//#endregion
|
|
222
|
+
export { createExecCommandTool };
|
|
223
|
+
|
|
224
|
+
//# sourceMappingURL=exec-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec-command.js","names":[],"sources":["../../../../src/agent/tools/exec-command.ts"],"sourcesContent":["import { Type } from '@sinclair/typebox';\nimport type {\n AgentTool,\n AgentToolResult,\n AgentToolUpdateCallback,\n} from '@earendil-works/pi-agent-core';\nimport { spawn } from 'node:child_process';\nimport { resolve } from 'node:path';\n\nimport { evaluateExecPolicy } from '../sandbox/exec-policy.js';\nimport { formatSize, truncateTail } from './truncate.js';\nimport type { GoalEvidenceRecordInput } from './goal-evidence-recorder.js';\n\nconst MAX_COMMAND_TIMEOUT_MS = 300_000;\nconst DEFAULT_TIMEOUT_MS = 120_000;\nconst DEFAULT_MAX_OUTPUT_CHARS = 50_000;\nconst STREAM_DELTA_MAX_CHARS = 16_000;\n\nconst ExecCommandSchema = Type.Object({\n cmd: Type.String({ description: 'Shell command to execute.' }),\n cwd: Type.Optional(\n Type.String({\n description: 'Working directory. Relative paths are resolved under the agent workspace.',\n }),\n ),\n timeoutMs: Type.Optional(\n Type.Number({\n description: 'Command timeout in milliseconds. Defaults to 120000 and is capped at 300000.',\n }),\n ),\n maxOutputChars: Type.Optional(\n Type.Number({\n description: 'Maximum characters returned to the model. UI streaming still receives output deltas.',\n }),\n ),\n});\n\nexport interface ExecCommandDetails {\n command: string;\n cwd: string;\n status: 'success' | 'failed' | 'timed_out' | 'blocked';\n exitCode: number | null;\n durationMs: number;\n timedOut: boolean;\n truncated: boolean;\n truncatedBy?: 'lines' | 'bytes' | null;\n outputBytes: number;\n stdout: string;\n stderr: string;\n aggregatedOutput: string;\n failureHint?: string;\n}\n\nexport interface ExecCommandUpdateDetails {\n kind: 'command_output_delta';\n command: string;\n cwd: string;\n stream: 'stdout' | 'stderr';\n delta: string;\n}\n\nexport interface CreateExecCommandToolOptions {\n /** Env var names allowed through prepareSafeToolEnv even if they match secret heuristics. */\n getSkillPassthroughEnvVarNames?: () => string[];\n recordGoalEvidence?: (input: GoalEvidenceRecordInput) => Promise<void> | void;\n}\n\ntype ExecCommandParams = {\n cmd?: string;\n command?: string;\n cwd?: string;\n timeoutMs?: number;\n maxOutputChars?: number;\n};\n\nfunction clampTimeoutMs(raw: unknown): number {\n const n = typeof raw === 'number' && Number.isFinite(raw) ? raw : DEFAULT_TIMEOUT_MS;\n return Math.min(MAX_COMMAND_TIMEOUT_MS, Math.max(1_000, Math.floor(n)));\n}\n\nfunction clampMaxOutputChars(raw: unknown): number {\n const n = typeof raw === 'number' && Number.isFinite(raw) ? raw : DEFAULT_MAX_OUTPUT_CHARS;\n return Math.max(1_000, Math.min(500_000, Math.floor(n)));\n}\n\nfunction isLikelyTestCommand(command: string): boolean {\n return /\\b(test|vitest|jest|pytest|go test|cargo test|npm test|pnpm test|yarn test|typecheck|type-check|lint)\\b/i.test(command);\n}\n\nfunction commandStatus(exitCode: number | null, timedOut: boolean): ExecCommandDetails['status'] {\n if (timedOut) return 'timed_out';\n if (exitCode === 0) return 'success';\n return 'failed';\n}\n\nfunction commandFailureHint(details: Pick<ExecCommandDetails, 'status' | 'exitCode' | 'timedOut' | 'stderr' | 'stdout'>): string | undefined {\n if (details.status === 'success') return undefined;\n if (details.status === 'timed_out') {\n return 'The command timed out. Re-run a narrower command, increase timeoutMs if the long run is expected, or inspect partial output before retrying.';\n }\n if (details.exitCode !== 0 && details.stderr.trim()) {\n return 'The command failed. Inspect stderr first, fix the underlying issue, then re-run the narrowest relevant verification command.';\n }\n if (details.exitCode !== 0 && details.stdout.trim()) {\n return 'The command failed. Inspect stdout for the failure location, then re-run the narrowest relevant verification command.';\n }\n return 'The command failed without output. Verify the command, cwd, and required dependencies before retrying.';\n}\n\nfunction formatOutputForModel(\n details: ExecCommandDetails,\n maxOutputChars: number,\n): { text: string; truncated: boolean; truncatedBy?: 'lines' | 'bytes' | null; outputBytes: number } {\n let prefix = '';\n if (details.timedOut) {\n prefix += `Command timed out after ${Math.round(details.durationMs / 1000)}s\\n`;\n }\n if (details.exitCode !== 0 && details.exitCode != null) {\n prefix += `Command exited with code ${details.exitCode}\\n`;\n }\n\n const truncation = truncateTail(details.aggregatedOutput, {\n maxBytes: Math.min(maxOutputChars, DEFAULT_MAX_OUTPUT_CHARS),\n });\n let text = `${prefix}${truncation.content}`.trimEnd();\n if (!text) text = '(no output)';\n if (truncation.truncated) {\n text += `\\n\\n[Output truncated: ${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)}]`;\n }\n if (details.failureHint) {\n text += `\\n\\nNext action: ${details.failureHint}`;\n }\n return {\n text,\n truncated: truncation.truncated,\n truncatedBy: truncation.truncatedBy,\n outputBytes: truncation.outputBytes,\n };\n}\n\nexport function createExecCommandTool(\n workspaceCwd: string,\n options?: CreateExecCommandToolOptions,\n): AgentTool {\n return {\n name: 'exec_command',\n description: [\n 'Run shell commands for code inspection, builds, tests, type checks, and verification.',\n 'Use apply_patch for file edits; do not edit files by shell redirection unless explicitly necessary.',\n 'Relative cwd values resolve under the current agent workspace.',\n ].join(' '),\n parameters: ExecCommandSchema,\n label: 'Run Command',\n\n async execute(\n _toolCallId: string,\n params: ExecCommandParams,\n signal?: AbortSignal,\n onUpdate?: AgentToolUpdateCallback<ExecCommandUpdateDetails>,\n ): Promise<AgentToolResult<ExecCommandDetails>> {\n const command = (params.cmd ?? params.command ?? '').trim();\n if (!command) {\n return {\n content: [{ type: 'text', text: 'Error: cmd is required' }],\n details: {\n command,\n cwd: workspaceCwd,\n status: 'failed',\n exitCode: null,\n durationMs: 0,\n timedOut: false,\n truncated: false,\n outputBytes: 0,\n stdout: '',\n stderr: 'cmd is required',\n aggregatedOutput: 'cmd is required',\n failureHint: 'Provide a non-empty cmd value.',\n },\n };\n }\n\n const requestedCwd = params.cwd?.trim()\n ? resolve(workspaceCwd, params.cwd.trim())\n : workspaceCwd;\n const passthroughNames = options?.getSkillPassthroughEnvVarNames?.() ?? [];\n const policy = evaluateExecPolicy({\n command,\n cwd: requestedCwd,\n allowedEnvVars: passthroughNames,\n });\n if (!policy.allowed) {\n const text = `Sandbox blocked command: ${policy.reason}`;\n return {\n content: [{ type: 'text', text }],\n details: {\n command,\n cwd: requestedCwd,\n status: 'blocked',\n exitCode: null,\n durationMs: 0,\n timedOut: false,\n truncated: false,\n outputBytes: Buffer.byteLength(text),\n stdout: '',\n stderr: text,\n aggregatedOutput: text,\n failureHint: 'Use a narrower workspace-safe command or inspect files with read/search tools instead.',\n },\n };\n }\n\n const timeoutMs = Math.min(clampTimeoutMs(params.timeoutMs), policy.timeoutMs);\n const maxOutputChars = clampMaxOutputChars(params.maxOutputChars);\n const startTime = Date.now();\n let stdout = '';\n let stderr = '';\n let aggregatedOutput = '';\n let timedOut = false;\n let settled = false;\n\n return new Promise((resolveTool) => {\n const proc = spawn(command, [], {\n shell: true,\n cwd: policy.effectiveCwd,\n env: {\n ...policy.sanitizedEnv,\n COLUMNS: '200',\n },\n });\n\n const publishDelta = (stream: 'stdout' | 'stderr', raw: Buffer | string) => {\n const text = raw.toString();\n if (!text) return;\n if (stream === 'stdout') stdout += text;\n else stderr += text;\n aggregatedOutput += text;\n\n const delta = text.length > STREAM_DELTA_MAX_CHARS\n ? `${text.slice(0, STREAM_DELTA_MAX_CHARS)}\\n[stream delta truncated]`\n : text;\n onUpdate?.({\n content: [],\n details: {\n kind: 'command_output_delta',\n command,\n cwd: policy.effectiveCwd,\n stream,\n delta,\n },\n });\n };\n\n const finish = (\n exitCode: number | null,\n errorText?: string,\n ) => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n signal?.removeEventListener('abort', abort);\n if (errorText) {\n stderr += errorText;\n aggregatedOutput += errorText;\n }\n\n const durationMs = Date.now() - startTime;\n const baseDetails: ExecCommandDetails = {\n command,\n cwd: policy.effectiveCwd,\n status: commandStatus(exitCode, timedOut),\n exitCode,\n durationMs,\n timedOut,\n truncated: false,\n outputBytes: Buffer.byteLength(aggregatedOutput),\n stdout,\n stderr,\n aggregatedOutput,\n };\n baseDetails.failureHint = commandFailureHint(baseDetails);\n const formatted = formatOutputForModel(baseDetails, maxOutputChars);\n const details: ExecCommandDetails = {\n ...baseDetails,\n truncated: formatted.truncated,\n truncatedBy: formatted.truncatedBy,\n outputBytes: formatted.outputBytes,\n };\n\n const result: AgentToolResult<ExecCommandDetails> = {\n content: [{ type: 'text', text: formatted.text }],\n details,\n };\n\n void Promise.resolve(options?.recordGoalEvidence?.({\n kind: timedOut || exitCode !== 0 ? 'command' : isLikelyTestCommand(command) ? 'test' : 'command',\n title: `Command: ${command.slice(0, 120)}`,\n summary: formatted.text.slice(0, 2000),\n data: {\n command,\n cwd: policy.effectiveCwd,\n exitCode,\n durationMs,\n timedOut,\n truncated: details.truncated,\n outputBytes: details.outputBytes,\n },\n })).finally(() => resolveTool(result));\n };\n\n const abort = () => {\n timedOut = true;\n proc.kill('SIGKILL');\n };\n\n const timeout = setTimeout(() => {\n timedOut = true;\n proc.kill('SIGKILL');\n }, timeoutMs);\n\n if (signal?.aborted) {\n abort();\n } else {\n signal?.addEventListener('abort', abort, { once: true });\n }\n\n proc.stdout?.on('data', (data) => publishDelta('stdout', data));\n proc.stderr?.on('data', (data) => publishDelta('stderr', data));\n proc.on('error', (err) => finish(null, `Error: ${err.message}`));\n proc.on('close', (code) => finish(code));\n });\n },\n } as any;\n}\n"],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ const DEFAULT_TIMEOUT_SEC = 1800;
|
|
|
10
10
|
/** Hard cap for `timeout` parameter (4 hours). */
|
|
11
11
|
const MAX_TIMEOUT_SEC = 14400;
|
|
12
12
|
const ExecuteCodeSchema = Type.Object({
|
|
13
|
-
code: Type.String({ description: "JavaScript to run. Exposed as `tools` (async functions) and `console`:\n await tools.web_search(query, count?)\n await tools.web_fetch(url, maxChars?)\n await tools.read_file(path, limit?)\n await tools.write_file(path, content)\n await tools.grep(pattern, { path?, glob?, ignoreCase?, literal?, context?, limit? })\n await tools.find(pattern, { path?, limit? })\n await tools.
|
|
13
|
+
code: Type.String({ description: "JavaScript to run. Exposed as `tools` (async functions) and `console`:\n await tools.web_search(query, count?)\n await tools.web_fetch(url, maxChars?)\n await tools.read_file(path, limit?)\n await tools.write_file(path, content)\n await tools.grep(pattern, { path?, glob?, ignoreCase?, literal?, context?, limit? })\n await tools.find(pattern, { path?, limit? })\n await tools.exec_command(cmd, cwd?)\n\nUse console.log() for output; combined stdout/stderr is returned." }),
|
|
14
14
|
timeout: Type.Optional(Type.Number({
|
|
15
15
|
description: "Execution timeout in seconds (default: 3600 = 60m, max: 14400 = 4h)",
|
|
16
16
|
default: DEFAULT_TIMEOUT_SEC
|
|
@@ -23,7 +23,7 @@ const SANDBOX_ALLOWED_TOOLS = new Set([
|
|
|
23
23
|
"write_file",
|
|
24
24
|
"grep",
|
|
25
25
|
"find",
|
|
26
|
-
"
|
|
26
|
+
"exec_command",
|
|
27
27
|
"skills_list",
|
|
28
28
|
"skill_view"
|
|
29
29
|
]);
|
|
@@ -99,7 +99,10 @@ function createToolsApi(getMap, signal) {
|
|
|
99
99
|
...typeof o.limit === "number" && Number.isFinite(o.limit) ? { limit: o.limit } : {}
|
|
100
100
|
});
|
|
101
101
|
},
|
|
102
|
-
|
|
102
|
+
exec_command: async (cmd, cwd) => run("exec_command", {
|
|
103
|
+
cmd: String(cmd ?? ""),
|
|
104
|
+
...typeof cwd === "string" && cwd.trim() ? { cwd } : {}
|
|
105
|
+
})
|
|
103
106
|
};
|
|
104
107
|
}
|
|
105
108
|
async function runSandboxedScript(code, sandbox, timeoutMs, signal) {
|
|
@@ -128,7 +131,7 @@ function createExecuteCodeTool(deps) {
|
|
|
128
131
|
return {
|
|
129
132
|
name: "execute_code",
|
|
130
133
|
label: "⚡ Execute Code",
|
|
131
|
-
description: "Run sandboxed JavaScript that calls a subset of tools via `tools.*` (batch work in one step).\n\nOnly stdout/stderr from `console` plus tool return text (as strings) are visible — not full tool JSON.\n\nWHEN TO USE: loops over files/URLs, simple branching between tool calls.\nWHEN NOT TO USE: single tool calls; tasks needing full tool schemas or disallowed tools.\n\nAPI: `await tools.web_search(q, count?)`, `web_fetch(url, maxChars?)`, `read_file(path, limit?)`, `write_file(path, content)`, `grep(pattern, opts?)`, `find(glob, opts?)`, `
|
|
134
|
+
description: "Run sandboxed JavaScript that calls a subset of tools via `tools.*` (batch work in one step).\n\nOnly stdout/stderr from `console` plus tool return text (as strings) are visible — not full tool JSON.\n\nWHEN TO USE: loops over files/URLs, simple branching between tool calls.\nWHEN NOT TO USE: single tool calls; tasks needing full tool schemas or disallowed tools.\n\nAPI: `await tools.web_search(q, count?)`, `web_fetch(url, maxChars?)`, `read_file(path, limit?)`, `write_file(path, content)`, `grep(pattern, opts?)`, `find(glob, opts?)`, `exec_command(cmd, cwd?)`. Use `console.log` for output.",
|
|
132
135
|
parameters: ExecuteCodeSchema,
|
|
133
136
|
async execute(_toolCallId, params, signal) {
|
|
134
137
|
const p = params;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute-code-tool.js","names":[],"sources":["../../../../src/agent/tools/execute-code-tool.ts"],"sourcesContent":["/**\n * Programmatic tool calling (PTC): run sandboxed JS that invokes a subset of agent tools.\n * vm is not a strong security boundary; only trusted models should use this tool.\n */\n\nimport { Script, createContext } from 'node:vm';\n\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\n\n/** Default script wall time when `timeout` omitted (30 minutes). */\nconst DEFAULT_TIMEOUT_SEC = 30 * 60;\n/** Hard cap for `timeout` parameter (4 hours). */\nconst MAX_TIMEOUT_SEC = 4 * 60 * 60;\n\nconst ExecuteCodeSchema = Type.Object({\n code: Type.String({\n description:\n 'JavaScript to run. Exposed as `tools` (async functions) and `console`:\\n' +\n ' await tools.web_search(query, count?)\\n' +\n ' await tools.web_fetch(url, maxChars?)\\n' +\n ' await tools.read_file(path, limit?)\\n' +\n ' await tools.write_file(path, content)\\n' +\n ' await tools.grep(pattern, { path?, glob?, ignoreCase?, literal?, context?, limit? })\\n' +\n ' await tools.find(pattern, { path?, limit? })\\n' +\n ' await tools.shell(command)\\n\\n' +\n 'Use console.log() for output; combined stdout/stderr is returned.',\n }),\n timeout: Type.Optional(\n Type.Number({\n description: 'Execution timeout in seconds (default: 3600 = 60m, max: 14400 = 4h)',\n default: DEFAULT_TIMEOUT_SEC,\n }),\n ),\n});\n\nexport const SANDBOX_ALLOWED_TOOLS = new Set([\n 'web_search',\n 'web_fetch',\n 'read_file',\n 'write_file',\n 'grep',\n 'find',\n 'shell',\n 'skills_list',\n 'skill_view',\n]);\n\nconst MAX_TIMEOUT_MS = MAX_TIMEOUT_SEC * 1000;\nconst MAX_TOOL_CALLS = 50;\nconst MAX_STDOUT_CHARS = 50_000;\nconst MAX_STDERR_CHARS = 10_000;\n\nfunction stringifyArg(a: unknown): string {\n if (typeof a === 'string') {\n return a;\n }\n try {\n return JSON.stringify(a);\n } catch {\n return String(a);\n }\n}\n\nfunction extractTextFromResult(result: AgentToolResult<unknown>): string {\n return result.content\n .filter((c): c is { type: 'text'; text: string } => c.type === 'text')\n .map((c) => c.text)\n .join('');\n}\n\nexport function buildSandboxToolMap(tools: AgentTool<any, any>[]): Map<string, AgentTool<any, any>> {\n const m = new Map<string, AgentTool<any, any>>();\n for (const t of tools) {\n if (SANDBOX_ALLOWED_TOOLS.has(t.name)) {\n m.set(t.name, t);\n }\n }\n return m;\n}\n\nfunction createToolsApi(\n getMap: () => Map<string, AgentTool<any, any>>,\n signal: AbortSignal | undefined,\n): Record<string, (...args: unknown[]) => Promise<string>> {\n let seq = 0;\n let calls = 0;\n\n const bump = (): void => {\n calls += 1;\n if (calls > MAX_TOOL_CALLS) {\n throw new Error(`Exceeded max sandbox tool calls (${MAX_TOOL_CALLS})`);\n }\n };\n\n const run = async (name: string, params: Record<string, unknown>): Promise<string> => {\n if (signal?.aborted) {\n throw new Error('aborted');\n }\n bump();\n const tool = getMap().get(name);\n if (!tool) {\n throw new Error(`Tool not available in sandbox: ${name}`);\n }\n const id = `ptc-${Date.now()}-${seq++}`;\n const result = await (tool as any).execute(id, params, signal);\n return extractTextFromResult(result);\n };\n\n return {\n web_search: async (query: unknown, count?: unknown) =>\n run('web_search', {\n query: String(query ?? ''),\n ...(typeof count === 'number' && Number.isFinite(count) ? { count } : {}),\n }),\n\n web_fetch: async (url: unknown, maxChars?: unknown) =>\n run('web_fetch', {\n url: String(url ?? ''),\n ...(typeof maxChars === 'number' && Number.isFinite(maxChars) ? { maxChars } : {}),\n }),\n\n read_file: async (path: unknown, limit?: unknown) =>\n run('read_file', {\n path: String(path ?? ''),\n ...(typeof limit === 'number' && Number.isFinite(limit) ? { limit } : {}),\n }),\n\n write_file: async (path: unknown, content: unknown) =>\n run('write_file', {\n path: String(path ?? ''),\n content: String(content ?? ''),\n }),\n\n grep: async (pattern: unknown, opts?: unknown) => {\n const o = opts && typeof opts === 'object' && opts !== null ? (opts as Record<string, unknown>) : {};\n return run('grep', {\n pattern: String(pattern ?? ''),\n ...(typeof o.path === 'string' ? { path: o.path } : {}),\n ...(typeof o.glob === 'string' ? { glob: o.glob } : {}),\n ...(typeof o.ignoreCase === 'boolean' ? { ignoreCase: o.ignoreCase } : {}),\n ...(typeof o.literal === 'boolean' ? { literal: o.literal } : {}),\n ...(typeof o.context === 'number' && Number.isFinite(o.context) ? { context: o.context } : {}),\n ...(typeof o.limit === 'number' && Number.isFinite(o.limit) ? { limit: o.limit } : {}),\n });\n },\n\n find: async (pattern: unknown, opts?: unknown) => {\n const o = opts && typeof opts === 'object' && opts !== null ? (opts as Record<string, unknown>) : {};\n return run('find', {\n pattern: String(pattern ?? ''),\n ...(typeof o.path === 'string' ? { path: o.path } : {}),\n ...(typeof o.limit === 'number' && Number.isFinite(o.limit) ? { limit: o.limit } : {}),\n });\n },\n\n shell: async (command: unknown) => run('shell', { command: String(command ?? '') }),\n };\n}\n\nasync function runSandboxedScript(\n code: string,\n sandbox: Record<string, unknown>,\n timeoutMs: number,\n signal?: AbortSignal,\n): Promise<void> {\n const context = createContext(sandbox, { name: 'execute_code' });\n const wrapped = `(async () => {\\n${code}\\n})()`;\n const script = new Script(wrapped, { filename: 'execute_code.vm' });\n const runPromise = script.runInContext(context) as Promise<unknown>;\n\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n const timeoutPromise = new Promise<never>((_, rej) => {\n timeoutId = setTimeout(\n () => rej(new Error(`Script timed out after ${Math.round(timeoutMs / 1000)}s`)),\n timeoutMs,\n );\n });\n\n const abortPromise =\n signal &&\n new Promise<never>((_, rej) => {\n if (signal.aborted) {\n rej(new Error('aborted'));\n return;\n }\n signal.addEventListener('abort', () => rej(new Error('aborted')), { once: true });\n });\n\n const racers: Promise<unknown>[] = [runPromise, timeoutPromise];\n if (abortPromise) {\n racers.push(abortPromise);\n }\n\n try {\n await Promise.race(racers);\n } finally {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n }\n }\n}\n\nexport interface ExecuteCodeToolDeps {\n getSandboxToolMap: () => Map<string, AgentTool<any, any>>;\n}\n\ntype ExecuteCodeParams = { code: string; timeout?: number };\n\nexport function createExecuteCodeTool(deps: ExecuteCodeToolDeps): AgentTool {\n return {\n name: 'execute_code',\n label: '⚡ Execute Code',\n description:\n 'Run sandboxed JavaScript that calls a subset of tools via `tools.*` (batch work in one step).\\n\\n' +\n 'Only stdout/stderr from `console` plus tool return text (as strings) are visible — not full tool JSON.\\n\\n' +\n 'WHEN TO USE: loops over files/URLs, simple branching between tool calls.\\n' +\n 'WHEN NOT TO USE: single tool calls; tasks needing full tool schemas or disallowed tools.\\n\\n' +\n 'API: `await tools.web_search(q, count?)`, `web_fetch(url, maxChars?)`, `read_file(path, limit?)`, ' +\n '`write_file(path, content)`, `grep(pattern, opts?)`, `find(glob, opts?)`, `shell(command)`. ' +\n 'Use `console.log` for output.',\n parameters: ExecuteCodeSchema,\n\n async execute(\n _toolCallId: string,\n params: any,\n signal?: AbortSignal,\n ): Promise<AgentToolResult<{ exitCode: number }>> {\n const p = params as ExecuteCodeParams;\n const sec = p.timeout ?? DEFAULT_TIMEOUT_SEC;\n const timeoutMs = Math.min(\n Math.max(1, Number.isFinite(sec) ? sec : DEFAULT_TIMEOUT_SEC) * 1000,\n MAX_TIMEOUT_MS,\n );\n\n const stdout: string[] = [];\n const stderr: string[] = [];\n\n const toolsApi = createToolsApi(deps.getSandboxToolMap, signal);\n\n const sandbox: Record<string, unknown> = {\n tools: toolsApi,\n Promise,\n JSON,\n Math,\n Date,\n Array,\n Object,\n String,\n Number,\n Boolean,\n RegExp,\n Map,\n Set,\n Error,\n TypeError,\n RangeError,\n parseInt,\n parseFloat,\n isNaN,\n isFinite,\n console: {\n log: (...args: unknown[]) => {\n stdout.push(args.map(stringifyArg).join(' '));\n },\n error: (...args: unknown[]) => {\n stderr.push(args.map(stringifyArg).join(' '));\n },\n warn: (...args: unknown[]) => {\n stderr.push(args.map(stringifyArg).join(' '));\n },\n },\n setTimeout,\n clearTimeout,\n };\n\n try {\n await runSandboxedScript(p.code, sandbox, timeoutMs, signal);\n\n let out = stdout.join('\\n');\n if (out.length > MAX_STDOUT_CHARS) {\n out = `${out.slice(0, MAX_STDOUT_CHARS)}\\n...(truncated)`;\n }\n\n const parts: string[] = [];\n if (out.length > 0) {\n parts.push(out);\n }\n if (stderr.length > 0) {\n let err = stderr.join('\\n');\n if (err.length > MAX_STDERR_CHARS) {\n err = `${err.slice(0, MAX_STDERR_CHARS)}\\n...(truncated)`;\n }\n parts.push(`\\nSTDERR:\\n${err}`);\n }\n\n return {\n content: [{ type: 'text', text: parts.join('') || '(no output)' }],\n details: { exitCode: 0 },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text', text: `Execution failed: ${message}` }],\n details: { exitCode: 1 },\n };\n }\n },\n } as any;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"execute-code-tool.js","names":[],"sources":["../../../../src/agent/tools/execute-code-tool.ts"],"sourcesContent":["/**\n * Programmatic tool calling (PTC): run sandboxed JS that invokes a subset of agent tools.\n * vm is not a strong security boundary; only trusted models should use this tool.\n */\n\nimport { Script, createContext } from 'node:vm';\n\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\n\n/** Default script wall time when `timeout` omitted (30 minutes). */\nconst DEFAULT_TIMEOUT_SEC = 30 * 60;\n/** Hard cap for `timeout` parameter (4 hours). */\nconst MAX_TIMEOUT_SEC = 4 * 60 * 60;\n\nconst ExecuteCodeSchema = Type.Object({\n code: Type.String({\n description:\n 'JavaScript to run. Exposed as `tools` (async functions) and `console`:\\n' +\n ' await tools.web_search(query, count?)\\n' +\n ' await tools.web_fetch(url, maxChars?)\\n' +\n ' await tools.read_file(path, limit?)\\n' +\n ' await tools.write_file(path, content)\\n' +\n ' await tools.grep(pattern, { path?, glob?, ignoreCase?, literal?, context?, limit? })\\n' +\n ' await tools.find(pattern, { path?, limit? })\\n' +\n ' await tools.exec_command(cmd, cwd?)\\n\\n' +\n 'Use console.log() for output; combined stdout/stderr is returned.',\n }),\n timeout: Type.Optional(\n Type.Number({\n description: 'Execution timeout in seconds (default: 3600 = 60m, max: 14400 = 4h)',\n default: DEFAULT_TIMEOUT_SEC,\n }),\n ),\n});\n\nexport const SANDBOX_ALLOWED_TOOLS = new Set([\n 'web_search',\n 'web_fetch',\n 'read_file',\n 'write_file',\n 'grep',\n 'find',\n 'exec_command',\n 'skills_list',\n 'skill_view',\n]);\n\nconst MAX_TIMEOUT_MS = MAX_TIMEOUT_SEC * 1000;\nconst MAX_TOOL_CALLS = 50;\nconst MAX_STDOUT_CHARS = 50_000;\nconst MAX_STDERR_CHARS = 10_000;\n\nfunction stringifyArg(a: unknown): string {\n if (typeof a === 'string') {\n return a;\n }\n try {\n return JSON.stringify(a);\n } catch {\n return String(a);\n }\n}\n\nfunction extractTextFromResult(result: AgentToolResult<unknown>): string {\n return result.content\n .filter((c): c is { type: 'text'; text: string } => c.type === 'text')\n .map((c) => c.text)\n .join('');\n}\n\nexport function buildSandboxToolMap(tools: AgentTool<any, any>[]): Map<string, AgentTool<any, any>> {\n const m = new Map<string, AgentTool<any, any>>();\n for (const t of tools) {\n if (SANDBOX_ALLOWED_TOOLS.has(t.name)) {\n m.set(t.name, t);\n }\n }\n return m;\n}\n\nfunction createToolsApi(\n getMap: () => Map<string, AgentTool<any, any>>,\n signal: AbortSignal | undefined,\n): Record<string, (...args: unknown[]) => Promise<string>> {\n let seq = 0;\n let calls = 0;\n\n const bump = (): void => {\n calls += 1;\n if (calls > MAX_TOOL_CALLS) {\n throw new Error(`Exceeded max sandbox tool calls (${MAX_TOOL_CALLS})`);\n }\n };\n\n const run = async (name: string, params: Record<string, unknown>): Promise<string> => {\n if (signal?.aborted) {\n throw new Error('aborted');\n }\n bump();\n const tool = getMap().get(name);\n if (!tool) {\n throw new Error(`Tool not available in sandbox: ${name}`);\n }\n const id = `ptc-${Date.now()}-${seq++}`;\n const result = await (tool as any).execute(id, params, signal);\n return extractTextFromResult(result);\n };\n\n return {\n web_search: async (query: unknown, count?: unknown) =>\n run('web_search', {\n query: String(query ?? ''),\n ...(typeof count === 'number' && Number.isFinite(count) ? { count } : {}),\n }),\n\n web_fetch: async (url: unknown, maxChars?: unknown) =>\n run('web_fetch', {\n url: String(url ?? ''),\n ...(typeof maxChars === 'number' && Number.isFinite(maxChars) ? { maxChars } : {}),\n }),\n\n read_file: async (path: unknown, limit?: unknown) =>\n run('read_file', {\n path: String(path ?? ''),\n ...(typeof limit === 'number' && Number.isFinite(limit) ? { limit } : {}),\n }),\n\n write_file: async (path: unknown, content: unknown) =>\n run('write_file', {\n path: String(path ?? ''),\n content: String(content ?? ''),\n }),\n\n grep: async (pattern: unknown, opts?: unknown) => {\n const o = opts && typeof opts === 'object' && opts !== null ? (opts as Record<string, unknown>) : {};\n return run('grep', {\n pattern: String(pattern ?? ''),\n ...(typeof o.path === 'string' ? { path: o.path } : {}),\n ...(typeof o.glob === 'string' ? { glob: o.glob } : {}),\n ...(typeof o.ignoreCase === 'boolean' ? { ignoreCase: o.ignoreCase } : {}),\n ...(typeof o.literal === 'boolean' ? { literal: o.literal } : {}),\n ...(typeof o.context === 'number' && Number.isFinite(o.context) ? { context: o.context } : {}),\n ...(typeof o.limit === 'number' && Number.isFinite(o.limit) ? { limit: o.limit } : {}),\n });\n },\n\n find: async (pattern: unknown, opts?: unknown) => {\n const o = opts && typeof opts === 'object' && opts !== null ? (opts as Record<string, unknown>) : {};\n return run('find', {\n pattern: String(pattern ?? ''),\n ...(typeof o.path === 'string' ? { path: o.path } : {}),\n ...(typeof o.limit === 'number' && Number.isFinite(o.limit) ? { limit: o.limit } : {}),\n });\n },\n\n exec_command: async (cmd: unknown, cwd?: unknown) =>\n run('exec_command', {\n cmd: String(cmd ?? ''),\n ...(typeof cwd === 'string' && cwd.trim() ? { cwd } : {}),\n }),\n };\n}\n\nasync function runSandboxedScript(\n code: string,\n sandbox: Record<string, unknown>,\n timeoutMs: number,\n signal?: AbortSignal,\n): Promise<void> {\n const context = createContext(sandbox, { name: 'execute_code' });\n const wrapped = `(async () => {\\n${code}\\n})()`;\n const script = new Script(wrapped, { filename: 'execute_code.vm' });\n const runPromise = script.runInContext(context) as Promise<unknown>;\n\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n const timeoutPromise = new Promise<never>((_, rej) => {\n timeoutId = setTimeout(\n () => rej(new Error(`Script timed out after ${Math.round(timeoutMs / 1000)}s`)),\n timeoutMs,\n );\n });\n\n const abortPromise =\n signal &&\n new Promise<never>((_, rej) => {\n if (signal.aborted) {\n rej(new Error('aborted'));\n return;\n }\n signal.addEventListener('abort', () => rej(new Error('aborted')), { once: true });\n });\n\n const racers: Promise<unknown>[] = [runPromise, timeoutPromise];\n if (abortPromise) {\n racers.push(abortPromise);\n }\n\n try {\n await Promise.race(racers);\n } finally {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n }\n }\n}\n\nexport interface ExecuteCodeToolDeps {\n getSandboxToolMap: () => Map<string, AgentTool<any, any>>;\n}\n\ntype ExecuteCodeParams = { code: string; timeout?: number };\n\nexport function createExecuteCodeTool(deps: ExecuteCodeToolDeps): AgentTool {\n return {\n name: 'execute_code',\n label: '⚡ Execute Code',\n description:\n 'Run sandboxed JavaScript that calls a subset of tools via `tools.*` (batch work in one step).\\n\\n' +\n 'Only stdout/stderr from `console` plus tool return text (as strings) are visible — not full tool JSON.\\n\\n' +\n 'WHEN TO USE: loops over files/URLs, simple branching between tool calls.\\n' +\n 'WHEN NOT TO USE: single tool calls; tasks needing full tool schemas or disallowed tools.\\n\\n' +\n 'API: `await tools.web_search(q, count?)`, `web_fetch(url, maxChars?)`, `read_file(path, limit?)`, ' +\n '`write_file(path, content)`, `grep(pattern, opts?)`, `find(glob, opts?)`, `exec_command(cmd, cwd?)`. ' +\n 'Use `console.log` for output.',\n parameters: ExecuteCodeSchema,\n\n async execute(\n _toolCallId: string,\n params: any,\n signal?: AbortSignal,\n ): Promise<AgentToolResult<{ exitCode: number }>> {\n const p = params as ExecuteCodeParams;\n const sec = p.timeout ?? DEFAULT_TIMEOUT_SEC;\n const timeoutMs = Math.min(\n Math.max(1, Number.isFinite(sec) ? sec : DEFAULT_TIMEOUT_SEC) * 1000,\n MAX_TIMEOUT_MS,\n );\n\n const stdout: string[] = [];\n const stderr: string[] = [];\n\n const toolsApi = createToolsApi(deps.getSandboxToolMap, signal);\n\n const sandbox: Record<string, unknown> = {\n tools: toolsApi,\n Promise,\n JSON,\n Math,\n Date,\n Array,\n Object,\n String,\n Number,\n Boolean,\n RegExp,\n Map,\n Set,\n Error,\n TypeError,\n RangeError,\n parseInt,\n parseFloat,\n isNaN,\n isFinite,\n console: {\n log: (...args: unknown[]) => {\n stdout.push(args.map(stringifyArg).join(' '));\n },\n error: (...args: unknown[]) => {\n stderr.push(args.map(stringifyArg).join(' '));\n },\n warn: (...args: unknown[]) => {\n stderr.push(args.map(stringifyArg).join(' '));\n },\n },\n setTimeout,\n clearTimeout,\n };\n\n try {\n await runSandboxedScript(p.code, sandbox, timeoutMs, signal);\n\n let out = stdout.join('\\n');\n if (out.length > MAX_STDOUT_CHARS) {\n out = `${out.slice(0, MAX_STDOUT_CHARS)}\\n...(truncated)`;\n }\n\n const parts: string[] = [];\n if (out.length > 0) {\n parts.push(out);\n }\n if (stderr.length > 0) {\n let err = stderr.join('\\n');\n if (err.length > MAX_STDERR_CHARS) {\n err = `${err.slice(0, MAX_STDERR_CHARS)}\\n...(truncated)`;\n }\n parts.push(`\\nSTDERR:\\n${err}`);\n }\n\n return {\n content: [{ type: 'text', text: parts.join('') || '(no output)' }],\n details: { exitCode: 0 },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text', text: `Execution failed: ${message}` }],\n details: { exitCode: 1 },\n };\n }\n },\n } as any;\n}\n"],"mappings":"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"}
|
|
@@ -51,17 +51,17 @@ export interface ToolFactoryDeps {
|
|
|
51
51
|
} | undefined;
|
|
52
52
|
/** After skill_manage mutates disk, reload skills + refresh agent prompts (optional). */
|
|
53
53
|
onSkillsFilesystemMutate?: () => void;
|
|
54
|
-
/** Names registered via skill_view for
|
|
54
|
+
/** Names registered via skill_view for command env passthrough. */
|
|
55
55
|
getSkillPassthroughEnvVarNames?: () => string[];
|
|
56
56
|
/** Add declared env names for the current session (no values stored). */
|
|
57
57
|
registerSkillEnvPassthrough?: (names: string[]) => void;
|
|
58
58
|
}
|
|
59
59
|
export interface CreateCoreToolsOptions {
|
|
60
|
-
/** Workspace root for file/
|
|
60
|
+
/** Workspace root for file/command tools (defaults to factory workspace). */
|
|
61
61
|
workspace?: string;
|
|
62
62
|
/** Canonical `agents/<id>/profile/`: bare SOUL.md / IDENTITY.md resolve here after the workspace. */
|
|
63
63
|
profileMarkdownRoot?: string;
|
|
64
|
-
/** Tool `name` values to omit (e.g. `
|
|
64
|
+
/** Tool `name` values to omit (e.g. `exec_command`, `extensions` for extension tools). */
|
|
65
65
|
disabledTools?: Set<string>;
|
|
66
66
|
/** Optional primary model for image tool heuristics. */
|
|
67
67
|
getPrimaryModel?: () => Model<Api>;
|
|
@@ -2,9 +2,9 @@ import { createLogger } from "../../utils/logger/index.js";
|
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { createReadFileTool } from "./read.js";
|
|
4
4
|
import { createWriteFileTool } from "./write.js";
|
|
5
|
-
import { createEditFileTool } from "./edit.js";
|
|
6
5
|
import { createListDirTool } from "./list-dir.js";
|
|
7
|
-
import {
|
|
6
|
+
import { createExecCommandTool } from "./exec-command.js";
|
|
7
|
+
import { createApplyPatchTool } from "./apply-patch.js";
|
|
8
8
|
import { createMemoryGetTool, createMemorySearchTool } from "./memory-tool.js";
|
|
9
9
|
import { createCuratedMemoryTool } from "./curated-memory-tool.js";
|
|
10
10
|
import { createSessionSearchTool } from "./session-search-tool.js";
|
|
@@ -18,6 +18,7 @@ import { createSendMediaTool } from "./send-media.js";
|
|
|
18
18
|
import { createReadMediaTool } from "./media-read-tool.js";
|
|
19
19
|
import { createCreateShareTool, isShareToolAvailable } from "./create-share-tool.js";
|
|
20
20
|
import { createTodoTool } from "./todo-tool.js";
|
|
21
|
+
import { createUpdatePlanTool } from "./update-plan-tool.js";
|
|
21
22
|
import { createSessionStatusTool } from "./session-status-tool.js";
|
|
22
23
|
import { createDreamingTool } from "./dreaming-tool.js";
|
|
23
24
|
import { createClarifyTool } from "./clarify-tool.js";
|
|
@@ -170,10 +171,7 @@ var AgentToolsFactory = class {
|
|
|
170
171
|
profileMarkdownRoot: options?.profileMarkdownRoot,
|
|
171
172
|
recordGoalEvidence
|
|
172
173
|
});
|
|
173
|
-
const
|
|
174
|
-
profileMarkdownRoot: options?.profileMarkdownRoot,
|
|
175
|
-
recordGoalEvidence
|
|
176
|
-
});
|
|
174
|
+
const applyPatchTool = createApplyPatchTool(workspace, { recordGoalEvidence });
|
|
177
175
|
const listDir = createListDirTool(workspace);
|
|
178
176
|
const grep = createGrepTool(workspace);
|
|
179
177
|
const find = createFindTool(workspace);
|
|
@@ -193,6 +191,7 @@ var AgentToolsFactory = class {
|
|
|
193
191
|
return (r) => req(ctx.sessionKey, r);
|
|
194
192
|
} }),
|
|
195
193
|
createTodoTool({ getSessionKey: () => this.deps.getCurrentContext()?.sessionKey }),
|
|
194
|
+
createUpdatePlanTool(),
|
|
196
195
|
...getSkillMgr ? [
|
|
197
196
|
createSkillsListTool({
|
|
198
197
|
getSkillManager: getSkillMgr,
|
|
@@ -211,11 +210,11 @@ var AgentToolsFactory = class {
|
|
|
211
210
|
] : [],
|
|
212
211
|
readTool,
|
|
213
212
|
writeTool,
|
|
214
|
-
|
|
213
|
+
applyPatchTool,
|
|
215
214
|
listDir,
|
|
216
215
|
grep,
|
|
217
216
|
find,
|
|
218
|
-
|
|
217
|
+
createExecCommandTool(workspace, {
|
|
219
218
|
getSkillPassthroughEnvVarNames: this.deps.getSkillPassthroughEnvVarNames,
|
|
220
219
|
recordGoalEvidence
|
|
221
220
|
}),
|
|
@@ -249,7 +248,7 @@ var AgentToolsFactory = class {
|
|
|
249
248
|
getCurrentSessionKey: () => this.deps.getCurrentContext()?.sessionKey
|
|
250
249
|
})] : [],
|
|
251
250
|
...this.deps.getAutomationService ? [createAutomationTool({ getAutomationService: this.deps.getAutomationService })] : [],
|
|
252
|
-
createGoalTool(),
|
|
251
|
+
createGoalTool({ getCurrentSessionKey: () => this.deps.getCurrentContext()?.sessionKey }),
|
|
253
252
|
...browserEnabled ? [createBrowserUseTool({
|
|
254
253
|
getManager: () => this.ensureBrowserManager(),
|
|
255
254
|
getPageForTask: () => this.acquireBrowserPage(),
|
|
@@ -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 createEditFileTool,\n createListDirTool,\n createGrepTool,\n createFindTool,\n createShellTool,\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 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 shell 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/shell 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. `shell`, `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 editTool = createEditFileTool(workspace, {\n profileMarkdownRoot: options?.profileMarkdownRoot,\n recordGoalEvidence,\n });\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 ...(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 editTool,\n listDir,\n grep,\n find,\n createShellTool(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 ...(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 { 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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"}
|
|
@@ -13,7 +13,11 @@ declare const GoalToolSchema: import("@sinclair/typebox/build/cjs/index.js").TOb
|
|
|
13
13
|
judgeModelRef: import("@sinclair/typebox/build/cjs/index.js").TOptional<import("@sinclair/typebox/build/cjs/index.js").TString>;
|
|
14
14
|
agentId: import("@sinclair/typebox/build/cjs/index.js").TOptional<import("@sinclair/typebox/build/cjs/index.js").TString>;
|
|
15
15
|
sessionKey: import("@sinclair/typebox/build/cjs/index.js").TOptional<import("@sinclair/typebox/build/cjs/index.js").TString>;
|
|
16
|
+
projectId: import("@sinclair/typebox/build/cjs/index.js").TOptional<import("@sinclair/typebox/build/cjs/index.js").TString>;
|
|
16
17
|
limit: import("@sinclair/typebox/build/cjs/index.js").TOptional<import("@sinclair/typebox/build/cjs/index.js").TNumber>;
|
|
17
18
|
}>;
|
|
18
|
-
export
|
|
19
|
+
export interface GoalToolOptions {
|
|
20
|
+
getCurrentSessionKey?: () => string | undefined;
|
|
21
|
+
}
|
|
22
|
+
export declare function createGoalTool(options?: GoalToolOptions): AgentTool<typeof GoalToolSchema, {}>;
|
|
19
23
|
export {};
|