markdown-flow 0.2.19__py3-none-any.whl → 0.2.30__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.
markdown_flow/__init__.py CHANGED
@@ -9,7 +9,7 @@ Core Features:
9
9
  - Extract variable placeholders ({{variable}} and %{{variable}} formats)
10
10
  - Build LLM-ready prompts and message formats
11
11
  - Handle user interaction validation and input processing
12
- - Support multiple processing modes: PROMPT_ONLY, COMPLETE, STREAM
12
+ - Support multiple processing modes: COMPLETE, STREAM
13
13
 
14
14
  Supported Interaction Types:
15
15
  - TEXT_ONLY: ?[%{{var}}...question] - Text input only
@@ -35,7 +35,6 @@ Basic Usage:
35
35
  result = mf.process(0, variables={'name': 'John'}, mode=ProcessMode.COMPLETE)
36
36
 
37
37
  # Different processing modes
38
- prompt_result = mf.process(0, mode=ProcessMode.PROMPT_ONLY)
39
38
  complete_result = mf.process(0, mode=ProcessMode.COMPLETE)
40
39
  stream_result = mf.process(0, mode=ProcessMode.STREAM)
41
40
 
@@ -53,7 +52,7 @@ Import Guide:
53
52
  from .core import MarkdownFlow
54
53
  from .enums import BlockType, InputType
55
54
  from .llm import LLMProvider, LLMResult, ProcessMode
