fast-agent-mcp 0.0.16__py3-none-any.whl → 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fast-agent-mcp
3
- Version: 0.0.16
3
+ Version: 0.1.0
4
4
  Summary: Define, Prompt and Test MCP enabled Agents and Workflows
5
5
  Author-email: Shaun Smith <fastagent@llmindset.co.uk>, Sarmad Qadri <sarmad@lastmileai.dev>
6
6
  License: Apache License
@@ -235,7 +235,7 @@ Provides-Extra: temporal
235
235
  Requires-Dist: temporalio>=1.8.0; extra == 'temporal'
236
236
  Description-Content-Type: text/markdown
237
237
 
238
- ## FastAgent
238
+ ## fast-agent
239
239
 
240
240
  <p align="center">
241
241
  <a href="https://pypi.org/project/fast-agent-mcp/"><img src="https://img.shields.io/pypi/v/fast-agent-mcp?color=%2334D058&label=pypi" /></a>
@@ -415,9 +415,13 @@ Look at the `parallel.py` workflow example for more examples. If you don't speci
415
415
 
416
416
  `parallel` is also useful to ensemble ideas from different LLMs.
417
417
 
418
+ When using `parallel` in other workflows, specify an `instruction` to describe its operation.
419
+
418
420
  ### Evaluator-Optimizer
419
421
 
420
- Evaluator-Optimizers combine 2 agents: one to generate content (the `generator`), and the other to judge that content and provide actionable feedback (the `evaluator`). Messages are sent to the generator first, then the pair run in a loop until either the evaluator is satisfied with the quality, or the maximum number of refinements is reached.
422
+ Evaluator-Optimizers combine 2 agents: one to generate content (the `generator`), and the other to judge that content and provide actionable feedback (the `evaluator`). Messages are sent to the generator first, then the pair run in a loop until either the evaluator is satisfied with the quality, or the maximum number of refinements is reached. The final result from the Generator is returned.
423
+
424
+ If the Generator has `use_history` off, the previous iteration is returned when asking for improvements - otherwise conversational context is used.
421
425
 
422
426
  ```python
423
427
  @fast.evaluator_optimizer(
@@ -432,6 +436,8 @@ async with fast.run() as agent:
432
436
  await agent.researcher.send("produce a report on how to make the perfect espresso")
433
437
  ```
434
438
 
439
+ When used in a workflow, it returns the last `generator` message as the result.
440
+
435
441
  See the `evaluator.py` workflow example, or `fast-agent bootstrap researcher` for a more complete example.
436
442
 
437
443
  ### Router
@@ -540,7 +546,7 @@ agent["greeter"].send("Good Evening!") # Dictionary access is supported
540
546
  name="route", # name of the router
541
547
  agents=["agent1", "agent2", "agent3"], # list of agent names router can delegate to
542
548
  model="o3-mini.high", # specify routing model
543
- use_history=True, # router maintains chat history
549
+ use_history=False, # router maintains conversation history
544
550
  human_input=False, # whether router can request human input
545
551
  )
