SRHarness Core Abstractions¶
This page defines two foundational SRHarness extension contracts: BaseTool specifies how tools declare inputs and return results, while BaseParser normalizes calls between language models and tools. See Formula Evaluation and Custom Evaluators for the evaluation protocol and its extension points, and Structured Data and context.data for the persistent data contract.
See SRHarness Agent Workflow for how the Agent coordinates these objects during a search, and the API Reference for complete class and method signatures.
BaseTool¶
Every callable tool derives from BaseTool. A tool normally needs only metadata and an execute() implementation; the base class supplies the common behavior.
from typing import Any
from sr_harness.tools import BaseTool, ToolMetadata
@BaseTool.register("example_tool")
class ExampleTool(BaseTool):
metadata = ToolMetadata(name="example_tool")
def execute(self, expression: str, limit: int = 10) -> dict[str, Any]:
"""Inspect an expression.
Args:
expression: Expression supplied by the model.
limit: Maximum number of returned items.
Returns:
Structured inspection results.
"""
parsed = self.parse_formula(expression)
return {"expression": parsed.to_str(), "limit": limit}
Input contract¶
- Arguments to
execute()are generated by the model, so they should remain simple, serializable, and fully type-annotated. - Data, Evaluators, workspace access, and runtime parameters belong in
self.context; the model should not repeat a complex execution environment in every call. - A tool may explicitly declare
metadata.descriptionand its JSON parameter schema. Otherwise,BaseToolinfers them from theexecute()signature, type annotations, and Google-style docstring. - Tool classes are discovered by name through a registry, but the Agent exposes only the tools enabled for the current run.
Result and error contract¶
execute()returns a structureddictfor recording and downstream candidate processing.format_result_dict()converts that structure into concise model-readable text. A tool may override the formatter without changing the machine-readable result.BaseTool.__call__()measures execution and returnsToolCallResult(ok, result, result_str, meta_data).- Ordinary exceptions, including timeout exceptions raised inside a tool, become
ok=Falsetool results so that the model can inspect the failure and recover. The control-flow-specificToolRunAbortis not swallowed as an ordinary failure. result_stris bounded in length, whileresultretains the complete structured value to prevent unbounded model-context growth.cancel()is an optional active-cancellation hook. Long-running tools should also inspect the runtime cancellation signal at suitable boundaries.
Formula-oriented tools can additionally reuse BaseTool helpers for formula normalization, parsing, evaluation, and result formatting instead of reimplementing the same boundary logic.
Tool-call Parser¶
Here, Parser means a tool-call Parser, not a mathematical-expression Parser. Model APIs may represent tool calls through native function calling, JSON, or text, while the Agent loop handles only normalized ToolCall and ToolCallResult objects.
BaseParser defines three transformations:
- format tool names, descriptions, and parameter schemas for the model;
- parse model output into zero or more normalized
ToolCallobjects; - format
ToolCallResultobjects as messages for the next turn.
In openai mode, services with native function calling receive JSON schemas directly, and BaseAPI normalizes provider-native calls into ToolCall. For endpoints without native tool support, the text or json Parser writes tool descriptions and call syntax into the prompt and recovers structured calls from model text. Tool execution, search recording, and candidate collection therefore use the same internal structures regardless of the input format.
When the model emits no parseable tool call, the Parser returns an empty list rather than inventing a call or treating ordinary prose as an error. Mathematical expressions are handled separately by the restricted expression Parser in SRHarness Engine: one determines which tool to call with which parameters, while the other determines what a formula means.
See Formula Evaluation and Custom Evaluators for how formula tools split data, fit parameters, and compute metrics.