Skip to main content

Client library for AI agent runtime communication over WebSocket

Project description

runtimeuse (Python)

Python client library for communicating with a runtimeuse agent runtime over WebSocket.

Handles the WebSocket connection lifecycle, message dispatch, artifact upload handshake, cancellation, and structured result parsing -- so you can focus on what to do with agent results rather than wire protocol details.

Installation

pip install runtimeuse-client

Quick Start

Start the runtime inside any sandbox, then connect from outside:

import asyncio
from runtimeuse_client import (
    AssistantMessageInterface,
    QueryOptions,
    RuntimeEnvironmentDownloadableInterface,
    RuntimeUseClient,
    StructuredOutputResult,
    TextResult,
)

WORKDIR = "/runtimeuse"

async def main():
    # Start the runtime in a sandbox (provider-specific)
    sandbox = Sandbox.create()
    sandbox.run("npx -y runtimeuse@latest")
    ws_url = sandbox.get_url(8080)

    client = RuntimeUseClient(ws_url=ws_url)

    async def on_assistant(msg: AssistantMessageInterface) -> None:
        for block in msg.text_blocks:
            print(f"[assistant] {block}")

    # Text response (no output schema)
    result = await client.query(
        prompt="Summarize the contents of the codex repository and list your favorite file in the repository.",
        options=QueryOptions(
            system_prompt="You are a helpful assistant.",
            model="gpt-4.1",
            on_assistant_message=on_assistant,
            pre_agent_downloadables=[
                RuntimeEnvironmentDownloadableInterface(
                    download_url="https://github.com/openai/codex/archive/refs/heads/main.zip",
                    working_dir=WORKDIR,
                )
            ],
        ),
    )
    assert isinstance(result.data, TextResult)
    print(result.data.text)

    # Structured response (with output schema)
    result = await client.query(
        prompt="Inspect the codex repository and return the total file count and total character count across all files as JSON.",
        options=QueryOptions(
            system_prompt="You are a helpful assistant.",
            model="gpt-4.1",
            pre_agent_downloadables=[
                RuntimeEnvironmentDownloadableInterface(
                    download_url="https://github.com/openai/codex/archive/refs/heads/main.zip",
                    working_dir=WORKDIR,
                )
            ],
            output_format_json_schema_str="""
{
  "type": "json_schema",
  "schema": {
    "type": "object",
    "properties": {
      "file_count": { "type": "integer" },
      "char_count": { "type": "integer" }
    },
    "required": ["file_count", "char_count"],
    "additionalProperties": false
  }
}
""",
        ),
    )
    assert isinstance(result.data, StructuredOutputResult)
    print(result.data.structured_output)
    print(result.metadata)  # execution metadata

asyncio.run(main())

For local development without a sandbox, connect directly:

client = RuntimeUseClient(ws_url="ws://localhost:8080")

Usage

RuntimeUseClient

Manages the WebSocket connection to the agent runtime and runs the message loop: sends a prompt, iterates the response stream, and returns a QueryResult. Raises AgentRuntimeError if the runtime returns an error.

query() returns a QueryResult with .data (a TextResult or StructuredOutputResult) and .metadata.

client = RuntimeUseClient(ws_url="ws://localhost:8080")

result = await client.query(
    prompt="Summarize the contents of the codex repository.",
    options=QueryOptions(
        system_prompt="You are a helpful assistant.",
        model="gpt-4.1",
        pre_agent_downloadables=[downloadable],          # optional
        output_format_json_schema_str='...',         # optional -- omit for text response
        on_assistant_message=on_assistant,            # optional
        on_artifact_upload_request=on_artifact,       # optional -- return ArtifactUploadResult
        timeout=300,                                  # optional -- seconds
    ),
)

if isinstance(result.data, TextResult):
    print(result.data.text)
elif isinstance(result.data, StructuredOutputResult):
    print(result.data.structured_output)

print(result.metadata)  # execution metadata

Command-Only Execution

Use execute_commands() when you need to run shell commands in the sandbox without invoking the agent. This is useful for setup steps, health checks, or any workflow where you only need command exit codes.

from runtimeuse_client import (
    CommandInterface,
    ExecuteCommandsOptions,
    RuntimeUseClient,
)

client = RuntimeUseClient(ws_url="ws://localhost:8080")

