fast-agent-mcp 0.3.2__py3-none-any.whl → 0.3.3__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.
- fast_agent/agents/llm_decorator.py +2 -1
- fast_agent/agents/tool_agent.py +4 -1
- fast_agent/agents/workflow/orchestrator_models.py +1 -1
- fast_agent/cli/commands/url_parser.py +3 -3
- fast_agent/cli/main.py +7 -1
- fast_agent/config.py +2 -0
- fast_agent/core/__init__.py +44 -5
- fast_agent/core/direct_decorators.py +85 -103
- fast_agent/core/error_handling.py +1 -1
- fast_agent/core/fastagent.py +153 -34
- fast_agent/core/logging/events.py +4 -9
- fast_agent/llm/prompt_utils.py +10 -4
- fast_agent/llm/provider/anthropic/llm_anthropic.py +16 -5
- fast_agent/llm/provider/bedrock/llm_bedrock.py +13 -5
- fast_agent/llm/provider/google/llm_google_native.py +13 -2
- fast_agent/llm/provider/openai/llm_openai.py +22 -13
- fast_agent/ui/rich_progress.py +8 -6
- {fast_agent_mcp-0.3.2.dist-info → fast_agent_mcp-0.3.3.dist-info}/METADATA +1 -1
- {fast_agent_mcp-0.3.2.dist-info → fast_agent_mcp-0.3.3.dist-info}/RECORD +22 -22
- {fast_agent_mcp-0.3.2.dist-info → fast_agent_mcp-0.3.3.dist-info}/WHEEL +0 -0
- {fast_agent_mcp-0.3.2.dist-info → fast_agent_mcp-0.3.3.dist-info}/entry_points.txt +0 -0
- {fast_agent_mcp-0.3.2.dist-info → fast_agent_mcp-0.3.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -189,6 +189,7 @@ class LlmDecorator(AgentProtocol):
|
|
|
189
189
|
Sequence[Union[str, PromptMessage, PromptMessageExtended]],
|
|
190
190
|
],
|
|
191
191
|
request_params: RequestParams | None = None,
|
|
192
|
+
tools: List[Tool] | None = None,
|
|
192
193
|
) -> PromptMessageExtended:
|
|
193
194
|
"""
|
|
194
195
|
Create a completion with the LLM using the provided messages.
|
|
@@ -212,7 +213,7 @@ class LlmDecorator(AgentProtocol):
|
|
|
212
213
|
multipart_messages = normalize_to_extended_list(messages)
|
|
213
214
|
|
|
214
215
|
with self._tracer.start_as_current_span(f"Agent: '{self._name}' generate"):
|
|
215
|
-
return await self.generate_impl(multipart_messages, request_params,
|
|
216
|
+
return await self.generate_impl(multipart_messages, request_params, tools)
|
|
216
217
|
|
|
217
218
|
async def generate_impl(
|
|
218
219
|
self,
|
fast_agent/agents/tool_agent.py
CHANGED
|
@@ -97,7 +97,10 @@ class ToolAgent(LlmAgent):
|
|
|
97
97
|
)
|
|
98
98
|
|
|
99
99
|
if LlmStopReason.TOOL_USE == result.stop_reason:
|
|
100
|
-
|
|
100
|
+
if self.config.use_history:
|
|
101
|
+
messages = [await self.run_tools(result)]
|
|
102
|
+
else:
|
|
103
|
+
messages.extend([result, await self.run_tools(result)])
|
|
101
104
|
else:
|
|
102
105
|
break
|
|
103
106
|
|
|
@@ -72,7 +72,7 @@ class TaskWithResult(Task):
|
|
|
72
72
|
class StepResult(BaseModel):
|
|
73
73
|
"""Result of executing a step"""
|
|
74
74
|
|
|
75
|
-
step: Step = Field(description="The step that was executed"
|
|
75
|
+
step: Step = Field(description="The step that was executed")
|
|
76
76
|
task_results: List[TaskWithResult] = Field(
|
|
77
77
|
description="Results of executing each task", default_factory=list
|
|
78
78
|
)
|
|
@@ -104,7 +104,7 @@ def generate_server_name(url: str) -> str:
|
|
|
104
104
|
|
|
105
105
|
|
|
106
106
|
def parse_server_urls(
|
|
107
|
-
urls_param: str, auth_token: str = None
|
|
107
|
+
urls_param: str, auth_token: str | None = None
|
|
108
108
|
) -> List[Tuple[str, Literal["http", "sse"], str, Dict[str, str] | None]]:
|
|
109
109
|
"""
|
|
110
110
|
Parse a comma-separated list of URLs into server configurations.
|
|
@@ -155,7 +155,7 @@ def generate_server_configs(
|
|
|
155
155
|
Returns:
|
|
156
156
|
Dictionary of server configurations
|
|
157
157
|
"""
|
|
158
|
-
server_configs = {}
|
|
158
|
+
server_configs: Dict[str, Dict[str, str | Dict[str, str]]] = {}
|
|
159
159
|
# Keep track of server name occurrences to handle collisions
|
|
160
160
|
name_counts = {}
|
|
161
161
|
|
|
@@ -178,7 +178,7 @@ def generate_server_configs(
|
|
|
178
178
|
final_name = f"{server_name}_{suffix}"
|
|
179
179
|
name_counts[server_name] += 1
|
|
180
180
|
|
|
181
|
-
config = {
|
|
181
|
+
config: Dict[str, str | Dict[str, str]] = {
|
|
182
182
|
"transport": transport_type,
|
|
183
183
|
"url": url,
|
|
184
184
|
}
|
fast_agent/cli/main.py
CHANGED
|
@@ -85,7 +85,13 @@ def main(
|
|
|
85
85
|
Use --help with any command for detailed usage information.
|
|
86
86
|
"""
|
|
87
87
|
application.verbosity = 1 if verbose else 0 if not quiet else -1
|
|
88
|
-
|
|
88
|
+
if not color:
|
|
89
|
+
# Recreate consoles without color when --no-color is provided
|
|
90
|
+
from fast_agent.ui.console import console as base_console
|
|
91
|
+
from fast_agent.ui.console import error_console as base_error_console
|
|
92
|
+
|
|
93
|
+
application.console = base_console.__class__(color_system=None)
|
|
94
|
+
application.error_console = base_error_console.__class__(color_system=None, stderr=True)
|
|
89
95
|
|
|
90
96
|
# Handle version flag
|
|
91
97
|
if version:
|
fast_agent/config.py
CHANGED
|
@@ -547,6 +547,8 @@ def get_settings(config_path: str | None = None) -> Settings:
|
|
|
547
547
|
return _settings
|
|
548
548
|
|
|
549
549
|
# Handle config path - convert string to Path if needed
|
|
550
|
+
config_file: Path | None
|
|
551
|
+
secrets_file: Path | None
|
|
550
552
|
if config_path:
|
|
551
553
|
config_file = Path(config_path)
|
|
552
554
|
# If it's a relative path and doesn't exist, try finding it
|
fast_agent/core/__init__.py
CHANGED
|
@@ -2,14 +2,19 @@
|
|
|
2
2
|
Core interfaces and decorators for fast-agent.
|
|
3
3
|
|
|
4
4
|
Public API:
|
|
5
|
-
- `Core`: The core application container (
|
|
5
|
+
- `Core`: The core application container (eagerly exported)
|
|
6
6
|
- `FastAgent`: High-level, decorator-driven application class (lazy-loaded)
|
|
7
7
|
- Decorators: `agent`, `custom`, `orchestrator`, `iterative_planner`,
|
|
8
8
|
`router`, `chain`, `parallel`, `evaluator_optimizer` (lazy-loaded)
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
+
from typing import TYPE_CHECKING as _TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
from .core_app import Core # Eager export for external applications
|
|
14
|
+
|
|
11
15
|
__all__ = [
|
|
12
16
|
"Core",
|
|
17
|
+
"AgentApp",
|
|
13
18
|
"FastAgent",
|
|
14
19
|
# Decorators
|
|
15
20
|
"agent",
|
|
@@ -25,14 +30,14 @@ __all__ = [
|
|
|
25
30
|
|
|
26
31
|
def __getattr__(name: str):
|
|
27
32
|
# Lazy imports to avoid heavy dependencies and circular imports at init time
|
|
28
|
-
if name == "Core":
|
|
29
|
-
from .core_app import Core
|
|
30
|
-
|
|
31
|
-
return Core
|
|
32
33
|
if name == "FastAgent":
|
|
33
34
|
from .fastagent import FastAgent
|
|
34
35
|
|
|
35
36
|
return FastAgent
|
|
37
|
+
if name == "AgentApp":
|
|
38
|
+
from .agent_app import AgentApp
|
|
39
|
+
|
|
40
|
+
return AgentApp
|
|
36
41
|
|
|
37
42
|
# Decorators from direct_decorators
|
|
38
43
|
if name in {
|
|
@@ -50,3 +55,37 @@ def __getattr__(name: str):
|
|
|
50
55
|
return getattr(_dd, name)
|
|
51
56
|
|
|
52
57
|
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Help static analyzers/IDEs resolve symbols and signatures without importing at runtime.
|
|
61
|
+
if _TYPE_CHECKING: # pragma: no cover - typing aid only
|
|
62
|
+
from .agent_app import AgentApp as AgentApp # noqa: F401
|
|
63
|
+
from .direct_decorators import (
|
|
64
|
+
agent as agent,
|
|
65
|
+
) # noqa: F401
|
|
66
|
+
from .direct_decorators import (
|
|
67
|
+
chain as chain,
|
|
68
|
+
)
|
|
69
|
+
from .direct_decorators import (
|
|
70
|
+
custom as custom,
|
|
71
|
+
)
|
|
72
|
+
from .direct_decorators import (
|
|
73
|
+
evaluator_optimizer as evaluator_optimizer,
|
|
74
|
+
)
|
|
75
|
+
from .direct_decorators import (
|
|
76
|
+
iterative_planner as iterative_planner,
|
|
77
|
+
)
|
|
78
|
+
from .direct_decorators import (
|
|
79
|
+
orchestrator as orchestrator,
|
|
80
|
+
)
|
|
81
|
+
from .direct_decorators import (
|
|
82
|
+
parallel as parallel,
|
|
83
|
+
)
|
|
84
|
+
from .direct_decorators import (
|
|
85
|
+
router as router,
|
|
86
|
+
)
|
|
87
|
+
from .fastagent import FastAgent as FastAgent # noqa: F401
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def __dir__(): # pragma: no cover - developer experience aid
|
|
91
|
+
return sorted(__all__)
|
|
@@ -186,7 +186,7 @@ def _decorator_impl(
|
|
|
186
186
|
resources: Optional[Dict[str, List[str]]] = None,
|
|
187
187
|
prompts: Optional[Dict[str, List[str]]] = None,
|
|
188
188
|
**extra_kwargs,
|
|
189
|
-
) -> Callable[[AgentCallable[P, R]],
|
|
189
|
+
) -> Callable[[AgentCallable[P, R]], AgentCallable[P, R]]:
|
|
190
190
|
"""
|
|
191
191
|
Core implementation for agent decorators with common behavior and type safety.
|
|
192
192
|
|
|
@@ -203,7 +203,7 @@ def _decorator_impl(
|
|
|
203
203
|
**extra_kwargs: Additional agent/workflow-specific parameters
|
|
204
204
|
"""
|
|
205
205
|
|
|
206
|
-
def decorator(func: AgentCallable[P, R]) ->
|
|
206
|
+
def decorator(func: AgentCallable[P, R]) -> AgentCallable[P, R]:
|
|
207
207
|
@wraps(func)
|
|
208
208
|
def wrapper(*args: P.args, **kwargs: P.kwargs) -> Awaitable[R]:
|
|
209
209
|
# Call the original function
|
|
@@ -249,7 +249,7 @@ def _decorator_impl(
|
|
|
249
249
|
for key, value in extra_kwargs.items():
|
|
250
250
|
setattr(wrapper, f"_{key}", value)
|
|
251
251
|
|
|
252
|
-
return cast("
|
|
252
|
+
return cast("AgentCallable[P, R]", wrapper)
|
|
253
253
|
|
|
254
254
|
return decorator
|
|
255
255
|
|
|
@@ -271,7 +271,7 @@ def agent(
|
|
|
271
271
|
default: bool = False,
|
|
272
272
|
elicitation_handler: Optional[ElicitationFnT] = None,
|
|
273
273
|
api_key: str | None = None,
|
|
274
|
-
) -> Callable[[AgentCallable[P, R]],
|
|
274
|
+
) -> Callable[[AgentCallable[P, R]], AgentCallable[P, R]]:
|
|
275
275
|
"""
|
|
276
276
|
Decorator to create and register a standard agent with type-safe signature.
|
|
277
277
|
|
|
@@ -336,7 +336,7 @@ def custom(
|
|
|
336
336
|
default: bool = False,
|
|
337
337
|
elicitation_handler: Optional[ElicitationFnT] = None,
|
|
338
338
|
api_key: str | None = None,
|
|
339
|
-
) -> Callable[[AgentCallable[P, R]],
|
|
339
|
+
) -> Callable[[AgentCallable[P, R]], AgentCallable[P, R]]:
|
|
340
340
|
"""
|
|
341
341
|
Decorator to create and register a standard agent with type-safe signature.
|
|
342
342
|
|
|
@@ -400,7 +400,7 @@ def orchestrator(
|
|
|
400
400
|
plan_iterations: int = 5,
|
|
401
401
|
default: bool = False,
|
|
402
402
|
api_key: str | None = None,
|
|
403
|
-
) -> Callable[[AgentCallable[P, R]],
|
|
403
|
+
) -> Callable[[AgentCallable[P, R]], AgentCallable[P, R]]:
|
|
404
404
|
"""
|
|
405
405
|
Decorator to create and register an orchestrator agent with type-safe signature.
|
|
406
406
|
|
|
@@ -423,24 +423,21 @@ def orchestrator(
|
|
|
423
423
|
# Create final request params with plan_iterations
|
|
424
424
|
resolved_instruction = _resolve_instruction(instruction)
|
|
425
425
|
|
|
426
|
-
return
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
default=default,
|
|
442
|
-
api_key=api_key,
|
|
443
|
-
),
|
|
426
|
+
return _decorator_impl(
|
|
427
|
+
self,
|
|
428
|
+
AgentType.ORCHESTRATOR,
|
|
429
|
+
name=name,
|
|
430
|
+
instruction=resolved_instruction,
|
|
431
|
+
servers=[], # Orchestrators don't connect to servers directly
|
|
432
|
+
model=model,
|
|
433
|
+
use_history=use_history,
|
|
434
|
+
request_params=request_params,
|
|
435
|
+
human_input=human_input,
|
|
436
|
+
child_agents=agents,
|
|
437
|
+
plan_type=plan_type,
|
|
438
|
+
plan_iterations=plan_iterations,
|
|
439
|
+
default=default,
|
|
440
|
+
api_key=api_key,
|
|
444
441
|
)
|
|
445
442
|
|
|
446
443
|
|
|
@@ -455,7 +452,7 @@ def iterative_planner(
|
|
|
455
452
|
plan_iterations: int = -1,
|
|
456
453
|
default: bool = False,
|
|
457
454
|
api_key: str | None = None,
|
|
458
|
-
) -> Callable[[AgentCallable[P, R]],
|
|
455
|
+
) -> Callable[[AgentCallable[P, R]], AgentCallable[P, R]]:
|
|
459
456
|
"""
|
|
460
457
|
Decorator to create and register an orchestrator agent with type-safe signature.
|
|
461
458
|
|
|
@@ -478,22 +475,19 @@ def iterative_planner(
|
|
|
478
475
|
# Create final request params with plan_iterations
|
|
479
476
|
resolved_instruction = _resolve_instruction(instruction)
|
|
480
477
|
|
|
481
|
-
return
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
default=default,
|
|
495
|
-
api_key=api_key,
|
|
496
|
-
),
|
|
478
|
+
return _decorator_impl(
|
|
479
|
+
self,
|
|
480
|
+
AgentType.ITERATIVE_PLANNER,
|
|
481
|
+
name=name,
|
|
482
|
+
instruction=resolved_instruction,
|
|
483
|
+
servers=[], # Orchestrators don't connect to servers directly
|
|
484
|
+
model=model,
|
|
485
|
+
use_history=False,
|
|
486
|
+
request_params=request_params,
|
|
487
|
+
child_agents=agents,
|
|
488
|
+
plan_iterations=plan_iterations,
|
|
489
|
+
default=default,
|
|
490
|
+
api_key=api_key,
|
|
497
491
|
)
|
|
498
492
|
|
|
499
493
|
|
|
@@ -516,7 +510,7 @@ def router(
|
|
|
516
510
|
ElicitationFnT
|
|
517
511
|
] = None, ## exclude from docs, decide whether allowable
|
|
518
512
|
api_key: str | None = None,
|
|
519
|
-
) -> Callable[[AgentCallable[P, R]],
|
|
513
|
+
) -> Callable[[AgentCallable[P, R]], AgentCallable[P, R]]:
|
|
520
514
|
"""
|
|
521
515
|
Decorator to create and register a router agent with type-safe signature.
|
|
522
516
|
|
|
@@ -536,26 +530,23 @@ def router(
|
|
|
536
530
|
"""
|
|
537
531
|
resolved_instruction = _resolve_instruction(instruction or ROUTING_SYSTEM_INSTRUCTION)
|
|
538
532
|
|
|
539
|
-
return
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
prompts=prompts,
|
|
557
|
-
resources=resources,
|
|
558
|
-
),
|
|
533
|
+
return _decorator_impl(
|
|
534
|
+
self,
|
|
535
|
+
AgentType.ROUTER,
|
|
536
|
+
name=name,
|
|
537
|
+
instruction=resolved_instruction,
|
|
538
|
+
servers=servers,
|
|
539
|
+
model=model,
|
|
540
|
+
use_history=use_history,
|
|
541
|
+
request_params=request_params,
|
|
542
|
+
human_input=human_input,
|
|
543
|
+
default=default,
|
|
544
|
+
router_agents=agents,
|
|
545
|
+
elicitation_handler=elicitation_handler,
|
|
546
|
+
api_key=api_key,
|
|
547
|
+
tools=tools,
|
|
548
|
+
prompts=prompts,
|
|
549
|
+
resources=resources,
|
|
559
550
|
)
|
|
560
551
|
|
|
561
552
|
|
|
@@ -567,7 +558,7 @@ def chain(
|
|
|
567
558
|
instruction: Optional[str | Path | AnyUrl] = None,
|
|
568
559
|
cumulative: bool = False,
|
|
569
560
|
default: bool = False,
|
|
570
|
-
) -> Callable[[AgentCallable[P, R]],
|
|
561
|
+
) -> Callable[[AgentCallable[P, R]], AgentCallable[P, R]]:
|
|
571
562
|
"""
|
|
572
563
|
Decorator to create and register a chain agent with type-safe signature.
|
|
573
564
|
|
|
@@ -593,17 +584,14 @@ def chain(
|
|
|
593
584
|
"""
|
|
594
585
|
resolved_instruction = _resolve_instruction(instruction or default_instruction)
|
|
595
586
|
|
|
596
|
-
return
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
cumulative=cumulative,
|
|
605
|
-
default=default,
|
|
606
|
-
),
|
|
587
|
+
return _decorator_impl(
|
|
588
|
+
self,
|
|
589
|
+
AgentType.CHAIN,
|
|
590
|
+
name=name,
|
|
591
|
+
instruction=resolved_instruction,
|
|
592
|
+
sequence=sequence,
|
|
593
|
+
cumulative=cumulative,
|
|
594
|
+
default=default,
|
|
607
595
|
)
|
|
608
596
|
|
|
609
597
|
|
|
@@ -616,7 +604,7 @@ def parallel(
|
|
|
616
604
|
instruction: Optional[str | Path | AnyUrl] = None,
|
|
617
605
|
include_request: bool = True,
|
|
618
606
|
default: bool = False,
|
|
619
|
-
) -> Callable[[AgentCallable[P, R]],
|
|
607
|
+
) -> Callable[[AgentCallable[P, R]], AgentCallable[P, R]]:
|
|
620
608
|
"""
|
|
621
609
|
Decorator to create and register a parallel agent with type-safe signature.
|
|
622
610
|
|
|
@@ -637,19 +625,16 @@ def parallel(
|
|
|
637
625
|
"""
|
|
638
626
|
resolved_instruction = _resolve_instruction(instruction or default_instruction)
|
|
639
627
|
|
|
640
|
-
return
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
include_request=include_request,
|
|
651
|
-
default=default,
|
|
652
|
-
),
|
|
628
|
+
return _decorator_impl(
|
|
629
|
+
self,
|
|
630
|
+
AgentType.PARALLEL,
|
|
631
|
+
name=name,
|
|
632
|
+
instruction=resolved_instruction,
|
|
633
|
+
servers=[], # Parallel agents don't connect to servers directly
|
|
634
|
+
fan_in=fan_in,
|
|
635
|
+
fan_out=fan_out,
|
|
636
|
+
include_request=include_request,
|
|
637
|
+
default=default,
|
|
653
638
|
)
|
|
654
639
|
|
|
655
640
|
|
|
@@ -663,7 +648,7 @@ def evaluator_optimizer(
|
|
|
663
648
|
min_rating: str = "GOOD",
|
|
664
649
|
max_refinements: int = 3,
|
|
665
650
|
default: bool = False,
|
|
666
|
-
) -> Callable[[AgentCallable[P, R]],
|
|
651
|
+
) -> Callable[[AgentCallable[P, R]], AgentCallable[P, R]]:
|
|
667
652
|
"""
|
|
668
653
|
Decorator to create and register an evaluator-optimizer agent with type-safe signature.
|
|
669
654
|
|
|
@@ -686,18 +671,15 @@ def evaluator_optimizer(
|
|
|
686
671
|
"""
|
|
687
672
|
resolved_instruction = _resolve_instruction(instruction or default_instruction)
|
|
688
673
|
|
|
689
|
-
return
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
max_refinements=max_refinements,
|
|
701
|
-
default=default,
|
|
702
|
-
),
|
|
674
|
+
return _decorator_impl(
|
|
675
|
+
self,
|
|
676
|
+
AgentType.EVALUATOR_OPTIMIZER,
|
|
677
|
+
name=name,
|
|
678
|
+
instruction=resolved_instruction,
|
|
679
|
+
servers=[], # Evaluator-optimizer doesn't connect to servers directly
|
|
680
|
+
generator=generator,
|
|
681
|
+
evaluator=evaluator,
|
|
682
|
+
min_rating=min_rating,
|
|
683
|
+
max_refinements=max_refinements,
|
|
684
|
+
default=default,
|
|
703
685
|
)
|
|
@@ -5,7 +5,7 @@ Error handling utilities for agent operations.
|
|
|
5
5
|
from rich import print
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
def handle_error(e: Exception, error_type: str, suggestion: str = None) -> None:
|
|
8
|
+
def handle_error(e: Exception, error_type: str, suggestion: str | None = None) -> None:
|
|
9
9
|
"""
|
|
10
10
|
Handle errors with consistent formatting and messaging.
|
|
11
11
|
|
fast_agent/core/fastagent.py
CHANGED
|
@@ -10,7 +10,19 @@ import sys
|
|
|
10
10
|
from contextlib import asynccontextmanager
|
|
11
11
|
from importlib.metadata import version as get_version
|
|
12
12
|
from pathlib import Path
|
|
13
|
-
from typing import
|
|
13
|
+
from typing import (
|
|
14
|
+
TYPE_CHECKING,
|
|
15
|
+
Any,
|
|
16
|
+
AsyncIterator,
|
|
17
|
+
Awaitable,
|
|
18
|
+
Callable,
|
|
19
|
+
Dict,
|
|
20
|
+
List,
|
|
21
|
+
Literal,
|
|
22
|
+
Optional,
|
|
23
|
+
ParamSpec,
|
|
24
|
+
TypeVar,
|
|
25
|
+
)
|
|
14
26
|
|
|
15
27
|
import yaml
|
|
16
28
|
from opentelemetry import trace
|
|
@@ -67,6 +79,9 @@ from fast_agent.mcp.prompts.prompt_load import load_prompt_multipart
|
|
|
67
79
|
from fast_agent.ui.usage_display import display_usage_report
|
|
68
80
|
|
|
69
81
|
if TYPE_CHECKING:
|
|
82
|
+
from mcp.client.session import ElicitationFnT
|
|
83
|
+
from pydantic import AnyUrl
|
|
84
|
+
|
|
70
85
|
from fast_agent.interfaces import AgentProtocol
|
|
71
86
|
from fast_agent.types import PromptMessageExtended
|
|
72
87
|
|
|
@@ -250,32 +265,137 @@ class FastAgent:
|
|
|
250
265
|
"""Access the application context"""
|
|
251
266
|
return self.app.context
|
|
252
267
|
|
|
253
|
-
# Decorator methods with
|
|
268
|
+
# Decorator methods with precise signatures for IDE completion
|
|
254
269
|
# Provide annotations so IDEs can discover these attributes on instances
|
|
255
270
|
if TYPE_CHECKING: # pragma: no cover - typing aid only
|
|
256
|
-
from
|
|
257
|
-
|
|
258
|
-
from fast_agent.
|
|
259
|
-
DecoratedAgentProtocol,
|
|
260
|
-
DecoratedChainProtocol,
|
|
261
|
-
DecoratedEvaluatorOptimizerProtocol,
|
|
262
|
-
DecoratedOrchestratorProtocol,
|
|
263
|
-
DecoratedParallelProtocol,
|
|
264
|
-
DecoratedRouterProtocol,
|
|
265
|
-
)
|
|
271
|
+
from pathlib import Path
|
|
272
|
+
|
|
273
|
+
from fast_agent.types import RequestParams
|
|
266
274
|
|
|
267
275
|
P = ParamSpec("P")
|
|
268
276
|
R = TypeVar("R")
|
|
269
277
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
278
|
+
def agent(
|
|
279
|
+
self,
|
|
280
|
+
name: str = "default",
|
|
281
|
+
instruction_or_kwarg: Optional[str | Path | AnyUrl] = None,
|
|
282
|
+
*,
|
|
283
|
+
instruction: str | Path | AnyUrl = "You are a helpful agent.",
|
|
284
|
+
servers: List[str] = [],
|
|
285
|
+
tools: Optional[Dict[str, List[str]]] = None,
|
|
286
|
+
resources: Optional[Dict[str, List[str]]] = None,
|
|
287
|
+
prompts: Optional[Dict[str, List[str]]] = None,
|
|
288
|
+
model: Optional[str] = None,
|
|
289
|
+
use_history: bool = True,
|
|
290
|
+
request_params: RequestParams | None = None,
|
|
291
|
+
human_input: bool = False,
|
|
292
|
+
default: bool = False,
|
|
293
|
+
elicitation_handler: Optional[ElicitationFnT] = None,
|
|
294
|
+
api_key: str | None = None,
|
|
295
|
+
) -> Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[R]]]: ...
|
|
296
|
+
|
|
297
|
+
def custom(
|
|
298
|
+
self,
|
|
299
|
+
cls,
|
|
300
|
+
name: str = "default",
|
|
301
|
+
instruction_or_kwarg: Optional[str | Path | AnyUrl] = None,
|
|
302
|
+
*,
|
|
303
|
+
instruction: str | Path | AnyUrl = "You are a helpful agent.",
|
|
304
|
+
servers: List[str] = [],
|
|
305
|
+
tools: Optional[Dict[str, List[str]]] = None,
|
|
306
|
+
resources: Optional[Dict[str, List[str]]] = None,
|
|
307
|
+
prompts: Optional[Dict[str, List[str]]] = None,
|
|
308
|
+
model: Optional[str] = None,
|
|
309
|
+
use_history: bool = True,
|
|
310
|
+
request_params: RequestParams | None = None,
|
|
311
|
+
human_input: bool = False,
|
|
312
|
+
default: bool = False,
|
|
313
|
+
elicitation_handler: Optional[ElicitationFnT] = None,
|
|
314
|
+
api_key: str | None = None,
|
|
315
|
+
) -> Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[R]]]: ...
|
|
316
|
+
|
|
317
|
+
def orchestrator(
|
|
318
|
+
self,
|
|
319
|
+
name: str,
|
|
320
|
+
*,
|
|
321
|
+
agents: List[str],
|
|
322
|
+
instruction: str
|
|
323
|
+
| Path
|
|
324
|
+
| AnyUrl = "You are an expert planner. Given an objective task and a list of Agents\n(which are collections of capabilities), your job is to break down the objective\ninto a series of steps, which can be performed by these agents.\n",
|
|
325
|
+
model: Optional[str] = None,
|
|
326
|
+
request_params: RequestParams | None = None,
|
|
327
|
+
use_history: bool = False,
|
|
328
|
+
human_input: bool = False,
|
|
329
|
+
plan_type: Literal["full", "iterative"] = "full",
|
|
330
|
+
plan_iterations: int = 5,
|
|
331
|
+
default: bool = False,
|
|
332
|
+
api_key: str | None = None,
|
|
333
|
+
) -> Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[R]]]: ...
|
|
334
|
+
|
|
335
|
+
def iterative_planner(
|
|
336
|
+
self,
|
|
337
|
+
name: str,
|
|
338
|
+
*,
|
|
339
|
+
agents: List[str],
|
|
340
|
+
instruction: str | Path | AnyUrl = "You are an expert planner. Plan iteratively.",
|
|
341
|
+
model: Optional[str] = None,
|
|
342
|
+
request_params: RequestParams | None = None,
|
|
343
|
+
plan_iterations: int = -1,
|
|
344
|
+
default: bool = False,
|
|
345
|
+
api_key: str | None = None,
|
|
346
|
+
) -> Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[R]]]: ...
|
|
347
|
+
|
|
348
|
+
def router(
|
|
349
|
+
self,
|
|
350
|
+
name: str,
|
|
351
|
+
*,
|
|
352
|
+
agents: List[str],
|
|
353
|
+
instruction: Optional[str | Path | AnyUrl] = None,
|
|
354
|
+
servers: List[str] = [],
|
|
355
|
+
tools: Optional[Dict[str, List[str]]] = None,
|
|
356
|
+
resources: Optional[Dict[str, List[str]]] = None,
|
|
357
|
+
prompts: Optional[Dict[str, List[str]]] = None,
|
|
358
|
+
model: Optional[str] = None,
|
|
359
|
+
use_history: bool = False,
|
|
360
|
+
request_params: RequestParams | None = None,
|
|
361
|
+
human_input: bool = False,
|
|
362
|
+
default: bool = False,
|
|
363
|
+
elicitation_handler: Optional[ElicitationFnT] = None,
|
|
364
|
+
api_key: str | None = None,
|
|
365
|
+
) -> Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[R]]]: ...
|
|
366
|
+
|
|
367
|
+
def chain(
|
|
368
|
+
self,
|
|
369
|
+
name: str,
|
|
370
|
+
*,
|
|
371
|
+
sequence: List[str],
|
|
372
|
+
instruction: Optional[str | Path | AnyUrl] = None,
|
|
373
|
+
cumulative: bool = False,
|
|
374
|
+
default: bool = False,
|
|
375
|
+
) -> Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[R]]]: ...
|
|
376
|
+
|
|
377
|
+
def parallel(
|
|
378
|
+
self,
|
|
379
|
+
name: str,
|
|
380
|
+
*,
|
|
381
|
+
fan_out: List[str],
|
|
382
|
+
fan_in: str | None = None,
|
|
383
|
+
instruction: Optional[str | Path | AnyUrl] = None,
|
|
384
|
+
include_request: bool = True,
|
|
385
|
+
default: bool = False,
|
|
386
|
+
) -> Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[R]]]: ...
|
|
387
|
+
|
|
388
|
+
def evaluator_optimizer(
|
|
389
|
+
self,
|
|
390
|
+
name: str,
|
|
391
|
+
*,
|
|
392
|
+
generator: str,
|
|
393
|
+
evaluator: str,
|
|
394
|
+
instruction: Optional[str | Path | AnyUrl] = None,
|
|
395
|
+
min_rating: str = "GOOD",
|
|
396
|
+
max_refinements: int = 3,
|
|
397
|
+
default: bool = False,
|
|
398
|
+
) -> Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[R]]]: ...
|
|
279
399
|
|
|
280
400
|
# Runtime bindings (actual implementations)
|
|
281
401
|
agent = agent_decorator
|
|
@@ -288,7 +408,7 @@ class FastAgent:
|
|
|
288
408
|
evaluator_optimizer = evaluator_optimizer_decorator
|
|
289
409
|
|
|
290
410
|
@asynccontextmanager
|
|
291
|
-
async def run(self):
|
|
411
|
+
async def run(self) -> AsyncIterator["AgentApp"]:
|
|
292
412
|
"""
|
|
293
413
|
Context manager for running the application.
|
|
294
414
|
Initializes all registered agents.
|
|
@@ -308,15 +428,14 @@ class FastAgent:
|
|
|
308
428
|
try:
|
|
309
429
|
async with self.app.run():
|
|
310
430
|
# Apply quiet mode if requested
|
|
311
|
-
if
|
|
312
|
-
|
|
313
|
-
and
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
self.app.context.config.logger.show_tools = False
|
|
431
|
+
if quiet_mode:
|
|
432
|
+
cfg = self.app.context.config
|
|
433
|
+
if cfg is not None and cfg.logger is not None:
|
|
434
|
+
# Update our app's config directly
|
|
435
|
+
cfg_logger = cfg.logger
|
|
436
|
+
cfg_logger.progress_display = False
|
|
437
|
+
cfg_logger.show_chat = False
|
|
438
|
+
cfg_logger.show_tools = False
|
|
320
439
|
|
|
321
440
|
# Directly disable the progress display singleton
|
|
322
441
|
from fast_agent.ui.progress_display import progress_display
|
|
@@ -437,12 +556,12 @@ class FastAgent:
|
|
|
437
556
|
try:
|
|
438
557
|
# Get response from the agent
|
|
439
558
|
agent = active_agents[agent_name]
|
|
440
|
-
|
|
559
|
+
prompt_result = await agent.generate(prompt)
|
|
441
560
|
|
|
442
561
|
# In quiet mode, just print the raw response
|
|
443
562
|
# The chat display should already be turned off by the configuration
|
|
444
563
|
if self.args.quiet:
|
|
445
|
-
print(f"{
|
|
564
|
+
print(f"{prompt_result.last_text()}")
|
|
446
565
|
|
|
447
566
|
raise SystemExit(0)
|
|
448
567
|
except Exception as e:
|
|
@@ -590,7 +709,7 @@ class FastAgent:
|
|
|
590
709
|
original_args.quiet if original_args and hasattr(original_args, "quiet") else False
|
|
591
710
|
)
|
|
592
711
|
self.args.model = None
|
|
593
|
-
if hasattr(original_args, "model"):
|
|
712
|
+
if original_args is not None and hasattr(original_args, "model"):
|
|
594
713
|
self.args.model = original_args.model
|
|
595
714
|
|
|
596
715
|
# Run the application, which will detect the server flag and start server mode
|
|
@@ -5,12 +5,7 @@ Events and event filters for the logger module for the MCP Agent
|
|
|
5
5
|
import logging
|
|
6
6
|
import random
|
|
7
7
|
from datetime import datetime
|
|
8
|
-
from typing import
|
|
9
|
-
Any,
|
|
10
|
-
Dict,
|
|
11
|
-
Literal,
|
|
12
|
-
Set,
|
|
13
|
-
)
|
|
8
|
+
from typing import Any, Dict, Literal
|
|
14
9
|
|
|
15
10
|
from pydantic import BaseModel, ConfigDict, Field
|
|
16
11
|
|
|
@@ -64,9 +59,9 @@ class EventFilter(BaseModel):
|
|
|
64
59
|
- a minimum severity level (DEBUG < INFO < WARNING < ERROR)
|
|
65
60
|
"""
|
|
66
61
|
|
|
67
|
-
types:
|
|
68
|
-
names:
|
|
69
|
-
namespaces:
|
|
62
|
+
types: set[EventType] = Field(default_factory=set)
|
|
63
|
+
names: set[str] = Field(default_factory=set)
|
|
64
|
+
namespaces: set[str] = Field(default_factory=set)
|
|
70
65
|
min_level: EventType | None = "debug"
|
|
71
66
|
|
|
72
67
|
def matches(self, event: Event) -> bool:
|
fast_agent/llm/prompt_utils.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
XML formatting utilities for consistent prompt engineering across components.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from typing import Dict, List, Optional,
|
|
5
|
+
from typing import Dict, List, Optional, TypedDict
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def format_xml_tag(
|
|
@@ -100,10 +100,16 @@ def format_server_info(
|
|
|
100
100
|
return format_fastagent_tag("server", f"\n{server_content}\n", {"name": server_name})
|
|
101
101
|
|
|
102
102
|
|
|
103
|
+
class ServerInfo(TypedDict, total=False):
|
|
104
|
+
name: str
|
|
105
|
+
description: str
|
|
106
|
+
tools: List[Dict[str, str]]
|
|
107
|
+
|
|
108
|
+
|
|
103
109
|
def format_agent_info(
|
|
104
110
|
agent_name: str,
|
|
105
111
|
description: Optional[str] = None,
|
|
106
|
-
servers: Optional[List[
|
|
112
|
+
servers: Optional[List[ServerInfo]] = None,
|
|
107
113
|
) -> str:
|
|
108
114
|
"""
|
|
109
115
|
Format agent information consistently across router and orchestrator modules.
|
|
@@ -133,8 +139,8 @@ def format_agent_info(
|
|
|
133
139
|
server_tags = []
|
|
134
140
|
for server in servers:
|
|
135
141
|
server_name = server.get("name", "")
|
|
136
|
-
server_desc = server.get("description"
|
|
137
|
-
server_tools = server.get("tools"
|
|
142
|
+
server_desc = server.get("description")
|
|
143
|
+
server_tools = server.get("tools")
|
|
138
144
|
server_tag = format_server_info(server_name, server_desc, server_tools)
|
|
139
145
|
server_tags.append(server_tag)
|
|
140
146
|
|
|
@@ -291,6 +291,7 @@ class AnthropicLLM(FastAgentLLM[MessageParam, Message]):
|
|
|
291
291
|
request_params: RequestParams | None = None,
|
|
292
292
|
structured_model: Type[ModelT] | None = None,
|
|
293
293
|
tools: List[Tool] | None = None,
|
|
294
|
+
pre_messages: List[MessageParam] | None = None,
|
|
294
295
|
) -> PromptMessageExtended:
|
|
295
296
|
"""
|
|
296
297
|
Process a query using an LLM and available tools.
|
|
@@ -304,7 +305,7 @@ class AnthropicLLM(FastAgentLLM[MessageParam, Message]):
|
|
|
304
305
|
|
|
305
306
|
try:
|
|
306
307
|
anthropic = AsyncAnthropic(api_key=api_key, base_url=base_url)
|
|
307
|
-
messages: List[MessageParam] = []
|
|
308
|
+
messages: List[MessageParam] = list(pre_messages) if pre_messages else []
|
|
308
309
|
params = self.get_request_params(request_params)
|
|
309
310
|
except AuthenticationError as e:
|
|
310
311
|
raise ProviderKeyError(
|
|
@@ -312,7 +313,7 @@ class AnthropicLLM(FastAgentLLM[MessageParam, Message]):
|
|
|
312
313
|
"The configured Anthropic API key was rejected.\nPlease check that your API key is valid and not expired.",
|
|
313
314
|
) from e
|
|
314
315
|
|
|
315
|
-
# Always include prompt messages, but only include conversation history
|
|
316
|
+
# Always include prompt messages, but only include conversation history if enabled
|
|
316
317
|
messages.extend(self.history.get(include_completion_history=params.use_history))
|
|
317
318
|
messages.append(message_param) # message_param is the current user turn
|
|
318
319
|
|
|
@@ -470,6 +471,9 @@ class AnthropicLLM(FastAgentLLM[MessageParam, Message]):
|
|
|
470
471
|
tools: List[Tool] | None = None,
|
|
471
472
|
is_template: bool = False,
|
|
472
473
|
) -> PromptMessageExtended:
|
|
474
|
+
# Effective params for this turn
|
|
475
|
+
params = self.get_request_params(request_params)
|
|
476
|
+
|
|
473
477
|
# Check the last message role
|
|
474
478
|
last_message = multipart_messages[-1]
|
|
475
479
|
|
|
@@ -477,7 +481,7 @@ class AnthropicLLM(FastAgentLLM[MessageParam, Message]):
|
|
|
477
481
|
messages_to_add = (
|
|
478
482
|
multipart_messages[:-1] if last_message.role == "user" else multipart_messages
|
|
479
483
|
)
|
|
480
|
-
converted = []
|
|
484
|
+
converted: List[MessageParam] = []
|
|
481
485
|
|
|
482
486
|
# Get cache mode configuration
|
|
483
487
|
cache_mode = self._get_cache_mode()
|
|
@@ -499,12 +503,19 @@ class AnthropicLLM(FastAgentLLM[MessageParam, Message]):
|
|
|
499
503
|
|
|
500
504
|
converted.append(anthropic_msg)
|
|
501
505
|
|
|
502
|
-
|
|
506
|
+
# Persist prior only when history is enabled; otherwise inline for this call
|
|
507
|
+
pre_messages: List[MessageParam] | None = None
|
|
508
|
+
if params.use_history:
|
|
509
|
+
self.history.extend(converted, is_prompt=is_template)
|
|
510
|
+
else:
|
|
511
|
+
pre_messages = converted
|
|
503
512
|
|
|
504
513
|
if last_message.role == "user":
|
|
505
514
|
logger.debug("Last message in prompt is from user, generating assistant response")
|
|
506
515
|
message_param = AnthropicConverter.convert_to_anthropic(last_message)
|
|
507
|
-
return await self._anthropic_completion(
|
|
516
|
+
return await self._anthropic_completion(
|
|
517
|
+
message_param, request_params, tools=tools, pre_messages=pre_messages
|
|
518
|
+
)
|
|
508
519
|
else:
|
|
509
520
|
# For assistant messages: Return the last message content as text
|
|
510
521
|
logger.debug("Last message in prompt is from assistant, returning it directly")
|
|
@@ -1192,6 +1192,7 @@ class BedrockLLM(FastAgentLLM[BedrockMessageParam, BedrockMessage]):
|
|
|
1192
1192
|
message_param: BedrockMessageParam,
|
|
1193
1193
|
request_params: RequestParams | None = None,
|
|
1194
1194
|
tools: List[Tool] | None = None,
|
|
1195
|
+
pre_messages: List[BedrockMessageParam] | None = None,
|
|
1195
1196
|
) -> PromptMessageExtended:
|
|
1196
1197
|
"""
|
|
1197
1198
|
Process a query using Bedrock and available tools.
|
|
@@ -1200,7 +1201,7 @@ class BedrockLLM(FastAgentLLM[BedrockMessageParam, BedrockMessage]):
|
|
|
1200
1201
|
client = self._get_bedrock_runtime_client()
|
|
1201
1202
|
|
|
1202
1203
|
try:
|
|
1203
|
-
messages: List[BedrockMessageParam] = []
|
|
1204
|
+
messages: List[BedrockMessageParam] = list(pre_messages) if pre_messages else []
|
|
1204
1205
|
params = self.get_request_params(request_params)
|
|
1205
1206
|
except (ClientError, BotoCoreError) as e:
|
|
1206
1207
|
error_msg = str(e)
|
|
@@ -1869,8 +1870,13 @@ class BedrockLLM(FastAgentLLM[BedrockMessageParam, BedrockMessage]):
|
|
|
1869
1870
|
bedrock_msg = self._convert_multipart_to_bedrock_message(msg)
|
|
1870
1871
|
converted.append(bedrock_msg)
|
|
1871
1872
|
|
|
1872
|
-
#
|
|
1873
|
-
self.
|
|
1873
|
+
# Only persist prior messages when history is enabled; otherwise inline for this call
|
|
1874
|
+
params = self.get_request_params(request_params)
|
|
1875
|
+
pre_messages: List[BedrockMessageParam] | None = None
|
|
1876
|
+
if params.use_history:
|
|
1877
|
+
self.history.extend(converted, is_prompt=is_template)
|
|
1878
|
+
else:
|
|
1879
|
+
pre_messages = converted
|
|
1874
1880
|
|
|
1875
1881
|
if last_message.role == "assistant":
|
|
1876
1882
|
# For assistant messages: Return the last message (no completion needed)
|
|
@@ -1884,8 +1890,10 @@ class BedrockLLM(FastAgentLLM[BedrockMessageParam, BedrockMessage]):
|
|
|
1884
1890
|
# Convert the last user message to Bedrock message parameter format
|
|
1885
1891
|
message_param = self._convert_multipart_to_bedrock_message(last_message)
|
|
1886
1892
|
|
|
1887
|
-
# Call the
|
|
1888
|
-
return await self._bedrock_completion(
|
|
1893
|
+
# Call the completion method with optional pre_messages for no-history mode
|
|
1894
|
+
return await self._bedrock_completion(
|
|
1895
|
+
message_param, request_params, tools, pre_messages=pre_messages
|
|
1896
|
+
)
|
|
1889
1897
|
|
|
1890
1898
|
def _generate_simplified_schema(self, model: Type[ModelT]) -> str:
|
|
1891
1899
|
"""Generates a simplified, human-readable schema with inline enum constraints."""
|
|
@@ -280,9 +280,15 @@ class GoogleNativeLLM(FastAgentLLM[types.Content, types.Content]):
|
|
|
280
280
|
)
|
|
281
281
|
|
|
282
282
|
if messages_to_add:
|
|
283
|
-
# Convert prior messages to google.genai Content
|
|
283
|
+
# Convert prior messages to google.genai Content
|
|
284
284
|
converted_prior = self._converter.convert_to_google_content(messages_to_add)
|
|
285
|
-
|
|
285
|
+
# Only persist prior context when history is enabled; otherwise inline later
|
|
286
|
+
if request_params.use_history:
|
|
287
|
+
self.history.extend(converted_prior, is_prompt=is_template)
|
|
288
|
+
else:
|
|
289
|
+
# Prepend prior context directly to the turn message list
|
|
290
|
+
# This keeps the single-turn chain intact without relying on provider memory
|
|
291
|
+
pass
|
|
286
292
|
|
|
287
293
|
if last_message.role == "assistant":
|
|
288
294
|
# No generation required; the provided assistant message is the output
|
|
@@ -322,6 +328,11 @@ class GoogleNativeLLM(FastAgentLLM[types.Content, types.Content]):
|
|
|
322
328
|
# convert_to_google_content returns a list; preserve order after tool responses
|
|
323
329
|
turn_messages.extend(user_contents)
|
|
324
330
|
|
|
331
|
+
# If not using provider history, include prior messages inline for this turn
|
|
332
|
+
if messages_to_add and not request_params.use_history:
|
|
333
|
+
prior_contents = self._converter.convert_to_google_content(messages_to_add)
|
|
334
|
+
turn_messages = prior_contents + turn_messages
|
|
335
|
+
|
|
325
336
|
# If we somehow have no provider-native parts, ensure we send an empty user content
|
|
326
337
|
if not turn_messages:
|
|
327
338
|
turn_messages.append(types.Content(role="user", parts=[types.Part.from_text("")]))
|
|
@@ -448,32 +448,41 @@ class OpenAILLM(FastAgentLLM[ChatCompletionMessageParam, ChatCompletionMessage])
|
|
|
448
448
|
tools: List[Tool] | None = None,
|
|
449
449
|
is_template: bool = False,
|
|
450
450
|
) -> PromptMessageExtended:
|
|
451
|
-
#
|
|
451
|
+
# Determine effective params to respect use_history for this turn
|
|
452
|
+
req_params = self.get_request_params(request_params)
|
|
452
453
|
|
|
453
454
|
last_message = multipart_messages[-1]
|
|
454
455
|
|
|
455
|
-
#
|
|
456
|
-
# if the last message is a "user" inference is required
|
|
456
|
+
# Prepare prior messages (everything before the last user message), or all if last is assistant
|
|
457
457
|
messages_to_add = (
|
|
458
458
|
multipart_messages[:-1] if last_message.role == "user" else multipart_messages
|
|
459
459
|
)
|
|
460
|
-
|
|
460
|
+
|
|
461
|
+
converted_prior: List[ChatCompletionMessageParam] = []
|
|
461
462
|
for msg in messages_to_add:
|
|
462
463
|
# convert_to_openai now returns a list of messages
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
self.history.extend(converted, is_prompt=is_template)
|
|
464
|
+
converted_prior.extend(OpenAIConverter.convert_to_openai(msg))
|
|
466
465
|
|
|
467
|
-
|
|
466
|
+
# If the last message is from the assistant, no inference required
|
|
467
|
+
if last_message.role == "assistant":
|
|
468
468
|
return last_message
|
|
469
469
|
|
|
470
|
-
|
|
471
|
-
|
|
470
|
+
# Convert the last user message
|
|
471
|
+
converted_last = OpenAIConverter.convert_to_openai(last_message)
|
|
472
|
+
if not converted_last:
|
|
472
473
|
# Fallback for empty conversion
|
|
473
|
-
|
|
474
|
+
converted_last = [{"role": "user", "content": ""}]
|
|
475
|
+
|
|
476
|
+
# History-aware vs stateless turn construction
|
|
477
|
+
if req_params.use_history:
|
|
478
|
+
# Persist prior context to provider memory; send only the last message for this turn
|
|
479
|
+
self.history.extend(converted_prior, is_prompt=is_template)
|
|
480
|
+
turn_messages = converted_last
|
|
481
|
+
else:
|
|
482
|
+
# Do NOT persist; inline the full turn context to the provider call
|
|
483
|
+
turn_messages = converted_prior + converted_last
|
|
474
484
|
|
|
475
|
-
|
|
476
|
-
return await self._openai_completion(converted_messages, request_params, tools)
|
|
485
|
+
return await self._openai_completion(turn_messages, req_params, tools)
|
|
477
486
|
|
|
478
487
|
def _prepare_api_request(
|
|
479
488
|
self, messages, tools: List[ChatCompletionToolParam] | None, request_params: RequestParams
|
fast_agent/ui/rich_progress.py
CHANGED
|
@@ -5,7 +5,7 @@ from contextlib import contextmanager
|
|
|
5
5
|
from typing import Optional
|
|
6
6
|
|
|
7
7
|
from rich.console import Console
|
|
8
|
-
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
8
|
+
from rich.progress import Progress, SpinnerColumn, TaskID, TextColumn
|
|
9
9
|
|
|
10
10
|
from fast_agent.event_progress import ProgressAction, ProgressEvent
|
|
11
11
|
from fast_agent.ui.console import console as default_console
|
|
@@ -17,7 +17,7 @@ class RichProgressDisplay:
|
|
|
17
17
|
def __init__(self, console: Optional[Console] = None) -> None:
|
|
18
18
|
"""Initialize the progress display."""
|
|
19
19
|
self.console = console or default_console
|
|
20
|
-
self._taskmap = {}
|
|
20
|
+
self._taskmap: dict[str, TaskID] = {}
|
|
21
21
|
self._progress = Progress(
|
|
22
22
|
SpinnerColumn(spinner_name="simpleDotsScrolling"),
|
|
23
23
|
TextColumn(
|
|
@@ -134,11 +134,13 @@ class RichProgressDisplay:
|
|
|
134
134
|
description = f"[{self._get_action_style(event.action)}]▎ {event.action.value:<15}"
|
|
135
135
|
|
|
136
136
|
# Update basic task information
|
|
137
|
-
update_kwargs = {
|
|
137
|
+
update_kwargs: dict[str, object] = {
|
|
138
138
|
"description": description,
|
|
139
|
-
"
|
|
140
|
-
|
|
141
|
-
|
|
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
|
+
},
|
|
142
144
|
}
|
|
143
145
|
|
|
144
146
|
# For TOOL_PROGRESS events, update progress if available
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
fast_agent/__init__.py,sha256=sljPsYHqDmv5v0fBpQdhtwBm5IDyu37lwdSQA0IPEwQ,3628
|
|
2
|
-
fast_agent/config.py,sha256=
|
|
2
|
+
fast_agent/config.py,sha256=RLCYW9k4lgnfJVc3JpBWJscOC2mHw35gkVGrBS46M-4,19945
|
|
3
3
|
fast_agent/constants.py,sha256=d5EMSO2msRkjRFz8MgnnhpMnO3woqKP0EcQ4b_yI60w,235
|
|
4
4
|
fast_agent/context.py,sha256=nBelOqehSH91z3aG2nYhwETP-biRzz-iuA2fqmKdHP8,7700
|
|
5
5
|
fast_agent/context_dependent.py,sha256=KU1eydVBoIt4bYOZroqxDgE1AUexDaZi7hurE26QsF4,1584
|
|
@@ -10,35 +10,35 @@ fast_agent/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
10
10
|
fast_agent/agents/__init__.py,sha256=kBI2VWTitLyWf8K3dFMyuE-K7Ufp7mkHBomM2K3I8H8,1128
|
|
11
11
|
fast_agent/agents/agent_types.py,sha256=ugolD3lC2KxSfBYjjRf9HjNATZaFx1o4Fhjb15huSgk,1776
|
|
12
12
|
fast_agent/agents/llm_agent.py,sha256=iuy3kO5Q-f9bm3tjYLG2Wurd0gK2sLhTfTkSnfVWzSw,8311
|
|
13
|
-
fast_agent/agents/llm_decorator.py,sha256=
|
|
13
|
+
fast_agent/agents/llm_decorator.py,sha256=IhvMOZVjo1qT4GII0KP000VYTCprzBQBGZPbZwBIEd0,16485
|
|
14
14
|
fast_agent/agents/mcp_agent.py,sha256=BMSTcGd9_SdoyEGNGVAWXu8ubaE1TAeAMl-2c_wymQU,35240
|
|
15
|
-
fast_agent/agents/tool_agent.py,sha256=
|
|
15
|
+
fast_agent/agents/tool_agent.py,sha256=owGcc1an9P8jb8ZfNYjCsLK6lv85IL7friWcSbZxMIo,6717
|
|
16
16
|
fast_agent/agents/workflow/chain_agent.py,sha256=Pd8dOH_YdKu3LXsKa4fwqzY_B2qVuhzdfCUiKi5v17s,6293
|
|
17
17
|
fast_agent/agents/workflow/evaluator_optimizer.py,sha256=rhzazy8Aj-ydId6kmBC77TmtYZ5mirSe7eV6PPMWkBA,12040
|
|
18
18
|
fast_agent/agents/workflow/iterative_planner.py,sha256=CTtDpK-YGrFFZMQQmFeE-2I_9-cZv23pNwUoh8w5voA,20478
|
|
19
|
-
fast_agent/agents/workflow/orchestrator_models.py,sha256=
|
|
19
|
+
fast_agent/agents/workflow/orchestrator_models.py,sha256=VNnnVegnjimgiuL8ZhxkBPhg8tjbeJRGq2JAIl0FAbU,7216
|
|
20
20
|
fast_agent/agents/workflow/orchestrator_prompts.py,sha256=EXKEI174sshkZyPPEnWbwwNafzSPuA39MXL7iqG9cWc,9106
|
|
21
21
|
fast_agent/agents/workflow/parallel_agent.py,sha256=DlJXDURAfx-WBF297tKBLfH93gDFSAPUyEmJr7QNGyw,7476
|
|
22
22
|
fast_agent/agents/workflow/router_agent.py,sha256=KWLOZMFI4YPn0fqzR001qLFbOe7DYxx-E2c0BgIgO-g,11081
|
|
23
23
|
fast_agent/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
24
|
fast_agent/cli/__main__.py,sha256=VD-UuXvIHJtrDGgVVpsAZGJ_GfVTalSD1Kx9vzixzfM,1129
|
|
25
25
|
fast_agent/cli/constants.py,sha256=KawdkaN289nVB02DKPB4IVUJ8-fohIUD0gLfOp0P7B8,551
|
|
26
|
-
fast_agent/cli/main.py,sha256=
|
|
26
|
+
fast_agent/cli/main.py,sha256=H3brvpmDGE0g4WCJc2-volADCjpPmh7cSjedSfzqfOQ,4242
|
|
27
27
|
fast_agent/cli/terminal.py,sha256=tDN1fJ91Nc_wZJTNafkQuD7Z7gFscvo1PHh-t7Wl-5s,1066
|
|
28
28
|
fast_agent/cli/commands/check_config.py,sha256=nMiOBs-Sc7XqUU6tLReLn1JPXHqjR0Kuz4rCa3mDXp0,22831
|
|
29
29
|
fast_agent/cli/commands/go.py,sha256=VRiHq9h1UGIndLdQJMAwEM6bwTGy-h5n6w__bYCGaHM,15094
|
|
30
30
|
fast_agent/cli/commands/quickstart.py,sha256=hQZYlvktPdDNdaZOZkBgcvi8u0bMW5yFhz4BLBZ251I,21175
|
|
31
31
|
fast_agent/cli/commands/server_helpers.py,sha256=BmljUNLIcZdFpffYxEPfJf8rrX3JhTzMA7VONoZLAjM,3650
|
|
32
32
|
fast_agent/cli/commands/setup.py,sha256=rCp5wUs5kjbHJqi3Jz9ByCpOSvJ7L4KB0hpcKB8qpCM,6377
|
|
33
|
-
fast_agent/cli/commands/url_parser.py,sha256=
|
|
34
|
-
fast_agent/core/__init__.py,sha256=
|
|
33
|
+
fast_agent/cli/commands/url_parser.py,sha256=v9KoprPBEEST5Fo7qXgbW50GC5vMpxFteKqAT6mFkdI,5991
|
|
34
|
+
fast_agent/core/__init__.py,sha256=CnEL3AiklrG7jc0O-8RaF8_PTwBoDaHfmbXo3hOqR-I,2371
|
|
35
35
|
fast_agent/core/agent_app.py,sha256=cdzNwpb--SUNYbhkUX6RolqVnxJ5WSchxw5I4gFrvpk,16836
|
|
36
36
|
fast_agent/core/core_app.py,sha256=_8Di00HD2BzWhCAaopAUS0Hzc7pg0249QUUfPuLZ36A,4266
|
|
37
|
-
fast_agent/core/direct_decorators.py,sha256=
|
|
37
|
+
fast_agent/core/direct_decorators.py,sha256=0U4_qJl7pdom9mjQ5qwCeb0zBwc5hj-lKFF6zXs62sI,22621
|
|
38
38
|
fast_agent/core/direct_factory.py,sha256=HGGnnF4Z9k_N3r0Iin_sp2Ch308To1oKX8JTKHjuUq0,21350
|
|
39
|
-
fast_agent/core/error_handling.py,sha256=
|
|
39
|
+
fast_agent/core/error_handling.py,sha256=tZkO8LnXO-qf6jD8a12Pv5fD4NhnN1Ag5_tJ6DwbXjg,631
|
|
40
40
|
fast_agent/core/exceptions.py,sha256=ENAD_qGG67foxy6vDkIvc-lgopIUQy6O7zvNPpPXaQg,2289
|
|
41
|
-
fast_agent/core/fastagent.py,sha256=
|
|
41
|
+
fast_agent/core/fastagent.py,sha256=5f9jOteVVV7BzX3b_BsUSo_kdciVukVKw567uu-u3qE,30848
|
|
42
42
|
fast_agent/core/prompt.py,sha256=qNUFlK3KtU7leYysYUglzBYQnEYiXu__iR_T8189zc0,203
|
|
43
43
|
fast_agent/core/validation.py,sha256=GZ0hUTxkr5KMY1wr6_ifDy91Ycvcx384gZEMOwdie9w,12681
|
|
44
44
|
fast_agent/core/executor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -46,7 +46,7 @@ fast_agent/core/executor/executor.py,sha256=egmu1bBJmNjfkMZRdaF2CowyHu0t20TiroKB
|
|
|
46
46
|
fast_agent/core/executor/task_registry.py,sha256=PCALFeYtkQrPBg4RBJnlA0aDI8nHclrNkHGUS4kV3W8,1242
|
|
47
47
|
fast_agent/core/executor/workflow_signal.py,sha256=Cg1uZBk3fn8kXhPOg-wINNuVaf3v9pvLD6NbqWy5Z6E,11142
|
|
48
48
|
fast_agent/core/logging/__init__.py,sha256=dFW2bbTtz45zebUuQs7RVi7mg1RJm4DHH6TGfBMhW14,167
|
|
49
|
-
fast_agent/core/logging/events.py,sha256=
|
|
49
|
+
fast_agent/core/logging/events.py,sha256=WTjr26uIxtbxhnoLNPROVUIt0HNJrzK1g1fUMZ-zVsQ,4207
|
|
50
50
|
fast_agent/core/logging/json_serializer.py,sha256=kQDkwTHIkHSQgbhDOJhMoetNvfJVMZGOScaKoLX8kmw,5797
|
|
51
51
|
fast_agent/core/logging/listeners.py,sha256=dubbGJoieryyhXN-JF-GrjkW-dgMq93bElM-NBkwA_Q,9366
|
|
52
52
|
fast_agent/core/logging/logger.py,sha256=L-hLfUGFCIABoNYDiUkNHWvFxL6j-6zn5Pc5E7aC44M,11074
|
|
@@ -64,7 +64,7 @@ fast_agent/llm/memory.py,sha256=POFoBVMHK0wX4oLd3Gz-6Ru3uC4kTCvAqsVQ77e7KJA,8551
|
|
|
64
64
|
fast_agent/llm/model_database.py,sha256=CXpAncjfFGmzjVyvAaKE5QuvDoLwMWXqUHngv_4oDl8,12609
|
|
65
65
|
fast_agent/llm/model_factory.py,sha256=0quhsqz816GxEM_vuRaJ4n6U8C3lp5KxtIphxepIXVI,12862
|
|
66
66
|
fast_agent/llm/model_info.py,sha256=DAIMW70W-EFqNLIudhjHJE2gobHUAKg90gkwOPuaFUc,4125
|
|
67
|
-
fast_agent/llm/prompt_utils.py,sha256=
|
|
67
|
+
fast_agent/llm/prompt_utils.py,sha256=1WU67G-BFqftja5I8FKPMMzsvDk1K_1jDi9A9kkFdOg,4899
|
|
68
68
|
fast_agent/llm/provider_key_manager.py,sha256=igzs1ghXsUp0wA4nJVVfWCWiYOib8Ux4jMGlhWbgXu8,3396
|
|
69
69
|
fast_agent/llm/provider_types.py,sha256=Ya0MGo_4cE0oCwinqPvr9SJUwx4hEJ7CFbCrLB_27FI,1142
|
|
70
70
|
fast_agent/llm/request_params.py,sha256=OW9WnQAD-I2fz2JzMsqPY2wwwHFG0SI4yAvC1WxTfNY,1735
|
|
@@ -75,19 +75,19 @@ fast_agent/llm/internal/playback.py,sha256=HzV0BitORA977_3OWAbMZjLZpIHBKt-_PeOO3
|
|
|
75
75
|
fast_agent/llm/internal/silent.py,sha256=TVhjp0sEcPpR35n_QjYrMu0CKVX2humAt1GBR6y_itE,1563
|
|
76
76
|
fast_agent/llm/internal/slow.py,sha256=MQf21cK7aM0yPN1_j1hSJRTEp4UGbrPo_sCP81WDcxQ,1310
|
|
77
77
|
fast_agent/llm/provider/anthropic/anthropic_utils.py,sha256=zkeMpAlV9YW9pP1FObkyqR8wg8e-Xir9SCwsom94zao,3246
|
|
78
|
-
fast_agent/llm/provider/anthropic/llm_anthropic.py,sha256=
|
|
78
|
+
fast_agent/llm/provider/anthropic/llm_anthropic.py,sha256=EYd3_xy0OwSz4vM6XRkmQyG62_hTho-bsKpcg7CL9JI,25797
|
|
79
79
|
fast_agent/llm/provider/anthropic/multipart_converter_anthropic.py,sha256=fO6qoKvG2ede85CvdvMipOlATwLjbGKahvsu2OzJhvk,16460
|
|
80
80
|
fast_agent/llm/provider/bedrock/bedrock_utils.py,sha256=mqWCCeB1gUQSL2KRUMqpFjvHZ0ZTJugCsd5YOrx6U30,7750
|
|
81
|
-
fast_agent/llm/provider/bedrock/llm_bedrock.py,sha256=
|
|
81
|
+
fast_agent/llm/provider/bedrock/llm_bedrock.py,sha256=VSwl-UbU5Qh7umqNzQ5NofeO8p7aHhGl89eL4wTJchY,100199
|
|
82
82
|
fast_agent/llm/provider/google/google_converter.py,sha256=iQZps4773Bc8SUODduLpfkVpT3J1rIg1bFgLQ2CCqZc,18926
|
|
83
|
-
fast_agent/llm/provider/google/llm_google_native.py,sha256=
|
|
83
|
+
fast_agent/llm/provider/google/llm_google_native.py,sha256=Uzkz8GXH-tzRO1mHnO1N7qiLuPdQ5NFkRoSa9_3uAPc,19451
|
|
84
84
|
fast_agent/llm/provider/openai/llm_aliyun.py,sha256=ti7VHTpwl0AG3ytwBERpDzVtacvCfamKnl2bAnTE96s,1213
|
|
85
85
|
fast_agent/llm/provider/openai/llm_azure.py,sha256=O-TIEL6hGOArqRlvEjocaeW4OMUaelSnh6xpqhrrcHQ,6070
|
|
86
86
|
fast_agent/llm/provider/openai/llm_deepseek.py,sha256=aAMX7pd1qDfl54Z9pLvJTVYETc4yKKMRYrEMiPIhd7w,3762
|
|
87
87
|
fast_agent/llm/provider/openai/llm_generic.py,sha256=O_mmu3o9LeAZ6Kp405I-GfwrS8AuVkyX3tT6aCDCfLY,1168
|
|
88
88
|
fast_agent/llm/provider/openai/llm_google_oai.py,sha256=u1yZVeDds9z2hvydz_kUpFe2RANTNwEtlPgB-OEmgrY,1095
|
|
89
89
|
fast_agent/llm/provider/openai/llm_groq.py,sha256=trNSy3T94_fJWAhVn51iESP_J7sQh_23ufVegKKNHBs,5247
|
|
90
|
-
fast_agent/llm/provider/openai/llm_openai.py,sha256=
|
|
90
|
+
fast_agent/llm/provider/openai/llm_openai.py,sha256=I4qcAjqUsMDRJtNdSmol57XYar8rj0mqV3VRtkOCZ_8,22681
|
|
91
91
|
fast_agent/llm/provider/openai/llm_openrouter.py,sha256=RBTUkNBRqE8WoucCoVnXP5GhnMwc2tiRacXbMHVf1xM,1943
|
|
92
92
|
fast_agent/llm/provider/openai/llm_tensorzero_openai.py,sha256=yrV0kZ2zRohErdjhvWGDTl0OnPi2SbuzY_8MchXiVTU,5466
|
|
93
93
|
fast_agent/llm/provider/openai/llm_xai.py,sha256=fEyO9XlU3Ef1a-cXdJl0Qe-FmE562cA-UJOGvzqLO6M,1375
|
|
@@ -194,10 +194,10 @@ fast_agent/ui/interactive_prompt.py,sha256=lxY26PNBNihtccO4iI7CxIag_9CxEcbajbIPd
|
|
|
194
194
|
fast_agent/ui/mcp_ui_utils.py,sha256=UVX-VZI7PaJ8JlYuWsletml4K3XrUGUFRn4lqFwsAWg,8099
|
|
195
195
|
fast_agent/ui/mermaid_utils.py,sha256=MpcRyVCPMTwU1XeIxnyFg0fQLjcyXZduWRF8NhEqvXE,5332
|
|
196
196
|
fast_agent/ui/progress_display.py,sha256=hajDob65PttiJ2mPS6FsCtnmTcnyvDWGn-UqQboXqkQ,361
|
|
197
|
-
fast_agent/ui/rich_progress.py,sha256=
|
|
197
|
+
fast_agent/ui/rich_progress.py,sha256=jy6VuUOYFkWXdyvnRTSBPAmmNAP6TJDFw_lgbt_YYLo,7548
|
|
198
198
|
fast_agent/ui/usage_display.py,sha256=ltJpn_sDzo8PDNSXWx-QdEUbQWUnhmajCItNt5mA5rM,7285
|
|
199
|
-
fast_agent_mcp-0.3.
|
|
200
|
-
fast_agent_mcp-0.3.
|
|
201
|
-
fast_agent_mcp-0.3.
|
|
202
|
-
fast_agent_mcp-0.3.
|
|
203
|
-
fast_agent_mcp-0.3.
|
|
199
|
+
fast_agent_mcp-0.3.3.dist-info/METADATA,sha256=OaL4vvtEurj2Cffo53cry42F1aGNlJxWGMkZj9qmDVg,30462
|
|
200
|
+
fast_agent_mcp-0.3.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
201
|
+
fast_agent_mcp-0.3.3.dist-info/entry_points.txt,sha256=i6Ujja9J-hRxttOKqTYdbYP_tyaS4gLHg53vupoCSsg,199
|
|
202
|
+
fast_agent_mcp-0.3.3.dist-info/licenses/LICENSE,sha256=Gx1L3axA4PnuK4FxsbX87jQ1opoOkSFfHHSytW6wLUU,10935
|
|
203
|
+
fast_agent_mcp-0.3.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|