riffer-rig 0.8.0 → 0.10.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 +30 -0
- data/README.md +13 -2
- data/lib/riffer/rig/cli/flags.rb +28 -2
- data/lib/riffer/rig/cli.rb +39 -7
- data/lib/riffer/rig/commands/auth.rb +79 -0
- data/lib/riffer/rig/commands/model.rb +70 -21
- data/lib/riffer/rig/commands/reload.rb +23 -0
- data/lib/riffer/rig/credentials.rb +13 -1
- data/lib/riffer/rig/extension.rb +12 -0
- data/lib/riffer/rig/loader.rb +383 -32
- data/lib/riffer/rig/provider_setup.rb +36 -5
- data/lib/riffer/rig/providers.rb +48 -0
- data/lib/riffer/rig/registrar.rb +8 -0
- data/lib/riffer/rig/runtime.rb +124 -21
- data/lib/riffer/rig/sdk.rb +62 -0
- data/lib/riffer/rig/settings/document.rb +9 -1
- data/lib/riffer/rig/settings.rb +5 -4
- data/lib/riffer/rig/stores/jsonl.rb +128 -0
- data/lib/riffer/rig/stores/recorder.rb +124 -0
- data/lib/riffer/rig/version.rb +1 -1
- data/lib/riffer/rig.rb +7 -1
- data/sig/generated/riffer/rig/cli/flags.rbs +11 -2
- data/sig/generated/riffer/rig/cli.rbs +15 -0
- data/sig/generated/riffer/rig/commands/auth.rbs +35 -0
- data/sig/generated/riffer/rig/commands/model.rbs +21 -9
- data/sig/generated/riffer/rig/commands/reload.rbs +12 -0
- data/sig/generated/riffer/rig/credentials.rbs +8 -0
- data/sig/generated/riffer/rig/extension.rbs +4 -0
- data/sig/generated/riffer/rig/loader.rbs +167 -8
- data/sig/generated/riffer/rig/provider_setup.rbs +15 -4
- data/sig/generated/riffer/rig/providers.rbs +28 -0
- data/sig/generated/riffer/rig/registrar.rbs +6 -0
- data/sig/generated/riffer/rig/runtime.rbs +73 -10
- data/sig/generated/riffer/rig/sdk.rbs +33 -0
- data/sig/generated/riffer/rig/settings/document.rbs +7 -1
- data/sig/generated/riffer/rig/settings.rbs +2 -3
- data/sig/generated/riffer/rig/stores/jsonl.rbs +69 -0
- data/sig/generated/riffer/rig/stores/recorder.rbs +72 -0
- data/sig/generated/riffer/rig.rbs +4 -0
- data/sig/manual/riffer/rig/commands/auth.rbs +6 -0
- data/sig/manual/riffer/rig/commands/reload.rbs +6 -0
- data/sig/manual/riffer/rig/providers.rbs +6 -0
- data/sig/manual/riffer/rig/sdk.rbs +6 -0
- data/sig/manual/riffer/rig/stores.rbs +12 -0
- metadata +18 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0bc260756e56f8ed0d89556ef071a3ecb1922b637eb5b10cc0268416e0ceb26d
|
|
4
|
+
data.tar.gz: b7e6d6314a893ff23f289336b5e3df25f11e032f060272d7656695f1e96e584d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: edda5ec3d1675966361db52a009328703f0f62340d8d18ea3f5e689f3e9194762fec33804072989f1cb92d357038e03ca9481e7ab9f34eb123964f3f025b8749
|
|
7
|
+
data.tar.gz: c1953f30afa3a7871291852d3aaeba52a256006732582c82f71ad3245234f1e2a974524b174a801df81096af6effc37186e3a10e11ace5f5be644edbe4ed1c49
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.10.0](https://github.com/bottrall/riffer-rig/compare/v0.9.0...v0.10.0) (2026-10-05)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* continue and resume sessions with -c and -r ([#220](https://github.com/bottrall/riffer-rig/issues/220)) ([e43d3ac](https://github.com/bottrall/riffer-rig/commit/e43d3ac44678e56016791545ea241779569687c9))
|
|
9
|
+
* reload automatically before each request ([#222](https://github.com/bottrall/riffer-rig/issues/222)) ([fe96aa4](https://github.com/bottrall/riffer-rig/commit/fe96aa4476b0765e58824a8eb59301f0986e397c))
|
|
10
|
+
|
|
11
|
+
## [0.9.0](https://github.com/bottrall/riffer-rig/compare/v0.8.0...v0.9.0) (2026-10-04)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### ⚠ BREAKING CHANGES
|
|
15
|
+
|
|
16
|
+
* optional provider SDKs and the missing-SDK flow ([#211](https://github.com/bottrall/riffer-rig/issues/211))
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* /auth lists, re-runs and removes provider credentials ([#213](https://github.com/bottrall/riffer-rig/issues/213)) ([ce17f15](https://github.com/bottrall/riffer-rig/commit/ce17f15286f5bc776775e1cbff4fb6db673379f7))
|
|
21
|
+
* /model --save and provider switching through the Loader ([#214](https://github.com/bottrall/riffer-rig/issues/214)) ([f033caa](https://github.com/bottrall/riffer-rig/commit/f033caa6fc4b02b8a4429174f7d5256e4e7ece5b))
|
|
22
|
+
* extension providers with a setup on the provider seam ([#216](https://github.com/bottrall/riffer-rig/issues/216)) ([f24f632](https://github.com/bottrall/riffer-rig/commit/f24f632f7f6a1a9903e1bdd0985076a1d03f12d3))
|
|
23
|
+
* JSONL session store appends every Loader-built Runtime ([#219](https://github.com/bottrall/riffer-rig/issues/219)) ([67c5e80](https://github.com/bottrall/riffer-rig/commit/67c5e80efcea07b421b2c8512e576593d7a826d3))
|
|
24
|
+
* optional provider SDKs and the missing-SDK flow ([#211](https://github.com/bottrall/riffer-rig/issues/211)) ([334c94b](https://github.com/bottrall/riffer-rig/commit/334c94bc4954f87846ead17a936690a40d847c75)), closes [#127](https://github.com/bottrall/riffer-rig/issues/127)
|
|
25
|
+
* provider-native tools switched on in settings ([#217](https://github.com/bottrall/riffer-rig/issues/217)) ([6ba2a6a](https://github.com/bottrall/riffer-rig/commit/6ba2a6ad7ca0885af3e5c853786a0f3e22e0373a))
|
|
26
|
+
* reload tracked files with /reload ([#218](https://github.com/bottrall/riffer-rig/issues/218)) ([403de96](https://github.com/bottrall/riffer-rig/commit/403de9645afd91082551a966d04cc18beeb8f194)), closes [#132](https://github.com/bottrall/riffer-rig/issues/132)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Bug Fixes
|
|
30
|
+
|
|
31
|
+
* bundle provider SDKs for the checkout's bundler/setup ([#215](https://github.com/bottrall/riffer-rig/issues/215)) ([f0cc9e6](https://github.com/bottrall/riffer-rig/commit/f0cc9e6afcf82d1f006ab09679a4be38be846af2))
|
|
32
|
+
|
|
3
33
|
## [0.8.0](https://github.com/bottrall/riffer-rig/compare/v0.7.0...v0.8.0) (2026-10-02)
|
|
4
34
|
|
|
5
35
|
|
data/README.md
CHANGED
|
@@ -16,7 +16,13 @@ Install the gem:
|
|
|
16
16
|
gem install riffer-rig
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
This provides a `riffer` executable.
|
|
19
|
+
This provides a `riffer` executable. No provider SDK is installed with it: `gemini/…` models work out of the box, and every other provider's SDK gem is either installed on its first use — `riffer-rig` asks, then installs it in-process — or added to a Gemfile ahead of time:
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
gem 'anthropic', '~> 1.69'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
[Providers](docs/PROVIDERS.md#sdk-gems) lists each provider's gem and how the install offer works.
|
|
20
26
|
|
|
21
27
|
## Usage
|
|
22
28
|
|
|
@@ -40,6 +46,9 @@ The model is the first of these that is set: `--model`, `RIFFER_MODEL`, `model`
|
|
|
40
46
|
| `--no-agents-md` | leaves out the [AGENTS.md](docs/INSTRUCTIONS.md#agentsmd) instructions |
|
|
41
47
|
| `--tools read,bash` | only these tools, by identifier ([Tools](docs/TOOLS.md)) |
|
|
42
48
|
| `--max-steps N` | stops a turn after `N` model calls |
|
|
49
|
+
| `--no-save` | does not save this session to the [store](docs/SESSIONS.md) |
|
|
50
|
+
| `-c`, `--continue` | continues the most recent session in this directory ([Sessions](docs/SESSIONS.md#resuming)) |
|
|
51
|
+
| `-r ID`, `--resume ID` | resumes the session with id `ID` ([Sessions](docs/SESSIONS.md#resuming)) |
|
|
43
52
|
| `-h`, `--help` | prints the usage |
|
|
44
53
|
|
|
45
54
|
`riffer -p` (one prompt, no terminal) and `riffer acp` (an editor's agent over stdio) are reserved: for now each prints the usage and exits with status 2.
|
|
@@ -82,9 +91,11 @@ Each value resolves on its own: environment variable first, then the stored valu
|
|
|
82
91
|
|
|
83
92
|
The flat `{"anthropic": "sk-…"}` shape earlier versions wrote is no longer read; paste the key again when prompted. [Providers](docs/PROVIDERS.md) has the full format.
|
|
84
93
|
|
|
94
|
+
Inside a session, `/auth` lists every provider with where its secret comes from — `env`, `stored`, `chain` (the SDK's own credential chain, for Bedrock) or `missing`. `/auth <provider>` re-runs that provider's setup, which is how you rotate a key, and applies the new values to the current session, so the next request uses them. `/auth remove <provider>` deletes the provider's `auth.json` entry and its `providers` block in settings.
|
|
95
|
+
|
|
85
96
|
### Switching the model
|
|
86
97
|
|
|
87
|
-
`/model provider/name` switches the model for the current session only, keeping the conversation so far — `/model openai/gpt-5`, say. The provider prefix is required: a bare name such as `/model sonnet` is rejected with the list of providers. `/model` alone shows the model in use.
|
|
98
|
+
`/model provider/name` switches the model for the current session only, keeping the conversation so far — `/model openai/gpt-5`, say. The provider prefix is required: a bare name such as `/model sonnet` is rejected with the list of providers. `/model` alone shows the model in use. Switching runs the same setup for the new provider as startup does: its SDK gem is offered for install (or refused with the exact Gemfile line), and missing credentials are resolved — you are prompted for them when the host can ask, and the values apply to the running session immediately. The switch is refused with one error when the host cannot supply what is missing, and the model is left unchanged. `/model --save` writes the model in effect to the home `settings.json`, so new sessions start with it; `/model provider/name --save` switches and saves in one step, and a refused switch saves nothing ([Configuration](docs/CONFIGURATION.md#model)).
|
|
88
99
|
|
|
89
100
|
### Configuration
|
|
90
101
|
|
data/lib/riffer/rig/cli/flags.rb
CHANGED
|
@@ -9,11 +9,14 @@ class Riffer::Rig::CLI::Flags
|
|
|
9
9
|
riffer acp (not available yet)
|
|
10
10
|
TEXT
|
|
11
11
|
|
|
12
|
-
# @dynamic model, extensions, skills, agents_md, tools, max_steps, help
|
|
12
|
+
# @dynamic model, extensions, skills, agents_md, tools, max_steps, help, save, continue, resume
|
|
13
13
|
attr_reader :model #: String?
|
|
14
14
|
attr_reader :extensions, :skills, :agents_md, :help #: bool
|
|
15
15
|
attr_reader :tools #: Array[String]?
|
|
16
16
|
attr_reader :max_steps #: Integer?
|
|
17
|
+
attr_reader :save #: bool
|
|
18
|
+
attr_reader :continue #: bool
|
|
19
|
+
attr_reader :resume #: String?
|
|
17
20
|
|
|
18
21
|
# @rbs argv: Array[String]
|
|
19
22
|
# @rbs return: Riffer::Rig::CLI::Flags | String
|
|
@@ -29,6 +32,9 @@ class Riffer::Rig::CLI::Flags
|
|
|
29
32
|
agents_md: !values.key?(:'no-agents-md'),
|
|
30
33
|
tools: values[:tools],
|
|
31
34
|
max_steps: values[:'max-steps'],
|
|
35
|
+
save: !values.key?(:'no-save'),
|
|
36
|
+
continue: values.key?(:continue),
|
|
37
|
+
resume: values[:resume],
|
|
32
38
|
help: values.key?(:help)
|
|
33
39
|
)
|
|
34
40
|
rescue OptionParser::ParseError => e
|
|
@@ -51,6 +57,9 @@ class Riffer::Rig::CLI::Flags
|
|
|
51
57
|
parser.on('--no-agents-md', 'Leave out AGENTS.md instructions')
|
|
52
58
|
parser.on('--tools NAME,NAME', Array, 'Only these tools, by identifier')
|
|
53
59
|
parser.on('--max-steps N', Integer, 'Stop a turn after N model calls')
|
|
60
|
+
parser.on('--no-save', 'Do not save this session')
|
|
61
|
+
parser.on('-c', '--continue', 'Continue the most recent session in this directory')
|
|
62
|
+
parser.on('-r ID', '--resume ID', String, 'Resume the session with this id')
|
|
54
63
|
parser.on('-h', '--help', 'Show this help')
|
|
55
64
|
end
|
|
56
65
|
end
|
|
@@ -62,15 +71,32 @@ class Riffer::Rig::CLI::Flags
|
|
|
62
71
|
# @rbs agents_md: bool
|
|
63
72
|
# @rbs tools: Array[String]?
|
|
64
73
|
# @rbs max_steps: Integer?
|
|
74
|
+
# @rbs save: bool
|
|
75
|
+
# @rbs continue: bool
|
|
76
|
+
# @rbs resume: String?
|
|
65
77
|
# @rbs help: bool
|
|
66
78
|
# @rbs return: void
|
|
67
|
-
def initialize(
|
|
79
|
+
def initialize(
|
|
80
|
+
model: nil,
|
|
81
|
+
extensions: true,
|
|
82
|
+
skills: true,
|
|
83
|
+
agents_md: true,
|
|
84
|
+
tools: nil,
|
|
85
|
+
max_steps: nil,
|
|
86
|
+
save: true,
|
|
87
|
+
continue: false,
|
|
88
|
+
resume: nil,
|
|
89
|
+
help: false
|
|
90
|
+
)
|
|
68
91
|
@model = model
|
|
69
92
|
@extensions = extensions
|
|
70
93
|
@skills = skills
|
|
71
94
|
@agents_md = agents_md
|
|
72
95
|
@tools = tools&.freeze
|
|
73
96
|
@max_steps = max_steps
|
|
97
|
+
@save = save
|
|
98
|
+
@continue = continue
|
|
99
|
+
@resume = resume
|
|
74
100
|
@help = help
|
|
75
101
|
freeze
|
|
76
102
|
end
|
data/lib/riffer/rig/cli.rb
CHANGED
|
@@ -52,21 +52,53 @@ module Riffer::Rig::CLI
|
|
|
52
52
|
version: Riffer::Rig::VERSION,
|
|
53
53
|
no_color: env.is_a?(Riffer::Rig::Env) && env.no_color
|
|
54
54
|
).run do |host|
|
|
55
|
-
Riffer::Rig::Loader.
|
|
55
|
+
loader = Riffer::Rig::Loader.new(
|
|
56
56
|
cwd: cwd,
|
|
57
57
|
host: host,
|
|
58
58
|
env: env,
|
|
59
59
|
home: home,
|
|
60
|
-
|
|
61
|
-
extensions: flags.extensions,
|
|
62
|
-
skills: flags.skills,
|
|
63
|
-
agents_md: flags.agents_md,
|
|
64
|
-
tools: flags.tools,
|
|
65
|
-
max_steps: flags.max_steps
|
|
60
|
+
store: flags.save ? Riffer::Rig::Stores::JSONL.new : nil
|
|
66
61
|
)
|
|
62
|
+
resumed(flags, host, loader) || build(loader, flags)
|
|
67
63
|
end
|
|
68
64
|
end
|
|
69
65
|
|
|
66
|
+
# @rbs flags: Riffer::Rig::CLI::Flags
|
|
67
|
+
# @rbs host: Riffer::Rig::Hosts::_Host
|
|
68
|
+
# @rbs loader: Riffer::Rig::Loader
|
|
69
|
+
# @rbs return: Riffer::Rig::Runtime?
|
|
70
|
+
def resumed(flags, host, loader)
|
|
71
|
+
if flags.resume
|
|
72
|
+
started = loader.resume(flags.resume, **keywords(flags))
|
|
73
|
+
host.notify("No saved session #{flags.resume}.") unless started
|
|
74
|
+
started
|
|
75
|
+
elsif flags.continue
|
|
76
|
+
started = loader.continue(**keywords(flags))
|
|
77
|
+
host.notify('No saved session in this directory.') unless started
|
|
78
|
+
started
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @rbs loader: Riffer::Rig::Loader
|
|
83
|
+
# @rbs flags: Riffer::Rig::CLI::Flags
|
|
84
|
+
# @rbs return: Riffer::Rig::Runtime
|
|
85
|
+
def build(loader, flags)
|
|
86
|
+
loader.runtime(**keywords(flags))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @rbs flags: Riffer::Rig::CLI::Flags
|
|
90
|
+
# @rbs return: Hash[Symbol, untyped]
|
|
91
|
+
def keywords(flags)
|
|
92
|
+
{
|
|
93
|
+
model: flags.model,
|
|
94
|
+
extensions: flags.extensions,
|
|
95
|
+
skills: flags.skills,
|
|
96
|
+
agents_md: flags.agents_md,
|
|
97
|
+
tools: flags.tools,
|
|
98
|
+
max_steps: flags.max_steps
|
|
99
|
+
}
|
|
100
|
+
end
|
|
101
|
+
|
|
70
102
|
# @rbs name: String
|
|
71
103
|
# @rbs error: IO
|
|
72
104
|
# @rbs return: Integer
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Riffer::Rig::Commands::Auth
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
USAGE = 'Use /auth, /auth <provider> or /auth remove <provider>' #: String
|
|
7
|
+
|
|
8
|
+
# @rbs return: Riffer::Rig::Command
|
|
9
|
+
def command
|
|
10
|
+
Riffer::Rig::Command.new(
|
|
11
|
+
'auth',
|
|
12
|
+
description: 'Show, re-run or remove provider credentials',
|
|
13
|
+
extension: 'core'
|
|
14
|
+
) { |ctx| run(ctx) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @rbs ctx: Riffer::Rig::Command::Context
|
|
18
|
+
# @rbs return: void
|
|
19
|
+
def run(ctx)
|
|
20
|
+
words = ctx.args.split
|
|
21
|
+
return ctx.say(list) if words.empty?
|
|
22
|
+
return remove(ctx, words[1]) if words[0] == 'remove' && words.length == 2
|
|
23
|
+
return rerun(ctx, words[0]) if words.length == 1
|
|
24
|
+
|
|
25
|
+
ctx.say(USAGE)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
# @rbs return: String
|
|
31
|
+
def hint
|
|
32
|
+
'Use /auth <provider> or /auth remove <provider>, with a provider from: ' \
|
|
33
|
+
"#{Riffer::Rig::Settings.providers.join(', ')}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @rbs return: String
|
|
37
|
+
def list
|
|
38
|
+
statuses = Riffer::Rig::Settings.providers.to_h do |identifier|
|
|
39
|
+
[identifier, Riffer::Rig::Credentials.status(identifier)]
|
|
40
|
+
end
|
|
41
|
+
width = statuses.keys.map { |identifier| identifier.to_s.length }.max || 0
|
|
42
|
+
statuses.map { |identifier, status| "#{identifier.to_s.ljust(width)} #{status}" }.join("\n")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @rbs ctx: Riffer::Rig::Command::Context
|
|
46
|
+
# @rbs identifier: String
|
|
47
|
+
# @rbs return: void
|
|
48
|
+
def rerun(ctx, identifier)
|
|
49
|
+
return ctx.say(hint) unless Riffer::Providers::Repository.find(identifier)
|
|
50
|
+
|
|
51
|
+
provider = identifier.to_sym
|
|
52
|
+
resolution = Riffer::Rig::Credentials.resolve(provider, host: ctx.host)
|
|
53
|
+
Riffer::Rig::Credentials.apply(provider, resolution.values)
|
|
54
|
+
ctx.runtime.merge_credentials(provider, resolution.values)
|
|
55
|
+
return ctx.host.notify(refusal(provider, resolution.missing), level: :error) unless resolution.missing.empty?
|
|
56
|
+
|
|
57
|
+
ctx.say("Updated #{provider} credentials")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @rbs ctx: Riffer::Rig::Command::Context
|
|
61
|
+
# @rbs identifier: String
|
|
62
|
+
# @rbs return: void
|
|
63
|
+
def remove(ctx, identifier)
|
|
64
|
+
return ctx.say(hint) unless Riffer::Providers::Repository.find(identifier)
|
|
65
|
+
|
|
66
|
+
Riffer::Rig::Credentials.remove(identifier)
|
|
67
|
+
ctx.say("Removed stored #{identifier} credentials")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @rbs provider: Symbol
|
|
71
|
+
# @rbs missing: Array[Symbol]
|
|
72
|
+
# @rbs return: String
|
|
73
|
+
def refusal(provider, missing)
|
|
74
|
+
setup = Riffer::Rig::ProviderSetup.for(provider)
|
|
75
|
+
fields = setup.fields.select { |field| missing.include?(field.name) }
|
|
76
|
+
wanted = fields.map { |field| "#{field.name} (#{field.env.join(' or ')})" }.join(', ')
|
|
77
|
+
"#{provider} still has no #{wanted}"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -3,16 +3,13 @@
|
|
|
3
3
|
module Riffer::Rig::Commands::Model
|
|
4
4
|
extend self
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
"#{Riffer::Rig::Settings::PROVIDERS.join(', ')}".freeze #: String
|
|
8
|
-
|
|
9
|
-
SAVE_UNAVAILABLE = '/model --save is not available in this host'
|
|
6
|
+
SAVE = '--save' #: String
|
|
10
7
|
|
|
11
8
|
# @rbs return: Riffer::Rig::Command
|
|
12
9
|
def command
|
|
13
10
|
Riffer::Rig::Command.new(
|
|
14
11
|
'model',
|
|
15
|
-
description: 'Switch the model for this session: /model provider/name',
|
|
12
|
+
description: 'Switch the model for this session: /model provider/name, /model --save',
|
|
16
13
|
extension: 'core'
|
|
17
14
|
) { |ctx| run(ctx) }
|
|
18
15
|
end
|
|
@@ -20,35 +17,87 @@ module Riffer::Rig::Commands::Model
|
|
|
20
17
|
# @rbs ctx: Riffer::Rig::Command::Context
|
|
21
18
|
# @rbs return: void
|
|
22
19
|
def run(ctx)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
words = ctx.args.split
|
|
21
|
+
save = words.delete(SAVE)
|
|
22
|
+
model = words.join(' ')
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
if model.empty?
|
|
25
|
+
return ctx.say("Model: #{ctx.runtime.model}") unless save
|
|
26
|
+
|
|
27
|
+
Riffer::Rig::Settings.store_model(ctx.runtime.model)
|
|
28
|
+
return ctx.say("Saved #{ctx.runtime.model} to settings")
|
|
29
|
+
end
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
return ctx.
|
|
31
|
+
provider = Riffer::Rig::Settings.provider_for(model)
|
|
32
|
+
return ctx.say(hint) unless provider && Riffer::Providers::Repository.find(provider)
|
|
33
|
+
return unless ready?(ctx, model, provider)
|
|
32
34
|
|
|
33
35
|
ctx.runtime.model = model
|
|
36
|
+
Riffer::Rig::Settings.store_model(model) if save
|
|
34
37
|
ctx.say("Model: #{model}")
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
private
|
|
38
41
|
|
|
42
|
+
# @rbs return: String
|
|
43
|
+
def hint
|
|
44
|
+
"Use /model provider/name, with a provider from: #{Riffer::Rig::Settings.providers.join(', ')}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# The same setup flows the Loader runs when it builds a Runtime: the
|
|
48
|
+
# provider's SDK gem, then its credentials, asked for when the host can ask.
|
|
49
|
+
# @rbs ctx: Riffer::Rig::Command::Context
|
|
39
50
|
# @rbs model: String
|
|
40
51
|
# @rbs provider: String
|
|
41
|
-
# @rbs
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
# @rbs return: bool
|
|
53
|
+
def ready?(ctx, model, provider)
|
|
54
|
+
setup = Riffer::Rig::ProviderSetup[provider]
|
|
55
|
+
return true unless setup
|
|
56
|
+
|
|
57
|
+
sdk = setup.sdk
|
|
58
|
+
if sdk
|
|
59
|
+
message = Riffer::Rig::SDK.ensure(sdk[0], sdk[1], host: ctx.host)
|
|
60
|
+
if message
|
|
61
|
+
ctx.host.notify(message, level: :error)
|
|
62
|
+
return false
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
credentials_ready?(ctx, model, provider, setup)
|
|
45
67
|
end
|
|
46
68
|
|
|
69
|
+
# @rbs ctx: Riffer::Rig::Command::Context
|
|
70
|
+
# @rbs model: String
|
|
47
71
|
# @rbs provider: String
|
|
48
|
-
# @rbs
|
|
49
|
-
# @rbs return:
|
|
50
|
-
def
|
|
51
|
-
|
|
52
|
-
|
|
72
|
+
# @rbs setup: Riffer::Rig::ProviderSetup
|
|
73
|
+
# @rbs return: bool
|
|
74
|
+
def credentials_ready?(ctx, model, provider, setup)
|
|
75
|
+
missing = setup.fields.select(&:required)
|
|
76
|
+
.map(&:name)
|
|
77
|
+
.reject { |name| ctx.runtime.credentials.dig(provider.to_sym, name) }
|
|
78
|
+
return true if missing.empty?
|
|
79
|
+
|
|
80
|
+
resolution = Riffer::Rig::Credentials.resolve(provider, host: ctx.host)
|
|
81
|
+
unfilled = missing & resolution.missing
|
|
82
|
+
if unfilled.empty?
|
|
83
|
+
Riffer::Rig::Credentials.apply(provider, resolution.values)
|
|
84
|
+
empty = {} #: Hash[Symbol, String]
|
|
85
|
+
values = ctx.runtime.credentials.fetch(provider.to_sym, empty).merge(resolution.values)
|
|
86
|
+
ctx.runtime.merge_credentials(provider.to_sym, values)
|
|
87
|
+
true
|
|
88
|
+
else
|
|
89
|
+
refuse(ctx, model, provider, unfilled)
|
|
90
|
+
false
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @rbs ctx: Riffer::Rig::Command::Context
|
|
95
|
+
# @rbs model: String
|
|
96
|
+
# @rbs provider: String
|
|
97
|
+
# @rbs missing: Array[Symbol]
|
|
98
|
+
# @rbs return: void
|
|
99
|
+
def refuse(ctx, model, provider, missing)
|
|
100
|
+
wanted = Riffer::Rig::ProviderSetup.for(provider).missing_fields(missing)
|
|
101
|
+
ctx.host.notify("Not switching to #{model}: #{provider} has no #{wanted}", level: :error)
|
|
53
102
|
end
|
|
54
103
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Riffer::Rig::Commands::Reload
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
# @rbs loader: Riffer::Rig::Loader
|
|
7
|
+
# @rbs return: Riffer::Rig::Command
|
|
8
|
+
def command(loader)
|
|
9
|
+
Riffer::Rig::Command.new(
|
|
10
|
+
'reload',
|
|
11
|
+
description: 'Reload the rig.rb files, settings, credentials and trust',
|
|
12
|
+
extension: 'core'
|
|
13
|
+
) { |ctx| run(loader, ctx) }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @rbs loader: Riffer::Rig::Loader
|
|
17
|
+
# @rbs ctx: Riffer::Rig::Command::Context
|
|
18
|
+
# @rbs return: void
|
|
19
|
+
def run(loader, ctx)
|
|
20
|
+
reloaded = loader.reload(ctx.runtime, force: true)
|
|
21
|
+
ctx.say('Reloaded') if reloaded.is_a?(Riffer::Rig::Runtime)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -11,6 +11,9 @@ module Riffer::Rig::Credentials
|
|
|
11
11
|
|
|
12
12
|
ENTRY_TYPE = 'api_key'
|
|
13
13
|
|
|
14
|
+
# @rbs @applied: Hash[Symbol, Hash[Symbol, String]]
|
|
15
|
+
@applied = {} #: Hash[Symbol, Hash[Symbol, String]]
|
|
16
|
+
|
|
14
17
|
# @rbs identifier: String | Symbol
|
|
15
18
|
# @rbs host: Riffer::Rig::Hosts::_Host
|
|
16
19
|
# @rbs setup: Riffer::Rig::ProviderSetup
|
|
@@ -39,17 +42,26 @@ module Riffer::Rig::Credentials
|
|
|
39
42
|
Resolution.new(values:, missing: required.map(&:name) - values.keys)
|
|
40
43
|
end
|
|
41
44
|
|
|
45
|
+
# A registered extension provider has no Riffer::Config member, so the
|
|
46
|
+
# assignment stays built-ins-only.
|
|
42
47
|
# @rbs identifier: String | Symbol
|
|
43
48
|
# @rbs values: Hash[Symbol, String]
|
|
44
49
|
# @rbs config: Riffer::Config
|
|
45
50
|
# @rbs return: void
|
|
46
51
|
def apply(identifier, values, config: Riffer.config)
|
|
47
|
-
|
|
52
|
+
@applied[identifier.to_sym] = values.dup.freeze
|
|
53
|
+
return unless Riffer::Rig::ProviderSetup::TABLE.key?(identifier.to_sym)
|
|
48
54
|
|
|
49
55
|
provider_config = config.public_send(identifier)
|
|
50
56
|
values.each { |name, value| provider_config.public_send(:"#{name}=", value) }
|
|
51
57
|
end
|
|
52
58
|
|
|
59
|
+
# @rbs identifier: String | Symbol
|
|
60
|
+
# @rbs return: Hash[Symbol, String]?
|
|
61
|
+
def read(identifier)
|
|
62
|
+
@applied[identifier.to_sym]
|
|
63
|
+
end
|
|
64
|
+
|
|
53
65
|
# @rbs identifier: String | Symbol
|
|
54
66
|
# @rbs values: Hash[Symbol, String]
|
|
55
67
|
# @rbs setup: Riffer::Rig::ProviderSetup
|
data/lib/riffer/rig/extension.rb
CHANGED
|
@@ -30,6 +30,18 @@ class Riffer::Rig::Extension
|
|
|
30
30
|
@block.call(registrar)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
# @rbs registrar: Riffer::Rig::Registrar
|
|
34
|
+
# @rbs return: StandardError?
|
|
35
|
+
def load_into(registrar)
|
|
36
|
+
rejection = mismatch || registrar.collision
|
|
37
|
+
return rejection if rejection
|
|
38
|
+
|
|
39
|
+
run(registrar)
|
|
40
|
+
nil
|
|
41
|
+
rescue StandardError => e
|
|
42
|
+
e
|
|
43
|
+
end
|
|
44
|
+
|
|
33
45
|
private
|
|
34
46
|
|
|
35
47
|
# @rbs requirement: Gem::Requirement?
|