Testing
Deterministic test doubles for Agents SDK workflows.
InvalidModelStep
Bases: ModelScriptError
Raised when a model step is invalid before it enters the script queue.
Source code in src/agents/testing/model.py
ModelCall
dataclass
A recorded call at the provider-neutral Model boundary.
Source code in src/agents/testing/model.py
ModelScriptError
ModelStep
dataclass
One deterministic model call result.
output uses the normalized SDK output-item boundary. Set error to raise from the model
call, responder to derive the result from the recorded call, or stream_events to supply
an exact normalized event stream for advanced streaming tests. ScriptedModel also accepts
the equivalent dictionary form described by ModelStepSpec.
Source code in src/agents/testing/model.py
raise_error
classmethod
raise_error(
error: Exception,
*,
retry_advice: ModelRetryAdvice | None = None,
) -> ModelStep
Create a step that raises error with optional provider retry guidance.
Source code in src/agents/testing/model.py
respond
classmethod
respond(responder: ModelResponder) -> ModelStep
stream
classmethod
stream(
events: Sequence[TResponseStreamEvent]
| ModelStreamFactory,
*,
output: Sequence[TResponseOutputItem] = (),
usage: Usage | None = None,
response_id: str | None = "resp-789",
) -> ModelStep
Create a step with an exact normalized stream-event sequence or factory.
Source code in src/agents/testing/model.py
ModelStepSpec
Bases: TypedDict
Dictionary form of ModelStep accepted by ScriptedModel.
Source code in src/agents/testing/model.py
ScriptedModel
Bases: Model
A deterministic provider-neutral model for testing agent workflows.
Each step may be a ModelStep, an equivalent ModelStepSpec dictionary, a
ModelResponse, a normalized output-item sequence, or an exception.
Source code in src/agents/testing/model.py
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 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 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 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 | |
remaining_steps
property
Return the number of configured model calls that have not run yet.
close
async
Release any resources held by the model.
Models that maintain persistent connections can override this. The default implementation is a no-op.
enqueue
extend
Append multiple model steps.
set_default_usage
set_default_usage(usage: Usage | None) -> None
get_retry_advice
get_retry_advice(
request: ModelRetryAdviceRequest,
) -> ModelRetryAdvice | None
Return retry advice attached to the exact scripted error that was raised.
Source code in src/agents/testing/model.py
assert_complete
Raise when configured steps remain unconsumed.
Source code in src/agents/testing/model.py
UnconsumedModelSteps
Bases: ModelScriptError
Raised when a test finishes before consuming every configured step.
Source code in src/agents/testing/model.py
UnexpectedModelCall
Bases: ModelScriptError
Raised when the model is called after all configured steps were consumed.
Source code in src/agents/testing/model.py
InvalidSandboxStep
Bases: SandboxScriptError
Raised when a sandbox step is invalid at factory construction time.
Source code in src/agents/testing/sandbox.py
SandboxCall
dataclass
A detached invocation-time sandbox call snapshot.
Source code in src/agents/testing/sandbox.py
SandboxCallMatcherError
Bases: SandboxScriptError
Raised when a sandbox step matcher rejects its call.
Source code in src/agents/testing/sandbox.py
SandboxScriptError
SandboxStepSpec
Bases: TypedDict
Dictionary form of one FIFO scripted sandbox call.
Source code in src/agents/testing/sandbox.py
ScriptedSandboxSession
Bases: BaseSandboxSession, ABC
The typed result interface for scripted_sandbox_session.
Source code in src/agents/testing/sandbox.py
calls
abstractmethod
property
calls: tuple[SandboxCall, ...]
Return detached call-history snapshots in invocation order.
remaining_steps
abstractmethod
property
Return the number of configured calls that remain.
stop
async
Persist/snapshot the workspace.
Note: stop() is intentionally persistence-only. Sandboxes that need to tear down
sandbox resources (Docker containers, remote sessions, etc.) should implement
shutdown() instead.
Source code in src/agents/sandbox/session/base_sandbox_session.py
supports_docker_volume_mounts
Return whether this backend attaches Docker volume mounts before manifest apply.
shutdown
async
Tear down sandbox resources (best-effort).
Default is a no-op. Sandbox-specific sessions (e.g. Docker) should override.
Source code in src/agents/sandbox/session/base_sandbox_session.py
aclose
async
Run the session cleanup lifecycle outside of async with.
This performs the same session-owned cleanup as __aexit__(): persist/snapshot the
workspace via stop(), tear down session resources via shutdown(), and close
session-scoped dependencies. If the session came from a sandbox client, call the client's
delete() separately for backend-specific deletion such as removing a Docker container
or deleting a temporary host workspace.
Source code in src/agents/sandbox/session/base_sandbox_session.py
register_pre_stop_hook
Register an async hook to run once before the session workspace is persisted.
Source code in src/agents/sandbox/session/base_sandbox_session.py
run_pre_stop_hooks
async
Run registered pre-stop hooks once before workspace persistence.
Source code in src/agents/sandbox/session/base_sandbox_session.py
register_persist_workspace_skip_path
Exclude a runtime-created workspace path from future workspace snapshots.
Use this for session side effects that are not part of durable workspace state, such as generated mount config or ephemeral sink output.
Source code in src/agents/sandbox/session/base_sandbox_session.py
exec
async
exec(
*command: str | Path,
timeout: float | None = None,
shell: bool | list[str] = True,
user: str | User | None = None,
) -> ExecResult
Execute a command inside the session.
:param command: Command and args (will be stringified).
:param timeout: Optional wall-clock timeout in seconds.
:param shell: Whether to run this command in a shell. If True is provided,
the command will be run prefixed by sh -lc. A custom shell prefix may be used
by providing a list.
:returns: An ExecResult containing stdout/stderr and exit code.
:raises TimeoutError: If the sandbox cannot complete within timeout.
Source code in src/agents/sandbox/session/base_sandbox_session.py
read
abstractmethod
async
read(
path: Path, *, user: str | User | None = None
) -> IOBase
Read a file from the session's workspace.
:param path: Absolute path in the container or path relative to the workspace root. :param user: Optional sandbox user to perform the read as. :returns: A readable file-like object. :raises: FileNotFoundError: If the path does not exist.
Source code in src/agents/sandbox/session/base_sandbox_session.py
write
abstractmethod
async
write(
path: Path,
data: IOBase,
*,
user: str | User | None = None,
) -> None
Write a file into the session's workspace.
:param path: Absolute path in the container or path relative to the workspace root. :param data: A file-like object positioned at the start of the payload. :param user: Optional sandbox user to perform the write as.
Source code in src/agents/sandbox/session/base_sandbox_session.py
running
abstractmethod
async
persist_workspace
abstractmethod
async
Serialize the session's workspace into a byte stream.
:returns: A readable byte stream representing the workspace contents. Portable tar streams must use workspace-relative member paths rather than embedding the source backend's workspace root directory.
Source code in src/agents/sandbox/session/base_sandbox_session.py
hydrate_workspace
abstractmethod
async
Populate the session's workspace from a serialized byte stream.
:param data: A readable byte stream as produced by persist_workspace.
Portable tar streams are extracted underneath this session's workspace root.
Source code in src/agents/sandbox/session/base_sandbox_session.py
ls
async
ls(
path: Path | str, *, user: str | User | None = None
) -> list[FileEntry]
List directory contents.
:param path: Path to list.
:param user: Optional sandbox user to list as.
:returns: A list of FileEntry objects.
Source code in src/agents/sandbox/session/base_sandbox_session.py
rm
async
rm(
path: Path | str,
*,
recursive: bool = False,
user: str | User | None = None,
) -> None
Remove a file or directory.
:param path: Path to remove. :param recursive: If true, remove directories recursively. :param user: Optional sandbox user to remove as.
Source code in src/agents/sandbox/session/base_sandbox_session.py
mkdir
async
mkdir(
path: Path | str,
*,
parents: bool = False,
user: str | User | None = None,
) -> None
Create a directory.
:param path: Directory to create on the remote. :param parents: If true, create missing parents. :param user: Optional sandbox user to create the directory as.
Source code in src/agents/sandbox/session/base_sandbox_session.py
extract
async
extract(
path: Path | str,
data: IOBase,
*,
compression_scheme: Literal["tar", "zip"] | None = None,
archive_limits: SandboxArchiveLimits | None = None,
) -> None
Write a compressed archive to a destination on the remote. Optionally extract the archive once written.
:param path: Path on the host machine to extract to :param data: a file-like io stream. :param compression_scheme: either "tar" or "zip". If not provided, it will try to infer from the path. :param archive_limits: optional per-call archive resource limits. If omitted, the session default is used.
Source code in src/agents/sandbox/session/base_sandbox_session.py
should_provision_manifest_accounts_on_resume
Return whether resume should reprovision manifest-managed users and groups.
UnconsumedSandboxSteps
Bases: SandboxScriptError
Raised when configured sandbox steps remain unconsumed.
Source code in src/agents/testing/sandbox.py
UnexpectedSandboxCall
Bases: SandboxScriptError
Raised when a call does not match the next configured sandbox step.
Source code in src/agents/testing/sandbox.py
assistant_message
assistant_message(
text: str, *, item_id: str = "scripted-message"
) -> TResponseOutputItem
Build one normalized assistant text output item.
Source code in src/agents/testing/model.py
function_call
function_call(
name: str,
arguments: str | Mapping[str, Any],
*,
call_id: str,
item_id: str | None = None,
namespace: str | None = None,
) -> TResponseOutputItem
Build one normalized function-tool call output item.
Source code in src/agents/testing/model.py
scripted_sandbox_session
scripted_sandbox_session(
steps: Iterable[
SandboxStepSpec | Mapping[str, Any]
] = (),
*,
manifest: Manifest | None = None,
) -> ScriptedSandboxSession
Create a deterministic provider-free sandbox session for agent workflow tests.
Each FIFO step defines method plus exactly one of result, responder, or error.
An optional match callable receives a detached SandboxCall. The returned object is the
session itself, so pass it directly to SandboxRunConfig(session=session). Only configured
model-facing methods are visible. The two PTY methods are exposed together when either one is
configured because they form one advertised session capability. Use a custom
BaseSandboxSession or a real provider for lifecycle, persistence, mount, or broader
filesystem behavior.