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
44 changes: 27 additions & 17 deletions agent-think/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ agent-think (this dir — PUBLIC-safe, holds no App creds)
├─ AgentThink WorkerEntrypoint.dispatch (src/index.ts)
│ getAgentByName(env.ThinkAgent, session) → setContext → start()
│ start() ONLY submits the durable turn — returns in ~1s
├─ ThinkAgent DO (src/agent.ts) — owns durable turn state + Workspace transport
│ /workspace is authoritative in the container (backend sync is disabled);
│ container backend dials the warm pool per-connect:
├─ ThinkAgent DO (src/agent.ts) — owns durable turn state + complete Workspace VFS
│ file tools and both bash backends share the same synchronized tree;
│ container backend claims from the warm pool per turn:
│ resolveContainerId(env, id) → env.Sandbox.get(idFromName(uuid))
├─ Sandbox DO (src/sandbox.ts) — container host (wsd); handed out by pool
├─ WarmPool DO (src/warm-pool.ts) — keeps WARM_POOL_TARGET(=1) containers warm
├─ WarmPool DO (src/warm-pool.ts) — keeps exactly one unassigned container warm
├─ CommandCenterAgent DO (src/command-center.ts) — singleton ("main")
│ registry of every thread + per-thread counters; ThinkAgent reports
│ lifecycle events fire-and-forget (observing must never break a run)
Expand Down Expand Up @@ -88,12 +88,22 @@ the container's coding filesystem.
- **No Cloudflare Workflow.** An earlier shape wrapped the turn in a Workflow;
its 10-min step timeout + retry-from-scratch was the main death mode. Think's
native durable `submitMessages` is the durability layer.
- **The container owns `/workspace`.** Workspace's transport still connects the
ThinkAgent to its warm-pooled Sandbox, but `sync: "none"` prevents repo data,
`.git`, `node_modules`, builds, and logs from entering DO SQLite. The DO owns
only durable turn/recovery state. Skills use Think's native R2 source.
- **Everything runs on the `container` backend.** It provides the real Linux
filesystem, toolchain, and network used by bash and the file tools.
- **One Workspace owns `/workspace`.** Think internals and read/write/edit call
the durable VFS directly. The lightweight shell operates on the same VFS, and
the container backend runs against its mounted view. Workspace owns its sync
policy; agent-think adds no path router or ignore policy. Paths outside
`/workspace` remain container-local. Skills use Think's native R2 source.
- **Run identity is durable input, not prompt configuration.** The first user
message carries an `<agent-think-run>` JSON envelope (repo, issue,
instruction, requester, triggering comment). Skills fail closed without it.
This survives context-block prompt assembly, eviction, and continuation.
- **Container ownership follows the turn.** The first container use claims a warm
container. The Workspace keeps that connection for the turn. Terminal cleanup
closes it, stops and drops the used container, and restores the one-container
warm slot. There are no renewable leases, sticky idle assignments, or TTL policy.
- **Bash has two backends.** The lightweight VFS-backed `shell` is the default for
text and file commands. Select `container` for gh, npm, node, native binaries,
network access, builds, tests, and deploys. File tools call the VFS directly.
- **Repros must be clickable.** The reproduce skill mandates a minimal
Vite + React page (exact 7-file recipe in the skill) so maintainers see the
failing behavior without cloning anything.
Expand Down Expand Up @@ -144,10 +154,9 @@ the container's coding filesystem.
in `run_worker_first`. Symptom: the UI's HTTP calls work while every
`wss://` connect fails. (This bit us on the command center; the repro-skill
recipe carries the same rule.)
- **Never re-enable container Workspace sync.** Pulling a monorepo install
(roughly 1.9 GB / 158k entries) into the ThinkAgent DO causes a memory-reset
loop on every container `/ws` reconnect. Noisy output must still be redirected
to `/workspace/temp` and tailed so tool results stay bounded.
- **`/temp` is deliberately outside the VFS mount.** Put long logs there and
tail them with container bash so neither the VFS nor tool results absorb the
full output.
- **Deploys reset in-flight turns.** A deploy lazily resets every DO onto the
new code; a running turn loses its container connection and burns minutes on
Think's (working) recovery — it re-auths and resumes, but don't deploy while
Expand All @@ -165,9 +174,10 @@ pnpm run deploy # vite build (thread UI) + wrangler deploy (worker + image)
npm run seed:r2 # push skills/** to the R2 bucket (add -- --local for dev)
```

- Vitest configs live next to their suites: `test/vitest.config.ts` (unit) and
`tests-e2e/vitest.config.ts` (e2e). `vite.config.ts` at the root builds only
the thread UI into `dist/client`.
- Vitest configs live next to their suites: `test/vitest.config.ts` (Workers
runtime module/DO tests) and `tests-e2e/vitest.config.ts` (real Wrangler +
Docker infrastructure, with only inference replaced by a test subclass).
`vite.config.ts` at the root builds only the thread UI into `dist/client`.
- Local-only HTTP surface (gated on `LOCAL_DEV=1`, set automatically by the
e2e harness): `POST /dev/dispatch` and `GET /dev/messages/:session` — drive
the full agent path without gh-app or webhooks.
Expand Down
6 changes: 3 additions & 3 deletions agent-think/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Sandbox container image for the think agent.
#
# Pulls the prebuilt wsd SEA binary out of the public GHCR image
# published by github.com/cloudflare/workspace, pinned in lockstep
# with the `@cloudflare/workspace` npm dependency (see package.json).
# Pulls the prebuilt wsd SEA binary out of the public GHCR image published by
# github.com/cloudflare/workspace. The image is pinned separately from the host
# package and only needs to move when the workspace RPC / wsd wire changes.
# wsd runs as PID 1 and serves the workspace RPC + FUSE mount.
#
# Layered on top: a Node.js + Bun toolchain (node, npm, bun, esbuild,
Expand Down
2 changes: 1 addition & 1 deletion agent-think/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"dev": "wrangler dev --ip 0.0.0.0",
"build:client": "vite build",
"deploy": "vite build && wrangler deploy",
"typecheck": "tsc --noEmit",
"typecheck": "tsc --noEmit && tsc --noEmit -p tests-e2e/tsconfig.json",
"gen-types": "wrangler types",
"seed:r2": "node ./scripts/seed-skills.mjs",
"test": "vitest run --config test/vitest.config.ts",
Expand Down
43 changes: 29 additions & 14 deletions agent-think/skills/open-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,20 @@ name: open-pr
description: Take a cloudflare/agents GitHub issue plus any repro findings and one-shot a fix PR — branch, change, test, push, and open the PR linked to the issue.
---

The agent system prompt gives you `issueNumber`, `repo`, and the user's
instruction. Use those values directly; there is no separate arguments object.
The current user message contains an `<agent-think-run>` envelope with
`repository`, `issue`, `instruction`, `requested-by`, and (when available)
`trigger-comment-id`.
Use those values exactly. Never infer or substitute another target from examples,
workspace contents, GitHub searches, or concurrent issues. If the envelope or a
required field is absent, stop without cloning/editing/pushing/posting and return a
structured skipped result. When `trigger-comment-id` is present, your first
container action is the liveness reaction:

```bash
gh api repos/<repository>/issues/comments/<trigger-comment-id>/reactions \
-f content=rocket
```

Produce a focused fix PR, authored as **yourself** — the agent-think GitHub App.
Do not impersonate any user.

Expand All @@ -16,8 +28,8 @@ it highly, but stay within the scope of the issue.
All `gh`, `git`, `npm`, `curl`, and `wrangler` commands must run on the
`container` backend (`bash({ command, backend: "container" })`) — the `shell`
backend has no real binaries or network. `gh` is already authenticated as the
app; use it directly (no token handling). Work under `/workspace`; use
`/workspace/temp` for scratch files.
app; use it directly (no token handling). Work under `/workspace`; put long
logs and disposable scratch files in container-local `/temp`.

## 0. Clone the repo

Expand Down Expand Up @@ -48,7 +60,8 @@ known.
needing design, is too vague, spans many subsystems, or you cannot locate a
confident root cause, stop: return `prOpened: false`, `skipped: true`, and a
`summary` explaining why. Post a brief, polite comment saying the pr-agent is
skipping it and what additional detail would help.
skipping it and what additional detail would help; begin it with
`Requested by @<requestedBy>` when the run envelope has a requester.

## 2. Locate the root cause

Expand Down Expand Up @@ -85,21 +98,21 @@ Install and run the affected package's checks (monorepo uses pnpm + Nx):

```bash
# NOISY commands (installs, builds, test suites) MUST be redirected to a
# container-local file and tailed — streaming megabytes of live output
# container-local /temp file and tailed — streaming megabytes of live output
# through the session can kill it irrecoverably:
mkdir -p /workspace/temp
mkdir -p /temp
CI=1 pnpm install --frozen-lockfile --reporter=append-only \
> /workspace/temp/install.log 2>&1 || (tail -40 /workspace/temp/install.log; false)
tail -20 /workspace/temp/install.log
> /temp/install.log 2>&1 || (tail -40 /temp/install.log; false)
tail -20 /temp/install.log
# Prefer scoped/affected runs; fall back to package scripts.
pnpm -w exec oxfmt --check . || pnpm -w exec oxfmt --write .
pnpm -w exec oxlint . || true
# Run the relevant package's typecheck + tests, redirected the same way:
pnpm --filter <package> typecheck > /workspace/temp/typecheck.log 2>&1; tail -30 /workspace/temp/typecheck.log
pnpm --filter <package> test > /workspace/temp/test.log 2>&1; tail -40 /workspace/temp/test.log
pnpm --filter <package> typecheck > /temp/typecheck.log 2>&1; tail -30 /temp/typecheck.log
pnpm --filter <package> test > /temp/test.log 2>&1; tail -40 /temp/test.log
```

(`/workspace/temp` is container-local and never enters Agent DO storage.)
(`/temp` is outside the `/workspace` mount and is not synchronized.)

Record whether tests passed in `testsPassed`. If you cannot make tests pass and
the failure is your change's fault, fix it; if tests are unrelated/flaky, note
Expand Down Expand Up @@ -156,11 +169,13 @@ gh pr create --repo <repo> \
--base main \
--head "$BRANCH" \
--title "fix: <concise description> (#<issueNumber>)" \
--body-file /workspace/temp/pr-body.md
--body-file /temp/pr-body.md
```