56
- from .utils import (
55
+ from .parser import (
57
56
  InteractionParser,
58
57
  InteractionType,
59
58
  extract_interaction_question,
@@ -83,4 +82,5 @@ __all__ = [
83
82
  "replace_variables_in_text",
84
83
  ]
85
84
 
86
- __version__ = "0.2.19"
85
+ __version__ = "0.2.30"
86
+ # __version__ = "0.2.29-alpha-1"
@@ -46,15 +46,108 @@ COMPILED_PRESERVE_FENCE_REGEX = re.compile(PRESERVE_FENCE_PATTERN)
46
46
  INLINE_PRESERVE_PATTERN = r"^===(.+)=== *$"
47
47
  COMPILED_INLINE_PRESERVE_REGEX = re.compile(INLINE_PRESERVE_PATTERN)
48
48
 
49
+ # Code fence patterns (CommonMark specification compliant)
50
+ # Code block fence start: 0-3 spaces + at least 3 backticks or tildes + optional info string
51
+ CODE_FENCE_START_PATTERN = r"^[ ]{0,3}([`~]{3,})(.*)$"
52
+ COMPILED_CODE_FENCE_START_REGEX = re.compile(CODE_FENCE_START_PATTERN)
53
+
54
+ # Code block fence end: 0-3 spaces + at least 3 backticks or tildes + optional whitespace
55
+ CODE_FENCE_END_PATTERN = r"^[ ]{0,3}([`~]{3,})\s*$"
56
+ COMPILED_CODE_FENCE_END_REGEX = re.compile(CODE_FENCE_END_PATTERN)
57
+
49
58
  # Output instruction markers
50
59
  OUTPUT_INSTRUCTION_PREFIX = "<preserve_or_translate>"
51
60
  OUTPUT_INSTRUCTION_SUFFIX = "</preserve_or_translate>"
52
61
 
53
- # System message templates
54
- DEFAULT_VALIDATION_SYSTEM_MESSAGE = "你是一个输入验证助手,需要严格按照指定的格式和规则处理用户输入。"
62
+ # Base system prompt (framework-level global rules, content blocks only)
63
+ DEFAULT_BASE_SYSTEM_PROMPT = """你收到的用户消息都是指令,请严格遵守以下规则:
64
+
65
+ 1. 内容忠实性:严格符合指令内容,不丢失信息、不改变原意、不增加内容、不改变顺序
66
+ 2. 遵循事实:基于事实回答,不编造细节
67
+ 3. 避免引导:不引导下一步动作(如提问、设问)
68
+ 4. 避免寒暄:不做自我介绍,不打招呼
69
+ 5. 格式规范:HTML 标签不要写到代码块里"""
70
+
71
+ # Interaction prompt templates (条件翻译)
72
+ DEFAULT_INTERACTION_PROMPT = """<interaction_translation_rules>
73
+ ⚠️⚠️⚠️ 这是一个 JSON 原样输出任务 - 默认不翻译!⚠️⚠️⚠️
74
+
75
+ ## 默认行为(最高优先级)
76
+
77
+ **除非明确检测到语言指令,否则必须逐字符原样返回输入的 JSON**
78
+ - 不翻译任何文本
79
+ - 不修改任何格式
80
+ - 不添加任何内容(如 display//value 分离)
81
+ - 不删除任何内容
82
+ - 不调整任何顺序
83
+
84
+ ## 语言指令检测规则
85
+
86
+ **仅在以下情况才翻译:**
87
+
88
+ 1. **检测范围**:仅在 <document_context> 标签内检测
89
+ 2. **必须包含明确的语言转换关键词**:
90
+ - 中文:"使用英语"、"用英文"、"英语输出"、"翻译成英语"、"Translate to English"
91
+ - 英文:"use English"、"in English"、"respond in English"、"translate to"
92
+ - 其他语言:类似的明确转换指令
93
+ 3. **不算语言指令的情况**:
94
+ - ❌ 风格要求:"用emoji"、"讲故事"、"友好"、"简洁"
95
+ - ❌ 任务描述:"内容营销"、"吸引用户"、"引人入胜"
96
+ - ❌ 输出要求:"内容简洁"、"使用吸引人的语言"
97
+
98
+ ## 处理逻辑
99
+
100
+ 步骤1:在 <document_context> 中搜索语言转换关键词
101
+ 步骤2:
102
+ - 如果找到 → 将 buttons 和 question 翻译成指定语言(仅翻译文本,不改格式)
103
+ - 如果未找到 → 逐字符原样返回输入的 JSON
104
+
105
+ ## 输出格式要求
106
+
107
+ - **必须返回纯 JSON**,不要添加任何解释或 markdown 代码块
108
+ - **格式必须与输入完全一致**,包括空格、标点、引号
109
+
110
+ ## 示例
111
+
112
+ ### 示例 1:无语言指令(默认情况)
113
+
114
+ 输入:{"buttons": ["产品经理", "开发者", "大学生"], "question": "其他身份"}
115
+
116
+ <document_context>
117
+ 你是一个内容营销,擅长结合用户特点,给到引人入胜的内容。
118
+ 任务说明:认真理解给定的内容,站在用户角度...
119
+ 输出要求:内容简洁有力,使用吸引用户的语言...
120
+ </document_context>
121
+
122
+ ✅ 正确输出:{"buttons": ["产品经理", "开发者", "大学生"], "question": "其他身份"}
123
+ ❌ 错误输出:{"buttons": ["Product Manager//产品经理", ...], ...} ← 不要添加翻译!
55
124
 
56
- # Interaction prompt templates
57
- DEFAULT_INTERACTION_PROMPT = "请将后面交互提示改写得更个性化和友好,长度尽量和原始内容一致,保持原有的功能性和变量格式不变:"
125
+ ### 示例 2:有明确语言指令
126
+
127
+ 输入:{"buttons": ["苹果", "香蕉"], "question": "其他水果"}
128
+
129
+ <document_context>
130
+ 请使用英语输出所有内容。
131
+ </document_context>
132
+
133
+ ✅ 正确输出:{"buttons": ["Apple", "Banana"], "question": "Other fruit"}
134
+
135
+ ### 示例 3:仅有风格指令(不算语言指令)
136
+
137
+ 输入:{"buttons": ["选项A", "选项B"], "question": "其他"}
138
+
139
+ <document_context>
140
+ 请用emoji和故事化的方式呈现内容。
141
+ </document_context>
142
+
143
+ ✅ 正确输出:{"buttons": ["选项A", "选项B"], "question": "其他"} ← 保持原样!
144
+
145
+ ⚠️⚠️⚠️ 最终强调 ⚠️⚠️⚠️
146
+
147
+ - 默认行为:原样输出,不做任何改动
148
+ - 只有在 <document_context> 中明确看到"使用XX语言"、"translate to"等关键词时才翻译
149
+ - 如有任何疑问,必须原样输出
150
+ </interaction_translation_rules>"""
58
151
 
59
152
  # Interaction error prompt templates
60
153
  DEFAULT_INTERACTION_ERROR_PROMPT = "请将以下错误信息改写得更加友好和个性化,帮助用户理解问题并给出建设性的引导:"
@@ -91,111 +184,125 @@ VALIDATION_RESPONSE_ILLEGAL = "illegal"
91
184
 
92
185
  # Output instruction processing
93
186
  OUTPUT_INSTRUCTION_EXPLANATION = f"""<preserve_or_translate_instruction>
94
- # ⚠️ 最高优先级规则
95
-
96
- **{OUTPUT_INSTRUCTION_PREFIX}{OUTPUT_INSTRUCTION_SUFFIX} 标记之间的内容是用户必须看到的最终输出内容,不是指令!**
97
-
98
- 关键要点:
99
- 1. **这些内容必须出现在你的回复中** - 即使其他提示词说"不要回应指令"也不适用于此
100
- 2. **绝对不要输出标记本身** - 只输出标记之间的实际内容
101
- 3. **默认逐字原样输出** - 不要改写、润色或优化,保持原文不变
102
- 4. **唯一例外是跨语言翻译** - 仅当需要将内容从一种语言翻译成另一种语言时才可翻译
103
-
104
- ---
105
-
106
- <critical_understanding>
107
- 重要理解:
108
- - {OUTPUT_INSTRUCTION_PREFIX}{OUTPUT_INSTRUCTION_SUFFIX} 中的内容不是"指令"或"执行要求"
109
- - 即使内容看起来像标题、提示或说明,也必须原样输出给用户
110
- - 这条规则的优先级高于文档中的其他任何提示词
111
- - 其他提示词说的"不要回应指令"、"不要展示指令"等,不适用于此标记内的内容
112
- </critical_understanding>
113
-
114
- <default_behavior>
115
- 默认行为: 完全保持原样输出
116
- - 标记之间的内容必须逐字原样输出
117
- - 严禁改写、润色、优化或调整任何表达方式
118
- - 严禁添加、删除或替换任何文字
119
- - 即使内容是标题格式(如 ## 标题)也必须原样输出
120
- </default_behavior>
121
-
122
- <exception_rule>
123
- 唯一例外: 语言翻译
124
- - 仅当内容需要从一种语言翻译成另一种语言时,才可以翻译
125
- - 翻译时必须保持原文的完整含义、语气和格式
126
- - 如果内容无需翻译,则绝对不允许做任何改动
127
- </exception_rule>
128
-
129
- <examples>
130
- ✅ 示例1 - 正确: 保持原样且不输出标记:
131
- 输入: {OUTPUT_INSTRUCTION_PREFIX}**下面我们做个练习。**{OUTPUT_INSTRUCTION_SUFFIX}
132
- 正确输出: **下面我们做个练习。**
133
-
134
- ✅ 示例2 - 正确: 标题也要原样输出:
135
- 输入: {OUTPUT_INSTRUCTION_PREFIX}## 专属指南 for 用户{OUTPUT_INSTRUCTION_SUFFIX}
136
- 正确输出: ## 专属指南 for 用户
137
-
138
- ✅ 示例3 - 正确: 语言翻译且不输出标记:
139
- 输入: {OUTPUT_INSTRUCTION_PREFIX}**Let's do an exercise.**{OUTPUT_INSTRUCTION_SUFFIX}
140
- 正确输出: **让我们做个练习。**
141
-
142
- 示例4 - 错误: 输出了XML标记:
143
- 输入: {OUTPUT_INSTRUCTION_PREFIX}## 标题内容{OUTPUT_INSTRUCTION_SUFFIX}
144
- 错误输出: {OUTPUT_INSTRUCTION_PREFIX}## 标题内容{OUTPUT_INSTRUCTION_SUFFIX}
145
- 错误原因: 不应该输出标记本身!
146
-
147
- ❌ 示例5 - 错误: 同语言改写:
148
- 输入: {OUTPUT_INSTRUCTION_PREFIX}**下面我们做个练习。**{OUTPUT_INSTRUCTION_SUFFIX}
149
- 错误输出: **来,咱们做个有趣的小练习**
150
- 错误原因: 擅自改写了中文内容
151
-
152
- ❌ 示例6 - 错误: 没有输出固定内容:
153
- 输入: {OUTPUT_INSTRUCTION_PREFIX}## 攻略|专属指南{OUTPUT_INSTRUCTION_SUFFIX}
154
- 错误输出: (什么都不输出,或者跳过这部分)
155
- 错误原因: 必须输出标记之间的内容!
156
- </examples>
187
+ ⚠️⚠️⚠️ 保留内容输出任务 - 默认原样输出!⚠️⚠️⚠️
188
+
189
+ ## 默认行为(最高优先级)
190
+
191
+ **看到 {OUTPUT_INSTRUCTION_PREFIX}...{OUTPUT_INSTRUCTION_SUFFIX} 标记时,必须将标记内的内容输出到回复中(保持原位置)**
192
+ - 默认:逐字符原样输出,不做任何改动
193
+ - 绝对不要输出 {OUTPUT_INSTRUCTION_PREFIX} 和 {OUTPUT_INSTRUCTION_SUFFIX} 标记本身
194
+ - 始终保留 emoji、格式、特殊字符
195
+
196
+ ## 语言指令检测规则
197
+
198
+ **仅在以下情况才翻译:**
199
+
200
+ 1. **检测范围**:仅在 <document_prompt> 标签内检测
201
+ 2. **必须包含明确的语言转换关键词**:
202
+ - 中文:"使用英语"、"用韩文"、"英语输出"、"翻译成英语"、"Translate to English"
203
+ - 英文:"use English"、"in English"、"respond in English"、"translate to"
204
+ - 其他语言:类似的明确转换指令
205
+ 3. **不算语言指令的情况**:
206
+ - ❌ 风格要求:"用emoji"、"讲故事"、"友好"、"简洁"
207
+ - ❌ 任务描述:"内容营销"、"吸引用户"、"引人入胜"
208
+ - ❌ 输出要求:"内容简洁"、"使用吸引人的语言"
209
+
210
+ ## 处理逻辑
211
+
212
+ 步骤1:在 <document_prompt> 中搜索语言转换关键词
213
+ 步骤2:
214
+ - 如果找到 → 保持原意与风格,翻译成指定语言
215
+ - 如果未找到 → 逐字符原样输出,不做任何改动
216
+
217
+ ## 输出位置规则
218
+
219
+ - 保持内容在原文档中的位置(开头/中间/结尾)
220
+ - 不要强制移到开头或其他位置
221
+
222
+ ## 示例
223
+
224
+ ### 示例 1:无语言指令(默认情况)
225
+
226
+ 输入: {OUTPUT_INSTRUCTION_PREFIX}🌟 欢迎冒险!{OUTPUT_INSTRUCTION_SUFFIX}
227
+
228
+ 询问小朋友的名字:
229
+
230
+ <document_prompt>
231
+ 你是一个故事大王,擅长讲故事。
232
+ 用一些语气词,多用emoji。
233
+ </document_prompt>
234
+
235
+ 正确输出: 🌟 欢迎冒险!
236
+
237
+ 询问小朋友的名字:...(保留内容在开头,原样输出)
238
+
239
+ ❌ 错误输出: 询问小朋友的名字:...(完全不输出保留内容 ← 绝对禁止!)
240
+
241
+ ### 示例 2:有明确语言指令
242
+
243
+ 输入: {OUTPUT_INSTRUCTION_PREFIX}🌟 欢迎冒险!{OUTPUT_INSTRUCTION_SUFFIX}
244
+
245
+ 询问小朋友的名字:
246
+
247
+ <document_prompt>
248
+ 请使用韩语输出所有内容。
249
+ </document_prompt>
250
+
251
+ ✅ 正确输出: 🌟 모험에 오신 것을 환영합니다!
252
+
253
+ 아이의 이름을 물어보세요:...(保留内容翻译为韩语)
254
+
255
+ ### 示例 3:仅有风格指令(不算语言指令)
256
+
257
+ 输入: {OUTPUT_INSTRUCTION_PREFIX}**重要提示**{OUTPUT_INSTRUCTION_SUFFIX}
258
+
259
+ 后续内容...
260
+
261
+ <document_prompt>
262
+ 请用emoji和故事化的方式呈现内容。
263
+ </document_prompt>
264
+
265
+ ✅ 正确输出: **重要提示**
266
+
267
+ 后续内容...(保持原样!)
268
+
269
+ ### 示例 4:标记剥离错误
270
+
271
+ 输入: {OUTPUT_INSTRUCTION_PREFIX}**Title**{OUTPUT_INSTRUCTION_SUFFIX}
272
+
273
+ ❌ 绝对不要: {OUTPUT_INSTRUCTION_PREFIX}**Title**{OUTPUT_INSTRUCTION_SUFFIX}(包含了标记)
274
+ ✅ 正确输出: **Title**(排除了标记)
275
+
276
+ ⚠️⚠️⚠️ 最终强调 ⚠️⚠️⚠️
277
+
278
+ - 默认行为:原样输出保留内容,不做任何改动
279
+ - 只有在 <document_prompt> 中明确看到"使用XX语言"、"translate to"等关键词时才翻译
280
+ - 如有任何疑问,必须原样输出
281
+ - 此规则优先级最高,覆盖所有其他指令
157
282
  </preserve_or_translate_instruction>
158
283
 
159
284
  """
160
285
 
161
- # Smart validation template
162
- SMART_VALIDATION_TEMPLATE = """# 任务
286
+ # Validation task template (merged with system message)
287
+ VALIDATION_TASK_TEMPLATE = """你是一个验证用户输入的助手,请严格按照给定的指令进行验证。
288
+
289
+ # 任务
163
290
  从用户回答中提取相关信息,返回JSON格式结果:
164
291
  - 合法:{{"result": "ok", "parse_vars": {{"{target_variable}": "提取的内容"}}}}
165
292
  - 不合法:{{"result": "illegal", "reason": "原因"}}
166
293
 
167
- {context_info}
168
-
169
- # 用户回答
170
- {sys_user_input}
294
+ # 输出语言
295
+ - 如果在 <document_context> 中明确要求使用特定语言,则错误信息和原因说明应使用该语言
296
+ - 否则,使用用户输入或问题描述的主要语言"""
171
297
 
172
- # 提取要求
298
+ # Validation requirements template (lenient general version)
299
+ VALIDATION_REQUIREMENTS_TEMPLATE = """# 提取要求
173
300
  1. 仔细阅读上述相关问题,理解这个问题想要获取什么信息
174
301
  2. 从用户回答中提取与该问题相关的信息
175
- 3. 对于昵称/姓名类问题,任何非空的合理字符串(包括简短的如"ee"、"aa"、"007"等)都应该接受
176
- 4. 只有当用户回答完全无关、包含不当内容或明显不合理时才标记为不合法
177
- 5. 确保提取的信息准确、完整且符合预期格式"""
178
-
179
- # Validation template for buttons with text input
180
- BUTTONS_WITH_TEXT_VALIDATION_TEMPLATE = """用户针对以下问题进行了输入:
181
-
182
- 问题:{question}
183
- 可选按钮:{options}
184
- 用户输入:{user_input}
185
-
186
- 用户的输入不在预定义的按钮选项中,这意味着用户选择了自定义输入。
187
- 根据问题的性质,请判断用户的输入是否合理:
188
-
189
- 1. 如果用户输入能够表达与按钮选项类似的概念(比如按钮有"幽默、大气、二次元",用户输入了"搞笑"),请接受。
190
- 2. 如果用户输入是对问题的合理回答(比如问题要求描述风格,用户输入了任何有效的风格描述),请接受。
191
- 3. 只有当用户输入完全不相关、包含不当内容、或明显不合理时,才拒绝。
192
-
193
- 请按以下 JSON 格式回复:
194
- {{
195
- "result": "ok|illegal",
196
- "parse_vars": {{"{target_variable}": "提取的值"}},
197
- "reason": "接受或拒绝的原因"
198
- }}"""
302
+ 3. 如果提供了预定义选项,用户选择这些选项时都应该接受;自定义输入只要是对问题的合理回答即可接受
303
+ 4. 对于昵称、姓名、标签等自由文本输入,任何非空的合理表达都应该接受(包括数字、字母、符号、emoji等创意性表达)
304
+ 5. 只有当用户回答完全无关、包含不当内容或明显违背常识时才标记为不合法
305
+ 6. 宽松验证原则:理解用户意图,接受多样化的合理表达形式"""
199
306
 
200
307
  # ========== Error Message Constants ==========
201
308
 
@@ -204,7 +311,7 @@ OPTION_SELECTION_ERROR_TEMPLATE = "请选择以下选项之一:{options}"
204
311
  INPUT_EMPTY_ERROR = "输入不能为空"
205
312
 
206
313
  # System error messages
207
- UNSUPPORTED_PROMPT_TYPE_ERROR = "不支持的提示词类型: {prompt_type}"
314
+ UNSUPPORTED_PROMPT_TYPE_ERROR = "不支持的提示词类型: {prompt_type} (支持的类型: base_system, document, interaction, interaction_error)"
208
315
  BLOCK_INDEX_OUT_OF_RANGE_ERROR = "Block index {index} is out of range; total={total}"
209
316
  LLM_PROVIDER_REQUIRED_ERROR = "需要设置 LLMProvider 才能调用 LLM"
210
317
  INTERACTION_PARSE_ERROR = "交互格式解析失败: {error}"
@@ -220,7 +327,11 @@ VARIABLE_DEFAULT_VALUE = "UNKNOWN"
220
327
  # Context generation constants
221
328
  CONTEXT_QUESTION_MARKER = "# 相关问题"
222
329
  CONTEXT_CONVERSATION_MARKER = "# 对话上下文"
330
+ CONTEXT_BUTTON_OPTIONS_MARKER = "## 预定义选项"
223
331
 
224
332
  # Context generation templates
225
333
  CONTEXT_QUESTION_TEMPLATE = f"{CONTEXT_QUESTION_MARKER}\n{{question}}"
226
334
  CONTEXT_CONVERSATION_TEMPLATE = f"{CONTEXT_CONVERSATION_MARKER}\n{{content}}"
335
+ CONTEXT_BUTTON_OPTIONS_TEMPLATE = (
336
+ f"{CONTEXT_BUTTON_OPTIONS_MARKER}\n可选的预定义选项包括:{{button_options}}\n注意:用户如果选择了这些选项,都应该接受;如果输入了自定义内容,只要是对问题的合理回答即可接受。"
337
+ )