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 .changeset/brave-think-framework.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
"@cloudflare/think": minor
"@cloudflare/think": patch
"agents": patch
"@cloudflare/worker-bundler": patch
---
Expand Down
5 changes: 5 additions & 0 deletions .changeset/create-think-and-starters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudflare/think": patch
---

Add a `--template` flag to `think init` and a programmatic `@cloudflare/think/cli` entry point. `think init` now scaffolds from the repo's starter templates (locally, or via an injected fetcher) instead of generating a single inline app. This is what powers the new `create-think` package.
5 changes: 5 additions & 0 deletions .changeset/create-think-new-package.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-think": patch
---

New package. Scaffold a Cloudflare Think agent with `npm create think` (also `pnpm`/`yarn`/`bun create think`). Ships four starters — `basic`, `personal-assistant`, `coding-agent`, and `customer-support` — each a complete, deployable Workers app.
2 changes: 1 addition & 1 deletion .changeset/skills-precompile-stub-worker-bundler.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
"agents": minor
"agents": patch
---

Compile skill scripts ahead of time and remove the in-Worker bundler (drops ~14MB of `esbuild-wasm` from Worker bundles).
Expand Down
52 changes: 52 additions & 0 deletions packages/create-think/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# create-think

Scaffold a new [Cloudflare Think](https://www.npmjs.com/package/@cloudflare/think)
agent in seconds.

```sh
npm create think@latest
# or
pnpm create think
yarn create think
bun create think
```

## Usage

```sh
npm create think@latest [directory] -- [options]
```

| Option | Description |
| ---------------- | ------------------------------------------------- |
| `--template, -t` | Starter template (see below). Defaults to `basic` |
| `--name` | Package and Worker name |
| `--ref` | Git ref to fetch templates from |
| `--yes, -y` | Skip prompts and use defaults |
| `--no-install` | Skip `npm install` |
| `--dry-run` | Print what would be created without writing |

## Templates

| Template | Description |
| -------------------- | ---------------------------------------------------------- |
| `basic` | Minimal Think chat agent with a small React chat UI |
| `personal-assistant` | Persistent memory (`configureSession`) and scheduled tasks |
| `coding-agent` | Workspace file tools and a coding skill |
| `customer-support` | Custom tools and an escalation skill |

```sh
npm create think@latest my-agent -- --template coding-agent
```

## What you get

Each starter is a complete, deployable Cloudflare Workers app using the Think
framework: a streaming chat agent, persistent history, resumable streams, and
built-in workspace file tools, wired up with Vite and Wrangler.

```sh
cd my-agent
npm run dev # local dev
npm run deploy # deploy to Cloudflare
```
45 changes: 45 additions & 0 deletions packages/create-think/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "create-think",
"description": "Scaffold a new Cloudflare Think agent — npm create think",
"version": "0.0.1",
"type": "module",
"license": "MIT",
"author": "Cloudflare Inc.",
"keywords": [
"cloudflare",
"agents",
"think",
"ai",
"create",
"starter"
],
"repository": {
"directory": "packages/create-think",
"type": "git",
"url": "git+https://github.com/cloudflare/agents.git"
},
"bugs": {
"url": "https://github.com/cloudflare/agents/issues"
},
"bin": {
"create-think": "dist/index.js"
},
"files": [
"dist",
"README.md"
],
"publishConfig": {
"access": "public"
},
"dependencies": {
"@cloudflare/think": "workspace:*",
"tiged": "^2.12.7",
"yargs": "^18.0.0"
},
"devDependencies": {
"@types/yargs": "^17.0.35"
},
"scripts": {
"build": "tsx ./scripts/build.ts"
}
}
27 changes: 27 additions & 0 deletions packages/create-think/scripts/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { build } from "tsdown";
import { formatDeclarationFiles } from "../../../scripts/format-declarations";

async function main() {
await build({
clean: true,
dts: true,
entry: ["src/index.ts"],
deps: {
skipNodeModulesBundle: true
},
format: "esm",
sourcemap: true,
fixedExtension: false
});

// then run oxfmt on the generated .d.ts files
formatDeclarationFiles();

process.exit(0);
}

main().catch((err) => {
// Build failures should fail
console.error(err);
process.exit(1);
});
82 changes: 82 additions & 0 deletions packages/create-think/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env node
import {
initCommand,
THINK_TEMPLATES,
THINK_TEMPLATES_REPO,
type TemplateFetchRequest
} from "@cloudflare/think/cli";
import tiged from "tiged";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";

/**
* Remote template fetcher. Pulls a starter folder out of the agents repo with
* degit (tiged). `create-think` injects this so it can scaffold from the
* published templates when no local copy is available.
*/
async function fetchTemplate({
template,
ref,
dest
}: TemplateFetchRequest): Promise<void> {
const source = `${THINK_TEMPLATES_REPO}/${template}#${ref}`;
const emitter = tiged(source, { disableCache: true, mode: "tar" });
await emitter.clone(dest);
}

async function main(): Promise<void> {
const templateList = THINK_TEMPLATES.map((t) => t.name).join(", ");
const args = await yargs(hideBin(process.argv))
.scriptName("create-think")
.usage("$0 [directory] [options]")
.option("template", {
alias: "t",
type: "string",
describe: `Starter template (${templateList})`
})
.option("name", {
type: "string",
describe: "Package and Worker name for the generated app"
})
.option("ref", {
type: "string",
describe: "Git ref to fetch templates from",
default: "main"
})
.option("install", {
type: "boolean",
describe: "Run npm install after scaffolding",
default: true
})
.option("yes", {
alias: "y",
type: "boolean",
describe: "Use defaults and skip prompts",
default: false
})
.option("dry-run", {
type: "boolean",
describe: "Show what would be created without writing files",
default: false
})
.help()
.parse();

const directory = args._[0] != null ? String(args._[0]) : undefined;

await initCommand({
directory,
template: args.template,
name: args.name,
ref: args.ref,
yes: args.yes,
install: args.install,
dryRun: args.dryRun,
fetchTemplate
});
}

main().catch((error: unknown) => {
console.error(error instanceof Error ? error.message : error);
process.exit(1);
});
14 changes: 14 additions & 0 deletions packages/create-think/src/tiged.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Minimal type declaration for `tiged` (the maintained degit fork), which
// ships no types. We only use the default factory and `clone`.
declare module "tiged" {
interface TigedOptions {
disableCache?: boolean;
mode?: "tar" | "git";
force?: boolean;
verbose?: boolean;
}
interface TigedEmitter {
clone(dest: string): Promise<void>;
}
export default function tiged(src: string, opts?: TigedOptions): TigedEmitter;
}
3 changes: 3 additions & 0 deletions packages/create-think/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "agents/tsconfig"
}
4 changes: 4 additions & 0 deletions packages/think/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@
"./vite": {
"types": "./dist/vite.d.ts",
"import": "./dist/vite.js"
},
"./cli": {
"types": "./dist/cli.d.ts",
"import": "./dist/cli.js"
}
},
"files": [
Expand Down
1 change: 1 addition & 0 deletions packages/think/scripts/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ async function main() {
"src/tools/browser.ts",
"src/tools/sandbox.ts",
"src/cli/index.ts",
"src/cli.ts",
"src/vite.ts"
],
deps: {
Expand Down
Loading
Loading