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
18 changes: 9 additions & 9 deletions packages/agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ client‑side loop without re‑implementing the loop.

## Agent vs. provider — which package?

| | `@coder/ai-sdk-agent` (this package) | [`@coder/ai-sdk-provider`](../provider) |
| | `@coder/ai-sdk-agent` (this package) | [`@coder/ai-sdk-provider`](https://github.com/coder/ai-sdk/tree/main/packages/provider) |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| What runs | Coder's server‑side agent: tool loop, built‑in tools, MCP servers, workspace‑scoped file/shell tools, sub‑agents, and compaction, on the deployment | Plain model calls through Coder's AI Gateway. A normal AI SDK provider: `generateText`, `streamText`, `generateObject` |
| Server state | Each `CoderAgent` is one server chat ("session"), bound to at most one workspace | No chat, no workspace; natively cancelable |
Expand Down Expand Up @@ -91,7 +91,7 @@ the rest of the AI SDK.

## Examples

Runnable scripts in [`examples/`](./examples) run against a real deployment via
Runnable scripts in [`examples/`](https://github.com/coder/ai-sdk/tree/main/packages/agent/examples) run against a real deployment via
`tsx`:

```bash
Expand All @@ -107,7 +107,7 @@ pnpm example:structured # typed structured output via the structured_output to
```

Each example creates a new chat and archives it when done; none touches
workspaces. Details: [`examples/README.md`](./examples/README.md).
workspaces. Details: [`examples/README.md`](https://github.com/coder/ai-sdk/blob/main/packages/agent/examples/README.md).

## Custom tools

Expand Down Expand Up @@ -200,7 +200,7 @@ This needs a `workspaceFiles` adapter. The agent core stays dependency‑free, s
whoever holds a workspace connection supplies a few‑line adapter:

```ts
const agent = new CoderAgent({ /* … */ workspaceId: ws.id, workspaceFiles });
const agent = new CoderAgent({ organizationId, workspaceId: ws.id, workspaceFiles });
const { path } = await agent.uploadToWorkspace({
content: await openAsBlob("assets.zip"),
path: "assets.zip",
Expand All @@ -215,7 +215,7 @@ constrain what the model **says** to a JSON schema. A `responseFormat` /
`experimental_output` request emits a warning and is best‑effort at most.

- **Pure text‑in / JSON‑out, no server‑side tools** → use
[`@coder/ai-sdk-provider`](../provider) with `generateObject` /
[`@coder/ai-sdk-provider`](https://github.com/coder/ai-sdk/tree/main/packages/provider) with `generateObject` /
`Output.object` (schema‑constrained; requires AI Gateway on the deployment).
- **The answer must come out of an agent run** (server‑side tools, MCP, a
workspace) → have the model submit its answer by _calling a tool_ whose
Expand All @@ -224,7 +224,7 @@ constrain what the model **says** to a JSON schema. A `responseFormat` /

The tool pattern needs four rules to stay robust (validate client‑side, never
stop on the call, and more). Guide: [docs/structured-output.md](./docs/structured-output.md).
Copyable helper: [`examples/06-structured-output.ts`](./examples/06-structured-output.ts).
Copyable helper: [`examples/06-structured-output.ts`](https://github.com/coder/ai-sdk/blob/main/packages/agent/examples/06-structured-output.ts).

## Sessions

Expand Down Expand Up @@ -423,7 +423,7 @@ const agent = new CoderAgent({ client, organizationId });
| `planMode` | enable plan mode (`"plan"`) |
| `stopWhen` | AI SDK stop condition(s); default `stepCountIs(64)` |
| `maxRetries` | default `0` — SDK retries can duplicate server‑side turns; override with care |
| `requestTimeoutMs` | per‑turn time budget (ms); interrupts the run and rejects (`kind: "timeout"`) instead of hanging |
| `requestTimeoutMs` | per‑segment time budget (ms), not per call; interrupts the run and rejects (`kind: "timeout"`) instead of hanging |
| `onTransportEvent` | observability hook for typed transport events (see [Observability](#observability)) |
| `settleDeadlineMs` | overall deadline for bounded cleanup (`archive()` 409 retries, disposal); default 15 000 |
| `settleRetryDelayMs` | pause between `archive()` retries while the chat settles; default 1000 |
Expand Down Expand Up @@ -545,7 +545,7 @@ and the call rejects with a retryable `CoderChatError` (`kind: "timeout"`)
instead of hanging:

```ts
const agent = new CoderAgent({ /* … */ requestTimeoutMs: 120_000 });
const agent = new CoderAgent({ organizationId, requestTimeoutMs: 120_000 });
```

A segment is one model round‑trip, until it settles or pauses for a client tool.
Expand Down Expand Up @@ -637,7 +637,7 @@ The agent is an **async disposable**, so cleanup can ride scope exit instead of
`finally` you have to remember:

```ts
await using agent = new CoderAgent({/* … */});
await using agent = new CoderAgent({ organizationId });
const { text } = await agent.generate({ prompt: "…" });
// agent.interrupt() + agent.archive() run automatically when the scope exits.
```
Expand Down
7 changes: 5 additions & 2 deletions packages/agent/docs/durable-workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,10 @@ const chargeCard = (chatId: () => string) =>
// checker — defer it through a box assigned right after.
let self: { chatId?: string } | undefined;
const agent = new CoderAgent({
/* …base options as in runTurn… */
baseUrl: process.env.CODER_URL!,
token: process.env.CODER_SESSION_TOKEN!,
organizationId: process.env.CODER_ORG_ID!,
// …plus chatId, requestTimeoutMs, etc. as in runTurn
tools: { charge_card: chargeCard(() => self!.chatId!) },
});
self = agent;
Expand Down Expand Up @@ -882,6 +885,6 @@ for (const call of filed.reverse()) {
[Workspaces & quota](./workspaces-and-quota.md).
- Steps that don't need server‑side tools (plan / extract / synthesize) are
cheaper and natively structured through
[`@coder/ai-sdk-provider`](../../provider) + `generateObject` — no chat, no
[`@coder/ai-sdk-provider`](https://github.com/coder/ai-sdk/tree/main/packages/provider) + `generateObject` — no chat, no
workspace, no cleanup.
- Archive in the final step / failure handler — never per step.
12 changes: 6 additions & 6 deletions packages/agent/docs/structured-output.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ what the model **says** to a JSON schema: a `responseFormat` /

Pick by what the step needs:

| The step… | Use |
| ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| is pure text‑in / JSON‑out, with no server‑side tools | [`@coder/ai-sdk-provider`](../../provider) with `generateObject` / `Output.object` — schema‑constrained; requires AI Gateway on the deployment |
| must produce its answer from an agent run (server‑side tools, MCP, a workspace) | the **`structured_output` tool pattern** below |
| The step… | Use |
| ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| is pure text‑in / JSON‑out, with no server‑side tools | [`@coder/ai-sdk-provider`](https://github.com/coder/ai-sdk/tree/main/packages/provider) with `generateObject` / `Output.object` — schema‑constrained; requires AI Gateway on the deployment |
| must produce its answer from an agent run (server‑side tools, MCP, a workspace) | the **`structured_output` tool pattern** below |

## The `structured_output` tool pattern

Expand All @@ -26,7 +26,7 @@ import { z } from "zod";
const Answer = z.object({ severity: z.enum(["critical", "major", "minor"]), summary: z.string() });

const agent = new CoderAgent({
/* … */
organizationId: "your-org-uuid", // connection defaults to CODER_URL + CODER_SESSION_TOKEN
instructions: "… Submit your final answer by calling the structured_output tool exactly once.",
tools: {
structured_output: tool({
Expand Down Expand Up @@ -122,7 +122,7 @@ under a short deadline instead of giving up.

## Copyable helper

[`examples/06-structured-output.ts`](../examples/06-structured-output.ts)
[`examples/06-structured-output.ts`](https://github.com/coder/ai-sdk/blob/main/packages/agent/examples/06-structured-output.ts)
packages all four rules into a small helper:

- `structuredOutput(schema)` returns `agentOpts` to spread into the constructor,
Expand Down
14 changes: 7 additions & 7 deletions packages/agent/docs/workspaces-and-quota.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ bound, a turn can sit unscheduled and never settle.
as `workspace_id` on chat creation; message and update requests carry no
workspace field. To move work to another workspace, start a new agent/chat.
- **This SDK never provisions workspaces.** Pass an existing one. Provision it
with [`@coder/ai-sdk-sandbox`](../../sandbox)'s `ensureCoderWorkspace`, the
with [`@coder/ai-sdk-sandbox`](https://github.com/coder/ai-sdk/tree/main/packages/sandbox)'s `ensureCoderWorkspace`, the
CLI, or the v2 API.
- **A chat created without `workspaceId` can still be workspace‑backed.**
Deployments may assign one server‑side. The SDK reads the created chat's
Expand Down Expand Up @@ -67,7 +67,7 @@ Practical sizing:
filesystem carries one session's artifacts (and secrets) into the next.
Provision per tenant, or securely reset a workspace before reassigning it.
4. **Send steps that don't need server‑side tools to the
[provider](../../provider)** — it never touches a workspace.
[provider](https://github.com/coder/ai-sdk/tree/main/packages/provider)** — it never touches a workspace.

## Autostop & cleanup

Expand All @@ -78,11 +78,11 @@ Manage two lifetimes separately:
resources.
- **Workspaces:** rely on template‑level scheduling, not manual hygiene.

| Template setting | What to do |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Autostop TTL** | Long enough to survive a normal session (including idle gaps between turns), short enough that a leaked workspace stops burning running‑cost within hours. Without autostop, a leaked workspace pins its full quota until someone notices. [Sandbox](../../sandbox): `stopAfter: "8h"` sets `ttl_ms` at creation. |
| **Activity bump** (default 1 h) | Extends a running workspace's deadline when Coder detects sessions. Check [what counts as activity](https://coder.com/docs/user-guides/workspace-scheduling) before assuming server‑side tool use keeps a workspace alive. |
| **Dormancy / failure cleanup** | Reaps abandoned and repeatedly‑failing workspaces automatically ([template scheduling](https://coder.com/docs/admin/templates/managing-templates/schedule)). |
| Template setting | What to do |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Autostop TTL** | Long enough to survive a normal session (including idle gaps between turns), short enough that a leaked workspace stops burning running‑cost within hours. Without autostop, a leaked workspace pins its full quota until someone notices. [Sandbox](https://github.com/coder/ai-sdk/tree/main/packages/sandbox): `stopAfter: "8h"` sets `ttl_ms` at creation. |
| **Activity bump** (default 1 h) | Extends a running workspace's deadline when Coder detects sessions. Check [what counts as activity](https://coder.com/docs/user-guides/workspace-scheduling) before assuming server‑side tool use keeps a workspace alive. |
| **Dormancy / failure cleanup** | Reaps abandoned and repeatedly‑failing workspaces automatically ([template scheduling](https://coder.com/docs/admin/templates/managing-templates/schedule)). |

**Stopping is not enough.** A _stopped_ workspace typically still consumes its
persistent resources' `daily_cost` (disks, volumes), so a scratch fleet that
Expand Down
18 changes: 10 additions & 8 deletions packages/provider/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,19 @@ const { text } = await generateText({
});
```

**Why:** developers authenticate with their Coder token and never handle raw
provider keys. AI Gateway authenticates each request against a Coder identity,
injects the centrally managed keys for the upstream providers (Anthropic,
OpenAI, Bedrock, Copilot, …), and audits usage per user. The deployment decides
**Why:** in centralized mode (the default), developers authenticate with their
Coder token and never handle raw provider keys. AI Gateway authenticates each
request against a Coder identity, injects the centrally managed keys for the
upstream providers (Anthropic, OpenAI, Bedrock, Copilot, …), and audits usage
per user. In bring-your-own-key mode, developers supply their own upstream key
instead (see [Authentication](#authentication)). The deployment decides
which models and providers are available.

> [!TIP]
> This package is for **plain model calls**: `generateText`, `streamText`, and
> `generateObject` (schema-constrained structured output). For Coder's
> **server-side agent** (multi-step tool loop, built-in tools, MCP servers,
> workspace file/shell tools), use [`@coder/ai-sdk-agent`](../agent). They
> workspace file/shell tools), use [`@coder/ai-sdk-agent`](https://github.com/coder/ai-sdk/tree/main/packages/agent). They
> compose: provider for pure text/JSON steps, Agent for tool-driven ones.

## Install
Expand Down Expand Up @@ -183,7 +185,7 @@ audit capture, required permissions, and a security FAQ.
Key points:

- **Client vs. gateway.** What this package puts on the wire is verifiable in
[`src/provider.ts`](./src/provider.ts). Key custody, audit capture, and
[`src/provider.ts`](https://github.com/coder/ai-sdk/blob/main/packages/provider/src/provider.ts). Key custody, audit capture, and
retention are enforced server-side by your Coder deployment.
- **One destination.** The package only initiates requests to your `baseURL`.
It never contacts upstream vendors directly and adds no telemetry.
Expand All @@ -205,8 +207,8 @@ Key points:

## Examples

Runnable scripts live in [`examples/`](./examples); see its
[README](./examples/README.md) for setup.
Runnable scripts live in [`examples/`](https://github.com/coder/ai-sdk/tree/main/packages/provider/examples); see its
[README](https://github.com/coder/ai-sdk/blob/main/packages/provider/examples/README.md) for setup.

```bash
pnpm example:generate # non-streaming generateText
Expand Down
12 changes: 6 additions & 6 deletions packages/provider/docs/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ Reference for security reviewers evaluating `@coder/ai-sdk-provider`.

Two kinds of claims appear below. Keep them apart:

| Claim kind | Covers | Where it is enforced / verifiable |
| -------------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| **Client behavior** | What this package puts on the wire | [`src/provider.ts`](../src/provider.ts): ~250 lines, no dependencies beyond the official AI SDK provider packages |
| **Gateway behavior** | Key custody, audit capture, retention | Your Coder deployment, server-side, regardless of what any client does. See the [AI Gateway docs](https://coder.com/docs/ai-coder/ai-gateway) |
| Claim kind | Covers | Where it is enforced / verifiable |
| -------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Client behavior** | What this package puts on the wire | [`src/provider.ts`](https://github.com/coder/ai-sdk/blob/main/packages/provider/src/provider.ts): ~250 lines, no dependencies beyond the official AI SDK provider packages |
| **Gateway behavior** | Key custody, audit capture, retention | Your Coder deployment, server-side, regardless of what any client does. See the [AI Gateway docs](https://coder.com/docs/ai-coder/ai-gateway) |

## Data flow

Expand Down Expand Up @@ -149,10 +149,10 @@ counts are retained alongside them.

Yes.

- [`src/provider.ts`](../src/provider.ts) is the entire wire-facing surface. It
- [`src/provider.ts`](https://github.com/coder/ai-sdk/blob/main/packages/provider/src/provider.ts) is the entire wire-facing surface. It
only selects base URLs and auth headers, then delegates request construction
to the official AI SDK provider packages.
- [`test/provider.test.ts`](../test/provider.test.ts) asserts the request URL,
- [`test/provider.test.ts`](https://github.com/coder/ai-sdk/blob/main/packages/provider/test/provider.test.ts) asserts the request URL,
auth headers, and model pass-through for the chat/messages routes in both
auth modes.
- The underlying AI SDK packages add their own protocol headers (e.g.
Expand Down
Loading
Loading