riffer 0.30.0 → 0.32.0
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/.agents/code-style.md +63 -4
- data/.agents/rbs-inline.md +1 -6
- data/.release-please-manifest.json +1 -1
- data/AGENTS.md +1 -2
- data/CHANGELOG.md +25 -0
- data/docs/08_MESSAGES.md +1 -1
- data/docs/14_MCP.md +50 -5
- data/docs/15_SERIALIZATION.md +23 -12
- data/docs/providers/02_AMAZON_BEDROCK.md +14 -0
- data/lib/riffer/agent/config.rb +42 -47
- data/lib/riffer/agent/context.rb +70 -50
- data/lib/riffer/agent/response.rb +4 -20
- data/lib/riffer/agent/run.rb +28 -67
- data/lib/riffer/agent/serializer.rb +36 -85
- data/lib/riffer/agent/session/repair.rb +14 -40
- data/lib/riffer/agent/session.rb +25 -67
- data/lib/riffer/agent/structured_output/result.rb +3 -11
- data/lib/riffer/agent/structured_output.rb +5 -13
- data/lib/riffer/agent.rb +81 -199
- data/lib/riffer/config.rb +34 -101
- data/lib/riffer/evals/evaluator.rb +7 -27
- data/lib/riffer/evals/evaluator_runner.rb +11 -19
- data/lib/riffer/evals/judge.rb +4 -25
- data/lib/riffer/evals/result.rb +1 -18
- data/lib/riffer/evals/run_result.rb +0 -11
- data/lib/riffer/evals/scenario_result.rb +0 -14
- data/lib/riffer/evals.rb +0 -6
- data/lib/riffer/guardrail.rb +4 -27
- data/lib/riffer/guardrails/modification.rb +0 -10
- data/lib/riffer/guardrails/result.rb +3 -30
- data/lib/riffer/guardrails/runner.rb +5 -22
- data/lib/riffer/guardrails/tripwire.rb +1 -19
- data/lib/riffer/guardrails.rb +2 -4
- data/lib/riffer/helpers/call_or_value.rb +4 -3
- data/lib/riffer/helpers/class_name_converter.rb +3 -1
- data/lib/riffer/helpers/dependencies.rb +5 -7
- data/lib/riffer/helpers.rb +0 -5
- data/lib/riffer/mcp/authenticated_tool.rb +9 -9
- data/lib/riffer/mcp/client.rb +12 -17
- data/lib/riffer/mcp/manifest.rb +13 -10
- data/lib/riffer/mcp/registration.rb +2 -11
- data/lib/riffer/mcp/registry.rb +44 -52
- data/lib/riffer/mcp/search_tool.rb +53 -0
- data/lib/riffer/mcp/tool_factory.rb +13 -18
- data/lib/riffer/mcp.rb +12 -17
- data/lib/riffer/messages/assistant.rb +2 -9
- data/lib/riffer/messages/base.rb +46 -16
- data/lib/riffer/messages/file_part.rb +32 -24
- data/lib/riffer/messages/system.rb +0 -5
- data/lib/riffer/messages/tool.rb +0 -10
- data/lib/riffer/messages/user.rb +0 -10
- data/lib/riffer/messages.rb +0 -7
- data/lib/riffer/params/boolean.rb +2 -4
- data/lib/riffer/params/param.rb +28 -39
- data/lib/riffer/params.rb +9 -21
- data/lib/riffer/providers/amazon_bedrock.rb +42 -28
- data/lib/riffer/providers/anthropic.rb +4 -9
- data/lib/riffer/providers/azure_open_ai.rb +3 -19
- data/lib/riffer/providers/base.rb +13 -26
- data/lib/riffer/providers/gemini.rb +4 -4
- data/lib/riffer/providers/mock.rb +6 -26
- data/lib/riffer/providers/open_ai.rb +6 -8
- data/lib/riffer/providers/open_router.rb +4 -10
- data/lib/riffer/providers/repository.rb +4 -3
- data/lib/riffer/providers/token_usage.rb +9 -20
- data/lib/riffer/providers.rb +0 -8
- data/lib/riffer/runner/fibers.rb +10 -16
- data/lib/riffer/runner/sequential.rb +1 -4
- data/lib/riffer/runner/threaded.rb +3 -14
- data/lib/riffer/runner.rb +2 -15
- data/lib/riffer/skills/activate_tool.rb +2 -11
- data/lib/riffer/skills/adapter.rb +4 -22
- data/lib/riffer/skills/backend.rb +7 -21
- data/lib/riffer/skills/config.rb +10 -31
- data/lib/riffer/skills/context.rb +5 -20
- data/lib/riffer/skills/filesystem_backend.rb +7 -25
- data/lib/riffer/skills/frontmatter.rb +10 -28
- data/lib/riffer/skills/markdown_adapter.rb +2 -9
- data/lib/riffer/skills/xml_adapter.rb +2 -8
- data/lib/riffer/stream_events/base.rb +1 -6
- data/lib/riffer/stream_events/guardrail_modification.rb +1 -8
- data/lib/riffer/stream_events/guardrail_tripwire.rb +1 -8
- data/lib/riffer/stream_events/interrupt.rb +4 -7
- data/lib/riffer/stream_events/reasoning_delta.rb +2 -4
- data/lib/riffer/stream_events/reasoning_done.rb +2 -4
- data/lib/riffer/stream_events/skill_activation.rb +2 -4
- data/lib/riffer/stream_events/text_delta.rb +0 -2
- data/lib/riffer/stream_events/text_done.rb +1 -3
- data/lib/riffer/stream_events/token_usage_done.rb +1 -8
- data/lib/riffer/stream_events/tool_call_delta.rb +2 -3
- data/lib/riffer/stream_events/tool_call_done.rb +1 -3
- data/lib/riffer/stream_events/web_search_done.rb +1 -3
- data/lib/riffer/stream_events/web_search_status.rb +2 -3
- data/lib/riffer/stream_events.rb +0 -10
- data/lib/riffer/tool.rb +6 -13
- data/lib/riffer/tools/response.rb +8 -4
- data/lib/riffer/tools/runtime/fibers.rb +0 -3
- data/lib/riffer/tools/runtime/inline.rb +1 -4
- data/lib/riffer/tools/runtime/threaded.rb +0 -2
- data/lib/riffer/tools/runtime.rb +5 -38
- data/lib/riffer/tools/toolable.rb +5 -16
- data/lib/riffer/tools.rb +0 -4
- data/lib/riffer/version.rb +1 -1
- data/lib/riffer.rb +7 -8
- data/sig/generated/riffer/agent/config.rbs +29 -46
- data/sig/generated/riffer/agent/context.rbs +40 -48
- data/sig/generated/riffer/agent/response.rbs +4 -20
- data/sig/generated/riffer/agent/run.rbs +12 -61
- data/sig/generated/riffer/agent/serializer.rbs +28 -81
- data/sig/generated/riffer/agent/session/repair.rbs +12 -40
- data/sig/generated/riffer/agent/session.rbs +25 -67
- data/sig/generated/riffer/agent/structured_output/result.rbs +2 -10
- data/sig/generated/riffer/agent/structured_output.rbs +5 -12
- data/sig/generated/riffer/agent.rbs +62 -191
- data/sig/generated/riffer/config.rbs +34 -100
- data/sig/generated/riffer/evals/evaluator.rbs +7 -27
- data/sig/generated/riffer/evals/evaluator_runner.rbs +9 -19
- data/sig/generated/riffer/evals/judge.rbs +4 -24
- data/sig/generated/riffer/evals/result.rbs +1 -17
- data/sig/generated/riffer/evals/run_result.rbs +0 -10
- data/sig/generated/riffer/evals/scenario_result.rbs +0 -13
- data/sig/generated/riffer/evals.rbs +0 -6
- data/sig/generated/riffer/guardrail.rbs +4 -27
- data/sig/generated/riffer/guardrails/modification.rbs +0 -10
- data/sig/generated/riffer/guardrails/result.rbs +3 -30
- data/sig/generated/riffer/guardrails/runner.rbs +5 -22
- data/sig/generated/riffer/guardrails/tripwire.rbs +1 -19
- data/sig/generated/riffer/guardrails.rbs +2 -4
- data/sig/generated/riffer/helpers/call_or_value.rbs +4 -3
- data/sig/generated/riffer/helpers/class_name_converter.rbs +1 -1
- data/sig/generated/riffer/helpers/dependencies.rbs +3 -7
- data/sig/generated/riffer/helpers.rbs +0 -5
- data/sig/generated/riffer/mcp/authenticated_tool.rbs +5 -4
- data/sig/generated/riffer/mcp/client.rbs +10 -16
- data/sig/generated/riffer/mcp/manifest.rbs +9 -9
- data/sig/generated/riffer/mcp/registration.rbs +2 -10
- data/sig/generated/riffer/mcp/registry.rbs +11 -18
- data/sig/generated/riffer/mcp/search_tool.rbs +26 -0
- data/sig/generated/riffer/mcp/tool_factory.rbs +10 -15
- data/sig/generated/riffer/mcp.rbs +10 -17
- data/sig/generated/riffer/messages/assistant.rbs +2 -8
- data/sig/generated/riffer/messages/base.rbs +11 -16
- data/sig/generated/riffer/messages/file_part.rbs +13 -23
- data/sig/generated/riffer/messages/system.rbs +0 -4
- data/sig/generated/riffer/messages/tool.rbs +0 -9
- data/sig/generated/riffer/messages/user.rbs +0 -9
- data/sig/generated/riffer/messages.rbs +0 -7
- data/sig/generated/riffer/params/boolean.rbs +2 -4
- data/sig/generated/riffer/params/param.rbs +21 -39
- data/sig/generated/riffer/params.rbs +9 -21
- data/sig/generated/riffer/providers/amazon_bedrock.rbs +21 -25
- data/sig/generated/riffer/providers/anthropic.rbs +2 -7
- data/sig/generated/riffer/providers/azure_open_ai.rbs +3 -18
- data/sig/generated/riffer/providers/base.rbs +9 -25
- data/sig/generated/riffer/providers/gemini.rbs +0 -2
- data/sig/generated/riffer/providers/mock.rbs +6 -26
- data/sig/generated/riffer/providers/open_ai.rbs +1 -5
- data/sig/generated/riffer/providers/open_router.rbs +4 -10
- data/sig/generated/riffer/providers/repository.rbs +2 -3
- data/sig/generated/riffer/providers/token_usage.rbs +6 -16
- data/sig/generated/riffer/providers.rbs +0 -8
- data/sig/generated/riffer/runner/fibers.rbs +8 -15
- data/sig/generated/riffer/runner/sequential.rbs +1 -3
- data/sig/generated/riffer/runner/threaded.rbs +3 -13
- data/sig/generated/riffer/runner.rbs +2 -14
- data/sig/generated/riffer/skills/activate_tool.rbs +2 -11
- data/sig/generated/riffer/skills/adapter.rbs +4 -22
- data/sig/generated/riffer/skills/backend.rbs +7 -21
- data/sig/generated/riffer/skills/config.rbs +10 -31
- data/sig/generated/riffer/skills/context.rbs +5 -20
- data/sig/generated/riffer/skills/filesystem_backend.rbs +7 -24
- data/sig/generated/riffer/skills/frontmatter.rbs +10 -27
- data/sig/generated/riffer/skills/markdown_adapter.rbs +2 -9
- data/sig/generated/riffer/skills/xml_adapter.rbs +2 -8
- data/sig/generated/riffer/stream_events/base.rbs +1 -6
- data/sig/generated/riffer/stream_events/guardrail_modification.rbs +1 -8
- data/sig/generated/riffer/stream_events/guardrail_tripwire.rbs +1 -8
- data/sig/generated/riffer/stream_events/interrupt.rbs +4 -7
- data/sig/generated/riffer/stream_events/reasoning_delta.rbs +2 -4
- data/sig/generated/riffer/stream_events/reasoning_done.rbs +2 -4
- data/sig/generated/riffer/stream_events/skill_activation.rbs +2 -4
- data/sig/generated/riffer/stream_events/text_delta.rbs +0 -2
- data/sig/generated/riffer/stream_events/text_done.rbs +1 -3
- data/sig/generated/riffer/stream_events/token_usage_done.rbs +1 -7
- data/sig/generated/riffer/stream_events/tool_call_delta.rbs +2 -3
- data/sig/generated/riffer/stream_events/tool_call_done.rbs +1 -3
- data/sig/generated/riffer/stream_events/web_search_done.rbs +1 -3
- data/sig/generated/riffer/stream_events/web_search_status.rbs +2 -3
- data/sig/generated/riffer/stream_events.rbs +0 -10
- data/sig/generated/riffer/tool.rbs +5 -12
- data/sig/generated/riffer/tools/response.rbs +6 -4
- data/sig/generated/riffer/tools/runtime/fibers.rbs +0 -3
- data/sig/generated/riffer/tools/runtime/inline.rbs +1 -3
- data/sig/generated/riffer/tools/runtime/threaded.rbs +0 -2
- data/sig/generated/riffer/tools/runtime.rbs +5 -37
- data/sig/generated/riffer/tools/toolable.rbs +4 -14
- data/sig/generated/riffer/tools.rbs +0 -4
- data/sig/generated/riffer.rbs +5 -4
- data/sig/manual/riffer/agent/session/repair.rbs +5 -0
- data/sig/manual/riffer/evals/evaluator_runner.rbs +5 -0
- data/sig/manual/riffer/helpers/class_name_converter.rbs +5 -0
- data/sig/manual/riffer/helpers/dependencies.rbs +5 -0
- data/sig/manual/riffer/mcp/authenticated_tool.rbs +5 -0
- data/sig/manual/riffer/mcp/registry.rbs +5 -0
- data/sig/manual/riffer/mcp/tool_factory.rbs +5 -0
- data/sig/manual/riffer/mcp.rbs +5 -0
- data/sig/manual/riffer/providers/repository.rbs +5 -0
- data/sig/manual/riffer.rbs +5 -0
- metadata +17 -9
- data/.agents/rdoc.md +0 -69
- data/lib/riffer/messages/converter.rb +0 -90
- data/sig/generated/riffer/messages/converter.rbs +0 -33
- data/sig/manual/riffer/tools/toolable.rbs +0 -6
|
@@ -1,39 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# +Riffer.config.experimental_history_healing+: when the flag is off the
|
|
8
|
-
# function returns its input unchanged.
|
|
9
|
-
#
|
|
10
|
-
# Two seams:
|
|
11
|
-
#
|
|
12
|
-
# - +fill_orphans+ — fills orphan +tool_use+ blocks with placeholder
|
|
13
|
-
# results. Used on interrupt (caller-issued or +max_steps+).
|
|
14
|
-
# - +prune_orphans+ — drops orphan +tool_use+ blocks and parentless Tool
|
|
15
|
-
# messages from a caller-provided seed so it is well-formed before the
|
|
16
|
-
# next inference call. Used at construction time when
|
|
17
|
-
# +Riffer::Agent.new(session:)+ receives a session.
|
|
4
|
+
# Pure, stateless transformations keeping the +tool_use+ ↔ +tool_result+
|
|
5
|
+
# invariant on a message array. Each entry point no-ops when
|
|
6
|
+
# +Riffer.config.experimental_history_healing+ is off.
|
|
18
7
|
module Riffer::Agent::Session::Repair
|
|
19
|
-
|
|
20
|
-
|
|
8
|
+
extend self
|
|
9
|
+
|
|
10
|
+
# Placeholder response filled in for an orphaned +tool_use+ on interrupt.
|
|
21
11
|
ORPHAN_PLACEHOLDER = ->(_tool_call) {
|
|
22
12
|
Riffer::Tools::Response.error("Tool call interrupted before completion.", type: :interrupted)
|
|
23
13
|
} #: ^(Riffer::Messages::Assistant::ToolCall) -> Riffer::Tools::Response
|
|
24
14
|
|
|
25
|
-
# Fills
|
|
26
|
-
#
|
|
27
|
-
# inserted immediately after its parent assistant message. Returns
|
|
28
|
-
# +[new_messages, filled_call_ids]+; +filled_call_ids+ is empty when
|
|
29
|
-
# there are no orphans.
|
|
30
|
-
#
|
|
31
|
-
# No-op when +Riffer.config.experimental_history_healing+ is off:
|
|
32
|
-
# returns +[messages, []]+ with the same array reference.
|
|
33
|
-
#
|
|
15
|
+
# Fills each orphaned +tool_use+ in +messages+ with an +ORPHAN_PLACEHOLDER+
|
|
16
|
+
# result inserted after its parent. Returns +[new_messages, filled_call_ids]+.
|
|
34
17
|
#--
|
|
35
18
|
#: (Array[Riffer::Messages::Base]) -> [Array[Riffer::Messages::Base], Array[String]]
|
|
36
|
-
def
|
|
19
|
+
def fill_orphans(messages)
|
|
37
20
|
return [messages, []] unless Riffer.config.experimental_history_healing
|
|
38
21
|
|
|
39
22
|
result_ids = messages.filter_map { |m| m.tool_call_id if m.is_a?(Riffer::Messages::Tool) }
|
|
@@ -62,22 +45,13 @@ module Riffer::Agent::Session::Repair
|
|
|
62
45
|
[new_messages, filled]
|
|
63
46
|
end
|
|
64
47
|
|
|
65
|
-
# Prunes a seeded message array
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
# Pending tool_calls on the resume boundary — the last assistant whose
|
|
71
|
-
# tail is purely Tool results (or empty) — are preserved. They get
|
|
72
|
-
# swept up by +execute_pending_tool_calls+ at the start of the next
|
|
73
|
-
# generate/stream call.
|
|
74
|
-
#
|
|
75
|
-
# No-op when +Riffer.config.experimental_history_healing+ is off:
|
|
76
|
-
# returns +messages+ unchanged.
|
|
77
|
-
#
|
|
48
|
+
# Prunes a seeded message array to the invariant — dropping orphaned tool
|
|
49
|
+
# exchanges and parentless Tool messages, but preserving the pending
|
|
50
|
+
# tool_calls on the resume boundary (the last assistant) for
|
|
51
|
+
# +execute_pending_tool_calls+. Returns a new array.
|
|
78
52
|
#--
|
|
79
53
|
#: (Array[Riffer::Messages::Base]) -> Array[Riffer::Messages::Base]
|
|
80
|
-
def
|
|
54
|
+
def prune_orphans(messages)
|
|
81
55
|
return messages unless Riffer.config.experimental_history_healing
|
|
82
56
|
|
|
83
57
|
resume_boundary = (messages.length - 1).downto(0).find { |idx|
|
data/lib/riffer/agent/session.rb
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# Access via +agent.session+. Sessions are constructed by +Riffer::Agent+
|
|
9
|
-
# and live for the lifetime of the agent.
|
|
4
|
+
# Owns the conversation handle for an agent: the message array, the
|
|
5
|
+
# +on_message+ callbacks, and the +tool_use+ ↔ +tool_result+ invariant that
|
|
6
|
+
# keeps tool calls and their results consistent.
|
|
10
7
|
#
|
|
11
8
|
# agent.session.add(msg) # append + fire callbacks
|
|
12
9
|
# agent.session.set([msg1, msg2]) # bulk replace (silent)
|
|
@@ -31,12 +28,6 @@ class Riffer::Agent::Session
|
|
|
31
28
|
end
|
|
32
29
|
|
|
33
30
|
# Registers a callback invoked once per message appended via +#add+.
|
|
34
|
-
#
|
|
35
|
-
# Callbacks do NOT fire for +#set+, +#unset+, +#remove+, or +#update+.
|
|
36
|
-
# Returns +self+ to allow chaining.
|
|
37
|
-
#
|
|
38
|
-
# Raises Riffer::ArgumentError if no block is given.
|
|
39
|
-
#
|
|
40
31
|
#--
|
|
41
32
|
#: () { (Riffer::Messages::Base) -> void } -> self
|
|
42
33
|
def on_message(&block)
|
|
@@ -45,13 +36,9 @@ class Riffer::Agent::Session
|
|
|
45
36
|
self
|
|
46
37
|
end
|
|
47
38
|
|
|
48
|
-
# Appends +message+ and fires every registered callback once with it.
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
# non-inference inputs like user messages, which subscribers don't
|
|
52
|
-
# expect to observe through the callback channel. Inference-produced
|
|
53
|
-
# messages (Assistant, Tool) always go through +add+ without +silent+.
|
|
54
|
-
#
|
|
39
|
+
# Appends +message+ and fires every registered callback once with it. Pass
|
|
40
|
+
# +silent: true+ to skip callbacks — used for non-inference inputs like user
|
|
41
|
+
# messages that subscribers don't expect on the callback channel.
|
|
55
42
|
#--
|
|
56
43
|
#: (Riffer::Messages::Base, ?silent: bool) -> Riffer::Messages::Base
|
|
57
44
|
def add(message, silent: false)
|
|
@@ -60,13 +47,7 @@ class Riffer::Agent::Session
|
|
|
60
47
|
message
|
|
61
48
|
end
|
|
62
49
|
|
|
63
|
-
# Replaces the message history wholesale
|
|
64
|
-
# callbacks; registered callbacks persist across the swap.
|
|
65
|
-
#
|
|
66
|
-
# Used for seeding, guardrail rewrites, and history healing — cases
|
|
67
|
-
# where firing callbacks would double-emit messages that subscribers
|
|
68
|
-
# have already observed (or never produced).
|
|
69
|
-
#
|
|
50
|
+
# Replaces the message history wholesale
|
|
70
51
|
#--
|
|
71
52
|
#: (Array[Riffer::Messages::Base]) -> self
|
|
72
53
|
def set(messages)
|
|
@@ -74,9 +55,7 @@ class Riffer::Agent::Session
|
|
|
74
55
|
self
|
|
75
56
|
end
|
|
76
57
|
|
|
77
|
-
# Clears the session.
|
|
78
|
-
# callbacks persist.
|
|
79
|
-
#
|
|
58
|
+
# Clears the session.
|
|
80
59
|
#--
|
|
81
60
|
#: () -> self
|
|
82
61
|
def unset
|
|
@@ -84,18 +63,10 @@ class Riffer::Agent::Session
|
|
|
84
63
|
self
|
|
85
64
|
end
|
|
86
65
|
|
|
87
|
-
# Removes a message by id
|
|
88
|
-
#
|
|
89
|
-
# +
|
|
90
|
-
#
|
|
91
|
-
#
|
|
92
|
-
# Raises Riffer::ArgumentError when called on a +Riffer::Messages::Tool+
|
|
93
|
-
# message — that would orphan the parent's +tool_use+. Use
|
|
94
|
-
# +#update+ to rewrite a tool result instead.
|
|
95
|
-
#
|
|
96
|
-
# Returns the removed message, or +nil+ when no message has the given id
|
|
97
|
-
# (idempotent).
|
|
98
|
-
#
|
|
66
|
+
# Removes a message by id, cascading to drop the +Tool+ results of a removed
|
|
67
|
+
# assistant's +tool_calls+ so the +tool_use+ ↔ +tool_result+ invariant holds.
|
|
68
|
+
# Raises on a +Tool+ message — that would orphan its parent; use +#update+
|
|
69
|
+
# instead. Returns +nil+ if no message matches.
|
|
99
70
|
#--
|
|
100
71
|
#: (id: String) -> Riffer::Messages::Base?
|
|
101
72
|
def remove(id:)
|
|
@@ -118,19 +89,10 @@ class Riffer::Agent::Session
|
|
|
118
89
|
target
|
|
119
90
|
end
|
|
120
91
|
|
|
121
|
-
# Partial in-place update
|
|
122
|
-
#
|
|
123
|
-
#
|
|
124
|
-
#
|
|
125
|
-
#
|
|
126
|
-
# When the target is an assistant message and the update drops one or more
|
|
127
|
-
# entries from +tool_calls+, every +Riffer::Messages::Tool+ result whose
|
|
128
|
-
# +tool_call_id+ matches a dropped call is removed atomically — keeping the
|
|
129
|
-
# +tool_use+ ↔ +tool_result+ invariant intact.
|
|
130
|
-
#
|
|
131
|
-
# Raises Riffer::ArgumentError when neither or both lookup keys are
|
|
132
|
-
# provided, or when no message matches.
|
|
133
|
-
#
|
|
92
|
+
# Partial in-place update: looks up a message by +id:+ or +tool_call_id:+
|
|
93
|
+
# (exactly one), overlays +attrs+ onto a same-type replacement, and swaps it
|
|
94
|
+
# in. Dropping +tool_calls+ from an assistant cascades to remove their +Tool+
|
|
95
|
+
# results, preserving the invariant. Raises on neither/both keys or no match.
|
|
134
96
|
#--
|
|
135
97
|
#: (?id: String?, ?tool_call_id: String?, **untyped) -> Riffer::Messages::Base
|
|
136
98
|
def update(id: nil, tool_call_id: nil, **attrs)
|
|
@@ -155,12 +117,9 @@ class Riffer::Agent::Session
|
|
|
155
117
|
replacement
|
|
156
118
|
end
|
|
157
119
|
|
|
158
|
-
# Returns the call_ids of every +tool_call+
|
|
159
|
-
#
|
|
160
|
-
#
|
|
161
|
-
# Zero-cost validation hook for callers that want to check the
|
|
162
|
-
# +tool_use+ ↔ +tool_result+ invariant before mutating or persisting.
|
|
163
|
-
#
|
|
120
|
+
# Returns the call_ids of every +tool_call+ with no matching
|
|
121
|
+
# +Riffer::Messages::Tool+ result anywhere in history — a hook for checking
|
|
122
|
+
# the +tool_use+ ↔ +tool_result+ invariant before mutating or persisting.
|
|
164
123
|
#--
|
|
165
124
|
#: () -> Array[String]
|
|
166
125
|
def orphaned_tool_call_ids
|
|
@@ -171,10 +130,8 @@ class Riffer::Agent::Session
|
|
|
171
130
|
}
|
|
172
131
|
end
|
|
173
132
|
|
|
174
|
-
# Returns +[
|
|
175
|
-
#
|
|
176
|
-
# element is an empty array.
|
|
177
|
-
#
|
|
133
|
+
# Returns +[last_assistant, pending_tool_calls]+; the second element is empty
|
|
134
|
+
# when there's no assistant message or no pending calls.
|
|
178
135
|
#--
|
|
179
136
|
#: () -> [Riffer::Messages::Assistant?, Array[Riffer::Messages::Assistant::ToolCall]]
|
|
180
137
|
def pending_tool_calls
|
|
@@ -191,6 +148,7 @@ class Riffer::Agent::Session
|
|
|
191
148
|
[assistant, assistant.tool_calls.reject { |tc| executed_ids.include?(tc.call_id) }]
|
|
192
149
|
end
|
|
193
150
|
|
|
151
|
+
# Yields each message in order, or returns an Enumerator without a block.
|
|
194
152
|
#--
|
|
195
153
|
#: () -> Enumerator[Riffer::Messages::Base, self]
|
|
196
154
|
#: () { (Riffer::Messages::Base) -> void } -> untyped
|
|
@@ -199,10 +157,8 @@ class Riffer::Agent::Session
|
|
|
199
157
|
@messages.each(&block)
|
|
200
158
|
end
|
|
201
159
|
|
|
202
|
-
# The number of LLM steps completed
|
|
203
|
-
# count of assistant messages. Used by the agent loop to enforce
|
|
160
|
+
# The number of LLM steps completed, used by the agent loop to enforce
|
|
204
161
|
# +max_steps+ on resume.
|
|
205
|
-
#
|
|
206
162
|
#--
|
|
207
163
|
#: () -> Integer
|
|
208
164
|
def steps
|
|
@@ -223,6 +179,7 @@ class Riffer::Agent::Session
|
|
|
223
179
|
|
|
224
180
|
private
|
|
225
181
|
|
|
182
|
+
#--
|
|
226
183
|
#: (Riffer::Messages::Base, Riffer::Messages::Base) -> void
|
|
227
184
|
def cascade_dropped_tool_calls(old, replacement)
|
|
228
185
|
return unless old.is_a?(Riffer::Messages::Assistant)
|
|
@@ -234,6 +191,7 @@ class Riffer::Agent::Session
|
|
|
234
191
|
@messages.reject! { |m| m.is_a?(Riffer::Messages::Tool) && removed_ids.include?(m.tool_call_id) }
|
|
235
192
|
end
|
|
236
193
|
|
|
194
|
+
#--
|
|
237
195
|
#: (Riffer::Messages::Base, Hash[Symbol, untyped]) -> Riffer::Messages::Base
|
|
238
196
|
def rebuild_message(old, attrs)
|
|
239
197
|
case old
|
|
@@ -2,19 +2,11 @@
|
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
4
|
# Wraps the result of structured output parsing and validation.
|
|
5
|
-
#
|
|
6
|
-
# On success, +object+ contains the validated Hash and +error+ is nil.
|
|
7
|
-
# On failure, +error+ contains the error message and +object+ is nil.
|
|
8
|
-
#
|
|
9
|
-
# result = structured_output.parse_and_validate(json_string)
|
|
10
|
-
# if result.success?
|
|
11
|
-
# result.object #=> {sentiment: "positive", score: 0.9}
|
|
12
|
-
# else
|
|
13
|
-
# result.error #=> "JSON parse error: ..."
|
|
14
|
-
# end
|
|
15
|
-
#
|
|
16
5
|
class Riffer::Agent::StructuredOutput::Result
|
|
6
|
+
# The validated object, or +nil+ on failure.
|
|
17
7
|
attr_reader :object #: Hash[Symbol, untyped]?
|
|
8
|
+
|
|
9
|
+
# The error message, or +nil+ on success.
|
|
18
10
|
attr_reader :error #: String?
|
|
19
11
|
|
|
20
12
|
#--
|
|
@@ -3,16 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
require "json"
|
|
5
5
|
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# params = Riffer::Params.new
|
|
10
|
-
# params.required(:sentiment, String)
|
|
11
|
-
# so = Riffer::Agent::StructuredOutput.new(params)
|
|
12
|
-
# result = so.parse_and_validate('{"sentiment":"positive","score":0.9}')
|
|
13
|
-
# result.object #=> {sentiment: "positive", score: 0.9}
|
|
14
|
-
#
|
|
6
|
+
# Parses and validates structured JSON responses against a Riffer::Params
|
|
7
|
+
# schema.
|
|
15
8
|
class Riffer::Agent::StructuredOutput
|
|
9
|
+
# The schema parameters.
|
|
16
10
|
attr_reader :params #: Riffer::Params
|
|
17
11
|
|
|
18
12
|
#--
|
|
@@ -29,10 +23,8 @@ class Riffer::Agent::StructuredOutput
|
|
|
29
23
|
@params.to_json_schema(strict: strict)
|
|
30
24
|
end
|
|
31
25
|
|
|
32
|
-
# Parses a JSON string and validates it against the schema
|
|
33
|
-
#
|
|
34
|
-
# Returns a Result with the validated object on success, or an error message on failure.
|
|
35
|
-
#
|
|
26
|
+
# Parses a JSON string and validates it against the schema, returning a
|
|
27
|
+
# Result carrying either the validated object or an error message.
|
|
36
28
|
#--
|
|
37
29
|
#: (String) -> Riffer::Agent::StructuredOutput::Result
|
|
38
30
|
def parse_and_validate(json_string)
|