fast-agent-mcp 0.0.12__tar.gz → 0.0.13__tar.gz

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.

Potentially problematic release.


This version of fast-agent-mcp might be problematic. Click here for more details.

Files changed (117) hide show
  1. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/.gitignore +1 -0
  2. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/PKG-INFO +7 -1
  3. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/README.md +6 -0
  4. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/pyproject.toml +1 -1
  5. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/agents/agent.py +48 -8
  6. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/cli/commands/bootstrap.py +1 -0
  7. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/cli/commands/setup.py +1 -1
  8. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/cli/main.py +3 -3
  9. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/core/enhanced_prompt.py +59 -16
  10. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/core/exceptions.py +17 -0
  11. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/core/fastagent.py +43 -7
  12. fast_agent_mcp-0.0.13/src/mcp_agent/human_input/handler.py +78 -0
  13. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/mcp/mcp_connection_manager.py +14 -12
  14. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/workflows/chaining.py +5 -1
  15. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/workflows/evaluator.py +2 -2
  16. fast_agent_mcp-0.0.13/src/mcp_agent/resources/examples/workflows/fastagent.config.yaml +24 -0
  17. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/workflows/orchestrator.py +3 -2
  18. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/workflows/parallel.py +2 -1
  19. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/llm/augmented_llm.py +3 -0
  20. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/llm/model_factory.py +7 -4
  21. fast_agent_mcp-0.0.12/src/mcp_agent/human_input/handler.py +0 -53
  22. fast_agent_mcp-0.0.12/src/mcp_agent/resources/examples/researcher/researcher.py +0 -38
  23. fast_agent_mcp-0.0.12/src/mcp_agent/resources/examples/workflows/agent.py +0 -17
  24. fast_agent_mcp-0.0.12/src/mcp_agent/resources/examples/workflows/fastagent.py +0 -22
  25. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/LICENSE +0 -0
  26. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/__init__.py +0 -0
  27. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/agents/__init__.py +0 -0
  28. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/app.py +0 -0
  29. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/cli/__init__.py +0 -0
  30. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/cli/__main__.py +0 -0
  31. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/cli/commands/config.py +0 -0
  32. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/cli/terminal.py +0 -0
  33. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/config.py +0 -0
  34. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/console.py +0 -0
  35. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/context.py +0 -0
  36. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/context_dependent.py +0 -0
  37. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/core/__init__.py +0 -0
  38. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/core/server_validation.py +0 -0
  39. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/eval/__init__.py +0 -0
  40. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/event_progress.py +0 -0
  41. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/executor/__init__.py +0 -0
  42. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/executor/decorator_registry.py +0 -0
  43. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/executor/executor.py +0 -0
  44. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/executor/task_registry.py +0 -0
  45. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/executor/temporal.py +0 -0
  46. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/executor/workflow.py +0 -0
  47. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/executor/workflow_signal.py +0 -0
  48. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/human_input/__init__.py +0 -0
  49. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/human_input/types.py +0 -0
  50. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/logging/__init__.py +0 -0
  51. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/logging/events.py +0 -0
  52. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/logging/json_serializer.py +0 -0
  53. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/logging/listeners.py +0 -0
  54. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/logging/logger.py +0 -0
  55. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/logging/rich_progress.py +0 -0
  56. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/logging/tracing.py +0 -0
  57. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/logging/transport.py +0 -0
  58. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/mcp/__init__.py +0 -0
  59. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/mcp/gen_client.py +0 -0
  60. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/mcp/mcp_activity.py +0 -0
  61. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/mcp/mcp_agent_client_session.py +0 -0
  62. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/mcp/mcp_agent_server.py +0 -0
  63. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/mcp/mcp_aggregator.py +0 -0
  64. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/mcp/stdio.py +0 -0
  65. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/mcp_server_registry.py +0 -0
  66. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/progress_display.py +0 -0
  67. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/data-analysis/analysis.py +0 -0
  68. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/data-analysis/fastagent.config.yaml +0 -0
  69. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +0 -0
  70. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/internal/agent.py +0 -0
  71. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/internal/job.py +0 -0
  72. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/mcp_researcher/researcher-eval.py +0 -0
  73. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/researcher/fastagent.config.yaml +0 -0
  74. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/researcher/researcher-eval.py +0 -0
  75. {fast_agent_mcp-0.0.12/src/mcp_agent/resources/examples/mcp_researcher → fast_agent_mcp-0.0.13/src/mcp_agent/resources/examples/researcher}/researcher.py +0 -0
  76. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/workflows/agent_build.py +0 -0
  77. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/workflows/human_input.py +0 -0
  78. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/resources/examples/workflows/router.py +0 -0
  79. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/telemetry/__init__.py +0 -0
  80. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/telemetry/usage_tracking.py +0 -0
  81. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/__init__.py +0 -0
  82. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/embedding/__init__.py +0 -0
  83. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/embedding/embedding_base.py +0 -0
  84. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/embedding/embedding_cohere.py +0 -0
  85. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/embedding/embedding_openai.py +0 -0
  86. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/evaluator_optimizer/__init__.py +0 -0
  87. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +0 -0
  88. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/intent_classifier/__init__.py +0 -0
  89. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/intent_classifier/intent_classifier_base.py +0 -0
  90. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py +0 -0
  91. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/intent_classifier/intent_classifier_embedding_cohere.py +0 -0
  92. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/intent_classifier/intent_classifier_embedding_openai.py +0 -0
  93. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/intent_classifier/intent_classifier_llm.py +0 -0
  94. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/intent_classifier/intent_classifier_llm_anthropic.py +0 -0
  95. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/intent_classifier/intent_classifier_llm_openai.py +0 -0
  96. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/llm/__init__.py +0 -0
  97. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/llm/augmented_llm_anthropic.py +0 -0
  98. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/llm/augmented_llm_openai.py +0 -0
  99. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/llm/llm_selector.py +0 -0
  100. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/orchestrator/__init__.py +0 -0
  101. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/orchestrator/orchestrator.py +0 -0
  102. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/orchestrator/orchestrator_models.py +0 -0
  103. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/orchestrator/orchestrator_prompts.py +0 -0
  104. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/parallel/__init__.py +0 -0
  105. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/parallel/fan_in.py +0 -0
  106. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/parallel/fan_out.py +0 -0
  107. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/parallel/parallel_llm.py +0 -0
  108. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/router/__init__.py +0 -0
  109. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/router/router_base.py +0 -0
  110. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/router/router_embedding.py +0 -0
  111. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/router/router_embedding_cohere.py +0 -0
  112. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/router/router_embedding_openai.py +0 -0
  113. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/router/router_llm.py +0 -0
  114. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/swarm/__init__.py +0 -0
  115. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/swarm/swarm.py +0 -0
  116. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/swarm/swarm_anthropic.py +0 -0
  117. {fast_agent_mcp-0.0.12 → fast_agent_mcp-0.0.13}/src/mcp_agent/workflows/swarm/swarm_openai.py +0 -0
@@ -179,3 +179,4 @@ examples/**/*.jsonl
179
179
  mcp_agent.config.yaml
180
180
  mcp_agent.secrets.yaml
181
181
  fastagent.secrets.yaml
182
+ CLAUDE.md
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fast-agent-mcp
3
- Version: 0.0.12
3
+ Version: 0.0.13
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
@@ -269,6 +269,12 @@ Other bootstrap examples include a Researcher (with Evaluator-Optimizer workflow
269
269
 
270
270
  > Windows Users - there are a couple of configuration changes needed for the Filesystem and Docker MCP Servers - necessary changes are detailed within the configuration files.
271
271
 
272
+ ## Agent Development
273
+
274
+ FastAgent lets you interact with Agents during a workflow, enabling "warm-up" and diagnostic prompting to improve behaviour and refine prompts.
275
+
276
+ ## MCP Server Development
277
+
272
278
  ### llmindset.co.uk fork:
273
279
 
274
280
  - "FastAgent" style prototyping, with per-agent models
@@ -32,6 +32,12 @@ Other bootstrap examples include a Researcher (with Evaluator-Optimizer workflow
32
32
 
33
33
  > Windows Users - there are a couple of configuration changes needed for the Filesystem and Docker MCP Servers - necessary changes are detailed within the configuration files.
34
34
 
35
+ ## Agent Development
36
+
37
+ FastAgent lets you interact with Agents during a workflow, enabling "warm-up" and diagnostic prompting to improve behaviour and refine prompts.
38
+
39
+ ## MCP Server Development
40
+
35
41
  ### llmindset.co.uk fork:
36
42
 
37
43
  - "FastAgent" style prototyping, with per-agent models
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fast-agent-mcp"
3
- version = "0.0.12"
3
+ version = "0.0.13"
4
4
  description = "Define, Prompt and Test MCP enabled Agents and Workflows"
5
5
  readme = "README.md"
6
6
  license = { file = "LICENSE" }
@@ -11,6 +11,7 @@ from mcp.types import (
11
11
  Tool,
12
12
  )
13
13
 
14
+ from mcp_agent.core.exceptions import PromptExitError
14
15
  from mcp_agent.mcp.mcp_aggregator import MCPAggregator
15
16
  from mcp_agent.workflows.llm.augmented_llm import RequestParams
16
17
  from mcp_agent.human_input.types import (
@@ -24,6 +25,7 @@ from mcp_agent.logging.logger import get_logger
24
25
 
25
26
  if TYPE_CHECKING:
26
27
  from mcp_agent.context import Context
28
+ import traceback
27
29
 
28
30
  logger = get_logger(__name__)
29
31
 
@@ -148,10 +150,7 @@ class Agent(MCPAggregator):
148
150
  """
149
151
  await super().close()
150
152
 
151
- async def request_human_input(
152
- self,
153
- request: HumanInputRequest,
154
- ) -> str:
153
+ async def request_human_input(self, request: HumanInputRequest) -> str:
155
154
  """
156
155
  Request input from a human user. Pauses the workflow until input is received.
157
156
 
@@ -170,14 +169,23 @@ class Agent(MCPAggregator):
170
169
  # Generate a unique ID for this request to avoid signal collisions
171
170
  request_id = f"{HUMAN_INPUT_SIGNAL_NAME}_{self.name}_{uuid.uuid4()}"
172
171
  request.request_id = request_id
173
-
172
+ # Use metadata as a dictionary to pass agent name
173
+ request.metadata = {"agent_name": self.name}
174
174
  self.logger.debug("Requesting human input:", data=request)
175
175
 
176
176
  async def call_callback_and_signal():
177
177
  try:
178
178
  user_input = await self.human_input_callback(request)
179
+
179
180
  self.logger.debug("Received human input:", data=user_input)
180
181
  await self.executor.signal(signal_name=request_id, payload=user_input)
182
+ except PromptExitError as e:
183
+ # Propagate the exit error through the signal system
184
+ self.logger.info("User requested to exit session")
185
+ await self.executor.signal(
186
+ signal_name=request_id,
187
+ payload={"exit_requested": True, "error": str(e)},
188
+ )
181
189
  except Exception as e:
182
190
  await self.executor.signal(
183
191
  request_id, payload=f"Error getting human input: {str(e)}"
@@ -197,6 +205,10 @@ class Agent(MCPAggregator):
197
205
  signal_type=HumanInputResponse, # TODO: saqadri - should this be HumanInputResponse?
198
206
  )
199
207
 
208
+ if isinstance(result, dict) and result.get("exit_requested", False):
209
+ raise PromptExitError(
210
+ result.get("error", "User requested to exit FastAgent session")
211
+ )
200
212
  self.logger.debug("Received human input signal", data=result)
201
213
  return result
202
214
 
@@ -253,13 +265,39 @@ class Agent(MCPAggregator):
253
265
  ) -> CallToolResult:
254
266
  # Handle human input request
255
267
  try:
256
- request = HumanInputRequest(**arguments.get("request"))
257
- result: HumanInputResponse = await self.request_human_input(request=request)
268
+ # Make sure arguments is not None
269
+ if arguments is None:
270
+ arguments = {}
271
+
272
+ # Extract request data
273
+ request_data = arguments.get("request")
274
+
275
+ # Handle both string and dict request formats
276
+ if isinstance(request_data, str):
277
+ request = HumanInputRequest(prompt=request_data)
278
+ elif isinstance(request_data, dict):
279
+ request = HumanInputRequest(**request_data)
280
+ else:
281
+ # Fallback for invalid or missing request data
282
+ request = HumanInputRequest(prompt="Please provide input:")
283
+
284
+ result = await self.request_human_input(request=request)
285
+
286
+ # Use response attribute if available, otherwise use the result directly
287
+ response_text = (
288
+ result.response
289
+ if isinstance(result, HumanInputResponse)
290
+ else str(result)
291
+ )
292
+
258
293
  return CallToolResult(
259
294
  content=[
260
- TextContent(type="text", text=f"Human response: {result.response}")
295
+ TextContent(type="text", text=f"Human response: {response_text}")
261
296
  ]
262
297
  )
298
+
299
+ except PromptExitError:
300
+ raise
263
301
  except TimeoutError as e:
264
302
  return CallToolResult(
265
303
  isError=True,
@@ -271,6 +309,8 @@ class Agent(MCPAggregator):
271
309
  ],
272
310
  )
273
311
  except Exception as e:
312
+ print(f"Error in _call_human_input_tool: {traceback.format_exc()}")
313
+
274
314
  return CallToolResult(
275
315
  isError=True,
276
316
  content=[
@@ -26,6 +26,7 @@ EXAMPLE_TYPES = {
26
26
  "orchestrator.py",
27
27
  "parallel.py",
28
28
  "router.py",
29
+ "fastagent.config.yaml",
29
30
  ],
30
31
  "create_subdir": False,
31
32
  },
@@ -119,7 +119,7 @@ fast = FastAgent("FastAgent Example")
119
119
 
120
120
 
121
121
  # Define the agent
122
- @fast.agent(servers=["fetch"])
122
+ @fast.agent(instruction="You are a helpful AI Agent", servers=["fetch"])
123
123
  async def main():
124
124
  # use the --model command line switch or agent arguments to change model
125
125
  async with fast.run() as agent:
@@ -32,7 +32,7 @@ def show_welcome():
32
32
 
33
33
  table.add_row("setup", "Set up a new agent project with configuration files")
34
34
  table.add_row(
35
- "bootstrap", "Create example applications (decorator, researcher, etc.)"
35
+ "bootstrap", "Create example applications (workflow, researcher, etc.)"
36
36
  )
37
37
  # table.add_row("config", "Manage agent configuration settings")
38
38
 
@@ -41,8 +41,8 @@ def show_welcome():
41
41
  console.print("\n[bold]Getting Started:[/bold]")
42
42
  console.print("1. Set up a new project:")
43
43
  console.print(" fastagent setup")
44
- console.print("\n2. Try an example:")
45
- console.print(" fastagent bootstrap create decorator")
44
+ console.print("\n2. Try an example workflow:")
45
+ console.print(" fastagent bootstrap create workflow")
46
46
  console.print("\nUse --help with any command for more information")
47
47
  console.print("Example: fastagent bootstrap --help")
48
48
 
@@ -13,6 +13,8 @@ from prompt_toolkit.filters import Condition
13
13
  from pygments.lexers.python import PythonLexer
14
14
  from rich import print as rich_print
15
15
 
16
+ from mcp_agent.core.exceptions import PromptExitError
17
+
16
18
  # Map of agent names to their history
17
19
  agent_histories = {}
18
20
 
@@ -29,9 +31,25 @@ agent_messages_shown = set()
29
31
  class AgentCompleter(Completer):
30
32
  """Provide completion for agent names and common commands."""
31
33
 
32
- def __init__(self, agents: List[str], commands: List[str] = None, agent_types: dict = None):
34
+ def __init__(
35
+ self,
36
+ agents: List[str],
37
+ commands: List[str] = None,
38
+ agent_types: dict = None,
39
+ is_human_input: bool = False,
40
+ ):
33
41
  self.agents = agents
34
- self.commands = commands or ["help", "clear", "STOP"]
42
+ # Map commands to their descriptions for better completion hints
43
+ self.commands = {
44
+ "help": "Show available commands",
45
+ "clear": "Clear the screen",
46
+ "agents": "List available agents",
47
+ "STOP": "Stop this prompting session and move to next workflow step",
48
+ "EXIT": "Exit FastAgent, terminating any running workflows",
49
+ **(commands or {}), # Allow custom commands to be passed in
50
+ }
51
+ if is_human_input:
52
+ self.commands.pop("agents")
35
53
  self.agent_types = agent_types or {}
36
54
 
37
55
  def get_completions(self, document, complete_event):
@@ -41,13 +59,13 @@ class AgentCompleter(Completer):
41
59
  # Complete commands
42
60
  if text.startswith("/"):
43
61
  cmd = text[1:]
44
- for command in self.commands:
62
+ for command, description in self.commands.items():
45
63
  if command.lower().startswith(cmd):
46
64
  yield Completion(
47
65
  command,
48
66
  start_position=-len(cmd),
49
67
  display=command,
50
- display_meta="Command",
68
+ display_meta=description,
51
69
  )
52
70
 
53
71
  # Complete agent names for agent-related commands
@@ -62,6 +80,7 @@ class AgentCompleter(Completer):
62
80
  start_position=-len(agent_name),
63
81
  display=agent,
64
82
  display_meta=agent_type,
83
+ style="bg:ansiblack fg:ansiblue",
65
84
  )
66
85
 
67
86
 
@@ -79,9 +98,10 @@ def create_keybindings(on_toggle_multiline=None, app=None):
79
98
  """Enter: insert newline when in multiline mode."""
80
99
  event.current_buffer.insert_text("\n")
81
100
 
82
- @kb.add("escape", "enter")
101
+ # Use c-j (Ctrl+J) as an alternative to represent Ctrl+Enter in multiline mode
102
+ @kb.add("c-j", filter=Condition(lambda: in_multiline_mode))
83
103
  def _(event):
84
- """Alt+Enter: always submit even in multiline mode."""
104
+ """Ctrl+J (equivalent to Ctrl+Enter): Submit in multiline mode."""
85
105
  event.current_buffer.validate_and_handle()
86
106
 
87
107
  @kb.add("c-t")
@@ -105,7 +125,7 @@ def create_keybindings(on_toggle_multiline=None, app=None):
105
125
 
106
126
  @kb.add("c-l")
107
127
  def _(event):
108
- """Ctrl+L: Clear input."""
128
+ """Ctrl+L: Clear the input buffer."""
109
129
  event.current_buffer.text = ""
110
130
 
111
131
  return kb
@@ -120,6 +140,8 @@ async def get_enhanced_input(
120
140
  available_agent_names: List[str] = None,
121
141
  syntax: str = None,
122
142
  agent_types: dict = None,
143
+ is_human_input: bool = False,
144
+ toolbar_color: str = "ansiblue",
123
145
  ) -> str:
124
146
  """
125
147
  Enhanced input with advanced prompt_toolkit features.
@@ -133,6 +155,8 @@ async def get_enhanced_input(
133
155
  available_agent_names: List of agent names for auto-completion
134
156
  syntax: Syntax highlighting (e.g., 'python', 'sql')
135
157
  agent_types: Dictionary mapping agent names to their types for display
158
+ is_human_input: Whether this is a human input request (disables agent selection features)
159
+ toolbar_color: Color to use for the agent name in the toolbar (default: "ansiblue")
136
160
 
137
161
  Returns:
138
162
  User input string
@@ -167,16 +191,20 @@ async def get_enhanced_input(
167
191
 
168
192
  shortcuts = [
169
193
  ("Ctrl+T", toggle_text),
170
- ("Alt+Enter", "Submit" if in_multiline_mode else ""),
171
194
  ("Ctrl+L", "Clear"),
172
195
  ("↑/↓", "History"),
173
196
  ]
197
+
198
+ newline = (
199
+ "Ctrl+&lt;Enter&gt;:Submit" if in_multiline_mode else "&lt;Enter&gt;:Submit"
200
+ )
201
+
174
202
  # Only show relevant shortcuts based on mode
175
203
  shortcuts = [(k, v) for k, v in shortcuts if v]
176
204
 
177
205
  shortcut_text = " | ".join(f"{key}:{action}" for key, action in shortcuts)
178
206
  return HTML(
179
- f" <b>Agent:</b> <ansiblue> {agent_name} </ansiblue> | <b>Mode:</b> <{mode_style}> {mode_text} </{mode_style}> | {shortcut_text}"
207
+ f" <{toolbar_color}> {agent_name} </{toolbar_color}> | <b>Mode:</b> <{mode_style}> {mode_text} </{mode_style}> {newline} | {shortcut_text}"
180
208
  )
181
209
 
182
210
  # Create session with history and completions
@@ -185,12 +213,13 @@ async def get_enhanced_input(
185
213
  completer=AgentCompleter(
186
214
  agents=list(available_agents) if available_agents else [],
187
215
  agent_types=agent_types or {},
216
+ is_human_input=is_human_input,
188
217
  ),
189
218
  complete_while_typing=True,
190
219
  lexer=PygmentsLexer(PythonLexer) if syntax == "python" else None,
191
220
  multiline=Condition(lambda: in_multiline_mode),
192
221
  complete_in_thread=True,
193
- mouse_support=True,
222
+ mouse_support=False,
194
223
  bottom_toolbar=get_toolbar, # Pass the function here
195
224
  )
196
225
 
@@ -220,9 +249,14 @@ async def get_enhanced_input(
220
249
 
221
250
  # Mention available features but only on first usage for this agent
222
251
  if agent_name not in agent_messages_shown:
223
- rich_print(
224
- "[dim]Tip: Type /help for commands, press F1 for keyboard shortcuts. Ctrl+T toggles multiline mode. @Agent to switch agent[/dim]"
225
- )
252
+ if is_human_input:
253
+ rich_print(
254
+ "[dim]Tip: Type /help for commands. Ctrl+T toggles multiline mode. Ctrl+Enter to submit in multiline mode.[/dim]"
255
+ )
256
+ else:
257
+ rich_print(
258
+ "[dim]Tip: Type /help for commands, @Agent to switch agent. Ctrl+T toggles multiline mode. [/dim]"
259
+ )
226
260
  agent_messages_shown.add(agent_name)
227
261
 
228
262
  # Process special commands
@@ -236,6 +270,10 @@ async def get_enhanced_input(
236
270
  return "CLEAR"
237
271
  elif cmd == "agents":
238
272
  return "LIST_AGENTS"
273
+ elif cmd == "exit":
274
+ return "EXIT"
275
+ elif cmd == "stop":
276
+ return "STOP"
239
277
 
240
278
  # Agent switching
241
279
  if text and text.startswith("@"):
@@ -272,16 +310,18 @@ async def handle_special_commands(command, agent_app=None):
272
310
  rich_print(" /clear - Clear screen")
273
311
  rich_print(" /agents - List available agents")
274
312
  rich_print(" @agent_name - Switch to agent")
275
- rich_print(" STOP - End session")
313
+ rich_print(" STOP - Return control back to the workflow")
314
+ rich_print(
315
+ " EXIT - Exit FastAgent, terminating any running workflows"
316
+ )
276
317
  rich_print("\n[bold]Keyboard Shortcuts:[/bold]")
277
318
  rich_print(
278
319
  " Enter - Submit (normal mode) / New line (multiline mode)"
279
320
  )
280
- rich_print(" Alt+Enter - Always submit (even in multiline mode)")
321
+ rich_print(" Ctrl+Enter - Always submit (even in multiline mode)")
281
322
  rich_print(" Ctrl+T - Toggle multiline mode")
282
323
  rich_print(" Ctrl+L - Clear input")
283
324
  rich_print(" Up/Down - Navigate history")
284
- rich_print(" F1 - Show help")
285
325
  return True
286
326
 
287
327
  elif command == "CLEAR":
@@ -289,6 +329,9 @@ async def handle_special_commands(command, agent_app=None):
289
329
  print("\033c", end="")
290
330
  return True
291
331
 
332
+ elif command == "EXIT":
333
+ raise PromptExitError("User requested to exit FastAgent session")
334
+
292
335
  elif command == "LIST_AGENTS":
293
336
  if available_agents:
294
337
  rich_print("\n[bold]Available Agents:[/bold]")
@@ -45,3 +45,20 @@ class ServerInitializationError(FastAgentError):
45
45
 
46
46
  def __init__(self, message: str, details: str = ""):
47
47
  super().__init__(message, details)
48
+
49
+
50
+ class ModelConfigError(FastAgentError):
51
+ """Raised when there are issues with LLM model configuration
52
+ Example: Unknown model name in model specification string
53
+ """
54
+
55
+ def __init__(self, message: str, details: str = ""):
56
+ super().__init__(message, details)
57
+
58
+
59
+ class PromptExitError(FastAgentError):
60
+ """Raised from enhanced_prompt when the user requests hard exits"""
61
+
62
+ # TODO an exception for flow control :(
63
+ def __init__(self, message: str, details: str = ""):
64
+ super().__init__(message, details)
@@ -3,7 +3,17 @@ Decorator-based interface for MCP Agent applications.
3
3
  Provides a simplified way to create and manage agents using decorators.
4
4
  """
5
5
 
6
- from typing import List, Optional, Dict, Callable, TypeVar, Any, Union, TypeAlias
6
+ from typing import (
7
+ List,
8
+ Optional,
9
+ Dict,
10
+ Callable,
11
+ TypeVar,
12
+ Any,
13
+ Union,
14
+ TypeAlias,
15
+ Literal,
16
+ )
7
17
  from enum import Enum
8
18
  import yaml
9
19
  import argparse
@@ -11,6 +21,8 @@ from contextlib import asynccontextmanager
11
21
 
12
22
  from mcp_agent.core.exceptions import (
13
23
  AgentConfigError,
24
+ ModelConfigError,
25
+ PromptExitError,
14
26
  ServerConfigError,
15
27
  ProviderKeyError,
16
28
  ServerInitializationError,
@@ -175,7 +187,7 @@ class AgentApp:
175
187
 
176
188
  # Pass all available agent names for auto-completion
177
189
  available_agents = list(self._agents.keys())
178
-
190
+
179
191
  # Create agent_types dictionary mapping agent names to their types
180
192
  agent_types = {}
181
193
  for name, proxy in self._agents.items():
@@ -633,6 +645,7 @@ class FastAgent(ContextDependent):
633
645
  use_history: bool = False,
634
646
  request_params: Optional[Dict] = None,
635
647
  human_input: bool = False,
648
+ plan_type: Literal["full", "iterative"] = "full",
636
649
  ) -> Callable:
637
650
  """
638
651
  Decorator to create and register an orchestrator.
@@ -645,6 +658,7 @@ class FastAgent(ContextDependent):
645
658
  use_history: Whether to maintain conversation history (forced false)
646
659
  request_params: Additional request parameters for the LLM
647
660
  human_input: Whether to enable human input capabilities
661
+ plan_type: Planning approach - "full" generates entire plan first, "iterative" plans one step at a time
648
662
  """
649
663
  default_instruction = """
650
664
  You are an expert planner. Given an objective task and a list of MCP servers (which are collections of tools)
@@ -666,6 +680,7 @@ class FastAgent(ContextDependent):
666
680
  use_history=use_history,
667
681
  request_params=request_params,
668
682
  human_input=human_input,
683
+ plan_type=plan_type,
669
684
  )
670
685
  return decorator
671
686
 
@@ -864,7 +879,7 @@ class FastAgent(ContextDependent):
864
879
  which can be performed by LLMs with access to the servers or agents.
865
880
  """,
866
881
  servers=[], # Planner doesn't need server access
867
- model=config.model, # Use same model as orchestrator
882
+ model=config.model,
868
883
  default_request_params=base_params,
869
884
  )
