Field reference
All types below live in agentstage.reconstruction.schema. Every example on this page reconstructs from the local fixture described in the core concepts page.
from examples.fixtures import build_environment
env = build_environment()
invoice_system = env.reconstruct("invoice-agent")
pipeline_system = env.reconstruct("support-pipeline")
team_system = env.reconstruct("support-team")
ToolSpec
A reconstructed tool as a framework-neutral definition. Every field is always populated; there is no unavailable state for ToolSpec itself, only for the source system prompts and orchestration structure it sits alongside.
| Field | Type | Meaning |
|---|---|---|
name | str | The tool's name as observed in the traces. |
description | str | A generated description naming how many historical calls this tool was reconstructed from. Not something the real system necessarily said about itself. |
parameters | dict[str, Any] | JSON Schema for the tool's arguments. No field is ever marked required, since an argument being observed at all does not mean it was present on every call. |
behavior | ToolBehaviorProfile | Everything inferable about this tool's real historical behavior. See below. |
lookup_invoice = invoice_system.tools["lookup_invoice"]
print(lookup_invoice.name)
print(lookup_invoice.description)
print(lookup_invoice.parameters)
lookup_invoice
lookup_invoice (reconstructed from 5 observed historical call(s))
{'type': 'object', 'properties': {'invoice_id': {'type': 'string'}}, 'required': []}
ToolBehaviorProfile
| Field | Type | Meaning |
|---|---|---|
tool_name | str | Matches the owning ToolSpec.name. |
n_calls_observed | int | How many historical calls to this tool were found across the reconstructed trace batch. |
argument_profiles | dict[str, ArgumentProfile] | Per-argument observed shape. See below. |
response_key_set | list[str] | Union of top-level response keys seen across every observed call, sorted. Not assumed to be any particular envelope shape, just whatever this tool's real responses happened to use. |
example_calls | list[ObservedToolCall] | The real (arguments, response) pairs this tool's replay matching draws from, capped by the extractor. |
profile = lookup_invoice.behavior
print(profile.tool_name)
print(profile.n_calls_observed)
print(list(profile.argument_profiles.keys()))
print(profile.response_key_set)
print(len(profile.example_calls))
lookup_invoice
5
['invoice_id']
['amount', 'status']
5
ArgumentProfile
Nested under ToolBehaviorProfile.argument_profiles, one per observed argument name.
| Field | Type | Meaning |
|---|---|---|
observed_types | list[str] | Python type names seen for this argument's value, sorted. |
distinct_value_count | int | Count of distinct values observed for this argument. |
sample_values | list[Any] | Real observed values, capped by the extractor. |
numeric_range | tuple[float, float] | None | (min, max) across every observed numeric value for this argument, or None if it was never numeric. |
string_length_range | tuple[int, int] | None | (min, max) string length across every observed string value, or None if it was never a string. |
A string-valued argument, where numeric_range is genuinely None:
ap = profile.argument_profiles["invoice_id"]
print(ap.observed_types)
print(ap.distinct_value_count)
print(ap.sample_values)
print(ap.numeric_range)
print(ap.string_length_range)
['str']
5
['inv_1001', 'inv_1002', 'inv_1003', 'inv_1004', 'inv_1005']
None
(8, 8)
A numeric-valued argument (support-pipeline's issue_refund tool takes a refund amount), where string_length_range would instead be None:
issue_refund = pipeline_system.tools["issue_refund"]
amount_profile = issue_refund.behavior.argument_profiles["amount"]
print(amount_profile.observed_types)
print(amount_profile.numeric_range)
print(amount_profile.sample_values)
['float']
(19.99, 89.5)
[19.99, 45.0, 89.5]
ObservedToolCall
Nested under ToolBehaviorProfile.example_calls. This is the raw material replay matching scores against.
| Field | Type | Meaning |
|---|---|---|
arguments | dict[str, Any] | The real arguments of one historical call. |
response | Any | The real response that call returned. |
observed_at | str | None | The observation's timestamp in the source trace, if present. |
call = profile.example_calls[0]
print(call.arguments)
print(call.response)
print(call.observed_at)
{'invoice_id': 'inv_1001'}
{'status': 'paid', 'amount': 129.0}
2026-01-01T09:00:02Z
OrchestrationGraph
| Field | Type | Meaning |
|---|---|---|
source | "observed" | "unavailable" | Whether any role/edge evidence exists at all. |
nodes | list[OrchestrationNode] | Every reconstructed role. |
edges | list[OrchestrationEdge] | Every observed control-flow transition. |
entry_role | str | None | The role that received the initial input, most often across the batch. None only when source == "unavailable". |
terminal_roles | list[str] | Roles with no observed outgoing edge. |
pattern | "single_agent" | "pipeline" | "supervisor_delegates" | "unclassified" | A classification derived purely from the graph's shape. |
A real multi-role graph:
o = team_system.orchestration
print(o.source)
print(o.pattern)
print(o.entry_role)
print(o.terminal_roles)
print(len(o.nodes), len(o.edges))
observed
supervisor_delegates
supervisor
['researcher', 'writer']
3 4
source == "unavailable" only happens when there is no trace data to reconstruct orchestration structure from at all, for example reconstructing from an empty trace batch:
from agentstage.reconstruction.build import build_reconstructed_system
empty_system = build_reconstructed_system([], label="empty", project_id="demo_project", source_agent_name=None)
print(empty_system.orchestration.source)
print(empty_system.orchestration.nodes)
print(empty_system.orchestration.edges)
print(empty_system.orchestration.pattern)
unavailable
[]
[]
unclassified
nodes and edges are empty and pattern sits at its unclassified default. This is a stricter, rarer state than a real reconstructed single_agent system, which has source == "observed" with one node and zero edges, a genuine positive observation that everything happens in one flat role, not a gap.
OrchestrationNode
| Field | Type | Meaning |
|---|---|---|
role | str | The role identifier, lowercased, used to key edges, entry_role, terminal_roles, and ReconstructedSystem.role(...). |
name | str | The role's display name as first seen in the traces. |
node = o.nodes[0]
print(node.role, node.name)
researcher researcher
OrchestrationEdge
| Field | Type | Meaning |
|---|---|---|
from_role | str | The role the transition was observed from. |
to_role | str | The role the transition was observed into. |
trigger | str | None | What was observed to cause the handoff, for example "handoff" (an explicit transfer_to_x-style observation name) or "nested_span" (a role change inferred from a nested observation's own metadata). Descriptive, not a guarantee of the real system's internal mechanism, since traces only show what was instrumented. |
n_observed | int | How many times this exact (from_role, to_role, trigger) transition was seen across the batch. |
edge = o.edges[0]
print(edge.from_role, edge.to_role, edge.trigger, edge.n_observed)
supervisor researcher handoff 3
RoleSpec
| Field | Type | Meaning |
|---|---|---|
role | str | Matches the corresponding OrchestrationNode.role. |
name | str | Display name. |
system_prompt | str | The real observed system prompt text, or the fixed placeholder string "[unavailable — no system prompt observed in source traces]" when none was captured. |
system_prompt_source | "observed" | "unavailable" | Which of the two system_prompt actually is. |
tools | list[str] | Tool names attributed to this specific role. |
A role with an observed prompt:
researcher = team_system.role("researcher")
print(researcher.role)
print(researcher.name)
print(researcher.system_prompt_source)
print(researcher.system_prompt)
print(researcher.tools)
researcher
researcher
observed
You research internal documentation to answer support questions accurately.
['search_docs']
The same system's writer role, where the fixture deliberately never captured a system prompt:
writer = team_system.role("writer")
print(writer.system_prompt_source)
print(writer.system_prompt)
unavailable
[unavailable — no system prompt observed in source traces]
ReconstructedSystem itself (label, roles, tools, orchestration, provenance) and ReconstructionProvenance (trace_count, source_agent_name, other_groups_found, warnings, extraction_date) are covered with real examples in the core concepts page rather than repeated here.