markdown-flow 0.2.28__tar.gz → 0.2.30__tar.gz

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 (34) hide show
  1. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/PKG-INFO +1 -1
  2. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/__init__.py +2 -2
  3. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/constants.py +14 -36
  4. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/core.py +69 -99
  5. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/models.py +0 -16
  6. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/parser/validation.py +16 -37
  7. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/providers/config.py +1 -3
  8. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/providers/openai.py +1 -1
  9. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow.egg-info/PKG-INFO +1 -1
  10. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/LICENSE +0 -0
  11. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/README.md +0 -0
  12. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/enums.py +0 -0
  13. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/exceptions.py +0 -0
  14. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/llm.py +0 -0
  15. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/parser/__init__.py +0 -0
  16. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/parser/code_fence_utils.py +0 -0
  17. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/parser/interaction.py +0 -0
  18. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/parser/json_parser.py +0 -0
  19. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/parser/output.py +0 -0
  20. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/parser/preprocessor.py +0 -0
  21. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/parser/variable.py +0 -0
  22. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/providers/__init__.py +0 -0
  23. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow/utils.py +0 -0
  24. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow.egg-info/SOURCES.txt +0 -0
  25. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow.egg-info/dependency_links.txt +0 -0
  26. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/markdown_flow.egg-info/top_level.txt +0 -0
  27. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/pyproject.toml +0 -0
  28. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/setup.cfg +0 -0
  29. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/tests/test_dynamic_interaction.py +0 -0
  30. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/tests/test_markdownflow_basic.py +0 -0
  31. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/tests/test_parser_interaction.py +0 -0
  32. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/tests/test_parser_variable.py +0 -0
  33. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/tests/test_preprocessor.py +0 -0
  34. {markdown_flow-0.2.28 → markdown_flow-0.2.30}/tests/test_preserved_simple.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markdown-flow
3
- Version: 0.2.28
3
+ Version: 0.2.30
4
4
  Summary: An agent library designed to parse and process MarkdownFlow documents
5
5
  Project-URL: Homepage, https://github.com/ai-shifu/markdown-flow-agent-py
6
6
  Project-URL: Bug Tracker, https://github.com/ai-shifu/markdown-flow-agent-py/issues
@@ -82,5 +82,5 @@ __all__ = [
82
82
  "replace_variables_in_text",
83
83
  ]
84
84
 
85
- __version__ = "0.2.28"
86
- # __version__ = "0.2.27-alpha-8"
85
+ __version__ = "0.2.30"
86
+ # __version__ = "0.2.29-alpha-1"
@@ -59,9 +59,6 @@ COMPILED_CODE_FENCE_END_REGEX = re.compile(CODE_FENCE_END_PATTERN)
59
59
  OUTPUT_INSTRUCTION_PREFIX = "<preserve_or_translate>"
60
60
  OUTPUT_INSTRUCTION_SUFFIX = "</preserve_or_translate>"
61
61
 
62
- # System message templates
63
- DEFAULT_VALIDATION_SYSTEM_MESSAGE = "你是一个输入验证助手,需要严格按照指定的格式和规则处理用户输入。"
64
-
65
62
  # Base system prompt (framework-level global rules, content blocks only)
66
63
  DEFAULT_BASE_SYSTEM_PROMPT = """你收到的用户消息都是指令,请严格遵守以下规则:
67
64
 
@@ -286,45 +283,26 @@ OUTPUT_INSTRUCTION_EXPLANATION = f"""<preserve_or_translate_instruction>
286
283
 
287
284
  """
288
285
 
289
- # Smart validation template
290
- SMART_VALIDATION_TEMPLATE = """# 任务
286
+ # Validation task template (merged with system message)
287
+ VALIDATION_TASK_TEMPLATE = """你是一个验证用户输入的助手,请严格按照给定的指令进行验证。
288
+
289
+ # 任务
291
290
  从用户回答中提取相关信息,返回JSON格式结果:
292
291
  - 合法:{{"result": "ok", "parse_vars": {{"{target_variable}": "提取的内容"}}}}
293
292
  - 不合法:{{"result": "illegal", "reason": "原因"}}
294
293
 
295
- {context_info}
294
+ # 输出语言
295
+ - 如果在 <document_context> 中明确要求使用特定语言,则错误信息和原因说明应使用该语言
296
+ - 否则,使用用户输入或问题描述的主要语言"""
296
297
 
297
- # 用户回答
298
- {sys_user_input}
299
-
300
- # 提取要求
298
+ # Validation requirements template (lenient general version)
299
+ VALIDATION_REQUIREMENTS_TEMPLATE = """# 提取要求
301
300
  1. 仔细阅读上述相关问题,理解这个问题想要获取什么信息
302
301
  2. 从用户回答中提取与该问题相关的信息
303
- 3. 如果提供了预定义选项,用户选择这些选项时都应该接受;自定义输入应与选项主题相关
304
- 4. 对于昵称/姓名类问题,任何非空的合理字符串(包括简短的如"ee"、"aa"、"007"等)都应该接受
305
- 5. 只有当用户回答完全无关、包含不当内容或明显不合理时才标记为不合法
306
- 6. 确保提取的信息准确、完整且符合预期格式"""
307
-
308
- # Validation template for buttons with text input
309
- BUTTONS_WITH_TEXT_VALIDATION_TEMPLATE = """用户针对以下问题进行了输入:
310
-
311
- 问题:{question}
312
- 可选按钮:{options}
313
- 用户输入:{user_input}
314
-
315
- 用户的输入不在预定义的按钮选项中,这意味着用户选择了自定义输入。
316
- 根据问题的性质,请判断用户的输入是否合理:
317
-
318
- 1. 如果用户输入能够表达与按钮选项类似的概念(比如按钮有"幽默、大气、二次元",用户输入了"搞笑"),请接受。
319
- 2. 如果用户输入是对问题的合理回答(比如问题要求描述风格,用户输入了任何有效的风格描述),请接受。
320
- 3. 只有当用户输入完全不相关、包含不当内容、或明显不合理时,才拒绝。
321
-
322
- 请按以下 JSON 格式回复:
323
- {{
324
- "result": "ok|illegal",
325
- "parse_vars": {{"{target_variable}": "提取的值"}},
326
- "reason": "接受或拒绝的原因"
327
- }}"""
302
+ 3. 如果提供了预定义选项,用户选择这些选项时都应该接受;自定义输入只要是对问题的合理回答即可接受
303
+ 4. 对于昵称、姓名、标签等自由文本输入,任何非空的合理表达都应该接受(包括数字、字母、符号、emoji等创意性表达)
304
+ 5. 只有当用户回答完全无关、包含不当内容或明显违背常识时才标记为不合法
305
+ 6. 宽松验证原则:理解用户意图,接受多样化的合理表达形式"""
328
306
 
329
307
  # ========== Error Message Constants ==========
330
308
 
@@ -355,5 +333,5 @@ CONTEXT_BUTTON_OPTIONS_MARKER = "## 预定义选项"
355
333
  CONTEXT_QUESTION_TEMPLATE = f"{CONTEXT_QUESTION_MARKER}\n{{question}}"
356
334
  CONTEXT_CONVERSATION_TEMPLATE = f"{CONTEXT_CONVERSATION_MARKER}\n{{content}}"
357
335
  CONTEXT_BUTTON_OPTIONS_TEMPLATE = (
358
- f"{CONTEXT_BUTTON_OPTIONS_MARKER}\n可选的预定义选项包括:{{button_options}}\n注意:用户如果选择了这些选项,都应该接受;如果输入了自定义内容,应检查是否与选项主题相关。"
336
+ f"{CONTEXT_BUTTON_OPTIONS_MARKER}\n可选的预定义选项包括:{{button_options}}\n注意:用户如果选择了这些选项,都应该接受;如果输入了自定义内容,只要是对问题的合理回答即可接受。"
359
337
  )
@@ -13,11 +13,11 @@ from typing import Any
13
13
  from .constants import (
14
14
  BLOCK_INDEX_OUT_OF_RANGE_ERROR,
15
15
  BLOCK_SEPARATOR,
16
- BUTTONS_WITH_TEXT_VALIDATION_TEMPLATE,
16
+ CONTEXT_BUTTON_OPTIONS_TEMPLATE,
17
+ CONTEXT_QUESTION_TEMPLATE,
17
18
  DEFAULT_BASE_SYSTEM_PROMPT,
18
19
  DEFAULT_INTERACTION_ERROR_PROMPT,
19
20
  DEFAULT_INTERACTION_PROMPT,
20
- DEFAULT_VALIDATION_SYSTEM_MESSAGE,
21
21
  INPUT_EMPTY_ERROR,
22
22
  INTERACTION_ERROR_RENDER_INSTRUCTIONS,
23
23
  INTERACTION_PARSE_ERROR,
@@ -26,16 +26,17 @@ from .constants import (
26
26
  LLM_PROVIDER_REQUIRED_ERROR,
27
27
  OUTPUT_INSTRUCTION_EXPLANATION,
28
28
  UNSUPPORTED_PROMPT_TYPE_ERROR,
29
+ VALIDATION_REQUIREMENTS_TEMPLATE,
30
+ VALIDATION_TASK_TEMPLATE,
29
31
  )
30
32
  from .enums import BlockType
31
33
  from .exceptions import BlockIndexError
32
34
  from .llm import LLMProvider, LLMResult, ProcessMode
33
- from .models import Block, InteractionValidationConfig
35
+ from .models import Block
34
36
  from .parser import (
35
37
  CodeBlockPreprocessor,
36
38
  InteractionParser,
37
39
  InteractionType,
38
- extract_interaction_question,
39
40
  extract_preserved_content,
40
41
  extract_variables_from_text,
41
42
  is_preserved_content_block,
@@ -60,7 +61,6 @@ class MarkdownFlow:
60
61
  _interaction_error_prompt: str | None
61
62
  _max_context_length: int
62
63
  _blocks: list[Block] | None
63
- _interaction_configs: dict[int, InteractionValidationConfig]
64
64
  _model: str | None
65
65
  _temperature: float | None
66
66
  _preprocessor: CodeBlockPreprocessor
@@ -95,7 +95,6 @@ class MarkdownFlow:
95
95
  self._interaction_error_prompt = interaction_error_prompt or DEFAULT_INTERACTION_ERROR_PROMPT
96
96
  self._max_context_length = max_context_length
97
97
  self._blocks = None
98
- self._interaction_configs: dict[int, InteractionValidationConfig] = {}
99
98
  self._model: str | None = None
100
99
  self._temperature: float | None = None
101
100
 
@@ -310,14 +309,6 @@ class MarkdownFlow:
310
309
  """Extract all variable names from the document."""
311
310
  return extract_variables_from_text(self._document)
312
311
 
313
- def set_interaction_validation_config(self, block_index: int, config: InteractionValidationConfig) -> None:
314
- """Set validation config for specified interaction block."""
315
- self._interaction_configs[block_index] = config
316
-
317
- def get_interaction_validation_config(self, block_index: int) -> InteractionValidationConfig | None:
318
- """Get validation config for specified interaction block."""
319
- return self._interaction_configs.get(block_index)
320
-
321
312
  # Core unified interface
322
313
 
323
314
  def process(
@@ -472,9 +463,7 @@ class MarkdownFlow:
472
463
  translated_json = self._llm_provider.complete(messages, model=self._model, temperature=self._temperature)
473
464
 
474
465
  # 使用翻译结果重构交互内容
475
- translated_content = self._reconstruct_with_translation(
476
- processed_block.content, translatable_json, translated_json, interaction_info
477
- )
466
+ translated_content = self._reconstruct_with_translation(processed_block.content, translatable_json, translated_json, interaction_info)
478
467
 
479
468
  return LLMResult(
480
469
  content=translated_content,
@@ -509,9 +498,7 @@ class MarkdownFlow:
509
498
  full_response += chunk
510
499
 
511
500
  # 使用翻译结果重构交互内容
512
- translated_content = self._reconstruct_with_translation(
513
- processed_block.content, translatable_json, full_response, interaction_info
514
- )
501
+ translated_content = self._reconstruct_with_translation(processed_block.content, translatable_json, full_response, interaction_info)
515
502
 
516
503
  # 一次性返回完整内容(不是增量)
517
504
  yield LLMResult(
@@ -847,8 +834,8 @@ class MarkdownFlow:
847
834
  mode: ProcessMode,
848
835
  ) -> LLMResult | Generator[LLMResult, None, None]:
849
836
  """Process LLM validation with button options (third case)."""
850
- # Build special validation messages containing button option information
851
- messages = self._build_validation_messages_with_options(user_input, target_variable, options, question)
837
+ # Use unified validation message builder (button context will be included automatically)
838
+ messages = self._build_validation_messages(block_index, user_input, target_variable, context=None)
852
839
 
853
840
  if mode == ProcessMode.COMPLETE:
854
841
  if not self._llm_provider:
@@ -977,9 +964,7 @@ class MarkdownFlow:
977
964
 
978
965
  return messages
979
966
 
980
- def _extract_translatable_content(
981
- self, interaction_content: str
982
- ) -> tuple[str, dict[str, Any] | None]:
967
+ def _extract_translatable_content(self, interaction_content: str) -> tuple[str, dict[str, Any] | None]:
983
968
  """提取交互内容中需要翻译的部分为 JSON 格式
