agentfootprint 9.6.0 → 9.7.0

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.
Files changed (98) hide show
  1. package/AGENTS.md +1 -1
  2. package/CLAUDE.md +1 -1
  3. package/ai-instructions/claude-code/SKILL.md +1 -1
  4. package/dist/adapters/code/agentcore.js +294 -0
  5. package/dist/adapters/code/agentcore.js.map +1 -0
  6. package/dist/adapters/code/local.js +200 -0
  7. package/dist/adapters/code/local.js.map +1 -0
  8. package/dist/core/Agent.js +132 -0
  9. package/dist/core/Agent.js.map +1 -1
  10. package/dist/core/RunnerBase.js +67 -0
  11. package/dist/core/RunnerBase.js.map +1 -1
  12. package/dist/core/agent/stages/toolCalls.js +90 -0
  13. package/dist/core/agent/stages/toolCalls.js.map +1 -1
  14. package/dist/core/codeRunnerTool.js +252 -0
  15. package/dist/core/codeRunnerTool.js.map +1 -0
  16. package/dist/core/toolSessions.js +396 -0
  17. package/dist/core/toolSessions.js.map +1 -0
  18. package/dist/core/tools.js.map +1 -1
  19. package/dist/doors/providers.js +13 -0
  20. package/dist/doors/providers.js.map +1 -1
  21. package/dist/esm/adapters/code/agentcore.d.ts +133 -0
  22. package/dist/esm/adapters/code/agentcore.js +290 -0
  23. package/dist/esm/adapters/code/agentcore.js.map +1 -0
  24. package/dist/esm/adapters/code/local.d.ts +99 -0
  25. package/dist/esm/adapters/code/local.js +196 -0
  26. package/dist/esm/adapters/code/local.js.map +1 -0
  27. package/dist/esm/adapters/types.d.ts +87 -0
  28. package/dist/esm/core/Agent.d.ts +65 -0
  29. package/dist/esm/core/Agent.js +133 -1
  30. package/dist/esm/core/Agent.js.map +1 -1
  31. package/dist/esm/core/RunnerBase.d.ts +51 -0
  32. package/dist/esm/core/RunnerBase.js +67 -0
  33. package/dist/esm/core/RunnerBase.js.map +1 -1
  34. package/dist/esm/core/agent/stages/toolCalls.d.ts +31 -0
  35. package/dist/esm/core/agent/stages/toolCalls.js +90 -0
  36. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
  37. package/dist/esm/core/agent/types.d.ts +23 -2
  38. package/dist/esm/core/codeRunnerTool.d.ts +120 -0
  39. package/dist/esm/core/codeRunnerTool.js +247 -0
  40. package/dist/esm/core/codeRunnerTool.js.map +1 -0
  41. package/dist/esm/core/toolSessions.d.ts +318 -0
  42. package/dist/esm/core/toolSessions.js +389 -0
  43. package/dist/esm/core/toolSessions.js.map +1 -0
  44. package/dist/esm/core/tools.d.ts +60 -0
  45. package/dist/esm/core/tools.js.map +1 -1
  46. package/dist/esm/doors/providers.d.ts +7 -0
  47. package/dist/esm/doors/providers.js +10 -0
  48. package/dist/esm/doors/providers.js.map +1 -1
  49. package/dist/esm/events/payloads.d.ts +50 -0
  50. package/dist/esm/events/registry.d.ts +9 -1
  51. package/dist/esm/events/registry.js +8 -0
  52. package/dist/esm/events/registry.js.map +1 -1
  53. package/dist/esm/index.d.ts +2 -0
  54. package/dist/esm/index.js +5 -0
  55. package/dist/esm/index.js.map +1 -1
  56. package/dist/esm/lib/mcp/mcpServe.js +37 -1
  57. package/dist/esm/lib/mcp/mcpServe.js.map +1 -1
  58. package/dist/esm/lib/trace-toolpack/traceToolpack.js +15 -1
  59. package/dist/esm/lib/trace-toolpack/traceToolpack.js.map +1 -1
  60. package/dist/events/registry.js +8 -0
  61. package/dist/events/registry.js.map +1 -1
  62. package/dist/index.js +14 -1
  63. package/dist/index.js.map +1 -1
  64. package/dist/lib/mcp/mcpServe.js +37 -1
  65. package/dist/lib/mcp/mcpServe.js.map +1 -1
  66. package/dist/lib/trace-toolpack/traceToolpack.js +15 -1
  67. package/dist/lib/trace-toolpack/traceToolpack.js.map +1 -1
  68. package/dist/types/adapters/code/agentcore.d.ts +134 -0
  69. package/dist/types/adapters/code/agentcore.d.ts.map +1 -0
  70. package/dist/types/adapters/code/local.d.ts +100 -0
  71. package/dist/types/adapters/code/local.d.ts.map +1 -0
  72. package/dist/types/adapters/types.d.ts +87 -0
  73. package/dist/types/adapters/types.d.ts.map +1 -1
  74. package/dist/types/core/Agent.d.ts +65 -0
  75. package/dist/types/core/Agent.d.ts.map +1 -1
  76. package/dist/types/core/RunnerBase.d.ts +51 -0
  77. package/dist/types/core/RunnerBase.d.ts.map +1 -1
  78. package/dist/types/core/agent/stages/toolCalls.d.ts +31 -0
  79. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
  80. package/dist/types/core/agent/types.d.ts +23 -2
  81. package/dist/types/core/agent/types.d.ts.map +1 -1
  82. package/dist/types/core/codeRunnerTool.d.ts +121 -0
  83. package/dist/types/core/codeRunnerTool.d.ts.map +1 -0
  84. package/dist/types/core/toolSessions.d.ts +319 -0
  85. package/dist/types/core/toolSessions.d.ts.map +1 -0
  86. package/dist/types/core/tools.d.ts +60 -0
  87. package/dist/types/core/tools.d.ts.map +1 -1
  88. package/dist/types/doors/providers.d.ts +7 -0
  89. package/dist/types/doors/providers.d.ts.map +1 -1
  90. package/dist/types/events/payloads.d.ts +50 -0
  91. package/dist/types/events/payloads.d.ts.map +1 -1
  92. package/dist/types/events/registry.d.ts +9 -1
  93. package/dist/types/events/registry.d.ts.map +1 -1
  94. package/dist/types/index.d.ts +2 -0
  95. package/dist/types/index.d.ts.map +1 -1
  96. package/dist/types/lib/mcp/mcpServe.d.ts.map +1 -1
  97. package/dist/types/lib/trace-toolpack/traceToolpack.d.ts.map +1 -1
  98. package/package.json +1 -1