result = await client.execute_commands(
    commands=[
        CommandInterface(command="mkdir -p /app/output"),
        CommandInterface(command="echo 'sandbox is ready' > /app/output/status.txt"),
        CommandInterface(command="cat /app/output/status.txt"),
    ],
    options=ExecuteCommandsOptions(
        on_assistant_message=on_assistant,  # optional -- streams stdout/stderr
    ),
)

for item in result.results:
    print(f"{item.command} -> exit code {item.exit_code}")

execute_commands() supports the same streaming, cancellation, timeout, secret redaction, artifact upload, and error semantics as query(). If any command exits non-zero, AgentRuntimeError is raised.

Artifact Upload Handshake

When the agent runtime requests an artifact upload, provide a callback that returns a presigned URL and content type. The client sends the response back automatically.

from runtimeuse_client import ArtifactUploadResult

async def on_artifact(request: ArtifactUploadRequestMessageInterface) -> ArtifactUploadResult:
    presigned_url = await my_storage.create_presigned_url(request.filename)
    content_type = guess_content_type(request.filename)
    return ArtifactUploadResult(presigned_url=presigned_url, content_type=content_type)

When using artifact uploads, set both artifacts_dir and on_artifact_upload_request in QueryOptions; the client validates that they are provided together.

Cancellation

Call client.abort() from any coroutine to cancel a running query. The client sends a cancel message to the runtime and query raises CancelledException.

from runtimeuse_client import CancelledException

async def cancel_after_delay(client, seconds):
    await asyncio.sleep(seconds)
    client.abort()

try:
    asyncio.create_task(cancel_after_delay(client, 30))
    result = await client.query(
        prompt="Do the thing.",
        options=QueryOptions(
            system_prompt="You are a helpful assistant.",
            model="gpt-4.1",
        ),
    )
except CancelledException:
    print("Run was cancelled")

API Reference

Types

Class Description
QueryOptions Configuration for client.query() (prompt options, callbacks, timeout)
QueryResult Return type of query() (.data, .metadata)
ResultMessageInterface Wire-format result message from the runtime
TextResult Result variant when no output schema is specified (.text)
StructuredOutputResult Result variant when an output schema is specified (.structured_output)
AssistantMessageInterface Intermediate assistant text messages
ArtifactUploadRequestMessageInterface Runtime requesting a presigned URL for artifact upload
ArtifactUploadResponseMessageInterface Response with presigned URL sent back to runtime
ErrorMessageInterface Error from the agent runtime
ExecuteCommandsOptions Configuration for client.execute_commands() (callbacks, timeout)
CommandExecutionResult Return type of execute_commands() (.results)
CommandResultItem Per-command result (.command, .exit_code)
CommandInterface Shell command to execute (.command, .cwd)
RuntimeEnvironmentDownloadableInterface File to download into the runtime before invocation

Exceptions

Class Description
AgentRuntimeError Raised when the agent runtime returns an error (carries .error and .metadata)
CancelledException Raised when client.abort() is called during a query

Related Docs

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

runtimeuse_client-0.8.0.tar.gz (135.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

runtimeuse_client-0.8.0-py3-none-any.whl (10.8 kB view details)

Uploaded Python 3

File details

Details for the file runtimeuse_client-0.8.0.tar.gz.

File metadata

  • Download URL: runtimeuse_client-0.8.0.tar.gz
  • Upload date:
  • Size: 135.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for runtimeuse_client-0.8.0.tar.gz
Algorithm Hash digest
SHA256 3a466fc6258afca5c03e10e57735d3c84adaeeb9ca31305c43fc82925589d727
MD5 82ab12327754a4f45288bc18a20fd485
BLAKE2b-256 7fa9416d8b1f57df9d786653fc30b18328ae34b8f6195f6447d031108e6c8729

See more details on using hashes here.

Provenance

The following attestation bundles were made for runtimeuse_client-0.8.0.tar.gz:

Publisher: publish-runtimeuse-client-python.yml on getlark/runtimeuse

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file runtimeuse_client-0.8.0-py3-none-any.whl.

File metadata

File hashes

Hashes for runtimeuse_client-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8d228f7327dd35c4d92ced9c3ad214d43f8642ff7078f917de59950081b0f8dc
MD5 4aaec1334349859d9eed5286546679a2
BLAKE2b-256 0cab8b3ef46d1a2ffbd57bbd0b7b552a806cfbc0ffb25fbc631db3aa7d5ebd0d

See more details on using hashes here.

Provenance

The following attestation bundles were made for runtimeuse_client-0.8.0-py3-none-any.whl:

Publisher: publish-runtimeuse-client-python.yml on getlark/runtimeuse

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page