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.
Files changed (169) hide show
  1. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.2.0.dist-info}/METADATA +3 -4
  2. fast_agent_mcp-0.2.0.dist-info/RECORD +123 -0
  3. mcp_agent/__init__.py +75 -0
  4. mcp_agent/agents/agent.py +61 -415
  5. mcp_agent/agents/base_agent.py +522 -0
  6. mcp_agent/agents/workflow/__init__.py +1 -0
  7. mcp_agent/agents/workflow/chain_agent.py +173 -0
  8. mcp_agent/agents/workflow/evaluator_optimizer.py +362 -0
  9. mcp_agent/agents/workflow/orchestrator_agent.py +591 -0
  10. mcp_agent/{workflows/orchestrator → agents/workflow}/orchestrator_models.py +11 -21
  11. mcp_agent/agents/workflow/parallel_agent.py +182 -0
  12. mcp_agent/agents/workflow/router_agent.py +307 -0
  13. mcp_agent/app.py +15 -19
  14. mcp_agent/cli/commands/bootstrap.py +19 -38
  15. mcp_agent/cli/commands/config.py +4 -4
  16. mcp_agent/cli/commands/setup.py +7 -14
  17. mcp_agent/cli/main.py +7 -10
  18. mcp_agent/cli/terminal.py +3 -3
  19. mcp_agent/config.py +25 -40
  20. mcp_agent/context.py +12 -21
  21. mcp_agent/context_dependent.py +3 -5
  22. mcp_agent/core/agent_types.py +10 -7
  23. mcp_agent/core/direct_agent_app.py +179 -0
  24. mcp_agent/core/direct_decorators.py +443 -0
  25. mcp_agent/core/direct_factory.py +476 -0
  26. mcp_agent/core/enhanced_prompt.py +23 -55
  27. mcp_agent/core/exceptions.py +8 -8
  28. mcp_agent/core/fastagent.py +145 -371
  29. mcp_agent/core/interactive_prompt.py +424 -0
  30. mcp_agent/core/mcp_content.py +17 -17
  31. mcp_agent/core/prompt.py +6 -9
  32. mcp_agent/core/request_params.py +6 -3
  33. mcp_agent/core/validation.py +92 -18
  34. mcp_agent/executor/decorator_registry.py +9 -17
  35. mcp_agent/executor/executor.py +8 -17
  36. mcp_agent/executor/task_registry.py +2 -4
  37. mcp_agent/executor/temporal.py +19 -41
  38. mcp_agent/executor/workflow.py +3 -5
  39. mcp_agent/executor/workflow_signal.py +15 -21
  40. mcp_agent/human_input/handler.py +4 -7
  41. mcp_agent/human_input/types.py +2 -3
  42. mcp_agent/llm/__init__.py +2 -0
  43. mcp_agent/llm/augmented_llm.py +450 -0
  44. mcp_agent/llm/augmented_llm_passthrough.py +162 -0
  45. mcp_agent/llm/augmented_llm_playback.py +83 -0
  46. mcp_agent/llm/memory.py +103 -0
  47. mcp_agent/{workflows/llm → llm}/model_factory.py +22 -16
  48. mcp_agent/{workflows/llm → llm}/prompt_utils.py +1 -3
  49. mcp_agent/llm/providers/__init__.py +8 -0
  50. mcp_agent/{workflows/llm → llm/providers}/anthropic_utils.py +8 -25
  51. mcp_agent/{workflows/llm → llm/providers}/augmented_llm_anthropic.py +56 -194
  52. mcp_agent/llm/providers/augmented_llm_deepseek.py +53 -0
  53. mcp_agent/{workflows/llm → llm/providers}/augmented_llm_openai.py +99 -190
  54. mcp_agent/{workflows/llm → llm}/providers/multipart_converter_anthropic.py +72 -71
  55. mcp_agent/{workflows/llm → llm}/providers/multipart_converter_openai.py +65 -71
  56. mcp_agent/{workflows/llm → llm}/providers/openai_multipart.py +16 -44
  57. mcp_agent/{workflows/llm → llm/providers}/openai_utils.py +4 -4
  58. mcp_agent/{workflows/llm → llm}/providers/sampling_converter_anthropic.py +9 -11
  59. mcp_agent/{workflows/llm → llm}/providers/sampling_converter_openai.py +8 -12
  60. mcp_agent/{workflows/llm → llm}/sampling_converter.py +3 -31
  61. mcp_agent/llm/sampling_format_converter.py +37 -0
  62. mcp_agent/logging/events.py +1 -5
  63. mcp_agent/logging/json_serializer.py +7 -6
  64. mcp_agent/logging/listeners.py +20 -23
  65. mcp_agent/logging/logger.py +17 -19
  66. mcp_agent/logging/rich_progress.py +10 -8
  67. mcp_agent/logging/tracing.py +4 -6
  68. mcp_agent/logging/transport.py +22 -22
  69. mcp_agent/mcp/gen_client.py +1 -3
  70. mcp_agent/mcp/interfaces.py +117 -110
  71. mcp_agent/mcp/logger_textio.py +97 -0
  72. mcp_agent/mcp/mcp_agent_client_session.py +7 -7
  73. mcp_agent/mcp/mcp_agent_server.py +8 -8
  74. mcp_agent/mcp/mcp_aggregator.py +102 -143
  75. mcp_agent/mcp/mcp_connection_manager.py +20 -27
  76. mcp_agent/mcp/prompt_message_multipart.py +68 -16
  77. mcp_agent/mcp/prompt_render.py +77 -0
  78. mcp_agent/mcp/prompt_serialization.py +30 -48
  79. mcp_agent/mcp/prompts/prompt_constants.py +18 -0
  80. mcp_agent/mcp/prompts/prompt_helpers.py +327 -0
  81. mcp_agent/mcp/prompts/prompt_load.py +109 -0
  82. mcp_agent/mcp/prompts/prompt_server.py +155 -195
  83. mcp_agent/mcp/prompts/prompt_template.py +35 -66
  84. mcp_agent/mcp/resource_utils.py +7 -14
  85. mcp_agent/mcp/sampling.py +17 -17
  86. mcp_agent/mcp_server/agent_server.py +13 -17
  87. mcp_agent/mcp_server_registry.py +13 -22
  88. mcp_agent/resources/examples/{workflows → in_dev}/agent_build.py +3 -2
  89. mcp_agent/resources/examples/in_dev/slides.py +110 -0
  90. mcp_agent/resources/examples/internal/agent.py +6 -3
  91. mcp_agent/resources/examples/internal/fastagent.config.yaml +8 -2
  92. mcp_agent/resources/examples/internal/job.py +2 -1
  93. mcp_agent/resources/examples/internal/prompt_category.py +1 -1
  94. mcp_agent/resources/examples/internal/prompt_sizing.py +3 -5
  95. mcp_agent/resources/examples/internal/sizer.py +2 -1
  96. mcp_agent/resources/examples/internal/social.py +2 -1
  97. mcp_agent/resources/examples/prompting/agent.py +2 -1
  98. mcp_agent/resources/examples/prompting/image_server.py +4 -8
  99. mcp_agent/resources/examples/prompting/work_with_image.py +19 -0
  100. mcp_agent/ui/console_display.py +16 -20
  101. fast_agent_mcp-0.1.12.dist-info/RECORD +0 -161
  102. mcp_agent/core/agent_app.py +0 -646
  103. mcp_agent/core/agent_utils.py +0 -71
  104. mcp_agent/core/decorators.py +0 -455
  105. mcp_agent/core/factory.py +0 -463
  106. mcp_agent/core/proxies.py +0 -269
  107. mcp_agent/core/types.py +0 -24
  108. mcp_agent/eval/__init__.py +0 -0
  109. mcp_agent/mcp/stdio.py +0 -111
  110. mcp_agent/resources/examples/data-analysis/analysis-campaign.py +0 -188
  111. mcp_agent/resources/examples/data-analysis/analysis.py +0 -65
  112. mcp_agent/resources/examples/data-analysis/fastagent.config.yaml +0 -41
  113. mcp_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +0 -1471
  114. mcp_agent/resources/examples/mcp_researcher/researcher-eval.py +0 -53
  115. mcp_agent/resources/examples/researcher/fastagent.config.yaml +0 -66
  116. mcp_agent/resources/examples/researcher/researcher-eval.py +0 -53
  117. mcp_agent/resources/examples/researcher/researcher-imp.py +0 -190
  118. mcp_agent/resources/examples/researcher/researcher.py +0 -38
  119. mcp_agent/resources/examples/workflows/chaining.py +0 -44
  120. mcp_agent/resources/examples/workflows/evaluator.py +0 -78
  121. mcp_agent/resources/examples/workflows/fastagent.config.yaml +0 -24
  122. mcp_agent/resources/examples/workflows/human_input.py +0 -25
  123. mcp_agent/resources/examples/workflows/orchestrator.py +0 -73
  124. mcp_agent/resources/examples/workflows/parallel.py +0 -78
  125. mcp_agent/resources/examples/workflows/router.py +0 -53
  126. mcp_agent/resources/examples/workflows/sse.py +0 -23
  127. mcp_agent/telemetry/__init__.py +0 -0
  128. mcp_agent/telemetry/usage_tracking.py +0 -18
  129. mcp_agent/workflows/__init__.py +0 -0
  130. mcp_agent/workflows/embedding/__init__.py +0 -0
  131. mcp_agent/workflows/embedding/embedding_base.py +0 -61
  132. mcp_agent/workflows/embedding/embedding_cohere.py +0 -49
  133. mcp_agent/workflows/embedding/embedding_openai.py +0 -46
  134. mcp_agent/workflows/evaluator_optimizer/__init__.py +0 -0
  135. mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +0 -481
  136. mcp_agent/workflows/intent_classifier/__init__.py +0 -0
  137. mcp_agent/workflows/intent_classifier/intent_classifier_base.py +0 -120
  138. mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py +0 -134
  139. mcp_agent/workflows/intent_classifier/intent_classifier_embedding_cohere.py +0 -45
  140. mcp_agent/workflows/intent_classifier/intent_classifier_embedding_openai.py +0 -45
  141. mcp_agent/workflows/intent_classifier/intent_classifier_llm.py +0 -161
  142. mcp_agent/workflows/intent_classifier/intent_classifier_llm_anthropic.py +0 -60
  143. mcp_agent/workflows/intent_classifier/intent_classifier_llm_openai.py +0 -60
  144. mcp_agent/workflows/llm/__init__.py +0 -0
  145. mcp_agent/workflows/llm/augmented_llm.py +0 -753
  146. mcp_agent/workflows/llm/augmented_llm_passthrough.py +0 -241
  147. mcp_agent/workflows/llm/augmented_llm_playback.py +0 -109
  148. mcp_agent/workflows/llm/providers/__init__.py +0 -8
  149. mcp_agent/workflows/llm/sampling_format_converter.py +0 -22
  150. mcp_agent/workflows/orchestrator/__init__.py +0 -0
  151. mcp_agent/workflows/orchestrator/orchestrator.py +0 -578
  152. mcp_agent/workflows/parallel/__init__.py +0 -0
  153. mcp_agent/workflows/parallel/fan_in.py +0 -350
  154. mcp_agent/workflows/parallel/fan_out.py +0 -187
  155. mcp_agent/workflows/parallel/parallel_llm.py +0 -166
  156. mcp_agent/workflows/router/__init__.py +0 -0
  157. mcp_agent/workflows/router/router_base.py +0 -368
  158. mcp_agent/workflows/router/router_embedding.py +0 -240
  159. mcp_agent/workflows/router/router_embedding_cohere.py +0 -59
  160. mcp_agent/workflows/router/router_embedding_openai.py +0 -59
  161. mcp_agent/workflows/router/router_llm.py +0 -320
  162. mcp_agent/workflows/swarm/__init__.py +0 -0
  163. mcp_agent/workflows/swarm/swarm.py +0 -320
  164. mcp_agent/workflows/swarm/swarm_anthropic.py +0 -42
  165. mcp_agent/workflows/swarm/swarm_openai.py +0 -41
  166. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.2.0.dist-info}/WHEEL +0 -0
  167. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.2.0.dist-info}/entry_points.txt +0 -0
  168. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.2.0.dist-info}/licenses/LICENSE +0 -0
  169. /mcp_agent/{workflows/orchestrator → agents/workflow}/orchestrator_prompts.py +0 -0
