From db01b793cf6a2a88858be96b6a8d813f52c0d768 Mon Sep 17 00:00:00 2001 From: rholinshead <5060851+rholinshead@users.noreply.github.com> Date: Thu, 28 Aug 2025 12:52:06 -0400 Subject: [PATCH 1/7] Move workflows to workflows.py file --- examples/temporal/run_worker.py | 7 +------ examples/temporal/workflows.py | 6 ++++++ 2 files changed, 7 insertions(+), 6 deletions(-) create mode 100644 examples/temporal/workflows.py diff --git a/examples/temporal/run_worker.py b/examples/temporal/run_worker.py index e5b658209..5af3dfd71 100644 --- a/examples/temporal/run_worker.py +++ b/examples/temporal/run_worker.py @@ -9,13 +9,8 @@ import asyncio import logging +import workflows # noqa: F401 from main import app -from basic import SimpleWorkflow # noqa: F401 -from evaluator_optimizer import EvaluatorOptimizerWorkflow # noqa: F401 -from orchestrator import OrchestratorWorkflow # noqa: F401 -from parallel import ParallelWorkflow # noqa: F401 -from router import RouterWorkflow # noqa: F401 -from interactive import WorkflowWithInteraction # noqa: F401 from mcp_agent.executor.temporal import create_temporal_worker_for_app diff --git a/examples/temporal/workflows.py b/examples/temporal/workflows.py new file mode 100644 index 000000000..4d67f3904 --- /dev/null +++ b/examples/temporal/workflows.py @@ -0,0 +1,6 @@ +from basic import SimpleWorkflow # noqa: F401 +from evaluator_optimizer import EvaluatorOptimizerWorkflow # noqa: F401 +from orchestrator import OrchestratorWorkflow # noqa: F401 +from parallel import ParallelWorkflow # noqa: F401 +from router import RouterWorkflow # noqa: F401 +from interactive import WorkflowWithInteraction # noqa: F401 From 5f8eb8950509275ef89ab28ded63b48bc0871cbe Mon Sep 17 00:00:00 2001 From: rholinshead <5060851+rholinshead@users.noreply.github.com> Date: Thu, 28 Aug 2025 17:45:37 -0400 Subject: [PATCH 2/7] Fix router example --- examples/temporal/router.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/examples/temporal/router.py b/examples/temporal/router.py index 835b7c9fe..41752df5c 100644 --- a/examples/temporal/router.py +++ b/examples/temporal/router.py @@ -38,12 +38,9 @@ class RouterWorkflow(Workflow[str]): """ @app.workflow_run - async def run(self, input: str) -> WorkflowResult[str]: + async def run(self) -> WorkflowResult[str]: """ - Run the workflow, processing the input data. - - Args: - input_data: The data to process + Run the workflow, routing to the correct agents. Returns: A WorkflowResult containing the processed data @@ -81,7 +78,7 @@ async def run(self, input: str) -> WorkflowResult[str]: # You can use any LLM with an LLMRouter llm = OpenAIAugmentedLLM(name="openai_router", instruction="You are a router") router = LLMRouter( - llm=llm, + llm_factory=lambda _agent: llm, agents=[finder_agent, writer_agent, reasoning_agent], functions=[print_to_console, print_hello_world], context=app.context, @@ -150,7 +147,6 @@ async def main(): handle = await executor.start_workflow( "RouterWorkflow", - None, ) a = await handle.result() print(a) From 33d9ae9dc2352ee1874945e79e5ea1ef9303dcde Mon Sep 17 00:00:00 2001 From: rholinshead <5060851+rholinshead@users.noreply.github.com> Date: Tue, 2 Sep 2025 17:41:30 -0400 Subject: [PATCH 3/7] Add remaining dependencies --- examples/temporal/requirements.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/temporal/requirements.txt b/examples/temporal/requirements.txt index d3bc4baae..bcfc1a51a 100644 --- a/examples/temporal/requirements.txt +++ b/examples/temporal/requirements.txt @@ -1,5 +1,7 @@ # Core framework dependency -mcp-agent @ file://../../ # Link to the local mcp-agent project root +mcp-agent @ file://../../ # Link to the local mcp-agent project root. Remove @ file://../../ for cloud deployment # Additional dependencies specific to this example -temporalio \ No newline at end of file +anthropic +openai +temporalio From 742e26c8bec00ba8973577db498f75eb35f27e82 Mon Sep 17 00:00:00 2001 From: rholinshead <5060851+rholinshead@users.noreply.github.com> Date: Wed, 3 Sep 2025 17:59:26 -0400 Subject: [PATCH 4/7] Update orchestrator to @app.async_tool example --- examples/temporal/README.md | 1 + examples/temporal/orchestrator.py | 159 +++++++++++++++--------------- examples/temporal/workflows.py | 2 +- 3 files changed, 81 insertions(+), 81 deletions(-) diff --git a/examples/temporal/README.md b/examples/temporal/README.md index 32ecbcbca..34efc513c 100644 --- a/examples/temporal/README.md +++ b/examples/temporal/README.md @@ -107,6 +107,7 @@ An example showcasing a workflow that iteratively improves content based on eval A more complex example that demonstrates how to orchestrate multiple agents: +- Uses the @app.async_tool decorator instead of explicit workflow/run definitions - Uses a combination of finder, writer, proofreader, fact-checker and style enforcer agents - Orchestrates these agents to collaboratively complete a task - Dynamically plans each step of the workflow diff --git a/examples/temporal/orchestrator.py b/examples/temporal/orchestrator.py index 0d32fae07..c99aa5024 100644 --- a/examples/temporal/orchestrator.py +++ b/examples/temporal/orchestrator.py @@ -6,99 +6,98 @@ import asyncio import os +from typing import Optional + +from main import app from mcp_agent.agents.agent import Agent +from mcp_agent.core.context import Context as AppContext from mcp_agent.executor.temporal import TemporalExecutor -from mcp_agent.executor.workflow import Workflow, WorkflowResult from mcp_agent.workflows.llm.augmented_llm import RequestParams from mcp_agent.workflows.llm.augmented_llm_openai import OpenAIAugmentedLLM from mcp_agent.workflows.orchestrator.orchestrator import Orchestrator -from main import app +""" +A more complex example that demonstrates how to orchestrate multiple agents. +This example uses the @app.async_tool decorator instead of traditional workflow/run definitions +and will have a workflow created behind the scenes. +""" -@app.workflow -class OrchestratorWorkflow(Workflow[str]): - """ - A simple workflow that demonstrates the basic structure of a Temporal workflow. +@app.async_tool(name="OrchestratorWorkflow") +async def run_orchestrator(input: str, app_ctx: Optional[AppContext]) -> str: """ + Run the workflow, processing the input data. - @app.workflow_run - async def run(self, input: str) -> WorkflowResult[str]: - """ - Run the workflow, processing the input data. + Args: + input_data: The data to process - Args: - input_data: The data to process - - Returns: - A WorkflowResult containing the processed data - """ - - context = app.context - context.config.mcp.servers["filesystem"].args.extend([os.getcwd()]) - - finder_agent = Agent( - name="finder", - instruction="""You are an agent with access to the filesystem, - as well as the ability to fetch URLs. Your job is to identify - the closest match to a user's request, make the appropriate tool calls, - and return the URI and CONTENTS of the closest match.""", - server_names=["fetch", "filesystem"], - ) - - writer_agent = Agent( - name="writer", - instruction="""You are an agent that can write to the filesystem. - You are tasked with taking the user's input, addressing it, and - writing the result to disk in the appropriate location.""", - server_names=["filesystem"], - ) - - proofreader = Agent( - name="proofreader", - instruction=""""Review the short story for grammar, spelling, and punctuation errors. - Identify any awkward phrasing or structural issues that could improve clarity. - Provide detailed feedback on corrections.""", - server_names=["fetch"], - ) - - fact_checker = Agent( - name="fact_checker", - instruction="""Verify the factual consistency within the story. Identify any contradictions, - logical inconsistencies, or inaccuracies in the plot, character actions, or setting. - Highlight potential issues with reasoning or coherence.""", - server_names=["fetch"], - ) - - style_enforcer = Agent( - name="style_enforcer", - instruction="""Analyze the story for adherence to style guidelines. - Evaluate the narrative flow, clarity of expression, and tone. Suggest improvements to - enhance storytelling, readability, and engagement.""", - server_names=["fetch"], - ) - - orchestrator = Orchestrator( - llm_factory=OpenAIAugmentedLLM, - available_agents=[ - finder_agent, - writer_agent, - proofreader, - fact_checker, - style_enforcer, - ], - # We will let the orchestrator iteratively plan the task at every step - plan_type="full", - context=app.context, - ) - - result = await orchestrator.generate_str( - message=input, - request_params=RequestParams(model="gpt-4o", max_iterations=100), - ) + Returns: + A WorkflowResult containing the processed data + """ - return WorkflowResult(value=result) + context = app_ctx or app.context + context.config.mcp.servers["filesystem"].args.extend([os.getcwd()]) + + finder_agent = Agent( + name="finder", + instruction="""You are an agent with access to the filesystem, + as well as the ability to fetch URLs. Your job is to identify + the closest match to a user's request, make the appropriate tool calls, + and return the URI and CONTENTS of the closest match.""", + server_names=["fetch", "filesystem"], + ) + + writer_agent = Agent( + name="writer", + instruction="""You are an agent that can write to the filesystem. + You are tasked with taking the user's input, addressing it, and + writing the result to disk in the appropriate location.""", + server_names=["filesystem"], + ) + + proofreader = Agent( + name="proofreader", + instruction=""""Review the short story for grammar, spelling, and punctuation errors. + Identify any awkward phrasing or structural issues that could improve clarity. + Provide detailed feedback on corrections.""", + server_names=["fetch"], + ) + + fact_checker = Agent( + name="fact_checker", + instruction="""Verify the factual consistency within the story. Identify any contradictions, + logical inconsistencies, or inaccuracies in the plot, character actions, or setting. + Highlight potential issues with reasoning or coherence.""", + server_names=["fetch"], + ) + + style_enforcer = Agent( + name="style_enforcer", + instruction="""Analyze the story for adherence to style guidelines. + Evaluate the narrative flow, clarity of expression, and tone. Suggest improvements to + enhance storytelling, readability, and engagement.""", + server_names=["fetch"], + ) + + orchestrator = Orchestrator( + llm_factory=OpenAIAugmentedLLM, + available_agents=[ + finder_agent, + writer_agent, + proofreader, + fact_checker, + style_enforcer, + ], + # We will let the orchestrator iteratively plan the task at every step + plan_type="full", + context=app.context, + ) + + return await orchestrator.generate_str( + message=input, + request_params=RequestParams(model="gpt-4o", max_iterations=100), + ) async def main(): diff --git a/examples/temporal/workflows.py b/examples/temporal/workflows.py index 4d67f3904..dd9fa2314 100644 --- a/examples/temporal/workflows.py +++ b/examples/temporal/workflows.py @@ -1,6 +1,6 @@ from basic import SimpleWorkflow # noqa: F401 from evaluator_optimizer import EvaluatorOptimizerWorkflow # noqa: F401 -from orchestrator import OrchestratorWorkflow # noqa: F401 +from orchestrator import run_orchestrator # noqa: F401 from parallel import ParallelWorkflow # noqa: F401 from router import RouterWorkflow # noqa: F401 from interactive import WorkflowWithInteraction # noqa: F401 From 9573453beac86a0695342cac34ef9d2e184a89e2 Mon Sep 17 00:00:00 2001 From: rholinshead <5060851+rholinshead@users.noreply.github.com> Date: Tue, 9 Sep 2025 16:17:50 -0400 Subject: [PATCH 5/7] Changes from review --- examples/temporal/orchestrator.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/temporal/orchestrator.py b/examples/temporal/orchestrator.py index c99aa5024..810c201ea 100644 --- a/examples/temporal/orchestrator.py +++ b/examples/temporal/orchestrator.py @@ -30,7 +30,8 @@ async def run_orchestrator(input: str, app_ctx: Optional[AppContext]) -> str: Run the workflow, processing the input data. Args: - input_data: The data to process + input: Task description or instruction text. + app_ctx: Optional application context for the workflow. Returns: A WorkflowResult containing the processed data @@ -58,7 +59,7 @@ async def run_orchestrator(input: str, app_ctx: Optional[AppContext]) -> str: proofreader = Agent( name="proofreader", - instruction=""""Review the short story for grammar, spelling, and punctuation errors. + instruction="""Review the short story for grammar, spelling, and punctuation errors. Identify any awkward phrasing or structural issues that could improve clarity. Provide detailed feedback on corrections.""", server_names=["fetch"], @@ -91,7 +92,7 @@ async def run_orchestrator(input: str, app_ctx: Optional[AppContext]) -> str: ], # We will let the orchestrator iteratively plan the task at every step plan_type="full", - context=app.context, + context=context, ) return await orchestrator.generate_str( From 22d1a5dec5d909ae181518d93bcf281c7d630d18 Mon Sep 17 00:00:00 2001 From: rholinshead <5060851+rholinshead@users.noreply.github.com> Date: Tue, 9 Sep 2025 16:42:08 -0400 Subject: [PATCH 6/7] Fix interactive_workflow to be runnable via tool --- src/mcp_agent/executor/temporal/interactive_workflow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mcp_agent/executor/temporal/interactive_workflow.py b/src/mcp_agent/executor/temporal/interactive_workflow.py index e8ff06218..93054c0a9 100644 --- a/src/mcp_agent/executor/temporal/interactive_workflow.py +++ b/src/mcp_agent/executor/temporal/interactive_workflow.py @@ -38,8 +38,8 @@ async def run(self, input: str) -> WorkflowResult[str]: # etc. """ - def __init__(self) -> None: - super().__init__() + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) self._lock = asyncio.Lock() self._request: HumanInputRequest = None self._response: str = None From c643529c4f69ba4a22da6db17b6b52e32db7c39d Mon Sep 17 00:00:00 2001 From: rholinshead <5060851+rholinshead@users.noreply.github.com> Date: Tue, 9 Sep 2025 16:59:20 -0400 Subject: [PATCH 7/7] Fix resume tool params --- src/mcp_agent/server/app_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mcp_agent/server/app_server.py b/src/mcp_agent/server/app_server.py index 8b46735de..fe9ec2c6b 100644 --- a/src/mcp_agent/server/app_server.py +++ b/src/mcp_agent/server/app_server.py @@ -772,7 +772,7 @@ async def resume_workflow( run_id: str | None = None, workflow_id: str | None = None, signal_name: str | None = "resume", - payload: str | None = None, + payload: Dict[str, Any] | None = None, ) -> bool: """ Resume a paused workflow.