Write the PR body outside the checkout at `/workspace/temp/pr-body.md`. It must include:
Write the PR body outside the checkout at `/temp/pr-body.md`. It must include:

- `Requested by @<requestedBy>` near the top, using the exact sanitized
`requested-by` mention from the run envelope (omit only when it is `unknown`).
- `Closes #<issueNumber>` so the issue auto-links.
- **What was wrong** (root cause, citing the file/line).
- **What changed** and why this is the minimal fix.
Expand Down
30 changes: 23 additions & 7 deletions agent-think/skills/reproduce/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,20 @@ name: reproduce
description: Reproduce a cloudflare/agents GitHub issue by scaffolding a minimal Agents/Worker project and deploying it to a temporary Cloudflare account, then report findings back on the issue.
---

The agent system prompt gives you `issueNumber`, `repo`, and the user's
instruction. Use those values directly; there is no separate arguments object.
The current user message contains an `<agent-think-run>` envelope with
`repository`, `issue`, `instruction`, `requested-by`, and (when available)
`trigger-comment-id`.
Use those values exactly. Never infer or substitute another target from examples,
workspace contents, GitHub searches, or concurrent issues. If the envelope or a
required field is absent, stop without cloning/editing/posting and return a
structured skipped result. When `trigger-comment-id` is present, your first
container action is the liveness reaction:

