markdown-flow 0.2.30__py3-none-any.whl → 0.2.31__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 +2 -2
- markdown_flow/constants.py +57 -47
- markdown_flow/core.py +102 -9
- markdown_flow/parser/validation.py +0 -4
- {markdown_flow-0.2.30.dist-info → markdown_flow-0.2.31.dist-info}/METADATA +1 -1
- {markdown_flow-0.2.30.dist-info → markdown_flow-0.2.31.dist-info}/RECORD +9 -9
- {markdown_flow-0.2.30.dist-info → markdown_flow-0.2.31.dist-info}/WHEEL +0 -0
- {markdown_flow-0.2.30.dist-info → markdown_flow-0.2.31.dist-info}/licenses/LICENSE +0 -0
- {markdown_flow-0.2.30.dist-info → markdown_flow-0.2.31.dist-info}/top_level.txt +0 -0
markdown_flow/__init__.py
CHANGED
markdown_flow/constants.py
CHANGED
|
@@ -26,12 +26,6 @@ COMPILED_LAYER3_BUTTON_VALUE_REGEX = re.compile(r"^(.+)//(.+)$") # Layer 3: Par
|
|
|
26
26
|
COMPILED_BRACE_VARIABLE_REGEX = re.compile(
|
|
27
27
|
r"(?<!%)\{\{([^}]+)\}\}" # Match {{variable}} format for replaceable variables
|
|
28
28
|
)
|
|
29
|
-
COMPILED_INTERACTION_CONTENT_RECONSTRUCT_REGEX = re.compile(
|
|
30
|
-
r"(\?\[[^]]*\.\.\.)([^]]*\])" # Reconstruct interaction content: prefix + question + suffix
|
|
31
|
-
)
|
|
32
|
-
COMPILED_BRACKETS_CLEANUP_REGEX = re.compile(r"[\[\]()]")
|
|
33
|
-
COMPILED_VARIABLE_REFERENCE_CLEANUP_REGEX = re.compile(r"%\{\{[^}]*\}\}")
|
|
34
|
-
COMPILED_WHITESPACE_CLEANUP_REGEX = re.compile(r"\s+")
|
|
35
29
|
COMPILED_SINGLE_PIPE_SPLIT_REGEX = re.compile(r"(?<!\|)\|(?!\|)") # Split on single | but not ||
|
|
36
30
|
|
|
37
31
|
# Document parsing constants (using shared INTERACTION_PATTERN defined above)
|
|
@@ -152,28 +146,6 @@ DEFAULT_INTERACTION_PROMPT = """<interaction_translation_rules>
|
|
|
152
146
|
# Interaction error prompt templates
|
|
153
147
|
DEFAULT_INTERACTION_ERROR_PROMPT = "请将以下错误信息改写得更加友好和个性化,帮助用户理解问题并给出建设性的引导:"
|
|
154
148
|
|
|
155
|
-
# Detailed interaction rendering instructions
|
|
156
|
-
INTERACTION_RENDER_INSTRUCTIONS = """
|
|
157
|
-
核心要求:
|
|
158
|
-
1. **绝对禁止改变问题的含义和方向** - 这是最重要的原则
|
|
159
|
-
2. 只能改变表达方式,不能改变问题的核心内容
|
|
160
|
-
3. 必须保持问题的主体和客体关系不变
|
|
161
|
-
4. 只返回改写后的问题文本,不要包含任何其他内容
|
|
162
|
-
5. 保持专业友好的语气,禁止可爱化表达
|
|
163
|
-
|
|
164
|
-
关键示例说明:
|
|
165
|
-
✅ 正确改写(保持含义):
|
|
166
|
-
- "希望我怎么称呼你?" → "请问我应该如何称呼您?"
|
|
167
|
-
- "请输入您的姓名" → "请告诉我您的姓名"
|
|
168
|
-
- "你的年龄是多少?" → "请问您今年多大了?"
|
|
169
|
-
|
|
170
|
-
❌ 严重错误(改变含义):
|
|
171
|
-
- "希望我怎么称呼你?" → "你想叫我什么名字?" (方向颠倒)
|
|
172
|
-
- "请输入您的姓名" → "我叫什么好呢?" (主客体颠倒)
|
|
173
|
-
- "你喜欢什么?" → "我应该喜欢什么?" (完全改变意思)
|
|
174
|
-
|
|
175
|
-
请严格按照以上要求改写,确保不改变问题的原始含义:"""
|
|
176
|
-
|
|
177
149
|
# Interaction error rendering instructions
|
|
178
150
|
INTERACTION_ERROR_RENDER_INSTRUCTIONS = """
|
|
179
151
|
请只返回友好的错误提示,不要包含其他格式或说明。"""
|
|
@@ -284,25 +256,63 @@ OUTPUT_INSTRUCTION_EXPLANATION = f"""<preserve_or_translate_instruction>
|
|
|
284
256
|
"""
|
|
285
257
|
|
|
286
258
|
# Validation task template (merged with system message)
|
|
287
|
-
VALIDATION_TASK_TEMPLATE = """
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
#
|
|
295
|
-
|
|
296
|
-
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
259
|
+
VALIDATION_TASK_TEMPLATE = """你是字符串验证程序,不是对话助手。
|
|
260
|
+
|
|
261
|
+
你的唯一任务:按后续规则检查输入,输出 JSON:
|
|
262
|
+
{{"result": "ok", "parse_vars": {{"{target_variable}": "用户输入"}}}} 或 {{"result": "illegal", "reason": "原因"}}
|
|
263
|
+
|
|
264
|
+
严禁输出任何自然语言解释。
|
|
265
|
+
|
|
266
|
+
# reason 语言
|
|
267
|
+
从 <document_context> 中仅提取语言要求(如"使用英文"、"use English")
|
|
268
|
+
- 如果有明确语言要求 → reason 使用该语言
|
|
269
|
+
- 否则 → reason 使用用户输入或问题的语言
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
# Validation requirements template (极致宽松版本)
|
|
273
|
+
VALIDATION_REQUIREMENTS_TEMPLATE = """# 验证算法(按顺序执行)
|
|
274
|
+
|
|
275
|
+
步骤 1:空值检查(字符串长度检查)
|
|
276
|
+
|
|
277
|
+
检查规则:input.trim().length == 0 ?
|
|
278
|
+
- YES → 空
|
|
279
|
+
- NO → 非空
|
|
280
|
+
|
|
281
|
+
⚠️ 只要去除首尾空格后字符数 > 0,就是非空
|
|
282
|
+
⚠️ 不判断语义!所有可见字符(a、1、@、中)都计入长度
|
|
283
|
+
⚠️ 示例:
|
|
284
|
+
- "" → 长度0 → 空
|
|
285
|
+
- " " → 长度0 → 空
|
|
286
|
+
- "aa" → 长度2 → 非空
|
|
287
|
+
- "@_@" → 长度3 → 非空
|
|
288
|
+
- "棒棒糖" → 长度3 → 非空
|
|
289
|
+
|
|
290
|
+
步骤 2:模糊回答检查
|
|
291
|
+
|
|
292
|
+
拒绝以下模糊回答:"不知道"、"不清楚"、"没有"、"不告诉你"
|
|
293
|
+
|
|
294
|
+
步骤 3:宗教政治检查
|
|
295
|
+
|
|
296
|
+
只拒绝明确的宗教政治立场表达(宗教教义、政治口号等)
|
|
297
|
+
地名,地区等(北京、上海等)、普通词汇都不算
|
|
298
|
+
|
|
299
|
+
步骤 4:输出结果(reason 语言跟随 <document_context> 中的语言要求)
|
|
300
|
+
|
|
301
|
+
伪代码逻辑:
|
|
302
|
+
if 空:
|
|
303
|
+
输出 {{"result": "illegal", "reason": "输入为空(或对应语言的翻译)"}}
|
|
304
|
+
else if 模糊回答:
|
|
305
|
+
输出 {{"result": "illegal", "reason": "请提供具体内容(或对应语言的翻译)"}}
|
|
306
|
+
else if 宗教政治:
|
|
307
|
+
输出 {{"result": "illegal", "reason": "包含敏感内容(或对应语言的翻译)"}}
|
|
308
|
+
else:
|
|
309
|
+
输出 {{"result": "ok", "parse_vars": {{"{target_variable}": "用户输入"}}}}
|
|
310
|
+
|
|
311
|
+
⚠️ 极致重要:
|
|
312
|
+
- len(去除空格后的输入) > 0 → 必须视为非空
|
|
313
|
+
- 符号、数字、品牌名、地名等都不是"空",也不是"无效"
|
|
314
|
+
- 默认通过,只在明确违规时才拒绝
|
|
315
|
+
"""
|
|
306
316
|
|
|
307
317
|
# ========== Error Message Constants ==========
|
|
308
318
|
|
markdown_flow/core.py
CHANGED
|
@@ -97,6 +97,7 @@ class MarkdownFlow:
|
|
|
97
97
|
self._blocks = None
|
|
98
98
|
self._model: str | None = None
|
|
99
99
|
self._temperature: float | None = None
|
|
100
|
+
self._enable_text_validation: bool = False # Default: validation disabled for performance
|
|
100
101
|
|
|
101
102
|
# Preprocess document: extract code blocks and replace with placeholders
|
|
102
103
|
# This is done once during initialization, similar to Go implementation
|
|
@@ -194,6 +195,37 @@ class MarkdownFlow:
|
|
|
194
195
|
"""
|
|
195
196
|
return self._temperature
|
|
196
197
|
|
|
198
|
+
def set_text_validation_enabled(self, enabled: bool) -> "MarkdownFlow":
|
|
199
|
+
"""
|
|
200
|
+
Set whether to enable text input LLM validation.
|
|
201
|
+
|
|
202
|
+
Default is False (disabled) for performance and cost optimization.
|
|
203
|
+
When disabled, text inputs are accepted directly without LLM validation.
|
|
204
|
+
When enabled, uses ValidationTaskTemplate for LLM validation.
|
|
205
|
+
|
|
206
|
+
Affects interaction types:
|
|
207
|
+
- TEXT_ONLY: Pure text input
|
|
208
|
+
- BUTTONS_WITH_TEXT: Buttons + text fallback
|
|
209
|
+
- BUTTONS_MULTI_WITH_TEXT: Multi-select buttons + text fallback
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
enabled: True to enable validation, False to disable
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
Self for method chaining
|
|
216
|
+
"""
|
|
217
|
+
self._enable_text_validation = enabled
|
|
218
|
+
return self
|
|
219
|
+
|
|
220
|
+
def is_text_validation_enabled(self) -> bool:
|
|
221
|
+
"""
|
|
222
|
+
Check if text input validation is enabled.
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
True if validation is enabled, False otherwise
|
|
226
|
+
"""
|
|
227
|
+
return self._enable_text_validation
|
|
228
|
+
|
|
197
229
|
def set_prompt(self, prompt_type: str, value: str | None) -> None:
|
|
198
230
|
"""
|
|
199
231
|
Set prompt template.
|
|
@@ -558,9 +590,30 @@ class MarkdownFlow:
|
|
|
558
590
|
# Step 1: Match button values
|
|
559
591
|
matched_values, unmatched_values = self._match_button_values(buttons, target_values)
|
|
560
592
|
|
|
561
|
-
# Step 2: If there are unmatched values (custom text)
|
|
593
|
+
# Step 2: If there are unmatched values (custom text)
|
|
562
594
|
if unmatched_values:
|
|
563
|
-
#
|
|
595
|
+
# Check if text validation is enabled
|
|
596
|
+
if not self._enable_text_validation:
|
|
597
|
+
# Validation disabled: directly accept unmatched custom text
|
|
598
|
+
all_values = matched_values + unmatched_values
|
|
599
|
+
result = LLMResult(
|
|
600
|
+
content="",
|
|
601
|
+
variables={target_variable: all_values},
|
|
602
|
+
metadata={
|
|
603
|
+
"interaction_type": str(interaction_type),
|
|
604
|
+
"matched_button_values": matched_values,
|
|
605
|
+
"custom_text_values": unmatched_values,
|
|
606
|
+
"validation_bypassed": True, # Mark validation was skipped
|
|
607
|
+
},
|
|
608
|
+
)
|
|
609
|
+
# Return generator for STREAM mode, direct result for COMPLETE mode
|
|
610
|
+
if mode == ProcessMode.STREAM:
|
|
611
|
+
def stream_generator():
|
|
612
|
+
yield result
|
|
613
|
+
return stream_generator()
|
|
614
|
+
return result
|
|
615
|
+
|
|
616
|
+
# Validation enabled: create user_input for LLM validation (only custom text)
|
|
564
617
|
custom_input = {target_variable: unmatched_values}
|
|
565
618
|
|
|
566
619
|
validation_result = self._process_llm_validation(
|
|
@@ -614,7 +667,7 @@ class MarkdownFlow:
|
|
|
614
667
|
return stream_merge_generator()
|
|
615
668
|
else:
|
|
616
669
|
# All values matched buttons, return directly
|
|
617
|
-
|
|
670
|
+
result = LLMResult(
|
|
618
671
|
content="",
|
|
619
672
|
variables={target_variable: matched_values},
|
|
620
673
|
metadata={
|
|
@@ -622,6 +675,12 @@ class MarkdownFlow:
|
|
|
622
675
|
"all_matched_buttons": True,
|
|
623
676
|
},
|
|
624
677
|
)
|
|
678
|
+
# Return generator for STREAM mode, direct result for COMPLETE mode
|
|
679
|
+
if mode == ProcessMode.STREAM:
|
|
680
|
+
def stream_generator():
|
|
681
|
+
yield result
|
|
682
|
+
return stream_generator()
|
|
683
|
+
return result
|
|
625
684
|
|
|
626
685
|
if interaction_type in [
|
|
627
686
|
InteractionType.BUTTONS_ONLY,
|
|
@@ -640,7 +699,7 @@ class MarkdownFlow:
|
|
|
640
699
|
if interaction_type == InteractionType.NON_ASSIGNMENT_BUTTON:
|
|
641
700
|
# Non-assignment buttons: ?[Continue] or ?[Continue|Cancel]
|
|
642
701
|
# These buttons don't assign variables, any input completes the interaction
|
|
643
|
-
|
|
702
|
+
result = LLMResult(
|
|
644
703
|
content="", # Empty content indicates interaction complete
|
|
645
704
|
variables={}, # Non-assignment buttons don't set variables
|
|
646
705
|
metadata={
|
|
@@ -648,10 +707,34 @@ class MarkdownFlow:
|
|
|
648
707
|
"user_input": user_input,
|
|
649
708
|
},
|
|
650
709
|
)
|
|
710
|
+
# Return generator for STREAM mode, direct result for COMPLETE mode
|
|
711
|
+
if mode == ProcessMode.STREAM:
|
|
712
|
+
def stream_generator():
|
|
713
|
+
yield result
|
|
714
|
+
return stream_generator()
|
|
715
|
+
return result
|
|
651
716
|
|
|
652
717
|
# Text-only input type: ?[%{{sys_user_nickname}}...question]
|
|
653
|
-
# Use LLM validation to check if input is relevant to the question
|
|
654
718
|
if target_values:
|
|
719
|
+
# Check if text validation is enabled
|
|
720
|
+
if not self._enable_text_validation:
|
|
721
|
+
# Validation disabled: directly accept all text input
|
|
722
|
+
result = LLMResult(
|
|
723
|
+
content="",
|
|
724
|
+
variables={target_variable: target_values},
|
|
725
|
+
metadata={
|
|
726
|
+
"interaction_type": "text_only",
|
|
727
|
+
"validation_bypassed": True, # Mark validation was skipped
|
|
728
|
+
},
|
|
729
|
+
)
|
|
730
|
+
# Return generator for STREAM mode, direct result for COMPLETE mode
|
|
731
|
+
if mode == ProcessMode.STREAM:
|
|
732
|
+
def stream_generator():
|
|
733
|
+
yield result
|
|
734
|
+
return stream_generator()
|
|
735
|
+
return result
|
|
736
|
+
|
|
737
|
+
# Validation enabled: use LLM validation to check if input is relevant to the question
|
|
655
738
|
return self._process_llm_validation(
|
|
656
739
|
block_index=block_index,
|
|
657
740
|
user_input=user_input,
|
|
@@ -728,7 +811,7 @@ class MarkdownFlow:
|
|
|
728
811
|
if not target_values:
|
|
729
812
|
if allow_text_input:
|
|
730
813
|
# Allow empty input for buttons+text mode
|
|
731
|
-
|
|
814
|
+
result = LLMResult(
|
|
732
815
|
content="",
|
|
733
816
|
variables={target_variable: []},
|
|
734
817
|
metadata={
|
|
@@ -736,6 +819,12 @@ class MarkdownFlow:
|
|
|
736
819
|
"empty_input": True,
|
|
737
820
|
},
|
|
738
821
|
)
|
|
822
|
+
# Return generator for STREAM mode, direct result for COMPLETE mode
|
|
823
|
+
if mode == ProcessMode.STREAM:
|
|
824
|
+
def stream_generator():
|
|
825
|
+
yield result
|
|
826
|
+
return stream_generator()
|
|
827
|
+
return result
|
|
739
828
|
# Pure button mode requires input
|
|
740
829
|
button_displays = [btn["display"] for btn in buttons]
|
|
741
830
|
error_msg = f"Please select from: {', '.join(button_displays)}"
|
|
@@ -767,7 +856,7 @@ class MarkdownFlow:
|
|
|
767
856
|
return self._render_error(error_msg, mode, context)
|
|
768
857
|
|
|
769
858
|
# Success: return validated values
|
|
770
|
-
|
|
859
|
+
result = LLMResult(
|
|
771
860
|
content="",
|
|
772
861
|
variables={target_variable: valid_values},
|
|
773
862
|
metadata={
|
|
@@ -778,6 +867,12 @@ class MarkdownFlow:
|
|
|
778
867
|
"total_input_count": len(target_values),
|
|
779
868
|
},
|
|
780
869
|
)
|
|
870
|
+
# Return generator for STREAM mode, direct result for COMPLETE mode
|
|
871
|
+
if mode == ProcessMode.STREAM:
|
|
872
|
+
def stream_generator():
|
|
873
|
+
yield result
|
|
874
|
+
return stream_generator()
|
|
875
|
+
return result
|
|
781
876
|
|
|
782
877
|
def _process_llm_validation(
|
|
783
878
|
self,
|
|
@@ -991,7 +1086,6 @@ class MarkdownFlow:
|
|
|
991
1086
|
translatable["question"] = interaction_info["question"]
|
|
992
1087
|
|
|
993
1088
|
# 转换为 JSON
|
|
994
|
-
import json
|
|
995
1089
|
|
|
996
1090
|
json_str = json.dumps(translatable, ensure_ascii=False)
|
|
997
1091
|
|
|
@@ -1041,7 +1135,6 @@ class MarkdownFlow:
|
|
|
1041
1135
|
Returns:
|
|
1042
1136
|
str: 重构后的交互内容
|
|
1043
1137
|
"""
|
|
1044
|
-
import json
|
|
1045
1138
|
|
|
1046
1139
|
# 解析原始 JSON
|
|
1047
1140
|
try:
|
|
@@ -8,10 +8,6 @@ import json
|
|
|
8
8
|
from typing import Any
|
|
9
9
|
|
|
10
10
|
from ..constants import (
|
|
11
|
-
CONTEXT_BUTTON_OPTIONS_TEMPLATE,
|
|
12
|
-
CONTEXT_CONVERSATION_TEMPLATE,
|
|
13
|
-
CONTEXT_QUESTION_MARKER,
|
|
14
|
-
CONTEXT_QUESTION_TEMPLATE,
|
|
15
11
|
VALIDATION_ILLEGAL_DEFAULT_REASON,
|
|
16
12
|
VALIDATION_RESPONSE_ILLEGAL,
|
|
17
13
|
VALIDATION_RESPONSE_OK,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: markdown-flow
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.31
|
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
markdown_flow/__init__.py,sha256=
|
|
2
|
-
markdown_flow/constants.py,sha256=
|
|
3
|
-
markdown_flow/core.py,sha256=
|
|
1
|
+
markdown_flow/__init__.py,sha256=x92vtEJ3BZbfjRvIIGsV68mLxubg_QqXvqKiK9YQVE0,2808
|
|
2
|
+
markdown_flow/constants.py,sha256=l6I16NLgnu_7AxG8hRcSRBLedQPROvA-qqpWLjmGF8Q,13801
|
|
3
|
+
markdown_flow/core.py,sha256=tpUB8fHe16WCsCtq1WHzMVBsLnvBlbKsBRz1reYH8T8,51927
|
|
4
4
|
markdown_flow/enums.py,sha256=Wr41zt0Ce5b3fyLtOTE2erEVp1n92g9OVaBF_BZg_l8,820
|
|
5
5
|
markdown_flow/exceptions.py,sha256=9sUZ-Jd3CPLdSRqG8Pw7eMm7cv_S3VZM6jmjUU8OhIc,976
|
|
6
6
|
markdown_flow/llm.py,sha256=MJRbXKj35AjLCAhWpFhS07s-m3YU2qO1HOFff05HG2I,2239
|
|
@@ -12,13 +12,13 @@ markdown_flow/parser/interaction.py,sha256=T4W7iO-iyNJnpM7SmvOH_DRlLuWSDcFyIrN2f
|
|
|
12
12
|
markdown_flow/parser/json_parser.py,sha256=78GhyyOjlg0l4UmKKNc4zrg-4pSHzrJEt7VKqbz3uyE,1305
|
|
13
13
|
markdown_flow/parser/output.py,sha256=LgxvH6-RINM50p58miQtw_fHER1JEWDGucHk5-sZ-gk,8087
|
|
14
14
|
markdown_flow/parser/preprocessor.py,sha256=YO2znQo7biYAxZZIO5oyrH4h88LZPIe3SidX7ZEOS88,4877
|
|
15
|
-
markdown_flow/parser/validation.py,sha256=
|
|
15
|
+
markdown_flow/parser/validation.py,sha256=qm_YJ0NNWdFrZZfXL800OWTHGtmkX_b3PVF1te7XmTQ,3515
|
|
16
16
|
markdown_flow/parser/variable.py,sha256=eJLbVOyZT8uYM5eJNv5kHLqdRoNz5iNlxHhhi2oDW94,2986
|
|
17
17
|
markdown_flow/providers/__init__.py,sha256=QMr8H9gxoLr6pWXoAb11oZX_She6KWPxnRips537nQ4,319
|
|
18
18
|
markdown_flow/providers/config.py,sha256=Y4Nihqj3KxI6_RyvVKF_mv4mBoPNXeLgYQgv0FqxQfU,2057
|
|
19
19
|
markdown_flow/providers/openai.py,sha256=KgExRJ8QsCeU_c-Yx3IhxG2hBbYN5uZ-uf0VTMvD1LE,12326
|
|
20
|
-
markdown_flow-0.2.
|
|
21
|
-
markdown_flow-0.2.
|
|
22
|
-
markdown_flow-0.2.
|
|
23
|
-
markdown_flow-0.2.
|
|
24
|
-
markdown_flow-0.2.
|
|
20
|
+
markdown_flow-0.2.31.dist-info/licenses/LICENSE,sha256=qz3BziejhHPd1xa5eVtYEU5Qp6L2pn4otuj194uGxmc,1069
|
|
21
|
+
markdown_flow-0.2.31.dist-info/METADATA,sha256=isqtJHsTgU_2KPpmmPfnNnLgzBCeP4PsNTdGyUuNf8I,20686
|
|
22
|
+
markdown_flow-0.2.31.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
23
|
+
markdown_flow-0.2.31.dist-info/top_level.txt,sha256=DpigGvQuIt2L0TTLnDU5sylhiTGiZS7MmAMa2hi-AJs,14
|
|
24
|
+
markdown_flow-0.2.31.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|