RemoteWorkflow

Execute workflows hosted on a remote AgentOS or A2A server.

RemoteWorkflow runs workflows hosted on a remote AgentOS instance or A2A-compatible server.

Installation

uv pip install -U 'agno[os]'
export OS_SECURITY_KEY=your_os_security_key_here

Start the Python client example server on port 7778. Its setup installs the server dependencies, sets OPENAI_API_KEY, and registers qa-workflow. Use the same OS_SECURITY_KEY in the client terminal.

Basic Usage

import asyncio
import os
from agno.workflow import RemoteWorkflow

async def main():
    # Create a remote workflow pointing to a remote AgentOS instance
    workflow = RemoteWorkflow(
        base_url="http://localhost:7778",
        workflow_id="qa-workflow",
    )

    # Run the workflow (async)
    response = await workflow.arun("What are the benefits of Python?", auth_token=os.environ["OS_SECURITY_KEY"])
    print(response.content)

asyncio.run(main())

Unless labeled as complete programs, later snippets are fragments for this async main() with the same workflow and os imports.

Parameters

ParameterTypeDefaultDescription
base_urlstrRequiredBase URL of the remote AgentOS instance (e.g., "http://localhost:7778")
workflow_idstrRequiredID of the remote workflow to execute
timeoutfloat300.0Request timeout in seconds
protocolLiteral["agentos", "a2a"]"agentos"Communication protocol: AgentOS REST API or A2A for cross-framework communication
a2a_protocolLiteral["json-rpc", "rest"]"rest"Transport used when protocol="a2a": JSON-RPC or REST
config_ttlfloat300.0Time-to-live for cached configuration in seconds

Properties

Metadata access can make synchronous requests when the cache is empty or expired. Properties and configuration methods do not forward the run's auth_token; they require metadata access without a bearer credential. For the protected example server, use AgentOSClient.aget_workflow() with explicit Authorization headers. See client reference.

id

Returns the workflow ID.

print(workflow.id)  # "qa-workflow"

name

Returns the workflow's name from the remote configuration.

print(workflow.name)  # "QA Workflow"

description

Returns the workflow's description from the remote configuration.

print(workflow.description)  # "A Q&A workflow for answering questions"

db

Returns a RemoteDb instance if the workflow has a database configured.

if workflow.db:
    print(f"Database ID: {workflow.db.id}")

Methods

arun

Execute the remote workflow asynchronously.

# Non-streaming
response = await workflow.arun(
    "Explain machine learning",
    auth_token=os.environ["OS_SECURITY_KEY"],
    user_id="user-123",
    session_id="session-456",
)
print(response.content)
print(f"Status: {response.status}")

# Streaming
async for event in workflow.arun(
    "Generate a report",
    auth_token=os.environ["OS_SECURITY_KEY"],
    stream=True,
    user_id="user-123",
):
    if event.event == "WorkflowCompleted":
        print(event.content)
    elif event.event in {"WorkflowError", "WorkflowCancelled", "WorkflowPaused"}:
        print(event.event)

Parameters:

ParameterTypeDefaultDescription
inputstr | Dict | List | BaseModelRequiredThe input for the workflow
additional_dataOptional[Dict]NoneAdditional data to pass to the workflow
user_idOptional[str]NoneUser ID for the run
run_idOptional[str]NoneCustom run ID
session_idOptional[str]NoneSession ID for context persistence
session_stateOptional[Dict]NoneSession state dictionary
imagesOptional[List[Image]]NoneImages to include
audioOptional[List[Audio]]NoneAudio to include
videosOptional[List[Video]]NoneVideos to include
filesOptional[List[File]]NoneFiles to include
streamboolFalseWhether to stream the response
stream_eventsOptional[bool]NoneWhether to stream events
auth_tokenOptional[str]NoneJWT token for authentication

Returns:

  • WorkflowRunOutput when stream=False
  • AsyncIterator[WorkflowRunOutputEvent] when stream=True

acontinue_run

Continue a paused workflow run through the AgentOS protocol. The example below assumes paused is the actual WorkflowRunOutput from a server workflow with confirmation pauses and persistent storage. The basic QA server does not pause automatically. Keep the original requirements, run ID, session ID, and authenticated identity. Different pause kinds need their matching resolution methods; see workflow HITL.

from agno.run.base import RunStatus

if paused.status != RunStatus.paused or not paused.run_id or not paused.session_id:
    raise ValueError("Expected the original persisted paused workflow run")
for requirement in paused.active_step_requirements:
    if not requirement.needs_confirmation:
        raise ValueError("Resolve this pause using its matching HITL handler")
    if input("Approve this step? [y/N] ").lower() == "y":
        requirement.confirm()
    else:
        requirement.reject()
response = await workflow.acontinue_run(
    run_response=paused,
    auth_token=os.environ["OS_SECURITY_KEY"],
)

