sorbet-baml 0.1.0 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '087824d783258689f016d3fe337fe9cfe445715f175a7d56c2ea7d6e9439b60b'
4
- data.tar.gz: 273faf0407c8fec863e7efa412d0060659a9f4de85b0658024c73dfc33c88363
3
+ metadata.gz: e6ebc9d978b525e29a1a19ef184f073393d6a588e54d84dc2b9fd7034d1fa40c
4
+ data.tar.gz: f7d5e028fe65a4a4cc9b19c60dc17dd65fd13353634e55201db5189bb457447a
5
5
  SHA512:
6
- metadata.gz: d2d2aaae155fb4f4b0747de8ba2cbaf39d6ef97d1698b6dbf14968b4e3a6b935c59ed20a88643da333291fbbdf5d6e622a04beccc9c46887e2fc1c6a3bcd436d
7
- data.tar.gz: 444968d3450fcd2776f3dac4618d59f8a76ba4032669335cbbe269eb3bbf92d63ea1f1b0eae989e432e1b601978625bb8830c23d7656bae76396c5a46a915e3c
6
+ metadata.gz: 40b4736cc561b5135ee32e08543148c018ea9963e016c6cbb66697cd346ff7cf30f7438d370853c045b40d062a47f38d7aaa1a9c6c8e92f8e7f6721b495966e0
7
+ data.tar.gz: 0caf0a19906655bbfae88723bbe5b38301601c1523c3cc3b8dc31a15bf6bdd02ceacb790cf0d4bddf718c1162ba51d7b0fcd08110578616cd7c7ac27272bcd42
data/CLAUDE.md ADDED
@@ -0,0 +1,94 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Development Commands
6
+
7
+ **Running Tests:**
8
+ ```bash
9
+ bundle exec rspec # Run all tests
10
+ bundle exec rspec spec/path_spec.rb # Run specific test file
11
+ ```
12
+
13
+ **Type Checking:**
14
+ ```bash
15
+ bundle exec srb tc # Run Sorbet type checker
16
+ ```
17
+
18
+ **Development Setup:**
19
+ ```bash
20
+ bundle install # Install dependencies
21
+ bundle exec tapioca dsl # Generate RBI files for gems
22
+ bundle exec tapioca gem # Generate RBI files for dependencies
23
+ ```
24
+
25
+ **Linting:**
26
+ ```bash
27
+ bundle exec rubocop # Run RuboCop linter
28
+ bundle exec rubocop -a # Auto-fix violations where possible
29
+ ```
30
+
31
+ **Gem Tasks:**
32
+ ```bash
33
+ bundle exec rake build # Build the gem
34
+ bundle exec rake install # Install locally
35
+ bundle exec rake release # Release to RubyGems (maintainers only)
36
+ ```
37
+
38
+ ## Code Architecture
39
+
40
+ ### Core Components
41
+
42
+ **Main Library Entry Point:**
43
+ - `lib/sorbet_baml.rb` - Main module with public API methods and extension loading
44
+
45
+ **Core Conversion System:**
46
+ - `lib/sorbet_baml/converter.rb` - Main converter orchestrating BAML generation
47
+ - `lib/sorbet_baml/type_mapper.rb` - Maps Sorbet type objects to BAML type strings
48
+ - `lib/sorbet_baml/dependency_resolver.rb` - Handles topological sorting of dependencies
49
+
50
+ **Ruby-Idiomatic API Extensions:**
51
+ - `lib/sorbet_baml/struct_extensions.rb` - Adds `.to_baml` method to T::Struct
52
+ - `lib/sorbet_baml/enum_extensions.rb` - Adds `.to_baml` method to T::Enum
53
+
54
+ **Field Documentation:**
55
+ - `lib/sorbet_baml/comment_extractor.rb` - Extracts comments from source for field descriptions
56
+
57
+ ### Key Design Patterns
58
+
59
+ **Extension Pattern:** The gem extends T::Struct and T::Enum classes with `.to_baml` methods for a Ruby-idiomatic API.
60
+
61
+ **Dependency Resolution:** Uses topological sorting to ensure dependencies are output before types that reference them, preventing forward reference issues.
62
+
63
+ **Type Mapping:** Comprehensive mapping from Sorbet type system to BAML types:
64
+ - `T::Struct` → BAML classes
65
+ - `T::Enum` → BAML enums
66
+ - `T.nilable(T)` → optional types (`T?`)
67
+ - `T::Array[T]` → array types (`T[]`)
68
+ - `T::Hash[K,V]` → map types (`map<K,V>`)
69
+ - `T.any(T1, T2)` → union types (`T1 | T2`)
70
+
71
+ **Smart Defaults:** The API includes dependencies and field descriptions by default.
72
+
73
+ ### Type System Support
74
+
75
+ The gem provides complete coverage of Sorbet's type system:
76
+ - Basic types (String, Integer, Float, Boolean, Symbol, Date/Time)
77
+ - Complex types (Arrays, Hashes, Unions, Nilable)
78
+ - Structured types (T::Struct, T::Enum with full nesting support)
79
+ - Circular reference handling to prevent infinite loops
80
+
81
+ ### Testing Structure
82
+
83
+ - `spec/fixtures/` - Test data including complex type examples
84
+ - `spec/integration/` - End-to-end feature tests
85
+ - `spec/sorbet_baml/` - Unit tests for each component
86
+ - Comprehensive test coverage includes edge cases, circular references, and complex type combinations
87
+
88
+ ## Development Guidelines
89
+
90
+ **Type Safety:** All code uses `# typed: strict` and maintains full Sorbet compliance.
91
+
92
+ **Ruby Idioms:** The public API follows Ruby conventions with `.to_baml` instance methods rather than static factory methods.
93
+
94
+ **Field Descriptions:** Comments above field definitions are automatically extracted and included as BAML `@description` annotations for LLM context.
data/README.md CHANGED
@@ -15,25 +15,43 @@ When working with LLMs, token efficiency directly impacts:
15
15
 
