Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ pnpm tsx examples/recursive-supervisor/recursive-supervisor.ts
pnpm tsx examples/driver-loop/driver-loop.ts # SEE THE FOLD (offline)
TANGLE_API_KEY=... pnpm tsx examples/supervise/supervise.ts # the one-call supervisor
WORKER_MODEL=opencode/anthropic/claude-sonnet-4-5 \
pnpm tsx examples/supervisor-loop/run-bridge.ts # same supervisor, local cli-bridge backend
WORKER_BACKEND=bridge WORKER_MODEL=opencode/... pnpm tsx examples/supervisor-loop/run.ts # one knob: bridge|sandbox
TANGLE_API_KEY=... pnpm tsx examples/delegate/delegate.ts # delegate(intent), one call

# Tier 2 — the runLoop kernel
Expand Down
30 changes: 17 additions & 13 deletions examples/supervisor-loop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ see [`../supervise/`](../supervise/); the runners here add the per-backend worke

| Runner | Worker backend | Command |
|---|---|---|
| `run-bridge.ts` | local cli-bridge (real harness CLI) | `WORKER_MODEL=opencode/anthropic/claude-sonnet-4-5 pnpm tsx examples/supervisor-loop/run-bridge.ts` |
| `run-sandbox.ts` | a real cloud box | `TANGLE_API_KEY=sk-... SANDBOX_BASE_URL=https://... pnpm tsx examples/supervisor-loop/run-sandbox.ts` |
| `run.ts` | local cli-bridge (real harness CLI) | `WORKER_BACKEND=bridge WORKER_MODEL=opencode/anthropic/claude-sonnet-4-5 pnpm tsx examples/supervisor-loop/run.ts` |
| `run.ts` | a real cloud box | `WORKER_BACKEND=sandbox TANGLE_API_KEY=sk-... SANDBOX_BASE_URL=https://... pnpm tsx examples/supervisor-loop/run.ts` |
| `run-supervisor-mcp.ts` | `WORKER_BACKEND` (`bridge`\|`sandbox`) over the coordination MCP | `WORKER_BACKEND=bridge pnpm dlx tsx examples/supervisor-loop/run-supervisor-mcp.ts` |

## Details
Expand All @@ -19,12 +19,16 @@ the offline-vs-real driver brain, and the one-call run-context boilerplate.

### Files

- **`shared.ts`** — the demo fixtures the runners reuse: `demoGoal` + the deployable `demoCheck`
(the completion oracle), and `scriptedSupervisorChat` (a fixed `spawn → await → stop` brain so
the box/bridge wiring runs offline with no inference).
- **`run-sandbox.ts`** — `supervise()` with `backend: 'sandbox'`. Each worker is a coding harness in a real box.
- **`run-bridge.ts`** — `supervise()` with `backend: 'bridge'`. Each worker is a real harness CLI (claude-code / codex / opencode / kimi / gemini) fronted by the OpenAI-compatible bridge in `~/code/cli-bridge`. **The local path.**
- **`run-supervisor-mcp.ts`** — the real MCP path (below): a harness agent IS the supervisor and calls `spawn_agent` natively over the coordination MCP.
- **`shared.ts`** — the demo fixtures + the swap seam: `demoGoal` + the deployable `demoCheck` (the
completion oracle), `scriptedSupervisorChat` (a fixed `spawn → await → stop` brain so the wiring runs
offline with no inference), and the two functions that make the "one knob" real — **`buildWorkerBackend()`**
(returns the worker `ExecutorConfig` for `WORKER_BACKEND=bridge` or `sandbox`) and **`resolveSupervisorBrain()`**
(router brain if a key is present, else scripted).
- **`run.ts`** — the plain `supervise()` runner. **One file, one knob:** `WORKER_BACKEND=bridge` runs workers
through the local cli-bridge (real harness CLIs — claude-code / codex / opencode / kimi / gemini); flip to
`WORKER_BACKEND=sandbox` and the *same* supervisor drives workers in real Tangle boxes.
- **`run-supervisor-mcp.ts`** — the real MCP path (below): a harness agent IS the supervisor and calls
`spawn_agent` natively over the coordination MCP. Same `WORKER_BACKEND` knob (via `buildWorkerBackend`).

