dspy-code_act 1.0.2 → 1.0.3

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: b5b0506a94a331329847db4d8a8aa0e0f8e3dfb71171d41e4e10540fa0400645
4
- data.tar.gz: 29681588c29708ec9a315edb46c6e4630707b051d915968ea365130270440809
3
+ metadata.gz: 1e81ad2629b9d652887180a6209dc803301c39a8989317907fd92e4b0bd08c40
4
+ data.tar.gz: 41f24b4c59be3ee80d3eaaa329fa0d4c1ded4b44ba62f337fd36328271cb886b
5
5
  SHA512:
6
- metadata.gz: 142ec9519da18ef7f4fcc8e76dfca18398bd93f5b2e0ca05fb8ecbe50eabbb65dd8db29686bc31e0c33f59ca9fcc964b2de54e1c4b3f07f7cea1d0a560d6100c
7
- data.tar.gz: cb18480490094769069058aa9fb30f04771532bd35fcaeba6df635567cc46641b696ec5a0aab1c9d6576c005095f3022456dc3456773ccaaaab8d681ee5bcd17
6
+ metadata.gz: 52355d8730ca9f9f3455bfc87e6fba782a934feece0ccc418cd1adec8c4bd597191cf9975c66afded7dbfb5c41bcbc751c1bee6c2c4e0d72b569fc92d04b6ed6
7
+ data.tar.gz: ed2f38b62d55cf52a8f93755c432138aa6686e644b2175d74c03ab79c0812e77a62a078938b3a0e7d7908469f00e431731d77b8a75833fd1d94c096f11acd0fc
data/README.md CHANGED
@@ -6,95 +6,16 @@
6
6
  [![Documentation](https://img.shields.io/badge/docs-oss.vicente.services%2Fdspy.rb-blue)](https://oss.vicente.services/dspy.rb/)
7
7
  [![Discord](https://img.shields.io/discord/1161519468141355160?label=discord&logo=discord&logoColor=white)](https://discord.gg/zWBhrMqn)
8
8
 
9
- **Build reliable LLM applications in idiomatic Ruby using composable, type-safe modules.**
9
+ **Build typed agents and model-backed programs in Ruby.**
10
10
 
11
- DSPy.rb is the Ruby port of Stanford's [DSPy](https://dspy.ai). Instead of wrestling with brittle prompt strings, you define typed signatures and let the framework handle the rest. Prompts become functions. LLM calls become predictable.
11
+ DSPy.rb brings [DSPy](https://dspy.ai)'s signature, module, agent, and optimizer model to Ruby, with Sorbet types and Ruby-native integrations. A signature declares a task as typed inputs and outputs. A module chooses how to execute it. Ruby composes modules into programs, while `ReAct` adds a bounded loop when the model should choose the next action. DSPy.rb builds the provider request and validates the returned shape.
12
12
 
13
- ```ruby
14
- require 'dspy'
15
-
16
- DSPy.configure do |c|
17
- c.lm = DSPy::LM.new('openai/gpt-4o-mini', api_key: ENV['OPENAI_API_KEY'])
18
- end
19
-
20
- class Summarize < DSPy::Signature
21
- description "Summarize the given text in one sentence."
22
-
23
- input do
24
- const :text, String
25
- end
13
+ The `1.x` series is the current stable release line.
26
14
 
27
- output do
28
- const :summary, String
29
- end
30
- end
31
-
32
- summarizer = DSPy::Predict.new(Summarize)
33
- result = summarizer.call(text: "DSPy.rb brings structured LLM programming to Ruby...")
34
- puts result.summary
35
- ```
36
-
37
- That's it. No prompt templates. No JSON parsing. No prayer-based error handling.
38
-
39
- ## Installation
40
-
41
- ```ruby
42
- # Gemfile
43
- gem 'dspy'
44
- gem 'dspy-openai' # For OpenAI, OpenRouter, or Ollama
45
- # gem 'dspy-anthropic' # For Claude
46
- # gem 'dspy-gemini' # For Gemini
47
- # gem 'dspy-ruby_llm' # For 12+ providers via RubyLLM
48
- ```
49
-
50
- ```bash
51
- bundle install
52
- ```
53
-
54
- ## Quick Start
55
-
56
- ### Configure Your LLM
57
-
58
- ```ruby
59
- # OpenAI
60
- DSPy.configure do |c|
61
- c.lm = DSPy::LM.new('openai/gpt-4o-mini',
62
- api_key: ENV['OPENAI_API_KEY'],
63
- structured_outputs: true)
64
- end
65
-
66
- # Anthropic Claude
67
- DSPy.configure do |c|
68
- c.lm = DSPy::LM.new('anthropic/claude-sonnet-4-20250514',
69
- api_key: ENV['ANTHROPIC_API_KEY'])
70
- end
71
-
72
- # Google Gemini
73
- DSPy.configure do |c|
74
- c.lm = DSPy::LM.new('gemini/gemini-2.5-flash',
75
- api_key: ENV['GEMINI_API_KEY'])
76
- end
77
-
78
- # Ollama (local, free)
79
- DSPy.configure do |c|
80
- c.lm = DSPy::LM.new('ollama/llama3.2')
81
- end
82
-
83
- # OpenRouter (200+ models)
84
- DSPy.configure do |c|
85
- c.lm = DSPy::LM.new('openrouter/deepseek/deepseek-chat-v3.1:free',
86
- api_key: ENV['OPENROUTER_API_KEY'])
87
- end
88
- ```
89
-
90
- ### Define a Signature
91
-
92
- Signatures are typed contracts for LLM operations. Define inputs, outputs, and let DSPy handle the prompt:
15
+ In a configured application, the task contract and call look like this:
93
16
 
94
17
  ```ruby
95
18
  class Classify < DSPy::Signature
96
- description "Classify sentiment of a given sentence."
97
-
98
19
  class Sentiment < T::Enum
99
20
  enums do
100
21
  Positive = new('positive')
@@ -104,7 +25,7 @@ class Classify < DSPy::Signature
104
25
  end
105
26
 
106
27
  input do
107
- const :sentence, String, description: 'The sentence to analyze'
28
+ const :sentence, String
108
29
  end
109
30
 
110
31
  output do
@@ -114,115 +35,39 @@ class Classify < DSPy::Signature
114
35
  end
115
36
 
116
37
  classifier = DSPy::Predict.new(Classify)
117
- result = classifier.call(sentence: "This book was super fun to read!")
118
-
119
- result.sentiment # => #<Sentiment::Positive>
120
- result.confidence # => 0.92
38
+ result = classifier.call(sentence: "This book was fun to read!")
121
39
  ```
122
40
 
123
- ### Chain of Thought
41
+ Define a typed task contract instead of maintaining an output template. Receive validated Ruby values instead of parsing provider JSON. Handle configuration, transport, and validation errors explicitly.
124
42
 
125
- For complex reasoning, use `ChainOfThought` to get step-by-step explanations:
43
+ ## Start Here
126
44
 
127
- ```ruby
128
- solver = DSPy::ChainOfThought.new(MathProblem)
129
- result = solver.call(problem: "If a train travels 120km in 2 hours, what's its speed?")
130
-
131
- result.reasoning # => "Speed = Distance / Time = 120km / 2h = 60km/h"
132
- result.answer # => "60 km/h"
133
- ```
134
-
135
- ### ReAct Agents
136
-
137
- Build agents that use tools to accomplish tasks:
138
-
139
- ```ruby
140
- class SearchTool < DSPy::Tools::Tool
141
- tool_name "search"
142
- description "Search for information"
143
-
144
- input do
145
- const :query, String
146
- end
147
-
148
- output do
149
- const :results, T::Array[String]
150
- end
151
-
152
- def call(query:)
153
- # Your search implementation
154
- { results: ["Result 1", "Result 2"] }
155
- end
156
- end
157
-
158
- toolset = DSPy::Tools::Toolset.new(tools: [SearchTool.new])
159
- agent = DSPy::ReAct.new(signature: ResearchTask, tools: toolset, max_iterations: 5)
160
- result = agent.call(question: "What's the latest on Ruby 3.4?")
161
- ```
162
-
163
- ## What's Included
164
-
165
- **Core Modules**: Predict, ChainOfThought, ReAct agents, and composable pipelines.
166
-
167
- **Type Safety**: Sorbet-based runtime validation. Enums, unions, nested structs—all work.
168
-
169
- **Multimodal**: Image analysis with `DSPy::Image` for vision-capable models.
170
-
171
- **Observability**: Zero-config Langfuse integration via OpenTelemetry. Non-blocking, production-ready.
172
-
173
- **Optimization**: MIPROv2 (Bayesian optimization) and GEPA (genetic evolution) for prompt tuning.
174
-
175
- **Provider Support**: OpenAI, Anthropic, Gemini, Ollama, and OpenRouter via official SDKs.
176
-
177
- ## Documentation
45
+ The [Quick Start](https://oss.vicente.services/dspy.rb/getting-started/quick-start/) is the complete supported path: install the core and provider gems, configure a key, save a program, and run it.
178
46
 
179
- **[Full Documentation](https://oss.vicente.services/dspy.rb/)** Getting started, core concepts, advanced patterns.
47
+ Use [Installation](https://oss.vicente.services/dspy.rb/getting-started/installation/) to choose a provider. The [package and capability matrix](https://oss.vicente.services/dspy.rb/getting-started/packages/) records exact gem names, require behavior, support labels, and model or SDK boundaries.
180
48
 
181
- **[llms.txt](https://oss.vicente.services/dspy.rb/llms.txt)** LLM-friendly reference for AI assistants.
49
+ ## Mental Model
182
50
 
183
- ### Claude Skill
51
+ - A `DSPy::Signature` defines the task contract.
52
+ - `DSPy::Predict` and other modules choose an execution strategy.
53
+ - Ordinary Ruby owns fixed sequencing, branching, persistence, permissions, and failure policy.
54
+ - Results cross a runtime validation boundary; validation establishes shape, not factual correctness.
184
55
 
185
- A [Claude Skill](https://github.com/vicentereig/dspy-rb-skill) is available to help you build DSPy.rb applications:
186
-
187
- ```bash
188
- # Claude Code
189
- git clone https://github.com/vicentereig/dspy-rb-skill ~/.claude/skills/dspy-rb
190
- ```
191
-
192
- For Claude.ai Pro/Max, download the [skill ZIP](https://github.com/vicentereig/dspy-rb-skill/archive/refs/heads/main.zip) and upload via Settings > Skills.
193
-
194
- ## Examples
195
-
196
- The [examples/](examples/) directory has runnable code for common patterns:
197
-
198
- - Sentiment classification
199
- - ReAct agents with tools
200
- - Image analysis
201
- - Prompt optimization
202
-
203
- ```bash
204
- bundle exec ruby examples/first_predictor.rb
205
- ```
56
+ ### ReAct Agents
206
57
 
207
- ## Optional Gems
58
+ Use `ReAct` when the model needs to choose among typed Ruby tools inside an iteration bound. The application still owns tool authorization, side effects, budgets, and errors. See [Predictors](https://oss.vicente.services/dspy.rb/core-concepts/predictors/) and [Toolsets](https://oss.vicente.services/dspy.rb/core-concepts/toolsets/).
208
59
 
209
- DSPy.rb ships sibling gems for features with heavier dependencies. Add them as needed:
60
+ ## Explore
210
61
 
211
- | Gem | What it does |
212
- | --- | --- |
213
- | `dspy-datasets` | Dataset helpers, Parquet/Polars tooling |
214
- | `dspy-evals` | Evaluation harness with metrics and callbacks |
215
- | `dspy-miprov2` | Bayesian optimization for prompt tuning |
216
- | `dspy-gepa` | Genetic-Pareto prompt evolution |
217
- | `dspy-o11y-langfuse` | Auto-configure Langfuse tracing |
218
- | `dspy-code_act` | Think-Code-Observe agents |
219
- | `dspy-deep_search` | Production DeepSearch with Exa |
62
+ - [Documentation](https://oss.vicente.services/dspy.rb/) task-oriented guides and reference
63
+ - [Examples](examples/) repository demos indexed by capability and prerequisites
64
+ - [llms.txt](https://oss.vicente.services/dspy.rb/llms.txt) generated reference for AI assistants
220
65
 
221
- See [the full list](https://oss.vicente.services/dspy.rb/getting-started/installation/) in the docs.
66
+ Provider adapters, optimizers, observability exporters, datasets, and code-executing agents are separate packages when they add dependencies. Check the package matrix before selecting one; package availability does not guarantee uniform provider or model behavior.
222
67
 
223
68
  ## Contributing
224
69
 
225
- Feedback is invaluable. If you encounter issues, [open an issue](https://github.com/vicentereig/dspy.rb/issues). For suggestions, [start a discussion](https://github.com/vicentereig/dspy.rb/discussions).
70
+ For bugs, [open an issue](https://github.com/vicentereig/dspy.rb/issues). For suggestions, [start a discussion](https://github.com/vicentereig/dspy.rb/discussions).
226
71
 
227
72
  Want to contribute code? Reach out: hey at vicente.services
228
73
 
@@ -1,152 +1,77 @@
1
1
  # CodeAct: Dynamic Code Generation for DSPy.rb
2
2
 
3
- CodeAct is a DSPy.rb module that enables agents to write and execute Ruby code dynamically. Unlike ReAct agents that rely on predefined tools, CodeAct generates tailored Ruby code on the fly to solve complex tasks.
3
+ `dspy-code_act` is for controlled experiments with trusted input. The current implementation evaluates model-generated Ruby inside the application process. It does not provide a sandbox, permission boundary, resource isolation, or safe handling of untrusted or multi-tenant input.
4
4
 
5
- ## When to Use CodeAct
5
+ See the [package and capability matrix](https://oss.vicente.services/dspy.rb/getting-started/packages/) for canonical package status and the execution-safety boundary.
6
6
 
7
- - Choose CodeAct when you need creative problem solving, custom data transformations, or bespoke algorithms.
8
- - Prefer ReAct when you have well-defined tools, must call external services, or need stricter safety guarantees.
7
+ ## Prerequisites
9
8
 
10
- ## Quick Start
9
+ - Ruby 3.3 or newer and Bundler
10
+ - `dspy`, one provider adapter, and `dspy-code_act`
11
+ - a provider key and model that can produce the required structured responses
12
+ - trusted input and a controlled execution environment
13
+ - outbound network access for the repository research example; generated Ruby calls a live HTTP API
11
14
 
12
- ```ruby
13
- require 'dspy'
14
- require 'dspy/code_act'
15
-
16
- DSPy.configure do |config|
17
- config.lm = DSPy::LM.new('openai/gpt-4o-mini', api_key: ENV.fetch('OPENAI_API_KEY'))
18
- end
19
-
20
- agent = DSPy::CodeAct.new
21
-
22
- result = agent.forward(
23
- task: "Calculate the Fibonacci sequence up to the 10th number",
24
- context: "You have access to standard Ruby libraries"
25
- )
26
-
27
- puts result.final_answer
28
- # => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
29
-
30
- result.history.each do |step|
31
- puts "Step #{step.step}"
32
- puts "Thought: #{step.thought}"
33
- puts "Code: #{step.ruby_code}"
34
- puts "Result: #{step.execution_result}"
35
- end
36
- ```
37
-
38
- ## Advanced Usage
39
-
40
- ### Custom Execution Context
41
-
42
- Provide structured data or helper methods with the `context` argument so generated code can reference them:
15
+ ## Install and Run the Example
43
16
 
44
17
  ```ruby
45
- sales_data = {
46
- "January" => [100, 150, 200],
47
- "February" => [120, 180, 190],
48
- "March" => [140, 210, 220]
49
- }
50
-
51
- agent = DSPy::CodeAct.new
52
-
53
- result = agent.forward(
54
- task: "Calculate the average sales for each month and report the best performer",
55
- context: "You have access to `sales_data`, a hash keyed by month with numeric arrays",
56
- data: { sales_data: sales_data }
57
- )
58
-
59
- puts result.final_answer
60
- # => "March is the best performing month with an average of 190.0"
18
+ gem "dspy"
19
+ gem "dspy-openai"
20
+ gem "dspy-code_act"
61
21
  ```
62
22
 
63
- ### Arbitrary Data Processing
23
+ In an application, run `bundle install` after adding those gems. From this repository, enable the optional package while installing the monorepo bundle, then run the example:
64
24
 
65
- ```ruby
66
- csv_content = <<~CSV
67
- name,email,department
68
- John Doe,john@gmail.com,Engineering
69
- Jane Smith,jane@company.com,Marketing
70
- Bob Johnson,bob@gmail.com,Sales
71
- CSV
72
-
73
- result = agent.forward(
74
- task: "Parse the CSV data and list gmail.com addresses",
75
- context: "CSV data is available in `csv_content`",
76
- data: { csv_content: csv_content }
77
- )
25
+ ```bash
26
+ DSPY_WITH_CODE_ACT=1 bundle install
27
+ export OPENAI_API_KEY="your-key"
28
+ bundle exec ruby examples/codeact_research_agent.rb \
29
+ "How many stars does rails/rails have?"
78
30
  ```
79
31
 
80
- ## Safety Checklist
32
+ The script prints the final answer and records the generated code and observations in `result.history`. The answer can change with the live API; inspect the generated code and observation rather than treating an old count as a fixture.
81
33
 
82
- Executing arbitrary Ruby code is powerful but risky. Consider:
34
+ ## Define a CodeAct Task
83
35
 
84
- 1. **Sandboxing & Timeouts** – wrap execution in `Timeout.timeout` and restrict accessible objects.
85
- 2. **Input Sanitization** – scrub user input to remove shell-outs and dangerous methods.
86
- 3. **Resource Monitoring** – track memory and CPU usage to abort runaway code.
36
+ CodeAct requires a signature and an iteration bound:
87
37
 
88
38
  ```ruby
89
- class SafeCodeAct < DSPy::CodeAct
90
- def execute_code(ruby_code)
91
- Timeout.timeout(5) { super }
92
- rescue Timeout::Error
93
- "Code execution timed out"
94
- end
39
+ class Calculate < DSPy::Signature
40
+ input { const :question, String }
41
+ output { const :answer, String }
95
42
  end
96
- ```
97
-
98
- ## Example: Sales Analysis Pipeline
99
43
 
100
- ```ruby
101
- class SalesAnalyzer < DSPy::Module
102
- def initialize
103
- @agent = DSPy::CodeAct.new
104
- end
105
-
106
- def analyze_trends(sales_data)
107
- result = @agent.forward(
108
- task: <<~TASK,
109
- Analyze the sales data to:
110
- 1. Compute month-over-month growth
111
- 2. Identify seasonal patterns
112
- 3. Predict next month's sales with simple linear regression
113
- TASK
114
- context: "You have access to `sales_data` and standard Ruby libraries",
115
- data: { sales_data: sales_data }
116
- )
117
-
118
- {
119
- analysis: result.final_answer,
120
- code_steps: result.history.map(&:ruby_code),
121
- execution_time: result.metadata[:total_time]
122
- }
123
- end
44
+ DSPy.configure do |config|
45
+ config.lm = DSPy::LM.new(
46
+ "openai/gpt-4o-mini",
47
+ api_key: ENV.fetch("OPENAI_API_KEY")
48
+ )
124
49
  end
50
+
51
+ agent = DSPy::CodeAct.new(Calculate, max_iterations: 4)
52
+ result = agent.call(question: "Return the first ten Fibonacci numbers")
53
+
54
+ puts result.answer
55
+ puts result.history.map(&:ruby_code)
125
56
  ```
126
57
 
127
- ## Debugging
58
+ The model chooses Ruby code, CodeAct evaluates it, and a second prediction chooses whether to continue or finish. The application owns the iteration limit and execution boundary.
128
59
 
129
- Enable structured logging to observe each iteration:
60
+ ## Choose CodeAct or ReAct
130
61
 
131
- ```ruby
132
- DSPy.configure do |config|
133
- config.logger = Dry.Logger(:dspy, formatter: :json) do |logger|
134
- logger.add_backend(level: :debug, stream: $stdout)
135
- end
136
- end
137
- ```
62
+ Prefer `DSPy::ReAct` when the allowed operations can be exposed as narrow typed tools. Use CodeAct only when open-ended computation is necessary and the execution environment can carry the larger authority boundary.
138
63
 
139
- Inspect `result.history` entry-by-entry to review generated code, observations, and errors.
64
+ ## Safety Checklist
140
65
 
141
- ## Limitations & Roadmap
66
+ Timeouts and forbidden-string checks do not make Ruby `eval` safe. Generated code can reach loaded constants, files, environment variables, network clients, and process APIs through many equivalent expressions.
142
67
 
143
- - Basic sandboxing—do not run untrusted input without additional guards.
144
- - No support for external gem loading during execution.
145
- - Future roadmap targets hardened sandboxing, async execution, and richer explanations.
68
+ Before accepting untrusted input, move execution outside the application process and provide:
146
69
 
147
- ## Best Practices
70
+ - a disposable process, container, or virtual machine;
71
+ - no inherited application secrets;
72
+ - allowlisted network access;
73
+ - read-only or ephemeral storage;
74
+ - CPU, memory, wall-clock, and output limits; and
75
+ - a narrow protocol for returning observations.
148
76
 
149
- 1. Start with simple prompts before moving to complex tasks.
150
- 2. Provide precise context and structured data for better code generation.
151
- 3. Always validate outputs and enforce timeouts or resource caps.
152
- 4. Capture telemetry (Observability, Langfuse) for production usage.
77
+ The gem does not supply those controls. A provider error, invalid generated program, execution exception, or maximum-iteration result can stop or degrade a run; inspect `result.history` and handle those outcomes in the application.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module DSPy
4
4
  module CodeActVersion
5
- VERSION = '1.0.2'
5
+ VERSION = '1.0.3'
6
6
  end
7
7
  end
data/lib/dspy/code_act.rb CHANGED
@@ -118,6 +118,18 @@ module DSPy
118
118
  # Create enhanced output struct with CodeAct fields
119
119
  @enhanced_output_struct = create_enhanced_output_struct(signature_class)
120
120
  enhanced_output_struct = @enhanced_output_struct
121
+ input_descriptors = signature_class.input_field_descriptors
122
+ output_descriptors = input_descriptors.merge(signature_class.output_field_descriptors).merge(
123
+ history: DSPy::Signature::FieldDescriptor.new(
124
+ T::Array[CodeActHistoryEntry],
125
+ "CodeAct execution history"
126
+ ),
127
+ iterations: DSPy::Signature::FieldDescriptor.new(Integer, "Number of iterations executed"),
128
+ execution_context: DSPy::Signature::FieldDescriptor.new(
129
+ T::Hash[Symbol, T.untyped],
130
+ "Variables and context from code execution"
131
+ )
132
+ )
121
133
 
122
134
  # Create enhanced signature class
123
135
  enhanced_signature = Class.new(DSPy::Signature) do
@@ -126,9 +138,11 @@ module DSPy
126
138
 
127
139
  # Use the same input struct
128
140
  @input_struct_class = signature_class.input_struct_class
141
+ @input_field_descriptors = input_descriptors
129
142
 
130
143
  # Use the enhanced output struct with CodeAct fields
131
144
  @output_struct_class = enhanced_output_struct
145
+ @output_field_descriptors = output_descriptors
132
146
 
133
147
  # Store original signature name
134
148
  @original_signature_name = signature_class.name
@@ -306,6 +320,11 @@ module DSPy
306
320
  })
307
321
  output_data[output_field_name] = reasoning_result[:final_answer]
308
322
 
323
+ @signature_class.validate_required_fields!(
324
+ output_data,
325
+ @signature_class.output_field_descriptors
326
+ )
327
+
309
328
  @enhanced_output_struct.new(**output_data)
310
329
  end
311
330
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dspy-code_act
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vicente Reig Rincón de Arellano
@@ -15,14 +15,20 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '0.30'
18
+ version: 1.0.2
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '2.0'
19
22
  type: :runtime
20
23
  prerelease: false
21
24
  version_requirements: !ruby/object:Gem::Requirement
22
25
  requirements:
23
26
  - - ">="
24
27
  - !ruby/object:Gem::Version
25
- version: '0.30'
28
+ version: 1.0.2
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '2.0'
26
32
  description: CodeAct provides Think-Code-Observe agents that synthesize and execute
27
33
  Ruby code dynamically. Ship DSPy.rb workflows that write custom Ruby code while
28
34
  tracking execution history, observations, and safety signals.