@animalabs/agent-framework 0.23.3 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +212 -42
- package/dist/src/agent.d.ts +65 -9
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +98 -12
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +14 -12
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/clock-rows.d.ts +115 -0
- package/dist/src/clock-rows.d.ts.map +1 -0
- package/dist/src/clock-rows.js +222 -0
- package/dist/src/clock-rows.js.map +1 -0
- package/dist/src/code-execution/engine.d.ts +177 -0
- package/dist/src/code-execution/engine.d.ts.map +1 -0
- package/dist/src/code-execution/engine.js +494 -0
- package/dist/src/code-execution/engine.js.map +1 -0
- package/dist/src/code-execution/index.d.ts +5 -10
- package/dist/src/code-execution/index.d.ts.map +1 -1
- package/dist/src/code-execution/index.js +5 -9
- package/dist/src/code-execution/index.js.map +1 -1
- package/dist/src/code-execution/isolate/calls.d.ts +114 -0
- package/dist/src/code-execution/isolate/calls.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/calls.js +145 -0
- package/dist/src/code-execution/isolate/calls.js.map +1 -0
- package/dist/src/code-execution/isolate/child-entry.d.ts +2 -0
- package/dist/src/code-execution/isolate/child-entry.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child-entry.js +5 -0
- package/dist/src/code-execution/isolate/child-entry.js.map +1 -0
- package/dist/src/code-execution/isolate/child-main.d.ts +26 -0
- package/dist/src/code-execution/isolate/child-main.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child-main.js +132 -0
- package/dist/src/code-execution/isolate/child-main.js.map +1 -0
- package/dist/src/code-execution/isolate/child.d.ts +44 -0
- package/dist/src/code-execution/isolate/child.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child.js +315 -0
- package/dist/src/code-execution/isolate/child.js.map +1 -0
- package/dist/src/code-execution/isolate/frames.d.ts +80 -0
- package/dist/src/code-execution/isolate/frames.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/frames.js +210 -0
- package/dist/src/code-execution/isolate/frames.js.map +1 -0
- package/dist/src/code-execution/isolate/output.d.ts +68 -0
- package/dist/src/code-execution/isolate/output.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/output.js +143 -0
- package/dist/src/code-execution/isolate/output.js.map +1 -0
- package/dist/src/code-execution/isolate/prelude.d.ts +109 -0
- package/dist/src/code-execution/isolate/prelude.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/prelude.js +401 -0
- package/dist/src/code-execution/isolate/prelude.js.map +1 -0
- package/dist/src/code-execution/isolate/protocol.d.ts +151 -0
- package/dist/src/code-execution/isolate/protocol.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/protocol.js +150 -0
- package/dist/src/code-execution/isolate/protocol.js.map +1 -0
- package/dist/src/code-execution/isolate/render.d.ts +57 -0
- package/dist/src/code-execution/isolate/render.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/render.js +214 -0
- package/dist/src/code-execution/isolate/render.js.map +1 -0
- package/dist/src/code-execution/isolate/runner.d.ts +250 -0
- package/dist/src/code-execution/isolate/runner.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/runner.js +854 -0
- package/dist/src/code-execution/isolate/runner.js.map +1 -0
- package/dist/src/code-execution/isolate/scripts.d.ts +175 -0
- package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/scripts.js +357 -0
- package/dist/src/code-execution/isolate/scripts.js.map +1 -0
- package/dist/src/code-execution/quickjs.wasm +0 -0
- package/dist/src/code-execution/tool-definition.d.ts +93 -43
- package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
- package/dist/src/code-execution/tool-definition.js +176 -142
- package/dist/src/code-execution/tool-definition.js.map +1 -1
- package/dist/src/deadline-timer.d.ts +3 -0
- package/dist/src/deadline-timer.d.ts.map +1 -1
- package/dist/src/deadline-timer.js +1 -1
- package/dist/src/deadline-timer.js.map +1 -1
- package/dist/src/framework.d.ts +1120 -457
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +4635 -2505
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +28 -4
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +89 -13
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/held-writes.d.ts +16 -3
- package/dist/src/held-writes.d.ts.map +1 -1
- package/dist/src/held-writes.js +16 -3
- package/dist/src/held-writes.js.map +1 -1
- package/dist/src/index.d.ts +8 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +10 -8
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +483 -115
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +1735 -425
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/conversation-router.d.ts +19 -39
- package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
- package/dist/src/mcpl/conversation-router.js +27 -59
- package/dist/src/mcpl/conversation-router.js.map +1 -1
- package/dist/src/mcpl/convert-block.d.ts.map +1 -1
- package/dist/src/mcpl/convert-block.js +9 -5
- package/dist/src/mcpl/convert-block.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +50 -0
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +130 -0
- package/dist/src/mcpl/inbound-source.js.map +1 -1
- package/dist/src/mcpl/index.d.ts +2 -1
- package/dist/src/mcpl/index.d.ts.map +1 -1
- package/dist/src/mcpl/index.js +3 -2
- package/dist/src/mcpl/index.js.map +1 -1
- package/dist/src/mcpl/log-value.d.ts +6 -0
- package/dist/src/mcpl/log-value.d.ts.map +1 -1
- package/dist/src/mcpl/log-value.js +8 -0
- package/dist/src/mcpl/log-value.js.map +1 -1
- package/dist/src/mcpl/modern-connection.d.ts +15 -6
- package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
- package/dist/src/mcpl/modern-connection.js +168 -53
- package/dist/src/mcpl/modern-connection.js.map +1 -1
- package/dist/src/mcpl/prose-grammar.d.ts +4 -5
- package/dist/src/mcpl/prose-grammar.d.ts.map +1 -1
- package/dist/src/mcpl/prose-grammar.js +4 -5
- package/dist/src/mcpl/prose-grammar.js.map +1 -1
- package/dist/src/mcpl/protocol-family.d.ts +97 -10
- package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
- package/dist/src/mcpl/protocol-family.js +174 -17
- package/dist/src/mcpl/protocol-family.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +132 -14
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +227 -50
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/push-handler.d.ts +9 -20
- package/dist/src/mcpl/push-handler.d.ts.map +1 -1
- package/dist/src/mcpl/push-handler.js +7 -49
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/reference-fetcher.d.ts +2 -2
- package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
- package/dist/src/mcpl/reference-fetcher.js +4 -4
- package/dist/src/mcpl/reference-fetcher.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +50 -21
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +158 -74
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/tags.d.ts +24 -0
- package/dist/src/mcpl/tags.d.ts.map +1 -1
- package/dist/src/mcpl/tags.js +33 -0
- package/dist/src/mcpl/tags.js.map +1 -1
- package/dist/src/mcpl/tool-result-normalize.d.ts +2 -1
- package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -1
- package/dist/src/mcpl/tool-result-normalize.js.map +1 -1
- package/dist/src/mcpl/transport.d.ts +55 -7
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +163 -34
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +22 -6
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/module-registry.d.ts +4 -2
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +100 -13
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +8 -13
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/history/index.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +27 -4
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/history/semantic.d.ts +15 -3
- package/dist/src/modules/history/semantic.d.ts.map +1 -1
- package/dist/src/modules/history/semantic.js +27 -5
- package/dist/src/modules/history/semantic.js.map +1 -1
- package/dist/src/modules/index.d.ts +1 -1
- package/dist/src/modules/index.d.ts.map +1 -1
- package/dist/src/modules/index.js.map +1 -1
- package/dist/src/modules/unknown-tool.d.ts +4 -1
- package/dist/src/modules/unknown-tool.d.ts.map +1 -1
- package/dist/src/modules/unknown-tool.js +4 -1
- package/dist/src/modules/unknown-tool.js.map +1 -1
- package/dist/src/modules/workspace/branch-intent.d.ts +3 -1
- package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
- package/dist/src/modules/workspace/branch-intent.js +3 -1
- package/dist/src/modules/workspace/branch-intent.js.map +1 -1
- package/dist/src/modules/workspace/edit-plan.d.ts +265 -0
- package/dist/src/modules/workspace/edit-plan.d.ts.map +1 -0
- package/dist/src/modules/workspace/edit-plan.js +794 -0
- package/dist/src/modules/workspace/edit-plan.js.map +1 -0
- package/dist/src/modules/workspace/edit-text.d.ts +117 -0
- package/dist/src/modules/workspace/edit-text.d.ts.map +1 -0
- package/dist/src/modules/workspace/edit-text.js +584 -0
- package/dist/src/modules/workspace/edit-text.js.map +1 -0
- package/dist/src/modules/workspace/effects.d.ts +5 -4
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +78 -25
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +493 -62
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +2216 -652
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +213 -38
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +416 -36
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
- package/dist/src/modules/workspace/reconcile.js +15 -8
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/modules/workspace/text.d.ts +32 -0
- package/dist/src/modules/workspace/text.d.ts.map +1 -0
- package/dist/src/modules/workspace/text.js +67 -0
- package/dist/src/modules/workspace/text.js.map +1 -0
- package/dist/src/modules/workspace/types.d.ts +210 -6
- package/dist/src/modules/workspace/types.d.ts.map +1 -1
- package/dist/src/modules/workspace/types.js.map +1 -1
- package/dist/src/modules/workspace/watcher.d.ts +3 -2
- package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
- package/dist/src/modules/workspace/watcher.js.map +1 -1
- package/dist/src/operator-log.d.ts +52 -24
- package/dist/src/operator-log.d.ts.map +1 -1
- package/dist/src/operator-log.js.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.d.ts +496 -72
- package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.js +1196 -289
- package/dist/src/recovery/discord-awareness-outbox.js.map +1 -1
- package/dist/src/recovery/offline-branch.d.ts +26 -1
- package/dist/src/recovery/offline-branch.d.ts.map +1 -1
- package/dist/src/recovery/offline-branch.js +164 -39
- package/dist/src/recovery/offline-branch.js.map +1 -1
- package/dist/src/recovery/recover-cli.js +23 -4
- package/dist/src/recovery/recover-cli.js.map +1 -1
- package/dist/src/send-tools.d.ts +11 -0
- package/dist/src/send-tools.d.ts.map +1 -0
- package/dist/src/send-tools.js +11 -0
- package/dist/src/send-tools.js.map +1 -0
- package/dist/src/timezone.d.ts +4 -2
- package/dist/src/timezone.d.ts.map +1 -1
- package/dist/src/timezone.js +4 -2
- package/dist/src/timezone.js.map +1 -1
- package/dist/src/tool-image-ledger.d.ts +46 -7
- package/dist/src/tool-image-ledger.d.ts.map +1 -1
- package/dist/src/tool-image-ledger.js +60 -7
- package/dist/src/tool-image-ledger.js.map +1 -1
- package/dist/src/tool-result-guard.d.ts +14 -11
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +17 -14
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tool-result-history.d.ts +3 -2
- package/dist/src/tool-result-history.d.ts.map +1 -1
- package/dist/src/tool-result-history.js +3 -2
- package/dist/src/tool-result-history.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +21 -0
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +142 -40
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/types/agent.d.ts +31 -6
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +66 -9
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +69 -62
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +40 -8
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +111 -10
- package/dist/src/types/trace.d.ts.map +1 -1
- package/dist/src/usage/types.d.ts +16 -0
- package/dist/src/usage/types.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.d.ts +14 -1
- package/dist/src/usage/usage-tracker.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.js +81 -41
- package/dist/src/usage/usage-tracker.js.map +1 -1
- package/package.json +6 -8
- package/src/agent.ts +99 -12
- package/src/api/server.ts +14 -12
- package/src/clock-rows.ts +302 -0
- package/src/code-execution/engine.ts +595 -0
- package/src/code-execution/index.ts +5 -17
- package/src/code-execution/isolate/calls.ts +199 -0
- package/src/code-execution/isolate/child-entry.ts +5 -0
- package/src/code-execution/isolate/child-main.ts +132 -0
- package/src/code-execution/isolate/child.ts +327 -0
- package/src/code-execution/isolate/frames.ts +209 -0
- package/src/code-execution/isolate/output.ts +161 -0
- package/src/code-execution/isolate/prelude.ts +409 -0
- package/src/code-execution/isolate/protocol.ts +240 -0
- package/src/code-execution/isolate/render.ts +230 -0
- package/src/code-execution/isolate/runner.ts +911 -0
- package/src/code-execution/isolate/scripts.ts +479 -0
- package/src/code-execution/quickjs.wasm +0 -0
- package/src/code-execution/quickjs.wasm.LICENSES +149 -0
- package/src/code-execution/tool-definition.ts +236 -167
- package/src/deadline-timer.ts +1 -1
- package/src/framework.ts +4978 -2671
- package/src/gate/event-gate.ts +79 -17
- package/src/held-writes.ts +17 -3
- package/src/index.ts +32 -22
- package/src/mcpl/channel-registry.ts +1892 -471
- package/src/mcpl/conversation-router.ts +26 -72
- package/src/mcpl/convert-block.ts +9 -5
- package/src/mcpl/inbound-source.ts +131 -0
- package/src/mcpl/index.ts +4 -2
- package/src/mcpl/log-value.ts +9 -0
- package/src/mcpl/modern-connection.ts +162 -53
- package/src/mcpl/prose-grammar.ts +4 -5
- package/src/mcpl/protocol-family.ts +200 -22
- package/src/mcpl/push-coalescer.ts +306 -62
- package/src/mcpl/push-handler.ts +12 -54
- package/src/mcpl/reference-fetcher.ts +4 -4
- package/src/mcpl/server-connection.ts +180 -79
- package/src/mcpl/tags.ts +36 -0
- package/src/mcpl/tool-result-normalize.ts +2 -1
- package/src/mcpl/transport.ts +162 -33
- package/src/mcpl/types.ts +23 -6
- package/src/module-registry.ts +92 -13
- package/src/modules/discord/index.ts +8 -13
- package/src/modules/history/index.ts +25 -3
- package/src/modules/history/semantic.ts +29 -6
- package/src/modules/index.ts +1 -0
- package/src/modules/unknown-tool.ts +4 -1
- package/src/modules/workspace/branch-intent.ts +3 -1
- package/src/modules/workspace/edit-plan.ts +954 -0
- package/src/modules/workspace/edit-text.ts +618 -0
- package/src/modules/workspace/effects.ts +70 -19
- package/src/modules/workspace/index.ts +2293 -650
- package/src/modules/workspace/observe.ts +465 -56
- package/src/modules/workspace/reconcile.ts +14 -7
- package/src/modules/workspace/text.ts +68 -0
- package/src/modules/workspace/types.ts +211 -6
- package/src/modules/workspace/watcher.ts +3 -2
- package/src/operator-log.ts +47 -19
- package/src/recovery/discord-awareness-outbox.ts +1500 -356
- package/src/recovery/offline-branch.ts +189 -55
- package/src/recovery/recover-cli.ts +25 -4
- package/src/send-tools.ts +11 -0
- package/src/timezone.ts +4 -2
- package/src/tool-image-ledger.ts +62 -8
- package/src/tool-result-guard.ts +18 -15
- package/src/tool-result-history.ts +3 -2
- package/src/tune-out/coordinator.ts +166 -45
- package/src/types/agent.ts +32 -6
- package/src/types/events.ts +66 -9
- package/src/types/framework.ts +69 -62
- package/src/types/module.ts +40 -8
- package/src/types/trace.ts +121 -15
- package/src/usage/types.ts +16 -0
- package/src/usage/usage-tracker.ts +86 -43
- package/dist/src/code-execution/py-runner.d.ts +0 -191
- package/dist/src/code-execution/py-runner.d.ts.map +0 -1
- package/dist/src/code-execution/py-runner.js +0 -655
- package/dist/src/code-execution/py-runner.js.map +0 -1
- package/dist/src/code-execution/runtime-py.d.ts +0 -50
- package/dist/src/code-execution/runtime-py.d.ts.map +0 -1
- package/dist/src/code-execution/runtime-py.js +0 -677
- package/dist/src/code-execution/runtime-py.js.map +0 -1
- package/dist/src/mcpl/prose-stream-router.d.ts +0 -88
- package/dist/src/mcpl/prose-stream-router.d.ts.map +0 -1
- package/dist/src/mcpl/prose-stream-router.js +0 -291
- package/dist/src/mcpl/prose-stream-router.js.map +0 -1
- package/src/code-execution/py-runner.ts +0 -791
- package/src/code-execution/runtime-py.ts +0 -677
- package/src/mcpl/prose-stream-router.ts +0 -268
|
@@ -1,104 +1,212 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* dict and returning a string, stdout as the return channel, persistent
|
|
8
|
-
* interpreter state, asyncio.gather for fan-out.
|
|
2
|
+
* `code_execution`: its configuration, the check that refuses one that still
|
|
3
|
+
* sets what the Python runner took, and the tool's definition, the text an
|
|
4
|
+
* agent reads before it writes a script. It follows the surface of Code Mode
|
|
5
|
+
* tools elsewhere (exact names, one result shape, top-level await), and says
|
|
6
|
+
* each rule once.
|
|
9
7
|
*/
|
|
10
8
|
|
|
11
|
-
import type { ToolDefinition } from '../types/index.js';
|
|
12
|
-
import { assertBooleanSetting, holdsSettings
|
|
13
|
-
import {
|
|
9
|
+
import type { CodeExecutionConfig, ToolDefinition } from '../types/index.js';
|
|
10
|
+
import { assertBooleanSetting, holdsSettings } from '../config-checks.js';
|
|
11
|
+
import { MAX_MEMORY_BYTES, MAX_RESULT_DEPTH, MIN_MEMORY_BYTES } from './engine.js';
|
|
12
|
+
import { DEFAULT_OUTPUT_BOUNDS } from './isolate/output.js';
|
|
13
|
+
import { MAX_ARGUMENT_BYTES, MAX_ARGUMENT_VALUES, MAX_CALLS_IN_FLIGHT, MAX_WAKE_PAYLOAD_BYTES } from './isolate/protocol.js';
|
|
14
|
+
import { formatMs, VALUE_CHARS } from './isolate/render.js';
|
|
15
|
+
|
|
16
|
+
const PAGE_BYTES = 64 * 1024;
|
|
14
17
|
|
|
15
18
|
export const CODE_EXECUTION_TOOL_NAME = 'code_execution';
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
/** The isolate's settings. Each has a default. */
|
|
21
|
+
export interface IsolateSettings {
|
|
22
|
+
/** The bound a run or wait yields at, unless the agent asks otherwise. */
|
|
23
|
+
yieldMs: number;
|
|
24
|
+
/** The most an agent may ask for. */
|
|
25
|
+
maxYieldMs: number;
|
|
26
|
+
/** A script's limit: there it's stopped. */
|
|
27
|
+
scriptLifetimeMs: number;
|
|
28
|
+
/** Scripts one agent may have running at once, yielded ones included. */
|
|
29
|
+
maxRunningScripts: number;
|
|
30
|
+
/** Script children a host runs at once. */
|
|
31
|
+
maxScriptChildren: number;
|
|
32
|
+
/** How long a call may go unanswered before the script is told it timed out. */
|
|
33
|
+
toolCallTimeoutMs: number;
|
|
34
|
+
wakeMinIntervalMs: number;
|
|
35
|
+
maxWakesPerScript: number;
|
|
36
|
+
/**
|
|
37
|
+
* The WebAssembly memory's maximum for each script: its budget, a whole
|
|
38
|
+
* number of 64 KiB pages from 4 MiB to 2 GiB. A child stays within about its
|
|
39
|
+
* runtime's base plus 2.7 times this: the linear memory itself, and a result
|
|
40
|
+
* in transit, which takes two to five times its size and is refused past a
|
|
41
|
+
* third of this. Beside that come the script's calls as they go out, held
|
|
42
|
+
* while a result settles or not: at most 16 at once, the calls the prelude
|
|
43
|
+
* lets out, each with at most 4 MiB of JSON arguments, which the child holds
|
|
44
|
+
* as text and encodes, up to about 200 MiB under Node and 410 MiB under
|
|
45
|
+
* Bun. Measured on the child under Node 24.22.0 and Bun 1.4.3, whose base
|
|
46
|
+
* was about 85 and 55 MiB, at budgets from 32 MiB to 1 GiB.
|
|
47
|
+
*
|
|
48
|
+
* The host holds, for each script, the calls it has out and their answers:
|
|
49
|
+
* at most 16 calls out in the host at once, timed-out ones whose tools still
|
|
50
|
+
* run included, each with at most 4 MiB of JSON arguments holding 100,000
|
|
51
|
+
* values (about 25 MiB as text and parsed, by a probe of the costliest
|
|
52
|
+
* shapes under Node 24 and Bun 1.4), up to 16 more waiting for those as
|
|
53
|
+
* their text (at most 8 MiB each), up to 16 answers until the child takes
|
|
54
|
+
* them, each at most a third of this as its frame, and the one being
|
|
55
|
+
* encoded also as its JSON text (up to twice its bytes), the frame from the
|
|
56
|
+
* child being read (at most 25 MiB, and its text and its parse up to twice
|
|
57
|
+
* that each, since a string can take two bytes a character: 125 MiB), and
|
|
58
|
+
* its waiting wakes, at most 64 KiB of JSON each, up to 128 KiB as text.
|
|
59
|
+
* That's at most about 6 times this, plus 653 MiB,
|
|
60
|
+
* plus 128 KiB for each wake maxWakesPerScript allows: about 1.4 GiB a
|
|
61
|
+
* script at the defaults. A tool's
|
|
62
|
+
* own result, and the one serialization the bridge makes of it to check its
|
|
63
|
+
* size, are the tool's, outside this. Size a host by that and by the
|
|
64
|
+
* child's own memory.
|
|
65
|
+
*
|
|
66
|
+
* A result is sent only if it's at most a third of this; within that, what
|
|
67
|
+
* fits the script depends on its shape, since parsing builds it in this
|
|
68
|
+
* memory: at 128 MiB, a string or an array of numbers up to that third fits,
|
|
69
|
+
* and an array of small objects up to about 24 MiB, by a probe of each
|
|
70
|
+
* shape. A result that doesn't fit reaches the script as ResultTooLarge,
|
|
71
|
+
* which says the call took effect.
|
|
72
|
+
*/
|
|
73
|
+
memoryMaxBytes: number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const DEFAULT_SETTINGS: IsolateSettings = {
|
|
77
|
+
yieldMs: 30_000,
|
|
78
|
+
maxYieldMs: 600_000,
|
|
79
|
+
scriptLifetimeMs: 86_400_000,
|
|
80
|
+
maxRunningScripts: 3,
|
|
81
|
+
maxScriptChildren: 16,
|
|
82
|
+
toolCallTimeoutMs: 270_000,
|
|
83
|
+
wakeMinIntervalMs: 60_000,
|
|
84
|
+
maxWakesPerScript: 100,
|
|
85
|
+
memoryMaxBytes: 128 * 1024 * 1024,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/** What the Python runner took that the isolate doesn't, and what to set instead. */
|
|
89
|
+
const RETIRED: Record<string, string> = {
|
|
90
|
+
pythonPath: 'scripts are JavaScript now, run by an engine built into agent-framework, so there is no interpreter to name; leave it out',
|
|
91
|
+
idleReclaimMs: 'each script starts fresh and keeps nothing after it ends, so there is nothing to reclaim; leave it out',
|
|
92
|
+
env: "a script's world holds only your agent's tools, with no environment; leave it out",
|
|
93
|
+
inheritEnv: "a script's world holds only your agent's tools, with no environment; leave it out",
|
|
94
|
+
scriptTimeoutMs: 'a script now yields at its bound and keeps running: set yieldMs for the bound',
|
|
95
|
+
maxScriptTimeoutMs: 'set maxYieldMs, the most an agent may ask a run or a wait to wait',
|
|
96
|
+
backgroundMaxLifetimeMs: "every script now has one limit: set scriptLifetimeMs",
|
|
97
|
+
maxBackgroundScripts: 'set maxRunningScripts, how many scripts an agent may have running at once, yielded ones included',
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const MS_KEYS = ['yieldMs', 'maxYieldMs', 'scriptLifetimeMs', 'toolCallTimeoutMs', 'wakeMinIntervalMs'] as const;
|
|
101
|
+
const COUNT_KEYS = ['maxRunningScripts', 'maxScriptChildren', 'maxWakesPerScript', 'memoryMaxBytes'] as const;
|
|
102
|
+
/** Node's timer range: a timer longer than this fires at once. */
|
|
103
|
+
const MAX_TIMER_MS = 2_147_483_647;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* The isolate's settings from a `codeExecution` configuration that's on, with each
|
|
107
|
+
* default filled in. Throws, naming the key and what to do, for a key the
|
|
108
|
+
* Python runner took, or a value that isn't a whole number in range.
|
|
109
|
+
*/
|
|
110
|
+
export function isolateSettings(cfg: Record<string, unknown>): IsolateSettings {
|
|
111
|
+
for (const [key, why] of Object.entries(RETIRED)) {
|
|
112
|
+
if (cfg[key] !== undefined && cfg[key] !== null) throw new Error(`codeExecution.${key} is no longer read: ${why}`);
|
|
113
|
+
}
|
|
114
|
+
const out: IsolateSettings = { ...DEFAULT_SETTINGS };
|
|
115
|
+
for (const key of [...MS_KEYS, ...COUNT_KEYS]) {
|
|
116
|
+
const value = cfg[key];
|
|
117
|
+
if (value === undefined || value === null) continue;
|
|
118
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {
|
|
119
|
+
throw new Error(`codeExecution.${key} must be a whole number of ${MS_KEYS.includes(key as never) ? 'milliseconds' : 'units'} of 0 or more`);
|
|
120
|
+
}
|
|
121
|
+
if (MS_KEYS.includes(key as never) && value > MAX_TIMER_MS) {
|
|
122
|
+
throw new Error(`codeExecution.${key} must be at most ${MAX_TIMER_MS} ms, the longest a timer can wait`);
|
|
123
|
+
}
|
|
124
|
+
(out as unknown as Record<string, number>)[key] = value;
|
|
125
|
+
}
|
|
126
|
+
if (out.maxYieldMs < out.yieldMs) {
|
|
127
|
+
throw new Error(`codeExecution.maxYieldMs (${out.maxYieldMs}) must be at least yieldMs (${out.yieldMs}): the default is always allowed`);
|
|
128
|
+
}
|
|
129
|
+
if (out.maxRunningScripts < 1 || out.maxScriptChildren < 1) {
|
|
130
|
+
throw new Error('codeExecution.maxRunningScripts and maxScriptChildren must each be at least 1');
|
|
131
|
+
}
|
|
132
|
+
if (out.memoryMaxBytes % PAGE_BYTES !== 0 || out.memoryMaxBytes < MIN_MEMORY_BYTES || out.memoryMaxBytes > MAX_MEMORY_BYTES) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
`codeExecution.memoryMaxBytes must be a whole number of 64 KiB pages from ${MIN_MEMORY_BYTES} (4 MiB) to ${MAX_MEMORY_BYTES} (2 GiB), not ${out.memoryMaxBytes}`,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
return out;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function formatBytes(bytes: number): string {
|
|
141
|
+
const MiB = 1024 * 1024;
|
|
142
|
+
if (bytes % (1024 * MiB) === 0) return `${bytes / (1024 * MiB)} GiB`;
|
|
143
|
+
if (bytes % MiB === 0) return `${bytes / MiB} MiB`;
|
|
144
|
+
if (bytes % 1024 === 0) return `${bytes / 1024} KiB`;
|
|
145
|
+
return `${bytes} bytes`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* The `code_execution` tool as an agent is offered it under these settings,
|
|
150
|
+
* the `codeExecution` that `create()` takes (each left out has its default).
|
|
151
|
+
* A setting the Python runner took is refused by name, as `create()` refuses it.
|
|
152
|
+
*/
|
|
153
|
+
export function buildCodeExecutionToolDefinition(config: Partial<CodeExecutionConfig> = {}): ToolDefinition {
|
|
154
|
+
return describeCodeExecution(isolateSettings(config as unknown as Record<string, unknown>));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** The tool's definition under settings already resolved. */
|
|
158
|
+
export function describeCodeExecution(s: IsolateSettings): ToolDefinition {
|
|
159
|
+
const { headChars, tailChars } = DEFAULT_OUTPUT_BOUNDS;
|
|
160
|
+
const chars = (n: number) => n.toLocaleString('en-US');
|
|
27
161
|
return {
|
|
28
162
|
name: CODE_EXECUTION_TOOL_NAME,
|
|
29
163
|
description:
|
|
30
|
-
'Run
|
|
31
|
-
'
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
'
|
|
37
|
-
'
|
|
38
|
-
'
|
|
39
|
-
'
|
|
40
|
-
`
|
|
41
|
-
'
|
|
42
|
-
`
|
|
43
|
-
|
|
44
|
-
'
|
|
45
|
-
'
|
|
46
|
-
'
|
|
47
|
-
'
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
'
|
|
51
|
-
'
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
`A
|
|
58
|
-
`
|
|
59
|
-
'
|
|
60
|
-
'
|
|
61
|
-
'
|
|
62
|
-
|
|
63
|
-
'result before deciding the next step. ' +
|
|
64
|
-
'BACKGROUND MODE: pass background=true to run the script as a detached watcher that ' +
|
|
65
|
-
'outlives this turn — the tool returns immediately with a script_id and you can end ' +
|
|
66
|
-
'your turn (e.g. sleep). Inside a background script, await wake_agent(payload) wakes ' +
|
|
67
|
-
'you: the payload plus provenance (script id, the line number in your script, elapsed ' +
|
|
68
|
-
'time) is delivered into your context and starts a turn for you. A script that ends ' +
|
|
69
|
-
'without calling wake_agent wakes nobody — that silence is the point (poll cheaply, ' +
|
|
70
|
-
'wake only on signal). If your background script CRASHES you are woken with the error. ' +
|
|
71
|
-
'Its print() output streams to a workspace log file you can read any time. Wakes are ' +
|
|
72
|
-
'rate-limited (early wakes are delayed, not dropped) and capped per script. ' +
|
|
73
|
-
'CAUTION: background scripts die silently if the host process restarts — for a wake ' +
|
|
74
|
-
'you absolutely must not miss, also arm a wake rule as backup. ' +
|
|
75
|
-
'Manage your scripts with {"action": "list"} and {"action": "cancel", "script_id": "..."}.',
|
|
164
|
+
'Run JavaScript that calls your other tools, so that many calls, and the results between them, happen in one step and stay out of your context. ' +
|
|
165
|
+
'The script is the body of an async function: await at its top level, and return a value to see it. ' +
|
|
166
|
+
`The value comes back as JSON, and past ${chars(VALUE_CHARS)} characters as its first and last ${chars(VALUE_CHARS / 2)}. It's made in the script's memory, so a large one needs room there for its text twice over. ` +
|
|
167
|
+
'Call a tool by its exact name, as ALL_TOOLS gives it: await tools["module--tool"]({ ...its arguments }). ' +
|
|
168
|
+
'Every tool answers one shape, { content, structuredContent, isError }: content is a list of blocks, what you would have read, most often one { type: "text", text }; ' +
|
|
169
|
+
"structuredContent is the tool's data as a value, when it gives one beside that text, otherwise null; and isError is true when the tool failed, its text saying why. " +
|
|
170
|
+
'With no structuredContent, the answer is in content, most often its text: JSON.parse(result.content[0].text) reads one given as JSON. ' +
|
|
171
|
+
'A tool that turns a call down itself, such as for a missing argument, answers this way, with isError. ' +
|
|
172
|
+
"A call that can't go out (the tool isn't yours now, or its arguments aren't an object) doesn't answer: its await throws a ToolRefused error, and nothing is sent for it. " +
|
|
173
|
+
'A Promise.all holding it rejects with that error, while the calls beside it still go out. ' +
|
|
174
|
+
`A call's arguments may be up to ${formatBytes(MAX_ARGUMENT_BYTES)} of JSON with at most ${chars(MAX_ARGUMENT_VALUES)} values: ` +
|
|
175
|
+
'a generated file of a few MB of ordinary text fits as one string (quotes, backslashes and control characters take more room once escaped), and more goes in parts, over several calls. ' +
|
|
176
|
+
`ALL_TOOLS lists your tools, each with its name, description and inputSchema. Run independent calls together with Promise.all: up to ${MAX_CALLS_IN_FLIGHT} are out at once, and the rest wait their turn. ` +
|
|
177
|
+
`A call out that gets no answer within ${formatMs(s.toolCallTimeoutMs)} throws a TimeoutError that says whether it was sent: one never sent did nothing, but one sent may still take effect, so a retry may do it twice. ` +
|
|
178
|
+
'Write output with text(value) or console.log(...): only what the script writes and returns comes back to you, with how it ended and what became of its calls, ' +
|
|
179
|
+
'so filter large results in the script. ' +
|
|
180
|
+
'Each script starts fresh and keeps nothing after it ends: write what must last with a tool. ' +
|
|
181
|
+
'A script reaches nothing but your tools: no network, files, timers or packages. ' +
|
|
182
|
+
`A script has ${formatBytes(s.memoryMaxBytes)} of memory. A result too large for it, or nested more than ${chars(MAX_RESULT_DEPTH)} deep, doesn't reach the script: the call's ResultTooLarge error says the tool ran. ` +
|
|
183
|
+
`A run or a wait takes yield_time_ms, how long to wait for the script (default ${formatMs(s.yieldMs)}, at most ${formatMs(s.maxYieldMs)}). ` +
|
|
184
|
+
'If the script is still running then, you get what it has written, and it keeps running: ' +
|
|
185
|
+
'{"action": "wait", "script_id": ...} waits again, {"action": "stop", "script_id": ...} stops it, and {"action": "list"} lists your scripts. ' +
|
|
186
|
+
`Each return shows what the script wrote since the previous one: its first ${chars(headChars)} and last ${chars(tailChars)} characters, with a count of what was dropped between them. ` +
|
|
187
|
+
"A return longer than your inline cap for tool results (tool_result_inline_max_chars in agent_settings) has its output's first and last parts cut alike to fit; " +
|
|
188
|
+
"if the rest of the return leaves the output no room, the return is cut there as any long tool result is, keeping its start. " +
|
|
189
|
+
"You may leave a script running past your turn, unless the host names another agent as its primary agent, whose scripts alone outlive a turn: " +
|
|
190
|
+
'a yield says when yours will be stopped at your turn\'s end. ' +
|
|
191
|
+
`A script left running can wake you with await wake_agent(payload), a payload of at most ${formatBytes(MAX_WAKE_PAYLOAD_BYTES)} of JSON, ` +
|
|
192
|
+
`and you are woken if it fails, crashes or reaches its limit of ${formatMs(s.scriptLifetimeMs)}; a clean finish waits for your wait or list. ` +
|
|
193
|
+
'A script whose body returns while its calls are still running waits for them, and for the calls its pending work goes on to make: ' +
|
|
194
|
+
"it's still running until they're done. " +
|
|
195
|
+
'When a script ends, the result says how, what became of its calls (any still running when it was stopped may or may not have taken effect), ' +
|
|
196
|
+
`what it returned, and its output. You may have ${s.maxRunningScripts} scripts running at once.`,
|
|
76
197
|
inputSchema: {
|
|
77
198
|
type: 'object' as const,
|
|
78
199
|
properties: {
|
|
79
|
-
code: {
|
|
80
|
-
type: 'string',
|
|
81
|
-
description: 'Python code to execute. Top-level await is allowed.',
|
|
82
|
-
},
|
|
83
|
-
background: {
|
|
84
|
-
type: 'boolean',
|
|
85
|
-
description: 'Run detached as a background watcher with wake_agent() available (default false).',
|
|
86
|
-
},
|
|
200
|
+
code: { type: 'string', description: 'JavaScript to run, as the body of an async function.' },
|
|
87
201
|
action: {
|
|
88
202
|
type: 'string',
|
|
89
|
-
enum: ['run', '
|
|
90
|
-
description: 'run (default)
|
|
203
|
+
enum: ['run', 'wait', 'stop', 'list'],
|
|
204
|
+
description: 'run (default) runs code; wait and stop take a script_id; list shows your scripts.',
|
|
91
205
|
},
|
|
92
|
-
script_id: {
|
|
93
|
-
|
|
94
|
-
description: 'Background script id (for action: cancel).',
|
|
95
|
-
},
|
|
96
|
-
time_limit_ms: {
|
|
206
|
+
script_id: { type: 'string', description: 'The script to wait for or stop.' },
|
|
207
|
+
yield_time_ms: {
|
|
97
208
|
type: 'integer',
|
|
98
|
-
description:
|
|
99
|
-
`Time limit for this script in milliseconds; it is stopped when the limit is reached. ` +
|
|
100
|
-
`Default ${limits.defaultMs}, at most ${limits.maxMs}; a background script defaults to and is capped at ` +
|
|
101
|
-
`its ${formatLimit(limits.backgroundMaxMs)} lifetime.`,
|
|
209
|
+
description: `For a run or a wait: how long to wait for the script, in milliseconds, before it yields. Default ${s.yieldMs}, at most ${s.maxYieldMs}.`,
|
|
102
210
|
},
|
|
103
211
|
},
|
|
104
212
|
required: [],
|
|
@@ -106,98 +214,59 @@ export function buildCodeExecutionToolDefinition(opts?: {
|
|
|
106
214
|
};
|
|
107
215
|
}
|
|
108
216
|
|
|
217
|
+
/** The first Bun a script's process runs on reliably. */
|
|
218
|
+
export const MIN_BUN_VERSION = '1.4.0';
|
|
219
|
+
|
|
109
220
|
/**
|
|
110
|
-
*
|
|
111
|
-
* `
|
|
221
|
+
* Why code execution can't run on this Bun, or null when it can (and under
|
|
222
|
+
* Node, where `bun` is undefined). Bun 1.3.14 loses a child's fd 3, the pipe a
|
|
223
|
+
* script's process answers on, at some starts: in a probe, 30 of 200 children
|
|
224
|
+
* started one at a time lost it before their first write, where under Bun
|
|
225
|
+
* 1.4.0 through 1.4.3, and Node 24, none of 200 did.
|
|
112
226
|
*/
|
|
113
|
-
export function
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
227
|
+
export function bunVersionProblem(bun: string | null): string | null {
|
|
228
|
+
if (bun === null) return null;
|
|
229
|
+
const parts = (v: string) => v.split(/[.-]/).slice(0, 3).map((n) => Number.parseInt(n, 10) || 0);
|
|
230
|
+
const [have, need] = [parts(bun), parts(MIN_BUN_VERSION)];
|
|
231
|
+
for (let i = 0; i < 3; i++) {
|
|
232
|
+
if (have[i]! > need[i]!) return null;
|
|
233
|
+
if (have[i]! < need[i]!) {
|
|
234
|
+
return `codeExecution needs Bun ${MIN_BUN_VERSION} or later, and this host runs Bun ${bun}, ` +
|
|
235
|
+
"which at some starts loses the pipe a script's process answers on, crashing the script: " +
|
|
236
|
+
`move the host to Bun ${MIN_BUN_VERSION} or later, or run it on Node`;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// The floor's own version, as a prerelease (1.4.0-canary.1), comes before it,
|
|
240
|
+
// and no such build was checked.
|
|
241
|
+
return /^\d+\.\d+\.\d+-/.test(bun)
|
|
242
|
+
? `codeExecution needs Bun ${MIN_BUN_VERSION} or later, and this host runs Bun ${bun}, a build from before ${MIN_BUN_VERSION}'s release, ` +
|
|
243
|
+
`which hasn't been checked with it: move the host to Bun ${MIN_BUN_VERSION} or later, or run it on Node`
|
|
244
|
+
: null;
|
|
128
245
|
}
|
|
129
246
|
|
|
130
247
|
/**
|
|
131
248
|
* Refuse a codeExecution that isn't an object, or whose switch is set to
|
|
132
|
-
* anything but true or false, and, once it's on, one
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* would quietly keep the allowlist. A null or false codeExecution, and a null
|
|
140
|
-
* setting, count as not set, as left-out ones do. The refusal names the
|
|
141
|
-
* value's kind, not the value. A configuration that isn't on has nothing else
|
|
249
|
+
* anything but true or false, and, once it's on, one that sets what the
|
|
250
|
+
* Python runner took or a value out of range (isolateSettings), or that a Bun
|
|
251
|
+
* too old to run it would run (bunVersionProblem). A JSON config,
|
|
252
|
+
* or a `${VAR}` substituted as a string, can carry a quoted "false" where the
|
|
253
|
+
* type says boolean, and only `true` turns code execution on, so the quotes
|
|
254
|
+
* would hide what the value does. A null or false codeExecution counts as not
|
|
255
|
+
* set, as a left-out one does. A configuration that isn't on has nothing else
|
|
142
256
|
* read.
|
|
143
257
|
*/
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
scriptTimeoutMs?: number;
|
|
147
|
-
maxScriptTimeoutMs?: number;
|
|
148
|
-
env?: unknown;
|
|
149
|
-
inheritEnv?: unknown;
|
|
150
|
-
}): void {
|
|
258
|
+
/** `bun` is the Bun this runs on, null under Node: the running one's when left out. */
|
|
259
|
+
export function validateCodeExecutionConfig(cfg: unknown, bun: string | null = process.versions.bun ?? null): void {
|
|
151
260
|
if (!holdsSettings('codeExecution', cfg, '{ enabled: true }')) return;
|
|
261
|
+
const settings = cfg as Record<string, unknown>;
|
|
152
262
|
assertBooleanSetting(
|
|
153
263
|
'codeExecution.enabled',
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
);
|
|
158
|
-
if (cfg.enabled !== true) return;
|
|
159
|
-
const defaultMs = cfg.scriptTimeoutMs ?? 600_000;
|
|
160
|
-
if (cfg.maxScriptTimeoutMs !== undefined && !(cfg.maxScriptTimeoutMs >= defaultMs)) {
|
|
161
|
-
throw new Error(
|
|
162
|
-
`codeExecution.maxScriptTimeoutMs (${cfg.maxScriptTimeoutMs}) must be at least scriptTimeoutMs (${defaultMs}): ` +
|
|
163
|
-
'it is the most an agent may ask for, and the default is always allowed',
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
// None of the environment's refusals below shows the value it refuses,
|
|
167
|
-
// at most its kind: a substituted value can be a credential. null counts
|
|
168
|
-
// as not set, so a generated config that writes an unset setting as null
|
|
169
|
-
// keeps working.
|
|
170
|
-
assertBooleanSetting(
|
|
171
|
-
'codeExecution.inheritEnv',
|
|
172
|
-
cfg.inheritEnv,
|
|
173
|
-
"true hands the interpreter the host's whole environment, and false or leaving it out keeps the allowlist",
|
|
264
|
+
settings.enabled,
|
|
265
|
+
"true gives agents the code_execution tool, which runs their scripts in a JavaScript engine of the host's, " +
|
|
266
|
+
"and false or leaving it out doesn't",
|
|
174
267
|
);
|
|
175
|
-
if (
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
for (const [name, value] of Object.entries(cfg.env)) {
|
|
180
|
-
// spawn writes each variable as name=value: a name that is empty or
|
|
181
|
-
// holds '=' doesn't reach the interpreter as written, and a NUL in a
|
|
182
|
-
// name or a value makes spawn throw at every start.
|
|
183
|
-
// Only what comes before an '=' or NUL is shown: what follows can be a
|
|
184
|
-
// value pasted into the name.
|
|
185
|
-
if (name === '' || name.includes('=') || name.includes('\0')) {
|
|
186
|
-
const shown = name === '' ? 'that is empty' : `starting ${JSON.stringify(name.split(/[=\0]/, 1)[0])} that holds '=' or NUL`;
|
|
187
|
-
throw new Error(`codeExecution.env has a variable name ${shown}, and a name can't be empty or hold '=' or NUL`);
|
|
188
|
-
}
|
|
189
|
-
if (typeof value !== 'string') {
|
|
190
|
-
throw new Error(`codeExecution.env.${name} must be a string, not ${kindOf(value)}: give its value as a string, or leave ${name} out`);
|
|
191
|
-
}
|
|
192
|
-
if (value.includes('\0')) {
|
|
193
|
-
throw new Error(`codeExecution.env.${name} holds a NUL character, which no environment variable can carry`);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
200
|
-
if (typeof value !== 'object' || value === null) return false;
|
|
201
|
-
const proto = Object.getPrototypeOf(value);
|
|
202
|
-
return proto === Object.prototype || proto === null;
|
|
268
|
+
if (settings.enabled !== true) return;
|
|
269
|
+
isolateSettings(settings);
|
|
270
|
+
const problem = bunVersionProblem(bun);
|
|
271
|
+
if (problem) throw new Error(problem);
|
|
203
272
|
}
|
package/src/deadline-timer.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** The longest delay one setTimeout holds (2^31 - 1 ms, about 24.8 days).
|
|
2
2
|
* Node fires a longer one almost at once, with a TimeoutOverflowWarning. */
|
|
3
|
-
const MAX_TIMER_MS = 2_147_483_647;
|
|
3
|
+
export const MAX_TIMER_MS = 2_147_483_647;
|
|
4
4
|
|
|
5
5
|
type Hold = (timer: ReturnType<typeof setTimeout>) => void;
|
|
6
6
|
|