dspy 0.14.0 → 0.15.1

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: 92f074914faabe00390399080ef0efecca6ca6dbfeeca38201c127cfbef11528
4
- data.tar.gz: 91c07b99351fd1095f5e61e1b8c9560c1c67ee67c97c945437f4a2964172eaca
3
+ metadata.gz: 2f0a8e9dc70e65ef655829a080bc1a7a44cbcf5927c4903c42881c72c8796060
4
+ data.tar.gz: 39195cb9177617a61e21aae7ed7cedaed536f6862f5840bef3a09b3ade9966d0
5
5
  SHA512:
6
- metadata.gz: 303990f2586f73beaf638ed85b1e5266a318f760aae0342af4738652078b0087e7d6826588d80fb4d26b3b9ca026dfc1b3f3e6645e3b24213d0cf94b1fbb450f
7
- data.tar.gz: db445cef172a2009d565b659fd4170895045dacbbbd9073b0d20ab8c054e2085ed62cfb8d1dbf6b98e203422cc999a495fb2e84ba3363d31360472b10f1487e9
6
+ metadata.gz: 8b0f2378f818914e4752f1ba309f79c9abfca9a34d5223f55cebc384023f8b76586f36eef725dc170f197c88669df9ab1b3c742dd2a13d2afd65759753066ec2
7
+ data.tar.gz: 9039f598229486c785d4b254d0d0e0101b312e2975e4e56dbef52c5b7eb99fa29eba74c661fedfabac39688fa59a20fe64823777f39a87b32f55aa546b4ecfa6
data/README.md CHANGED
@@ -40,6 +40,7 @@ The result? LLM applications that actually scale and don't break when you sneeze
40
40
  - LLM provider support using official Ruby clients:
