Agent, AgentTeam, and AgentFlow now tells you — from repr() alone or via where_does_it_run() — where the model runs and where the tools run.
Quick Start
1
Ask an agent where it runs
2
A workflow with a shared sandbox
3
Read the answer as a dictionary
Three topologies at a glance
tools_run_on= moves the tools out but keeps the model call local. A whole-loop backend moves both off this machine — hosted on a vendor’s cloud, or self-hosted in a container you own. The repr names both places, so you can tell them apart at a glance.
There is no
HostedAgent class to import today. When a backend= object reports its provider as anthropic (its class name contains Hosted or Anthropic and it exposes a .provider), both places become Anthropic's cloud. You can see the exact phrasing without any backend using say_place:How the object knows
repr() asks a single shared helper — describe() — which reads three attributes off the object and turns provider names into plain phrases.
describe() never raises — if a property throws, thinks_on falls back to this machine so that describing where something runs can never break the thing it describes.
_backend_places() now asks the backend via provider_name rather than name-matching the class. A self-hosted backend (like run_on="docker") used to be misreported as thinking on this machine because its class name did not contain Hosted or Anthropic; asking it what it is fixes that — the whole-loop container is now reported as a Docker container for both places.
What each place name means
Provider names map to phrases a non-developer can read. These are the exact strings the object returns.
Two public aliases resolve to the backend that actually runs — the alias name never appears in the output:
An unknown provider falls back to its own name:
say_place("some-new-cloud") returns "some-new-cloud".
local means two different backends depending on which parameter carried it, so the phrase depends on where the word came from. run_in="local" collapses to the subprocess backend; tools_run_on="local" is a plain shell with no policy. Pass via="compute" for the tools_run_on= reading:
The subprocess warning
Asandbox=True agent runs tools in a separate process — but a separate process is not a security boundary.
~/.ssh stays readable under a subprocess. A real container (run_on="docker") is a real boundary, so it does not trigger this note. See Sandbox for the same warning in depth.
Configuration Options
This page adds no new knobs — where things run comes fromsandbox=, run_on=, and backend=, documented on the sandbox pages below. The only new vocabulary is the field names the object returns:
The field is
thinks_on / tools_run_on, never loop — that word already means the workflow loop() primitive, asyncio’s event loop, and agent-loop jargon, so it was deliberately rejected.
Sandbox
Per-agent
sandbox= and the explicit execute_code() APIShared Sandbox
run_on= gives a whole flow one shared sandboxCommon Patterns
Check where things run before a paid run, log it at startup, or assert it in a test.Best Practices
Print the object, don't guess where it runs
Print the object, don't guess where it runs
The repr is now the primary source of truth.
repr(agent) names both places, so you never have to consult docs to learn whether tools run locally or in a container.Believe the 'not a security boundary' note
Believe the 'not a security boundary' note
Under a subprocess the network is reachable and
~/.ssh is readable. Use docker or a cloud provider for untrusted code — the note appears precisely because that isolation is bypassable.Call describe() for programmatic access
Call describe() for programmatic access
The string format is for humans. For the raw dict, call
describe(obj) from praisonaiagents.agent.execution_location — it returns {thinks_on, tools_run_on, code_runs_on?} and never raises.Related
Sandbox
Per-agent
sandbox=Shared Sandbox
One shared sandbox with
run_on=Sandboxed Agent
Local loop, sandboxed tools
Self-Hosted Agent (Docker)
run_on="docker" — the whole loop self-hosted
