synkro 0.4.30__tar.gz → 0.4.53__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 (106) hide show
  1. {synkro-0.4.30 → synkro-0.4.53}/PKG-INFO +298 -9
  2. synkro-0.4.53/README.md +551 -0
  3. {synkro-0.4.30 → synkro-0.4.53}/examples/advanced_usage.py +5 -0
  4. {synkro-0.4.30 → synkro-0.4.53}/examples/anthropic_basic.py +6 -1
  5. synkro-0.4.53/examples/coverage_tracking.py +58 -0
  6. synkro-0.4.53/examples/eval_scenarios.py +138 -0
  7. synkro-0.4.53/examples/evaluation_test.py +37 -0
  8. {synkro-0.4.30 → synkro-0.4.53}/examples/finetune_llama.py +9 -4
  9. {synkro-0.4.30 → synkro-0.4.53}/examples/multi_file_policy.py +6 -1
  10. {synkro-0.4.30 → synkro-0.4.53}/examples/openai_basic.py +5 -0
  11. synkro-0.4.53/examples/pdf_examples/dmv_handbook.py +87 -0
  12. {synkro-0.4.30 → synkro-0.4.53}/examples/quickstart.py +12 -10
  13. {synkro-0.4.30 → synkro-0.4.53}/examples/tool_calling.py +5 -0
  14. {synkro-0.4.30 → synkro-0.4.53}/pyproject.toml +4 -5
  15. {synkro-0.4.30 → synkro-0.4.53}/synkro/__init__.py +157 -4
  16. {synkro-0.4.30 → synkro-0.4.53}/synkro/advanced.py +2 -2
  17. {synkro-0.4.30 → synkro-0.4.53}/synkro/cli.py +2 -2
  18. {synkro-0.4.30 → synkro-0.4.53}/synkro/core/checkpoint.py +1 -1
  19. {synkro-0.4.30 → synkro-0.4.53}/synkro/core/dataset.py +61 -28
  20. {synkro-0.4.30 → synkro-0.4.53}/synkro/core/policy.py +10 -10
  21. synkro-0.4.53/synkro/coverage/__init__.py +23 -0
  22. synkro-0.4.53/synkro/coverage/calculator.py +363 -0
  23. synkro-0.4.53/synkro/coverage/improver.py +321 -0
  24. synkro-0.4.53/synkro/coverage/scenario_tagger.py +186 -0
  25. synkro-0.4.53/synkro/coverage/taxonomy_extractor.py +161 -0
  26. {synkro-0.4.30 → synkro-0.4.53}/synkro/factory.py +50 -2
  27. synkro-0.4.53/synkro/formatters/__init__.py +17 -0
  28. {synkro-0.4.30 → synkro-0.4.53}/synkro/formatters/chatml.py +10 -3
  29. synkro-0.4.53/synkro/formatters/langfuse.py +109 -0
  30. synkro-0.4.53/synkro/formatters/langsmith.py +109 -0
  31. synkro-0.4.30/synkro/formatters/sft.py → synkro-0.4.53/synkro/formatters/messages.py +16 -11
  32. synkro-0.4.53/synkro/formatters/qa.py +123 -0
  33. {synkro-0.4.30 → synkro-0.4.53}/synkro/formatters/tool_call.py +14 -7
  34. {synkro-0.4.30 → synkro-0.4.53}/synkro/generation/generator.py +86 -4
  35. {synkro-0.4.30 → synkro-0.4.53}/synkro/generation/golden_responses.py +25 -0
  36. {synkro-0.4.30 → synkro-0.4.53}/synkro/generation/golden_scenarios.py +168 -49
  37. {synkro-0.4.30 → synkro-0.4.53}/synkro/generation/golden_tool_responses.py +29 -0
  38. {synkro-0.4.30 → synkro-0.4.53}/synkro/interactive/intent_classifier.py +3 -0
  39. {synkro-0.4.30 → synkro-0.4.53}/synkro/interactive/rich_ui.py +109 -13
  40. {synkro-0.4.30 → synkro-0.4.53}/synkro/llm/client.py +37 -1
  41. {synkro-0.4.30 → synkro-0.4.53}/synkro/modes/config.py +2 -1
  42. {synkro-0.4.30 → synkro-0.4.53}/synkro/modes/conversation.py +9 -0
  43. {synkro-0.4.30 → synkro-0.4.53}/synkro/pipeline/runner.py +417 -9
  44. {synkro-0.4.30 → synkro-0.4.53}/synkro/pipelines.py +11 -1
  45. synkro-0.4.53/synkro/prompts/coverage_templates.py +294 -0
  46. {synkro-0.4.30 → synkro-0.4.53}/synkro/prompts/golden_templates.py +77 -0
  47. {synkro-0.4.30 → synkro-0.4.53}/synkro/prompts/interactive_templates.py +20 -2
  48. synkro-0.4.53/synkro/reporting.py +803 -0
  49. {synkro-0.4.30 → synkro-0.4.53}/synkro/schemas.py +83 -2
  50. {synkro-0.4.30 → synkro-0.4.53}/synkro/types/__init__.py +2 -0
  51. {synkro-0.4.30 → synkro-0.4.53}/synkro/types/core.py +33 -0
  52. synkro-0.4.53/synkro/types/coverage.py +399 -0
  53. {synkro-0.4.30 → synkro-0.4.53}/synkro/types/dataset_type.py +5 -1
  54. {synkro-0.4.30 → synkro-0.4.53}/synkro/types/logic_map.py +9 -1
  55. {synkro-0.4.30 → synkro-0.4.53}/tests/test_imports.py +3 -3
  56. synkro-0.4.30/README.md +0 -261
  57. synkro-0.4.30/synkro/formatters/__init__.py +0 -12
  58. synkro-0.4.30/synkro/reporting.py +0 -403
  59. {synkro-0.4.30 → synkro-0.4.53}/.gitignore +0 -0
  60. {synkro-0.4.30 → synkro-0.4.53}/LICENSE +0 -0
  61. {synkro-0.4.30 → synkro-0.4.53}/examples/policies/hr_policy.md +0 -0
  62. {synkro-0.4.30 → synkro-0.4.53}/examples/policies/security_policy.txt +0 -0
  63. {synkro-0.4.30 → synkro-0.4.53}/examples/test_fixes.py +0 -0
  64. {synkro-0.4.30 → synkro-0.4.53}/synkro/core/__init__.py +0 -0
  65. {synkro-0.4.30 → synkro-0.4.53}/synkro/errors.py +0 -0
  66. {synkro-0.4.30 → synkro-0.4.53}/synkro/examples/__init__.py +0 -0
  67. {synkro-0.4.30 → synkro-0.4.53}/synkro/generation/__init__.py +0 -0
  68. {synkro-0.4.30 → synkro-0.4.53}/synkro/generation/follow_ups.py +0 -0
  69. {synkro-0.4.30 → synkro-0.4.53}/synkro/generation/logic_extractor.py +0 -0
  70. {synkro-0.4.30 → synkro-0.4.53}/synkro/generation/multiturn_responses.py +0 -0
  71. {synkro-0.4.30 → synkro-0.4.53}/synkro/generation/planner.py +0 -0
  72. {synkro-0.4.30 → synkro-0.4.53}/synkro/generation/responses.py +0 -0
  73. {synkro-0.4.30 → synkro-0.4.53}/synkro/generation/scenarios.py +0 -0
  74. {synkro-0.4.30 → synkro-0.4.53}/synkro/generation/tool_responses.py +0 -0
  75. {synkro-0.4.30 → synkro-0.4.53}/synkro/generation/tool_simulator.py +0 -0
  76. {synkro-0.4.30 → synkro-0.4.53}/synkro/interactive/__init__.py +0 -0
  77. {synkro-0.4.30 → synkro-0.4.53}/synkro/interactive/hitl_session.py +0 -0
  78. {synkro-0.4.30 → synkro-0.4.53}/synkro/interactive/logic_map_editor.py +0 -0
  79. {synkro-0.4.30 → synkro-0.4.53}/synkro/interactive/scenario_editor.py +0 -0
  80. {synkro-0.4.30 → synkro-0.4.53}/synkro/llm/__init__.py +0 -0
  81. {synkro-0.4.30 → synkro-0.4.53}/synkro/llm/rate_limits.py +0 -0
  82. {synkro-0.4.30 → synkro-0.4.53}/synkro/models/__init__.py +0 -0
  83. {synkro-0.4.30 → synkro-0.4.53}/synkro/models/anthropic.py +0 -0
  84. {synkro-0.4.30 → synkro-0.4.53}/synkro/models/google.py +0 -0
  85. {synkro-0.4.30 → synkro-0.4.53}/synkro/models/local.py +0 -0
  86. {synkro-0.4.30 → synkro-0.4.53}/synkro/models/openai.py +0 -0
  87. {synkro-0.4.30 → synkro-0.4.53}/synkro/modes/__init__.py +0 -0
  88. {synkro-0.4.30 → synkro-0.4.53}/synkro/modes/tool_call.py +0 -0
  89. {synkro-0.4.30 → synkro-0.4.53}/synkro/parsers.py +0 -0
  90. {synkro-0.4.30 → synkro-0.4.53}/synkro/pipeline/__init__.py +0 -0
  91. {synkro-0.4.30 → synkro-0.4.53}/synkro/pipeline/phases.py +0 -0
  92. {synkro-0.4.30 → synkro-0.4.53}/synkro/prompts/__init__.py +0 -0
  93. {synkro-0.4.30 → synkro-0.4.53}/synkro/prompts/base.py +0 -0
  94. {synkro-0.4.30 → synkro-0.4.53}/synkro/prompts/multiturn_templates.py +0 -0
  95. {synkro-0.4.30 → synkro-0.4.53}/synkro/prompts/templates.py +0 -0
  96. {synkro-0.4.30 → synkro-0.4.53}/synkro/prompts/tool_templates.py +0 -0
  97. {synkro-0.4.30 → synkro-0.4.53}/synkro/quality/__init__.py +0 -0
  98. {synkro-0.4.30 → synkro-0.4.53}/synkro/quality/golden_refiner.py +0 -0
  99. {synkro-0.4.30 → synkro-0.4.53}/synkro/quality/grader.py +0 -0
  100. {synkro-0.4.30 → synkro-0.4.53}/synkro/quality/multiturn_grader.py +0 -0
  101. {synkro-0.4.30 → synkro-0.4.53}/synkro/quality/refiner.py +0 -0
  102. {synkro-0.4.30 → synkro-0.4.53}/synkro/quality/tool_grader.py +0 -0
  103. {synkro-0.4.30 → synkro-0.4.53}/synkro/quality/tool_refiner.py +0 -0
  104. {synkro-0.4.30 → synkro-0.4.53}/synkro/quality/verifier.py +0 -0
  105. {synkro-0.4.30 → synkro-0.4.53}/synkro/types/tool.py +0 -0
  106. {synkro-0.4.30 → synkro-0.4.53}/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: synkro
