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

@@ -3,12 +3,13 @@ Enhanced prompt functionality with advanced prompt_toolkit features.
3
3
  """
4
4
 
5
5
  import asyncio
6
+ import json
6
7
  import os
7
8
  import shlex
8
9
  import subprocess
9
10
  import tempfile
10
11
  from importlib.metadata import version
11
- from typing import List, Optional
12
+ from typing import TYPE_CHECKING, List, Optional
12
13
 
13
14
  from prompt_toolkit import PromptSession
14
15
  from prompt_toolkit.completion import Completer, Completion, WordCompleter
@@ -20,9 +21,13 @@ from prompt_toolkit.styles import Style
20
21
  from rich import print as rich_print
21
22
 
22
23
  from fast_agent.agents.agent_types import AgentType
24
+ from fast_agent.constants import FAST_AGENT_ERROR_CHANNEL, FAST_AGENT_REMOVED_METADATA_CHANNEL
23
25
  from fast_agent.core.exceptions import PromptExitError
24
26
  from fast_agent.llm.model_info import get_model_info
25
27
 
28
+ if TYPE_CHECKING:
29
+ from fast_agent.core.agent_app import AgentApp
30
+
26
31
  # Get the application version
27
32
  try:
28
33
  app_version = version("fast-agent-mcp")
@@ -38,6 +43,30 @@ available_agents = set()
38
43
  # Keep track of multi-line mode state
39
44
  in_multiline_mode = False
40
45
 
46
+
47
+ def _extract_alert_flags_from_meta(blocks) -> set[str]:
48
+ flags: set[str] = set()
49
+ for block in blocks or []:
50
+ text = getattr(block, "text", None)
51
+ if not text:
52
+ continue
53
+ try:
54
+ payload = json.loads(text)
55
+ except (TypeError, ValueError):
56
+ continue
57
+ if payload.get("type") != "fast-agent-removed":
58
+ continue
59
+ category = payload.get("category")
60
+ match category:
61
+ case "text":
62
+ flags.add("T")
63
+ case "document":
64
+ flags.add("D")
65
+ case "vision":
66
+ flags.add("V")
67
+ return flags
68
+
69
+
41
70
  # Track whether help text has been shown globally
42
71
  help_message_shown = False
43
72
 
@@ -45,20 +74,17 @@ help_message_shown = False
45
74
  _agent_info_shown = set()
46
75
 
47
76
 
48
- async def _display_agent_info_helper(agent_name: str, agent_provider: object) -> None:
77
+ async def _display_agent_info_helper(agent_name: str, agent_provider: "AgentApp | None") -> None:
49
78
  """Helper function to display agent information."""
50
79
  # Only show once per agent
51
80
  if agent_name in _agent_info_shown:
52
81
  return
53
82
 
54
83
  try:
55
- # Get agent info
56
- if hasattr(agent_provider, "_agent"):
57
- # This is an AgentApp - get the specific agent
58
- agent = agent_provider._agent(agent_name)
59
- else:
60
- # This is a single agent
61
- agent = agent_provider
84
+ # Get agent info from AgentApp
85
+ if agent_provider is None:
86
+ return
87
+ agent = agent_provider._agent(agent_name)
62
88
 
63
89
  # Get counts TODO -- add this to the type library or adjust the way aggregator/reporting works
64
90
  server_count = 0
@@ -148,7 +174,9 @@ async def _display_agent_info_helper(agent_name: str, agent_provider: object) ->
148
174
  pass
149
175
 
150
176
 
151
- async def _display_all_agents_with_hierarchy(available_agents: List[str], agent_provider) -> None:
177
+ async def _display_all_agents_with_hierarchy(
178
+ available_agents: List[str], agent_provider: "AgentApp | None"
179
+ ) -> None:
152
180
  """Display all agents with tree structure for workflow agents."""
153
181
  # Track which agents are children to avoid displaying them twice
154
182
  child_agents = set()
@@ -156,10 +184,9 @@ async def _display_all_agents_with_hierarchy(available_agents: List[str], agent_
156
184
  # First pass: identify all child agents
157
185
  for agent_name in available_agents:
158
186
  try:
159
- if hasattr(agent_provider, "_agent"):
160
- agent = agent_provider._agent(agent_name)
161
- else:
162
- agent = agent_provider
187
+ if agent_provider is None:
188
+ continue
189
+ agent = agent_provider._agent(agent_name)
163
190
 
164
191
  if agent.agent_type == AgentType.PARALLEL:
165
192
  if hasattr(agent, "fan_out_agents") and agent.fan_out_agents:
@@ -184,10 +211,9 @@ async def _display_all_agents_with_hierarchy(available_agents: List[str], agent_
184
211
  continue
185
212
 
186
213
  try:
187
- if hasattr(agent_provider, "_agent"):
188
- agent = agent_provider._agent(agent_name)
189
- else:
190
- agent = agent_provider
214
+ if agent_provider is None:
215
+ continue
216
+ agent = agent_provider._agent(agent_name)
191
217
 
192
218
  # Display parent agent
193
219
  await _display_agent_info_helper(agent_name, agent_provider)
@@ -202,7 +228,7 @@ async def _display_all_agents_with_hierarchy(available_agents: List[str], agent_
202
228
  continue
203
229
 
204
230
 
205
- async def _display_parallel_children(parallel_agent, agent_provider) -> None:
231
+ async def _display_parallel_children(parallel_agent, agent_provider: "AgentApp | None") -> None:
206
232
  """Display child agents of a parallel agent in tree format."""
207
233
  children = []
208
234
 
@@ -222,7 +248,7 @@ async def _display_parallel_children(parallel_agent, agent_provider) -> None:
222
248
  await _display_child_agent_info(child_agent, prefix, agent_provider)
223
249
 
224
250
 
225
- async def _display_router_children(router_agent, agent_provider) -> None:
251
+ async def _display_router_children(router_agent, agent_provider: "AgentApp | None") -> None:
226
252
  """Display child agents of a router agent in tree format."""
227
253
  children = []
228
254
 
@@ -239,7 +265,9 @@ async def _display_router_children(router_agent, agent_provider) -> None:
239
265
  await _display_child_agent_info(child_agent, prefix, agent_provider)
240
266
 
241
267
 
242
- async def _display_child_agent_info(child_agent, prefix: str, agent_provider) -> None:
268
+ async def _display_child_agent_info(
269
+ child_agent, prefix: str, agent_provider: "AgentApp | None"
270
+ ) -> None:
243
271
  """Display info for a child agent with tree prefix."""
244
272
  try:
245
273
  # Get counts for child agent
@@ -425,7 +453,9 @@ def get_text_from_editor(initial_text: str = "") -> str:
425
453
  return edited_text.strip() # Added strip() to remove trailing newlines often added by editors
426
454
 
427
455
 
428
- def create_keybindings(on_toggle_multiline=None, app=None, agent_provider=None, agent_name=None):
456
+ def create_keybindings(
457
+ on_toggle_multiline=None, app=None, agent_provider: "AgentApp | None" = None, agent_name=None
458
+ ):
429
459
  """Create custom key bindings."""
430
460
  kb = KeyBindings()
431
461
 
@@ -504,30 +534,20 @@ def create_keybindings(on_toggle_multiline=None, app=None, agent_provider=None,
504
534
  """Ctrl+Y: Copy last assistant response to clipboard."""
505
535
  if kb.agent_provider and kb.current_agent_name:
506
536
  try:
507
- # Get the agent
508
- if hasattr(kb.agent_provider, "_agent"):
509
- agent = kb.agent_provider._agent(kb.current_agent_name)
510
- else:
511
- agent = kb.agent_provider
512
-
513
- # Get message history
514
- if hasattr(agent, "_llm") and agent._llm and agent._llm.message_history:
515
- # Find last assistant message
516
- for msg in reversed(agent._llm.message_history):
517
- if msg.role == "assistant":
518
- content = msg.last_text()
519
- import pyperclip
520
-
521
- pyperclip.copy(content)
522
- rich_print("\n[green]✓ Copied to clipboard[/green]")
523
- return
524
-
525
- else:
526
- pass
537
+ # Get the agent from AgentApp
538
+ agent = kb.agent_provider._agent(kb.current_agent_name)
539
+
540
+ # Find last assistant message
541
+ for msg in reversed(agent.message_history):
542
+ if msg.role == "assistant":
543
+ content = msg.last_text()
544
+ import pyperclip
545
+
546
+ pyperclip.copy(content)
547
+ rich_print("\n[green]✓ Copied to clipboard[/green]")
548
+ return
527
549
  except Exception:
528
550
  pass
529
- else:
530
- pass
531
551
 
532
552
  return kb
533
553
 
@@ -542,7 +562,7 @@ async def get_enhanced_input(
542
562
  agent_types: dict[str, AgentType] = None,
543
563
  is_human_input: bool = False,
544
564
  toolbar_color: str = "ansiblue",
545
- agent_provider: object = None,
565
+ agent_provider: "AgentApp | None" = None,
546
566
  ) -> str:
547
567
  """