16
16
  BAML provides the perfect balance: concise, readable, and LLM-friendly.
17
17
 
18
- ### Example
18
+ ### Example: Autonomous Research Workflow
19
19
 
20
20
  ```ruby
21
- # Your Sorbet types
22
- class User < T::Struct
23
- const :name, String
24
- const :age, Integer
25
- const :email, T.nilable(String)
26
- const :preferences, T::Hash[String, T.any(String, Integer)]
21
+ # Complex LLM workflow types for autonomous research
22
+ class ComplexityLevel < T::Enum
23
+ enums do
24
+ # Basic analysis requiring straightforward research
25
+ Basic = new('basic')
26
+ # Advanced analysis requiring deep domain expertise
27
+ Advanced = new('advanced')
28
+ end
29
+ end
30
+
31
+ class TaskDecomposition < T::Struct
32
+ # The main research topic being investigated
33
+ const :research_topic, String
34
+ # Target complexity level for the decomposition
35
+ const :complexity_level, ComplexityLevel
36
+ # Autonomously generated list of research subtasks
37
+ const :subtasks, T::Array[String]
38
+ # Strategic priority rankings for each subtask
39
+ const :priority_order, T::Array[Integer]
27
40
  end
28
41
 
29
- # Ruby-idiomatic conversion
30
- User.to_baml
42
+ # Ruby-idiomatic conversion with dependencies
43
+ TaskDecomposition.to_baml
31
44
  # =>
32
- # class User {
33
- # name string
34
- # age int
35
- # email string?
36
- # preferences map<string, string | int>
45
+ # enum ComplexityLevel {
46
+ # "basic" @description("Basic analysis requiring straightforward research")
47
+ # "advanced" @description("Advanced analysis requiring deep domain expertise")
48
+ # }
49
+ #
50
+ # class TaskDecomposition {
51
+ # research_topic string @description("The main research topic being investigated")
52
+ # complexity_level ComplexityLevel @description("Target complexity level for the decomposition")
53
+ # subtasks string[] @description("Autonomously generated list of research subtasks")
54
+ # priority_order int[] @description("Strategic priority rankings for each subtask")
37
55
  # }
38
56
  ```
39
57
 
