markdown-flow 0.2.8__tar.gz → 0.2.10__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.

Potentially problematic release.


This version of markdown-flow might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markdown-flow
3
- Version: 0.2.8
3
+ Version: 0.2.10
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
@@ -83,4 +83,4 @@ __all__ = [
83
83
  "replace_variables_in_text",
84
84
  ]
85
85
 
86
- __version__ = "0.2.8"
86
+ __version__ = "0.2.10"
@@ -478,7 +478,7 @@ class MarkdownFlow:
478
478
  error_msg = f"Please select from: {', '.join(button_displays)}"
479
479
  return self._render_error(error_msg, mode)
480
480
 
481
- # Validate input values against available buttons
481
+ # First, check if user input matches available buttons
482
482
  valid_values = []
483
483
  invalid_values = []
484
484
 
@@ -491,19 +491,30 @@ class MarkdownFlow:
491
491
  break
492
492
 
493
493
  if not matched:
494
- if allow_text_input:
495
- # Allow custom text in buttons+text mode
496
- valid_values.append(value)
497
- else:
498
- invalid_values.append(value)
499
-
500
- # Check for validation errors
501
- if invalid_values and not allow_text_input:
494
+ invalid_values.append(value)
495
+
496
+ # If there are invalid values and this interaction allows text input, use LLM validation
497
+ if invalid_values and allow_text_input:
498
+ # Use LLM validation for text input interactions
499
+ button_displays = [btn["display"] for btn in buttons]
500
+ question = parse_result.get("question", "")
501
+
502
+ return self._process_llm_validation_with_options(
503
+ block_index=0, # Not used in the method
504
+ user_input={target_variable: target_values},
505
+ target_variable=target_variable,
506
+ options=button_displays,
507
+ question=question,
508
+ mode=mode
509
+ )
510
+
511
+ # Check for validation errors in pure button mode or when text input not allowed
512
+ if invalid_values:
502
513
  button_displays = [btn["display"] for btn in buttons]
503
514
  error_msg = f"Invalid options: {', '.join(invalid_values)}. Please select from: {', '.join(button_displays)}"
504
515
  return self._render_error(error_msg, mode)
505
516
 
506
- # Success: return validated values
517
+ # Success: return validated button values
507
518
  return LLMResult(
508
519
  content="",
509
520
  variables={target_variable: valid_values},
@@ -513,6 +524,7 @@ class MarkdownFlow:
513
524
  "valid_values": valid_values,
514
525
  "invalid_values": invalid_values,
515
526
  "total_input_count": len(target_values),
527
+ "llm_validated": False,
516
528
  },
517
529
  )
518
530
 
