nat.atif#

Pydantic models for Agent Trajectory Interchange Format (ATIF).

Models are derived from the Harbor reference implementation (harbor-framework/harbor) and follow the ATIF RFC (0001-trajectory-format). NAT-specific relaxations are documented inline in the individual model files.

Backward-compatible aliases (ATIFStep, ATIFTrajectory, and so on) are provided so existing code can continue to work without import changes.

Submodules#

Attributes#

Classes#

Agent

Agent system identification and configuration.

AtifAncestry

Validated ancestry metadata embedded in ATIF extra dicts.

AtifInvocationInfo

Invocation timing metadata embedded in ATIF extra dicts.

AtifStepExtra

Validated structure for NAT-owned ATIF Step.extra payload.

AtifToolCallExtra

Validated structure for NAT-owned ATIF ToolCall.extra payload.

ContentPart

A single content part within a multimodal message.

ImageSource

Image source specification for images stored as files or at remote URLs.

FinalMetrics

Aggregate statistics for the entire trajectory.

Metrics

LLM operational and confidence data for a single step.

Observation

Environment feedback/result after actions or system events.

ObservationResult

A single result within an observation.

Step

A single step in an ATIF trajectory.

SubagentTrajectoryRef

Reference to a delegated subagent trajectory (ATIF v1.7).

ToolCall

A tool call within a step.

Trajectory

ATIF trajectory — the complete interaction history of an agent run.

Package Contents#

class Agent(/, **data: Any)#

Bases: pydantic.BaseModel

Agent system identification and configuration.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

name: str = None#
version: str = None#
model_name: str | None = None#
tool_definitions: list[dict[str, Any]] | None = None#
extra: dict[str, Any] | None = None#
model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class AtifAncestry(/, **data: Any)#

Bases: pydantic.BaseModel

Validated ancestry metadata embedded in ATIF extra dicts.

Used in two locations under the NAT convention:

  • Step.extra["ancestry"] — step-level: which callable produced this step (e.g. an LLM node under a parent agent).

  • ToolCall.extra["ancestry"] — per-tool-call: which callable issued this tool invocation.

The model enforces a parent-pair invariant: parent_name MAY only be set when parent_id is also set. The inverse — parent_id set, parent_name unset — is allowed (the converter emits this when a parent’s UUID isn’t in the local name map).

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

function_id: str = None#
function_name: str = None#
parent_id: str | None = None#
parent_name: str | None = None#
_validate_parent_pair() Self#
class AtifInvocationInfo(/, **data: Any)#

Bases: pydantic.BaseModel

Invocation timing metadata embedded in ATIF extra dicts.

Used at Step.extra["invocation"] for step-level timing and at ToolCall.extra["invocation"] for per-tool timing.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

start_timestamp: float | None = None#
end_timestamp: float | None = None#
invocation_id: str | None = None#
status: str | None = None#
framework: str | None = None#
validate_timestamp_pairing() Self#
class AtifStepExtra(/, **data: Any)#

Bases: pydantic.BaseModel

Validated structure for NAT-owned ATIF Step.extra payload.

NAT writes the following keys into Step.extra under this convention:

  • ancestry (required by NAT’s converter) — AtifAncestry shape: which callable produced this step.

  • invocation (optional) — AtifInvocationInfo shape: step-level timing.

  • data_schema (optional, opaque dict) — the producer-declared ATOF data_schema preserved for downstream validation.

Per-tool-call ancestry and timing live on ToolCall.extra, NOT here — they’re co-located with the tool_call they describe rather than aligned by index on the parent step. This is the v1.7-aligned layout (the spec adds extra to ToolCall for this purpose).

model_config = ConfigDict(extra="allow") so callers MAY add additional keys. The required ancestry field documents NAT’s own convention but does not preclude other producers from emitting different Step.extra shapes.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

ancestry: AtifAncestry = None#
invocation: AtifInvocationInfo | None = None#
class AtifToolCallExtra(/, **data: Any)#

Bases: pydantic.BaseModel

Validated structure for NAT-owned ATIF ToolCall.extra payload.

NAT writes the following keys into ToolCall.extra under this convention:

  • ancestry (optional) — AtifAncestry shape: which callable issued this tool invocation.

  • invocation (optional) — AtifInvocationInfo shape: per-tool-call timing.

model_config = ConfigDict(extra="allow") so callers MAY add additional keys. extra="allow" also means a ToolCall.extra that lacks both keys still validates — neither is required by the NAT convention.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

ancestry: AtifAncestry | None = None#
invocation: AtifInvocationInfo | None = None#
class ContentPart(/, **data: Any)#

Bases: pydantic.BaseModel

A single content part within a multimodal message.

Used when a message or observation contains mixed content types (text and images). For text-only content, a plain string can still be used instead of a ContentPart array.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

type: Literal['text', 'image'] = None#
text: str | None = None#
source: ImageSource | None = None#
model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

validate_content_type() ContentPart#

Validate that the correct fields are present for each content type.

class ImageSource(/, **data: Any)#

Bases: pydantic.BaseModel

Image source specification for images stored as files or at remote URLs.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

media_type: Literal['image/jpeg', 'image/png', 'image/gif', 'image/webp'] = None#
path: str = None#
model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class FinalMetrics(/, **data: Any)#

Bases: pydantic.BaseModel

Aggregate statistics for the entire trajectory.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