546
552
  ```
@@ -570,6 +576,7 @@ agent["greeter"].send("Good Evening!") # Dictionary access is supported
570
576
 
571
577
  ### llmindset.co.uk fork:
572
578
 
579
+ - Overhaul of Eval/Opt for Conversation Management
573
580
  - Remove instructor use for Orchestrator
574
581
  - Improved handling of Parallel/Fan-In and respose option
575
582
  - XML based generated prompts
@@ -590,9 +597,3 @@ agent["greeter"].send("Good Evening!") # Dictionary access is supported
590
597
  - Numerous defect fixes
591
598
 
592
599
  ### Features to add.
593
-
594
- - Chat History Clear.
595
-
596
- ```
597
-
598
- ```
@@ -11,19 +11,19 @@ mcp_agent/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
11
11
  mcp_agent/agents/agent.py,sha256=losanPSdZXZzmeiX-J6ctOinLlkhNZsxwi3Swr8lnxA,11482
12
12
  mcp_agent/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  mcp_agent/cli/__main__.py,sha256=AVZ7tQFhU_sDOGuUGJq8ujgKtcxsYJBJwHbVaaiRDlI,166
14
- mcp_agent/cli/main.py,sha256=cqRxYTpeZ656lzf9qLR3LPnQXrFVDxlWm5gRuqyzUQg,2456
14
+ mcp_agent/cli/main.py,sha256=DE6EZzspfzHwPK59x8vL4AIDHRQkVQ1Ja70XRGU1IQs,2753
15
15
  mcp_agent/cli/terminal.py,sha256=5fqrKlJvIpKEuvpvZ653OueQSYFFktBEbosjr2ucMUc,1026
16
- mcp_agent/cli/commands/bootstrap.py,sha256=z1wZSy8vO_GZPGLrFGzG3EKFQgAHC08jiIdVyylo-58,10778
16
+ mcp_agent/cli/commands/bootstrap.py,sha256=Rmwbuwl52eHfnya7fnwKk2J7nCsHpSh6irka4mBDEnU,10779
17
17
  mcp_agent/cli/commands/config.py,sha256=32YTS5jmsYAs9QzAhjkG70_daAHqOemf4XbZBBSMz6g,204
18
- mcp_agent/cli/commands/setup.py,sha256=8ofxUAF2nUSu1IarDZSAsTt6_6PoEht3TGbz9N6WSbs,6239
18
+ mcp_agent/cli/commands/setup.py,sha256=_SCpd6_PrixqbSaE72JQ7erIRkZnJGmh_3TvvwSzEiE,6392
19
19
  mcp_agent/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- mcp_agent/core/agent_app.py,sha256=2gnORb52cpWYGjRDNTJ9lVCEEc11c7Xi874ho7bbYVQ,6097
20
+ mcp_agent/core/agent_app.py,sha256=6U3HLYAJOfyVuUpZVELWT5lOo64-b_sfWp0yn88s7Wo,6085
21
21
  mcp_agent/core/agent_types.py,sha256=yKiMbv9QO2dduq4zXmoMZlOZpXJZhM4oNwIq1-134FE,318
22
22
  mcp_agent/core/agent_utils.py,sha256=yUJ-qvw5TblqqOsB1vj0Qvcz9mass9awPA6UNNvuw0A,1738
23
- mcp_agent/core/enhanced_prompt.py,sha256=ka-uuGNW7XggaGzXZQFB9T4azej455VPcgO66Q_7jnY,13008
23
+ mcp_agent/core/enhanced_prompt.py,sha256=XraDKdIMW960KXCiMfCEPKDakbf1wHYgvHwD-9CBDi0,13011
24
24
  mcp_agent/core/error_handling.py,sha256=D3HMW5odrbJvaKqcpCGj6eDXrbFcuqYaCZz7fyYiTu4,623
25
25
  mcp_agent/core/exceptions.py,sha256=a2-JGRwFFRoQEPuAq0JC5PhAJ5TO3xVJfdS4-VN29cw,2225
26
- mcp_agent/core/fastagent.py,sha256=MLMdQ4_Cjb2svWyGVWLGf8EzI3dSFCl4BS5qq8UrKgg,56966
26
+ mcp_agent/core/fastagent.py,sha256=CuT50oaexYq7L5-1xHR5HfS7qYKNToH3wmBAeD8kcBY,58234
27
27
  mcp_agent/core/proxies.py,sha256=hXDUpsgGO4xBTIjdUeXj6vULPb8sf55vAFVQh6Ybn60,4411
28
28
  mcp_agent/core/server_validation.py,sha256=_59cn16nNT4HGPwg19HgxMtHK4MsdWYDUw_CuL-5xek,1696
29
29
  mcp_agent/core/types.py,sha256=Zhi9iW7uiOfdpSt9NC0FCtGRFtJPg4mpZPK2aYi7a7M,817
@@ -54,7 +54,8 @@ mcp_agent/mcp/mcp_agent_server.py,sha256=xP09HZTeguJi4Fq0p3fjLBP55uSYe5AdqM90xCg
54
54
  mcp_agent/mcp/mcp_aggregator.py,sha256=RVsgNnSJ1IPBkqKgF_Gp-Cpv97FVBIdppPey6FRoHB0,14751
55
55
  mcp_agent/mcp/mcp_connection_manager.py,sha256=WLli0w3TVcsszyD9M7zP7vLKPetnQLTf_0PGhvMm9YM,13145
56
56
  mcp_agent/mcp/stdio.py,sha256=tW075R5rQ-UlflXWFKIFDgCbWbuhKqxhiYolWvyEkFs,3985
57
- mcp_agent/resources/examples/data-analysis/analysis.py,sha256=1Ce68epq8j6yjgxkJeTtnLR4l5yq8ANGEZ2k1sIf6dw,2292
57
+ mcp_agent/resources/examples/data-analysis/analysis-campaign.py,sha256=EG-HhaDHltZ4hHAqhgfX_pHM2wem48aYhSIKJxyWHKc,7269
58
+ mcp_agent/resources/examples/data-analysis/analysis.py,sha256=yRwcYob-jaqwR1vdx_gYXpfqtBN4w7creNeNgimOHa4,2443
58
59
  mcp_agent/resources/examples/data-analysis/fastagent.config.yaml,sha256=eTKGbjnTHhDTeNRPQvG_fr9OQpEZ5Y9v7X2NyCj0V70,530
59
60
  mcp_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv,sha256=pcMeOL1_r8m8MziE6xgbBrQbjl5Ijo98yycZn7O-dlk,227977
60
61
  mcp_agent/resources/examples/internal/agent.py,sha256=f-jTgYabV3nWCQm0ZP9NtSEWjx3nQbRngzArRufcELg,384
@@ -66,10 +67,10 @@ mcp_agent/resources/examples/researcher/researcher-eval.py,sha256=kNPjIU-JwE0oIB
66
67
  mcp_agent/resources/examples/researcher/researcher.py,sha256=jPRafm7jbpHKkX_dQiYGG3Sw-e1Dm86q-JZT-WZDhM0,1425
67
68
  mcp_agent/resources/examples/workflows/agent_build.py,sha256=vdjS02rZR88RU53WYzXxPscfFNEFFe_niHYE_i49I8Q,2396
68
69
  mcp_agent/resources/examples/workflows/chaining.py,sha256=1G_0XBcFkSJCOXb6N_iXWlSc_oGAlhENR0k_CN1vJKI,1208
69
- mcp_agent/resources/examples/workflows/evaluator.py,sha256=aUotC9-soTjWgw5GAf9m74BKAHzwxRPBdnSb5ga3lY8,3072
70
+ mcp_agent/resources/examples/workflows/evaluator.py,sha256=3XmW1mjImlaWb0c5FWHYS9yP8nVGTbEdJySAoWXwrDg,3109
70
71
  mcp_agent/resources/examples/workflows/fastagent.config.yaml,sha256=k2AiapOcK42uqG2nWDVvnSLqN4okQIQZK0FTbZufBpY,809
71
72
  mcp_agent/resources/examples/workflows/human_input.py,sha256=c8cBdLEPbaMXddFwsfN3Z7RFs5PZXsdrjANfvq1VTPM,605
72
- mcp_agent/resources/examples/workflows/orchestrator.py,sha256=pRJqB-ok79_iEj8aG4FysHyXz6wAHLUX-5tS8khUI7k,2574
73
+ mcp_agent/resources/examples/workflows/orchestrator.py,sha256=5TGFWrRQiTCdYY738cyd_OzZc7vckYkk1Up9VejFXB0,2574
73
74
  mcp_agent/resources/examples/workflows/parallel.py,sha256=pLbQrtXfbdYqMVddxtg5dZnBnm5Wo2mXlIa1Vf2F1FQ,3096
74
75
  mcp_agent/resources/examples/workflows/router.py,sha256=XT_ewCrxPxdUTMCYQGw34qZQ3GGu8TYY_v5Lige8By4,1707
75
76
  mcp_agent/telemetry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -80,7 +81,7 @@ mcp_agent/workflows/embedding/embedding_base.py,sha256=-c20ggQ8s7XhMxRX-WEhOgHE7
80
81
  mcp_agent/workflows/embedding/embedding_cohere.py,sha256=OKTJvKD_uEafd4c2uhR5tBjprea1nyvlJOO-3FDqOnk,1540
81
82
  mcp_agent/workflows/embedding/embedding_openai.py,sha256=dntjJ5P-FSMGYuyPZC8MuCU_ehwjXw9wDfzZZuSQN1E,1480
82
83
  mcp_agent/workflows/evaluator_optimizer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
- mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py,sha256=NsRaRte0_zbGPrvwAZadvcgSpY3d5ugbfVHooHOcJfc,15706
84
+ mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py,sha256=N4HjckQf_boFRxoWJmuvwq1IEnGYW-k8pKtqjpsnLSE,19223
84
85
  mcp_agent/workflows/intent_classifier/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
85
86
  mcp_agent/workflows/intent_classifier/intent_classifier_base.py,sha256=zTbOmq6EY_abOlme4zl28HM4RWNNS6bbHl3tF7SshJ0,4004
86
87
  mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py,sha256=_bWZGukc_q9LdA_Q18UoAMSzhN8tt4K_bRHNUhy7Crw,3997
@@ -97,7 +98,7 @@ mcp_agent/workflows/llm/llm_selector.py,sha256=G7pIybuBDwtmyxUDov_QrNYH2FoI0qFRu
97
98
  mcp_agent/workflows/llm/model_factory.py,sha256=7zTJrO2ReHa_6dfh_gY6xO8dTySqGFCKlOG9-AMJ-i8,6920
98
99
  mcp_agent/workflows/llm/prompt_utils.py,sha256=EY3eddqnmc_YDUQJFysPnpTH6hr4r2HneeEmX76P8TQ,4948
99
100
  mcp_agent/workflows/orchestrator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
100
- mcp_agent/workflows/orchestrator/orchestrator.py,sha256=dmj7CwTEHj0f8bTakijjvaOfJJ8ShgWwOWaCmFRiX7s,21933
101
+ mcp_agent/workflows/orchestrator/orchestrator.py,sha256=nyn0vTjUz-lea7nIYY-aoVWOKB2ceNNV4x4z92bP3CI,23638
101
102
  mcp_agent/workflows/orchestrator/orchestrator_models.py,sha256=xTl2vUIqdLPvDAnqA485Hf_A3DD48TWhAbo-jfGrmRE,7182
102
103
  mcp_agent/workflows/orchestrator/orchestrator_prompts.py,sha256=eJSQThfd6Jvr1jTDx104sJI5R684yE55L_edCiWERsQ,6153
103
104
  mcp_agent/workflows/parallel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -114,8 +115,8 @@ mcp_agent/workflows/swarm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
114
115
  mcp_agent/workflows/swarm/swarm.py,sha256=-lAIeSWDqbGHGRPTvjiP9nIKWvxxy9DAojl9yQzO1Pw,11050
115
116
  mcp_agent/workflows/swarm/swarm_anthropic.py,sha256=pW8zFx5baUWGd5Vw3nIDF2oVOOGNorij4qvGJKdYPcs,1624
116
117
  mcp_agent/workflows/swarm/swarm_openai.py,sha256=wfteywvAGkT5bLmIxX_StHJq8144whYmCRnJASAjOes,1596
117
- fast_agent_mcp-0.0.16.dist-info/METADATA,sha256=8lvkk2i0uitUQtc30LcOd7Wdak4uflU0aXO_Ve37X1Y,26857
118
- fast_agent_mcp-0.0.16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
119
- fast_agent_mcp-0.0.16.dist-info/entry_points.txt,sha256=2IXtSmDK9XjWN__RWuRIJTgWyW17wJnJ_h-pb0pZAxo,174
120
- fast_agent_mcp-0.0.16.dist-info/licenses/LICENSE,sha256=cN3FxDURL9XuzE5mhK9L2paZo82LTfjwCYVT7e3j0e4,10939
121
- fast_agent_mcp-0.0.16.dist-info/RECORD,,
118
+ fast_agent_mcp-0.1.0.dist-info/METADATA,sha256=hN241Foz895Wj3dxkXWKDVeeTuIWmAT1zh7Jvgpo3Bo,27257
119
+ fast_agent_mcp-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
120
+ fast_agent_mcp-0.1.0.dist-info/entry_points.txt,sha256=2IXtSmDK9XjWN__RWuRIJTgWyW17wJnJ_h-pb0pZAxo,174
121
+ fast_agent_mcp-0.1.0.dist-info/licenses/LICENSE,sha256=cN3FxDURL9XuzE5mhK9L2paZo82LTfjwCYVT7e3j0e4,10939
122
+ fast_agent_mcp-0.1.0.dist-info/RECORD,,
@@ -135,7 +135,7 @@ def copy_example_files(
135
135
 
136
136
  def show_overview():
137
137
  """Display an overview of available examples in a nicely formatted table."""
138
- console.print("\n[bold cyan]FastAgent Example Applications[/bold cyan]")
138
+ console.print("\n[bold cyan]fast-agent Example Applications[/bold cyan]")
139
139
  console.print("Build agents and compose workflows through practical examples\n")
140
140
 
141
141
  # Create a table for better organization
@@ -185,7 +185,7 @@ def init(
185
185
  # Check for existing .gitignore
186
186
  needs_gitignore = not find_gitignore(config_path)
187
187
 
188
- console.print("\n[bold]FastAgent Setup[/bold]\n")
188
+ console.print("\n[bold]fast-agent Setup[/bold]\n")
189
189
  console.print("This will create the following files:")
190
190
  console.print(f" - {config_path}/fastagent.config.yaml")
191
191
  console.print(f" - {config_path}/fastagent.secrets.yaml")
@@ -227,6 +227,9 @@ def init(
227
227
  console.print(
228
228
  "2. Keep fastagent.secrets.yaml secure and never commit it to version control"
229
229
  )
230
+ console.print(
231
+ "3. Update fastagent.config.yaml to set a default model (currently system default is 'haiku')"
232
+ )
230
233
  console.print("\nTo get started, run:")
231
234
  console.print(" uv run agent.py")
232
235
  else:
mcp_agent/cli/main.py CHANGED
@@ -22,7 +22,14 @@ console = Console()
22
22
 
23
23
  def show_welcome():
24
24
  """Show a welcome message with available commands."""
25
- console.print("\n[bold]Welcome to MCP Agent![/bold]")
25
+ from importlib.metadata import version
26
+
27
+ try:
28
+ app_version = version("fast-agent-mcp")
29
+ except: # noqa: E722
30
+ app_version = "unknown"
31
+
32
+ console.print(f"\n[bold]fast-agent (fast-agent-mcp) {app_version}[/bold]")
26
33
  console.print("Build effective agents using Model Context Protocol (MCP)")
27
34
 
28
35
  # Create a table for commands
@@ -41,8 +48,11 @@ def show_welcome():
41
48
  console.print("\n[bold]Getting Started:[/bold]")
42
49
  console.print("1. Set up a new project:")
43
50
  console.print(" fastagent setup")
44
- console.print("\n2. Try an example workflow:")
45
- console.print(" fastagent bootstrap create workflow")
51
+ console.print("\n2. Create Building Effective Agents workflow examples:")
52
+ console.print(" fastagent bootstrap workflow")
53
+ console.print("\n3. Explore other examples:")
54
+ console.print(" fastagent bootstrap")
55
+
46
56
  console.print("\nUse --help with any command for more information")
47
57
  console.print("Example: fastagent bootstrap --help")
48
58
 
@@ -129,7 +129,7 @@ class AgentApp:
129
129
  continue
130
130
 
131
131
  result = await self.send(agent, user_input)
132
-
132
+
133
133
  # Check if current agent is a chain that should continue with final agent
134
134
  if agent_types.get(agent) == "Chain":
135
135
  proxy = self._agents[agent]
@@ -52,7 +52,7 @@ class AgentCompleter(Completer):
52
52
  "clear": "Clear the screen",
53
53
  "agents": "List available agents",
54
54
  "STOP": "Stop this prompting session and move to next workflow step",
55
- "EXIT": "Exit FastAgent, terminating any running workflows",
55
+ "EXIT": "Exit fast-agent, terminating any running workflows",
56
56
  **(commands or {}), # Allow custom commands to be passed in
57
57
  }
58
58
  if is_human_input:
@@ -319,7 +319,7 @@ async def handle_special_commands(command, agent_app=None):
319
319
  rich_print(" @agent_name - Switch to agent")
320
320
  rich_print(" STOP - Return control back to the workflow")
321
321
  rich_print(
322
- " EXIT - Exit FastAgent, terminating any running workflows"
322
+ " EXIT - Exit fast-agent, terminating any running workflows"
323
323
  )
324
324
  rich_print("\n[bold]Keyboard Shortcuts:[/bold]")
325
325
  rich_print(
@@ -338,7 +338,7 @@ async def handle_special_commands(command, agent_app=None):
338
338
  return True
339
339
 
340
340
  elif command == "EXIT":
341
- raise PromptExitError("User requested to exit FastAgent session")
341
+ raise PromptExitError("User requested to exit fast-agent session")
342
342
 
343
343
  elif command == "LIST_AGENTS":
344
344
  if available_agents:
@@ -89,21 +89,23 @@ class FastAgent(ContextDependent):
89
89
  help="Specify the agent to send a message to (used with --message)",
90
90
  )
91
91
  parser.add_argument(
92
- "-m", "--message",
92
+ "-m",
93
+ "--message",
93
94
  help="Message to send to the specified agent (requires --agent)",
94
95
  )
95
96
  parser.add_argument(
96
- "--quiet", action="store_true",
97
+ "--quiet",
98
+ action="store_true",
97
99
  help="Disable progress display, tool and message logging for cleaner output",
98
100
  )
99
101
  self.args = parser.parse_args()
100
-
102
+
101
103
  # Quiet mode will be handled in _load_config()
102
104
 
103
105
  self.name = name
104
106
  self.config_path = config_path
105
107
  self._load_config()
106
-
108
+
107
109
  # Create the MCPApp with the config
108
110
  self.app = MCPApp(
109
111
  name=name,
@@ -244,10 +246,24 @@ class FastAgent(ContextDependent):
244
246
  if child_data["type"] == AgentType.BASIC.value:
245
247
  # For basic agents, we'll validate LLM config during creation
246
248
  continue
247
- elif not isinstance(child_data["func"], AugmentedLLM):
249
+ # Check if it's a workflow type or has LLM capability
250
+ # Workflows like EvaluatorOptimizer and Parallel are valid for orchestrator
251
+ func = child_data["func"]
252
+ workflow_types = [
253
+ AgentType.EVALUATOR_OPTIMIZER.value,
254
+ AgentType.PARALLEL.value,
255
+ AgentType.ROUTER.value,
256
+ AgentType.CHAIN.value,
257
+ ]
258
+
259
+ if not (
260
+ isinstance(func, AugmentedLLM)
261
+ or child_data["type"] in workflow_types
262
+ or (hasattr(func, "_llm") and func._llm is not None)
263
+ ):
248
264
  raise AgentConfigError(
249
265
  f"Agent '{agent_name}' used by orchestrator '{name}' lacks LLM capability",
250
- "All agents used by orchestrators must be LLM-capable",
266
+ "All agents used by orchestrators must be LLM-capable (either an AugmentedLLM or have an _llm property)",
251
267
  )
252
268
 
253
269
  elif agent_type == AgentType.ROUTER.value:
@@ -536,7 +552,7 @@ class FastAgent(ContextDependent):
536
552
  Args:
537
553
  name: Name of the parallel executing agent
538
554
  fan_out: List of parallel execution agents
539
- fan_in: Optional name of collecting agent. If not provided, a passthrough agent
555
+ fan_in: Optional name of collecting agent. If not provided, a passthrough agent
540
556
  will be created automatically with the name "{name}_fan_in"
541
557
  instruction: Optional instruction for the parallel agent
542
558
  model: Model specification string
@@ -547,7 +563,7 @@ class FastAgent(ContextDependent):
547
563
  # If fan_in is not provided, create a passthrough agent with a derived name
548
564
  if fan_in is None:
549
565
  passthrough_name = f"{name}_fan_in"
550
-
566
+
551
567
  # Register the passthrough agent directly in self.agents
552
568
  self.agents[passthrough_name] = {
553
569
  "config": AgentConfig(
@@ -559,10 +575,10 @@ class FastAgent(ContextDependent):
559
575
  "type": AgentType.BASIC.value, # Using BASIC type since we're just attaching a PassthroughLLM
560
576
  "func": lambda x: x, # Simple passthrough function (never actually called)
561
577
  }
562
-
578
+
563
579
  # Use this passthrough as the fan-in
564
580
  fan_in = passthrough_name
565
-
581
+
566
582
  decorator = self._create_decorator(
567
583
  AgentType.PARALLEL,
568
584
  default_instruction="",
@@ -589,6 +605,7 @@ class FastAgent(ContextDependent):
589
605
  max_refinements: int = 3,
590
606
  use_history: bool = True,
591
607
  request_params: Optional[Dict] = None,
608
+ instruction: Optional[str] = None,
592
609
  ) -> Callable:
593
610
  """
594
611
  Decorator to create and register an evaluator-optimizer workflow.
@@ -601,10 +618,11 @@ class FastAgent(ContextDependent):
601
618
  max_refinements: Maximum number of refinement iterations
602
619
  use_history: Whether to maintain conversation history
603
620
  request_params: Additional request parameters for the LLM
621
+ instruction: Optional instruction for the workflow (if not provided, uses generator's instruction)
604
622
  """
605
623
  decorator = self._create_decorator(
606
624
  AgentType.EVALUATOR_OPTIMIZER,
607
- default_instruction="",
625
+ default_instruction="", # We'll get instruction from generator or override
608
626
  default_servers=[],
609
627
  default_use_history=True,
610
628
  wrapper_needed=True,
@@ -616,6 +634,7 @@ class FastAgent(ContextDependent):
616
634
  max_refinements=max_refinements,
617
635
  use_history=use_history,
618
636
  request_params=request_params,
637
+ instruction=instruction, # Pass through any custom instruction
619
638
  )
620
639
  return decorator
621
640
 
@@ -645,7 +664,7 @@ class FastAgent(ContextDependent):
645
664
  AgentType.ROUTER,
646
665
  default_instruction="",
647
666
  default_servers=[],
648
- default_use_history=True,
667
+ default_use_history=False,
649
668
  wrapper_needed=True,
650
669
  )(
651
670
  name=name,
@@ -708,17 +727,14 @@ class FastAgent(ContextDependent):
708
727
  continue_with_final=continue_with_final,
709
728
  )
710
729
  return decorator
711
-
730
+
712
731
  def passthrough(
713
- self,
714
- name: str = "Passthrough",
715
- use_history: bool = True,
716
- **kwargs
732
+ self, name: str = "Passthrough", use_history: bool = True, **kwargs
717
733
  ) -> Callable:
718
734
  """
719
735
  Decorator to create and register a passthrough agent.
720
736
  A passthrough agent simply returns any input message without modification.
721
-
737
+
722
738
  This is useful for parallel workflows where no fan-in aggregation is needed
723
739
  (the fan-in agent can be a passthrough that simply returns the combined outputs).
724
740
 
@@ -774,15 +790,17 @@ class FastAgent(ContextDependent):
774
790
  if agent_type == AgentType.BASIC:
775
791
  # Get the agent name for special handling
776
792
  agent_name = agent_data["config"].name
777
-
793
+
778
794
  # Check if this is an agent that should use the PassthroughLLM
779
- if agent_name.endswith("_fan_in") or agent_name.startswith("passthrough"):
795
+ if agent_name.endswith("_fan_in") or agent_name.startswith(
796
+ "passthrough"
797
+ ):
780
798
  # Import here to avoid circular imports
781
799
  from mcp_agent.workflows.llm.augmented_llm import PassthroughLLM
782
-
800
+
783
801
  # Create basic agent with configuration
784
802
  agent = Agent(config=config, context=agent_app.context)
785
-
803
+
786
804
  # Set up a PassthroughLLM directly
787
805
  async with agent:
788
806
  agent._llm = PassthroughLLM(
@@ -791,13 +809,13 @@ class FastAgent(ContextDependent):
791
809
  agent=agent,
792
810
  default_request_params=config.default_request_params,
793
811
  )
794
-
812
+
795
813
  # Store the agent
796
814
  instance = agent
797
815
  else:
798
816
  # Standard basic agent with LLM
799
817
  agent = Agent(config=config, context=agent_app.context)
800
-
818
+
801
819
  # Set up LLM with proper configuration
802
820
  async with agent:
803
821
  llm_factory = self._get_model_factory(
@@ -805,7 +823,7 @@ class FastAgent(ContextDependent):
805
823
  request_params=config.default_request_params,
806
824
  )
807
825
  agent._llm = await agent.attach_llm(llm_factory)
808
-
826
+
809
827
  # Store the agent
810
828
  instance = agent
811
829
 
@@ -885,18 +903,19 @@ class FastAgent(ContextDependent):
885
903
  f"evaluator={agent_data['evaluator']}"
886
904
  )
887
905
 
888
- # TODO: Remove legacy - factory usage is only needed for str evaluators
889
- # Later this should only be passed when evaluator is a string
890
906
  optimizer_model = (
891
907
  generator.config.model if isinstance(generator, Agent) else None
892
908
  )
909
+
893
910
  instance = EvaluatorOptimizerLLM(
911
+ name=config.name, # Pass name from config
894
912
  generator=generator,
895
913
  evaluator=evaluator,
896
914
  min_rating=QualityRating[agent_data["min_rating"]],
897
915
  max_refinements=agent_data["max_refinements"],
898
916
  llm_factory=self._get_model_factory(model=optimizer_model),
899
917
  context=agent_app.context,
918
+ instruction=config.instruction, # Pass any custom instruction
900
919
  )
901
920
 
902
921
  elif agent_type == AgentType.ROUTER:
@@ -1249,77 +1268,96 @@ class FastAgent(ContextDependent):
1249
1268
  """
1250
1269
  active_agents = {}
1251
1270
  had_error = False
1252
-
1271
+
1253
1272
  # Handle quiet mode by disabling logger settings after initialization
1254
1273
  quiet_mode = hasattr(self, "args") and self.args.quiet
1255
-
1274
+
1256
1275
  try:
1257
1276
  async with self.app.run() as agent_app:
1258
1277
  # Apply quiet mode directly to the context's config if needed
1259
- if quiet_mode and hasattr(agent_app.context, "config") and hasattr(agent_app.context.config, "logger"):
1278
+ if (
1279
+ quiet_mode
1280
+ and hasattr(agent_app.context, "config")
1281
+ and hasattr(agent_app.context.config, "logger")
1282
+ ):
1260
1283
  # Apply after initialization but before agents are created
1261
1284
  agent_app.context.config.logger.progress_display = False
1262
1285
  agent_app.context.config.logger.show_chat = False
1263
1286
  agent_app.context.config.logger.show_tools = False
1264
-
1287
+
1265
1288
  # Directly disable the progress display singleton
1266
1289
  from mcp_agent.progress_display import progress_display
1290
+
1267
1291
  progress_display.stop() # This will stop and hide the display
1268
-
1292
+
1269
1293
  # Pre-flight validation
1270
1294
  self._validate_server_references()
1271
1295
  self._validate_workflow_references()
1272
1296
 
1273
1297
  # Create all types of agents in dependency order
1298
+ # First create basic agents
1274
1299
  active_agents = await self._create_basic_agents(agent_app)
1275
1300
 
1276
- orchestrators = await self._create_orchestrators(
1301
+ # Create workflow types that don't depend on other workflows first
1302
+ evaluator_optimizers = await self._create_evaluator_optimizers(
1277
1303
  agent_app, active_agents
1278
1304
  )
1305
+ active_agents.update(evaluator_optimizers)
1306
+
1307
+ # Create parallel agents next as they might be dependencies
1279
1308
  parallel_agents = await self._create_parallel_agents(
1280
1309
  agent_app, active_agents
1281
1310
  )
1282
- evaluator_optimizers = await self._create_evaluator_optimizers(
1283
- agent_app, active_agents
1284
- )
1311
+ active_agents.update(parallel_agents)
1312
+
1313
+ # Create routers next
1285
1314
  routers = await self._create_routers(agent_app, active_agents)
1315
+ active_agents.update(routers)
1316
+
1317
+ # Create chains next
1286
1318
  chains = await self._create_agents_in_dependency_order(
1287
1319
  agent_app, active_agents, AgentType.CHAIN
1288
1320
  )
1321
+ active_agents.update(chains)
1289
1322
 
1290
- # Merge all agents into active_agents
1323
+ # Create orchestrators last as they might depend on any other agent type
1324
+ orchestrators = await self._create_orchestrators(
1325
+ agent_app, active_agents
1326
+ )
1327
+
1328
+ # Add orchestrators to active_agents (other types were already added)
1291
1329
  active_agents.update(orchestrators)
1292
- active_agents.update(parallel_agents)
1293
- active_agents.update(evaluator_optimizers)
1294
- active_agents.update(routers)
1295
- active_agents.update(chains)
1296
1330
 
1297
1331
  # Create wrapper with all agents
1298
1332
  wrapper = AgentApp(agent_app, active_agents)
1299
-
1333
+
1300
1334
  # Handle direct message sending if --agent and --message are provided
1301
1335
  if self.args.agent and self.args.message:
1302
1336
  agent_name = self.args.agent
1303
1337
  message = self.args.message
1304
-
1338
+
1305
1339
  if agent_name not in active_agents:
1306
1340
  available_agents = ", ".join(active_agents.keys())
1307
- print(f"\n\nError: Agent '{agent_name}' not found. Available agents: {available_agents}")
1341
+ print(
1342
+ f"\n\nError: Agent '{agent_name}' not found. Available agents: {available_agents}"
1343
+ )
1308
1344
  raise SystemExit(1)
1309
-
1345
+
1310
1346
  try:
1311
1347
  # Get response
1312
1348
  response = await wrapper[agent_name].send(message)
1313
-
1349
+
1314
1350
  # Only print the response in quiet mode
1315
1351
  if self.args.quiet:
1316
1352
  print(f"{response}")
1317
-
1353
+
1318
1354
  raise SystemExit(0)
1319
1355
  except Exception as e:
1320
- print(f"\n\nError sending message to agent '{agent_name}': {str(e)}")
1356
+ print(
1357
+ f"\n\nError sending message to agent '{agent_name}': {str(e)}"
1358
+ )
1321
1359
  raise SystemExit(1)
1322
-
1360
+
1323
1361
  yield wrapper
1324
1362
 
1325
1363
  except ServerConfigError as e: