fast-agent-mcp 0.0.12__py3-none-any.whl → 0.0.14__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.

Potentially problematic release.


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

@@ -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+<Enter>:Submit" if in_multiline_mode else "<Enter>: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,27 @@ 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 CircularDependencyError(FastAgentError):
60
+ """Raised when we detect a Circular Dependency in the workflow"""
61
+
62
+ def __init__(self, message: str, details: str = ""):
63
+ super().__init__(message, details)
64
+
65
+
66
+ class PromptExitError(FastAgentError):
67
+ """Raised from enhanced_prompt when the user requests hard exits"""
68
+
69
+ # TODO an exception for flow control :(
70
+ def __init__(self, message: str, details: str = ""):
71
+ super().__init__(message, details)