@@ -1132,7 +1144,7 @@ Analyze the content and provide the structured interaction data.""")
1132
1144
  )
1133
1145
 
1134
1146
  # Merge with existing variables for dynamic interactions
1135
- if hasattr(button_result, 'variables') and variables:
1147
+ if hasattr(button_result, 'variables') and button_result.variables is not None and variables:
1136
1148
  merged_variables = dict(variables)
1137
1149
  merged_variables.update(button_result.variables)
1138
1150
  return LLMResult(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markdown-flow
3
- Version: 0.2.8
3
+ Version: 0.2.10
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
@@ -77,36 +77,30 @@ def test_chinese_restaurant_scenario():
77
77
 
78
78
  # 第三步:测试无效选择
79
79
  print("\n--- 测试无效选择 ---")
80
- try:
81
- invalid_choices = ["意大利面", "汉堡包"] # 不在选项中的选择
82
- result3 = mf.process(
83
- block_index=0,
84
- mode=ProcessMode.COMPLETE,
85
- user_input={"菜品选择": invalid_choices},
86
- dynamic_interaction_format=result1.content
87
- )
88
- if hasattr(result3, 'content') and result3.content and "Invalid" in result3.content:
89
- print(" 正确处理无效选择")
90
- else:
91
- print("⚠️ 可能允许了无效选择")
92
- except Exception as e:
93
- print(f"✅ 正确拒绝无效选择: {str(e)[:50]}...")
80
+ invalid_choices = ["意大利面", "汉堡包"] # 不在选项中的选择
81
+ result3 = mf.process(
82
+ block_index=0,
83
+ mode=ProcessMode.COMPLETE,
84
+ user_input={"菜品选择": invalid_choices},
85
+ dynamic_interaction_format=result1.content
86
+ )
87
+ print(f"无效选择输入: {invalid_choices}")
88
+ print(f"LLM完整响应: {result3.content}")
89
+ print(f"返回变量: {result3.variables}")
90
+ print(f"元数据: {result3.metadata}")
94
91
 
95
92
  # 第四步:测试空输入
96
93
  print("\n--- 测试空输入 ---")
97
- try:
98
- result4 = mf.process(
99
- block_index=0,
100
- mode=ProcessMode.COMPLETE,
101
- user_input={"菜品选择": []},
102
- dynamic_interaction_format=result1.content
103
- )
104
- if hasattr(result4, 'content') and result4.content:
105
- print("⚠️ 空输入可能被接受(取决于交互类型)")
106
- else:
107
- print("✅ 正确处理空输入")
108
- except Exception as e:
109
- print(f"✅ 正确处理空输入错误: {str(e)[:50]}...")
94
+ result4 = mf.process(
95
+ block_index=0,
96
+ mode=ProcessMode.COMPLETE,
97
+ user_input={"菜品选择": []},
98
+ dynamic_interaction_format=result1.content
99
+ )
100
+ print(f"空输入: []")
101
+ print(f"LLM完整响应: {result4.content}")
102
+ print(f"返回变量: {result4.variables}")
103
+ print(f"元数据: {result4.metadata}")
110
104
 
111
105
  print("✅ 中文餐厅场景完整验证通过")
112
106
 
@@ -176,18 +170,17 @@ Format: Provide specific educational options"""
176
170
 
177
171
  # 第三步:测试部分匹配选择
178
172
  print("\n--- Test Partial Match ---")
179
- try:
180
- partial_choices = ["Computer"] # 只选择一个词
181
- result3 = mf.process(
182
- block_index=0,
183
- mode=ProcessMode.COMPLETE,
184
- user_input={"learning_choice": partial_choices},
185
- dynamic_interaction_format=result1.content
186
- )
187
- print(f"Partial selection: {partial_choices}")
188
- print(f"Result: {result3.variables}")
189
- except Exception as e:
190
- print(f"Partial selection handling: {str(e)[:50]}...")
173
+ partial_choices = ["Computer"] # 只选择一个词
174
+ result3 = mf.process(
175
+ block_index=0,
176
+ mode=ProcessMode.COMPLETE,
177
+ user_input={"learning_choice": partial_choices},
178
+ dynamic_interaction_format=result1.content
179
+ )
180
+ print(f"部分匹配输入: {partial_choices}")
181
+ print(f"LLM完整响应: {result3.content}")
182
+ print(f"返回变量: {result3.variables}")
183
+ print(f"元数据: {result3.metadata}")
191
184
 
192
185
  # 第四步:测试单个选择
193
186
  print("\n--- Test Single Selection ---")
@@ -414,20 +407,18 @@ def test_complex_job_consultation_scenario():
414
407
 
415
408
  # 测试无效职位选择
416
409
  print("\n--- 测试无效职位选择 ---")
