fast-agent-mcp 0.2.17__py3-none-any.whl → 0.2.18__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.2.17
3
+ Version: 0.2.18
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
@@ -259,7 +259,8 @@ The simple declarative syntax lets you concentrate on composing your Prompts and
259
259
 
260
260
  `fast-agent` is multi-modal, supporting Images and PDFs for both Anthropic and OpenAI endpoints via Prompts, Resources and MCP Tool Call results. The inclusion of passthrough and playback LLMs enable rapid development and test of Python glue-code for your applications.
261
261
 
262
- > [!TIP] > `fast-agent` is now MCP Native! Coming Soon - Full Documentation Site and Further MCP Examples.
262
+ > [!TIP]
263
+ > `fast-agent` is now MCP Native! Coming Soon - Full Documentation Site and Further MCP Examples.
263
264
 
264
265
  ### Agent Application Development
265
266
 
@@ -20,25 +20,26 @@ mcp_agent/agents/workflow/parallel_agent.py,sha256=GQTxAqwrPEdle-rPWMvoLOuzE_X69
20
20
  mcp_agent/agents/workflow/router_agent.py,sha256=NugAJcA1ooZ-TNLNh7H26xIFChZoryxofJ7fTkrw4cU,9128
21
21
  mcp_agent/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  mcp_agent/cli/__main__.py,sha256=AVZ7tQFhU_sDOGuUGJq8ujgKtcxsYJBJwHbVaaiRDlI,166
23
- mcp_agent/cli/main.py,sha256=m0Ndb8y5qCfYyTDBDaJ4g1TuUiX-xtTKNJJDPsltw6o,2884
23
+ mcp_agent/cli/main.py,sha256=XjrgXMBaPKkVqAFo8T9LJz6Tp1-ivrKDOuNYWke99YA,3090
24
24
  mcp_agent/cli/terminal.py,sha256=GRwD-RGW7saIz2IOWZn5vD6JjiArscELBThm1GTFkuI,1065
25
25
  mcp_agent/cli/commands/check_config.py,sha256=9Ryxo_fLInm3YKdYv46yLrAJgnQtMisGreu6Kkriw2g,16677
26
+ mcp_agent/cli/commands/go.py,sha256=DJpmq4n-p5r8BXH10UqBOexmLND-zSODl5f-w4noR5Q,4304
26
27
  mcp_agent/cli/commands/quickstart.py,sha256=SM3CHMzDgvTxIpKjFuX9BrS_N1vRoXNBDaO90aWx1Rk,14586
27
- mcp_agent/cli/commands/setup.py,sha256=hToVzlCDucf1RI6Jri7BPuSeNA6Y67ONG-nyUT-n7tE,6472
28
+ mcp_agent/cli/commands/setup.py,sha256=eOEd4TL-b0DaDeSJMGOfNOsTEItoZ67W88eTP4aP-bo,6482
28
29
  mcp_agent/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
30
  mcp_agent/core/agent_app.py,sha256=5nQJNo8DocIRWiX4pVKAHUZF8s6HWpc-hJnfzl_1v1c,9697
30
31
  mcp_agent/core/agent_types.py,sha256=bQVQMTwKH7qHIJsNglj4C_d6PNFBBzC_0RIkcENSII4,1459
31
32
  mcp_agent/core/direct_decorators.py,sha256=aaVR4G6a8H9pVg6X_PGEZ8GzreP0ZO1-48ksIKvMNDI,14452
32
33
  mcp_agent/core/direct_factory.py,sha256=d96OM1yS3eIocIiaA9FQt6C2zr6VDUyCJBTZCp_D4bs,17912
33
- mcp_agent/core/enhanced_prompt.py,sha256=kEgeD7F1s8LRZDc3Xr6CIxQxewxXy9z-0xZsxfIblsY,18851
34
+ mcp_agent/core/enhanced_prompt.py,sha256=bzvcengS7XzHWB7NWhyxHM3hhO2HI4zP5DbGXAOw0Jw,19155
34
35
  mcp_agent/core/error_handling.py,sha256=xoyS2kLe0eG0bj2eSJCJ2odIhGUve2SbDR7jP-A-uRw,624
