@tangle-network/agent-runtime 0.134.9 → 0.135.2

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 (59) hide show
  1. package/README.md +80 -538
  2. package/dist/{activation-CAexDnXt.js → activation-n_QCjFyg.js} +2 -2
  3. package/dist/{activation-CAexDnXt.js.map → activation-n_QCjFyg.js.map} +1 -1
  4. package/dist/agent.d.ts +2 -2
  5. package/dist/agent.js +2 -2
  6. package/dist/analyst-loop.d.ts +1 -1
  7. package/dist/{authoring-DHVHhbJO.js → authoring-Cl5xwuKl.js} +2 -2
  8. package/dist/{authoring-DHVHhbJO.js.map → authoring-Cl5xwuKl.js.map} +1 -1
  9. package/dist/conversation.d.ts +1 -1
  10. package/dist/{environment-provider-BIZMHOQw.d.ts → environment-provider-DA8LqBV-.d.ts} +3 -3
  11. package/dist/environment-provider.d.ts +1 -1
  12. package/dist/{graph-BWsEZmDL.js → graph-NKOjYL1z.js} +12 -8
  13. package/dist/graph-NKOjYL1z.js.map +1 -0
  14. package/dist/{improvement-cycle-DN0QhoCi.js → improvement-cycle-B8KrGlT4.js} +3 -3
  15. package/dist/{improvement-cycle-DN0QhoCi.js.map → improvement-cycle-B8KrGlT4.js.map} +1 -1
  16. package/dist/{index-RYbM0cUo.d.ts → index-CETQJlqT.d.ts} +3 -3
  17. package/dist/{index-DC7CNU9n.d.ts → index-CP1RvdOw.d.ts} +4 -4
  18. package/dist/{index-CRauzLFH.d.ts → index-DjPLpg7-.d.ts} +47 -9
  19. package/dist/index.d.ts +9 -9
  20. package/dist/index.js +7 -7
  21. package/dist/intelligence.d.ts +5 -5
  22. package/dist/intelligence.js +3 -3
  23. package/dist/kernel.d.ts +7 -7
  24. package/dist/kernel.js +7 -7
  25. package/dist/{knowledge-DDhcxfdu.js → knowledge-_7FWqPwl.js} +3 -3
  26. package/dist/{knowledge-DDhcxfdu.js.map → knowledge-_7FWqPwl.js.map} +1 -1
  27. package/dist/knowledge.d.ts +1 -1
  28. package/dist/knowledge.js +1 -1
  29. package/dist/{loop-runner-bin-bnDuiEQU.js → loop-runner-bin-CnlVnCM1.js} +3 -3
  30. package/dist/{loop-runner-bin-bnDuiEQU.js.map → loop-runner-bin-CnlVnCM1.js.map} +1 -1
  31. package/dist/{loop-runner-bin-Yp4T-tUJ.d.ts → loop-runner-bin-DndNkp6D.d.ts} +3 -3
  32. package/dist/loop-runner-bin.d.ts +1 -1
  33. package/dist/loop-runner-bin.js +1 -1
  34. package/dist/mcp/bin.js +3 -3
  35. package/dist/mcp/index.d.ts +5 -5
  36. package/dist/mcp/index.js +4 -4
  37. package/dist/{openai-tools-BulrPqjW.d.ts → openai-tools-DU3TZvFY.d.ts} +2 -2
  38. package/dist/{openai-tools-ne97uXo0.js → openai-tools-o7jw10Fn.js} +2 -2
  39. package/dist/{openai-tools-ne97uXo0.js.map → openai-tools-o7jw10Fn.js.map} +1 -1
  40. package/dist/primeintellect/index.d.ts +1 -1
  41. package/dist/profiles.d.ts +1 -1
  42. package/dist/{redact-Bojh05mQ.d.ts → redact--KfuCwwo.d.ts} +3 -3
  43. package/dist/{runtime-CwY043ZD.js → runtime-BQTE0RJS.js} +6 -6
  44. package/dist/{runtime-CwY043ZD.js.map → runtime-BQTE0RJS.js.map} +1 -1
  45. package/dist/{runtime-DHrzFy2v.d.ts → runtime-WugWo__W.d.ts} +4 -4
  46. package/dist/{stream-agent-turn-BEv31Log.d.ts → stream-agent-turn-DhPlvHwp.d.ts} +3 -3
  47. package/dist/{structural-rollout-BMnPPcJP.js → structural-rollout-keBf4YEc.js} +2 -2
  48. package/dist/{structural-rollout-BMnPPcJP.js.map → structural-rollout-keBf4YEc.js.map} +1 -1
  49. package/dist/{supervise-B-nTWUCK.js → supervise-CVP9ku5U.js} +36 -4
  50. package/dist/{supervise-B-nTWUCK.js.map → supervise-CVP9ku5U.js.map} +1 -1
  51. package/dist/{supervisor-Dl9Fk7g5.js → supervisor-mZ9Glkz7.js} +18 -3
  52. package/dist/supervisor-mZ9Glkz7.js.map +1 -0
  53. package/dist/testing.d.ts +2 -2
  54. package/dist/testing.js +11 -11
  55. package/dist/{types-DzZCZcwI.d.ts → types-BBwGSiAj.d.ts} +8 -5
  56. package/dist/{types-C7UNjVce.d.ts → types-BCkweg3w.d.ts} +2 -2
  57. package/package.json +1 -1
  58. package/dist/graph-BWsEZmDL.js.map +0 -1
  59. package/dist/supervisor-Dl9Fk7g5.js.map +0 -1