@@ -56,107 +74,120 @@ gem install sorbet-baml
56
74
  ```ruby
57
75
  require 'sorbet-baml'
58
76
 
59
- # 🎯 Ruby-idiomatic API - just call .to_baml on any T::Struct or T::Enum!
77
+ # 🎯 Ruby-idiomatic API for complex LLM workflows
60
78
 
61
- class Status < T::Enum
79
+ class ConfidenceLevel < T::Enum
62
80
  enums do
63
- Active = new('active')
64
- Inactive = new('inactive')
81
+ # Low confidence, requires further verification
82
+ Low = new('low')
83
+ # High confidence, strongly supported by multiple sources
84
+ High = new('high')
65
85
  end
66
86
  end
67
87
 
68
- class Address < T::Struct
69
- const :street, String
70
- const :city, String
71
- const :postal_code, T.nilable(String)
88
+ class ResearchFindings < T::Struct
89
+ # Detailed findings and analysis results
90
+ const :findings, String
91
+ # Key actionable insights extracted
92
+ const :key_insights, T::Array[String]
93
+ # Assessment of evidence quality and reliability
94
+ const :evidence_quality, ConfidenceLevel
95
+ # Confidence score for the findings (1-10 scale)
96
+ const :confidence_score, Integer
72
97
  end
73
98
 
74
- class User < T::Struct
75
- const :name, String
76
- const :status, Status
77
- const :address, Address
78
- const :tags, T::Array[String]
79
- const :metadata, T::Hash[String, T.any(String, Integer)]
99
+ class ResearchSynthesis < T::Struct
100
+ # High-level executive summary of all findings
101
+ const :executive_summary, String
102
+ # Primary conclusions drawn from the research
103
+ const :key_conclusions, T::Array[String]
104
+ # Collection of research findings
105
+ const :findings_collection, T::Array[ResearchFindings]
80
106
  end
81
107
 
82
108
  # Convert with smart defaults (dependencies + descriptions included!)
83
- User.to_baml
84
- Status.to_baml
85
- Address.to_baml
109
+ ResearchSynthesis.to_baml
86
110
 
87
111
  # 🚀 Smart defaults include dependencies and descriptions automatically
88
112
  # =>
89
- # enum Status {
90
- # "active"
91
- # "inactive"
113
+ # enum ConfidenceLevel {
114
+ # "low" @description("Low confidence, requires further verification")
115
+ # "high" @description("High confidence, strongly supported by multiple sources")
92
116
  # }
93
117
  #
94
- # class Address {
95
- # street string
96
- # city string
97
- # postal_code string?
118
+ # class ResearchFindings {
119
+ # findings string @description("Detailed findings and analysis results")
120
+ # key_insights string[] @description("Key actionable insights extracted")
121
+ # evidence_quality ConfidenceLevel @description("Assessment of evidence quality and reliability")
122
+ # confidence_score int @description("Confidence score for the findings (1-10 scale)")
98
123
  # }
99
124
  #
100
- # class User {
101
- # name string
102
- # status Status
103
- # address Address
104
- # tags string[]
105
- # metadata map<string, string | int>
125
+ # class ResearchSynthesis {
126
+ # executive_summary string @description("High-level executive summary of all findings")
127
+ # key_conclusions string[] @description("Primary conclusions drawn from the research")
128
+ # findings_collection ResearchFindings[] @description("Collection of research findings")
106
129
  # }
107
130
 
108
131
  # 🎯 Disable features if needed
109
- User.to_baml(include_descriptions: false)
110
- User.to_baml(include_dependencies: false)
132
+ ResearchSynthesis.to_baml(include_descriptions: false)
133
+ ResearchSynthesis.to_baml(include_dependencies: false)
111
134
 
112
135
  # 🚀 Customize formatting (smart defaults still apply)
113
- User.to_baml(indent_size: 4)
136
+ ResearchSynthesis.to_baml(indent_size: 4)
114
137
 
115
138
  # Legacy API (no smart defaults, for backwards compatibility)
116
- SorbetBaml.from_struct(User)
117
- SorbetBaml.from_structs([User, Address])
139
+ SorbetBaml.from_struct(ResearchSynthesis)
140
+ SorbetBaml.from_structs([ResearchSynthesis, ResearchFindings])
118
141
  ```
119
142
 
120
- ## 🎯 Field Descriptions
143
+ ## 🎯 Field Descriptions for LLM Context
121
144
 
122
- Add context to your BAML types by documenting fields with comments:
145
+ Add crucial context to your BAML types by documenting fields with comments - essential for autonomous agents and complex workflows:
123
146
 