984
969
 
985
970
  Args:
@@ -1007,13 +992,12 @@ class MarkdownFlow:
1007
992
 
1008
993
  # 转换为 JSON
1009
994
  import json
995
+
1010
996
  json_str = json.dumps(translatable, ensure_ascii=False)
1011
997
 
1012
998
  return json_str, interaction_info
1013
999
 
1014
- def _build_translation_messages(
1015
- self, translatable_json: str
1016
- ) -> list[dict[str, str]]:
1000
+ def _build_translation_messages(self, translatable_json: str) -> list[dict[str, str]]:
1017
1001
  """构建翻译用的消息列表
1018
1002
 
1019
1003
  Args:
@@ -1118,87 +1102,73 @@ class MarkdownFlow:
1118
1102
  target_variable: str,
1119
1103
  context: list[dict[str, str]] | None = None,
1120
1104
  ) -> list[dict[str, str]]:
1121
- """Build validation messages."""
1122
- block = self.get_block(block_index)
1123
- config = self.get_interaction_validation_config(block_index)
1124
-
1125
- # Truncate context to configured maximum length
1126
- truncated_context = self._truncate_context(context)
1127
-
1128
- if config and config.validation_template:
1129
- # Use custom validation template
1130
- validation_prompt = config.validation_template
1131
- user_input_str = json.dumps(user_input, ensure_ascii=False)
1132
- validation_prompt = validation_prompt.replace("{sys_user_input}", user_input_str)
1133
- validation_prompt = validation_prompt.replace("{block_content}", block.content)
1134
- validation_prompt = validation_prompt.replace("{target_variable}", target_variable)
1135
- system_message = DEFAULT_VALIDATION_SYSTEM_MESSAGE
1136
- else:
1137
- # Use smart default validation template
1138
- from .parser import (
1139
- InteractionParser,
1140
- extract_interaction_question,
1141
- generate_smart_validation_template,
1142
- )
1143
-
1144
- # Extract interaction question
1145
- interaction_question = extract_interaction_question(block.content)
1146
-
1147
- # Parse interaction to extract button information
1148
- parser = InteractionParser()
1149
- parse_result = parser.parse(block.content)
1150
- buttons = parse_result.get("buttons") if "buttons" in parse_result else None
1151
-
1152
- # Generate smart validation template with context and buttons
1153
- validation_template = generate_smart_validation_template(
1154
- target_variable,
1155
- context=truncated_context,
1156
- interaction_question=interaction_question,
1157
- buttons=buttons,
1158
- )
1105
+ """
1106
+ Build validation messages with new structure.
1159
1107
 
