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.
- package/AGENTS.md +1 -1
- package/CLAUDE.md +1 -1
- package/ai-instructions/claude-code/SKILL.md +1 -1
- package/dist/adapters/code/agentcore.js +294 -0
- package/dist/adapters/code/agentcore.js.map +1 -0
- package/dist/adapters/code/local.js +200 -0
- package/dist/adapters/code/local.js.map +1 -0
- package/dist/core/Agent.js +132 -0
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/RunnerBase.js +67 -0
- package/dist/core/RunnerBase.js.map +1 -1
- package/dist/core/agent/stages/toolCalls.js +90 -0
- package/dist/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/core/codeRunnerTool.js +252 -0
- package/dist/core/codeRunnerTool.js.map +1 -0
- package/dist/core/toolSessions.js +396 -0
- package/dist/core/toolSessions.js.map +1 -0
- package/dist/core/tools.js.map +1 -1
- package/dist/doors/providers.js +13 -0
- package/dist/doors/providers.js.map +1 -1
- package/dist/esm/adapters/code/agentcore.d.ts +133 -0
- package/dist/esm/adapters/code/agentcore.js +290 -0
- package/dist/esm/adapters/code/agentcore.js.map +1 -0
- package/dist/esm/adapters/code/local.d.ts +99 -0
- package/dist/esm/adapters/code/local.js +196 -0
- package/dist/esm/adapters/code/local.js.map +1 -0
- package/dist/esm/adapters/types.d.ts +87 -0
- package/dist/esm/core/Agent.d.ts +65 -0
- package/dist/esm/core/Agent.js +133 -1
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/RunnerBase.d.ts +51 -0
- package/dist/esm/core/RunnerBase.js +67 -0
- package/dist/esm/core/RunnerBase.js.map +1 -1
- package/dist/esm/core/agent/stages/toolCalls.d.ts +31 -0
- package/dist/esm/core/agent/stages/toolCalls.js +90 -0
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/core/agent/types.d.ts +23 -2
- package/dist/esm/core/codeRunnerTool.d.ts +120 -0
- package/dist/esm/core/codeRunnerTool.js +247 -0
- package/dist/esm/core/codeRunnerTool.js.map +1 -0
- package/dist/esm/core/toolSessions.d.ts +318 -0
- package/dist/esm/core/toolSessions.js +389 -0
- package/dist/esm/core/toolSessions.js.map +1 -0
- package/dist/esm/core/tools.d.ts +60 -0
- package/dist/esm/core/tools.js.map +1 -1
- package/dist/esm/doors/providers.d.ts +7 -0
- package/dist/esm/doors/providers.js +10 -0
- package/dist/esm/doors/providers.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +50 -0
- package/dist/esm/events/registry.d.ts +9 -1
- package/dist/esm/events/registry.js +8 -0
- package/dist/esm/events/registry.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/mcp/mcpServe.js +37 -1
- package/dist/esm/lib/mcp/mcpServe.js.map +1 -1
- package/dist/esm/lib/trace-toolpack/traceToolpack.js +15 -1
- package/dist/esm/lib/trace-toolpack/traceToolpack.js.map +1 -1
- package/dist/events/registry.js +8 -0
- package/dist/events/registry.js.map +1 -1
- package/dist/index.js +14 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/mcp/mcpServe.js +37 -1
- package/dist/lib/mcp/mcpServe.js.map +1 -1
- package/dist/lib/trace-toolpack/traceToolpack.js +15 -1
- package/dist/lib/trace-toolpack/traceToolpack.js.map +1 -1
- package/dist/types/adapters/code/agentcore.d.ts +134 -0
- package/dist/types/adapters/code/agentcore.d.ts.map +1 -0
- package/dist/types/adapters/code/local.d.ts +100 -0
- package/dist/types/adapters/code/local.d.ts.map +1 -0
- package/dist/types/adapters/types.d.ts +87 -0
- package/dist/types/adapters/types.d.ts.map +1 -1
- package/dist/types/core/Agent.d.ts +65 -0
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/RunnerBase.d.ts +51 -0
- package/dist/types/core/RunnerBase.d.ts.map +1 -1
- package/dist/types/core/agent/stages/toolCalls.d.ts +31 -0
- package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
- package/dist/types/core/agent/types.d.ts +23 -2
- package/dist/types/core/agent/types.d.ts.map +1 -1
- package/dist/types/core/codeRunnerTool.d.ts +121 -0
- package/dist/types/core/codeRunnerTool.d.ts.map +1 -0
- package/dist/types/core/toolSessions.d.ts +319 -0
- package/dist/types/core/toolSessions.d.ts.map +1 -0
- package/dist/types/core/tools.d.ts +60 -0
- package/dist/types/core/tools.d.ts.map +1 -1
- package/dist/types/doors/providers.d.ts +7 -0
- package/dist/types/doors/providers.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +50 -0
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/events/registry.d.ts +9 -1
- package/dist/types/events/registry.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/mcp/mcpServe.d.ts.map +1 -1
- package/dist/types/lib/trace-toolpack/traceToolpack.d.ts.map +1 -1
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -475,7 +475,7 @@ Resilience decorators live on the `agentfootprint/resilience` subpath
|
|
|
475
475
|
(not the main barrel). Each preserves the `LLMProvider` interface and
|
|
476
476
|
stacks freely.
|
|
477
477
|
|
|
478
|
-
### Observability —
|
|
478
|
+
### Observability — 77 typed events across 20 domains
|
|
479
479
|
|
|
480
480
|
```typescript
|
|
481
481
|
agent.on('agentfootprint.context.injected', (e) =>
|
package/CLAUDE.md
CHANGED
|
@@ -60,7 +60,7 @@ Traps: `src/observability/` holds the finder IMPLEMENTATIONS (canonical home; `d
|
|
|
60
60
|
- **Embedder fingerprint** (8.9.0) → `Embedder.id` (optional; every shipped embedder sets one, and NONE include dims — the store appends `@<dims>` itself, so an id carrying its own size double-stamps) + `indexDocuments` defaulting `embedderId` to it + `SqliteVectorStore.reconcileFingerprint` (the only comparison site). Rule: dimensions ALWAYS decide, model ids decide only when BOTH sides named themselves — refusing on an absent name would block the majority of callers who never pass `embedderId`.
|
|
61
61
|
- **Retrieval record** (8.8.0) → FOUR stages write one object in sequence: `loadRelevant` (candidates+scores+threshold verdicts) → `pickByBudget` (re-marks admitted→over-budget/over-max-entries) → `formatDefault` (`promptFragment` + `promptPosition`) → the read mount's outputMapper lifts it to root as `retrievalEvidence_<id>`. `memoryRecallInjections` then splits ONE recall into one ActiveInjection PER CHUNK — guarded by a byte-equality check (`fragments.join('\n\n') === systemContent`) that falls back to the single injection rather than change the prompt. `rank` (score order) and `promptPosition` (picker order) are DIFFERENT and both load-bearing: joining fragments in rank order reproduces the right bytes in a sequence the model never saw.
|
|
62
62
|
- **AgentState** → all 8 stages/ files, both builders' mappers, memory-wire STRING-TYPED keys ('runIdentity'/'turnNumber'/… buildAgentChart.ts:177-180 — not refactor-safe), finalizeResult's `reliabilityFail*`/`policyHalt*` reads (rename silently kills the typed errors).
|
|
63
|
-
- **events/** →
|
|
63
|
+
- **events/** → 77 typed events across 20 domains (counts anti-drift-tested against this file — update BOTH when adding events): ALL_EVENT_TYPES exhaustiveness tests, DomainWildcard hand-list, ~42 importers (recorders, strategies, stream, commentary).
|
|
64
64
|
- **adapters/types.ts LLMMessage/LLMRequest** → 62 importers: tool_use round-trip (toolCalls.ts:115-135), wire assembly (callLLM.ts:150-160), providers, cache strategies, security/extractSequence, reliability loop.
|
|
65
65
|
- **Cache** → strategy registration is a MODULE SIDE EFFECT (src/index.ts:15-17); an entry point skipping that import silently falls back to NoOp. Resolved once per Agent at construction (Agent.ts:347).
|
|
66
66
|
- **Injection engine eval semantics** → Evaluate stage cursor keystone (buildInjectionEngineSubflow.ts:214-222), Route stage MIRRORS slot filters (keep in sync with buildSystemPromptSlot), read_skill gate (toolCalls.ts:747). The gate's allowed set is TWO kinds of id (8.4.0): a HOP (`deps.allowedSkillIds` = `graph.reachableSkills(cursor)` — activates AND moves the cursor) ∪ an OPEN skill (`deps.openSkillIds` = `Agent.openSkillIds()`, Agent.ts:1052 — a registered skill whose trigger is `llm-activated` AND that the graph declares no incoming edge to; activates, never moves the cursor). Both clauses are load-bearing: the trigger test is "read_skill can really activate this", the edge test keeps a bare model edge `.route(a,m)` from-gated. **8.5.0** extends the SAME trigger test three ways: a decision `tree()` returns `[]` from `reachableSkills` (leaves compile to `rule` triggers, so a pick could only be accepted then dropped — the gate refuses with a tree-specific message, `deps.skillGraphIsTree`, derived in AgentBuilder from `graph.nodes.some(kind==='predicate')`); `surfaceMode:'tool-only'` is refused at agent build for any skill whose trigger is not `llm-activated` (skillBodyDelivery.ts — the read_skill tool result is the only channel that mode has, and the graph never calls read_skill); and `read_skill`'s DESCRIPTION is rebuilt per iteration from `reachableSkills(cursor) ∪ open` (Agent.readSkillOfferFor → buildToolsSlot's `readSkillFor`). **The read_skill ENUM must stay the full catalog** — `toolArgValidation` defaults to `'enforce'` and runs at toolCalls.ts:570, BEFORE the gate at :765, and sets `error = true` which the gate skips; narrowing the enum silently retires the teaching refusal, `skill.rejected`, routeRecorder's rejection hops and the rejected-cap governor.
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* agentCoreCodeRunner — AWS Bedrock AgentCore Code Interpreter behind the
|
|
4
|
+
* {@link CodeRunner} port (peer-dep `@aws-sdk/client-bedrock-agentcore`).
|
|
5
|
+
*
|
|
6
|
+
* import { agentCoreCodeRunner } from 'agentfootprint/providers';
|
|
7
|
+
* const runner = agentCoreCodeRunner({ region: 'us-east-1', identifier: 'aws.codeinterpreter.v1' });
|
|
8
|
+
*
|
|
9
|
+
* A REAL sandbox, which is the point: `localCodeRunner` gives you process
|
|
10
|
+
* isolation on your own machine and says so; this gives you a managed,
|
|
11
|
+
* network-and-filesystem-isolated environment, and the tool code is identical
|
|
12
|
+
* across the swap.
|
|
13
|
+
*
|
|
14
|
+
* ── The three operations, verified against the SDK ──────────────────────────
|
|
15
|
+
* Pinned in `test/adapters/aws/awsCommandPin.ts`, and verified against a real
|
|
16
|
+
* install of `@aws-sdk/client-bedrock-agentcore` 3.1108.0:
|
|
17
|
+
*
|
|
18
|
+
* • `StartCodeInterpreterSessionCommand`
|
|
19
|
+
* in `{ codeInterpreterIdentifier, name?, sessionTimeoutSeconds? }`
|
|
20
|
+
* out `{ codeInterpreterIdentifier, sessionId, createdAt }`
|
|
21
|
+
* • `InvokeCodeInterpreterCommand`
|
|
22
|
+
* in `{ codeInterpreterIdentifier, sessionId, name: 'executeCode',
|
|
23
|
+
* arguments: { code, language } }`
|
|
24
|
+
* out `{ sessionId, stream }` — an **event stream**, not a body (below)
|
|
25
|
+
* • `StopCodeInterpreterSessionCommand`
|
|
26
|
+
* in `{ codeInterpreterIdentifier, sessionId }` ← the session ID, not a URI
|
|
27
|
+
* out `{ codeInterpreterIdentifier, sessionId, lastUpdatedAt }`
|
|
28
|
+
*
|
|
29
|
+
* **`Invoke` answers with an `AsyncIterable`.** `InvokeCodeInterpreterResponse`
|
|
30
|
+
* is `{ sessionId?, stream?: AsyncIterable<CodeInterpreterStreamOutput> }`, and
|
|
31
|
+
* every member of that union is either `{ result }` or a modelled EXCEPTION —
|
|
32
|
+
* `accessDeniedException`, `throttlingException`, `validationException`, and
|
|
33
|
+
* four more. An adapter that read a `body` field would find `undefined` and
|
|
34
|
+
* report an empty success on every call, and one that iterated only for
|
|
35
|
+
* `result` would treat an AccessDenied as "the code printed nothing." So this
|
|
36
|
+
* drains the stream, raises the exception members BY NAME, and folds the
|
|
37
|
+
* result members into one `CodeResult`.
|
|
38
|
+
*
|
|
39
|
+
* The payload lands twice: `structuredContent` carries `{ stdout, stderr,
|
|
40
|
+
* exitCode, executionTime }` and `content[]` carries typed blocks. The
|
|
41
|
+
* structured half is preferred because it is typed; the text blocks are the
|
|
42
|
+
* fallback for a response that only filled the other one.
|
|
43
|
+
*
|
|
44
|
+
* ── How this talks to the SDK (the 9.4.0 law) ───────────────────────────────
|
|
45
|
+
* Through `client.send(new SomeCommand(input))`, never a method on the client.
|
|
46
|
+
* A bare `@aws-sdk/client-*` **Client is command-based**: its prototype carries
|
|
47
|
+
* `send` and `destroy` and nothing else — verified again for this adapter
|
|
48
|
+
* (`BedrockAgentCoreClient.prototype.startCodeInterpreterSession` is
|
|
49
|
+
* `undefined`; the shortcut exists only on the aggregated `BedrockAgentCore`).
|
|
50
|
+
* Three adapters have shipped that bug in this package.
|
|
51
|
+
*
|
|
52
|
+
* ── Credentials ─────────────────────────────────────────────────────────────
|
|
53
|
+
* Standard AWS credential resolution (the SDK's own chain). A tool holding a
|
|
54
|
+
* long-lived session must NOT cache a `Credential` object from `ctx.credential`
|
|
55
|
+
* past the call that produced it — a session outliving a run outlives its
|
|
56
|
+
* token. Re-resolve per execute through `ctx.credentials`.
|
|
57
|
+
*
|
|
58
|
+
* Pattern: Adapter (GoF) + lazy peer-dep load — the SDK is required only when
|
|
59
|
+
* `start()` first runs (or never, if you inject `_client` / `_sdk`).
|
|
60
|
+
*/
|
|
61
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
62
|
+
exports.agentCoreCodeRunner = void 0;
|
|
63
|
+
const lazyRequire_js_1 = require("../../lib/lazyRequire.js");
|
|
64
|
+
const DEFAULT_MAX_OUTPUT_CHARS = 8_000;
|
|
65
|
+
/** The service's own name for "run this code". Not a name we chose. */
|
|
66
|
+
const EXECUTE_CODE = 'executeCode';
|
|
67
|
+
function agentCoreCodeRunner(options) {
|
|
68
|
+
const id = options.id ?? 'agentcore-code-runner';
|
|
69
|
+
const maxOutputChars = options.maxOutputChars ?? DEFAULT_MAX_OUTPUT_CHARS;
|
|
70
|
+
let client;
|
|
71
|
+
const resolve = () => {
|
|
72
|
+
client ??= options._client ?? createCodeClient(options);
|
|
73
|
+
return client;
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
id,
|
|
77
|
+
async start(req) {
|
|
78
|
+
const api = resolve();
|
|
79
|
+
const started = await api.startSession({
|
|
80
|
+
codeInterpreterIdentifier: options.identifier,
|
|
81
|
+
// The isolation key names the session on AWS's side too, so an operator
|
|
82
|
+
// reading the console sees the same partition the runtime enforces. It
|
|
83
|
+
// is a HASH-free label AWS documents as non-unique; the key is already
|
|
84
|
+
// the caller's own composition, never widened here.
|
|
85
|
+
name: sessionName(req.key),
|
|
86
|
+
...(options.sessionTimeoutSeconds !== undefined && {
|
|
87
|
+
sessionTimeoutSeconds: options.sessionTimeoutSeconds,
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
const sessionId = started.sessionId;
|
|
91
|
+
if (!sessionId) {
|
|
92
|
+
throw new Error('agentCoreCodeRunner: StartCodeInterpreterSession returned no sessionId. ' +
|
|
93
|
+
'Nothing can be invoked or stopped without one, so this is raised rather than ' +
|
|
94
|
+
'carried forward as an unusable session.');
|
|
95
|
+
}
|
|
96
|
+
let stopped = false;
|
|
97
|
+
return {
|
|
98
|
+
id: sessionId,
|
|
99
|
+
async execute(exec) {
|
|
100
|
+
if (stopped) {
|
|
101
|
+
throw new Error(`agentCoreCodeRunner: session ${sessionId} was stopped; open a new one to run more code.`);
|
|
102
|
+
}
|
|
103
|
+
const answer = await api.invoke({
|
|
104
|
+
codeInterpreterIdentifier: options.identifier,
|
|
105
|
+
sessionId,
|
|
106
|
+
name: EXECUTE_CODE,
|
|
107
|
+
arguments: {
|
|
108
|
+
code: exec.code,
|
|
109
|
+
...(exec.language ?? req.language ?? options.language
|
|
110
|
+
? { language: exec.language ?? req.language ?? options.language ?? 'python' }
|
|
111
|
+
: {}),
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
const stdout = cut(answer.stdout, maxOutputChars);
|
|
115
|
+
const stderr = cut(answer.stderr, maxOutputChars);
|
|
116
|
+
const truncated = {
|
|
117
|
+
...(stdout.cut && { stdout: true }),
|
|
118
|
+
...(stderr.cut && { stderr: true }),
|
|
119
|
+
...((stdout.cut || stderr.cut) && {
|
|
120
|
+
ofChars: Math.max(answer.stdout.length, answer.stderr.length),
|
|
121
|
+
}),
|
|
122
|
+
};
|
|
123
|
+
return {
|
|
124
|
+
// `isError` is the service's own verdict; a non-zero exit is ours.
|
|
125
|
+
ok: answer.isError !== true && (answer.exitCode ?? 0) === 0,
|
|
126
|
+
stdout: stdout.text,
|
|
127
|
+
stderr: stderr.text,
|
|
128
|
+
...(answer.exitCode !== undefined && { exitCode: answer.exitCode }),
|
|
129
|
+
...(Object.keys(truncated).length > 0 && { truncated }),
|
|
130
|
+
};
|
|
131
|
+
},
|
|
132
|
+
async stop() {
|
|
133
|
+
if (stopped)
|
|
134
|
+
return;
|
|
135
|
+
stopped = true;
|
|
136
|
+
try {
|
|
137
|
+
await api.stopSession({
|
|
138
|
+
codeInterpreterIdentifier: options.identifier,
|
|
139
|
+
sessionId,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
// "Already gone" is the EXPECTED shape here, not an incident: the
|
|
144
|
+
// session TTL is enforced by AWS, so a run that idled past it finds
|
|
145
|
+
// the session collected. Anything else is re-raised, and the tier
|
|
146
|
+
// reports it on `tools.session_close_failed`.
|
|
147
|
+
if (!isAlreadyGone(err))
|
|
148
|
+
throw err;
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
exports.agentCoreCodeRunner = agentCoreCodeRunner;
|
|
156
|
+
/** A session label from the isolation key — AWS's `name` is a human handle. */
|
|
157
|
+
function sessionName(key) {
|
|
158
|
+
// Keep it recognisable and within the service's naming charset.
|
|
159
|
+
return `af-${key.replace(/[^A-Za-z0-9_-]/g, '-')}`.slice(0, 100);
|
|
160
|
+
}
|
|
161
|
+
function isAlreadyGone(err) {
|
|
162
|
+
const name = err instanceof Error ? err.name : '';
|
|
163
|
+
return name === 'ResourceNotFoundException' || name === 'ValidationException';
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Map {@link AgentCoreCodeClientLike} onto the real SDK commands.
|
|
167
|
+
*
|
|
168
|
+
* Two things this function owns and nothing else does: the COMMAND FORM (see
|
|
169
|
+
* the module header), and the DRAIN of `InvokeCodeInterpreterResponse.stream`.
|
|
170
|
+
*/
|
|
171
|
+
function createCodeClient(options) {
|
|
172
|
+
let mod;
|
|
173
|
+
if (options._sdk) {
|
|
174
|
+
mod = options._sdk;
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
try {
|
|
178
|
+
// Lazy peer-dep: only loaded when no _client/_sdk is injected and start() runs.
|
|
179
|
+
mod = (0, lazyRequire_js_1.lazyRequire)('@aws-sdk/client-bedrock-agentcore');
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
throw new Error('agentCoreCodeRunner requires the `@aws-sdk/client-bedrock-agentcore` peer dependency.\n' +
|
|
183
|
+
' Install: npm install @aws-sdk/client-bedrock-agentcore\n' +
|
|
184
|
+
' Or pass `_client` for a pre-built or mock client.\n' +
|
|
185
|
+
' For a local dev loop with no AWS at all, use `localCodeRunner()`.');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (!mod.BedrockAgentCoreClient) {
|
|
189
|
+
throw new Error('agentCoreCodeRunner: `@aws-sdk/client-bedrock-agentcore` is installed but ' +
|
|
190
|
+
'`BedrockAgentCoreClient` was not found. Update the SDK.');
|
|
191
|
+
}
|
|
192
|
+
const sdk = new mod.BedrockAgentCoreClient({ ...(options.region && { region: options.region }) });
|
|
193
|
+
const send = async (Ctor, name, input) => {
|
|
194
|
+
if (!Ctor) {
|
|
195
|
+
throw new Error(`agentCoreCodeRunner: \`@aws-sdk/client-bedrock-agentcore\` is missing ${name}. ` +
|
|
196
|
+
'Upgrade the SDK, or pass `_client` with your own mapping.');
|
|
197
|
+
}
|
|
198
|
+
return sdk.send(new Ctor(input));
|
|
199
|
+
};
|
|
200
|
+
return {
|
|
201
|
+
async startSession(input) {
|
|
202
|
+
const r = (await send(mod.StartCodeInterpreterSessionCommand, 'StartCodeInterpreterSessionCommand', input));
|
|
203
|
+
return { ...(r?.sessionId !== undefined && { sessionId: r.sessionId }) };
|
|
204
|
+
},
|
|
205
|
+
async invoke(input) {
|
|
206
|
+
const r = (await send(mod.InvokeCodeInterpreterCommand, 'InvokeCodeInterpreterCommand', input));
|
|
207
|
+
return drainStream(r?.stream);
|
|
208
|
+
},
|
|
209
|
+
async stopSession(input) {
|
|
210
|
+
await send(mod.StopCodeInterpreterSessionCommand, 'StopCodeInterpreterSessionCommand', input);
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
/** Every modelled error member of the stream union, in SDK spelling. */
|
|
215
|
+
const STREAM_ERROR_MEMBERS = [
|
|
216
|
+
'accessDeniedException',
|
|
217
|
+
'conflictException',
|
|
218
|
+
'internalServerException',
|
|
219
|
+
'resourceNotFoundException',
|
|
220
|
+
'serviceQuotaExceededException',
|
|
221
|
+
'throttlingException',
|
|
222
|
+
'validationException',
|
|
223
|
+
];
|
|
224
|
+
/**
|
|
225
|
+
* Drain the event stream into one answer.
|
|
226
|
+
*
|
|
227
|
+
* An ERROR MEMBER RAISES. This is the honesty line for this adapter: the SDK
|
|
228
|
+
* models seven failure shapes as ordinary members of the stream union, so an
|
|
229
|
+
* `AccessDeniedException` arrives as a value, not a rejection. Folding it in
|
|
230
|
+
* as empty output would report a clean run in which the code "printed
|
|
231
|
+
* nothing" — a silent success, at the exact moment an operator most needs the
|
|
232
|
+
* word "AccessDenied".
|
|
233
|
+
*/
|
|
234
|
+
async function drainStream(stream) {
|
|
235
|
+
if (!stream) {
|
|
236
|
+
throw new Error('agentCoreCodeRunner: InvokeCodeInterpreter returned no stream. The response carries ' +
|
|
237
|
+
'its payload as an event stream (`response.stream`), so an absent one is a broken ' +
|
|
238
|
+
'call, not an empty result.');
|
|
239
|
+
}
|
|
240
|
+
let stdout = '';
|
|
241
|
+
let stderr = '';
|
|
242
|
+
let exitCode;
|
|
243
|
+
let isError = false;
|
|
244
|
+
for await (const event of stream) {
|
|
245
|
+
for (const member of STREAM_ERROR_MEMBERS) {
|
|
246
|
+
const raised = event[member];
|
|
247
|
+
if (raised) {
|
|
248
|
+
const error = new Error(`agentCoreCodeRunner: ${member} from InvokeCodeInterpreter — ` +
|
|
249
|
+
`${raised.message ?? 'no message supplied'}`);
|
|
250
|
+
error.name = member.charAt(0).toUpperCase() + member.slice(1);
|
|
251
|
+
throw error;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const result = event.result;
|
|
255
|
+
if (!result)
|
|
256
|
+
continue;
|
|
257
|
+
if (result.isError === true)
|
|
258
|
+
isError = true;
|
|
259
|
+
const structured = result.structuredContent;
|
|
260
|
+
if (structured) {
|
|
261
|
+
if (structured.stdout !== undefined)
|
|
262
|
+
stdout += structured.stdout;
|
|
263
|
+
if (structured.stderr !== undefined)
|
|
264
|
+
stderr += structured.stderr;
|
|
265
|
+
if (structured.exitCode !== undefined)
|
|
266
|
+
exitCode = structured.exitCode;
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
// Fallback: a response that filled only the typed content blocks. Text
|
|
270
|
+
// blocks are the readable half; a binary/resource block is described by
|
|
271
|
+
// name rather than inlined, because inlining it is the bug this port exists
|
|
272
|
+
// to prevent.
|
|
273
|
+
for (const block of result.content ?? []) {
|
|
274
|
+
if (block.text !== undefined)
|
|
275
|
+
stdout += block.text;
|
|
276
|
+
else if (block.name !== undefined)
|
|
277
|
+
stdout += `[${block.type ?? 'resource'}: ${block.name}]`;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
stdout,
|
|
283
|
+
stderr,
|
|
284
|
+
...(exitCode !== undefined && { exitCode }),
|
|
285
|
+
...(isError && { isError }),
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
/** Cut to `max` characters, saying whether it cut. */
|
|
289
|
+
function cut(text, max) {
|
|
290
|
+
if (text.length <= max)
|
|
291
|
+
return { text, cut: false };
|
|
292
|
+
return { text: text.slice(0, max), cut: true };
|
|
293
|
+
}
|
|
294
|
+
//# 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,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* localCodeRunner — run code in a child process, on this machine.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: Adapter (GoF) over `node:child_process`.
|
|
6
|
+
* Role: the dev default behind the {@link CodeRunner} port. `agentCoreCodeRunner`
|
|
7
|
+
* is the production swap; the tool code does not change.
|
|
8
|
+
* Emits: nothing. The tool that owns the session emits.
|
|
9
|
+
*
|
|
10
|
+
* ── ISOLATION, NOT A SANDBOX. Read this before deploying it. ────────────────
|
|
11
|
+
* The name is `localCodeRunner`, never `sandboxedCodeRunner`, and the
|
|
12
|
+
* difference is not modesty — it is the whole security posture.
|
|
13
|
+
*
|
|
14
|
+
* What a child process DOES give you:
|
|
15
|
+
* • a separate process and heap — a crash or an OOM takes the child, not you;
|
|
16
|
+
* • kill on timeout, so runaway code has a ceiling;
|
|
17
|
+
* • no inherited stdin, so nothing can block waiting for a terminal;
|
|
18
|
+
* • an environment ALLOWLIST — `process.env` is not inherited (only `PATH`,
|
|
19
|
+
* so the interpreter can be found), so an `AWS_SECRET_ACCESS_KEY` in your
|
|
20
|
+
* shell is not in the model's reach;
|
|
21
|
+
* • a working directory, by convention.
|
|
22
|
+
*
|
|
23
|
+
* What it does NOT give you, at all:
|
|
24
|
+
* • a filesystem jail — the code can read and write anywhere this process can;
|
|
25
|
+
* • a network jail — it can call out;
|
|
26
|
+
* • CPU or memory limits beyond the timeout;
|
|
27
|
+
* • any protection from code that deletes something outside `cwd`.
|
|
28
|
+
*
|
|
29
|
+
* So: a development loop, a trusted-input pipeline, a machine you would be
|
|
30
|
+
* relaxed about a shell script running on. NOT arbitrary model-written code
|
|
31
|
+
* from an untrusted user, on a host with anything on it. For that, run a real
|
|
32
|
+
* sandbox behind the same port — `agentCoreCodeRunner`, a gVisor container, a
|
|
33
|
+
* Firecracker VM — and keep the tool identical.
|
|
34
|
+
*
|
|
35
|
+
* **In-process `eval` / `node:vm` is refused outright.** Node's own
|
|
36
|
+
* documentation says `vm` is not a security mechanism ("do not use it to run
|
|
37
|
+
* untrusted code"), so shipping it as one would be theater: the same code
|
|
38
|
+
* reaching the same globals, wearing a word that makes a reader stop checking.
|
|
39
|
+
* A subprocess is genuinely a boundary; it is just a smaller one than the word
|
|
40
|
+
* "sandbox" implies. The library teaches refusals for things that are WRONG and
|
|
41
|
+
* honest names for things that are merely LIMITED — running local code in a dev
|
|
42
|
+
* loop is not wrong, and calling it a sandbox is.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const agent = Agent.create({ provider })
|
|
46
|
+
* .tool(codeRunnerTool({ runner: localCodeRunner() }))
|
|
47
|
+
* .build();
|
|
48
|
+
*/
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.localCodeRunner = void 0;
|
|
51
|
+
const lazyRequire_js_1 = require("../../lib/lazyRequire.js");
|
|
52
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
53
|
+
const DEFAULT_MAX_OUTPUT_CHARS = 8_000;
|
|
54
|
+
/** How each supported language is invoked when no `command` was given. */
|
|
55
|
+
const DEFAULT_COMMANDS = {
|
|
56
|
+
javascript: ['node', '-e'],
|
|
57
|
+
js: ['node', '-e'],
|
|
58
|
+
node: ['node', '-e'],
|
|
59
|
+
typescript: ['npx', 'tsx', '-e'],
|
|
60
|
+
ts: ['npx', 'tsx', '-e'],
|
|
61
|
+
python: ['python3', '-c'],
|
|
62
|
+
python3: ['python3', '-c'],
|
|
63
|
+
py: ['python3', '-c'],
|
|
64
|
+
};
|
|
65
|
+
function localCodeRunner(options = {}) {
|
|
66
|
+
const id = options.id ?? 'local-code-runner';
|
|
67
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
68
|
+
const maxOutputChars = options.maxOutputChars ?? DEFAULT_MAX_OUTPUT_CHARS;
|
|
69
|
+
return {
|
|
70
|
+
id,
|
|
71
|
+
start(req) {
|
|
72
|
+
// A local session is a NAME and a working directory, not a live handle:
|
|
73
|
+
// each execution is its own process. Saying so matters — a consumer who
|
|
74
|
+
// assumed variables carry between calls (they do on AgentCore, whose
|
|
75
|
+
// session is a live kernel) would silently get different semantics.
|
|
76
|
+
// `codeRunnerTool` states this in the tool description it hands the model.
|
|
77
|
+
const sessionId = `local:${req.key}`;
|
|
78
|
+
let stopped = false;
|
|
79
|
+
return Promise.resolve({
|
|
80
|
+
id: sessionId,
|
|
81
|
+
async execute(exec) {
|
|
82
|
+
if (stopped) {
|
|
83
|
+
throw new Error(`localCodeRunner: session ${sessionId} was stopped; open a new one to run more code.`);
|
|
84
|
+
}
|
|
85
|
+
const language = exec.language ?? req.language ?? 'javascript';
|
|
86
|
+
const command = options.command ?? DEFAULT_COMMANDS[language.toLowerCase()];
|
|
87
|
+
if (!command || command.length === 0) {
|
|
88
|
+
throw new Error(`localCodeRunner: no command for language '${language}'. ` +
|
|
89
|
+
`Known: ${Object.keys(DEFAULT_COMMANDS).join(', ')}. ` +
|
|
90
|
+
"Pass `command: ['your-interpreter', '-c']` for anything else.");
|
|
91
|
+
}
|
|
92
|
+
const [file, ...args] = command;
|
|
93
|
+
const raw = await runChild(resolveChildProcess(options), file, [...args, exec.code], {
|
|
94
|
+
cwd: options.cwd ?? process.cwd(),
|
|
95
|
+
// ALLOWLIST. `process.env` is deliberately NOT spread in — only
|
|
96
|
+
// PATH, so the OS can find the interpreter, and it is overridable.
|
|
97
|
+
env: { PATH: process.env.PATH ?? '', ...(options.env ?? {}) },
|
|
98
|
+
timeoutMs: exec.timeoutMs ?? timeoutMs,
|
|
99
|
+
...(exec.signal && { signal: exec.signal }),
|
|
100
|
+
});
|
|
101
|
+
const stdout = cut(raw.stdout, maxOutputChars);
|
|
102
|
+
const stderr = cut(raw.stderr, maxOutputChars);
|
|
103
|
+
const truncated = {
|
|
104
|
+
...(stdout.cut && { stdout: true }),
|
|
105
|
+
...(stderr.cut && { stderr: true }),
|
|
106
|
+
...((stdout.cut || stderr.cut) && {
|
|
107
|
+
ofChars: Math.max(raw.stdout.length, raw.stderr.length),
|
|
108
|
+
}),
|
|
109
|
+
};
|
|
110
|
+
return {
|
|
111
|
+
ok: raw.exitCode === 0,
|
|
112
|
+
stdout: stdout.text,
|
|
113
|
+
stderr: stderr.text,
|
|
114
|
+
...(raw.exitCode !== undefined && { exitCode: raw.exitCode }),
|
|
115
|
+
// Present IFF something was actually cut — an empty object here
|
|
116
|
+
// would read as "truncation happened, magnitude unknown".
|
|
117
|
+
...(Object.keys(truncated).length > 0 && { truncated }),
|
|
118
|
+
};
|
|
119
|
+
},
|
|
120
|
+
stop() {
|
|
121
|
+
// Nothing to release: each execution already ended with its process.
|
|
122
|
+
// Idempotent, and it refuses later executions rather than silently
|
|
123
|
+
// starting a fresh process under a session the caller closed.
|
|
124
|
+
stopped = true;
|
|
125
|
+
return Promise.resolve();
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
exports.localCodeRunner = localCodeRunner;
|
|
132
|
+
function resolveChildProcess(options) {
|
|
133
|
+
if (options._childProcess)
|
|
134
|
+
return options._childProcess;
|
|
135
|
+
try {
|
|
136
|
+
return (0, lazyRequire_js_1.lazyRequire)('node:child_process');
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
throw new Error('localCodeRunner needs `node:child_process`, which this runtime does not provide ' +
|
|
140
|
+
'(a browser bundle, or a restricted worker). Use a remote runner — ' +
|
|
141
|
+
'`agentCoreCodeRunner` — or supply your own `CodeRunner`.');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* One child process, promisified.
|
|
146
|
+
*
|
|
147
|
+
* A NON-ZERO EXIT IS NOT A REJECTION. Code that fails is a normal answer here —
|
|
148
|
+
* the model wrote it, it needs to read the traceback, and turning that into a
|
|
149
|
+
* thrown tool error would replace the one thing that teaches the next attempt
|
|
150
|
+
* with `error: true`. What DOES reject is the runner failing to run at all
|
|
151
|
+
* (interpreter missing, timeout, abort), because that is not the code's answer.
|
|
152
|
+
*/
|
|
153
|
+
async function runChild(mod, file, args, opts) {
|
|
154
|
+
const execFile = mod.execFile;
|
|
155
|
+
if (typeof execFile !== 'function') {
|
|
156
|
+
throw new Error('localCodeRunner: `node:child_process` resolved but `execFile` is missing.');
|
|
157
|
+
}
|
|
158
|
+
return new Promise((resolve, reject) => {
|
|
159
|
+
execFile(file, args, {
|
|
160
|
+
cwd: opts.cwd,
|
|
161
|
+
env: opts.env,
|
|
162
|
+
timeout: opts.timeoutMs,
|
|
163
|
+
// Generous, because the CUT is ours to make and to report — letting the
|
|
164
|
+
// runtime's own buffer overflow would surface as an error whose message
|
|
165
|
+
// says nothing about how much was lost.
|
|
166
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
167
|
+
...(opts.signal && { signal: opts.signal }),
|
|
168
|
+
}, (error, stdout, stderr) => {
|
|
169
|
+
if (!error) {
|
|
170
|
+
resolve({ stdout: String(stdout ?? ''), stderr: String(stderr ?? ''), exitCode: 0 });
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (error.killed === true) {
|
|
174
|
+
reject(new Error(`localCodeRunner: the code did not finish within ${opts.timeoutMs}ms and the ` +
|
|
175
|
+
'process was killed. Raise `timeoutMs`, or have the code do less per call.'));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (typeof error.code === 'string') {
|
|
179
|
+
// ENOENT and friends — the interpreter itself is not here. Naming it
|
|
180
|
+
// beats handing the model a traceback it cannot act on.
|
|
181
|
+
reject(new Error(`localCodeRunner: could not run '${file}' (${error.code}). ` +
|
|
182
|
+
'Install the interpreter, or pass `command` pointing at one.'));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// A real non-zero exit: the code ran and failed. That IS the result.
|
|
186
|
+
resolve({
|
|
187
|
+
stdout: String(stdout ?? ''),
|
|
188
|
+
stderr: String(stderr ?? '') || error.message,
|
|
189
|
+
exitCode: typeof error.code === 'number' ? error.code : 1,
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
/** Cut to `max` characters, saying whether it cut. */
|
|
195
|
+
function cut(text, max) {
|
|
196
|
+
if (text.length <= max)
|
|
197
|
+
return { text, cut: false };
|
|
198
|
+
return { text: text.slice(0, max), cut: true };
|
|
199
|
+
}
|
|
200
|
+
//# 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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"}
|