sorbet-baml 0.1.0 → 0.3.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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/CLAUDE.md +94 -0
  3. data/README.md +315 -122
  4. data/Rakefile +2 -2
  5. data/docs-site/.gitignore +48 -0
  6. data/docs-site/Gemfile +5 -0
  7. data/docs-site/Gemfile.lock +140 -0
  8. data/docs-site/Rakefile +3 -0
  9. data/docs-site/bridgetown.config.yml +15 -0
  10. data/docs-site/config/initializers.rb +9 -0
  11. data/docs-site/config/puma.rb +9 -0
  12. data/docs-site/config.ru +5 -0
  13. data/docs-site/esbuild.config.js +11 -0
  14. data/docs-site/frontend/javascript/index.js +22 -0
  15. data/docs-site/frontend/styles/index.css +61 -0
  16. data/docs-site/package.json +18 -0
  17. data/docs-site/postcss.config.js +6 -0
  18. data/docs-site/server/roda_app.rb +9 -0
  19. data/docs-site/src/_components/head.liquid +26 -0
  20. data/docs-site/src/_components/nav.liquid +68 -0
  21. data/docs-site/src/_layouts/default.liquid +27 -0
  22. data/docs-site/src/_layouts/doc.liquid +39 -0
  23. data/docs-site/src/advanced-usage.md +598 -0
  24. data/docs-site/src/getting-started.md +170 -0
  25. data/docs-site/src/index.md +183 -0
  26. data/docs-site/src/troubleshooting.md +317 -0
  27. data/docs-site/src/type-mapping.md +236 -0
  28. data/docs-site/tailwind.config.js +85 -0
  29. data/examples/description_parameters.rb +49 -0
  30. data/lib/sorbet_baml/comment_extractor.rb +51 -54
  31. data/lib/sorbet_baml/converter.rb +69 -35
  32. data/lib/sorbet_baml/dependency_resolver.rb +11 -11
  33. data/lib/sorbet_baml/description_extension.rb +34 -0
  34. data/lib/sorbet_baml/description_extractor.rb +34 -0
  35. data/lib/sorbet_baml/dspy_tool_converter.rb +97 -0
  36. data/lib/sorbet_baml/dspy_tool_extensions.rb +23 -0
  37. data/lib/sorbet_baml/enum_extensions.rb +2 -2
  38. data/lib/sorbet_baml/struct_extensions.rb +2 -2
  39. data/lib/sorbet_baml/tool_extensions.rb +23 -0
  40. data/lib/sorbet_baml/type_mapper.rb +35 -37
  41. data/lib/sorbet_baml/version.rb +1 -1
  42. data/lib/sorbet_baml.rb +41 -10
  43. data/sorbet/config +2 -0
  44. data/sorbet/rbi/gems/anthropic@1.5.0.rbi +21252 -0
  45. data/sorbet/rbi/gems/async@2.27.3.rbi +9 -0
  46. data/sorbet/rbi/gems/bigdecimal@3.2.2.rbi +9 -0
  47. data/sorbet/rbi/gems/concurrent-ruby@1.3.5.rbi +424 -0
  48. data/sorbet/rbi/gems/connection_pool@2.5.3.rbi +9 -0
  49. data/sorbet/rbi/gems/console@1.33.0.rbi +9 -0
  50. data/sorbet/rbi/gems/dry-configurable@1.3.0.rbi +672 -0
  51. data/sorbet/rbi/gems/dry-core@1.1.0.rbi +1729 -0
  52. data/sorbet/rbi/gems/dry-logger@1.1.0.rbi +1317 -0
  53. data/sorbet/rbi/gems/dspy@0.19.1.rbi +6677 -0
  54. data/sorbet/rbi/gems/ffi@1.17.2.rbi +2174 -0
  55. data/sorbet/rbi/gems/fiber-annotation@0.2.0.rbi +9 -0
  56. data/sorbet/rbi/gems/fiber-local@1.1.0.rbi +9 -0
  57. data/sorbet/rbi/gems/fiber-storage@1.0.1.rbi +9 -0
  58. data/sorbet/rbi/gems/google-protobuf@4.32.0.rbi +9 -0
  59. data/sorbet/rbi/gems/googleapis-common-protos-types@1.20.0.rbi +9 -0
  60. data/sorbet/rbi/gems/informers@1.2.1.rbi +1875 -0
  61. data/sorbet/rbi/gems/io-event@1.12.1.rbi +9 -0
  62. data/sorbet/rbi/gems/metrics@0.13.0.rbi +9 -0
  63. data/sorbet/rbi/gems/onnxruntime@0.10.0.rbi +304 -0
  64. data/sorbet/rbi/gems/openai@0.16.0.rbi +68055 -0
  65. data/sorbet/rbi/gems/opentelemetry-api@1.6.0.rbi +9 -0
  66. data/sorbet/rbi/gems/opentelemetry-common@0.22.0.rbi +9 -0
  67. data/sorbet/rbi/gems/opentelemetry-exporter-otlp@0.30.0.rbi +9 -0
  68. data/sorbet/rbi/gems/opentelemetry-registry@0.4.0.rbi +9 -0
  69. data/sorbet/rbi/gems/opentelemetry-sdk@1.8.1.rbi +9 -0
  70. data/sorbet/rbi/gems/opentelemetry-semantic_conventions@1.11.0.rbi +9 -0
  71. data/sorbet/rbi/gems/polars-df@0.20.0.rbi +9 -0
  72. data/sorbet/rbi/gems/sorbet-result@1.4.0.rbi +242 -0
  73. data/sorbet/rbi/gems/sorbet-schema@0.9.2.rbi +743 -0
  74. data/sorbet/rbi/gems/sorbet-struct-comparable@1.3.0.rbi +48 -0
  75. data/sorbet/rbi/gems/tokenizers@0.5.5.rbi +754 -0
  76. data/sorbet/rbi/gems/traces@0.17.0.rbi +9 -0
  77. data/sorbet/rbi/gems/zeitwerk@2.7.3.rbi +1429 -0
  78. metadata +67 -7
  79. data/docs/README.md +0 -117
  80. data/docs/advanced-usage.md +0 -427
  81. data/docs/getting-started.md +0 -91
  82. data/docs/troubleshooting.md +0 -291
  83. data/docs/type-mapping.md +0 -192
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sorbet-baml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vicente Reig Rincon de Arellano
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-08-16 00:00:00.000000000 Z
10
+ date: 2025-08-17 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: sorbet-runtime
@@ -36,20 +36,46 @@ files:
36
36
  - ".idea/inspectionProfiles/Project_Default.xml"
