Class: Ask::Providers::Bedrock
- Inherits:
-
Ask::Provider
- Object
- Ask::Provider
- Ask::Providers::Bedrock
- Includes:
- LLM::ProviderConfig
- Defined in:
- lib/ask/provider/bedrock.rb
Overview
Amazon Bedrock provider using the Converse API. Uses the AWS SDK for authentication (credentials chain: env, ~/.aws, instance profile).
Class Method Summary collapse
- .capabilities ⇒ Object
- .configuration_options ⇒ Object
- .configuration_requirements ⇒ Object
- .slug ⇒ Object
Instance Method Summary collapse
- #api_base ⇒ Object
-
#build_request(messages, model:, tools: nil, temperature: nil, stream: nil, schema: nil, **params) ⇒ Object
--- Config transformation contract ---.
- #chat(messages, model:, tools: nil, temperature: nil, stream: nil, schema: nil, **params, &block) ⇒ Object
- #embed(_texts, model: nil) ⇒ Object
- #format_message(msg) ⇒ Object
- #format_tools(tools) ⇒ Object
-
#initialize(config = {}) ⇒ Bedrock
constructor
A new instance of Bedrock.
- #list_models ⇒ Object
- #parse_error(response) ⇒ Object
- #parse_response(body, model) ⇒ Object
- #parse_stream(raw, stream, model, &block) ⇒ Object
Constructor Details
#initialize(config = {}) ⇒ Bedrock
Returns a new instance of Bedrock.
10 11 12 13 |
# File 'lib/ask/provider/bedrock.rb', line 10 def initialize(config = {}) config = normalize_config(config) super(config) end |
Class Method Details
.capabilities ⇒ Object
44 45 46 |
# File 'lib/ask/provider/bedrock.rb', line 44 def capabilities { chat: true, streaming: true, tool_calls: true, vision: true } end |
.configuration_options ⇒ Object
48 |
# File 'lib/ask/provider/bedrock.rb', line 48 def ; %i[region access_key_id secret_access_key session_token]; end |
.configuration_requirements ⇒ Object
49 |
# File 'lib/ask/provider/bedrock.rb', line 49 def configuration_requirements; %i[]; end |
.slug ⇒ Object
42 |
# File 'lib/ask/provider/bedrock.rb', line 42 def slug; "bedrock"; end |
Instance Method Details
#api_base ⇒ Object
15 16 17 |
# File 'lib/ask/provider/bedrock.rb', line 15 def api_base @config.region || "us-east-1" end |
#build_request(messages, model:, tools: nil, temperature: nil, stream: nil, schema: nil, **params) ⇒ Object
--- Config transformation contract ---
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/ask/provider/bedrock.rb', line 54 def build_request(, model:, tools: nil, temperature: nil, stream: nil, schema: nil, **params) system_msgs, chat_msgs = .partition { |m| (m[:role] || m["role"]).to_s == "system" } payload = { modelId: model, messages: chat_msgs.map { |m| (m) }, inferenceConfig: { temperature: temperature || 1.0 }.compact } sys = system_msgs.map { |m| m[:content] || m["content"] }.compact payload[:system] = sys.map { |s| { text: s } } if sys.any? tool_defs = format_tools(tools) if tools&.any? payload[:toolConfig] = { tools: tool_defs } if tool_defs if schema payload[:inferenceConfig][:response_type] = "json_object" end payload.merge(params) end |
#chat(messages, model:, tools: nil, temperature: nil, stream: nil, schema: nil, **params, &block) ⇒ Object
19 20 21 22 23 24 25 26 27 |
# File 'lib/ask/provider/bedrock.rb', line 19 def chat(, model:, tools: nil, temperature: nil, stream: nil, schema: nil, **params, &block) msgs = .is_a?(Ask::Conversation) ? .to_a : payload = build_request(msgs, model:, tools:, temperature:, stream:, schema:, **params) if stream chat_stream(payload, model, &block) else chat_nonstream(payload, model) end end |
#embed(_texts, model: nil) ⇒ Object
29 30 31 |
# File 'lib/ask/provider/bedrock.rb', line 29 def (_texts, model: nil) raise Ask::CapabilityNotSupported, "Bedrock does not support embeddings via Converse API" end |
#format_message(msg) ⇒ Object
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/ask/provider/bedrock.rb', line 119 def (msg) role = (msg[:role] || msg["role"]).to_s content = msg[:content] || msg["content"] bedrock_role = role == "assistant" ? "assistant" : "user" parts = [] parts << { text: content } if content if msg[:tool_calls] || msg["tool_calls"] (msg[:tool_calls] || msg["tool_calls"]).each do |tc| parts << { toolUse: { toolUseId: tc[:id] || tc["id"], name: tc.dig(:function, :name) || tc.dig("function", "name") || tc[:name], input: parse_json(tc.dig(:function, :arguments) || tc.dig("function", "arguments") || tc[:arguments] || "{}") } } end end if msg[:tool_call_id] || msg["tool_call_id"] parts << { toolResult: { toolUseId: msg[:tool_call_id] || msg["tool_call_id"], content: [{ text: content || "" }] } } bedrock_role = "user" end { role: bedrock_role, content: parts } end |
#format_tools(tools) ⇒ Object
152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/ask/provider/bedrock.rb', line 152 def format_tools(tools) tools.map do |t| { toolSpec: { name: t.respond_to?(:name) ? t.name : t[:name], description: t.respond_to?(:description) ? t.description : t[:description], inputSchema: { json: t.respond_to?(:parameters) ? t.parameters : (t[:parameters] || { type: "object", properties: {} }) } } } end end |
#list_models ⇒ Object
33 34 35 |
# File 'lib/ask/provider/bedrock.rb', line 33 def list_models [] end |
#parse_error(response) ⇒ Object
37 38 39 |
# File 'lib/ask/provider/bedrock.rb', line 37 def parse_error(response) response.body["message"] rescue nil end |
#parse_response(body, model) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/ask/provider/bedrock.rb', line 72 def parse_response(body, model) output = body.output return Ask::Message.new(role: :assistant, content: nil) unless output msg = output. text = msg.content&.map { |c| c.text }&.compact&.join tool_uses = msg.content&.select { |c| c.tool_use } || [] tool_calls = tool_uses.map do |tu| { id: tu.tool_use.tool_use_id, type: "function", name: tu.tool_use.name, arguments: JSON.generate(tu.tool_use.input.to_h) } end usage = body.usage || {} Ask::Message.new( role: :assistant, content: text, tool_calls: tool_calls.empty? ? nil : tool_calls, metadata: { model:, stop_reason: body.stop_reason, input_tokens: usage.input_tokens, output_tokens: usage.output_tokens, raw: body.to_h } ) end |
#parse_stream(raw, stream, model, &block) ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/ask/provider/bedrock.rb', line 98 def parse_stream(raw, stream, model, &block) event = raw if event.content_block_delta delta = event.content_block_delta.delta if delta.respond_to?(:text) chunk = Ask::Chunk.new(content: delta.text) stream.add(chunk) yield chunk if block_given? end end if event. usage = event..usage || {} chunk = Ask::Chunk.new( finish_reason: "stop", usage: { input_tokens: usage.input_tokens, output_tokens: usage.output_tokens } ) stream.add(chunk) yield chunk if block_given? end end |