sorbet-baml 0.2.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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +123 -2
  3. data/Rakefile +2 -2
  4. data/docs-site/.gitignore +48 -0
  5. data/docs-site/Gemfile +5 -0
  6. data/docs-site/Gemfile.lock +140 -0
  7. data/docs-site/Rakefile +3 -0
  8. data/docs-site/bridgetown.config.yml +15 -0
  9. data/docs-site/config/initializers.rb +9 -0
  10. data/docs-site/config/puma.rb +9 -0
  11. data/docs-site/config.ru +5 -0
  12. data/docs-site/esbuild.config.js +11 -0
  13. data/docs-site/frontend/javascript/index.js +22 -0
  14. data/docs-site/frontend/styles/index.css +61 -0
  15. data/docs-site/package.json +18 -0
  16. data/docs-site/postcss.config.js +6 -0
  17. data/docs-site/server/roda_app.rb +9 -0
  18. data/docs-site/src/_components/head.liquid +26 -0
  19. data/docs-site/src/_components/nav.liquid +68 -0
  20. data/docs-site/src/_layouts/default.liquid +27 -0
  21. data/docs-site/src/_layouts/doc.liquid +39 -0
  22. data/docs-site/src/advanced-usage.md +598 -0
  23. data/docs-site/src/getting-started.md +170 -0
  24. data/docs-site/src/index.md +183 -0
  25. data/docs-site/src/troubleshooting.md +317 -0
  26. data/docs-site/src/type-mapping.md +236 -0
  27. data/docs-site/tailwind.config.js +85 -0
  28. data/examples/description_parameters.rb +16 -16
  29. data/lib/sorbet_baml/comment_extractor.rb +31 -39
  30. data/lib/sorbet_baml/converter.rb +66 -32
  31. data/lib/sorbet_baml/dependency_resolver.rb +11 -11
  32. data/lib/sorbet_baml/description_extension.rb +5 -5
  33. data/lib/sorbet_baml/description_extractor.rb +8 -10
  34. data/lib/sorbet_baml/dspy_tool_converter.rb +97 -0
  35. data/lib/sorbet_baml/dspy_tool_extensions.rb +23 -0
  36. data/lib/sorbet_baml/enum_extensions.rb +2 -2
  37. data/lib/sorbet_baml/struct_extensions.rb +2 -2
  38. data/lib/sorbet_baml/tool_extensions.rb +23 -0
  39. data/lib/sorbet_baml/type_mapper.rb +35 -37
  40. data/lib/sorbet_baml/version.rb +1 -1
  41. data/lib/sorbet_baml.rb +41 -13
  42. data/sorbet/config +2 -0
  43. data/sorbet/rbi/gems/anthropic@1.5.0.rbi +21252 -0
  44. data/sorbet/rbi/gems/async@2.27.3.rbi +9 -0
  45. data/sorbet/rbi/gems/bigdecimal@3.2.2.rbi +9 -0
  46. data/sorbet/rbi/gems/concurrent-ruby@1.3.5.rbi +424 -0
  47. data/sorbet/rbi/gems/connection_pool@2.5.3.rbi +9 -0
  48. data/sorbet/rbi/gems/console@1.33.0.rbi +9 -0
  49. data/sorbet/rbi/gems/dry-configurable@1.3.0.rbi +672 -0
  50. data/sorbet/rbi/gems/dry-core@1.1.0.rbi +1729 -0
  51. data/sorbet/rbi/gems/dry-logger@1.1.0.rbi +1317 -0
  52. data/sorbet/rbi/gems/dspy@0.19.1.rbi +6677 -0
  53. data/sorbet/rbi/gems/ffi@1.17.2.rbi +2174 -0
  54. data/sorbet/rbi/gems/fiber-annotation@0.2.0.rbi +9 -0
  55. data/sorbet/rbi/gems/fiber-local@1.1.0.rbi +9 -0
  56. data/sorbet/rbi/gems/fiber-storage@1.0.1.rbi +9 -0
  57. data/sorbet/rbi/gems/google-protobuf@4.32.0.rbi +9 -0
  58. data/sorbet/rbi/gems/googleapis-common-protos-types@1.20.0.rbi +9 -0
  59. data/sorbet/rbi/gems/informers@1.2.1.rbi +1875 -0
  60. data/sorbet/rbi/gems/io-event@1.12.1.rbi +9 -0
  61. data/sorbet/rbi/gems/metrics@0.13.0.rbi +9 -0
  62. data/sorbet/rbi/gems/onnxruntime@0.10.0.rbi +304 -0
  63. data/sorbet/rbi/gems/openai@0.16.0.rbi +68055 -0
  64. data/sorbet/rbi/gems/opentelemetry-api@1.6.0.rbi +9 -0
  65. data/sorbet/rbi/gems/opentelemetry-common@0.22.0.rbi +9 -0
  66. data/sorbet/rbi/gems/opentelemetry-exporter-otlp@0.30.0.rbi +9 -0
  67. data/sorbet/rbi/gems/opentelemetry-registry@0.4.0.rbi +9 -0
  68. data/sorbet/rbi/gems/opentelemetry-sdk@1.8.1.rbi +9 -0
  69. data/sorbet/rbi/gems/opentelemetry-semantic_conventions@1.11.0.rbi +9 -0
  70. data/sorbet/rbi/gems/polars-df@0.20.0.rbi +9 -0
  71. data/sorbet/rbi/gems/sorbet-result@1.4.0.rbi +242 -0
  72. data/sorbet/rbi/gems/sorbet-schema@0.9.2.rbi +743 -0
  73. data/sorbet/rbi/gems/sorbet-struct-comparable@1.3.0.rbi +48 -0
  74. data/sorbet/rbi/gems/tokenizers@0.5.5.rbi +754 -0
  75. data/sorbet/rbi/gems/traces@0.17.0.rbi +9 -0
  76. data/sorbet/rbi/gems/zeitwerk@2.7.3.rbi +1429 -0
  77. metadata +63 -2