417
- try:
418
- invalid_job = ["厨师", "司机"] # 不属于科技行业的职位
419
- result_invalid = mf.process(
420
- block_index=1,
421
- mode=ProcessMode.COMPLETE,
422
- variables=result1.variables,
423
- user_input={"职位选择": invalid_job},
424
- dynamic_interaction_format=result2.content
425
- )
426
- print("⚠️ 无效职位选择可能被接受")
427
- # 避免未使用变量警告
428
- _ = result_invalid
429
- except Exception as e:
430
- print(f"✅ 正确拒绝无效职位选择: {str(e)[:50]}...")
410
+ invalid_job = ["厨师", "司机"] # 不属于科技行业的职位
411
+ result_invalid = mf.process(
412
+ block_index=1,
413
+ mode=ProcessMode.COMPLETE,
414
+ variables=result1.variables,
415
+ user_input={"职位选择": invalid_job},
416
+ dynamic_interaction_format=result2.content
417
+ )
418
+ print(f"无效职位输入: {invalid_job}")
419
+ print(f"LLM完整响应: {result_invalid.content}")
420
+ print(f"返回变量: {result_invalid.variables}")
421
+ print(f"元数据: {result_invalid.metadata}")
431
422
 
432
423
  # 第四步:生成薪资选项
433
424
  print("\n--- 步骤4: 生成薪资选项 ---")
@@ -567,16 +558,16 @@ def test_text_input_scenario():
567
558
 
568
559
  # 测试空输入(对于支持文本输入的交互,可能允许空输入)
569
560
  print("\n--- 测试空输入处理 ---")
570
- try:
571
- result5 = mf.process(
572
- block_index=0,
573
- mode=ProcessMode.COMPLETE,
574
- user_input={"自定义需求": []},
575
- dynamic_interaction_format=result1.content
576
- )
577
- print(" 空输入被接受(支持文本输入的交互可能允许空输入)")
578
- except Exception as e:
579
- print(f"空输入被拒绝: {str(e)[:50]}...")
561
+ result5 = mf.process(
562
+ block_index=0,
563
+ mode=ProcessMode.COMPLETE,
564
+ user_input={"自定义需求": []},
565
+ dynamic_interaction_format=result1.content
566
+ )
567
+ print(f"空输入: []")
568
+ print(f"LLM完整响应: {result5.content}")
569
+ print(f"返回变量: {result5.variables}")
570
+ print(f"元数据: {result5.metadata}")
580
571
 
581
572
  print("✅ 文本输入场景完整验证通过")
582
573
 
@@ -701,20 +692,18 @@ def test_variable_context_cuisine_scenario():
701
692
 
702
693
  # 测试无效菜品选择
703
694
  print("\n--- 测试无效菜品选择 ---")
704
- try:
705
- invalid_dishes = ["北京烤鸭", "小笼包"] # 非川菜选项
706
- result_invalid = mf.process(
707
- block_index=1,
708
- mode=ProcessMode.COMPLETE,
709
- variables=result1.variables,
710
- user_input={"菜品": invalid_dishes},
711
- dynamic_interaction_format=result2.content
712
- )
713
- print("⚠️ 无效菜品选择可能被接受")
714
- # 避免未使用变量警告
715
- _ = result_invalid
716
- except Exception as e:
717
- print(f"✅ 正确拒绝无效菜品选择: {str(e)[:50]}...")
695
+ invalid_dishes = ["北京烤鸭", "小笼包"] # 非川菜选项
696
+ result_invalid = mf.process(
697
+ block_index=1,
698
+ mode=ProcessMode.COMPLETE,
699
+ variables=result1.variables,
700
+ user_input={"菜品": invalid_dishes},
701
+ dynamic_interaction_format=result2.content
702
+ )
703
+ print(f"无效菜品输入: {invalid_dishes}")
704
+ print(f"LLM完整响应: {result_invalid.content}")
705
+ print(f"返回变量: {result_invalid.variables}")
706
+ print(f"元数据: {result_invalid.metadata}")
718
707
 
719
708
  print("✅ 变量上下文场景完整验证通过")
720
709
 
@@ -823,6 +812,89 @@ Format: Provide specific project options based on the selected programming langu
823
812
  print(f"❌ Test failed: {e}")
824
813
 
825
814
 
