agentfootprint 11.4.0 → 12.0.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/CAPABILITIES.md +3 -1
- package/dist/adapters/code/agentcore.js +295 -214
- package/dist/adapters/code/agentcore.js.map +1 -1
- package/dist/adapters/code/agentcoreClient.js +178 -0
- package/dist/adapters/code/agentcoreClient.js.map +1 -0
- package/dist/adapters/code/agentcoreWire.js +348 -0
- package/dist/adapters/code/agentcoreWire.js.map +1 -0
- package/dist/adapters/code/fileName.js +100 -0
- package/dist/adapters/code/fileName.js.map +1 -0
- package/dist/adapters/code/local.js +529 -183
- package/dist/adapters/code/local.js.map +1 -1
- package/dist/adapters/code/output.js +140 -0
- package/dist/adapters/code/output.js.map +1 -0
- package/dist/adapters/mcp/agentcoreRuntime/invoke.js +7 -6
- package/dist/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
- package/dist/adapters/mcp/agentcoreRuntime/sessionBusy.js +36 -2
- package/dist/adapters/mcp/agentcoreRuntime/sessionBusy.js.map +1 -1
- package/dist/adapters/mcp/agentcoreRuntime/transport.js +3 -1
- package/dist/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
- package/dist/core/codeRunnerTool.js +52 -7
- package/dist/core/codeRunnerTool.js.map +1 -1
- package/dist/doors/providers.js.map +1 -1
- package/dist/esm/adapters/code/agentcore.d.ts +65 -68
- package/dist/esm/adapters/code/agentcore.js +293 -212
- package/dist/esm/adapters/code/agentcore.js.map +1 -1
- package/dist/esm/adapters/code/agentcoreClient.d.ts +193 -0
- package/dist/esm/adapters/code/agentcoreClient.js +173 -0
- package/dist/esm/adapters/code/agentcoreClient.js.map +1 -0
- package/dist/esm/adapters/code/agentcoreWire.d.ts +119 -0
- package/dist/esm/adapters/code/agentcoreWire.js +334 -0
- package/dist/esm/adapters/code/agentcoreWire.js.map +1 -0
- package/dist/esm/adapters/code/fileName.d.ts +43 -0
- package/dist/esm/adapters/code/fileName.js +96 -0
- package/dist/esm/adapters/code/fileName.js.map +1 -0
- package/dist/esm/adapters/code/local.d.ts +91 -12
- package/dist/esm/adapters/code/local.js +528 -182
- package/dist/esm/adapters/code/local.js.map +1 -1
- package/dist/esm/adapters/code/output.d.ts +70 -0
- package/dist/esm/adapters/code/output.js +129 -0
- package/dist/esm/adapters/code/output.js.map +1 -0
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.d.ts +7 -6
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js +7 -6
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts +32 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.js +35 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.js.map +1 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js +4 -2
- package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
- package/dist/esm/core/codeRunnerTool.d.ts +15 -3
- package/dist/esm/core/codeRunnerTool.js +52 -7
- package/dist/esm/core/codeRunnerTool.js.map +1 -1
- package/dist/esm/doors/providers.d.ts +1 -1
- package/dist/esm/doors/providers.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +144 -29
- 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/mcp/callLifetime.d.ts +57 -14
- package/dist/esm/mcp/callLifetime.js +67 -19
- package/dist/esm/mcp/callLifetime.js.map +1 -1
- package/dist/esm/mcp/callMarker.d.ts +43 -0
- package/dist/esm/mcp/callMarker.js +69 -0
- package/dist/esm/mcp/callMarker.js.map +1 -0
- package/dist/esm/mcp/connectionRefusals.js +7 -0
- package/dist/esm/mcp/connectionRefusals.js.map +1 -1
- package/dist/esm/mcp/index.d.ts +2 -0
- package/dist/esm/mcp/index.js +3 -0
- package/dist/esm/mcp/index.js.map +1 -1
- package/dist/esm/mcp/mcpClient.js +93 -26
- package/dist/esm/mcp/mcpClient.js.map +1 -1
- package/dist/esm/mcp/replay.d.ts +291 -0
- package/dist/esm/mcp/replay.js +405 -0
- package/dist/esm/mcp/replay.js.map +1 -0
- package/dist/esm/mcp/replayUnavailable.d.ts +68 -0
- package/dist/esm/mcp/replayUnavailable.js +87 -0
- package/dist/esm/mcp/replayUnavailable.js.map +1 -0
- package/dist/esm/mcp/requestLedger.d.ts +115 -32
- package/dist/esm/mcp/requestLedger.js +193 -52
- package/dist/esm/mcp/requestLedger.js.map +1 -1
- package/dist/esm/mcp/seriesEvidence.d.ts +73 -15
- package/dist/esm/mcp/seriesEvidence.js +114 -21
- package/dist/esm/mcp/seriesEvidence.js.map +1 -1
- package/dist/esm/mcp/throttleRetry.d.ts +86 -42
- package/dist/esm/mcp/throttleRetry.js +158 -50
- package/dist/esm/mcp/throttleRetry.js.map +1 -1
- package/dist/esm/mcp/toolResult.d.ts +6 -0
- package/dist/esm/mcp/toolResult.js +15 -0
- package/dist/esm/mcp/toolResult.js.map +1 -1
- package/dist/esm/mcp/types.d.ts +73 -8
- package/dist/esm/provider-contract/codeSandbox.d.ts +89 -0
- package/dist/esm/provider-contract/codeSandbox.js +119 -0
- package/dist/esm/provider-contract/codeSandbox.js.map +1 -0
- package/dist/esm/provider-contract/sessionExpired.d.ts +31 -0
- package/dist/esm/provider-contract/sessionExpired.js +40 -0
- package/dist/esm/provider-contract/sessionExpired.js.map +1 -0
- package/dist/esm/provider-contract/types.d.ts +166 -17
- package/dist/esm/provider-contract/types.js +9 -0
- package/dist/esm/provider-contract/types.js.map +1 -1
- package/dist/esm/redaction/knownStrings.js +16 -0
- package/dist/esm/redaction/knownStrings.js.map +1 -1
- package/dist/esm/tool-providers/index.d.ts +2 -2
- package/dist/esm/tool-providers/index.js +4 -0
- package/dist/esm/tool-providers/index.js.map +1 -1
- package/dist/esm/tools/requestEvidence.js +60 -0
- package/dist/esm/tools/requestEvidence.js.map +1 -1
- package/dist/index.js +12 -4
- package/dist/index.js.map +1 -1
- package/dist/mcp/callLifetime.js +66 -18
- package/dist/mcp/callLifetime.js.map +1 -1
- package/dist/mcp/callMarker.js +74 -0
- package/dist/mcp/callMarker.js.map +1 -0
- package/dist/mcp/connectionRefusals.js +7 -0
- package/dist/mcp/connectionRefusals.js.map +1 -1
- package/dist/mcp/index.js +5 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/mcpClient.js +91 -24
- package/dist/mcp/mcpClient.js.map +1 -1
- package/dist/mcp/replay.js +415 -0
- package/dist/mcp/replay.js.map +1 -0
- package/dist/mcp/replayUnavailable.js +92 -0
- package/dist/mcp/replayUnavailable.js.map +1 -0
- package/dist/mcp/requestLedger.js +193 -52
- package/dist/mcp/requestLedger.js.map +1 -1
- package/dist/mcp/seriesEvidence.js +116 -22
- package/dist/mcp/seriesEvidence.js.map +1 -1
- package/dist/mcp/throttleRetry.js +160 -51
- package/dist/mcp/throttleRetry.js.map +1 -1
- package/dist/mcp/toolResult.js +17 -1
- package/dist/mcp/toolResult.js.map +1 -1
- package/dist/provider-contract/codeSandbox.js +125 -0
- package/dist/provider-contract/codeSandbox.js.map +1 -0
- package/dist/provider-contract/sessionExpired.js +44 -0
- package/dist/provider-contract/sessionExpired.js.map +1 -0
- package/dist/provider-contract/types.js +12 -1
- package/dist/provider-contract/types.js.map +1 -1
- package/dist/redaction/knownStrings.js +16 -0
- package/dist/redaction/knownStrings.js.map +1 -1
- package/dist/tool-providers/index.js +5 -1
- package/dist/tool-providers/index.js.map +1 -1
- package/dist/tools/requestEvidence.js +60 -0
- package/dist/tools/requestEvidence.js.map +1 -1
- package/dist/types/adapters/code/agentcore.d.ts +65 -68
- package/dist/types/adapters/code/agentcore.d.ts.map +1 -1
- package/dist/types/adapters/code/agentcoreClient.d.ts +194 -0
- package/dist/types/adapters/code/agentcoreClient.d.ts.map +1 -0
- package/dist/types/adapters/code/agentcoreWire.d.ts +120 -0
- package/dist/types/adapters/code/agentcoreWire.d.ts.map +1 -0
- package/dist/types/adapters/code/fileName.d.ts +44 -0
- package/dist/types/adapters/code/fileName.d.ts.map +1 -0
- package/dist/types/adapters/code/local.d.ts +91 -12
- package/dist/types/adapters/code/local.d.ts.map +1 -1
- package/dist/types/adapters/code/output.d.ts +71 -0
- package/dist/types/adapters/code/output.d.ts.map +1 -0
- package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts +7 -6
- package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts.map +1 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts +32 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts.map +1 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/transport.d.ts.map +1 -1
- package/dist/types/core/codeRunnerTool.d.ts +15 -3
- package/dist/types/core/codeRunnerTool.d.ts.map +1 -1
- package/dist/types/doors/providers.d.ts +1 -1
- package/dist/types/doors/providers.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +144 -29
- package/dist/types/events/payloads.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/mcp/callLifetime.d.ts +57 -14
- package/dist/types/mcp/callLifetime.d.ts.map +1 -1
- package/dist/types/mcp/callMarker.d.ts +44 -0
- package/dist/types/mcp/callMarker.d.ts.map +1 -0
- package/dist/types/mcp/index.d.ts +2 -0
- package/dist/types/mcp/index.d.ts.map +1 -1
- package/dist/types/mcp/mcpClient.d.ts.map +1 -1
- package/dist/types/mcp/replay.d.ts +292 -0
- package/dist/types/mcp/replay.d.ts.map +1 -0
- package/dist/types/mcp/replayUnavailable.d.ts +69 -0
- package/dist/types/mcp/replayUnavailable.d.ts.map +1 -0
- package/dist/types/mcp/requestLedger.d.ts +115 -32
- package/dist/types/mcp/requestLedger.d.ts.map +1 -1
- package/dist/types/mcp/seriesEvidence.d.ts +73 -15
- package/dist/types/mcp/seriesEvidence.d.ts.map +1 -1
- package/dist/types/mcp/throttleRetry.d.ts +86 -42
- package/dist/types/mcp/throttleRetry.d.ts.map +1 -1
- package/dist/types/mcp/toolResult.d.ts +6 -0
- package/dist/types/mcp/toolResult.d.ts.map +1 -1
- package/dist/types/mcp/types.d.ts +73 -8
- package/dist/types/mcp/types.d.ts.map +1 -1
- package/dist/types/provider-contract/codeSandbox.d.ts +90 -0
- package/dist/types/provider-contract/codeSandbox.d.ts.map +1 -0
- package/dist/types/provider-contract/sessionExpired.d.ts +32 -0
- package/dist/types/provider-contract/sessionExpired.d.ts.map +1 -0
- package/dist/types/provider-contract/types.d.ts +166 -17
- package/dist/types/provider-contract/types.d.ts.map +1 -1
- package/dist/types/redaction/knownStrings.d.ts.map +1 -1
- package/dist/types/tool-providers/index.d.ts +2 -2
- package/dist/types/tool-providers/index.d.ts.map +1 -1
- package/dist/types/tools/requestEvidence.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `agentCoreCodeRunner` has to know about AgentCore's wire, as pure
|
|
3
|
+
* functions: how big a request is, how a returned file is paired with the
|
|
4
|
+
* path asked for, how the staged-input manifest reaches a runtime that has no
|
|
5
|
+
* environment parameter, and which service errors mean the session is gone.
|
|
6
|
+
*
|
|
7
|
+
* Kept apart from the session so each rule is one small function with its
|
|
8
|
+
* own test, and so the session reads as the sequence it is.
|
|
9
|
+
*/
|
|
10
|
+
import { STAGED_INPUTS_ENV } from '../../provider-contract/types.js';
|
|
11
|
+
import { CodeSandboxError } from '../../provider-contract/codeSandbox.js';
|
|
12
|
+
import { isHighSurrogate, isLowSurrogate, payloadBytes } from './output.js';
|
|
13
|
+
// ── Request size ─────────────────────────────────────────────────────────
|
|
14
|
+
/**
|
|
15
|
+
* AgentCore's per-call limit for `InvokeCodeInterpreter`: "Max payload size —
|
|
16
|
+
* 100 MB — Maximum size for request/response payloads", not adjustable
|
|
17
|
+
* (AgentCore Code Interpreter service quotas).
|
|
18
|
+
*
|
|
19
|
+
* The service does not say whether that MB is 10^6 or 2^20 bytes, so the
|
|
20
|
+
* adapter holds a request to the SMALLER reading: a request it sends is never
|
|
21
|
+
* one the limit could refuse on size, and one between the two readings is
|
|
22
|
+
* refused here by name rather than by the service in words nobody can act on.
|
|
23
|
+
*/
|
|
24
|
+
export const AGENTCORE_MAX_REQUEST_BYTES = 100_000_000;
|
|
25
|
+
/** `{"arguments":{"content":[` … `]},"name":"writeFiles"}` around the entries. */
|
|
26
|
+
const WRITE_FILES_ENVELOPE_BYTES = JSON.stringify({
|
|
27
|
+
arguments: { content: [] },
|
|
28
|
+
name: 'writeFiles',
|
|
29
|
+
}).length;
|
|
30
|
+
/**
|
|
31
|
+
* The size, in bytes, of the JSON body one `writeFiles` request sends —
|
|
32
|
+
* computed, not built: text as its JSON-escaped UTF-8, bytes as base64 (how
|
|
33
|
+
* the JSON protocol carries a blob), plus the envelope. Building the body to
|
|
34
|
+
* measure it would hold a second copy of up to a hundred megabytes.
|
|
35
|
+
*/
|
|
36
|
+
export function writeFilesRequestBytes(content) {
|
|
37
|
+
let bytes = WRITE_FILES_ENVELOPE_BYTES + Math.max(content.length - 1, 0); // the commas
|
|
38
|
+
for (const entry of content) {
|
|
39
|
+
bytes += '{"path":'.length + jsonStringBytes(entry.path) + '}'.length;
|
|
40
|
+
if (entry.text !== undefined)
|
|
41
|
+
bytes += ',"text":'.length + jsonStringBytes(entry.text);
|
|
42
|
+
else
|
|
43
|
+
bytes += ',"blob":'.length + 2 + base64Length(entry.blob.byteLength);
|
|
44
|
+
}
|
|
45
|
+
return bytes;
|
|
46
|
+
}
|
|
47
|
+
/** Bytes of `JSON.stringify(text)` encoded as UTF-8, quotes included, without building it. */
|
|
48
|
+
export function jsonStringBytes(text) {
|
|
49
|
+
let bytes = 2;
|
|
50
|
+
for (let i = 0; i < text.length; i++) {
|
|
51
|
+
const unit = text.charCodeAt(i);
|
|
52
|
+
if (unit === 0x22 || unit === 0x5c)
|
|
53
|
+
bytes += 2; // \" and \\
|
|
54
|
+
else if (unit < 0x20)
|
|
55
|
+
bytes += SHORT_ESCAPES.has(unit) ? 2 : 6; // \n … or \u00XX
|
|
56
|
+
else if (unit < 0x80)
|
|
57
|
+
bytes += 1;
|
|
58
|
+
else if (unit < 0x800)
|
|
59
|
+
bytes += 2;
|
|
60
|
+
else if (isHighSurrogate(unit) && isLowSurrogate(text.charCodeAt(i + 1))) {
|
|
61
|
+
bytes += 4;
|
|
62
|
+
i++;
|
|
63
|
+
}
|
|
64
|
+
else if (isHighSurrogate(unit) || isLowSurrogate(unit))
|
|
65
|
+
bytes += 6; // a lone half: \udXXX
|
|
66
|
+
else
|
|
67
|
+
bytes += 3;
|
|
68
|
+
}
|
|
69
|
+
return bytes;
|
|
70
|
+
}
|
|
71
|
+
/** Control characters JSON writes as a two-character escape: \b \t \n \f \r. */
|
|
72
|
+
const SHORT_ESCAPES = new Set([0x08, 0x09, 0x0a, 0x0c, 0x0d]);
|
|
73
|
+
function base64Length(bytes) {
|
|
74
|
+
return 4 * Math.ceil(bytes / 3);
|
|
75
|
+
}
|
|
76
|
+
/** One `writeFiles` entry for a payload: TEXT for a string, BYTES for bytes. */
|
|
77
|
+
export function fileContent(path, data) {
|
|
78
|
+
return typeof data === 'string' ? { path, text: data } : { path, blob: data };
|
|
79
|
+
}
|
|
80
|
+
// ── Reading a file back ──────────────────────────────────────────────────
|
|
81
|
+
/** How AgentCore names a file it returns: `file:///` + the path asked for,
|
|
82
|
+
* percent-encoded (read from a published real `readFiles` answer:
|
|
83
|
+
* `report.csv` → `file:///report.csv`; the shape is not in AWS's docs). */
|
|
84
|
+
const FILE_URI_PREFIX = 'file:///';
|
|
85
|
+
/**
|
|
86
|
+
* The one file a `readFiles` answer returned for `path` — or a refusal.
|
|
87
|
+
*
|
|
88
|
+
* Paired by the URI the SERVICE put on the file, never by position: a file
|
|
89
|
+
* with no URI, or a URI naming another path, fails closed, and so does an
|
|
90
|
+
* answer carrying several files for one path. Text or bytes is read off which
|
|
91
|
+
* field the service filled — never off the file's name — and an entry with
|
|
92
|
+
* both, or neither, is refused. A file over `maxBytes` is refused whole.
|
|
93
|
+
*/
|
|
94
|
+
export function pairReadFile(path, answer, maxBytes) {
|
|
95
|
+
const refuse = (reason, why) => {
|
|
96
|
+
throw new CodeSandboxError(reason, `agentCoreCodeRunner: reading '${path}' — ${why}`, { path });
|
|
97
|
+
};
|
|
98
|
+
if (answer.isError === true) {
|
|
99
|
+
refuse('file-not-returned', 'the service flagged its answer as an error, so no file came back. Its words are not ' +
|
|
100
|
+
'repeated here.');
|
|
101
|
+
}
|
|
102
|
+
const resources = answer.resources ?? [];
|
|
103
|
+
if (resources.length === 0)
|
|
104
|
+
refuse('file-not-returned', 'the answer held no file.');
|
|
105
|
+
for (const resource of resources) {
|
|
106
|
+
if (typeof resource.uri !== 'string' || resource.uri.length === 0) {
|
|
107
|
+
refuse('uri-missing', 'a file came back without a URI, so it cannot be paired with the path asked for.');
|
|
108
|
+
}
|
|
109
|
+
if (hasQueryOrFragment(resource.uri)) {
|
|
110
|
+
refuse('uri-mismatch', 'a file came back under a URI with a query or fragment, which is not part of any file ' +
|
|
111
|
+
'name (a literal ? or # in a name arrives as %3F or %23).');
|
|
112
|
+
}
|
|
113
|
+
if (!uriNames(resource.uri, path)) {
|
|
114
|
+
refuse('uri-mismatch', 'a file came back under a URI that names another path.');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (resources.length > 1)
|
|
118
|
+
refuse('content-ambiguous', `${resources.length} files came back for one path.`);
|
|
119
|
+
const resource = resources[0];
|
|
120
|
+
const hasText = resource.text !== undefined && resource.text !== null;
|
|
121
|
+
const hasBlob = resource.blob !== undefined && resource.blob !== null;
|
|
122
|
+
if (hasText === hasBlob) {
|
|
123
|
+
refuse('content-ambiguous', hasText
|
|
124
|
+
? 'the file came back as both text and bytes.'
|
|
125
|
+
: 'the file came back with neither text nor bytes.');
|
|
126
|
+
}
|
|
127
|
+
if (hasText && typeof resource.text !== 'string')
|
|
128
|
+
refuse('content-ambiguous', 'its text is not a string.');
|
|
129
|
+
if (hasBlob && !isBytes(resource.blob))
|
|
130
|
+
refuse('content-ambiguous', 'its bytes are not bytes.');
|
|
131
|
+
const data = hasText ? resource.text : resource.blob;
|
|
132
|
+
const bytes = payloadBytes(data);
|
|
133
|
+
if (bytes > maxBytes) {
|
|
134
|
+
throw new CodeSandboxError('file-too-large', `agentCoreCodeRunner: '${path}' is ${bytes} bytes and this read allows ${maxBytes}. ` +
|
|
135
|
+
'Nothing was returned — a file is never handed back cut.', { path, bytes, limit: maxBytes });
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
path,
|
|
139
|
+
data,
|
|
140
|
+
bytes,
|
|
141
|
+
...(typeof resource.mimeType === 'string' &&
|
|
142
|
+
resource.mimeType.length > 0 && {
|
|
143
|
+
mediaType: resource.mimeType,
|
|
144
|
+
}),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Does `uri` name `path`? ONE declared form, read ONE way (RFC 8089's file
|
|
149
|
+
* URI, RFC 3986's path syntax): `file:///` followed by a path whose segments
|
|
150
|
+
* are percent-encoded.
|
|
151
|
+
*
|
|
152
|
+
* - A raw `?` or `#` starts a query or a fragment, which is never part of a
|
|
153
|
+
* file name, so a URI carrying one is refused outright. A name that really
|
|
154
|
+
* contains `?` or `#` arrives as `%3F` / `%23`.
|
|
155
|
+
* - Each segment is decoded on its own. An invalid escape refuses the URI, and
|
|
156
|
+
* a decoded `/` (an encoded `%2F`) is a character inside one name, so it can
|
|
157
|
+
* never stand in for the separator.
|
|
158
|
+
* - Only the decoded path is compared. There is no second, raw reading to fall
|
|
159
|
+
* back on when the first does not match.
|
|
160
|
+
*/
|
|
161
|
+
export function uriNames(uri, path) {
|
|
162
|
+
if (!uri.startsWith(FILE_URI_PREFIX))
|
|
163
|
+
return false;
|
|
164
|
+
const named = uri.slice(FILE_URI_PREFIX.length);
|
|
165
|
+
if (hasQueryOrFragment(named))
|
|
166
|
+
return false;
|
|
167
|
+
const segments = [];
|
|
168
|
+
for (const encoded of named.split('/')) {
|
|
169
|
+
let segment;
|
|
170
|
+
try {
|
|
171
|
+
segment = decodeURIComponent(encoded);
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
if (segment.includes('/'))
|
|
177
|
+
return false;
|
|
178
|
+
segments.push(segment);
|
|
179
|
+
}
|
|
180
|
+
return segments.join('/') === path;
|
|
181
|
+
}
|
|
182
|
+
/** A raw `?` or `#` in a URI: a query or a fragment component. */
|
|
183
|
+
function hasQueryOrFragment(uriTail) {
|
|
184
|
+
return uriTail.includes('?') || uriTail.includes('#');
|
|
185
|
+
}
|
|
186
|
+
function isBytes(value) {
|
|
187
|
+
return (value instanceof Uint8Array || Object.prototype.toString.call(value) === '[object Uint8Array]');
|
|
188
|
+
}
|
|
189
|
+
// ── The staged-input manifest ────────────────────────────────────────────
|
|
190
|
+
/** Where staged inputs land, relative to the session's working directory. */
|
|
191
|
+
export const STAGED_INPUTS_DIR = 'af-staged-inputs';
|
|
192
|
+
/** The line the manifest setup prints once the variable is set. */
|
|
193
|
+
export const MANIFEST_SET_MARKER = 'af-staged-inputs-set';
|
|
194
|
+
/**
|
|
195
|
+
* Which runtime a language names, for the manifest setup. `undefined` (no
|
|
196
|
+
* language sent) is the service's default runtime, Python; a language this
|
|
197
|
+
* adapter does not know is `undefined` — and refused, never guessed.
|
|
198
|
+
*/
|
|
199
|
+
export function manifestRuntime(language) {
|
|
200
|
+
if (language === undefined || language === '')
|
|
201
|
+
return 'python';
|
|
202
|
+
const lower = language.toLowerCase();
|
|
203
|
+
if (lower === 'python' || lower === 'python3' || lower === 'py')
|
|
204
|
+
return 'python';
|
|
205
|
+
if (lower === 'javascript' || lower === 'js' || lower === 'node')
|
|
206
|
+
return 'javascript';
|
|
207
|
+
if (lower === 'typescript' || lower === 'ts')
|
|
208
|
+
return 'typescript';
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* The code that sets {@link STAGED_INPUTS_ENV} inside one runtime of the
|
|
213
|
+
* session, then prints {@link MANIFEST_SET_MARKER}.
|
|
214
|
+
*
|
|
215
|
+
* WHY A SEPARATE CALL. `executeCode` takes no environment, and prepending a
|
|
216
|
+
* line to the caller's code would shift every line number its traceback
|
|
217
|
+
* reports and break a Python `from __future__` import. The session's runtime
|
|
218
|
+
* keeps its state between executions, so the variable is set once per
|
|
219
|
+
* runtime and manifest, by this code, before the caller's code runs.
|
|
220
|
+
*
|
|
221
|
+
* The value is the manifest JSON as a JSON string literal, which is a valid
|
|
222
|
+
* string literal in Python and in JavaScript alike.
|
|
223
|
+
*/
|
|
224
|
+
export function manifestSetupCode(runtime, manifestJson) {
|
|
225
|
+
const value = JSON.stringify(manifestJson);
|
|
226
|
+
const name = JSON.stringify(STAGED_INPUTS_ENV);
|
|
227
|
+
const marker = JSON.stringify(MANIFEST_SET_MARKER);
|
|
228
|
+
if (runtime === 'python') {
|
|
229
|
+
return [
|
|
230
|
+
'import os as _af_os',
|
|
231
|
+
`_af_os.environ[${name}] = ${value}`,
|
|
232
|
+
'del _af_os',
|
|
233
|
+
`print(${marker})`,
|
|
234
|
+
].join('\n');
|
|
235
|
+
}
|
|
236
|
+
return [
|
|
237
|
+
'{',
|
|
238
|
+
runtime === 'typescript'
|
|
239
|
+
? ' const _afHost: any = globalThis;'
|
|
240
|
+
: ' const _afHost = globalThis;',
|
|
241
|
+
` const _afValue = ${value};`,
|
|
242
|
+
' if (_afHost.process && _afHost.process.env) {',
|
|
243
|
+
` _afHost.process.env[${name}] = _afValue;`,
|
|
244
|
+
' } else {',
|
|
245
|
+
` _afHost.Deno.env.set(${name}, _afValue);`,
|
|
246
|
+
' }',
|
|
247
|
+
` console.log(${marker});`,
|
|
248
|
+
'}',
|
|
249
|
+
].join('\n');
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* `command`, with {@link STAGED_INPUTS_ENV} exported ahead of it.
|
|
253
|
+
*
|
|
254
|
+
* A command is its own shell process, so a variable set in a code runtime
|
|
255
|
+
* never reaches it; this line does, every time, and needs no state. The value
|
|
256
|
+
* is single-quoted, the one shell quoting with no expansions inside it.
|
|
257
|
+
*/
|
|
258
|
+
export function withManifestExport(command, manifestJson) {
|
|
259
|
+
return `export ${STAGED_INPUTS_ENV}=${shellQuoted(manifestJson)}\n${command}`;
|
|
260
|
+
}
|
|
261
|
+
function shellQuoted(text) {
|
|
262
|
+
return `'${text.split("'").join(`'\\''`)}'`;
|
|
263
|
+
}
|
|
264
|
+
// ── Service errors ───────────────────────────────────────────────────────
|
|
265
|
+
/** The exceptions AgentCore models for `InvokeCodeInterpreter`, by class name. */
|
|
266
|
+
const MODELLED_EXCEPTIONS = new Set([
|
|
267
|
+
'AccessDeniedException',
|
|
268
|
+
'ConflictException',
|
|
269
|
+
'InternalServerException',
|
|
270
|
+
'ResourceNotFoundException',
|
|
271
|
+
'ServiceQuotaExceededException',
|
|
272
|
+
'ThrottlingException',
|
|
273
|
+
'ValidationException',
|
|
274
|
+
]);
|
|
275
|
+
/** Words a service uses for a session that is gone — both halves required, so
|
|
276
|
+
* a validation message that merely echoes a request containing "inactive"
|
|
277
|
+
* is not read as a dead session. */
|
|
278
|
+
const SAYS_INACTIVE = /\bnot active\b|\binactive\b/i;
|
|
279
|
+
const NAMES_A_SESSION = /\bsession\b/i;
|
|
280
|
+
/**
|
|
281
|
+
* What a service error says about the session: `'session'` when it means the
|
|
282
|
+
* session itself is gone, `'file-or-session'` when it could mean that or a
|
|
283
|
+
* missing file, `undefined` otherwise.
|
|
284
|
+
*
|
|
285
|
+
* - A modelled exception — a `ValidationException` above all — whose words
|
|
286
|
+
* name a session and say it is "not active" or "inactive": `'session'`.
|
|
287
|
+
* - A `ResourceNotFoundException`, thrown by the SDK or carried on the stream:
|
|
288
|
+
* on a call that addresses nothing but the session (code, a command, a
|
|
289
|
+
* write) the missing resource is the session, so `'session'`. A READ also
|
|
290
|
+
* names a file, and AgentCore does not say which resource was missing, so
|
|
291
|
+
* `'file-or-session'` — never taken as proof the session is gone.
|
|
292
|
+
*/
|
|
293
|
+
export function sessionExpiryEvidence(err, tool) {
|
|
294
|
+
const name = errorNameOf(err);
|
|
295
|
+
const message = errorMessage(err);
|
|
296
|
+
if (MODELLED_EXCEPTIONS.has(name) &&
|
|
297
|
+
SAYS_INACTIVE.test(message) &&
|
|
298
|
+
NAMES_A_SESSION.test(message)) {
|
|
299
|
+
return 'session';
|
|
300
|
+
}
|
|
301
|
+
if (name === 'ResourceNotFoundException') {
|
|
302
|
+
return tool === 'readFiles' ? 'file-or-session' : 'session';
|
|
303
|
+
}
|
|
304
|
+
return undefined;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* A modelled service exception from a file or command call, rewritten in
|
|
308
|
+
* fixed words that name the exception and the call — or `undefined` for any
|
|
309
|
+
* other error, which passes through as it is.
|
|
310
|
+
*
|
|
311
|
+
* The service's own message is NOT repeated: a validation message can quote
|
|
312
|
+
* what was sent, and what was sent here is a path, a command or a file's
|
|
313
|
+
* bytes. The exception's name is kept as the error's `name`, so a caller
|
|
314
|
+
* branches on it exactly as on the SDK's own error.
|
|
315
|
+
*/
|
|
316
|
+
export function serviceRefusal(err, tool) {
|
|
317
|
+
const name = errorNameOf(err);
|
|
318
|
+
if (!MODELLED_EXCEPTIONS.has(name))
|
|
319
|
+
return undefined;
|
|
320
|
+
const refusal = new Error(`agentCoreCodeRunner: the service refused ${tool} (${name}). Its message is not repeated ` +
|
|
321
|
+
'here, because it can quote what was sent.');
|
|
322
|
+
refusal.name = name;
|
|
323
|
+
return refusal;
|
|
324
|
+
}
|
|
325
|
+
/** The `name` an error carries — an SDK exception's class name — or `''`. */
|
|
326
|
+
export function errorNameOf(err) {
|
|
327
|
+
const name = err?.name;
|
|
328
|
+
return typeof name === 'string' ? name : '';
|
|
329
|
+
}
|
|
330
|
+
function errorMessage(err) {
|
|
331
|
+
const message = err?.message;
|
|
332
|
+
return typeof message === 'string' ? message : '';
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=agentcoreWire.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentcoreWire.js","sourceRoot":"","sources":["../../../../src/adapters/code/agentcoreWire.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one file-name encoder both code adapters stage inputs under.
|
|
3
|
+
*
|
|
4
|
+
* A staged input's name is caller data landing in a filesystem — a local temp
|
|
5
|
+
* directory for `localCodeRunner`, the sandbox's own disk for
|
|
6
|
+
* `agentCoreCodeRunner`. Both turn it into ONE inert segment through this
|
|
7
|
+
* function, so the same name lands under the same file name on either backend
|
|
8
|
+
* and two names never become one file on either.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* One caller-supplied name → one inert file-name segment, **without ever
|
|
12
|
+
* folding two names into one file**.
|
|
13
|
+
*
|
|
14
|
+
* Separators cannot survive as a parent hop and `a/b` cannot become two
|
|
15
|
+
* segments — the same law `artifacts/scopePath` states for scope tuples,
|
|
16
|
+
* applied to the one other place caller strings become file names in this
|
|
17
|
+
* package. But the old version got there by REPLACING every illegal character
|
|
18
|
+
* with `_`, which meant `a/b.csv` and `a_b.csv` became the same file: the
|
|
19
|
+
* second write clobbered the first's bytes, `stageInputs` answered two manifest
|
|
20
|
+
* entries pointing at one path, and the model's code opened `a/b.csv` and read
|
|
21
|
+
* whatever `a_b.csv` contained. Nothing failed. The computation was simply run
|
|
22
|
+
* against the wrong dataset — which is the worst shape a data bug can take,
|
|
23
|
+
* because the answer still looks like an answer. `.slice(0, 120)` folded the
|
|
24
|
+
* same way for any two names agreeing on their first 120 characters.
|
|
25
|
+
*
|
|
26
|
+
* So this ENCODES instead of sanitising, in two arms whose outputs cannot meet
|
|
27
|
+
* (the shape `safeSessionId` uses in `adapters/hosting/agentcore.ts`):
|
|
28
|
+
*
|
|
29
|
+
* A. already one legal segment, not claiming to be an encoded name, and not
|
|
30
|
+
* dots-only → returned BYTE FOR BYTE. This is what keeps the fix from
|
|
31
|
+
* renaming anything that works today: `dataset.json`, `a_b.json`, every
|
|
32
|
+
* name `codeRunnerTool` derives from a declared argument, all land at
|
|
33
|
+
* exactly the path they landed at before.
|
|
34
|
+
* B. anything else → `_enc_` + an escaped form, where `_` is the escape
|
|
35
|
+
* character (`_` → `__`, any other illegal UTF-16 unit → `_uXXXX`). A
|
|
36
|
+
* decoder is a left inverse of that, which is what makes it injective.
|
|
37
|
+
*
|
|
38
|
+
* Arm A never starts with `_enc_` (excluded by construction) and every arm B
|
|
39
|
+
* output does, so no name from one arm can collide with a name from the other.
|
|
40
|
+
* Both arms produce ASCII with no `/`, no `\` and no NUL, so the path-hop law
|
|
41
|
+
* the old version enforced is unchanged.
|
|
42
|
+
*/
|
|
43
|
+
export declare function safeFileName(raw: string): string;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one file-name encoder both code adapters stage inputs under.
|
|
3
|
+
*
|
|
4
|
+
* A staged input's name is caller data landing in a filesystem — a local temp
|
|
5
|
+
* directory for `localCodeRunner`, the sandbox's own disk for
|
|
6
|
+
* `agentCoreCodeRunner`. Both turn it into ONE inert segment through this
|
|
7
|
+
* function, so the same name lands under the same file name on either backend
|
|
8
|
+
* and two names never become one file on either.
|
|
9
|
+
*/
|
|
10
|
+
import { sha256Hex } from '../../lib/sha256.js';
|
|
11
|
+
/** Longest file name this adapter will write. Well inside every POSIX
|
|
12
|
+
* `NAME_MAX`, and the cap this adapter has always used. */
|
|
13
|
+
const FILE_NAME_MAX = 120;
|
|
14
|
+
/** Marks a name this adapter had to rewrite. Nothing arm A returns may start
|
|
15
|
+
* with it. */
|
|
16
|
+
const ENCODED_FILE_PREFIX = '_enc_';
|
|
17
|
+
/** Already one inert segment: no separator, no escape-looking bytes. */
|
|
18
|
+
const FILE_NAME_ALREADY_LEGAL = /^[A-Za-z0-9._-]+$/;
|
|
19
|
+
/** `.`, `..`, `...` — a name that is nothing but dots. Not a hop once the
|
|
20
|
+
* separators are gone, but not a name either, so it goes to arm B. */
|
|
21
|
+
const DOTS_ONLY = /^\.+$/;
|
|
22
|
+
/** Legal AND not the escape character — the set {@link encodeFileName} passes
|
|
23
|
+
* through untouched. */
|
|
24
|
+
const FILE_CHAR_PASSES_THROUGH = /[A-Za-z0-9.-]/;
|
|
25
|
+
/**
|
|
26
|
+
* One caller-supplied name → one inert file-name segment, **without ever
|
|
27
|
+
* folding two names into one file**.
|
|
28
|
+
*
|
|
29
|
+
* Separators cannot survive as a parent hop and `a/b` cannot become two
|
|
30
|
+
* segments — the same law `artifacts/scopePath` states for scope tuples,
|
|
31
|
+
* applied to the one other place caller strings become file names in this
|
|
32
|
+
* package. But the old version got there by REPLACING every illegal character
|
|
33
|
+
* with `_`, which meant `a/b.csv` and `a_b.csv` became the same file: the
|
|
34
|
+
* second write clobbered the first's bytes, `stageInputs` answered two manifest
|
|
35
|
+
* entries pointing at one path, and the model's code opened `a/b.csv` and read
|
|
36
|
+
* whatever `a_b.csv` contained. Nothing failed. The computation was simply run
|
|
37
|
+
* against the wrong dataset — which is the worst shape a data bug can take,
|
|
38
|
+
* because the answer still looks like an answer. `.slice(0, 120)` folded the
|
|
39
|
+
* same way for any two names agreeing on their first 120 characters.
|
|
40
|
+
*
|
|
41
|
+
* So this ENCODES instead of sanitising, in two arms whose outputs cannot meet
|
|
42
|
+
* (the shape `safeSessionId` uses in `adapters/hosting/agentcore.ts`):
|
|
43
|
+
*
|
|
44
|
+
* A. already one legal segment, not claiming to be an encoded name, and not
|
|
45
|
+
* dots-only → returned BYTE FOR BYTE. This is what keeps the fix from
|
|
46
|
+
* renaming anything that works today: `dataset.json`, `a_b.json`, every
|
|
47
|
+
* name `codeRunnerTool` derives from a declared argument, all land at
|
|
48
|
+
* exactly the path they landed at before.
|
|
49
|
+
* B. anything else → `_enc_` + an escaped form, where `_` is the escape
|
|
50
|
+
* character (`_` → `__`, any other illegal UTF-16 unit → `_uXXXX`). A
|
|
51
|
+
* decoder is a left inverse of that, which is what makes it injective.
|
|
52
|
+
*
|
|
53
|
+
* Arm A never starts with `_enc_` (excluded by construction) and every arm B
|
|
54
|
+
* output does, so no name from one arm can collide with a name from the other.
|
|
55
|
+
* Both arms produce ASCII with no `/`, no `\` and no NUL, so the path-hop law
|
|
56
|
+
* the old version enforced is unchanged.
|
|
57
|
+
*/
|
|
58
|
+
export function safeFileName(raw) {
|
|
59
|
+
if (raw.length <= FILE_NAME_MAX &&
|
|
60
|
+
FILE_NAME_ALREADY_LEGAL.test(raw) &&
|
|
61
|
+
!raw.startsWith(ENCODED_FILE_PREFIX) &&
|
|
62
|
+
!DOTS_ONLY.test(raw)) {
|
|
63
|
+
return raw;
|
|
64
|
+
}
|
|
65
|
+
const encoded = ENCODED_FILE_PREFIX + encodeFileName(raw);
|
|
66
|
+
// Strictly less, so the two shapes below are told apart by LENGTH alone: a
|
|
67
|
+
// digested name is always exactly FILE_NAME_MAX and an escaped one never is.
|
|
68
|
+
if (encoded.length < FILE_NAME_MAX)
|
|
69
|
+
return encoded;
|
|
70
|
+
// Past the cap no mapping can stay injective — there are more names than
|
|
71
|
+
// there are file names — so the tail becomes a digest of the WHOLE raw name.
|
|
72
|
+
// SHA-256 rather than the package's 32-bit FNV-1a: a name reaching this
|
|
73
|
+
// adapter is caller data, and a 32-bit digest is a collision somebody can go
|
|
74
|
+
// and find, which for a file the model then reads as data is the same defect
|
|
75
|
+
// this function exists to close. `lib/sha256.ts` — the library's own,
|
|
76
|
+
// checked against `node:crypto` — so `agentCoreCodeRunner`, which may run
|
|
77
|
+
// where there is no `node:crypto`, encodes a name exactly as the local runner
|
|
78
|
+
// does.
|
|
79
|
+
const digest = sha256Hex(raw).slice(0, 32);
|
|
80
|
+
return `${encoded.slice(0, FILE_NAME_MAX - digest.length - 2)}_z${digest}`;
|
|
81
|
+
}
|
|
82
|
+
/** `_` → `__`, anything else illegal → `_uXXXX`. Injective by construction. */
|
|
83
|
+
function encodeFileName(raw) {
|
|
84
|
+
let out = '';
|
|
85
|
+
for (let i = 0; i < raw.length; i++) {
|
|
86
|
+
const ch = raw[i];
|
|
87
|
+
if (ch === '_')
|
|
88
|
+
out += '__';
|
|
89
|
+
else if (FILE_CHAR_PASSES_THROUGH.test(ch))
|
|
90
|
+
out += ch;
|
|
91
|
+
else
|
|
92
|
+
out += `_u${raw.charCodeAt(i).toString(16).padStart(4, '0')}`;
|
|
93
|
+
}
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=fileName.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileName.js","sourceRoot":"","sources":["../../../../src/adapters/code/fileName.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD;4DAC4D;AAC5D,MAAM,aAAa,GAAG,GAAG,CAAC;AAE1B;eACe;AACf,MAAM,mBAAmB,GAAG,OAAO,CAAC;AAEpC,wEAAwE;AACxE,MAAM,uBAAuB,GAAG,mBAAmB,CAAC;AAEpD;uEACuE;AACvE,MAAM,SAAS,GAAG,OAAO,CAAC;AAE1B;yBACyB;AACzB,MAAM,wBAAwB,GAAG,eAAe,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,IACE,GAAG,CAAC,MAAM,IAAI,aAAa;QAC3B,uBAAuB,CAAC,IAAI,CAAC,GAAG,CAAC;QACjC,CAAC,GAAG,CAAC,UAAU,CAAC,mBAAmB,CAAC;QACpC,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EACpB,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,OAAO,GAAG,mBAAmB,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IAC1D,2EAA2E;IAC3E,6EAA6E;IAC7E,IAAI,OAAO,CAAC,MAAM,GAAG,aAAa;QAAE,OAAO,OAAO,CAAC;IACnD,yEAAyE;IACzE,6EAA6E;IAC7E,wEAAwE;IACxE,6EAA6E;IAC7E,6EAA6E;IAC7E,sEAAsE;IACtE,0EAA0E;IAC1E,8EAA8E;IAC9E,QAAQ;IACR,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3C,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;AAC7E,CAAC;AAED,+EAA+E;AAC/E,SAAS,cAAc,CAAC,GAAW;IACjC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAW,CAAC;QAC5B,IAAI,EAAE,KAAK,GAAG;YAAE,GAAG,IAAI,IAAI,CAAC;aACvB,IAAI,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,GAAG,IAAI,EAAE,CAAC;;YACjD,GAAG,IAAI,KAAK,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IACrE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -12,7 +12,13 @@
|
|
|
12
12
|
*
|
|
13
13
|
* What a child process DOES give you:
|
|
14
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
|
|
15
|
+
* • kill on timeout, so runaway code has a ceiling — on POSIX the child
|
|
16
|
+
* runs in a process group of its own, and at the timeout, on an abort or
|
|
17
|
+
* at the output ceiling the runner stops that OWNED group (SIGKILL). That
|
|
18
|
+
* is cleanup, not containment: a descendant that starts its own session
|
|
19
|
+
* or group escapes it, and a host killed before its exit handlers run
|
|
20
|
+
* stops nothing. On Windows only the child itself can be stopped, and the
|
|
21
|
+
* timeout error says so;
|
|
16
22
|
* • no inherited stdin, so nothing can block waiting for a terminal;
|
|
17
23
|
* • an environment ALLOWLIST — `process.env` is not inherited (only `PATH`,
|
|
18
24
|
* so the interpreter can be found), so an `AWS_SECRET_ACCESS_KEY` in your
|
|
@@ -34,11 +40,21 @@
|
|
|
34
40
|
* is not a set this adapter can identify without guessing which of a developer's
|
|
35
41
|
* files were meant, and a dev-loop runner that quietly uploaded whatever
|
|
36
42
|
* appeared beside your source would be the worse failure. Producing outputs
|
|
37
|
-
* needs
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
43
|
+
* needs a declared output directory the model is told about and a size policy
|
|
44
|
+
* for what is too big to carry in-band; `readFile` below is the bounded
|
|
45
|
+
* read-back, for a caller that names the file. A runner that has all three
|
|
46
|
+
* fills the field, and `codeRunnerTool` mints every data-carrying entry with
|
|
47
|
+
* no further wiring.
|
|
48
|
+
*
|
|
49
|
+
* ── Files and commands ─────────────────────────────────────────────────────
|
|
50
|
+
* `readFile(path, { maxBytes })` reads ONE file back from the working
|
|
51
|
+
* directory — the path checked by the port's one rule (`sandboxPath`), then
|
|
52
|
+
* by its REAL location, so a symbolic link cannot lead it outside; a file over
|
|
53
|
+
* `maxBytes` is refused, never cut; a file on disk is bytes, so bytes come
|
|
54
|
+
* back and no encoding is guessed. `runCommand(command)` runs ONE `sh -c`
|
|
55
|
+
* command with the same environment allowlist as the code, and exists only on
|
|
56
|
+
* a runner built with `commands: true`. Neither is a network or filesystem
|
|
57
|
+
* jail: a command reaches whatever this machine reaches.
|
|
42
58
|
*
|
|
43
59
|
* So: a development loop, a trusted-input pipeline, a machine you would be
|
|
44
60
|
* relaxed about a shell script running on. NOT arbitrary model-written code
|
|
@@ -93,19 +109,30 @@ export interface LocalCodeRunnerOptions {
|
|
|
93
109
|
* reason over is a fragment.
|
|
94
110
|
*/
|
|
95
111
|
readonly maxOutputChars?: number;
|
|
112
|
+
/**
|
|
113
|
+
* Give each session `runCommand` — one `sh -c` command in the working
|
|
114
|
+
* directory, with the same environment allowlist as the code. Default
|
|
115
|
+
* `false`, and then the member is ABSENT (`canRunCodeCommands` says no):
|
|
116
|
+
* it runs arbitrary shell, so a runner offers it only when built to. Build
|
|
117
|
+
* one runner per agent that should have it.
|
|
118
|
+
*
|
|
119
|
+
* Not a jail: the command reaches this machine's filesystem and network, as
|
|
120
|
+
* the code already does.
|
|
121
|
+
*/
|
|
122
|
+
readonly commands?: boolean;
|
|
96
123
|
/** Stable id (default `'local-code-runner'`). Rides the session events. */
|
|
97
124
|
readonly id?: string;
|
|
98
125
|
/** @internal Test seam — the `node:child_process` module. */
|
|
99
126
|
readonly _childProcess?: ChildProcessModuleLike;
|
|
100
|
-
/** @internal Test seam — the `node:fs` slice staging
|
|
127
|
+
/** @internal Test seam — the `node:fs` slice staging and reading use. */
|
|
101
128
|
readonly _fs?: FsModuleLike;
|
|
102
129
|
/** @internal Test seam — where staging directories are created. Defaults to
|
|
103
130
|
* the OS temp directory. */
|
|
104
131
|
readonly _stagingRoot?: string;
|
|
105
132
|
}
|
|
106
|
-
/** The slice of `node:fs` staging
|
|
107
|
-
* caller actually stages something — a session that
|
|
108
|
-
* this runtime for a filesystem. */
|
|
133
|
+
/** The slice of `node:fs` staging and reading touch. Loaded lazily, and ONLY
|
|
134
|
+
* when a caller actually stages or reads something — a session that does
|
|
135
|
+
* neither never asks this runtime for a filesystem. */
|
|
109
136
|
export interface FsModuleLike {
|
|
110
137
|
readonly mkdtempSync?: (prefix: string) => string;
|
|
111
138
|
readonly writeFileSync?: (path: string, data: string | Uint8Array) => void;
|
|
@@ -113,18 +140,70 @@ export interface FsModuleLike {
|
|
|
113
140
|
recursive?: boolean;
|
|
114
141
|
force?: boolean;
|
|
115
142
|
}) => void;
|
|
143
|
+
readonly realpathSync?: (path: string) => string;
|
|
144
|
+
readonly openSync?: (path: string, flags: string | number) => number;
|
|
145
|
+
/** The open flags a read uses where the platform has them. */
|
|
146
|
+
readonly constants?: {
|
|
147
|
+
readonly O_RDONLY?: number;
|
|
148
|
+
readonly O_NONBLOCK?: number;
|
|
149
|
+
readonly O_NOFOLLOW?: number;
|
|
150
|
+
};
|
|
151
|
+
readonly fstatSync?: (fd: number) => {
|
|
152
|
+
isFile(): boolean;
|
|
153
|
+
readonly size: number;
|
|
154
|
+
};
|
|
155
|
+
readonly readSync?: (fd: number, buffer: Uint8Array, offset: number, length: number, position: number | null) => number;
|
|
156
|
+
readonly closeSync?: (fd: number) => void;
|
|
116
157
|
}
|
|
117
158
|
/** The slice of `node:child_process` this adapter touches. */
|
|
118
159
|
export interface ChildProcessModuleLike {
|
|
160
|
+
/** Used when present (the real module always has it): only `spawn` can give
|
|
161
|
+
* a child a process group of its own. */
|
|
162
|
+
readonly spawn?: SpawnLike;
|
|
119
163
|
readonly execFile?: (file: string, args: readonly string[], options: {
|
|
120
164
|
cwd?: string;
|
|
121
165
|
env?: Record<string, string>;
|
|
122
|
-
timeout?: number;
|
|
123
166
|
maxBuffer?: number;
|
|
124
|
-
|
|
167
|
+
killSignal?: string;
|
|
168
|
+
detached?: boolean;
|
|
125
169
|
}, callback: (error: (Error & {
|
|
126
170
|
code?: number | string;
|
|
127
171
|
killed?: boolean;
|
|
172
|
+
signal?: string | null;
|
|
128
173
|
}) | null, stdout: string, stderr: string) => void) => unknown;
|
|
129
174
|
}
|
|
175
|
+
/** The part of the child `execFile` / `spawn` hands back that ending it needs. */
|
|
176
|
+
interface ChildLike {
|
|
177
|
+
readonly pid?: number;
|
|
178
|
+
kill?(signal?: string): boolean;
|
|
179
|
+
readonly stdout?: {
|
|
180
|
+
destroy?(): void;
|
|
181
|
+
} | null;
|
|
182
|
+
readonly stderr?: {
|
|
183
|
+
destroy?(): void;
|
|
184
|
+
} | null;
|
|
185
|
+
}
|
|
186
|
+
/** A readable end of a spawned child's pipe, as far as collecting it goes. */
|
|
187
|
+
interface PipeLike {
|
|
188
|
+
on(event: 'data', listener: (chunk: Uint8Array) => void): unknown;
|
|
189
|
+
destroy?(): void;
|
|
190
|
+
}
|
|
191
|
+
/** The child `spawn` hands back, as far as this adapter uses it. */
|
|
192
|
+
interface SpawnedLike extends ChildLike {
|
|
193
|
+
readonly stdout?: PipeLike | null;
|
|
194
|
+
readonly stderr?: PipeLike | null;
|
|
195
|
+
on(event: 'error', listener: (error: Error & {
|
|
196
|
+
code?: string;
|
|
197
|
+
}) => void): unknown;
|
|
198
|
+
on(event: 'close', listener: (code: number | null, signal: string | null) => void): unknown;
|
|
199
|
+
}
|
|
200
|
+
/** The slice of `node:child_process` · `spawn` the runner uses — preferred
|
|
201
|
+
* over `execFile`, which does not pass `detached` on to the child. */
|
|
202
|
+
type SpawnLike = (file: string, args: readonly string[], options: {
|
|
203
|
+
cwd?: string;
|
|
204
|
+
env?: Record<string, string>;
|
|
205
|
+
detached?: boolean;
|
|
206
|
+
stdio?: readonly ['ignore', 'pipe', 'pipe'];
|
|
207
|
+
}) => SpawnedLike;
|
|
130
208
|
export declare function localCodeRunner(options?: LocalCodeRunnerOptions): CodeRunner;
|
|
209
|
+
export {};
|