tool#

class baf.reasoning.tool.Tool(fn, name=None, description=None)[source]#

Bases: object

Wraps a Python callable so a reasoning loop can invoke it via JSON-schema args.

The wrapper auto-introspects the callable’s signature, type hints and docstring to build a JSON schema in OpenAI function-calling format, validates LLM-supplied arguments before invocation, and converts the result (and any raised exception) to a string the LLM can read.

Parameters:
  • fn (Callable) – the Python callable to expose as a tool.

  • name (str) – the public tool name. Defaults to fn.__name__.

  • description (str) – a short description shown to the LLM. Defaults to the first non-empty line of fn.__doc__.

fn#

the wrapped callable.

Type:

Callable

name#

the public tool name.

Type:

str

description#

the human-readable description.

Type:

str

schema#

the JSONSchema parameters object describing fn’s signature.

Type:

dict

call(args)[source]#

Validate args, invoke the wrapped callable, and stringify the result.

Any exception raised either by validation or by the callable itself is caught and converted to a string of the form ERROR: <ExceptionType>: <message> so the reasoning loop can read it and recover.

Parameters:

args (dict) – the LLM-supplied arguments.

Returns:

the stringified result ("OK" for None), or an ERROR: ... string on failure.

Return type:

str

property openai_schema#

Return the OpenAI function-calling schema for this tool.

Returns:

a dict of the shape {"type": "function", "function": {"name", "description", "parameters"}}.

Return type:

dict

validate_args(args)[source]#

Validate and lightly coerce args against self.schema.

Parameters:

args (dict) – the arguments supplied by the LLM.

Returns:

the validated (possibly coerced) arguments, ready to be passed as **kwargs to self.fn.

Return type:

dict

Raises:

ToolError – if an argument is missing, unknown, or has the wrong type.

exception baf.reasoning.tool.ToolError[source]#

Bases: Exception

Raised when a Tool’s argument validation fails.

The message is intended to be readable by an LLM so it can recover and retry with corrected arguments on the next reasoning step.

baf.reasoning.tool._annotation_to_schema(annotation, param_name='')[source]#

Map a Python annotation to a minimal JSONSchema property.

Parameters:
  • annotation – the annotation to translate.

  • param_name (str) – the parameter name, only used for diagnostic logging.

Returns:

the JSONSchema property describing the annotation.

Return type:

dict

baf.reasoning.tool._build_schema(fn)[source]#

Introspect fn and build a JSONSchema parameters object.

The returned dict has the shape:

{"type": "object", "properties": {...}, "required": [...]}
Parameters:

fn (Callable) – the function to introspect.

Returns:

the JSONSchema parameters object.

Return type:

dict

baf.reasoning.tool._coerce_value(value, json_type, arg_name)[source]#

Validate and lightly coerce value to the expected JSONSchema json_type.

Allowed coercions:
  • integer accepts strings of digits (optionally signed).

  • number accepts ints and strings parseable as floats.

  • boolean accepts the strings “true”/”false” (case-insensitive).

Raises:

ToolError – if the value cannot be safely coerced.

baf.reasoning.tool._first_non_empty_line(text)[source]#

Return the first non-empty stripped line of text (or empty string).

baf.reasoning.tool._is_optional(annotation)[source]#

Return True if the annotation is an Optional[X] / X | None form.

Parameters:

annotation – a type annotation as seen by typing.get_type_hints.

Returns:

True if None is one of the union members, False otherwise.

Return type:

bool

baf.reasoning.tool._parse_arg_descriptions(docstring)[source]#

Best-effort extraction of per-argument descriptions from a docstring.

Recognises Google-style Args: blocks and bare Arguments: / Parameters: blocks. Lines that do not match the simple name (type?): description pattern are ignored.

Parameters:

docstring (Optional[str]) – the function docstring, may be None.

Returns:

a mapping arg_name -> description.

Return type:

dict[str, str]

baf.reasoning.tool._strip_optional(annotation)[source]#

Return the underlying annotation of an Optional[X] / X | None.

If the annotation is not optional, it is returned unchanged.