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,121 @@
1
+ /**
2
+ * codeRunnerTool — the tool that turns a {@link CodeRunner} into something an
3
+ * LLM can call, holding ONE session per isolation key.
4
+ *
5
+ * Pattern: Factory over `defineTool` + the 9.7.0 tool-session contract.
6
+ * Role: the first consumer of `ctx.onTeardown` — and the proof it works.
7
+ * Emits: nothing directly; the teardown tier reports
8
+ * `agentfootprint.tools.session_started` / `_reused` / `_closed` /
9
+ * `_close_failed`.
10
+ *
11
+ * ── The doctrine: summarize prose, compute data ─────────────────────────────
12
+ * A tool that hands the model 40,000 rows has not given it data; it has spent
13
+ * the window. The motivating failure is real and measured: a production request
14
+ * of 879,073 tokens, almost all of it one tool result pasted into the prompt.
15
+ * (Since 9.6.0 that shape at least fails by NAME —
16
+ * `ContextWindowExceededError` — instead of as a vendor 400. This is the other
17
+ * half: not failing better, but not needing to.)
18
+ *
19
+ * With a code runner the model writes an aggregation, the RUNNER holds the
20
+ * rows, and what comes back is the number. Prose gets summarized; data gets
21
+ * computed.
22
+ *
23
+ * ── Why the session must be keyed, and keyed WIDELY ENOUGH ──────────────────
24
+ * The session is the whole value: a code interpreter costs seconds to start and
25
+ * milliseconds to invoke. But a session holds a filesystem, an environment and
26
+ * half-run state, so the thing it is keyed on IS the isolation boundary. A
27
+ * standing agent serving many people from one process, holding one session in a
28
+ * module map, gives person B person A's files.
29
+ *
30
+ * So the key comes from `toolSessionKey(ctx, scope)` — one exported
31
+ * implementation, composing tenant + principal + (session | run). Never a bare
32
+ * `sessionId`: that is caller data, and anyone who can reach the host can put
33
+ * someone else's there.
34
+ *
35
+ * ── Degradation is REFUSED, never silent ────────────────────────────────────
36
+ * Ask for `scope: 'session'` at a door with no session and this throws, naming
37
+ * the door. It does not quietly fall back. Falling back to a WIDER key is the
38
+ * cross-binding bug itself; falling back to a NARROWER one is a silent 30×
39
+ * latency change nobody sees until the bill.
40
+ *
41
+ * @example a session per run, on a local dev machine
42
+ * const agent = Agent.create({ provider })
43
+ * .tool(codeRunnerTool({ runner: localCodeRunner() }))
44
+ * .build();
45
+ *
46
+ * @example a session per hosted conversation, on a real sandbox
47
+ * const runner = agentCoreCodeRunner({ region, identifier: 'aws.codeinterpreter.v1' });
48
+ * const agent = Agent.create({ provider })
49
+ * .tool(codeRunnerTool({ runner, scope: 'session', language: 'python' }))
50
+ * .build();
51
+ * // the composition root says when a session is over:
52
+ * conversation.onClose(() => void agent.closeToolSessions({ sessionId }));
53
+ */
54
+ import type { CodeRunner, CodeSession } from '../adapters/types.js';
55
+ import type { CredentialNeed } from '../identity/types.js';
56
+ import type { CheckInDemand } from './checkin.js';
57
+ import { type Tool } from './tools.js';
58
+ import { type TeardownScope } from './toolSessions.js';
59
+ /** The scopes a code session can be held under. `'shutdown'` is not one: it is
60
+ * when everything goes, not a thing to key a session on. */
61
+ export type CodeRunnerToolScope = Extract<TeardownScope, 'call' | 'run' | 'session'>;
62
+ export interface CodeRunnerToolOptions {
63
+ /** The backend. `localCodeRunner()` for a dev loop, `agentCoreCodeRunner(...)`
64
+ * for a real sandbox — the tool is identical across the swap. */
65
+ readonly runner: CodeRunner;
66
+ /** Tool name the model sees. Default `'run_code'`. */
67
+ readonly name?: string;
68
+ /** Description the model sees. A sensible one is composed from `scope` +
69
+ * `language` when you do not pass one. */
70
+ readonly description?: string;
71
+ /**
72
+ * How long one session lives. Default `'run'` — a turn's worth of work shares
73
+ * one interpreter, and nothing outlives the turn.
74
+ *
75
+ * `'session'` keeps the interpreter across the turns of one hosted
76
+ * conversation (variables persist, files persist) and REQUIRES a
77
+ * session-bound run plus a composition root that calls
78
+ * `agent.closeToolSessions({ sessionId })`.
79
+ *
80
+ * `'call'` starts and stops per invocation — the safest and the slowest.
81
+ */
82
+ readonly scope?: CodeRunnerToolScope;
83
+ /** Default language for the code the model writes. Default `'python'`. */
84
+ readonly language?: string;
85
+ /** Per-stream ceiling for what reaches the model, in characters. Default 4000.
86
+ * Anything cut is STATED in the result, never dropped quietly. */
87
+ readonly maxOutputChars?: number;
88
+ /** Per-execution ceiling handed to the runner. */
89
+ readonly timeoutMs?: number;
90
+ /** Demand a human check-in before code runs — `'always'`, or a predicate over
91
+ * the code string. A pause here does NOT tear the session down. */
92
+ readonly checkIn?: CheckInDemand<{
93
+ code: string;
94
+ }>;
95
+ /** A credential this tool needs (declare-and-push). Resolved before execute.
96
+ * Do NOT cache it past the call: a session outliving a run outlives its token. */
97
+ readonly needs?: CredentialNeed;
98
+ }
99
+ /**
100
+ * The per-tool session map, riding the `Tool` under a REGISTRY symbol.
101
+ *
102
+ * `Symbol.for`, not a unique symbol: this package ships CJS and ESM, and a tool
103
+ * built through one entry point must be readable through the other. The same
104
+ * move `INNER_RUN_RECORDS` makes for `flowchartAsTool({ keepRecord })` — and
105
+ * deliberately a DIFFERENT symbol, so one tool can carry both (spreading a tool
106
+ * preserves symbol keys, which is why `{...tool, [SYM]: store}` composes).
107
+ *
108
+ * Invisible to the LLM, invisible to `Tool`'s shape, reachable by a test and by
109
+ * whatever inspector comes next.
110
+ */
111
+ export declare const TOOL_SESSIONS: unique symbol;
112
+ /** A `Tool` that holds live sessions, keyed by isolation key. */
113
+ export interface HoldsToolSessions {
114
+ readonly [TOOL_SESSIONS]: ReadonlyMap<string, CodeSession>;
115
+ }
116
+ /** Read the live-session map off a candidate, or `undefined` when it holds none. */
117
+ export declare function toolSessionsOf(candidate: unknown): ReadonlyMap<string, CodeSession> | undefined;
118
+ export declare function codeRunnerTool(options: CodeRunnerToolOptions): Tool<{
119
+ code: string;
120
+ }, string> & HoldsToolSessions;
121
+ //# sourceMappingURL=codeRunnerTool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codeRunnerTool.d.ts","sourceRoot":"","sources":["../../../src/core/codeRunnerTool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,KAAK,EAAc,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAc,KAAK,IAAI,EAA6B,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvE;6DAC6D;AAC7D,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC,CAAC;AAErF,MAAM,WAAW,qBAAqB;IACpC;sEACkE;IAClE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,sDAAsD;IACtD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;+CAC2C;IAC3C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,mBAAmB,CAAC;IACrC,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;uEACmE;IACnE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,kDAAkD;IAClD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;wEACoE;IACpE,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD;uFACmF;IACnF,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;CACjC;AAID;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,EAAE,OAAO,MAAoD,CAAC;AAExF,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CAC5D;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,SAAS,EAAE,OAAO,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,SAAS,CAI/F;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,qBAAqB,GAC7B,IAAI,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,CAAC,GAAG,iBAAiB,CA2FpD"}
@@ -0,0 +1,319 @@
1
+ /**
2
+ * toolSessions — the end-signal a tool can be handed, and the tier that fires it.
3
+ *
4
+ * Pattern: Registrar + Template Method for the firing matrix.
5
+ * Role: core primitive. `ToolExecutionContext.onTeardown` registers here;
6
+ * `Agent.run`'s terminals, `RunnerBase.closeToolSessions` and
7
+ * `RunnerBase.shutdown` fire it.
8
+ * Emits: nothing itself. `register()` ANSWERS what it did (started/reused) so
9
+ * the caller — still inside a stage — can emit with a real
10
+ * `runtimeStageId`, and teardown REPORTS (see {@link ToolSessionReport})
11
+ * so the runner can emit the two that fire after the last stage.
12
+ *
13
+ * ── The gap this closes ─────────────────────────────────────────────────────
14
+ * A session-based tool service (a managed code interpreter, a headless browser)
15
+ * is Start → Invoke ×N → Stop. Before 9.7.0 a `Tool` had nowhere to hold the
16
+ * middle of that: `ToolExecutionContext` carried no run or session identity, and
17
+ * nothing in the framework ever said "this is over". So a tool either paid
18
+ * start-up on every call, or held the session in a module-level map — which, in
19
+ * a standing agent serving many people from one process, hands ONE live sandbox
20
+ * to whoever calls next. That is not a leak of memory; it is a leak of a
21
+ * filesystem, an environment and half-run state, across users.
22
+ *
23
+ * ── Why the registration lives on the CONTEXT ───────────────────────────────
24
+ * Not `Tool.dispose()`: a `Tool` is a singleton, built once and shared by every
25
+ * run and every session, so "dispose the tool" cannot mean "dispose this
26
+ * caller's session".
27
+ * Not a lifecycle PORT the consumer wires: that makes the common case (one tool
28
+ * that happens to hold a session) a wiring exercise, and the tool that knows the
29
+ * key is the one that cannot reach the port.
30
+ * `ctx.onTeardown(cleanup, { scope, key })` is the only seam where the key and
31
+ * the resource are both in hand at the same instant.
32
+ *
33
+ * ── The seven laws ──────────────────────────────────────────────────────────
34
+ * 1. **At most once, ever** per registration — the `stopped`-flag mechanism
35
+ * `strategies/lifecycle.ts` uses for strategies, applied one layer down.
36
+ * 2. **Idempotent by `(tool, scope, key)`, first wins.** A second registration
37
+ * under the same key does not replace the first — the first is the one
38
+ * holding the live handle; replacing it would drop that handle on the
39
+ * floor. The repeat is a TOUCH: it refreshes liveness (that is how the
40
+ * idle sweep and the LRU learn a session is still in use) and answers
41
+ * `'reused'`.
42
+ * 3. **Reverse order of registration**, settled with `Promise.allSettled`.
43
+ * 4. **Bounded** by `timeoutMs` (default 5s). Teardown is on the SIGTERM path;
44
+ * an unbounded `stop()` turns a container stop into a wait for SIGKILL.
45
+ * 5. **Never throws into the run** — but **never silent** either. Every
46
+ * failure, and every timeout, is reported. "Swallowed AND silent" is what
47
+ * separates a passive recorder from a resource that did not get released.
48
+ * 6. **Tolerates "already gone."** The far side reaps idle sessions on its own
49
+ * schedule; a `Stop` on a session AWS already collected is a no-op, not an
50
+ * incident. It still reports, so the difference is visible.
51
+ * 7. **Nothing live is ever persisted.** A checkpoint carries what survives
52
+ * `structuredClone`; a session handle does not. A resumed run re-opens.
53
+ *
54
+ * Zero-cost when unused: no tool registers → the runner never builds a tier →
55
+ * the terminal path is one `undefined` check.
56
+ */
57
+ import type { ToolExecutionContext } from './tools.js';
58
+ /**
59
+ * How long a registered cleanup is allowed to live.
60
+ *
61
+ * - `'call'` — until `tool.execute` settles (resolve OR throw). Available
62
+ * at every door, including `mcpServe`, where a served call is
63
+ * the only unit there is.
64
+ * - `'run'` — until the run reaches a terminal that is NOT a pause.
65
+ * **A pause is not a terminal**: a check-in on a code
66
+ * interpreter is a person deciding, and tearing the sandbox
67
+ * down there destroys the exact state the resume needs.
68
+ * - `'session'` — until the composition root says the hosting session ended
69
+ * (`agent.closeToolSessions({ sessionId })`). Nobody but the
70
+ * composition root can know that: a request/reply deployment
71
+ * has no end-of-session signal, and inventing one would be a
72
+ * library guessing about somebody else's protocol.
73
+ * - `'shutdown'` — until `agent.shutdown()` (which `standingAgent`'s close
74
+ * calls). The backstop under all three.
75
+ */
76
+ export type TeardownScope = 'call' | 'run' | 'session' | 'shutdown';
77
+ /** Why a cleanup ran. Reported on `agentfootprint.tools.session_closed`. */
78
+ export type TeardownReason = 'call-end' | 'run-end' | 'session-end' | 'shutdown' | 'idle' | 'evicted';
79
+ /** What a tool says about the cleanup it is registering. */
80
+ export interface TeardownOptions {
81
+ /** Default `'run'`. Refused by name when the door cannot honour it — see
82
+ * {@link ToolExecutionContext.teardownScopes}. */
83
+ readonly scope?: TeardownScope;
84
+ /**
85
+ * Dedup key within `(tool, scope)`. Omitted → the tool gets one registration
86
+ * per scope, which is right for a tool that holds exactly one thing.
87
+ *
88
+ * Derive it with {@link toolSessionKey} rather than by hand: a key that is
89
+ * narrower than the identity it isolates is the cross-binding bug, and a key
90
+ * that is wider is a silent latency change.
91
+ */
92
+ readonly key?: string;
93
+ /** The adapter holding the resource — `CodeRunner.id`, say. Reported so a
94
+ * row names its backend instead of only its tool. */
95
+ readonly runnerId?: string;
96
+ /** One free-form fact about what was opened (the language, the browser
97
+ * profile). Reported as-is; never a place for user data. */
98
+ readonly label?: string;
99
+ }
100
+ /** The call a registration came from — what the firing matrix filters on. */
101
+ export interface ToolSessionOrigin {
102
+ readonly tool: string;
103
+ readonly toolCallId: string;
104
+ /** Absent when the door has no run (`mcpServe`). */
105
+ readonly runId?: string;
106
+ /** Absent unless the run is bound to a hosting conversation. */
107
+ readonly sessionId?: string;
108
+ }
109
+ /**
110
+ * What `register()` did — a new session, or a call joining one already held.
111
+ *
112
+ * Returned rather than reported, because the two halves of a session's life
113
+ * happen in different places and only one of them has a stage to be stamped
114
+ * with. A start and a reuse happen INSIDE `tool.execute`, where the caller
115
+ * still holds the scope and can emit with the real `runtimeStageId`; a close
116
+ * happens after the run's last stage committed, where nothing does. Reporting
117
+ * both through one channel would have meant stamping a live, mid-stage event
118
+ * with the teardown pseudo-stage — a small lie, and exactly the kind that makes
119
+ * a trace disagree with itself.
120
+ */
121
+ export type RegisterOutcome = 'started' | 'reused';
122
+ /**
123
+ * A teardown that happened. The runner turns it into
124
+ * `agentfootprint.tools.session_closed` / `_close_failed`.
125
+ */
126
+ export interface ToolSessionReport {
127
+ readonly kind: 'closed' | 'close-failed';
128
+ readonly tool: string;
129
+ readonly scope: TeardownScope;
130
+ /** {@link hashSessionKey} of the isolation key — never the key. */
131
+ readonly keyHash: string;
132
+ readonly runnerId?: string;
133
+ readonly label?: string;
134
+ /** Which firing site ran it. */
135
+ readonly reason: TeardownReason;
136
+ /** Wall-clock from registration to close. */
137
+ readonly durationMs: number;
138
+ /** `close-failed` only. */
139
+ readonly error?: string;
140
+ readonly errorClass?: string;
141
+ }
142
+ /**
143
+ * Derive the isolation key a tool should hold a session under.
144
+ *
145
+ * ONE implementation, exported, because the derivation is the security
146
+ * boundary. Returns `undefined` when the facts the scope needs are absent —
147
+ * which is a refusal to guess, not a failure: the caller decides whether to
148
+ * narrow the scope loudly or refuse the call.
149
+ *
150
+ * ```
151
+ * session → t=<tenant|_>/p=<principal|_>/s=<sessionId> requires sessionId
152
+ * run → t=<tenant|_>/p=<principal|_>/r=<runId> requires runId
153
+ * call → c=<toolCallId> always available
154
+ * ```
155
+ *
156
+ * **`sessionId` alone must never key a live session.** The hosting port says
157
+ * why in its own words: a `sessionId` "is not identity and must never be
158
+ * trusted as identity on its own: anyone who can reach the host can put any
159
+ * string here, including someone else's." A code interpreter keyed on
160
+ * `sessionId` alone hands a live sandbox — files, environment, half-run state —
161
+ * to anyone who guesses one. Tenant and principal are in the key whenever they
162
+ * exist; a deployment that has no principal is thereby STATING it is
163
+ * single-principal rather than quietly assuming it.
164
+ *
165
+ * `'shutdown'` is not a key scope: it is when everything goes, not a thing to
166
+ * hold one session under. Ask for it and you get `undefined`.
167
+ *
168
+ * @example
169
+ * const key = toolSessionKey(ctx, 'run');
170
+ * if (!key) throw new Error("run_code: scope 'run' needs a run …");
171
+ */
172
+ export declare function toolSessionKey(ctx: Pick<ToolExecutionContext, 'toolCallId' | 'runId' | 'sessionId' | 'identity'>, scope: TeardownScope): string | undefined;
173
+ /**
174
+ * A short, stable digest of an isolation key.
175
+ *
176
+ * The key carries tenant, principal and the hosting `sessionId`. Publishing it
177
+ * on the event wire would put a user identifier into every exporter's payload —
178
+ * so the wire carries this instead, which is enough to JOIN two rows and not
179
+ * enough to name whose they are. `meta.sessionId` already carries the session
180
+ * legitimately (9.4.0); the payload does not repeat it.
181
+ *
182
+ * SHA-256, first 12 hex chars, wherever `node:crypto` resolves. In a browser
183
+ * bundle, where it does not, this falls back to the package's non-cryptographic
184
+ * FNV-1a digest — stated here rather than implied, because a fallback nobody
185
+ * documented is how "hashed" comes to mean less than a reader assumed.
186
+ */
187
+ export declare function hashSessionKey(key: string): string;
188
+ /** Defaults, named so a test and a docstring cannot drift from the code. */
189
+ export declare const TOOL_TEARDOWN_TIMEOUT_MS = 5000;
190
+ /** A session untouched this long is swept on the tier's next interaction. */
191
+ export declare const TOOL_SESSION_IDLE_MS = 900000;
192
+ /** How many live registrations one tier holds before it evicts the coldest. */
193
+ export declare const TOOL_SESSION_MAX_LIVE = 64;
194
+ export interface ToolSessionTierOptions {
195
+ /** Per-cleanup ceiling. Default {@link TOOL_TEARDOWN_TIMEOUT_MS}. */
196
+ readonly timeoutMs?: number;
197
+ /** Idle ceiling for the lazy sweep. Default {@link TOOL_SESSION_IDLE_MS}. */
198
+ readonly idleMs?: number;
199
+ /** Live-registration ceiling before LRU eviction. Default
200
+ * {@link TOOL_SESSION_MAX_LIVE}. */
201
+ readonly maxLive?: number;
202
+ /** Where TEARDOWN reports go. The runner wires this to the typed event
203
+ * dispatcher. Starts and reuses are the caller's to announce — see
204
+ * {@link RegisterOutcome}. */
205
+ readonly report?: (report: ToolSessionReport) => void;
206
+ /** Clock seam — tests drive idle and duration without waiting. */
207
+ readonly now?: () => number;
208
+ }
209
+ /**
210
+ * The teardown tier for one runner.
211
+ *
212
+ * Holds nothing until a tool registers, and the runner builds one only when
213
+ * that happens — so an agent whose tools hold no sessions pays a single
214
+ * `undefined` check at each terminal and nothing else.
215
+ */
216
+ export declare class ToolSessionTier {
217
+ private readonly registrations;
218
+ private readonly timeoutMs;
219
+ private readonly idleMs;
220
+ private readonly maxLive;
221
+ private readonly report;
222
+ private readonly now;
223
+ private seq;
224
+ constructor(options?: ToolSessionTierOptions);
225
+ /** Live registrations. Diagnostics and tests. */
226
+ liveCount(): number;
227
+ /**
228
+ * Resolve once every teardown this tier started IN THE BACKGROUND has
229
+ * settled.
230
+ *
231
+ * Two firings have no caller to await them: the idle sweep and the LRU
232
+ * eviction, both of which are triggered by a SYNCHRONOUS `register()` inside
233
+ * somebody else's `tool.execute`. They cannot be awaited there without making
234
+ * a cleanup's latency the tool's latency, so they run detached — and this is
235
+ * how a shutdown path, or a test, joins them.
236
+ */
237
+ settled(): Promise<void>;
238
+ /** Fires nobody is awaiting — see {@link settled}. */
239
+ private readonly background;
240
+ /** Start a detached fire and keep it joinable. */
241
+ private detach;
242
+ /**
243
+ * Register a cleanup, or TOUCH the one already holding this key (law 2).
244
+ *
245
+ * Synchronous and total: it never throws, because it runs inside somebody
246
+ * else's `tool.execute`. Scope support is judged one layer up, where
247
+ * `teardownScopes` is known.
248
+ *
249
+ * @returns `'started'` for a new session, `'reused'` when this call joined
250
+ * one already held, with `calls` counting how many have now shared it. The
251
+ * CALLER announces it, because the caller is the one still inside a stage
252
+ * and able to stamp a real `runtimeStageId` — see {@link RegisterOutcome}.
253
+ */
254
+ register(origin: ToolSessionOrigin, cleanup: () => void | Promise<void>, options?: TeardownOptions): {
255
+ readonly outcome: RegisterOutcome;
256
+ readonly keyHash: string;
257
+ readonly calls: number;
258
+ };
259
+ /** Fire every `'call'` registration this tool call opened. */
260
+ fireCall(toolCallId: string): Promise<void>;
261
+ /**
262
+ * Fire `'run'`-scoped registrations at a run terminal.
263
+ *
264
+ * Called from `Agent.run`/`resume` at a terminal that is NOT a pause — and
265
+ * deliberately not from a `finally`, which also runs on the two pause shapes.
266
+ *
267
+ * **`runId` is optional, and the Agent omits it.** A `'run'` scope means
268
+ * "release this when the TURN that opened it ends", and a turn is not a
269
+ * runId: a pause and its resume are one turn across two runs (`resume()`
270
+ * builds a fresh executor with a fresh id). Filtering on the id would leave
271
+ * every session a paused turn had opened alive forever — the failure would
272
+ * look like nothing at all, because the run answered fine.
273
+ *
274
+ * Firing all of them is exactly right under the runner's own
275
+ * ONE-IN-FLIGHT-RUN-PER-AGENT invariant: at a terminal there is no other turn
276
+ * whose sessions these could be. An ABANDONED pause is the interesting case
277
+ * and it lands the right way round too — the next completed turn releases
278
+ * what the abandoned one left holding.
279
+ *
280
+ * Pass an id where a caller really does mean one specific run.
281
+ */
282
+ fireRun(runId?: string): Promise<void>;
283
+ /**
284
+ * Fire the `'session'` registrations for one hosting session — or, with no
285
+ * `sessionId`, every `'session'` registration there is.
286
+ *
287
+ * Answers how many it closed, so a composition root can log a number instead
288
+ * of hoping.
289
+ */
290
+ fireSession(sessionId?: string, reason?: TeardownReason): Promise<number>;
291
+ /** Fire EVERYTHING, whatever scope it asked for. The backstop. */
292
+ fireShutdown(): Promise<number>;
293
+ /**
294
+ * Sweep sessions nobody has touched for `idleMs`.
295
+ *
296
+ * LAZY, on the next tier interaction — never a timer. A library that installs
297
+ * an interval keeps the host process alive, which is the same reason
298
+ * `shutdownOn` refuses to grab signals unless asked.
299
+ */
300
+ sweepIdle(): void;
301
+ private evictOverflow;
302
+ /**
303
+ * The one firing implementation: select, claim (law 1), reverse (law 3),
304
+ * settle everything (law 5).
305
+ *
306
+ * Selection and claiming happen SYNCHRONOUSLY before the first `await`, so
307
+ * two overlapping fires — a shutdown racing an idle sweep — cannot both take
308
+ * the same registration.
309
+ */
310
+ private fire;
311
+ /** One cleanup, bounded, reported either way. Never rethrows. */
312
+ private run;
313
+ }
314
+ /** A teardown that outran its budget. Named so an alert can route on it. */
315
+ export declare class ToolTeardownTimeoutError extends Error {
316
+ readonly timeoutMs: number;
317
+ constructor(what: string, timeoutMs: number);
318
+ }
319
+ //# sourceMappingURL=toolSessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolSessions.d.ts","sourceRoot":"","sources":["../../../src/core/toolSessions.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,9 @@
8
8
  */
9
9
  import type { LLMToolSchema } from '../adapters/types.js';
10
10
  import type { Credential, CredentialNeed, CredentialProvider } from '../identity/types.js';
11
+ import type { MemoryIdentity } from '../memory/identity/types.js';
11
12
  import type { CheckInDemand } from './checkin.js';
13
+ import type { TeardownOptions, TeardownScope } from './toolSessions.js';
12
14
  /**
13
15
  * One executable tool the Agent can call.
14
16
  *
@@ -79,6 +81,64 @@ export interface ToolExecutionContext {
79
81
  /** The credential resolved for this tool's declared `needs` (declare-and-push).
80
82
  * Present only when the tool declared a need and it resolved successfully. */
81
83
  readonly credential?: Credential;
84
+ /**
85
+ * The run this call belongs to.
86
+ *
87
+ * **Absent when there is no run.** A call served over `mcpServe` is one call,
88
+ * not a turn in a conversation, and minting a synthetic run id there would
89
+ * fabricate a run that never existed. Branch on the absence.
90
+ */
91
+ readonly runId?: string;
92
+ /**
93
+ * The hosting conversation this run is bound to, when it is bound to one —
94
+ * `HostRequest.sessionId`, threaded through `agent.run({ sessionId })`.
95
+ *
96
+ * Never derived, never defaulted to `runId`, never the anonymous latch.
97
+ *
98
+ * **It is caller data, not identity.** Anyone who can reach the host can put
99
+ * any string here, including someone else's. Never key a live session on it
100
+ * alone — compose it with tenant and principal via {@link toolSessionKey}.
101
+ */
102
+ readonly sessionId?: string;
103
+ /**
104
+ * The identity the CALLER supplied — `run({ identity })`, the same tuple
105
+ * memory and the permission gate scope on.
106
+ *
107
+ * **Absent when the caller passed none.** Deliberately NOT the run's internal
108
+ * `runIdentity`, which is always populated (it defaults to
109
+ * `{ conversationId: '<runId>' }`): handing that to a tool would publish a
110
+ * synthesized conversation as if somebody had named one.
111
+ */
112
+ readonly identity?: MemoryIdentity;
113
+ /**
114
+ * Register cleanup for work THIS call started — a code-interpreter session, a
115
+ * browser context, a lease.
116
+ *
117
+ * The tool learns its isolation key at execute time and registers cleanup for
118
+ * exactly that key in the same breath; there is no other seam where both are
119
+ * in hand. Registering twice under one `(tool, scope, key)` is a no-op that
120
+ * keeps the FIRST cleanup (it holds the live handle) and refreshes liveness,
121
+ * so calling this on every execute is the intended shape for a reused
122
+ * session.
123
+ *
124
+ * Throws, naming the door, when `scope` is not in {@link teardownScopes} — a
125
+ * capability nobody implements is a promise the library cannot keep.
126
+ *
127
+ * @example a session that lives as long as the run
128
+ * const key = toolSessionKey(ctx, 'run');
129
+ * const session = await runner.start({ key });
130
+ * ctx.onTeardown?.(() => session.stop(), { scope: 'run', key });
131
+ */
132
+ onTeardown?(cleanup: () => void | Promise<void>, options?: TeardownOptions): void;
133
+ /**
134
+ * Which teardown scopes this door can actually honour — `[]` means none ever
135
+ * fires here.
136
+ *
137
+ * A FACT to branch on, exactly like `hasCredentials`, rather than an
138
+ * `undefined` to optional-chain past: a tool that wants a run-scoped session
139
+ * needs to know it is talking to a door that has no runs BEFORE it opens one.
140
+ */
141
+ readonly teardownScopes?: readonly TeardownScope[];
82
142
  }
83
143
  /**
84
144
  * Internal: registry entry keyed by tool name.
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/core/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,WAAW,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO;IACtE,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B;;sCAEkC;IAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAChC;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;IACjC;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAC7E;AAED,gDAAgD;AAChD,MAAM,WAAW,oBAAoB;IACnC,gFAAgF;IAChF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,kDAAkD;IAClD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;IACzC;2EACuE;IACvE,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;mFAC+E;IAC/E,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;CAClC;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB,CAAC,KAAK,EAAE,OAAO;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACzD;uEACmE;IACnE,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAChC;8DAC0D;IAC1D,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IACxC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAC7E;AA+BD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM,CAkBzE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAQzD;AAED,wBAAgB,UAAU,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,EAC3E,OAAO,EAAE,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,GACzC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CActB"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/core/tools.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,11 @@
11
11
  * plus the MCP client/server bridge.
12
12
  * • Thinking handlers — per-vendor parsing of extended-thinking blocks,
13
13
  * which is a provider concern wearing another hat.
14
+ * • Code runners — `localCodeRunner` (process isolation, on this
15
+ * machine, and it says so) and `agentCoreCodeRunner`
16
+ * (a real managed sandbox). Both are backends behind
17
+ * the `CodeRunner` port; `codeRunnerTool` on the main
18
+ * barrel is the tool that holds one.
14
19
  *
15
20
  * Each vendor SDK is lazy-required, so importing this door loads no vendor
16
21
  * code — only calling a factory does.
@@ -24,4 +29,6 @@ export * from '../llm-providers.js';
24
29
  export * from '../embedders/index.js';
25
30
  export * from '../tool-providers/index.js';
26
31
  export * from '../thinking/index.js';
32
+ export { localCodeRunner, type LocalCodeRunnerOptions } from '../adapters/code/local.js';
33
+ export { agentCoreCodeRunner, type AgentCoreCodeRunnerOptions, type AgentCoreCodeClientLike, type AgentCoreInvokeAnswer, type BedrockAgentCoreCodeSdkModule, } from '../adapters/code/agentcore.js';
27
34
  //# sourceMappingURL=providers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../../src/doors/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../../src/doors/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AAKrC,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACzF,OAAO,EACL,mBAAmB,EACnB,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,GACnC,MAAM,+BAA+B,CAAC"}
@@ -624,6 +624,55 @@ export interface ToolsShadowedPayload {
624
624
  /** That source's id — the skill id, for the provider↔skill pair. */
625
625
  readonly dispatchToId?: string;
626
626
  }
627
+ /** Shared shape of the four `tools.session_*` payloads. */
628
+ interface ToolSessionPayloadBase {
629
+ /** The tool that registered the cleanup. */
630
+ readonly tool: string;
631
+ /** Which scope it asked for — how long it expected to live. */
632
+ readonly scope: 'call' | 'run' | 'session' | 'shutdown';
633
+ /** Digest of the isolation key. SHA-256 (12 hex chars) where `node:crypto`
634
+ * resolves, FNV-1a in a browser bundle. NEVER the key. */
635
+ readonly keyHash: string;
636
+ /** The adapter holding the resource — `CodeRunner.id`, say. */
637
+ readonly runnerId?: string;
638
+ /** One fact the tool chose to state about what was opened (the language, the
639
+ * browser profile). Never user data. */
640
+ readonly label?: string;
641
+ }
642
+ /** A tool opened something and registered its cleanup. */
643
+ export type ToolsSessionStartedPayload = ToolSessionPayloadBase;
644
+ /**
645
+ * A later call reused the session already held under this key.
646
+ *
647
+ * This is the payoff being measured: `calls` is how many dispatches have shared
648
+ * one start-up. It is also the liveness signal the idle sweep and the LRU bound
649
+ * read, which is why a tool re-registers on every execute rather than only once.
650
+ */
651
+ export interface ToolsSessionReusedPayload extends ToolSessionPayloadBase {
652
+ /** How many calls have now shared this session, including this one. */
653
+ readonly calls: number;
654
+ }
655
+ /** The cleanup ran. `reason` says which firing site ran it. */
656
+ export interface ToolsSessionClosedPayload extends ToolSessionPayloadBase {
657
+ readonly reason: 'call-end' | 'run-end' | 'session-end' | 'shutdown' | 'idle' | 'evicted';
658
+ /** Wall-clock from registration to close. */
659
+ readonly durationMs: number;
660
+ }
661
+ /**
662
+ * The cleanup threw, or outran `toolTeardownTimeoutMs`.
663
+ *
664
+ * Teardown never throws into the run — but it is never SILENT either, and this
665
+ * event is the difference. A vendor `Stop` that fails leaves a live sandbox
666
+ * somebody is still paying for; the run has no way to say so, so this does.
667
+ * `errorClass` mirrors `credential.failed`'s 9.4.0 addition: routable without
668
+ * parsing prose (`'ToolTeardownTimeoutError'` for the budget case).
669
+ */
670
+ export interface ToolsSessionCloseFailedPayload extends ToolSessionPayloadBase {
671
+ readonly reason: 'call-end' | 'run-end' | 'session-end' | 'shutdown' | 'idle' | 'evicted';
672
+ readonly durationMs: number;
673
+ readonly error: string;
674
+ readonly errorClass?: string;
675
+ }
627
676
  /**
628
677
  * Emitted when LLM-produced tool args fail validation against the tool's
629
678
  * declared `inputSchema` (backlog #9). Fires for BOTH modes that validate:
@@ -1117,4 +1166,5 @@ export interface AgentThinkingParseFailedPayload {
1117
1166
  readonly errorName: string;
1118
1167
  readonly iteration: number;
1119
1168
  }
1169
+ export {};
1120
1170
  //# sourceMappingURL=payloads.d.ts.map