Parameters:

ParameterTypeDefaultDescription
run_responseOptional[WorkflowRunOutput]NonePaused run output containing the run ID, session ID, and requirements
run_idOptional[str]NoneRun ID. Required unless run_response supplies one
session_idOptional[str]NoneSession ID. Overrides the ID from run_response
step_requirementsOptional[List[Any]]NoneResolved requirements. Overrides requirements from run_response
streamboolFalseWhether to stream the continued run
auth_tokenOptional[str]NoneJWT token for authentication

Returns:

  • WorkflowRunOutput when stream=False
  • AsyncIterator[WorkflowRunOutputEvent] when stream=True

acancel_run

Request cancellation through the AgentOS protocol using a real saved_run_id from a still-running execution. A successful request records intent; it does not prove execution has stopped.

success = await workflow.acancel_run(run_id=saved_run_id, auth_token=os.environ["OS_SECURITY_KEY"])
if success:
    print("Cancellation requested")

Parameters:

ParameterTypeDefaultDescription
run_idstrRequiredID of the run to cancel
auth_tokenOptional[str]NoneJWT token for authentication

Returns: bool — whether the request succeeded. Errors return False.

The wrapper cannot supply a session_id. For scoped authentication that requires the original session, send direct HTTP POST /workflows/qa-workflow/runs/{run_id}/cancel?session_id={session_id} with the same bearer identity. Continuation and cancellation are AgentOS-protocol operations, not A2A operations.

get_workflow_config

Get the workflow configuration from the remote server (always fetches fresh).

config = await workflow.get_workflow_config()
print(f"Workflow name: {config.name}")
print(f"Steps: {config.steps}")

Returns: WorkflowResponse

refresh_config

Force refresh the cached workflow configuration through the AgentOS protocol.

config = await workflow.refresh_config()

Returns: WorkflowResponse

A2A Protocol Support

RemoteWorkflow supports the A2A REST and JSON-RPC transports below. The A2A execution path forwards message, media, user identity, and the session as context_id. AgentOS-specific run IDs, session state, additional data, and stream-event controls are not forwarded.

Connecting to Agno A2A Servers

Install uv pip install -U "agno[os,a2a]". This fragment requires a separate A2A server exposing my-workflow at the displayed path; it is not provided by the Python client example server. See A2A setup.

from agno.workflow import RemoteWorkflow

# Connect to an Agno AgentOS with A2A interface
workflow = RemoteWorkflow(
    base_url="http://localhost:7001/a2a/workflows/my-workflow",
    workflow_id="my-workflow",
    protocol="a2a",
)

response = await workflow.arun("Hello!")
print(response.content)

Protocol Options

Protocola2a_protocolUse Case
"agentos"N/ADefault. Connect to Agno AgentOS REST API
"a2a""rest"Connect to A2A servers using REST endpoints
"a2a""json-rpc"Connect to Google ADK or pure JSON-RPC A2A servers

Using in AgentOS Gateway

This gateway configuration fragment requires the two deployed servers below. Discovery has the same unauthenticated metadata limitation described above:

from agno.workflow import RemoteWorkflow
from agno.os import AgentOS

agent_os = AgentOS(
    workflows=[
        RemoteWorkflow(base_url="http://server-1:7777", workflow_id="qa-workflow"),
        RemoteWorkflow(base_url="http://server-2:7777", workflow_id="analysis-workflow"),
    ],
)

See AgentOS Gateway for more details.

Streaming Example

Complete client program for the protected QA example server. Read the workflow's final content once; this also works for function-only workflows that emit no model-content deltas.

import asyncio
import os
from agno.workflow import RemoteWorkflow

async def main():
    workflow = RemoteWorkflow(base_url="http://localhost:7778", workflow_id="qa-workflow")
    async for event in workflow.arun(
        "Explain machine learning",
        stream=True,
        auth_token=os.environ["OS_SECURITY_KEY"],
    ):
        if event.event == "WorkflowCompleted":
            print(event.content)
        elif event.event in {"WorkflowError", "WorkflowCancelled", "WorkflowPaused"}:
            print(event.event)

asyncio.run(main())

For streaming continuation, await workflow.acontinue_run(..., stream=True) first, then iterate the returned asynchronous iterator.

Error Handling

from agno.exceptions import RemoteServerUnavailableError

try:
    response = await workflow.arun("Hello", auth_token=os.environ["OS_SECURITY_KEY"])
except RemoteServerUnavailableError as e:
    print(f"Remote server unavailable: {e.message}")

Authentication

For authenticated AgentOS instances, pass the auth_token parameter:

response = await workflow.arun(
    "Process this request",
    auth_token="your-jwt-token",
)

Notes

Remote Workflows via WebSocket are not yet supported. Use HTTP streaming instead.