@@ -0,0 +1,170 @@
1
+ ---
2
+ layout: doc
3
+ title: "Getting Started"
4
+ description: "Learn how to install and use sorbet-baml to convert your Sorbet types to BAML for efficient LLM prompting."
5
+ ---
6
+
7
+ # Getting Started
8
+
9
+ ## Prerequisites
10
+
11
+ - Ruby 3.2+
12
+ - Sorbet installed in your project
13
+ - Basic familiarity with T::Struct
14
+
15
+ ## Quick Start
16
+
17
+ ### 1. Define your autonomous workflow types
18
+
19
+ ```ruby
20
+ # Define complex LLM workflow types for research agents
21
+ class TaskType < T::Enum
22
+ enums do
23
+ # Literature review and information gathering
24
+ Research = new('research')
25
+ # Combining multiple sources into coherent insights
26
+ Synthesis = new('synthesis')
27
+ end
28
+ end
29
+
30
+ class ResearchTask < T::Struct
31
+ # Clear description of the research objective
32
+ const :objective, String
33
+ # Type of research task to be performed
34
+ const :task_type, TaskType
35
+ # Strategic priority ranking (1-5 scale)
36
+ const :priority, Integer
37
+ end
38
+ ```
39
+
40
+ ### 2. Convert to BAML
41
+
42
+ ```ruby
43
+ require 'sorbet-baml'
44
+
45
+ # Ruby-idiomatic API (recommended)
46
+ ResearchTask.to_baml
47
+
48
+ # Legacy API (still supported)
49
+ baml = SorbetBaml.from_struct(ResearchTask)
50
+ puts baml
51
+ ```
52
+
53
+ **Generated BAML:**
54
+ ```baml
55
+ enum TaskType {
56
+ "research" @description("Literature review and information gathering")
57
+ "synthesis" @description("Combining multiple sources into coherent insights")
58
+ }
59
+
60
+ class ResearchTask {
61
+ objective string @description("Clear description of the research objective")
62
+ task_type TaskType @description("Type of research task to be performed")
63
+ priority int @description("Strategic priority ranking (1-5 scale)")
64
+ }
65
+ ```
66
+
67
+ ### 3. Field descriptions are included by default
68
+
69
+ The smart defaults automatically extract field descriptions from your comments:
70
+
71
+ ```ruby
72
+ class ResearchFindings < T::Struct
73
+ # Detailed analysis results from the research
74
+ const :findings, String
75
+
76
+ # Key actionable insights extracted from findings
77
+ const :key_insights, T::Array[String]
78
+
79
+ # Confidence level in the research quality (1-10)
80
+ const :confidence_score, Integer
81
+ end
82
+
83
+ # Generate BAML (descriptions included by default!)
84
+ ResearchFindings.to_baml
85
+ ```
86
+
87
+ **Generated BAML with descriptions:**
88
+ ```baml
89
+ class ResearchFindings {
90
+ findings string @description("Detailed analysis results from the research")
91
+ key_insights string[] @description("Key actionable insights extracted from findings")
92
+ confidence_score int @description("Confidence level in the research quality (1-10)")
93
+ }
94
+ ```
95
+
96
+ ### 4. Use with autonomous research agents
97
+
98
+ Include the BAML definition in your agent prompts:
99
+
100
+ ```ruby
101
+ baml = ResearchTask.to_baml
102
+ prompt = <<~PROMPT
103
+ You are an autonomous research agent. Analyze the topic "AI in Healthcare" and break it down into strategic research tasks.
104
+
105
+ Schema for your output:
106
+ #{baml}
107
+
108
+ Provide a comprehensive task decomposition in JSON format.
109
+ PROMPT
110
+
111
+ # Use with OpenAI, Anthropic, or any LLM provider
112
+ response = llm_client.chat(prompt)
113
+ result = JSON.parse(response.content)
114
+ ```
115
+
116
+ ### 5. Generate Tool Definitions
117
+
118
+ Create BAML tool specifications for function calling and agentic workflows:
119
+
120
+ ```ruby
121
+ # Define tool parameter structures
122
+ class SearchTool < T::Struct
123
+ # The search query to execute
124
+ const :query, String
125
+ # Maximum number of results to return
126
+ const :limit, T.nilable(Integer)
127
+ end
128
+
129
+ class ReplyTool < T::Struct
130
+ # The response message to send back to the user
131
+ const :response, String
132
+ end
133
+
134
+ # Generate BAML tool definitions
135
+ SearchTool.to_baml_tool
136
+ ReplyTool.to_baml_tool
137
+
138
+ # Or use module API
139
+ SorbetBaml.from_tool(SearchTool)
140
+ ```
141
+
142
+ **Generated BAML Tool Specifications:**
143
+ ```baml
144
+ class SearchTool {
145
+ query string @description("The search query to execute")
146
+ limit int? @description("Maximum number of results to return")
147
+ }
148
+
149
+ class ReplyTool {
150
+ response string @description("The response message to send back to the user")
151
+ }
152
+ ```
153
+
154
+ **Perfect for LLM function calling schemas:**
155
+ ```ruby
156
+ tools = [SearchTool, ReplyTool].map(&:to_baml_tool).join("\n\n")
157
+
158
+ prompt = <<~PROMPT
159
+ You have access to these tools:
160
+ #{tools}
161
+
162
+ Use the appropriate tool to help the user with their request.
163
+ PROMPT
164
+ ```
165
+
166
+ ## Next Steps
167
+
168
+ - [Type Mapping Reference](./type-mapping.md)
169
+ - [Advanced Usage](./advanced-usage.md)
170
+ - [Troubleshooting](./troubleshooting.md)
@@ -0,0 +1,183 @@
1
+ ---
2
+ layout: default
3
+ title: "sorbet-baml"
4
+ description: "Ruby-idiomatic conversion from Sorbet types to BAML for efficient LLM prompting. 60% fewer tokens than JSON Schema while maintaining complete type information."
5
+ ---
6
+
7
+ <div class="text-center mb-12">
8
+ <h1 class="text-4xl font-bold text-gray-900 mb-4">sorbet-baml</h1>
9
+ <p class="text-xl text-gray-600 max-w-3xl mx-auto">
10
+ Ruby-idiomatic conversion from Sorbet types to BAML (Boundary AI Markup Language) for efficient LLM prompting.
11
+ </p>
12
+
13
+ <div class="flex flex-wrap justify-center gap-4 mt-8">
14
+ <img src="https://img.shields.io/gem/v/sorbet-baml" alt="Gem Version" />
15
+ <img src="https://img.shields.io/gem/dt/sorbet-baml" alt="Total Downloads" />
16
+ <img src="https://img.shields.io/github/license/vicentereig/sorbet-baml" alt="License" />
17
+ <img src="https://img.shields.io/badge/Sorbet-compatible-blue" alt="Sorbet Compatible" />
18
+ </div>
19
+
20
+ <div class="flex flex-wrap justify-center gap-4 mt-6">
21
+ <a href="/sorbet-baml/getting-started/" class="bg-blue-600 text-white px-6 py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors">
22
+ Get Started
23
+ </a>
24
+ <a href="https://github.com/vicentereig/sorbet-baml" class="bg-gray-100 text-gray-700 px-6 py-3 rounded-lg font-medium hover:bg-gray-200 transition-colors">
25
+ View on GitHub
26
+ </a>
27
+ </div>
28
+ </div>
29
+
30
+ ## Why BAML?
31
+
32
+ BAML uses approximately **60% fewer tokens** than JSON Schema while maintaining complete type information, making your LLM interactions more efficient and cost-effective.
33
+
34
+ <div class="bg-blue-50 border border-blue-200 rounded-lg p-6 my-8">
35
+ <h3 class="text-lg font-semibold text-blue-900 mb-3">🚀 Token Efficiency Comparison</h3>
36
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
37
+ <div>
38
+ <strong>JSON Schema:</strong> ~680 tokens
39
+ </div>
40
+ <div>
41
+ <strong>BAML:</strong> ~320 tokens <span class="text-blue-600 font-semibold">(53% reduction)</span>
42
+ </div>
43
+ </div>
44
+ <p class="text-blue-800 mt-3">
45
+ Real-world comparison from production agentic workflows using complex nested types, enums, and arrays.
46
+ </p>
47
+ </div>
48
+
49
+ ## Quick Example
50
+
51
+ ```ruby
52
+ # Define a Sorbet struct
53
+ class User < T::Struct
54
+ const :name, String
55
+ const :age, Integer
56
+ const :email, T.nilable(String)
57
+ end
58
+
59
+ # Convert to BAML (Ruby-idiomatic API)
60
+ require 'sorbet-baml'
61
+ User.to_baml
62
+ ```
63
+
64
+ **Generated BAML:**
65
+ ```baml
66
+ class User {
67
+ name string
68
+ age int
69
+ email string?
70
+ }
71
+ ```
72
+
73
+ ## Key Features
74
+
75
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 my-8">
76
+ <div class="bg-white p-6 rounded-lg border border-gray-200">
77
+ <h3 class="font-semibold text-gray-900 mb-2">🎯 Ruby-Idiomatic API</h3>
78
+ <p class="text-gray-600">Every T::Struct and T::Enum gets a natural <code>.to_baml</code> method that feels native to Ruby.</p>
79
+ </div>
80
+
81
+ <div class="bg-white p-6 rounded-lg border border-gray-200">
82
+ <h3 class="font-semibold text-gray-900 mb-2">🧠 Smart Defaults</h3>
83
+ <p class="text-gray-600">Field descriptions and dependencies included automatically for better LLM understanding.</p>
84
+ </div>
85
+
86
+ <div class="bg-white p-6 rounded-lg border border-gray-200">
87
+ <h3 class="font-semibold text-gray-900 mb-2">📝 Field Descriptions</h3>
88
+ <p class="text-gray-600">Extracts comments from source code to provide crucial context for autonomous agents.</p>
89
+ </div>
90
+
91
+ <div class="bg-white p-6 rounded-lg border border-gray-200">
92
+ <h3 class="font-semibold text-gray-900 mb-2">🔗 Dependency Management</h3>
93
+ <p class="text-gray-600">Automatically includes all referenced types with proper topological sorting.</p>
94
+ </div>
95
+
96
+ <div class="bg-white p-6 rounded-lg border border-gray-200">
97
+ <h3 class="font-semibold text-gray-900 mb-2">✅ Type-Safe</h3>
98
+ <p class="text-gray-600">Full Sorbet type checking throughout the gem with 100% test coverage.</p>
99
+ </div>
100
+
101
+ <div class="bg-white p-6 rounded-lg border border-gray-200">
102
+ <h3 class="font-semibold text-gray-900 mb-2">🛠️ Tool Definitions</h3>
103
+ <p class="text-gray-600">Generate BAML tool specifications for function calling and agentic workflows.</p>
104
+ </div>
105
+
106
+ <div class="bg-white p-6 rounded-lg border border-gray-200">
107
+ <h3 class="font-semibold text-gray-900 mb-2">🏁 Production Ready</h3>
108
+ <p class="text-gray-600">Complete type support, dependency management, and comprehensive test coverage.</p>
109
+ </div>
110
+ </div>
111
+
112
+ ## Complete Type Support
113
+
114
+ ### Basic Types
115
+ - `String` → `string`
116
+ - `Integer` → `int`
117
+ - `Float` → `float`
118
+ - `T::Boolean` → `bool`
119
+ - `Symbol` → `string`
120
+ - `Date/DateTime/Time` → `string`
121
+
122
+ ### Complex Types
123
+ - `T.nilable(T)` → `T?` (optional types)
124
+ - `T::Array[T]` → `T[]` (arrays)
125
+ - `T::Hash[K,V]` → `map<K,V>` (hash maps)
126
+ - `T.any(T1, T2)` → `T1 | T2` (union types)
127
+
128
+ ### Structured Types
129
+ - `T::Struct` → `class Name { ... }` (classes with fields)
130
+ - `T::Enum` → `enum Name { "value1" "value2" }` (enums)
131
+ - Nested structs with proper reference handling
132
+ - **Automatic dependency resolution** with topological sorting
133
+
134
+ ## Perfect for Agentic Workflows
135
+
136
+ ```ruby
137
+ # Define your autonomous research workflow types
138
+ class TaskDecomposition < T::Struct
139
+ # The main research topic being investigated
140
+ const :research_topic, String
141
+ # Target complexity level for the decomposition
142
+ const :complexity_level, ComplexityLevel
143
+ # Autonomously generated list of research subtasks
144
+ const :subtasks, T::Array[String]
145
+ end
146
+
147
+ # Generate BAML for LLM agents
148
+ prompt = <<~PROMPT
149
+ You are an autonomous research agent. Analyze this topic and decompose it.
150
+
151
+ Schema for your output:
152
+ #{TaskDecomposition.to_baml}
153
+
154
+ Topic: "Impact of AI on healthcare delivery systems"
155
+ PROMPT
156
+
157
+ # Use with any LLM provider
158
+ response = llm_client.chat(prompt)
159
+ result = TaskDecomposition.from_json(response.content)
160
+ ```
161
+
162
+ ## Installation
163
+
164
+ Add to your Gemfile:
165
+
166
+ ```ruby
167
+ gem 'sorbet-baml'
168
+ ```
169
+
170
+ Or install directly:
171
+
172
+ ```bash
173
+ gem install sorbet-baml
174
+ ```
175
+
176
+ ---
177
+
178
+ <div class="text-center mt-12">
179
+ <h2 class="text-2xl font-bold text-gray-900 mb-4">Ready to get started?</h2>
180
+ <a href="/sorbet-baml/getting-started/" class="bg-blue-600 text-white px-8 py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors inline-block">
181
+ Read the Getting Started Guide →
182
+ </a>
183
+ </div>
@@ -0,0 +1,317 @@
1
+ ---
2
+ layout: doc
3
+ title: "Troubleshooting"
4
+ description: "Common issues and solutions when using sorbet-baml. Find quick fixes for installation, conversion, and usage problems."
5
+ ---
6
+
7
+ # Troubleshooting
8
+
9
+ ## Common Issues
10
+
11
+ ### "undefined method `props' for Class"
12
+
13
+ **Problem**: The class you're trying to convert is not a T::Struct.
14
+
15
+ **Solution**: Ensure your class inherits from `T::Struct`:
16
+
17
+ ```ruby
18
+ # ❌ Wrong
19
+ class ResearchAgent
20
+ attr_reader :domain_expertise
21
+ end
22
+
23
+ # ✅ Correct
24
+ class ResearchAgent < T::Struct
25
+ # Agent's specialized domain of expertise
26
+ const :domain_expertise, String
27
+ end
28
+
29
+ # Generate BAML (descriptions included by default!)
30
+ ResearchAgent.to_baml
31
+ ```
32
+
33
+ **Generated BAML:**
34
+ ```baml
35
+ class ResearchAgent {
36
+ domain_expertise string @description("Agent's specialized domain of expertise")
37
+ }
38
+ ```
39
+
40
+ ### Empty output
41
+
42
+ **Problem**: The struct has no properties defined.
43
+
44
+ **Solution**: Define at least one property using `const` or `prop`:
45
+
46
+ ```ruby
47
+ class ResearchAgent < T::Struct
48
+ # Agent's specialized domain of expertise
49
+ const :domain_expertise, String
50
+ # Maximum concurrent research tasks
51
+ const :task_capacity, Integer
52
+ end
53
+
54
+ ResearchAgent.to_baml
55
+ ```
56
+
57
+ **Generated BAML:**
58
+ ```baml
59
+ class ResearchAgent {
60
+ domain_expertise string @description("Agent's specialized domain of expertise")
61
+ task_capacity int @description("Maximum concurrent research tasks")
62
+ }
63
+ ```
64
+
65
+ ### Self-referential types work fine
66
+
67
+ **Problem**: You think self-referential types aren't supported.
68
+
69
+ **Solution**: They actually work perfectly! Self-referential types are fully supported:
70
+
71
+ ```ruby
72
+ class ResearchHierarchy < T::Struct
73
+ # Name of the research domain or subdomain
74
+ const :domain_name, String
75
+ # Parent research domain for hierarchical organization
76
+ const :parent_domain, T.nilable(ResearchHierarchy)
77
+ # Child research subdomains
78
+ const :subdomains, T::Array[ResearchHierarchy]
79
+ end
80
+
81
+ ResearchHierarchy.to_baml
82
+ ```
83
+
84
+ **Generated BAML:**
85
+ ```baml
86
+ class ResearchHierarchy {
87
+ domain_name string @description("Name of the research domain or subdomain")
88
+ parent_domain ResearchHierarchy? @description("Parent research domain for hierarchical organization")
89
+ subdomains ResearchHierarchy[] @description("Child research subdomains")
90
+ }
91
+ ```
92
+
93
+ ## Type-Specific Issues
94
+
95
+ ### Arrays not converting correctly
96
+
97
+ Ensure you're using the Sorbet array syntax:
98
+
99
+ ```ruby
100
+ # ❌ Wrong
101
+ class ResearchAgent < T::Struct
102
+ const :research_methods, Array # Generic Array won't work
103
+ end
104
+
105
+ # ✅ Correct
106
+ class ResearchAgent < T::Struct
107
+ # List of research methodologies the agent can employ
108
+ const :research_methods, T::Array[String]
109
+ end
110
+
111
+ ResearchAgent.to_baml
112
+ ```
113
+
114
+ **Generated BAML:**
115
+ ```baml
116
+ class ResearchAgent {
117
+ research_methods string[] @description("List of research methodologies the agent can employ")
118
+ }
119
+ ```
120
+
121
+ ### Optional fields showing as required
122
+
123
+ Make sure to use `T.nilable`:
124
+
125
+ ```ruby
126
+ # ❌ Wrong - will be required
127
+ class ResearchAgent < T::Struct
128
+ # Peer review notes
129
+ const :peer_review, String
130
+ end
131
+
132
+ # ✅ Correct - will be optional
133
+ class ResearchAgent < T::Struct
134
+ # Optional peer review notes
135
+ const :peer_review, T.nilable(String)
136
+ end
137
+
138
+ ResearchAgent.to_baml
139
+ ```
140
+
141
+ **Generated BAML:**
142
+ ```baml
143
+ class ResearchAgent {
144
+ peer_review string? @description("Optional peer review notes")
145
+ }
146
+ ```
147
+
148
+ ### Union types not working
149
+
150
+ Ensure you're using `T.any` for union types:
151
+
152
+ ```ruby
153
+ # ❌ Wrong
154
+ class ResearchConfig < T::Struct
155
+ const :parameter_value, String || Integer # Ruby OR, not Sorbet union
156
+ end
157
+
158
+ # ✅ Correct
159
+ class ResearchConfig < T::Struct
160
+ # Configuration parameter supporting multiple value types
161
+ const :parameter_value, T.any(String, Integer)
162
+ end
163
+
164
+ ResearchConfig.to_baml
165
+ ```
166
+
167
+ **Generated BAML:**
168
+ ```baml
169
+ class ResearchConfig {
170
+ parameter_value string | int @description("Configuration parameter supporting multiple value types")
171
+ }
172
+ ```
173
+
174
+ ### Hash types not mapping correctly
175
+
176
+ Use the full `T::Hash[K, V]` syntax:
177
+
178
+ ```ruby
179
+ # ❌ Wrong
180
+ class ResearchAgent < T::Struct
181
+ const :agent_metadata, Hash # Generic Hash won't work
182
+ end
183
+
184
+ # ✅ Correct
185
+ class ResearchAgent < T::Struct
186
+ # Agent coordination metadata with flexible value types
187
+ const :agent_metadata, T::Hash[String, T.any(String, Integer)]
188
+ end
189
+
190
+ ResearchAgent.to_baml
191
+ ```
192
+
193
+ **Generated BAML:**
194
+ ```baml
195
+ class ResearchAgent {
196
+ agent_metadata map<string, string | int> @description("Agent coordination metadata with flexible value types")
197
+ }
198
+ ```
199
+
200
+ ## Dependency Issues
201
+
202
+ ### Missing dependencies in output
203
+
204
+ Dependencies are included by default! Smart defaults make this automatic:
205
+
206
+ ```ruby
207
+ class TaskType < T::Enum
208
+ enums do
209
+ # Literature review and information gathering
210
+ Research = new('research')
211
+ end
212
+ end
213
+
214
+ class ResearchTask < T::Struct
215
+ # Clear description of the research objective
216
+ const :objective, String
217
+ # Type of research task to be performed
218
+ const :task_type, TaskType
219
+ end
220
+
221
+ # ✅ Smart defaults: outputs both TaskType and ResearchTask automatically
222
+ ResearchTask.to_baml
223
+
224
+ # ❌ Only if you explicitly disable dependencies
225
+ ResearchTask.to_baml(include_dependencies: false)
226
+ ```
227
+
228
+ **Generated BAML (with dependencies by default):**
229
+ ```baml
230
+ enum TaskType {
231
+ "research" @description("Literature review and information gathering")
232
+ }
233
+
234
+ class ResearchTask {
235
+ objective string @description("Clear description of the research objective")
236
+ task_type TaskType @description("Type of research task to be performed")
237
+ }
238
+ ```
239
+
240
+ ### Wrong dependency order
241
+
242
+ The gem automatically handles dependency ordering using topological sorting. Dependencies always come before the types that reference them.
243
+
244
+ ## Enum Issues
245
+
246
+ ### Enums not converting
247
+
248
+ Ensure you're using the correct T::Enum syntax:
249
+
250
+ ```ruby
251
+ # ❌ Wrong
252
+ class ResearchStatus
253
+ ACTIVE = 'active'
254
+ COMPLETED = 'completed'
255
+ end
256
+
257
+ # ✅ Correct
258
+ class ResearchStatus < T::Enum
259
+ enums do
260
+ # Research is actively in progress
261
+ Active = new('active')
262
+ # Research has been completed successfully
263
+ Completed = new('completed')
264
+ end
265
+ end
266
+
267
+ ResearchStatus.to_baml
268
+ ```
269
+
270
+ **Generated BAML:**
271
+ ```baml
272
+ enum ResearchStatus {
273
+ "active" @description("Research is actively in progress")
274
+ "completed" @description("Research has been completed successfully")
275
+ }
276
+ ```
277
+
278
+ ## Getting Help
279
+
280
+ 1. Check the [Type Mapping Reference](./type-mapping.md) for complete type support
281
+ 2. Review examples in [Getting Started](./getting-started.md) and [Advanced Usage](./advanced-usage.md)
282
+ 3. File an issue at https://github.com/vicentereig/sorbet-baml/issues
283
+
284
+ ## Advanced Debugging
285
+
286
+ ### Inspect Sorbet type information
287
+
288
+ ```ruby
289
+ # See what Sorbet sees for your struct
290
+ MyStruct.props
291
+ # => {name: String, age: Integer, ...}
292
+
293
+ # Check if a class is a T::Struct
294
+ MyStruct < T::Struct
295
+ # => true
296
+
297
+ # See enum values
298
+ MyEnum.values
299
+ # => [#<MyEnum:0x... @serialize="value1">, ...]
300
+ ```
301
+
302
+ ### Testing your BAML output
303
+
304
+ ```ruby
305
+ # Verify the output looks correct (dependencies included by default)
306
+ baml = ResearchTask.to_baml
307
+ puts baml
308
+
309
+ # Check that all expected types are included
310
+ expected_types = ['class ResearchTask', 'enum TaskType']
311
+ expected_types.all? { |type| baml.include?(type) }
312
+ # => true
313
+
314
+ # Verify descriptions are included
315
+ baml.include?('@description')
316
+ # => true
317
+ ```