package/README.md CHANGED
@@ -9,526 +9,109 @@ Domain behavior (models, tools, knowledge) plugs in as adapters; the scoring sta
9
9
  pnpm add @tangle-network/agent-runtime @tangle-network/agent-eval @tangle-network/sandbox
10
10
  ```
11
11
 
12
- ## Contents
13
-
14
- - [Quickstart](#quickstart-offline-no-api-keys)
15
- - [What you do with it](#what-you-do-with-it)
16
- - [Run a chat turn](#run-a-chat-turn)
17
- - [Retain and reconnect a run](#retain-and-reconnect-a-run)
18
- - [Supervise a team of agents](#supervise-a-team-of-agents)
19
- - [Improve an agent](#improve-an-agent)
20
- - [Improve a knowledge base](#improve-a-knowledge-base)
21
- - [Run on PrimeIntellect](#run-on-primeintellect)
22
- - [How it works](#how-it-works-the-short-version)
23
- - [Primitives](#primitives)
24
- - [Examples](#examples)
25
- - [Where to go next](#where-to-go-next)
12
+ New here? Read [`docs/concepts.md`](./docs/concepts.md) for the mental model in plain terms, then pick a front door below.
26
13
 
27
14
  ## Quickstart (offline, no API keys)
28
15
 
29
- A driver runs a worker, reads its output, and writes the next prompt until a check passes.
30
- This excerpt shows the driver from the runnable [`examples/quickstart/quickstart.ts`](./examples/quickstart/quickstart.ts).
31
- That file defines the scripted `worker`, `output`, and `validator` used below so it runs without credentials.
32
- Replace the scripted worker with a sandbox, CLI bridge, or router backend without changing the driver.
16
+ One agent attempt, run by a loop you control.
17
+ This is [`examples/quickstart/minimal.ts`](./examples/quickstart/minimal.ts) in full: it compiles and runs as pasted, with no credentials.
33
18
 
34
19
  ```ts
35
20
  import type { AgentProfile } from '@tangle-network/agent-interface'
36
- import { inProcessSandboxClient, runAgentRounds } from '@tangle-network/agent-runtime/kernel'
21
+ import {
22
+ inProcessSandboxClient,
23
+ runAgentRounds,
24
+ type TerminalDecision,
25
+ } from '@tangle-network/agent-runtime/kernel'
26
+ import type { SandboxEvent } from '@tangle-network/sandbox'
37
27
 