3
- Version: 0.4.30
3
+ Version: 0.4.53
4
4
  Summary: Generate training datasets from any document
5
5
  Author: Murtaza Meerza
6
6
  License-Expression: MIT
@@ -20,9 +20,8 @@ Requires-Dist: html2text>=2020.1
20
20
  Requires-Dist: httpx>=0.25
21
21
  Requires-Dist: litellm>=1.40
22
22
  Requires-Dist: mammoth>=1.6
23
- Requires-Dist: marker-pdf>=0.2
24
23
  Requires-Dist: pydantic>=2.0
25
- Requires-Dist: python-dotenv>=1.0
24
+ Requires-Dist: pymupdf>=1.24
26
25
  Requires-Dist: rich>=13.0
27
26
  Requires-Dist: typer>=0.9
28
27
  Provides-Extra: dev
@@ -33,16 +32,19 @@ Description-Content-Type: text/markdown
33
32
 
34
33
  # Synkro
35
34
 
36
- Turn policies, handbooks, and documentation into high-quality training data for fine-tuning LLMs.
35
+ Library for turning unstructured policies, handbooks, and documentation into high-quality conversation, tool calling or evaluation data for LLMs.
37
36
 
38
37
  ## Features
39
38
 
40
39
  - **Quality Evaluation** - Each response is graded and automatically refined if it fails