548
568
  Enhanced input with advanced prompt_toolkit features.
@@ -557,7 +577,7 @@ async def get_enhanced_input(
557
577
  agent_types: Dictionary mapping agent names to their types for display
558
578
  is_human_input: Whether this is a human input request (disables agent selection features)
559
579
  toolbar_color: Color to use for the agent name in the toolbar (default: "ansiblue")
560
- agent_provider: Optional agent provider for displaying agent info
580
+ agent_provider: Optional AgentApp for displaying agent info
561
581
 
562
582
  Returns:
563
583
  User input string
@@ -598,18 +618,22 @@ async def get_enhanced_input(
598
618
 
599
619
  shortcut_text = " | ".join(f"{key}:{action}" for key, action in shortcuts)
600
620
 
601
- # Resolve model name and TDV from the current agent if available
621
+ # Resolve model name, turn counter, and TDV from the current agent if available
602
622
  model_display = None
603
623
  tdv_segment = None
624
+ turn_count = 0
604
625
  try:
605
- agent_obj = (
606
- agent_provider._agent(agent_name)
607
- if agent_provider and hasattr(agent_provider, "_agent")
608
- else agent_provider
609
- )
610
- if agent_obj and hasattr(agent_obj, "llm") and agent_obj.llm:
611
- model_name = getattr(agent_obj.llm, "model_name", None)
612
- if model_name:
626
+ if agent_provider:
627
+ agent = agent_provider._agent(agent_name)
628
+
629
+ # Get turn count from message history
630
+ for message in agent.message_history:
631
+ if message.role == "user":
632
+ turn_count += 1
633
+
634
+ # Get model name from LLM
635
+ if agent.llm and agent.llm.model_name:
636
+ model_name = agent.llm.model_name
613
637
  # Truncate model name to max 25 characters with ellipsis
614
638
  max_len = 25
615
639
  if len(model_name) > max_len:
@@ -619,20 +643,35 @@ async def get_enhanced_input(
619
643
  model_display = model_name
620
644
 
621
645
  # Build TDV capability segment based on model database
622
- info = get_model_info(agent_obj)
646
+ info = get_model_info(agent)
623
647
  # Default to text-only if info resolution fails for any reason
624
648
  t, d, v = (True, False, False)
625
649
  if info:
626
650
  t, d, v = info.tdv_flags
627
651
 
652
+ # Check for alert flags in user messages
653
+ alert_flags: set[str] = set()
654
+ error_seen = False
655
+ for message in agent.message_history:
656
+ if message.channels:
657
+ if message.channels.get(FAST_AGENT_ERROR_CHANNEL):
658
+ error_seen = True
659
+ if message.role == "user" and message.channels:
660
+ meta_blocks = message.channels.get(FAST_AGENT_REMOVED_METADATA_CHANNEL, [])
661
+ alert_flags.update(_extract_alert_flags_from_meta(meta_blocks))
662
+
663
+ if error_seen and not alert_flags:
664
+ alert_flags.add("T")
665
+
628
666
  def _style_flag(letter: str, supported: bool) -> str:
629
667
  # Enabled uses the same color as NORMAL mode (ansigreen), disabled is dim
668
+ if letter in alert_flags:
669
+ return f"<style fg='ansired' bg='ansiblack'>{letter}</style>"
670
+
630
671
  enabled_color = "ansigreen"
631
- return (
632
- f"<style fg='{enabled_color}' bg='ansiblack'>{letter}</style>"
633
- if supported
634
- else f"<style fg='ansiblack' bg='ansiwhite'>{letter}</style>"
635
- )
672
+ if supported:
673
+ return f"<style fg='{enabled_color}' bg='ansiblack'>{letter}</style>"
674
+ return f"<style fg='ansiblack' bg='ansiwhite'>{letter}</style>"
636
675
 
637
676
  tdv_segment = f"{_style_flag('T', t)}{_style_flag('D', d)}{_style_flag('V', v)}"
638
677
  except Exception:
@@ -640,7 +679,7 @@ async def get_enhanced_input(
640
679
  model_display = None
641
680
  tdv_segment = None
642
681
 
643
- # Build dynamic middle segments: model (in green) and optional shortcuts
682
+ # Build dynamic middle segments: model (in green), turn counter, and optional shortcuts
644
683
  middle_segments = []
645
684
  if model_display:
646
685
  # Model chip + inline TDV flags
@@ -650,6 +689,10 @@ async def get_enhanced_input(
650
689
  )
651
690
  else:
652
691
  middle_segments.append(f"<style bg='ansigreen'>{model_display}</style>")
692
+
693
+ # Add turn counter (formatted as 3 digits)
694
+ middle_segments.append(f"{turn_count:03d}")
695
+
653
696
  if shortcut_text:
654
697
  middle_segments.append(shortcut_text)
655
698
  middle = " | ".join(middle_segments)
@@ -761,7 +804,9 @@ async def get_enhanced_input(
761
804
  elif cmd in ("save_history", "save"):
762
805
  # Return a structured action for the interactive loop to handle
763
806
  # Prefer programmatic saving via HistoryExporter; fall back to magic-string there if needed
764
- filename = cmd_parts[1].strip() if len(cmd_parts) > 1 and cmd_parts[1].strip() else None
807
+ filename = (
808
+ cmd_parts[1].strip() if len(cmd_parts) > 1 and cmd_parts[1].strip() else None
809
+ )
765
810
  return {"save_history": True, "filename": filename}
766
811
  elif cmd == "prompt":
767
812
  # Handle /prompt with no arguments as interactive mode
@@ -941,7 +986,9 @@ async def handle_special_commands(command, agent_app=None):
941
986
  rich_print(" /usage - Show current usage statistics")
942
987
  rich_print(" /markdown - Show last assistant message without markdown formatting")
943
988
  rich_print(" /save_history <filename> - Save current chat history to a file")
944
- rich_print(" [dim]Tip: Use a .json extension for MCP-compatible JSON; any other extension saves Markdown.[/dim]")
989
+ rich_print(
990
+ " [dim]Tip: Use a .json extension for MCP-compatible JSON; any other extension saves Markdown.[/dim]"
991
+ )
945
992
  rich_print(" @agent_name - Switch to agent")
946
993
  rich_print(" STOP - Return control back to the workflow")
947
994
  rich_print(" EXIT - Exit fast-agent, terminating any running workflows")
@@ -14,14 +14,16 @@ Usage:
14
14
  )
15
15
  """
16
16
 
17
- from typing import Awaitable, Callable, Dict, List, Mapping, Optional, Protocol, Union
17
+ from typing import TYPE_CHECKING, Awaitable, Callable, Dict, List, Optional, Union
18
+
19
+ if TYPE_CHECKING:
20
+ from fast_agent.core.agent_app import AgentApp
18
21
 
19
22
  from mcp.types import Prompt, PromptMessage
20
23
  from rich import print as rich_print
21
24
 
22
25
  from fast_agent.agents.agent_types import AgentType
23
26
  from fast_agent.history.history_exporter import HistoryExporter
24
- from fast_agent.interfaces import AgentProtocol
25
27
  from fast_agent.mcp.mcp_aggregator import SEP
26
28
  from fast_agent.types import PromptMessageExtended
27
29
  from fast_agent.ui.enhanced_prompt import (
@@ -41,36 +43,6 @@ SendFunc = Callable[[Union[str, PromptMessage, PromptMessageExtended], str], Awa
41
43
  AgentGetter = Callable[[str], Optional[object]]
42
44
 
43
45
 
44
- class PromptProvider(Protocol):
45
- """Protocol for objects that can provide prompt functionality."""
46
-
47
- async def list_prompts(
48
- self, namespace: Optional[str] = None, agent_name: Optional[str] = None
49
- ) -> Mapping[str, List[Prompt]]:
50
- """List available prompts."""
51
- ...
52
-
53
- async def apply_prompt(
54
- self,
55
- prompt_name: str,
56
- prompt_title: Optional[str] = None,
57
- arguments: Optional[Dict[str, str]] = None,
58
- agent_name: Optional[str] = None,
59
- as_template: bool = False,
60
- **kwargs,
61
- ) -> str:
62
- """Apply a prompt."""
63
- ...
64
-
65
- def _agent(self, agent_name: str) -> AgentProtocol:
66
- """Return the concrete agent by name (AgentApp provides this)."""
67
- ...
68
-
69
- def _show_turn_usage(self, agent_name: str) -> None:
70
- """Display usage for a given agent after a turn."""
71
- ...
72
-
73
-
74
46
  class InteractivePrompt:
75
47
  """
76
48
  Provides interactive prompt functionality that works with any agent implementation.
@@ -91,7 +63,7 @@ class InteractivePrompt:
91
63
  send_func: SendFunc,
92
64
  default_agent: str,
93
65
  available_agents: List[str],
94
- prompt_provider: PromptProvider,
66
+ prompt_provider: "AgentApp",
95
67
  default: str = "",
96
68
  ) -> str:
97
69
  """
@@ -101,7 +73,7 @@ class InteractivePrompt:
101
73
  send_func: Function to send messages to agents
102
74
  default_agent: Name of the default agent to use
103
75
  available_agents: List of available agent names
104
- prompt_provider: Optional provider that implements list_prompts and apply_prompt
76
+ prompt_provider: AgentApp instance for accessing agents and prompts
105
77
  default: Default message to use when user presses enter
106
78
 
107
79
  Returns:
@@ -290,7 +262,7 @@ class InteractivePrompt:
290
262
  rich_print()
291
263
 
292
264
  async def _get_all_prompts(
293
- self, prompt_provider: PromptProvider, agent_name: Optional[str] = None
265
+ self, prompt_provider: "AgentApp", agent_name: Optional[str] = None
294
266
  ):
295
267
  """
296
268
  Get a list of all available prompts.
@@ -370,7 +342,7 @@ class InteractivePrompt:
370
342
  rich_print(f"[dim]{traceback.format_exc()}[/dim]")
371
343
  return []
372
344
 
373
- async def _list_prompts(self, prompt_provider: PromptProvider, agent_name: str) -> None:
345
+ async def _list_prompts(self, prompt_provider: "AgentApp", agent_name: str) -> None:
374
346
  """
375
347
  List available prompts for an agent.
376
348
 
@@ -474,7 +446,7 @@ class InteractivePrompt:
474
446
 
475
447
  async def _select_prompt(
476
448
  self,
477
- prompt_provider: PromptProvider,
449
+ prompt_provider: "AgentApp",
478
450
  agent_name: str,
479
451
  requested_name: Optional[str] = None,
480
452
  send_func: Optional[SendFunc] = None,
@@ -808,7 +780,7 @@ class InteractivePrompt:
808
780
  rich_print(f"[red]Error selecting or applying prompt: {e}[/red]")
809
781
  rich_print(f"[dim]{traceback.format_exc()}[/dim]")
810
782
 
811
- async def _list_tools(self, prompt_provider: PromptProvider, agent_name: str) -> None:
783
+ async def _list_tools(self, prompt_provider: "AgentApp", agent_name: str) -> None:
812
784
  """
813
785
  List available tools for an agent.
814
786
 
@@ -908,7 +880,7 @@ class InteractivePrompt:
908
880
  rich_print(f"[red]Error listing tools: {e}[/red]")
909
881
  rich_print(f"[dim]{traceback.format_exc()}[/dim]")
910
882
 
911
- async def _show_usage(self, prompt_provider: PromptProvider, agent_name: str) -> None:
883
+ async def _show_usage(self, prompt_provider: "AgentApp", agent_name: str) -> None:
912
884
  """
913
885
  Show usage statistics for the current agent(s) in a colorful table format.
914
886
 
@@ -930,7 +902,7 @@ class InteractivePrompt:
930
902
  except Exception as e:
931
903
  rich_print(f"[red]Error showing usage: {e}[/red]")
932
904
 
933
- async def _show_system(self, prompt_provider: PromptProvider, agent_name: str) -> None:
905
+ async def _show_system(self, prompt_provider: "AgentApp", agent_name: str) -> None:
934
906
  """
935
907
  Show the current system prompt for the agent.
936
908
 
@@ -980,7 +952,7 @@ class InteractivePrompt:
980
952
  rich_print(f"[red]Error showing system prompt: {e}[/red]")
981
953
  rich_print(f"[dim]{traceback.format_exc()}[/dim]")
982
954
 
983
- async def _show_markdown(self, prompt_provider: PromptProvider, agent_name: str) -> None:
955
+ async def _show_markdown(self, prompt_provider: "AgentApp", agent_name: str) -> None:
984
956
  """
985
957
  Show the last assistant message without markdown formatting.
986
958
 
@@ -98,8 +98,9 @@ class RichProgressDisplay:
98
98
  task_id = self._progress.add_task(
99
99
  "",
100
100
  total=None,
101
- target=f"{event.target or task_name}", # Use task_name as fallback for target
102
- details=f"{event.agent_name or ''}",
101
+ target=event.target or task_name,
102
+ details=event.details or "",
103
+ task_name=task_name,
103
104
  )
104
105
  self._taskmap[task_name] = task_id
105
106
  else:
@@ -136,11 +137,9 @@ class RichProgressDisplay:
136
137
  # Update basic task information
137
138
  update_kwargs: dict[str, object] = {
138
139
  "description": description,
139
- "fields": {
140
- "target": event.target or task_name, # Use task_name as fallback for target
141
- "details": event.details or "",
142
- "task_name": task_name,
143
- },
140
+ "target": event.target or task_name, # Use task_name as fallback for target
141
+ "details": event.details or "",
142
+ "task_name": task_name,
144
143
  }
145
144
 
146
145
  # For TOOL_PROGRESS events, update progress if available
@@ -149,8 +148,9 @@ class RichProgressDisplay:
149
148
  update_kwargs["completed"] = event.progress
150
149
  update_kwargs["total"] = event.total
151
150
  else:
152
- # If no total, just show as indeterminate progress
151
+ # If no total, reset to indeterminate but keep other fields
153
152
  self._progress.reset(task_id)
153
+ # Still need to update after reset to apply the fields
154
154
 
155
155
  self._progress.update(task_id, **update_kwargs)
156
156
 
@@ -165,7 +165,9 @@ class RichProgressDisplay:
165
165
  task_id,
166
166
  completed=100,
167
167
  total=100,
168
+ target=event.target or task_name,
168
169
  details=f" / Elapsed Time {time.strftime('%H:%M:%S', time.gmtime(self._progress.tasks[task_id].elapsed))}",
170
+ task_name=task_name,
169
171
  )
170
172
  for task in self._progress.tasks:
171
173
  if task.id != task_id:
@@ -175,7 +177,9 @@ class RichProgressDisplay:
175
177
  task_id,
176
178
  completed=100,
177
179
  total=100,
180
+ target=event.target or task_name,
178
181
  details=f" / {event.details}",
182
+ task_name=task_name,
179
183
  )
180
184
  for task in self._progress.tasks:
181
185
  if task.id != task_id:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fast-agent-mcp
3
- Version: 0.3.6
3
+ Version: 0.3.7
4
4
  Summary: Define, Prompt and Test MCP enabled Agents and Workflows
5
5
  Author-email: Shaun Smith <fastagent@llmindset.co.uk>
6
6
  License: Apache License
@@ -211,7 +211,7 @@ Classifier: Programming Language :: Python :: 3
211
211
  Requires-Python: >=3.13.5
212
212
  Requires-Dist: a2a-sdk>=0.3.0
213
213
  Requires-Dist: aiohttp>=3.11.13
214
- Requires-Dist: anthropic>=0.66.0
214
+ Requires-Dist: anthropic>=0.68.0
215
215
  Requires-Dist: azure-identity>=1.14.0
216
216
  Requires-Dist: boto3>=1.35.0
217
217
  Requires-Dist: deprecated>=1.2.18
@@ -220,7 +220,7 @@ Requires-Dist: fastapi>=0.115.6
220
220
  Requires-Dist: google-genai>=1.33.0
221
221
  Requires-Dist: keyring>=24.3.1
222
222
  Requires-Dist: mcp==1.14.0
223
- Requires-Dist: openai>=1.106.1
223
+ Requires-Dist: openai>=1.108.0
224
224
  Requires-Dist: opentelemetry-distro>=0.55b0
225
225
  Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.7.0
226
226
  Requires-Dist: opentelemetry-instrumentation-anthropic>=0.43.1; python_version >= '3.10' and python_version < '4.0'