@@ -1,14 +1,35 @@
1
1
  from typing import List, Union
2
- from pydantic import BaseModel
3
2
 
4
3
  from mcp.types import (
5
- PromptMessage,
6
- TextContent,
7
- ImageContent,
8
4
  EmbeddedResource,
9
- Role,
10
5
  GetPromptResult,
6
+ ImageContent,
7
+ PromptMessage,
8
+ Role,
9
+ TextContent,
10
+ TextResourceContents,
11
11
  )
12
+ from pydantic import BaseModel
13
+
14
+
15
+ def get_text(content: Union[TextContent, ImageContent, EmbeddedResource]) -> str | None:
16
+ """
17
+ Extract text content from a content object if available.
18
+
19
+ Args:
20
+ content: A content object (TextContent, ImageContent, or EmbeddedResource)
21
+
22
+ Returns:
23
+ The text content as a string or None if not a text content
24
+ """
25
+ if isinstance(content, TextContent):
26
+ return content.text
27
+
28
+ if isinstance(content, EmbeddedResource):
29
+ if isinstance(content.resource, TextResourceContents):
30
+ return content.resource.text
31
+
32
+ return None
12
33
 
13
34
 
14
35
  class PromptMessageMultipart(BaseModel):
@@ -21,9 +42,7 @@ class PromptMessageMultipart(BaseModel):
21
42
  content: List[Union[TextContent, ImageContent, EmbeddedResource]]