37
37
  - ".rspec"
38
38
  - CHANGELOG.md
39
+ - CLAUDE.md
39
40
  - LICENSE.txt
40
41
  - README.md
41
42
  - Rakefile
42
- - docs/README.md
43
- - docs/advanced-usage.md
44
- - docs/getting-started.md
45
- - docs/troubleshooting.md
46
- - docs/type-mapping.md
43
+ - docs-site/.gitignore
44
+ - docs-site/Gemfile
45
+ - docs-site/Gemfile.lock
46
+ - docs-site/Rakefile
47
+ - docs-site/bridgetown.config.yml
48
+ - docs-site/config.ru
49
+ - docs-site/config/initializers.rb
50
+ - docs-site/config/puma.rb
51
+ - docs-site/esbuild.config.js
52
+ - docs-site/frontend/javascript/index.js
53
+ - docs-site/frontend/styles/index.css
54
+ - docs-site/package.json
55
+ - docs-site/postcss.config.js
56
+ - docs-site/server/roda_app.rb
57
+ - docs-site/src/_components/head.liquid
58
+ - docs-site/src/_components/nav.liquid
59
+ - docs-site/src/_layouts/default.liquid
60
+ - docs-site/src/_layouts/doc.liquid
61
+ - docs-site/src/advanced-usage.md
62
+ - docs-site/src/getting-started.md
63
+ - docs-site/src/index.md
64
+ - docs-site/src/troubleshooting.md
65
+ - docs-site/src/type-mapping.md
66
+ - docs-site/tailwind.config.js
67
+ - examples/description_parameters.rb
47
68
  - lib/sorbet_baml.rb
48
69
  - lib/sorbet_baml/comment_extractor.rb
49
70
  - lib/sorbet_baml/converter.rb
50
71
  - lib/sorbet_baml/dependency_resolver.rb
72
+ - lib/sorbet_baml/description_extension.rb
73
+ - lib/sorbet_baml/description_extractor.rb
74
+ - lib/sorbet_baml/dspy_tool_converter.rb
75
+ - lib/sorbet_baml/dspy_tool_extensions.rb
51
76
  - lib/sorbet_baml/enum_extensions.rb
