Skip to main content

Runtime

runtime.py starts the local ProtoLink mesh for a single run. It is the main runtime integration point between ProtoAgent and ProtoLink.

Entry Point

run_selected_model(prompt, workspace=None, session_id=None, progress_path=None, user_prompt=None)

Steps:

  1. Load config and selected provider/model.
  2. Resolve the prompt profile and optional Scout setting.
  3. Create a RuntimeBridge for progress, approvals, and cancellation.
  4. Run _run_agent_deck() in an asyncio event loop.
  5. Clean up bridge control files.

If no model is selected for the active provider, runtime startup raises an error and agent_engine.process_prompt() returns fallback diagnostics.

Runtime Objects

Inside _run_agent_deck():

ObjectPurpose
RegistryLocal HTTP registry used for agent discovery.
AgentClientSends task to Architect and streams events.
TaskUser request task.
RunContextSession id, workspace URI, permissions, budget, metadata, run id, trace id.
RunBudgetTyped runtime budget from environment/provider settings.
ProtoAgent RunContractTask kind, required workers, required write artifacts, and completion rule derived from the original user prompt.
RunRecorderCaptures normalized RunEvents and builds a redacted RunReport.
RuntimeBridgeEmits CLI progress, handles approvals, watches cancellation.

Run Contracts

run_contracts.py derives a contract before the model receives the prompt. Runtime attaches it to:

RunContext.metadata["run_contract"]

Read-only repository questions do not require write artifacts. Workspace-change tasks require one of these terminal signals:

  1. Coder delegation in the normalized run events.
  2. A write approval request or diff preview artifact.
  3. An explicit blocker in the model answer.

After Architect returns, runtime calls validate_run_completion(). If a write task ended as prose without Coder, approval/diff artifacts, or blocker, the runtime changes the status to incomplete and prefixes the answer with a completion-guard message.

RunContext Permissions

The top-level run context grants app-level permissions:

PermissionEffect
agent.delegateallow
workspace.readallow
workspace.writeallow
network.readallow at the run level; only enabled Scout's deny-by-default agent policy exposes it

Agent-specific CapabilityPolicy still applies. Coder's workspace.write policy requires approval even though the top-level context permits the category.

URLs And Transports

The runtime resolves URLs for Registry, client, Architect, Explorer, Coder, and enabled Scout. By default it binds free localhost ports.

Environment overrides:

VariablePurpose
PROTOAGENT_RUNTIME_HOSTHost used for generated local URLs. Defaults to 127.0.0.1.
PROTOAGENT_REGISTRY_URL or REGISTRY_URLRegistry URL override.
PROTOAGENT_CLIENT_URL or CLIENT_URLClient URL override.
PROTOAGENT_ARCHITECT_URL or ARCHITECT_AGENT_URLArchitect URL override.
PROTOAGENT_EXPLORER_URL or EXPLORER_AGENT_URLExplorer URL override.
PROTOAGENT_CODER_URL or CODER_AGENT_URLCoder URL override.
PROTOAGENT_SCOUT_URL or SCOUT_AGENT_URLOptional Scout URL override.

Agent transport:

PROTOAGENT_AGENT_TRANSPORT=sse
PROTOAGENT_AGENT_TRANSPORT=http

Aliases such as jsonrpc, json-rpc, sse-jsonrpc, and sse-json-rpc map to sse.

ProtoAgent constructs concrete transports through ProtoLink's shared TransportConfig contract. ProtoLink therefore owns payload and concurrency limits, idempotency, lifecycle health, shutdown, capabilities, and operational metrics for the Registry, each agent, and the CLI-side AgentClient. The core does not maintain a parallel retry, health, or transport-metrics layer.

ProtoLink 0.6.6 also accepts grpc when the separate protolink[grpc] extra is installed. It remains opt-in rather than adding grpcio to every local CLI installation. TLS and multi-interface agent metadata are likewise left to networked deployments because ProtoAgent's embedded mesh uses loopback HTTP/SSE by default.

Streaming can be disabled independently:

PROTOAGENT_STREAM=0

Startup Sequence

Streaming Event Handling

_send_task_streaming() consumes AgentClient.send_task_streaming().

It suppresses raw token chunks, records useful events with RunRecorder, emits summary rows to the Rust progress bridge, and extracts final content from:

  1. Final task metadata.
  2. Final LLM stream content.
  3. Artifact content fallback.

If streaming is unavailable for a transport, runtime falls back to one-shot send_task().

Each completed core response includes a transport_report containing the first-party configuration, capabilities, and TransportMetricsSnapshot for the Registry, client, and all enabled agent transports. The shell CLI summarizes client request, stream, retry, and byte counters; the TUI keeps the full report in response details.

Optional Scout Startup

When optional_agents.scout.enabled is false, Scout is not constructed, started, or registered. When true, runtime adds a tool-only agent with ProtoLink 0.6.6 web_search and fetch_url tools and a deny-by-default policy allowing only network.read. Registration performs no outbound request. Architect discovery then includes Scout, and the transport report includes its transport.

Run Reports

After delivery, runtime builds a redacted RunReport:

recorder.to_report(
context=final_context,
final_task=final_task,
metadata={
"application": "protoagent",
"interface": "rust-cli",
"provider": provider,
"model": model,
},
)

Rust stores this in CoreResponse.run_report so users can inspect structured diagnostics. CoreResponse.status can be answered, blocked, canceled, or incomplete.

Run Budgets

Environment variables populate RunBudget:

VariableBudget field
PROTOAGENT_RUN_MAX_STEPSmax_steps
PROTOAGENT_RUN_MAX_LLM_CALLSmax_llm_calls
PROTOAGENT_RUN_MAX_TOOL_CALLSmax_tool_calls
PROTOAGENT_RUN_MAX_SECONDSmax_runtime_seconds
PROTOAGENT_RUN_MAX_INPUT_TOKENSmax_input_tokens
PROTOAGENT_RUN_MAX_OUTPUT_TOKENSmax_output_tokens

For Ollama, max_input_tokens comes from the effective Ollama context window. For other providers, it comes from the environment or provider config.

The embedded mesh intentionally keeps the Registry on HTTP even when agent transport is set to SSE, HTTP, or optional gRPC. In ProtoLink 0.6.6, switching this Registry path to the runtime transport exposes an AgentCard list serialization mismatch in RegistryClient.discover(). ProtoAgent keeps the working first-party Registry rather than adding a local discovery layer.

Direct delegated Scout tool calls still receive ProtoLink capability policy, authentication, and cancellation handling. ProtoLink 0.6.6 applies BudgetEnforcer.check_tool_call() inside the LLM infer-loop tool path, not the direct delegated tool path, so RunBudget.max_tool_calls does not currently cap those Scout calls. Scout remains opt-in while this is tracked upstream; the application does not duplicate ProtoLink's budget engine.

Local Trace Telemetry

Enable ProtoLink local trace telemetry:

PROTOAGENT_TRACE=1 proto-cli run "task"

Trace file:

~/.protoagent/traces.jsonl

or:

${PROTOAGENT_CONFIG_DIR}/traces.jsonl

Cancellation

The runtime starts _monitor_cancellation() while the task is active. It polls the bridge's cancel file and sends a TaskCancellationRequest:

  1. First to the in-process Architect agent, if available.
  2. Then through AgentClient.cancel_task().

The preflight cancellation path handles the case where the user cancels before agent startup finishes. It cancels the RunContext and Task, then returns a normal canceled result.