mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Fix HIL regression (#2167)
* fix devui regression from #2021 where all input is stringified but devui HIL input does not handle stringified json strings correctly. * update incorrect test * add devui hil input tests
This commit is contained in:
committed by
GitHub
Unverified
parent
e92dcb3d5d
commit
7e5de8f920
@@ -781,6 +781,27 @@ class AgentFrameworkExecutor:
|
||||
Returns:
|
||||
Dict of {request_id: response_value} if found, None otherwise
|
||||
"""
|
||||
# Handle case where input_data might be a JSON string (from streamWorkflowExecutionOpenAI)
|
||||
# The input field type is: str | list[Any] | dict[str, Any]
|
||||
if isinstance(input_data, str):
|
||||
try:
|
||||
parsed = json.loads(input_data)
|
||||
# Only use parsed value if it's a list (ResponseInputParam format expected for HIL)
|
||||
if isinstance(parsed, list):
|
||||
input_data = parsed
|
||||
else:
|
||||
# Parsed to dict, string, or primitive - not HIL response format
|
||||
return None
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
# Plain text string, not valid JSON - not HIL format
|
||||
return None
|
||||
|
||||
# At this point, input_data should be a list or dict
|
||||
# HIL responses are always in list format (ResponseInputParam)
|
||||
if isinstance(input_data, dict):
|
||||
# This is structured workflow input (dict), not HIL responses
|
||||
return None
|
||||
|
||||
if not isinstance(input_data, list):
|
||||
return None
|
||||
|
||||
|
||||
@@ -261,6 +261,27 @@ def test_executor_parse_stringified_json_workflow_input():
|
||||
assert parsed.metadata == {"key": "value"}
|
||||
|
||||
|
||||
def test_extract_workflow_hil_responses_handles_stringified_json():
|
||||
"""Test HIL response extraction handles both stringified and parsed JSON (regression test)."""
|
||||
from agent_framework_devui._discovery import EntityDiscovery
|
||||
from agent_framework_devui._executor import AgentFrameworkExecutor
|
||||
from agent_framework_devui._mapper import MessageMapper
|
||||
|
||||
executor = AgentFrameworkExecutor(EntityDiscovery(None), MessageMapper())
|
||||
|
||||
# Regression test: Frontend sends stringified JSON via streamWorkflowExecutionOpenAI
|
||||
stringified = '[{"type":"message","content":[{"type":"workflow_hil_response","responses":{"req_1":"spam"}}]}]'
|
||||
assert executor._extract_workflow_hil_responses(stringified) == {"req_1": "spam"}
|
||||
|
||||
# Ensure parsed format still works
|
||||
parsed = [{"type": "message", "content": [{"type": "workflow_hil_response", "responses": {"req_2": "ham"}}]}]
|
||||
assert executor._extract_workflow_hil_responses(parsed) == {"req_2": "ham"}
|
||||
|
||||
# Non-HIL inputs should return None
|
||||
assert executor._extract_workflow_hil_responses("plain text") is None
|
||||
assert executor._extract_workflow_hil_responses({"email": "test"}) is None
|
||||
|
||||
|
||||
async def test_executor_handles_non_streaming_agent():
|
||||
"""Test executor can handle agents with only run() method (no run_stream)."""
|
||||
from agent_framework import AgentRunResponse, AgentThread, ChatMessage, Role, TextContent
|
||||
|
||||
@@ -280,18 +280,14 @@ async def test_api_restrictions_in_user_mode():
|
||||
assert dev_client.get("/v1/entities").status_code == 200
|
||||
assert user_client.get("/v1/entities").status_code == 200
|
||||
|
||||
# Test 4: Entity info should be restricted in user mode
|
||||
# Test 4: Entity info should be accessible in both modes (UI needs this)
|
||||
dev_response = dev_client.get("/v1/entities/test_agent/info")
|
||||
assert dev_response.status_code in [200, 404, 500] # Not 403
|
||||
|
||||
user_response = user_client.get("/v1/entities/test_agent/info")
|
||||
assert user_response.status_code == 403
|
||||
error_data = user_response.json()
|
||||
# FastAPI wraps HTTPException detail in 'detail' field
|
||||
error = error_data.get("detail", {}).get("error") or error_data.get("error")
|
||||
assert error is not None
|
||||
assert "developer mode" in error["message"].lower()
|
||||
assert error["code"] == "developer_mode_required"
|
||||
# Should return 404 (entity doesn't exist) or 500 (other error), but NOT 403 (forbidden)
|
||||
# User mode needs entity info to display workflows/agents in the UI
|
||||
assert user_response.status_code in [200, 404, 500] # Not 403
|
||||
|
||||
# Test 5: Hot reload should be restricted in user mode
|
||||
dev_response = dev_client.post("/v1/entities/test_agent/reload")
|
||||
@@ -329,10 +325,11 @@ async def test_api_restrictions_in_user_mode():
|
||||
# Test 8: Chat endpoint should work in both modes
|
||||
chat_payload = {"model": "test_agent", "input": "Hello"}
|
||||
dev_response = dev_client.post("/v1/responses", json=chat_payload)
|
||||
assert dev_response.status_code in [200, 404] # 404 if agent doesn't exist
|
||||
# 200=success, 400=missing entity_id in metadata, 404=entity not found
|
||||
assert dev_response.status_code in [200, 400, 404]
|
||||
|
||||
user_response = user_client.post("/v1/responses", json=chat_payload)
|
||||
assert user_response.status_code in [200, 404]
|
||||
assert user_response.status_code in [200, 400, 404]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user