22
43
 
23
44
  @classmethod
24
- def from_prompt_messages(
25
- cls, messages: List[PromptMessage]
26
- ) -> List["PromptMessageMultipart"]:
45
+ def to_multipart(cls, messages: List[PromptMessage]) -> List["PromptMessageMultipart"]:
27
46
  """Convert a sequence of PromptMessages into PromptMessageMultipart objects."""
28
47
  if not messages:
29
48
  return []
@@ -41,7 +60,8 @@ class PromptMessageMultipart(BaseModel):
41
60
  current_group = cls(role=msg.role, content=[msg.content])
42
61
  else:
43
62
  # Same role, add to current message
44
- current_group.content.append(msg.content)
63
+ if current_group is not None:
64
+ current_group.content.append(msg.content)
45
65
 
46
66
  # Add the last group
47
67
  if current_group is not None:
@@ -49,16 +69,48 @@ class PromptMessageMultipart(BaseModel):
49
69
 
50
70
  return result
51
71
 
52
- def to_prompt_messages(self) -> List[PromptMessage]:
72
+ def from_multipart(self) -> List[PromptMessage]:
53
73
  """Convert this PromptMessageMultipart to a sequence of standard PromptMessages."""
54
74
  return [
55
- PromptMessage(role=self.role, content=content_part)
56
- for content_part in self.content
75
+ PromptMessage(role=self.role, content=content_part) for content_part in self.content
57
76
  ]
