fast-agent-mcp 0.1.12__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.
- {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.2.0.dist-info}/METADATA +3 -4
- fast_agent_mcp-0.2.0.dist-info/RECORD +123 -0
- mcp_agent/__init__.py +75 -0
- mcp_agent/agents/agent.py +61 -415
- mcp_agent/agents/base_agent.py +522 -0
- mcp_agent/agents/workflow/__init__.py +1 -0
- mcp_agent/agents/workflow/chain_agent.py +173 -0
- mcp_agent/agents/workflow/evaluator_optimizer.py +362 -0
- mcp_agent/agents/workflow/orchestrator_agent.py +591 -0
- mcp_agent/{workflows/orchestrator → agents/workflow}/orchestrator_models.py +11 -21
- mcp_agent/agents/workflow/parallel_agent.py +182 -0
- mcp_agent/agents/workflow/router_agent.py +307 -0
- mcp_agent/app.py +15 -19
- mcp_agent/cli/commands/bootstrap.py +19 -38
- mcp_agent/cli/commands/config.py +4 -4
- mcp_agent/cli/commands/setup.py +7 -14
- mcp_agent/cli/main.py +7 -10
- mcp_agent/cli/terminal.py +3 -3
- mcp_agent/config.py +25 -40
- mcp_agent/context.py +12 -21
- mcp_agent/context_dependent.py +3 -5
- mcp_agent/core/agent_types.py +10 -7
- mcp_agent/core/direct_agent_app.py +179 -0
- mcp_agent/core/direct_decorators.py +443 -0
- mcp_agent/core/direct_factory.py +476 -0
- mcp_agent/core/enhanced_prompt.py +23 -55
- mcp_agent/core/exceptions.py +8 -8
- mcp_agent/core/fastagent.py +145 -371
- mcp_agent/core/interactive_prompt.py +424 -0
- mcp_agent/core/mcp_content.py +17 -17
- mcp_agent/core/prompt.py +6 -9
- mcp_agent/core/request_params.py +6 -3
- mcp_agent/core/validation.py +92 -18
- mcp_agent/executor/decorator_registry.py +9 -17
- mcp_agent/executor/executor.py +8 -17
- mcp_agent/executor/task_registry.py +2 -4
- mcp_agent/executor/temporal.py +19 -41
- mcp_agent/executor/workflow.py +3 -5
- mcp_agent/executor/workflow_signal.py +15 -21
- mcp_agent/human_input/handler.py +4 -7
- mcp_agent/human_input/types.py +2 -3
- mcp_agent/llm/__init__.py +2 -0
- mcp_agent/llm/augmented_llm.py +450 -0
- mcp_agent/llm/augmented_llm_passthrough.py +162 -0
- mcp_agent/llm/augmented_llm_playback.py +83 -0
- mcp_agent/llm/memory.py +103 -0
- mcp_agent/{workflows/llm → llm}/model_factory.py +22 -16
- mcp_agent/{workflows/llm → llm}/prompt_utils.py +1 -3
- mcp_agent/llm/providers/__init__.py +8 -0
- mcp_agent/{workflows/llm → llm/providers}/anthropic_utils.py +8 -25
- mcp_agent/{workflows/llm → llm/providers}/augmented_llm_anthropic.py +56 -194
- mcp_agent/llm/providers/augmented_llm_deepseek.py +53 -0
- mcp_agent/{workflows/llm → llm/providers}/augmented_llm_openai.py +99 -190
- mcp_agent/{workflows/llm → llm}/providers/multipart_converter_anthropic.py +72 -71
- mcp_agent/{workflows/llm → llm}/providers/multipart_converter_openai.py +65 -71
- mcp_agent/{workflows/llm → llm}/providers/openai_multipart.py +16 -44
- mcp_agent/{workflows/llm → llm/providers}/openai_utils.py +4 -4
- mcp_agent/{workflows/llm → llm}/providers/sampling_converter_anthropic.py +9 -11
- mcp_agent/{workflows/llm → llm}/providers/sampling_converter_openai.py +8 -12
- mcp_agent/{workflows/llm → llm}/sampling_converter.py +3 -31
- mcp_agent/llm/sampling_format_converter.py +37 -0
- mcp_agent/logging/events.py +1 -5
- mcp_agent/logging/json_serializer.py +7 -6
- mcp_agent/logging/listeners.py +20 -23
- mcp_agent/logging/logger.py +17 -19
- mcp_agent/logging/rich_progress.py +10 -8
- mcp_agent/logging/tracing.py +4 -6
- mcp_agent/logging/transport.py +22 -22
- mcp_agent/mcp/gen_client.py +1 -3
- mcp_agent/mcp/interfaces.py +117 -110
- mcp_agent/mcp/logger_textio.py +97 -0
- mcp_agent/mcp/mcp_agent_client_session.py +7 -7
- mcp_agent/mcp/mcp_agent_server.py +8 -8
- mcp_agent/mcp/mcp_aggregator.py +102 -143
- mcp_agent/mcp/mcp_connection_manager.py +20 -27
- mcp_agent/mcp/prompt_message_multipart.py +68 -16
- mcp_agent/mcp/prompt_render.py +77 -0
- mcp_agent/mcp/prompt_serialization.py +30 -48
- mcp_agent/mcp/prompts/prompt_constants.py +18 -0
- mcp_agent/mcp/prompts/prompt_helpers.py +327 -0
- mcp_agent/mcp/prompts/prompt_load.py +109 -0
- mcp_agent/mcp/prompts/prompt_server.py +155 -195
- mcp_agent/mcp/prompts/prompt_template.py +35 -66
- mcp_agent/mcp/resource_utils.py +7 -14
- mcp_agent/mcp/sampling.py +17 -17
- mcp_agent/mcp_server/agent_server.py +13 -17
- mcp_agent/mcp_server_registry.py +13 -22
- mcp_agent/resources/examples/{workflows → in_dev}/agent_build.py +3 -2
- mcp_agent/resources/examples/in_dev/slides.py +110 -0
- mcp_agent/resources/examples/internal/agent.py +6 -3
- mcp_agent/resources/examples/internal/fastagent.config.yaml +8 -2
- mcp_agent/resources/examples/internal/job.py +2 -1
- mcp_agent/resources/examples/internal/prompt_category.py +1 -1
- mcp_agent/resources/examples/internal/prompt_sizing.py +3 -5
- mcp_agent/resources/examples/internal/sizer.py +2 -1
- mcp_agent/resources/examples/internal/social.py +2 -1
- mcp_agent/resources/examples/prompting/agent.py +2 -1
- mcp_agent/resources/examples/prompting/image_server.py +4 -8
- mcp_agent/resources/examples/prompting/work_with_image.py +19 -0
- mcp_agent/ui/console_display.py +16 -20
- fast_agent_mcp-0.1.12.dist-info/RECORD +0 -161
- mcp_agent/core/agent_app.py +0 -646
- mcp_agent/core/agent_utils.py +0 -71
- mcp_agent/core/decorators.py +0 -455
- mcp_agent/core/factory.py +0 -463
- mcp_agent/core/proxies.py +0 -269
- mcp_agent/core/types.py +0 -24
- mcp_agent/eval/__init__.py +0 -0
- mcp_agent/mcp/stdio.py +0 -111
- mcp_agent/resources/examples/data-analysis/analysis-campaign.py +0 -188
- mcp_agent/resources/examples/data-analysis/analysis.py +0 -65
- mcp_agent/resources/examples/data-analysis/fastagent.config.yaml +0 -41
- mcp_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +0 -1471
- mcp_agent/resources/examples/mcp_researcher/researcher-eval.py +0 -53
- mcp_agent/resources/examples/researcher/fastagent.config.yaml +0 -66
- mcp_agent/resources/examples/researcher/researcher-eval.py +0 -53
- mcp_agent/resources/examples/researcher/researcher-imp.py +0 -190
- mcp_agent/resources/examples/researcher/researcher.py +0 -38
- mcp_agent/resources/examples/workflows/chaining.py +0 -44
- mcp_agent/resources/examples/workflows/evaluator.py +0 -78
- mcp_agent/resources/examples/workflows/fastagent.config.yaml +0 -24
- mcp_agent/resources/examples/workflows/human_input.py +0 -25
- mcp_agent/resources/examples/workflows/orchestrator.py +0 -73
- mcp_agent/resources/examples/workflows/parallel.py +0 -78
- mcp_agent/resources/examples/workflows/router.py +0 -53
- mcp_agent/resources/examples/workflows/sse.py +0 -23
- mcp_agent/telemetry/__init__.py +0 -0
- mcp_agent/telemetry/usage_tracking.py +0 -18
- mcp_agent/workflows/__init__.py +0 -0
- mcp_agent/workflows/embedding/__init__.py +0 -0
- mcp_agent/workflows/embedding/embedding_base.py +0 -61
- mcp_agent/workflows/embedding/embedding_cohere.py +0 -49
- mcp_agent/workflows/embedding/embedding_openai.py +0 -46
- mcp_agent/workflows/evaluator_optimizer/__init__.py +0 -0
- mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +0 -481
- mcp_agent/workflows/intent_classifier/__init__.py +0 -0
- mcp_agent/workflows/intent_classifier/intent_classifier_base.py +0 -120
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py +0 -134
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding_cohere.py +0 -45
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding_openai.py +0 -45
- mcp_agent/workflows/intent_classifier/intent_classifier_llm.py +0 -161
- mcp_agent/workflows/intent_classifier/intent_classifier_llm_anthropic.py +0 -60
- mcp_agent/workflows/intent_classifier/intent_classifier_llm_openai.py +0 -60
- mcp_agent/workflows/llm/__init__.py +0 -0
- mcp_agent/workflows/llm/augmented_llm.py +0 -753
- mcp_agent/workflows/llm/augmented_llm_passthrough.py +0 -241
- mcp_agent/workflows/llm/augmented_llm_playback.py +0 -109
- mcp_agent/workflows/llm/providers/__init__.py +0 -8
- mcp_agent/workflows/llm/sampling_format_converter.py +0 -22
- mcp_agent/workflows/orchestrator/__init__.py +0 -0
- mcp_agent/workflows/orchestrator/orchestrator.py +0 -578
- mcp_agent/workflows/parallel/__init__.py +0 -0
- mcp_agent/workflows/parallel/fan_in.py +0 -350
- mcp_agent/workflows/parallel/fan_out.py +0 -187
- mcp_agent/workflows/parallel/parallel_llm.py +0 -166
- mcp_agent/workflows/router/__init__.py +0 -0
- mcp_agent/workflows/router/router_base.py +0 -368
- mcp_agent/workflows/router/router_embedding.py +0 -240
- mcp_agent/workflows/router/router_embedding_cohere.py +0 -59
- mcp_agent/workflows/router/router_embedding_openai.py +0 -59
- mcp_agent/workflows/router/router_llm.py +0 -320
- mcp_agent/workflows/swarm/__init__.py +0 -0
- mcp_agent/workflows/swarm/swarm.py +0 -320
- mcp_agent/workflows/swarm/swarm_anthropic.py +0 -42
- mcp_agent/workflows/swarm/swarm_openai.py +0 -41
- {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.2.0.dist-info}/WHEEL +0 -0
- {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.2.0.dist-info}/entry_points.txt +0 -0
- {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.2.0.dist-info}/licenses/LICENSE +0 -0
- /mcp_agent/{workflows/orchestrator → agents/workflow}/orchestrator_prompts.py +0 -0
@@ -1,29 +1,25 @@
|
|
1
|
-
from typing import
|
2
|
-
|
3
|
-
from openai.types.chat import (
|
4
|
-
ChatCompletionMessage,
|
5
|
-
)
|
1
|
+
from typing import Any, Dict
|
6
2
|
|
7
3
|
from mcp.types import (
|
8
4
|
PromptMessage,
|
9
5
|
)
|
10
|
-
|
11
|
-
|
12
|
-
SamplingFormatConverter,
|
6
|
+
from openai.types.chat import (
|
7
|
+
ChatCompletionMessage,
|
13
8
|
)
|
14
9
|
|
10
|
+
from mcp_agent.llm.sampling_format_converter import (
|
11
|
+
ProviderFormatConverter,
|
12
|
+
)
|
15
13
|
from mcp_agent.logging.logger import get_logger
|
16
14
|
|
17
15
|
_logger = get_logger(__name__)
|
18
16
|
|
19
17
|
|
20
|
-
class OpenAISamplingConverter(
|
21
|
-
SamplingFormatConverter[Dict[str, Any], ChatCompletionMessage]
|
22
|
-
):
|
18
|
+
class OpenAISamplingConverter(ProviderFormatConverter[Dict[str, Any], ChatCompletionMessage]):
|
23
19
|
@classmethod
|
24
20
|
def from_prompt_message(cls, message: PromptMessage) -> Dict[str, Any]:
|
25
21
|
"""Convert an MCP PromptMessage to an OpenAI message dict."""
|
26
|
-
from mcp_agent.
|
22
|
+
from mcp_agent.llm.providers.multipart_converter_openai import (
|
27
23
|
OpenAIConverter,
|
28
24
|
)
|
29
25
|
|
@@ -9,12 +9,11 @@ from mcp.types import (
|
|
9
9
|
CreateMessageRequestParams,
|
10
10
|
CreateMessageResult,
|
11
11
|
SamplingMessage,
|
12
|
-
StopReason,
|
13
12
|
TextContent,
|
14
13
|
)
|
15
14
|
|
16
|
-
from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
|
17
15
|
from mcp_agent.mcp.interfaces import RequestParams
|
16
|
+
from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
|
18
17
|
|
19
18
|
|
20
19
|
class SamplingConverter:
|
@@ -63,31 +62,7 @@ class SamplingConverter:
|
|
63
62
|
)
|
64
63
|
|
65
64
|
@staticmethod
|
66
|
-
def
|
67
|
-
response: str, model: str, stop_reason: StopReason = "endTurn"
|
68
|
-
) -> CreateMessageResult:
|
69
|
-
"""
|
70
|
-
Create a CreateMessageResult from an LLM response.
|
71
|
-
|
72
|
-
Args:
|
73
|
-
response: Text response from the LLM
|
74
|
-
model: Model identifier
|
75
|
-
stop_reason: Reason generation stopped
|
76
|
-
|
77
|
-
Returns:
|
78
|
-
CreateMessageResult suitable for returning to MCP
|
79
|
-
"""
|
80
|
-
return CreateMessageResult(
|
81
|
-
role="assistant",
|
82
|
-
content=TextContent(type="text", text=response),
|
83
|
-
model=model,
|
84
|
-
stopReason=stop_reason,
|
85
|
-
)
|
86
|
-
|
87
|
-
@staticmethod
|
88
|
-
def error_result(
|
89
|
-
error_message: str, model: Optional[str] = None
|
90
|
-
) -> CreateMessageResult:
|
65
|
+
def error_result(error_message: str, model: Optional[str] = None) -> CreateMessageResult:
|
91
66
|
"""
|
92
67
|
Create an error result.
|
93
68
|
|
@@ -118,7 +93,4 @@ class SamplingConverter:
|
|
118
93
|
Returns:
|
119
94
|
List of PromptMessageMultipart objects, each with a single content item
|
120
95
|
"""
|
121
|
-
return [
|
122
|
-
SamplingConverter.sampling_message_to_prompt_message(msg)
|
123
|
-
for msg in messages
|
124
|
-
]
|
96
|
+
return [SamplingConverter.sampling_message_to_prompt_message(msg) for msg in messages]
|
@@ -0,0 +1,37 @@
|
|
1
|
+
from typing import Generic, List, Protocol, TypeVar
|
2
|
+
|
3
|
+
from mcp.types import PromptMessage
|
4
|
+
|
5
|
+
from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
|
6
|
+
|
7
|
+
# Define covariant type variables
|
8
|
+
MessageParamT_co = TypeVar("MessageParamT_co", covariant=True)
|
9
|
+
MessageT_co = TypeVar("MessageT_co", covariant=True)
|
10
|
+
|
11
|
+
|
12
|
+
class ProviderFormatConverter(Protocol, Generic[MessageParamT_co, MessageT_co]):
|
13
|
+
"""Conversions between LLM provider and MCP types"""
|
14
|
+
|
15
|
+
@classmethod
|
16
|
+
def from_prompt_message(cls, message: PromptMessage) -> MessageParamT_co:
|
17
|
+
"""Convert an MCP PromptMessage to a provider-specific message parameter."""
|
18
|
+
...
|
19
|
+
|
20
|
+
@classmethod
|
21
|
+
def from_mutlipart_prompts(
|
22
|
+
cls, messages: List[PromptMessageMultipart]
|
23
|
+
) -> List[MessageParamT_co]:
|
24
|
+
"""Convert a list of PromptMessageMultiparts to a list of provider-specific implementations"""
|
25
|
+
...
|
26
|
+
|
27
|
+
|
28
|
+
class BasicFormatConverter(ProviderFormatConverter[PromptMessage, PromptMessage]):
|
29
|
+
@classmethod
|
30
|
+
def from_prompt_message(cls, message: PromptMessage) -> PromptMessage:
|
31
|
+
return message
|
32
|
+
|
33
|
+
@classmethod
|
34
|
+
def from_multipart_prompts(
|
35
|
+
cls, messages: List[PromptMessageMultipart]
|
36
|
+
) -> List[PromptMessageMultipart]:
|
37
|
+
return messages
|
mcp_agent/logging/events.py
CHANGED
@@ -4,7 +4,6 @@ Events and event filters for the logger module for the MCP Agent
|
|
4
4
|
|
5
5
|
import logging
|
6
6
|
import random
|
7
|
-
|
8
7
|
from datetime import datetime
|
9
8
|
from typing import (
|
10
9
|
Any,
|
@@ -15,7 +14,6 @@ from typing import (
|
|
15
14
|
|
16
15
|
from pydantic import BaseModel, ConfigDict, Field
|
17
16
|
|
18
|
-
|
19
17
|
EventType = Literal["debug", "info", "warning", "error", "progress"]
|
20
18
|
"""Broad categories for events (severity or role)."""
|
21
19
|
|
@@ -86,9 +84,7 @@ class EventFilter(BaseModel):
|
|
86
84
|
return False
|
87
85
|
|
88
86
|
# 3) Filter by namespace prefix
|
89
|
-
if self.namespaces and not any(
|
90
|
-
event.namespace.startswith(ns) for ns in self.namespaces
|
91
|
-
):
|
87
|
+
if self.namespaces and not any(event.namespace.startswith(ns) for ns in self.namespaces):
|
92
88
|
return False
|
93
89
|
|
94
90
|
# 4) Minimum severity
|
@@ -1,13 +1,14 @@
|
|
1
|
+
import dataclasses
|
2
|
+
import inspect
|
1
3
|
import os
|
2
4
|
import warnings
|
3
|
-
from
|
4
|
-
from datetime import datetime, date
|
5
|
+
from datetime import date, datetime
|
5
6
|
from decimal import Decimal
|
7
|
+
from enum import Enum
|
6
8
|
from pathlib import Path
|
9
|
+
from typing import Any, Dict, Iterable, Set
|
7
10
|
from uuid import UUID
|
8
|
-
|
9
|
-
import dataclasses
|
10
|
-
import inspect
|
11
|
+
|
11
12
|
import httpx
|
12
13
|
|
13
14
|
from mcp_agent.logging import logger
|
@@ -34,7 +35,7 @@ class JSONSerializer:
|
|
34
35
|
"refresh_token",
|
35
36
|
}
|
36
37
|
|
37
|
-
def __init__(self):
|
38
|
+
def __init__(self) -> None:
|
38
39
|
# Set of already processed objects to prevent infinite recursion
|
39
40
|
self._processed_objects: Set[int] = set()
|
40
41
|
# Check if secrets should be logged in full
|
mcp_agent/logging/listeners.py
CHANGED
@@ -5,12 +5,11 @@ Listeners for the logger module of MCP Agent.
|
|
5
5
|
import asyncio
|
6
6
|
import logging
|
7
7
|
import time
|
8
|
-
|
9
8
|
from abc import ABC, abstractmethod
|
10
9
|
from typing import Dict, List
|
11
10
|
|
12
|
-
from mcp_agent.logging.events import Event, EventFilter, EventType
|
13
11
|
from mcp_agent.event_progress import convert_log_event
|
12
|
+
from mcp_agent.logging.events import Event, EventFilter, EventType
|
14
13
|
|
15
14
|
|
16
15
|
class EventListener(ABC):
|
@@ -27,11 +26,11 @@ class LifecycleAwareListener(EventListener):
|
|
27
26
|
The event bus calls these at bus start/stop time.
|
28
27
|
"""
|
29
28
|
|
30
|
-
async def start(self):
|
29
|
+
async def start(self) -> None:
|
31
30
|
"""Start an event listener, usually when the event bus is set up."""
|
32
31
|
pass
|
33
32
|
|
34
|
-
async def stop(self):
|
33
|
+
async def stop(self) -> None:
|
35
34
|
"""Stop an event listener, usually when the event bus is shutting down."""
|
36
35
|
pass
|
37
36
|
|
@@ -42,7 +41,7 @@ class FilteredListener(LifecycleAwareListener):
|
|
42
41
|
Subclasses override _handle_matched_event().
|
43
42
|
"""
|
44
43
|
|
45
|
-
def __init__(self, event_filter: EventFilter | None = None):
|
44
|
+
def __init__(self, event_filter: EventFilter | None = None) -> None:
|
46
45
|
"""
|
47
46
|
Initialize the listener.
|
48
47
|
Args:
|
@@ -50,11 +49,11 @@ class FilteredListener(LifecycleAwareListener):
|
|
50
49
|
"""
|
51
50
|
self.filter = event_filter
|
52
51
|
|
53
|
-
async def handle_event(self, event):
|
52
|
+
async def handle_event(self, event) -> None:
|
54
53
|
if not self.filter or self.filter.matches(event):
|
55
54
|
await self.handle_matched_event(event)
|
56
55
|
|
57
|
-
async def handle_matched_event(self, event: Event):
|
56
|
+
async def handle_matched_event(self, event: Event) -> None:
|
58
57
|
"""Process an event that matches the filter."""
|
59
58
|
pass
|
60
59
|
|
@@ -68,7 +67,7 @@ class LoggingListener(FilteredListener):
|
|
68
67
|
self,
|
69
68
|
event_filter: EventFilter | None = None,
|
70
69
|
logger: logging.Logger | None = None,
|
71
|
-
):
|
70
|
+
) -> None:
|
72
71
|
"""
|
73
72
|
Initialize the listener.
|
74
73
|
Args:
|
@@ -77,7 +76,7 @@ class LoggingListener(FilteredListener):
|
|
77
76
|
super().__init__(event_filter=event_filter)
|
78
77
|
self.logger = logger or logging.getLogger("mcp_agent")
|
79
78
|
|
80
|
-
async def handle_matched_event(self, event):
|
79
|
+
async def handle_matched_event(self, event) -> None:
|
81
80
|
level_map: Dict[EventType, int] = {
|
82
81
|
"debug": logging.DEBUG,
|
83
82
|
"info": logging.INFO,
|
@@ -113,7 +112,7 @@ class ProgressListener(LifecycleAwareListener):
|
|
113
112
|
FilteredListener, we get events before any filtering occurs.
|
114
113
|
"""
|
115
114
|
|
116
|
-
def __init__(self, display=None):
|
115
|
+
def __init__(self, display=None) -> None:
|
117
116
|
"""Initialize the progress listener.
|
118
117
|
Args:
|
119
118
|
display: Optional display handler. If None, the shared progress_display will be used.
|
@@ -122,15 +121,15 @@ class ProgressListener(LifecycleAwareListener):
|
|
122
121
|
|
123
122
|
self.display = display or progress_display
|
124
123
|
|
125
|
-
async def start(self):
|
124
|
+
async def start(self) -> None:
|
126
125
|
"""Start the progress display."""
|
127
126
|
self.display.start()
|
128
127
|
|
129
|
-
async def stop(self):
|
128
|
+
async def stop(self) -> None:
|
130
129
|
"""Stop the progress display."""
|
131
130
|
self.display.stop()
|
132
131
|
|
133
|
-
async def handle_event(self, event: Event):
|
132
|
+
async def handle_event(self, event: Event) -> None:
|
134
133
|
"""Process an incoming event and display progress if relevant."""
|
135
134
|
|
136
135
|
if event.data:
|
@@ -150,7 +149,7 @@ class BatchingListener(FilteredListener):
|
|
150
149
|
event_filter: EventFilter | None = None,
|
151
150
|
batch_size: int = 5,
|
152
151
|
flush_interval: float = 2.0,
|
153
|
-
):
|
152
|
+
) -> None:
|
154
153
|
"""
|
155
154
|
Initialize the listener.
|
156
155
|
Args:
|
@@ -165,12 +164,12 @@ class BatchingListener(FilteredListener):
|
|
165
164
|
self._flush_task: asyncio.Task | None = None # Task for periodic flush loop
|
166
165
|
self._stop_event = None # Event to signal flush task to stop
|
167
166
|
|
168
|
-
async def start(self, loop=None):
|
167
|
+
async def start(self, loop=None) -> None:
|
169
168
|
"""Spawn a periodic flush loop."""
|
170
169
|
self._stop_event = asyncio.Event()
|
171
170
|
self._flush_task = asyncio.create_task(self._periodic_flush())
|
172
171
|
|
173
|
-
async def stop(self):
|
172
|
+
async def stop(self) -> None:
|
174
173
|
"""Stop flush loop and flush any remaining events."""
|
175
174
|
if self._stop_event:
|
176
175
|
self._stop_event.set()
|
@@ -181,13 +180,11 @@ class BatchingListener(FilteredListener):
|
|
181
180
|
self._flush_task = None
|
182
181
|
await self.flush()
|
183
182
|
|
184
|
-
async def _periodic_flush(self):
|
183
|
+
async def _periodic_flush(self) -> None:
|
185
184
|
try:
|
186
185
|
while not self._stop_event.is_set():
|
187
186
|
try:
|
188
|
-
await asyncio.wait_for(
|
189
|
-
self._stop_event.wait(), timeout=self.flush_interval
|
190
|
-
)
|
187
|
+
await asyncio.wait_for(self._stop_event.wait(), timeout=self.flush_interval)
|
191
188
|
except asyncio.TimeoutError:
|
192
189
|
await self.flush()
|
193
190
|
# except asyncio.CancelledError:
|
@@ -195,12 +192,12 @@ class BatchingListener(FilteredListener):
|
|
195
192
|
finally:
|
196
193
|
await self.flush() # Final flush
|
197
194
|
|
198
|
-
async def handle_matched_event(self, event):
|
195
|
+
async def handle_matched_event(self, event) -> None:
|
199
196
|
self.batch.append(event)
|
200
197
|
if len(self.batch) >= self.batch_size:
|
201
198
|
await self.flush()
|
202
199
|
|
203
|
-
async def flush(self):
|
200
|
+
async def flush(self) -> None:
|
204
201
|
"""Flush the current batch of events."""
|
205
202
|
if not self.batch:
|
206
203
|
return
|
@@ -209,5 +206,5 @@ class BatchingListener(FilteredListener):
|
|
209
206
|
self.last_flush = time.time()
|
210
207
|
await self._process_batch(to_process)
|
211
208
|
|
212
|
-
async def _process_batch(self, events: List[Event]):
|
209
|
+
async def _process_batch(self, events: List[Event]) -> None:
|
213
210
|
pass
|
mcp_agent/logging/logger.py
CHANGED
@@ -10,10 +10,8 @@ Logger module for the MCP Agent, which provides:
|
|
10
10
|
import asyncio
|
11
11
|
import threading
|
12
12
|
import time
|
13
|
-
|
14
|
-
from typing import Any, Dict
|
15
|
-
|
16
13
|
from contextlib import asynccontextmanager, contextmanager
|
14
|
+
from typing import Any, Dict
|
17
15
|
|
18
16
|
from mcp_agent.logging.events import Event, EventContext, EventFilter, EventType
|
19
17
|
from mcp_agent.logging.listeners import (
|
@@ -31,7 +29,7 @@ class Logger:
|
|
31
29
|
- `name` can be a custom domain-specific event name, e.g. "ORDER_PLACED".
|
32
30
|
"""
|
33
31
|
|
34
|
-
def __init__(self, namespace: str):
|
32
|
+
def __init__(self, namespace: str) -> None:
|
35
33
|
self.namespace = namespace
|
36
34
|
self.event_bus = AsyncEventBus.get()
|
37
35
|
|
@@ -45,7 +43,7 @@ class Logger:
|
|
45
43
|
asyncio.set_event_loop(loop)
|
46
44
|
return loop
|
47
45
|
|
48
|
-
def _emit_event(self, event: Event):
|
46
|
+
def _emit_event(self, event: Event) -> None:
|
49
47
|
"""Emit an event by running it in the event loop."""
|
50
48
|
loop = self._ensure_event_loop()
|
51
49
|
if loop.is_running():
|
@@ -62,7 +60,7 @@ class Logger:
|
|
62
60
|
message: str,
|
63
61
|
context: EventContext | None,
|
64
62
|
data: dict,
|
65
|
-
):
|
63
|
+
) -> None:
|
66
64
|
"""Create and emit an event."""
|
67
65
|
evt = Event(
|
68
66
|
type=etype,
|
@@ -78,9 +76,9 @@ class Logger:
|
|
78
76
|
self,
|
79
77
|
message: str,
|
80
78
|
name: str | None = None,
|
81
|
-
context: EventContext = None,
|
79
|
+
context: EventContext | None = None,
|
82
80
|
**data,
|
83
|
-
):
|
81
|
+
) -> None:
|
84
82
|
"""Log a debug message."""
|
85
83
|
self.event("debug", name, message, context, data)
|
86
84
|
|
@@ -88,9 +86,9 @@ class Logger:
|
|
88
86
|
self,
|
89
87
|
message: str,
|
90
88
|
name: str | None = None,
|
91
|
-
context: EventContext = None,
|
89
|
+
context: EventContext | None = None,
|
92
90
|
**data,
|
93
|
-
):
|
91
|
+
) -> None:
|
94
92
|
"""Log an info message."""
|
95
93
|
self.event("info", name, message, context, data)
|
96
94
|
|
@@ -98,9 +96,9 @@ class Logger:
|
|
98
96
|
self,
|
99
97
|
message: str,
|
100
98
|
name: str | None = None,
|
101
|
-
context: EventContext = None,
|
99
|
+
context: EventContext | None = None,
|
102
100
|
**data,
|
103
|
-
):
|
101
|
+
) -> None:
|
104
102
|
"""Log a warning message."""
|
105
103
|
self.event("warning", name, message, context, data)
|
106
104
|
|
@@ -108,9 +106,9 @@ class Logger:
|
|
108
106
|
self,
|
109
107
|
message: str,
|
110
108
|
name: str | None = None,
|
111
|
-
context: EventContext = None,
|
109
|
+
context: EventContext | None = None,
|
112
110
|
**data,
|
113
|
-
):
|
111
|
+
) -> None:
|
114
112
|
"""Log an error message."""
|
115
113
|
self.event("error", name, message, context, data)
|
116
114
|
|
@@ -118,10 +116,10 @@ class Logger:
|
|
118
116
|
self,
|
119
117
|
message: str,
|
120
118
|
name: str | None = None,
|
121
|
-
percentage: float = None,
|
122
|
-
context: EventContext = None,
|
119
|
+
percentage: float | None = None,
|
120
|
+
context: EventContext | None = None,
|
123
121
|
**data,
|
124
|
-
):
|
122
|
+
) -> None:
|
125
123
|
"""Log a progress message."""
|
126
124
|
merged_data = dict(percentage=percentage, **data)
|
127
125
|
self.event("progress", name, message, context, merged_data)
|
@@ -194,7 +192,7 @@ class LoggingConfig:
|
|
194
192
|
batch_size: int = 100,
|
195
193
|
flush_interval: float = 2.0,
|
196
194
|
**kwargs: Any,
|
197
|
-
):
|
195
|
+
) -> None:
|
198
196
|
"""
|
199
197
|
Configure the logging system.
|
200
198
|
|
@@ -232,7 +230,7 @@ class LoggingConfig:
|
|
232
230
|
cls._initialized = True
|
233
231
|
|
234
232
|
@classmethod
|
235
|
-
async def shutdown(cls):
|
233
|
+
async def shutdown(cls) -> None:
|
236
234
|
"""Shutdown the logging system gracefully."""
|
237
235
|
if not cls._initialized:
|
238
236
|
return
|
@@ -1,18 +1,20 @@
|
|
1
1
|
"""Rich-based progress display for MCP Agent."""
|
2
2
|
|
3
3
|
import time
|
4
|
+
from contextlib import contextmanager
|
4
5
|
from typing import Optional
|
6
|
+
|
5
7
|
from rich.console import Console
|
6
|
-
from mcp_agent.console import console as default_console
|
7
|
-
from mcp_agent.event_progress import ProgressEvent, ProgressAction
|
8
8
|
from rich.progress import Progress, SpinnerColumn, TextColumn
|
9
|
-
|
9
|
+
|
10
|
+
from mcp_agent.console import console as default_console
|
11
|
+
from mcp_agent.event_progress import ProgressAction, ProgressEvent
|
10
12
|
|
11
13
|
|
12
14
|
class RichProgressDisplay:
|
13
15
|
"""Rich-based display for progress events."""
|
14
16
|
|
15
|
-
def __init__(self, console: Optional[Console] = None):
|
17
|
+
def __init__(self, console: Optional[Console] = None) -> None:
|
16
18
|
"""Initialize the progress display."""
|
17
19
|
self.console = console or default_console
|
18
20
|
self._taskmap = {}
|
@@ -29,16 +31,16 @@ class RichProgressDisplay:
|
|
29
31
|
)
|
30
32
|
self._paused = False
|
31
33
|
|
32
|
-
def start(self):
|
34
|
+
def start(self) -> None:
|
33
35
|
"""start"""
|
34
36
|
|
35
37
|
self._progress.start()
|
36
38
|
|
37
|
-
def stop(self):
|
39
|
+
def stop(self) -> None:
|
38
40
|
"""stop"""
|
39
41
|
self._progress.stop()
|
40
42
|
|
41
|
-
def pause(self):
|
43
|
+
def pause(self) -> None:
|
42
44
|
"""Pause the progress display."""
|
43
45
|
if not self._paused:
|
44
46
|
self._paused = True
|
@@ -47,7 +49,7 @@ class RichProgressDisplay:
|
|
47
49
|
task.visible = False
|
48
50
|
self._progress.stop()
|
49
51
|
|
50
|
-
def resume(self):
|
52
|
+
def resume(self) -> None:
|
51
53
|
"""Resume the progress display."""
|
52
54
|
if self._paused:
|
53
55
|
for task in self._progress.tasks:
|
mcp_agent/logging/tracing.py
CHANGED
@@ -5,16 +5,14 @@ for the Logger module for MCP Agent
|
|
5
5
|
|
6
6
|
import asyncio
|
7
7
|
import functools
|
8
|
-
from typing import
|
8
|
+
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple
|
9
9
|
|
10
10
|
from opentelemetry import trace
|
11
11
|
from opentelemetry.context import Context as OtelContext
|
12
12
|
from opentelemetry.propagate import extract as otel_extract
|
13
|
-
from opentelemetry.trace import set_span_in_context
|
13
|
+
from opentelemetry.trace import SpanKind, Status, StatusCode, set_span_in_context
|
14
14
|
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
|
15
15
|
|
16
|
-
from opentelemetry.trace import SpanKind, Status, StatusCode
|
17
|
-
|
18
16
|
from mcp_agent.context_dependent import ContextDependent
|
19
17
|
|
20
18
|
if TYPE_CHECKING:
|
@@ -27,7 +25,7 @@ class TelemetryManager(ContextDependent):
|
|
27
25
|
Decorator usage: @telemetry.traced("SomeSpanName")
|
28
26
|
"""
|
29
27
|
|
30
|
-
def __init__(self, context: Optional["Context"] = None, **kwargs):
|
28
|
+
def __init__(self, context: Optional["Context"] = None, **kwargs) -> None:
|
31
29
|
# If needed, configure resources, exporters, etc.
|
32
30
|
# E.g.: from opentelemetry.sdk.trace import TracerProvider
|
33
31
|
# trace.set_tracer_provider(TracerProvider(...))
|
@@ -88,7 +86,7 @@ class TelemetryManager(ContextDependent):
|
|
88
86
|
|
89
87
|
return decorator
|
90
88
|
|
91
|
-
def _record_args(self, span, args, kwargs):
|
89
|
+
def _record_args(self, span, args, kwargs) -> None:
|
92
90
|
"""Optionally record primitive args as span attributes."""
|
93
91
|
for i, arg in enumerate(args):
|
94
92
|
if isinstance(arg, (str, int, float, bool)):
|