41
- - **Multiple Formats** - Conversation (multi-turn), Instruction (single-turn), and Tool Calling
40
+ - **Multiple Formats** - Conversation (multi-turn), Instruction (single-turn), Evaluation (Q&A), and Tool Calling
41
+ - **Eval Platform Support** - Export to LangSmith, Langfuse, or generic Q&A format
42
42
  - **Tool Call Training** - Generate OpenAI function calling format for teaching models to use custom tools
43
- - **Top LLM Providers** - OpenAI, Anthropic, and Google
43
+ - **Coverage Tracking** - Track scenario diversity like code coverage, identify gaps, and improve coverage with natural language commands
44
+ - **Top LLM Providers** - OpenAI, Anthropic, Google, and local models (Ollama, vLLM)
44
45
  - **File Support** - PDF, DOCX, TXT, Markdown, URLs
45
46
  - **CLI Included** - Generate datasets from the command line
47
+ - **Cost Tracking** - See total cost and LLM call breakdown after each generation
46
48
 
47
49
  ## Installation
48
50
 
@@ -95,9 +97,10 @@ dataset = pipeline.generate(policy)
95
97
 
96
98
  | Type | Turns | Output Formats | Best For |
97
99
  |------|-------|----------------|----------|
98
- | **CONVERSATION** | Multi | messages | Fine-tuning chat models |
99
- | **INSTRUCTION** | 1 | messages | Instruction-following models |
100
- | **TOOL_CALL** | Multi | OpenAI function calling, ChatML | Teaching tool use |
100
+ | **CONVERSATION** | Multi | messages, chatml | Fine-tuning chat models |
101
+ | **INSTRUCTION** | 1 | messages, chatml | Instruction-following models |
102
+ | **EVALUATION** | 1 | qa, langsmith, langfuse | LLM evaluation & benchmarks |
103
+ | **TOOL_CALL** | Multi | tool_call, chatml | Teaching tool use |
101
104
 