870
885
  planner_agent = Agent(
@@ -885,8 +900,10 @@ class FastAgent(ContextDependent):
885
900
  available_agents=child_agents,
886
901
  context=agent_app.context,
887
902
  request_params=planner.default_request_params, # Base params already include model settings
888
- plan_type="full", # TODO -- support iterative plan type properly
889
- verb=ProgressAction.PLANNING, # Using PLANNING instead of ORCHESTRATING
903
+ plan_type=agent_data.get(
904
+ "plan_type", "full"
905
+ ), # Get plan_type from agent_data
906
+ verb=ProgressAction.PLANNING,
890
907
  )
891
908
 
892
909
  elif agent_type == AgentType.EVALUATOR_OPTIMIZER:
@@ -1228,10 +1245,28 @@ class FastAgent(ContextDependent):
1228
1245
  had_error = True
1229
1246
  self._handle_error(
1230
1247
  e,
1231
- "Server Startup Error",
1248
+ "MCP Server Startup Error",
1232
1249
  "There was an error starting up the MCP Server.",
1233
1250
  )
1234
1251
  raise SystemExit(1)
1252
+
1253
+ except ModelConfigError as e:
1254
+ had_error = True
1255
+ self._handle_error(
1256
+ e,
1257
+ "Model Configuration Error",
1258
+ "Common models: gpt-4o, o3-mini, sonnet, haiku. for o3, set reasoning effort with o3-mini.high",
1259
+ )
1260
+ raise SystemExit(1)
1261
+
1262
+ except PromptExitError as e:
1263
+ had_error = True
1264
+ self._handle_error(
1265
+ e,
1266
+ "User requested exit",
1267
+ )
1268
+ raise SystemExit(1)
1269
+
1235
1270
  finally:
1236
1271
  # Clean up any active agents without re-raising errors
1237
1272
  if active_agents and not had_error:
@@ -1239,7 +1274,8 @@ class FastAgent(ContextDependent):
1239
1274
  if isinstance(proxy, LLMAgentProxy):
1240
1275
  try:
1241
1276
  await proxy._agent.__aexit__(None, None, None)
1242
- except Exception:
1277
+ except Exception as e:
1278
+ print(f"DEBUG {e.message}")
1243
1279
  pass # Ignore cleanup errors
1244
1280
 
1245
1281
  def _handle_error(
@@ -0,0 +1,78 @@
1
+ import asyncio
2
+ from rich.panel import Panel
3
+
4
+ from mcp_agent.console import console
5
+ from mcp_agent.human_input.types import (
6
+ HumanInputRequest,
7
+ HumanInputResponse,
8
+ )
9
+ from mcp_agent.progress_display import progress_display
10
+ from mcp_agent.core.enhanced_prompt import get_enhanced_input, handle_special_commands
11
+
12
+
13
+ async def console_input_callback(request: HumanInputRequest) -> HumanInputResponse:
14
+ """Request input from a human user via console using prompt_toolkit."""
15
+
16
+ # Prepare the prompt text
17
+ prompt_text = request.prompt
18
+ if request.description:
19
+ prompt_text = f"[bold]{request.description}[/bold]\n\n{request.prompt}"
20
+
21
+ # Create a panel with the prompt
22
+ panel = Panel(
23
+ prompt_text,
24
+ title="[HUMAN INPUT REQUESTED]",
25
+ title_align="left",
26
+ style="green",
27
+ border_style="bold white",
28
+ padding=(1, 2),
29
+ )
30
+
31
+ # Extract agent name from metadata dictionary
32
+ agent_name = (
33
+ request.metadata.get("agent_name", "Unknown Agent")
34
+ if request.metadata
35
+ else "Unknown Agent"
36
+ )
37
+
38
+ # Use the context manager to pause the progress display while getting input
39
+ with progress_display.paused():
40
+ console.print(panel)
41
+
42
+ try:
43
+ if request.timeout_seconds:
44
+ try:
45
+ # Use get_enhanced_input with empty agent list to disable agent switching
46
+ response = await asyncio.wait_for(
47
+ get_enhanced_input(
48
+ agent_name=agent_name,
49
+ available_agent_names=[], # No agents for selection
50
+ show_stop_hint=False,
51
+ is_human_input=True,
52
+ toolbar_color="ansimagenta",
53
+ ),
54
+ request.timeout_seconds,
55
+ )
56
+ except asyncio.TimeoutError:
57
+ console.print("\n[red]Timeout waiting for input[/red]")
58
+ raise TimeoutError("No response received within timeout period")
59
+ else:
60
+ response = await get_enhanced_input(
61
+ agent_name=agent_name,
62
+ available_agent_names=[], # No agents for selection
63
+ show_stop_hint=False,
64
+ is_human_input=True,
65
+ toolbar_color="ansimagenta",
66
+ )
67
+
68
+ # if response and (response.startswith("/") or response.startswith("@")):
69
+ await handle_special_commands(response)
70
+
71
+ except KeyboardInterrupt:
72
+ console.print("\n[yellow]Input interrupted[/yellow]")
73
+ response = ""
74
+ except EOFError:
75
+ console.print("\n[yellow]Input terminated[/yellow]")
76
+ response = ""
77
+
78
+ return HumanInputResponse(request_id=request.request_id, response=response.strip())