total_prompt_tokens: int | None = None#
total_completion_tokens: int | None = None#
total_cached_tokens: int | None = None#
total_cost_usd: float | None = None#
total_steps: int | None = None#
extra: dict[str, Any] | None = None#
model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class Metrics(/, **data: Any)#

Bases: pydantic.BaseModel

LLM operational and confidence data for a single step.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

prompt_tokens: int | None = None#
completion_tokens: int | None = None#
cached_tokens: int | None = None#
cost_usd: float | None = None#
prompt_token_ids: list[int] | None = None#
completion_token_ids: list[int] | None = None#
logprobs: list[float] | None = None#
extra: dict[str, Any] | None = None#
model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class Observation(/, **data: Any)#

Bases: pydantic.BaseModel

Environment feedback/result after actions or system events.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

results: list[nat.atif.observation_result.ObservationResult] = None#
model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class ObservationResult(/, **data: Any)#

Bases: pydantic.BaseModel

A single result within an observation.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

source_call_id: str | None = None#
content: str | list[nat.atif.content.ContentPart] | None = None#
subagent_trajectory_ref: list[nat.atif.subagent_trajectory_ref.SubagentTrajectoryRef] | None = None#
extra: dict[str, Any] | None = None#
model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class Step(/, **data: Any)#

Bases: pydantic.BaseModel

A single step in an ATIF trajectory.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

step_id: int = None#
timestamp: str | None = None#
source: Literal['system', 'user', 'agent'] = None#
model_name: str | None = None#
reasoning_effort: str | float | None = None#
message: str | list[nat.atif.content.ContentPart] = None#
reasoning_content: str | None = None#
tool_calls: list[nat.atif.tool_call.ToolCall] | None = None#
observation: nat.atif.observation.Observation | None = None#
metrics: nat.atif.metrics.Metrics | None = None#
is_copied_context: bool | None = None#
extra: dict[str, Any] | None = None#
llm_call_count: int | None = None#
model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

classmethod validate_timestamp(v: str | None) str | None#

Validate that timestamp is a valid ISO 8601 string.

validate_agent_only_fields() Step#

Validate that certain fields are only present for agent steps.

class SubagentTrajectoryRef(/, **data: Any)#

Bases: pydantic.BaseModel

Reference to a delegated subagent trajectory (ATIF v1.7).

A ref MUST be resolvable via at least one of two mechanisms:

  • Embedded formtrajectory_id matches the trajectory_id of an entry in the parent Trajectory.subagent_trajectories array.

  • File-ref formtrajectory_path references an external file (path, S3 URL, database identifier, etc.).

A ref MUST set at least one of trajectory_id or trajectory_path; setting both is permitted (an embedded ref MAY also record the original file path for debug). session_id is run-scoped and informational only — it is NOT a valid resolution key (two sibling subagents MAY legitimately share a session_id).

Breaking vs. v1.6: in v1.6 session_id was required on the ref and served as the resolution key. Under v1.7 a ref of the shape {"session_id": "..."} (no trajectory_id and no trajectory_path) no longer validates. Producers MUST migrate by setting trajectory_id for embedded refs or trajectory_path for external-file refs. Pre-v1.7 refs that already set trajectory_path remain valid.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

trajectory_id: str | None = None#
trajectory_path: str | None = None#
session_id: str | None = None#
extra: dict[str, Any] | None = None#
model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

_validate_resolution_key_present() Self#
class ToolCall(/, **data: Any)#

Bases: pydantic.BaseModel

A tool call within a step.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

tool_call_id: str = None#
function_name: str = None#
arguments: dict[str, Any] = None#
extra: dict[str, Any] | None = None#
model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

ATIF_VERSION = 'ATIF-v1.7'#
class Trajectory(/, **data: Any)#

Bases: pydantic.BaseModel

ATIF trajectory — the complete interaction history of an agent run.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

schema_version: Literal['ATIF-v1.0', 'ATIF-v1.1', 'ATIF-v1.2', 'ATIF-v1.3', 'ATIF-v1.4', 'ATIF-v1.5', 'ATIF-v1.6', 'ATIF-v1.7'] = None#
session_id: str | None = None#
trajectory_id: str | None = None#
agent: nat.atif.agent.Agent = None#
steps: list[nat.atif.step.Step] = None#
notes: str | None = None#
final_metrics: nat.atif.final_metrics.FinalMetrics | None = None#
continued_trajectory_ref: str | None = None#
extra: dict[str, Any] | None = None#
subagent_trajectories: list[Trajectory] | None = None#
model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

to_json_dict(exclude_none: bool = True) dict[str, Any]#

Export trajectory to a dictionary suitable for JSON serialization.

validate_step_ids() Trajectory#

Validate that step_ids are sequential starting from 1.

validate_subagent_trajectory_ids() Trajectory#

Spec §IV: every embedded subagent MUST set trajectory_id, and trajectory_ids within the parent’s subagent_trajectories array MUST be unique. (session_ids, by contrast, are run-scoped and MAY collide across siblings.)

validate_tool_call_references() Trajectory#

Validate that observation source_call_ids reference valid tool_call_ids.

has_multimodal_content() bool#

Check if any step contains multimodal content (images).

ATIFAgentConfig#
ATIFContentPart#
ATIFImageSource#
ATIFFinalMetrics#
ATIFStepMetrics#
ATIFObservation#
ATIFObservationResult#
ATIFStep#
ATIFSubagentTrajectoryRef#
ATIFToolCall#
ATIFTrajectory#