52
77
  - lib/sorbet_baml/struct_extensions.rb
78
+ - lib/sorbet_baml/tool_extensions.rb
53
79
  - lib/sorbet_baml/type_mapper.rb
54
80
  - lib/sorbet_baml/version.rb
55
81
  - sig/sorbet/baml.rbs
@@ -57,21 +83,49 @@ files:
57
83
  - sorbet/rbi/annotations/.gitattributes
58
84
  - sorbet/rbi/annotations/rainbow.rbi
59
85
  - sorbet/rbi/gems/.gitattributes
86
+ - sorbet/rbi/gems/anthropic@1.5.0.rbi
60
87
  - sorbet/rbi/gems/ast@2.4.3.rbi
88
+ - sorbet/rbi/gems/async@2.27.3.rbi
61
89
  - sorbet/rbi/gems/benchmark@0.4.1.rbi
90
+ - sorbet/rbi/gems/bigdecimal@3.2.2.rbi
62
91
  - sorbet/rbi/gems/byebug@11.1.3.rbi
92
+ - sorbet/rbi/gems/concurrent-ruby@1.3.5.rbi
93
+ - sorbet/rbi/gems/connection_pool@2.5.3.rbi
94
+ - sorbet/rbi/gems/console@1.33.0.rbi
63
95
  - sorbet/rbi/gems/date@3.4.1.rbi
64
96
  - sorbet/rbi/gems/diff-lcs@1.6.2.rbi
97
+ - sorbet/rbi/gems/dry-configurable@1.3.0.rbi
98
+ - sorbet/rbi/gems/dry-core@1.1.0.rbi
99
+ - sorbet/rbi/gems/dry-logger@1.1.0.rbi
100
+ - sorbet/rbi/gems/dspy@0.19.1.rbi
65
101
  - sorbet/rbi/gems/erb@5.0.2.rbi
66
102
  - sorbet/rbi/gems/erubi@1.13.1.rbi
103
+ - sorbet/rbi/gems/ffi@1.17.2.rbi
104
+ - sorbet/rbi/gems/fiber-annotation@0.2.0.rbi
105
+ - sorbet/rbi/gems/fiber-local@1.1.0.rbi
106
+ - sorbet/rbi/gems/fiber-storage@1.0.1.rbi
107
+ - sorbet/rbi/gems/google-protobuf@4.32.0.rbi
108
+ - sorbet/rbi/gems/googleapis-common-protos-types@1.20.0.rbi
109
+ - sorbet/rbi/gems/informers@1.2.1.rbi
67
110
  - sorbet/rbi/gems/io-console@0.8.1.rbi
111
+ - sorbet/rbi/gems/io-event@1.12.1.rbi
68
112
  - sorbet/rbi/gems/json@2.13.2.rbi
69
113
  - sorbet/rbi/gems/language_server-protocol@3.17.0.5.rbi
70
114
  - sorbet/rbi/gems/lint_roller@1.1.0.rbi
71
115
  - sorbet/rbi/gems/logger@1.7.0.rbi
116
+ - sorbet/rbi/gems/metrics@0.13.0.rbi
72
117
  - sorbet/rbi/gems/netrc@0.11.0.rbi
118
+ - sorbet/rbi/gems/onnxruntime@0.10.0.rbi
119
+ - sorbet/rbi/gems/openai@0.16.0.rbi
120
+ - sorbet/rbi/gems/opentelemetry-api@1.6.0.rbi
121
+ - sorbet/rbi/gems/opentelemetry-common@0.22.0.rbi
122
+ - sorbet/rbi/gems/opentelemetry-exporter-otlp@0.30.0.rbi
123
+ - sorbet/rbi/gems/opentelemetry-registry@0.4.0.rbi
124
+ - sorbet/rbi/gems/opentelemetry-sdk@1.8.1.rbi
125
+ - sorbet/rbi/gems/opentelemetry-semantic_conventions@1.11.0.rbi
73
126
  - sorbet/rbi/gems/parallel@1.27.0.rbi
74
127
  - sorbet/rbi/gems/parser@3.3.9.0.rbi
128
+ - sorbet/rbi/gems/polars-df@0.20.0.rbi
75
129
  - sorbet/rbi/gems/pp@0.6.2.rbi
76
130
  - sorbet/rbi/gems/prettyprint@0.2.0.rbi