@@ -0,0 +1,290 @@
1
+ /**
2
+ * agentCoreCodeRunner — AWS Bedrock AgentCore Code Interpreter behind the
3
+ * {@link CodeRunner} port (peer-dep `@aws-sdk/client-bedrock-agentcore`).
4
+ *
5
+ * import { agentCoreCodeRunner } from 'agentfootprint/providers';
6
+ * const runner = agentCoreCodeRunner({ region: 'us-east-1', identifier: 'aws.codeinterpreter.v1' });
7
+ *
8
+ * A REAL sandbox, which is the point: `localCodeRunner` gives you process
9
+ * isolation on your own machine and says so; this gives you a managed,
10
+ * network-and-filesystem-isolated environment, and the tool code is identical
11
+ * across the swap.
12
+ *
13
+ * ── The three operations, verified against the SDK ──────────────────────────
14
+ * Pinned in `test/adapters/aws/awsCommandPin.ts`, and verified against a real
15
+ * install of `@aws-sdk/client-bedrock-agentcore` 3.1108.0:
16
+ *
17
+ * • `StartCodeInterpreterSessionCommand`
18
+ * in `{ codeInterpreterIdentifier, name?, sessionTimeoutSeconds? }`
19
+ * out `{ codeInterpreterIdentifier, sessionId, createdAt }`
20
+ * • `InvokeCodeInterpreterCommand`
21
+ * in `{ codeInterpreterIdentifier, sessionId, name: 'executeCode',
22
+ * arguments: { code, language } }`
23
+ * out `{ sessionId, stream }` — an **event stream**, not a body (below)
24
+ * • `StopCodeInterpreterSessionCommand`
25
+ * in `{ codeInterpreterIdentifier, sessionId }` ← the session ID, not a URI
26
+ * out `{ codeInterpreterIdentifier, sessionId, lastUpdatedAt }`
27
+ *
28
+ * **`Invoke` answers with an `AsyncIterable`.** `InvokeCodeInterpreterResponse`
29
+ * is `{ sessionId?, stream?: AsyncIterable<CodeInterpreterStreamOutput> }`, and
30
+ * every member of that union is either `{ result }` or a modelled EXCEPTION —
31
+ * `accessDeniedException`, `throttlingException`, `validationException`, and
32
+ * four more. An adapter that read a `body` field would find `undefined` and
33
+ * report an empty success on every call, and one that iterated only for
34
+ * `result` would treat an AccessDenied as "the code printed nothing." So this
35
+ * drains the stream, raises the exception members BY NAME, and folds the
36
+ * result members into one `CodeResult`.
37
+ *
38
+ * The payload lands twice: `structuredContent` carries `{ stdout, stderr,
39
+ * exitCode, executionTime }` and `content[]` carries typed blocks. The
40
+ * structured half is preferred because it is typed; the text blocks are the
41
+ * fallback for a response that only filled the other one.
42
+ *
43
+ * ── How this talks to the SDK (the 9.4.0 law) ───────────────────────────────
44
+ * Through `client.send(new SomeCommand(input))`, never a method on the client.
45
+ * A bare `@aws-sdk/client-*` **Client is command-based**: its prototype carries
46
+ * `send` and `destroy` and nothing else — verified again for this adapter
47
+ * (`BedrockAgentCoreClient.prototype.startCodeInterpreterSession` is
48
+ * `undefined`; the shortcut exists only on the aggregated `BedrockAgentCore`).
49
+ * Three adapters have shipped that bug in this package.
50
+ *
51
+ * ── Credentials ─────────────────────────────────────────────────────────────
52
+ * Standard AWS credential resolution (the SDK's own chain). A tool holding a
53
+ * long-lived session must NOT cache a `Credential` object from `ctx.credential`
54
+ * past the call that produced it — a session outliving a run outlives its
55
+ * token. Re-resolve per execute through `ctx.credentials`.
56
+ *
57
+ * Pattern: Adapter (GoF) + lazy peer-dep load — the SDK is required only when
58
+ * `start()` first runs (or never, if you inject `_client` / `_sdk`).
59
+ */
60
+ import { lazyRequire } from '../../lib/lazyRequire.js';
61
+ const DEFAULT_MAX_OUTPUT_CHARS = 8_000;
62
+ /** The service's own name for "run this code". Not a name we chose. */
63
+ const EXECUTE_CODE = 'executeCode';
64
+ export function agentCoreCodeRunner(options) {
65
+ const id = options.id ?? 'agentcore-code-runner';
66
+ const maxOutputChars = options.maxOutputChars ?? DEFAULT_MAX_OUTPUT_CHARS;
67
+ let client;
68
+ const resolve = () => {
69
+ client ??= options._client ?? createCodeClient(options);
70
+ return client;
71
+ };
72
+ return {
73
+ id,
74
+ async start(req) {
75
+ const api = resolve();
76
+ const started = await api.startSession({
77
+ codeInterpreterIdentifier: options.identifier,
78
+ // The isolation key names the session on AWS's side too, so an operator
79
+ // reading the console sees the same partition the runtime enforces. It
80
+ // is a HASH-free label AWS documents as non-unique; the key is already
81
+ // the caller's own composition, never widened here.
82
+ name: sessionName(req.key),
83
+ ...(options.sessionTimeoutSeconds !== undefined && {
84
+ sessionTimeoutSeconds: options.sessionTimeoutSeconds,
85
+ }),
86
+ });
87
+ const sessionId = started.sessionId;
88
+ if (!sessionId) {
89
+ throw new Error('agentCoreCodeRunner: StartCodeInterpreterSession returned no sessionId. ' +
90
+ 'Nothing can be invoked or stopped without one, so this is raised rather than ' +
91
+ 'carried forward as an unusable session.');
92
+ }
93
+ let stopped = false;
94
+ return {
95
+ id: sessionId,
96
+ async execute(exec) {
97
+ if (stopped) {
98
+ throw new Error(`agentCoreCodeRunner: session ${sessionId} was stopped; open a new one to run more code.`);
99
+ }
100
+ const answer = await api.invoke({
101
+ codeInterpreterIdentifier: options.identifier,
102
+ sessionId,
103
+ name: EXECUTE_CODE,
104
+ arguments: {
105
+ code: exec.code,
106
+ ...(exec.language ?? req.language ?? options.language
107
+ ? { language: exec.language ?? req.language ?? options.language ?? 'python' }
108
+ : {}),
109
+ },
110
+ });
111
+ const stdout = cut(answer.stdout, maxOutputChars);
112
+ const stderr = cut(answer.stderr, maxOutputChars);
113
+ const truncated = {
114
+ ...(stdout.cut && { stdout: true }),
115
+ ...(stderr.cut && { stderr: true }),
116
+ ...((stdout.cut || stderr.cut) && {
117
+ ofChars: Math.max(answer.stdout.length, answer.stderr.length),
118
+ }),
119
+ };
120
+ return {
121
+ // `isError` is the service's own verdict; a non-zero exit is ours.
122
+ ok: answer.isError !== true && (answer.exitCode ?? 0) === 0,
123
+ stdout: stdout.text,
124
+ stderr: stderr.text,
125
+ ...(answer.exitCode !== undefined && { exitCode: answer.exitCode }),
126
+ ...(Object.keys(truncated).length > 0 && { truncated }),
127
+ };
128
+ },
129
+ async stop() {
130
+ if (stopped)
131
+ return;
132
+ stopped = true;
133
+ try {
134
+ await api.stopSession({
135
+ codeInterpreterIdentifier: options.identifier,
136
+ sessionId,
137
+ });
138
+ }
139
+ catch (err) {
140
+ // "Already gone" is the EXPECTED shape here, not an incident: the
141
+ // session TTL is enforced by AWS, so a run that idled past it finds
142
+ // the session collected. Anything else is re-raised, and the tier
143
+ // reports it on `tools.session_close_failed`.
144
+ if (!isAlreadyGone(err))
145
+ throw err;
146
+ }
147
+ },
148
+ };
149
+ },
150
+ };
151
+ }
152
+ /** A session label from the isolation key — AWS's `name` is a human handle. */
153
+ function sessionName(key) {
154
+ // Keep it recognisable and within the service's naming charset.
155
+ return `af-${key.replace(/[^A-Za-z0-9_-]/g, '-')}`.slice(0, 100);
156
+ }
157
+ function isAlreadyGone(err) {
158
+ const name = err instanceof Error ? err.name : '';
159
+ return name === 'ResourceNotFoundException' || name === 'ValidationException';
160
+ }
161
+ /**
162
+ * Map {@link AgentCoreCodeClientLike} onto the real SDK commands.
163
+ *
164
+ * Two things this function owns and nothing else does: the COMMAND FORM (see
165
+ * the module header), and the DRAIN of `InvokeCodeInterpreterResponse.stream`.
166
+ */
167
+ function createCodeClient(options) {
168
+ let mod;
169
+ if (options._sdk) {
170
+ mod = options._sdk;
171
+ }
172
+ else {
173
+ try {
174
+ // Lazy peer-dep: only loaded when no _client/_sdk is injected and start() runs.
175
+ mod = lazyRequire('@aws-sdk/client-bedrock-agentcore');
176
+ }
177
+ catch {
178
+ throw new Error('agentCoreCodeRunner requires the `@aws-sdk/client-bedrock-agentcore` peer dependency.\n' +
179
+ ' Install: npm install @aws-sdk/client-bedrock-agentcore\n' +
180
+ ' Or pass `_client` for a pre-built or mock client.\n' +
181
+ ' For a local dev loop with no AWS at all, use `localCodeRunner()`.');
182
+ }
183
+ }
184
+ if (!mod.BedrockAgentCoreClient) {
185
+ throw new Error('agentCoreCodeRunner: `@aws-sdk/client-bedrock-agentcore` is installed but ' +
186
+ '`BedrockAgentCoreClient` was not found. Update the SDK.');
187
+ }
188
+ const sdk = new mod.BedrockAgentCoreClient({ ...(options.region && { region: options.region }) });
189
+ const send = async (Ctor, name, input) => {
190
+ if (!Ctor) {
191
+ throw new Error(`agentCoreCodeRunner: \`@aws-sdk/client-bedrock-agentcore\` is missing ${name}. ` +
192
+ 'Upgrade the SDK, or pass `_client` with your own mapping.');
193
+ }
194
+ return sdk.send(new Ctor(input));
195
+ };
196
+ return {
197
+ async startSession(input) {
198
+ const r = (await send(mod.StartCodeInterpreterSessionCommand, 'StartCodeInterpreterSessionCommand', input));
199
+ return { ...(r?.sessionId !== undefined && { sessionId: r.sessionId }) };
200
+ },
201
+ async invoke(input) {
202
+ const r = (await send(mod.InvokeCodeInterpreterCommand, 'InvokeCodeInterpreterCommand', input));
203
+ return drainStream(r?.stream);
204
+ },
205
+ async stopSession(input) {
206
+ await send(mod.StopCodeInterpreterSessionCommand, 'StopCodeInterpreterSessionCommand', input);
207
+ },
208
+ };
209
+ }
210
+ /** Every modelled error member of the stream union, in SDK spelling. */
211
+ const STREAM_ERROR_MEMBERS = [
212
+ 'accessDeniedException',
213
+ 'conflictException',
214
+ 'internalServerException',
215
+ 'resourceNotFoundException',
216
+ 'serviceQuotaExceededException',
217
+ 'throttlingException',
218
+ 'validationException',
219
+ ];
220
+ /**
221
+ * Drain the event stream into one answer.
222
+ *
223
+ * An ERROR MEMBER RAISES. This is the honesty line for this adapter: the SDK
224
+ * models seven failure shapes as ordinary members of the stream union, so an
225
+ * `AccessDeniedException` arrives as a value, not a rejection. Folding it in
226
+ * as empty output would report a clean run in which the code "printed
227
+ * nothing" — a silent success, at the exact moment an operator most needs the
228
+ * word "AccessDenied".
229
+ */
230
+ async function drainStream(stream) {
231
+ if (!stream) {
232
+ throw new Error('agentCoreCodeRunner: InvokeCodeInterpreter returned no stream. The response carries ' +
233
+ 'its payload as an event stream (`response.stream`), so an absent one is a broken ' +
234
+ 'call, not an empty result.');
235
+ }
236
+ let stdout = '';
237
+ let stderr = '';
238
+ let exitCode;
239
+ let isError = false;
240
+ for await (const event of stream) {
241
+ for (const member of STREAM_ERROR_MEMBERS) {
242
+ const raised = event[member];
243
+ if (raised) {
244
+ const error = new Error(`agentCoreCodeRunner: ${member} from InvokeCodeInterpreter — ` +
245
+ `${raised.message ?? 'no message supplied'}`);
246
+ error.name = member.charAt(0).toUpperCase() + member.slice(1);
247
+ throw error;
248
+ }
249
+ }
250
+ const result = event.result;
251
+ if (!result)
252
+ continue;
253
+ if (result.isError === true)
254
+ isError = true;
255
+ const structured = result.structuredContent;
256
+ if (structured) {
257
+ if (structured.stdout !== undefined)
258
+ stdout += structured.stdout;
259
+ if (structured.stderr !== undefined)
260
+ stderr += structured.stderr;
261
+ if (structured.exitCode !== undefined)
262
+ exitCode = structured.exitCode;
263
+ }
264
+ else {
265
+ // Fallback: a response that filled only the typed content blocks. Text
266
+ // blocks are the readable half; a binary/resource block is described by
267
+ // name rather than inlined, because inlining it is the bug this port exists
268
+ // to prevent.
269
+ for (const block of result.content ?? []) {
270
+ if (block.text !== undefined)
271
+ stdout += block.text;
272
+ else if (block.name !== undefined)
273
+ stdout += `[${block.type ?? 'resource'}: ${block.name}]`;
274
+ }
275
+ }
276
+ }
277
+ return {
278
+ stdout,
279
+ stderr,
280
+ ...(exitCode !== undefined && { exitCode }),
281
+ ...(isError && { isError }),
282
+ };
283
+ }
284
+ /** Cut to `max` characters, saying whether it cut. */
285
+ function cut(text, max) {
286
+ if (text.length <= max)
287
+ return { text, cut: false };
288
+ return { text: text.slice(0, max), cut: true };
289
+ }
290
+ //# sourceMappingURL=agentcore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentcore.js","sourceRoot":"","sources":["../../../../src/adapters/code/agentcore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * localCodeRunner — run code in a child process, on this machine.
3
+ *
4
+ * Pattern: Adapter (GoF) over `node:child_process`.
5
+ * Role: the dev default behind the {@link CodeRunner} port. `agentCoreCodeRunner`
6
+ * is the production swap; the tool code does not change.
7
+ * Emits: nothing. The tool that owns the session emits.
8
+ *
9
+ * ── ISOLATION, NOT A SANDBOX. Read this before deploying it. ────────────────
10
+ * The name is `localCodeRunner`, never `sandboxedCodeRunner`, and the
11
+ * difference is not modesty — it is the whole security posture.
12
+ *
13
+ * What a child process DOES give you:
14
+ * • a separate process and heap — a crash or an OOM takes the child, not you;
15
+ * • kill on timeout, so runaway code has a ceiling;
16
+ * • no inherited stdin, so nothing can block waiting for a terminal;
17
+ * • an environment ALLOWLIST — `process.env` is not inherited (only `PATH`,
18
+ * so the interpreter can be found), so an `AWS_SECRET_ACCESS_KEY` in your
19
+ * shell is not in the model's reach;
20
+ * • a working directory, by convention.
21
+ *
22
+ * What it does NOT give you, at all:
23
+ * • a filesystem jail — the code can read and write anywhere this process can;
24
+ * • a network jail — it can call out;
25
+ * • CPU or memory limits beyond the timeout;
26
+ * • any protection from code that deletes something outside `cwd`.
27
+ *
28
+ * So: a development loop, a trusted-input pipeline, a machine you would be
29
+ * relaxed about a shell script running on. NOT arbitrary model-written code
30
+ * from an untrusted user, on a host with anything on it. For that, run a real
31
+ * sandbox behind the same port — `agentCoreCodeRunner`, a gVisor container, a
32
+ * Firecracker VM — and keep the tool identical.
33
+ *
34
+ * **In-process `eval` / `node:vm` is refused outright.** Node's own
35
+ * documentation says `vm` is not a security mechanism ("do not use it to run
36
+ * untrusted code"), so shipping it as one would be theater: the same code
37
+ * reaching the same globals, wearing a word that makes a reader stop checking.
38
+ * A subprocess is genuinely a boundary; it is just a smaller one than the word
39
+ * "sandbox" implies. The library teaches refusals for things that are WRONG and
40
+ * honest names for things that are merely LIMITED — running local code in a dev
41
+ * loop is not wrong, and calling it a sandbox is.
42
+ *
43
+ * @example
44
+ * const agent = Agent.create({ provider })
45
+ * .tool(codeRunnerTool({ runner: localCodeRunner() }))
46
+ * .build();
47
+ */
48
+ import type { CodeRunner } from '../types.js';
49
+ export interface LocalCodeRunnerOptions {
50
+ /**
51
+ * How to run a snippet, as `[command, ...args]` — the code is appended as the
52
+ * final argument. Defaults by language: `['node', '-e']` for javascript,
53
+ * `['python3', '-c']` for python.
54
+ */
55
+ readonly command?: readonly string[];
56
+ /** Working directory for the child. Defaults to `process.cwd()`. */
57
+ readonly cwd?: string;
58
+ /**
59
+ * The child's environment. An ALLOWLIST, never a merge: `process.env` is NOT
60
+ * inherited, so a credential sitting in this process's environment is not
61
+ * handed to model-written code by default. Pass exactly what the code needs.
62
+ *
63
+ * ONE exception, stated because an unstated one is a hole: `PATH` is passed
64
+ * through, because without it the operating system cannot find the
65
+ * interpreter and nothing runs at all. `PATH` names directories, not secrets.
66
+ * Set `env: { PATH: '/usr/bin' }` to narrow it, or `env: { PATH: '' }` to
67
+ * refuse even that — anything you supply here WINS over the inherited value.
68
+ */
69
+ readonly env?: Readonly<Record<string, string>>;
70
+ /** Per-execution ceiling; the child is killed past it. Default 30s. */
71
+ readonly timeoutMs?: number;
72
+ /**
73
+ * Per-stream output ceiling, in characters. Default 8000.
74
+ *
75
+ * Cutting is allowed; cutting SILENTLY is not — anything cut is reported on
76
+ * `CodeResult.truncated`, and `codeRunnerTool` renders that as a visible
77
+ * marker in the tool result. The model has to know the table it is about to
78
+ * reason over is a fragment.
79
+ */
80
+ readonly maxOutputChars?: number;
81
+ /** Stable id (default `'local-code-runner'`). Rides the session events. */
82
+ readonly id?: string;
83
+ /** @internal Test seam — the `node:child_process` module. */
84
+ readonly _childProcess?: ChildProcessModuleLike;
85
+ }
86
+ /** The slice of `node:child_process` this adapter touches. */
87
+ export interface ChildProcessModuleLike {
88
+ readonly execFile?: (file: string, args: readonly string[], options: {
89
+ cwd?: string;
90
+ env?: Record<string, string>;
91
+ timeout?: number;
92
+ maxBuffer?: number;
93
+ signal?: AbortSignal;
94
+ }, callback: (error: (Error & {
95
+ code?: number | string;
96
+ killed?: boolean;
97
+ }) | null, stdout: string, stderr: string) => void) => unknown;
98
+ }
99
+ export declare function localCodeRunner(options?: LocalCodeRunnerOptions): CodeRunner;
@@ -0,0 +1,196 @@
1
+ /**
2
+ * localCodeRunner — run code in a child process, on this machine.
3
+ *
4
+ * Pattern: Adapter (GoF) over `node:child_process`.
5
+ * Role: the dev default behind the {@link CodeRunner} port. `agentCoreCodeRunner`
6
+ * is the production swap; the tool code does not change.
7
+ * Emits: nothing. The tool that owns the session emits.
8
+ *
9
+ * ── ISOLATION, NOT A SANDBOX. Read this before deploying it. ────────────────
10
+ * The name is `localCodeRunner`, never `sandboxedCodeRunner`, and the
11
+ * difference is not modesty — it is the whole security posture.
12
+ *
13
+ * What a child process DOES give you:
14
+ * • a separate process and heap — a crash or an OOM takes the child, not you;
15
+ * • kill on timeout, so runaway code has a ceiling;
16
+ * • no inherited stdin, so nothing can block waiting for a terminal;
17
+ * • an environment ALLOWLIST — `process.env` is not inherited (only `PATH`,
18
+ * so the interpreter can be found), so an `AWS_SECRET_ACCESS_KEY` in your
19
+ * shell is not in the model's reach;
20
+ * • a working directory, by convention.
21
+ *
22
+ * What it does NOT give you, at all:
23
+ * • a filesystem jail — the code can read and write anywhere this process can;
24
+ * • a network jail — it can call out;
25
+ * • CPU or memory limits beyond the timeout;
26
+ * • any protection from code that deletes something outside `cwd`.
27
+ *
28
+ * So: a development loop, a trusted-input pipeline, a machine you would be
29
+ * relaxed about a shell script running on. NOT arbitrary model-written code
30
+ * from an untrusted user, on a host with anything on it. For that, run a real
31
+ * sandbox behind the same port — `agentCoreCodeRunner`, a gVisor container, a
32
+ * Firecracker VM — and keep the tool identical.
33
+ *
34
+ * **In-process `eval` / `node:vm` is refused outright.** Node's own
35
+ * documentation says `vm` is not a security mechanism ("do not use it to run
36
+ * untrusted code"), so shipping it as one would be theater: the same code
37
+ * reaching the same globals, wearing a word that makes a reader stop checking.
38
+ * A subprocess is genuinely a boundary; it is just a smaller one than the word
39
+ * "sandbox" implies. The library teaches refusals for things that are WRONG and
40
+ * honest names for things that are merely LIMITED — running local code in a dev
41
+ * loop is not wrong, and calling it a sandbox is.
42
+ *
43
+ * @example
44
+ * const agent = Agent.create({ provider })
45
+ * .tool(codeRunnerTool({ runner: localCodeRunner() }))
46
+ * .build();
47
+ */
48
+ import { lazyRequire } from '../../lib/lazyRequire.js';
49
+ const DEFAULT_TIMEOUT_MS = 30_000;
50
+ const DEFAULT_MAX_OUTPUT_CHARS = 8_000;
51
+ /** How each supported language is invoked when no `command` was given. */
52
+ const DEFAULT_COMMANDS = {
53
+ javascript: ['node', '-e'],
54
+ js: ['node', '-e'],
55
+ node: ['node', '-e'],
56
+ typescript: ['npx', 'tsx', '-e'],
57
+ ts: ['npx', 'tsx', '-e'],
58
+ python: ['python3', '-c'],
59
+ python3: ['python3', '-c'],
60
+ py: ['python3', '-c'],
61
+ };
62
+ export function localCodeRunner(options = {}) {
63
+ const id = options.id ?? 'local-code-runner';
64
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
65
+ const maxOutputChars = options.maxOutputChars ?? DEFAULT_MAX_OUTPUT_CHARS;
66
+ return {
67
+ id,
68
+ start(req) {
69
+ // A local session is a NAME and a working directory, not a live handle:
70
+ // each execution is its own process. Saying so matters — a consumer who
71
+ // assumed variables carry between calls (they do on AgentCore, whose
72
+ // session is a live kernel) would silently get different semantics.
73
+ // `codeRunnerTool` states this in the tool description it hands the model.
74
+ const sessionId = `local:${req.key}`;
75
+ let stopped = false;
76
+ return Promise.resolve({
77
+ id: sessionId,
78
+ async execute(exec) {
79
+ if (stopped) {
80
+ throw new Error(`localCodeRunner: session ${sessionId} was stopped; open a new one to run more code.`);
81
+ }
82
+ const language = exec.language ?? req.language ?? 'javascript';
83
+ const command = options.command ?? DEFAULT_COMMANDS[language.toLowerCase()];
84
+ if (!command || command.length === 0) {
85
+ throw new Error(`localCodeRunner: no command for language '${language}'. ` +
86
+ `Known: ${Object.keys(DEFAULT_COMMANDS).join(', ')}. ` +
87
+ "Pass `command: ['your-interpreter', '-c']` for anything else.");
88
+ }
89
+ const [file, ...args] = command;
90
+ const raw = await runChild(resolveChildProcess(options), file, [...args, exec.code], {
91
+ cwd: options.cwd ?? process.cwd(),
92
+ // ALLOWLIST. `process.env` is deliberately NOT spread in — only
93
+ // PATH, so the OS can find the interpreter, and it is overridable.
94
+ env: { PATH: process.env.PATH ?? '', ...(options.env ?? {}) },
95
+ timeoutMs: exec.timeoutMs ?? timeoutMs,
96
+ ...(exec.signal && { signal: exec.signal }),
97
+ });
98
+ const stdout = cut(raw.stdout, maxOutputChars);
99
+ const stderr = cut(raw.stderr, maxOutputChars);
100
+ const truncated = {
101
+ ...(stdout.cut && { stdout: true }),
102
+ ...(stderr.cut && { stderr: true }),
103
+ ...((stdout.cut || stderr.cut) && {
104
+ ofChars: Math.max(raw.stdout.length, raw.stderr.length),
105
+ }),
106
+ };
107
+ return {
108
+ ok: raw.exitCode === 0,
109
+ stdout: stdout.text,
110
+ stderr: stderr.text,
111
+ ...(raw.exitCode !== undefined && { exitCode: raw.exitCode }),
112
+ // Present IFF something was actually cut — an empty object here
113
+ // would read as "truncation happened, magnitude unknown".
114
+ ...(Object.keys(truncated).length > 0 && { truncated }),
115
+ };
116
+ },
117
+ stop() {
118
+ // Nothing to release: each execution already ended with its process.
119
+ // Idempotent, and it refuses later executions rather than silently
120
+ // starting a fresh process under a session the caller closed.
121
+ stopped = true;
122
+ return Promise.resolve();
123
+ },
124
+ });
125
+ },
126
+ };
127
+ }
128
+ function resolveChildProcess(options) {
129
+ if (options._childProcess)
130
+ return options._childProcess;
131
+ try {
132
+ return lazyRequire('node:child_process');
133
+ }
134
+ catch {
135
+ throw new Error('localCodeRunner needs `node:child_process`, which this runtime does not provide ' +
136
+ '(a browser bundle, or a restricted worker). Use a remote runner — ' +
137
+ '`agentCoreCodeRunner` — or supply your own `CodeRunner`.');
138
+ }
139
+ }
140
+ /**
141
+ * One child process, promisified.
142
+ *
143
+ * A NON-ZERO EXIT IS NOT A REJECTION. Code that fails is a normal answer here —
144
+ * the model wrote it, it needs to read the traceback, and turning that into a
145
+ * thrown tool error would replace the one thing that teaches the next attempt
146
+ * with `error: true`. What DOES reject is the runner failing to run at all
147
+ * (interpreter missing, timeout, abort), because that is not the code's answer.
148
+ */
149
+ async function runChild(mod, file, args, opts) {
150
+ const execFile = mod.execFile;
151
+ if (typeof execFile !== 'function') {
152
+ throw new Error('localCodeRunner: `node:child_process` resolved but `execFile` is missing.');
153
+ }
154
+ return new Promise((resolve, reject) => {
155
+ execFile(file, args, {
156
+ cwd: opts.cwd,
157
+ env: opts.env,
158
+ timeout: opts.timeoutMs,
159
+ // Generous, because the CUT is ours to make and to report — letting the
160
+ // runtime's own buffer overflow would surface as an error whose message
161
+ // says nothing about how much was lost.
162
+ maxBuffer: 32 * 1024 * 1024,
163
+ ...(opts.signal && { signal: opts.signal }),
164
+ }, (error, stdout, stderr) => {
165
+ if (!error) {
166
+ resolve({ stdout: String(stdout ?? ''), stderr: String(stderr ?? ''), exitCode: 0 });
167
+ return;
168
+ }
169
+ if (error.killed === true) {
170
+ reject(new Error(`localCodeRunner: the code did not finish within ${opts.timeoutMs}ms and the ` +
171
+ 'process was killed. Raise `timeoutMs`, or have the code do less per call.'));
172
+ return;
173
+ }
174
+ if (typeof error.code === 'string') {
175
+ // ENOENT and friends — the interpreter itself is not here. Naming it
176
+ // beats handing the model a traceback it cannot act on.
177
+ reject(new Error(`localCodeRunner: could not run '${file}' (${error.code}). ` +
178
+ 'Install the interpreter, or pass `command` pointing at one.'));
179
+ return;
180
+ }
181
+ // A real non-zero exit: the code ran and failed. That IS the result.
182
+ resolve({
183
+ stdout: String(stdout ?? ''),
184
+ stderr: String(stderr ?? '') || error.message,
185
+ exitCode: typeof error.code === 'number' ? error.code : 1,
186
+ });
187
+ });
188
+ });
189
+ }
190
+ /** Cut to `max` characters, saying whether it cut. */
191
+ function cut(text, max) {
192
+ if (text.length <= max)
193
+ return { text, cut: false };
194
+ return { text: text.slice(0, max), cut: true };
195
+ }
196
+ //# sourceMappingURL=local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.js","sourceRoot":"","sources":["../../../../src/adapters/code/local.ts"],"names":[],"mappings":"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"}