102
105
  ### Conversation (Default)
103
106
 
@@ -133,6 +136,50 @@ Output (single-turn):
133
136
  ]}
134
137
  ```
135
138
 
139
+ ### Evaluation
140
+
141
+ Generate Q&A datasets for LLM evaluation with ground truth:
142
+
143
+ ```python
144
+ pipeline = create_pipeline(dataset_type=DatasetType.EVALUATION)
145
+ dataset = pipeline.generate(policy, traces=50)
146
+
147
+ # Save in different formats
148
+ dataset.save("eval.jsonl", format="qa") # Generic Q&A
149
+ dataset.save("eval.jsonl", format="langsmith") # LangSmith format
150
+ dataset.save("eval.jsonl", format="langfuse") # Langfuse format
151
+ ```
152
+
153
+ Output (`format="qa"`):
154
+ ```json
155
+ {
156
+ "question": "Can I submit a $200 expense without a receipt?",
157
+ "answer": "All expenses require receipts per policy...",
158
+ "expected_outcome": "Deny - missing receipt violates R003",
159
+ "ground_truth_rules": ["R003", "R005"],
160
+ "difficulty": "negative",
161
+ "category": "Receipt Requirements"
162
+ }
163
+ ```
164
+
165
+ Output (`format="langsmith"`):
166
+ ```json
167
+ {
168
+ "inputs": {"question": "...", "context": "..."},
169
+ "outputs": {"answer": "..."},
170
+ "metadata": {"expected_outcome": "...", "ground_truth_rules": [...]}
171
+ }
172
+ ```
173
+
174
+ Output (`format="langfuse"`):
175
+ ```json
176
+ {
177
+ "input": {"question": "...", "context": "..."},
178
+ "expectedOutput": {"answer": "...", "expected_outcome": "..."},
179
+ "metadata": {"ground_truth_rules": [...], "difficulty": "..."}
180
+ }
181
+ ```
182
+
136
183
  ### Tool Calling
137
184
 
138
185
  Generate training data for teaching models when and how to use your custom tools:
@@ -218,6 +265,188 @@ high_quality = dataset.filter(passed=True)
218
265
  high_quality.save("training.jsonl")
219
266
  ```