77
131
  - sorbet/rbi/gems/prism@1.4.0.rbi
@@ -94,14 +148,20 @@ files:
94
148
  - sorbet/rbi/gems/rubocop-sorbet@0.10.5.rbi
95
149
  - sorbet/rbi/gems/rubocop@1.79.2.rbi
96
150
  - sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi
151
+ - sorbet/rbi/gems/sorbet-result@1.4.0.rbi
152
+ - sorbet/rbi/gems/sorbet-schema@0.9.2.rbi
153
+ - sorbet/rbi/gems/sorbet-struct-comparable@1.3.0.rbi
97
154
  - sorbet/rbi/gems/spoom@1.6.3.rbi
98
155
  - sorbet/rbi/gems/stringio@3.1.7.rbi
99
156
  - sorbet/rbi/gems/tapioca@0.16.11.rbi
100
157
  - sorbet/rbi/gems/thor@1.4.0.rbi
158
+ - sorbet/rbi/gems/tokenizers@0.5.5.rbi
159
+ - sorbet/rbi/gems/traces@0.17.0.rbi
101
160
  - sorbet/rbi/gems/unicode-display_width@3.1.5.rbi
102
161
  - sorbet/rbi/gems/unicode-emoji@4.0.4.rbi
103
162
  - sorbet/rbi/gems/yard-sorbet@0.9.0.rbi
104
163
  - sorbet/rbi/gems/yard@0.9.37.rbi
164
+ - sorbet/rbi/gems/zeitwerk@2.7.3.rbi
105
165
  - sorbet/tapioca/config.yml
106
166
  - sorbet/tapioca/require.rb
107
167
  homepage: https://github.com/vicentereig/sorbet-baml