```bash
gh api repos/<repository>/issues/comments/<trigger-comment-id>/reactions \
-f content=rocket
```

Reproduce the bug end-to-end and post your findings as an issue comment.

The instruction is the free-form text the user typed after `@agent-think` (it
Expand Down Expand Up @@ -45,7 +57,8 @@ Read it carefully. Extract:
**Decide if it is reproducible at all.** If it is a feature request, a question,
a pure-docs issue, or has no concrete runnable behavior, stop here: return
`skipped: true`, `reproduced: false`, and a `summary` explaining why. Still post
a short, polite comment saying the repro-agent skipped it and why.
a short, polite comment saying the repro-agent skipped it and why; begin it with
`Requested by @<requestedBy>` when the run envelope has a requester.

## 2. Understand the relevant code

Expand All @@ -56,9 +69,10 @@ matters.

## 3. Scaffold a minimal reproduction

Work in a scratch dir under `/workspace`, never touch the checkout. The entire
workspace is container-local; `/workspace/temp` is available for logs and other
scratch files. The shell and `read`/`write`/`edit` tools see the same files.
Work in a scratch dir under `/workspace`, never touch the checkout. The
read/write/edit tools use the Workspace VFS, and container bash uses its mounted
view. Put long logs in `/temp`, which is outside the VFS mount and only visible
through container bash.

```bash
REPRO_DIR="/workspace/repro-<issueNumber>"
Expand Down Expand Up @@ -86,7 +100,7 @@ Every repro deploy MUST ship a minimal Vite + React page at the Worker's root UR
**Steps**

1. In `$REPRO_DIR`, create the 7 files below.
2. `mkdir -p /workspace/temp && npm install > /workspace/temp/install.log 2>&1; tail -15 /workspace/temp/install.log` (pin `agents` to the exact version under test if the bug is version-specific). Always redirect noisy commands to a container-local file like this — streaming megabytes of live output through the session can kill it.
2. `mkdir -p /temp && npm install > /temp/install.log 2>&1; tail -15 /temp/install.log` (pin `agents` to the exact version under test if the bug is version-specific). Always redirect noisy commands to a container-local `/temp` file like this — streaming megabytes of live output through the session can kill it.
3. Sanity-check the build before deploying: `npx vite build` (catches config errors cheaply; do NOT run `vite dev` — it blocks waiting for a browser).
4. Deploy per the **Deploy** step below (`vite build` first is mandatory; the build writes `dist/` plus a `.wrangler/deploy/config.json` redirect that `wrangler deploy` follows).
5. After deploy, confirm the root URL serves the page (the **Verify** step) and include the URL + click instructions in your report (the **Report back** step).
Expand Down Expand Up @@ -307,6 +321,8 @@ gh issue comment <issueNumber> --repo <repo> --body-file comment.md

The comment should contain:

- `Requested by @<requestedBy>` near the top, using the exact sanitized
`requested-by` mention from the run envelope (omit only when it is `unknown`).
- **Verdict**: reproduced / could not reproduce / skipped, with one-line reason.
- **Live URL** plus one line of click instructions ("open it, press _Trigger
bug_, watch the log") — the page is the demo. Phrase it exactly like:
Expand Down
Loading
Loading