### Supervisor + coordinator MCP, workers on sandbox OR cli-bridge — swap `WORKER_BACKEND`, same code

Expand Down Expand Up @@ -59,7 +63,7 @@ WORKER_BACKEND=sandbox SANDBOX_BASE_URL=https://... TANGLE_API_KEY=sk-... \
pnpm dlx tsx examples/supervisor-loop/run-supervisor-mcp.ts
```

This is distinct from the `run-bridge.ts` / `run-sandbox.ts` runners below, which drive a
This is distinct from the plain `run.ts` runner above, which drives a
**scripted/router `ToolLoopChat` brain** through `supervise()`. `run-supervisor-mcp.ts` has no
driver brain at all — the harness itself reasons the spawn → await → stop loop via the MCP.

Expand All @@ -71,8 +75,8 @@ resolves from `dist/`.
| Backend | Command | Needs |
|---|---|---|
| **`router-tools`** | `TANGLE_API_KEY=sk-... pnpm tsx examples/supervise/supervise.ts` | `TANGLE_API_KEY`; optional `TANGLE_ROUTER_URL`, `MODEL` — the one-call entry (router brain + router-tools workers) |
| **`sandbox`** | `TANGLE_API_KEY=sk-... SANDBOX_BASE_URL=https://... pnpm tsx examples/supervisor-loop/run-sandbox.ts` | a real `SandboxClient` (key + base URL); optional `LOOP_HARNESS` (default `opencode`); driver defaults to router-brain, `DRIVER=scripted` for no driver inference |
| **`bridge`** (local) | `WORKER_MODEL=opencode/anthropic/claude-sonnet-4-5 pnpm tsx examples/supervisor-loop/run-bridge.ts` | a running `~/code/cli-bridge` (base `http://127.0.0.1:3344`, no `/v1`, bearer optional/default `local`); `WORKER_MODEL` = `<harness>/<model>`. Override `BRIDGE_URL` / `BRIDGE_BEARER` if you started it with auth. Set `TANGLE_API_KEY` + `DRIVER_MODEL` for a real driver brain (else scripted) |
| **`sandbox`** | `WORKER_BACKEND=sandbox TANGLE_API_KEY=sk-... SANDBOX_BASE_URL=https://... pnpm tsx examples/supervisor-loop/run.ts` | a real `SandboxClient` (key + base URL); optional `LOOP_HARNESS` (default `opencode`); driver defaults to router-brain, `DRIVER=scripted` for no driver inference |
| **`bridge`** (local) | `WORKER_BACKEND=bridge WORKER_MODEL=opencode/anthropic/claude-sonnet-4-5 pnpm tsx examples/supervisor-loop/run.ts` | a running `~/code/cli-bridge` (base `http://127.0.0.1:3344`, no `/v1`, bearer optional/default `local`); `WORKER_MODEL` = `<harness>/<model>`. Override `BRIDGE_URL` / `BRIDGE_BEARER` if you started it with auth. Set `TANGLE_API_KEY` + `DRIVER_MODEL` for a real driver brain (else scripted) |

### Test locally — the cli-bridge backend

Expand All @@ -84,7 +88,7 @@ box. Start it, then point a worker at it:
cd ~/code/cli-bridge && pnpm install && pnpm install:harness -- opencode && pnpm start
# → http://127.0.0.1:3344