data/docs/README.md DELETED
@@ -1,117 +0,0 @@
1
- # sorbet-baml Documentation
2
-
3
- Developer documentation for the sorbet-baml gem.
4
-
5
- ## For Users
6
-
7
- If you want to use this gem in your project:
8
-
9
- 1. **[Getting Started](./getting-started.md)** - Installation and basic usage
10
- 2. **[Type Mapping Reference](./type-mapping.md)** - Complete type conversion table
11
- 3. **[Advanced Usage](./advanced-usage.md)** - Complex scenarios and integrations
12
- 4. **[Troubleshooting](./troubleshooting.md)** - Common issues and solutions
13
-
14
- ## For Contributors
15
-
16
- This gem has reached **feature completeness** for core BAML conversion needs. The implementation is production-ready with:
17
-
18
- - ✅ **Complete type support** - All Sorbet types mapped to BAML
19
- - ✅ **Ruby-idiomatic API** - `.to_baml` method on all T::Struct/T::Enum classes
20
- - ✅ **Dependency management** - Automatic topological sorting
21
- - ✅ **100% test coverage** - 34 comprehensive test cases
22
- - ✅ **Full Sorbet type safety** - Zero type errors
23
-
24
- Future enhancements are optional nice-to-haves rather than core requirements.
25
-
26
- ## Quick Example
27
-
28
- ```ruby
29
- # Define a Sorbet struct
30
- class User < T::Struct
31
- const :name, String
32
- const :age, Integer
33
- const :email, T.nilable(String)
34
- end
35
-
36
- # Convert to BAML (Ruby-idiomatic API)
37
- require 'sorbet-baml'
38
- User.to_baml
39
-
40
- # Legacy API also supported
41
- # SorbetBaml.from_struct(User)
42
- ```
43
-
44
- **Generated BAML:**
45
- ```baml
46
- class User {
47
- name string
48
- age int
49
- email string?
50
- }
51
- ```
52
-
53
- ## Design Goals
54
-
55
- 1. **Ruby-Idiomatic** - Natural `.to_baml` API that feels native
56
- 2. **Production-Ready** - Complete type support, dependency management, full test coverage
57
- 3. **Token Efficiency** - 60% fewer tokens than JSON Schema for real workloads
58
- 4. **Zero-Config** - Works automatically with existing Sorbet codebases
59
- 5. **Type-Safe** - Full Sorbet type checking throughout the gem
60
-
61
- ## What This Is Not
62
-
63
- - Not a BAML runtime or executor
64
- - Not a JSON Schema generator (use [sorbet-schema](https://github.com/maxveldink/sorbet-schema) for that)
65
- - Not a Sorbet type checker
66
- - Not a serialization library
67
-
68
- ## Advanced Features
69
-
70
- ### Ruby-Idiomatic API
71
- ```ruby
72
- User.to_baml # Single type
73
- User.to_baml(indent_size: 4) # Custom formatting
74
- User.to_baml(include_dependencies: true) # With dependencies
75
- ```
76
-
77
- ### Automatic Dependency Management
78
- ```ruby
79
- class Address < T::Struct
80
- const :street, String
81
- end
82
-
83
- class User < T::Struct
84
- const :address, Address
85
- end
86
-
87
- User.to_baml(include_dependencies: true)
88
- ```
89
-
90
- **Generated BAML (correct ordering):**
91
- ```baml
92
- class Address {
93
- street string
94
- }
95
-
96
- class User {
97
- address Address
98
- }
99
- ```
100
-
101
- ## Why BAML?
102
-
103
- BAML (Boundary AI Markup Language) provides a concise way to define types for LLM consumption. **Real-world comparison** from production agentic workflows:
104
-
105
- | Format | Tokens | Efficiency |
106
- |--------|--------|-----------|
107
- | JSON Schema | ~450 | baseline |
108
- | **BAML** | **~180** | **🔥 60% fewer** |
109
-
110
- ### Benefits:
111
- - **Cost Savings**: 60% reduction in prompt tokens = 60% lower LLM API costs
112
- - **Performance**: Smaller prompts = faster LLM response times
113
- - **Context Efficiency**: More room for actual content vs. type definitions
114
- - **Readability**: Human-readable and maintainable
115
- - **LLM-Friendly**: Designed specifically for AI consumption
116
-
117
- Perfect for prompt engineering, structured output generation, and agentic workflows where token efficiency matters.
@@ -1,427 +0,0 @@
1
- # Advanced Usage
2
-
3
- ## Ruby-Idiomatic API
4
-
5
- The gem automatically extends all T::Struct and T::Enum classes with conversion methods:
6
-
7
- ```ruby
8
- class User < T::Struct
9
- const :name, String
10
- const :age, Integer
11
- end
12
-
13
- # Ruby-idiomatic - just call the method!
14
- User.to_baml
15
- User.baml_type_definition # Same as to_baml
16
- ```
17
-
18
- ## Automatic Dependency Management
19
-
20
- The most powerful feature is automatic dependency resolution:
21
-
22
- ```ruby
23
- class ContactInfo < T::Struct
24
- const :email, String
25
- const :phone, T.nilable(String)
26
- end
27
-
28
- class Company < T::Struct
29
- const :name, String
30
- const :contact, ContactInfo
31
- end
32
-
33
- class User < T::Struct
34
- const :name, String
35
- const :company, Company
36
- end
37
-
38
- # Dependencies included automatically with smart defaults!
39
- User.to_baml
40
- ```
41
-
42
- **Generated BAML (with correct ordering):**
43
- ```baml
44
- class ContactInfo {
45
- email string
46
- phone string?
47
- }
48
-
49
- class Company {
50
- name string
51
- contact ContactInfo
52
- }
53
-
54
- class User {
55
- name string
56
- company Company
57
- }
58
- ```
59
-
60
- ## Converting Multiple Types
61
-
62
- ### Manual Collection
63
-
64
- ```ruby
65
- # Convert multiple types manually
66
- types = [ContactInfo, Company, User]
67
- baml_output = types.map(&:to_baml).join("\n\n")
68
- ```
69
-
70
- ### Legacy API (still supported)
71
-
72
- ```ruby
73
- # Legacy API for multiple structs
74
- SorbetBaml.from_structs([ContactInfo, Company, User])
75
-
76
- # Legacy API for single struct
77
- SorbetBaml.from_struct(User)
78
- ```
79
-
80
- ## Advanced Type Examples
81
-
82
- ### Complex Enums with Structs
83
-
84
- ```ruby
85
- class OrderStatus < T::Enum
86
- enums do
87
- Pending = new('pending')
88
- Processing = new('processing')
89
- Shipped = new('shipped')
90
- Delivered = new('delivered')
91
- Cancelled = new('cancelled')
92
- end
93
- end
94
-
95
- class OrderItem < T::Struct
96
- const :product_id, String
97
- const :quantity, Integer
98
- const :price, Float
99
- end
100
-
101
- class Order < T::Struct
102
- const :id, String
103
- const :status, OrderStatus
104
- const :items, T::Array[OrderItem]
105
- const :metadata, T::Hash[String, T.any(String, Integer, Float)]
106
- const :shipping_address, T.nilable(Address)
107
- end
108
-
109
- # Generate complete type definitions
110
- [OrderStatus, OrderItem, Order].map(&:to_baml).join("\n\n")
111
- ```
112
-
113
- **Generated BAML:**
114
- ```baml
115
- enum OrderStatus {
116
- "pending"
117
- "processing"
118
- "shipped"
119
- "delivered"
120
- "cancelled"
121
- }
122
-
123
- class OrderItem {
124
- product_id string
125
- quantity int
126
- price float
127
- }
128
-
129
- class Order {
130
- id string
131
- status OrderStatus
132
- items OrderItem[]
133
- metadata map<string, string | int | float>
134
- shipping_address Address?
135
- }
136
- ```
137
-
138
- ### Self-Referential Types
139
-
140
- ```ruby
141
- class Category < T::Struct
142
- const :name, String
143
- const :parent, T.nilable(Category)
144
- const :children, T::Array[Category]
145
- end
146
-
147
- Category.to_baml
148
- ```
149
-
150
- **Generated BAML:**
151
- ```baml
152
- class Category {
153
- name string
154
- parent Category?
155
- children Category[]
156
- }
157
- ```
158
-
159
- ## Configuration Options
160
-
161
- ### Custom Indentation
162
-
163
- ```ruby
164
- User.to_baml(indent_size: 4)
165
- ```
166
-
167
- **Generated BAML:**
168
- ```baml
169
- class User {
170
- name string
171
- age int
172
- }
173
- ```
174
-
175
- ### Field Descriptions
176
-
177
- Extract documentation from Ruby comments to provide LLM context:
178
-
179
- ```ruby
180
- class DocumentedUser < T::Struct
181
- # User's full legal name for official records
182
- const :full_name, String
183
-
184
- # Age in years, must be 18 or older for account creation
185
- const :age, Integer
186
-
187
- # Primary email address for account notifications
188
- const :email, String
189
- end
190
-
191
- DocumentedUser.to_baml
192
- ```
193
-
194
- **Generated BAML with descriptions:**
195
- ```baml
196
- class DocumentedUser {
197
- full_name string @description("User's full legal name for official records")
198
- age int @description("Age in years, must be 18 or older for account creation")
199
- email string @description("Primary email address for account notifications")
200
- }
201
- ```
202
-
203
- ### Combining Options
204
-
205
- ```ruby
206
- # Smart defaults: dependencies and descriptions already included!
207
- User.to_baml(indent_size: 4)
208
-
209
- # Or disable features if needed
210
- User.to_baml(
211
- include_dependencies: false,
212
- include_descriptions: false,
213
- indent_size: 4
214
- )
215
- ```
216
-
217
- ## File Generation
218
-
219
- ### Single File Output
220
-
221
- ```ruby
222
- # Generate and write to file (dependencies included by default)
223
- baml_content = User.to_baml
224
- File.write("types/user.baml", baml_content)
225
- ```
226
-
227
- ### Multiple Files
228
-
229
- ```ruby
230
- # Generate separate files for each type
231
- [User, Company, ContactInfo].each do |type|
232
- filename = type.name.downcase.gsub('::', '_')
233
- File.write("types/#{filename}.baml", type.to_baml)
234
- end
235
- ```
236
-
237
- ### Build Process Integration
238
-
239
- ```ruby
240
- # Rakefile
241
- desc "Generate BAML type definitions"
242
- task :generate_baml do
243
- require 'sorbet-baml'
244
- require_relative 'app/models'
245
-
246
- types = [User, Company, Order, Product] # Your app types
247
- baml_content = types.map(&:to_baml).join("\n\n")
248
-
249
- File.write("lib/types.baml", baml_content)
250
- puts "Generated BAML types in lib/types.baml"
251
- end
252
- ```
253
-
254
- ## LLM Integration Patterns
255
-
256
- ### With OpenAI Structured Outputs
257
-
258
- ```ruby
259
- require 'openai'
260
- require 'sorbet-baml'
261
-
262
- # Define your response format
263
- class AnalysisResult < T::Struct
264
- const :sentiment, String
265
- const :confidence, Float
266
- const :key_phrases, T::Array[String]
267
- const :metadata, T::Hash[String, String]
268
- end
269
-
270
- # Generate schema for LLM
271
- schema = AnalysisResult.to_baml
272
-
273
- client = OpenAI::Client.new
274
- response = client.chat(
275
- parameters: {
276
- model: "gpt-4o",
277
- messages: [
278
- {
279
- role: "system",
280
- content: "Analyze text and respond with data matching this BAML schema:\n\n#{schema}"
281
- },
282
- {
283
- role: "user",
284
- content: "Analyze: 'I love this new product!'"
285
- }
286
- ]
287
- }
288
- )
289
- ```
290
-
291
- ### With Anthropic Claude
292
-
293
- ```ruby
294
- require 'anthropic'
295
- require 'sorbet-baml'
296
-
297
- schema = UserProfile.to_baml(include_dependencies: true)
298
-
299
- client = Anthropic::Client.new
300
- response = client.messages(
301
- model: "claude-3-5-sonnet-20241022",
302
- max_tokens: 1000,
303
- messages: [
304
- {
305
- role: "user",
306
- content: "Generate a realistic user profile matching this schema:\n\n#{schema}"
307
- }
308
- ]
309
- )
310
- ```
311
-
312
- ### With DSPy.rb Integration
313
-
314
- ```ruby
315
- require 'dspy'
316
- require 'sorbet-baml'
317
-
318
- # Your T::Struct automatically works with DSPy signatures
319
- class UserAnalysis < DSPy::Signature
320
- input { const :user_data, String }
321
- output { const :analysis, AnalysisResult } # Uses your T::Struct
322
- end
323
-
324
- # The BAML schema is automatically generated for LLM prompts
325
- predictor = DSPy::Predict.new(UserAnalysis)
326
- result = predictor.call(user_data: "John, 25, loves hiking")
327
- ```
328
-
329
- ### Prompt Engineering
330
-
331
- ```ruby
332
- # Template for complex prompts
333
- def build_analysis_prompt(data, schema)
334
- <<~PROMPT
335
- You are a data analyst. Analyze the following data and return results
336
- in the exact format specified by this BAML schema:
337
-
338
- #{schema}
339
-
340
- Data to analyze:
341
- #{data}
342
-
343
- Requirements:
344
- - Follow the schema exactly
345
- - Provide confidence scores between 0.0 and 1.0
346
- - Extract meaningful insights
347
- PROMPT
348
- end
349
-
350
- schema = AnalysisResult.to_baml
351
- prompt = build_analysis_prompt(user_input, schema)
352
- ```
353
-
354
- ## Rails Integration
355
-
356
- ### Model Integration
357
-
358
- ```ruby
359
- # app/models/user.rb
360
- class User < ApplicationRecord
361
- # Your ActiveRecord model...
362
-
363
- # Add Sorbet types for API schemas
364
- class UserAPI < T::Struct
365
- const :id, Integer
366
- const :name, String
367
- const :email, String
368
- const :created_at, String
369
- end
370
-
371
- def to_api_schema
372
- UserAPI.to_baml
373
- end
374
- end
375
-
376
- # Usage in controllers
377
- class UsersController < ApplicationController
378
- def schema
379
- render json: { schema: User::UserAPI.to_baml }
380
- end
381
- end
382
- ```
383
-
384
- ### API Documentation
385
-
386
- ```ruby
387
- # Generate API docs automatically
388
- class ApiDocsGenerator
389
- API_TYPES = [
390
- User::UserAPI,
391
- Order::OrderAPI,
392
- Product::ProductAPI
393
- ].freeze
394
-
395
- def self.generate
396
- schema = API_TYPES.map(&:to_baml).join("\n\n")
397
- File.write("docs/api_schema.baml", schema)
398
- end
399
- end
400
- ```
401
-
402
- ## Performance Considerations
403
-
404
- ### Caching Generated BAML
405
-
406
- ```ruby
407
- class CachedTypeConverter
408
- def self.to_baml(type)
409
- @cache ||= {}
410
- @cache[type] ||= type.to_baml
411
- end
412
- end
413
-
414
- # Use in production for frequently accessed types
415
- schema = CachedTypeConverter.to_baml(User)
416
- ```
417
-
418
- ### Lazy Loading
419
-
420
- ```ruby
421
- # Only generate BAML when needed (smart defaults apply)
422
- class ApiResponse
423
- def schema
424
- @schema ||= self.class.to_baml
425
- end
426
- end
427
- ```