124
147
  ```ruby
125
- class User < T::Struct
126
- # User's full legal name for display
127
- const :name, String
128
-
129
- # Age in years, must be 18+
130
- const :age, Integer
131
-
132
- # Primary email for notifications
133
- const :email, T.nilable(String)
134
- end
135
-
136
- class Status < T::Enum
148
+ class TaskType < T::Enum
137
149
  enums do
138
- # Account is active and verified
139
- Active = new('active')
140
-
141
- # Account suspended for policy violation
142
- Suspended = new('suspended')
150
+ # Literature review and information gathering
151
+ Research = new('research')
152
+ # Combining multiple sources into coherent insights
153
+ Synthesis = new('synthesis')
154
+ # Evaluating options or making recommendations
155
+ Evaluation = new('evaluation')
143
156
  end
144
157
  end
145
158
 
159
+ class ResearchSubtask < T::Struct
160
+ # Clear description of the specific research objective
161
+ const :objective, String
162
+
163
+ # Type of research task to be performed
164
+ const :task_type, TaskType
165
+
166
+ # Strategic priority ranking for task sequencing (1-5 scale)
167
+ const :priority, Integer
168
+
169
+ # Estimated effort required in hours
170
+ const :estimated_hours, Integer
171
+
172
+ # Suggested agent capabilities needed for optimal execution
173
+ const :required_capabilities, T::Array[String]
174
+ end
175
+
146
176
  # Generate BAML (descriptions included by default!)
147
- User.to_baml
177
+ ResearchSubtask.to_baml
148
178
  # =>
149
- # class User {
150
- # name string @description("User's full legal name for display")
151
- # age int @description("Age in years, must be 18+")
152
- # email string? @description("Primary email for notifications")
179
+ # enum TaskType {
180
+ # "research" @description("Literature review and information gathering")
181
+ # "synthesis" @description("Combining multiple sources into coherent insights")
182
+ # "evaluation" @description("Evaluating options or making recommendations")
153
183
  # }
154
-
155
- Status.to_baml
156
- # =>
157
- # enum Status {
158
- # "active" @description("Account is active and verified")
159
- # "suspended" @description("Account suspended for policy violation")
184
+ #
185
+ # class ResearchSubtask {
186
+ # objective string @description("Clear description of the specific research objective")
187
+ # task_type TaskType @description("Type of research task to be performed")
188
+ # priority int @description("Strategic priority ranking for task sequencing (1-5 scale)")
189
+ # estimated_hours int @description("Estimated effort required in hours")
190
+ # required_capabilities string[] @description("Suggested agent capabilities needed for optimal execution")
160
191
  # }
161
192
  ```
162
193
 
@@ -218,53 +249,65 @@ Status.to_baml
218
249
 
219
250
  ## 🏁 Production Ready
220
251
 
221
- This gem has reached **feature completeness** for core BAML conversion needs. The Ruby-idiomatic API is stable and thoroughly tested with **34 test cases** covering all type combinations and edge cases.
252
+ This gem has reached **feature completeness** for core BAML conversion needs. The Ruby-idiomatic API is stable and thoroughly tested with **50+ test cases** covering all type combinations and edge cases.
222
253
 
223
254
  ### 📊 Quality Metrics
224
255
 
225
256
  - ✅ **100% Test Coverage** - All features comprehensively tested
226
257
  - ✅ **Full Sorbet Type Safety** - Zero type errors throughout codebase
227
- - ✅ **34 Test Cases** - Covering basic types, complex combinations, and edge cases
258
+ - ✅ **50+ Test Cases** - Covering basic types, complex combinations, and edge cases
228
259
  - ✅ **TDD Development** - All features built test-first
260
+ - ✅ **Field Descriptions** - Automatic comment extraction for LLM context
261
+ - ✅ **Smart Defaults** - Dependencies and descriptions included by default
229
262
  - ✅ **Zero Breaking Changes** - Maintains backward compatibility
230
263
 
231
- ### 🗺️ Future Enhancements (Optional)
264
+ ### Complete Feature Set
232
265
 