35
36
  mcp_agent/core/exceptions.py,sha256=ENAD_qGG67foxy6vDkIvc-lgopIUQy6O7zvNPpPXaQg,2289
36
- mcp_agent/core/fastagent.py,sha256=NahciY0tY6K-rvSzkSgahzGXAWa-1nN2JgMlvRTze6E,18645
37
- mcp_agent/core/interactive_prompt.py,sha256=9s5c-XXGAKAqYh1SUVQIMRGFIcxfFjkaPmke1tyInaA,23854
37
+ mcp_agent/core/fastagent.py,sha256=nj2o7T-ClI8ZeUHEr0pSfVxGIkbUffoJ9jT11DNKD_c,20195
38
+ mcp_agent/core/interactive_prompt.py,sha256=w3VyRzW4hzn0xhWZRwo_qRRAD5WVSrJYe8QDe1XZ55Y,24252
38
39
  mcp_agent/core/mcp_content.py,sha256=2D7KHY9mG_vxoDwFLKvsPQV9VRIzHItM7V-jcEnACh8,8878
39
40
  mcp_agent/core/prompt.py,sha256=qnintOUGEoDPYLI9bu9G2OlgVMCe5ZPUZilgMzydXhc,7919
40
41
  mcp_agent/core/request_params.py,sha256=loYf13DN7e-DsdYRd37jWkJWJGwVBL-iFkcANP1J60Q,1366
41
- mcp_agent/core/validation.py,sha256=Kmio1Xx-xNyCVd03RLfTxofEAWmVDPxUnQoyOSUMjR0,11445
42
+ mcp_agent/core/validation.py,sha256=RIBKFlh0GJg4rTcFQXoXp8A0sK1HpsCigKcYSK3gFaY,12090
42
43
  mcp_agent/executor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
44
  mcp_agent/executor/executor.py,sha256=MzLSnW9nHrLHYChR3oQa5B8dajQGX26q6-S2BJCxv0o,9507
44
45
  mcp_agent/executor/task_registry.py,sha256=PCALFeYtkQrPBg4RBJnlA0aDI8nHclrNkHGUS4kV3W8,1242
@@ -59,11 +60,11 @@ mcp_agent/llm/sampling_converter.py,sha256=C7wPBlmT0eD90XWabC22zkxsrVHKCrjwIwg6c
59
60
  mcp_agent/llm/sampling_format_converter.py,sha256=xGz4odHpOcP7--eFaJaFtUR8eR9jxZS7MnLH6J7n0EU,1263
60
61
  mcp_agent/llm/providers/__init__.py,sha256=heVxtmuqFJOnjjxHz4bWSqTAxXoN1E8twC_gQ_yJpHk,265
61
62
  mcp_agent/llm/providers/anthropic_utils.py,sha256=vYDN5G5jKMhD2CQg8veJYab7tvvzYkDMq8M1g_hUAQg,3275
62
- mcp_agent/llm/providers/augmented_llm_anthropic.py,sha256=GuqBJvkaM8SQ3NYBnMlKrV56dACLafhKec-Hl84qOi8,15344
63
- mcp_agent/llm/providers/augmented_llm_deepseek.py,sha256=MHsCffnrXpiWdUCpVTUblILVBTQtBnbX7atwny0X2N8,1210
63
+ mcp_agent/llm/providers/augmented_llm_anthropic.py,sha256=poouQMsDoZSH-5a_TL2Z2EFPSqFlsAgXuKuYcqge-Gg,15468
64
+ mcp_agent/llm/providers/augmented_llm_deepseek.py,sha256=NiZK5nv91ZS2VgVFXpbsFNFYLsLcppcbo_RstlRMd7I,1145
64
65
  mcp_agent/llm/providers/augmented_llm_generic.py,sha256=5Uq8ZBhcFuQTt7koP_5ykolREh2iWu8zKhNbh3pM9lQ,1210
