riffer-rig 0.5.0 → 0.7.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/CHANGELOG.md +58 -0
- data/README.md +77 -7
- data/exe/riffer +1 -1
- data/lib/riffer/rig/bundled/agents_md.rb +7 -0
- data/lib/riffer/rig/bundled/bash.rb +5 -0
- data/lib/riffer/rig/bundled/edit.rb +5 -0
- data/lib/riffer/rig/bundled/mcp.rb +9 -0
- data/lib/riffer/rig/bundled/read.rb +5 -0
- data/lib/riffer/rig/bundled/skills.rb +10 -0
- data/lib/riffer/rig/bundled/write.rb +5 -0
- data/lib/riffer/rig/bundled.rb +7 -0
- data/lib/riffer/rig/cli/flags.rb +77 -0
- data/lib/riffer/rig/cli.rb +70 -102
- data/lib/riffer/rig/command/context.rb +70 -0
- data/lib/riffer/rig/command.rb +29 -0
- data/lib/riffer/rig/commands/model.rb +54 -0
- data/lib/riffer/rig/commands/skill.rb +27 -0
- data/lib/riffer/rig/commands.rb +4 -0
- data/lib/riffer/rig/credentials/resolution.rb +16 -0
- data/lib/riffer/rig/credentials.rb +151 -60
- data/lib/riffer/rig/directories.rb +20 -0
- data/lib/riffer/rig/env/invalid.rb +13 -0
- data/lib/riffer/rig/env.rb +40 -0
- data/lib/riffer/rig/events/after_response.rb +25 -0
- data/lib/riffer/rig/events/after_tool_call.rb +31 -0
- data/lib/riffer/rig/events/before_prompt.rb +25 -0
- data/lib/riffer/rig/events/before_request.rb +25 -0
- data/lib/riffer/rig/events/before_tool_call.rb +28 -0
- data/lib/riffer/rig/events/command_output.rb +28 -0
- data/lib/riffer/rig/events/notify.rb +28 -0
- data/lib/riffer/rig/events/session_end.rb +25 -0
- data/lib/riffer/rig/events/session_start.rb +28 -0
- data/lib/riffer/rig/events/skill_activated.rb +25 -0
- data/lib/riffer/rig/events/turn_end.rb +33 -0
- data/lib/riffer/rig/events.rb +4 -0
- data/lib/riffer/rig/extension/failure.rb +16 -0
- data/lib/riffer/rig/extension.rb +16 -5
- data/lib/riffer/rig/hosts/mirror.rb +59 -0
- data/lib/riffer/rig/hosts/null.rb +36 -0
- data/lib/riffer/rig/loader.rb +163 -0
- data/lib/riffer/rig/mcp/declaration.rb +23 -0
- data/lib/riffer/rig/mcp/server.rb +16 -0
- data/lib/riffer/rig/mcp.rb +12 -0
- data/lib/riffer/rig/prompts/agents_md.rb +32 -0
- data/lib/riffer/rig/prompts.rb +4 -0
- data/lib/riffer/rig/provider_setup/field.rb +24 -0
- data/lib/riffer/rig/provider_setup.rb +84 -0
- data/lib/riffer/rig/registrar.rb +134 -7
- data/lib/riffer/rig/runtime/blocked.rb +13 -0
- data/lib/riffer/rig/runtime/cancel_flag.rb +27 -0
- data/lib/riffer/rig/runtime/hooks.rb +78 -0
- data/lib/riffer/rig/runtime/request_guardrail.rb +24 -0
- data/lib/riffer/rig/runtime/tool_runtime.rb +44 -0
- data/lib/riffer/rig/runtime.rb +582 -70
- data/lib/riffer/rig/settings/document.rb +28 -12
- data/lib/riffer/rig/settings/pricing.rb +16 -6
- data/lib/riffer/rig/settings.rb +108 -81
- data/lib/riffer/rig/skills/sources.rb +28 -0
- data/lib/riffer/rig/skills.rb +12 -0
- data/lib/riffer/rig/support/equatable.rb +21 -0
- data/lib/riffer/rig/{ui → terminal}/animator.rb +6 -13
- data/lib/riffer/rig/{ui → terminal}/banner.rb +17 -21
- data/lib/riffer/rig/{ui → terminal}/cursor.rb +4 -6
- data/lib/riffer/rig/terminal/host.rb +85 -0
- data/lib/riffer/rig/{ui → terminal}/palette.rb +1 -1
- data/lib/riffer/rig/{ui → terminal}/renderer.rb +121 -87
- data/lib/riffer/rig/{ui → terminal}/smoother.rb +15 -23
- data/lib/riffer/rig/{ui → terminal}/theme.rb +12 -14
- data/lib/riffer/rig/terminal.rb +207 -0
- data/lib/riffer/rig/tools/bash.rb +36 -13
- data/lib/riffer/rig/tools/edit.rb +3 -2
- data/lib/riffer/rig/tools/read.rb +3 -2
- data/lib/riffer/rig/tools/write.rb +3 -2
- data/lib/riffer/rig/version.rb +1 -1
- data/lib/riffer/rig.rb +10 -15
- data/sig/generated/riffer/rig/bundled/agents_md.rbs +5 -0
- data/sig/generated/riffer/rig/bundled/bash.rbs +5 -0
- data/sig/generated/riffer/rig/bundled/edit.rbs +5 -0
- data/sig/generated/riffer/rig/bundled/mcp.rbs +5 -0
- data/sig/generated/riffer/rig/bundled/read.rbs +5 -0
- data/sig/generated/riffer/rig/bundled/skills.rbs +5 -0
- data/sig/generated/riffer/rig/bundled/write.rbs +5 -0
- data/sig/generated/riffer/rig/bundled.rbs +5 -0
- data/sig/generated/riffer/rig/cli/flags.rbs +40 -0
- data/sig/generated/riffer/rig/cli.rbs +30 -27
- data/sig/generated/riffer/rig/command/context.rbs +50 -0
- data/sig/generated/riffer/rig/command.rbs +23 -0
- data/sig/generated/riffer/rig/commands/model.rbs +27 -0
- data/sig/generated/riffer/rig/commands/skill.rbs +12 -0
- data/sig/generated/riffer/rig/commands.rbs +4 -0
- data/sig/generated/riffer/rig/credentials/resolution.rbs +13 -0
- data/sig/generated/riffer/rig/credentials.rbs +70 -41
- data/sig/generated/riffer/rig/directories.rbs +11 -0
- data/sig/generated/riffer/rig/env/invalid.rbs +10 -0
- data/sig/generated/riffer/rig/env.rbs +26 -0
- data/sig/generated/riffer/rig/events/after_response.rbs +18 -0
- data/sig/generated/riffer/rig/events/after_tool_call.rbs +24 -0
- data/sig/generated/riffer/rig/events/before_prompt.rbs +18 -0
- data/sig/generated/riffer/rig/events/before_request.rbs +18 -0
- data/sig/generated/riffer/rig/events/before_tool_call.rbs +21 -0
- data/sig/generated/riffer/rig/events/command_output.rbs +21 -0
- data/sig/generated/riffer/rig/events/notify.rbs +21 -0
- data/sig/generated/riffer/rig/events/session_end.rbs +18 -0
- data/sig/generated/riffer/rig/events/session_start.rbs +21 -0
- data/sig/generated/riffer/rig/events/skill_activated.rbs +18 -0
- data/sig/generated/riffer/rig/events/turn_end.rbs +24 -0
- data/sig/generated/riffer/rig/events.rbs +4 -0
- data/sig/generated/riffer/rig/extension/failure.rbs +13 -0
- data/sig/generated/riffer/rig/extension.rbs +14 -5
- data/sig/generated/riffer/rig/hosts/mirror.rbs +41 -0
- data/sig/generated/riffer/rig/hosts/null.rbs +26 -0
- data/sig/generated/riffer/rig/loader.rbs +77 -0
- data/sig/generated/riffer/rig/mcp/declaration.rbs +18 -0
- data/sig/generated/riffer/rig/mcp/server.rbs +13 -0
- data/sig/generated/riffer/rig/mcp.rbs +8 -0
- data/sig/generated/riffer/rig/prompts/agents_md.rbs +19 -0
- data/sig/generated/riffer/rig/prompts.rbs +4 -0
- data/sig/generated/riffer/rig/provider_setup/field.rbs +22 -0
- data/sig/generated/riffer/rig/provider_setup.rbs +30 -0
- data/sig/generated/riffer/rig/registrar.rbs +88 -6
- data/sig/generated/riffer/rig/runtime/blocked.rbs +10 -0
- data/sig/generated/riffer/rig/runtime/cancel_flag.rbs +19 -0
- data/sig/generated/riffer/rig/runtime/hooks.rbs +49 -0
- data/sig/generated/riffer/rig/runtime/request_guardrail.rbs +16 -0
- data/sig/generated/riffer/rig/runtime/tool_runtime.rbs +23 -0
- data/sig/generated/riffer/rig/runtime.rbs +262 -40
- data/sig/generated/riffer/rig/settings/document.rbs +13 -9
- data/sig/generated/riffer/rig/settings/pricing.rbs +7 -3
- data/sig/generated/riffer/rig/settings.rbs +56 -64
- data/sig/generated/riffer/rig/skills/sources.rbs +18 -0
- data/sig/generated/riffer/rig/skills.rbs +7 -0
- data/sig/generated/riffer/rig/support/equatable.rbs +15 -0
- data/sig/generated/riffer/rig/{ui → terminal}/animator.rbs +5 -13
- data/sig/generated/riffer/rig/terminal/banner.rbs +39 -0
- data/sig/generated/riffer/rig/terminal/cursor.rbs +31 -0
- data/sig/generated/riffer/rig/terminal/host.rbs +50 -0
- data/sig/generated/riffer/rig/{ui → terminal}/palette.rbs +2 -2
- data/sig/generated/riffer/rig/terminal/renderer.rbs +126 -0
- data/sig/generated/riffer/rig/terminal/smoother.rbs +59 -0
- data/sig/generated/riffer/rig/{ui → terminal}/theme.rbs +5 -7
- data/sig/generated/riffer/rig/terminal.rbs +85 -0
- data/sig/generated/riffer/rig/tools/bash.rbs +14 -1
- data/sig/generated/riffer/rig.rbs +4 -7
- data/sig/manual/riffer/rig/cli.rbs +2 -4
- data/sig/manual/riffer/rig/commands/model.rbs +6 -0
- data/sig/manual/riffer/rig/commands/skill.rbs +6 -0
- data/sig/manual/riffer/rig/credentials.rbs +2 -4
- data/sig/manual/riffer/rig/directories.rbs +6 -0
- data/sig/manual/riffer/rig/events.rbs +6 -0
- data/sig/manual/riffer/rig/hosts.rbs +12 -0
- data/sig/manual/riffer/rig/mcp.rbs +11 -0
- data/sig/manual/riffer/rig/prompts/agents_md.rbs +6 -0
- data/sig/manual/riffer/rig/settings.rbs +2 -4
- data/sig/manual/riffer/rig/skills.rbs +6 -0
- data/sig/manual/riffer/rig/support.rbs +8 -0
- data/sig/manual/riffer/rig/terminal/banner.rbs +6 -0
- metadata +173 -35
- data/lib/riffer/rig/coding_agent.rb +0 -53
- data/lib/riffer/rig/host.rb +0 -52
- data/lib/riffer/rig/repl.rb +0 -189
- data/lib/riffer/rig/token_tally.rb +0 -74
- data/sig/generated/riffer/rig/coding_agent.rbs +0 -9
- data/sig/generated/riffer/rig/host.rbs +0 -42
- data/sig/generated/riffer/rig/repl.rbs +0 -77
- data/sig/generated/riffer/rig/token_tally.rbs +0 -61
- data/sig/generated/riffer/rig/ui/banner.rbs +0 -42
- data/sig/generated/riffer/rig/ui/cursor.rbs +0 -33
- data/sig/generated/riffer/rig/ui/renderer.rbs +0 -118
- data/sig/generated/riffer/rig/ui/smoother.rbs +0 -72
- data/sig/manual/riffer/rig/ui/banner.rbs +0 -8
- data/sig/manual/riffer/rig/ui.rbs +0 -5
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Riffer::Rig::Events::SkillActivated
|
|
4
|
+
include Riffer::Rig::Support::Equatable
|
|
5
|
+
|
|
6
|
+
# @dynamic name
|
|
7
|
+
attr_reader :name #: String
|
|
8
|
+
|
|
9
|
+
# @rbs name: String
|
|
10
|
+
# @rbs return: void
|
|
11
|
+
def initialize(name)
|
|
12
|
+
@name = name
|
|
13
|
+
freeze
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @rbs return: Symbol
|
|
17
|
+
def type
|
|
18
|
+
:skill_activated
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @rbs return: Hash[Symbol, untyped]
|
|
22
|
+
def to_h
|
|
23
|
+
{ type: type, name: name }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Riffer::Rig::Events::TurnEnd
|
|
4
|
+
include Riffer::Rig::Support::Equatable
|
|
5
|
+
|
|
6
|
+
# @dynamic stop_reason, usage
|
|
7
|
+
attr_reader :stop_reason #: Symbol
|
|
8
|
+
attr_reader :usage #: ::Riffer::Providers::TokenUsage?
|
|
9
|
+
|
|
10
|
+
# @rbs stop_reason: Symbol
|
|
11
|
+
# @rbs usage: ::Riffer::Providers::TokenUsage?
|
|
12
|
+
# @rbs return: void
|
|
13
|
+
def initialize(stop_reason, usage)
|
|
14
|
+
@stop_reason = stop_reason
|
|
15
|
+
@usage = usage
|
|
16
|
+
freeze
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @rbs return: Float?
|
|
20
|
+
def cost
|
|
21
|
+
usage&.cost
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @rbs return: Symbol
|
|
25
|
+
def type
|
|
26
|
+
:turn_end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @rbs return: Hash[Symbol, untyped]
|
|
30
|
+
def to_h
|
|
31
|
+
{ type: type, stop_reason: stop_reason, usage: usage }
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Riffer::Rig::Extension::Failure
|
|
4
|
+
# @dynamic extension, error
|
|
5
|
+
attr_reader :extension #: Riffer::Rig::Extension
|
|
6
|
+
attr_reader :error #: StandardError
|
|
7
|
+
|
|
8
|
+
# @rbs extension: Riffer::Rig::Extension
|
|
9
|
+
# @rbs error: StandardError
|
|
10
|
+
# @rbs return: void
|
|
11
|
+
def initialize(extension:, error:)
|
|
12
|
+
@extension = extension
|
|
13
|
+
@error = error
|
|
14
|
+
freeze
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/riffer/rig/extension.rb
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# An extension recorded by <tt>Riffer::Rig.extension</tt>: a name, an optional
|
|
4
|
-
# Gem::Requirement on riffer-rig, and the block that runs against a Runtime's
|
|
5
|
-
# registrar. The process registry holds these objects; Runtime.new runs their
|
|
6
|
-
# blocks.
|
|
7
3
|
class Riffer::Rig::Extension
|
|
4
|
+
class RequirementError < StandardError; end
|
|
5
|
+
|
|
8
6
|
# @rbs @name: String
|
|
9
7
|
# @rbs @requires: Gem::Requirement?
|
|
8
|
+
# @rbs @mismatch: RequirementError?
|
|
10
9
|
# @rbs @block: ^(::Riffer::Rig::Registrar) -> void
|
|
11
10
|
|
|
12
|
-
# @dynamic name, requires
|
|
11
|
+
# @dynamic name, requires, mismatch
|
|
13
12
|
attr_reader :name #: String
|
|
14
13
|
attr_reader :requires #: Gem::Requirement?
|
|
14
|
+
attr_reader :mismatch #: RequirementError?
|
|
15
15
|
|
|
16
16
|
# @rbs name: String
|
|
17
17
|
# @rbs requires: String?
|
|
@@ -20,6 +20,7 @@ class Riffer::Rig::Extension
|
|
|
20
20
|
def initialize(name, requires: nil, &block)
|
|
21
21
|
@name = name
|
|
22
22
|
@requires = requires && Gem::Requirement.new(requires)
|
|
23
|
+
@mismatch = check(@requires)
|
|
23
24
|
@block = block
|
|
24
25
|
end
|
|
25
26
|
|
|
@@ -28,4 +29,14 @@ class Riffer::Rig::Extension
|
|
|
28
29
|
def run(registrar)
|
|
29
30
|
@block.call(registrar)
|
|
30
31
|
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
# @rbs requirement: Gem::Requirement?
|
|
36
|
+
# @rbs return: RequirementError?
|
|
37
|
+
def check(requirement)
|
|
38
|
+
return if requirement.nil? || requirement.satisfied_by?(Gem::Version.new(Riffer::Rig::VERSION))
|
|
39
|
+
|
|
40
|
+
RequirementError.new("extension #{@name} requires riffer-rig #{requirement}, found #{Riffer::Rig::VERSION}")
|
|
41
|
+
end
|
|
31
42
|
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Riffer::Rig::Hosts::Mirror
|
|
4
|
+
# @rbs @host: Riffer::Rig::Hosts::_Host
|
|
5
|
+
# @rbs @queue: Array[Riffer::Rig::Events::_Event]
|
|
6
|
+
|
|
7
|
+
# @dynamic capabilities
|
|
8
|
+
attr_reader :capabilities #: Set[Symbol]
|
|
9
|
+
|
|
10
|
+
# @rbs host: Riffer::Rig::Hosts::_Host
|
|
11
|
+
# @rbs return: void
|
|
12
|
+
def initialize(host)
|
|
13
|
+
@host = host
|
|
14
|
+
@capabilities = host.capabilities
|
|
15
|
+
@queue = []
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @rbs question: String?
|
|
19
|
+
# @rbs options: Array[String]?
|
|
20
|
+
# @rbs secret: bool
|
|
21
|
+
# @rbs return: String?
|
|
22
|
+
def ask(question = nil, options: nil, secret: false)
|
|
23
|
+
@host.ask(question, options: options, secret: secret)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @rbs question: String?
|
|
27
|
+
# @rbs return: bool
|
|
28
|
+
def confirm(question = nil)
|
|
29
|
+
@host.confirm(question)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @rbs message: String?
|
|
33
|
+
# @rbs level: Symbol
|
|
34
|
+
# @rbs return: void
|
|
35
|
+
def notify(message = nil, level: :info)
|
|
36
|
+
queue(Riffer::Rig::Events::Notify.new(message, level))
|
|
37
|
+
@host.notify(message, level: level)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @rbs label: String?
|
|
41
|
+
# @rbs &block: ? () -> void
|
|
42
|
+
# @rbs return: void
|
|
43
|
+
def progress(label = nil, &block)
|
|
44
|
+
@host.progress(label) { block&.call }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# @rbs event: Riffer::Rig::Events::_Event
|
|
48
|
+
# @rbs return: void
|
|
49
|
+
def queue(event)
|
|
50
|
+
@queue << event
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @rbs return: Array[Riffer::Rig::Events::_Event]
|
|
54
|
+
def drain
|
|
55
|
+
queued = @queue
|
|
56
|
+
@queue = []
|
|
57
|
+
queued
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Riffer::Rig::Hosts::Null
|
|
4
|
+
# @rbs return: Set[Symbol]
|
|
5
|
+
def capabilities
|
|
6
|
+
Set.new.freeze
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# @rbs question: String?
|
|
10
|
+
# @rbs options: Array[String]?
|
|
11
|
+
# @rbs secret: bool
|
|
12
|
+
# @rbs return: String?
|
|
13
|
+
def ask(question = nil, options: nil, secret: false)
|
|
14
|
+
nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @rbs question: String?
|
|
18
|
+
# @rbs return: bool
|
|
19
|
+
def confirm(question = nil)
|
|
20
|
+
false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @rbs message: String?
|
|
24
|
+
# @rbs level: Symbol
|
|
25
|
+
# @rbs return: void
|
|
26
|
+
def notify(message = nil, level: :info)
|
|
27
|
+
nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @rbs label: String?
|
|
31
|
+
# @rbs &block: ? () -> void
|
|
32
|
+
# @rbs return: void
|
|
33
|
+
def progress(label = nil, &block)
|
|
34
|
+
block&.call
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Riffer::Rig::Loader
|
|
4
|
+
class ConfigurationError < StandardError; end
|
|
5
|
+
|
|
6
|
+
PROVIDER_LIST = Riffer::Rig::Settings::PROVIDERS.join(', ') #: String
|
|
7
|
+
|
|
8
|
+
ONBOARDING_QUESTION = 'Which model should riffer use? Enter provider/name, ' \
|
|
9
|
+
"with a provider from: #{PROVIDER_LIST}".freeze #: String
|
|
10
|
+
|
|
11
|
+
NO_MODEL = 'No model is set: pass --model provider/name, set RIFFER_MODEL, or set "model" in ' \
|
|
12
|
+
"~/.riffer/settings.json, with a provider from: #{PROVIDER_LIST}".freeze #: String
|
|
13
|
+
|
|
14
|
+
private_constant :PROVIDER_LIST, :ONBOARDING_QUESTION, :NO_MODEL
|
|
15
|
+
|
|
16
|
+
# @rbs @cwd: String
|
|
17
|
+
# @rbs @host: Riffer::Rig::Hosts::_Host
|
|
18
|
+
# @rbs @env: Riffer::Rig::Env
|
|
19
|
+
# @rbs @home: String
|
|
20
|
+
# @rbs @riffer_config: Riffer::Config
|
|
21
|
+
|
|
22
|
+
# @rbs cwd: String
|
|
23
|
+
# @rbs host: Riffer::Rig::Hosts::_Host
|
|
24
|
+
# @rbs env: Riffer::Rig::Env | Riffer::Rig::Env::Invalid
|
|
25
|
+
# @rbs home: String
|
|
26
|
+
# @rbs riffer_config: Riffer::Config
|
|
27
|
+
# @rbs model: String?
|
|
28
|
+
# @rbs extensions: bool
|
|
29
|
+
# @rbs skills: bool
|
|
30
|
+
# @rbs agents_md: bool
|
|
31
|
+
# @rbs tools: Array[String]?
|
|
32
|
+
# @rbs max_steps: Integer?
|
|
33
|
+
# @rbs return: Riffer::Rig::Runtime
|
|
34
|
+
def self.runtime(
|
|
35
|
+
cwd:,
|
|
36
|
+
host:,
|
|
37
|
+
env: Riffer::Rig::Env.load,
|
|
38
|
+
home: Dir.home,
|
|
39
|
+
riffer_config: Riffer.config,
|
|
40
|
+
model: nil,
|
|
41
|
+
extensions: true,
|
|
42
|
+
skills: true,
|
|
43
|
+
agents_md: true,
|
|
44
|
+
tools: nil,
|
|
45
|
+
max_steps: Riffer::Rig::Runtime::DEFAULT_MAX_STEPS
|
|
46
|
+
)
|
|
47
|
+
new(cwd:, host:, env:, home:, riffer_config:).runtime(model:, extensions:, skills:, agents_md:, tools:, max_steps:)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @rbs cwd: String
|
|
51
|
+
# @rbs host: Riffer::Rig::Hosts::_Host
|
|
52
|
+
# @rbs env: Riffer::Rig::Env | Riffer::Rig::Env::Invalid
|
|
53
|
+
# @rbs home: String
|
|
54
|
+
# @rbs riffer_config: Riffer::Config
|
|
55
|
+
# @rbs return: void
|
|
56
|
+
def initialize(cwd:, host:, env: Riffer::Rig::Env.load, home: Dir.home, riffer_config: Riffer.config)
|
|
57
|
+
raise ConfigurationError, env.message if env.is_a?(Riffer::Rig::Env::Invalid)
|
|
58
|
+
|
|
59
|
+
@cwd = cwd
|
|
60
|
+
@host = host
|
|
61
|
+
@env = env
|
|
62
|
+
@home = home
|
|
63
|
+
@riffer_config = riffer_config
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @rbs model: String?
|
|
67
|
+
# @rbs extensions: bool
|
|
68
|
+
# @rbs skills: bool
|
|
69
|
+
# @rbs agents_md: bool
|
|
70
|
+
# @rbs tools: Array[String]?
|
|
71
|
+
# @rbs max_steps: Integer?
|
|
72
|
+
# @rbs return: Riffer::Rig::Runtime
|
|
73
|
+
def runtime(
|
|
74
|
+
model: nil,
|
|
75
|
+
extensions: true,
|
|
76
|
+
skills: true,
|
|
77
|
+
agents_md: true,
|
|
78
|
+
tools: nil,
|
|
79
|
+
max_steps: Riffer::Rig::Runtime::DEFAULT_MAX_STEPS
|
|
80
|
+
)
|
|
81
|
+
settings = Riffer::Rig::Settings.merge(
|
|
82
|
+
Riffer::Rig::Settings.read(home_settings_path),
|
|
83
|
+
Riffer::Rig::Settings.read(File.join(@cwd, '.riffer', 'settings.json'))
|
|
84
|
+
)
|
|
85
|
+
document = Riffer::Rig::Settings::Document.new(settings)
|
|
86
|
+
selected = select_model(model || @env.model || document.model)
|
|
87
|
+
provider = Riffer::Rig::Settings.provider_for(selected).to_s
|
|
88
|
+
credentials = { provider.to_sym => credentials_for(provider) }
|
|
89
|
+
stripped = { skills: skills, agents_md: agents_md }.reject { |_name, kept| kept }.keys
|
|
90
|
+
|
|
91
|
+
Riffer::Rig::Runtime.new(
|
|
92
|
+
selected,
|
|
93
|
+
extensions: Riffer::Rig::Bundled::BY_NAME.except(*document.disabled.map(&:to_sym), *stripped).values,
|
|
94
|
+
tools: tools,
|
|
95
|
+
settings: settings,
|
|
96
|
+
host: @host,
|
|
97
|
+
cwd: @cwd,
|
|
98
|
+
max_steps: max_steps,
|
|
99
|
+
credentials: credentials,
|
|
100
|
+
pricing: document.models,
|
|
101
|
+
riffer_config: @riffer_config,
|
|
102
|
+
model_options: Riffer::Rig::Settings.model_options(selected, document.reasoning)
|
|
103
|
+
)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
# @rbs configured: String?
|
|
109
|
+
# @rbs return: String
|
|
110
|
+
def select_model(configured)
|
|
111
|
+
model = configured || ask_for_model
|
|
112
|
+
rejection = Riffer::Rig::Settings.rejection(model)
|
|
113
|
+
raise ConfigurationError, rejection if rejection
|
|
114
|
+
|
|
115
|
+
Riffer::Rig::Settings.store_model(model, path: home_settings_path) unless configured
|
|
116
|
+
model
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# @rbs return: String
|
|
120
|
+
def ask_for_model
|
|
121
|
+
answer = asking_host.ask(ONBOARDING_QUESTION).to_s.strip
|
|
122
|
+
raise ConfigurationError, NO_MODEL if answer.empty?
|
|
123
|
+
|
|
124
|
+
answer
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# @rbs provider: String
|
|
128
|
+
# @rbs return: Hash[Symbol, String]
|
|
129
|
+
def credentials_for(provider)
|
|
130
|
+
resolution = Riffer::Rig::Credentials.resolve(
|
|
131
|
+
provider,
|
|
132
|
+
host: asking_host,
|
|
133
|
+
env: @env,
|
|
134
|
+
auth_path: File.join(@home, '.riffer', 'auth.json'),
|
|
135
|
+
settings_path: home_settings_path
|
|
136
|
+
)
|
|
137
|
+
raise ConfigurationError, missing_credentials(provider, resolution.missing) unless resolution.missing.empty?
|
|
138
|
+
|
|
139
|
+
Riffer::Rig::Credentials.apply(provider, resolution.values, config: @riffer_config)
|
|
140
|
+
resolution.values
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# @rbs provider: String
|
|
144
|
+
# @rbs missing: Array[Symbol]
|
|
145
|
+
# @rbs return: String
|
|
146
|
+
def missing_credentials(provider, missing)
|
|
147
|
+
setup = Riffer::Rig::ProviderSetup.for(provider)
|
|
148
|
+
fields = setup.fields.select { |field| missing.include?(field.name) }
|
|
149
|
+
wanted = fields.map { |field| "#{field.name} (#{field.env.join(' or ')})" }.join(', ')
|
|
150
|
+
"#{provider} has no #{wanted}; set it in the environment or run riffer interactively to paste it" \
|
|
151
|
+
"#{" (create one at #{setup.url})" if setup.url}"
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# @rbs return: Riffer::Rig::Hosts::_Host
|
|
155
|
+
def asking_host
|
|
156
|
+
@host.capabilities.include?(:ask) ? @host : Riffer::Rig::Hosts::Null.new
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# @rbs return: String
|
|
160
|
+
def home_settings_path
|
|
161
|
+
File.join(@home, '.riffer', 'settings.json')
|
|
162
|
+
end
|
|
163
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Riffer::Rig::Mcp::Declaration
|
|
4
|
+
include Riffer::Rig::Support::Equatable
|
|
5
|
+
|
|
6
|
+
# @dynamic url, headers
|
|
7
|
+
attr_reader :url #: String
|
|
8
|
+
attr_reader :headers #: Hash[String, String]
|
|
9
|
+
|
|
10
|
+
# @rbs url: String
|
|
11
|
+
# @rbs headers: Hash[String, String]
|
|
12
|
+
# @rbs return: void
|
|
13
|
+
def initialize(url:, headers:)
|
|
14
|
+
@url = url
|
|
15
|
+
@headers = headers
|
|
16
|
+
freeze
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @rbs return: Hash[Symbol, untyped]
|
|
20
|
+
def to_h
|
|
21
|
+
{ url: url, headers: headers }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Riffer::Rig::Mcp::Server
|
|
4
|
+
# @dynamic declaration, registration
|
|
5
|
+
attr_reader :declaration #: Riffer::Rig::Mcp::Declaration
|
|
6
|
+
attr_reader :registration #: Riffer::Mcp::Registration
|
|
7
|
+
|
|
8
|
+
# @rbs declaration: Riffer::Rig::Mcp::Declaration
|
|
9
|
+
# @rbs registration: Riffer::Mcp::Registration
|
|
10
|
+
# @rbs return: void
|
|
11
|
+
def initialize(declaration:, registration:)
|
|
12
|
+
@declaration = declaration
|
|
13
|
+
@registration = registration
|
|
14
|
+
freeze
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Riffer::Rig::Mcp
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
# @rbs home: Hash[Symbol, untyped]
|
|
7
|
+
# @rbs project: Hash[Symbol, untyped]
|
|
8
|
+
# @rbs return: Hash[Symbol, untyped]
|
|
9
|
+
def merge(home, project)
|
|
10
|
+
home.merge(project, servers: home[:servers].to_h.merge(project[:servers].to_h))
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Riffer::Rig::Prompts::AgentsMd
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
FRAMING = 'The user wrote the following instructions in AGENTS.md files, ordered from the most general to ' \
|
|
7
|
+
'the one closest to the working directory. Follow them; where they conflict with the guidance ' \
|
|
8
|
+
'above, they take precedence, and where they conflict with each other, the later file wins.' #: String
|
|
9
|
+
|
|
10
|
+
# @rbs cwd: String
|
|
11
|
+
# @rbs return: Array[String]
|
|
12
|
+
def paths(cwd)
|
|
13
|
+
global = File.join(Dir.home, '.riffer', 'AGENTS.md')
|
|
14
|
+
project = Riffer::Rig::Directories.ancestors(File.expand_path(cwd)).reverse.map { |dir| File.join(dir, 'AGENTS.md') }
|
|
15
|
+
[global, *project].uniq.select { |path| File.file?(path) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @rbs cwd: String
|
|
19
|
+
# @rbs return: String?
|
|
20
|
+
def section(cwd)
|
|
21
|
+
blocks = paths(cwd).map { |path| block(path) }
|
|
22
|
+
[FRAMING, *blocks].join("\n\n") unless blocks.empty?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# @rbs path: String
|
|
28
|
+
# @rbs return: String
|
|
29
|
+
def block(path)
|
|
30
|
+
"<project_instructions path=\"#{path}\">\n#{File.read(path)}\n</project_instructions>"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Riffer::Rig::ProviderSetup::Field
|
|
4
|
+
# @dynamic name, env, secret, required, fallback
|
|
5
|
+
attr_reader :name #: Symbol
|
|
6
|
+
attr_reader :env #: Array[String]
|
|
7
|
+
attr_reader :secret, :required #: bool
|
|
8
|
+
attr_reader :fallback #: (^() -> String?)?
|
|
9
|
+
|
|
10
|
+
# @rbs name: Symbol
|
|
11
|
+
# @rbs env: Array[String]
|
|
12
|
+
# @rbs secret: bool
|
|
13
|
+
# @rbs required: bool
|
|
14
|
+
# @rbs fallback: (^() -> String?)?
|
|
15
|
+
# @rbs return: void
|
|
16
|
+
def initialize(name:, env:, secret:, required:, fallback: nil)
|
|
17
|
+
@name = name
|
|
18
|
+
@env = env.freeze
|
|
19
|
+
@secret = secret
|
|
20
|
+
@required = required
|
|
21
|
+
@fallback = fallback
|
|
22
|
+
freeze
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Riffer::Rig::ProviderSetup
|
|
4
|
+
# @dynamic url, chain, fields
|
|
5
|
+
attr_reader :url #: String?
|
|
6
|
+
attr_reader :chain #: bool
|
|
7
|
+
attr_reader :fields #: Array[Riffer::Rig::ProviderSetup::Field]
|
|
8
|
+
|
|
9
|
+
# @rbs fields: Array[Riffer::Rig::ProviderSetup::Field]
|
|
10
|
+
# @rbs url: String?
|
|
11
|
+
# @rbs chain: bool
|
|
12
|
+
# @rbs return: void
|
|
13
|
+
def initialize(fields:, url: nil, chain: false)
|
|
14
|
+
@url = url
|
|
15
|
+
@chain = chain
|
|
16
|
+
@fields = fields.freeze
|
|
17
|
+
freeze
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
AWS_SHARED_CONFIG_REGION = lambda do
|
|
21
|
+
require 'aws-sdk-core'
|
|
22
|
+
Object.const_get(:Aws).shared_config.region
|
|
23
|
+
rescue LoadError
|
|
24
|
+
nil
|
|
25
|
+
end #: ^() -> String?
|
|
26
|
+
|
|
27
|
+
# Upstream candidate: each riffer provider could declare its own credential
|
|
28
|
+
# fields, and this table would go.
|
|
29
|
+
TABLE = {
|
|
30
|
+
anthropic: new(
|
|
31
|
+
url: 'https://console.anthropic.com/settings/keys',
|
|
32
|
+
fields: [Field.new(name: :api_key, env: ['ANTHROPIC_API_KEY'], secret: true, required: true)]
|
|
33
|
+
),
|
|
34
|
+
openai: new(
|
|
35
|
+
url: 'https://platform.openai.com/api-keys',
|
|
36
|
+
fields: [
|
|
37
|
+
Field.new(name: :api_key, env: ['OPENAI_API_KEY'], secret: true, required: true),
|
|
38
|
+
Field.new(name: :base_url, env: ['OPENAI_BASE_URL'], secret: false, required: false)
|
|
39
|
+
]
|
|
40
|
+
),
|
|
41
|
+
gemini: new(
|
|
42
|
+
url: 'https://aistudio.google.com/app/apikey',
|
|
43
|
+
fields: [Field.new(name: :api_key, env: ['GEMINI_API_KEY'], secret: true, required: true)]
|
|
44
|
+
),
|
|
45
|
+
openrouter: new(
|
|
46
|
+
url: 'https://openrouter.ai/keys',
|
|
47
|
+
fields: [Field.new(name: :api_key, env: ['OPENROUTER_API_KEY'], secret: true, required: true)]
|
|
48
|
+
),
|
|
49
|
+
azure_openai: new(
|
|
50
|
+
url: 'https://portal.azure.com',
|
|
51
|
+
fields: [
|
|
52
|
+
Field.new(name: :endpoint, env: ['AZURE_OPENAI_ENDPOINT'], secret: false, required: true),
|
|
53
|
+
Field.new(name: :api_key, env: ['AZURE_OPENAI_API_KEY'], secret: true, required: true)
|
|
54
|
+
]
|
|
55
|
+
),
|
|
56
|
+
amazon_bedrock: new(
|
|
57
|
+
url: 'https://console.aws.amazon.com/bedrock',
|
|
58
|
+
chain: true,
|
|
59
|
+
fields: [
|
|
60
|
+
Field.new(
|
|
61
|
+
name: :region,
|
|
62
|
+
env: %w[AWS_REGION AWS_DEFAULT_REGION],
|
|
63
|
+
secret: false,
|
|
64
|
+
required: true,
|
|
65
|
+
fallback: AWS_SHARED_CONFIG_REGION
|
|
66
|
+
),
|
|
67
|
+
Field.new(name: :api_token, env: ['AWS_BEARER_TOKEN_BEDROCK'], secret: true, required: false)
|
|
68
|
+
]
|
|
69
|
+
)
|
|
70
|
+
}.freeze #: Hash[Symbol, Riffer::Rig::ProviderSetup]
|
|
71
|
+
|
|
72
|
+
# @rbs identifier: String | Symbol
|
|
73
|
+
# @rbs return: Riffer::Rig::ProviderSetup?
|
|
74
|
+
def self.[](identifier)
|
|
75
|
+
TABLE[identifier.to_sym]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @rbs identifier: String | Symbol
|
|
79
|
+
# @rbs return: Riffer::Rig::ProviderSetup
|
|
80
|
+
def self.for(identifier)
|
|
81
|
+
self[identifier] ||
|
|
82
|
+
new(fields: [Field.new(name: :api_key, env: ["#{identifier.to_s.upcase}_API_KEY"], secret: true, required: true)])
|
|
83
|
+
end
|
|
84
|
+
end
|