fast-agent-mcp 0.4.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fast_agent/__init__.py +183 -0
- fast_agent/acp/__init__.py +19 -0
- fast_agent/acp/acp_aware_mixin.py +304 -0
- fast_agent/acp/acp_context.py +437 -0
- fast_agent/acp/content_conversion.py +136 -0
- fast_agent/acp/filesystem_runtime.py +427 -0
- fast_agent/acp/permission_store.py +269 -0
- fast_agent/acp/server/__init__.py +5 -0
- fast_agent/acp/server/agent_acp_server.py +1472 -0
- fast_agent/acp/slash_commands.py +1050 -0
- fast_agent/acp/terminal_runtime.py +408 -0
- fast_agent/acp/tool_permission_adapter.py +125 -0
- fast_agent/acp/tool_permissions.py +474 -0
- fast_agent/acp/tool_progress.py +814 -0
- fast_agent/agents/__init__.py +85 -0
- fast_agent/agents/agent_types.py +64 -0
- fast_agent/agents/llm_agent.py +350 -0
- fast_agent/agents/llm_decorator.py +1139 -0
- fast_agent/agents/mcp_agent.py +1337 -0
- fast_agent/agents/tool_agent.py +271 -0
- fast_agent/agents/workflow/agents_as_tools_agent.py +849 -0
- fast_agent/agents/workflow/chain_agent.py +212 -0
- fast_agent/agents/workflow/evaluator_optimizer.py +380 -0
- fast_agent/agents/workflow/iterative_planner.py +652 -0
- fast_agent/agents/workflow/maker_agent.py +379 -0
- fast_agent/agents/workflow/orchestrator_models.py +218 -0
- fast_agent/agents/workflow/orchestrator_prompts.py +248 -0
- fast_agent/agents/workflow/parallel_agent.py +250 -0
- fast_agent/agents/workflow/router_agent.py +353 -0
- fast_agent/cli/__init__.py +0 -0
- fast_agent/cli/__main__.py +73 -0
- fast_agent/cli/commands/acp.py +159 -0
- fast_agent/cli/commands/auth.py +404 -0
- fast_agent/cli/commands/check_config.py +783 -0
- fast_agent/cli/commands/go.py +514 -0
- fast_agent/cli/commands/quickstart.py +557 -0
- fast_agent/cli/commands/serve.py +143 -0
- fast_agent/cli/commands/server_helpers.py +114 -0
- fast_agent/cli/commands/setup.py +174 -0
- fast_agent/cli/commands/url_parser.py +190 -0
- fast_agent/cli/constants.py +40 -0
- fast_agent/cli/main.py +115 -0
- fast_agent/cli/terminal.py +24 -0
- fast_agent/config.py +798 -0
- fast_agent/constants.py +41 -0
- fast_agent/context.py +279 -0
- fast_agent/context_dependent.py +50 -0
- fast_agent/core/__init__.py +92 -0
- fast_agent/core/agent_app.py +448 -0
- fast_agent/core/core_app.py +137 -0
- fast_agent/core/direct_decorators.py +784 -0
- fast_agent/core/direct_factory.py +620 -0
- fast_agent/core/error_handling.py +27 -0
- fast_agent/core/exceptions.py +90 -0
- fast_agent/core/executor/__init__.py +0 -0
- fast_agent/core/executor/executor.py +280 -0
- fast_agent/core/executor/task_registry.py +32 -0
- fast_agent/core/executor/workflow_signal.py +324 -0
- fast_agent/core/fastagent.py +1186 -0
- fast_agent/core/logging/__init__.py +5 -0
- fast_agent/core/logging/events.py +138 -0
- fast_agent/core/logging/json_serializer.py +164 -0
- fast_agent/core/logging/listeners.py +309 -0
- fast_agent/core/logging/logger.py +278 -0
- fast_agent/core/logging/transport.py +481 -0
- fast_agent/core/prompt.py +9 -0
- fast_agent/core/prompt_templates.py +183 -0
- fast_agent/core/validation.py +326 -0
- fast_agent/event_progress.py +62 -0
- fast_agent/history/history_exporter.py +49 -0
- fast_agent/human_input/__init__.py +47 -0
- fast_agent/human_input/elicitation_handler.py +123 -0
- fast_agent/human_input/elicitation_state.py +33 -0
- fast_agent/human_input/form_elements.py +59 -0
- fast_agent/human_input/form_fields.py +256 -0
- fast_agent/human_input/simple_form.py +113 -0
- fast_agent/human_input/types.py +40 -0
- fast_agent/interfaces.py +310 -0
- fast_agent/llm/__init__.py +9 -0
- fast_agent/llm/cancellation.py +22 -0
- fast_agent/llm/fastagent_llm.py +931 -0
- fast_agent/llm/internal/passthrough.py +161 -0
- fast_agent/llm/internal/playback.py +129 -0
- fast_agent/llm/internal/silent.py +41 -0
- fast_agent/llm/internal/slow.py +38 -0
- fast_agent/llm/memory.py +275 -0
- fast_agent/llm/model_database.py +490 -0
- fast_agent/llm/model_factory.py +388 -0
- fast_agent/llm/model_info.py +102 -0
- fast_agent/llm/prompt_utils.py +155 -0
- fast_agent/llm/provider/anthropic/anthropic_utils.py +84 -0
- fast_agent/llm/provider/anthropic/cache_planner.py +56 -0
- fast_agent/llm/provider/anthropic/llm_anthropic.py +796 -0
- fast_agent/llm/provider/anthropic/multipart_converter_anthropic.py +462 -0
- fast_agent/llm/provider/bedrock/bedrock_utils.py +218 -0
- fast_agent/llm/provider/bedrock/llm_bedrock.py +2207 -0
- fast_agent/llm/provider/bedrock/multipart_converter_bedrock.py +84 -0
- fast_agent/llm/provider/google/google_converter.py +466 -0
- fast_agent/llm/provider/google/llm_google_native.py +681 -0
- fast_agent/llm/provider/openai/llm_aliyun.py +31 -0
- fast_agent/llm/provider/openai/llm_azure.py +143 -0
- fast_agent/llm/provider/openai/llm_deepseek.py +76 -0
- fast_agent/llm/provider/openai/llm_generic.py +35 -0
- fast_agent/llm/provider/openai/llm_google_oai.py +32 -0
- fast_agent/llm/provider/openai/llm_groq.py +42 -0
- fast_agent/llm/provider/openai/llm_huggingface.py +85 -0
- fast_agent/llm/provider/openai/llm_openai.py +1195 -0
- fast_agent/llm/provider/openai/llm_openai_compatible.py +138 -0
- fast_agent/llm/provider/openai/llm_openrouter.py +45 -0
- fast_agent/llm/provider/openai/llm_tensorzero_openai.py +128 -0
- fast_agent/llm/provider/openai/llm_xai.py +38 -0
- fast_agent/llm/provider/openai/multipart_converter_openai.py +561 -0
- fast_agent/llm/provider/openai/openai_multipart.py +169 -0
- fast_agent/llm/provider/openai/openai_utils.py +67 -0
- fast_agent/llm/provider/openai/responses.py +133 -0
- fast_agent/llm/provider_key_manager.py +139 -0
- fast_agent/llm/provider_types.py +34 -0
- fast_agent/llm/request_params.py +61 -0
- fast_agent/llm/sampling_converter.py +98 -0
- fast_agent/llm/stream_types.py +9 -0
- fast_agent/llm/usage_tracking.py +445 -0
- fast_agent/mcp/__init__.py +56 -0
- fast_agent/mcp/common.py +26 -0
- fast_agent/mcp/elicitation_factory.py +84 -0
- fast_agent/mcp/elicitation_handlers.py +164 -0
- fast_agent/mcp/gen_client.py +83 -0
- fast_agent/mcp/helpers/__init__.py +36 -0
- fast_agent/mcp/helpers/content_helpers.py +352 -0
- fast_agent/mcp/helpers/server_config_helpers.py +25 -0
- fast_agent/mcp/hf_auth.py +147 -0
- fast_agent/mcp/interfaces.py +92 -0
- fast_agent/mcp/logger_textio.py +108 -0
- fast_agent/mcp/mcp_agent_client_session.py +411 -0
- fast_agent/mcp/mcp_aggregator.py +2175 -0
- fast_agent/mcp/mcp_connection_manager.py +723 -0
- fast_agent/mcp/mcp_content.py +262 -0
- fast_agent/mcp/mime_utils.py +108 -0
- fast_agent/mcp/oauth_client.py +509 -0
- fast_agent/mcp/prompt.py +159 -0
- fast_agent/mcp/prompt_message_extended.py +155 -0
- fast_agent/mcp/prompt_render.py +84 -0
- fast_agent/mcp/prompt_serialization.py +580 -0
- fast_agent/mcp/prompts/__init__.py +0 -0
- fast_agent/mcp/prompts/__main__.py +7 -0
- fast_agent/mcp/prompts/prompt_constants.py +18 -0
- fast_agent/mcp/prompts/prompt_helpers.py +238 -0
- fast_agent/mcp/prompts/prompt_load.py +186 -0
- fast_agent/mcp/prompts/prompt_server.py +552 -0
- fast_agent/mcp/prompts/prompt_template.py +438 -0
- fast_agent/mcp/resource_utils.py +215 -0
- fast_agent/mcp/sampling.py +200 -0
- fast_agent/mcp/server/__init__.py +4 -0
- fast_agent/mcp/server/agent_server.py +613 -0
- fast_agent/mcp/skybridge.py +44 -0
- fast_agent/mcp/sse_tracking.py +287 -0
- fast_agent/mcp/stdio_tracking_simple.py +59 -0
- fast_agent/mcp/streamable_http_tracking.py +309 -0
- fast_agent/mcp/tool_execution_handler.py +137 -0
- fast_agent/mcp/tool_permission_handler.py +88 -0
- fast_agent/mcp/transport_tracking.py +634 -0
- fast_agent/mcp/types.py +24 -0
- fast_agent/mcp/ui_agent.py +48 -0
- fast_agent/mcp/ui_mixin.py +209 -0
- fast_agent/mcp_server_registry.py +89 -0
- fast_agent/py.typed +0 -0
- fast_agent/resources/examples/data-analysis/analysis-campaign.py +189 -0
- fast_agent/resources/examples/data-analysis/analysis.py +68 -0
- fast_agent/resources/examples/data-analysis/fastagent.config.yaml +41 -0
- fast_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +1471 -0
- fast_agent/resources/examples/mcp/elicitations/elicitation_account_server.py +88 -0
- fast_agent/resources/examples/mcp/elicitations/elicitation_forms_server.py +297 -0
- fast_agent/resources/examples/mcp/elicitations/elicitation_game_server.py +164 -0
- fast_agent/resources/examples/mcp/elicitations/fastagent.config.yaml +35 -0
- fast_agent/resources/examples/mcp/elicitations/fastagent.secrets.yaml.example +17 -0
- fast_agent/resources/examples/mcp/elicitations/forms_demo.py +107 -0
- fast_agent/resources/examples/mcp/elicitations/game_character.py +65 -0
- fast_agent/resources/examples/mcp/elicitations/game_character_handler.py +256 -0
- fast_agent/resources/examples/mcp/elicitations/tool_call.py +21 -0
- fast_agent/resources/examples/mcp/state-transfer/agent_one.py +18 -0
- fast_agent/resources/examples/mcp/state-transfer/agent_two.py +18 -0
- fast_agent/resources/examples/mcp/state-transfer/fastagent.config.yaml +27 -0
- fast_agent/resources/examples/mcp/state-transfer/fastagent.secrets.yaml.example +15 -0
- fast_agent/resources/examples/researcher/fastagent.config.yaml +61 -0
- fast_agent/resources/examples/researcher/researcher-eval.py +53 -0
- fast_agent/resources/examples/researcher/researcher-imp.py +189 -0
- fast_agent/resources/examples/researcher/researcher.py +36 -0
- fast_agent/resources/examples/tensorzero/.env.sample +2 -0
- fast_agent/resources/examples/tensorzero/Makefile +31 -0
- fast_agent/resources/examples/tensorzero/README.md +56 -0
- fast_agent/resources/examples/tensorzero/agent.py +35 -0
- fast_agent/resources/examples/tensorzero/demo_images/clam.jpg +0 -0
- fast_agent/resources/examples/tensorzero/demo_images/crab.png +0 -0
- fast_agent/resources/examples/tensorzero/demo_images/shrimp.png +0 -0
- fast_agent/resources/examples/tensorzero/docker-compose.yml +105 -0
- fast_agent/resources/examples/tensorzero/fastagent.config.yaml +19 -0
- fast_agent/resources/examples/tensorzero/image_demo.py +67 -0
- fast_agent/resources/examples/tensorzero/mcp_server/Dockerfile +25 -0
- fast_agent/resources/examples/tensorzero/mcp_server/entrypoint.sh +35 -0
- fast_agent/resources/examples/tensorzero/mcp_server/mcp_server.py +31 -0
- fast_agent/resources/examples/tensorzero/mcp_server/pyproject.toml +11 -0
- fast_agent/resources/examples/tensorzero/simple_agent.py +25 -0
- fast_agent/resources/examples/tensorzero/tensorzero_config/system_schema.json +29 -0
- fast_agent/resources/examples/tensorzero/tensorzero_config/system_template.minijinja +11 -0
- fast_agent/resources/examples/tensorzero/tensorzero_config/tensorzero.toml +35 -0
- fast_agent/resources/examples/workflows/agents_as_tools_extended.py +73 -0
- fast_agent/resources/examples/workflows/agents_as_tools_simple.py +50 -0
- fast_agent/resources/examples/workflows/chaining.py +37 -0
- fast_agent/resources/examples/workflows/evaluator.py +77 -0
- fast_agent/resources/examples/workflows/fastagent.config.yaml +26 -0
- fast_agent/resources/examples/workflows/graded_report.md +89 -0
- fast_agent/resources/examples/workflows/human_input.py +28 -0
- fast_agent/resources/examples/workflows/maker.py +156 -0
- fast_agent/resources/examples/workflows/orchestrator.py +70 -0
- fast_agent/resources/examples/workflows/parallel.py +56 -0
- fast_agent/resources/examples/workflows/router.py +69 -0
- fast_agent/resources/examples/workflows/short_story.md +13 -0
- fast_agent/resources/examples/workflows/short_story.txt +19 -0
- fast_agent/resources/setup/.gitignore +30 -0
- fast_agent/resources/setup/agent.py +28 -0
- fast_agent/resources/setup/fastagent.config.yaml +65 -0
- fast_agent/resources/setup/fastagent.secrets.yaml.example +38 -0
- fast_agent/resources/setup/pyproject.toml.tmpl +23 -0
- fast_agent/skills/__init__.py +9 -0
- fast_agent/skills/registry.py +235 -0
- fast_agent/tools/elicitation.py +369 -0
- fast_agent/tools/shell_runtime.py +402 -0
- fast_agent/types/__init__.py +59 -0
- fast_agent/types/conversation_summary.py +294 -0
- fast_agent/types/llm_stop_reason.py +78 -0
- fast_agent/types/message_search.py +249 -0
- fast_agent/ui/__init__.py +38 -0
- fast_agent/ui/console.py +59 -0
- fast_agent/ui/console_display.py +1080 -0
- fast_agent/ui/elicitation_form.py +946 -0
- fast_agent/ui/elicitation_style.py +59 -0
- fast_agent/ui/enhanced_prompt.py +1400 -0
- fast_agent/ui/history_display.py +734 -0
- fast_agent/ui/interactive_prompt.py +1199 -0
- fast_agent/ui/markdown_helpers.py +104 -0
- fast_agent/ui/markdown_truncator.py +1004 -0
- fast_agent/ui/mcp_display.py +857 -0
- fast_agent/ui/mcp_ui_utils.py +235 -0
- fast_agent/ui/mermaid_utils.py +169 -0
- fast_agent/ui/message_primitives.py +50 -0
- fast_agent/ui/notification_tracker.py +205 -0
- fast_agent/ui/plain_text_truncator.py +68 -0
- fast_agent/ui/progress_display.py +10 -0
- fast_agent/ui/rich_progress.py +195 -0
- fast_agent/ui/streaming.py +774 -0
- fast_agent/ui/streaming_buffer.py +449 -0
- fast_agent/ui/tool_display.py +422 -0
- fast_agent/ui/usage_display.py +204 -0
- fast_agent/utils/__init__.py +5 -0
- fast_agent/utils/reasoning_stream_parser.py +77 -0
- fast_agent/utils/time.py +22 -0
- fast_agent/workflow_telemetry.py +261 -0
- fast_agent_mcp-0.4.7.dist-info/METADATA +788 -0
- fast_agent_mcp-0.4.7.dist-info/RECORD +261 -0
- fast_agent_mcp-0.4.7.dist-info/WHEEL +4 -0
- fast_agent_mcp-0.4.7.dist-info/entry_points.txt +7 -0
- fast_agent_mcp-0.4.7.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
from typing import Mapping, Sequence
|
|
2
|
+
|
|
3
|
+
from mcp.types import (
|
|
4
|
+
CallToolRequest,
|
|
5
|
+
CallToolResult,
|
|
6
|
+
ContentBlock,
|
|
7
|
+
GetPromptResult,
|
|
8
|
+
PromptMessage,
|
|
9
|
+
Role,
|
|
10
|
+
TextContent,
|
|
11
|
+
)
|
|
12
|
+
from pydantic import BaseModel
|
|
13
|
+
|
|
14
|
+
from fast_agent.mcp.helpers.content_helpers import get_text
|
|
15
|
+
|
|
16
|
+
# Import directly to avoid circular dependency with types/__init__.py
|
|
17
|
+
from fast_agent.types.llm_stop_reason import LlmStopReason
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class PromptMessageExtended(BaseModel):
|
|
21
|
+
"""
|
|
22
|
+
Extension of PromptMessage that handles multiple content parts.
|
|
23
|
+
Internally converts to/from a sequence of standard PromptMessages.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
role: Role
|
|
27
|
+
content: list[ContentBlock] = []
|
|
28
|
+
tool_calls: dict[str, CallToolRequest] | None = None
|
|
29
|
+
tool_results: dict[str, CallToolResult] | None = None
|
|
30
|
+
channels: Mapping[str, Sequence[ContentBlock]] | None = None
|
|
31
|
+
stop_reason: LlmStopReason | None = None
|
|
32
|
+
is_template: bool = False
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def to_extended(cls, messages: list[PromptMessage]) -> list["PromptMessageExtended"]:
|
|
36
|
+
"""Convert a sequence of PromptMessages into PromptMessageExtended objects."""
|
|
37
|
+
if not messages:
|
|
38
|
+
return []
|
|
39
|
+
|
|
40
|
+
result = []
|
|
41
|
+
current_group = None
|
|
42
|
+
current_role = None
|
|
43
|
+
|
|
44
|
+
for msg in messages:
|
|
45
|
+
if msg.role != current_role:
|
|
46
|
+
# Role changed, start new message
|
|
47
|
+
if current_group is not None:
|
|
48
|
+
result.append(current_group)
|
|
49
|
+
current_role = msg.role
|
|
50
|
+
current_group = cls(role=msg.role, content=[msg.content])
|
|
51
|
+
else:
|
|
52
|
+
# Same role, add to current message
|
|
53
|
+
if current_group is not None:
|
|
54
|
+
current_group.content.append(msg.content)
|
|
55
|
+
|
|
56
|
+
# Add the last group
|
|
57
|
+
if current_group is not None:
|
|
58
|
+
result.append(current_group)
|
|
59
|
+
|
|
60
|
+
return result
|
|
61
|
+
|
|
62
|
+
def from_multipart(self) -> list[PromptMessage]:
|
|
63
|
+
"""Convert this PromptMessageExtended to a sequence of standard PromptMessages."""
|
|
64
|
+
return [
|
|
65
|
+
PromptMessage(role=self.role, content=content_part) for content_part in self.content
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
def first_text(self) -> str:
|
|
69
|
+
"""
|
|
70
|
+
Get the first available text content from a message. Note this could be tool content etc.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
message: A PromptMessage or PromptMessageExtended
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
First text content or None if no text content exists
|
|
77
|
+
"""
|
|
78
|
+
for content in self.content:
|
|
79
|
+
text = get_text(content)
|
|
80
|
+
if text is not None:
|
|
81
|
+
return text
|
|
82
|
+
|
|
83
|
+
return "<no text>"
|
|
84
|
+
|
|
85
|
+
def last_text(self) -> str | None:
|
|
86
|
+
"""
|
|
87
|
+
Get the last available text content from a message. This will usually be the final
|
|
88
|
+
generation from the Assistant.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
message: A PromptMessage or PromptMessageExtended
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
First text content or None if no text content exists
|
|
95
|
+
"""
|
|
96
|
+
for content in reversed(self.content):
|
|
97
|
+
text = get_text(content)
|
|
98
|
+
if text is not None:
|
|
99
|
+
return text
|
|
100
|
+
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
def all_text(self) -> str:
|
|
104
|
+
"""
|
|
105
|
+
Get all the text available.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
message: A PromptMessage or PromptMessageExtended
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
First text content or None if no text content exists
|
|
112
|
+
"""
|
|
113
|
+
result = []
|
|
114
|
+
for content in self.content:
|
|
115
|
+
text = get_text(content)
|
|
116
|
+
if text is not None:
|
|
117
|
+
result.append(text)
|
|
118
|
+
|
|
119
|
+
return "\n".join(result)
|
|
120
|
+
|
|
121
|
+
def add_text(self, to_add: str) -> TextContent:
|
|
122
|
+
text = TextContent(type="text", text=to_add)
|
|
123
|
+
self.content.append(text)
|
|
124
|
+
return text
|
|
125
|
+
|
|
126
|
+
@classmethod
|
|
127
|
+
def parse_get_prompt_result(cls, result: GetPromptResult) -> list["PromptMessageExtended"]:
|
|
128
|
+
"""
|
|
129
|
+
Parse a GetPromptResult into PromptMessageExtended objects.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
result: GetPromptResult from MCP server
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
List of PromptMessageExtended objects
|
|
136
|
+
"""
|
|
137
|
+
return cls.to_extended(result.messages)
|
|
138
|
+
|
|
139
|
+
@classmethod
|
|
140
|
+
def from_get_prompt_result(
|
|
141
|
+
cls, result: GetPromptResult | None
|
|
142
|
+
) -> list["PromptMessageExtended"]:
|
|
143
|
+
"""
|
|
144
|
+
Convert a GetPromptResult to PromptMessageExtended objects with error handling.
|
|
145
|
+
This method safely handles None values and empty results.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
result: GetPromptResult from MCP server or None
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
List of PromptMessageExtended objects or empty list if result is None/empty
|
|
152
|
+
"""
|
|
153
|
+
if not result or not result.messages:
|
|
154
|
+
return []
|
|
155
|
+
return cls.to_extended(result.messages)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utilities for rendering PromptMessageExtended objects for display.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import cast
|
|
6
|
+
|
|
7
|
+
from mcp.types import BlobResourceContents, EmbeddedResource, ImageContent, TextResourceContents
|
|
8
|
+
|
|
9
|
+
from fast_agent.mcp.helpers.content_helpers import (
|
|
10
|
+
get_resource_uri,
|
|
11
|
+
get_text,
|
|
12
|
+
is_image_content,
|
|
13
|
+
is_resource_content,
|
|
14
|
+
is_text_content,
|
|
15
|
+
)
|
|
16
|
+
from fast_agent.types import PromptMessageExtended
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def render_multipart_message(message: PromptMessageExtended) -> str:
|
|
20
|
+
"""
|
|
21
|
+
Render a multipart message for display purposes.
|
|
22
|
+
|
|
23
|
+
This function formats the message content for user-friendly display,
|
|
24
|
+
handling different content types appropriately.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
message: A PromptMessageExtended object to render
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
A string representation of the message's content
|
|
31
|
+
"""
|
|
32
|
+
rendered_parts: list[str] = []
|
|
33
|
+
|
|
34
|
+
for content in message.content:
|
|
35
|
+
if is_text_content(content):
|
|
36
|
+
# Handle text content
|
|
37
|
+
text = get_text(content)
|
|
38
|
+
if text:
|
|
39
|
+
rendered_parts.append(text)
|
|
40
|
+
|
|
41
|
+
elif is_image_content(content):
|
|
42
|
+
# Format details about the image
|
|
43
|
+
image = cast("ImageContent", content)
|
|
44
|
+
image_data = image.data
|
|
45
|
+
data_size = len(image_data) if image_data else 0
|
|
46
|
+
mime_type = image.mimeType
|
|
47
|
+
image_info = f"[IMAGE: {mime_type}, {data_size} bytes]"
|
|
48
|
+
rendered_parts.append(image_info)
|
|
49
|
+
|
|
50
|
+
elif is_resource_content(content):
|
|
51
|
+
# Handle embedded resources
|
|
52
|
+
uri = get_resource_uri(content)
|
|
53
|
+
embedded = cast("EmbeddedResource", content)
|
|
54
|
+
resource = embedded.resource
|
|
55
|
+
|
|
56
|
+
if isinstance(resource, TextResourceContents):
|
|
57
|
+
# Handle text resources
|
|
58
|
+
text = resource.text
|
|
59
|
+
text_length = len(text)
|
|
60
|
+
mime_type = resource.mimeType or "text/plain"
|
|
61
|
+
|
|
62
|
+
# Preview with truncation for long content
|
|
63
|
+
preview = text[:300] + ("..." if text_length > 300 else "")
|
|
64
|
+
resource_info = (
|
|
65
|
+
f"[EMBEDDED TEXT RESOURCE: {mime_type}, {uri}, {text_length} chars]\n{preview}"
|
|
66
|
+
)
|
|
67
|
+
rendered_parts.append(resource_info)
|
|
68
|
+
|
|
69
|
+
elif isinstance(resource, BlobResourceContents):
|
|
70
|
+
# Handle blob resources (binary data)
|
|
71
|
+
blob = resource.blob
|
|
72
|
+
blob_length = len(blob) if blob else 0
|
|
73
|
+
mime_type = resource.mimeType or "application/octet-stream"
|
|
74
|
+
|
|
75
|
+
resource_info = f"[EMBEDDED BLOB RESOURCE: {mime_type}, {uri}, {blob_length} bytes]"
|
|
76
|
+
rendered_parts.append(resource_info)
|
|
77
|
+
|
|
78
|
+
else:
|
|
79
|
+
# Fallback for other content types
|
|
80
|
+
text = get_text(content)
|
|
81
|
+
if text is not None:
|
|
82
|
+
rendered_parts.append(text)
|
|
83
|
+
|
|
84
|
+
return "\n".join(rendered_parts)
|