58
77
 
78
+ def first_text(self) -> str:
79
+ """
80
+ Get the first available text content from a message.
81
+
82
+ Args:
83
+ message: A PromptMessage or PromptMessageMultipart
84
+
85
+ Returns:
86
+ First text content or None if no text content exists
87
+ """
88
+ for content in self.content:
89
+ text = get_text(content)
90
+ if text is not None:
91
+ return text
92
+
93
+ return "<no text>"
94
+
95
+ def all_text(self) -> str:
96
+ """
97
+ Get all the text available.
98
+
99
+ Args:
100
+ message: A PromptMessage or PromptMessageMultipart
101
+
102
+ Returns:
103
+ First text content or None if no text content exists
104
+ """
105
+ result = []
106
+ for content in self.content:
107
+ text = get_text(content)
108
+ if text is not None:
109
+ result.append(text)
110
+
111
+ return "\n".join(result)
112
+
59
113
  @classmethod
60
- def parse_get_prompt_result(
61
- cls, result: GetPromptResult
62
- ) -> List["PromptMessageMultipart"]:
114
+ def parse_get_prompt_result(cls, result: GetPromptResult) -> List["PromptMessageMultipart"]:
63
115
  """Parse a GetPromptResult into PromptMessageMultipart objects."""
64
- return cls.from_prompt_messages(result.messages)
116
+ return cls.to_multipart(result.messages)
@@ -0,0 +1,77 @@
1
+ """
2
+ Utilities for rendering PromptMessageMultipart objects for display.
3
+ """
4
+
5
+ from typing import List
6
+
7
+ from mcp.types import BlobResourceContents, TextResourceContents
8
+
9
+ from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
10
+ from mcp_agent.mcp.prompts.prompt_helpers import (
11
+ get_resource_uri,
12
+ get_text,
13
+ is_image_content,
14
+ is_resource_content,
15
+ is_text_content,
16
+ )
17
+
18
+
19
+ def render_multipart_message(message: PromptMessageMultipart) -> 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 PromptMessageMultipart 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_content = content # type: TextContent
38
+ rendered_parts.append(text_content.text)
39
+
40
+ elif is_image_content(content):
41
+ # Format details about the image
42
+ image_content = content # type: ImageContent
43
+ data_size = len(image_content.data) if image_content.data else 0
44
+ image_info = f"[IMAGE: {image_content.mimeType}, {data_size} bytes]"
45
+ rendered_parts.append(image_info)
46
+
47
+ elif is_resource_content(content):
48
+ # Handle embedded resources
49
+ resource = content # type: EmbeddedResource
50
+ uri = get_resource_uri(resource)
51
+
52
+ if isinstance(resource.resource, TextResourceContents):
53
+ # Handle text resources
54
+ text = resource.resource.text
55
+ text_length = len(text)
56
+ mime_type = resource.resource.mimeType
57
+
58
+ # Preview with truncation for long content
59
+ preview = text[:300] + ("..." if text_length > 300 else "")
60
+ resource_info = f"[EMBEDDED TEXT RESOURCE: {mime_type}, {uri}, {text_length} chars]\n{preview}"
61
+ rendered_parts.append(resource_info)
62
+
63
+ elif isinstance(resource.resource, BlobResourceContents):
64
+ # Handle blob resources (binary data)
65
+ blob_length = len(resource.resource.blob) if resource.resource.blob else 0
66
+ mime_type = resource.resource.mimeType
67
+
68
+ resource_info = f"[EMBEDDED BLOB RESOURCE: {mime_type}, {uri}, {blob_length} bytes]"
69
+ rendered_parts.append(resource_info)
70
+
71
+ else:
72
+ # Fallback for other content types
73
+ text = get_text(content)
74
+ if text is not None:
75
+ rendered_parts.append(text)
76
+
77
+ return "\n".join(rendered_parts)
@@ -19,9 +19,14 @@ and PromptMessageMultipart objects. It includes functionality for:
19
19
  import json
