@code-yeongyu/senpi 2026.5.13 → 2026.5.15-2
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/CHANGELOG.md +1109 -1150
- package/README.md +1 -2
- package/dist/core/agent-session.d.ts +9 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +121 -12
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +1 -1
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +2 -2
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/dynamic-prompt/verification.d.ts +31 -0
- package/dist/core/dynamic-prompt/verification.d.ts.map +1 -1
- package/dist/core/dynamic-prompt/verification.js +41 -0
- package/dist/core/dynamic-prompt/verification.js.map +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +8 -1
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/extensions/builtin/anthropic-web-search/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/anthropic-web-search/index.js +20 -0
- package/dist/core/extensions/builtin/anthropic-web-search/index.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/index.js +157 -29
- package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/openai-remote.d.ts +197 -0
- package/dist/core/extensions/builtin/compaction/openai-remote.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/openai-remote.js +690 -0
- package/dist/core/extensions/builtin/compaction/openai-remote.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/prompts.d.ts +3 -3
- package/dist/core/extensions/builtin/compaction/prompts.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/prompts.js +0 -22
- package/dist/core/extensions/builtin/compaction/prompts.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/repair-tool-pairs.d.ts +4 -0
- package/dist/core/extensions/builtin/compaction/repair-tool-pairs.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/repair-tool-pairs.js +48 -0
- package/dist/core/extensions/builtin/compaction/repair-tool-pairs.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculative.d.ts +3 -1
- package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.js +82 -33
- package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/todo-bridge.d.ts +8 -0
- package/dist/core/extensions/builtin/compaction/todo-bridge.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/todo-bridge.js +12 -6
- package/dist/core/extensions/builtin/compaction/todo-bridge.js.map +1 -1
- package/dist/core/extensions/builtin/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/index.js +0 -20
- package/dist/core/extensions/builtin/index.js.map +1 -1
- package/dist/core/extensions/builtin/openai-web-search/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/openai-web-search/index.js +28 -0
- package/dist/core/extensions/builtin/openai-web-search/index.js.map +1 -1
- package/dist/core/extensions/builtin/permission-system/prompt.d.ts.map +1 -1
- package/dist/core/extensions/builtin/permission-system/prompt.js +0 -5
- package/dist/core/extensions/builtin/permission-system/prompt.js.map +1 -1
- package/dist/core/extensions/builtin/system-messages.d.ts +7 -7
- package/dist/core/extensions/builtin/system-messages.d.ts.map +1 -1
- package/dist/core/extensions/builtin/system-messages.js +10 -10
- package/dist/core/extensions/builtin/system-messages.js.map +1 -1
- package/dist/core/extensions/builtin/todotools/continuation/prompt.d.ts +1 -1
- package/dist/core/extensions/builtin/todotools/continuation/prompt.d.ts.map +1 -1
- package/dist/core/extensions/builtin/todotools/continuation/prompt.js +1 -1
- package/dist/core/extensions/builtin/todotools/continuation/prompt.js.map +1 -1
- package/dist/core/extensions/builtin/todotools/state.d.ts +1 -1
- package/dist/core/extensions/builtin/todotools/state.d.ts.map +1 -1
- package/dist/core/extensions/builtin/todotools/state.js +2 -2
- package/dist/core/extensions/builtin/todotools/state.js.map +1 -1
- package/dist/core/extensions/builtin/todotools/system-messages.d.ts +3 -3
- package/dist/core/extensions/builtin/todotools/system-messages.d.ts.map +1 -1
- package/dist/core/extensions/builtin/todotools/system-messages.js +6 -6
- package/dist/core/extensions/builtin/todotools/system-messages.js.map +1 -1
- package/dist/core/extensions/builtin/tool-pair-guard/index.d.ts +1 -1
- package/dist/core/extensions/builtin/tool-pair-guard/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/tool-pair-guard/index.js +8 -4
- package/dist/core/extensions/builtin/tool-pair-guard/index.js.map +1 -1
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.d.ts +3 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.d.ts.map +1 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.js +89 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.js.map +1 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.d.ts +3 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.d.ts.map +1 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.js +122 -0
- package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.js.map +1 -0
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +2 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +18 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +22 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/messages.d.ts +3 -3
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +5 -10
- package/dist/core/messages.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +0 -9
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +2 -2
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +8 -23
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +1 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +0 -5
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/thinking-levels.d.ts +6 -0
- package/dist/core/thinking-levels.d.ts.map +1 -0
- package/dist/core/thinking-levels.js +36 -0
- package/dist/core/thinking-levels.js.map +1 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +15 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +3 -2
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +0 -3
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +3 -22
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +1 -1
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +20 -2
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +2 -0
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +6 -1
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +3 -1
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +23 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +139 -54
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +2 -2
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +3 -11
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/provider-native-rendering.d.ts +5 -0
- package/dist/modes/provider-native-rendering.d.ts.map +1 -0
- package/dist/modes/provider-native-rendering.js +247 -0
- package/dist/modes/provider-native-rendering.js.map +1 -0
- package/dist/utils/ansi.d.ts +2 -0
- package/dist/utils/ansi.d.ts.map +1 -0
- package/dist/utils/ansi.js +52 -0
- package/dist/utils/ansi.js.map +1 -0
- package/dist/utils/html.d.ts +7 -0
- package/dist/utils/html.d.ts.map +1 -0
- package/dist/utils/html.js +40 -0
- package/dist/utils/html.js.map +1 -0
- package/dist/utils/mime.d.ts +1 -0
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/mime.js +59 -16
- package/dist/utils/mime.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts +12 -0
- package/dist/utils/syntax-highlight.d.ts.map +1 -0
- package/dist/utils/syntax-highlight.js +118 -0
- package/dist/utils/syntax-highlight.js.map +1 -0
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +76 -7
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/extensions.md +0 -1
- package/docs/index.md +0 -1
- package/docs/sdk.md +25 -44
- package/docs/settings.md +1 -29
- package/docs/termux.md +2 -2
- package/docs/usage.md +1 -1
- package/examples/README.md +1 -1
- package/examples/extensions/README.md +0 -1
- package/examples/extensions/overlay-qa-tests.ts +1 -1
- package/examples/sdk/01-minimal.ts +14 -10
- package/examples/sdk/02-custom-model.ts +12 -8
- package/examples/sdk/03-custom-prompt.ts +24 -16
- package/examples/sdk/04-skills.ts +2 -2
- package/examples/sdk/05-tools.ts +8 -4
- package/examples/sdk/06-extensions.ts +11 -7
- package/examples/sdk/07-context-files.ts +2 -2
- package/examples/sdk/08-prompt-templates.ts +2 -2
- package/examples/sdk/09-api-keys-and-oauth.ts +8 -4
- package/examples/sdk/10-settings.ts +4 -4
- package/examples/sdk/11-sessions.ts +4 -0
- package/examples/sdk/12-full-control.ts +11 -7
- package/examples/sdk/README.md +6 -9
- package/package.json +7 -12
- package/dist/core/extensions/builtin/anthropic-code-execution/index.d.ts +0 -7
- package/dist/core/extensions/builtin/anthropic-code-execution/index.d.ts.map +0 -1
- package/dist/core/extensions/builtin/anthropic-code-execution/index.js +0 -79
- package/dist/core/extensions/builtin/anthropic-code-execution/index.js.map +0 -1
- package/dist/core/extensions/builtin/anthropic-computer-use/index.d.ts +0 -53
- package/dist/core/extensions/builtin/anthropic-computer-use/index.d.ts.map +0 -1
- package/dist/core/extensions/builtin/anthropic-computer-use/index.js +0 -676
- package/dist/core/extensions/builtin/anthropic-computer-use/index.js.map +0 -1
- package/dist/core/extensions/builtin/anthropic-text-editor/index.d.ts +0 -25
- package/dist/core/extensions/builtin/anthropic-text-editor/index.d.ts.map +0 -1
- package/dist/core/extensions/builtin/anthropic-text-editor/index.js +0 -244
- package/dist/core/extensions/builtin/anthropic-text-editor/index.js.map +0 -1
- package/dist/core/extensions/builtin/anthropic-tool-search/index.d.ts +0 -6
- package/dist/core/extensions/builtin/anthropic-tool-search/index.d.ts.map +0 -1
- package/dist/core/extensions/builtin/anthropic-tool-search/index.js +0 -112
- package/dist/core/extensions/builtin/anthropic-tool-search/index.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/cancel-tool.d.ts +0 -10
- package/dist/core/extensions/builtin/background-task/cancel-tool.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/cancel-tool.js +0 -109
- package/dist/core/extensions/builtin/background-task/cancel-tool.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/index.d.ts +0 -3
- package/dist/core/extensions/builtin/background-task/index.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/index.js +0 -207
- package/dist/core/extensions/builtin/background-task/index.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/manager.d.ts +0 -17
- package/dist/core/extensions/builtin/background-task/manager.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/manager.js +0 -114
- package/dist/core/extensions/builtin/background-task/manager.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/notification.d.ts +0 -22
- package/dist/core/extensions/builtin/background-task/notification.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/notification.js +0 -105
- package/dist/core/extensions/builtin/background-task/notification.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/output-tool.d.ts +0 -11
- package/dist/core/extensions/builtin/background-task/output-tool.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/output-tool.js +0 -127
- package/dist/core/extensions/builtin/background-task/output-tool.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/spawner.d.ts +0 -8
- package/dist/core/extensions/builtin/background-task/spawner.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/spawner.js +0 -207
- package/dist/core/extensions/builtin/background-task/spawner.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/task-tool.d.ts +0 -20
- package/dist/core/extensions/builtin/background-task/task-tool.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/task-tool.js +0 -302
- package/dist/core/extensions/builtin/background-task/task-tool.js.map +0 -1
- package/dist/core/extensions/builtin/background-task/types.d.ts +0 -72
- package/dist/core/extensions/builtin/background-task/types.d.ts.map +0 -1
- package/dist/core/extensions/builtin/background-task/types.js +0 -32
- package/dist/core/extensions/builtin/background-task/types.js.map +0 -1
- package/dist/core/extensions/builtin/google-code-execution/index.d.ts +0 -7
- package/dist/core/extensions/builtin/google-code-execution/index.d.ts.map +0 -1
- package/dist/core/extensions/builtin/google-code-execution/index.js +0 -73
- package/dist/core/extensions/builtin/google-code-execution/index.js.map +0 -1
- package/dist/core/extensions/builtin/google-google-search/index.d.ts +0 -7
- package/dist/core/extensions/builtin/google-google-search/index.d.ts.map +0 -1
- package/dist/core/extensions/builtin/google-google-search/index.js +0 -83
- package/dist/core/extensions/builtin/google-google-search/index.js.map +0 -1
- package/dist/core/extensions/builtin/google-url-context/index.d.ts +0 -7
- package/dist/core/extensions/builtin/google-url-context/index.d.ts.map +0 -1
- package/dist/core/extensions/builtin/google-url-context/index.js +0 -82
- package/dist/core/extensions/builtin/google-url-context/index.js.map +0 -1
- package/dist/core/extensions/builtin/openai-api-parallel-tool-calls/index.d.ts +0 -6
- package/dist/core/extensions/builtin/openai-api-parallel-tool-calls/index.d.ts.map +0 -1
- package/dist/core/extensions/builtin/openai-api-parallel-tool-calls/index.js +0 -57
- package/dist/core/extensions/builtin/openai-api-parallel-tool-calls/index.js.map +0 -1
- package/dist/core/extensions/builtin/openai-code-interpreter/index.d.ts +0 -10
- package/dist/core/extensions/builtin/openai-code-interpreter/index.d.ts.map +0 -1
- package/dist/core/extensions/builtin/openai-code-interpreter/index.js +0 -95
- package/dist/core/extensions/builtin/openai-code-interpreter/index.js.map +0 -1
- package/docs/agents.md +0 -348
- package/examples/extensions/subagent/README.md +0 -172
- package/examples/extensions/subagent/agents/planner.md +0 -37
- package/examples/extensions/subagent/agents/reviewer.md +0 -35
- package/examples/extensions/subagent/agents/scout.md +0 -50
- package/examples/extensions/subagent/agents/worker.md +0 -24
- package/examples/extensions/subagent/agents.ts +0 -126
- package/examples/extensions/subagent/index.ts +0 -987
- package/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
- package/examples/extensions/subagent/prompts/implement.md +0 -10
- package/examples/extensions/subagent/prompts/scout-and-plan.md +0 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/senpi",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.5.15-2",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"piConfig": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"scripts": {
|
|
32
32
|
"clean": "shx rm -rf dist",
|
|
33
33
|
"dev": "tsgo -p tsconfig.build.json --watch --preserveWatchOutput",
|
|
34
|
-
"build": "tsgo -p tsconfig.build.json && shx chmod +x dist/cli.js && shx cp dist/cli.js dist/senpi && shx chmod +x dist/senpi",
|
|
34
|
+
"build": "tsgo -p tsconfig.build.json && npm run copy-assets && shx chmod +x dist/cli.js && shx cp dist/cli.js dist/senpi && shx chmod +x dist/senpi",
|
|
35
35
|
"build:binary": "npm --prefix ../tui run build && npm --prefix ../ai run build && npm --prefix ../agent run build && npm run build && bun build --compile ./dist/bun/cli.js --outfile dist/pi && npm run copy-binary-assets",
|
|
36
36
|
"copy-assets": "shx mkdir -p dist/modes/interactive/theme && shx cp src/modes/interactive/theme/*.json dist/modes/interactive/theme/ && shx mkdir -p dist/modes/interactive/assets && shx cp src/modes/interactive/assets/*.png dist/modes/interactive/assets/ && shx mkdir -p dist/core/export-html/vendor && shx cp src/core/export-html/template.html src/core/export-html/template.css src/core/export-html/template.js dist/core/export-html/ && shx cp src/core/export-html/vendor/*.js dist/core/export-html/vendor/",
|
|
37
37
|
"copy-binary-assets": "shx cp package.json dist/ && shx cp README.md dist/ && shx cp CHANGELOG.md dist/ && shx mkdir -p dist/theme && shx cp src/modes/interactive/theme/*.json dist/theme/ && shx mkdir -p dist/assets && shx cp src/modes/interactive/assets/*.png dist/assets/ && shx mkdir -p dist/export-html/vendor && shx cp src/core/export-html/template.html dist/export-html/ && shx cp src/core/export-html/vendor/*.js dist/export-html/vendor/ && shx cp -r docs dist/ && shx cp -r examples dist/ && shx cp ../../node_modules/@silvia-odwyer/photon-node/photon_rs_bg.wasm dist/",
|
|
@@ -40,26 +40,21 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@anthropic-ai/sdk": "^0.91.1",
|
|
43
|
-
"@earendil-works/pi-agent-core": "^2026.
|
|
44
|
-
"@earendil-works/pi-ai": "^2026.
|
|
45
|
-
"@earendil-works/pi-tui": "^2026.
|
|
43
|
+
"@earendil-works/pi-agent-core": "^2026.5.15-2",
|
|
44
|
+
"@earendil-works/pi-ai": "^2026.5.15-2",
|
|
45
|
+
"@earendil-works/pi-tui": "^2026.5.15-2",
|
|
46
46
|
"@silvia-odwyer/photon-node": "^0.3.4",
|
|
47
47
|
"chalk": "^5.5.0",
|
|
48
|
-
"cli-highlight": "^2.1.11",
|
|
49
48
|
"diff": "^8.0.2",
|
|
50
|
-
"extract-zip": "^2.0.1",
|
|
51
|
-
"file-type": "^21.1.1",
|
|
52
49
|
"glob": "^13.0.1",
|
|
50
|
+
"highlight.js": "^10.7.3",
|
|
53
51
|
"hosted-git-info": "^9.0.2",
|
|
54
52
|
"ignore": "^7.0.5",
|
|
55
53
|
"jiti": "^2.7.0",
|
|
56
|
-
"marked": "^15.0.12",
|
|
57
54
|
"minimatch": "^10.2.3",
|
|
58
55
|
"proper-lockfile": "^4.1.2",
|
|
59
|
-
"strip-ansi": "^7.1.0",
|
|
60
56
|
"typebox": "^1.1.24",
|
|
61
57
|
"undici": "^7.19.1",
|
|
62
|
-
"uuid": "^14.0.0",
|
|
63
58
|
"yaml": "^2.8.2"
|
|
64
59
|
},
|
|
65
60
|
"overrides": {
|
|
@@ -97,6 +92,6 @@
|
|
|
97
92
|
"directory": "packages/coding-agent"
|
|
98
93
|
},
|
|
99
94
|
"engines": {
|
|
100
|
-
"node": ">=
|
|
95
|
+
"node": ">=24.0.0"
|
|
101
96
|
}
|
|
102
97
|
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Api } from "@earendil-works/pi-ai";
|
|
2
|
-
import type { ExtensionAPI } from "../../types.js";
|
|
3
|
-
export declare function isCodeExecutionEnabled(): boolean;
|
|
4
|
-
export declare function addAnthropicCodeExecutionToPayload(api: Api | undefined, payload: unknown): unknown;
|
|
5
|
-
export declare const ANTHROPIC_CODE_EXECUTION_SECTION = "\n## Code Execution\n\nThe native code_execution tool is available in this session. The model\nruns Python (and shell commands via the bash subtool) inside an\nAnthropic-managed sandbox container. Prefer code_execution for\nnumerical work, file analysis, and one-off computations when explicit\nresults are needed.\n";
|
|
6
|
-
export default function anthropicCodeExecutionExtension(pi: ExtensionAPI): void;
|
|
7
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/anthropic-code-execution/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAiCnD,wBAAgB,sBAAsB,IAAI,OAAO,CAQhD;AAED,wBAAgB,kCAAkC,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAwBlG;AAED,eAAO,MAAM,gCAAgC,iUAQ5C,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,+BAA+B,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAkB9E","sourcesContent":["import type { Api } from \"@earendil-works/pi-ai\";\nimport type { ExtensionAPI } from \"../../types.js\";\n\ntype ToolDefinition = Record<string, unknown>;\n\nconst CODE_EXECUTION_ENV = \"PI_ANTHROPIC_CODE_EXECUTION\";\nconst CODE_EXECUTION_TOOL = {\n\ttype: \"code_execution_20250825\",\n\tname: \"code_execution\",\n} as const;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction isCodeExecutionType(value: unknown): value is string {\n\treturn typeof value === \"string\" && value.startsWith(\"code_execution_\");\n}\n\nfunction sanitizeTools(tools: unknown[]): ToolDefinition[] {\n\tconst sanitizedTools: ToolDefinition[] = [];\n\tfor (const tool of tools) {\n\t\tif (!isRecord(tool)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst shouldStripFunctionVariant = tool.name === \"code_execution\" && !isCodeExecutionType(tool.type);\n\t\tif (!shouldStripFunctionVariant) {\n\t\t\tsanitizedTools.push(tool);\n\t\t}\n\t}\n\treturn sanitizedTools;\n}\n\nexport function isCodeExecutionEnabled(): boolean {\n\tconst value = process.env[CODE_EXECUTION_ENV];\n\tif (!value) {\n\t\treturn false;\n\t}\n\n\tconst normalized = value.trim().toLowerCase();\n\treturn normalized === \"1\" || normalized === \"true\" || normalized === \"yes\" || normalized === \"on\";\n}\n\nexport function addAnthropicCodeExecutionToPayload(api: Api | undefined, payload: unknown): unknown {\n\tif (api !== \"anthropic-messages\") {\n\t\treturn payload;\n\t}\n\n\tif (!isCodeExecutionEnabled()) {\n\t\treturn payload;\n\t}\n\n\tif (!isRecord(payload)) {\n\t\treturn payload;\n\t}\n\n\tconst tools = Array.isArray(payload.tools) ? payload.tools : [];\n\tconst sanitizedTools = sanitizeTools(tools);\n\tconst hasNativeCodeExecution = sanitizedTools.some((tool) => isCodeExecutionType(tool.type));\n\tif (!hasNativeCodeExecution) {\n\t\tsanitizedTools.push(CODE_EXECUTION_TOOL);\n\t}\n\n\treturn {\n\t\t...payload,\n\t\ttools: sanitizedTools,\n\t};\n}\n\nexport const ANTHROPIC_CODE_EXECUTION_SECTION = `\n## Code Execution\n\nThe native code_execution tool is available in this session. The model\nruns Python (and shell commands via the bash subtool) inside an\nAnthropic-managed sandbox container. Prefer code_execution for\nnumerical work, file analysis, and one-off computations when explicit\nresults are needed.\n`;\n\nexport default function anthropicCodeExecutionExtension(pi: ExtensionAPI): void {\n\tpi.on(\"before_provider_request\", (event, ctx) => {\n\t\treturn addAnthropicCodeExecutionToPayload(ctx.model?.api, event.payload);\n\t});\n\n\tpi.on(\"before_agent_start\", async (event, ctx) => {\n\t\tif (ctx.model?.api !== \"anthropic-messages\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!isCodeExecutionEnabled()) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn {\n\t\t\tsystemPrompt: `${event.systemPrompt}\\n${ANTHROPIC_CODE_EXECUTION_SECTION}`,\n\t\t};\n\t});\n}\n"]}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
const CODE_EXECUTION_ENV = "PI_ANTHROPIC_CODE_EXECUTION";
|
|
2
|
-
const CODE_EXECUTION_TOOL = {
|
|
3
|
-
type: "code_execution_20250825",
|
|
4
|
-
name: "code_execution",
|
|
5
|
-
};
|
|
6
|
-
function isRecord(value) {
|
|
7
|
-
return typeof value === "object" && value !== null;
|
|
8
|
-
}
|
|
9
|
-
function isCodeExecutionType(value) {
|
|
10
|
-
return typeof value === "string" && value.startsWith("code_execution_");
|
|
11
|
-
}
|
|
12
|
-
function sanitizeTools(tools) {
|
|
13
|
-
const sanitizedTools = [];
|
|
14
|
-
for (const tool of tools) {
|
|
15
|
-
if (!isRecord(tool)) {
|
|
16
|
-
continue;
|
|
17
|
-
}
|
|
18
|
-
const shouldStripFunctionVariant = tool.name === "code_execution" && !isCodeExecutionType(tool.type);
|
|
19
|
-
if (!shouldStripFunctionVariant) {
|
|
20
|
-
sanitizedTools.push(tool);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return sanitizedTools;
|
|
24
|
-
}
|
|
25
|
-
export function isCodeExecutionEnabled() {
|
|
26
|
-
const value = process.env[CODE_EXECUTION_ENV];
|
|
27
|
-
if (!value) {
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
const normalized = value.trim().toLowerCase();
|
|
31
|
-
return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
|
|
32
|
-
}
|
|
33
|
-
export function addAnthropicCodeExecutionToPayload(api, payload) {
|
|
34
|
-
if (api !== "anthropic-messages") {
|
|
35
|
-
return payload;
|
|
36
|
-
}
|
|
37
|
-
if (!isCodeExecutionEnabled()) {
|
|
38
|
-
return payload;
|
|
39
|
-
}
|
|
40
|
-
if (!isRecord(payload)) {
|
|
41
|
-
return payload;
|
|
42
|
-
}
|
|
43
|
-
const tools = Array.isArray(payload.tools) ? payload.tools : [];
|
|
44
|
-
const sanitizedTools = sanitizeTools(tools);
|
|
45
|
-
const hasNativeCodeExecution = sanitizedTools.some((tool) => isCodeExecutionType(tool.type));
|
|
46
|
-
if (!hasNativeCodeExecution) {
|
|
47
|
-
sanitizedTools.push(CODE_EXECUTION_TOOL);
|
|
48
|
-
}
|
|
49
|
-
return {
|
|
50
|
-
...payload,
|
|
51
|
-
tools: sanitizedTools,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
export const ANTHROPIC_CODE_EXECUTION_SECTION = `
|
|
55
|
-
## Code Execution
|
|
56
|
-
|
|
57
|
-
The native code_execution tool is available in this session. The model
|
|
58
|
-
runs Python (and shell commands via the bash subtool) inside an
|
|
59
|
-
Anthropic-managed sandbox container. Prefer code_execution for
|
|
60
|
-
numerical work, file analysis, and one-off computations when explicit
|
|
61
|
-
results are needed.
|
|
62
|
-
`;
|
|
63
|
-
export default function anthropicCodeExecutionExtension(pi) {
|
|
64
|
-
pi.on("before_provider_request", (event, ctx) => {
|
|
65
|
-
return addAnthropicCodeExecutionToPayload(ctx.model?.api, event.payload);
|
|
66
|
-
});
|
|
67
|
-
pi.on("before_agent_start", async (event, ctx) => {
|
|
68
|
-
if (ctx.model?.api !== "anthropic-messages") {
|
|
69
|
-
return undefined;
|
|
70
|
-
}
|
|
71
|
-
if (!isCodeExecutionEnabled()) {
|
|
72
|
-
return undefined;
|
|
73
|
-
}
|
|
74
|
-
return {
|
|
75
|
-
systemPrompt: `${event.systemPrompt}\n${ANTHROPIC_CODE_EXECUTION_SECTION}`,
|
|
76
|
-
};
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/anthropic-code-execution/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Api } from \"@earendil-works/pi-ai\";\nimport type { ExtensionAPI } from \"../../types.js\";\n\ntype ToolDefinition = Record<string, unknown>;\n\nconst CODE_EXECUTION_ENV = \"PI_ANTHROPIC_CODE_EXECUTION\";\nconst CODE_EXECUTION_TOOL = {\n\ttype: \"code_execution_20250825\",\n\tname: \"code_execution\",\n} as const;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction isCodeExecutionType(value: unknown): value is string {\n\treturn typeof value === \"string\" && value.startsWith(\"code_execution_\");\n}\n\nfunction sanitizeTools(tools: unknown[]): ToolDefinition[] {\n\tconst sanitizedTools: ToolDefinition[] = [];\n\tfor (const tool of tools) {\n\t\tif (!isRecord(tool)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst shouldStripFunctionVariant = tool.name === \"code_execution\" && !isCodeExecutionType(tool.type);\n\t\tif (!shouldStripFunctionVariant) {\n\t\t\tsanitizedTools.push(tool);\n\t\t}\n\t}\n\treturn sanitizedTools;\n}\n\nexport function isCodeExecutionEnabled(): boolean {\n\tconst value = process.env[CODE_EXECUTION_ENV];\n\tif (!value) {\n\t\treturn false;\n\t}\n\n\tconst normalized = value.trim().toLowerCase();\n\treturn normalized === \"1\" || normalized === \"true\" || normalized === \"yes\" || normalized === \"on\";\n}\n\nexport function addAnthropicCodeExecutionToPayload(api: Api | undefined, payload: unknown): unknown {\n\tif (api !== \"anthropic-messages\") {\n\t\treturn payload;\n\t}\n\n\tif (!isCodeExecutionEnabled()) {\n\t\treturn payload;\n\t}\n\n\tif (!isRecord(payload)) {\n\t\treturn payload;\n\t}\n\n\tconst tools = Array.isArray(payload.tools) ? payload.tools : [];\n\tconst sanitizedTools = sanitizeTools(tools);\n\tconst hasNativeCodeExecution = sanitizedTools.some((tool) => isCodeExecutionType(tool.type));\n\tif (!hasNativeCodeExecution) {\n\t\tsanitizedTools.push(CODE_EXECUTION_TOOL);\n\t}\n\n\treturn {\n\t\t...payload,\n\t\ttools: sanitizedTools,\n\t};\n}\n\nexport const ANTHROPIC_CODE_EXECUTION_SECTION = `\n## Code Execution\n\nThe native code_execution tool is available in this session. The model\nruns Python (and shell commands via the bash subtool) inside an\nAnthropic-managed sandbox container. Prefer code_execution for\nnumerical work, file analysis, and one-off computations when explicit\nresults are needed.\n`;\n\nexport default function anthropicCodeExecutionExtension(pi: ExtensionAPI): void {\n\tpi.on(\"before_provider_request\", (event, ctx) => {\n\t\treturn addAnthropicCodeExecutionToPayload(ctx.model?.api, event.payload);\n\t});\n\n\tpi.on(\"before_agent_start\", async (event, ctx) => {\n\t\tif (ctx.model?.api !== \"anthropic-messages\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!isCodeExecutionEnabled()) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn {\n\t\t\tsystemPrompt: `${event.systemPrompt}\\n${ANTHROPIC_CODE_EXECUTION_SECTION}`,\n\t\t};\n\t});\n}\n"]}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import type { Api, TextContent } from "@earendil-works/pi-ai";
|
|
2
|
-
import { type Static, Type } from "typebox";
|
|
3
|
-
import type { ExtensionAPI } from "../../types.js";
|
|
4
|
-
export declare const computerSchema: Type.TObject<{
|
|
5
|
-
action: Type.TUnion<[Type.TLiteral<"screenshot">, Type.TLiteral<"key">, Type.TLiteral<"type">, Type.TLiteral<"mouse_move">, Type.TLiteral<"left_click">, Type.TLiteral<"right_click">, Type.TLiteral<"middle_click">, Type.TLiteral<"double_click">, Type.TLiteral<"triple_click">, Type.TLiteral<"left_click_drag">, Type.TLiteral<"cursor_position">, Type.TLiteral<"left_mouse_down">, Type.TLiteral<"left_mouse_up">, Type.TLiteral<"scroll">, Type.TLiteral<"hold_key">, Type.TLiteral<"wait">]>;
|
|
6
|
-
coordinate: Type.TOptional<Type.TArray<Type.TNumber>>;
|
|
7
|
-
start_coordinate: Type.TOptional<Type.TArray<Type.TNumber>>;
|
|
8
|
-
text: Type.TOptional<Type.TString>;
|
|
9
|
-
key: Type.TOptional<Type.TString>;
|
|
10
|
-
scroll_direction: Type.TOptional<Type.TUnion<[Type.TLiteral<"up">, Type.TLiteral<"down">, Type.TLiteral<"left">, Type.TLiteral<"right">]>>;
|
|
11
|
-
scroll_amount: Type.TOptional<Type.TNumber>;
|
|
12
|
-
duration: Type.TOptional<Type.TNumber>;
|
|
13
|
-
}>;
|
|
14
|
-
export type ComputerToolInput = Static<typeof computerSchema>;
|
|
15
|
-
export type ComputerResult = {
|
|
16
|
-
content: Array<TextContent | {
|
|
17
|
-
type: "image";
|
|
18
|
-
data: string;
|
|
19
|
-
mimeType: "image/png";
|
|
20
|
-
}>;
|
|
21
|
-
isError?: boolean;
|
|
22
|
-
};
|
|
23
|
-
export interface ComputerOperations {
|
|
24
|
-
screenshot(): Promise<{
|
|
25
|
-
base64: string;
|
|
26
|
-
}>;
|
|
27
|
-
cursorPosition(): Promise<{
|
|
28
|
-
x: number;
|
|
29
|
-
y: number;
|
|
30
|
-
}>;
|
|
31
|
-
mouseMove(x: number, y: number): Promise<void>;
|
|
32
|
-
click(button: "left" | "right" | "middle", x?: number, y?: number, modifier?: string): Promise<void>;
|
|
33
|
-
doubleClick(x?: number, y?: number): Promise<void>;
|
|
34
|
-
tripleClick(x?: number, y?: number): Promise<void>;
|
|
35
|
-
drag(startX: number, startY: number, endX: number, endY: number): Promise<void>;
|
|
36
|
-
mouseDown(button: "left", x?: number, y?: number): Promise<void>;
|
|
37
|
-
mouseUp(button: "left", x?: number, y?: number): Promise<void>;
|
|
38
|
-
scroll(direction: "up" | "down" | "left" | "right", amount: number, x?: number, y?: number, modifier?: string): Promise<void>;
|
|
39
|
-
keyPress(combo: string): Promise<void>;
|
|
40
|
-
type(text: string): Promise<void>;
|
|
41
|
-
holdKey(combo: string, durationSec: number): Promise<void>;
|
|
42
|
-
wait(durationSec: number): Promise<void>;
|
|
43
|
-
}
|
|
44
|
-
export declare function isAnthropicComputerUseEnabled(): boolean;
|
|
45
|
-
export declare function addAnthropicComputerUseToPayload(api: Api | undefined, payload: unknown): unknown;
|
|
46
|
-
export declare function executeComputerAction(input: ComputerToolInput, ops: ComputerOperations): Promise<ComputerResult>;
|
|
47
|
-
export declare function createUnsupportedOps(): ComputerOperations;
|
|
48
|
-
export declare function createMacOSComputerOps(): ComputerOperations;
|
|
49
|
-
export declare function createLinuxComputerOps(): ComputerOperations;
|
|
50
|
-
export declare function createComputerOps(platform?: NodeJS.Platform): ComputerOperations;
|
|
51
|
-
export declare const ANTHROPIC_COMPUTER_USE_SECTION = "\n## Computer Use\n\nThe native computer tool is available in this session. The model can\ncontrol the screen via screenshot, key, type, mouse actions, scroll,\nand wait commands.\n";
|
|
52
|
-
export default function anthropicComputerUseExtension(pi: ExtensionAPI): void;
|
|
53
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/anthropic-computer-use/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { readFile, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport type { Api, TextContent } from \"@earendil-works/pi-ai\";\nimport { type Static, Type } from \"typebox\";\nimport type { AgentToolResult, ExtensionAPI } from \"../../types.js\";\n\nconst execFileAsync = promisify(execFile);\n\ntype ToolDefinition = Record<string, unknown>;\n\nconst ANTHROPIC_COMPUTER_USE_ENV = \"PI_ANTHROPIC_COMPUTER_USE\";\nconst ANTHROPIC_COMPUTER_USE_WIDTH_ENV = \"PI_ANTHROPIC_COMPUTER_USE_WIDTH\";\nconst ANTHROPIC_COMPUTER_USE_HEIGHT_ENV = \"PI_ANTHROPIC_COMPUTER_USE_HEIGHT\";\nconst ANTHROPIC_COMPUTER_USE_DISPLAY_NUMBER_ENV = \"PI_ANTHROPIC_COMPUTER_USE_DISPLAY_NUMBER\";\nconst ANTHROPIC_COMPUTER_USE_BETA = \"computer-use-2025-01-24\";\n\nconst ANTHROPIC_NATIVE_COMPUTER_TOOL_TYPE = \"computer_20250124\";\nconst ANTHROPIC_NATIVE_COMPUTER_TOOL_NAME = \"computer\";\n\nexport const computerSchema = Type.Object({\n\taction: Type.Union([\n\t\tType.Literal(\"screenshot\"),\n\t\tType.Literal(\"key\"),\n\t\tType.Literal(\"type\"),\n\t\tType.Literal(\"mouse_move\"),\n\t\tType.Literal(\"left_click\"),\n\t\tType.Literal(\"right_click\"),\n\t\tType.Literal(\"middle_click\"),\n\t\tType.Literal(\"double_click\"),\n\t\tType.Literal(\"triple_click\"),\n\t\tType.Literal(\"left_click_drag\"),\n\t\tType.Literal(\"cursor_position\"),\n\t\tType.Literal(\"left_mouse_down\"),\n\t\tType.Literal(\"left_mouse_up\"),\n\t\tType.Literal(\"scroll\"),\n\t\tType.Literal(\"hold_key\"),\n\t\tType.Literal(\"wait\"),\n\t]),\n\tcoordinate: Type.Optional(Type.Array(Type.Number(), { minItems: 2, maxItems: 2 })),\n\tstart_coordinate: Type.Optional(Type.Array(Type.Number(), { minItems: 2, maxItems: 2 })),\n\ttext: Type.Optional(Type.String()),\n\tkey: Type.Optional(Type.String()),\n\tscroll_direction: Type.Optional(\n\t\tType.Union([Type.Literal(\"up\"), Type.Literal(\"down\"), Type.Literal(\"left\"), Type.Literal(\"right\")]),\n\t),\n\tscroll_amount: Type.Optional(Type.Number()),\n\tduration: Type.Optional(Type.Number()),\n});\n\nexport type ComputerToolInput = Static<typeof computerSchema>;\n\nexport type ComputerResult = {\n\tcontent: Array<\n\t\t| TextContent\n\t\t| {\n\t\t\t\ttype: \"image\";\n\t\t\t\tdata: string;\n\t\t\t\tmimeType: \"image/png\";\n\t\t }\n\t>;\n\tisError?: boolean;\n};\n\nexport interface ComputerOperations {\n\tscreenshot(): Promise<{ base64: string }>;\n\tcursorPosition(): Promise<{ x: number; y: number }>;\n\tmouseMove(x: number, y: number): Promise<void>;\n\tclick(button: \"left\" | \"right\" | \"middle\", x?: number, y?: number, modifier?: string): Promise<void>;\n\tdoubleClick(x?: number, y?: number): Promise<void>;\n\ttripleClick(x?: number, y?: number): Promise<void>;\n\tdrag(startX: number, startY: number, endX: number, endY: number): Promise<void>;\n\tmouseDown(button: \"left\", x?: number, y?: number): Promise<void>;\n\tmouseUp(button: \"left\", x?: number, y?: number): Promise<void>;\n\tscroll(\n\t\tdirection: \"up\" | \"down\" | \"left\" | \"right\",\n\t\tamount: number,\n\t\tx?: number,\n\t\ty?: number,\n\t\tmodifier?: string,\n\t): Promise<void>;\n\tkeyPress(combo: string): Promise<void>;\n\ttype(text: string): Promise<void>;\n\tholdKey(combo: string, durationSec: number): Promise<void>;\n\twait(durationSec: number): Promise<void>;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction enabledByEnv(env: string | undefined): boolean {\n\tif (!env) {\n\t\treturn false;\n\t}\n\tconst normalized = env.trim().toLowerCase();\n\treturn normalized === \"1\" || normalized === \"true\" || normalized === \"yes\" || normalized === \"on\";\n}\n\nfunction parsePositiveInt(value: string | undefined): number | undefined {\n\tif (!value) {\n\t\treturn undefined;\n\t}\n\tconst trimmed = value.trim();\n\tif (!/^\\d+$/.test(trimmed)) {\n\t\treturn undefined;\n\t}\n\tconst parsed = Number.parseInt(trimmed, 10);\n\treturn parsed > 0 ? parsed : undefined;\n}\n\nfunction getComputerDisplayConfig(): { width: number; height: number; displayNumber?: number } | undefined {\n\tconst width = parsePositiveInt(process.env[ANTHROPIC_COMPUTER_USE_WIDTH_ENV]);\n\tconst height = parsePositiveInt(process.env[ANTHROPIC_COMPUTER_USE_HEIGHT_ENV]);\n\tconst displayNumber = parsePositiveInt(process.env[ANTHROPIC_COMPUTER_USE_DISPLAY_NUMBER_ENV]);\n\tif (width === undefined || height === undefined) {\n\t\treturn undefined;\n\t}\n\tif (displayNumber === undefined) {\n\t\treturn { width, height };\n\t}\n\treturn { width, height, displayNumber };\n}\n\nfunction getComputerEnableState(): {\n\tenabled: boolean;\n\tconfig?: { width: number; height: number; displayNumber?: number };\n} {\n\tif (!enabledByEnv(process.env[ANTHROPIC_COMPUTER_USE_ENV])) {\n\t\treturn { enabled: false };\n\t}\n\tconst config = getComputerDisplayConfig();\n\tif (!config) {\n\t\treturn { enabled: false };\n\t}\n\treturn { enabled: true, config };\n}\n\nexport function isAnthropicComputerUseEnabled(): boolean {\n\treturn getComputerEnableState().enabled;\n}\n\nfunction isComputerToolType(value: unknown): value is string {\n\treturn typeof value === \"string\" && value.startsWith(\"computer_\");\n}\n\nfunction sanitizeTools(tools: unknown[]): ToolDefinition[] {\n\tconst sanitizedTools: ToolDefinition[] = [];\n\tfor (const tool of tools) {\n\t\tif (!isRecord(tool)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst shouldStripFunctionVariant =\n\t\t\ttool.name === ANTHROPIC_NATIVE_COMPUTER_TOOL_NAME && !isComputerToolType(tool.type);\n\t\tif (!shouldStripFunctionVariant) {\n\t\t\tsanitizedTools.push(tool);\n\t\t}\n\t}\n\treturn sanitizedTools;\n}\n\nfunction mergeBetaHeader(existing: unknown): string {\n\tconst existingParts =\n\t\ttypeof existing === \"string\"\n\t\t\t? existing\n\t\t\t\t\t.split(\",\")\n\t\t\t\t\t.map((part) => part.trim())\n\t\t\t\t\t.filter(Boolean)\n\t\t\t: [];\n\tif (existingParts.includes(ANTHROPIC_COMPUTER_USE_BETA)) {\n\t\treturn existingParts.join(\",\");\n\t}\n\treturn [...existingParts, ANTHROPIC_COMPUTER_USE_BETA].join(\",\");\n}\n\nexport function addAnthropicComputerUseToPayload(api: Api | undefined, payload: unknown): unknown {\n\tif (api !== \"anthropic-messages\") {\n\t\treturn payload;\n\t}\n\tconst state = getComputerEnableState();\n\tif (!state.enabled || !state.config) {\n\t\treturn payload;\n\t}\n\tif (!isRecord(payload)) {\n\t\treturn payload;\n\t}\n\n\tconst tools = Array.isArray(payload.tools) ? payload.tools : [];\n\tconst sanitizedTools = sanitizeTools(tools);\n\tconst hasNativeComputer = sanitizedTools.some((tool) => isComputerToolType(tool.type));\n\tif (!hasNativeComputer) {\n\t\tsanitizedTools.push({\n\t\t\ttype: ANTHROPIC_NATIVE_COMPUTER_TOOL_TYPE,\n\t\t\tname: ANTHROPIC_NATIVE_COMPUTER_TOOL_NAME,\n\t\t\tdisplay_width_px: state.config.width,\n\t\t\tdisplay_height_px: state.config.height,\n\t\t\t...(state.config.displayNumber !== undefined ? { display_number: state.config.displayNumber } : {}),\n\t\t});\n\t}\n\n\tconst existingBetas = isRecord(payload.extra_body) ? payload.extra_body.betas : undefined;\n\tconst mergedBetas = Array.isArray(existingBetas)\n\t\t? existingBetas.includes(ANTHROPIC_COMPUTER_USE_BETA)\n\t\t\t? existingBetas\n\t\t\t: [...existingBetas, ANTHROPIC_COMPUTER_USE_BETA]\n\t\t: [ANTHROPIC_COMPUTER_USE_BETA];\n\n\tconst headers = isRecord(payload.headers) ? payload.headers : {};\n\tconst nextHeaders = {\n\t\t...headers,\n\t\t\"anthropic-beta\": mergeBetaHeader(headers[\"anthropic-beta\"]),\n\t};\n\n\treturn {\n\t\t...payload,\n\t\ttools: sanitizedTools,\n\t\theaders: nextHeaders,\n\t\textra_body: {\n\t\t\t...(isRecord(payload.extra_body) ? payload.extra_body : {}),\n\t\t\tbetas: mergedBetas,\n\t\t},\n\t};\n}\n\nfunction imageResult(base64: string): ComputerResult {\n\treturn {\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttype: \"image\",\n\t\t\t\tdata: base64,\n\t\t\t\tmimeType: \"image/png\",\n\t\t\t},\n\t\t],\n\t};\n}\n\nfunction errorResult(message: string): ComputerResult {\n\treturn {\n\t\tisError: true,\n\t\tcontent: [{ type: \"text\", text: message }],\n\t};\n}\n\nfunction parseCoordinate(coordinate: number[] | undefined, action: string): [number, number] {\n\tif (!coordinate || coordinate.length !== 2) {\n\t\tthrow new Error(`${action} requires coordinate [x, y]`);\n\t}\n\treturn [coordinate[0] ?? 0, coordinate[1] ?? 0];\n}\n\nfunction parseDuration(duration: number | undefined, action: string): number {\n\tif (duration === undefined || Number.isNaN(duration) || duration < 0) {\n\t\tthrow new Error(`${action} requires duration >= 0`);\n\t}\n\treturn duration;\n}\n\nfunction parseText(text: string | undefined, action: string): string {\n\tif (!text) {\n\t\tthrow new Error(`${action} requires text`);\n\t}\n\treturn text;\n}\n\nexport async function executeComputerAction(\n\tinput: ComputerToolInput,\n\tops: ComputerOperations,\n): Promise<ComputerResult> {\n\ttry {\n\t\tswitch (input.action) {\n\t\t\tcase \"screenshot\": {\n\t\t\t\tconst screenshot = await ops.screenshot();\n\t\t\t\treturn imageResult(screenshot.base64);\n\t\t\t}\n\t\t\tcase \"key\": {\n\t\t\t\tconst combo = parseText(input.text ?? input.key, \"key\");\n\t\t\t\tawait ops.keyPress(combo);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"type\": {\n\t\t\t\tawait ops.type(parseText(input.text, \"type\"));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"mouse_move\": {\n\t\t\t\tconst [x, y] = parseCoordinate(input.coordinate, \"mouse_move\");\n\t\t\t\tawait ops.mouseMove(x, y);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"left_click\": {\n\t\t\t\tconst coordinate = input.coordinate;\n\t\t\t\tif (coordinate) {\n\t\t\t\t\tconst [x, y] = parseCoordinate(coordinate, \"left_click\");\n\t\t\t\t\tawait ops.click(\"left\", x, y);\n\t\t\t\t} else {\n\t\t\t\t\tawait ops.click(\"left\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"right_click\": {\n\t\t\t\tconst coordinate = input.coordinate;\n\t\t\t\tif (coordinate) {\n\t\t\t\t\tconst [x, y] = parseCoordinate(coordinate, \"right_click\");\n\t\t\t\t\tawait ops.click(\"right\", x, y);\n\t\t\t\t} else {\n\t\t\t\t\tawait ops.click(\"right\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"middle_click\": {\n\t\t\t\tconst coordinate = input.coordinate;\n\t\t\t\tif (coordinate) {\n\t\t\t\t\tconst [x, y] = parseCoordinate(coordinate, \"middle_click\");\n\t\t\t\t\tawait ops.click(\"middle\", x, y);\n\t\t\t\t} else {\n\t\t\t\t\tawait ops.click(\"middle\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"double_click\": {\n\t\t\t\tconst coordinate = input.coordinate;\n\t\t\t\tif (coordinate) {\n\t\t\t\t\tconst [x, y] = parseCoordinate(coordinate, \"double_click\");\n\t\t\t\t\tawait ops.doubleClick(x, y);\n\t\t\t\t} else {\n\t\t\t\t\tawait ops.doubleClick();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"triple_click\": {\n\t\t\t\tconst coordinate = input.coordinate;\n\t\t\t\tif (coordinate) {\n\t\t\t\t\tconst [x, y] = parseCoordinate(coordinate, \"triple_click\");\n\t\t\t\t\tawait ops.tripleClick(x, y);\n\t\t\t\t} else {\n\t\t\t\t\tawait ops.tripleClick();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"left_click_drag\": {\n\t\t\t\tconst [startX, startY] = parseCoordinate(input.start_coordinate, \"left_click_drag.start_coordinate\");\n\t\t\t\tconst [endX, endY] = parseCoordinate(input.coordinate, \"left_click_drag.coordinate\");\n\t\t\t\tawait ops.drag(startX, startY, endX, endY);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"cursor_position\": {\n\t\t\t\tconst position = await ops.cursorPosition();\n\t\t\t\treturn { content: [{ type: \"text\", text: `X=${position.x},Y=${position.y}` }] };\n\t\t\t}\n\t\t\tcase \"left_mouse_down\": {\n\t\t\t\tconst coordinate = input.coordinate;\n\t\t\t\tif (coordinate) {\n\t\t\t\t\tconst [x, y] = parseCoordinate(coordinate, \"left_mouse_down\");\n\t\t\t\t\tawait ops.mouseDown(\"left\", x, y);\n\t\t\t\t} else {\n\t\t\t\t\tawait ops.mouseDown(\"left\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"left_mouse_up\": {\n\t\t\t\tconst coordinate = input.coordinate;\n\t\t\t\tif (coordinate) {\n\t\t\t\t\tconst [x, y] = parseCoordinate(coordinate, \"left_mouse_up\");\n\t\t\t\t\tawait ops.mouseUp(\"left\", x, y);\n\t\t\t\t} else {\n\t\t\t\t\tawait ops.mouseUp(\"left\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"scroll\": {\n\t\t\t\tif (!input.scroll_direction) {\n\t\t\t\t\tthrow new Error(\"scroll requires scroll_direction\");\n\t\t\t\t}\n\t\t\t\tif (input.scroll_amount === undefined || input.scroll_amount <= 0) {\n\t\t\t\t\tthrow new Error(\"scroll requires positive scroll_amount\");\n\t\t\t\t}\n\t\t\t\tconst coordinate = input.coordinate;\n\t\t\t\tif (coordinate) {\n\t\t\t\t\tconst [x, y] = parseCoordinate(coordinate, \"scroll\");\n\t\t\t\t\tawait ops.scroll(input.scroll_direction, input.scroll_amount, x, y);\n\t\t\t\t} else {\n\t\t\t\t\tawait ops.scroll(input.scroll_direction, input.scroll_amount);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"hold_key\": {\n\t\t\t\tawait ops.holdKey(\n\t\t\t\t\tparseText(input.text ?? input.key, \"hold_key\"),\n\t\t\t\t\tparseDuration(input.duration, \"hold_key\"),\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"wait\": {\n\t\t\t\tawait ops.wait(parseDuration(input.duration, \"wait\"));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tconst screenshot = await ops.screenshot();\n\t\treturn imageResult(screenshot.base64);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\treturn errorResult(message);\n\t}\n}\n\nasync function commandExists(command: string): Promise<boolean> {\n\ttry {\n\t\tawait execFileAsync(\"which\", [command]);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function run(command: string, args: string[]): Promise<string> {\n\tconst result = await execFileAsync(command, args);\n\treturn result.stdout;\n}\n\nfunction parseKeyComboToAppleScript(combo: string): string {\n\tconst parts = combo\n\t\t.split(\"+\")\n\t\t.map((part) => part.trim().toLowerCase())\n\t\t.filter(Boolean);\n\tif (parts.length === 0) {\n\t\tthrow new Error(\"Empty key combo\");\n\t}\n\tconst main = parts[parts.length - 1] ?? \"\";\n\tconst modifiers = new Set(parts.slice(0, -1));\n\tconst usingParts: string[] = [];\n\tif (modifiers.has(\"ctrl\") || modifiers.has(\"control\")) usingParts.push(\"control down\");\n\tif (modifiers.has(\"cmd\") || modifiers.has(\"command\")) usingParts.push(\"command down\");\n\tif (modifiers.has(\"alt\") || modifiers.has(\"option\")) usingParts.push(\"option down\");\n\tif (modifiers.has(\"shift\")) usingParts.push(\"shift down\");\n\tconst targetKey = main.length === 1 ? `keystroke ${JSON.stringify(main)}` : `key code ${mapKeyCode(main)}`;\n\tif (usingParts.length === 0) {\n\t\treturn `tell application \"System Events\" to ${targetKey}`;\n\t}\n\treturn `tell application \"System Events\" to ${targetKey} using {${usingParts.join(\", \")}}`;\n}\n\nfunction mapKeyCode(key: string): number {\n\tconst map: Record<string, number> = { enter: 36, return: 36, tab: 48, space: 49, esc: 53, escape: 53 };\n\tconst code = map[key];\n\tif (code === undefined) {\n\t\tthrow new Error(`Unsupported macOS special key: ${key}`);\n\t}\n\treturn code;\n}\n\nexport function createUnsupportedOps(): ComputerOperations {\n\tconst fail = async (): Promise<never> => {\n\t\tthrow new Error(\"Computer use not supported on Windows\");\n\t};\n\treturn {\n\t\tscreenshot: fail,\n\t\tcursorPosition: fail,\n\t\tmouseMove: fail,\n\t\tclick: fail,\n\t\tdoubleClick: fail,\n\t\ttripleClick: fail,\n\t\tdrag: fail,\n\t\tmouseDown: fail,\n\t\tmouseUp: fail,\n\t\tscroll: fail,\n\t\tkeyPress: fail,\n\t\ttype: fail,\n\t\tholdKey: fail,\n\t\twait: fail,\n\t};\n}\n\nexport function createMacOSComputerOps(): ComputerOperations {\n\treturn {\n\t\tasync screenshot() {\n\t\t\tconst filePath = path.join(tmpdir(), `senpi-computer-${randomUUID()}.png`);\n\t\t\ttry {\n\t\t\t\tawait run(\"screencapture\", [\"-x\", \"-t\", \"png\", filePath]);\n\t\t\t\tconst buffer = await readFile(filePath);\n\t\t\t\treturn { base64: buffer.toString(\"base64\") };\n\t\t\t} finally {\n\t\t\t\tawait rm(filePath, { force: true });\n\t\t\t}\n\t\t},\n\t\tasync cursorPosition() {\n\t\t\tconst output = await run(\"osascript\", [\n\t\t\t\t\"-e\",\n\t\t\t\t'tell app \"System Events\" to return position of pointer as text',\n\t\t\t]);\n\t\t\tconst parts = output.trim().split(\",\");\n\t\t\tconst xRaw = Number.parseInt((parts[0] ?? \"0\").trim(), 10);\n\t\t\tconst yRaw = Number.parseInt((parts[1] ?? \"0\").trim(), 10);\n\t\t\treturn { x: Number.isFinite(xRaw) ? xRaw : 0, y: Number.isFinite(yRaw) ? yRaw : 0 };\n\t\t},\n\t\tasync mouseMove(x, y) {\n\t\t\tawait run(\"cliclick\", [`m:${x},${y}`]);\n\t\t},\n\t\tasync click(button, x, y) {\n\t\t\tif (x !== undefined && y !== undefined) {\n\t\t\t\tawait run(\"cliclick\", [`m:${x},${y}`]);\n\t\t\t}\n\t\t\tconst command = button === \"left\" ? \"c:.\" : button === \"right\" ? \"rc:.\" : \"mc:.\";\n\t\t\tawait run(\"cliclick\", [command]);\n\t\t},\n\t\tasync doubleClick(x, y) {\n\t\t\tif (x !== undefined && y !== undefined) {\n\t\t\t\tawait run(\"cliclick\", [`m:${x},${y}`]);\n\t\t\t}\n\t\t\tawait run(\"cliclick\", [\"dc:.\"]);\n\t\t},\n\t\tasync tripleClick(x, y) {\n\t\t\tif (x !== undefined && y !== undefined) {\n\t\t\t\tawait run(\"cliclick\", [`m:${x},${y}`]);\n\t\t\t}\n\t\t\tawait run(\"cliclick\", [\"tc:.\"]);\n\t\t},\n\t\tasync drag(startX, startY, endX, endY) {\n\t\t\tawait run(\"cliclick\", [`dd:${startX},${startY}`, `du:${endX},${endY}`]);\n\t\t},\n\t\tasync mouseDown(_button, x, y) {\n\t\t\tif (x !== undefined && y !== undefined) {\n\t\t\t\tawait run(\"cliclick\", [`m:${x},${y}`]);\n\t\t\t}\n\t\t\tawait run(\"cliclick\", [\"dd:.\"]);\n\t\t},\n\t\tasync mouseUp(_button, x, y) {\n\t\t\tif (x !== undefined && y !== undefined) {\n\t\t\t\tawait run(\"cliclick\", [`m:${x},${y}`]);\n\t\t\t}\n\t\t\tawait run(\"cliclick\", [\"du:.\"]);\n\t\t},\n\t\tasync scroll(direction, amount, x, y) {\n\t\t\tif (x !== undefined && y !== undefined) {\n\t\t\t\tawait run(\"cliclick\", [`m:${x},${y}`]);\n\t\t\t}\n\t\t\tconst clicks = Math.max(1, Math.round(amount));\n\t\t\tconst wheel = direction === \"up\" ? \"wd\" : direction === \"down\" ? \"wu\" : direction === \"left\" ? \"wl\" : \"wr\";\n\t\t\tawait run(\"cliclick\", [`${wheel}:${clicks}`]);\n\t\t},\n\t\tasync keyPress(combo) {\n\t\t\tawait run(\"osascript\", [\"-e\", parseKeyComboToAppleScript(combo)]);\n\t\t},\n\t\tasync type(text) {\n\t\t\tawait run(\"osascript\", [\"-e\", `tell application \"System Events\" to keystroke ${JSON.stringify(text)}`]);\n\t\t},\n\t\tasync holdKey(combo, durationSec) {\n\t\t\tawait run(\"osascript\", [\"-e\", parseKeyComboToAppleScript(combo)]);\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, durationSec * 1000));\n\t\t},\n\t\tasync wait(durationSec) {\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, durationSec * 1000));\n\t\t},\n\t};\n}\n\nexport function createLinuxComputerOps(): ComputerOperations {\n\treturn {\n\t\tasync screenshot() {\n\t\t\tconst filePath = path.join(tmpdir(), `senpi-computer-${randomUUID()}.png`);\n\t\t\ttry {\n\t\t\t\tawait run(\"scrot\", [filePath]);\n\t\t\t\tconst buffer = await readFile(filePath);\n\t\t\t\treturn { base64: buffer.toString(\"base64\") };\n\t\t\t} finally {\n\t\t\t\tawait rm(filePath, { force: true });\n\t\t\t}\n\t\t},\n\t\tasync cursorPosition() {\n\t\t\tconst output = await run(\"xdotool\", [\"getmouselocation\", \"--shell\"]);\n\t\t\tconst xMatch = output.match(/^X=(\\d+)$/m);\n\t\t\tconst yMatch = output.match(/^Y=(\\d+)$/m);\n\t\t\treturn {\n\t\t\t\tx: xMatch ? Number.parseInt(xMatch[1] ?? \"0\", 10) : 0,\n\t\t\t\ty: yMatch ? Number.parseInt(yMatch[1] ?? \"0\", 10) : 0,\n\t\t\t};\n\t\t},\n\t\tasync mouseMove(x, y) {\n\t\t\tawait run(\"xdotool\", [\"mousemove\", `${x}`, `${y}`]);\n\t\t},\n\t\tasync click(button, x, y) {\n\t\t\tif (x !== undefined && y !== undefined) {\n\t\t\t\tawait run(\"xdotool\", [\"mousemove\", `${x}`, `${y}`]);\n\t\t\t}\n\t\t\tconst buttonNumber = button === \"left\" ? \"1\" : button === \"middle\" ? \"2\" : \"3\";\n\t\t\tawait run(\"xdotool\", [\"click\", buttonNumber]);\n\t\t},\n\t\tasync doubleClick(x, y) {\n\t\t\tif (x !== undefined && y !== undefined) {\n\t\t\t\tawait run(\"xdotool\", [\"mousemove\", `${x}`, `${y}`]);\n\t\t\t}\n\t\t\tawait run(\"xdotool\", [\"click\", \"--repeat\", \"2\", \"1\"]);\n\t\t},\n\t\tasync tripleClick(x, y) {\n\t\t\tif (x !== undefined && y !== undefined) {\n\t\t\t\tawait run(\"xdotool\", [\"mousemove\", `${x}`, `${y}`]);\n\t\t\t}\n\t\t\tawait run(\"xdotool\", [\"click\", \"--repeat\", \"3\", \"1\"]);\n\t\t},\n\t\tasync drag(startX, startY, endX, endY) {\n\t\t\tawait run(\"xdotool\", [\n\t\t\t\t\"mousemove\",\n\t\t\t\t`${startX}`,\n\t\t\t\t`${startY}`,\n\t\t\t\t\"mousedown\",\n\t\t\t\t\"1\",\n\t\t\t\t\"mousemove\",\n\t\t\t\t`${endX}`,\n\t\t\t\t`${endY}`,\n\t\t\t\t\"mouseup\",\n\t\t\t\t\"1\",\n\t\t\t]);\n\t\t},\n\t\tasync mouseDown(_button, x, y) {\n\t\t\tif (x !== undefined && y !== undefined) {\n\t\t\t\tawait run(\"xdotool\", [\"mousemove\", `${x}`, `${y}`]);\n\t\t\t}\n\t\t\tawait run(\"xdotool\", [\"mousedown\", \"1\"]);\n\t\t},\n\t\tasync mouseUp(_button, x, y) {\n\t\t\tif (x !== undefined && y !== undefined) {\n\t\t\t\tawait run(\"xdotool\", [\"mousemove\", `${x}`, `${y}`]);\n\t\t\t}\n\t\t\tawait run(\"xdotool\", [\"mouseup\", \"1\"]);\n\t\t},\n\t\tasync scroll(direction, amount, x, y) {\n\t\t\tif (x !== undefined && y !== undefined) {\n\t\t\t\tawait run(\"xdotool\", [\"mousemove\", `${x}`, `${y}`]);\n\t\t\t}\n\t\t\tconst button = direction === \"up\" ? \"4\" : direction === \"down\" ? \"5\" : direction === \"left\" ? \"6\" : \"7\";\n\t\t\tconst repeat = `${Math.max(1, Math.round(amount))}`;\n\t\t\tawait run(\"xdotool\", [\"click\", \"--repeat\", repeat, button]);\n\t\t},\n\t\tasync keyPress(combo) {\n\t\t\tawait run(\"xdotool\", [\"key\", combo]);\n\t\t},\n\t\tasync type(text) {\n\t\t\tawait run(\"xdotool\", [\"type\", \"--delay\", \"12\", \"--\", text]);\n\t\t},\n\t\tasync holdKey(combo, durationSec) {\n\t\t\tawait run(\"xdotool\", [\"keydown\", combo]);\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, durationSec * 1000));\n\t\t\tawait run(\"xdotool\", [\"keyup\", combo]);\n\t\t},\n\t\tasync wait(durationSec) {\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, durationSec * 1000));\n\t\t},\n\t};\n}\n\nexport function createComputerOps(platform: NodeJS.Platform = process.platform): ComputerOperations {\n\tif (platform === \"darwin\") {\n\t\treturn createMacOSComputerOps();\n\t}\n\tif (platform === \"linux\") {\n\t\treturn createLinuxComputerOps();\n\t}\n\treturn createUnsupportedOps();\n}\n\nasync function validateCliDependencies(platform: NodeJS.Platform): Promise<string[]> {\n\tconst missing: string[] = [];\n\tif (platform === \"darwin\") {\n\t\tif (!(await commandExists(\"cliclick\"))) {\n\t\t\tmissing.push(\"cliclick\");\n\t\t}\n\t} else if (platform === \"linux\") {\n\t\tif (!(await commandExists(\"xdotool\"))) {\n\t\t\tmissing.push(\"xdotool\");\n\t\t}\n\t\tif (!(await commandExists(\"scrot\"))) {\n\t\t\tmissing.push(\"scrot\");\n\t\t}\n\t}\n\treturn missing;\n}\n\nexport const ANTHROPIC_COMPUTER_USE_SECTION = `\n## Computer Use\n\nThe native computer tool is available in this session. The model can\ncontrol the screen via screenshot, key, type, mouse actions, scroll,\nand wait commands.\n`;\n\nfunction buildComputerUseSection(width: number, height: number): string {\n\treturn `${ANTHROPIC_COMPUTER_USE_SECTION.trimEnd()} Display dimensions: ${width}x${height}. Use computer when the user asks to interact with GUI applications.\\n`;\n}\n\nexport default function anthropicComputerUseExtension(pi: ExtensionAPI): void {\n\tlet extensionDisabledForSession = false;\n\n\tpi.on(\"session_start\", async (_event) => {\n\t\tif (!enabledByEnv(process.env[ANTHROPIC_COMPUTER_USE_ENV])) {\n\t\t\textensionDisabledForSession = true;\n\t\t\treturn undefined;\n\t\t}\n\t\tif (!getComputerDisplayConfig()) {\n\t\t\textensionDisabledForSession = true;\n\t\t\tconsole.error(\n\t\t\t\t`[anthropic-computer-use] ${ANTHROPIC_COMPUTER_USE_WIDTH_ENV} and ${ANTHROPIC_COMPUTER_USE_HEIGHT_ENV} must be positive integers; extension disabled for this session.`,\n\t\t\t);\n\t\t\treturn undefined;\n\t\t}\n\t\textensionDisabledForSession = false;\n\t\tconst missingTools = await validateCliDependencies(process.platform);\n\t\tif (missingTools.length > 0) {\n\t\t\tconsole.warn(\n\t\t\t\t`[anthropic-computer-use] Missing OS automation dependencies: ${missingTools.join(\", \")}. Install them for full functionality.`,\n\t\t\t);\n\t\t}\n\t\treturn undefined;\n\t});\n\n\tif (enabledByEnv(process.env[ANTHROPIC_COMPUTER_USE_ENV]) && getComputerDisplayConfig()) {\n\t\tconst ops = createComputerOps();\n\t\tpi.registerTool({\n\t\t\tname: ANTHROPIC_NATIVE_COMPUTER_TOOL_NAME,\n\t\t\tlabel: \"Computer Use\",\n\t\t\tdescription:\n\t\t\t\t\"Actions: screenshot, key, type, mouse_move, left/right/middle click, double/triple click, drag, cursor_position, mouse down/up, scroll, hold_key, wait.\",\n\t\t\tparameters: computerSchema,\n\t\t\tasync execute(_toolCallId, params): Promise<AgentToolResult<undefined>> {\n\t\t\t\tconst result = await executeComputerAction(params, ops);\n\t\t\t\tif (result.isError) {\n\t\t\t\t\tconst firstContent = result.content[0];\n\t\t\t\t\tthrow new Error(firstContent?.type === \"text\" ? firstContent.text : \"Computer action failed\");\n\t\t\t\t}\n\t\t\t\treturn { content: result.content, details: undefined };\n\t\t\t},\n\t\t});\n\t}\n\n\tpi.on(\"before_provider_request\", (event, ctx) => {\n\t\tif (extensionDisabledForSession) {\n\t\t\treturn event.payload;\n\t\t}\n\t\treturn addAnthropicComputerUseToPayload(ctx.model?.api, event.payload);\n\t});\n\n\tpi.on(\"before_agent_start\", async (event, ctx) => {\n\t\tif (ctx.model?.api !== \"anthropic-messages\") {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (extensionDisabledForSession) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst config = getComputerDisplayConfig();\n\t\tif (!enabledByEnv(process.env[ANTHROPIC_COMPUTER_USE_ENV]) || !config) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn {\n\t\t\tsystemPrompt: `${event.systemPrompt}\\n${buildComputerUseSection(config.width, config.height)}`,\n\t\t};\n\t});\n}\n"]}
|