diff --git a/examples/README.md b/examples/README.md index d468135f..b6f6d143 100644 --- a/examples/README.md +++ b/examples/README.md @@ -43,7 +43,7 @@ pnpm tsx examples/improve/improve.ts | [`mcp-delegation`](./mcp-delegation/) | another agent needs Runtime's delegation tools over MCP | | [`fleet-delegation`](./fleet-delegation/) | delegated workers must share a fleet workspace | | [`knowledge-gating`](./knowledge-gating/) | execution must stop when required knowledge is below threshold | -| [`researcher-loop`](./researcher-loop/) | a domain uses the optional `agent-knowledge` peer and a hard isolation check | +| [`researcher-loop`](./researcher-loop/) | a domain preset on a caller-owned profile, with a hard tenant-isolation check | | [`sanitized-telemetry-streaming`](./sanitized-telemetry-streaming/) | runtime telemetry must be useful without leaking user content | ## Specialized examples diff --git a/examples/driver-loop/scripted-worker.ts b/examples/driver-loop/scripted-worker.ts index 4e692db6..3fa36d81 100644 --- a/examples/driver-loop/scripted-worker.ts +++ b/examples/driver-loop/scripted-worker.ts @@ -52,6 +52,7 @@ export function scriptedWorkerClient(): SandboxClient { data: { model: 'scripted', tokensIn: 200, tokensOut: 40, costUsd: 0.0006 }, }, { type: 'result', data: { result: { note } satisfies NoteOutput } }, + { type: 'done', data: { outcome: { type: 'completed' } } }, ] }, }) diff --git a/examples/quickstart/minimal.ts b/examples/quickstart/minimal.ts index fbfad70a..30c1f315 100644 --- a/examples/quickstart/minimal.ts +++ b/examples/quickstart/minimal.ts @@ -23,6 +23,7 @@ const profile = { const worker = inProcessSandboxClient({ onPrompt: (): SandboxEvent[] => [ { type: 'result', data: { result: { note: 'Shipped one-click restore.' } } }, + { type: 'done', data: { outcome: { type: 'completed' } } }, ], }) diff --git a/examples/quickstart/quickstart.ts b/examples/quickstart/quickstart.ts index e1d69989..404f6ff7 100644 --- a/examples/quickstart/quickstart.ts +++ b/examples/quickstart/quickstart.ts @@ -40,6 +40,7 @@ const worker = inProcessSandboxClient({ }, }, }, + { type: 'done', data: { outcome: { type: 'completed' } } }, ], }) diff --git a/examples/researcher-loop/README.md b/examples/researcher-loop/README.md index d2b806fe..bd26d04b 100644 --- a/examples/researcher-loop/README.md +++ b/examples/researcher-loop/README.md @@ -18,9 +18,10 @@ written. It also shows the **propose-don't-apply** contract: the winning agent r ## How it works -1. `researcherProfile({ task })` hands you three things wired to work together: the system prompt for - a research agent, the output parser that turns its reply into structured findings, and the - validator that scores them. +1. `researcherProfile({ profile, task })` hands you three things wired to work together on top of a + profile you own: the system prompt for a research agent, the output parser that turns its reply + into structured findings, and the validator that scores them. The harness, provider and model + stay yours; the preset supplies the research half. 2. A tiny **driver** launches two agents on the same question (a "fanout"), collects both answers, and asks the loop to pick the best valid one. 3. The validator scores each answer on citation density and per-claim evidence, and **hard-fails** @@ -32,11 +33,8 @@ written. It also shows the **propose-don't-apply** contract: the winning agent r ## Run ```bash -# 1. Install the one optional package this example needs (the runtime does NOT depend on it — -# domain packs are injected, not bundled, so it isn't installed by default): -pnpm add -D @tangle-network/agent-knowledge - -# 2. Run it (fully offline — the two agent answers are scripted fixtures, no model call, no key): +# Fully offline — the two agent answers are scripted fixtures, no model call, no key, no +# extra package. `researcherProfile` ships in this repo, under @tangle-network/agent-runtime/profiles. pnpm tsx examples/researcher-loop/researcher-loop.ts ``` diff --git a/examples/researcher-loop/researcher-loop.ts b/examples/researcher-loop/researcher-loop.ts index 73ce247c..ed65a440 100644 --- a/examples/researcher-loop/researcher-loop.ts +++ b/examples/researcher-loop/researcher-loop.ts @@ -7,21 +7,31 @@ * different knowledge namespace, so the bad candidate is pruned by construction. * * Offline: the two synthetic researcher outputs and the stand-in `sandboxClient` live in - * ./synthetic-researcher.ts. Needs the optional `@tangle-network/agent-knowledge` peer. + * ./synthetic-researcher.ts. No model call, no key, no extra package. * * Run: pnpm tsx examples/researcher-loop/researcher-loop.ts */ +import type { AgentProfile } from '@tangle-network/agent-interface' +import { type Driver, runAgentRounds } from '@tangle-network/agent-runtime/kernel' import { type ResearchOutput, type ResearchTask, researcherProfile, -} from '@tangle-network/agent-knowledge/profiles' -import { type Driver, runAgentRounds } from '@tangle-network/agent-runtime/kernel' +} from '@tangle-network/agent-runtime/profiles' import { sandboxClient, task } from './synthetic-researcher' +// The caller owns the harness/provider/model identity; the preset supplies the research system +// prompt, the output parser, and the validator on top of it. `scripted` is what the offline +// sandbox client below answers to — swap it for a real provider to run this live. +const researcher = { + name: 'researcher', + harness: 'cli-base', + model: { provider: 'scripted', default: 'scripted/researcher' }, +} satisfies AgentProfile + async function main(): Promise { - const { output, validator, agentRunSpec } = researcherProfile({ task }) + const { output, validator, agentRunSpec } = researcherProfile({ profile: researcher, task }) const driver: Driver = { name: 'fanout', // A "round" = one plan → run workers → decide cycle. This driver is SINGLE-ROUND: diff --git a/examples/researcher-loop/synthetic-researcher.ts b/examples/researcher-loop/synthetic-researcher.ts index 1fb902e4..fbdf2ea8 100644 --- a/examples/researcher-loop/synthetic-researcher.ts +++ b/examples/researcher-loop/synthetic-researcher.ts @@ -11,8 +11,8 @@ * whole output, so the kernel prunes it and the valid candidate wins. */ -import type { ResearchOutput, ResearchTask } from '@tangle-network/agent-knowledge/profiles' import { inProcessSandboxClient, type SandboxClient } from '@tangle-network/agent-runtime/kernel' +import type { ResearchOutput, ResearchTask } from '@tangle-network/agent-runtime/profiles' import type { SandboxEvent } from '@tangle-network/sandbox' export const namespace = 'example-tenant' @@ -138,6 +138,7 @@ export const sandboxClient: SandboxClient = inProcessSandboxClient({ }, }, { type: 'result', data: { result: output } }, + { type: 'done', data: { outcome: { type: 'completed' } } }, ] }, }) diff --git a/tsconfig.examples.json b/tsconfig.examples.json index 348cf602..858dc0d2 100644 --- a/tsconfig.examples.json +++ b/tsconfig.examples.json @@ -23,5 +23,5 @@ "sourceMap": false }, "include": ["examples"], - "exclude": ["node_modules", "dist", "examples/researcher-loop"] + "exclude": ["node_modules", "dist"] }