synkro 0.4.5__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.

Potentially problematic release.


This version of synkro might be problematic. Click here for more details.

Files changed (58) hide show
  1. synkro/__init__.py +165 -0
  2. synkro/cli.py +120 -0
  3. synkro/core/__init__.py +7 -0
  4. synkro/core/dataset.py +233 -0
  5. synkro/core/policy.py +337 -0
  6. synkro/errors.py +178 -0
  7. synkro/examples/__init__.py +148 -0
  8. synkro/factory.py +160 -0
  9. synkro/formatters/__init__.py +12 -0
  10. synkro/formatters/qa.py +85 -0
  11. synkro/formatters/sft.py +90 -0
  12. synkro/formatters/tool_call.py +127 -0
  13. synkro/generation/__init__.py +9 -0
  14. synkro/generation/generator.py +163 -0
  15. synkro/generation/planner.py +87 -0
  16. synkro/generation/responses.py +160 -0
  17. synkro/generation/scenarios.py +90 -0
  18. synkro/generation/tool_responses.py +370 -0
  19. synkro/generation/tool_simulator.py +114 -0
  20. synkro/llm/__init__.py +7 -0
  21. synkro/llm/client.py +235 -0
  22. synkro/llm/rate_limits.py +95 -0
  23. synkro/models/__init__.py +43 -0
  24. synkro/models/anthropic.py +26 -0
  25. synkro/models/google.py +19 -0
  26. synkro/models/openai.py +31 -0
  27. synkro/modes/__init__.py +15 -0
  28. synkro/modes/config.py +66 -0
  29. synkro/modes/qa.py +18 -0
  30. synkro/modes/sft.py +18 -0
  31. synkro/modes/tool_call.py +18 -0
  32. synkro/parsers.py +442 -0
  33. synkro/pipeline/__init__.py +20 -0
  34. synkro/pipeline/phases.py +237 -0
  35. synkro/pipeline/runner.py +198 -0
  36. synkro/pipelines.py +105 -0
  37. synkro/prompts/__init__.py +44 -0
  38. synkro/prompts/base.py +167 -0
  39. synkro/prompts/qa_templates.py +97 -0
  40. synkro/prompts/templates.py +281 -0
  41. synkro/prompts/tool_templates.py +201 -0
  42. synkro/quality/__init__.py +14 -0
  43. synkro/quality/grader.py +130 -0
  44. synkro/quality/refiner.py +137 -0
  45. synkro/quality/tool_grader.py +126 -0
  46. synkro/quality/tool_refiner.py +128 -0
  47. synkro/reporting.py +213 -0
  48. synkro/schemas.py +325 -0
  49. synkro/types/__init__.py +41 -0
  50. synkro/types/core.py +113 -0
  51. synkro/types/dataset_type.py +30 -0
  52. synkro/types/tool.py +94 -0
  53. synkro-0.4.5.data/data/examples/__init__.py +148 -0
  54. synkro-0.4.5.dist-info/METADATA +221 -0
  55. synkro-0.4.5.dist-info/RECORD +58 -0
  56. synkro-0.4.5.dist-info/WHEEL +4 -0
  57. synkro-0.4.5.dist-info/entry_points.txt +2 -0
  58. synkro-0.4.5.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,41 @@