815
+ def test_user_question_text_input():
816
+ """测试用户疑问式文本输入场景"""
817
+ print("\n=== 用户疑问文本输入测试 ===")
818
+
819
+ document = """询问用户的故事风格偏好,并记录到变量{{风格选择}}"""
820
+
821
+ document_prompt = """你是故事创作助手。为用户提供故事风格选项:
822
+ - 常见风格:幽默、搞笑、悬疑、浪漫、文言文
823
+ - 同时允许用户输入其他风格偏好
824
+
825
+ 语言:中文
826
+ 格式:提供常见风格选项 + 允许自定义文本输入(使用...前缀)"""
827
+
828
+ try:
829
+ llm_provider = create_llm_provider()
830
+ mf = MarkdownFlow(
831
+ document=document,
832
+ llm_provider=llm_provider,
833
+ document_prompt=document_prompt
834
+ )
835
+
836
+ # 生成动态交互
837
+ print("--- 生成故事风格选项 ---")
838
+ result1 = mf.process(
839
+ block_index=0,
840
+ mode=ProcessMode.COMPLETE
841
+ )
842
+
843
+ print(f"转换为交互块: {result1.transformed_to_interaction}")
844
+ print(f"生成的交互: {result1.content}")
845
+
846
+ if result1.transformed_to_interaction:
847
+ # 验证是否包含文本输入选项
848
+ has_text_input = "..." in result1.content
849
+ if has_text_input:
850
+ print("✅ 包含文本输入选项")
851
+
852
+ # 测试用户疑问式输入
853
+ print("\n--- 测试疑问式文本输入 ---")
854
+ question_input = ["这里必须要选择么?"]
855
+
856
+ result2 = mf.process(
857
+ block_index=0,
858
+ mode=ProcessMode.COMPLETE,
859
+ user_input={"风格选择": question_input},
860
+ dynamic_interaction_format=result1.content
861
+ )
862
+
863
+ print(f"用户疑问输入: {question_input}")
864
+ print(f"验证结果: {result2.variables}")
865
+
866
+ # 显示疑问输入的完整处理结果
867
+ print(f"疑问输入: {question_input}")
868
+ print(f"LLM完整响应: {result2.content}")
869
+ print(f"返回变量: {result2.variables}")
870
+ print(f"元数据: {result2.metadata}")
871
+
872
+ # 测试其他类型的自定义输入
873
+ print("\n--- 测试其他自定义输入 ---")
874
+ custom_inputs = [
875
+ ["我想要科幻加悬疑的混合风格"],
876
+ ["可以不选择吗"],
877
+ ["这些选项都不适合我"]
878
+ ]
879
+
880
+ for custom_input in custom_inputs:
881
+ result_custom = mf.process(
882
+ block_index=0,
883
+ mode=ProcessMode.COMPLETE,
884
+ user_input={"风格选择": custom_input},
885
+ dynamic_interaction_format=result1.content
886
+ )
887
+ print(f"\n自定义输入: {custom_input}")
888
+ print(f"LLM完整响应: {result_custom.content}")
889
+ print(f"返回变量: {result_custom.variables}")
890
+ print(f"元数据: {result_custom.metadata}")
891
+
892
+ print("✅ 用户疑问文本输入场景测试完成")
893
+
894
+ except Exception as e:
895
+ print(f"❌ 测试失败: {e}")
896
+
897
+
826
898
  def run_all_tests():
827
899
  """运行所有 document_prompt 测试"""
828
900
  print("🧪 开始 document_prompt 动态交互测试")
@@ -836,7 +908,8 @@ def run_all_tests():
836
908
  test_complex_job_consultation_scenario,
837
909
  test_text_input_scenario,
838
910
  test_variable_context_cuisine_scenario,
839
- test_variable_context_skill_project_scenario
911
+ test_variable_context_skill_project_scenario,
912
+ test_user_question_text_input
840
913
  ]
841
914
 
842
915
  for test_func in tests:
File without changes
File without changes
File without changes