fast-agent-mcp 0.1.13__py3-none-any.whl → 0.2.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.
Files changed (147) hide show
  1. {fast_agent_mcp-0.1.13.dist-info → fast_agent_mcp-0.2.0.dist-info}/METADATA +3 -4
  2. fast_agent_mcp-0.2.0.dist-info/RECORD +123 -0
  3. mcp_agent/__init__.py +75 -0
  4. mcp_agent/agents/agent.py +59 -371
  5. mcp_agent/agents/base_agent.py +522 -0
  6. mcp_agent/agents/workflow/__init__.py +1 -0
  7. mcp_agent/agents/workflow/chain_agent.py +173 -0
  8. mcp_agent/agents/workflow/evaluator_optimizer.py +362 -0
  9. mcp_agent/agents/workflow/orchestrator_agent.py +591 -0
  10. mcp_agent/{workflows/orchestrator → agents/workflow}/orchestrator_models.py +27 -11
  11. mcp_agent/agents/workflow/parallel_agent.py +182 -0
  12. mcp_agent/agents/workflow/router_agent.py +307 -0
  13. mcp_agent/app.py +3 -1
  14. mcp_agent/cli/commands/bootstrap.py +18 -7
  15. mcp_agent/cli/commands/setup.py +12 -4
  16. mcp_agent/cli/main.py +1 -1
  17. mcp_agent/cli/terminal.py +1 -1
  18. mcp_agent/config.py +24 -35
  19. mcp_agent/context.py +3 -1
  20. mcp_agent/context_dependent.py +3 -1
  21. mcp_agent/core/agent_types.py +10 -7
  22. mcp_agent/core/direct_agent_app.py +179 -0
  23. mcp_agent/core/direct_decorators.py +443 -0
  24. mcp_agent/core/direct_factory.py +476 -0
  25. mcp_agent/core/enhanced_prompt.py +15 -20
  26. mcp_agent/core/fastagent.py +151 -337
  27. mcp_agent/core/interactive_prompt.py +424 -0
  28. mcp_agent/core/mcp_content.py +19 -11
  29. mcp_agent/core/prompt.py +6 -2
  30. mcp_agent/core/validation.py +89 -16
  31. mcp_agent/executor/decorator_registry.py +6 -2
  32. mcp_agent/executor/temporal.py +35 -11
  33. mcp_agent/executor/workflow_signal.py +8 -2
  34. mcp_agent/human_input/handler.py +3 -1
  35. mcp_agent/llm/__init__.py +2 -0
  36. mcp_agent/{workflows/llm → llm}/augmented_llm.py +131 -256
  37. mcp_agent/{workflows/llm → llm}/augmented_llm_passthrough.py +35 -107
  38. mcp_agent/llm/augmented_llm_playback.py +83 -0
  39. mcp_agent/{workflows/llm → llm}/model_factory.py +26 -8
  40. mcp_agent/llm/providers/__init__.py +8 -0
  41. mcp_agent/{workflows/llm → llm/providers}/anthropic_utils.py +5 -1
  42. mcp_agent/{workflows/llm → llm/providers}/augmented_llm_anthropic.py +37 -141
  43. mcp_agent/llm/providers/augmented_llm_deepseek.py +53 -0
  44. mcp_agent/{workflows/llm → llm/providers}/augmented_llm_openai.py +112 -148
  45. mcp_agent/{workflows/llm → llm}/providers/multipart_converter_anthropic.py +78 -35
  46. mcp_agent/{workflows/llm → llm}/providers/multipart_converter_openai.py +73 -44
  47. mcp_agent/{workflows/llm → llm}/providers/openai_multipart.py +18 -4
  48. mcp_agent/{workflows/llm → llm/providers}/openai_utils.py +3 -3
  49. mcp_agent/{workflows/llm → llm}/providers/sampling_converter_anthropic.py +3 -3
  50. mcp_agent/{workflows/llm → llm}/providers/sampling_converter_openai.py +3 -3
  51. mcp_agent/{workflows/llm → llm}/sampling_converter.py +0 -21
  52. mcp_agent/{workflows/llm → llm}/sampling_format_converter.py +16 -1
  53. mcp_agent/logging/logger.py +2 -2
  54. mcp_agent/mcp/gen_client.py +9 -3
  55. mcp_agent/mcp/interfaces.py +67 -45
  56. mcp_agent/mcp/logger_textio.py +97 -0
  57. mcp_agent/mcp/mcp_agent_client_session.py +12 -4
  58. mcp_agent/mcp/mcp_agent_server.py +3 -1
  59. mcp_agent/mcp/mcp_aggregator.py +124 -93
  60. mcp_agent/mcp/mcp_connection_manager.py +21 -7
  61. mcp_agent/mcp/prompt_message_multipart.py +59 -1
  62. mcp_agent/mcp/prompt_render.py +77 -0
  63. mcp_agent/mcp/prompt_serialization.py +20 -13
  64. mcp_agent/mcp/prompts/prompt_constants.py +18 -0
  65. mcp_agent/mcp/prompts/prompt_helpers.py +327 -0
  66. mcp_agent/mcp/prompts/prompt_load.py +15 -5
  67. mcp_agent/mcp/prompts/prompt_server.py +154 -87
  68. mcp_agent/mcp/prompts/prompt_template.py +26 -35
  69. mcp_agent/mcp/resource_utils.py +3 -1
  70. mcp_agent/mcp/sampling.py +24 -15
  71. mcp_agent/mcp_server/agent_server.py +8 -5
  72. mcp_agent/mcp_server_registry.py +22 -9
  73. mcp_agent/resources/examples/{workflows → in_dev}/agent_build.py +1 -1
  74. mcp_agent/resources/examples/{data-analysis → in_dev}/slides.py +1 -1
  75. mcp_agent/resources/examples/internal/agent.py +4 -2
  76. mcp_agent/resources/examples/internal/fastagent.config.yaml +8 -2
  77. mcp_agent/resources/examples/prompting/image_server.py +3 -1
  78. mcp_agent/resources/examples/prompting/work_with_image.py +19 -0
  79. mcp_agent/ui/console_display.py +27 -7
  80. fast_agent_mcp-0.1.13.dist-info/RECORD +0 -164
  81. mcp_agent/core/agent_app.py +0 -570
  82. mcp_agent/core/agent_utils.py +0 -69
  83. mcp_agent/core/decorators.py +0 -448
  84. mcp_agent/core/factory.py +0 -422
  85. mcp_agent/core/proxies.py +0 -278
  86. mcp_agent/core/types.py +0 -22
  87. mcp_agent/eval/__init__.py +0 -0
  88. mcp_agent/mcp/stdio.py +0 -114
  89. mcp_agent/resources/examples/data-analysis/analysis-campaign.py +0 -188
  90. mcp_agent/resources/examples/data-analysis/analysis.py +0 -65
  91. mcp_agent/resources/examples/data-analysis/fastagent.config.yaml +0 -41
  92. mcp_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +0 -1471
  93. mcp_agent/resources/examples/mcp_researcher/researcher-eval.py +0 -53
  94. mcp_agent/resources/examples/researcher/fastagent.config.yaml +0 -66
  95. mcp_agent/resources/examples/researcher/researcher-eval.py +0 -53
  96. mcp_agent/resources/examples/researcher/researcher-imp.py +0 -189
  97. mcp_agent/resources/examples/researcher/researcher.py +0 -39
  98. mcp_agent/resources/examples/workflows/chaining.py +0 -45
  99. mcp_agent/resources/examples/workflows/evaluator.py +0 -79
  100. mcp_agent/resources/examples/workflows/fastagent.config.yaml +0 -24
  101. mcp_agent/resources/examples/workflows/human_input.py +0 -26
  102. mcp_agent/resources/examples/workflows/orchestrator.py +0 -74
  103. mcp_agent/resources/examples/workflows/parallel.py +0 -79
  104. mcp_agent/resources/examples/workflows/router.py +0 -54
  105. mcp_agent/resources/examples/workflows/sse.py +0 -23
  106. mcp_agent/telemetry/__init__.py +0 -0
  107. mcp_agent/telemetry/usage_tracking.py +0 -19
  108. mcp_agent/workflows/__init__.py +0 -0
  109. mcp_agent/workflows/embedding/__init__.py +0 -0
  110. mcp_agent/workflows/embedding/embedding_base.py +0 -58
  111. mcp_agent/workflows/embedding/embedding_cohere.py +0 -49
  112. mcp_agent/workflows/embedding/embedding_openai.py +0 -37
  113. mcp_agent/workflows/evaluator_optimizer/__init__.py +0 -0
  114. mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +0 -447
  115. mcp_agent/workflows/intent_classifier/__init__.py +0 -0
  116. mcp_agent/workflows/intent_classifier/intent_classifier_base.py +0 -117
  117. mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py +0 -130
  118. mcp_agent/workflows/intent_classifier/intent_classifier_embedding_cohere.py +0 -41
  119. mcp_agent/workflows/intent_classifier/intent_classifier_embedding_openai.py +0 -41
  120. mcp_agent/workflows/intent_classifier/intent_classifier_llm.py +0 -150
  121. mcp_agent/workflows/intent_classifier/intent_classifier_llm_anthropic.py +0 -60
  122. mcp_agent/workflows/intent_classifier/intent_classifier_llm_openai.py +0 -58
  123. mcp_agent/workflows/llm/__init__.py +0 -0
  124. mcp_agent/workflows/llm/augmented_llm_playback.py +0 -111
  125. mcp_agent/workflows/llm/providers/__init__.py +0 -8
  126. mcp_agent/workflows/orchestrator/__init__.py +0 -0
  127. mcp_agent/workflows/orchestrator/orchestrator.py +0 -535
  128. mcp_agent/workflows/parallel/__init__.py +0 -0
  129. mcp_agent/workflows/parallel/fan_in.py +0 -320
  130. mcp_agent/workflows/parallel/fan_out.py +0 -181
  131. mcp_agent/workflows/parallel/parallel_llm.py +0 -149
  132. mcp_agent/workflows/router/__init__.py +0 -0
  133. mcp_agent/workflows/router/router_base.py +0 -338
  134. mcp_agent/workflows/router/router_embedding.py +0 -226
  135. mcp_agent/workflows/router/router_embedding_cohere.py +0 -59
  136. mcp_agent/workflows/router/router_embedding_openai.py +0 -59
  137. mcp_agent/workflows/router/router_llm.py +0 -304
  138. mcp_agent/workflows/swarm/__init__.py +0 -0
  139. mcp_agent/workflows/swarm/swarm.py +0 -292
  140. mcp_agent/workflows/swarm/swarm_anthropic.py +0 -42
  141. mcp_agent/workflows/swarm/swarm_openai.py +0 -41
  142. {fast_agent_mcp-0.1.13.dist-info → fast_agent_mcp-0.2.0.dist-info}/WHEEL +0 -0
  143. {fast_agent_mcp-0.1.13.dist-info → fast_agent_mcp-0.2.0.dist-info}/entry_points.txt +0 -0
  144. {fast_agent_mcp-0.1.13.dist-info → fast_agent_mcp-0.2.0.dist-info}/licenses/LICENSE +0 -0
  145. /mcp_agent/{workflows/orchestrator → agents/workflow}/orchestrator_prompts.py +0 -0
  146. /mcp_agent/{workflows/llm → llm}/memory.py +0 -0
  147. /mcp_agent/{workflows/llm → llm}/prompt_utils.py +0 -0
