> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polpo.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# TypeScript SDK

> Typed access to the Polpo 0.15.35 Agent API

## Install

```bash theme={null}
npm install @polpo-ai/sdk@0.15.35
```

## Configure

```typescript theme={null}
import { PolpoClient } from "@polpo-ai/sdk";

const client = new PolpoClient({
  baseUrl: "https://{project}.polpo.cloud",
  apiKey: process.env.POLPO_API_KEY,
  user: "usr_123",
});
```

| Option      | Type           | Description                                                    |
| ----------- | -------------- | -------------------------------------------------------------- |
| `baseUrl`   | `string`       | Project or self-hosted base URL                                |
| `apiKey`    | `string`       | Project API key                                                |
| `apiPrefix` | `string`       | Override `/v1` on Cloud or `/api/v1` when self-hosted          |
| `fetch`     | `typeof fetch` | Custom fetch implementation                                    |
| `user`      | `string`       | Default external user identifier for chat, tasks, and missions |

`projectId` remains in the configuration type for compatibility but is deprecated and ignored.

## Chat

```typescript theme={null}
const stream = client.chatCompletionsStream({
  agent: "backend-dev",
  loop: "implementation-flow",
  model: "anthropic/claude-sonnet-4-5",
  sandbox: { isolation: "reuse" },
  messages: [{ role: "user", content: "Review the auth module" }],
  metadata: { tenant_id: "tenant_123" },
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}

console.log(stream.sessionId, stream.aborted);
```

`messages` is required. `agent` is optional and omission selects the orchestrator. Other fields are `loop`, `sessionId`, `user`, `metadata`, `sandbox`, and `stream`. `model` can override the selected agent model for this request.

`ChatCompletionStream` exposes `sessionId`, `aborted`, `askUser`, `missionPreview`, `vaultPreview`, `openFile`, `navigateTo`, and `openTab`, plus `abort()`.

```typescript theme={null}
const response = await client.chatCompletions({
  messages: [{ role: "user", content: "Summarize the project" }],
});
console.log(response.choices[0].message.content);
```

## Sessions

```typescript theme={null}
const { sessions } = await client.getSessions();
const { session, messages } = await client.getSessionMessages(sessions[0].id);
await client.renameSession(session.id, "Architecture review");
await client.deleteSession(session.id);
```

Pass `sessionId` to chat calls to continue a session. The caller should still include the message history needed by the model.

## Agents and loops

```typescript theme={null}
await client.addAgent({
  name: "qa-engineer",
  role: "Writes and runs tests",
  model: "anthropic/claude-sonnet-4-5",
  allowedTools: ["read", "write", "edit", "bash"],
  sandbox: { isolation: "fresh" },
  assignedLoops: ["qa-flow"],
});

await client.updateAgent("qa-engineer", { reasoning: "high" });
const agent = await client.getAgent("qa-engineer");
const agents = await client.getAgents();
await client.removeAgent("qa-engineer");
```

Use `getLoops`, `getLoop`, `createLoop`, `updateLoop`, and `deleteLoop` for project loops. Agents only store `assignedLoops`; a chat or task selects a loop explicitly.

## Memory and legacy vault

```typescript theme={null}
const shared = await client.getMemory();
await client.saveMemory("Updated project context");
const agentMemory = await client.getAgentMemory("backend-dev");
await client.saveAgentMemory("backend-dev", "Prefers functional patterns");

await client.saveVaultEntry({
  agent: "emailer",
  service: "smtp",
  type: "smtp",
  credentials: { host: "smtp.example.com", user: "bot", pass: "secret" },
});
const entries = await client.listVaultEntries("emailer");
await client.patchVaultEntry("emailer", "smtp", { credentials: { pass: "rotated" } });
await client.removeVaultEntry("emailer", "smtp");
```

Vault list operations return metadata and credential key names, never values.

Use project Connections for new shared API keys, OAuth accounts, and external integrations. Vault APIs remain for compatibility with agent-scoped secrets.

## Files

```typescript theme={null}
const { roots } = await client.getFileRoots();
const { path, entries } = await client.listFiles("/src");
const preview = await client.previewFile("/src/index.ts");
const response = await client.readFile("/src/index.ts");
await client.uploadFile("/workspace", file, file.name);
await client.createDirectory("/src/utils");
await client.renameFile("/src/old.ts", "new.ts");
await client.deleteFile("/src/obsolete.ts");
const results = await client.searchFiles("config", "/src", 20);
```

Attach an uploaded path with a chat content part such as `{ type: "file", file_id: "/workspace/report.pdf" }`. Agents use their configured file or image tools to inspect it.

## Skills

```typescript theme={null}
await client.createSkill({
  name: "code-review",
  description: "Reviews changes for correctness",
  content: "Review behavior, tests, and error handling.",
  allowedTools: ["read", "grep"],
});

await client.installSkills("github:acme/polpo-skills", {
  skillNames: ["testing"],
  force: false,
});
await client.assignSkill("code-review", "backend-dev");
await client.unassignSkill("code-review", "backend-dev");
await client.deleteSkill("code-review");
```

## Schedules and playbooks

```typescript theme={null}
await client.createSchedule({
  missionId: "mission_abc123",
  expression: "0 2 * * *",
  recurring: true,
});
await client.updateSchedule("mission_abc123", { enabled: false });
await client.deleteSchedule("mission_abc123");

await client.createPlaybook({
  name: "onboard-repo",
  description: "Analyze a repository",
  mission: {
    tasks: [{ title: "Scan", description: "Map the repository", assignTo: "analyst" }],
  },
});
await client.deletePlaybook("onboard-repo");
```

## Live events

`getEventsUrl()` and `EventSourceManager` use an `apiKey` query parameter for browser EventSource compatibility. The current Cloud authentication middleware does not accept query-string API keys, so these helpers cannot authenticate a direct Cloud SSE connection. Use a server-side SSE client with an `Authorization` header or an application-owned authenticated proxy. See [Events](/agent-api/events).

## Errors

```typescript theme={null}
import { PolpoApiError } from "@polpo-ai/sdk";

try {
  await client.getAgent("missing");
} catch (error) {
  if (error instanceof PolpoApiError) {
    console.error(error.code, error.statusCode, error.message);
  }
}
```