38
- const noteWriterProfile = {
28
+ const profile = {
39
29
  name: 'note-writer',
40
30
  harness: 'cli-base',
41
31
  model: { provider: 'scripted', default: 'scripted/note-writer' },
42
32
  } satisfies AgentProfile
43
33
 
44
- const result = await runAgentRounds<Task, Note, 'refine' | 'pick-winner' | 'fail'>({
45
- task: { prompt: 'Write a one-line release note for one-click restore.' },
34
+ // A scripted worker. Swap in a sandbox, CLI-harness, or router backend later.
35
+ const worker = inProcessSandboxClient({
36
+ onPrompt: (): SandboxEvent[] => [
37
+ { type: 'result', data: { result: { note: 'Shipped one-click restore.' } } },
38
+ ],
39
+ })
40
+
41
+ const result = await runAgentRounds({
42
+ task: 'Write a one-line release note for one-click restore.',
46
43
  driver: {
47
- name: 'refine',
48
- plan: async (task, history) => {
49
- const last = history[history.length - 1]
50
- if (!last) return [task] // shot 0: run the task as written
51
- if (last.verdict?.valid || history.length >= 3) return [] // done, or out of shots
52
- // The core move: read the last worker's real output, write the next prompt FROM it.
53
- return [{ prompt: `Rewrite "${last.output?.note}" to mention the rollback path.` }]
54
- },
55
- decide: (history) =>
56
- history.some((shot) => shot.verdict?.valid) ? 'pick-winner' : history.length < 3 ? 'refine' : 'fail',
44
+ // plan returns the tasks to run this iteration; [] means no more work.
45
+ plan: async (task, history) => (history.length === 0 ? [task] : []),
46
+ // 'done' is one of the four kernel keywords in TERMINAL_DECISIONS.
47
+ decide: (): TerminalDecision => 'done',
57
48
  },
58
- agentRun: { profile: noteWriterProfile, taskToPrompt: (t) => t.prompt },
59
- output, // parses the worker's event stream into { note }
60
- validator, // pass/fail check: does the note mention "rollback"?
49
+ agentRun: { profile, taskToPrompt: (t) => t },
50
+ output: { parse: (events) => events },
61
51
  ctx: { sandboxClient: worker },
62
- maxIterations: 3,
63
52
  })
53
+
54
+ console.log(`decision: ${result.decision} — ${result.iterations.length} iteration(s)`)
64
55
  ```
65
56
 
66
57
  Run it from a clone of this repo and you get exactly this:
67
58
 
68
59
  ```bash
69
60
  $ pnpm i && pnpm build
70
- $ pnpm tsx examples/quickstart/quickstart.ts
71
- shot 0: reject"Shipped one-click restore."
72
- shot 1: PASS — "Shipped one-click restore with an instant rollback path."
73
- decision: pick-winner — winner: shot 1
61
+ $ pnpm tsx examples/quickstart/minimal.ts
62
+ decision: done1 iteration(s)
74
63
  ```
75
64
 
76
- The annotated version is [`examples/driver-loop`](./examples/driver-loop).
65
+ [`examples/quickstart`](./examples/quickstart) grows the same call into a loop that reads each output and writes the next prompt from it.
77
66
 
78
- ## What you do with it
67
+ Five words appear everywhere:
79
68
 
80
- | You want to… | Call |
69
+ | Word | What it means |
81
70
  |---|---|
82
- | Run a **chat turn** for a production product agent | `handleChatTurn(...)` |
83
- | Have one agent **supervise a team of agents** toward a goal | `supervise(profile, task, opts)` |
84
- | **Improve** an agent and prove the gain on fresh tasks | `improve(profile, opts)` |
85
- | Produce a measured knowledge-base candidate with agents and checks | `runKnowledgeImprovementJob(...)` |
86
- | Evaluate or train the same agent on **PrimeIntellect** | `createPrimeIntellectPackage(...)` |
87
-
88
- ### Run a chat turn
89
-
90
- A product agent is one `handleChatTurn` call inside a route. You give it how to produce the response and how to persist it; it streams, traces, and persists.
91
-
92
- ```ts
93
- import { deriveExecutionId, handleChatTurn } from '@tangle-network/agent-runtime/durable'
94
-
95
- const turnIndex = 0
96
- const executionId = deriveExecutionId({ projectId, sessionId: threadId, turnIndex })
97
- const result = handleChatTurn({
98
- identity: { tenantId, sessionId: threadId, userId, turnIndex },
99
- hooks: {
100
- produce: () => ({
101
- stream: box.streamPrompt(userMessage, {
102
- sessionId: threadId,
103
- executionId,
104
- turnId: executionId,
105
- detach: true,
106
- }),
107
- finalText: () => box.lastResponse(),
108
- }),
109
- persistAssistantMessage: async ({ identity, finalText }) => db.insertMessage(identity, finalText),
110
- },
111
- waitUntil,
112
- })
113
- return new Response(result.body, { headers: { 'content-type': result.contentType } })
114
- ```
115
-
116
- For a stream reconnect, call `streamPrompt` with the same `executionId` and the last event id the client received.
117
- For a repeated initial dispatch, reuse both `sessionId` and `turnId`; `executionId` alone is not an idempotency key.
118
-
119
- ### Retain and reconnect a run
120
-
121
- Use the retained-run API when the provider owns a job that must outlive one HTTP reader or application process.
122
- The provider must advertise exact run identity, replay, result identity, and idempotent cancellation.
123
-
124
- ```ts
125
- import {
126
- reconnectRetainedRun,
127
- recoverRetainedRun,
128
- startRetainedRun,
129
- } from '@tangle-network/agent-runtime/kernel'
130
-
131
- const run = await startRetainedRun({
132
- provider,
133
- environment: { idempotencyKey: 'workspace-42', profile },
134
- turn: { turnId: 'turn-7', prompt: 'Finish the migration and run its tests.' },
135
- identity: { sessionId: 'thread-42', executionId: 'execution-7' },
136
- onAdmission: async (admission) => {
137
- await journal.write(admission)
138
- },
139
- })
140
-
141
- for await (const event of run.events()) {
142
- await journal.write(event)
143
- }
144
-
145
- const recovered = await reconnectRetainedRun({
146
- provider: freshProvider,
147
- controlRef: (await journal.readDispatchedAdmission()).controlRef,
148
- })
149
- if (!recovered) throw new Error('the provider no longer retains this environment')
150
-
151
- const snapshot = await recovered.status({ waitMs: 30_000 })
152
- const result = await recovered.result()
153
- ```
154
-
155
- The runtime awaits `onAdmission` after environment creation and again after dispatch.
156
- The start promise resolves only after the dispatched admission, so the exact reference is durable before any caller observes success.
157
- Persist each admission record inside the hook before it returns.
158
- A hook rejection fails the start with `RetainedRunAdmissionError` and keeps the environment for recovery.
159
- When you omit `identity`, the runtime mints deterministic coordinates from the two keys, so every process derives the same values.
160
- After dispatch, the runtime verifies the provider honored the requested identity and fails with `RetainedRunDispatchBindingError` when it did not.
161
- Persist each event cursor and sequence before advancing the visible transcript.
162
- `reconnectRetainedRun` reconstructs a client from a dispatched admission's `controlRef` and rejects any provider, environment, session, execution, run, or digest mismatch.
163
- After a crash that left only the `environment` admission, call `recoverRetainedRun` with its coordinates.
164
- It reports `recovered` with a handle, `not_found` when the environment is gone, or `unverifiable` when the provider cannot self-identify the session.
165
- Never destroy an environment on `unverifiable`; keep it, retry `reconnectRetainedRun` later, or inspect it with provider-native tools.
166
- An unknown provider result remains unknown; the runtime never converts it into success or confirmed cancellation.
167
-
168
- ### Supervise a team of agents
169
-
170
- One supervisor spawns and steers workers toward a goal. Where the workers run (an in-process loop, or a sandboxed coding harness) is one data value; the budget, journaling, and stopping are handled for you.
171
-
172
- ```ts
173
- import { supervise } from '@tangle-network/agent-runtime/kernel'
174
-
175
- const result = await supervise(
176
- {
177
- name: 'supervisor',
178
- harness: 'cli-base',
179
- model: { provider: 'tangle-router', default: process.env.TANGLE_MODEL! },
180
- prompt: {
181
- systemPrompt: 'Delegate to workers; do not solve the task yourself.',
182
- },
183
- },
184
- 'Implement the feature and make the tests pass.',
185
- { budget, router, backend }, // backend = where workers run: router-tools | sandbox+harness | bridge
186
- )
187
- ```
188
-
189
- ### Improve an agent
190
-
191
- `improve` runs one complete `OptimizationMethod` against one profile field.
192
- The method owns candidate generation and selection.
193
- Runtime keeps the final test set out of the method, scores the baseline and selected candidate on it, and returns `ship` only when the paired confidence interval clears `minimumLift`.
194
- The profile is never changed.
195
-
196
- ```ts
197
- import { improve, officialGepa } from '@tangle-network/agent-runtime'
198
- import { profileOptimizerModelCall } from '@tangle-network/agent-runtime/kernel'
199
- import {
200
- type AgentProfile,
201
- canonicalAgentProfileDigest,
202
- canonicalCandidateDigest,
203
- } from '@tangle-network/agent-interface'
204
-
205
- const executionRef = canonicalCandidateDigest({
206
- deployment: process.env.AGENT_DEPLOYMENT_SHA!,
207
- model: process.env.AGENT_MODEL!,
208
- tools: process.env.AGENT_TOOLSET_SHA!,
209
- })
210
-
211
- const optimizerProfile = {
212
- name: 'support-prompt-optimizer',
213
- harness: 'cli-base',
214
- model: {
215
- provider: 'tangle-router',
216
- default: process.env.OPTIMIZER_MODEL!,
217
- metadata: { maxTokens: 16_384 },
218
- },
219
- } satisfies AgentProfile
220
- const optimizerPricing = {
221
- inputUsdPerMillion: Number(process.env.OPTIMIZER_INPUT_USD_PER_MILLION),
222
- outputUsdPerMillion: Number(process.env.OPTIMIZER_OUTPUT_USD_PER_MILLION),
223
- }
224
- const optimizer = {
225
- model: optimizerProfile.model.default,
226
- call: profileOptimizerModelCall({
227
- profile: optimizerProfile,
228
- context: 'support-prompt optimizer',
229
- executor: {
230
- backend: 'router',
231
- routerBaseUrl: process.env.OPTIMIZER_BASE_URL!,
232
- routerKey: process.env.OPTIMIZER_API_KEY!,
233
- },
234
- pricing: optimizerPricing,
235
- }),
236
- callRef: canonicalCandidateDigest({
237
- profile: canonicalAgentProfileDigest(optimizerProfile),
238
- deployment: process.env.OPTIMIZER_DEPLOYMENT_SHA!,
239
- }),
240
- budget: {
241
- maxCostUsd: 10,
242
- maxRequests: 50,
243
- maxRequestBytes: 2_000_000,
244
- maxResponseBytes: 2_000_000,
245
- maxOutputTokensPerRequest: 16_384,
246
- pricing: optimizerPricing,
247
- },
248
- }
249
-
250
- const result = await improve(baseProfile, {
251
- surface: 'prompt',
252
- executionRef,
253
- method: officialGepa({
254
- objective: 'Improve the complete support-agent prompt.',
255
- recipe: {
256
- kind: 'engine',
257
- run: {
258
- engine: 'gepa',
259
- maxEvaluations: 40,
260
- maxProposerCostUsd: 10,
261
- },
262
- },
263
- optimizer,
264
- resume: 'if-compatible',
265
- trustResumeState: true,
266
- describeScenario: ({ input }) => ({ input }),
267
- }),
268
- findings,
269
- trainScenarios,
270
- selectionScenarios,
271
- testScenarios,
272
- judges: [judge],
273
- agent: (candidateProfile, scenario, ctx) =>
274
- runProfile(candidateProfile, scenario, ctx),
275
- runDir: '.runs/support-prompt',
276
- costCeiling: 25,
277
- })
278
-
279
- if (result.decision === 'ship') {
280
- console.log(result.candidate.profile, result.liftInterval)
281
- }
282
- ```
283
-
284
- `officialGepa(...)` delegates the complete search to GEPA's upstream Optimize Anything API through agent-eval.
285
- Pass one explicit `engine`, `sequential`, `adaptive-sequential`, `best-of`, `vote`, or `omni` recipe.
286
- Runtime derives the upstream resume identity from `executionRef`, the complete baseline profile, and the selected surface.
287
- With `resume: 'if-compatible'`, agent-eval resumes only when the saved run identity matches the candidate, recipe, data, optimizer settings, runner, and derived execution identity.
288
- Set `trustResumeState: true` only when that run directory is private to the current operator.
289
- Use `resume: 'required'` to fail when no matching run exists.
290
- `result.provenance` reports the upstream package, run ID, resume status, evaluation count, and artifact directory.
291
- `result.candidatePopulation` verifies and joins callback observations with an optimizer's official candidate graph.
292
- It returns every unique candidate as a complete profile with ordered Interface diffs, or as an explicit materialization refusal.
293
- GEPA candidates retain exact parent indices and selection scores; callback-only proposals report lineage as unavailable.
294
- Methods without either artifact return `status: 'unavailable'` instead of treating the winner as the full population.
295
- There is no local fallback.
296
- Install its optional Python process before using it:
297
-
298
- ```bash
299
- python -m pip install "agent-eval-rpc==0.145.0"
300
- python -m pip install "gepa[full]==0.1.4"
301
- ```
302
-
303
- The published GEPA 0.1.4 wheel supports the direct `gepa` engine.
304
- Sequential, adaptive, best-of, vote, Omni, AutoResearch, Meta Harness, and Best-of-N require the tested official source revision:
305
-
306
- ```bash
307
- python -m pip install "gepa[full] @ git+https://github.com/gepa-ai/gepa.git@f919db0a622e2e9f9204779b81fe00cc1b2d808f"
308
- ```
309
-
310
- Use `officialSkillOpt(...)` for Microsoft's SkillOpt:
311
-
312
- ```bash
313
- python -m pip install "agent-eval-rpc==0.145.0"
314
- python -m pip install "skillopt @ git+https://github.com/microsoft/SkillOpt.git@61735e3922efc2b90c6d6cab561e62e98452ca90"
315
- ```
316
-
317
- SkillOpt 0.2.0's published wheel omits prompt files required by `ReflACTTrainer`, so the tested SkillOpt source revision remains necessary.
318
- SkillOpt and GEPA's standard reflection engine require `optimizer: { model, call, callRef, budget }`.
319
- Agent-based GEPA engines may own their model connection instead.
320
- Runtime owns those model calls through one exact `AgentProfile`; Agent Eval enforces the nested budget and records their measured cost and execution evidence without receiving provider credentials.
321
- `costCeiling` is the total limit for optimizer calls, candidate runs, judges, and final scoring.
322
- Runtime returns `hold` when any part of that cost is unknown.
323
- Runtime rejects a reported total above the limit.
324
-
325
- SkillOpt accepts one text surface.
326
- GEPA accepts text or named components.
327
- Any complete method from `@tangle-network/agent-eval` uses the same call.
328
- The `agent` callback receives the complete immutable candidate profile, not a raw prompt or component fragment.
329
- Runtime uses that exact profile for every candidate run and returns the same measured profile in `result.candidate.profile`.
330
- `executionRef` is a content digest of the agent callback, profile component mapping, model, tools, and closure settings.
331
- Runtime combines it with the complete baseline profile and selected surface for saved work.
332
- Changing any of them runs the affected work again.
333
- For a skill, set `surface: 'skills'` and `skills.resourceName`.
334
- For the complete profile, set `surface: 'agent-profile'`.
335
- To optimize several named profile fields together, also provide `profileComponents.read` and `profileComponents.apply`.
336
- Tools, MCP, hooks, subagents, curated instructions, and rollout policy are also exact profile coordinates.
337
- Runtime does not choose an optimizer for them.
338
-
339
- Without `describeScenario`, the external optimizer receives only each development case ID.
340
- Without `describeArtifact`, evaluation feedback contains no artifact body.
341
- When either descriptor is present, its result passes through `redact` together with findings, background text, profile name, and judge notes.
342
- The built-in redactor removes common credentials and email addresses.
343
- Supply a domain redactor for customer names, account IDs, or other private data the built-in rules cannot identify.
344
- Runtime applies that hook first and then still applies its built-in scrubber.
345
- Set `redact: false` only when every outbound value is public and already reviewed.
346
-
347
- The selected profile surface is the optimizer's candidate and cannot be redacted without changing the measured candidate.
348
- Runtime always rejects recognized credentials in those bytes.
349
- It also rejects structurally sensitive fields such as MCP env, headers, URLs, metadata, and extensions.
350
- For `tools`, `mcp`, `hooks`, `subagents`, and `agent-profile`, Runtime treats the entire selected coordinate as execution-capable.
351
- Use `authorizeSensitiveCandidate` to inspect and accept each exact immutable profile containing public values or safe references.
352
- The callback runs for the baseline and every distinct candidate before either reaches your agent.
353
- Its `sensitivePaths` includes `$` when the whole coordinate requires review.
354
-
355
- Code is the exception.
356
- It uses Runtime's isolated git worktrees and coding-agent candidate execution:
357
-
358
- ```ts
359
- const result = await improve({
360
- surface: 'code',
361
- code: { repoRoot, baseRef, profile, generator },
362
- scenarios,
363
- judge,
364
- agent,
365
- budget,
366
- })
367
- ```
368
-
369
- `improve` is the search call.
370
- For production, `proposeAgentImprovement` adds trace analysis and reruns the exact frozen baseline and winner before creating a reviewable proposal.
371
- Runtime rejects a candidate bundle that differs from the search winner.
372
-
373
- ```ts
374
- import {
375
- createAgentImprovementActivation,
376
- executeAgentImprovementActivation,
377
- proposeAgentImprovement,
378
- reviewAgentImprovementProposal,
379
- } from '@tangle-network/agent-runtime/intelligence'
380
-
381
- const baseline = freezeBaseline(liveProfile)
382
- const result = await proposeAgentImprovement({
383
- runId,
384
- profile: liveProfile,
385
- analysis,
386
- improvement: {
387
- surface: 'prompt',
388
- executionRef,
389
- method,
390
- trainScenarios,
391
- selectionScenarios,
392
- testScenarios,
393
- judges: [judge],
394
- agent,
395
- },
396
- buildExperiment: ({ improvement }) =>
397
- buildExperimentMaterial({
398
- baseline,
399
- candidate: compileCandidateBundle({ baseline, improvement: improvement.candidate }),
400
- benchmark: heldOutBenchmark,
401
- policy: comparisonPolicy,
402
- }),
403
- placeCell,
404
- })
405
-
406
- const review = reviewAgentImprovementProposal(result.proposal, {
407
- decision: 'approve',
408
- reviewedBy: user.id,
409
- reason: 'The measured gain is worth the cost.',
410
- })
411
- const activation = createAgentImprovementActivation(result.proposal, review, {
412
- intent: 'activate-candidate',
413
- targets: [{ surface: 'prompt', identity: profileId }],
414
- fundingOwner: tenantId,
415
- authorizedBy: user.id,
416
- expiresAt,
417
- })
418
- const outcome = await executeAgentImprovementActivation(
419
- { proposal: result.proposal, review, activation },
420
- { transition: commitProfileTransaction, reconcile: readCommittedResult },
421
- )
422
- ```
423
-
424
- `buildExperimentMaterial`, `placeCell`, and the transaction functions are application ports because storage and compute differ by product.
425
- The builder returns only baseline, candidate, tasks, and policy; Runtime adds the search ancestry and seals the final experiment.
426
- Runtime owns candidate identity, measurement, review binding, expiry, retry identity, and result validation; the application owns its atomic write.
427
- Official optimizer proposals carry the observed package versions, optimizer model, evaluation and token usage, separate optimization and final-test costs, and resumed-run identity.
428
- `createOptimizationActivationReceipt(result)` exposes the same detached record for callers that need to inspect an `improve()` result before building a proposal.
429
-
430
- ### Improve a knowledge base
431
-
432
- `runKnowledgeImprovementJob` runs KB, wiki, memory-backed, and RAG improvement jobs.
433
- It creates a candidate copy, runs agents against it, checks it through `@tangle-network/agent-knowledge`, and returns frozen baseline and candidate snapshots with spend and timing.
434
- It never changes the live knowledge base.
435
- Use `improve(profile, { surface: 'memory', ... })` for the agent's curated lesson document.
436
- Use this job for source, retrieval, and knowledge-store changes.
437
-
438
- ```ts
439
- import { runKnowledgeImprovementJob } from '@tangle-network/agent-runtime/knowledge'
440
-
441
- const result = await runKnowledgeImprovementJob({
442
- root: './kb',
443
- goal: 'Improve support refund-policy knowledge',
444
- implementationRef: 'git:0123456789abcdef0123456789abcdef01234567',
445
- readinessSpecs,
446
- budget: { maxIterations: 8, maxTokens: 120_000, maxUsd: 10 },
447
- backend,
448
- })
449
-
450
- console.log(result.knowledge?.reference.candidateHash, result.measurement.supervisedSpent)
451
- ```
452
-
453
- Use it when the product needs one knob for "make this knowledge base better" instead of wiring `improveKnowledgeBase`, a runtime supervisor, candidate workspaces, and readiness checks by hand.
454
- Set `implementationRef` to the deployed `git:<40 hex>` revision or a `sha256:<64 hex>` digest covering every callback, model, index, and external setting that can change the result.
455
- The same run ID resumes only when this identity still matches.
456
- Measure the returned bundle pair, record the review, then activate through `executeAgentImprovementActivation`; activation is the only write path.
457
-
458
- ### Run on PrimeIntellect
459
-
460
- `@tangle-network/agent-runtime/primeintellect` packages typed train and eval tasks as a PrimeIntellect Verifiers environment.
461
- Prime launches your actual runtime program against an intercepted model endpoint, so `runPersonified`, `runAgentic`, product agents, tool calls, and multiple rounds stay intact.
462
- Reference answers remain in Prime's task process and never enter the agent workspace.
463
- The runner file must be one executable bundle containing the app and its runtime dependencies.
464
-
465
- ```ts
466
- import { readFile } from 'node:fs/promises'
467
- import {
468
- createPrimeIntellectPackage,
469
- writePrimeIntellectPackage,
470
- } from '@tangle-network/agent-runtime/primeintellect'
471
-
472
- const bundledRunner = await readFile('./dist/prime-runner.mjs', 'utf8')
473
- const bundle = createPrimeIntellectPackage({
474
- name: 'support-agent',
475
- version: '1.0.0',
476
- tasks: [
477
- {
478
- id: 'train-refund-policy',
479
- split: 'train',
480
- prompt: 'Can a subscription renewal be refunded?',
481
- answer: 'No',
482
- },
483
- {
484
- id: 'eval-final-sale',
485
- split: 'eval',
486
- prompt: 'Can a final-sale order be refunded?',
487
- answer: 'No',
488
- },
489
- ],
490
- scoring: { kind: 'exact', normalization: 'trim-casefold' },
491
- runner: {
492
- image: 'node:22-bookworm-slim',
493
- files: { 'runner.mjs': bundledRunner },
494
- command: ['node', 'runner.mjs'],
495
- },
496
- })
497
-
498
- await writePrimeIntellectPackage(bundle, './prime/support-agent')
499
- ```
500
-
501
- The runner reads the episode and uses the normal runtime APIs:
502
- Here, `runProductAgent` is the application's existing entry point, not another loop supplied by this adapter.
503
-
504
- ```ts
505
- import {
506
- primeIntellectExecutorConfig,
507
- runPrimeIntellectProgram,
508
- } from '@tangle-network/agent-runtime/primeintellect'
509
- import {
510
- collectAgentTurn,
511
- createExecutor,
512
- streamAgentTurn,
513
- } from '@tangle-network/agent-runtime/kernel'
514
-
515
- await runPrimeIntellectProgram(async (episode) => {
516
- const profile = makeProductProfile({ model: episode.model.name })
517
- return collectAgentTurn(
518
- streamAgentTurn(
519
- {
520
- kind: 'executor',
521
- profile,
522
- factory: createExecutor(primeIntellectExecutorConfig(episode)),
523
- },
524
- episode.task.prompt,
525
- ),
526
- )
527
- })
528
- ```
529
-
530
- Prime writes complete `traces.jsonl` rows.
531
- Use `importPrimeIntellectTraces(...)` to convert them to agent-eval `RunRecord`s for the existing reports and release checks.
71
+ | **worker** | An agent that produces an answer. Here it is a `SandboxClient`. |
72
+ | **driver** | Your code. It runs a worker, reads the output, and writes the next prompt. |
73
+ | **decision** | What `decide` returns. The four keywords in `TERMINAL_DECISIONS` (`stop`, `pick-winner`, `fail`, `done`) end the loop; every other value is your own vocabulary and continues it. |
74
+ | **verdict** | What a validator returns: valid or not, with a score. |
75
+ | **harness** | What drives an agent. `cli-base` is the router-backed mode with no coding agent behind it; `claude-code`, `codex`, and `opencode` each run a real coding CLI. |
76
+
77
+ ## Which front door
78
+
79
+ One row per entry point, ordered by how often real products use it.
80
+ Each row links to a runnable example.
81
+
82
+ | Front door | When to call it | What you give it | What you get back |
83
+ |---|---|---|---|
84
+ | **`runAgentTaskStream`** · [example](./examples/stream-a-turn) | You run one agent turn and read its events yourself. | a task, a backend, a message | an async stream of `RuntimeStreamEvent` |
85
+ | **`handleChatTurn`** (`/durable`) · [example](./examples/chat-handler) | A web route must stream one turn to a browser and save the reply. | how to produce tokens, how to persist | an HTTP body plus a persist call after the last token |
86
+ | **`AgentExecutionBackend`** · [example](./examples/stream-backends) | You choose where the tokens come from: your loop, a sandbox, or an exact profile. | `kind` plus a `stream()` generator | the same event union from any source |
87
+ | **`runToolLoop`** (`/tool-loop`) · [example](./examples/tool-loop) | The model must call your tools and answer in the same turn. | one model turn, your executors | final text, every tool outcome, a stop reason |
88
+ | **`startRuntimeRun`** · [example](./examples/runtime-run) | You must record what a run cost and whether it succeeded. | run identity, a store adapter | a live cost tally and one persisted row |
89
+ | **`runAgentRounds`** (`/kernel`) · [example](./examples/quickstart) | One prompt is not enough, and your code owns the stop rule. | `plan`, `decide`, an output adapter, a sandbox client | every attempt, the verdicts, and a winner |
90
+ | **`supervise`** (`/kernel`) · [example](./examples/supervise) | A model must decide the plan and drive other agents. | a supervisor profile, a goal, a budget | the delivered result, or a typed reason and the spend |
91
+ | **`startRetainedRun`** (`/kernel`) · [example](./examples/retained-run) | The job must outlive the process that started it. | a provider, keys, a durable admission hook | a claim ticket any process can reattach to |
92
+ | **`improve`** · [example](./examples/improve) | You must change one part of an agent and prove the gain. | a profile field, three case sets, a judge | a detached candidate, a lift interval, ship or hold |
93
+
94
+ Five mechanisms continue interrupted work.
95
+ Pick by what died.
96
+
97
+ - The HTTP connection — call `streamPrompt` again with the same `executionId`.
98
+ - Nothing, but you want the same box for the next turn — `openSandboxRun`.
99
+ - The coordinator process, mid-orchestration — `supervise({ runDir })`.
100
+ - The user's chat session — the `/conversation` store adapters.
101
+ - Everything except the provider — [retained runs](./examples/retained-run).
102
+
103
+ ## Also in the box
104
+
105
+ - **Benchmarks and leaderboards** compare strategies with significance stats (`runBenchmark`), or stand up a harness×model board (`defineLeaderboard`): [`examples/coding-benchmark`](./examples/coding-benchmark), [`examples/webcode-matrix`](./examples/webcode-matrix).
106
+ - **Agent graphs** fixed topologies authored as data and run through `runGraph`: [`examples/graphs`](./examples/graphs).
107
+ - **Improve a knowledge base** — a measured candidate copy of a KB, wiki, or RAG corpus: [`docs/improve.md`](./docs/improve.md).
108
+ - **PrimeIntellect** package the same runtime program as a Verifiers environment: [`docs/primeintellect.md`](./docs/primeintellect.md).
109
+ - **Conversations** (`/conversation`) — multi-turn two-agent sessions with SQL-backed resume.
110
+ - **MCP servers** (`/mcp`) give any agent a `delegate` tool plus live coordination tools.
111
+ - **Live run view** (`/tui`) — `agent-runtime-top` shows every supervisor run in a workspace, with steer and cancel.
112
+ - **Telemetry** — every loop emits `loop.*` trace events, exported as OpenTelemetry GenAI spans when `OTEL_EXPORTER_OTLP_ENDPOINT` is set.
113
+
114
+ All 33 examples live in [`examples/`](./examples).
532
115
 
533
116
  ## How it works (the short version)
534
117
 
@@ -537,55 +120,14 @@ Use `importPrimeIntellectTraces(...)` to convert them to agent-eval `RunRecord`s
537
120
  - **Candidates face fresh tasks.** The optimizer uses train and selection tasks. Promotion uses a separate final set.
538
121
  - **Scores come from executed attempts.** Runtime recomputes results from the recorded cells and rejects incomplete cost or source evidence.
539
122
 
540
- ## Primitives
541
-
542
- The general-purpose pieces, by import path. Every export with its one-line summary lives in the generated [`docs/api/primitive-catalog.md`](./docs/api/primitive-catalog.md): check it before building anything new.
543
-
544
- | Primitive | What it does | Import |
545
- |---|---|---|
546
- | Chat-turn runtime | Stream and persist one production chat turn (`handleChatTurn`); derive its stable execution and turn identity (`deriveExecutionId`); normalize any backend's stream into one event shape (`streamAgentTurn`) | `/durable` · `/kernel` |
547
- | Retained provider runs | Start one detached provider job with a durable admission hook, replay exact events, reconnect after restart, rebuild from pre-dispatch coordinates, continue its native context, and cancel idempotently (`startRetainedRun`, `reconnectRetainedRun`, `recoverRetainedRun`) | `/kernel` |
548
- | Tool-call loop | Run one model turn, execute requested tools, feed results back, and stop on completion, repetition, time, or cost limits (`runToolLoop`, `streamToolLoop`) | `/tool-loop` |
549
- | Supervision | One agent spawns, budgets, and steers workers toward a goal (`supervise`, `delegate`), on an in-process loop or a sandboxed coding harness | `/kernel` · `/mcp` |
550
- | Loop kernel + combinators | Write a driver (`plan`/`decide`) and run it (`runAgentRounds`), or compose fixed shapes: refine (`loopUntil`), best-of-N (`fanout`), chain (`pipeline`), multi-judge (`panel`) | `/kernel` |
551
- | Improvement driver | Optimize one part of an agent and ship only if it wins on tasks it never practiced on (`improve`); production proposal/review/activation flow | root · `/intelligence` |
552
- | Benchmarks + leaderboards | Compare strategies with significance stats (`runBenchmark`), stand up a harness×model leaderboard (`defineLeaderboard`, `leaderboard`) | `/kernel` |
553
- | Knowledge improvement | Produce a measured candidate copy of a KB/wiki/RAG corpus without touching the live one (`runKnowledgeImprovementJob`) | `/knowledge` |
554
- | MCP tool servers | Give an agent a `delegate` tool or live worker-coordination tools over MCP | `/mcp` |
555
- | Conversations + durability | Multi-turn two-agent sessions with SQL-backed resume (D1/pg/sqlite/libSQL adapters) | `/conversation` |
556
- | Training/eval adapter | Package the same runtime program as a PrimeIntellect Verifiers environment; import its traces back | `/primeintellect` |
557
-
558
- | Watching live runs | A terminal view of every supervisor run in a workspace — workers, spend, tokens, latency, plus steer and cancel (`agent-runtime-top`) | `/tui` |
559
-
560
- Remaining subpaths: `/agent`, `/profiles`, `/platform`, `/analyst-loop`, `/environment-provider`, `/testing` (validated fixture records for consumer tests).
561
-
562
- ## Examples
563
-
564
- Runnable, grouped by what they show. Copy the one nearest your task:
565
-
566
- | Do this | Example |
567
- |---|---|
568
- | The smallest complete loop (start here) | [`quickstart`](./examples/quickstart) · [`driver-loop`](./examples/driver-loop) |
569
- | Run a product chat turn | [`chat-handler`](./examples/chat-handler) |
570
- | Drive a team of agents to a goal | [`supervise`](./examples/supervise) · [`recursive-supervisor`](./examples/recursive-supervisor) |
571
- | Benchmark strategies on your own domain | [`coding-benchmark`](./examples/coding-benchmark) |
572
- | Benchmark **harnesses × models** over a real task suite (the real WebCode dataset) | [`webcode-matrix`](./examples/webcode-matrix) |
573
- | Render a **multi-profile leaderboard** with ranked board, score matrix, and SVG/HTML charts | `leaderboard(records)` → `renderLeaderboardMarkdown` / `Svg` / `Html` |
574
- | Trace + bill + effort-gate the WebCode benchmark (the Intelligence SDK) | [`intelligence-webcode`](./examples/intelligence-webcode) |
575
- | Self-improve an agent, gated on a held-out set | [`improve`](./examples/improve) · [`self-improving-coder`](./examples/self-improving-coder) |
576
- | Improve a KB, wiki, or RAG corpus with runtime agents | [`docs/canonical-api.md`](./docs/canonical-api.md) |
577
- | Evaluate or train a runtime program on PrimeIntellect | `@tangle-network/agent-runtime/primeintellect` |
578
- | Study coordination vs raw compute | [`ablation-suite`](./examples/ablation-suite) |
579
-
580
- All 29 live in [`examples/`](./examples).
581
-
582
123
  ## Where to go next
583
124
 
584
- - New here? [`docs/concepts.md`](./docs/concepts.md), the mental model in plain terms.
125
+ - [`docs/concepts.md`](./docs/concepts.md), the mental model in plain terms.
585
126
  - [`docs/canonical-api.md`](./docs/canonical-api.md), find the primitive: "I want to ___ → use ___".
586
127
  - [`docs/api/primitive-catalog.md`](./docs/api/primitive-catalog.md), every export in one generated, never-stale list with its import path. Check it before building anything new.
587
- - [`docs/STABILITY.md`](./docs/STABILITY.md), what `@stable` / `@experimental` promise you, and how a symbol graduates.
588
- - [`docs/design.md`](./docs/design.md), the design philosophy and the internal research docs behind it: background reading, not required to use the package.
128
+ - [`docs/improve.md`](./docs/improve.md), the improvement reference: optimizers, surfaces, redaction, proposal, review, activation.
129
+ - [`docs/STABILITY.md`](./docs/STABILITY.md), what `@stable` and `@experimental` promise you, and how a symbol graduates.
130
+ - [`docs/design.md`](./docs/design.md), the design philosophy and the research behind it: background reading, not required to use the package.
589
131
  - [`bench/HARNESS.md`](./bench/HARNESS.md), the experiment harness and how to run a benchmark.
590
132
 
591
133
  **Contributing:** `pnpm i && pnpm build && pnpm test` gets you running; the full local gate is the [`package.json`](./package.json) scripts (`lint`, `typecheck`, `docs:check`).