@@ -1,41 +0,0 @@
1
- from typing import TYPE_CHECKING, List, Optional
2
-
3
- from mcp_agent.workflows.embedding.embedding_cohere import CohereEmbeddingModel
4
- from mcp_agent.workflows.intent_classifier.intent_classifier_base import Intent
5
- from mcp_agent.workflows.intent_classifier.intent_classifier_embedding import (
6
- EmbeddingIntentClassifier,
7
- )
8
-
9
- if TYPE_CHECKING:
10
- from mcp_agent.context import Context
11
-
12
-
13
- class CohereEmbeddingIntentClassifier(EmbeddingIntentClassifier):
14
- """
15
- An intent classifier that uses Cohere's embedding models for computing semantic simiarity based classifications.
16
- """
17
-
18
- def __init__(
19
- self,
20
- intents: List[Intent],
21
- embedding_model: CohereEmbeddingModel | None = None,
22
- context: Optional["Context"] = None,
23
- **kwargs,
24
- ) -> None:
25
- embedding_model = embedding_model or CohereEmbeddingModel()
26
- super().__init__(embedding_model=embedding_model, intents=intents, context=context, **kwargs)
27
-
28
- @classmethod
29
- async def create(
30
- cls,
31
- intents: List[Intent],
32
- embedding_model: CohereEmbeddingModel | None = None,
33
- context: Optional["Context"] = None,
34
- ) -> "CohereEmbeddingIntentClassifier":
35
- """
36
- Factory method to create and initialize a classifier.
37
- Use this instead of constructor since we need async initialization.
38
- """
39
- instance = cls(intents=intents, embedding_model=embedding_model, context=context)
40
- await instance.initialize()
41
- return instance
@@ -1,41 +0,0 @@
1
- from typing import TYPE_CHECKING, List, Optional
2
-
3
- from mcp_agent.workflows.embedding.embedding_openai import OpenAIEmbeddingModel
4
- from mcp_agent.workflows.intent_classifier.intent_classifier_base import Intent
5
- from mcp_agent.workflows.intent_classifier.intent_classifier_embedding import (
6
- EmbeddingIntentClassifier,
7
- )
8
-
9
- if TYPE_CHECKING:
10
- from mcp_agent.context import Context
11
-
12
-
13
- class OpenAIEmbeddingIntentClassifier(EmbeddingIntentClassifier):
14
- """
15
- An intent classifier that uses OpenAI's embedding models for computing semantic simiarity based classifications.
16
- """
17
-
18
- def __init__(
19
- self,
20
- intents: List[Intent],
21
- embedding_model: OpenAIEmbeddingModel | None = None,
22
- context: Optional["Context"] = None,
23
- **kwargs,
24
- ) -> None:
25
- embedding_model = embedding_model or OpenAIEmbeddingModel()
26
- super().__init__(embedding_model=embedding_model, intents=intents, context=context, **kwargs)
27
-
28
- @classmethod
29
- async def create(
30
- cls,
31
- intents: List[Intent],
32
- embedding_model: OpenAIEmbeddingModel | None = None,
33
- context: Optional["Context"] = None,
34
- ) -> "OpenAIEmbeddingIntentClassifier":
35
- """
36
- Factory method to create and initialize a classifier.
37
- Use this instead of constructor since we need async initialization.
38
- """
39
- instance = cls(intents=intents, embedding_model=embedding_model, context=context)
40
- await instance.initialize()
41
- return instance
@@ -1,150 +0,0 @@
1
- from typing import TYPE_CHECKING, List, Literal, Optional
2
-
3
- from pydantic import BaseModel
4
-
5
- from mcp_agent.workflows.intent_classifier.intent_classifier_base import (
6
- Intent,
7
- IntentClassificationResult,
8
- IntentClassifier,
9
- )
10
- from mcp_agent.workflows.llm.augmented_llm import AugmentedLLM
11
-
12
- if TYPE_CHECKING:
13
- from mcp_agent.context import Context
14
-
15
- DEFAULT_INTENT_CLASSIFICATION_INSTRUCTION = """
16
- You are a precise intent classifier that analyzes user requests to determine their intended action or purpose.
17
- Below are the available intents with their descriptions and examples:
18
-
19
- {context}
20
-
21
- Your task is to analyze the following request and determine the most likely intent(s). Consider:
22
- - How well the request matches the intent descriptions and examples
23
- - Any specific entities or parameters that should be extracted
24
- - The confidence level in the classification
25
-
26
- Request: {request}
27
-
28
- Respond in JSON format:
29
- {{
30
- "classifications": [
31
- {{
32
- "intent": <intent name>,
33
- "confidence": <float between 0 and 1>,
34
- "extracted_entities": {{
35
- "entity_name": "entity_value"
36
- }},
37
- "reasoning": <brief explanation>
38
- }}
39
- ]
40
- }}
41
-
42
- Return up to {top_k} most likely intents. Only include intents with reasonable confidence (>0.5).
43
- If no intents match well, return an empty list.
44
- """
45
-
46
-
47
- class LLMIntentClassificationResult(IntentClassificationResult):
48
- """The result of intent classification using an LLM."""
49
-
50
- confidence: Literal["low", "medium", "high"]
51
- """Confidence level of the classification"""
52
-
53
- reasoning: str | None = None
54
- """Optional explanation of why this intent was chosen"""
55
-
56
-
57
- class StructuredIntentResponse(BaseModel):
58
- """The complete structured response from the LLM"""
59
-
60
- classifications: List[LLMIntentClassificationResult]
61
-
62
-
63
- class LLMIntentClassifier(IntentClassifier):
64
- """
65
- An intent classifier that uses an LLM to determine the user's intent.
66
- Particularly useful when you need:
67
- - Flexible understanding of natural language
68
- - Detailed reasoning about classifications
69
- - Entity extraction alongside classification
70
- """
71
-
72
- def __init__(
73
- self,
74
- llm: AugmentedLLM,
75
- intents: List[Intent],
76
- classification_instruction: str | None = None,
77
- context: Optional["Context"] = None,
78
- **kwargs,
79
- ) -> None:
80
- super().__init__(intents=intents, context=context, **kwargs)
81
- self.llm = llm
82
- self.classification_instruction = classification_instruction
83
-
84
- @classmethod
85
- async def create(
86
- cls,
87
- llm: AugmentedLLM,
88
- intents: List[Intent],
89
- classification_instruction: str | None = None,
90
- ) -> "LLMIntentClassifier":
91
- """
92
- Factory method to create and initialize a classifier.
93
- Use this instead of constructor since we need async initialization.
94
- """
95
- instance = cls(
96
- llm=llm,
97
- intents=intents,
98
- classification_instruction=classification_instruction,
99
- )
100
- await instance.initialize()
101
- return instance
102
-
103
- async def classify(self, request: str, top_k: int = 1) -> List[LLMIntentClassificationResult]:
104
- if not self.initialized:
105
- self.initialize()
106
-
107
- classification_instruction = self.classification_instruction or DEFAULT_INTENT_CLASSIFICATION_INSTRUCTION
108
-
109
- # Generate the context with intent descriptions and examples
110
- context = self._generate_context()
111
-
112
- # Format the prompt with all the necessary information
113
- prompt = classification_instruction.format(context=context, request=request, top_k=top_k)
114
-
115
- # Get classification from LLM
116
- response = await self.llm.generate_structured(message=prompt, response_model=StructuredIntentResponse)
117
-
118
- if not response or not response.classifications:
119
- return []
120
-
121
- results = []
122
- for classification in response.classifications:
123
- intent = self.intents.get(classification.intent)
124
- if not intent:
125
- # Skip invalid categories
126
- # TODO: saqadri - log or raise an error
127
- continue
128
-
129
- results.append(classification)
130
-
131
- return results[:top_k]
132
-
133
- def _generate_context(self) -> str:
134
- """Generate a formatted context string describing all intents"""
135
- context_parts = []
136
-
137
- for idx, intent in enumerate(self.intents.values(), 1):
138
- description = f"{idx}. Intent: {intent.name}\nDescription: {intent.description}"
139
-
140
- if intent.examples:
141
- examples = "\n".join(f"- {example}" for example in intent.examples)
142
- description += f"\nExamples:\n{examples}"
143
-
144
- if intent.metadata:
145
- metadata = "\n".join(f"- {key}: {value}" for key, value in intent.metadata.items())
146
- description += f"\nAdditional Information:\n{metadata}"
147
-
148
- context_parts.append(description)
149
-
150
- return "\n\n".join(context_parts)
@@ -1,60 +0,0 @@
1
- from typing import TYPE_CHECKING, List, Optional
2
-
3
- from mcp_agent.workflows.intent_classifier.intent_classifier_base import Intent
4
- from mcp_agent.workflows.intent_classifier.intent_classifier_llm import (
5
- LLMIntentClassifier,
6
- )
7
- from mcp_agent.workflows.llm.augmented_llm_anthropic import AnthropicAugmentedLLM
8
-
9
- if TYPE_CHECKING:
10
- from mcp_agent.context import Context
11
-
12
- CLASSIFIER_SYSTEM_INSTRUCTION = """
13
- You are a precise intent classifier that analyzes input requests to determine their intended action or purpose.
14
- You are provided with a request and a list of intents to choose from.
15
- You can choose one or more intents, or choose none if no intent is appropriate.
16
- """
17
-
18
-
19
- class AnthropicLLMIntentClassifier(LLMIntentClassifier):
20
- """
21
- An LLM router that uses an Anthropic model to make routing decisions.
22
- """
23
-
24
- def __init__(
25
- self,
26
- intents: List[Intent],
27
- classification_instruction: str | None = None,
28
- context: Optional["Context"] = None,
29
- **kwargs,
30
- ) -> None:
31
- anthropic_llm = AnthropicAugmentedLLM(
32
- instruction=CLASSIFIER_SYSTEM_INSTRUCTION, context=context
33
- )
34
-
35
- super().__init__(
36
- llm=anthropic_llm,
37
- intents=intents,
38
- classification_instruction=classification_instruction,
39
- context=context,
40
- **kwargs,
41
- )
42
-
43
- @classmethod
44
- async def create(
45
- cls,
46
- intents: List[Intent],
47
- classification_instruction: str | None = None,
48
- context: Optional["Context"] = None,
49
- ) -> "AnthropicLLMIntentClassifier":
50
- """
51
- Factory method to create and initialize a classifier.
52
- Use this instead of constructor since we need async initialization.
53
- """
54
- instance = cls(
55
- intents=intents,
56
- classification_instruction=classification_instruction,
57
- context=context,
58
- )
59
- await instance.initialize()
60
- return instance
@@ -1,58 +0,0 @@
1
- from typing import TYPE_CHECKING, List, Optional
2
-
3
- from mcp_agent.workflows.intent_classifier.intent_classifier_base import Intent
4
- from mcp_agent.workflows.intent_classifier.intent_classifier_llm import (
5
- LLMIntentClassifier,
6
- )
7
- from mcp_agent.workflows.llm.augmented_llm_openai import OpenAIAugmentedLLM
8
-
9
- if TYPE_CHECKING:
10
- from mcp_agent.context import Context
11
-
12
- CLASSIFIER_SYSTEM_INSTRUCTION = """
13
- You are a precise intent classifier that analyzes input requests to determine their intended action or purpose.
14
- You are provided with a request and a list of intents to choose from.
15
- You can choose one or more intents, or choose none if no intent is appropriate.
16
- """
17
-
18
-
19
- class OpenAILLMIntentClassifier(LLMIntentClassifier):
20
- """
21
- An LLM router that uses an OpenAI model to make routing decisions.
22
- """
23
-
24
- def __init__(
25
- self,
26
- intents: List[Intent],
27
- classification_instruction: str | None = None,
28
- context: Optional["Context"] = None,
29
- **kwargs,
30
- ) -> None:
31
- openai_llm = OpenAIAugmentedLLM(instruction=CLASSIFIER_SYSTEM_INSTRUCTION, context=context)
32
-
33
- super().__init__(
34
- llm=openai_llm,
35
- intents=intents,
36
- classification_instruction=classification_instruction,
37
- context=context,
38
- **kwargs,
39
- )
40
-
41
- @classmethod
42
- async def create(
43
- cls,
44
- intents: List[Intent],
45
- classification_instruction: str | None = None,
46
- context: Optional["Context"] = None,
47
- ) -> "OpenAILLMIntentClassifier":
48
- """
49
- Factory method to create and initialize a classifier.
50
- Use this instead of constructor since we need async initialization.
51
- """
52
- instance = cls(
53
- intents=intents,
54
- classification_instruction=classification_instruction,
55
- context=context,
56
- )
57
- await instance.initialize()
58
- return instance
File without changes
@@ -1,111 +0,0 @@
1
- from typing import TYPE_CHECKING, List, Optional, Union
2
-
3
- from mcp import GetPromptResult
4
-
5
- from mcp_agent.workflows.llm.augmented_llm import MessageParamT, RequestParams
6
- from mcp_agent.workflows.llm.augmented_llm_passthrough import PassthroughLLM
7
-
8
- if TYPE_CHECKING:
9
- from mcp.types import PromptMessage
10
-
11
-
12
- # TODO -- support tool calling
13
- class PlaybackLLM(PassthroughLLM):
14
- """
15
- A specialized LLM implementation that plays back assistant messages when loaded with prompts.
16
-
17
- Unlike the PassthroughLLM which simply passes through messages without modification,
18
- PlaybackLLM is designed to simulate a conversation by playing back prompt messages
19
- in sequence when loaded with prompts through apply_prompt_template.
20
-
21
- After apply_prompts has been called, each call to generate_str returns the next
22
- "ASSISTANT" message in the loaded messages. If no messages are set or all messages have
23
- been played back, it returns a message indicating that messages are exhausted.
24
- """
25
-
26
- def __init__(self, name: str = "Playback", **kwargs) -> None:
27
- super().__init__(name=name, **kwargs)
28
- self._messages: List[PromptMessage] = []
29
- self._current_index = 0
30
-
31
- async def generate_str(
32
- self,
33
- message: Union[str, MessageParamT, List[MessageParamT]],
34
- request_params: Optional[RequestParams] = None,
35
- ) -> str:
36
- """
37
- Return the next ASSISTANT message in the loaded messages list.
38
- If no messages are available or all have been played back,
39
- returns a message indicating messages are exhausted.
40
-
41
- Note: Only assistant messages are returned; user messages are skipped.
42
- """
43
- self.show_user_message(message, model="fastagent-playback", chat_turn=0)
44
-
45
- if not self._messages or self._current_index >= len(self._messages):
46
- size = len(self._messages) if self._messages else 0
47
- response = f"MESSAGES EXHAUSTED (list size {size})"
48
- else:
49
- response = self._get_next_assistant_message()
50
-
51
- await self.show_assistant_message(response, title="ASSISTANT/PLAYBACK")
52
- return response
53
-
54
- def _get_next_assistant_message(self) -> str:
55
- """
56
- Get the next assistant message from the loaded messages.
57
- Increments the current message index and skips user messages.
58
- """
59
- # Find next assistant message
60
- while self._current_index < len(self._messages):
61
- message = self._messages[self._current_index]
62
- self._current_index += 1
63
-
64
- # Skip non-assistant messages
65
- if getattr(message, "role", None) != "assistant":
66
- continue
67
-
68
- # Get content as string
69
- content = message.content
70
- if hasattr(content, "text"):
71
- return content.text
72
- return str(content)
73
-
74
- # If we get here, we've run out of assistant messages
75
- return f"MESSAGES EXHAUSTED (list size {len(self._messages)})"
76
-
77
- async def apply_prompt_template(self, prompt_result: GetPromptResult, prompt_name: str) -> str:
78
- """
79
- Apply a prompt template by adding its messages to the playback queue.
80
-
81
- Args:
82
- prompt_result: The GetPromptResult containing prompt messages
83
- prompt_name: The name of the prompt being applied
84
-
85
- Returns:
86
- String representation of the first message or an indication that no messages were added
87
- """
88
- prompt_messages: List[PromptMessage] = prompt_result.messages
89
-
90
- # Extract arguments if they were stored in the result
91
- arguments = getattr(prompt_result, "arguments", None)
92
-
93
- # Display information about the loaded prompt
94
- await self.show_prompt_loaded(
95
- prompt_name=prompt_name,
96
- description=prompt_result.description,
97
- message_count=len(prompt_messages),
98
- arguments=arguments,
99
- )
100
-
101
- # Add new messages to the end of the existing messages list
102
- self._messages.extend(prompt_messages)
103
-
104
- if not prompt_messages:
105
- return "Prompt contains no messages"
106
-
107
- # Reset current index if this is the first time loading messages
108
- if len(self._messages) == len(prompt_messages):
109
- self._current_index = 0
110
-
111
- return f"Added {len(prompt_messages)} messages to playback queue"
@@ -1,8 +0,0 @@
1
- from mcp_agent.workflows.llm.providers.sampling_converter_anthropic import (
2
- AnthropicSamplingConverter,
3
- )
4
- from mcp_agent.workflows.llm.providers.sampling_converter_openai import (
5
- OpenAISamplingConverter,
6
- )
7
-
8
- __all__ = ["AnthropicSamplingConverter", "OpenAISamplingConverter"]
File without changes