Architecture helpers
Helpers for working with architectures directly.
run_architecture runs an architecture once without you building an
Agent (handy in tests), resolve_architecture turns a string like
"react" into an architecture instance, and parse_score reads a
0–1 score out of an evaluator’s reply.
from loomflow.architecture import resolve_architecture
from loomflow.architecture.helpers import parse_score
from loomflow.team import run_architecturerun_architecture
async def run_architecture(
architecture: Architecture,
prompt: str,
*,
instructions: str = "",
model: Model | str | None = None,
memory: Memory | None = None,
runtime: Runtime | None = None,
budget: Budget | None = None,
permissions: Permissions | None = None,
hooks: HookRegistry | None = None,
tools: list[Tool | Callable[..., object]] | ToolHost | Tool | Callable[..., object] | None = None,
telemetry: Telemetry | None = None,
audit_log: AuditLog | None = None,
max_turns: int = 50,
auto_consolidate: bool = False,
) -> RunResult: ...Build a minimal Agent around any Architecture instance and run
it once. Useful for testing orchestrators in isolation without
wiring a full Agent yourself.
| Parameter | Type | Default | Description |
|---|---|---|---|
architecture | Architecture | required | The orchestrator to run. |
prompt | str | required | The user message. |
instructions | str | "" | System prompt for the shell Agent. |
model | Model | str | None | None | The model the architecture’s Dependencies will see. There is no default model, so pass one. |
memory / runtime / budget / permissions / hooks / tools / telemetry / audit_log / max_turns / auto_consolidate | Agent defaults | Forwarded to the shell Agent. |
It doesn’t take per-run options such as user_id or
output_schema; for those, build an Agent(architecture=...) and
call run().
Returns a RunResult, the same shape as agent.run().
Example: testing a Supervisor in isolation
import pytest
from loomflow import Agent, ScriptedModel, ScriptedTurn, ToolCall
from loomflow.architecture import Supervisor
from loomflow.team import run_architecture
@pytest.mark.anyio
async def test_supervisor_delegates_to_writer():
writer = Agent(
"Write the answer.",
model=ScriptedModel(turns=[ScriptedTurn(text="Hello world.")]),
)
supervisor_model = ScriptedModel(turns=[
ScriptedTurn(tool_calls=[
ToolCall(id="c1", tool="delegate",
args={"worker": "writer", "instructions": "Say hello."}),
]),
ScriptedTurn(text="Here you go: Hello world."),
])
sup = Supervisor(workers={"writer": writer})
result = await run_architecture(sup, "say hello", model=supervisor_model)
assert "Hello world" in result.outputresolve_architecture
def resolve_architecture(spec: Architecture | str | None) -> Architecture: ...Coerce an architecture spec to a concrete Architecture instance.
Used internally by Agent.__init__; exposed for callers that want
the same coercion semantics.
spec | Resolves to |
|---|---|
None | ReAct() (the default) |
str | Looked up in the KNOWN map (see below), then in installed entry points |
Architecture instance | Returned as-is |
Unknown strings raise ConfigError with the list of known names.
Known string specs
| String | Resolves to |
|---|---|
"react" | ReAct() |
"plan-and-execute" | PlanAndExecute() |
"rewoo" | ReWOO() |
"reflexion" | Reflexion() |
"self-refine" | SelfRefine() |
"tree-of-thoughts" | TreeOfThoughts() |
Multi-agent architectures (Supervisor / Router / Swarm / Debate /
ActorCritic / Blackboard) require an instance. The string resolver
only knows single-agent loops, since multi-agent shapes need
worker Agents as constructor arguments.
Example
from loomflow.architecture import resolve_architecture
resolve_architecture(None) # ReAct()
resolve_architecture("react") # ReAct()
resolve_architecture("plan-and-execute") # PlanAndExecute()
resolve_architecture("bogus") # raises ConfigError
from loomflow.architecture import Supervisor
arch = Supervisor(workers={"a": agent_a})
resolve_architecture(arch) is arch # True (returned as-is)Entry-point discovery
Third-party packages can register custom architectures under
[project.entry-points."loomflow.architecture"], so users can refer
to them by string without an explicit import. Built-in names win over
entry-point names with the same key. Discovery is cached on first
lookup.
parse_score
def parse_score(text: str) -> float: ...Read a score in [0.0, 1.0] out of a model’s free-form reply. The
Reflexion and Tree of Thoughts evaluators and the ActorCritic critic
are scored with it, so it is what your custom evaluator_prompt or
critique_template has to satisfy. Use it in a custom architecture
with an evaluator step. It lives in loomflow.architecture.helpers
and is not re-exported from loomflow.architecture.
It looks for, in order: a "score" field in a JSON object (found
inside prose or a code fence too), a score: / score= / rating:
label, an unlabelled fraction, a line holding only a 0–1 number, and
a decimal in prose. Scales are read as scales:
| Reply | Score |
|---|---|
score: 0.3, **Score:** 0.3, Score (0-1): 0.3 | 0.3 |
score: 7/10, 2 out of 10 | 0.7, 0.2 |
score: 40%, {"score": "40%"} | 0.4 |
score: 7, {"score": 7} (2 or more with no scale is out of 10; above 10, out of 100) | 0.7 |
0.7 alone on a line, scored 0.6 overall | 0.7, 0.6 |
score: -3 | 0.0 |
1 issue remains (a bare integer in prose is not a score) | 0.0 |
Results are clamped to [0.0, 1.0], and a reply with no score
returns 0.0, which the built-in architectures treat as a failed
evaluation. (Before 0.17, score: 3/10 and score: 40% read as
1.0, a false success, and so did score: 7.)
from loomflow.architecture.helpers import parse_score
parse_score("Score: 7/10. Mostly right.") # 0.7
parse_score('Review: {"score": "40%"}') # 0.4
parse_score("No score here.") # 0.0Source
loomflow/architecture/resolver.py ·
loomflow/team.py (the run_architecture definition) ·
loomflow/architecture/helpers.py (parse_score)
run_architecture vs Team.*. Team.* builders return an
Agent you keep around for many runs. run_architecture builds a
single-use shell, runs once and returns the result. Use Team for
production wiring; use run_architecture for tests and one-off
explorations.