220
267
 
268
+ ## Eval API
269
+
270
+ Generate test scenarios and grade your own model's responses against policy compliance.
271
+
272
+ ```python
273
+ import synkro
274
+
275
+ # Generate scenarios with ground truth (no synthetic responses)
276
+ result = synkro.generate_scenarios(
277
+ policy="Expenses over $50 require manager approval...",
278
+ count=100,
279
+ )
280
+
281
+ # Each scenario has ground truth labels
282
+ for scenario in result.scenarios:
283
+ print(scenario.user_message) # "Can I expense a $200 dinner?"
284
+ print(scenario.expected_outcome) # "Requires manager approval per R001"
285
+ print(scenario.target_rule_ids) # ["R001", "R003"]
286
+ print(scenario.scenario_type) # "positive" | "negative" | "edge_case"
287
+
288
+ # Grade YOUR model's responses
289
+ for scenario in result.scenarios:
290
+ response = my_model(scenario.user_message) # Your model
291
+ grade = synkro.grade(response, scenario, policy)
292
+
293
+ if not grade.passed:
294
+ print(f"Failed: {grade.feedback}")
295
+ ```
296
+
297
+ ### When to Use
298
+
299
+ | Use Case | API |
300
+ |----------|-----|
301
+ | Generate training data | `synkro.generate()` |
302
+ | Generate eval scenarios | `synkro.generate_scenarios()` |
303
+ | Grade external model | `synkro.grade()` |
304
+
305
+ ### Scenario Types
306
+
307
+ Scenarios are generated with balanced coverage:
308
+
309
+ | Type | % | Description |
310
+ |------|---|-------------|
311
+ | `positive` | 35% | Happy path - user meets all criteria |
312
+ | `negative` | 30% | Violations - user fails one criterion |
313
+ | `edge_case` | 25% | Boundary conditions at exact limits |
314
+ | `irrelevant` | 10% | Outside policy scope |
315
+
316
+ ### EvalScenario Fields
317
+
318
+ ```python
319
+ scenario.user_message # The test input
320
+ scenario.expected_outcome # Ground truth behavior
321
+ scenario.target_rule_ids # Rules being tested
322
+ scenario.scenario_type # positive/negative/edge_case/irrelevant
323
+ scenario.category # Policy category
324
+ scenario.context # Additional context
325
+ ```
326
+
327
+ ### Temperature
328
+
329
+ Use `temperature` to control output diversity:
330
+
331
+ ```python
332
+ # High temp for diverse scenario coverage
333
+ result = synkro.generate_scenarios(policy, temperature=0.8)
334
+
335
+ # Low temp for deterministic training data
336
+ dataset = synkro.generate(policy, temperature=0.2)
337
+ ```
338
+
339
+ ## Coverage Tracking
340
+
341
+ Track how well your generated scenarios cover different aspects of your policy, similar to code coverage for tests.
342
+
343
+ ```python
344
+ import synkro
345
+
346
+ # Generate with logic map access
347
+ result = synkro.generate(policy, traces=50, return_logic_map=True)
348
+
349
+ # View coverage report
350
+ synkro.coverage_report(result)
351
+ ```
352
+
353
+ Output:
354
+ ```
355
+ Coverage Report
356
+ ========================================
357
+ Overall: 68.8%
358
+ Sub-categories: 2 covered, 1 partial, 1 uncovered
359
+ Total scenarios: 20
360
+
361
+ Gaps (2):
362
+ - Receipt requirements [HIGH] (0% coverage, 0 scenarios)
363
+ - Travel booking rules [MEDIUM] (partial: 40% coverage)
364
+
365
+ Suggestions:
366
+ 1. Add 3+ scenarios for 'Receipt requirements' testing R008, R009
367
+ 2. Add edge_case scenarios for 'Travel booking rules'
368
+ ```
369
+
370
+ ### Coverage Report Formats
371
+
372
+ ```python
373
+ # Print to console (default)
374
+ synkro.coverage_report(result)
375
+
376
+ # Get as dictionary for programmatic use
377
+ report = synkro.coverage_report(result, format="dict")
378
+ print(f"Coverage: {report['overall_coverage_percent']}%")
379
+ print(f"Gaps: {len(report['gaps'])}")
380
+
381
+ # Get as JSON string
382
+ json_str = synkro.coverage_report(result, format="json")
383
+
384
+ # Get raw CoverageReport object
385
+ report = synkro.coverage_report(result, format="report")
386
+ for gap in report.gaps:
387
+ print(f"Gap: {gap}")
388
+ ```
389
+
390
+ ### Interactive Coverage Commands
391
+
392
+ In interactive mode, use natural language to view and improve coverage:
393
+
394
+ | Command | Action |
395
+ |---------|--------|
396
+ | `"show coverage"` | Display coverage summary |
397
+ | `"show coverage gaps"` | Show uncovered sub-categories |
398
+ | `"show heatmap"` | Visual coverage by category |
399
+ | `"increase coverage for refunds by 20%"` | Add scenarios for a sub-category |
400
+ | `"get amount thresholds to 80%"` | Target specific coverage percentage |
401
+ | `"add more negative scenarios for time eligibility"` | Add specific scenario types |
402
+
403
+ ### Coverage Metrics
404
+
405
+ Each sub-category is tracked with:
406
+
407
+ | Metric | Description |
408
+ |--------|-------------|
409
+ | `coverage_percent` | % of expected coverage achieved |
410
+ | `coverage_status` | `covered` (80%+), `partial` (30-80%), `uncovered` (<30%) |
411
+ | `scenario_count` | Number of scenarios testing this sub-category |
412
+ | `type_distribution` | Breakdown by positive/negative/edge_case |
413
+
414
+ ## Cost & Performance
415
+
416
+ Approximate costs using Gemini 2.5 Flash (multi-turn conversations):
417
+
418
+ | Traces | LLM Calls | Time | Cost |
419
+ |--------|-----------|------|------|
420
+ | 100 | ~335 | ~13 min | ~$3 |
421
+ | 500 | ~1,675 | ~1 hour | ~$14 |
422
+ | 1000 | ~3,350 | ~2 hours | ~$28 |
423
+
424
+ *Based on ~3.3 LLM calls per trace (generation + grading) with max_iterations=3. Actual costs vary by policy complexity and turn count.*
425
+
426
+ ## Local LLMs
427
+
428
+ Run with Ollama, vLLM, or any OpenAI-compatible endpoint:
429
+
430
+ ```python
431
+ from synkro import create_pipeline
432
+ from synkro.models import Local
433
+
434
+ # Ollama
435
+ pipeline = create_pipeline(model=Local.OLLAMA("llama3.2"))
436
+
437
+ # vLLM
438
+ pipeline = create_pipeline(model=Local.VLLM("mistral-7b"))
439
+
440
+ # Custom endpoint
441
+ pipeline = create_pipeline(model=Local.CUSTOM("my-model", endpoint="http://localhost:8080"))
442
+ ```
443
+
444
+ **CLI:**
445
+ ```bash
446
+ synkro generate policy.pdf --provider ollama --model llama3.2
447
+ synkro generate policy.pdf --provider vllm --endpoint http://localhost:8000
448
+ ```
449
+
221
450
  ## CLI
