@xopcai/xopc 0.0.244 → 0.0.245
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-CAah-_8h.js → activity-store-BlxqErph.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BhXGsupm.js → agent-avatar-dicebear-DRQnogaU.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-Blzn2H6t.js → agent-defaults-settings-panel-CpOxGbMD.js} +1 -1
- package/dist/gateway/static/root/assets/{agents-Cmp-z8Y_.js → agents-flnXZLaT.js} +1 -1
- package/dist/gateway/static/root/assets/{api-B2tKxbcz.js → api-BbXzyQMj.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-CezjAP1K.js → app-management-settings-panel-CZl6n2xi.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-C-CfS05x.js → appearance-settings-Bglp-pn6.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-7Y13_bqZ.js → apps-page-CmsWarVB.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-BmSx7wzY.js → archive-plugin-DD2SweEH.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DI4CoIga.js → attachment-load-G0HenUmG.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-D04Xceck.js → automations-page-B78bFjH2.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-workspace-wEO1OWk0.js → automations-workspace-BMQGmn50.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-BJQe8TRu.js → binary-plugins-BbSQmXqn.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-BSzGjJC6.js → block-editor-DutTIH81.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-settings-page-DjAZ_LF2.js → browser-settings-page-CALiFKm4.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-CRnkgZHI.js → browser-workflow-inputs-BAAc151l.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-CwbxA3B7.js → browser-workflows-page-DE5HPrHZ.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-settings-panel-jt9bqUMK.js → capabilities-settings-panel-Dts7XtP3.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-Cz_TWY3a.js → channels-settings-CWEd3wzh.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-status-swr-DuY4MGxe.js → channels-status-swr-CCBCtLDg.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-D3gj2D3U.js → chat-terminal-dock-Bp1fXQm1.js} +1 -1
- package/dist/gateway/static/root/assets/{connectors-page-Shs5vbzx.js → connectors-page-CQ6wVNLm.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-expression-DgWHw0jX.js → cron-expression-B8HA5IRb.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-CKg-RPbs.js → date-picker-DD8b7oad.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-CVYkw-NN.js → dependency-picker-BC9zwIyH.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-Bf46oXTY.js → desktop-pet-DsrsPZTW.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-BJO_klc7.js → desktop-pet-settings-D7gp_HNA.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-T2PmFFOW.js → extension-debug-page-BoKbOX7x.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-2wAE2RCe.js → extension-page-BegL4FW8.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-Y9ZiCJ21.js → extension-settings-page-CjPqq57s.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-DaYY1Gkn.js → gateway-config-api-DaG57o4X.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-BC3pgb_P.js → gateway-config-swr-826dipyU.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-eO3IzW_J.js → gateway-settings-DkJGpgm6.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-uMcSfLru.js → gateway-startup-retry-DyvcAIMm.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-BAgrkyHc.js → heartbeat-settings-BLZ48kSU.js} +1 -1
- package/dist/gateway/static/root/assets/{home-page-GTjKH7LK.js → home-page-Dtw7Ipt1.js} +1 -1
- package/dist/gateway/static/root/assets/{image-generation-api-D1qlQA-A.js → image-generation-api-D7cyfks6.js} +1 -1
- package/dist/gateway/static/root/assets/{index-DUz0O54y.js → index-DG5CfYat.js} +10 -10
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CWGqL6o5.js → keyboard-shortcuts-settings-D2Has7-N.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-DKJ-rks0.js → local-app-workbench-page-BWidWY93.js} +1 -1
- package/dist/gateway/static/root/assets/{local-apps-page-Bfidv29d.js → local-apps-page-Bkekjoxf.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-CMZljTJx.js → locale-store-CBoCuIMx.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-DwAHrPbF.js → logs-page-C5zSSgvA.js} +1 -1
- package/dist/gateway/static/root/assets/{management-settings-BG7j1I9f.js → management-settings-B8c62vRS.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-AnmmpLs6.js → markdown-split-3kxTTGO7.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-PPCLt7fu.js → markdown-view-BXsHghJd.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-CGS-05cE.js → media-plugins-BW8J1nCG.js} +1 -1
- package/dist/gateway/static/root/assets/messages-BbdwoxVo.js +3 -0
- package/dist/gateway/static/root/assets/{mobile-pairing-wizard-DoKK5GfV.js → mobile-pairing-wizard-nwQ8iUcd.js} +1 -1
- package/dist/gateway/static/root/assets/models-hub-cache-88f4fzYS.js +1 -0
- package/dist/gateway/static/root/assets/{notes-page-Lr8rsFAR.js → notes-page-DdybD0QM.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-workbench-ISWnKLxO.js → notes-workbench-IYfpy2Jx.js} +2 -2
- package/dist/gateway/static/root/assets/{oauth-api-4VeMbkTJ.js → oauth-api-BjSUDIgq.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-BU0HiZtv.js → product-open-page-CAJeUXeU.js} +1 -1
- package/dist/gateway/static/root/assets/{project-detail-page-BZqr4yam.js → project-detail-page-4wjw-b7h.js} +1 -1
- package/dist/gateway/static/root/assets/{projects-page-Dau8733A.js → projects-page-CCMj9PeL.js} +1 -1
- package/dist/gateway/static/root/assets/{registry-api-CWOtPFrE.js → registry-api-BhGKnvLP.js} +1 -1
- package/dist/gateway/static/root/assets/{remote-access-hub-DdChlvGP.js → remote-access-hub-DsBJqWIk.js} +1 -1
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-CmZTNv1W.js → runtime-tools-settings-panel-B4IDcqx0.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-XlVPyiVQ.js → schema-form-DiGUUjO6.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-C3kADsd4.js → sessions-page-BwGj0t-2.js} +1 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-BJCfUghk.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-DblUeM3V.js → settings-page-CVQUsAhd.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-bDfRfSnq.js → setup-status-panel-CQACRh1i.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-DBMWFMN-.js → share-preview-page-DTP1dtuS.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-settings-Bu6lIStj.js → shares-settings-D_YPh6Rw.js} +1 -1
- package/dist/gateway/static/root/assets/skill-reload-api-B43xlJlX.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-CSOseeQe.js → skills-page-Czpn7Y28.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-CniRGhkJ.js → skills-page.utils-d39rm3hb.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-D0GqNpKy.js → system-settings-panel-CXXySCSp.js} +1 -1
- package/dist/gateway/static/root/assets/{task-detail-page-BRCq-nR7.js → task-detail-page-DHiOqQMx.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-uxUwr10D.js → theme-store-hybK3oC9.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-BtjS2nrM.js → tunnel-api-BiBGK7O2.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-TwuAycG8.js → use-autosave-DjpzpeIm.js} +1 -1
- package/dist/gateway/static/root/assets/{user-context-page-CbqPu8xZ.js → user-context-page-1XBRV5gX.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-CzwG5plu.js → voice-api-key-field-CUIPNmOc.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-MqyI6cgq.js → voice-config-api-CBbiF1T3.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-DS15FzQA.js → work-discovery-overlay-DVNxhb1x.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-C_boCemi.js → workflow-run-setup-panel-HxxFQFY7.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-CaI2ruyy.js → workflows-page-BCgL7PRm.js} +1 -1
- package/dist/gateway/static/root/index.html +11 -11
- package/dist/package.js +1 -1
- package/dist/packages/gateway-contract/src/turn-outcome.js +3 -1
- package/dist/src/agent/agent-instance-gateway.d.ts +3 -1
- package/dist/src/agent/agent-manager.d.ts +2 -4
- package/dist/src/agent/agent-manager.js +28 -32
- package/dist/src/agent/background-review/coordinator.js +1 -1
- package/dist/src/agent/background-review/run-background-review.js +2 -2
- package/dist/src/agent/child-agent-factory.d.ts +10 -7
- package/dist/src/agent/child-agent-factory.js +112 -158
- package/dist/src/agent/coding/index.d.ts +1 -1
- package/dist/src/agent/coding/index.js +2 -2
- package/dist/src/agent/coding/repository-instructions.d.ts +12 -0
- package/dist/src/agent/coding/repository-instructions.js +76 -0
- package/dist/src/agent/coding/run-verification.d.ts +34 -0
- package/dist/src/agent/coding/run-verification.js +134 -0
- package/dist/src/agent/coding/verification-command.d.ts +3 -0
- package/dist/src/agent/coding/verification-command.js +50 -0
- package/dist/src/agent/coding/workspace-revision.d.ts +2 -0
- package/dist/src/agent/coding/workspace-revision.js +77 -0
- package/dist/src/agent/commands/command-isolation.d.ts +21 -0
- package/dist/src/agent/commands/command-isolation.js +71 -0
- package/dist/src/agent/commands/command-registry.d.ts +56 -0
- package/dist/src/agent/commands/command-registry.js +259 -0
- package/dist/src/agent/embedded/index.js +1 -1
- package/dist/src/agent/embedded/model-runtime.js +1 -1
- package/dist/src/agent/embedded/run-for-session.js +3 -2
- package/dist/src/agent/embedded/run-turn.js +88 -25
- package/dist/src/agent/embedded/session-tool-result-guard.js +2 -2
- package/dist/src/agent/embedded/subscribe-session.d.ts +2 -1
- package/dist/src/agent/embedded/subscribe-session.js +2 -1
- package/dist/src/agent/embedded/types.d.ts +3 -1
- package/dist/src/agent/embedded/xopc-tools-bridge.js +4 -1
- package/dist/src/agent/image/index.js +1 -1
- package/dist/src/agent/image/tool-model-config.js +1 -1
- package/dist/src/agent/index.js +3 -3
- package/dist/src/agent/ipc/inbox.js +1 -1
- package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +1 -1
- package/dist/src/agent/memory/user-context-coordinator.js +1 -1
- package/dist/src/agent/middleware/index.d.ts +0 -5
- package/dist/src/agent/middleware/index.js +1 -2
- package/dist/src/agent/orchestration/agent-event-handler.d.ts +0 -5
- package/dist/src/agent/orchestration/agent-event-handler.js +1 -96
- package/dist/src/agent/orchestration/agent-orchestrator.js +1 -1
- package/dist/src/agent/orchestration/agent-turn-policy.js +5 -5
- package/dist/src/agent/orchestration/index.d.ts +1 -1
- package/dist/src/agent/orchestration/index.js +2 -2
- package/dist/src/agent/orchestration/loop-guard.d.ts +4 -31
- package/dist/src/agent/orchestration/loop-guard.js +14 -99
- package/dist/src/agent/prompt/sections/tooling.js +2 -4
- package/dist/src/agent/sandbox/types.d.ts +2 -2
- package/dist/src/agent/sandbox/types.js +1 -1
- package/dist/src/agent/service/direct-turn-helpers.js +1 -1
- package/dist/src/agent/service/process-direct-streaming.js +1 -1
- package/dist/src/agent/service.d.ts +0 -2
- package/dist/src/agent/service.js +8 -25
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/tasks/task-judge-service.d.ts +7 -0
- package/dist/src/agent/tasks/task-judge-service.js +27 -5
- package/dist/src/agent/tools/delegate-tool.d.ts +2 -1
- package/dist/src/agent/tools/delegate-tool.js +102 -124
- package/dist/src/agent/tools/exec-command.d.ts +8 -1
- package/dist/src/agent/tools/exec-command.js +77 -169
- package/dist/src/agent/tools/executor.js +9 -2
- package/dist/src/agent/tools/factory.js +50 -5
- package/dist/src/agent/tools/find.d.ts +10 -13
- package/dist/src/agent/tools/find.js +33 -80
- package/dist/src/agent/tools/grep.d.ts +14 -18
- package/dist/src/agent/tools/grep.js +56 -144
- package/dist/src/agent/tools/index.d.ts +0 -1
- package/dist/src/agent/tools/index.js +2 -3
- package/dist/src/agent/tools/language-diagnostics.d.ts +11 -0
- package/dist/src/agent/tools/language-diagnostics.js +62 -0
- package/dist/src/agent/tools/managed-job-tool.d.ts +2 -1
- package/dist/src/agent/tools/managed-job-tool.js +58 -118
- package/dist/src/agent/tools/read.js +24 -7
- package/dist/src/agent/tools/repository-search.d.ts +5 -0
- package/dist/src/agent/tools/repository-search.js +56 -0
- package/dist/src/agent/tools/review-workspace.d.ts +2 -0
- package/dist/src/agent/tools/review-workspace.js +103 -0
- package/dist/src/agent/tools/write.js +4 -4
- package/dist/src/agent/transcript/index.js +2 -2
- package/dist/src/agent/transcript/transcript-hygiene.js +2 -2
- package/dist/src/agent/workflow/subagent-runner.d.ts +0 -2
- package/dist/src/agent/workflow/subagent-runner.js +12 -31
- package/dist/src/agent-config/schema.d.ts +42 -0
- package/dist/src/agent-config/schema.js +5 -0
- package/dist/src/ai-assist/text-assist.js +1 -1
- package/dist/src/auth/credentials.js +2 -2
- package/dist/src/auth/profiles/store.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +2 -2
- package/dist/src/browser/providers/browser-ext-install.js +1 -1
- package/dist/src/cli/commands/agent.js +2 -2
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/cli/commands/models.js +2 -2
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/cli/commands/profile.js +1 -1
- package/dist/src/cli/commands/tunnel.js +1 -1
- package/dist/src/cli/commands/update.js +1 -1
- package/dist/src/cli/extension-cli-register.js +1 -1
- package/dist/src/config/index.js +5 -5
- package/dist/src/config/loader.js +1 -1
- package/dist/src/config/models-json.js +1 -1
- package/dist/src/config/schema.d.ts +28 -0
- package/dist/src/execution-environments/local-worktree-manager.d.ts +3 -1
- package/dist/src/execution-environments/local-worktree-manager.js +8 -3
- package/dist/src/execution-environments/session-environment-service.js +5 -3
- package/dist/src/extensions/lockfile.js +1 -1
- package/dist/src/extensions/update.js +1 -1
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/file-path-classifier.js +1 -1
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +7 -0
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +1 -1
- package/dist/src/gateway/media-access.js +1 -1
- package/dist/src/gateway/run-loop.js +1 -1
- package/dist/src/gateway/service/config-coordinator.js +2 -2
- package/dist/src/gateway/service/run-gateway-agent.js +4 -1
- package/dist/src/gateway/service.js +7 -7
- package/dist/src/gateway/session-reset-service.js +1 -1
- package/dist/src/gateway/workspace-ripgrep.d.ts +0 -6
- package/dist/src/gateway/workspace-ripgrep.js +2 -40
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/ripgrep.d.ts +13 -0
- package/dist/src/infra/ripgrep.js +46 -0
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/proactive/execution/agent-executor.js +1 -1
- package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/providers/register-runtime-providers.js +1 -1
- package/dist/src/session/store.js +1 -1
- package/dist/src/session/turn-outcome-projector.js +26 -6
- package/dist/src/share/hosted-session-share.js +1 -1
- package/dist/src/tasks/task-run-coordinator.d.ts +2 -2
- package/dist/src/tasks/task-run-coordinator.js +14 -12
- package/dist/src/tui/backends/embedded-backend.js +1 -1
- package/dist/src/tui/tui-startup-resources.js +1 -1
- package/dist/src/tui/tui.js +1 -1
- package/dist/src/workflows/service/workflow-run-service.js +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/messages-CTSgFlE4.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-cache-ZrbGRiGY.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CSYy6SUa.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BNMc4l04.js +0 -1
- package/dist/src/agent/coding/turn-diff-tracker.d.ts +0 -67
- package/dist/src/agent/coding/turn-diff-tracker.js +0 -231
- package/dist/src/agent/middleware/self-verify.d.ts +0 -136
- package/dist/src/agent/middleware/self-verify.js +0 -380
- package/dist/src/agent/tools/execute-code-tool.d.ts +0 -11
- package/dist/src/agent/tools/execute-code-tool.js +0 -208
|
@@ -1,380 +0,0 @@
|
|
|
1
|
-
import { createLogger } from "../../utils/logger/index.js";
|
|
2
|
-
import { init_logger } from "../../utils/logger.js";
|
|
3
|
-
//#region src/agent/middleware/self-verify.ts
|
|
4
|
-
init_logger();
|
|
5
|
-
const log = createLogger("SelfVerifyMiddleware");
|
|
6
|
-
const DEFAULT_CONFIG = {
|
|
7
|
-
maxEditsPerFile: 5,
|
|
8
|
-
enablePreCompletionCheck: true,
|
|
9
|
-
minTurnsForVerification: 3,
|
|
10
|
-
resetOnVerification: true
|
|
11
|
-
};
|
|
12
|
-
function createTrackerState() {
|
|
13
|
-
return {
|
|
14
|
-
fileEdits: /* @__PURE__ */ new Map(),
|
|
15
|
-
turnCount: 0,
|
|
16
|
-
verificationRequested: false,
|
|
17
|
-
hasUnverifiedEdits: false,
|
|
18
|
-
diffReviewed: false,
|
|
19
|
-
lastVerification: void 0,
|
|
20
|
-
lastMutationTool: void 0
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Tracks file modifications and provides verification guidance
|
|
25
|
-
*/
|
|
26
|
-
var SelfVerifyMiddleware = class {
|
|
27
|
-
states = /* @__PURE__ */ new Map();
|
|
28
|
-
config;
|
|
29
|
-
constructor(config = {}) {
|
|
30
|
-
this.config = {
|
|
31
|
-
...DEFAULT_CONFIG,
|
|
32
|
-
...config
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
getState(sessionKey) {
|
|
36
|
-
const key = sessionKey ?? "default";
|
|
37
|
-
let state = this.states.get(key);
|
|
38
|
-
if (!state) {
|
|
39
|
-
state = createTrackerState();
|
|
40
|
-
this.states.set(key, state);
|
|
41
|
-
}
|
|
42
|
-
return state;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Record a file edit operation
|
|
46
|
-
*/
|
|
47
|
-
recordEdit(filePath, operation, sessionKey) {
|
|
48
|
-
const state = this.getState(sessionKey);
|
|
49
|
-
const now = Date.now();
|
|
50
|
-
const existing = state.fileEdits.get(filePath);
|
|
51
|
-
if (existing) {
|
|
52
|
-
existing.editCount++;
|
|
53
|
-
existing.lastEditTime = now;
|
|
54
|
-
if (!existing.operations.includes(operation)) existing.operations.push(operation);
|
|
55
|
-
} else state.fileEdits.set(filePath, {
|
|
56
|
-
path: filePath,
|
|
57
|
-
editCount: 1,
|
|
58
|
-
lastEditTime: now,
|
|
59
|
-
operations: [operation]
|
|
60
|
-
});
|
|
61
|
-
state.hasUnverifiedEdits = true;
|
|
62
|
-
state.diffReviewed = false;
|
|
63
|
-
state.lastMutationTool = operation;
|
|
64
|
-
log.debug({
|
|
65
|
-
filePath,
|
|
66
|
-
editCount: this.getEditCount(filePath, sessionKey),
|
|
67
|
-
operation
|
|
68
|
-
}, "File edit recorded");
|
|
69
|
-
}
|
|
70
|
-
recordVerification(toolName, args, task, sessionKey) {
|
|
71
|
-
const state = this.getState(sessionKey);
|
|
72
|
-
const name = toolName.toLowerCase();
|
|
73
|
-
if (name === "exec_command") {
|
|
74
|
-
const command = this.extractExecCommand(args, task?.result);
|
|
75
|
-
const success = this.isSuccessfulExecVerification(task);
|
|
76
|
-
const details = this.extractResultDetails(task?.result);
|
|
77
|
-
if (success && this.isDiffReviewCommand(command)) {
|
|
78
|
-
state.diffReviewed = true;
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
if (!this.isVerificationCommand(command)) return;
|
|
82
|
-
const rawExitCode = details?.exitCode;
|
|
83
|
-
let exitCode;
|
|
84
|
-
if (typeof rawExitCode === "number") exitCode = rawExitCode;
|
|
85
|
-
else if (rawExitCode === null) exitCode = null;
|
|
86
|
-
state.lastVerification = {
|
|
87
|
-
toolName,
|
|
88
|
-
command,
|
|
89
|
-
success,
|
|
90
|
-
exitCode,
|
|
91
|
-
status: typeof details?.status === "string" ? details.status : void 0,
|
|
92
|
-
timedOut: details?.timedOut === true
|
|
93
|
-
};
|
|
94
|
-
if (success) state.hasUnverifiedEdits = false;
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
if (name.includes("test") || name.includes("verify") || name.includes("lint")) {
|
|
98
|
-
state.hasUnverifiedEdits = false;
|
|
99
|
-
state.lastVerification = {
|
|
100
|
-
toolName,
|
|
101
|
-
success: true
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
getVerificationState(sessionKey) {
|
|
106
|
-
const state = this.getState(sessionKey);
|
|
107
|
-
const changedFiles = Array.from(state.fileEdits.keys()).sort();
|
|
108
|
-
const lastVerification = state.lastVerification ? { ...state.lastVerification } : void 0;
|
|
109
|
-
return {
|
|
110
|
-
hasUnverifiedEdits: state.hasUnverifiedEdits,
|
|
111
|
-
changedFiles,
|
|
112
|
-
diffReviewed: state.diffReviewed,
|
|
113
|
-
verificationAttempted: Boolean(lastVerification),
|
|
114
|
-
lastVerificationFailed: Boolean(lastVerification && !lastVerification.success),
|
|
115
|
-
lastVerification,
|
|
116
|
-
lastMutationTool: state.lastMutationTool
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
getPendingVerificationContext(sessionKey, agentId) {
|
|
120
|
-
const state = this.getState(sessionKey);
|
|
121
|
-
if (!this.config.enablePreCompletionCheck || !state.hasUnverifiedEdits) return "";
|
|
122
|
-
return this.buildPendingVerificationReminder(sessionKey, agentId);
|
|
123
|
-
}
|
|
124
|
-
extractExecCommand(args, result) {
|
|
125
|
-
if (args && typeof args === "object") {
|
|
126
|
-
const rec = args;
|
|
127
|
-
if (typeof rec.cmd === "string") return rec.cmd.toLowerCase();
|
|
128
|
-
if (typeof rec.command === "string") return rec.command.toLowerCase();
|
|
129
|
-
}
|
|
130
|
-
const details = this.extractResultDetails(result);
|
|
131
|
-
if (details) {
|
|
132
|
-
const command = details.command;
|
|
133
|
-
if (typeof command === "string") return command.toLowerCase();
|
|
134
|
-
}
|
|
135
|
-
return "";
|
|
136
|
-
}
|
|
137
|
-
extractResultDetails(result) {
|
|
138
|
-
if (!result || typeof result !== "object") return null;
|
|
139
|
-
const details = result.details;
|
|
140
|
-
return details && typeof details === "object" ? details : null;
|
|
141
|
-
}
|
|
142
|
-
isSuccessfulExecVerification(task) {
|
|
143
|
-
if (!task || task.isError) return false;
|
|
144
|
-
const details = this.extractResultDetails(task.result);
|
|
145
|
-
if (!details) return false;
|
|
146
|
-
if (details.timedOut === true) return false;
|
|
147
|
-
if (details.status === "success") return true;
|
|
148
|
-
return details.exitCode === 0;
|
|
149
|
-
}
|
|
150
|
-
isVerificationCommand(command) {
|
|
151
|
-
return /\b(test|vitest|jest|mocha|ava|playwright|typecheck|type-check|tsc|build|lint)\b/.test(command);
|
|
152
|
-
}
|
|
153
|
-
isDiffReviewCommand(command) {
|
|
154
|
-
return /\bgit\s+(diff|status)\b/.test(command);
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Get edit count for a specific file
|
|
158
|
-
*/
|
|
159
|
-
getEditCount(filePath, sessionKey) {
|
|
160
|
-
return this.getState(sessionKey).fileEdits.get(filePath)?.editCount || 0;
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Check if any file has excessive edits (potential doom loop)
|
|
164
|
-
*/
|
|
165
|
-
hasExcessiveEdits(sessionKey) {
|
|
166
|
-
for (const [path, record] of this.getState(sessionKey).fileEdits.entries()) if (record.editCount >= this.config.maxEditsPerFile) return {
|
|
167
|
-
file: path,
|
|
168
|
-
count: record.editCount
|
|
169
|
-
};
|
|
170
|
-
return null;
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Increment turn counter
|
|
174
|
-
*/
|
|
175
|
-
onTurnStart(sessionKey) {
|
|
176
|
-
const state = this.getState(sessionKey);
|
|
177
|
-
state.turnCount++;
|
|
178
|
-
state.verificationRequested = false;
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Reset all tracking (e.g., after successful task completion)
|
|
182
|
-
*/
|
|
183
|
-
reset(sessionKey) {
|
|
184
|
-
if (sessionKey) this.states.set(sessionKey, createTrackerState());
|
|
185
|
-
else this.states.clear();
|
|
186
|
-
log.debug("Self-verify middleware reset");
|
|
187
|
-
}
|
|
188
|
-
consumePostEditReminder(sessionKey) {
|
|
189
|
-
const state = this.getState(sessionKey);
|
|
190
|
-
if (!this.config.enablePreCompletionCheck || !state.hasUnverifiedEdits) return "";
|
|
191
|
-
if (state.verificationRequested) return "";
|
|
192
|
-
state.verificationRequested = true;
|
|
193
|
-
return this.buildPendingVerificationReminder(sessionKey);
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Get context injection for system prompt
|
|
197
|
-
* Adds verification guidance based on current state
|
|
198
|
-
*/
|
|
199
|
-
getContextInjection(sessionKey, agentId) {
|
|
200
|
-
const sections = [];
|
|
201
|
-
sections.push(this.buildWorkflowGuidance());
|
|
202
|
-
const excessive = this.hasExcessiveEdits(sessionKey);
|
|
203
|
-
if (excessive) sections.push(this.buildExcessiveEditWarning(excessive.file, excessive.count));
|
|
204
|
-
if (this.shouldPromptForVerification(sessionKey)) sections.push(this.buildPreCompletionReminder(sessionKey));
|
|
205
|
-
const pending = this.getPendingVerificationContext(sessionKey, agentId);
|
|
206
|
-
if (pending) sections.push(pending);
|
|
207
|
-
return sections.filter(Boolean).join("\n\n");
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Check if we should inject verification reminder
|
|
211
|
-
*/
|
|
212
|
-
shouldPromptForVerification(sessionKey) {
|
|
213
|
-
const state = this.getState(sessionKey);
|
|
214
|
-
if (!this.config.enablePreCompletionCheck) return false;
|
|
215
|
-
if (state.turnCount < this.config.minTurnsForVerification) return false;
|
|
216
|
-
if (state.verificationRequested) return false;
|
|
217
|
-
return true;
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Mark verification as requested (to avoid spam)
|
|
221
|
-
*/
|
|
222
|
-
markVerificationRequested(sessionKey) {
|
|
223
|
-
this.getState(sessionKey).verificationRequested = true;
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Build workflow guidance section
|
|
227
|
-
*/
|
|
228
|
-
buildWorkflowGuidance() {
|
|
229
|
-
return `## Problem Solving Workflow
|
|
230
|
-
|
|
231
|
-
Follow this iterative process for all tasks:
|
|
232
|
-
|
|
233
|
-
1. **Plan**: Understand the task, read relevant files, and create a plan
|
|
234
|
-
2. **Build**: Implement your solution with verification in mind
|
|
235
|
-
3. **Verify**: Test your work, run checks, compare against requirements
|
|
236
|
-
4. **Fix**: If issues found, analyze and fix them
|
|
237
|
-
|
|
238
|
-
**Important**: Before declaring a task complete:
|
|
239
|
-
- Re-read the original requirements
|
|
240
|
-
- Verify your solution meets ALL requirements
|
|
241
|
-
- Run any available tests or validation
|
|
242
|
-
- Check for edge cases
|
|
243
|
-
|
|
244
|
-
Do not skip verification. Incomplete verification leads to incorrect solutions.`;
|
|
245
|
-
}
|
|
246
|
-
classifyAgent(agentId) {
|
|
247
|
-
const id = agentId?.trim().toLowerCase() ?? "";
|
|
248
|
-
if (!id) return "generic";
|
|
249
|
-
if (id.includes("coder") || id.includes("code") || id.includes("developer")) return "coder";
|
|
250
|
-
if (id.includes("data") || id.includes("analyst") || id.includes("analysis")) return "data";
|
|
251
|
-
if (id.includes("writer") || id.includes("writing")) return "writer";
|
|
252
|
-
if (id.includes("research")) return "researcher";
|
|
253
|
-
if (id.includes("creative") || id.includes("design")) return "creative";
|
|
254
|
-
return "generic";
|
|
255
|
-
}
|
|
256
|
-
buildPendingVerificationReminder(sessionKey, agentId) {
|
|
257
|
-
const state = this.getVerificationState(sessionKey);
|
|
258
|
-
const kind = this.classifyAgent(agentId);
|
|
259
|
-
const files = state.changedFiles.length > 0 ? state.changedFiles.slice(0, 12).join(", ") : "(unknown files)";
|
|
260
|
-
const extraFiles = state.changedFiles.length > 12 ? `, and ${state.changedFiles.length - 12} more` : "";
|
|
261
|
-
const profile = this.verificationProfile(kind);
|
|
262
|
-
const lines = [
|
|
263
|
-
`## ${profile.title}`,
|
|
264
|
-
profile.checkLine,
|
|
265
|
-
`${profile.changedLabel}: ${files}${extraFiles}.`,
|
|
266
|
-
state.diffReviewed ? "Diff review: completed with git diff/status." : "Diff review: not recorded yet."
|
|
267
|
-
];
|
|
268
|
-
if (state.lastVerification) {
|
|
269
|
-
const command = state.lastVerification.command ? ` (${state.lastVerification.command})` : "";
|
|
270
|
-
lines.push(state.lastVerification.success ? `Last verification: passed${command}.` : `Last verification: failed${command}.`);
|
|
271
|
-
} else lines.push("Last verification: none recorded.");
|
|
272
|
-
lines.push(profile.finalGuidance);
|
|
273
|
-
return lines.join("\n");
|
|
274
|
-
}
|
|
275
|
-
verificationProfile(kind) {
|
|
276
|
-
switch (kind) {
|
|
277
|
-
case "coder": return {
|
|
278
|
-
title: "Coder Verification State",
|
|
279
|
-
checkLine: "Coder check: source files changed.",
|
|
280
|
-
changedLabel: "Changed source files",
|
|
281
|
-
finalGuidance: "Before final response, inspect the diff and run the smallest meaningful code verification, such as a targeted test, typecheck, lint, or build. If verification cannot run, final response must state why and name the remaining risk."
|
|
282
|
-
};
|
|
283
|
-
case "data": return {
|
|
284
|
-
title: "Data Verification State",
|
|
285
|
-
checkLine: "Data check: analysis files or outputs changed.",
|
|
286
|
-
changedLabel: "Changed files or artifacts",
|
|
287
|
-
finalGuidance: "Before final response, inspect the diff or generated outputs and run the smallest meaningful data validation, such as rerunning the analysis, checking row counts, schemas, filters, joins, units, or output files. If validation cannot run, final response must state why and name the remaining risk."
|
|
288
|
-
};
|
|
289
|
-
case "writer": return {
|
|
290
|
-
title: "Writing Review State",
|
|
291
|
-
checkLine: "Writing check: draft or document files changed.",
|
|
292
|
-
changedLabel: "Changed files or artifacts",
|
|
293
|
-
finalGuidance: "Before final response, inspect the changed artifact for requested content, structure, formatting, placeholders, and obvious inconsistencies. If a review cannot be completed, final response must state why and name the remaining risk."
|
|
294
|
-
};
|
|
295
|
-
case "researcher": return {
|
|
296
|
-
title: "Research Review State",
|
|
297
|
-
checkLine: "Research check: research notes or report files changed.",
|
|
298
|
-
changedLabel: "Changed files or artifacts",
|
|
299
|
-
finalGuidance: "Before final response, inspect the changed artifact and verify citations, source-backed claims, unresolved uncertainty, and formatting. If source or artifact review cannot be completed, final response must state why and name the remaining risk."
|
|
300
|
-
};
|
|
301
|
-
case "creative": return {
|
|
302
|
-
title: "Creative Review State",
|
|
303
|
-
checkLine: "Creative check: creative artifact files changed.",
|
|
304
|
-
changedLabel: "Changed files or artifacts",
|
|
305
|
-
finalGuidance: "Before final response, inspect the changed artifact against the brief, requested format, visual/text quality, and any saved outputs. If review cannot be completed, final response must state why and name the remaining risk."
|
|
306
|
-
};
|
|
307
|
-
default: return {
|
|
308
|
-
title: "Workspace Verification State",
|
|
309
|
-
checkLine: "Workspace check: files changed.",
|
|
310
|
-
changedLabel: "Changed files or artifacts",
|
|
311
|
-
finalGuidance: "Before final response, inspect the changed files and run the smallest meaningful verification for this task. If verification cannot run, final response must state why and name the remaining risk."
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
/**
|
|
316
|
-
* Build warning for excessive file edits (doom loop detection)
|
|
317
|
-
*/
|
|
318
|
-
buildExcessiveEditWarning(filePath, count) {
|
|
319
|
-
return `⚠️ **Pattern Alert**: You have edited "${filePath}" ${count} times.
|
|
320
|
-
|
|
321
|
-
This may indicate:
|
|
322
|
-
- You're fixing symptoms rather than root causes
|
|
323
|
-
- The approach needs reconsideration
|
|
324
|
-
- Requirements may be unclear
|
|
325
|
-
|
|
326
|
-
**Recommendation**:
|
|
327
|
-
- Step back and re-read the original task
|
|
328
|
-
- Consider if there's a better approach
|
|
329
|
-
- Verify you understand the requirements correctly`;
|
|
330
|
-
}
|
|
331
|
-
/**
|
|
332
|
-
* Build pre-completion verification reminder
|
|
333
|
-
*/
|
|
334
|
-
buildPreCompletionReminder(sessionKey) {
|
|
335
|
-
const state = this.getState(sessionKey);
|
|
336
|
-
this.markVerificationRequested(sessionKey);
|
|
337
|
-
return `⏳ **Verification Check**: You've made ${state.turnCount} turns on this task.
|
|
338
|
-
|
|
339
|
-
Before completing:
|
|
340
|
-
1. ✅ Verify your solution matches the original requirements
|
|
341
|
-
2. ✅ Run tests or validation if available
|
|
342
|
-
3. ✅ Check edge cases and error handling
|
|
343
|
-
4. ✅ Review your changes one final time
|
|
344
|
-
|
|
345
|
-
If you're confident, proceed. If unsure, continue refining.`;
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* Get summary of file edits for debugging
|
|
349
|
-
*/
|
|
350
|
-
getEditSummary(sessionKey) {
|
|
351
|
-
const entries = Array.from(this.getState(sessionKey).fileEdits.entries());
|
|
352
|
-
const totalEdits = entries.reduce((sum, [, record]) => sum + record.editCount, 0);
|
|
353
|
-
const topFiles = entries.sort((a, b) => b[1].editCount - a[1].editCount).slice(0, 5).map(([path, record]) => ({
|
|
354
|
-
path,
|
|
355
|
-
count: record.editCount
|
|
356
|
-
}));
|
|
357
|
-
return {
|
|
358
|
-
totalFiles: entries.length,
|
|
359
|
-
totalEdits,
|
|
360
|
-
topFiles
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
/**
|
|
364
|
-
* Update configuration
|
|
365
|
-
*/
|
|
366
|
-
setConfig(config) {
|
|
367
|
-
this.config = {
|
|
368
|
-
...this.config,
|
|
369
|
-
...config
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
/**
|
|
373
|
-
* Get current configuration
|
|
374
|
-
*/
|
|
375
|
-
getConfig() {
|
|
376
|
-
return { ...this.config };
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
//#endregion
|
|
380
|
-
export { SelfVerifyMiddleware };
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Programmatic tool calling (PTC): run sandboxed JS that invokes a subset of agent tools.
|
|
3
|
-
* vm is not a strong security boundary; only trusted models should use this tool.
|
|
4
|
-
*/
|
|
5
|
-
import type { AgentTool } from '@earendil-works/pi-agent-core';
|
|
6
|
-
export declare const SANDBOX_ALLOWED_TOOLS: Set<string>;
|
|
7
|
-
export declare function buildSandboxToolMap(tools: AgentTool<any, any>[]): Map<string, AgentTool<any, any>>;
|
|
8
|
-
export interface ExecuteCodeToolDeps {
|
|
9
|
-
getSandboxToolMap: () => Map<string, AgentTool<any, any>>;
|
|
10
|
-
}
|
|
11
|
-
export declare function createExecuteCodeTool(deps: ExecuteCodeToolDeps): AgentTool;
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import { Type } from "@sinclair/typebox";
|
|
2
|
-
import { Script, createContext } from "node:vm";
|
|
3
|
-
//#region src/agent/tools/execute-code-tool.ts
|
|
4
|
-
/**
|
|
5
|
-
* Programmatic tool calling (PTC): run sandboxed JS that invokes a subset of agent tools.
|
|
6
|
-
* vm is not a strong security boundary; only trusted models should use this tool.
|
|
7
|
-
*/
|
|
8
|
-
/** Default script wall time when `timeout` omitted (30 minutes). */
|
|
9
|
-
const DEFAULT_TIMEOUT_SEC = 1800;
|
|
10
|
-
/** Hard cap for `timeout` parameter (4 hours). */
|
|
11
|
-
const MAX_TIMEOUT_SEC = 14400;
|
|
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.exec_command(cmd, cwd?)\n\nUse console.log() for output; combined stdout/stderr is returned." }),
|
|
14
|
-
timeout: Type.Optional(Type.Number({
|
|
15
|
-
description: "Execution timeout in seconds (default: 1800 = 30m, max: 14400 = 4h)",
|
|
16
|
-
default: DEFAULT_TIMEOUT_SEC
|
|
17
|
-
}))
|
|
18
|
-
});
|
|
19
|
-
const SANDBOX_ALLOWED_TOOLS = new Set([
|
|
20
|
-
"web_search",
|
|
21
|
-
"web_fetch",
|
|
22
|
-
"read_file",
|
|
23
|
-
"write_file",
|
|
24
|
-
"grep",
|
|
25
|
-
"find",
|
|
26
|
-
"exec_command",
|
|
27
|
-
"skills_list",
|
|
28
|
-
"skill_view"
|
|
29
|
-
]);
|
|
30
|
-
const MAX_TIMEOUT_MS = MAX_TIMEOUT_SEC * 1e3;
|
|
31
|
-
const MAX_TOOL_CALLS = 50;
|
|
32
|
-
const MAX_STDOUT_CHARS = 5e4;
|
|
33
|
-
const MAX_STDERR_CHARS = 1e4;
|
|
34
|
-
function stringifyArg(a) {
|
|
35
|
-
if (typeof a === "string") return a;
|
|
36
|
-
try {
|
|
37
|
-
return JSON.stringify(a);
|
|
38
|
-
} catch {
|
|
39
|
-
return String(a);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
function extractTextFromResult(result) {
|
|
43
|
-
return result.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
44
|
-
}
|
|
45
|
-
function buildSandboxToolMap(tools) {
|
|
46
|
-
const m = /* @__PURE__ */ new Map();
|
|
47
|
-
for (const t of tools) if (SANDBOX_ALLOWED_TOOLS.has(t.name)) m.set(t.name, t);
|
|
48
|
-
return m;
|
|
49
|
-
}
|
|
50
|
-
function createToolsApi(getMap, signal) {
|
|
51
|
-
let seq = 0;
|
|
52
|
-
let calls = 0;
|
|
53
|
-
const bump = () => {
|
|
54
|
-
calls += 1;
|
|
55
|
-
if (calls > MAX_TOOL_CALLS) throw new Error(`Exceeded max sandbox tool calls (${MAX_TOOL_CALLS})`);
|
|
56
|
-
};
|
|
57
|
-
const run = async (name, params) => {
|
|
58
|
-
if (signal?.aborted) throw new Error("aborted");
|
|
59
|
-
bump();
|
|
60
|
-
const tool = getMap().get(name);
|
|
61
|
-
if (!tool) throw new Error(`Tool not available in sandbox: ${name}`);
|
|
62
|
-
const id = `ptc-${Date.now()}-${seq++}`;
|
|
63
|
-
return extractTextFromResult(await tool.execute(id, params, signal));
|
|
64
|
-
};
|
|
65
|
-
return {
|
|
66
|
-
web_search: async (query, count) => run("web_search", {
|
|
67
|
-
query: String(query ?? ""),
|
|
68
|
-
...typeof count === "number" && Number.isFinite(count) ? { count } : {}
|
|
69
|
-
}),
|
|
70
|
-
web_fetch: async (url, maxChars) => run("web_fetch", {
|
|
71
|
-
url: String(url ?? ""),
|
|
72
|
-
...typeof maxChars === "number" && Number.isFinite(maxChars) ? { maxChars } : {}
|
|
73
|
-
}),
|
|
74
|
-
read_file: async (path, limit) => run("read_file", {
|
|
75
|
-
path: String(path ?? ""),
|
|
76
|
-
...typeof limit === "number" && Number.isFinite(limit) ? { limit } : {}
|
|
77
|
-
}),
|
|
78
|
-
write_file: async (path, content) => run("write_file", {
|
|
79
|
-
path: String(path ?? ""),
|
|
80
|
-
content: String(content ?? "")
|
|
81
|
-
}),
|
|
82
|
-
grep: async (pattern, opts) => {
|
|
83
|
-
const o = opts && typeof opts === "object" && opts !== null ? opts : {};
|
|
84
|
-
return run("grep", {
|
|
85
|
-
pattern: String(pattern ?? ""),
|
|
86
|
-
...typeof o.path === "string" ? { path: o.path } : {},
|
|
87
|
-
...typeof o.glob === "string" ? { glob: o.glob } : {},
|
|
88
|
-
...typeof o.ignoreCase === "boolean" ? { ignoreCase: o.ignoreCase } : {},
|
|
89
|
-
...typeof o.literal === "boolean" ? { literal: o.literal } : {},
|
|
90
|
-
...typeof o.context === "number" && Number.isFinite(o.context) ? { context: o.context } : {},
|
|
91
|
-
...typeof o.limit === "number" && Number.isFinite(o.limit) ? { limit: o.limit } : {}
|
|
92
|
-
});
|
|
93
|
-
},
|
|
94
|
-
find: async (pattern, opts) => {
|
|
95
|
-
const o = opts && typeof opts === "object" && opts !== null ? opts : {};
|
|
96
|
-
return run("find", {
|
|
97
|
-
pattern: String(pattern ?? ""),
|
|
98
|
-
...typeof o.path === "string" ? { path: o.path } : {},
|
|
99
|
-
...typeof o.limit === "number" && Number.isFinite(o.limit) ? { limit: o.limit } : {}
|
|
100
|
-
});
|
|
101
|
-
},
|
|
102
|
-
exec_command: async (cmd, cwd) => run("exec_command", {
|
|
103
|
-
cmd: String(cmd ?? ""),
|
|
104
|
-
...typeof cwd === "string" && cwd.trim() ? { cwd } : {}
|
|
105
|
-
})
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
async function runSandboxedScript(code, sandbox, timeoutMs, signal) {
|
|
109
|
-
const context = createContext(sandbox, { name: "execute_code" });
|
|
110
|
-
const runPromise = new Script(`(async () => {\n${code}\n})()`, { filename: "execute_code.vm" }).runInContext(context);
|
|
111
|
-
let timeoutId;
|
|
112
|
-
const timeoutPromise = new Promise((_, rej) => {
|
|
113
|
-
timeoutId = setTimeout(() => rej(/* @__PURE__ */ new Error(`Script timed out after ${Math.round(timeoutMs / 1e3)}s`)), timeoutMs);
|
|
114
|
-
});
|
|
115
|
-
const abortPromise = signal && new Promise((_, rej) => {
|
|
116
|
-
if (signal.aborted) {
|
|
117
|
-
rej(/* @__PURE__ */ new Error("aborted"));
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
signal.addEventListener("abort", () => rej(/* @__PURE__ */ new Error("aborted")), { once: true });
|
|
121
|
-
});
|
|
122
|
-
const racers = [runPromise, timeoutPromise];
|
|
123
|
-
if (abortPromise) racers.push(abortPromise);
|
|
124
|
-
try {
|
|
125
|
-
await Promise.race(racers);
|
|
126
|
-
} finally {
|
|
127
|
-
if (timeoutId !== void 0) clearTimeout(timeoutId);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
function createExecuteCodeTool(deps) {
|
|
131
|
-
return {
|
|
132
|
-
name: "execute_code",
|
|
133
|
-
label: "⚡ Execute Code",
|
|
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.",
|
|
135
|
-
parameters: ExecuteCodeSchema,
|
|
136
|
-
async execute(_toolCallId, params, signal) {
|
|
137
|
-
const p = params;
|
|
138
|
-
const sec = p.timeout ?? DEFAULT_TIMEOUT_SEC;
|
|
139
|
-
const timeoutMs = Math.min(Math.max(1, Number.isFinite(sec) ? sec : DEFAULT_TIMEOUT_SEC) * 1e3, MAX_TIMEOUT_MS);
|
|
140
|
-
const stdout = [];
|
|
141
|
-
const stderr = [];
|
|
142
|
-
const sandbox = {
|
|
143
|
-
tools: createToolsApi(deps.getSandboxToolMap, signal),
|
|
144
|
-
Promise,
|
|
145
|
-
JSON,
|
|
146
|
-
Math,
|
|
147
|
-
Date,
|
|
148
|
-
Array,
|
|
149
|
-
Object,
|
|
150
|
-
String,
|
|
151
|
-
Number,
|
|
152
|
-
Boolean,
|
|
153
|
-
RegExp,
|
|
154
|
-
Map,
|
|
155
|
-
Set,
|
|
156
|
-
Error,
|
|
157
|
-
TypeError,
|
|
158
|
-
RangeError,
|
|
159
|
-
parseInt,
|
|
160
|
-
parseFloat,
|
|
161
|
-
isNaN,
|
|
162
|
-
isFinite,
|
|
163
|
-
console: {
|
|
164
|
-
log: (...args) => {
|
|
165
|
-
stdout.push(args.map(stringifyArg).join(" "));
|
|
166
|
-
},
|
|
167
|
-
error: (...args) => {
|
|
168
|
-
stderr.push(args.map(stringifyArg).join(" "));
|
|
169
|
-
},
|
|
170
|
-
warn: (...args) => {
|
|
171
|
-
stderr.push(args.map(stringifyArg).join(" "));
|
|
172
|
-
}
|
|
173
|
-
},
|
|
174
|
-
setTimeout,
|
|
175
|
-
clearTimeout
|
|
176
|
-
};
|
|
177
|
-
try {
|
|
178
|
-
await runSandboxedScript(p.code, sandbox, timeoutMs, signal);
|
|
179
|
-
let out = stdout.join("\n");
|
|
180
|
-
if (out.length > MAX_STDOUT_CHARS) out = `${out.slice(0, MAX_STDOUT_CHARS)}\n...(truncated)`;
|
|
181
|
-
const parts = [];
|
|
182
|
-
if (out.length > 0) parts.push(out);
|
|
183
|
-
if (stderr.length > 0) {
|
|
184
|
-
let err = stderr.join("\n");
|
|
185
|
-
if (err.length > MAX_STDERR_CHARS) err = `${err.slice(0, MAX_STDERR_CHARS)}\n...(truncated)`;
|
|
186
|
-
parts.push(`\nSTDERR:\n${err}`);
|
|
187
|
-
}
|
|
188
|
-
return {
|
|
189
|
-
content: [{
|
|
190
|
-
type: "text",
|
|
191
|
-
text: parts.join("") || "(no output)"
|
|
192
|
-
}],
|
|
193
|
-
details: { exitCode: 0 }
|
|
194
|
-
};
|
|
195
|
-
} catch (error) {
|
|
196
|
-
return {
|
|
197
|
-
content: [{
|
|
198
|
-
type: "text",
|
|
199
|
-
text: `Execution failed: ${error instanceof Error ? error.message : String(error)}`
|
|
200
|
-
}],
|
|
201
|
-
details: { exitCode: 1 }
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
//#endregion
|
|
208
|
-
export { SANDBOX_ALLOWED_TOOLS, buildSandboxToolMap, createExecuteCodeTool };
|