Skip to content

Commit d486dfa

Browse files
committed
feat: python-sdk
1 parent e6da943 commit d486dfa

7 files changed

Lines changed: 491 additions & 6 deletions

File tree

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,10 @@ dist/
66
.DS_Store
77
*.tgz
88
CLAUDE.md
9+
__pycache__/
10+
*.py[cod]
11+
.venv/
12+
venv/
13+
*.egg-info/
14+
.eggs/
15+
*.egg

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ This directory contains the 21st SDK packages. Source of truth lives here in the
44

55
## Packages
66

7-
| Directory | npm package | What it does |
7+
| Directory | Package | What it does |
88
|---|---|---|
99
| `agent/` | `@21st-sdk/agent` | Agent + tool definition (types only) |
1010
| `react/` | `@21st-sdk/react` | React chat UI components |
1111
| `node/` | `@21st-sdk/node` | Node.js API client |
1212
| `nextjs/` | `@21st-sdk/nextjs` | Next.js integration (server + client) |
1313
| `cli/` | `@21st-sdk/cli` | `an login` + `an deploy` CLI |
14+
| `python-sdk/` | `21st-sdk` (PyPI) | Python API client |
1415
| `docs/` || Documentation (bundled into each package on publish) |
1516

1617
> **Note:** `agent-runtime` used to be here but was moved to `packages/agent-runtime/` — it's private and should never be in the public repo.
@@ -45,7 +46,7 @@ So your directory structure looks like:
4546
```
4647
Develop/21/
4748
├── 21st/ ← monorepo (this repo)
48-
└── an-sdk/ ← public repo
49+
└── 21st-sdk/ ← public repo
4950
```
5051

5152
### Releasing
@@ -66,13 +67,13 @@ From the monorepo root:
6667
Then push:
6768

6869
```bash
69-
cd ../an-sdk && git push # regular release
70-
cd ../an-sdk && git push --tags # if you created a tag
70+
cd ../21st-sdk && git push # regular release
71+
cd ../21st-sdk && git push --tags # if you created a tag
7172
```
7273

7374
### What the script does
7475

75-
1. Copies `agent/`, `react/`, `node/`, `nextjs/`, `cli/`, `docs/` to the public repo
76+
1. Copies `agent/`, `react/`, `node/`, `nextjs/`, `cli/`, `python-sdk/`, `docs/` to the public repo
7677
2. Excludes `node_modules/`, `dist/`, `.turbo/`, `CLAUDE.md` (private dev notes)
7778
3. If no `-m` flag, pulls recent commit messages from the monorepo that touched `packages/an-sdk/` and uses them as the commit message
7879
4. Creates a commit in the public repo (skips if nothing changed)
@@ -82,7 +83,7 @@ cd ../an-sdk && git push --tags # if you created a tag
8283

8384
- Don't develop directly in the public repo — always work in the monorepo
8485
- Don't manually copy files — always use the release script
85-
- Don't include `agent-runtime` — the script only copies the 6 listed packages
86+
- Don't include `agent-runtime` — the script only copies the 7 listed packages
8687

8788
## Publishing to npm
8889