65
66
  mcp_agent/llm/providers/augmented_llm_google.py,sha256=N0a2fphVtkvNYxKQpEX6J4tlO1C_mRw4sw3LBXnrOeI,1130
66
- mcp_agent/llm/providers/augmented_llm_openai.py,sha256=YDumEOjuhvAcqOOdw6xsy902lyC30iqgl1V2lS6PfTA,13911
67
+ mcp_agent/llm/providers/augmented_llm_openai.py,sha256=ypK1pDwBKjvdemyEsfzhebinQ6fSAnJS5OUsDVlvdOw,14001
67
68
  mcp_agent/llm/providers/augmented_llm_openrouter.py,sha256=V_TlVKm92GHBxYIo6gpvH_6cAaIdppS25Tz6x5T7LW0,2341
68
69
  mcp_agent/llm/providers/multipart_converter_anthropic.py,sha256=t5lHYGfFUacJldnrVtMNW-8gEMoto8Y7hJkDrnyZR-Y,16650
69
70
  mcp_agent/llm/providers/multipart_converter_openai.py,sha256=XPIulWntNpZWNGWrc240StPzok2RqrDAV7OigDwQ1uU,15850
@@ -143,8 +144,8 @@ mcp_agent/resources/examples/workflows/parallel.py,sha256=DQ5vY5-h8Qa5QHcYjsWXhZ
143
144
  mcp_agent/resources/examples/workflows/router.py,sha256=E4x_-c3l4YW9w1i4ARcDtkdeqIdbWEGfsMzwLYpdbVc,1677
144
145
  mcp_agent/resources/examples/workflows/short_story.txt,sha256=X3y_1AyhLFN2AKzCKvucJtDgAFIJfnlbsbGZO5bBWu0,1187
145
146
  mcp_agent/ui/console_display.py,sha256=TVGDtJ37hc6UG0ei9g7ZPZZfFNeS1MYozt-Mx8HsPCk,9752
