refs #732: preserve Select AI results in HMM reports

This commit is contained in:
devmrko
2026-08-10 15:51:29 +09:00
parent c0c5a36ba0
commit b13b913939
8 changed files with 105 additions and 31 deletions

View File

@@ -2670,6 +2670,28 @@ def _mcp_items(mcp_result: Any) -> list[Any]:
return items if isinstance(items, list) else []
def _mcp_structured_rows(value: Any) -> list[Any]:
"""Extract row arrays from common MCP wrappers, including JSON strings."""
if isinstance(value, str):
try:
return _mcp_structured_rows(json.loads(value))
except ValueError:
return []
if isinstance(value, list):
return value
if not isinstance(value, Mapping):
return []
for key in ("items", "results", "rows", "response", "result"):
if key not in value:
continue
rows = _mcp_structured_rows(value.get(key))
if rows:
return rows
return []
def _mcp_summary(mcp_result: Any) -> dict[str, Any]:
if not isinstance(mcp_result, Mapping):
return {"type": type(mcp_result).__name__}
@@ -2876,14 +2898,7 @@ def _presentation_payload(question: str, steps: list[Mapping[str, Any]]) -> dict
{},
)
raw_result = source.get("mcp_result", {}) if isinstance(source, Mapping) else {}
payload = _mcp_response_payload(raw_result)
source_rows = _mcp_items(raw_result)
if not source_rows:
for key in ("results", "rows"):
candidate = payload.get(key) if isinstance(payload, Mapping) else None
if isinstance(candidate, list):
source_rows = candidate
break
source_rows = _mcp_structured_rows(raw_result)
rows = [
_normalize_presentation_value(row)
for row in source_rows

View File

@@ -1,8 +1,10 @@
from __future__ import annotations
import ast
import json
from pathlib import Path
import tempfile
from typing import Any, Mapping
import unittest
from unittest.mock import patch
@@ -140,6 +142,38 @@ class DemoScenarioConfigTest(unittest.TestCase):
self.assertIn("render_hmm_carrier_report", server["tool_allowlist"])
self.assertNotIn('tool.name == "render_hmm_carrier_report"', source)
def test_hmm_report_rows_accept_nested_select_ai_json_array(self) -> None:
source = (Path(__file__).parents[1] / "app.py").read_text(encoding="utf-8")
tree = ast.parse(source)
helper = next(
node
for node in tree.body
if isinstance(node, ast.FunctionDef)
and node.name == "_mcp_structured_rows"
)
namespace: dict[str, Any] = {
"Any": Any,
"Mapping": Mapping,
"json": json,
}
exec(compile(ast.Module(body=[helper], type_ignores=[]), "app.py", "exec"), namespace)
rows = namespace["_mcp_structured_rows"](
{
"response": {
"result": json.dumps(
[
{"EMPLOYEE_CODE": "E9001", "CARRIER_CODE": "C901"},
{"EMPLOYEE_CODE": "E9002", "CARRIER_CODE": "C902"},
]
)
}
}
)
self.assertEqual(len(rows), 2)
self.assertEqual(rows[0]["CARRIER_CODE"], "C901")
def test_hmm_report_template_contains_only_dynamic_payload_slot(self) -> None:
template = (
Path(__file__).parents[1]