41
41
  - [OpenAI Ruby](https://github.com/openai/openai-ruby)
42
42
  - [Anthropic Ruby SDK](https://github.com/anthropics/anthropic-sdk-ruby)
43
+ - [Ollama](https://ollama.com/) via OpenAI compatibility layer
43
44
  - Runtime type checking with [Sorbet](https://sorbet.org/)
44
45
  - Type-safe tool definitions for ReAct agents
45
46
  - Comprehensive instrumentation and observability
data/lib/dspy/code_act.rb CHANGED
@@ -9,6 +9,7 @@ require 'stringio'
9
9
  require_relative 'instrumentation'
10
10
  require_relative 'mixins/struct_builder'
11
11
  require_relative 'mixins/instrumentation_helpers'
12
+ require_relative 'type_serializer'
12
13
 
13
14
  module DSPy
14
15
  # Define a simple struct for CodeAct history entries with proper type annotations
@@ -37,7 +38,7 @@ module DSPy
37
38
 
38
39
  input do
39
40
  const :task, String,
40
- description: "The task description requiring Ruby code solution"
41
+ description: "JSON representation of all input fields for the task"
41
42
  const :context, String,
42
43
  description: "Available variables and previous results from code execution history"
43
44
  const :history, T::Array[CodeActHistoryEntry],
@@ -67,7 +68,7 @@ module DSPy
67
68
 
68
69
  input do
69
70
  const :task, String,
70
- description: "The original task"
71
+ description: "JSON representation of all input fields for the task"
71
72
  const :history, T::Array[CodeActHistoryEntry],
72
73
  description: "Previous thoughts, code executions, and their results"
73
74
  const :execution_result, T.nilable(String),
@@ -148,9 +149,9 @@ module DSPy
148
149
  result = instrument_prediction('dspy.codeact', @original_signature_class, kwargs, {
149
150
  max_iterations: @max_iterations
150
151
  }) do
151
- # Validate input and extract task
152
+ # Validate input and serialize all fields as task context
152
153
  input_struct = @original_signature_class.input_struct_class.new(**kwargs)
153
- task = T.cast(input_struct.serialize.values.first, String)
154
+ task = DSPy::TypeSerializer.serialize(input_struct).to_json
154
155
 
155
156
  # Execute CodeAct reasoning loop
156
157
  reasoning_result = execute_codeact_reasoning_loop(task)
@@ -7,7 +7,8 @@ module DSPy
7
7
  # Maps provider prefixes to adapter classes
8
8
  ADAPTER_MAP = {
9
9
  'openai' => 'OpenAIAdapter',
10
- 'anthropic' => 'AnthropicAdapter'
10
+ 'anthropic' => 'AnthropicAdapter',
11
+ 'ollama' => 'OllamaAdapter'
11
12
  }.freeze
12
13
 
13
14
  class << self
@@ -22,7 +23,8 @@ module DSPy
22
23
 
23
24
  # Pass provider-specific options
24
25
  adapter_options = { model: model, api_key: api_key }
25
- adapter_options.merge!(options) if provider == 'openai' # Only OpenAI accepts structured_outputs for now
26
+ # Both OpenAI and Ollama accept additional options
27
+ adapter_options.merge!(options) if %w[openai ollama].include?(provider)
26
28
 
27
29
  adapter_class.new(**adapter_options)
28
30
  end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openai'
4
+
5
+ module DSPy
6
+ class LM
7
+ class OllamaAdapter < OpenAIAdapter
8
+ DEFAULT_BASE_URL = 'http://localhost:11434/v1'
9
+
10
+ def initialize(model:, api_key: nil, base_url: nil, structured_outputs: true)
11
+ # Ollama doesn't require API key for local instances
12
+ # But may need it for remote/protected instances
13
+ api_key ||= 'ollama' # OpenAI client requires non-empty key
14
+ base_url ||= DEFAULT_BASE_URL
15
+
16
+ # Store base_url before calling super
17
+ @base_url = base_url
18
+
19
+ # Don't call parent's initialize, do it manually to control client creation
20
+ @model = model
21
+ @api_key = api_key
22
+ @structured_outputs_enabled = structured_outputs
23
+ validate_configuration!
24
+
25
+ # Create client with custom base URL
26
+ @client = OpenAI::Client.new(
27
+ api_key: @api_key,
28
+ base_url: @base_url
29
+ )
30
+ end
31
+
32
+ def chat(messages:, signature: nil, response_format: nil, &block)
33
+ # For Ollama, we need to be more lenient with structured outputs
34
+ # as it may not fully support OpenAI's response_format spec
35
+ begin
36
+ super
37
+ rescue => e
38
+ # If structured output fails, retry with enhanced prompting
39
+ if @structured_outputs_enabled && signature && e.message.include?('response_format')
40
+ DSPy.logger.debug("Ollama structured output failed, falling back to enhanced prompting")
41
+ @structured_outputs_enabled = false
42
+ retry
43
+ else
44
+ raise
45
+ end
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def validate_configuration!
52
+ super
53
+ # Additional Ollama-specific validation could go here
54
+ end
55
+
56
+ def validate_api_key!(api_key, provider)
57
+ # For Ollama, API key is optional for local instances
58
+ # Only validate if it looks like a remote URL
59
+ if @base_url && !@base_url.include?('localhost') && !@base_url.include?('127.0.0.1')
60
+ super
61
+ end
62
+ end
63
+
64
+
65
+ # Ollama may have different model support for structured outputs
66
+ def supports_structured_outputs?
67
+ # For now, assume all Ollama models support basic JSON mode
68
+ # but may not support full OpenAI structured output spec
69
+ true
70
+ end
71
+ end
72
+ end
73
+ end
@@ -11,10 +11,15 @@ module DSPy
11
11
 
12
12
  sig { override.returns(T::Boolean) }
13
13
  def available?
14
- # Check if adapter is OpenAI and supports structured outputs
15
- return false unless adapter.is_a?(DSPy::LM::OpenAIAdapter)
14
+ # Check if adapter is OpenAI or Ollama and supports structured outputs
15
+ return false unless adapter.is_a?(DSPy::LM::OpenAIAdapter) || adapter.is_a?(DSPy::LM::OllamaAdapter)
16
16
  return false unless adapter.instance_variable_get(:@structured_outputs_enabled)
17
17
 
18
+ # For Ollama, we assume it supports basic structured outputs
19
+ if adapter.is_a?(DSPy::LM::OllamaAdapter)
20
+ return true
21
+ end
22
+
18
23
  DSPy::LM::Adapters::OpenAI::SchemaConverter.supports_structured_outputs?(adapter.model)
19
24
  end
20
25
 
data/lib/dspy/lm.rb CHANGED
@@ -13,6 +13,7 @@ require_relative 'instrumentation/token_tracker'
13
13
  # Load adapters
14
14
  require_relative 'lm/adapters/openai_adapter'
15
15
  require_relative 'lm/adapters/anthropic_adapter'
16
+ require_relative 'lm/adapters/ollama_adapter'
16
17
 
17
18
  # Load strategy system
18
19
  require_relative 'lm/strategy_selector'
data/lib/dspy/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DSPy
4
- VERSION = "0.14.0"
4
+ VERSION = "0.15.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dspy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.15.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vicente Reig Rincón de Arellano
@@ -172,6 +172,7 @@ files:
172
172
  - lib/dspy/lm/adapter.rb
173
173
  - lib/dspy/lm/adapter_factory.rb
174
174
  - lib/dspy/lm/adapters/anthropic_adapter.rb
175
+ - lib/dspy/lm/adapters/ollama_adapter.rb
175
176
  - lib/dspy/lm/adapters/openai/schema_converter.rb
176
177
  - lib/dspy/lm/adapters/openai_adapter.rb
177
178
  - lib/dspy/lm/cache_manager.rb