222
451
 
223
452
  ```bash
@@ -232,12 +461,18 @@ synkro generate https://example.com/policy -o training.jsonl
232
461
 
233
462
  # Skip interactive mode
234
463
  synkro generate policy.pdf --no-interactive
464
+
465
+ # Quick demo with built-in policy
466
+ synkro demo
235
467
  ```
236
468
 
237
469
  **Options:**
238
470
  - `--traces, -n` - Number of traces (default: 20)
239
471
  - `--output, -o` - Output file path
240
472
  - `--model, -m` - Model for generation
473
+ - `--format, -f` - Output format: `messages`, `qa`, `langsmith`, `langfuse`, `tool_call`, `chatml`
474
+ - `--provider, -p` - LLM provider for local models (`ollama`, `vllm`)
475
+ - `--endpoint, -e` - Custom API endpoint URL
241
476
  - `--interactive/-i, --no-interactive/-I` - Review/edit extracted rules before generation (default: on)
242
477
 
243
478
  ## Interactive Mode
@@ -278,6 +513,60 @@ You can adjust both **conversation turns** and **rules** using natural language:
278
513
 
279
514
  Commands: `done`, `undo`, `reset`, `show R001`, `help`
280
515
 
516
+ ## Advanced Features
517
+
518
+ ### Checkpointing
519
+
520
+ Resume interrupted generations:
521
+
522
+ ```python
523
+ pipeline = create_pipeline(checkpoint_dir="./checkpoints")
524
+ dataset = pipeline.generate(policy, traces=100) # Resumes from checkpoint
525
+ ```
526
+
527
+ ### Dataset Operations
528
+
529
+ ```python
530
+ # Filter by quality
531
+ high_quality = dataset.filter(passed=True)
532
+
533
+ # Remove duplicates
534
+ unique = dataset.dedupe(threshold=0.85)
535
+
536
+ # Check pass rate
537
+ print(f"Pass rate: {dataset.passing_rate:.1%}")
538
+ ```
539
+
540
+ ### Folder Loading
541
+
542
+ Generate from multiple documents at once:
543
+
544
+ ```python
545
+ from synkro.core.policy import Policy
546
+
547
+ policy = Policy.from_file("policies/") # Loads all PDF, DOCX, TXT, MD files
548
+ dataset = pipeline.generate(policy, traces=100)
549
+ ```
550
+
551
+ ### Thinking Mode
552
+
553
+ Generate training data with explicit reasoning in `<think>` tags, compatible with Qwen3 and DeepSeek-R1:
554
+
555
+ ```python
556
+ pipeline = create_pipeline(thinking=True)
557
+ dataset = pipeline.generate(policy, traces=50)
558
+ ```
559
+
560
+ Output:
561
+ ```json
562
+ {"messages": [
563
+ {"role": "user", "content": "Can I expense a $350 team dinner?"},
564
+ {"role": "assistant", "content": "<think>\nLet me check the expense policy...\n- Rule: Expenses over $50 require manager approval\n- $350 exceeds the $50 threshold\n- Manager approval is required\n</think>\n\nFor a $350 team dinner, you'll need manager approval since it exceeds the $50 threshold. Please submit your expense report with the receipt and request approval from your manager."}
565
+ ]}
566
+ ```
567
+
568
+ Works with all dataset types (`CONVERSATION`, `INSTRUCTION`, `TOOL_CALL`).
569
+
281
570
  ## Logic Map Inspection
282
571
 
283
572
  Access the extracted rules programmatically: