Skip to content

Commit 7c637d3

Browse files
docs(cookbook): Cookbook section + Daytona recipe + skill (OSS-222) (CopilotKit#5087)
## Summary - New top-level **Cookbook** docs section with a small landing page, added both as a top-level nav tab (next to Learn) and as a sidebar section under Documentation. First recipe wires CopilotKit's Built-in Agent up with a `runCode` server tool that executes Python, TypeScript, or JavaScript in an isolated [Daytona](https://www.daytona.io) sandbox and returns stdout to chat. - New **`copilotkit-daytona` Agent Skill** (`skills/copilotkit-daytona/`) — `SKILL.md` + `assets/` + `references/` + `eval.yaml` + a workspace fixture, mirroring `skills/copilotkit-setup`. The skill's reference doc deliberately points at Daytona's maintained sources (`llms.txt`, the dashboard limits page, the official `daytona` Agent Skill, and the Daytona MCP server) rather than duplicating a hand-copied SDK surface that would rot. - Fixes a stale `learn/meta.json` link that pointed at `../direct-to-llm/cookbook/state-machine` (target no longer exists). Closes OSS-222. ## Test plan - [x] `next build` compiles `/cookbook` and `/cookbook/daytona` as static routes; OG images emit for both. - [x] Broken-link checker shows no new broken links relative to `main`. - [x] Cookbook appears as a top-level nav tab next to Learn, and as a section in the Documentation sidebar. - [x] Recipe code validated end-to-end on a deployed Railway app against published `@copilotkit/runtime@1.58.0`: agent invokes `runCode`, a real Daytona sandbox executes both Python and JavaScript snippets, output round-trips through the chat (unique-token proof). ## Notes (out of scope, separate follow-ups) - The Built-in Agent **quickstart** doc shows a v1 `<CopilotKit>` provider mixed with v2 `<CopilotSidebar>`; the v2 demos use the all-v2 stack (`CopilotKitProvider` + `useSingleEndpoint` + `createCopilotEndpointSingleRoute`). Worth a doc reconciliation in a separate PR. - The Vercel AI SDK emits *"System messages in the prompt or messages fields…"* when the agent runs — it originates inside `BuiltInAgent`'s call construction (passes system content via `messages` rather than the SDK's `system` option). Benign, but a CopilotKit runtime improvement worth filing separately. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
2 parents 3dc9bea + 447e9d8 commit 7c637d3

16 files changed

Lines changed: 20816 additions & 3 deletions

File tree

.github/config-allowlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ examples/showcases/banking/next.config.mjs
3434
examples/showcases/chatkit-studio/apps/playground/next.config.ts
3535
examples/showcases/chatkit-studio/apps/studio/next.config.ts
3636
examples/showcases/chatkit-studio/apps/world/next.config.ts
37+
examples/showcases/daytona-runcode/next.config.ts
3738
examples/showcases/deep-agents-finance-erp/next.config.ts
3839
examples/showcases/deep-agents-job-search/next.config.ts
3940
examples/showcases/deep-agents/next.config.ts
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules
2+
.next
3+
.env
4+
.env.local
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# CopilotKit × Daytona — `runCode` showcase
2+
3+
The deployable demo behind the [Daytona cookbook recipe](../../../showcase/shell-docs/src/content/docs/cookbook/daytona.mdx).
4+
A minimal CopilotKit **Built-in Agent** app whose only added capability is a `runCode` server tool that executes
5+
Python / TypeScript / JavaScript inside an isolated [Daytona](https://www.daytona.io) sandbox and streams the
6+
result back to the chat — with a custom `useRenderTool` card (fixed-height streaming code pane with
7+
syntax highlighting and a fixed-height result pane).
8+
9+
## What's inside
10+
11+
- `app/api/copilotkit-single/route.ts` — the recipe's `runCode` tool wired into a `BuiltInAgent` on
12+
`createCopilotEndpointSingleRoute`. Pure recipe code (Python/TS/JS via `daytona.create({ language })`).
13+
- `app/page.tsx``CopilotKitProvider` + `CopilotSidebar` + a `useRenderTool({ name: "runCode" })`
14+
renderer using `react-syntax-highlighter` (Prism + `vscDarkPlus`, mirroring
15+
`@copilotkit/react-ui`'s own `CodeBlock`).
16+
- A system prompt that tells the agent the tool result is rendered directly to the user, so it
17+
doesn't restate stdout in chat text.
18+
19+
## Prerequisites
20+
21+
- Node 18+
22+
- An OpenAI API key (`OPENAI_API_KEY`) — the recipe defaults to `openai:gpt-5.4-mini`, overridable via
23+
the `MODEL` env var.
24+
- A Daytona API key (`DAYTONA_API_KEY`) — create one in the
25+
[Daytona dashboard](https://app.daytona.io/dashboard/keys).
26+
27+
## Run locally
28+
29+
```bash
30+
npm install
31+
echo "OPENAI_API_KEY=sk-…" > .env.local
32+
echo "DAYTONA_API_KEY=…" >> .env.local
33+
npm run dev # http://localhost:3000
34+
```
35+
36+
Open the page, click into the sidebar chat, and ask something like:
37+
38+
> Run a Python snippet that prints the first 10 Fibonacci numbers.
39+
40+
> Run JavaScript that logs Date.now().
41+
42+
## Notes
43+
44+
- This is a **standalone npm project** — intentionally not in the monorepo's `pnpm-workspace.yaml`.
45+
`npm install` here installs against published `@copilotkit/*@1.58.0`, which is the same surface the
46+
recipe targets.
47+
- `new Daytona()` throws at module load if `DAYTONA_API_KEY` is missing, so the app won't boot without
48+
it. That's by design — the key is required, not optional.
49+
- For arbitrary languages beyond Python/TS/JS, swap `sandbox.process.codeRun` for
50+
`sandbox.process.executeCommand(...)` and optionally use a custom Daytona `Image` with the toolchain
51+
preinstalled. See the recipe's _Going further_ section.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import {
2+
CopilotRuntime,
3+
InMemoryAgentRunner,
4+
createCopilotEndpointSingleRoute,
5+
BuiltInAgent,
6+
defineTool,
7+
} from "@copilotkit/runtime/v2";
8+
import { Daytona } from "@daytonaio/sdk";
9+
import { handle } from "hono/vercel";
10+
import { z } from "zod";
11+
12+
// --- The cookbook recipe: a server tool that runs code in a Daytona sandbox ---
13+
const daytona = new Daytona(); // reads DAYTONA_API_KEY
14+
15+
const runCode = defineTool({
16+
name: "runCode",
17+
description:
18+
"Execute code in an isolated Daytona sandbox and return its output.",
19+
parameters: z.object({
20+
code: z.string().describe("The code to run in the sandbox"),
21+
language: z
22+
.enum(["python", "typescript", "javascript"])
23+
.default("python")
24+
.describe("Language runtime for the code"),
25+
}),
26+
execute: async ({ code, language }) => {
27+
const sandbox = await daytona.create({ language });
28+
try {
29+
const res = await sandbox.process.codeRun(code);
30+
return { stdout: res.result, exitCode: res.exitCode };
31+
} finally {
32+
await sandbox.delete();
33+
}
34+
},
35+
});
36+
37+
const agent = new BuiltInAgent({
38+
model: process.env.MODEL ?? "openai:gpt-5.4-mini",
39+
prompt:
40+
"You are a coding assistant. When the user asks you to run, execute, or compute " +
41+
"something with code, use the runCode tool to run it in a Daytona sandbox. " +
42+
"Default to Python unless told otherwise. " +
43+
"IMPORTANT: the tool's output (stdout + exit code) is rendered directly to the user " +
44+
"in a separate UI panel; the user can already see it. Do NOT repeat, restate, or " +
45+
"include the stdout or the generated code in your reply. Acknowledge briefly (a single " +
46+
"short sentence) or stay silent. Never reproduce content that already appears in the " +
47+
"tool card.",
48+
tools: [runCode],
49+
maxSteps: 2,
50+
});
51+
52+
const runtime = new CopilotRuntime({
53+
agents: { default: agent },
54+
runner: new InMemoryAgentRunner(),
55+
});
56+
57+
const app = createCopilotEndpointSingleRoute({
58+
runtime,
59+
basePath: "/api/copilotkit-single",
60+
});
61+
62+
export const POST = handle(app);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { ReactNode } from "react";
2+
import "@copilotkit/react-core/v2/styles.css";
3+
4+
export const metadata = {
5+
title: "CopilotKit × Daytona",
6+
description: "A built-in agent that runs code in Daytona sandboxes.",
7+
};
8+
9+
export default function RootLayout({ children }: { children: ReactNode }) {
10+
return (
11+
<html lang="en">
12+
<body style={{ margin: 0 }}>{children}</body>
13+
</html>
14+
);
15+
}

0 commit comments

Comments
 (0)