Agent
The high-level entry point for most use cases. Agent and AsyncAgent compose
a Harness, SessionCache, and optional tools from a single configuration.
Agent
data_harness.Agent
Agent(
system: str,
*,
adapter: ProviderAdapter | None = None,
model: str | None = None,
max_turns: int = 25,
cache: SessionCache | None = None,
run_dir: str | Path | None = None,
execution: str = "inprocess",
sandbox_options: dict[str, Any] | None = None,
on_code: Callable[[str], Any] | None = None,
code_only: bool = False,
hooks: HookRegistry | None = None,
)
Bases: _AgentBase
High-level synchronous agent.
Agent composes a Harness, a SessionCache, and optional tools from a
single configuration. Each call to run builds a fresh Harness with a
fresh message history. Use session when you need multi-turn conversation
state to persist across questions.
Example::
from data_harness import Agent
agent = Agent(system="You are a data analyst.", model="claude-sonnet-4-6")
print(agent.run("Compute the mean of [1, 2, 3]."))
model resolves an adapter the same way resolve_adapter does: a
provider/model id routes to OpenRouter, deepseek-* to DeepSeek
direct, otherwise Anthropic or OpenAI by name. Pass adapter= instead
for a pre-built or custom adapter — it always wins over model::
from data_harness.llm.providers.anthropic import AnthropicAdapter
agent = Agent(
system="You are a data analyst.",
adapter=AnthropicAdapter(model="claude-sonnet-4-6", max_tokens=8192),
)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
system
|
str
|
System prompt passed unchanged to every |
required |
adapter
|
ProviderAdapter | None
|
Synchronous provider adapter. Takes priority over |
None
|
model
|
str | None
|
Model id resolved into an adapter via |
None
|
max_turns
|
int
|
Hard cap on provider turns per |
25
|
cache
|
SessionCache | None
|
Shared |
None
|
run_dir
|
str | Path | None
|
Directory for chart artefacts and subagent working state.
Defaults to |
None
|
execution
|
str
|
|
'inprocess'
|
sandbox_options
|
dict[str, Any] | None
|
Extra options for the subprocess interpreter. |
None
|
on_code
|
Callable[[str], Any] | None
|
Approval gate called with interpreter code before it runs. |
None
|
code_only
|
bool
|
When |
False
|
Source code in data_harness/app/agent.py
session
Create a stateful AgentSession for multi-turn conversations.
Returns:
| Type | Description |
|---|---|
AgentSession
|
A new |
run_result
Run the agent and return the full RunResult.
Builds a fresh Harness with a fresh message history for each call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_message
|
str
|
The user prompt to send. |
required |
Returns:
| Type | Description |
|---|---|
RunResult
|
A |
Source code in data_harness/app/agent.py
run
Run the agent and return the final text response.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_message
|
str
|
The user prompt to send. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The model's final text response. |
Raises:
| Type | Description |
|---|---|
MaxTurnsExceeded
|
If the loop reaches |
RuntimeError
|
If the provider raises an exception. |
Source code in data_harness/app/agent.py
AgentSession
data_harness.AgentSession
Bases: _SessionBase
Stateful chat session built from an Agent definition.
Agent.run() intentionally stays one-shot for examples and tests. Use
Agent.session() when an application needs follow-up questions over the
same message history and cache handles.
Source code in data_harness/app/agent.py
ask_result
Send a follow-up message and return the full RunResult.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_message
|
str
|
The follow-up user prompt. |
required |
Returns:
| Type | Description |
|---|---|
RunResult
|
A |
Source code in data_harness/app/agent.py
ask
Send a follow-up message and return the final text response.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_message
|
str
|
The follow-up user prompt. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The model's final text response. |
Raises:
| Type | Description |
|---|---|
MaxTurnsExceeded
|
If the loop reaches |
RuntimeError
|
If the provider raises an exception. |
Source code in data_harness/app/agent.py
AsyncAgent
data_harness.AsyncAgent
AsyncAgent(
system: str,
*,
adapter: AsyncProviderAdapter | None = None,
model: str | None = None,
max_turns: int = 25,
cache: SessionCache | None = None,
run_dir: str | Path | None = None,
execution: str = "inprocess",
sandbox_options: dict[str, Any] | None = None,
on_code: Callable[[str], Any] | None = None,
code_only: bool = False,
hooks: HookRegistry | None = None,
)
Bases: _AgentBase
Async agent for use with AsyncProviderAdapter.
run() and run_result() are coroutines. run_stream() is an async
generator that yields StreamEvents as they arrive from the provider.
Use async_session() for multi-turn streaming conversations.
Takes the same configuration and supports the same features as Agent:
connectors, MCP servers, SQL, the planner, subagents, the replay cache,
and the interpreter approval gate. Also takes the same model=
shortcut — see Agent for details; adapter= here must be an
AsyncProviderAdapter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
system
|
str
|
System prompt passed unchanged to every |
required |
adapter
|
AsyncProviderAdapter | None
|
Asynchronous provider adapter. Takes priority over |
None
|
model
|
str | None
|
Model id resolved into an |
None
|
max_turns
|
int
|
Hard cap on provider turns per |
25
|
cache
|
SessionCache | None
|
Shared |
None
|
run_dir
|
str | Path | None
|
Directory for chart artefacts and subagent working state.
Defaults to |
None
|
execution
|
str
|
|
'inprocess'
|
sandbox_options
|
dict[str, Any] | None
|
Extra options for the subprocess interpreter. |
None
|
on_code
|
Callable[[str], Any] | None
|
Approval gate called with interpreter code before it runs. |
None
|
code_only
|
bool
|
When |
False
|
Source code in data_harness/app/agent.py
async_session
run_result
async
Run the agent and return the full RunResult.
Source code in data_harness/app/agent.py
run
async
Run the agent and return the final text response.
Raises:
| Type | Description |
|---|---|
MaxTurnsExceeded
|
If the loop reaches |
RuntimeError
|
If the provider raises an exception. |
Source code in data_harness/app/agent.py
run_stream
async
Stream events for a one-shot run.
Yields StreamEvent objects (message_start, content_block_*, message_delta, message_stop, tool_result) following the Claude Agent SDK protocol.
After the generator is exhausted, agent.last_result holds the
RunResult for the run, including token usage. Read it there rather
than through last_harness: a replay-cache hit builds no harness, so
last_harness is either None or left over from an earlier run.
A cache hit yields the cached answer as a single synthetic text block and reports zero usage, so a streaming caller sees the same answer a non-streaming one would.
Usage::
async for event in agent.run_stream("hello"):
if event.type == "content_block_delta":
from data_harness.llm.streaming import TextDelta
if isinstance(event.delta, TextDelta):
print(event.delta.text, end="", flush=True)
Source code in data_harness/app/agent.py
AsyncAgentSession
data_harness.AsyncAgentSession
Bases: _SessionBase
Stateful async chat session built from an AsyncAgent definition.
Source code in data_harness/app/agent.py
ask_result
async
Send a follow-up message and return the full RunResult.
Source code in data_harness/app/agent.py
ask
async
Send a follow-up message and return the final text response.
Raises:
| Type | Description |
|---|---|
MaxTurnsExceeded
|
If the loop reaches |
RuntimeError
|
If the provider raises an exception. |
Source code in data_harness/app/agent.py
ask_stream
async
Stream events for a follow-up turn.
After the generator is exhausted, session.last_result holds the
RunResult for the turn, stamped with the session and run ids exactly
as a non-streamed turn would be.
Source code in data_harness/app/agent.py
RunResult
data_harness.RunResult
dataclass
RunResult(
text: str,
status: Literal[
"success", "max_turns_exceeded", "error"
],
turns: int,
stop_reason: StopReason | None,
usage: Usage,
cache_snapshots: dict[str, str] = dict(),
cache_storage: dict[str, CacheStorageInfo] = dict(),
error: str | None = None,
stopped_by: str | None = None,
run_id: str | None = None,
session_id: str | None = None,
value: Any = None,
charts: list[ChartArtifact] = list(),
)
The complete outcome of a single Harness.run() or Agent.run() call.
Attributes:
| Name | Type | Description |
|---|---|---|
text |
str
|
The final text response from the model. |
status |
Literal['success', 'max_turns_exceeded', 'error']
|
|
turns |
int
|
Number of provider turns executed. |
stop_reason |
StopReason | None
|
Provider stop reason from the final turn, or |
usage |
Usage
|
Cumulative token counts across all turns. |
cache_snapshots |
dict[str, str]
|
Mapping of handle name → compact snapshot string for every value in the session cache at the end of the run. |
cache_storage |
dict[str, CacheStorageInfo]
|
Mapping of handle name → |
error |
str | None
|
Exception repr when |
stopped_by |
str | None
|
Why a hook ended the run early, if one did. A capped run is otherwise indistinguishable from a model that answered with nothing. |
run_id |
str | None
|
Optional UUID assigned by |
session_id |
str | None
|
Optional session UUID when the run is part of an
|
value |
Any
|
The structured final answer the model recorded via |
charts |
list[ChartArtifact]
|
Chart artefacts rendered during the run. Image bytes live on disk; only paths are referenced here. |
Usage
data_harness.Usage
dataclass
Usage(
input_tokens: int = 0,
output_tokens: int = 0,
cache_read_tokens: int = 0,
cache_write_tokens: int = 0,
)
Accumulated token counts for a run or session turn.
Attributes:
| Name | Type | Description |
|---|---|---|
input_tokens |
int
|
Tokens in the prompt sent to the provider. |
output_tokens |
int
|
Tokens in the provider's response. |
cache_read_tokens |
int
|
Prompt tokens served from the provider's KV cache. |
cache_write_tokens |
int
|
Prompt tokens written to the provider's KV cache. |
CacheStorageInfo
data_harness.CacheStorageInfo
dataclass
Where a named handle is physically stored in the SessionCache.
Attributes:
| Name | Type | Description |
|---|---|---|
location |
Literal['memory', 'disk']
|
Either |
storage_type |
str
|
Format used on disk, e.g. |