test(good-fences): lent a mower, a Think agent mows (red)

The first end-to-end test: a Project Think agent, on the real model,
writes code that runs in a dynamic worker and drives a mower; the test
counts the cells cut, and saves the turn to itest-output/.

Installs @cloudflare/think, @cloudflare/codemode, agents, ai,
workers-ai-provider, zod. The model-test worker now has a main entry,
the Neighbor DO, and a LOADER binding.

Red: src/worker.ts doesn't exist yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
dckcandClaude Opus 5.5 committed 2026-10-09 00:31:25 -05:00
1 parent a2ca59a27e
commit d61cb8c9a1
5 files changed
+3071 -13

No files matched your search

+13
View File
@@ -0,0 +1,13 @@
/** @file A Think agent, lent a mower, mows: model, generated code, sandbox, mower. */
import { getAgentByName } from "agents";
import { env } from "cloudflare:workers";
import { expect, test } from "vitest";
test("lent a mower, the neighbor mows", async ({ annotate }) => {
const neighbor = await getAgentByName(env.Neighbor, "weekend");
const turn = await neighbor.runTurn({ input: "you can use this mower for the weekend" });
await annotate("the turn", { body: JSON.stringify(turn, null, 2), contentType: "application/json" });
const cells = await neighbor.cutCells();
expect(cells.length).toBeGreaterThan(10);
});
+1 -1
View File
@@ -5,7 +5,7 @@ import { mkdir, writeFile } from "node:fs/promises";
import type { Reporter } from "vitest/reporters"; import type { Reporter } from "vitest/reporters";
const outDir = new URL("../itest-output/", import.meta.url); const outDir = new URL("../itest-output/", import.meta.url);
const extFor: Record<string, string> = { "text/javascript": "js", "text/plain": "txt" }; const extFor: Record<string, string> = { "text/javascript": "js", "application/json": "json", "text/plain": "txt" };
const slug = (text: string) => text.replace(/[^\w]+/g, "-").replace(/^-|-$/g, ""); const slug = (text: string) => text.replace(/[^\w]+/g, "-").replace(/^-|-$/g, "");
export default class SaveAnnotations implements Reporter { export default class SaveAnnotations implements Reporter {
+7 -1
View File
@@ -8,7 +8,13 @@
"types": "wrangler types -c wrangler.model-tests.jsonc" "types": "wrangler types -c wrangler.model-tests.jsonc"
}, },
"dependencies": { "dependencies": {
"ses": "^1.14.0" "@cloudflare/codemode": "0.5.3",
"@cloudflare/think": "0.20.1",
"agents": "0.27.0",
"ai": "7.0.136",
"ses": "^1.14.0",
"workers-ai-provider": "4.0.0",
"zod": "4.6.5"
}, },
"devDependencies": { "devDependencies": {
"@cloudflare/vitest-plugin": "1.3.6", "@cloudflare/vitest-plugin": "1.3.6",
+3040 -10
View File
File diff suppressed because it is too large. Load diff
+10 -1
View File
@@ -2,6 +2,15 @@
"$schema": "node_modules/wrangler/config-schema.json", "$schema": "node_modules/wrangler/config-schema.json",
// model integration tests: AI always runs remotely, and costs money // model integration tests: AI always runs remotely, and costs money
"name": "good-fences-model-tests", "name": "good-fences-model-tests",
"main": "./src/worker.ts",
"compatibility_date": "2026-10-01", "compatibility_date": "2026-10-01",
"ai": { "binding": "AI", "remote": true } "compatibility_flags": ["nodejs_compat"],
"ai": { "binding": "AI", "remote": true },
"worker_loaders": [{ "binding": "LOADER" }],
"durable_objects": {
"bindings": [{ "name": "Neighbor", "class_name": "Neighbor" }]
},
"exports": {
"Neighbor": { "type": "durable-object", "storage": "sqlite" }
}
} }