🏖️ SandAgent

Quick Start

Get SandAgent running in your app in 5 minutes

Install

npm install @sandagent/sdk ai

Backend — API Route (Next.js)

Create app/api/ai/route.ts:

import { createSandAgent, LocalSandbox } from "@sandagent/sdk";
import {
  convertToModelMessages,
  createUIMessageStream,
  createUIMessageStreamResponse,
  streamText,
} from "ai";

export async function POST(request: Request) {
  const { messages } = await request.json();

  const sandbox = new LocalSandbox({
    workdir: process.cwd(),
    templatesPath: process.cwd(),
    runnerCommand: ["npx", "-y", "@sandagent/runner-cli@latest", "run"],
    env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
  });

  const sandagent = createSandAgent({
    sandbox,
    cwd: sandbox.getWorkdir(),
  });

  const stream = createUIMessageStream({
    execute: async ({ writer }) => {
      const result = streamText({
        model: sandagent("sonnet"),
        messages: await convertToModelMessages(messages),
        abortSignal: request.signal,
      });
      writer.merge(result.toUIMessageStream());
    },
  });

  return createUIMessageStreamResponse({ stream });
}

Frontend — Chat UI

Create app/page.tsx:

"use client";
import { useSandAgentChat } from "@sandagent/sdk/react";
import { useState } from "react";

export default function Chat() {
  const [input, setInput] = useState("");
  const { messages, isLoading, sendMessage } = useSandAgentChat({
    apiEndpoint: "/api/ai",
  });

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (!input.trim()) return;
    sendMessage(input);
    setInput("");
  };

  return (
    <div className="h-screen flex flex-col">
      <div className="flex-1 overflow-y-auto p-4 space-y-4">
        {messages.map((m) => (
          <div key={m.id} className={m.role === "user" ? "text-right" : ""}>
            <div className={`inline-block p-3 rounded-lg ${
              m.role === "user" ? "bg-blue-500 text-white" : "bg-gray-100"
            }`}>
              {m.parts.map((p, i) => p.type === "text" && <span key={i}>{p.text}</span>)}
            </div>
          </div>
        ))}
        {isLoading && <div className="text-gray-500">Thinking...</div>}
      </div>
      <form onSubmit={handleSubmit} className="p-4 border-t flex gap-2">
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="Ask anything…"
          className="flex-1 px-4 py-2 border rounded-lg"
        />
        <button type="submit" disabled={isLoading} className="px-4 py-2 bg-blue-500 text-white rounded-lg">
          Send
        </button>
      </form>
    </div>
  );
}

Environment Variables

export ANTHROPIC_API_KEY=sk-ant-xxx

For AWS Bedrock:

export AWS_BEARER_TOKEN_BEDROCK=xxx

Run

npm run dev

Open http://localhost:3000 — you now have a full Coding Agent streaming into your app.

Other Frameworks

The same core logic works for Express, Fastify, Koa, etc.:

import { createSandAgent, LocalSandbox } from "@sandagent/sdk";
import { streamText } from "ai";

const sandbox = new LocalSandbox({
  workdir: process.cwd(),
  templatesPath: process.cwd(),
  runnerCommand: ["npx", "-y", "@sandagent/runner-cli@latest", "run"],
  env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});

const sandagent = createSandAgent({ sandbox, cwd: sandbox.getWorkdir() });

const result = streamText({
  model: sandagent("sonnet"),
  messages,
});

Next Steps

On this page