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 +4 -4
- data/README.md +1 -0
- data/lib/dspy/code_act.rb +5 -4
- data/lib/dspy/lm/adapter_factory.rb +4 -2
- data/lib/dspy/lm/adapters/ollama_adapter.rb +73 -0
- data/lib/dspy/lm/strategies/openai_structured_output_strategy.rb +7 -2
- data/lib/dspy/lm.rb +1 -0
- data/lib/dspy/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f0a8e9dc70e65ef655829a080bc1a7a44cbcf5927c4903c42881c72c8796060
|
4
|
+
data.tar.gz: 39195cb9177617a61e21aae7ed7cedaed536f6862f5840bef3a09b3ade9966d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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: "
|
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: "
|
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
|
152
|
+
# Validate input and serialize all fields as task context
|
152
153
|
input_struct = @original_signature_class.input_struct_class.new(**kwargs)
|
153
|
-
task =
|
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
|
-
|
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
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.
|
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
|