1160
- # Replace template variables
1161
- user_input_str = json.dumps(user_input, ensure_ascii=False)
1162
- validation_prompt = validation_template.replace("{sys_user_input}", user_input_str)
1163
- validation_prompt = validation_prompt.replace("{block_content}", block.content)
1164
- validation_prompt = validation_prompt.replace("{target_variable}", target_variable)
1165
- system_message = DEFAULT_VALIDATION_SYSTEM_MESSAGE
1108
+ System message contains:
1109
+ - VALIDATION_TASK_TEMPLATE (includes task description and output language rules)
1110
+ - Question context (if exists)
1111
+ - Button options context (if exists)
1112
+ - VALIDATION_REQUIREMENTS_TEMPLATE
1113
+ - document_prompt wrapped in <document_context> tags (if exists)
1166
1114
 
1167
- messages = []
1115
+ User message contains:
1116
+ - User input only
1117
+ """
1118
+ from .parser import InteractionParser, extract_interaction_question
1168
1119
 
1169
- messages.append({"role": "system", "content": system_message})
1120
+ block = self.get_block(block_index)
1170
1121
 
1171
- # Add conversation history context if provided (only if not using custom template)
1172
- if truncated_context and not (config and config.validation_template):
1173
- messages.extend(truncated_context)
1122
+ # Extract user input values for target variable
1123
+ target_values = user_input.get(target_variable, [])
1124
+ user_input_str = ", ".join(target_values) if target_values else ""
1174
1125
 
1175
- messages.append({"role": "user", "content": validation_prompt})
1126
+ # Build System Message (contains all validation rules and context)
1127
+ # VALIDATION_TASK_TEMPLATE already includes system message, directly replace variables
1128
+ task_template = VALIDATION_TASK_TEMPLATE.replace("{target_variable}", target_variable)
1129
+ system_parts = [task_template]
1176
1130
 
1177
- return messages
1131
+ # Extract interaction question
1132
+ interaction_question = extract_interaction_question(block.content)
1178
1133
 
1179
- def _build_validation_messages_with_options(
1180
- self,
1181
- user_input: dict[str, list[str]],
1182
- target_variable: str,
1183
- options: list[str],
1184
- question: str,
1185
- ) -> list[dict[str, str]]:
1186
- """Build validation messages with button options (third case)."""
1187
- # Use validation template from constants
1188
- user_input_str = json.dumps(user_input, ensure_ascii=False)
1189
- validation_prompt = BUTTONS_WITH_TEXT_VALIDATION_TEMPLATE.format(
1190
- question=question,
1191
- options=", ".join(options),
1192
- user_input=user_input_str,
1193
- target_variable=target_variable,
1194
- )
1134
+ # Add question context (if exists)
1135
+ if interaction_question:
1136
+ question_context = CONTEXT_QUESTION_TEMPLATE.format(question=interaction_question)
1137
+ system_parts.append("")
1138
+ system_parts.append(question_context)
1195
1139
 
1196
- messages = []
1140
+ # Parse interaction to extract button information
1141
+ parser = InteractionParser()
1142
+ parse_result = parser.parse(block.content)
1143
+ buttons = parse_result.get("buttons") if "buttons" in parse_result else None
1144
+
1145
+ # Add button options context (if exists)
1146
+ if buttons:
1147
+ button_displays = [btn.get("display", "") for btn in buttons if btn.get("display")]
1148
+ if button_displays:
1149
+ button_options = "、".join(button_displays)
1150
+ button_context = CONTEXT_BUTTON_OPTIONS_TEMPLATE.format(button_options=button_options)
1151
+ system_parts.append("")
1152
+ system_parts.append(button_context)
1153
+
1154
+ # Add extraction requirements (using template)
1155
+ system_parts.append("")
1156
+ system_parts.append(VALIDATION_REQUIREMENTS_TEMPLATE)
1157
+
1158
+ # Add document_prompt (if exists)
1197
1159
  if self._document_prompt:
1198
- messages.append({"role": "system", "content": self._document_prompt})
1160
+ system_parts.append("")
1161
+ system_parts.append("<document_context>")
1162
+ system_parts.append(self._document_prompt)
1163
+ system_parts.append("</document_context>")
1199
1164
 
1200
- messages.append({"role": "system", "content": DEFAULT_VALIDATION_SYSTEM_MESSAGE})
1201
- messages.append({"role": "user", "content": validation_prompt})
1165
+ system_content = "\n".join(system_parts)
1166
+
1167
+ # Build message list
1168
+ messages = [
1169
+ {"role": "system", "content": system_content},
1170
+ {"role": "user", "content": user_input_str}, # Only user input
1171
+ ]
1202
1172
 
1203
1173
  return messages
1204
1174
 
@@ -26,22 +26,6 @@ class UserInput:
26
26
  is_multi_select: bool = False
27
27
 
28
28
 
29
- @dataclass
30
- class InteractionValidationConfig:
31
- """
32
- Simplified interaction validation configuration.
33
-
34
- Attributes:
35
- validation_template (Optional[str]): Validation prompt template
36
- target_variable (Optional[str]): Target variable name
37
- enable_custom_validation (bool): Enable custom validation, defaults to True
38
- """
39
-
40
- validation_template: str | None = None
41
- target_variable: str | None = None
42
- enable_custom_validation: bool = True
43
-
44
-
45
29
  @dataclass
46
30
  class Block:
47
31
  """