233
- The core implementation is complete. These are nice-to-have enhancements:
266
+ - **Ruby-idiomatic API**: Every T::Struct and T::Enum gets `.to_baml` method
267
+ - ✅ **Smart defaults**: Field descriptions and dependencies included automatically
268
+ - ✅ **Field descriptions**: Extract documentation from comments for LLM context
269
+ - ✅ **Dependency management**: Automatically includes all referenced types
270
+ - ✅ **Proper ordering**: Dependencies are sorted topologically
271
+ - ✅ **Type safety**: Full Sorbet type checking throughout
272
+
273
+ ### 🗺️ Future Enhancements (Optional)
234
274
 
235
275
  - [ ] **Type aliases**: `T.type_alias { String }` → `type Alias = string`
236
- - [ ] **Field descriptions**: Extract documentation from comments
237
276
  - [ ] **Custom naming**: Convert between snake_case ↔ camelCase
238
- - [ ] **CLI tool**: `sorbet-baml convert User` command
277
+ - [ ] **CLI tool**: `sorbet-baml convert MyStruct` command
239
278
  - [ ] **Validation**: Verify generated BAML syntax
240
279
  - [ ] **Self-referential types**: `Employee` with `manager: T.nilable(Employee)`
241
280
 
242
281
  ### 📈 Version History
243
282
 
244
283
  - **v0.0.1** - Initial implementation with basic type support
245
- - **v0.1.0** (Ready) - Complete type system + Ruby-idiomatic API
284
+ - **v0.1.0** - Complete type system + Ruby-idiomatic API + field descriptions + smart defaults
246
285
 
247
- ## 🌟 Real-World Usage
286
+ ## 🌟 Real-World Usage: Autonomous Research Agents
248
287
 
249
- Perfect for Rails applications, API documentation, and any Ruby codebase using Sorbet:
288
+ Perfect for agentic workflows, deep research systems, and complex LLM applications:
250
289
 
251
290
  ```ruby
252
- # In your Rails models
253
- class User < ApplicationRecord
254
- # Your existing Sorbet types...
291
+ # Define your autonomous research workflow types
292
+ class TaskDecomposition < T::Struct
293
+ # Your complex research schema...
255
294
  end
256
295
 
257
- # Generate BAML for LLM prompts
296
+ # Generate BAML for LLM agents
258
297
  prompt = <<~PROMPT
259
- Given this user schema:
298
+ You are an autonomous research agent. Analyze this topic and decompose it into strategic subtasks.
260
299
 
261
- #{User.to_baml}
300
+ Schema for your output:
301
+ #{TaskDecomposition.to_baml}
262
302
 
263
- Generate 5 realistic test users in JSON format.
303
+ Topic: "Impact of AI on healthcare delivery systems"
304
+
305
+ Provide a comprehensive task decomposition in JSON format.
264
306
  PROMPT
265
307
 
266
308
  # Use with OpenAI, Anthropic, or any LLM provider
267
- response = client.chat(prompt)
309
+ response = llm_client.chat(prompt)
310
+ result = TaskDecomposition.from_json(response.content)
268
311
  ```
269
312
 
270
313
  ## 🔗 Integration Examples
@@ -292,43 +335,65 @@ api_types = [User, Order, Product].map(&:to_baml).join("\n\n")
292
335
 
293
336
  Here's a real-world comparison using a complex agentic workflow from production DSPy.rb usage:
294
337
 
295
- ### Complex T::Struct Types (Real Agentic Workflow)
338
+ ### Complex T::Struct Types (Production Agentic Workflow)
296
339
 