20
20
  from typing import List
21
21
 
22
- from mcp.types import TextContent, EmbeddedResource, ImageContent, TextResourceContents
23
- from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
22
+ from mcp.types import EmbeddedResource, ImageContent, TextContent, TextResourceContents
24
23
 
24
+ from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
25
+ from mcp_agent.mcp.prompts.prompt_constants import (
26
+ ASSISTANT_DELIMITER,
27
+ RESOURCE_DELIMITER,
28
+ USER_DELIMITER,
29
+ )
25
30
 
26
31
  # -------------------------------------------------------------------------
27
32
  # JSON Serialization Functions
@@ -44,8 +49,7 @@ def multipart_messages_to_json(messages: List[PromptMessageMultipart]) -> str:
44
49
  # Convert to dictionaries using model_dump with proper JSON mode
45
50
  # The mode="json" parameter ensures proper handling of AnyUrl objects
46
51
  message_dicts = [
47
- message.model_dump(by_alias=True, mode="json", exclude_none=True)
48
- for message in messages
52
+ message.model_dump(by_alias=True, mode="json", exclude_none=True) for message in messages
49
53
  ]
50
54
 
51
55
  # Convert to JSON string
@@ -76,9 +80,7 @@ def json_to_multipart_messages(json_str: str) -> List[PromptMessageMultipart]:
76
80
  return messages