packages/python-sdk/README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# 21st-sdk Python
2+
3+
Server-side Python SDK for [21st Agents](https://21st.dev/agents). Manage sandboxes, threads, and tokens programmatically.
4+
5+
Method arguments use Python-style `snake_case`, but SDK responses keep the relay's `camelCase` field names.
6+
7+
## Install
8+
9+
```bash
10+
pip install 21st-sdk
11+
```
12+
13+
## Quick Start
14+
15+
```python
16+
import os
17+
18+
from twentyfirst_sdk import AgentClient
19+
20+
client = AgentClient(api_key=os.environ["API_KEY_21ST"]) # an_sk_...
21+
22+
# Create a sandbox for your agent
23+
sandbox = client.sandboxes.create(agent="my-agent")
24+
25+
# Create a thread
26+
thread = client.threads.create(sandbox_id=sandbox.id, name="Review PR #42")
27+
28+
# Generate a short-lived token for browser clients
29+
token = client.tokens.create(agent="my-agent", expires_in="1h")
30+
print(token.expiresAt)
31+
```
32+
33+
## API
34+
35+
### `AgentClient(api_key, base_url=...)`
36+
37+
```python
38+
AgentClient(
39+
api_key="...", # Your an_sk_ API key
40+
base_url="...", # Optional, default: "https://relay.an.dev"
41+
)
42+
```
43+
44+
### `client.sandboxes`
45+
46+
| Method | Description |
47+
|--------|-------------|
48+
| `create(agent=...)` | Create a new sandbox for an agent |
49+
| `get(sandbox_id)` | Get sandbox details (status, threads, agent info) |
50+
| `delete(sandbox_id)` | Delete a sandbox |
51+
| `exec(sandbox_id, command, ...)` | Run a command in a sandbox |
52+
| `files.write(sandbox_id, files)` | Write files into a sandbox |
53+
| `files.read(sandbox_id, path)` | Read a file from a sandbox |
54+
| `git.clone(sandbox_id, url, ...)` | Clone a repository into a sandbox |
55+
56+
### `client.threads`
57+
58+
| Method | Description |
59+
|--------|-------------|
60+
| `list(sandbox_id)` | List all threads in a sandbox |
61+
| `create(sandbox_id, name=...)` | Create a new thread |
62+
| `get(sandbox_id, thread_id)` | Get thread with messages |
63+
| `delete(sandbox_id, thread_id)` | Delete a thread |
64+
| `run(agent, messages, ...)` | Run a thread and return the raw streaming response |
65+
66+
### `client.tokens`
67+
68+
| Method | Description |
69+
|--------|-------------|
70+
| `create(agent=..., user_id=..., expires_in=...)` | Create a short-lived JWT (default: `"1h"`) |
71+
72+
## License
73+
74+
MIT

packages/python-sdk/pyproject.toml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
[build-system]
2+
requires = ["setuptools>=69", "wheel"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "21st-sdk"
7+
version = "0.0.1"
8+
description = "Server-side Python SDK for 21st Agents"
9+
readme = "README.md"
10+
requires-python = ">=3.9"
11+
license = "MIT"
12+
authors = [
13+
{ name = "21st.dev" },
14+
]
15+
dependencies = [
16+
"requests>=2.31.0",
17+
]
18+
keywords = [
19+
"ai",
20+
"agent",
21+
"sandbox",
22+
"21st",
23+
"21st.dev",
24+
"sdk",
25+
"python",
26+
]
27+
28+
[project.urls]
29+
Homepage = "https://21st.dev/agents"
30+
31+
[tool.setuptools.package-dir]
32+
"" = "src"
33+
34+
[tool.setuptools.packages.find]
35+
where = ["src"]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from .client import DEFAULT_BASE_URL, AgentClient, AgentClientError
2+
from .types import (
3+
APIObject,
4+
ApiError,
5+
ExecResult,
6+
FileContent,
7+
GitCloneResult,
8+
RunThreadMessage,
9+
RunThreadMessagePart,
10+
RunThreadResult,
11+
Sandbox,
12+
SandboxDetail,
13+
Thread,
14+
ThreadSummary,
15+
Token,
16+
)
17+
18+
__all__ = [
19+
"APIObject",
20+
"DEFAULT_BASE_URL",
21+
"AgentClient",
22+
"AgentClientError",
23+
"ApiError",
24+
"ExecResult",
25+
"FileContent",
26+
"GitCloneResult",
27+
"RunThreadMessage",
28+
"RunThreadMessagePart",
29+
"RunThreadResult",
30+
"Sandbox",
31+
"SandboxDetail",
32+
"Thread",
33+
"ThreadSummary",
34+
"Token",
35+
]

0 commit comments

Comments
 (0)