297
340
  ```ruby
341
+ # Real autonomous research workflow from production DSPy.rb usage
298
342
  class ComplexityLevel < T::Enum
299
343
  enums do
344
+ # Basic analysis requiring straightforward research
300
345
  Basic = new('basic')
346
+ # Intermediate analysis requiring synthesis of multiple sources
301
347
  Intermediate = new('intermediate')
348
+ # Advanced analysis requiring deep domain expertise and complex reasoning
302
349
  Advanced = new('advanced')
303
350
  end
304
351
  end
305
352
 
306
353
  class TaskDecomposition < T::Struct
307
- const :topic, String
354
+ # The main research topic being investigated
355
+ const :research_topic, String
356
+ # Additional context or constraints for the research
308
357
  const :context, String
358
+ # Target complexity level for the decomposition
309
359
  const :complexity_level, ComplexityLevel
360
+ # Autonomously generated list of research subtasks
310
361
  const :subtasks, T::Array[String]
362
+ # Type classification for each task (analysis, synthesis, investigation, etc.)
311
363
  const :task_types, T::Array[String]
364
+ # Strategic priority rankings (1-5 scale) for each subtask
312
365
  const :priority_order, T::Array[Integer]
366
+ # Effort estimates in hours for each subtask
313
367
  const :estimated_effort, T::Array[Integer]
368
+ # Task dependency relationships for optimal sequencing
314
369
  const :dependencies, T::Array[String]
370
+ # Suggested agent types/skills needed for each task
315
371
  const :agent_requirements, T::Array[String]
316
372
  end
317
373
 
318
374
  class ResearchExecution < T::Struct
375
+ # The specific research subtask to execute
319
376
  const :subtask, String
377
+ # Accumulated context from previous research steps
320
378
  const :context, String
379
+ # Any specific constraints or focus areas for this research
321
380
  const :constraints, String
381
+ # Detailed research findings and analysis
322
382
  const :findings, String
383
+ # Key actionable insights extracted from the research
323
384
  const :key_insights, T::Array[String]
385
+ # Confidence in findings quality (1-10 scale)
324
386
  const :confidence_level, Integer
387
+ # Assessment of evidence quality and reliability
325
388
  const :evidence_quality, String
389
+ # Recommended next steps based on these findings
326
390
  const :next_steps, T::Array[String]
391
+ # Identified gaps in knowledge or areas needing further research
327
392
  const :knowledge_gaps, T::Array[String]
328
393
  end
329
394
  ```
330
395
 
331
- ### 📊 **BAML Output (Ruby-idiomatic)**
396
+ ### 📊 **BAML Output (Ruby-idiomatic with descriptions)**
332
397
 
333
398
  ```ruby
334
399
  [ComplexityLevel, TaskDecomposition, ResearchExecution].map(&:to_baml).join("\n\n")
@@ -336,37 +401,37 @@ end
336
401
 
337
402
  ```baml
338
403
  enum ComplexityLevel {
339
- "basic"
340
- "intermediate"
341
- "advanced"
404
+ "basic" @description("Basic analysis requiring straightforward research")
405
+ "intermediate" @description("Intermediate analysis requiring synthesis of multiple sources")
406
+ "advanced" @description("Advanced analysis requiring deep domain expertise and complex reasoning")
342
407
  }
343
408
 
344
409
  class TaskDecomposition {
345
- topic string
346
- context string
347
- complexity_level ComplexityLevel
348
- subtasks string[]
349
- task_types string[]
350
- priority_order int[]
351
- estimated_effort int[]
352
- dependencies string[]
353
- agent_requirements string[]
410
+ research_topic string @description("The main research topic being investigated")
411
+ context string @description("Additional context or constraints for the research")
412
+ complexity_level ComplexityLevel @description("Target complexity level for the decomposition")
413
+ subtasks string[] @description("Autonomously generated list of research subtasks")
414
+ task_types string[] @description("Type classification for each task (analysis, synthesis, investigation, etc.)")
415
+ priority_order int[] @description("Strategic priority rankings (1-5 scale) for each subtask")
416
+ estimated_effort int[] @description("Effort estimates in hours for each subtask")
417
+ dependencies string[] @description("Task dependency relationships for optimal sequencing")
418
+ agent_requirements string[] @description("Suggested agent types/skills needed for each task")
354
419
  }
355
420
 
356
421
  class ResearchExecution {
357
- subtask string
358
- context string
359
- constraints string
360
- findings string
361
- key_insights string[]
362
- confidence_level int
363
- evidence_quality string
364
- next_steps string[]
365
- knowledge_gaps string[]
422
+ subtask string @description("The specific research subtask to execute")
423
+ context string @description("Accumulated context from previous research steps")
424
+ constraints string @description("Any specific constraints or focus areas for this research")
425
+ findings string @description("Detailed research findings and analysis")
426
+ key_insights string[] @description("Key actionable insights extracted from the research")
427
+ confidence_level int @description("Confidence in findings quality (1-10 scale)")
428
+ evidence_quality string @description("Assessment of evidence quality and reliability")
429
+ next_steps string[] @description("Recommended next steps based on these findings")
430
+ knowledge_gaps string[] @description("Identified gaps in knowledge or areas needing further research")
366
431
  }