146
- fast_agent_mcp-0.2.17.dist-info/METADATA,sha256=qH-sDtu59orBDwzB0M73kx9CZUfey-5g2izt3Ewjz0A,29893
147
- fast_agent_mcp-0.2.17.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
148
- fast_agent_mcp-0.2.17.dist-info/entry_points.txt,sha256=bRniFM5zk3Kix5z7scX0gf9VnmGQ2Cz_Q1Gh7Ir4W00,186
149
- fast_agent_mcp-0.2.17.dist-info/licenses/LICENSE,sha256=cN3FxDURL9XuzE5mhK9L2paZo82LTfjwCYVT7e3j0e4,10939
150
- fast_agent_mcp-0.2.17.dist-info/RECORD,,
147
+ fast_agent_mcp-0.2.18.dist-info/METADATA,sha256=gFL_3akF6ZiJirx5mn_IxBhdp_wJ4OkJGx5YF2hAu38,29893
148
+ fast_agent_mcp-0.2.18.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
149
+ fast_agent_mcp-0.2.18.dist-info/entry_points.txt,sha256=bRniFM5zk3Kix5z7scX0gf9VnmGQ2Cz_Q1Gh7Ir4W00,186
150
+ fast_agent_mcp-0.2.18.dist-info/licenses/LICENSE,sha256=cN3FxDURL9XuzE5mhK9L2paZo82LTfjwCYVT7e3j0e4,10939
151
+ fast_agent_mcp-0.2.18.dist-info/RECORD,,
@@ -0,0 +1,133 @@
1
+ """Run an interactive agent directly from the command line."""
2
+
3
+ import asyncio
4
+ import sys
5
+ from typing import List, Optional
6
+
7
+ import typer
8
+
9
+ from mcp_agent.core.fastagent import FastAgent
10
+
11
+ app = typer.Typer(
12
+ help="Run an interactive agent directly from the command line without creating an agent.py file"
13
+ )
14
+
15
+ async def _run_agent(
16
+ name: str = "FastAgent CLI",
17
+ instruction: str = "You are a helpful AI Agent.",
18
+ config_path: Optional[str] = None,
19
+ server_list: Optional[List[str]] = None,
20
+ model: Optional[str] = None,
21
+ ) -> None:
22
+ """Async implementation to run an interactive agent."""
23
+
24
+ # Create the FastAgent instance with CLI arg parsing enabled
25
+ # It will automatically parse args like --model, --quiet, etc.
26
+ fast_kwargs = {
27
+ "name": name,
28
+ "config_path": config_path,
29
+ "ignore_unknown_args": True,
30
+ }
31
+
32
+ fast = FastAgent(**fast_kwargs)
33
+
34
+ # Define the agent with specified parameters
35
+ agent_kwargs = {"instruction": instruction}
36
+ if server_list:
37
+ agent_kwargs["servers"] = server_list
38
+ if model:
39
+ agent_kwargs["model"] = model
40
+
41
+ @fast.agent(**agent_kwargs)
42
+ async def cli_agent():
43
+ async with fast.run() as agent:
44
+ await agent.interactive()
45
+
46
+ # Run the agent
47
+ await cli_agent()
48
+
49
+ def run_async_agent(
50
+ name: str,
51
+ instruction: str,
52
+ config_path: Optional[str] = None,
53
+ servers: Optional[str] = None,
54
+ model: Optional[str] = None
55
+ ):
56
+ """Run the async agent function with proper loop handling."""
57
+ server_list = servers.split(',') if servers else None
58
+
59
+ # Check if we're already in an event loop
60
+ try:
61
+ loop = asyncio.get_event_loop()
62
+ if loop.is_running():
63
+ # We're inside a running event loop, so we can't use asyncio.run
64
+ # Instead, create a new loop
65
+ loop = asyncio.new_event_loop()
66
+ asyncio.set_event_loop(loop)
67
+ except RuntimeError:
68
+ # No event loop exists, so we'll create one
69
+ loop = asyncio.new_event_loop()
70
+ asyncio.set_event_loop(loop)
71
+
72
+ try:
73
+ loop.run_until_complete(_run_agent(
74
+ name=name,
75
+ instruction=instruction,
76
+ config_path=config_path,
77
+ server_list=server_list,
78
+ model=model
79
+ ))
80
+ finally:
81
+ try:
82
+ # Clean up the loop
83
+ tasks = asyncio.all_tasks(loop)
84
+ for task in tasks:
85
+ task.cancel()
86
+
87
+ # Run the event loop until all tasks are done
88
+ if sys.version_info >= (3, 7):
89
+ loop.run_until_complete(asyncio.gather(*tasks, return_exceptions=True))
90
+ loop.run_until_complete(loop.shutdown_asyncgens())
91
+ loop.close()
92
+ except Exception:
93
+ pass
94
+
95
+ @app.callback(invoke_without_command=True)
96
+ def go(
97
+ ctx: typer.Context,
98
+ name: str = typer.Option("FastAgent CLI", "--name", help="Name for the agent"),
99
+ instruction: str = typer.Option(
100
+ "You are a helpful AI Agent.", "--instruction", "-i", help="Instruction for the agent"
101
+ ),
102
+ config_path: Optional[str] = typer.Option(
103
+ None, "--config-path", "-c", help="Path to config file"
104
+ ),
105
+ servers: Optional[str] = typer.Option(
106
+ None, "--servers", help="Comma-separated list of server names to enable from config"
107
+ ),
108
+ model: Optional[str] = typer.Option(
109
+ None, "--model", help="Override the default model (e.g., haiku, sonnet, gpt-4)"
110
+ ),
111
+ ) -> None:
112
+ """
113
+ Run an interactive agent directly from the command line.
114
+
115
+ Example:
116
+ fast-agent go --model=haiku --instruction="You are a coding assistant" --servers=fetch,filesystem
117
+
118
+ This will start an interactive session with the agent, using the specified model
119
+ and instruction. It will use the default configuration from fastagent.config.yaml
120
+ unless --config-path is specified.
121
+
122
+ Common options:
123
+ --model: Override the default model (e.g., --model=haiku)
124
+ --quiet: Disable progress display and logging
125
+ --servers: Comma-separated list of server names to enable from config
126
+ """
127
+ run_async_agent(
128
+ name=name,
129
+ instruction=instruction,
130
+ config_path=config_path,
131
+ servers=servers,
132
+ model=model
133
+ )
@@ -221,7 +221,7 @@ def init(
221
221
  if "fastagent.secrets.yaml" in created:
222
222
  console.print("\n[yellow]Important:[/yellow] Remember to:")
223
223
  console.print(
224
- "1. Add your API keys to fastagent.secrets.yaml or set OPENAI_API_KEY and ANTHROPIC_API_KEY environment variables"
224
+ "1. Add your API keys to fastagent.secrets.yaml, or set environment variables. Use [cyan]fast-agent check[/cyan] to verify."
225
225
  )
226
226
  console.print(
227
227
  "2. Keep fastagent.secrets.yaml secure and never commit it to version control"
mcp_agent/cli/main.py CHANGED
@@ -4,7 +4,7 @@ import typer
4
4
  from rich.console import Console
5
5
  from rich.table import Table
6
6
 
7
- from mcp_agent.cli.commands import check_config, quickstart, setup
7
+ from mcp_agent.cli.commands import check_config, go, quickstart, setup
8
8
  from mcp_agent.cli.terminal import Application
9
9
 
10
10
  app = typer.Typer(
@@ -13,6 +13,7 @@ app = typer.Typer(
13
13
  )
14
14
 
15
15
  # Subcommands
16
+ app.add_typer(go.app, name="go", help="Run an interactive agent directly from the command line")
16
17
  app.add_typer(setup.app, name="setup", help="Set up a new agent project")
17
18
  app.add_typer(check_config.app, name="check", help="Show or diagnose fast-agent configuration")
18
19
  app.add_typer(quickstart.app, name="bootstrap", help="Create example applications")
@@ -39,14 +40,15 @@ def show_welcome() -> None:
39
40
  table.add_column("Command", style="green")
40
41
  table.add_column("Description")
41
42
 
42
- table.add_row("setup", "Create a new agent and configuration files")
43
+ table.add_row("[bold]go[/bold]", "Start an interactive session with an agent")
44
+ table.add_row("setup", "Create a new agent template and configuration files")
43
45
  table.add_row("check", "Show or diagnose fast-agent configuration")
44
46
  table.add_row("quickstart", "Create example applications (workflow, researcher, etc.)")
45
47
 
46
48
  console.print(table)
47
49
 
48
50
  console.print(
49
- "\n[italic]get started with:[/italic] [cyan]fast-agent[/cyan] [green]setup[/green]"
51
+ "\n[italic]get started with:[/italic] [bold][cyan]fast-agent[/cyan][/bold] [green]setup[/green]"
50
52
  )
51
53
 
52
54
 
@@ -289,14 +289,19 @@ async def get_enhanced_input(
289
289
  # Return a dictionary with select_prompt action instead of a string
290
290
  # This way it will match what the command handler expects
291
291
  return {"select_prompt": True, "prompt_name": None}
292
- elif cmd == "prompt" and len(cmd_parts) > 1:
293
- # Direct prompt selection with name or number
294
- prompt_arg = cmd_parts[1].strip()
295
- # Check if it's a number (use as index) or a name (use directly)
296
- if prompt_arg.isdigit():
297
- return {"select_prompt": True, "prompt_index": int(prompt_arg)}
292
+ elif cmd == "prompt":
293
+ # Handle /prompt with no arguments the same way as /prompts
294
+ if len(cmd_parts) > 1:
295
+ # Direct prompt selection with name or number
296
+ prompt_arg = cmd_parts[1].strip()
297
+ # Check if it's a number (use as index) or a name (use directly)
298
+ if prompt_arg.isdigit():
299
+ return {"select_prompt": True, "prompt_index": int(prompt_arg)}
300
+ else:
301
+ return f"SELECT_PROMPT:{prompt_arg}"
298
302
  else:
299
- return f"SELECT_PROMPT:{prompt_arg}"
303
+ # If /prompt is used without arguments, treat it the same as /prompts
304
+ return {"select_prompt": True, "prompt_name": None}
300
305
  elif cmd == "exit":
301
306
  return "EXIT"
302
307
  elif cmd.lower() == "stop":
@@ -9,7 +9,8 @@ import asyncio
9
9
  import sys
10
10
  from contextlib import asynccontextmanager
11
11
  from importlib.metadata import version as get_version
12
- from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, TypeVar
12
+ from pathlib import Path
13
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, TypeVar
13
14
 
14
15
  import yaml
15
16
 
@@ -54,9 +55,11 @@ from mcp_agent.core.validation import (
54
55
  validate_workflow_references,
55
56
  )
56
57
  from mcp_agent.logging.logger import get_logger
58
+ from mcp_agent.mcp.prompts.prompt_load import load_prompt_multipart
57
59
 
58
60
  if TYPE_CHECKING:
59
61
  from mcp_agent.agents.agent import Agent
62
+ from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
60
63
 
61
64
  F = TypeVar("F", bound=Callable[..., Any]) # For decorated functions
62
65
  logger = get_logger(__name__)
@@ -90,12 +93,16 @@ class FastAgent:
90
93
  )
91
94
  parser.add_argument(
92
95
  "--agent",
96
+ default="default",
93
97
  help="Specify the agent to send a message to (used with --message)",
94
98
  )
95
99
  parser.add_argument(
96
100
  "-m",
97
101
  "--message",
98
- help="Message to send to the specified agent (requires --agent)",
102
+ help="Message to send to the specified agent",
103
+ )
104
+ parser.add_argument(
105
+ "-p", "--prompt-file", help="Path to a prompt file to use (either text or JSON)"
99
106
  )
100
107
  parser.add_argument(
101
108
  "--quiet",
@@ -294,8 +301,8 @@ class FastAgent:
294
301
  # Exit after server shutdown
295
302
  raise SystemExit(0)
296
303
 
297
- # Handle direct message sending if --agent and --message are provided
298
- if hasattr(self, "args") and self.args.agent and self.args.message:
304
+ # Handle direct message sending if --message is provided
305
+ if self.args.message:
299
306
  agent_name = self.args.agent
300
307
  message = self.args.message
301
308
 
@@ -321,6 +328,33 @@ class FastAgent:
321
328
  print(f"\n\nError sending message to agent '{agent_name}': {str(e)}")
322
329
  raise SystemExit(1)
323
330
 
331
+ if self.args.prompt_file:
332
+ agent_name = self.args.agent
333
+ prompt: List[PromptMessageMultipart] = load_prompt_multipart(
334
+ Path(self.args.prompt_file)
335
+ )
336
+ if agent_name not in active_agents:
337
+ available_agents = ", ".join(active_agents.keys())
338
+ print(
339
+ f"\n\nError: Agent '{agent_name}' not found. Available agents: {available_agents}"
340
+ )
341
+ raise SystemExit(1)
342
+
343
+ try:
344
+ # Get response from the agent
345
+ agent = active_agents[agent_name]
346
+ response = await agent.generate(prompt)
347
+
348
+ # In quiet mode, just print the raw response
349
+ # The chat display should already be turned off by the configuration
350
+ if self.args.quiet:
351
+ print(f"{response.last_text()}")
352
+
353
+ raise SystemExit(0)
354
+ except Exception as e:
355
+ print(f"\n\nError sending message to agent '{agent_name}': {str(e)}")
356
+ raise SystemExit(1)
357
+
324
358
  yield wrapper
325
359
 
326
360
  except (
@@ -153,8 +153,12 @@ class InteractivePrompt:
153
153
  )
154
154
  continue
155
155
 
156
- # Skip further processing if command was handled
157
- if command_result:
156
+ # Skip further processing if:
157
+ # 1. The command was handled (command_result is truthy)
158
+ # 2. The original input was a dictionary (special command like /prompt)
159
+ # 3. The command result itself is a dictionary (special command handling result)
160
+ # This fixes the issue where /prompt without arguments gets sent to the LLM
161
+ if command_result or isinstance(user_input, dict) or isinstance(command_result, dict):
158
162
  continue
159
163
 
160
164
  if user_input.upper() == "STOP":
@@ -231,6 +231,12 @@ def get_dependencies_groups(
231
231
  if agent_type == AgentType.PARALLEL.value:
232
232
  # Parallel agents depend on their fan-out and fan-in agents
233
233
  dependencies[name].update(agent_data.get("parallel_agents", []))
234
+ # Also add explicit fan_out dependencies if present
235
+ if "fan_out" in agent_data:
236
+ dependencies[name].update(agent_data["fan_out"])
237
+ # Add explicit fan_in dependency if present
238
+ if "fan_in" in agent_data and agent_data["fan_in"]:
239
+ dependencies[name].add(agent_data["fan_in"])
234
240
  elif agent_type == AgentType.CHAIN.value:
235
241
  # Chain agents depend on the agents in their sequence
236
242
  dependencies[name].update(agent_data.get("sequence", []))
@@ -241,7 +247,12 @@ def get_dependencies_groups(
241
247
  # Orchestrator agents depend on their child agents
242
248
  dependencies[name].update(agent_data.get("child_agents", []))
243
249
  elif agent_type == AgentType.EVALUATOR_OPTIMIZER.value:
244
- # Evaluator-Optimizer agents depend on their evaluation and optimization agents
250
+ # Evaluator-Optimizer agents depend on their evaluator and generator agents
251
+ if "evaluator" in agent_data:
252
+ dependencies[name].add(agent_data["evaluator"])
253
+ if "generator" in agent_data:
254
+ dependencies[name].add(agent_data["generator"])
255
+ # For backward compatibility - also check eval_optimizer_agents if present
245
256
  dependencies[name].update(agent_data.get("eval_optimizer_agents", []))
246
257
 
247
258
  # Check for cycles if not allowed
@@ -347,10 +347,11 @@ class AnthropicAugmentedLLM(AugmentedLLM[MessageParam, Message]):
347
347
  ) -> Tuple[ModelT | None, PromptMessageMultipart]: # noqa: F821
348
348
  request_params = self.get_request_params(request_params)
349
349
 
350
+ # TODO - convert this to use Tool Calling convention for Anthropic Structured outputs
350
351
  multipart_messages[-1].add_text(
351
352
  """YOU MUST RESPOND IN THE FOLLOWING FORMAT:
352
353
  {schema}
353
- RESPOND ONLY WITH THE JSON, NO PREAMBLE OR CODE FENCES """.format(
354
+ RESPOND ONLY WITH THE JSON, NO PREAMBLE, CODE FENCES OR 'properties' ARE PERMISSABLE """.format(
354
355
  schema=model.model_json_schema()
355
356
  )
356
357
  )
@@ -8,9 +8,7 @@ DEFAULT_DEEPSEEK_MODEL = "deepseekchat" # current Deepseek only has two type mo
8
8
 
9
9
  class DeepSeekAugmentedLLM(OpenAIAugmentedLLM):
10
10
  def __init__(self, *args, **kwargs) -> None:
11
- super().__init__(
12
- *args, provider=Provider.DEEPSEEK, **kwargs
13
- ) # Properly pass args and kwargs to parent
11
+ super().__init__(*args, provider=Provider.DEEPSEEK, **kwargs)
14
12
 
15
13
  def _initialize_default_params(self, kwargs: dict) -> RequestParams:
16
14
  """Initialize Deepseek-specific default parameters"""
@@ -222,7 +222,7 @@ class OpenAIAugmentedLLM(AugmentedLLM[ChatCompletionMessageParam, ChatCompletion
222
222
  method="tools/call",
223
223
  params=CallToolRequestParams(
224
224
  name=tool_call.function.name,
225
- arguments=from_json(tool_call.function.arguments, allow_partial=True),
225
+ arguments={} if not tool_call.function.arguments or tool_call.function.arguments.strip() == '' else from_json(tool_call.function.arguments, allow_partial=True),
226
226
  ),
227
227
  )
228
228
  result = await self.call_tool(tool_call_request, tool_call.id)