77
81
 
78
82
 
79
- def save_messages_to_json_file(
80
- messages: List[PromptMessageMultipart], file_path: str
81
- ) -> None:
83
+ def save_messages_to_json_file(messages: List[PromptMessageMultipart], file_path: str) -> None:
82
84
  """
83
85
  Save PromptMessageMultipart objects to a JSON file.
84
86
 
@@ -115,9 +117,9 @@ def load_messages_from_json_file(file_path: str) -> List[PromptMessageMultipart]
115
117
 
116
118
  def multipart_messages_to_delimited_format(
117
119
  messages: List[PromptMessageMultipart],
118
- user_delimiter: str = "---USER",
119
- assistant_delimiter: str = "---ASSISTANT",
120
- resource_delimiter: str = "---RESOURCE",
120
+ user_delimiter: str = USER_DELIMITER,
121
+ assistant_delimiter: str = ASSISTANT_DELIMITER,
122
+ resource_delimiter: str = RESOURCE_DELIMITER,
121
123
  combine_text: bool = True, # Set to False to maintain backward compatibility
122
124
  ) -> List[str]:
123
125
  """
@@ -169,9 +171,7 @@ def multipart_messages_to_delimited_format(
169
171
  delimited_content.append(resource_delimiter)
170
172
 
171
173
  # Convert to dictionary using proper JSON mode
172
- content_dict = content.model_dump(
173
- by_alias=True, mode="json", exclude_none=True
174
- )
174
+ content_dict = content.model_dump(by_alias=True, mode="json", exclude_none=True)
175
175
 
176
176
  # Add to delimited content as JSON
177
177
  delimited_content.append(json.dumps(content_dict, indent=2))
@@ -186,9 +186,7 @@ def multipart_messages_to_delimited_format(
186
186
  delimited_content.append(resource_delimiter)
187
187
 
188
188
  # Convert to dictionary using proper JSON mode
189
- content_dict = content.model_dump(
190
- by_alias=True, mode="json", exclude_none=True
191
- )
189
+ content_dict = content.model_dump(by_alias=True, mode="json", exclude_none=True)
192
190
 
193
191
  # Add to delimited content as JSON
194
192
  delimited_content.append(json.dumps(content_dict, indent=2))
@@ -198,9 +196,9 @@ def multipart_messages_to_delimited_format(
198
196
 
199
197
  def delimited_format_to_multipart_messages(
200
198
  content: str,
201
- user_delimiter: str = "---USER",
202
- assistant_delimiter: str = "---ASSISTANT",
203
- resource_delimiter: str = "---RESOURCE",
199
+ user_delimiter: str = USER_DELIMITER,
200
+ assistant_delimiter: str = ASSISTANT_DELIMITER,
201
+ resource_delimiter: str = RESOURCE_DELIMITER,
204
202
  ) -> List[PromptMessageMultipart]:
205
203
  """
206
204
  Parse hybrid delimited format into PromptMessageMultipart objects:
@@ -237,31 +235,23 @@ def delimited_format_to_multipart_messages(
237
235
  collecting_text = True
238
236
 
239
237
  # Process each line
240
- for line in (
241
- lines[1:] if lines else []
242
- ): # Skip the first line if already processed above
238
+ for line in lines[1:] if lines else []: # Skip the first line if already processed above
243
239
  line_stripped = line.strip()
244
240
 
245
241
  # Handle role delimiters
246
242
  if line_stripped == user_delimiter or line_stripped == assistant_delimiter:
247
243
  # Save previous message if it exists
248
- if current_role is not None and (
249
- text_contents or resource_contents or text_lines
250
- ):
244
+ if current_role is not None and (text_contents or resource_contents or text_lines):
251
245
  # If we were collecting text, add it to the text contents
252
246
  if collecting_text and text_lines:
253
- text_contents.append(
254
- TextContent(type="text", text="\n".join(text_lines))
255
- )
247
+ text_contents.append(TextContent(type="text", text="\n".join(text_lines)))
256
248
  text_lines = []
257
249
 
258
250
  # Create content list with text parts first, then resource parts
259
251
  combined_content = []
260
252
 
261
253
  # Filter out any empty text content items
262
- filtered_text_contents = [
263
- tc for tc in text_contents if tc.text.strip() != ""
264
- ]
254
+ filtered_text_contents = [tc for tc in text_contents if tc.text.strip() != ""]
265
255
 
266
256
  combined_content.extend(filtered_text_contents)
267
257
  combined_content.extend(resource_contents)
@@ -286,9 +276,7 @@ def delimited_format_to_multipart_messages(
286
276
  elif line_stripped == resource_delimiter:
287
277
  # If we were collecting text, add it to text contents
288
278
  if collecting_text and text_lines:
289
- text_contents.append(
290
- TextContent(type="text", text="\n".join(text_lines))
291
- )
279
+ text_contents.append(TextContent(type="text", text="\n".join(text_lines)))
292
280
  text_lines = []
293
281
 
294
282
  # Switch to collecting JSON or legacy format
@@ -303,11 +291,7 @@ def delimited_format_to_multipart_messages(
303
291
  json_lines.append(line)
304
292
 
305
293
  # For legacy format or files where resources are just plain text
306
- if (
307
- legacy_format
308
- and line_stripped
309
- and not line_stripped.startswith("{")
310
- ):
294
+ if legacy_format and line_stripped and not line_stripped.startswith("{"):
311
295
  # This is probably a legacy resource reference like a filename
312
296
  resource_uri = line_stripped
313
297
  if not resource_uri.startswith("resource://"):
@@ -370,9 +354,7 @@ def delimited_format_to_multipart_messages(
370
354
  combined_content = []
371
355
 
372
356
  # Filter out any empty text content items
373
- filtered_text_contents = [
374
- tc for tc in text_contents if tc.text.strip() != ""
375
- ]
357
+ filtered_text_contents = [tc for tc in text_contents if tc.text.strip() != ""]
376
358
 
377
359
  combined_content.extend(filtered_text_contents)
378
360
  combined_content.extend(resource_contents)
@@ -390,9 +372,9 @@ def delimited_format_to_multipart_messages(
390
372
  def save_messages_to_delimited_file(
391
373
  messages: List[PromptMessageMultipart],
392
374
  file_path: str,
393
- user_delimiter: str = "---USER",
394
- assistant_delimiter: str = "---ASSISTANT",
395
- resource_delimiter: str = "---RESOURCE",
375
+ user_delimiter: str = USER_DELIMITER,
376
+ assistant_delimiter: str = ASSISTANT_DELIMITER,
377
+ resource_delimiter: str = RESOURCE_DELIMITER,
396
378
  combine_text: bool = True,
397
379
  ) -> None:
398
380
  """
@@ -420,9 +402,9 @@ def save_messages_to_delimited_file(
420
402
 
421
403
  def load_messages_from_delimited_file(
422
404
  file_path: str,
423
- user_delimiter: str = "---USER",
424
- assistant_delimiter: str = "---ASSISTANT",
425
- resource_delimiter: str = "---RESOURCE",
405
+ user_delimiter: str = USER_DELIMITER,
406
+ assistant_delimiter: str = ASSISTANT_DELIMITER,
407
+ resource_delimiter: str = RESOURCE_DELIMITER,
426
408
  ) -> List[PromptMessageMultipart]:
427
409
  """
428
410
  Load PromptMessageMultipart objects from a file in hybrid delimited format.
@@ -0,0 +1,18 @@
1
+ """
2
+ Constants for the prompt system.
3
+
4
+ This module defines constants used throughout the prompt system, including
5
+ delimiters for parsing prompt files and serializing prompt messages.
6
+ """
7
+
8
+ # Standard delimiters used for prompt template parsing and serialization
9
+ USER_DELIMITER = "---USER"
10
+ ASSISTANT_DELIMITER = "---ASSISTANT"
11
+ RESOURCE_DELIMITER = "---RESOURCE"
12
+
13
+ # Default delimiter mapping used by PromptTemplate and PromptTemplateLoader
14
+ DEFAULT_DELIMITER_MAP = {
15
+ USER_DELIMITER: "user",
16
+ ASSISTANT_DELIMITER: "assistant",
17
+ RESOURCE_DELIMITER: "resource",
18
+ }