chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
This commit is contained in:
31
third_party/pi/packages/codemode/examples/cloudflare/README.md
vendored
Normal file
31
third_party/pi/packages/codemode/examples/cloudflare/README.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# pi-codemode on Cloudflare
|
||||
|
||||
This example has two Workers:
|
||||
|
||||
- **`sandbox/`** deploys `CodemodeSandboxDurableObject` as its own Worker, `pi-codemode-sandbox`.
|
||||
Scripts run there, in a separate isolate.
|
||||
- **`agent/`** has a `Session` Durable Object that owns the tools. It runs scripts through
|
||||
`RemoteCodemodeSandbox`, which keeps the tools and results in `Session` while the sandbox Worker
|
||||
runs the VM.
|
||||
|
||||
The [README of the package](../../README.md#usage-on-cloudflare-workers) explains why the
|
||||
sandbox must be a separate Worker, and which limits apply.
|
||||
|
||||
## Try it locally
|
||||
|
||||
Install `@earendil-works/pi-codemode` and `wrangler` in each directory, then start both Workers in
|
||||
one process:
|
||||
|
||||
```sh
|
||||
npx wrangler dev -c agent/wrangler.jsonc -c sandbox/wrangler.jsonc
|
||||
curl -X POST http://localhost:8787 --data 'const n = await tools.count({ add: 2 }); text("n=" + n); return n'
|
||||
```
|
||||
|
||||
## Deploy
|
||||
|
||||
Deploy the sandbox first, because the agent's binding refers to it by name:
|
||||
|
||||
```sh
|
||||
(cd sandbox && npx wrangler deploy)
|
||||
(cd agent && npx wrangler deploy)
|
||||
```
|
||||
50
third_party/pi/packages/codemode/examples/cloudflare/agent/src/index.ts
vendored
Normal file
50
third_party/pi/packages/codemode/examples/cloudflare/agent/src/index.ts
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// A Worker whose Durable Object runs codemode the way an agent session would: tools run here, in the
|
||||
// session object, and scripts run in the separately deployed pi-codemode-sandbox Worker.
|
||||
//
|
||||
// curl -X POST http://localhost:8787 --data 'const n = await tools.count({ add: 2 }); text("n=" + n); return n'
|
||||
import type { CodemodeSandboxDurableObject } from "@earendil-works/pi-codemode/cloudflare";
|
||||
// The portable entry has no QuickJS module: the WebAssembly lives only in the sandbox Worker.
|
||||
import { type CodemodeTool, RemoteCodemodeSandbox } from "@earendil-works/pi-codemode/portable";
|
||||
import { DurableObject } from "cloudflare:workers";
|
||||
|
||||
interface Env {
|
||||
SESSION: DurableObjectNamespace<Session>;
|
||||
CODEMODE_SANDBOX: DurableObjectNamespace<CodemodeSandboxDurableObject>;
|
||||
}
|
||||
|
||||
export class Session extends DurableObject<Env> {
|
||||
private counter = 0;
|
||||
|
||||
async runCodemode(code: string) {
|
||||
const tools: CodemodeTool[] = [
|
||||
{
|
||||
name: "count",
|
||||
description: "Adds to a counter kept in the session and returns the new value",
|
||||
execute: (args) => {
|
||||
this.counter += (args as { add: number }).add;
|
||||
return this.counter;
|
||||
},
|
||||
},
|
||||
];
|
||||
// Before: new CodemodeSandbox({ tools, timeoutMs: 60_000 })
|
||||
const sandbox = new RemoteCodemodeSandbox({
|
||||
tools,
|
||||
timeoutMs: 60_000,
|
||||
// One sandbox instance per session keeps a session's scripts together and apart from others.
|
||||
remote: () => this.env.CODEMODE_SANDBOX.getByName(this.ctx.id.toString()),
|
||||
});
|
||||
try {
|
||||
return await sandbox.execute(code);
|
||||
} finally {
|
||||
await sandbox.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
async fetch(request, env) {
|
||||
if (request.method !== "POST") return new Response("POST a script\n", { status: 405 });
|
||||
const result = await env.SESSION.getByName("demo").runCodemode(await request.text());
|
||||
return Response.json(result);
|
||||
},
|
||||
} satisfies ExportedHandler<Env>;
|
||||
15
third_party/pi/packages/codemode/examples/cloudflare/agent/wrangler.jsonc
vendored
Normal file
15
third_party/pi/packages/codemode/examples/cloudflare/agent/wrangler.jsonc
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "node_modules/wrangler/config-schema.json",
|
||||
"name": "pi-codemode-agent-example",
|
||||
"main": "src/index.ts",
|
||||
"compatibility_date": "2026-04-22",
|
||||
"durable_objects": {
|
||||
"bindings": [
|
||||
{ "name": "SESSION", "class_name": "Session" },
|
||||
// The sandbox class lives in its own Worker. `script_name` is what puts scripts in a different
|
||||
// isolate; binding a class exported from this Worker would run them on the session's thread.
|
||||
{ "name": "CODEMODE_SANDBOX", "class_name": "CodemodeSandbox", "script_name": "pi-codemode-sandbox" }
|
||||
]
|
||||
},
|
||||
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["Session"] }]
|
||||
}
|
||||
7
third_party/pi/packages/codemode/examples/cloudflare/sandbox/src/index.ts
vendored
Normal file
7
third_party/pi/packages/codemode/examples/cloudflare/sandbox/src/index.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// The whole sandbox Worker: one Durable Object class that runs codemode scripts for callers bound to
|
||||
// it. Only Workers with a binding can reach the class; HTTP requests get a 404.
|
||||
export { CodemodeSandboxDurableObject as CodemodeSandbox } from "@earendil-works/pi-codemode/cloudflare";
|
||||
|
||||
export default {
|
||||
fetch: () => new Response("Not found", { status: 404 }),
|
||||
};
|
||||
13
third_party/pi/packages/codemode/examples/cloudflare/sandbox/wrangler.jsonc
vendored
Normal file
13
third_party/pi/packages/codemode/examples/cloudflare/sandbox/wrangler.jsonc
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "node_modules/wrangler/config-schema.json",
|
||||
"name": "pi-codemode-sandbox",
|
||||
"main": "src/index.ts",
|
||||
"compatibility_date": "2026-04-22",
|
||||
// Reached only through Durable Object bindings, never over HTTP.
|
||||
"workers_dev": false,
|
||||
"preview_urls": false,
|
||||
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["CodemodeSandbox"] }],
|
||||
// Optional. The default is 30 seconds of CPU per request; one execution is one request. Keep it above
|
||||
// the time the interrupt budget allows, so scripts fail with a timeout instead of resetting the object.
|
||||
"limits": { "cpu_ms": 60000 }
|
||||
}
|
||||
Reference in New Issue
Block a user