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.
- checksums.yaml +4 -4
- data/CLAUDE.md +94 -0
- data/README.md +315 -122
- data/Rakefile +2 -2
- data/docs-site/.gitignore +48 -0
- data/docs-site/Gemfile +5 -0
- data/docs-site/Gemfile.lock +140 -0
- data/docs-site/Rakefile +3 -0
- data/docs-site/bridgetown.config.yml +15 -0
- data/docs-site/config/initializers.rb +9 -0
- data/docs-site/config/puma.rb +9 -0
- data/docs-site/config.ru +5 -0
- data/docs-site/esbuild.config.js +11 -0
- data/docs-site/frontend/javascript/index.js +22 -0
- data/docs-site/frontend/styles/index.css +61 -0
- data/docs-site/package.json +18 -0
- data/docs-site/postcss.config.js +6 -0
- data/docs-site/server/roda_app.rb +9 -0
- data/docs-site/src/_components/head.liquid +26 -0
- data/docs-site/src/_components/nav.liquid +68 -0
- data/docs-site/src/_layouts/default.liquid +27 -0
- data/docs-site/src/_layouts/doc.liquid +39 -0
- data/docs-site/src/advanced-usage.md +598 -0
- data/docs-site/src/getting-started.md +170 -0
- data/docs-site/src/index.md +183 -0
- data/docs-site/src/troubleshooting.md +317 -0
- data/docs-site/src/type-mapping.md +236 -0
- data/docs-site/tailwind.config.js +85 -0
- data/examples/description_parameters.rb +49 -0
- data/lib/sorbet_baml/comment_extractor.rb +51 -54
- data/lib/sorbet_baml/converter.rb +69 -35
- data/lib/sorbet_baml/dependency_resolver.rb +11 -11
- data/lib/sorbet_baml/description_extension.rb +34 -0
- data/lib/sorbet_baml/description_extractor.rb +34 -0
- data/lib/sorbet_baml/dspy_tool_converter.rb +97 -0
- data/lib/sorbet_baml/dspy_tool_extensions.rb +23 -0
- data/lib/sorbet_baml/enum_extensions.rb +2 -2
- data/lib/sorbet_baml/struct_extensions.rb +2 -2
- data/lib/sorbet_baml/tool_extensions.rb +23 -0
- data/lib/sorbet_baml/type_mapper.rb +35 -37
- data/lib/sorbet_baml/version.rb +1 -1
- data/lib/sorbet_baml.rb +41 -10
- data/sorbet/config +2 -0
- data/sorbet/rbi/gems/anthropic@1.5.0.rbi +21252 -0
- data/sorbet/rbi/gems/async@2.27.3.rbi +9 -0
- data/sorbet/rbi/gems/bigdecimal@3.2.2.rbi +9 -0
- data/sorbet/rbi/gems/concurrent-ruby@1.3.5.rbi +424 -0
- data/sorbet/rbi/gems/connection_pool@2.5.3.rbi +9 -0
- data/sorbet/rbi/gems/console@1.33.0.rbi +9 -0
- data/sorbet/rbi/gems/dry-configurable@1.3.0.rbi +672 -0
- data/sorbet/rbi/gems/dry-core@1.1.0.rbi +1729 -0
- data/sorbet/rbi/gems/dry-logger@1.1.0.rbi +1317 -0
- data/sorbet/rbi/gems/dspy@0.19.1.rbi +6677 -0
- data/sorbet/rbi/gems/ffi@1.17.2.rbi +2174 -0
- data/sorbet/rbi/gems/fiber-annotation@0.2.0.rbi +9 -0
- data/sorbet/rbi/gems/fiber-local@1.1.0.rbi +9 -0
- data/sorbet/rbi/gems/fiber-storage@1.0.1.rbi +9 -0
- data/sorbet/rbi/gems/google-protobuf@4.32.0.rbi +9 -0
- data/sorbet/rbi/gems/googleapis-common-protos-types@1.20.0.rbi +9 -0
- data/sorbet/rbi/gems/informers@1.2.1.rbi +1875 -0
- data/sorbet/rbi/gems/io-event@1.12.1.rbi +9 -0
- data/sorbet/rbi/gems/metrics@0.13.0.rbi +9 -0
- data/sorbet/rbi/gems/onnxruntime@0.10.0.rbi +304 -0
- data/sorbet/rbi/gems/openai@0.16.0.rbi +68055 -0
- data/sorbet/rbi/gems/opentelemetry-api@1.6.0.rbi +9 -0
- data/sorbet/rbi/gems/opentelemetry-common@0.22.0.rbi +9 -0
- data/sorbet/rbi/gems/opentelemetry-exporter-otlp@0.30.0.rbi +9 -0
- data/sorbet/rbi/gems/opentelemetry-registry@0.4.0.rbi +9 -0
- data/sorbet/rbi/gems/opentelemetry-sdk@1.8.1.rbi +9 -0
- data/sorbet/rbi/gems/opentelemetry-semantic_conventions@1.11.0.rbi +9 -0
- data/sorbet/rbi/gems/polars-df@0.20.0.rbi +9 -0
- data/sorbet/rbi/gems/sorbet-result@1.4.0.rbi +242 -0
- data/sorbet/rbi/gems/sorbet-schema@0.9.2.rbi +743 -0
- data/sorbet/rbi/gems/sorbet-struct-comparable@1.3.0.rbi +48 -0
- data/sorbet/rbi/gems/tokenizers@0.5.5.rbi +754 -0
- data/sorbet/rbi/gems/traces@0.17.0.rbi +9 -0
- data/sorbet/rbi/gems/zeitwerk@2.7.3.rbi +1429 -0
- metadata +67 -7
- data/docs/README.md +0 -117
- data/docs/advanced-usage.md +0 -427
- data/docs/getting-started.md +0 -91
- data/docs/troubleshooting.md +0 -291
- 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.
|
|
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-
|
|
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
|
|
43
|
-
- docs/
|
|
44
|
-
- docs/
|
|
45
|
-
- docs/
|
|
46
|
-
- docs/
|
|
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.
|
data/docs/advanced-usage.md
DELETED
|
@@ -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
|
-
```
|