From 09afca7a3e9df4b7040102fd1ecfee680ae4179b Mon Sep 17 00:00:00 2001 From: jbreite Date: Sun, 14 Jun 2026 20:26:18 -0400 Subject: [PATCH] Add Cloudflare Codemode support --- README.md | 49 +++ bun.lockb | Bin 87585 -> 87637 bytes docs/src/app/MobileNav.tsx | 1 + docs/src/app/SideNav.tsx | 11 + docs/src/app/api-reference/page.tsx | 7 + docs/src/app/codemode/page.tsx | 289 ++++++++++++++++ docs/src/app/components/NavIcons.tsx | 12 + package.json | 10 +- src/context/tool-guidance.ts | 4 + src/index.ts | 11 + src/tools/AGENTS.md | 7 + src/tools/codemode.ts | 264 +++++++++++++++ src/tools/index.ts | 52 +++ src/types.ts | 3 + tests/context/build-context.test.ts | 7 + tests/tools/codemode.test.ts | 479 +++++++++++++++++++++++++++ tests/tools/index.test.ts | 39 ++- 17 files changed, 1241 insertions(+), 4 deletions(-) create mode 100644 docs/src/app/codemode/page.tsx create mode 100644 src/tools/codemode.ts create mode 100644 tests/tools/codemode.test.ts diff --git a/README.md b/README.md index e5a8853..c45a9d5 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,7 @@ await sandbox.destroy(); | `AskUser` | Ask user clarifying questions | `askUser: true` | | `EnterPlanMode` | Enter planning/exploration mode | `planMode: true` | | `ExitPlanMode` | Exit planning mode with a plan | `planMode: true` | +| `codemode` | Write code to orchestrate selected tools via Cloudflare Codemode | `codemode: { executor }` | | `Skill` | Execute skills | `skill: { skills }` | | `WebSearch` | Search the web | `webSearch: { apiKey }` | | `WebFetch` | Fetch URL and process with AI | `webFetch: { apiKey, model }` | @@ -233,6 +234,10 @@ const { tools, planModeState } = createAgentTools(sandbox, { apiKey: process.env.PARALLEL_API_KEY, model: anthropic('claude-haiku-4'), }, + codemode: { + executor: new DynamicWorkerExecutor({ loader: env.LOADER }), + includeTools: ['Read', 'Glob', 'Grep'], // Opt into write tools explicitly + }, // Tool-specific config tools: { @@ -251,6 +256,49 @@ const { tools, planModeState } = createAgentTools(sandbox, { }); ``` +### Codemode + +BashKit can expose a Cloudflare Codemode tool so the model writes code that orchestrates BashKit tools instead of making many individual tool calls. Install `@cloudflare/codemode`, provide an executor, and enable `codemode`: + +Cloudflare Codemode currently targets AI SDK v6. BashKit's codemode adapter follows that path; AI SDK v5 support is intentionally not a compatibility goal for codemode. + +```typescript +import { DynamicWorkerExecutor } from '@cloudflare/codemode'; +import { createAgentTools, createPrepareStep } from 'bashkit'; +import { streamText } from 'ai'; + +const { tools, planModeState } = await createAgentTools(sandbox, { + planMode: true, + context: { executionPolicy: {} }, + codemode: { + executor: new DynamicWorkerExecutor({ loader: env.LOADER }), + includeTools: ['Read', 'Glob', 'Grep', 'Bash'], + tools: { + // Extra AI SDK tools exposed inside the default bashkit.* namespace + }, + providers: [ + { + name: 'repo', + tools: { + // Extra tools exposed as repo.* + }, + }, + ], + }, +}); + +await streamText({ + model, + tools, + messages, + prepareStep: createPrepareStep({ planModeState }), +}); +``` + +By default, generated code calls BashKit tools through BashKit's `bashkit.*` namespace, for example `await bashkit.Grep(...)`. Use `providers` when you want additional named tool groups such as `repo.SummarizeFile(...)`. + +Client-intervention tools are excluded from codemode automatically: `AskUser`, `EnterPlanMode`, `ExitPlanMode`, tools without `execute`, and tools with `needsApproval`. Top-level `includeTools` narrows the default `bashkit.*` namespace. Named providers can define their own `includeTools` or `excludeTools`. + ### Configuration Options #### Global Config @@ -1003,6 +1051,7 @@ Creates a set of agent tools bound to a sandbox instance. ### Optional Tools (also available via config) - `createAskUserTool(config?)` - Emit a deferred AskUser tool call for the client +- `createCodemodeTool(tools, config)` - Create a Cloudflare Codemode tool from a filtered tool set - `createEnterPlanModeTool(state)` - Enter planning/exploration mode - `createExitPlanModeTool(state, onPlanSubmit?)` - Exit planning mode with a plan - `createSkillTool(skills)` - Execute loaded skills diff --git a/bun.lockb b/bun.lockb index 97fe9cae2667967580009dcda380dec691563cd4..a2899032f750e9931c4ab75f1b21981eece3145a 100755 GIT binary patch delta 14011 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 diff --git a/docs/src/app/MobileNav.tsx b/docs/src/app/MobileNav.tsx index 9601b18..c607732 100644 --- a/docs/src/app/MobileNav.tsx +++ b/docs/src/app/MobileNav.tsx @@ -10,6 +10,7 @@ const links = [ { href: "/", label: "Overview" }, { href: "/getting-started", label: "Getting Started" }, { href: "/tools", label: "Tools" }, + { href: "/codemode", label: "Codemode" }, { href: "/sandboxes", label: "Sandboxes" }, { href: "/context", label: "Context" }, { href: "/api-reference", label: "API Reference" }, diff --git a/docs/src/app/SideNav.tsx b/docs/src/app/SideNav.tsx index 28a7807..4bdb61f 100644 --- a/docs/src/app/SideNav.tsx +++ b/docs/src/app/SideNav.tsx @@ -53,6 +53,17 @@ const links: { { id: "todowrite", text: "TodoWrite" }, ], }, + { + href: "/codemode", + label: "Codemode", + items: [ + { id: "overview", text: "Overview" }, + { id: "setup", text: "Setup" }, + { id: "batched-workflows", text: "Batched Workflows" }, + { id: "tool-selection", text: "Tool Selection" }, + { id: "policy", text: "Policy" }, + ], + }, { href: "/sandboxes", label: "Sandboxes", diff --git a/docs/src/app/api-reference/page.tsx b/docs/src/app/api-reference/page.tsx index 15cf511..f9e8cff 100644 --- a/docs/src/app/api-reference/page.tsx +++ b/docs/src/app/api-reference/page.tsx @@ -98,6 +98,13 @@ const { tools, budget } = await createAgentTools(sandbox, { Web search configuration. Presence enables WebSearch and WebFetch tools. + + Cloudflare Codemode adapter. Adds a single codemode{" "} + tool that can orchestrate selected executable tools. Excludes + client-intervention tools and tools with{" "} + needsApproval. Supports extra default-namespace tools + and named providers. + Enable tool result caching. Pass true for defaults or an object for fine-grained control. diff --git a/docs/src/app/codemode/page.tsx b/docs/src/app/codemode/page.tsx new file mode 100644 index 0000000..1a0e050 --- /dev/null +++ b/docs/src/app/codemode/page.tsx @@ -0,0 +1,289 @@ +"use client"; + +import { CodeBlock } from "../components/CodeBlock"; +import { Footer } from "../Footer"; + +export default function Codemode() { + return ( + <> +
+
+

Codemode

+

+ Let the model write code that orchestrates BashKit tools in batches. +

+
+ +
+

Overview

+

+ Codemode wraps selected BashKit tools behind one Cloudflare Codemode + tool. Instead of asking the model to call Glob, then{" "} + Grep, then Read one turn at a time, the + model can write a small JavaScript async arrow function that calls + those tools with loops, branches, and parallel work. +

+

+ BashKit does not run the code itself. It delegates to Cloudflare + Codemode's executor, while the code still calls BashKit's + policy-wrapped tools. That means context layers, plan-mode gates, + output policy, and sandbox restrictions keep applying. +

+
+ +
+

Setup

+

+ Install Cloudflare Codemode alongside BashKit, then provide an + executor through codemode config. +

+

+ Cloudflare Codemode currently targets AI SDK v6, so BashKit's + codemode adapter follows that path. +

+ + +
+ +
+

Batched Workflows

+

+ Codemode is useful when the model needs to fan out across files, + combine results, or retry/narrow a search. The generated code can + batch those steps into one tool call. +

+ { + const files = await bashkit.Glob({ + pattern: 'src/**/*.ts', + path: null, + }); + + const planModeMatches = await Promise.all( + files.matches.map((file) => + bashkit.Grep({ + pattern: 'PlanMode|planModeState|ExitPlanMode', + path: file, + glob: null, + type: null, + output_mode: 'content', + '-i': null, + '-n': true, + '-B': null, + '-A': null, + '-C': 2, + head_limit: 20, + offset: null, + multiline: null, + }), + ), + ); + + const interestingFiles = planModeMatches + .filter((result) => 'matches' in result && result.matches.length > 0) + .map((result) => result.matches[0].file); + + const snippets = await Promise.all( + interestingFiles.slice(0, 5).map((file_path) => + bashkit.Read({ + file_path, + offset: 1, + limit: 120, + }), + ), + ); + + return { + scanned: files.count, + matchedFiles: interestingFiles, + snippets, + }; +};`} + /> +

+ That would normally take many model/tool turns. With Codemode, the + model can express the workflow as code and return a structured + result. +

+
+ +
+

Tool Selection

+

+ Keep the inner tool set narrow. includeTools is the + safest default because generated code can loop and fan out calls. +

+ +

+ BashKit always excludes client-intervention tools from Codemode: + AskUser, EnterPlanMode,{" "} + ExitPlanMode, tools without an execute{" "} + function, and tools with needsApproval. +

+
+ +
+

Namespaces

+

+ The tool exposed to the model is named codemode by + default. Inside the generated JavaScript, selected BashKit tools are + exposed under BashKit's bashkit.* namespace. Tool + methods keep BashKit's public tool names, so the grep tool is{" "} + bashkit.Grep(...). +

+ { + const files = await bashkit.Glob({ + pattern: 'src/**/*.ts', + path: null, + }); + + return files.matches; + }\`, +});`} + /> +

+ Use providers when you want separate namespaces for + custom tool groups. Each provider gets its own object inside the + generated code, which keeps domain-specific helpers easier to scan. +

+ { + const todos = await bashkit.Grep({ + pattern: 'TODO|FIXME', + path: 'src', + glob: '*.ts', + type: null, + output_mode: 'content', + '-i': null, + '-n': true, + '-B': null, + '-A': null, + '-C': 2, + head_limit: 20, + offset: null, + multiline: null, + }); + + const issues = await github.ListIssues({ + labels: ['tech-debt'], + state: 'open', + }); + + return { todos, issues }; +};`} + /> +

+ Executable-only and needsApproval filtering applies to + every namespace. Top-level includeTools narrows the + default bashkit.* namespace; providers can define their + own includeTools or excludeTools. +

+
+ +
+

Policy

+

+ Codemode receives the same wrapped tools that normal model tool + calls receive. If plan mode is active, Bash,{" "} + Write, and Edit are still blocked by the + execution policy even when generated code calls them. +

+ +
+
+ +