367
432
  ```
368
433
 
369
- **BAML Token Count: ~180 tokens**
434
+ **BAML Token Count: ~320 tokens**
370
435
 
371
436
  ### 📊 **JSON Schema Equivalent**
372
437
 
@@ -439,22 +504,29 @@ class ResearchExecution {
439
504
  }
440
505
  ```
441
506
 
442
- **JSON Schema Token Count: ~450 tokens**
507
+ **JSON Schema Token Count: ~680 tokens**
508
+
509
+ ### 🎯 **Results: 53% Token Reduction (with descriptions)**
443
510
 
444
- ### 🎯 **Results: 60% Token Reduction**
511
+ | Format | Tokens | Reduction |
512
+ |--------|--------|-----------|
513
+ | JSON Schema | ~680 | baseline |
514
+ | **BAML** | **~320** | **🔥 53% fewer** |
445
515
 
516
+ **Without descriptions:**
446
517
  | Format | Tokens | Reduction |
447
518
  |--------|--------|-----------|
448
519
  | JSON Schema | ~450 | baseline |
449
520
  | **BAML** | **~180** | **🔥 60% fewer** |
450
521
 
451
522
  **Real Impact:**
452
- - **Cost Savings**: 60% reduction in prompt tokens = 60% lower LLM API costs
523
+ - **Cost Savings**: 53-60% reduction in prompt tokens = significant LLM API cost savings
453
524
  - **Performance**: Smaller prompts = faster LLM response times
454
525
  - **Context Efficiency**: More room for actual content vs. type definitions
526
+ - **LLM Understanding**: Descriptions provide crucial context for autonomous agents
455
527
  - **Readability**: BAML is human-readable and maintainable
456
528
 
457
- *This example represents actual agentic workflows from production DSPy.rb applications using complex nested types, enums, and arrays - exactly the scenarios where token efficiency matters most.*
529
+ *This example represents actual agentic workflows from production DSPy.rb applications using complex nested types, enums, and arrays - exactly the scenarios where token efficiency and LLM understanding matter most.*
458
530
 
459
531
  ## Credits
460
532
 
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env ruby
2
+ # typed: false
3
+
4
+ require_relative '../lib/sorbet_baml'
5
+
6
+ puts "🎯 Description Parameter Support Demo"
7
+ puts "=" * 50
8
+
9
+ # Example 1: Basic description parameters
10
+ class User < T::Struct
11
+ const :name, String, description: "User's full legal name"
12
+ prop :age, Integer, description: "Age in years"
13
+ const :email, T.nilable(String), description: "Optional email address for notifications"
14
+ const :interests, T::Array[String], description: "List of user hobbies and interests"
15
+ end
16
+
17
+ puts "\n1. Basic T::Struct with description parameters:"
18
+ puts User.to_baml
19
+
20
+ # Example 2: Mixed description sources (parameters + comments)
21
+ class Product < T::Struct
22
+ # This comment will be used as fallback
23
+ const :id, String
24
+
25
+ const :name, String, description: "Product name for display"
26
+
27
+ # Price in USD cents
28
+ prop :price_cents, Integer
29
+
30
+ const :category, String, description: "Product category classification"
31
+ end
32
+
33
+ puts "\n2. Mixed description sources (parameters take priority):"
34
+ puts Product.to_baml
35
+
36
+ # Example 3: Complex nested types with descriptions
37
+ class Order < T::Struct
38
+ const :id, String, description: "Unique order identifier"
39
+ const :customer, User, description: "Customer who placed the order"
40
+ const :items, T::Array[Product], description: "List of ordered products"
41
+ const :total_cents, Integer, description: "Total order value in USD cents"
42
+ const :status, String, description: "Current order processing status"
43
+ end
44
+
45
+ puts "\n3. Complex nested types with dependencies:"
46
+ puts Order.to_baml
47
+
48
+ puts "\n✨ Beautiful, readable, and LLM-friendly!"
49
+ puts "🚀 Perfect for DSPy.rb, autonomous agents, and structured LLM outputs"