ruby_llm-contract 0.2.1 → 0.2.2
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/CHANGELOG.md +11 -0
- data/Gemfile.lock +2 -2
- data/lib/ruby_llm/contract/adapters/test.rb +1 -1
- data/lib/ruby_llm/contract/pipeline/trace.rb +7 -0
- data/lib/ruby_llm/contract/step/base.rb +20 -14
- data/lib/ruby_llm/contract/step/dsl.rb +12 -0
- data/lib/ruby_llm/contract/step/result.rb +15 -2
- data/lib/ruby_llm/contract/step/trace.rb +7 -0
- data/lib/ruby_llm/contract/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c8111e9c77abab44b943129932bf6f225f619c930568bfe848c96b916cb72224
|
|
4
|
+
data.tar.gz: 4d54273d0b0dfd2fc4a44a34ff681aaa767956bbe89230659e975a91bf2a3821
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d5226bdd266a5676bbf4bef0b71580387825f15eb77e9739426e6845b62d6410d22583d2f3f3ad47d2eacca8980fb0763a8a23bf1c1f04c723cae5d4f021ed68
|
|
7
|
+
data.tar.gz: 2ee39172b68a94fd8dae1b633d17cc1e0bfac4f82413a0d4233d50f1851b860527248887ca35ebf88ef6b1fc69de78f6fc2775712c75e272891f36d44ba30f57
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.2 (2026-03-23)
|
|
4
|
+
|
|
5
|
+
Fixes from first real-world integration (persona_tool).
|
|
6
|
+
|
|
7
|
+
- **`around_call` fires per-run** — not per-attempt. With retry_policy, callback fires once with final result. Signature: `around_call { |step, input, result| ... }`
|
|
8
|
+
- **`Result#trace` always `Trace` object** — never bare Hash. `result.trace.model` works on success AND failure.
|
|
9
|
+
- **`around_call` exception safe** — warns and returns result instead of crashing.
|
|
10
|
+
- **`model` DSL** — `model "gpt-4o-mini"` per-step. Priority: context > step DSL > global config.
|
|
11
|
+
- **Test adapter `raw_output` always String** — Hash/Array normalized to `.to_json`.
|
|
12
|
+
- **`Trace#dig`** — `trace.dig(:usage, :input_tokens)` works.
|
|
13
|
+
|
|
3
14
|
## 0.2.1 (2026-03-23)
|
|
4
15
|
|
|
5
16
|
Production DX improvements from first real-world integration (persona_tool).
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
ruby_llm-contract (0.2.
|
|
4
|
+
ruby_llm-contract (0.2.2)
|
|
5
5
|
dry-types (~> 1.7)
|
|
6
6
|
ruby_llm (~> 1.0)
|
|
7
7
|
ruby_llm-schema (~> 0.3)
|
|
@@ -165,7 +165,7 @@ CHECKSUMS
|
|
|
165
165
|
rubocop-ast (1.49.1) sha256=4412f3ee70f6fe4546cc489548e0f6fcf76cafcfa80fa03af67098ffed755035
|
|
166
166
|
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
|
167
167
|
ruby_llm (1.14.0) sha256=57c6f7034fc4a44504ea137d70f853b07824f1c1cdbe774ab3ab3522e7098deb
|
|
168
|
-
ruby_llm-contract (0.2.
|
|
168
|
+
ruby_llm-contract (0.2.2)
|
|
169
169
|
ruby_llm-schema (0.3.0) sha256=a591edc5ca1b7f0304f0e2261de61ba4b3bea17be09f5cf7558153adfda3dec6
|
|
170
170
|
unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
|
|
171
171
|
unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
|
|
@@ -25,6 +25,13 @@ module RubyLLM
|
|
|
25
25
|
public_send(key)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
def dig(key, *rest)
|
|
29
|
+
value = self[key]
|
|
30
|
+
return value if rest.empty? || value.nil?
|
|
31
|
+
|
|
32
|
+
value.dig(*rest)
|
|
33
|
+
end
|
|
34
|
+
|
|
28
35
|
def to_h
|
|
29
36
|
{ trace_id: @trace_id, total_latency_ms: @total_latency_ms,
|
|
30
37
|
total_usage: @total_usage, step_traces: @step_traces,
|
|
@@ -63,14 +63,16 @@ module RubyLLM
|
|
|
63
63
|
def run(input, context: {})
|
|
64
64
|
warn_unknown_context_keys(context)
|
|
65
65
|
adapter = resolve_adapter(context)
|
|
66
|
-
default_model = context[:model] || RubyLLM::Contract.configuration.default_model
|
|
66
|
+
default_model = context[:model] || model || RubyLLM::Contract.configuration.default_model
|
|
67
67
|
policy = retry_policy
|
|
68
68
|
|
|
69
|
-
if policy
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
result = if policy
|
|
70
|
+
run_with_retry(input, adapter: adapter, default_model: default_model, policy: policy)
|
|
71
|
+
else
|
|
72
|
+
run_once(input, adapter: adapter, model: default_model, context_temperature: context[:temperature])
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
invoke_around_call(input, result)
|
|
74
76
|
end
|
|
75
77
|
|
|
76
78
|
def build_messages(input)
|
|
@@ -101,24 +103,28 @@ module RubyLLM
|
|
|
101
103
|
|
|
102
104
|
def run_once(input, adapter:, model:, context_temperature: nil)
|
|
103
105
|
effective_temp = context_temperature || temperature
|
|
104
|
-
|
|
106
|
+
Runner.new(
|
|
105
107
|
input_type: input_type, output_type: output_type,
|
|
106
108
|
prompt_block: prompt, contract_definition: effective_contract,
|
|
107
109
|
adapter: adapter, model: model, output_schema: output_schema,
|
|
108
110
|
max_output: max_output, max_input: max_input, max_cost: max_cost,
|
|
109
111
|
temperature: effective_temp
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
if around_call
|
|
113
|
-
around_call.call(self, input) { runner.call(input) }
|
|
114
|
-
else
|
|
115
|
-
runner.call(input)
|
|
116
|
-
end
|
|
112
|
+
).call(input)
|
|
117
113
|
rescue ArgumentError => e
|
|
118
114
|
Result.new(status: :input_error, raw_output: nil, parsed_output: nil,
|
|
119
115
|
validation_errors: [e.message])
|
|
120
116
|
end
|
|
121
117
|
|
|
118
|
+
def invoke_around_call(input, result)
|
|
119
|
+
return result unless around_call
|
|
120
|
+
|
|
121
|
+
around_call.call(self, input, result)
|
|
122
|
+
result
|
|
123
|
+
rescue StandardError => e
|
|
124
|
+
warn "[ruby_llm-contract] around_call raised #{e.class}: #{e.message}"
|
|
125
|
+
result
|
|
126
|
+
end
|
|
127
|
+
|
|
122
128
|
def effective_contract
|
|
123
129
|
base = contract
|
|
124
130
|
extra = class_validates
|
|
@@ -127,6 +127,18 @@ module RubyLLM
|
|
|
127
127
|
end
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
+
def model(name = nil)
|
|
131
|
+
if name
|
|
132
|
+
return @model = name
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
if defined?(@model)
|
|
136
|
+
@model
|
|
137
|
+
elsif superclass.respond_to?(:model)
|
|
138
|
+
superclass.model
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
130
142
|
def temperature(value = nil)
|
|
131
143
|
if value
|
|
132
144
|
unless value.is_a?(Numeric) && value >= 0 && value <= 2
|
|
@@ -6,12 +6,12 @@ module RubyLLM
|
|
|
6
6
|
class Result
|
|
7
7
|
attr_reader :status, :raw_output, :parsed_output, :validation_errors, :trace
|
|
8
8
|
|
|
9
|
-
def initialize(status:, raw_output:, parsed_output:, validation_errors: [], trace:
|
|
9
|
+
def initialize(status:, raw_output:, parsed_output:, validation_errors: [], trace: nil)
|
|
10
10
|
@status = status
|
|
11
11
|
@raw_output = raw_output
|
|
12
12
|
@parsed_output = parsed_output
|
|
13
13
|
@validation_errors = validation_errors.freeze
|
|
14
|
-
@trace = trace
|
|
14
|
+
@trace = normalize_trace(trace)
|
|
15
15
|
freeze
|
|
16
16
|
end
|
|
17
17
|
|
|
@@ -23,6 +23,19 @@ module RubyLLM
|
|
|
23
23
|
@status != :ok
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def normalize_trace(trace)
|
|
29
|
+
case trace
|
|
30
|
+
when Trace then trace
|
|
31
|
+
when Hash then Trace.new(**trace)
|
|
32
|
+
when nil then Trace.new
|
|
33
|
+
else trace
|
|
34
|
+
end.freeze
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
public
|
|
38
|
+
|
|
26
39
|
def to_s
|
|
27
40
|
if ok?
|
|
28
41
|
"#{@status} (#{@trace})"
|
|
@@ -26,6 +26,13 @@ module RubyLLM
|
|
|
26
26
|
public_send(key)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
def dig(key, *rest)
|
|
30
|
+
value = self[key]
|
|
31
|
+
return value if rest.empty? || value.nil?
|
|
32
|
+
|
|
33
|
+
value.dig(*rest)
|
|
34
|
+
end
|
|
35
|
+
|
|
29
36
|
def key?(key)
|
|
30
37
|
KNOWN_KEYS.include?(key.to_sym) && !public_send(key).nil?
|
|
31
38
|
end
|