Conversation
…ults (extra-org#134) - Introduce NormalizedToolResult domain model and normalize_tool_result function - Extract model-facing text alongside structuredContent and artifact metadata for MCP and local tools - Update ToolExecutionRecord and ToolExecutionManager to persist structured output across idempotent replays - Expose structured and artifact fields on ToolResultContext for transform_tool_result hooks - Add comprehensive test suite in test_tool_result_normalization.py
|
Thanks — the overall direction is good, and I like the introduction of a provider-agnostic I still see a few correctness/design gaps before approving.
The execution record now persists So the lifecycle is effectively: That means the structured result survives storage, but not the runtime replay path. The replayed execution should restore the same semantic
The JSON fallback currently exists only in the raw-dict path. For example: currently produces: So the model still receives an empty tool result even though useful structured data exists. Please add the fallback at the normalized-result level so structured-only results behave consistently regardless of whether the provider result arrived as a dict or A regression test should cover the real
This logic is too broad: An artifact is not necessarily structured tool output. For example: should not automatically become:
Please keep those semantics separate.
but and later persists: So if a hook intentionally transforms/redacts the structured result, that change is currently ignored and the original value is persisted. Either:
The current API suggests they are mutable while the runtime behaves as if they are not. There is also an API ambiguity in One smaller design concern: I would avoid using arbitrary The core architecture is heading in the right direction, but I think these cases need to be fixed so the result contract is consistent across: Once those invariants are aligned, I think this will be in a much stronger state. |
…acks, and hooks
…ructured-content # Conflicts: # src/agent_engine/approvals/in_memory_tool_execution_repository.py # src/agent_engine/approvals/models.py # src/agent_engine/approvals/tool_execution_manager.py # src/agent_engine/approvals/tool_execution_repository.py # src/agent_engine/engine/langgraph/tools/tool_invoker.py # src/agent_engine/runtime/hooks/models.py
|
Thanks for the work on this and for addressing the previous review feedback. Since this PR was opened, #135 has been merged into main and now implements the structured tool-result contract from #134 end-to-end, including normalization, persistence/replay, hooks, artifact handling, and structured-only results. At this point, merging #136 would introduce a second So I don't think it makes sense to continue iterating on this PR. I'm going to close this as superseded by #135. Thanks again for the contribution — the direction here was valid, but the underlying issue has now been implemented through the other PR. |
Summary
Fixes #134 by introducing a provider-agnostic
NormalizedToolResultabstraction that preserves MCPstructuredContentand artifact metadata alongside model-facing text content throughout the runtime execution pipeline.What Changed
NormalizedToolResultAbstraction (tool_result.py):NormalizedToolResult(text: str, structured: Any | None, artifact: Any | None).normalize_tool_result()to parseToolMessage.artifact["structuredContent"], dicts withstructuredContent, local structured return values (dataclasses/Pydantic/dicts), and multi-block text responses.Idempotency Ledger Persistence (
models.py,tool_execution_manager.py):structured: Any | Nonefield toToolExecutionRecord.ToolExecutionManagerandInMemoryToolExecutionRepositoryto persist and restore structured tool outputs across idempotent execution replays.Runtime Hooks Integration (
hooks/models.py,tool_invoker.py):structuredandartifactfields toToolResultContext.transform_tool_resulthooks preserve structured results even when text is truncated or redacted viawith_result().Safety & Robustness:
Test Suite Coverage:
test_tool_result_normalization.pycovering MCPstructuredContent, multi-block text, structured-only results, local string tools, local structured tools, replay persistence, and hook transformations.Verification
ruff format&ruff check— 0 errors ✅mypy src/agent_engine— 0 type errors ✅pytest— 948/948 passed ✅npm run test:widget—widget self-check: OK✅playwright test— 40/40 passed ✅Closes #134.