WORKER_MODEL=opencode/anthropic/claude-sonnet-4-5 pnpm tsx examples/supervisor-loop/run-bridge.ts
WORKER_BACKEND=bridge WORKER_MODEL=opencode/anthropic/claude-sonnet-4-5 pnpm tsx examples/supervisor-loop/run.ts
```

The workflow is: **prove the supervisor topology against local harness CLIs (`bridge`), then
Expand All @@ -101,7 +105,7 @@ pnpm test tests/loops/coordination-driver.test.ts tests/supervisor-loop-example.
The supervisor drives through an injected `ToolLoopChat` brain (one driver-LLM turn).
`supervise(..., { router })` (or `examples/supervise/supervise.ts`) uses **`routerBrain(cfg)`**
so the supervisor's turns are real router tool-calls and the brain decides the loop itself.
`run-sandbox.ts`/`run-bridge.ts` default to a **scripted** brain (`scriptedSupervisorChat`, a
`run.ts` defaults to a **scripted** brain (`scriptedSupervisorChat`, a
fixed `spawn → await → stop` plan) so the box/bridge wiring is the only moving part — the same
offline seam the unit tests use — and opt into `routerBrain` when a key is present. Same brain,
different seam.
Expand Down
105 changes: 0 additions & 105 deletions examples/supervisor-loop/run-bridge.ts

This file was deleted.

93 changes: 0 additions & 93 deletions examples/supervisor-loop/run-sandbox.ts

This file was deleted.

38 changes: 2 additions & 36 deletions examples/supervisor-loop/run-supervisor-mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,47 +34,13 @@ import {
type Agent,
createExecutorRegistry,
createSupervisor,
type ExecutorConfig,
InMemoryResultBlobStore,
InMemorySpawnJournal,
type Scope,
serveCoordinationMcp,
workerFromBackend,
} from '@tangle-network/agent-runtime/loops'
import { demoCheck, expectedAnswer } from './shared'

/** Build the worker-leaf `ExecutorConfig` for the chosen backend. THIS is the swap seam: the
* `backend` field, plus the matching per-backend seam fields. Nothing downstream cares which
* one it is — `workerFromBackend` injects the seam and returns a uniform spawnable worker. */
function workerBackend(): ExecutorConfig {
const backend = process.env.WORKER_BACKEND ?? 'bridge'
if (backend === 'sandbox') {
throw new Error(
'WORKER_BACKEND=sandbox needs a real SandboxClient (key + base URL). Construct it from\n' +
' @tangle-network/sandbox and return { backend: "sandbox", sandboxClient } here — the\n' +
' supervisor, MCP, spawn_agent, and the deployable check are identical to the bridge path.\n' +
'Run the proven path: WORKER_BACKEND=bridge WORKER_MODEL=opencode/zai-coding-plan/glm-5.1',
)
}
if (backend !== 'bridge') {
throw new Error(`WORKER_BACKEND must be "bridge" or "sandbox" (got ${JSON.stringify(backend)})`)
}
const model = process.env.WORKER_MODEL
if (!model) {
throw new Error(
'WORKER_BACKEND=bridge needs WORKER_MODEL=<harness>/<model> the bridge can serve,\n' +
' e.g. WORKER_MODEL=opencode/zai-coding-plan/glm-5.1\n' +
'Start the bridge first: cd ~/code/cli-bridge && pnpm start (→ http://127.0.0.1:3344)',
)
}
return {
backend: 'bridge',
bridgeUrl: process.env.BRIDGE_URL ?? 'http://127.0.0.1:3344',
bridgeBearer: process.env.BRIDGE_BEARER ?? 'local',
model,
timeoutMs: 180_000,
}
}
import { buildWorkerBackend, demoCheck, expectedAnswer } from './shared'

/** The supervisor's standing instructions — it delegates, it does not solve. */
const supervisorTask =
Expand Down Expand Up @@ -109,7 +75,7 @@ async function supervisorBridgeChat(opts: { mcpUrl: string }): Promise<string> {
}

async function main(): Promise<void> {
const backend = workerBackend()
const backend = buildWorkerBackend()
const blobs = new InMemoryResultBlobStore()

console.log(
Expand Down
Loading
Loading