Workspaces API¶
Pydantic AI workspace capabilities backed by this library's sandboxes. See
Workspaces for the concepts. Needs the workspaces
extra, plus the provider's own (docker, kubernetes, daytona).
DockerWorkspace¶
pydantic_ai_backends.workspaces.DockerWorkspace
dataclass
¶
Bases: AbstractCapability[object]
Supply a Docker container on this host as the run's workspace.
A run with no ref creates a container; one carrying a "docker" ref attaches
to that container, starting it if it was stopped. Containers are kept after
the run — the ref is how to come back to them, and :meth:destroy is how to
remove one.
This supplies the environment only. Compose it with something that uses the
workspace: Coder, Shell or FileSystem from the Pydantic AI harness, or
this library's ConsoleCapability.
A container is only as isolated as its runtime: Docker's default runc
shares the host kernel. See oci_runtime.
Example
Source code in src/pydantic_ai_backends/workspaces/_docker.py
| Python | |
|---|---|
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | |
backend(ref=None)
¶
A backend for ref, or for a new container; no I/O until its first operation.
Source code in src/pydantic_ai_backends/workspaces/_docker.py
| Python | |
|---|---|
get_workspace(ctx, *, ref)
¶
This run's backend, or None for a ref another provider owns.
Source code in src/pydantic_ai_backends/workspaces/_docker.py
destroy(ref)
async
¶
Remove the container ref names, files and all. Already gone is fine.
Raises:
| Type | Description |
|---|---|
ValueError
|
|
Source code in src/pydantic_ai_backends/workspaces/_docker.py
pydantic_ai_backends.workspaces.DockerWorkspaceBackend
¶
Bases: ContainerWorkspaceBackend
One Docker container, as the environment an agent run works in.
The container is named after the ref and never auto-removed, so a later run
can attach to it and find its files, installed packages included; a stopped
one is started again. It lives until :meth:DockerWorkspace.destroy. A ref
attaches only to a container named the way this class names the ones it
creates, never to any other container on the host.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_factory
|
SandboxFactory
|
Builds the |
required |
ref
|
WorkspaceRef | None
|
The workspace to attach to; |
None
|
env
|
Mapping[str, str] | None
|
Variables every command gets, under any a call passes. |
None
|
container_name
|
str | None
|
A container chosen by whoever configures the workspace rather than by this class: created under that name on first use when it does not exist, attached when it does. A ref naming it must still find it there, and no ref reaches any other container. |
None
|
Source code in src/pydantic_ai_backends/workspaces/_docker.py
SandboxdWorkspace¶
pydantic_ai_backends.workspaces.SandboxdWorkspace
dataclass
¶
Bases: AbstractCapability[object]
Supply a sandboxd session as the run's workspace.
A run with no ref opens a session; one carrying this capability's provider
attaches to that session, or to the workspace the service kept after it was
reaped. Sessions are kept after the run — the ref is how to come back, and
:meth:destroy is how to remove one with its files.
This supplies the environment only. Compose it with something that uses the
workspace: Coder, Shell or FileSystem from the Pydantic AI harness, or
this library's ConsoleCapability.
Example
Source code in src/pydantic_ai_backends/workspaces/_sandboxd.py
| Python | |
|---|---|
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | |
backend(ref=None)
¶
A backend for ref, or for a new session; no I/O until its first operation.
Source code in src/pydantic_ai_backends/workspaces/_sandboxd.py
get_workspace(ctx, *, ref)
¶
This run's backend, or None for a ref another provider owns.
Source code in src/pydantic_ai_backends/workspaces/_sandboxd.py
destroy(ref)
async
¶
Close the session ref names and delete its files. Already gone is fine.
Raises:
| Type | Description |
|---|---|
ValueError
|
|
HTTPError
|
The service could not be reached or refused. |
Source code in src/pydantic_ai_backends/workspaces/_sandboxd.py
pydantic_ai_backends.workspaces.SandboxdWorkspaceBackend
¶
Bases: WorkspaceBackend, SupportsCommands
One sandboxd session, as the environment an agent run works in.
Commands go through the service's /run, which keeps stdout and stderr
apart, reports a vanished sandbox as one and can be stopped; Workspace
derives file operations through them. The session's files live on the
service host, so a ref still attaches after the container was reaped, for as
long as the service keeps the workspace (its workspace_ttl).
Every command is bounded by the service's execute_timeout, including one
asking for no timeout: the service enforces its ceiling on every caller.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
service_url
|
str
|
Base URL of the service. |
required |
token
|
str
|
The service token. It can open a session on the service's host, so treat it as the Docker socket it sits in front of. |
required |
ref
|
WorkspaceRef | None
|
The workspace to attach to; |
None
|
provider
|
str
|
Provider name in refs. Give each service its own when an agent can reach more than one, or a ref from one would attach on another. |
SANDBOXD_PROVIDER
|
runtime
|
str | None
|
Runtime alias for a new session; the service default when |
None
|
tenant
|
str | None
|
Who the session is opened for, counted against the service's per-tenant ceiling. |
None
|
env
|
Mapping[str, str] | None
|
Variables every command gets, under any a call passes. |
None
|
client
|
AsyncClient | None
|
An |
None
|
request_timeout
|
float
|
Seconds for a request that runs no command. |
DEFAULT_REQUEST_TIMEOUT
|
session_name
|
str | None
|
A session id chosen by whoever configures the workspace rather than by the service: with no ref, the first operation opens the session under it, or attaches when it is open or its files are kept. A ref is still attach-only, so a caller that knows the session existed learns that it is gone instead of starting over in an empty one. |
None
|
Source code in src/pydantic_ai_backends/workspaces/_sandboxd.py
| Python | |
|---|---|
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 | |
ref
property
¶
The session id once it exists; None before the first operation.
working_dir()
async
¶
The directory commands start in, as the sandbox resolves it.
Source code in src/pydantic_ai_backends/workspaces/_sandboxd.py
run(command, *, shell=False, env=None, timeout=None)
async
¶
Run a command in the session's sandbox; see SupportsCommands.run.
Raises:
| Type | Description |
|---|---|
WorkspaceUnavailableError
|
The session or its sandbox is gone. |
WorkspaceTimeoutError
|
The command reached |
WorkspaceOutputLimitError
|
Its combined output passed the limit. |
HTTPError
|
The service could not be reached or answered with an unexpected status — transient, and left for a caller to retry. |
Source code in src/pydantic_ai_backends/workspaces/_sandboxd.py
purge()
async
¶
Close this backend's session and delete its files. Already gone is fine.
Attaches first when the session is closed but its workspace is kept, since the service deletes a workspace only through its session.
Raises:
| Type | Description |
|---|---|
HTTPError
|
The service could not be reached or refused. |
Source code in src/pydantic_ai_backends/workspaces/_sandboxd.py
KubernetesWorkspace¶
pydantic_ai_backends.workspaces.KubernetesWorkspace
dataclass
¶
Bases: AbstractCapability[object]
Supply a Kubernetes pod as the run's workspace.
A run with no ref creates a pod; one carrying this capability's provider
attaches to that pod. Pods are kept after the run — the ref is how to come
back, and :meth:destroy deletes one. Commands go through pods/exec, so
the caller needs that RBAC and the image needs /bin/sh.
Not checked against a live cluster in this repository's CI.
Example
from pydantic_ai import Agent
from pydantic_ai_backends import ConsoleCapability
from pydantic_ai_backends.workspaces import KubernetesWorkspace
pods = KubernetesWorkspace(image="python:3.12-slim", namespace="agents")
agent = Agent("anthropic:claude-opus-5-5", capabilities=[pods, ConsoleCapability()])
Source code in src/pydantic_ai_backends/workspaces/_kubernetes.py
| Python | |
|---|---|
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | |
backend(ref=None)
¶
A backend for ref, or for a new pod; no API call until its first operation.
Source code in src/pydantic_ai_backends/workspaces/_kubernetes.py
get_workspace(ctx, *, ref)
¶
This run's backend, or None for a ref another provider owns.
Source code in src/pydantic_ai_backends/workspaces/_kubernetes.py
| Python | |
|---|---|
destroy(ref)
async
¶
Delete the pod ref names. Already gone is fine.
Raises:
| Type | Description |
|---|---|
ValueError
|
|
Source code in src/pydantic_ai_backends/workspaces/_kubernetes.py
pydantic_ai_backends.workspaces.KubernetesWorkspaceBackend
¶
Bases: ContainerWorkspaceBackend
One pod, as the environment an agent run works in.
The first operation creates the pod and waits for it to be Ready; a ref
attaches to a running pod and fails with WorkspaceUnavailableError when it
is gone or has finished. The pod lives until :meth:KubernetesWorkspace.destroy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pod_factory
|
PodFactory
|
Builds the |
required |
ref
|
WorkspaceRef | None
|
The workspace to attach to; |
None
|
env
|
Mapping[str, str] | None
|
Variables every command gets, under any a call passes. |
None
|
provider
|
str
|
Provider name in refs; distinct per cluster when an agent can reach several. |
KUBERNETES_PROVIDER
|
Source code in src/pydantic_ai_backends/workspaces/_kubernetes.py
DaytonaWorkspace¶
pydantic_ai_backends.workspaces.DaytonaWorkspace
dataclass
¶
Bases: AbstractCapability[object]
Supply a Daytona sandbox as the run's workspace.
A run with no ref creates a sandbox; one carrying a "daytona" ref attaches
to it, starting it when Daytona stopped or archived it. Sandboxes are kept
after the run, subject to Daytona's own auto-stop and auto-delete; the ref is
how to come back, and :meth:destroy deletes one.
Not checked against a live Daytona account in this repository's CI.
Example
from daytona import DaytonaConfig
from pydantic_ai import Agent
from pydantic_ai_backends import ConsoleCapability
from pydantic_ai_backends.workspaces import DaytonaWorkspace
sandboxes = DaytonaWorkspace(config=DaytonaConfig(api_key="dtn_..."))
agent = Agent("anthropic:claude-opus-5-5", capabilities=[sandboxes, ConsoleCapability()])
Source code in src/pydantic_ai_backends/workspaces/_daytona.py
| Python | |
|---|---|
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 | |
backend(ref=None)
¶
A backend for ref, or for a new sandbox; no API call until its first operation.
Source code in src/pydantic_ai_backends/workspaces/_daytona.py
get_workspace(ctx, *, ref)
¶
This run's backend, or None for a ref another provider owns.
Source code in src/pydantic_ai_backends/workspaces/_daytona.py
destroy(ref)
async
¶
Delete the sandbox ref names. Already gone is fine.
Raises:
| Type | Description |
|---|---|
ValueError
|
|
Source code in src/pydantic_ai_backends/workspaces/_daytona.py
pydantic_ai_backends.workspaces.DaytonaWorkspaceBackend
¶
Bases: WorkspaceBackend, SupportsCommands
One Daytona sandbox, as the environment an agent run works in.
Commands only: Workspace derives the file operations through the shell.
The first operation creates the sandbox, or attaches to the one the ref
names, starting it when it was stopped or archived; a sandbox that is gone
fails with WorkspaceUnavailableError. It lives until
:meth:DaytonaWorkspace.destroy or Daytona's own auto-delete.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
DaytonaConfig | None
|
A |
None
|
create_params
|
CreateParams | None
|
Parameters for a new sandbox, such as
|
None
|
ref
|
WorkspaceRef | None
|
The workspace to attach to; |
None
|
env
|
Mapping[str, str] | None
|
Variables every command gets, under any a call passes. |
None
|
client
|
AsyncDaytona | None
|
An |
None
|
sandbox_name
|
str | None
|
A sandbox name chosen by whoever configures the workspace rather than by Daytona: with no ref, the first operation creates the sandbox under it, or attaches to the one that already has it. A ref is still attach-only, so a caller that knows the sandbox existed learns that it is gone instead of starting over in a new one. |
None
|
Source code in src/pydantic_ai_backends/workspaces/_daytona.py
| Python | |
|---|---|
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | |
ref
property
¶
The sandbox's id once it exists; None before the first operation.
working_dir()
async
¶
The sandbox's working directory, as Daytona reports it.
Source code in src/pydantic_ai_backends/workspaces/_daytona.py
run(command, *, shell=False, env=None, timeout=None)
async
¶
Run a command in the sandbox, stdin at EOF; see SupportsCommands.run.
Raises:
| Type | Description |
|---|---|
WorkspaceUnavailableError
|
The sandbox is gone. |
WorkspaceTimeoutError
|
The command reached |
WorkspaceOutputLimitError
|
Its combined output passed 10 MiB. |
Source code in src/pydantic_ai_backends/workspaces/_daytona.py
purge()
async
¶
Delete this backend's sandbox. Already gone is fine.
Source code in src/pydantic_ai_backends/workspaces/_daytona.py
StateWorkspace¶
pydantic_ai_backends.workspaces.StateWorkspace
dataclass
¶
Bases: AbstractCapability[object]
Supply a StateBackend document as the run's workspace.
A run with no ref adds a document to store; one carrying a "state" ref
works in the document under that id, and one whose document is gone fails
with WorkspaceUnavailableError. Commands are not available: compose it
with file tools such as the harness's FileSystem, or
ConsoleCapability(include_execute=False).
The default store lives as long as this capability. An application that
keeps documents elsewhere fills the mapping before a run and saves the
document afterwards — files and sorted(directories) are JSON.
Example
Source code in src/pydantic_ai_backends/workspaces/_state.py
backend(ref=None)
¶
A backend for ref, or for a new document created on first use.
get_workspace(ctx, *, ref)
¶
This run's backend, or None for a ref another provider owns.
Source code in src/pydantic_ai_backends/workspaces/_state.py
| Python | |
|---|---|
destroy(ref)
async
¶
Drop the document ref names. Already gone is fine.
Raises:
| Type | Description |
|---|---|
ValueError
|
|
Source code in src/pydantic_ai_backends/workspaces/_state.py
pydantic_ai_backends.workspaces.StateWorkspaceBackend
¶
Bases: WorkspaceBackend, SupportsFilesystem
A StateBackend document, as the environment an agent run works in.
Files only: there is nothing here to run a command in, so ctx.workspace.run
refuses and file tools work. The document lives in store under the ref's
id; a run with no ref adds a new one on its first operation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
MutableMapping[str, StateBackend]
|
Documents by id. The application owns it — an in-process dict, or a mapping it filled from its own storage before the run. |
required |
ref
|
WorkspaceRef | None
|
The document to work in; |
None
|
Source code in src/pydantic_ai_backends/workspaces/_state.py
ref
property
¶
The document's id once it exists; None before the first operation.
working_dir()
async
¶
read_bytes(path)
async
¶
write_bytes(path, data)
async
¶
stat(path)
async
¶
Metadata for a file or directory.
Source code in src/pydantic_ai_backends/workspaces/_state.py
list_dir(path)
async
¶
The entries directly in a directory.
Source code in src/pydantic_ai_backends/workspaces/_state.py
make_dir(path)
async
¶
remove(path)
async
¶
Remove a file, or a directory and everything under it.
Raises:
| Type | Description |
|---|---|
ValueError
|
|
Source code in src/pydantic_ai_backends/workspaces/_state.py
Commands under the workspace contract¶
pydantic_ai_backends.types.CommandOutcome
dataclass
¶
How one CommandRunner.run_command call ended.
Exactly one of three shapes: finished (exit_code set, non-zero included),
timed_out, or output_limited. The last two carry only the beginning of
each stream and no exit code, because the command was stopped rather than
allowed to finish. Undecodable bytes are replaced, never dropped.