fast-agent-mcp 0.0.16__py3-none-any.whl → 0.1.1__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.
- {fast_agent_mcp-0.0.16.dist-info → fast_agent_mcp-0.1.1.dist-info}/METADATA +30 -13
- {fast_agent_mcp-0.0.16.dist-info → fast_agent_mcp-0.1.1.dist-info}/RECORD +21 -20
- mcp_agent/cli/commands/bootstrap.py +1 -1
- mcp_agent/cli/commands/setup.py +4 -1
- mcp_agent/cli/main.py +13 -3
- mcp_agent/core/agent_app.py +1 -1
- mcp_agent/core/enhanced_prompt.py +3 -3
- mcp_agent/core/fastagent.py +96 -49
- mcp_agent/resources/examples/data-analysis/analysis-campaign.py +188 -0
- mcp_agent/resources/examples/data-analysis/analysis.py +36 -32
- mcp_agent/resources/examples/workflows/agent_build.py +48 -28
- mcp_agent/resources/examples/workflows/evaluator.py +3 -1
- mcp_agent/resources/examples/workflows/orchestrator.py +2 -2
- mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +120 -63
- mcp_agent/workflows/llm/augmented_llm_anthropic.py +4 -3
- mcp_agent/workflows/orchestrator/orchestrator.py +170 -70
- mcp_agent/workflows/orchestrator/orchestrator_models.py +3 -0
- mcp_agent/workflows/orchestrator/orchestrator_prompts.py +48 -0
- {fast_agent_mcp-0.0.16.dist-info → fast_agent_mcp-0.1.1.dist-info}/WHEEL +0 -0
- {fast_agent_mcp-0.0.16.dist-info → fast_agent_mcp-0.1.1.dist-info}/entry_points.txt +0 -0
- {fast_agent_mcp-0.0.16.dist-info → fast_agent_mcp-0.1.1.dist-info}/licenses/LICENSE +0 -0
@@ -4,6 +4,7 @@ This demonstrates creating multiple agents and an orchestrator to coordinate the
|
|
4
4
|
|
5
5
|
import asyncio
|
6
6
|
from mcp_agent.core.fastagent import FastAgent
|
7
|
+
from mcp_agent.workflows.llm.augmented_llm import RequestParams
|
7
8
|
|
8
9
|
# Create the application
|
9
10
|
fast = FastAgent("Agent Builder")
|
@@ -12,49 +13,68 @@ fast = FastAgent("Agent Builder")
|
|
12
13
|
@fast.agent(
|
13
14
|
"agent_expert",
|
14
15
|
instruction="""
|
15
|
-
You design agent workflows,
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
You design agent workflows, adhering to 'Building Effective Agents' (details to follow).
|
17
|
+
|
18
|
+
You provide concise specific guidance on design and composition. Prefer simple solutions,
|
19
|
+
and don't nest workflows more than one level deep.
|
20
|
+
|
21
|
+
Your objective is to produce a single '.py' agent in the style of the examples.
|
22
|
+
|
23
|
+
Keep the application simple, concentrationg on defining Agent instructions, MCP Servers and
|
24
|
+
appropriate use of Workflows.
|
25
|
+
|
26
|
+
The style of the program should be like the examples you have been shown, with a minimum of
|
27
|
+
additional code, using only very simple Python where absolutely necessary.
|
28
|
+
|
29
|
+
Concentrate on the quality of the Agent instructions and "warmup" prompts given to them.
|
30
|
+
|
31
|
+
Keep requirements minimal: focus on building the prompts and the best workflow. The program
|
32
|
+
is expected to be adjusted and refined later.
|
33
|
+
|
34
|
+
If you are unsure about how to proceed, request input from the Human.
|
35
|
+
|
36
|
+
""",
|
22
37
|
servers=["filesystem", "fetch"],
|
38
|
+
request_params=RequestParams(maxTokens=8192),
|
23
39
|
)
|
24
40
|
# Define worker agents
|
25
41
|
@fast.agent(
|
26
42
|
"requirements_capture",
|
27
43
|
instruction="""
|
28
|
-
You help the Human define their requirements for building Agent based systems.
|
29
|
-
|
30
|
-
Keep
|
44
|
+
You help the Human define their requirements for building Agent based systems.
|
45
|
+
|
46
|
+
Keep questions short, simple and minimal, always offering to complete the questioning
|
47
|
+
if desired. If uncertain about something, respond asking the 'agent_expert' for guidance.
|
48
|
+
|
49
|
+
Do not interrogate the Human, prefer to move the process on, as more details can be requested later
|
50
|
+
if needed. Remind the Human of this.
|
51
|
+
""",
|
31
52
|
human_input=True,
|
32
53
|
)
|
33
54
|
# Define the orchestrator to coordinate the other agents
|
34
55
|
@fast.orchestrator(
|
35
|
-
name="
|
56
|
+
name="agent_builder",
|
36
57
|
agents=["agent_expert", "requirements_capture"],
|
37
58
|
model="sonnet",
|
59
|
+
plan_type="iterative",
|
60
|
+
request_params=RequestParams(maxTokens=8192),
|
61
|
+
max_iterations=5,
|
38
62
|
)
|
39
63
|
async def main():
|
40
64
|
async with fast.run() as agent:
|
41
|
-
|
42
|
-
- Read this paper: https://www.anthropic.com/research/building-effective-agents" to understand
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
await agent.orchestrator_worker(
|
56
|
-
"Write an Agent program that fulfils the Human's needs."
|
57
|
-
)
|
65
|
+
CODER_WARMUP = """
|
66
|
+
- Read this paper: https://www.anthropic.com/research/building-effective-agents" to understand how
|
67
|
+
and when to use different types of Agents and Workflow types.
|
68
|
+
|
69
|
+
- Read this README https://raw.githubusercontent.com/evalstate/fast-agent/refs/heads/main/README.md file
|
70
|
+
to see how to use "fast-agent" framework.
|
71
|
+
|
72
|
+
- Look at the 'fastagent.config.yaml' file to see the available and configured MCP Servers.
|
73
|
+
|
74
|
+
"""
|
75
|
+
await agent.agent_expert(CODER_WARMUP)
|
76
|
+
|
77
|
+
await agent.agent_builder()
|
58
78
|
|
59
79
|
|
60
80
|
if __name__ == "__main__":
|
@@ -17,7 +17,8 @@ fast = FastAgent("Evaluator-Optimizer")
|
|
17
17
|
candidate details, and company information. Tailor the response to the company and job requirements.
|
18
18
|
""",
|
19
19
|
servers=["fetch"],
|
20
|
-
model="
|
20
|
+
model="haiku3",
|
21
|
+
use_history=True,
|
21
22
|
)
|
22
23
|
# Define evaluator agent
|
23
24
|
@fast.agent(
|
@@ -38,6 +39,7 @@ fast = FastAgent("Evaluator-Optimizer")
|
|
38
39
|
Summarize your evaluation as a structured response with:
|
39
40
|
- Overall quality rating.
|
40
41
|
- Specific feedback and areas for improvement.""",
|
42
|
+
model="gpt-4o",
|
41
43
|
)
|
42
44
|
# Define the evaluator-optimizer workflow
|
43
45
|
@fast.evaluator_optimizer(
|
@@ -45,11 +45,10 @@ fast = FastAgent("Orchestrator-Workers")
|
|
45
45
|
@fast.orchestrator(
|
46
46
|
name="orchestrate",
|
47
47
|
agents=["finder", "writer", "proofreader"],
|
48
|
-
plan_type="
|
48
|
+
plan_type="full",
|
49
49
|
)
|
50
50
|
async def main():
|
51
51
|
async with fast.run() as agent:
|
52
|
-
|
53
52
|
await agent.author(
|
54
53
|
"write a 250 word short story about kittens discovering a castle, and save it to short_story.md"
|
55
54
|
)
|
@@ -68,5 +67,6 @@ async def main():
|
|
68
67
|
await agent.orchestrate(task)
|
69
68
|
await agent()
|
70
69
|
|
70
|
+
|
71
71
|
if __name__ == "__main__":
|
72
72
|
asyncio.run(main())
|
@@ -10,7 +10,7 @@ from mcp_agent.workflows.llm.augmented_llm import (
|
|
10
10
|
ModelT,
|
11
11
|
RequestParams,
|
12
12
|
)
|
13
|
-
from mcp_agent.agents.agent import Agent
|
13
|
+
from mcp_agent.agents.agent import Agent, AgentConfig
|
14
14
|
from mcp_agent.logging.logger import get_logger
|
15
15
|
|
16
16
|
if TYPE_CHECKING:
|
@@ -64,6 +64,25 @@ class EvaluatorOptimizerLLM(AugmentedLLM[MessageParamT, MessageT]):
|
|
64
64
|
- Document writing requiring multiple revisions
|
65
65
|
"""
|
66
66
|
|
67
|
+
def _initialize_default_params(self, kwargs: dict) -> RequestParams:
|
68
|
+
"""Initialize default parameters using the workflow's settings."""
|
69
|
+
return RequestParams(
|
70
|
+
modelPreferences=self.model_preferences,
|
71
|
+
systemPrompt=self.instruction,
|
72
|
+
parallel_tool_calls=True,
|
73
|
+
max_iterations=10,
|
74
|
+
use_history=self.generator_use_history, # Use generator's history setting
|
75
|
+
)
|
76
|
+
|
77
|
+
def _init_request_params(self):
|
78
|
+
"""Initialize request parameters for both generator and evaluator components."""
|
79
|
+
# Set up workflow's default params based on generator's history setting
|
80
|
+
self.default_request_params = self._initialize_default_params({})
|
81
|
+
|
82
|
+
# Ensure evaluator's request params have history disabled
|
83
|
+
if hasattr(self.evaluator_llm, "default_request_params"):
|
84
|
+
self.evaluator_llm.default_request_params.use_history = False
|
85
|
+
|
67
86
|
def __init__(
|
68
87
|
self,
|
69
88
|
generator: Agent | AugmentedLLM,
|
@@ -73,6 +92,8 @@ class EvaluatorOptimizerLLM(AugmentedLLM[MessageParamT, MessageT]):
|
|
73
92
|
llm_factory: Callable[[Agent], AugmentedLLM]
|
74
93
|
| None = None, # TODO: Remove legacy - factory should only be needed for str evaluator
|
75
94
|
context: Optional["Context"] = None,
|
95
|
+
name: Optional[str] = None, # Allow overriding the name
|
96
|
+
instruction: Optional[str] = None, # Allow overriding the instruction
|
76
97
|
):
|
77
98
|
"""
|
78
99
|
Initialize the evaluator-optimizer workflow.
|
@@ -87,16 +108,50 @@ class EvaluatorOptimizerLLM(AugmentedLLM[MessageParamT, MessageT]):
|
|
87
108
|
min_rating: Minimum acceptable quality rating
|
88
109
|
max_refinements: Maximum refinement iterations
|
89
110
|
llm_factory: Optional factory to create LLMs from agents
|
111
|
+
name: Optional name for the workflow (defaults to generator's name)
|
112
|
+
instruction: Optional instruction (defaults to generator's instruction)
|
113
|
+
|
114
|
+
Note on History Management:
|
115
|
+
This workflow manages two distinct history contexts:
|
116
|
+
1. Generator History: Controlled by the generator's use_history setting. When False,
|
117
|
+
each refinement iteration starts fresh without previous context.
|
118
|
+
2. Evaluator History: Always disabled as each evaluation should be independent
|
119
|
+
and based solely on the current response.
|
90
120
|
"""
|
91
|
-
|
92
|
-
|
93
|
-
# Set up the optimizer
|
94
|
-
self.name = generator.name
|
121
|
+
# Set up initial instance attributes - allow name override
|
122
|
+
self.name = name or generator.name
|
95
123
|
self.llm_factory = llm_factory
|
96
124
|
self.generator = generator
|
97
125
|
self.evaluator = evaluator
|
126
|
+
self.min_rating = min_rating
|
127
|
+
self.max_refinements = max_refinements
|
128
|
+
|
129
|
+
# Determine generator's history setting before super().__init__
|
130
|
+
if isinstance(generator, Agent):
|
131
|
+
self.generator_use_history = generator.config.use_history
|
132
|
+
elif isinstance(generator, AugmentedLLM):
|
133
|
+
if hasattr(generator, "aggregator") and isinstance(
|
134
|
+
generator.aggregator, Agent
|
135
|
+
):
|
136
|
+
self.generator_use_history = generator.aggregator.config.use_history
|
137
|
+
else:
|
138
|
+
self.generator_use_history = getattr(
|
139
|
+
generator,
|
140
|
+
"use_history",
|
141
|
+
getattr(generator.default_request_params, "use_history", False),
|
142
|
+
)
|
143
|
+
else:
|
144
|
+
raise ValueError(f"Unsupported optimizer type: {type(generator)}")
|
145
|
+
|
146
|
+
# Now we can call super().__init__ which will use generator_use_history
|
147
|
+
super().__init__(context=context, name=name or generator.name)
|
148
|
+
|
149
|
+
# Add a PassthroughLLM as _llm property for compatibility with Orchestrator
|
150
|
+
from mcp_agent.workflows.llm.augmented_llm import PassthroughLLM
|
98
151
|
|
99
|
-
|
152
|
+
self._llm = PassthroughLLM(name=f"{self.name}_passthrough", context=context)
|
153
|
+
|
154
|
+
# Set up the generator
|
100
155
|
if isinstance(generator, Agent):
|
101
156
|
if not llm_factory:
|
102
157
|
raise ValueError("llm_factory is required when using an Agent")
|
@@ -109,9 +164,12 @@ class EvaluatorOptimizerLLM(AugmentedLLM[MessageParamT, MessageT]):
|
|
109
164
|
|
110
165
|
self.aggregator = generator
|
111
166
|
self.instruction = (
|
112
|
-
|
113
|
-
|
114
|
-
|
167
|
+
instruction # Use provided instruction if any
|
168
|
+
or (
|
169
|
+
generator.instruction
|
170
|
+
if isinstance(generator.instruction, str)
|
171
|
+
else None
|
172
|
+
) # Fallback to generator's
|
115
173
|
)
|
116
174
|
|
117
175
|
elif isinstance(generator, AugmentedLLM):
|
@@ -119,46 +177,58 @@ class EvaluatorOptimizerLLM(AugmentedLLM[MessageParamT, MessageT]):
|
|
119
177
|
self.aggregator = generator.aggregator
|
120
178
|
self.instruction = generator.instruction
|
121
179
|
|
122
|
-
|
123
|
-
raise ValueError(f"Unsupported optimizer type: {type(generator)}")
|
124
|
-
|
125
|
-
self.history = self.generator_llm.history
|
126
|
-
|
127
|
-
# Set up the evaluator
|
180
|
+
# Set up the evaluator - evaluations should be independent, so history is always disabled
|
128
181
|
if isinstance(evaluator, AugmentedLLM):
|
129
182
|
self.evaluator_llm = evaluator
|
130
|
-
|
183
|
+
# Override evaluator's history setting
|
184
|
+
if hasattr(evaluator, "default_request_params"):
|
185
|
+
evaluator.default_request_params.use_history = False
|
131
186
|
elif isinstance(evaluator, Agent):
|
132
187
|
if not llm_factory:
|
133
188
|
raise ValueError(
|
134
189
|
"llm_factory is required when using an Agent evaluator"
|
135
190
|
)
|
136
191
|
|
137
|
-
#
|
192
|
+
# Create evaluator with history disabled
|
138
193
|
if hasattr(evaluator, "_llm") and evaluator._llm:
|
139
194
|
self.evaluator_llm = evaluator._llm
|
195
|
+
if hasattr(self.evaluator_llm, "default_request_params"):
|
196
|
+
self.evaluator_llm.default_request_params.use_history = False
|
140
197
|
else:
|
198
|
+
# Force history off in config before creating LLM
|
199
|
+
evaluator.config.use_history = False
|
141
200
|
self.evaluator_llm = llm_factory(agent=evaluator)
|
142
201
|
elif isinstance(evaluator, str):
|
143
|
-
# If a string is passed as the evaluator, we use it as the evaluation criteria
|
144
|
-
# and create an evaluator agent with that instruction
|
145
202
|
if not llm_factory:
|
146
203
|
raise ValueError(
|
147
204
|
"llm_factory is required when using a string evaluator"
|
148
205
|
)
|
149
206
|
|
150
|
-
|
151
|
-
|
207
|
+
# Create evaluator agent with history disabled
|
208
|
+
evaluator_agent = Agent(
|
209
|
+
name="Evaluator",
|
210
|
+
instruction=evaluator,
|
211
|
+
config=AgentConfig(
|
212
|
+
name="Evaluator",
|
213
|
+
instruction=evaluator,
|
214
|
+
servers=[],
|
215
|
+
use_history=False, # Force history off for evaluator
|
216
|
+
),
|
152
217
|
)
|
218
|
+
self.evaluator_llm = llm_factory(agent=evaluator_agent)
|
153
219
|
else:
|
154
220
|
raise ValueError(f"Unsupported evaluator type: {type(evaluator)}")
|
155
221
|
|
156
|
-
|
157
|
-
self.max_refinements = max_refinements
|
158
|
-
|
159
|
-
# Track iteration history
|
222
|
+
# Track iteration history (for the workflow itself)
|
160
223
|
self.refinement_history = []
|
161
224
|
|
225
|
+
# Set up workflow's default params based on generator's history setting
|
226
|
+
self.default_request_params = self._initialize_default_params({})
|
227
|
+
|
228
|
+
# Ensure evaluator's request params have history disabled
|
229
|
+
if hasattr(self.evaluator_llm, "default_request_params"):
|
230
|
+
self.evaluator_llm.default_request_params.use_history = False
|
231
|
+
|
162
232
|
async def generate(
|
163
233
|
self,
|
164
234
|
message: str | MessageParamT | List[MessageParamT],
|
@@ -171,6 +241,9 @@ class EvaluatorOptimizerLLM(AugmentedLLM[MessageParamT, MessageT]):
|
|
171
241
|
best_rating = QualityRating.POOR
|
172
242
|
self.refinement_history = []
|
173
243
|
|
244
|
+
# Get request params with proper use_history setting
|
245
|
+
params = self.get_request_params(request_params)
|
246
|
+
|
174
247
|
# Use a single AsyncExitStack for the entire method to maintain connections
|
175
248
|
async with contextlib.AsyncExitStack() as stack:
|
176
249
|
# Enter all agent contexts once at the beginning
|
@@ -180,22 +253,20 @@ class EvaluatorOptimizerLLM(AugmentedLLM[MessageParamT, MessageT]):
|
|
180
253
|
await stack.enter_async_context(self.evaluator)
|
181
254
|
|
182
255
|
# Initial generation
|
183
|
-
response = await self.generator_llm.
|
256
|
+
response = await self.generator_llm.generate_str(
|
184
257
|
message=message,
|
185
|
-
request_params=
|
258
|
+
request_params=params, # Pass params which may override use_history
|
186
259
|
)
|
187
260
|
|
188
261
|
best_response = response
|
189
262
|
|
190
263
|
while refinement_count < self.max_refinements:
|
191
|
-
logger.debug("
|
264
|
+
logger.debug("Generator result:", data=response)
|
192
265
|
|
193
266
|
# Evaluate current response
|
194
267
|
eval_prompt = self._build_eval_prompt(
|
195
268
|
original_request=str(message),
|
196
|
-
current_response=
|
197
|
-
if isinstance(response, list)
|
198
|
-
else str(response),
|
269
|
+
current_response=response, # response is already a string
|
199
270
|
iteration=refinement_count,
|
200
271
|
)
|
201
272
|
|
@@ -244,22 +315,23 @@ class EvaluatorOptimizerLLM(AugmentedLLM[MessageParamT, MessageT]):
|
|
244
315
|
# Generate refined response
|
245
316
|
refinement_prompt = self._build_refinement_prompt(
|
246
317
|
original_request=str(message),
|
247
|
-
current_response=
|
248
|
-
if isinstance(response, list)
|
249
|
-
else str(response),
|
318
|
+
current_response=response,
|
250
319
|
feedback=evaluation_result,
|
251
320
|
iteration=refinement_count,
|
321
|
+
use_history=self.generator_use_history, # Use the generator's history setting
|
252
322
|
)
|
253
323
|
|
254
|
-
|
255
|
-
response = await self.generator_llm.generate(
|
324
|
+
response = await self.generator_llm.generate_str(
|
256
325
|
message=refinement_prompt,
|
257
|
-
request_params=
|
326
|
+
request_params=params, # Pass params which may override use_history
|
258
327
|
)
|
259
328
|
|
260
329
|
refinement_count += 1
|
261
330
|
|
262
|
-
|
331
|
+
# Return the best response as a list with a single string element
|
332
|
+
# This makes it consistent with other AugmentedLLM implementations
|
333
|
+
# that return List[MessageT]
|
334
|
+
return [best_response]
|
263
335
|
|
264
336
|
async def generate_str(
|
265
337
|
self,
|
@@ -271,28 +343,8 @@ class EvaluatorOptimizerLLM(AugmentedLLM[MessageParamT, MessageT]):
|
|
271
343
|
message=message,
|
272
344
|
request_params=request_params,
|
273
345
|
)
|
274
|
-
|
275
|
-
|
276
|
-
if not isinstance(response, list):
|
277
|
-
return str(response)
|
278
|
-
|
279
|
-
# Convert all messages to strings, handling different message types
|
280
|
-
result_strings = []
|
281
|
-
for r in response:
|
282
|
-
if hasattr(r, "text"):
|
283
|
-
result_strings.append(r.text)
|
284
|
-
elif hasattr(r, "content"):
|
285
|
-
# Handle ToolUseBlock and similar
|
286
|
-
if isinstance(r.content, list):
|
287
|
-
# Typically content is a list of blocks
|
288
|
-
result_strings.extend(str(block) for block in r.content)
|
289
|
-
else:
|
290
|
-
result_strings.append(str(r.content))
|
291
|
-
else:
|
292
|
-
# Fallback to string representation
|
293
|
-
result_strings.append(str(r))
|
294
|
-
|
295
|
-
return "\n".join(result_strings)
|
346
|
+
# Since generate now returns [best_response], just return the first element
|
347
|
+
return str(response[0])
|
296
348
|
|
297
349
|
async def generate_structured(
|
298
350
|
self,
|
@@ -367,9 +419,14 @@ Be concrete and actionable in your recommendations.
|
|
367
419
|
current_response: str,
|
368
420
|
feedback: EvaluationResult,
|
369
421
|
iteration: int,
|
422
|
+
use_history: bool = None,
|
370
423
|
) -> str:
|
371
424
|
"""Build the refinement prompt for the optimizer"""
|
372
|
-
|
425
|
+
# Get the correct history setting - use param if provided, otherwise class default
|
426
|
+
if use_history is None:
|
427
|
+
use_history = (
|
428
|
+
self.generator_use_history
|
429
|
+
) # Use generator's setting as default
|
373
430
|
|
374
431
|
# Start with clear non-delimited instructions
|
375
432
|
prompt = f"""
|
@@ -391,7 +448,7 @@ Your goal is to address all feedback points while maintaining accuracy and relev
|
|
391
448
|
"""
|
392
449
|
|
393
450
|
# Only include previous response if history is not enabled
|
394
|
-
if not
|
451
|
+
if not use_history:
|
395
452
|
prompt += f"""
|
396
453
|
<fastagent:previous-response>
|
397
454
|
{current_response}
|
@@ -409,7 +466,7 @@ Your goal is to address all feedback points while maintaining accuracy and relev
|
|
409
466
|
"""
|
410
467
|
|
411
468
|
# Customize instruction based on history availability
|
412
|
-
if not
|
469
|
+
if not use_history:
|
413
470
|
prompt += """
|
414
471
|
<fastagent:instruction>
|
415
472
|
Create an improved version of the response that:
|
@@ -246,15 +246,16 @@ class AnthropicAugmentedLLM(AugmentedLLM[MessageParam, Message]):
|
|
246
246
|
style="dim green italic",
|
247
247
|
)
|
248
248
|
|
249
|
-
await self.show_assistant_message(message_text)
|
250
|
-
|
251
249
|
# Process all tool calls and collect results
|
252
250
|
tool_results = []
|
253
|
-
for content in tool_uses:
|
251
|
+
for i, content in enumerate(tool_uses):
|
254
252
|
tool_name = content.name
|
255
253
|
tool_args = content.input
|
256
254
|
tool_use_id = content.id
|
257
255
|
|
256
|
+
if i == 0: # Only show message for first tool use
|
257
|
+
await self.show_assistant_message(message_text, tool_name)
|
258
|
+
|
258
259
|
self.show_tool_call(available_tools, tool_name, tool_args)
|
259
260
|
tool_call_request = CallToolRequest(
|
260
261
|
method="tools/call",
|