dspy-anthropic 1.0.2 → 1.0.4
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 +8 -16
- data/lib/dspy/anthropic/lm/adapters/anthropic_adapter.rb +28 -37
- data/lib/dspy/anthropic/lm/schema_converter.rb +60 -0
- data/lib/dspy/anthropic/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: 2b563f892087546b395c4c279b09684339170eb112898941d3129ac48f804cbf
|
|
4
|
+
data.tar.gz: 54f15263e44abd8b6feca18a9569973ee952c6dd9373e4302db9ed66e46811c3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e78bbfb62abdd747b2dbf0d31da401078eeab71c09a6411d78097769baae4a8d96f1c142617741b203031ba9494e6b99581d5c4a9dbc81e1c40fe8ca221bffa7
|
|
7
|
+
data.tar.gz: 9369dadfb40f324a0f27cf8cdb912245ec214a0e13c676865b561a8886f4a12b0059c4e3b0b67b75b923df7e4a3604462b48d0b8a7807508e1641e0f044173e5
|
data/README.md
CHANGED
|
@@ -137,26 +137,18 @@ result.answer # => "60 km/h"
|
|
|
137
137
|
Build agents that use tools to accomplish tasks:
|
|
138
138
|
|
|
139
139
|
```ruby
|
|
140
|
-
class SearchTool < DSPy::Tools::
|
|
140
|
+
class SearchTool < DSPy::Tools::Base
|
|
141
141
|
tool_name "search"
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
input do
|
|
145
|
-
const :query, String
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
output do
|
|
149
|
-
const :results, T::Array[String]
|
|
150
|
-
end
|
|
142
|
+
tool_description "Search for information"
|
|
151
143
|
|
|
144
|
+
sig { params(query: String).returns(String) }
|
|
152
145
|
def call(query:)
|
|
153
146
|
# Your search implementation
|
|
154
|
-
|
|
147
|
+
"Result 1, Result 2"
|
|
155
148
|
end
|
|
156
149
|
end
|
|
157
150
|
|
|
158
|
-
|
|
159
|
-
agent = DSPy::ReAct.new(signature: ResearchTask, tools: toolset, max_iterations: 5)
|
|
151
|
+
agent = DSPy::ReAct.new(ResearchTask, tools: [SearchTool.new], max_iterations: 5)
|
|
160
152
|
result = agent.call(question: "What's the latest on Ruby 3.4?")
|
|
161
153
|
```
|
|
162
154
|
|
|
@@ -185,8 +177,8 @@ result = agent.call(question: "What's the latest on Ruby 3.4?")
|
|
|
185
177
|
A [Claude Skill](https://github.com/vicentereig/dspy-rb-skill) is available to help you build DSPy.rb applications:
|
|
186
178
|
|
|
187
179
|
```bash
|
|
188
|
-
# Claude Code
|
|
189
|
-
|
|
180
|
+
# Claude Code — install from the vicentereig/engineering marketplace
|
|
181
|
+
claude install-skill vicentereig/engineering --skill dspy-rb
|
|
190
182
|
```
|
|
191
183
|
|
|
192
184
|
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.
|
|
@@ -201,7 +193,7 @@ The [examples/](examples/) directory has runnable code for common patterns:
|
|
|
201
193
|
- Prompt optimization
|
|
202
194
|
|
|
203
195
|
```bash
|
|
204
|
-
bundle exec ruby examples/
|
|
196
|
+
bundle exec ruby examples/basic_search_agent.rb
|
|
205
197
|
```
|
|
206
198
|
|
|
207
199
|
## Optional Gems
|
|
@@ -26,17 +26,21 @@ module DSPy
|
|
|
26
26
|
if contains_images?(normalized_messages)
|
|
27
27
|
DSPy::LM::VisionModels.validate_vision_support!('anthropic', model)
|
|
28
28
|
# Convert messages to Anthropic format with proper image handling
|
|
29
|
-
normalized_messages = format_multimodal_messages(normalized_messages)
|
|
29
|
+
normalized_messages = format_multimodal_messages(normalized_messages, 'anthropic')
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
# Anthropic requires system message to be separate from messages
|
|
33
33
|
system_message, user_messages = extract_system_message(normalized_messages)
|
|
34
34
|
|
|
35
|
+
# Extract Beta API parameters if present
|
|
36
|
+
output_format = extra_params.delete(:output_format)
|
|
37
|
+
betas = extra_params.delete(:betas)
|
|
38
|
+
|
|
35
39
|
# Check if this is a tool use request
|
|
36
40
|
has_tools = extra_params.key?(:tools) && !extra_params[:tools].empty?
|
|
37
41
|
|
|
38
|
-
# Apply JSON prefilling if needed for better Claude JSON compliance (but not for tool use)
|
|
39
|
-
unless has_tools || contains_images?(normalized_messages)
|
|
42
|
+
# Apply JSON prefilling if needed for better Claude JSON compliance (but not for tool use or Beta API)
|
|
43
|
+
unless has_tools || output_format || contains_images?(normalized_messages)
|
|
40
44
|
user_messages = prepare_messages_for_json(user_messages, system_message)
|
|
41
45
|
end
|
|
42
46
|
|
|
@@ -58,11 +62,21 @@ module DSPy
|
|
|
58
62
|
begin
|
|
59
63
|
if block_given?
|
|
60
64
|
content = ""
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
if output_format
|
|
66
|
+
@client.beta.messages.stream(**request_params, output_format: output_format, betas: betas) do |chunk|
|
|
67
|
+
if chunk.respond_to?(:delta) && chunk.delta.respond_to?(:text)
|
|
68
|
+
chunk_text = chunk.delta.text
|
|
69
|
+
content += chunk_text
|
|
70
|
+
block.call(chunk)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
else
|
|
74
|
+
@client.messages.stream(**request_params) do |chunk|
|
|
75
|
+
if chunk.respond_to?(:delta) && chunk.delta.respond_to?(:text)
|
|
76
|
+
chunk_text = chunk.delta.text
|
|
77
|
+
content += chunk_text
|
|
78
|
+
block.call(chunk)
|
|
79
|
+
end
|
|
66
80
|
end
|
|
67
81
|
end
|
|
68
82
|
|
|
@@ -78,7 +92,11 @@ module DSPy
|
|
|
78
92
|
metadata: metadata
|
|
79
93
|
)
|
|
80
94
|
else
|
|
81
|
-
response =
|
|
95
|
+
response = if output_format
|
|
96
|
+
@client.beta.messages.create(**request_params, output_format: output_format, betas: betas)
|
|
97
|
+
else
|
|
98
|
+
@client.messages.create(**request_params)
|
|
99
|
+
end
|
|
82
100
|
|
|
83
101
|
if response.respond_to?(:error) && response.error
|
|
84
102
|
raise DSPy::LM::AdapterError, "Anthropic API error: #{response.error}"
|
|
@@ -127,7 +145,7 @@ module DSPy
|
|
|
127
145
|
metadata: typed_metadata
|
|
128
146
|
)
|
|
129
147
|
end
|
|
130
|
-
rescue => e
|
|
148
|
+
rescue StandardError => e
|
|
131
149
|
# Check for specific image-related errors in the message
|
|
132
150
|
error_msg = e.message.to_s
|
|
133
151
|
|
|
@@ -267,33 +285,6 @@ module DSPy
|
|
|
267
285
|
|
|
268
286
|
[system_message, user_messages]
|
|
269
287
|
end
|
|
270
|
-
|
|
271
|
-
def format_multimodal_messages(messages)
|
|
272
|
-
messages.map do |msg|
|
|
273
|
-
if msg[:content].is_a?(Array)
|
|
274
|
-
# Convert multimodal content to Anthropic format
|
|
275
|
-
formatted_content = msg[:content].map do |item|
|
|
276
|
-
case item[:type]
|
|
277
|
-
when 'text'
|
|
278
|
-
{ type: 'text', text: item[:text] }
|
|
279
|
-
when 'image'
|
|
280
|
-
# Validate image compatibility before formatting
|
|
281
|
-
item[:image].validate_for_provider!('anthropic')
|
|
282
|
-
item[:image].to_anthropic_format
|
|
283
|
-
else
|
|
284
|
-
item
|
|
285
|
-
end
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
{
|
|
289
|
-
role: msg[:role],
|
|
290
|
-
content: formatted_content
|
|
291
|
-
}
|
|
292
|
-
else
|
|
293
|
-
msg
|
|
294
|
-
end
|
|
295
|
-
end
|
|
296
|
-
end
|
|
297
288
|
end
|
|
298
289
|
end
|
|
299
290
|
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "sorbet-runtime"
|
|
4
|
+
|
|
5
|
+
module DSPy
|
|
6
|
+
module Anthropic
|
|
7
|
+
module LM
|
|
8
|
+
# Converts DSPy signatures to Anthropic Beta API structured output format
|
|
9
|
+
module SchemaConverter
|
|
10
|
+
extend T::Sig
|
|
11
|
+
|
|
12
|
+
sig { params(signature_class: T.class_of(DSPy::Signature)).returns(T::Hash[Symbol, T.untyped]) }
|
|
13
|
+
def self.to_beta_format(signature_class)
|
|
14
|
+
schema = signature_class.output_json_schema.except(:$schema)
|
|
15
|
+
add_additional_properties_false(schema)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
sig { params(schema: T.untyped).returns(T.untyped) }
|
|
19
|
+
def self.add_additional_properties_false(schema)
|
|
20
|
+
return schema unless schema.is_a?(Hash)
|
|
21
|
+
|
|
22
|
+
result = schema.dup
|
|
23
|
+
|
|
24
|
+
# Add additionalProperties: false to any object type
|
|
25
|
+
result[:additionalProperties] = false if result[:type] == "object"
|
|
26
|
+
|
|
27
|
+
# Process nested properties
|
|
28
|
+
if result[:properties].is_a?(Hash)
|
|
29
|
+
result[:properties] = result[:properties].transform_values do |v|
|
|
30
|
+
add_additional_properties_false(v)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Process array items
|
|
35
|
+
if result[:items].is_a?(Hash)
|
|
36
|
+
result[:items] = add_additional_properties_false(result[:items])
|
|
37
|
+
elsif result[:items].is_a?(Array)
|
|
38
|
+
result[:items] = result[:items].map { |item| add_additional_properties_false(item) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Process oneOf, anyOf, allOf arrays
|
|
42
|
+
[:oneOf, :anyOf, :allOf].each do |key|
|
|
43
|
+
if result[key].is_a?(Array)
|
|
44
|
+
result[key] = result[key].map { |item| add_additional_properties_false(item) }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Process definitions
|
|
49
|
+
[:definitions, :$defs].each do |key|
|
|
50
|
+
if result[key].is_a?(Hash)
|
|
51
|
+
result[key] = result[key].transform_values { |v| add_additional_properties_false(v) }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
result
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dspy-anthropic
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vicente Reig Rincón de Arellano
|
|
@@ -51,6 +51,7 @@ files:
|
|
|
51
51
|
- lib/dspy/anthropic/errors.rb
|
|
52
52
|
- lib/dspy/anthropic/guardrails.rb
|
|
53
53
|
- lib/dspy/anthropic/lm/adapters/anthropic_adapter.rb
|
|
54
|
+
- lib/dspy/anthropic/lm/schema_converter.rb
|
|
54
55
|
- lib/dspy/anthropic/version.rb
|
|
55
56
|
homepage: https://github.com/vicentereig/dspy.rb
|
|
56
57
|
licenses:
|