lex-llm-anthropic 0.2.15 → 0.2.16
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/.rubocop.yml +40 -6
- data/CHANGELOG.md +6 -0
- data/lib/legion/extensions/llm/anthropic/actors/discovery_refresh.rb +1 -1
- data/lib/legion/extensions/llm/anthropic/provider.rb +61 -57
- data/lib/legion/extensions/llm/anthropic/registry_event_builder.rb +10 -10
- data/lib/legion/extensions/llm/anthropic/runners/fleet_worker.rb +5 -5
- data/lib/legion/extensions/llm/anthropic/transport/messages/registry_event.rb +1 -1
- data/lib/legion/extensions/llm/anthropic/version.rb +1 -1
- data/lib/legion/extensions/llm/anthropic.rb +34 -34
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9ef129fbcb71eb5500eff0ef7047dda892d97d57b21dab9567488be60cca0401
|
|
4
|
+
data.tar.gz: 3efed0ed6d287da75ac969e7dd29121b1c4e49e11f989a7fb7fed4f8c24f1ac2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dfd4e546964d3994cb294860aae5d2f81476c0c067b76519b9c65506eb782e32df58fda6ede3df2f9c17095b1b7aaf7e940a2e5afc4ea34efb7d086c00e17c4f
|
|
7
|
+
data.tar.gz: 62d2e1ac960fd5084becf6d83beb966ad02556205f1d70b183ab48892a69cb3783004eddcbea08435986b7a8ec569a3f41f8b835a5e12aed63b8388b078471e3
|
data/.rubocop.yml
CHANGED
|
@@ -1,18 +1,52 @@
|
|
|
1
1
|
plugins:
|
|
2
2
|
- rubocop-performance
|
|
3
3
|
- rubocop-rake
|
|
4
|
-
- rubocop-rspec
|
|
5
4
|
|
|
6
5
|
AllCops:
|
|
7
|
-
NewCops: enable
|
|
8
6
|
TargetRubyVersion: 3.4
|
|
7
|
+
NewCops: enable
|
|
9
8
|
SuggestExtensions: false
|
|
10
9
|
|
|
10
|
+
Layout/LineLength:
|
|
11
|
+
Max: 195
|
|
12
|
+
Layout/SpaceAroundEqualsInParameterDefault:
|
|
13
|
+
EnforcedStyle: space
|
|
14
|
+
Layout/HashAlignment:
|
|
15
|
+
EnforcedHashRocketStyle: table
|
|
16
|
+
EnforcedColonStyle: table
|
|
17
|
+
Metrics/MethodLength:
|
|
18
|
+
Max: 150
|
|
19
|
+
Metrics/ClassLength:
|
|
20
|
+
Max: 1500
|
|
21
|
+
Metrics/ModuleLength:
|
|
22
|
+
Max: 1500
|
|
11
23
|
Metrics/BlockLength:
|
|
24
|
+
Max: 150
|
|
12
25
|
Exclude:
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
Metrics/
|
|
26
|
+
- 'spec/**/*'
|
|
27
|
+
|
|
28
|
+
Metrics/AbcSize:
|
|
29
|
+
Max: 110
|
|
30
|
+
Metrics/BlockNesting:
|
|
31
|
+
Max: 4
|
|
32
|
+
Metrics/CyclomaticComplexity:
|
|
33
|
+
Max: 50
|
|
34
|
+
|
|
35
|
+
Metrics/PerceivedComplexity:
|
|
36
|
+
Max: 50
|
|
37
|
+
Style/Documentation:
|
|
16
38
|
Enabled: false
|
|
17
|
-
|
|
39
|
+
Style/SymbolArray:
|
|
40
|
+
Enabled: true
|
|
41
|
+
Style/FrozenStringLiteralComment:
|
|
42
|
+
Enabled: true
|
|
43
|
+
EnforcedStyle: always
|
|
44
|
+
Naming/FileName:
|
|
18
45
|
Enabled: false
|
|
46
|
+
Naming/PredicateMethod:
|
|
47
|
+
Enabled: false
|
|
48
|
+
Metrics/ParameterLists:
|
|
49
|
+
Max: 9
|
|
50
|
+
Style/RedundantConstantBase:
|
|
51
|
+
Exclude:
|
|
52
|
+
- 'spec/**/*'
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.16 - 2026-06-10
|
|
4
|
+
|
|
5
|
+
- **Hash-backed tool support** — `format_tools` and `tool_schema` now handle both `ToolDefinition` objects and plain Hashes from `native_dispatch` via `respond_to?` checks with symbol/string key fallbacks. Prevents `NoMethodError` when tools arrive as hash-backed definitions (provider.rb).
|
|
6
|
+
- **RuboCop configuration overhaul** — Relaxed metrics to match project scale: LineLength 195, MethodLength 150, ClassLength 1500, AbcSize 110, BlockNesting 4, CyclomaticComplexity/PerceivedComplexity 50. Added `Layout/HashAlignment` (table style), `Layout/SpaceAroundEqualsInParameterDefault`, `Naming/PredicateMethod` disable, `Style/RedundantConstantBase` spec exclusion. Removed `rubocop-rspec` plugin (no longer needed). All 28 specs passing, 0 offenses (.rubocop.yml).
|
|
7
|
+
- **Hash alignment formatting** — Applied consistent table-style hash alignment across provider.rb, anthropic.rb, registry_event_builder.rb, fleet_worker.rb, and transport messages for readability.
|
|
8
|
+
|
|
3
9
|
## 0.2.15 - 2026-06-05
|
|
4
10
|
|
|
5
11
|
- **Fix RuboCop cyclomatic complexity** — Extract `extract_hash_budget` helper to reduce `thinking_budget` cyclomatic complexity from 8 to 6, meeting the 7-line threshold.
|
|
@@ -13,7 +13,7 @@ module Legion
|
|
|
13
13
|
module Llm
|
|
14
14
|
module Anthropic
|
|
15
15
|
module Actor
|
|
16
|
-
class DiscoveryRefresh < Legion::Extensions::Actors::Every
|
|
16
|
+
class DiscoveryRefresh < Legion::Extensions::Actors::Every
|
|
17
17
|
include Legion::Logging::Helper
|
|
18
18
|
|
|
19
19
|
REFRESH_INTERVAL = 1800
|
|
@@ -8,7 +8,7 @@ module Legion
|
|
|
8
8
|
module Llm
|
|
9
9
|
module Anthropic
|
|
10
10
|
# Anthropic Messages API provider implementation for the Legion::Extensions::Llm contract.
|
|
11
|
-
class Provider < Legion::Extensions::Llm::Provider
|
|
11
|
+
class Provider < Legion::Extensions::Llm::Provider
|
|
12
12
|
include Legion::Logging::Helper
|
|
13
13
|
|
|
14
14
|
class << self
|
|
@@ -45,7 +45,7 @@ module Legion
|
|
|
45
45
|
|
|
46
46
|
def headers
|
|
47
47
|
identity_headers.merge({
|
|
48
|
-
'x-api-key'
|
|
48
|
+
'x-api-key' => config.anthropic_api_key,
|
|
49
49
|
'anthropic-version' => config.anthropic_version || settings[:api_version] || '2023-06-01'
|
|
50
50
|
}.compact)
|
|
51
51
|
end
|
|
@@ -67,18 +67,18 @@ module Legion
|
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
CONTEXT_WINDOWS = {
|
|
70
|
-
'claude-opus-4'
|
|
70
|
+
'claude-opus-4' => 200_000,
|
|
71
71
|
'claude-sonnet-4' => 200_000,
|
|
72
|
-
'claude-haiku-4'
|
|
73
|
-
'claude-3-5'
|
|
74
|
-
'claude-3-opus'
|
|
72
|
+
'claude-haiku-4' => 200_000,
|
|
73
|
+
'claude-3-5' => 200_000,
|
|
74
|
+
'claude-3-opus' => 200_000,
|
|
75
75
|
'claude-3-sonnet' => 200_000,
|
|
76
|
-
'claude-3-haiku'
|
|
76
|
+
'claude-3-haiku' => 200_000
|
|
77
77
|
}.freeze
|
|
78
78
|
|
|
79
79
|
private
|
|
80
80
|
|
|
81
|
-
def render_payload(messages, tools:, temperature:, model:, stream:, schema:, thinking:, tool_prefs:)
|
|
81
|
+
def render_payload(messages, tools:, temperature:, model:, stream:, schema:, thinking:, tool_prefs:)
|
|
82
82
|
log_render_payload(messages:, tools:, model:, stream:, schema:)
|
|
83
83
|
system_messages, chat_messages = messages.partition { |message| message.role == :system }
|
|
84
84
|
|
|
@@ -87,15 +87,15 @@ module Legion
|
|
|
87
87
|
cacheable_count = caching ? [chat_messages.size - exclude_count, 0].max : 0
|
|
88
88
|
|
|
89
89
|
{
|
|
90
|
-
model:
|
|
91
|
-
messages:
|
|
92
|
-
stream:
|
|
93
|
-
max_tokens:
|
|
94
|
-
system:
|
|
95
|
-
thinking:
|
|
96
|
-
temperature:
|
|
97
|
-
tools:
|
|
98
|
-
tool_choice:
|
|
90
|
+
model: model.id,
|
|
91
|
+
messages: format_messages(chat_messages, thinking: thinking_enabled?(thinking), cacheable_count:),
|
|
92
|
+
stream: stream,
|
|
93
|
+
max_tokens: model.max_tokens || settings[:default_max_tokens] || 4096,
|
|
94
|
+
system: system_content(system_messages, cache: caching),
|
|
95
|
+
thinking: thinking_payload(thinking),
|
|
96
|
+
temperature: temperature,
|
|
97
|
+
tools: format_tools(tools, cache: caching),
|
|
98
|
+
tool_choice: tool_choice(tool_prefs),
|
|
99
99
|
output_config: output_config(schema)
|
|
100
100
|
}.compact
|
|
101
101
|
end
|
|
@@ -123,7 +123,7 @@ module Legion
|
|
|
123
123
|
format_tool_result_message(message, cache:)
|
|
124
124
|
else
|
|
125
125
|
{
|
|
126
|
-
role:
|
|
126
|
+
role: anthropic_role(message.role),
|
|
127
127
|
content: content_blocks(message.content, thinking:, message:, cache:)
|
|
128
128
|
}
|
|
129
129
|
end
|
|
@@ -167,11 +167,11 @@ module Legion
|
|
|
167
167
|
next unless attachment.image?
|
|
168
168
|
|
|
169
169
|
{
|
|
170
|
-
type:
|
|
170
|
+
type: 'image',
|
|
171
171
|
source: {
|
|
172
|
-
type:
|
|
172
|
+
type: 'base64',
|
|
173
173
|
media_type: attachment.mime_type,
|
|
174
|
-
data:
|
|
174
|
+
data: attachment.encoded
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
177
|
end
|
|
@@ -192,10 +192,10 @@ module Legion
|
|
|
192
192
|
|
|
193
193
|
def tool_use_block(tool_call, cache: false)
|
|
194
194
|
{
|
|
195
|
-
type:
|
|
196
|
-
id:
|
|
197
|
-
name:
|
|
198
|
-
input:
|
|
195
|
+
type: 'tool_use',
|
|
196
|
+
id: tool_call.id,
|
|
197
|
+
name: tool_call.name,
|
|
198
|
+
input: tool_call.arguments,
|
|
199
199
|
cache_control: { type: 'ephemeral' }
|
|
200
200
|
}.tap do |block|
|
|
201
201
|
block.delete(:cache_control) unless cache
|
|
@@ -204,12 +204,12 @@ module Legion
|
|
|
204
204
|
|
|
205
205
|
def format_tool_result_message(message, cache: false)
|
|
206
206
|
{
|
|
207
|
-
role:
|
|
207
|
+
role: 'user',
|
|
208
208
|
content: [
|
|
209
209
|
{
|
|
210
|
-
type:
|
|
211
|
-
tool_use_id:
|
|
212
|
-
content:
|
|
210
|
+
type: 'tool_result',
|
|
211
|
+
tool_use_id: message.tool_call_id,
|
|
212
|
+
content: content_blocks(message.content, cache:),
|
|
213
213
|
cache_control: { type: 'ephemeral' }
|
|
214
214
|
}.tap { |block| block.delete(:cache_control) unless cache }
|
|
215
215
|
]
|
|
@@ -256,9 +256,12 @@ module Legion
|
|
|
256
256
|
return nil if tools.empty?
|
|
257
257
|
|
|
258
258
|
tool_array = tools.values.map do |tool|
|
|
259
|
+
# Tools can be ToolDefinition objects or plain Hashes from native_dispatch.
|
|
260
|
+
tool_name = tool.respond_to?(:name) ? tool.name : (tool[:name] || tool['name'])
|
|
261
|
+
tool_desc = tool.respond_to?(:description) ? tool.description : (tool[:description] || tool['description'] || '')
|
|
259
262
|
{
|
|
260
|
-
name:
|
|
261
|
-
description:
|
|
263
|
+
name: tool_name,
|
|
264
|
+
description: tool_desc,
|
|
262
265
|
input_schema: tool_schema(tool)
|
|
263
266
|
}
|
|
264
267
|
end
|
|
@@ -271,7 +274,8 @@ module Legion
|
|
|
271
274
|
def tool_schema(tool)
|
|
272
275
|
return tool.params_schema if tool.respond_to?(:params_schema) && tool.params_schema
|
|
273
276
|
|
|
274
|
-
{ type: 'object',
|
|
277
|
+
{ type: 'object',
|
|
278
|
+
properties: tool.respond_to?(:parameters) ? tool.parameters : (tool[:parameters] || tool['parameters'] || {}), required: [] }
|
|
275
279
|
end
|
|
276
280
|
|
|
277
281
|
def tool_choice(tool_prefs)
|
|
@@ -318,17 +322,17 @@ module Legion
|
|
|
318
322
|
usage = body['usage'] || {}
|
|
319
323
|
|
|
320
324
|
Legion::Extensions::Llm::Message.new(
|
|
321
|
-
role:
|
|
322
|
-
content:
|
|
323
|
-
model_id:
|
|
324
|
-
thinking:
|
|
325
|
-
tool_calls:
|
|
326
|
-
input_tokens:
|
|
327
|
-
output_tokens:
|
|
328
|
-
cached_tokens:
|
|
325
|
+
role: :assistant,
|
|
326
|
+
content: text_from(content_blocks),
|
|
327
|
+
model_id: body['model'],
|
|
328
|
+
thinking: thinking_from(content_blocks),
|
|
329
|
+
tool_calls: parse_tool_calls(content_blocks),
|
|
330
|
+
input_tokens: usage['input_tokens'],
|
|
331
|
+
output_tokens: usage['output_tokens'],
|
|
332
|
+
cached_tokens: usage['cache_read_input_tokens'],
|
|
329
333
|
cache_creation_tokens: cache_creation_tokens(usage),
|
|
330
|
-
thinking_tokens:
|
|
331
|
-
raw:
|
|
334
|
+
thinking_tokens: thinking_tokens(usage),
|
|
335
|
+
raw: body
|
|
332
336
|
)
|
|
333
337
|
end
|
|
334
338
|
|
|
@@ -341,7 +345,7 @@ module Legion
|
|
|
341
345
|
redacted_block = blocks.find { |block| block['type'] == 'redacted_thinking' }
|
|
342
346
|
|
|
343
347
|
Legion::Extensions::Llm::Thinking.build(
|
|
344
|
-
text:
|
|
348
|
+
text: thinking_block&.dig('thinking') || thinking_block&.dig('text'),
|
|
345
349
|
signature: thinking_block&.dig('signature') || redacted_block&.dig('data')
|
|
346
350
|
)
|
|
347
351
|
end
|
|
@@ -364,16 +368,16 @@ module Legion
|
|
|
364
368
|
delta_type = data.dig('delta', 'type')
|
|
365
369
|
|
|
366
370
|
Legion::Extensions::Llm::Chunk.new(
|
|
367
|
-
role:
|
|
368
|
-
content:
|
|
369
|
-
model_id:
|
|
370
|
-
thinking:
|
|
371
|
-
text:
|
|
371
|
+
role: :assistant,
|
|
372
|
+
content: delta_type == 'text_delta' ? data.dig('delta', 'text') : nil,
|
|
373
|
+
model_id: data.dig('message', 'model'),
|
|
374
|
+
thinking: Legion::Extensions::Llm::Thinking.build(
|
|
375
|
+
text: delta_type == 'thinking_delta' ? data.dig('delta', 'thinking') : nil,
|
|
372
376
|
signature: delta_type == 'signature_delta' ? data.dig('delta', 'signature') : nil
|
|
373
377
|
),
|
|
374
|
-
input_tokens:
|
|
378
|
+
input_tokens: data.dig('message', 'usage', 'input_tokens'),
|
|
375
379
|
output_tokens: data.dig('message', 'usage', 'output_tokens') || data.dig('usage', 'output_tokens'),
|
|
376
|
-
tool_calls:
|
|
380
|
+
tool_calls: extract_streaming_tool_calls(data, delta_type)
|
|
377
381
|
)
|
|
378
382
|
end
|
|
379
383
|
|
|
@@ -394,8 +398,8 @@ module Legion
|
|
|
394
398
|
[
|
|
395
399
|
block['id'],
|
|
396
400
|
Legion::Extensions::Llm::ToolCall.new(
|
|
397
|
-
id:
|
|
398
|
-
name:
|
|
401
|
+
id: block['id'],
|
|
402
|
+
name: block['name'],
|
|
399
403
|
arguments: block['input'] || {}
|
|
400
404
|
)
|
|
401
405
|
]
|
|
@@ -408,12 +412,12 @@ module Legion
|
|
|
408
412
|
detail = model_detail(model_id)
|
|
409
413
|
ctx = detail&.dig(:context_window) || infer_context_window(model_id)
|
|
410
414
|
Legion::Extensions::Llm::Model::Info.new(
|
|
411
|
-
id:
|
|
412
|
-
name:
|
|
413
|
-
provider:
|
|
414
|
-
capabilities:
|
|
415
|
+
id: model_id,
|
|
416
|
+
name: model['display_name'] || model_id,
|
|
417
|
+
provider: provider,
|
|
418
|
+
capabilities: %i[completion streaming tools],
|
|
415
419
|
context_length: ctx,
|
|
416
|
-
metadata:
|
|
420
|
+
metadata: model.merge('created_at' => model['created_at']).compact
|
|
417
421
|
)
|
|
418
422
|
end
|
|
419
423
|
end
|
|
@@ -13,8 +13,8 @@ module Legion
|
|
|
13
13
|
def model_available(model, readiness:)
|
|
14
14
|
registry_event_class.available(
|
|
15
15
|
model_offering(model),
|
|
16
|
-
runtime:
|
|
17
|
-
health:
|
|
16
|
+
runtime: runtime_metadata,
|
|
17
|
+
health: model_health(readiness),
|
|
18
18
|
metadata: model_metadata(model)
|
|
19
19
|
)
|
|
20
20
|
end
|
|
@@ -23,14 +23,14 @@ module Legion
|
|
|
23
23
|
|
|
24
24
|
def model_offering(model)
|
|
25
25
|
{
|
|
26
|
-
provider_family:
|
|
26
|
+
provider_family: :anthropic,
|
|
27
27
|
provider_instance: provider_instance,
|
|
28
|
-
transport:
|
|
29
|
-
model:
|
|
30
|
-
usage_type:
|
|
31
|
-
capabilities:
|
|
32
|
-
limits:
|
|
33
|
-
metadata:
|
|
28
|
+
transport: :http,
|
|
29
|
+
model: model.id,
|
|
30
|
+
usage_type: :inference,
|
|
31
|
+
capabilities: Array(model.capabilities).map(&:to_sym),
|
|
32
|
+
limits: model_limits(model),
|
|
33
|
+
metadata: { lex: :llm_anthropic, model_name: model.name }.compact
|
|
34
34
|
}
|
|
35
35
|
end
|
|
36
36
|
|
|
@@ -49,7 +49,7 @@ module Legion
|
|
|
49
49
|
|
|
50
50
|
def model_limits(model)
|
|
51
51
|
{
|
|
52
|
-
context_window:
|
|
52
|
+
context_window: model.context_window,
|
|
53
53
|
max_output_tokens: model.max_output_tokens
|
|
54
54
|
}.compact
|
|
55
55
|
end
|
|
@@ -14,12 +14,12 @@ module Legion
|
|
|
14
14
|
|
|
15
15
|
def handle_fleet_request(payload, delivery: nil, properties: nil)
|
|
16
16
|
Legion::Extensions::Llm::Fleet::ProviderResponder.call(
|
|
17
|
-
payload:
|
|
18
|
-
provider_family:
|
|
19
|
-
provider_class:
|
|
17
|
+
payload: payload,
|
|
18
|
+
provider_family: Anthropic::PROVIDER_FAMILY,
|
|
19
|
+
provider_class: Anthropic::Provider,
|
|
20
20
|
provider_instances: -> { Anthropic.discover_instances },
|
|
21
|
-
delivery:
|
|
22
|
-
properties:
|
|
21
|
+
delivery: delivery,
|
|
22
|
+
properties: properties
|
|
23
23
|
)
|
|
24
24
|
end
|
|
25
25
|
end
|
|
@@ -11,7 +11,7 @@ module Legion
|
|
|
11
11
|
module Extensions
|
|
12
12
|
module Llm
|
|
13
13
|
# Anthropic provider extension namespace.
|
|
14
|
-
module Anthropic
|
|
14
|
+
module Anthropic
|
|
15
15
|
extend ::Legion::Extensions::Core if ::Legion::Extensions.const_defined?(:Core, false)
|
|
16
16
|
extend Legion::Logging::Helper
|
|
17
17
|
extend Legion::Extensions::Llm::AutoRegistration
|
|
@@ -20,24 +20,24 @@ module Legion
|
|
|
20
20
|
|
|
21
21
|
def self.default_settings
|
|
22
22
|
::Legion::Extensions::Llm.provider_settings(
|
|
23
|
-
family:
|
|
23
|
+
family: PROVIDER_FAMILY,
|
|
24
24
|
instance: {
|
|
25
|
-
default_model:
|
|
26
|
-
endpoint:
|
|
27
|
-
api_version:
|
|
25
|
+
default_model: 'claude-sonnet-4-6',
|
|
26
|
+
endpoint: 'https://api.anthropic.com',
|
|
27
|
+
api_version: '2023-10-16',
|
|
28
28
|
default_max_tokens: 4096,
|
|
29
|
-
tier:
|
|
30
|
-
transport:
|
|
31
|
-
credentials:
|
|
32
|
-
usage:
|
|
33
|
-
limits:
|
|
34
|
-
fleet:
|
|
35
|
-
enabled:
|
|
29
|
+
tier: :frontier,
|
|
30
|
+
transport: :http,
|
|
31
|
+
credentials: { api_key: 'env://ANTHROPIC_API_KEY' },
|
|
32
|
+
usage: { inference: true, embedding: false, image: false },
|
|
33
|
+
limits: { concurrency: 4 },
|
|
34
|
+
fleet: {
|
|
35
|
+
enabled: false,
|
|
36
36
|
respond_to_requests: false,
|
|
37
|
-
capabilities:
|
|
38
|
-
lanes:
|
|
39
|
-
concurrency:
|
|
40
|
-
queue_suffix:
|
|
37
|
+
capabilities: %i[chat stream_chat],
|
|
38
|
+
lanes: [],
|
|
39
|
+
concurrency: 4,
|
|
40
|
+
queue_suffix: nil
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
)
|
|
@@ -51,16 +51,16 @@ module Legion
|
|
|
51
51
|
[]
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
def self.discover_instances
|
|
54
|
+
def self.discover_instances
|
|
55
55
|
candidates = {}
|
|
56
56
|
|
|
57
57
|
env_key = CredentialSources.env('ANTHROPIC_API_KEY')
|
|
58
58
|
if env_key
|
|
59
59
|
candidates[:env] = {
|
|
60
|
-
api_key:
|
|
61
|
-
anthropic_api_key:
|
|
62
|
-
tier:
|
|
63
|
-
source:
|
|
60
|
+
api_key: env_key,
|
|
61
|
+
anthropic_api_key: env_key,
|
|
62
|
+
tier: :frontier,
|
|
63
|
+
source: CredentialSources.source_tag(:env, 'ANTHROPIC_API_KEY'),
|
|
64
64
|
credential_fingerprint: CredentialSources.credential_fingerprint(env_key)
|
|
65
65
|
}
|
|
66
66
|
end
|
|
@@ -68,10 +68,10 @@ module Legion
|
|
|
68
68
|
claude_key = CredentialSources.claude_config_value(:anthropicApiKey)
|
|
69
69
|
if claude_key
|
|
70
70
|
candidates[:claude] = {
|
|
71
|
-
api_key:
|
|
72
|
-
anthropic_api_key:
|
|
73
|
-
tier:
|
|
74
|
-
source:
|
|
71
|
+
api_key: claude_key,
|
|
72
|
+
anthropic_api_key: claude_key,
|
|
73
|
+
tier: :frontier,
|
|
74
|
+
source: CredentialSources.source_tag(:file, '~/.claude/settings.json', 'anthropicApiKey'),
|
|
75
75
|
credential_fingerprint: CredentialSources.credential_fingerprint(claude_key)
|
|
76
76
|
}
|
|
77
77
|
end
|
|
@@ -81,10 +81,10 @@ module Legion
|
|
|
81
81
|
settings_key = settings_config[:api_key] || settings_config['api_key']
|
|
82
82
|
if settings_key
|
|
83
83
|
candidates[:settings] = normalize_instance_config(settings_config).merge(
|
|
84
|
-
api_key:
|
|
85
|
-
anthropic_api_key:
|
|
86
|
-
tier:
|
|
87
|
-
source:
|
|
84
|
+
api_key: settings_key,
|
|
85
|
+
anthropic_api_key: settings_key,
|
|
86
|
+
tier: :frontier,
|
|
87
|
+
source: CredentialSources.source_tag(:settings, 'extensions.llm.anthropic'),
|
|
88
88
|
credential_fingerprint: CredentialSources.credential_fingerprint(settings_key)
|
|
89
89
|
)
|
|
90
90
|
end
|
|
@@ -108,10 +108,10 @@ module Legion
|
|
|
108
108
|
broker_cred = Legion::Identity::Broker.credential_for(:anthropic)
|
|
109
109
|
if broker_cred
|
|
110
110
|
candidates[:broker] = {
|
|
111
|
-
api_key:
|
|
112
|
-
anthropic_api_key:
|
|
113
|
-
tier:
|
|
114
|
-
source:
|
|
111
|
+
api_key: broker_cred,
|
|
112
|
+
anthropic_api_key: broker_cred,
|
|
113
|
+
tier: :frontier,
|
|
114
|
+
source: CredentialSources.source_tag(:broker, 'identity', 'anthropic'),
|
|
115
115
|
credential_fingerprint: CredentialSources.credential_fingerprint(broker_cred)
|
|
116
116
|
}
|
|
117
117
|
end
|
|
@@ -130,7 +130,7 @@ module Legion
|
|
|
130
130
|
instances.is_a?(Hash) ? instances : {}
|
|
131
131
|
end
|
|
132
132
|
|
|
133
|
-
def self.normalize_instance_config(config)
|
|
133
|
+
def self.normalize_instance_config(config)
|
|
134
134
|
normalized = config.to_h.transform_keys { |key| key.respond_to?(:to_sym) ? key.to_sym : key }
|
|
135
135
|
normalized[:anthropic_api_key] ||= normalized.delete(:api_key)
|
|
136
136
|
normalized[:anthropic_api_base] ||= normalized.delete(:base_url)
|