riffer 0.47.2 → 0.49.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/.claude/rules/comments.md +2 -4
- data/.claude/rules/rbs-inline.md +2 -12
- data/.release-please-manifest.json +1 -1
- data/.rubocop.yml +5 -0
- data/CHANGELOG.md +42 -0
- data/docs/AGENTS.md +39 -7
- data/docs/AGENT_LIFECYCLE.md +14 -16
- data/docs/CONFIGURATION.md +23 -34
- data/docs/EVALS.md +2 -1
- data/docs/MCP.md +0 -4
- data/docs/MESSAGES.md +85 -17
- data/docs/STREAM_EVENTS.md +8 -4
- data/docs/TOOL_ADVANCED.md +1 -3
- data/docs/TRACING.md +2 -2
- data/docs/providers/AMAZON_BEDROCK.md +32 -1
- data/docs/providers/CUSTOM_PROVIDERS.md +56 -4
- data/docs/providers/GEMINI.md +1 -1
- data/docs/providers/MOCK_PROVIDER.md +17 -0
- data/docs/providers/OPENROUTER.md +18 -1
- data/docs-site/build.rb +0 -6
- data/docs-site/check.rb +1 -5
- data/lib/riffer/agent/config.rb +27 -44
- data/lib/riffer/agent/context.rb +2 -26
- data/lib/riffer/agent/outcome.rb +0 -20
- data/lib/riffer/agent/response.rb +4 -35
- data/lib/riffer/agent/run.rb +32 -48
- data/lib/riffer/agent/serializer.rb +10 -39
- data/lib/riffer/agent/session/repair.rb +3 -15
- data/lib/riffer/agent/session.rb +26 -38
- data/lib/riffer/agent/structured_output/result.rb +0 -8
- data/lib/riffer/agent/structured_output.rb +0 -7
- data/lib/riffer/agent.rb +31 -127
- data/lib/riffer/config/amazon_bedrock.rb +30 -0
- data/lib/riffer/config/anthropic.rb +21 -0
- data/lib/riffer/config/azure_open_ai.rb +30 -0
- data/lib/riffer/config/evals.rb +18 -0
- data/lib/riffer/config/files.rb +61 -0
- data/lib/riffer/config/gemini.rb +21 -0
- data/lib/riffer/config/mcp.rb +31 -0
- data/lib/riffer/config/open_ai.rb +30 -0
- data/lib/riffer/config/open_router.rb +21 -0
- data/lib/riffer/config/pricing/rates.rb +36 -0
- data/lib/riffer/config/pricing.rb +64 -0
- data/lib/riffer/config/skills.rb +38 -0
- data/lib/riffer/config/tracing.rb +43 -0
- data/lib/riffer/config.rb +3 -362
- data/lib/riffer/evals/evaluator.rb +22 -23
- data/lib/riffer/evals/evaluator_runner.rb +0 -15
- data/lib/riffer/evals/judge.rb +9 -11
- data/lib/riffer/evals/result.rb +1 -11
- data/lib/riffer/evals/run_result.rb +0 -12
- data/lib/riffer/evals/scenario_result.rb +0 -19
- data/lib/riffer/files/downloader.rb +2 -3
- data/lib/riffer/files/resolver.rb +5 -10
- data/lib/riffer/guardrail.rb +2 -22
- data/lib/riffer/guardrails/modification.rb +0 -8
- data/lib/riffer/guardrails/result.rb +0 -17
- data/lib/riffer/guardrails/runner.rb +2 -11
- data/lib/riffer/guardrails/tripwire.rb +0 -8
- data/lib/riffer/guardrails.rb +0 -2
- data/lib/riffer/helpers/boolean.rb +0 -4
- data/lib/riffer/helpers/call_or_value.rb +0 -3
- data/lib/riffer/helpers/deep_dup.rb +37 -0
- data/lib/riffer/helpers/dependencies.rb +0 -4
- data/lib/riffer/helpers/identifier.rb +3 -12
- data/lib/riffer/helpers/validate.rb +42 -0
- data/lib/riffer/mcp/authenticated_tool.rb +4 -12
- data/lib/riffer/mcp/client.rb +0 -7
- data/lib/riffer/mcp/manifest.rb +3 -7
- data/lib/riffer/mcp/registration.rb +0 -10
- data/lib/riffer/mcp/registry.rb +0 -9
- data/lib/riffer/mcp/search_tool.rb +0 -4
- data/lib/riffer/mcp/tool.rb +1 -4
- data/lib/riffer/mcp/tool_factory.rb +3 -6
- data/lib/riffer/mcp.rb +2 -23
- data/lib/riffer/messages/assistant/reasoning_part.rb +73 -0
- data/lib/riffer/messages/assistant/tool_call.rb +55 -0
- data/lib/riffer/messages/assistant.rb +43 -15
- data/lib/riffer/messages/base.rb +5 -33
- data/lib/riffer/messages/system.rb +8 -1
- data/lib/riffer/messages/tool.rb +15 -13
- data/lib/riffer/messages/{file_part.rb → user/file_part.rb} +16 -40
- data/lib/riffer/messages/user.rb +11 -4
- data/lib/riffer/params/boolean.rb +1 -5
- data/lib/riffer/params/param.rb +15 -31
- data/lib/riffer/params.rb +15 -39
- data/lib/riffer/providers/amazon_bedrock.rb +104 -44
- data/lib/riffer/providers/anthropic.rb +11 -26
- data/lib/riffer/providers/azure_open_ai.rb +3 -8
- data/lib/riffer/providers/base.rb +30 -32
- data/lib/riffer/providers/finish_reason.rb +0 -6
- data/lib/riffer/providers/gemini/client.rb +4 -17
- data/lib/riffer/providers/gemini.rb +6 -12
- data/lib/riffer/providers/mock.rb +18 -27
- data/lib/riffer/providers/open_ai.rb +12 -21
- data/lib/riffer/providers/open_router.rb +109 -33
- data/lib/riffer/providers/repository.rb +2 -14
- data/lib/riffer/providers/token_usage.rb +19 -12
- data/lib/riffer/registrable.rb +11 -45
- data/lib/riffer/runner/fibers.rb +1 -6
- data/lib/riffer/runner/sequential.rb +0 -1
- data/lib/riffer/runner/threaded.rb +0 -3
- data/lib/riffer/runner.rb +0 -3
- data/lib/riffer/skills/activate_tool.rb +0 -3
- data/lib/riffer/skills/adapter.rb +0 -8
- data/lib/riffer/skills/backend.rb +2 -7
- data/lib/riffer/skills/config.rb +13 -17
- data/lib/riffer/skills/context.rb +0 -29
- data/lib/riffer/skills/filesystem_backend.rb +0 -7
- data/lib/riffer/skills/frontmatter.rb +2 -16
- data/lib/riffer/skills/markdown_adapter.rb +3 -6
- data/lib/riffer/skills/xml_adapter.rb +0 -3
- data/lib/riffer/stream_events/base.rb +0 -3
- data/lib/riffer/stream_events/finish_reason_done.rb +1 -6
- data/lib/riffer/stream_events/guardrail_modification.rb +0 -10
- data/lib/riffer/stream_events/guardrail_tripwire.rb +0 -10
- data/lib/riffer/stream_events/interrupt.rb +2 -12
- data/lib/riffer/stream_events/reasoning_delta.rb +0 -3
- data/lib/riffer/stream_events/reasoning_done.rb +6 -8
- data/lib/riffer/stream_events/skill_activation.rb +0 -3
- data/lib/riffer/stream_events/text_delta.rb +0 -2
- data/lib/riffer/stream_events/text_done.rb +0 -2
- data/lib/riffer/stream_events/token_usage_done.rb +0 -2
- data/lib/riffer/stream_events/tool_call_delta.rb +1 -5
- data/lib/riffer/stream_events/tool_call_done.rb +0 -5
- data/lib/riffer/stream_events/web_search_done.rb +0 -3
- data/lib/riffer/stream_events/web_search_status.rb +1 -5
- data/lib/riffer/testing/minitest.rb +4 -5
- data/lib/riffer/testing.rb +5 -38
- data/lib/riffer/tool.rb +2 -28
- data/lib/riffer/tools/response.rb +3 -32
- data/lib/riffer/tools/runtime/fibers.rb +0 -6
- data/lib/riffer/tools/runtime/inline.rb +0 -1
- data/lib/riffer/tools/runtime/threaded.rb +0 -6
- data/lib/riffer/tools/runtime.rb +8 -30
- data/lib/riffer/tools/toolable.rb +0 -37
- data/lib/riffer/tracing/capture.rb +5 -9
- data/lib/riffer/tracing/no_op.rb +0 -7
- data/lib/riffer/tracing/otel.rb +7 -16
- data/lib/riffer/tracing/stream_recorder.rb +0 -7
- data/lib/riffer/tracing.rb +4 -27
- data/lib/riffer/version.rb +1 -1
- data/lib/riffer.rb +2 -30
- data/sig/generated/riffer/agent/config.rbs +24 -46
- data/sig/generated/riffer/agent/context.rbs +2 -26
- data/sig/generated/riffer/agent/outcome.rbs +0 -20
- data/sig/generated/riffer/agent/response.rbs +4 -27
- data/sig/generated/riffer/agent/run.rbs +12 -31
- data/sig/generated/riffer/agent/serializer.rbs +2 -27
- data/sig/generated/riffer/agent/session/repair.rbs +2 -10
- data/sig/generated/riffer/agent/session.rbs +10 -36
- data/sig/generated/riffer/agent/structured_output/result.rbs +0 -7
- data/sig/generated/riffer/agent/structured_output.rbs +0 -7
- data/sig/generated/riffer/agent.rbs +25 -125
- data/sig/generated/riffer/config/amazon_bedrock.rbs +21 -0
- data/sig/generated/riffer/config/anthropic.rbs +15 -0
- data/sig/generated/riffer/config/azure_open_ai.rbs +21 -0
- data/sig/generated/riffer/config/evals.rbs +13 -0
- data/sig/generated/riffer/config/files.rbs +43 -0
- data/sig/generated/riffer/config/gemini.rbs +15 -0
- data/sig/generated/riffer/config/mcp.rbs +19 -0
- data/sig/generated/riffer/config/open_ai.rbs +21 -0
- data/sig/generated/riffer/config/open_router.rbs +15 -0
- data/sig/generated/riffer/config/pricing/rates.rbs +19 -0
- data/sig/generated/riffer/config/pricing.rbs +31 -0
- data/sig/generated/riffer/config/skills.rbs +19 -0
- data/sig/generated/riffer/config/tracing.rbs +25 -0
- data/sig/generated/riffer/config.rbs +2 -307
- data/sig/generated/riffer/evals/evaluator.rbs +12 -21
- data/sig/generated/riffer/evals/evaluator_runner.rbs +0 -14
- data/sig/generated/riffer/evals/judge.rbs +4 -8
- data/sig/generated/riffer/evals/result.rbs +1 -11
- data/sig/generated/riffer/evals/run_result.rbs +0 -12
- data/sig/generated/riffer/evals/scenario_result.rbs +0 -14
- data/sig/generated/riffer/files/resolver.rbs +6 -13
- data/sig/generated/riffer/guardrail.rbs +2 -22
- data/sig/generated/riffer/guardrails/modification.rbs +0 -6
- data/sig/generated/riffer/guardrails/result.rbs +0 -15
- data/sig/generated/riffer/guardrails/runner.rbs +0 -11
- data/sig/generated/riffer/guardrails/tripwire.rbs +0 -8
- data/sig/generated/riffer/guardrails.rbs +0 -2
- data/sig/generated/riffer/helpers/boolean.rbs +0 -4
- data/sig/generated/riffer/helpers/call_or_value.rbs +0 -3
- data/sig/generated/riffer/helpers/deep_dup.rbs +13 -0
- data/sig/generated/riffer/helpers/dependencies.rbs +0 -4
- data/sig/generated/riffer/helpers/identifier.rbs +0 -12
- data/sig/generated/riffer/helpers/validate.rbs +21 -0
- data/sig/generated/riffer/mcp/authenticated_tool.rbs +0 -5
- data/sig/generated/riffer/mcp/client.rbs +0 -7
- data/sig/generated/riffer/mcp/manifest.rbs +3 -7
- data/sig/generated/riffer/mcp/registration.rbs +0 -10
- data/sig/generated/riffer/mcp/registry.rbs +0 -9
- data/sig/generated/riffer/mcp/search_tool.rbs +0 -4
- data/sig/generated/riffer/mcp/tool.rbs +0 -4
- data/sig/generated/riffer/mcp/tool_factory.rbs +0 -6
- data/sig/generated/riffer/mcp.rbs +2 -22
- data/sig/generated/riffer/messages/assistant/reasoning_part.rbs +45 -0
- data/sig/generated/riffer/messages/assistant/tool_call.rbs +34 -0
- data/sig/generated/riffer/messages/assistant.rbs +25 -31
- data/sig/generated/riffer/messages/base.rbs +0 -12
- data/sig/generated/riffer/messages/system.rbs +4 -1
- data/sig/generated/riffer/messages/tool.rbs +4 -10
- data/sig/generated/riffer/messages/user/file_part.rbs +76 -0
- data/sig/generated/riffer/messages/user.rbs +7 -5
- data/sig/generated/riffer/params/boolean.rbs +1 -4
- data/sig/generated/riffer/params/param.rbs +7 -31
- data/sig/generated/riffer/params.rbs +8 -38
- data/sig/generated/riffer/providers/amazon_bedrock.rbs +33 -29
- data/sig/generated/riffer/providers/anthropic.rbs +2 -12
- data/sig/generated/riffer/providers/azure_open_ai.rbs +0 -8
- data/sig/generated/riffer/providers/base.rbs +18 -34
- data/sig/generated/riffer/providers/finish_reason.rbs +0 -6
- data/sig/generated/riffer/providers/gemini/client.rbs +4 -17
- data/sig/generated/riffer/providers/gemini.rbs +4 -10
- data/sig/generated/riffer/providers/mock.rbs +6 -27
- data/sig/generated/riffer/providers/open_ai.rbs +6 -13
- data/sig/generated/riffer/providers/open_router.rbs +37 -18
- data/sig/generated/riffer/providers/repository.rbs +2 -14
- data/sig/generated/riffer/providers/token_usage.rbs +9 -12
- data/sig/generated/riffer/registrable.rbs +0 -45
- data/sig/generated/riffer/runner/fibers.rbs +0 -6
- data/sig/generated/riffer/runner/sequential.rbs +0 -1
- data/sig/generated/riffer/runner/threaded.rbs +0 -3
- data/sig/generated/riffer/runner.rbs +0 -3
- data/sig/generated/riffer/skills/activate_tool.rbs +0 -3
- data/sig/generated/riffer/skills/adapter.rbs +0 -8
- data/sig/generated/riffer/skills/backend.rbs +2 -7
- data/sig/generated/riffer/skills/config.rbs +6 -17
- data/sig/generated/riffer/skills/context.rbs +0 -29
- data/sig/generated/riffer/skills/filesystem_backend.rbs +0 -7
- data/sig/generated/riffer/skills/frontmatter.rbs +2 -16
- data/sig/generated/riffer/skills/markdown_adapter.rbs +0 -6
- data/sig/generated/riffer/skills/xml_adapter.rbs +0 -3
- data/sig/generated/riffer/stream_events/base.rbs +0 -3
- data/sig/generated/riffer/stream_events/finish_reason_done.rbs +1 -6
- data/sig/generated/riffer/stream_events/guardrail_modification.rbs +0 -10
- data/sig/generated/riffer/stream_events/guardrail_tripwire.rbs +0 -10
- data/sig/generated/riffer/stream_events/interrupt.rbs +2 -10
- data/sig/generated/riffer/stream_events/reasoning_delta.rbs +0 -3
- data/sig/generated/riffer/stream_events/reasoning_done.rbs +4 -6
- data/sig/generated/riffer/stream_events/skill_activation.rbs +0 -3
- data/sig/generated/riffer/stream_events/text_delta.rbs +0 -2
- data/sig/generated/riffer/stream_events/text_done.rbs +0 -2
- data/sig/generated/riffer/stream_events/token_usage_done.rbs +0 -2
- data/sig/generated/riffer/stream_events/tool_call_delta.rbs +1 -5
- data/sig/generated/riffer/stream_events/tool_call_done.rbs +0 -5
- data/sig/generated/riffer/stream_events/web_search_done.rbs +0 -3
- data/sig/generated/riffer/stream_events/web_search_status.rbs +1 -5
- data/sig/generated/riffer/testing.rbs +0 -38
- data/sig/generated/riffer/tool.rbs +0 -27
- data/sig/generated/riffer/tools/response.rbs +3 -29
- data/sig/generated/riffer/tools/runtime/fibers.rbs +0 -5
- data/sig/generated/riffer/tools/runtime/inline.rbs +0 -1
- data/sig/generated/riffer/tools/runtime/threaded.rbs +0 -5
- data/sig/generated/riffer/tools/runtime.rbs +4 -26
- data/sig/generated/riffer/tools/toolable.rbs +0 -37
- data/sig/generated/riffer/tracing/capture.rbs +6 -9
- data/sig/generated/riffer/tracing/no_op.rbs +0 -7
- data/sig/generated/riffer/tracing/otel.rbs +7 -16
- data/sig/generated/riffer/tracing/stream_recorder.rbs +0 -2
- data/sig/generated/riffer/tracing.rbs +4 -23
- data/sig/generated/riffer.rbs +2 -29
- data/sig/manual/riffer/helpers/deep_dup.rbs +5 -0
- data/sig/manual/riffer/helpers/validate.rbs +5 -0
- metadata +39 -3
- data/sig/generated/riffer/messages/file_part.rbs +0 -101
|
@@ -1,22 +1,34 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Normalized token usage for an LLM API call. Buckets carry the same
|
|
5
|
-
# meaning for every provider.
|
|
6
4
|
class Riffer::Providers::TokenUsage
|
|
7
|
-
|
|
5
|
+
#--
|
|
6
|
+
#: ((Hash[Symbol, untyped] | Riffer::Providers::TokenUsage)) -> Riffer::Providers::TokenUsage
|
|
7
|
+
def self.from_hash(usage)
|
|
8
|
+
return usage if usage.is_a?(Riffer::Providers::TokenUsage)
|
|
9
|
+
|
|
10
|
+
new(
|
|
11
|
+
input_tokens: usage[:input_tokens],
|
|
12
|
+
output_tokens: usage[:output_tokens],
|
|
13
|
+
cache_write_tokens: usage[:cache_write_tokens],
|
|
14
|
+
cache_read_tokens: usage[:cache_read_tokens],
|
|
15
|
+
cost: usage[:cost],
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Normalized across providers: includes cache reads and writes.
|
|
8
20
|
attr_reader :input_tokens #: Integer # @dynamic input_tokens
|
|
9
21
|
|
|
10
|
-
#
|
|
22
|
+
# Includes reasoning/thinking tokens.
|
|
11
23
|
attr_reader :output_tokens #: Integer # @dynamic output_tokens
|
|
12
24
|
|
|
13
|
-
# Subset of +input_tokens
|
|
25
|
+
# Subset of +input_tokens+.
|
|
14
26
|
attr_reader :cache_write_tokens #: Integer? # @dynamic cache_write_tokens
|
|
15
27
|
|
|
16
|
-
# Subset of +input_tokens
|
|
28
|
+
# Subset of +input_tokens+.
|
|
17
29
|
attr_reader :cache_read_tokens #: Integer? # @dynamic cache_read_tokens
|
|
18
30
|
|
|
19
|
-
#
|
|
31
|
+
# For observability, not billing.
|
|
20
32
|
attr_reader :cost #: Float? # @dynamic cost
|
|
21
33
|
|
|
22
34
|
#--
|
|
@@ -29,16 +41,12 @@ class Riffer::Providers::TokenUsage
|
|
|
29
41
|
@cost = cost
|
|
30
42
|
end
|
|
31
43
|
|
|
32
|
-
# Returns the total number of tokens (input + output).
|
|
33
|
-
#
|
|
34
44
|
#--
|
|
35
45
|
#: () -> Integer
|
|
36
46
|
def total_tokens
|
|
37
47
|
input_tokens + output_tokens
|
|
38
48
|
end
|
|
39
49
|
|
|
40
|
-
# Combines two TokenUsage objects for cumulative tracking.
|
|
41
|
-
#
|
|
42
50
|
#--
|
|
43
51
|
#: (Riffer::Providers::TokenUsage) -> Riffer::Providers::TokenUsage
|
|
44
52
|
def +(other)
|
|
@@ -51,7 +59,6 @@ class Riffer::Providers::TokenUsage
|
|
|
51
59
|
)
|
|
52
60
|
end
|
|
53
61
|
|
|
54
|
-
# Converts the token usage to a hash; cache tokens and cost are omitted when nil.
|
|
55
62
|
#--
|
|
56
63
|
#: () -> Hash[Symbol, (Integer | Float)]
|
|
57
64
|
def to_h
|
data/lib/riffer/registrable.rb
CHANGED
|
@@ -1,57 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Registry of a class's direct subclasses, keyed by identifier. Extend it
|
|
5
|
-
# onto a base class to look up subclasses in constant time via +find+ and +all+.
|
|
6
|
-
# Subclasses join implicitly by inheriting; +register+ adds one explicitly, for
|
|
7
|
-
# ephemeral classes a test suite builds and tears down. Registration is not
|
|
8
|
-
# synchronized — register during boot or from a single-threaded test, before
|
|
9
|
-
# concurrent lookups begin.
|
|
10
|
-
#
|
|
11
|
-
# class Riffer::Tool
|
|
12
|
-
# extend Riffer::Registrable
|
|
13
|
-
# end
|
|
14
|
-
#
|
|
15
|
-
# Riffer::Tool.find("weather_tool") # => WeatherTool
|
|
16
|
-
#
|
|
17
4
|
# @rbs module-self Class
|
|
18
5
|
module Riffer::Registrable
|
|
19
6
|
# @rbs @identifier_registry: Hash[String, Class]?
|
|
20
7
|
# @rbs @explicit_registrations: Hash[String, Class]?
|
|
21
8
|
|
|
22
|
-
# Finds a registered subclass by identifier, or +nil+ when none matches.
|
|
23
|
-
# Implicit registration covers only *named direct* subclasses: grandchildren
|
|
24
|
-
# are not visible to a grandparent's +find+ (call +find+ on their direct
|
|
25
|
-
# parent instead), anonymous classes are never registered implicitly, and a
|
|
26
|
-
# subclass whose name no longer resolves back to it is dropped at the next
|
|
27
|
-
# registry rebuild. Duplicate identifiers raise
|
|
28
|
-
# Riffer::DuplicateIdentifierError at first lookup.
|
|
29
|
-
#
|
|
30
9
|
#--
|
|
31
10
|
#: (String | Symbol) -> Class?
|
|
32
11
|
def find(identifier)
|
|
33
12
|
identifier_registry[identifier.to_s]
|
|
34
13
|
end
|
|
35
14
|
|
|
36
|
-
# Returns all registered subclasses, implicit and explicit. Carries the same
|
|
37
|
-
# registration rules as +find+.
|
|
38
|
-
#
|
|
39
15
|
#--
|
|
40
16
|
#: () -> Array[Class]
|
|
41
17
|
def all
|
|
42
18
|
identifier_registry.values
|
|
43
19
|
end
|
|
44
20
|
|
|
45
|
-
# Registers a direct subclass under its +identifier+, whether or not it is
|
|
46
|
-
# named — unlike implicit registration, it survives a name that no longer
|
|
47
|
-
# resolves, so an ephemeral class stays findable until +unregister+. Prefer
|
|
48
|
-
# Riffer::Testing for ordinary test setup, which stubs and cleans up
|
|
49
|
-
# automatically.
|
|
50
|
-
#
|
|
51
|
-
# Raises Riffer::ArgumentError when the identifier is blank or the class is
|
|
52
|
-
# not a direct subclass, and Riffer::DuplicateIdentifierError when the
|
|
53
|
-
# identifier is already taken — including by this same class.
|
|
54
|
-
#
|
|
55
21
|
#--
|
|
56
22
|
#: (Class) -> void
|
|
57
23
|
def register(klass)
|
|
@@ -65,12 +31,12 @@ module Riffer::Registrable
|
|
|
65
31
|
existing = identifier_registry[key]
|
|
66
32
|
raise_duplicate_identifier!(key, existing, klass) if existing
|
|
67
33
|
|
|
34
|
+
# Not synchronized: register during boot or from a single-threaded test,
|
|
35
|
+
# before concurrent lookups begin.
|
|
68
36
|
explicit_registrations[key] = klass
|
|
69
37
|
@identifier_registry = nil
|
|
70
38
|
end
|
|
71
39
|
|
|
72
|
-
# Removes an explicit registration of +klass+, leaving implicit registrations
|
|
73
|
-
# untouched.
|
|
74
40
|
#--
|
|
75
41
|
#: (Class) -> void
|
|
76
42
|
def unregister(klass)
|
|
@@ -83,13 +49,12 @@ module Riffer::Registrable
|
|
|
83
49
|
|
|
84
50
|
private
|
|
85
51
|
|
|
86
|
-
# Ruby invokes +inherited+ with +self+ bound to the direct superclass — the
|
|
87
|
-
# only registry the new subclass joins — so busting self's memo is exactly
|
|
88
|
-
# sufficient.
|
|
89
52
|
#--
|
|
90
53
|
#: (Class) -> void
|
|
91
54
|
def inherited(subclass)
|
|
92
55
|
super
|
|
56
|
+
# +self+ is the direct superclass — the only registry the new subclass
|
|
57
|
+
# joins — so busting self's memo is exactly sufficient.
|
|
93
58
|
@identifier_registry = nil
|
|
94
59
|
end
|
|
95
60
|
|
|
@@ -108,6 +73,8 @@ module Riffer::Registrable
|
|
|
108
73
|
#--
|
|
109
74
|
#: () -> Hash[String, Class]
|
|
110
75
|
def build_identifier_registry
|
|
76
|
+
# Explicit entries skip +live?+ so an ephemeral class stays findable until
|
|
77
|
+
# +unregister+, even once its name no longer resolves.
|
|
111
78
|
subclasses.each_with_object(explicit_registrations.dup) do |subclass, acc|
|
|
112
79
|
next unless live?(subclass)
|
|
113
80
|
|
|
@@ -121,15 +88,14 @@ module Riffer::Registrable
|
|
|
121
88
|
end.freeze
|
|
122
89
|
end
|
|
123
90
|
|
|
124
|
-
# Class#subclasses keeps returning superseded generations of a reloaded or
|
|
125
|
-
# stubbed class, so a subclass counts only while its own name still resolves
|
|
126
|
-
# back to it. An anonymous class has no name to resolve and is skipped even
|
|
127
|
-
# with an explicit identifier — the MCP factory and serializer shells
|
|
128
|
-
# synthesize short-lived anonymous classes whose registration would flake
|
|
129
|
-
# with GC timing.
|
|
130
91
|
#--
|
|
131
92
|
#: (Class) -> bool
|
|
132
93
|
def live?(subclass)
|
|
94
|
+
# Class#subclasses keeps returning superseded generations of a reloaded or
|
|
95
|
+
# stubbed class, so a subclass counts only while its own name still
|
|
96
|
+
# resolves back to it. Anonymous classes are skipped even with an
|
|
97
|
+
# identifier: the MCP factory and serializer shells synthesize short-lived
|
|
98
|
+
# anonymous classes whose registration would flake with GC timing.
|
|
133
99
|
real_name = Riffer::Helpers::Identifier.real_name(subclass)
|
|
134
100
|
return false if real_name.nil?
|
|
135
101
|
|
data/lib/riffer/runner/fibers.rb
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Processes items concurrently using fibers via the +async+ gem.
|
|
5
|
-
# +max_concurrency+ caps simultaneous fibers via an <tt>Async::Semaphore</tt>.
|
|
6
|
-
# If multiple fibers raise, only the first exception is re-raised after all
|
|
7
|
-
# finish.
|
|
8
|
-
# Joins the current reactor task when one is already running, and otherwise
|
|
9
|
-
# starts its own.
|
|
10
4
|
class Riffer::Runner::Fibers < Riffer::Runner
|
|
11
5
|
# @rbs @max_concurrency: Integer?
|
|
12
6
|
|
|
@@ -35,6 +29,7 @@ class Riffer::Runner::Fibers < Riffer::Runner
|
|
|
35
29
|
barrier
|
|
36
30
|
end
|
|
37
31
|
|
|
32
|
+
# Sync joins the running reactor task if there is one, otherwise starts its own.
|
|
38
33
|
Sync do
|
|
39
34
|
items.each_with_index do |item, index|
|
|
40
35
|
parent.async do
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Processes items sequentially in the current thread — the default runner.
|
|
5
4
|
class Riffer::Runner::Sequential < Riffer::Runner
|
|
6
5
|
#--
|
|
7
6
|
#: (Array[untyped], context: Riffer::Agent::Context?) { (untyped) -> untyped } -> Array[untyped]
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Processes items concurrently using a thread pool of up to +max_concurrency+
|
|
5
|
-
# workers pulling from a shared queue, so a slow item doesn't block others. If
|
|
6
|
-
# multiple workers raise, only the first exception is re-raised after all finish.
|
|
7
4
|
class Riffer::Runner::Threaded < Riffer::Runner
|
|
8
5
|
# @rbs @max_concurrency: Integer
|
|
9
6
|
|
data/lib/riffer/runner.rb
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Generic concurrency primitive for batch execution. Subclasses implement
|
|
5
|
-
# +map+ to control how items are processed.
|
|
6
4
|
class Riffer::Runner
|
|
7
|
-
# Maps over items using the provided block.
|
|
8
5
|
#--
|
|
9
6
|
#: (Array[untyped], context: Riffer::Agent::Context?) { (untyped) -> untyped } -> Array[untyped]
|
|
10
7
|
def map(items, context:, &block)
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Tool the LLM calls to activate a skill and receive its instructions;
|
|
5
|
-
# registered automatically when an agent has skills configured.
|
|
6
4
|
class Riffer::Skills::ActivateTool < Riffer::Tool
|
|
7
5
|
identifier "skill_activate"
|
|
8
6
|
description "Activates a skill and returns its instructions. " \
|
|
@@ -13,7 +11,6 @@ class Riffer::Skills::ActivateTool < Riffer::Tool
|
|
|
13
11
|
required :name, String, description: "The skill name to activate"
|
|
14
12
|
end
|
|
15
13
|
|
|
16
|
-
# Activates a skill by name and returns its wrapped body, or a short pointer when the skill is already active.
|
|
17
14
|
#--
|
|
18
15
|
#: (context: Riffer::Agent::Context?, name: String) -> Riffer::Tools::Response
|
|
19
16
|
def call(context:, name:)
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Interface for skill adapters — provider-specific rendering of the
|
|
5
|
-
# available-skills section in the system prompt. Subclass and override
|
|
6
|
-
# +render_catalog+; the activation tool is exposed via +#skill_activate_tool+
|
|
7
|
-
# for the rendered output.
|
|
8
4
|
class Riffer::Skills::Adapter
|
|
9
|
-
# The activation tool class for this adapter.
|
|
10
5
|
attr_reader :skill_activate_tool #: singleton(Riffer::Tool) # @dynamic skill_activate_tool
|
|
11
6
|
|
|
12
7
|
#--
|
|
@@ -15,21 +10,18 @@ class Riffer::Skills::Adapter
|
|
|
15
10
|
@skill_activate_tool = skill_activate_tool
|
|
16
11
|
end
|
|
17
12
|
|
|
18
|
-
# Renders a skill catalog section for the system prompt.
|
|
19
13
|
#--
|
|
20
14
|
#: (Array[Riffer::Skills::Frontmatter]) -> String
|
|
21
15
|
def render_catalog(skills)
|
|
22
16
|
raise NotImplementedError, "#{self.class} must implement #render_catalog"
|
|
23
17
|
end
|
|
24
18
|
|
|
25
|
-
# Renders an activated skill body wrapped in identifying tags.
|
|
26
19
|
#--
|
|
27
20
|
#: (Riffer::Skills::Frontmatter, String) -> String
|
|
28
21
|
def render_activation(skill, body)
|
|
29
22
|
%(<skill_content name="#{skill.name}">\n#{body}\n</skill_content>)
|
|
30
23
|
end
|
|
31
24
|
|
|
32
|
-
# The behavioral instructions rendered alongside the catalog.
|
|
33
25
|
#--
|
|
34
26
|
#: () -> String
|
|
35
27
|
def catalog_instructions
|
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Interface for skill storage backends. Subclass and implement +list_skills+
|
|
5
|
-
# and +read_skill+ for custom storage (database, S3, etc.); use
|
|
6
|
-
# Riffer::Skills::Frontmatter.parse on raw SKILL.md content.
|
|
7
4
|
class Riffer::Skills::Backend
|
|
8
5
|
SKILL_FILENAME = "SKILL.md" #: String
|
|
9
6
|
|
|
10
7
|
def initialize = nil
|
|
11
8
|
|
|
12
|
-
# Returns frontmatter for all available skills; called once at the start of
|
|
13
|
-
# generate/stream.
|
|
14
9
|
#--
|
|
15
10
|
#: () -> Array[Riffer::Skills::Frontmatter]
|
|
16
11
|
def list_skills
|
|
17
12
|
raise NotImplementedError, "#{self.class} must implement #list_skills"
|
|
18
13
|
end
|
|
19
14
|
|
|
20
|
-
# Returns the
|
|
21
|
-
#
|
|
15
|
+
# Returns the SKILL.md body without frontmatter. Raises Riffer::ArgumentError
|
|
16
|
+
# if the skill is not found.
|
|
22
17
|
#--
|
|
23
18
|
#: (String) -> String
|
|
24
19
|
def read_skill(name)
|
data/lib/riffer/skills/config.rb
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Configuration object for the skills block DSL.
|
|
5
|
-
#
|
|
6
|
-
# skills do
|
|
7
|
-
# backend Riffer::Skills::FilesystemBackend.new(".skills")
|
|
8
|
-
# adapter Riffer::Skills::XmlAdapter
|
|
9
|
-
# activate ["code-review"]
|
|
10
|
-
# end
|
|
11
4
|
class Riffer::Skills::Config
|
|
12
5
|
# @rbs @backend: (Riffer::Skills::Backend | Proc)?
|
|
13
6
|
# @rbs @adapter: singleton(Riffer::Skills::Adapter)?
|
|
@@ -23,7 +16,6 @@ class Riffer::Skills::Config
|
|
|
23
16
|
@activate_tool = nil
|
|
24
17
|
end
|
|
25
18
|
|
|
26
|
-
# Gets or sets the skills backend (a Backend or a +context+-resolved Proc).
|
|
27
19
|
#--
|
|
28
20
|
#: (?(Riffer::Skills::Backend | Proc)?) -> (Riffer::Skills::Backend | Proc)?
|
|
29
21
|
def backend(value = nil)
|
|
@@ -32,8 +24,6 @@ class Riffer::Skills::Config
|
|
|
32
24
|
@backend = value
|
|
33
25
|
end
|
|
34
26
|
|
|
35
|
-
# Gets or sets a custom skill adapter class; defaults to the provider's
|
|
36
|
-
# preferred adapter.
|
|
37
27
|
#--
|
|
38
28
|
#: (?singleton(Riffer::Skills::Adapter)?) -> singleton(Riffer::Skills::Adapter)?
|
|
39
29
|
def adapter(value = nil)
|
|
@@ -42,9 +32,6 @@ class Riffer::Skills::Config
|
|
|
42
32
|
@adapter = value
|
|
43
33
|
end
|
|
44
34
|
|
|
45
|
-
# Gets or sets skill names to activate at startup (an array or a
|
|
46
|
-
# +context+-resolved Proc); activated skills' bodies are included in the
|
|
47
|
-
# system prompt without a tool call.
|
|
48
35
|
#--
|
|
49
36
|
#: (?(Array[String] | Proc)?) -> (Array[String] | Proc)?
|
|
50
37
|
def activate(value = nil)
|
|
@@ -53,13 +40,11 @@ class Riffer::Skills::Config
|
|
|
53
40
|
@activate = value
|
|
54
41
|
end
|
|
55
42
|
|
|
56
|
-
# Gets or sets the per-agent skill activation tool override, or +nil+ when
|
|
57
|
-
# unset — the global fallback to <tt>Riffer.config.skills.default_activate_tool</tt>
|
|
58
|
-
# is applied by the agent at resolution, not here. Raises Riffer::ArgumentError
|
|
59
|
-
# on an invalid value.
|
|
60
43
|
#--
|
|
61
44
|
#: (?singleton(Riffer::Tool)?) -> singleton(Riffer::Tool)?
|
|
62
45
|
def activate_tool(value = nil)
|
|
46
|
+
# No fallback to <tt>Riffer.config.skills.default_activate_tool</tt> here;
|
|
47
|
+
# the agent applies it at resolution.
|
|
63
48
|
return @activate_tool if value.nil?
|
|
64
49
|
unless value.is_a?(Class) && value < Riffer::Tool
|
|
65
50
|
raise Riffer::ArgumentError, "activate_tool must be a Riffer::Tool subclass"
|
|
@@ -67,4 +52,15 @@ class Riffer::Skills::Config
|
|
|
67
52
|
|
|
68
53
|
@activate_tool = value
|
|
69
54
|
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
#--
|
|
59
|
+
#: (Riffer::Skills::Config) -> void
|
|
60
|
+
def initialize_copy(source)
|
|
61
|
+
super
|
|
62
|
+
# A shallow copy would share the activation list, so activating a skill on
|
|
63
|
+
# either config would reach the other.
|
|
64
|
+
@activate = Riffer::Helpers::DeepDup.call(source.activate)
|
|
65
|
+
end
|
|
70
66
|
end
|
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Skills context for an agent generation cycle — coordinates discovery,
|
|
5
|
-
# activation, and prompt rendering, caching skill bodies to avoid redundant
|
|
6
|
-
# backend reads. Exposed to tools via <tt>context.skills</tt>.
|
|
7
4
|
class Riffer::Skills::Context
|
|
8
5
|
# @rbs @backend: Riffer::Skills::Backend
|
|
9
6
|
# @rbs @bodies: Hash[String, String]
|
|
10
7
|
# @rbs @activated: Array[String]
|
|
11
8
|
# @rbs @preactivated: Array[String]
|
|
12
9
|
|
|
13
|
-
# Skill catalog indexed by name.
|
|
14
10
|
attr_reader :skills #: Hash[String, Riffer::Skills::Frontmatter] # @dynamic skills
|
|
15
11
|
|
|
16
|
-
# The skill adapter used for this context.
|
|
17
12
|
attr_reader :adapter #: Riffer::Skills::Adapter # @dynamic adapter
|
|
18
13
|
|
|
19
|
-
# Optional callback invoked when a skill is first activated.
|
|
20
14
|
attr_accessor :on_activate #: (^(String) -> void)? # @dynamic on_activate, on_activate=
|
|
21
15
|
|
|
22
16
|
#--
|
|
@@ -30,10 +24,7 @@ class Riffer::Skills::Context
|
|
|
30
24
|
@preactivated = [] #: Array[String]
|
|
31
25
|
end
|
|
32
26
|
|
|
33
|
-
# Returns a skill's body without recording an activation.
|
|
34
|
-
#
|
|
35
27
|
# Raises Riffer::ArgumentError if the skill is not in the catalog.
|
|
36
|
-
#
|
|
37
28
|
#--
|
|
38
29
|
#: (String) -> String
|
|
39
30
|
def read(name)
|
|
@@ -42,10 +33,7 @@ class Riffer::Skills::Context
|
|
|
42
33
|
@bodies[name] ||= @backend.read_skill(name)
|
|
43
34
|
end
|
|
44
35
|
|
|
45
|
-
# Activates a skill by name. Returns the cached body on re-activation.
|
|
46
|
-
#
|
|
47
36
|
# Raises Riffer::ArgumentError if the skill is not in the catalog.
|
|
48
|
-
#
|
|
49
37
|
#--
|
|
50
38
|
#: (String) -> String
|
|
51
39
|
def activate(name)
|
|
@@ -57,11 +45,7 @@ class Riffer::Skills::Context
|
|
|
57
45
|
body
|
|
58
46
|
end
|
|
59
47
|
|
|
60
|
-
# Activates a skill and returns its body wrapped for injection as a user
|
|
61
|
-
# message.
|
|
62
|
-
#
|
|
63
48
|
# Raises Riffer::ArgumentError if the skill is not in the catalog.
|
|
64
|
-
#
|
|
65
49
|
#--
|
|
66
50
|
#: (String) -> String
|
|
67
51
|
def activation_prompt(name)
|
|
@@ -69,11 +53,7 @@ class Riffer::Skills::Context
|
|
|
69
53
|
@adapter.render_activation(skills.fetch(name), body)
|
|
70
54
|
end
|
|
71
55
|
|
|
72
|
-
# Activates a skill whose body renders in the system prompt rather than the
|
|
73
|
-
# conversation.
|
|
74
|
-
#
|
|
75
56
|
# Raises Riffer::ArgumentError if the skill is not in the catalog.
|
|
76
|
-
#
|
|
77
57
|
#--
|
|
78
58
|
#: (String) -> void
|
|
79
59
|
def preactivate(name)
|
|
@@ -81,10 +61,7 @@ class Riffer::Skills::Context
|
|
|
81
61
|
@preactivated << name unless @preactivated.include?(name)
|
|
82
62
|
end
|
|
83
63
|
|
|
84
|
-
# Clears a skill's activation so the next activation is treated as the first.
|
|
85
|
-
#
|
|
86
64
|
# Raises Riffer::ArgumentError if the skill is not in the catalog.
|
|
87
|
-
#
|
|
88
65
|
#--
|
|
89
66
|
#: (String) -> void
|
|
90
67
|
def deactivate(name)
|
|
@@ -94,30 +71,24 @@ class Riffer::Skills::Context
|
|
|
94
71
|
nil
|
|
95
72
|
end
|
|
96
73
|
|
|
97
|
-
# Returns whether a skill has been activated.
|
|
98
|
-
#
|
|
99
74
|
#--
|
|
100
75
|
#: (String) -> bool
|
|
101
76
|
def activated?(name)
|
|
102
77
|
@activated.include?(name)
|
|
103
78
|
end
|
|
104
79
|
|
|
105
|
-
# Returns whether a skill exists and may be activated by the model.
|
|
106
80
|
#--
|
|
107
81
|
#: (String) -> bool
|
|
108
82
|
def model_invocable?(name)
|
|
109
83
|
skills.key?(name) && !skills.fetch(name).disable_model_invocation
|
|
110
84
|
end
|
|
111
85
|
|
|
112
|
-
# Returns whether any skill is available for the model to activate.
|
|
113
86
|
#--
|
|
114
87
|
#: () -> bool
|
|
115
88
|
def activatable?
|
|
116
89
|
available_skills.any?
|
|
117
90
|
end
|
|
118
91
|
|
|
119
|
-
# Returns the complete skills section for the system prompt — the catalog plus
|
|
120
|
-
# any pre-activated skill bodies.
|
|
121
92
|
#--
|
|
122
93
|
#: () -> String
|
|
123
94
|
def system_prompt
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Built-in backend that reads skills from the filesystem. Scans configured
|
|
5
|
-
# directories for immediate child directories containing +SKILL.md+; directory
|
|
6
|
-
# names must match the skill +name+.
|
|
7
4
|
class Riffer::Skills::FilesystemBackend < Riffer::Skills::Backend
|
|
8
5
|
# @rbs @paths: Array[String]
|
|
9
6
|
# @rbs @skills_cache: Hash[String, String]?
|
|
@@ -16,8 +13,6 @@ class Riffer::Skills::FilesystemBackend < Riffer::Skills::Backend
|
|
|
16
13
|
@skills_cache = nil #: Hash[String, String]?
|
|
17
14
|
end
|
|
18
15
|
|
|
19
|
-
# Returns frontmatter for all discovered skills; on a name collision across
|
|
20
|
-
# paths, first-path-wins.
|
|
21
16
|
#--
|
|
22
17
|
#: () -> Array[Riffer::Skills::Frontmatter]
|
|
23
18
|
def list_skills
|
|
@@ -46,8 +41,6 @@ class Riffer::Skills::FilesystemBackend < Riffer::Skills::Backend
|
|
|
46
41
|
frontmatters
|
|
47
42
|
end
|
|
48
43
|
|
|
49
|
-
# Returns the full SKILL.md body (without frontmatter) for a skill. Raises
|
|
50
|
-
# Riffer::ArgumentError if the skill is not found.
|
|
51
44
|
#--
|
|
52
45
|
#: (String) -> String
|
|
53
46
|
def read_skill(name)
|
|
@@ -3,33 +3,21 @@
|
|
|
3
3
|
|
|
4
4
|
require "yaml"
|
|
5
5
|
|
|
6
|
-
# Immutable value object holding parsed SKILL.md YAML frontmatter. Required
|
|
7
|
-
# fields: +name+ and +description+; the optional +disable-model-invocation+
|
|
8
|
-
# flag is recognized, and any other unrecognized top-level keys are merged into
|
|
9
|
-
# +metadata+.
|
|
10
6
|
class Riffer::Skills::Frontmatter
|
|
11
7
|
NAME_PATTERN = /\A[a-z0-9]+(-[a-z0-9]+)*\z/ #: Regexp
|
|
12
8
|
MAX_NAME_LENGTH = 64 #: Integer
|
|
13
9
|
MAX_DESCRIPTION_LENGTH = 1024 #: Integer
|
|
14
10
|
|
|
15
|
-
# The skill name (1-64 chars, lowercase alphanumeric and hyphens).
|
|
16
11
|
attr_reader :name #: String # @dynamic name
|
|
17
12
|
|
|
18
|
-
# The skill description (1-1024 chars).
|
|
19
13
|
attr_reader :description #: String # @dynamic description
|
|
20
14
|
|
|
21
|
-
# Whether the skill opts out of model-driven activation. Hidden from the
|
|
22
|
-
# catalog and rejected at model activation; still reachable via programmatic
|
|
23
|
-
# activation.
|
|
24
15
|
attr_reader :disable_model_invocation #: bool # @dynamic disable_model_invocation
|
|
25
16
|
|
|
26
|
-
# Metadata from the spec's +metadata+ field plus any unrecognized top-level
|
|
27
|
-
# keys.
|
|
28
17
|
attr_reader :metadata #: Hash[Symbol, untyped] # @dynamic metadata
|
|
29
18
|
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
# if the frontmatter is invalid.
|
|
19
|
+
# Public so custom backends needn't reimplement parsing. Raises
|
|
20
|
+
# Riffer::ArgumentError if the frontmatter is invalid.
|
|
33
21
|
#--
|
|
34
22
|
#: (String) -> [Riffer::Skills::Frontmatter, String]
|
|
35
23
|
def self.parse(raw)
|
|
@@ -47,7 +35,6 @@ class Riffer::Skills::Frontmatter
|
|
|
47
35
|
]
|
|
48
36
|
end
|
|
49
37
|
|
|
50
|
-
# Parses only the frontmatter from a raw SKILL.md string, ignoring the body.
|
|
51
38
|
# Raises Riffer::ArgumentError if the frontmatter is invalid.
|
|
52
39
|
#--
|
|
53
40
|
#: (String) -> Riffer::Skills::Frontmatter
|
|
@@ -80,7 +67,6 @@ class Riffer::Skills::Frontmatter
|
|
|
80
67
|
private_class_method :split_frontmatter
|
|
81
68
|
|
|
82
69
|
# Raises Riffer::ArgumentError if +name+ or +description+ is invalid.
|
|
83
|
-
# +disable_model_invocation+ is treated as set only when literally +true+.
|
|
84
70
|
#--
|
|
85
71
|
#: (name: String, description: String, ?disable_model_invocation: bool, ?metadata: Hash[Symbol, untyped]) -> void
|
|
86
72
|
def initialize(name:, description:, disable_model_invocation: false, metadata: {})
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Default skill adapter — renders a skill catalog as Markdown for the system
|
|
5
|
-
# prompt.
|
|
6
4
|
class Riffer::Skills::MarkdownAdapter < Riffer::Skills::Adapter
|
|
7
|
-
# Renders a skill catalog as Markdown.
|
|
8
5
|
#--
|
|
9
6
|
#: (Array[Riffer::Skills::Frontmatter]) -> String
|
|
10
7
|
def render_catalog(skills)
|
|
@@ -21,12 +18,12 @@ class Riffer::Skills::MarkdownAdapter < Riffer::Skills::Adapter
|
|
|
21
18
|
|
|
22
19
|
private
|
|
23
20
|
|
|
24
|
-
# Collapses whitespace so a multi-line (block scalar) description stays within
|
|
25
|
-
# its `-` list item instead of breaking out to column 0, where continuation
|
|
26
|
-
# lines would read as top-level prompt text or fabricated catalog entries.
|
|
27
21
|
#--
|
|
28
22
|
#: (String) -> String
|
|
29
23
|
def single_line(description)
|
|
24
|
+
# A multi-line (block scalar) description must stay within its `-` list
|
|
25
|
+
# item; continuation lines at column 0 would read as top-level prompt text
|
|
26
|
+
# or fabricated catalog entries.
|
|
30
27
|
description.gsub(/\s+/, " ").strip
|
|
31
28
|
end
|
|
32
29
|
end
|
|
@@ -3,10 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
require "cgi/escape"
|
|
5
5
|
|
|
6
|
-
# Renders a skill catalog as XML for the system prompt, optimized for
|
|
7
|
-
# Anthropic/Claude.
|
|
8
6
|
class Riffer::Skills::XmlAdapter < Riffer::Skills::Adapter
|
|
9
|
-
# Renders a skill catalog as XML.
|
|
10
7
|
#--
|
|
11
8
|
#: (Array[Riffer::Skills::Frontmatter]) -> String
|
|
12
9
|
def render_catalog(skills)
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
# Base class for all streaming events. Subclasses must implement +to_h+.
|
|
5
4
|
class Riffer::StreamEvents::Base
|
|
6
|
-
# The message role (typically :assistant).
|
|
7
5
|
attr_reader :role #: Symbol # @dynamic role
|
|
8
6
|
|
|
9
7
|
#--
|
|
@@ -12,7 +10,6 @@ class Riffer::StreamEvents::Base
|
|
|
12
10
|
@role = role
|
|
13
11
|
end
|
|
14
12
|
|
|
15
|
-
# Converts the event to a hash.
|
|
16
13
|
#--
|
|
17
14
|
#: () -> Hash[Symbol, untyped]
|
|
18
15
|
def to_h
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
# stream; no ordering guarantee relative to TokenUsageDone.
|
|
4
|
+
# No ordering guarantee relative to TokenUsageDone.
|
|
6
5
|
class Riffer::StreamEvents::FinishReasonDone < Riffer::StreamEvents::Base
|
|
7
|
-
# The normalized finish reason (see <tt>Riffer::Providers::FinishReason::VALUES</tt>).
|
|
8
6
|
attr_reader :finish_reason #: Symbol # @dynamic finish_reason
|
|
9
7
|
|
|
10
|
-
# The provider's raw finish-reason value, when one exists on the wire.
|
|
11
8
|
attr_reader :raw_finish_reason #: String? # @dynamic raw_finish_reason
|
|
12
9
|
|
|
13
|
-
# Raises Riffer::ArgumentError when +finish_reason+ is outside the
|
|
14
|
-
# normalized vocabulary.
|
|
15
10
|
#--
|
|
16
11
|
#: (finish_reason: Symbol, ?raw_finish_reason: String?, ?role: Symbol) -> void
|
|
17
12
|
def initialize(finish_reason:, raw_finish_reason: nil, role: :assistant)
|