Fix mcp native tool goals (#58)

* frontend ui error configurable timeout

* fixed bug where goals with MCP stopped native tools from executing
This commit is contained in:
Steve Androulakis
2025-09-28 12:20:36 -07:00
committed by GitHub
parent e248a6778d
commit 98a1b75dff
3 changed files with 122 additions and 12 deletions

View File

@@ -312,6 +312,109 @@ async def test_mcp_tool_execution_flow(client: Client):
assert captured["dynamic_args"]["server_definition"]["name"] == server_def.name
@pytest.mark.asyncio
async def test_create_invoice_defaults_days_until_due(client: Client):
"""create_invoice should include a default days_until_due when missing."""
task_queue_name = str(uuid.uuid4())
server_def = MCPServerDefinition(name="test", command="python", args=["srv.py"])
goal = AgentGoal(
id="g_invoice_default",
category_tag="food",
agent_name="agent",
agent_friendly_description="",
description="",
tools=[],
starter_prompt="",
example_conversation_history="",
mcp_server_definition=server_def,
)
combined_input = CombinedInput(
agent_goal=goal,
tool_params=AgentGoalWorkflowParams(
conversation_summary=None, prompt_queue=deque()
),
)
captured: dict = {}
@activity.defn(name="get_wf_env_vars")
async def mock_get_wf_env_vars(input: EnvLookupInput) -> EnvLookupOutput:
return EnvLookupOutput(show_confirm=True, multi_goal_mode=True)
@activity.defn(name="agent_validatePrompt")
async def mock_validate(prompt: ValidationInput) -> ValidationResult:
return ValidationResult(validationResult=True, validationFailedReason={})
@activity.defn(name="agent_toolPlanner")
async def mock_planner(input: ToolPromptInput) -> dict:
if "planner_called" not in captured:
captured["planner_called"] = True
return {
"next": "confirm",
"tool": "create_invoice",
"args": {"customer": "cus_123"},
"response": "Creating invoice",
}
return {"next": "done", "response": "done"}
@activity.defn(name="mcp_list_tools")
async def mock_mcp_list_tools(
server_definition: MCPServerDefinition, include_tools=None
):
return {
"server_name": server_definition.name,
"success": True,
"tools": {
"create_invoice": {
"name": "create_invoice",
"description": "",
"inputSchema": {
"properties": {
"customer": {"type": "string"},
"days_until_due": {"type": "number"},
}
},
},
},
"total_available": 1,
"filtered_count": 1,
}
@activity.defn(name="dynamic_tool_activity", dynamic=True)
async def mock_dynamic_tool_activity(args: Sequence[RawValue]) -> dict:
payload = activity.payload_converter().from_payload(args[0].payload, dict)
captured["dynamic_args"] = payload
return {"tool": "create_invoice", "success": True, "content": {"ok": True}}
async with Worker(
client,
task_queue=task_queue_name,
workflows=[AgentGoalWorkflow],
activities=[
mock_get_wf_env_vars,
mock_validate,
mock_planner,
mock_mcp_list_tools,
mock_dynamic_tool_activity,
],
):
handle = await client.start_workflow(
AgentGoalWorkflow.run,
combined_input,
id=str(uuid.uuid4()),
task_queue=task_queue_name,
)
await handle.signal(AgentGoalWorkflow.user_prompt, "make invoice")
await asyncio.sleep(0.5)
await handle.signal(AgentGoalWorkflow.confirm)
await asyncio.sleep(0.5)
await handle.result()
assert "dynamic_args" in captured
assert captured["dynamic_args"]["days_until_due"] == 7
@pytest.mark.asyncio
async def test_mcp_tool_failure_recorded(client: Client):
"""Failure of an MCP tool should be recorded in conversation history."""