Skip to content

v0.1.2 — JSON-safe normalization for LangGraph ToolCall path

Latest

Choose a tag to compare

@oabolade oabolade released this 18 Jun 09:35
· 2 commits to main since this release

Patch release. Hotfixes a real bug surfaced by a runnable LangGraph example against create_react_agent.

📦 PyPI: https://pypi.org/project/rootsign/0.1.2/
🐛 Fixes: ACTION_RECORD insertion crashed under LangGraph's canonical ToolNode / create_react_agent path.

What changed

When a tool is invoked through LangChain's ToolCall envelope (which is what ToolNode and create_react_agent use internally), BaseTool.ainvoke wraps the tool's plain-string return into a ToolMessage before returning. Before v0.1.2, _emit_action_record stored that raw return directly into the output_redacted JSONB column — and ToolMessage isn't JSON-serializable, so the INSERT crashed and the action never landed:

PendingRollbackError: ... Original exception was:
Object of type ToolMessage is not JSON serializable

v0.1.2 adds _to_json_safe in rootsign/sdk/decorator.py and applies it to both input_payload and output_payload before redaction and hashing. LangChain BaseMessage duck-types (anything with .content and a string .type) are coerced to {"_message_type": <type>, "content": <recursed content>} — preserving the agent's intent without dragging in per-run noise fields like tool_call_id or usage_metadata that would destabilize input hashes. Anything genuinely non-serializable falls back to str(value) so the hash never explodes.

Compatibility

  • Plain tool.ainvoke({dict}) callers — unchanged. Hash bytes are byte-for-byte identical to v0.1.1.
  • Chains emitted by v0.1.0 / v0.1.1 with plain-string tool returns — continue to verify cleanly under v0.1.2. compute_action_self_hash is unchanged.
  • Chains attempted under v0.1.1 with create_react_agent — there aren't any; the INSERT crashed before they could be written.

Tests

20 new cases in tests/unit/test_emit_action_record_json_safe.py lock in _to_json_safe's contract (primitives, nested dicts/lists, BaseMessage shape, private-field drop, arbitrary-object fallback, determinism) plus an end-to-end ToolCall envelope + ToolMessage return path through _emit_action_record. Full unit suite green (243/243). Show HN hard gate (tests/integration/test_show_hn_quickstart.py) and HiTL CLI integration tests green post-change.

Who should upgrade

Everyone running LangGraph through ToolNode or create_react_agent. pip install -U rootsign[langgraph] picks v0.1.2 automatically — no API surface change.