1
+ """Type definitions for Synkro.
2
+
3
+ Usage:
4
+ from synkro.types import DatasetType, Message, Trace
5
+ from synkro.types import ToolDefinition, ToolCall, ToolFunction
6
+ """
7
+
8
+ from synkro.types.core import (
9
+ Role,
10
+ Message,
11
+ Scenario,
12
+ Trace,
13
+ GradeResult,
14
+ Plan,
15
+ Category,
16
+ )
17
+ from synkro.types.dataset_type import DatasetType
18
+ from synkro.types.tool import (
19
+ ToolDefinition,
20
+ ToolCall,
21
+ ToolFunction,
22
+ ToolResult,
23
+ )
24
+
25
+ __all__ = [
26
+ # Dataset type
27
+ "DatasetType",
28
+ # Core types
29
+ "Role",
30
+ "Message",
31
+ "Scenario",
32
+ "Trace",
33
+ "GradeResult",
34
+ "Plan",
35
+ "Category",
36
+ # Tool types
37
+ "ToolDefinition",
38
+ "ToolCall",
39
+ "ToolFunction",
40
+ "ToolResult",
41
+ ]
synkro/types/core.py ADDED
@@ -0,0 +1,113 @@
1
+ """Core Pydantic models for Synkro."""
2
+
3
+ from typing import Literal, Any
4
+ from pydantic import BaseModel, Field
5
+
6
+
7
+ Role = Literal["system", "user", "assistant", "tool"]
8
+
9
+
10
+ class Message(BaseModel):
11
+ """
12
+ A single message in a conversation.
13
+
14
+ Supports both regular chat messages and tool-calling messages.
15
+
16
+ Examples:
17
+ >>> # Regular message
18
+ >>> Message(role="user", content="Hello")
19
+
20
+ >>> # Assistant with tool call (tool_calls is list of dicts or ToolCall objects)
21
+ >>> Message(role="assistant", content=None, tool_calls=[...])
22
+
23
+ >>> # Tool response
24
+ >>> Message(role="tool", content="Result", tool_call_id="call_123")
25
+ """
26
+
27
+ role: Role
28
+ content: str | None = None
29
+ tool_calls: list[Any] | None = Field(
30
+ default=None,
31
+ description="Tool calls made by the assistant (list of ToolCall or dicts)"
32
+ )
33
+ tool_call_id: str | None = Field(
34
+ default=None,
35
+ description="ID of the tool call this message responds to (for tool role)"
36
+ )
37
+
38
+ def model_post_init(self, __context) -> None:
39
+ """Validate message structure based on role."""
40
+ # For backwards compatibility, ensure content is string for non-tool roles
41
+ if self.role in ("system", "user") and self.content is None:
42
+ self.content = ""
43
+
44
+
45
+ class Scenario(BaseModel):
46
+ """A test scenario for trace generation."""
47
+
48
+ description: str = Field(description="The scenario description")
49
+ context: str = Field(description="Additional context and background")
50
+ category: str | None = Field(default=None, description="Category this scenario belongs to")
51
+
52
+
53
+ class GradeResult(BaseModel):
54
+ """Result of grading a trace."""
55
+
56
+ passed: bool = Field(description="Whether the trace passes quality checks")
57
+ issues: list[str] = Field(default_factory=list, description="List of issues found")
58
+ feedback: str = Field(default="", description="Summary feedback for improvement")
59
+
60
+
61
+ class Trace(BaseModel):
62
+ """A complete training trace with messages and metadata."""
63
+
64
+ messages: list[Message] = Field(description="The conversation messages")
65
+ scenario: Scenario = Field(description="The scenario this trace was generated from")
66
+ grade: GradeResult | None = Field(default=None, description="Grading result if graded")
67
+
68
+ @property
69
+ def system_message(self) -> str | None:
70
+ """Get the system message content."""
71
+ for m in self.messages:
72
+ if m.role == "system":
73
+ return m.content
74
+ return None
75
+
76
+ @property
77
+ def user_message(self) -> str:
78
+ """Get the first user message content."""
79
+ for m in self.messages:
80
+ if m.role == "user":
81
+ return m.content or ""
82
+ return ""
83
+
84
+ @property
85
+ def assistant_message(self) -> str:
86
+ """Get the last assistant message content."""
87
+ for m in reversed(self.messages):
88
+ if m.role == "assistant":
89
+ return m.content or ""
90
+ return ""
91
+
92
+ @property
93
+ def has_tool_calls(self) -> bool:
94
+ """Check if this trace contains any tool calls."""
95
+ for m in self.messages:
96
+ if m.tool_calls:
97
+ return True
98
+ return False
99
+
100
+
101
+ class Category(BaseModel):
102
+ """A category for organizing scenarios."""
103
+
104
+ name: str = Field(description="Category name")
105
+ description: str = Field(description="What this category tests")
106
+ count: int = Field(description="Number of traces to generate for this category")
107
+
108
+
109
+ class Plan(BaseModel):
110
+ """A generation plan with categories."""
111
+
112
+ categories: list[Category] = Field(description="Categories with trace allocations")
113
+ reasoning: str = Field(description="Explanation of why these categories were chosen")
@@ -0,0 +1,30 @@
1
+ """Dataset type enum for steering generation pipeline."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class DatasetType(str, Enum):
7
+ """
8
+ Type of dataset to generate.
9
+
10
+ The dataset type determines:
11
+ - Prompts used for scenario and response generation
12
+ - Grading criteria
13
+ - Output format and schema
14
+
15
+ Examples:
16
+ >>> from synkro import DatasetType
17
+ >>> synkro.generate(policy, dataset_type=DatasetType.QA)
18
+ >>> synkro.generate(policy, dataset_type=DatasetType.SFT)
19
+ >>> synkro.generate(policy, dataset_type=DatasetType.TOOL_CALL, tools=[...])
20
+ """
21
+
22
+ QA = "qa"
23
+ """Question-Answer pairs: {question, answer, context}"""
24
+
25
+ SFT = "sft"
26
+ """Supervised Fine-Tuning: {messages: [system, user, assistant]}"""
27
+
28
+ TOOL_CALL = "tool_call"
29
+ """Tool Calling: {messages: [..., {tool_calls: [...]}, {role: tool}, ...]}"""
30
+
synkro/types/tool.py ADDED
@@ -0,0 +1,94 @@
1
+ """Tool-related types for tool call trace generation."""
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class ToolFunction(BaseModel):
7
+ """Function details within a tool call."""
8
+
9
+ name: str = Field(description="Name of the function to call")
10
+ arguments: str = Field(description="JSON string of function arguments")
11
+
12
+
13
+ class ToolCall(BaseModel):
14
+ """A tool call made by the assistant."""
15
+
16
+ id: str = Field(description="Unique identifier for this tool call")
17
+ type: str = Field(default="function", description="Type of tool call")
18
+ function: ToolFunction = Field(description="Function details")
19
+
20
+
21
+ class ToolResult(BaseModel):
22
+ """Result from a tool execution."""
23
+
24
+ tool_call_id: str = Field(description="ID of the tool call this responds to")
25
+ content: str = Field(description="The tool's response content")
26
+
27
+
28
+ class ToolDefinition(BaseModel):
29
+ """
30
+ Definition of a tool that an agent can use.
31
+
32
+ Examples:
33
+ >>> web_search = ToolDefinition(
34
+ ... name="web_search",
35
+ ... description="Search the web for current information",
36
+ ... parameters={
37
+ ... "type": "object",
38
+ ... "properties": {
39
+ ... "query": {"type": "string", "description": "Search query"}
40
+ ... },
41
+ ... "required": ["query"]
42
+ ... },
43
+ ... examples=[{"query": "weather in NYC"}],
44
+ ... mock_responses=["NYC: 72°F, sunny"]
45
+ ... )
46
+ """
47
+
48
+ name: str = Field(description="Name of the tool")
49
+ description: str = Field(description="What the tool does")
50
+ parameters: dict = Field(
51
+ description="JSON Schema for the tool's parameters",
52
+ default_factory=lambda: {"type": "object", "properties": {}}
53
+ )
54
+ examples: list[dict] = Field(
55
+ default_factory=list,
56
+ description="Example tool calls for few-shot learning"
57
+ )
58
+ mock_responses: list[str] = Field(
59
+ default_factory=list,
60
+ description="Example responses for simulation"
61
+ )
62
+
63
+ def to_openai_format(self) -> dict:
64
+ """Convert to OpenAI function calling format."""
65
+ return {
66
+ "type": "function",
67
+ "function": {
68
+ "name": self.name,
69
+ "description": self.description,
70
+ "parameters": self.parameters,
71
+ }
72
+ }
73
+
74
+ def to_system_prompt(self) -> str:
75
+ """Generate a system prompt description of this tool."""
76
+ params_desc = []
77
+ props = self.parameters.get("properties", {})
78
+ required = self.parameters.get("required", [])
79
+
80
+ for param_name, param_info in props.items():
81
+ param_type = param_info.get("type", "any")
82
+ param_desc = param_info.get("description", "")
83
+ req_marker = " (required)" if param_name in required else ""
84
+ params_desc.append(f" - {param_name}: {param_type}{req_marker} - {param_desc}")
85
+
86
+ params_str = "\n".join(params_desc) if params_desc else " (no parameters)"
87
+
88
+ return f"""**{self.name}**: {self.description}
89
+ Parameters:
90
+ {params_str}"""
91
+
92
+
93
+ __all__ = ["ToolDefinition", "ToolCall", "ToolFunction", "ToolResult"]
94
+
@@ -0,0 +1,148 @@
1
+ """Built-in example policies for instant demos."""
2
+
3
+ EXPENSE_POLICY = """# Company Expense Policy
4
+
5
+ ## Approval Thresholds
6
+ - Expenses under $50: No approval required
7
+ - Expenses $50-$500: Manager approval required
8
+ - Expenses over $500: VP approval required
9
+
10
+ ## Receipt Requirements
11
+ - All expenses over $25 must have a receipt
12
+ - Digital receipts are acceptable
13
+ - Missing receipts require written justification within 48 hours
14
+
15
+ ## Categories
16
+ - Travel: Flights, hotels, ground transportation, meals while traveling
17
+ - Meals: Client meals, team events (max $75/person)
18
+ - Software: Must be on pre-approved list, exceptions need IT approval
19
+ - Equipment: Must be on asset tracking list if over $200
20
+ - Office Supplies: Under $100 can be purchased directly
21
+
22
+ ## Reimbursement Timeline
23
+ - Submit expenses within 30 days of purchase
24
+ - Reimbursements processed within 14 business days
25
+ - Late submissions require manager exception approval
26
+ """
27
+
28
+ HR_HANDBOOK = """# Employee Handbook
29
+
30
+ ## Work Hours
31
+ - Standard work week is 40 hours, Monday through Friday
32
+ - Core hours are 10am to 3pm when all employees should be available
33
+ - Flexible scheduling allowed with manager approval
34
+
35
+ ## Time Off
36
+ - Full-time employees receive 15 days PTO per year
37
+ - PTO accrues monthly (1.25 days per month)
38
+ - Unused PTO can roll over up to 5 days
39
+ - PTO requests must be submitted 2 weeks in advance for 3+ days
40
+
41
+ ## Remote Work
42
+ - Hybrid schedule: minimum 2 days in office per week
43
+ - Fully remote requires director approval
44
+ - Home office stipend of $500 for remote workers
45
+
46
+ ## Performance Reviews
47
+ - Annual reviews conducted in December
48
+ - Mid-year check-ins in June
49
+ - Goals set at start of fiscal year
50
+ - Promotions considered during annual review cycle only
51
+ """
52
+
53
+ REFUND_POLICY = """# Return and Refund Policy
54
+
55
+ ## Eligibility
56
+ - Items can be returned within 30 days of purchase
57
+ - Items must be unused and in original packaging
58
+ - Receipt or proof of purchase required
59
+
60
+ ## Exceptions
61
+ - Final sale items cannot be returned
62
+ - Personalized items cannot be returned
63
+ - Perishable goods cannot be returned after 7 days
64
+
65
+ ## Refund Process
66
+ - Refunds issued to original payment method
67
+ - Processing takes 5-10 business days
68
+ - Shipping costs are non-refundable unless item was defective
69
+
70
+ ## Exchanges
71
+ - Exchanges available within 30 days
72
+ - Size exchanges free of charge
73
+ - Different item exchanges treated as return + new purchase
74
+
75
+ ## Defective Items
76
+ - Report defects within 14 days
77
+ - Photos required for defect claims
78
+ - Replacement or full refund offered for confirmed defects
79
+ """
80
+
81
+ SUPPORT_GUIDELINES = """# Customer Support Guidelines
82
+
83
+ ## Response Times
84
+ - Chat: Respond within 2 minutes
85
+ - Email: Respond within 4 hours during business hours
86
+ - Phone: Answer within 30 seconds, max hold time 3 minutes
87
+
88
+ ## Escalation Tiers
89
+ - Tier 1: General questions, password resets, basic troubleshooting
90
+ - Tier 2: Technical issues, billing disputes, account problems
91
+ - Tier 3: Complex technical issues, executive escalations
92
+
93
+ ## Refund Authority
94
+ - Tier 1 can issue refunds up to $50
95
+ - Tier 2 can issue refunds up to $200
96
+ - Tier 3 or manager approval needed for refunds over $200
97
+
98
+ ## Documentation
99
+ - Log all customer interactions in CRM
100
+ - Include customer sentiment and issue category
101
+ - Note any promised follow-ups with deadlines
102
+ """
103
+
104
+ SECURITY_POLICY = """# Information Security Policy
105
+
106
+ ## Password Requirements
107
+ - Minimum 12 characters
108
+ - Must include uppercase, lowercase, number, and symbol
109
+ - Change every 90 days
110
+ - Cannot reuse last 10 passwords
111
+
112
+ ## Access Control
113
+ - Principle of least privilege applies
114
+ - Access requests require manager approval
115
+ - Quarterly access reviews mandatory
116
+ - Terminate access within 24 hours of employee departure
117
+
118
+ ## Data Classification
119
+ - Public: Marketing materials, job postings
120
+ - Internal: Company announcements, policies
121
+ - Confidential: Customer data, financials
122
+ - Restricted: PII, payment info, credentials
123
+
124
+ ## Incident Response
125
+ - Report security incidents within 1 hour
126
+ - Do not attempt to investigate independently
127
+ - Preserve evidence (don't delete logs or files)
128
+ - Security team leads all incident response
129
+ """
130
+
131
+ # All policies available as a list
132
+ ALL_POLICIES = [
133
+ ("expense", EXPENSE_POLICY),
134
+ ("hr", HR_HANDBOOK),
135
+ ("refund", REFUND_POLICY),
136
+ ("support", SUPPORT_GUIDELINES),
137
+ ("security", SECURITY_POLICY),
138
+ ]
139
+
140
+ __all__ = [
141
+ "EXPENSE_POLICY",
142
+ "HR_HANDBOOK",
143
+ "REFUND_POLICY",
144
+ "SUPPORT_GUIDELINES",
145
+ "SECURITY_POLICY",
146
+ "ALL_POLICIES",
147
+ ]
148
+
@@ -0,0 +1,221 @@
1
+ Metadata-Version: 2.4
2
+ Name: synkro
3
+ Version: 0.4.5
4
+ Summary: Generate training datasets from any document
5
+ Author: Murtaza Meerza
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Keywords: dataset-generation,fine-tuning,llm,synthetic-data,training-data
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
17
+ Requires-Python: >=3.10
18
+ Requires-Dist: beautifulsoup4>=4.12
19
+ Requires-Dist: html2text>=2020.1
20
+ Requires-Dist: httpx>=0.25
21
+ Requires-Dist: litellm>=1.40
22
+ Requires-Dist: mammoth>=1.6
23
+ Requires-Dist: marker-pdf>=0.2
24
+ Requires-Dist: pydantic>=2.0
25
+ Requires-Dist: python-dotenv>=1.0
26
+ Requires-Dist: rich>=13.0
27
+ Requires-Dist: typer>=0.9
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
30
+ Requires-Dist: pytest>=7.0; extra == 'dev'
31
+ Requires-Dist: ruff>=0.1; extra == 'dev'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # Synkro
35
+
36
+ Turn policies, handbooks, and documentation into high-quality training data for fine-tuning LLMs.
37
+
38
+ ## Features
39
+
40
+ - **Quality Evaluation** - Each response is graded and automatically refined if it fails
41
+ - **Multiple Formats** - SFT (chat), QA (question-answer), and Tool Calling
42
+ - **Tool Call Training** - Generate OpenAI function calling format for teaching models to use custom tools
43
+ - **Top LLM Providers** - OpenAI, Anthropic, and Google
44
+ - **File Support** - PDF, DOCX, TXT, Markdown, URLs
45
+ - **CLI Included** - Generate datasets from the command line
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ pip install synkro
51
+ ```
52
+
53
+ ## Quick Start
54
+
55
+ ```python
56
+ from synkro.pipelines import create_pipeline
57
+ from synkro.models.google import Google
58
+ from synkro.types import DatasetType
59
+
60
+ pipeline = create_pipeline(
61
+ model=Google.GEMINI_25_FLASH, # Fast generation
62
+ grading_model=Google.GEMINI_25_PRO, # Quality grading
63
+ dataset_type=DatasetType.SFT,
64
+ )
65
+
66
+ dataset = pipeline.generate(
67
+ "All expenses over $50 require manager approval.",
68
+ traces=50,
69
+ )
70
+ dataset.save("training.jsonl")
71
+ ```
72
+
73
+ ### From Files
74
+
75
+ ```python
76
+ from synkro.pipelines import create_pipeline
77
+ from synkro.core.policy import Policy
78
+
79
+ policy = Policy.from_file("handbook.pdf") # PDF, DOCX, TXT, MD
80
+ pipeline = create_pipeline()
81
+ dataset = pipeline.generate(policy, traces=100)
82
+ dataset.save()
83
+ ```
84
+
85
+ ### From URLs
86
+
87
+ ```python
88
+ from synkro.core.policy import Policy
89
+
90
+ policy = Policy.from_url("https://example.com/terms")
91
+ dataset = pipeline.generate(policy)
92
+ ```
93
+
94
+ ## Dataset Types
95
+
96
+ | Format | Output | Best For |
97
+ |--------|--------|----------|
98
+ | **SFT** | Chat messages | Fine-tuning chat models |
99
+ | **QA** | Question-answer pairs | RAG systems, knowledge bases |
100
+ | **TOOL_CALL** | Function calling format | Training models to use custom tools |
101
+
102
+ ### SFT (Default)
103
+
104
+ ```python
105
+ from synkro.types import DatasetType
106
+
107
+ pipeline = create_pipeline(dataset_type=DatasetType.SFT)
108
+ dataset = pipeline.generate(policy)
109
+ ```
110
+
111
+ Output:
112
+ ```json
113
+ {"messages": [
114
+ {"role": "system", "content": "You are a policy expert..."},
115
+ {"role": "user", "content": "What's the approval process for $350?"},
116
+ {"role": "assistant", "content": "For a $350 expense, you need..."}
117
+ ]}
118
+ ```
119
+
120
+ ### QA
121
+
122
+ ```python
123
+ pipeline = create_pipeline(dataset_type=DatasetType.QA)
124
+ ```
125
+
126
+ Output:
127
+ ```json
128
+ {"question": "What's the approval process?", "answer": "You need...", "context": "..."}
129
+ ```
130
+
131
+ ### Tool Calling
132
+
133
+ Generate training data for teaching models when and how to use your custom tools:
134
+
135
+ ```python
136
+ from synkro import create_pipeline, ToolDefinition, DatasetType
137
+
138
+ # Define your tools
139
+ web_search = ToolDefinition(
140
+ name="web_search",
141
+ description="Search the web for current information",
142
+ parameters={
143
+ "type": "object",
144
+ "properties": {
145
+ "query": {"type": "string", "description": "Search query"}
146
+ },
147
+ "required": ["query"]
148
+ },
149
+ mock_responses=["NYC: 72°F, sunny", "BTC: $67,234"]
150
+ )
151
+
152
+ # Create pipeline with tools
153
+ pipeline = create_pipeline(
154
+ dataset_type=DatasetType.TOOL_CALL,
155
+ tools=[web_search],
156
+ )
157
+
158
+ # Generate from tool usage guidelines
159
+ dataset = pipeline.generate("""
160
+ Use web_search for real-time data like weather, prices.
161
+ Answer general questions directly without tools.
162
+ """, traces=20)
163
+
164
+ dataset.save("tool_training.jsonl", format="tool_call")
165
+ ```
166
+
167
+ Output (OpenAI function calling format):
168
+ ```json
169
+ {"messages": [
170
+ {"role": "system", "content": "You have access to: web_search..."},
171
+ {"role": "user", "content": "What's the weather in NYC?"},
172
+ {"role": "assistant", "content": null, "tool_calls": [
173
+ {"id": "call_abc", "type": "function", "function": {"name": "web_search", "arguments": "{\"query\": \"weather NYC\"}"}}
174
+ ]},
175
+ {"role": "tool", "tool_call_id": "call_abc", "content": "NYC: 72°F, sunny"},
176
+ {"role": "assistant", "content": "The weather in NYC is 72°F and sunny."}
177
+ ]}
178
+ ```
179
+
180
+ ## Evaluation & Grading
181
+
182
+ Every response is graded on policy compliance, citations, and reasoning. Failed responses are automatically refined (up to N iterations).
183
+
184
+ ```python
185
+ from synkro.pipelines import create_pipeline
186
+ from synkro.models.openai import OpenAI
187
+
188
+ pipeline = create_pipeline(
189
+ model=OpenAI.GPT_4O_MINI, # Fast generation
190
+ grading_model=OpenAI.GPT_4O, # Quality grading
191
+ max_iterations=3, # Refinement attempts
192
+ )
193
+
194
+ dataset = pipeline.generate(policy, traces=100)
195
+
196
+ # Check quality
197
+ print(f"Pass rate: {dataset.passing_rate:.1%}")
198
+
199
+ # Filter to only passing traces
200
+ high_quality = dataset.filter(passed=True)
201
+ high_quality.save("training.jsonl")
202
+ ```
203
+
204
+ ## CLI
205
+
206
+ ```bash
207
+ # From file
208
+ synkro generate policy.pdf --traces 50 --format sft
209
+
210
+ # From text
211
+ synkro generate "All expenses over $50 need approval" -n 20
212
+
213
+ # From URL
214
+ synkro generate https://example.com/policy -o training.jsonl
215
+ ```
216
+
217
+ **Options:**
218
+ - `--traces, -n` - Number of traces (default: 20)
219
+ - `--format, -f` - Output format: sft, qa, or tool_call (default: sft)
220
+ - `--output, -o` - Output file path
221
+ - `--model, -m` - Model for generation