@rarebit-one/harness-kernel 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +286 -0
  3. package/dist/agent.d.ts +71 -0
  4. package/dist/agent.d.ts.map +1 -0
  5. package/dist/agent.js +258 -0
  6. package/dist/agent.js.map +1 -0
  7. package/dist/connectors/mcpClient.d.ts +22 -0
  8. package/dist/connectors/mcpClient.d.ts.map +1 -0
  9. package/dist/connectors/mcpClient.js +63 -0
  10. package/dist/connectors/mcpClient.js.map +1 -0
  11. package/dist/context/types.d.ts +68 -0
  12. package/dist/context/types.d.ts.map +1 -0
  13. package/dist/context/types.js +43 -0
  14. package/dist/context/types.js.map +1 -0
  15. package/dist/engines/capability.d.ts +67 -0
  16. package/dist/engines/capability.d.ts.map +1 -0
  17. package/dist/engines/capability.js +73 -0
  18. package/dist/engines/capability.js.map +1 -0
  19. package/dist/engines/capabilityEmissions.d.ts +27 -0
  20. package/dist/engines/capabilityEmissions.d.ts.map +1 -0
  21. package/dist/engines/capabilityEmissions.js +37 -0
  22. package/dist/engines/capabilityEmissions.js.map +1 -0
  23. package/dist/engines/capabilityMcp.d.ts +23 -0
  24. package/dist/engines/capabilityMcp.d.ts.map +1 -0
  25. package/dist/engines/capabilityMcp.js +36 -0
  26. package/dist/engines/capabilityMcp.js.map +1 -0
  27. package/dist/engines/capabilityStdio.d.ts +46 -0
  28. package/dist/engines/capabilityStdio.d.ts.map +1 -0
  29. package/dist/engines/capabilityStdio.js +39 -0
  30. package/dist/engines/capabilityStdio.js.map +1 -0
  31. package/dist/engines/claudeCode.d.ts +73 -0
  32. package/dist/engines/claudeCode.d.ts.map +1 -0
  33. package/dist/engines/claudeCode.js +100 -0
  34. package/dist/engines/claudeCode.js.map +1 -0
  35. package/dist/engines/claudeCodeDriver.d.ts +14 -0
  36. package/dist/engines/claudeCodeDriver.d.ts.map +1 -0
  37. package/dist/engines/claudeCodeDriver.js +90 -0
  38. package/dist/engines/claudeCodeDriver.js.map +1 -0
  39. package/dist/engines/codex.d.ts +72 -0
  40. package/dist/engines/codex.d.ts.map +1 -0
  41. package/dist/engines/codex.js +157 -0
  42. package/dist/engines/codex.js.map +1 -0
  43. package/dist/engines/codexDriver.d.ts +43 -0
  44. package/dist/engines/codexDriver.d.ts.map +1 -0
  45. package/dist/engines/codexDriver.js +110 -0
  46. package/dist/engines/codexDriver.js.map +1 -0
  47. package/dist/engines/connectorMcp.d.ts +60 -0
  48. package/dist/engines/connectorMcp.d.ts.map +1 -0
  49. package/dist/engines/connectorMcp.js +137 -0
  50. package/dist/engines/connectorMcp.js.map +1 -0
  51. package/dist/engines/index.d.ts +33 -0
  52. package/dist/engines/index.d.ts.map +1 -0
  53. package/dist/engines/index.js +29 -0
  54. package/dist/engines/index.js.map +1 -0
  55. package/dist/engines/native.d.ts +55 -0
  56. package/dist/engines/native.d.ts.map +1 -0
  57. package/dist/engines/native.js +117 -0
  58. package/dist/engines/native.js.map +1 -0
  59. package/dist/engines/types.d.ts +107 -0
  60. package/dist/engines/types.d.ts.map +1 -0
  61. package/dist/engines/types.js +2 -0
  62. package/dist/engines/types.js.map +1 -0
  63. package/dist/events.d.ts +211 -0
  64. package/dist/events.d.ts.map +1 -0
  65. package/dist/events.js +69 -0
  66. package/dist/events.js.map +1 -0
  67. package/dist/index.d.ts +63 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +82 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/loop.d.ts +132 -0
  72. package/dist/loop.d.ts.map +1 -0
  73. package/dist/loop.js +77 -0
  74. package/dist/loop.js.map +1 -0
  75. package/dist/models/chat.d.ts +65 -0
  76. package/dist/models/chat.d.ts.map +1 -0
  77. package/dist/models/chat.js +66 -0
  78. package/dist/models/chat.js.map +1 -0
  79. package/dist/models/middleware.d.ts +63 -0
  80. package/dist/models/middleware.d.ts.map +1 -0
  81. package/dist/models/middleware.js +139 -0
  82. package/dist/models/middleware.js.map +1 -0
  83. package/dist/models/registry.d.ts +78 -0
  84. package/dist/models/registry.d.ts.map +1 -0
  85. package/dist/models/registry.js +0 -0
  86. package/dist/models/registry.js.map +1 -0
  87. package/dist/models/types.d.ts +149 -0
  88. package/dist/models/types.d.ts.map +1 -0
  89. package/dist/models/types.js +64 -0
  90. package/dist/models/types.js.map +1 -0
  91. package/dist/primitives/codeExec.d.ts +25 -0
  92. package/dist/primitives/codeExec.d.ts.map +1 -0
  93. package/dist/primitives/codeExec.js +69 -0
  94. package/dist/primitives/codeExec.js.map +1 -0
  95. package/dist/primitives/download.d.ts +19 -0
  96. package/dist/primitives/download.d.ts.map +1 -0
  97. package/dist/primitives/download.js +113 -0
  98. package/dist/primitives/download.js.map +1 -0
  99. package/dist/primitives/fs.d.ts +5 -0
  100. package/dist/primitives/fs.d.ts.map +1 -0
  101. package/dist/primitives/fs.js +59 -0
  102. package/dist/primitives/fs.js.map +1 -0
  103. package/dist/primitives/http.d.ts +100 -0
  104. package/dist/primitives/http.d.ts.map +1 -0
  105. package/dist/primitives/http.js +257 -0
  106. package/dist/primitives/http.js.map +1 -0
  107. package/dist/providers/anthropic.d.ts +15 -0
  108. package/dist/providers/anthropic.d.ts.map +1 -0
  109. package/dist/providers/anthropic.js +90 -0
  110. package/dist/providers/anthropic.js.map +1 -0
  111. package/dist/providers/clientOptions.d.ts +14 -0
  112. package/dist/providers/clientOptions.d.ts.map +1 -0
  113. package/dist/providers/clientOptions.js +26 -0
  114. package/dist/providers/clientOptions.js.map +1 -0
  115. package/dist/providers/index.d.ts +24 -0
  116. package/dist/providers/index.d.ts.map +1 -0
  117. package/dist/providers/index.js +51 -0
  118. package/dist/providers/index.js.map +1 -0
  119. package/dist/providers/mock.d.ts +25 -0
  120. package/dist/providers/mock.d.ts.map +1 -0
  121. package/dist/providers/mock.js +85 -0
  122. package/dist/providers/mock.js.map +1 -0
  123. package/dist/providers/openai.d.ts +32 -0
  124. package/dist/providers/openai.d.ts.map +1 -0
  125. package/dist/providers/openai.js +118 -0
  126. package/dist/providers/openai.js.map +1 -0
  127. package/dist/providers/openrouter.d.ts +29 -0
  128. package/dist/providers/openrouter.d.ts.map +1 -0
  129. package/dist/providers/openrouter.js +35 -0
  130. package/dist/providers/openrouter.js.map +1 -0
  131. package/dist/providers/types.d.ts +60 -0
  132. package/dist/providers/types.d.ts.map +1 -0
  133. package/dist/providers/types.js +2 -0
  134. package/dist/providers/types.js.map +1 -0
  135. package/dist/routing/staticResolver.d.ts +41 -0
  136. package/dist/routing/staticResolver.d.ts.map +1 -0
  137. package/dist/routing/staticResolver.js +67 -0
  138. package/dist/routing/staticResolver.js.map +1 -0
  139. package/dist/routing/types.d.ts +72 -0
  140. package/dist/routing/types.d.ts.map +1 -0
  141. package/dist/routing/types.js +11 -0
  142. package/dist/routing/types.js.map +1 -0
  143. package/dist/secrets.d.ts +8 -0
  144. package/dist/secrets.d.ts.map +1 -0
  145. package/dist/secrets.js +14 -0
  146. package/dist/secrets.js.map +1 -0
  147. package/dist/tools/metadata.d.ts +93 -0
  148. package/dist/tools/metadata.d.ts.map +1 -0
  149. package/dist/tools/metadata.js +49 -0
  150. package/dist/tools/metadata.js.map +1 -0
  151. package/dist/tools/modelTool.d.ts +35 -0
  152. package/dist/tools/modelTool.d.ts.map +1 -0
  153. package/dist/tools/modelTool.js +37 -0
  154. package/dist/tools/modelTool.js.map +1 -0
  155. package/dist/tools/registry.d.ts +65 -0
  156. package/dist/tools/registry.d.ts.map +1 -0
  157. package/dist/tools/registry.js +166 -0
  158. package/dist/tools/registry.js.map +1 -0
  159. package/dist/types.d.ts +71 -0
  160. package/dist/types.d.ts.map +1 -0
  161. package/dist/types.js +10 -0
  162. package/dist/types.js.map +1 -0
  163. package/package.json +72 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rarebit One
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,286 @@
1
+ # harness-kernel
2
+
3
+ A **provider-neutral AI-harness kernel** in TypeScript: LLM adapters, a tool-use
4
+ loop, MCP connectors, sandbox primitives, and a pluggable agent-engine seam.
5
+
6
+ It is deliberately a *kernel*, not a framework. It holds the commodity mechanics
7
+ every AI harness needs and nothing else — applications are the userland. The
8
+ kernel never knows an application exists; dependencies point **one way only**
9
+ (`app layer → kernel`, never the reverse).
10
+
11
+ ```
12
+ harness-kernel
13
+ ▲ ▲ ▲
14
+ app harness app harness app harness (one-way deps)
15
+ ```
16
+
17
+ ## Status
18
+
19
+ **v0 — private, unpublished.** The package is built OSS-ready (MIT licensed, npm
20
+ OIDC trusted-publishing workflow wired) but the repo is private and nothing has
21
+ been published to npm. `publish.yml` fires on a GitHub Release for **any** tag,
22
+ so it ships **inert**: the one mutating step is skipped unless the repo variable
23
+ `PUBLISH_LIVE` is `"true"`, and an unarmed run reports what it would have
24
+ published. "No Release exists yet" was never a safety property — it was an
25
+ absence.
26
+
27
+ v0 is a mechanical extraction of a proven, already-provider-neutral agent core
28
+ into a standalone package — the mechanics are battle-tested, the packaging is
29
+ new. Seam-widening (a general `ModelInvocation` seam, streaming, multimodal
30
+ input, middleware, context providers) is planned as an additive v0.2.
31
+
32
+ ## Install
33
+
34
+ ```bash
35
+ npm install @rarebit-one/harness-kernel # once published
36
+ ```
37
+
38
+ ESM-only, Node >= 22.
39
+
40
+ ## What's in it
41
+
42
+ | Area | Exports |
43
+ |------|---------|
44
+ | **Model seam** | `ModelInvocation` — one arrow for every model kind, with declared capabilities, a uniform result envelope and `probe()` |
45
+ | **Providers** | `Provider` interface + `selectProvider()` over Anthropic, OpenAI, OpenRouter, and an offline `mock`; `chatModel()` puts any of them on the seam |
46
+ | **Agent loop** | `runAgent()` — a provider-neutral tool-use loop with step and wall-clock budgets |
47
+ | **Loop** | `Loop` + `nativeLoop` — the control loop as a seam; the kernel ships one and it is the loop `runAgent` has always run |
48
+ | **Run events** | `RunEvent` — an ordered, structured account of a run (turns, tool calls, budgets, outcome), emitted to an optional sink |
49
+ | **Tools** | `Tool`, `primitiveTools()` (`run_code`, `read_file`, `list_files`, `http_fetch`), `connectorTools()`, `modelAsTool()`, metadata + projections |
50
+ | **Connectors** | `connectMcp()` — MCP clients over stdio / streamable HTTP / SSE |
51
+ | **Engines** | The `AgentEngine` seam + `native`, `claude-code`, and `codex` harnesses, plus the capability *mechanism* (scope guards, a generic `write_file`, and MCP/stdio transports) — the capability *set* is yours to inject |
52
+ | **Routing** | `RouteResolver` + `StaticRouteResolver` — capability → model, prompt, tools |
53
+ | **Context** | `ContextProvider` chain, assembled in parallel and rendered into the prompt |
54
+ | **Secrets** | `secretsToEnv()` — resolved secret values into an exec environment |
55
+
56
+ ## Extension points
57
+
58
+ The kernel is meant to be extended from outside, never patched from inside.
59
+ There are seven seams, and each ships with the in-process default that makes it
60
+ usable on its own — no database, no service, no infrastructure.
61
+
62
+ **1. Model kinds.** A chat LLM is one kind among several. Register any other and
63
+ resolve it back through the same call:
64
+
65
+ ```ts
66
+ import { ModelRegistry, chatModel, selectProvider } from "@rarebit-one/harness-kernel"
67
+
68
+ const registry = new ModelRegistry()
69
+ .registerInstance(chatModel(selectProvider("anthropic")))
70
+ .register({ kind: "vision.detect", id: "yolo" }, () => myDetector)
71
+
72
+ const detector = registry.resolve<DetectRequest, DetectionResult>({
73
+ kind: "vision.detect",
74
+ id: "yolo",
75
+ })
76
+ ```
77
+
78
+ `Req` and `Res` stay typed per kind — the seam unifies the arrow and the
79
+ envelope (`ModelResult`, `InvokeContext`, `ModelCaps`, `probe`), never the
80
+ payload. An unresolved ref throws rather than returning `undefined`.
81
+
82
+ **2. Route resolution.** One layer up: which model, prompt and tools serve a
83
+ named capability. `StaticRouteResolver` is capabilities-as-code; a dynamic
84
+ resolver is your adapter behind the same interface.
85
+
86
+ ```ts
87
+ const resolver = new StaticRouteResolver([
88
+ { name: "summarise", model: { kind: "chat", id: "anthropic" }, prompt: "Summarise." },
89
+ ])
90
+ const route = await resolver.resolve("summarise")
91
+ const model = registry.resolve(route.model) // the resolver picks, the registry binds
92
+ ```
93
+
94
+ **3. Middleware.** Payload-blind, so one implementation covers every kind:
95
+
96
+ ```ts
97
+ const model = withMiddleware(anyModel, [correlationMiddleware(), loggingMiddleware()])
98
+ ```
99
+
100
+ **4. Engines.** The `AgentEngine` seam — `native`, `claude-code`, `codex`, or
101
+ your own. File mutations stay out of band.
102
+
103
+ **5. Context providers.** Replace a single pre-baked context string with a
104
+ chain, so a live source can inject fragments:
105
+
106
+ ```ts
107
+ new NativeEngine({ contextProviders: [myLiveFeed] })
108
+ ```
109
+
110
+ Providers run in parallel; one that fails is logged and skipped rather than
111
+ failing the run.
112
+
113
+ **6. Tools.** Rich metadata (capability scoping, invocation-mode gating,
114
+ confirmation, reversibility, retention, client visibility) with lossy
115
+ projections down to what a provider actually needs — and `modelAsTool()`, which
116
+ surfaces any model invocation as a callable tool. That last one is the cleanest
117
+ form of extension: a perception model becomes something the chat loop can call
118
+ without the loop, the engines, or any kernel code learning perception exists.
119
+
120
+ **7. The loop.** The control flow itself. Everything above answers "which
121
+ implementation?" for something the loop *uses*; this is the loop.
122
+
123
+ ```ts
124
+ const confirmFirst: Loop = {
125
+ name: "confirm-first",
126
+ run: async (req, ctx) => {
127
+ const gated = req.tools.filter((t) => t.meta?.requiresConfirmation)
128
+ if (gated.length > 0) return { text: "awaiting confirmation", steps: 0, outcome: "completed" }
129
+ return nativeLoop.run(req, ctx)
130
+ },
131
+ }
132
+ new NativeEngine({ loop: confirmFirst })
133
+ ```
134
+
135
+ A loop is handed **resolved** materials — a bound model, built prompts, a
136
+ projected tool surface, budgets as numbers rather than optionals (via
137
+ `resolveLoopLimits`, the one place defaults live). It decides control flow and
138
+ nothing else, which is what keeps a second implementation small enough to be
139
+ worth writing. `runAgent` and `nativeLoop` are the same code path, so they
140
+ cannot drift.
141
+
142
+ Capabilities are **checked, not assumed**: asking a model to stream when it
143
+ declared `streaming: false` throws a `CapabilityError` instead of quietly
144
+ returning a buffered response.
145
+
146
+ ### Run events
147
+
148
+ `log` is prose for a human. The event stream is the same run, machine-readable:
149
+
150
+ ```ts
151
+ import { runAgent, recordRunEvents } from "@rarebit-one/harness-kernel"
152
+
153
+ const { sink, events } = recordRunEvents()
154
+ await runAgent({ provider, system, userPrompt, tools, emit: sink })
155
+ // events: run.started -> model.turn -> tool.called -> tool.succeeded -> ... -> run.finished
156
+ ```
157
+
158
+ The **bookends** — `run.started` and `run.finished` — are emitted by
159
+ `runWithEvents`, which wraps whichever `Loop` runs. A loop emits only what
160
+ happens inside it, so a custom loop that emits nothing still produces a run that
161
+ is visibly a run. A guarantee that depends on every future implementor
162
+ remembering it is not a guarantee.
163
+
164
+ On the failure path `steps` and `text` are **omitted**, not zeroed: the loop
165
+ threw and never returned a result, so any number there would be invented. The
166
+ `model.turn` events already in the stream are the authoritative record of how
167
+ far it got.
168
+
169
+ Engines take the same sink through `EngineContext`:
170
+
171
+ ```ts
172
+ await engine.run(spec, { log, emit: sink })
173
+ ```
174
+
175
+ Both are **optional** — omit them and the loop behaves exactly as it did before
176
+ events existed. Every event carries a monotonic `seq` from a single per-run
177
+ counter, so a gap is detectable: a dropped event must never look like an event
178
+ that never happened. A sink that throws is reported through `log` and skipped,
179
+ never allowed to fail the run.
180
+
181
+ A sink is an observer and can never be a participant: `tool.called.input` is a
182
+ detached copy, so a sink that redacts in place cannot change what the tool
183
+ receives. The flip side is a disclosure surface worth knowing about — that field
184
+ carries the **raw tool arguments**, so any secret or PII a model passed as an
185
+ argument now reaches every attached sink. Nothing outside the model conversation
186
+ captured these before; a sink that persists or forwards events should redact.
187
+
188
+ `run.finished` is always the last event, including when the loop throws — the
189
+ error propagates unchanged, but `outcome: "failed"` closes the stream first, so
190
+ a crashed run is never mistaken for one still in flight.
191
+
192
+ **The kernel emits this stream; it does not store it.** Resume, fork, search and
193
+ replay all want persistence and a schema — infrastructure a kernel must not
194
+ ship. `recordRunEvents()` is an in-memory recorder for tests and the reference
195
+ shape for a real store, not a session store itself.
196
+
197
+ `tool.succeeded` carries the tool's own `reversible` / `undoToolName` /
198
+ `undoWindowSeconds` from `ToolMetadata`, copied at call time. That is the
199
+ missing half of a bargain the metadata already made: it could declare a tool
200
+ undoable but nothing recorded that the tool *ran*, so an application had nothing
201
+ concrete to undo. Deciding whether to undo remains policy, and stays in the
202
+ application.
203
+
204
+ ## Usage
205
+
206
+ ```ts
207
+ import { selectProvider, runAgent, primitiveTools } from "@rarebit-one/harness-kernel"
208
+
209
+ const provider = selectProvider("anthropic", { model: "claude-sonnet-5" })
210
+
211
+ const text = await runAgent({
212
+ provider,
213
+ system: "You are a helpful autonomous agent.",
214
+ userPrompt: "Summarise the repo's README.",
215
+ tools: primitiveTools("/path/to/sandbox", process.env),
216
+ })
217
+ ```
218
+
219
+ With no provider API key configured, `selectProvider` falls back to the offline
220
+ `mock` provider — so the whole loop runs end to end with no keys and no network.
221
+ That is deliberate: the test suite depends on it, and so can yours.
222
+
223
+ ### Engines
224
+
225
+ An engine is a pluggable agent harness. `native` is the in-process tool-use loop
226
+ above; `claude-code` and `codex` shell out to those CLIs/SDKs. All three share
227
+ one capability surface (`open_issue`, `write_file`, `promote_knowledge`) scoped
228
+ to a single run's workspace, and all three mutate files **out of band** — the
229
+ caller diffs the working tree afterwards, so the engine contract never has to
230
+ model "an edit" uniformly.
231
+
232
+ ```ts
233
+ import { selectEngine } from "@rarebit-one/harness-kernel"
234
+
235
+ const engine = selectEngine("native", { domainTools }) // "claude-code" | "codex" | unknown → native
236
+ const support = engine.supports(spec)
237
+ if (!support.ok) throw new Error(support.reason) // fail loud, never silently degrade
238
+ const { text } = await engine.run(spec, { log: console.error })
239
+ ```
240
+
241
+ ### The kernel defines no domain tools
242
+
243
+ `primitiveTools()` is strictly generic — sandboxed shell/file/HTTP access. Tools
244
+ that collect **application** output don't exist here at all: what a run may emit
245
+ is your vocabulary, so you define it and inject it.
246
+
247
+ ```ts
248
+ import { primitiveTools, writeFileCapability, denyCrossWorkspace } from "@rarebit-one/harness-kernel"
249
+
250
+ // Your sinks, your tools — the kernel never sees them.
251
+ const knowledge: MyNote[] = []
252
+ const domainTools = (allowed?: string[]) => myEmissionTools({ knowledge }, allowed)
253
+
254
+ const engine = selectEngine("native", { domainTools })
255
+ ```
256
+
257
+ The same holds for the workspace-scoped **capabilities** the external engines
258
+ mount over MCP. The kernel ships exactly one — `writeFileCapability`, a sandbox
259
+ write with no product semantics — plus the guards (`denyCrossWorkspace`,
260
+ `resolveWithin`) so your own capabilities inherit identical security properties:
261
+
262
+ ```ts
263
+ selectEngine("claude-code", {
264
+ capabilityTools: (ctx) => [writeFileCapability(ctx), ...myCapabilities(ctx)],
265
+ })
266
+
267
+ // codex runs out-of-process, so it needs a script it can spawn — a child
268
+ // process can't be handed a closure. Omitting it throws rather than serving an
269
+ // empty surface.
270
+ selectEngine("codex", { capabilityServerScript: "/app/dist/my-capability-server.js" })
271
+ ```
272
+
273
+ ## Development
274
+
275
+ ```bash
276
+ npm ci
277
+ npm run typecheck # tsc --noEmit
278
+ npm run lint # eslint . (lint:fix to autofix)
279
+ npm run format # prettier --write . (format:check to verify)
280
+ npm test # vitest run
281
+ npm run build # tsc -p tsconfig.build.json → dist/ + .d.ts
282
+ ```
283
+
284
+ ## License
285
+
286
+ MIT © Rarebit One
@@ -0,0 +1,71 @@
1
+ import { type RunEventSink } from "./events.js";
2
+ import { type LoopContext, type LoopRequest, type LoopResult } from "./loop.js";
3
+ import { type ChatModel } from "./models/chat.js";
4
+ import type { Provider } from "./providers/types.js";
5
+ import { type Tool } from "./tools/registry.js";
6
+ export interface RunAgentOptions {
7
+ /**
8
+ * The chat model driving the loop. A bare {@link Provider} is accepted and
9
+ * adapted onto the model seam internally, so existing callers are unaffected;
10
+ * pass a {@link ChatModel} to drive the loop through a registry-resolved,
11
+ * middleware-wrapped invocation instead.
12
+ */
13
+ provider: Provider | ChatModel;
14
+ system: string;
15
+ userPrompt: string;
16
+ tools: Tool[];
17
+ maxSteps?: number;
18
+ /**
19
+ * Wall-clock budget for the whole loop in ms. Checked between steps; when
20
+ * exceeded the loop stops cleanly and returns what's accumulated (with a note)
21
+ * rather than throwing. Defaults to `RUNNER_RUN_TIMEOUT_MS` if set, else 10min.
22
+ */
23
+ maxDurationMs?: number;
24
+ log?: (line: string) => void;
25
+ /**
26
+ * Structured event sink. Absent (the default) means the loop behaves exactly
27
+ * as it did before events existed — `log` is unaffected either way, and the
28
+ * return value is unchanged. See `events.ts` for why the kernel emits this
29
+ * stream but never stores it.
30
+ */
31
+ emit?: RunEventSink;
32
+ }
33
+ /**
34
+ * Resolve a partial budget to the concrete numbers a {@link LoopRequest} needs.
35
+ *
36
+ * One place, deliberately. A {@link Loop} is handed numbers rather than
37
+ * optionals, so if each caller resolved its own defaults a second loop
38
+ * implementation could silently run to a different ceiling than the one the
39
+ * kernel ships. `runAgent` and `NativeEngine` both come here.
40
+ */
41
+ export declare function resolveLoopLimits(limits?: {
42
+ maxSteps?: number | undefined;
43
+ maxDurationMs?: number | undefined;
44
+ }): {
45
+ maxSteps: number;
46
+ maxDurationMs: number;
47
+ };
48
+ /**
49
+ * Cap on tool output fed back into the conversation, independent of the sandbox
50
+ * buffer caps — an 8 MB stdout would otherwise blow the context window.
51
+ * Env-overridable (`RUNNER_MAX_TOOL_RESULT_BYTES`, default 64 KiB) and resolved
52
+ * per call so a changed env takes effect without a reload.
53
+ */
54
+ export declare function maxToolResultBytes(): number;
55
+ /**
56
+ * Drives a provider-agnostic tool-use loop: the model converses, the runner
57
+ * executes any requested tools in the sandbox, feeds the results back, and
58
+ * repeats until the model stops calling tools (or the step budget is hit). The
59
+ * model orchestrates; deterministic work happens in the tools.
60
+ */
61
+ export declare function runAgent(options: RunAgentOptions): Promise<string>;
62
+ /**
63
+ * The native tool-use loop, as a {@link Loop}.
64
+ *
65
+ * Exported for `loop.ts` to wrap; applications reach it through `nativeLoop`
66
+ * rather than calling this directly. It is the whole of the kernel's control
67
+ * flow, and the only place any of it lives — `runAgent` and `nativeLoop` both
68
+ * come here, so the two cannot drift.
69
+ */
70
+ export declare function runNativeLoop(req: LoopRequest, loopCtx: LoopContext): Promise<LoopResult>;
71
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EAGlB,MAAM,aAAa,CAAA;AACpB,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAE9D,OAAO,KAAK,EAAgB,QAAQ,EAAc,MAAM,sBAAsB,CAAA;AAC9E,OAAO,EAAe,KAAK,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAG5D,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAA;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,IAAI,EAAE,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC5B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,YAAY,CAAA;CACpB;AAYD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE;IACzC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACnC,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAK9C;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAG3C;AA0CD;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBxE;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAkK/F"}
package/dist/agent.js ADDED
@@ -0,0 +1,258 @@
1
+ import { runEventEmitter, } from "./events.js";
2
+ import { nativeLoop, runWithEvents, } from "./loop.js";
3
+ import { asChatModel } from "./models/chat.js";
4
+ import { executeTool } from "./tools/registry.js";
5
+ import { toToolSpecs } from "./tools/metadata.js";
6
+ const DEFAULT_MAX_STEPS = 12;
7
+ const FALLBACK_MAX_DURATION_MS = 10 * 60 * 1000;
8
+ /** Resolve the wall-clock run budget from env, falling back to 10 minutes. */
9
+ function defaultMaxDurationMs() {
10
+ const raw = Number(process.env.RUNNER_RUN_TIMEOUT_MS);
11
+ return Number.isFinite(raw) && raw > 0 ? raw : FALLBACK_MAX_DURATION_MS;
12
+ }
13
+ const FALLBACK_MAX_TOOL_RESULT_BYTES = 64 * 1024;
14
+ /**
15
+ * Resolve a partial budget to the concrete numbers a {@link LoopRequest} needs.
16
+ *
17
+ * One place, deliberately. A {@link Loop} is handed numbers rather than
18
+ * optionals, so if each caller resolved its own defaults a second loop
19
+ * implementation could silently run to a different ceiling than the one the
20
+ * kernel ships. `runAgent` and `NativeEngine` both come here.
21
+ */
22
+ export function resolveLoopLimits(limits) {
23
+ return {
24
+ maxSteps: limits?.maxSteps ?? DEFAULT_MAX_STEPS,
25
+ maxDurationMs: limits?.maxDurationMs ?? defaultMaxDurationMs(),
26
+ };
27
+ }
28
+ /**
29
+ * Cap on tool output fed back into the conversation, independent of the sandbox
30
+ * buffer caps — an 8 MB stdout would otherwise blow the context window.
31
+ * Env-overridable (`RUNNER_MAX_TOOL_RESULT_BYTES`, default 64 KiB) and resolved
32
+ * per call so a changed env takes effect without a reload.
33
+ */
34
+ export function maxToolResultBytes() {
35
+ const raw = Number(process.env.RUNNER_MAX_TOOL_RESULT_BYTES);
36
+ return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : FALLBACK_MAX_TOOL_RESULT_BYTES;
37
+ }
38
+ /**
39
+ * The reversibility fields a tool declares, copied at call time.
40
+ *
41
+ * Each is spread only when declared: absent means "makes no claim", which is a
42
+ * different fact from `reversible: false` ("declared irreversible") and a
43
+ * rollback consumer must be able to tell them apart.
44
+ */
45
+ function undoFields(meta) {
46
+ return {
47
+ ...(meta?.reversible !== undefined ? { reversible: meta.reversible } : {}),
48
+ ...(meta?.undoToolName !== undefined ? { undoToolName: meta.undoToolName } : {}),
49
+ ...(meta?.undoWindowSeconds !== undefined ? { undoWindowSeconds: meta.undoWindowSeconds } : {}),
50
+ };
51
+ }
52
+ /**
53
+ * A detached copy of a tool's arguments for the event stream.
54
+ *
55
+ * The sink must never be able to change what the tool receives: emitting is
56
+ * observation, and an observer that mutates `input` in place would make merely
57
+ * *attaching* a sink alter the run's side effects. `structuredClone` handles
58
+ * the nested case; the shallow fallback covers a value it refuses (a function,
59
+ * say) rather than letting a clone failure take the run down.
60
+ */
61
+ function detach(input) {
62
+ try {
63
+ return structuredClone(input);
64
+ }
65
+ catch {
66
+ return { ...input };
67
+ }
68
+ }
69
+ function truncate(text, max = maxToolResultBytes()) {
70
+ return text.length <= max
71
+ ? text
72
+ : `${text.slice(0, max)}\n…[truncated ${text.length - max} bytes]`;
73
+ }
74
+ /**
75
+ * Drives a provider-agnostic tool-use loop: the model converses, the runner
76
+ * executes any requested tools in the sandbox, feeds the results back, and
77
+ * repeats until the model stops calling tools (or the step budget is hit). The
78
+ * model orchestrates; deterministic work happens in the tools.
79
+ */
80
+ export async function runAgent(options) {
81
+ // A `Provider` is adapted onto the model seam; a `ChatModel` passes straight
82
+ // through. Either way the loop talks to one interface, so a
83
+ // middleware-wrapped or registry-resolved model drives it identically.
84
+ const log = options.log ?? (() => { });
85
+ const result = await runWithEvents(nativeLoop, {
86
+ model: asChatModel(options.provider),
87
+ system: options.system,
88
+ userPrompt: options.userPrompt,
89
+ tools: options.tools,
90
+ limits: resolveLoopLimits(options),
91
+ }, { log, events: runEventEmitter(options.emit, log) });
92
+ return result.text;
93
+ }
94
+ /**
95
+ * The native tool-use loop, as a {@link Loop}.
96
+ *
97
+ * Exported for `loop.ts` to wrap; applications reach it through `nativeLoop`
98
+ * rather than calling this directly. It is the whole of the kernel's control
99
+ * flow, and the only place any of it lives — `runAgent` and `nativeLoop` both
100
+ * come here, so the two cannot drift.
101
+ */
102
+ export async function runNativeLoop(req, loopCtx) {
103
+ const { model, system, userPrompt, tools } = req;
104
+ const { maxSteps, maxDurationMs } = req.limits;
105
+ const log = loopCtx.log;
106
+ const ctx = { log, budget: { maxDurationMs } };
107
+ // The emitter is the caller's: `seq` is per RUN, not per loop, so a loop that
108
+ // made its own would restart the numbering mid-stream.
109
+ const events = loopCtx.events;
110
+ const byName = new Map(tools.map((t) => [t.spec.name, t]));
111
+ const specs = toToolSpecs(tools);
112
+ const messages = [{ role: "user", text: userPrompt }];
113
+ const deadline = Date.now() + maxDurationMs;
114
+ let finalText = "";
115
+ let lastAssistantText = "";
116
+ let exhausted = false;
117
+ let timedOut = false;
118
+ let stepsTaken = 0;
119
+ // A throw propagates untouched; `runWithEvents` closes the stream around it,
120
+ // so every loop gets that property rather than only this one.
121
+ for (let step = 0; step < maxSteps; step += 1) {
122
+ // Wall-clock budget: enforced between steps so an in-flight provider/tool
123
+ // call isn't interrupted mid-flight, mirroring how maxSteps stops cleanly.
124
+ // Because the check is only between steps, a single step can overshoot the
125
+ // budget by its entire duration: up to (provider timeout × maxRetries) for the
126
+ // converse call plus the time to execute all of that step's tool calls. So the
127
+ // effective ceiling is `maxDurationMs + one full step`, not `maxDurationMs`.
128
+ if (Date.now() >= deadline) {
129
+ timedOut = true;
130
+ log(`reached run time budget (${maxDurationMs}ms) after ${step} step(s)`);
131
+ events.emit({ type: "run.budget_exhausted", kind: "duration", step });
132
+ break;
133
+ }
134
+ const { value: turn } = await model.invoke({ system, messages, tools: specs }, ctx);
135
+ stepsTaken = step + 1;
136
+ messages.push({ role: "assistant", text: turn.text, toolCalls: turn.toolCalls });
137
+ if (turn.text)
138
+ lastAssistantText = turn.text;
139
+ events.emit({
140
+ type: "model.turn",
141
+ step,
142
+ text: turn.text,
143
+ toolCalls: turn.toolCalls.map((c) => ({ id: c.id, name: c.name })),
144
+ });
145
+ if (turn.toolCalls.length === 0) {
146
+ finalText = turn.text;
147
+ break;
148
+ }
149
+ const results = [];
150
+ for (const call of turn.toolCalls) {
151
+ const tool = byName.get(call.name);
152
+ if (!tool) {
153
+ results.push({
154
+ toolCallId: call.id,
155
+ content: `unknown tool: ${call.name}`,
156
+ isError: true,
157
+ });
158
+ log(`tool ${call.name} (unknown)`);
159
+ events.emit({
160
+ type: "tool.failed",
161
+ step,
162
+ callId: call.id,
163
+ name: call.name,
164
+ reason: "unknown_tool",
165
+ error: `unknown tool: ${call.name}`,
166
+ });
167
+ continue;
168
+ }
169
+ // Emitted BEFORE execution: a process that dies mid-tool still leaves
170
+ // evidence that the effect may have started, which is the one case a
171
+ // rollback consumer cannot afford to infer from silence.
172
+ events.emit({
173
+ type: "tool.called",
174
+ step,
175
+ callId: call.id,
176
+ name: call.name,
177
+ input: detach(call.input),
178
+ ...undoFields(tool.meta),
179
+ });
180
+ try {
181
+ // Uses the tool's structured executor when it has one, so a typed
182
+ // payload survives alongside the string the model sees. Tools without
183
+ // one take the original string path unchanged.
184
+ const output = await executeTool(tool, call.input);
185
+ results.push({
186
+ toolCallId: call.id,
187
+ content: truncate(output.content),
188
+ ...(output.structured !== undefined ? { structured: output.structured } : {}),
189
+ });
190
+ log(`tool ${call.name} ok (${output.content.length} bytes)`);
191
+ // Reversibility is copied from the tool's own metadata at call time —
192
+ // the tool set can differ per run, so a consumer reading the stream
193
+ // later must not have to reconstruct which registry was in play.
194
+ events.emit({
195
+ type: "tool.succeeded",
196
+ step,
197
+ callId: call.id,
198
+ name: call.name,
199
+ bytes: Buffer.byteLength(output.content, "utf8"),
200
+ ...undoFields(tool.meta),
201
+ });
202
+ }
203
+ catch (err) {
204
+ const message = err instanceof Error ? err.message : String(err);
205
+ results.push({ toolCallId: call.id, content: message, isError: true });
206
+ log(`tool ${call.name} error: ${message}`);
207
+ events.emit({
208
+ type: "tool.failed",
209
+ step,
210
+ callId: call.id,
211
+ name: call.name,
212
+ reason: "threw",
213
+ error: message,
214
+ });
215
+ }
216
+ }
217
+ messages.push({ role: "tool", results });
218
+ if (step === maxSteps - 1) {
219
+ exhausted = true;
220
+ events.emit({ type: "run.budget_exhausted", kind: "steps", step });
221
+ }
222
+ }
223
+ // Ran out of time mid-loop: don't spend more of the (already-blown) budget on
224
+ // a summary call — just return whatever prose we accumulated, clearly noted.
225
+ if (!finalText && timedOut) {
226
+ const accumulated = lastAssistantText || "(no output before time budget exhausted)";
227
+ const text = `${accumulated}\n\n[run stopped: wall-clock budget of ${maxDurationMs}ms exceeded]`;
228
+ return { text, steps: stepsTaken, outcome: "timed_out" };
229
+ }
230
+ // Hit the step budget mid-tool-use: ask once more with no tools so the model
231
+ // can summarize, falling back to its last prose rather than losing the work.
232
+ if (!finalText && exhausted) {
233
+ log(`reached max steps (${maxSteps}); requesting a final summary`);
234
+ try {
235
+ const summary = (await model.invoke({ system, messages, tools: [] }, ctx)).value;
236
+ // Emitted like any other turn: `run.finished.text` can come from this
237
+ // call, and a terminal event whose text traces back to no turn in the
238
+ // transcript would break the stream's one promise.
239
+ events.emit({ type: "model.turn", step: stepsTaken, text: summary.text, toolCalls: [] });
240
+ finalText = summary.text || lastAssistantText;
241
+ }
242
+ catch (err) {
243
+ log(`final summary failed: ${err instanceof Error ? err.message : String(err)}`);
244
+ finalText = lastAssistantText;
245
+ }
246
+ }
247
+ const text = finalText || "(no output)";
248
+ // `completed` means the model stopped calling tools of its own accord. A run
249
+ // that hit the step budget and was asked for a summary still reports
250
+ // `steps_exhausted`, because the distinction is exactly what a consumer needs
251
+ // to know about the trustworthiness of the answer.
252
+ const outcome = timedOut ? "timed_out" : exhausted ? "steps_exhausted" : "completed";
253
+ // `runWithEvents` builds the terminal event from exactly this result, so the
254
+ // return value and the stream cannot disagree — there is one source now, not
255
+ // two that happen to be written from the same variables.
256
+ return { text, steps: stepsTaken, outcome };
257
+ }
258
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}