@@ -12,10 +12,10 @@ from ..constants import (
12
12
  CONTEXT_CONVERSATION_TEMPLATE,
13
13
  CONTEXT_QUESTION_MARKER,
14
14
  CONTEXT_QUESTION_TEMPLATE,
15
- SMART_VALIDATION_TEMPLATE,
16
15
  VALIDATION_ILLEGAL_DEFAULT_REASON,
17
16
  VALIDATION_RESPONSE_ILLEGAL,
18
17
  VALIDATION_RESPONSE_OK,
18
+ VALIDATION_TASK_TEMPLATE,
19
19
  )
20
20
  from .json_parser import parse_json_response
21
21
 
@@ -29,6 +29,9 @@ def generate_smart_validation_template(
29
29
  """
30
30
  Generate smart validation template based on context and question.
31
31
 
32
+ DEPRECATED: This function is no longer used internally.
33
+ Use _build_validation_messages() in MarkdownFlow class instead.
34
+
32
35
  Args:
33
36
  target_variable: Target variable name
34
37
  context: Context message list with role and content fields
@@ -36,42 +39,13 @@ def generate_smart_validation_template(
36
39
  buttons: Button options list with display and value fields
37
40
 
38
41
  Returns:
39
- Generated validation template
42
+ Generated validation template (for backward compatibility)
40
43
  """
41
- # Build context information
42
- context_info = ""
43
- if interaction_question or context or buttons:
44
- context_parts = []
45
-
46
- # Add question information (most important, put first)
47
- if interaction_question:
48
- context_parts.append(CONTEXT_QUESTION_TEMPLATE.format(question=interaction_question))
49
-
50
- # Add button options information
51
- if buttons:
52
- button_displays = [btn.get("display", "") for btn in buttons if btn.get("display")]
53
- if button_displays:
54
- button_options_str = ", ".join(button_displays)
55
- button_info = CONTEXT_BUTTON_OPTIONS_TEMPLATE.format(button_options=button_options_str)
56
- context_parts.append(button_info)
57
-
58
- # Add conversation context
59
- if context:
60
- for msg in context:
61
- if msg.get("role") == "assistant" and CONTEXT_QUESTION_MARKER not in msg.get("content", ""):
62
- # Other assistant messages as context (exclude extracted questions)
63
- context_parts.append(CONTEXT_CONVERSATION_TEMPLATE.format(content=msg.get("content", "")))
64
-
65
- if context_parts:
66
- context_info = "\n\n".join(context_parts)
67
-
68
- # Use template from constants
69
- # Note: {sys_user_input} will be replaced later in _build_validation_messages
70
- return SMART_VALIDATION_TEMPLATE.format(
71
- target_variable=target_variable,
72
- context_info=context_info,
73
- sys_user_input="{sys_user_input}", # Keep placeholder for later replacement
74
- ).strip()
44
+ # For backward compatibility, return a simple template
45
+ # This function is no longer used in the core validation flow
46
+ template = VALIDATION_TASK_TEMPLATE.replace("{target_variable}", target_variable)
47
+ template += "\n\n# 用户回答\n{sys_user_input}"
48
+ return template.strip()
75
49
 
76
50
 
77
51
  def parse_validation_response(llm_response: str, original_input: str, target_variable: str) -> dict[str, Any]:
@@ -101,6 +75,10 @@ def parse_validation_response(llm_response: str, original_input: str, target_var
101
75
  if target_variable not in parse_vars:
102
76
  parse_vars[target_variable] = original_input.strip()
103
77
 
78
+ # Ensure the variable value is in list format (user_input format)
79
+ if target_variable in parse_vars and not isinstance(parse_vars[target_variable], list):
80
+ parse_vars[target_variable] = [parse_vars[target_variable]]
81
+
104
82
  return {"content": "", "variables": parse_vars}
105
83
 
106
84
  if result == VALIDATION_RESPONSE_ILLEGAL:
@@ -117,5 +95,6 @@ def parse_validation_response(llm_response: str, original_input: str, target_var
117
95
 
118
96
  # Check against standard response format
119
97
  if "ok" in response_lower or "valid" in response_lower:
120
- return {"content": "", "variables": {target_variable: original_input.strip()}}
98
+ # Return in list format to match user_input format
99
+ return {"content": "", "variables": {target_variable: [original_input.strip()]}}
121
100
  return {"content": llm_response, "variables": None}
@@ -31,9 +31,7 @@ class ProviderConfig:
31
31
  debug: bool = field(default_factory=lambda: os.getenv("LLM_DEBUG", "false").lower() in ("true", "1", "yes"))
32
32
  """Enable debug mode (colorized console output). Default: LLM_DEBUG environment variable or False."""
33
33
 
34
- timeout: float | None = field(
35
- default_factory=lambda: float(os.getenv("LLM_TIMEOUT")) if os.getenv("LLM_TIMEOUT") else None
36
- )
34
+ timeout: float | None = field(default_factory=lambda: float(os.getenv("LLM_TIMEOUT")) if os.getenv("LLM_TIMEOUT") else None)
37
35
  """Request timeout in seconds. None means no timeout. Default: LLM_TIMEOUT environment variable or None."""
38
36
 
39
37
  def __post_init__(self):
@@ -281,7 +281,7 @@ class OpenAIProvider(LLMProvider):
281
281
  role = message.get("role", "user")
282
282
  content = message.get("content", "")
283
283
  # Truncate long content for readability
284
- display_content = content if len(content) <= 200 else content[:200] + "..."
284
+ display_content = content
285
285
  print(f"\033[30m\033[43m{role}\033[0m: {display_content}")
286
286
 
287
287
  print("\033[97m\033[44m[ ====== LLM Request End ====== ]\033[0m")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markdown-flow
3
- Version: 0.2.28
3
+ Version: 0.2.30
4
4
  Summary: An agent library designed to parse and process MarkdownFlow documents
5
5
  Project-URL: Homepage, https://github.com/ai-shifu/markdown-flow-agent-py
6
6
  Project-URL: Bug Tracker, https://github.com/ai-shifu/markdown-flow-agent-py/issues
File without changes
File without changes
File without changes