activeagent 1.0.0.rc1 → 1.0.1
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 +102 -1
- data/lib/active_agent/providers/_base_provider.rb +94 -82
- data/lib/active_agent/providers/anthropic/_types.rb +2 -2
- data/lib/active_agent/providers/anthropic/options.rb +4 -6
- data/lib/active_agent/providers/anthropic/request.rb +157 -78
- data/lib/active_agent/providers/anthropic/transforms.rb +482 -0
- data/lib/active_agent/providers/anthropic_provider.rb +159 -59
- data/lib/active_agent/providers/common/messages/_types.rb +46 -3
- data/lib/active_agent/providers/common/messages/assistant.rb +20 -4
- data/lib/active_agent/providers/common/responses/base.rb +118 -70
- data/lib/active_agent/providers/common/usage.rb +385 -0
- data/lib/active_agent/providers/concerns/instrumentation.rb +263 -0
- data/lib/active_agent/providers/concerns/previewable.rb +39 -5
- data/lib/active_agent/providers/concerns/tool_choice_clearing.rb +62 -0
- data/lib/active_agent/providers/log_subscriber.rb +64 -246
- data/lib/active_agent/providers/mock_provider.rb +23 -23
- data/lib/active_agent/providers/ollama/chat/request.rb +214 -35
- data/lib/active_agent/providers/ollama/chat/transforms.rb +135 -0
- data/lib/active_agent/providers/ollama/embedding/request.rb +160 -47
- data/lib/active_agent/providers/ollama/embedding/transforms.rb +160 -0
- data/lib/active_agent/providers/ollama_provider.rb +0 -1
- data/lib/active_agent/providers/open_ai/_base.rb +3 -2
- data/lib/active_agent/providers/open_ai/chat/_types.rb +13 -1
- data/lib/active_agent/providers/open_ai/chat/request.rb +132 -186
- data/lib/active_agent/providers/open_ai/chat/transforms.rb +444 -0
- data/lib/active_agent/providers/open_ai/chat_provider.rb +95 -36
- data/lib/active_agent/providers/open_ai/embedding/_types.rb +13 -2
- data/lib/active_agent/providers/open_ai/embedding/request.rb +38 -70
- data/lib/active_agent/providers/open_ai/embedding/transforms.rb +88 -0
- data/lib/active_agent/providers/open_ai/responses/_types.rb +1 -7
- data/lib/active_agent/providers/open_ai/responses/request.rb +116 -135
- data/lib/active_agent/providers/open_ai/responses/transforms.rb +363 -0
- data/lib/active_agent/providers/open_ai/responses_provider.rb +115 -30
- data/lib/active_agent/providers/open_ai_provider.rb +0 -3
- data/lib/active_agent/providers/open_router/_types.rb +27 -1
- data/lib/active_agent/providers/open_router/options.rb +49 -1
- data/lib/active_agent/providers/open_router/request.rb +252 -66
- data/lib/active_agent/providers/open_router/requests/_types.rb +0 -1
- data/lib/active_agent/providers/open_router/requests/messages/_types.rb +37 -40
- data/lib/active_agent/providers/open_router/requests/messages/content/file.rb +19 -3
- data/lib/active_agent/providers/open_router/requests/messages/content/files/details.rb +15 -4
- data/lib/active_agent/providers/open_router/requests/plugin.rb +19 -3
- data/lib/active_agent/providers/open_router/requests/plugins/pdf_config.rb +30 -8
- data/lib/active_agent/providers/open_router/requests/prediction.rb +17 -0
- data/lib/active_agent/providers/open_router/requests/provider_preferences/max_price.rb +41 -7
- data/lib/active_agent/providers/open_router/requests/provider_preferences.rb +60 -19
- data/lib/active_agent/providers/open_router/requests/response_format.rb +30 -2
- data/lib/active_agent/providers/open_router/transforms.rb +164 -0
- data/lib/active_agent/providers/open_router_provider.rb +23 -0
- data/lib/active_agent/version.rb +1 -1
- metadata +17 -160
- data/lib/active_agent/generation_provider/open_router/types.rb +0 -505
- data/lib/active_agent/generation_provider/xai_provider.rb +0 -144
- data/lib/active_agent/providers/anthropic/requests/_types.rb +0 -190
- data/lib/active_agent/providers/anthropic/requests/container_params.rb +0 -19
- data/lib/active_agent/providers/anthropic/requests/content/base.rb +0 -21
- data/lib/active_agent/providers/anthropic/requests/content/sources/base.rb +0 -22
- data/lib/active_agent/providers/anthropic/requests/context_management_config.rb +0 -18
- data/lib/active_agent/providers/anthropic/requests/messages/_types.rb +0 -189
- data/lib/active_agent/providers/anthropic/requests/messages/assistant.rb +0 -23
- data/lib/active_agent/providers/anthropic/requests/messages/base.rb +0 -63
- data/lib/active_agent/providers/anthropic/requests/messages/content/_types.rb +0 -143
- data/lib/active_agent/providers/anthropic/requests/messages/content/base.rb +0 -21
- data/lib/active_agent/providers/anthropic/requests/messages/content/document.rb +0 -26
- data/lib/active_agent/providers/anthropic/requests/messages/content/image.rb +0 -23
- data/lib/active_agent/providers/anthropic/requests/messages/content/redacted_thinking.rb +0 -21
- data/lib/active_agent/providers/anthropic/requests/messages/content/search_result.rb +0 -27
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/_types.rb +0 -171
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/base.rb +0 -22
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_base64.rb +0 -25
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_file.rb +0 -23
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_text.rb +0 -25
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_url.rb +0 -23
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_base64.rb +0 -27
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_file.rb +0 -23
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_url.rb +0 -23
- data/lib/active_agent/providers/anthropic/requests/messages/content/text.rb +0 -22
- data/lib/active_agent/providers/anthropic/requests/messages/content/thinking.rb +0 -23
- data/lib/active_agent/providers/anthropic/requests/messages/content/tool_result.rb +0 -24
- data/lib/active_agent/providers/anthropic/requests/messages/content/tool_use.rb +0 -28
- data/lib/active_agent/providers/anthropic/requests/messages/user.rb +0 -21
- data/lib/active_agent/providers/anthropic/requests/metadata.rb +0 -18
- data/lib/active_agent/providers/anthropic/requests/response_format.rb +0 -22
- data/lib/active_agent/providers/anthropic/requests/thinking_config/_types.rb +0 -60
- data/lib/active_agent/providers/anthropic/requests/thinking_config/base.rb +0 -20
- data/lib/active_agent/providers/anthropic/requests/thinking_config/disabled.rb +0 -16
- data/lib/active_agent/providers/anthropic/requests/thinking_config/enabled.rb +0 -20
- data/lib/active_agent/providers/anthropic/requests/tool_choice/_types.rb +0 -78
- data/lib/active_agent/providers/anthropic/requests/tool_choice/any.rb +0 -17
- data/lib/active_agent/providers/anthropic/requests/tool_choice/auto.rb +0 -17
- data/lib/active_agent/providers/anthropic/requests/tool_choice/base.rb +0 -20
- data/lib/active_agent/providers/anthropic/requests/tool_choice/none.rb +0 -16
- data/lib/active_agent/providers/anthropic/requests/tool_choice/tool.rb +0 -20
- data/lib/active_agent/providers/ollama/chat/requests/_types.rb +0 -3
- data/lib/active_agent/providers/ollama/chat/requests/messages/_types.rb +0 -116
- data/lib/active_agent/providers/ollama/chat/requests/messages/assistant.rb +0 -19
- data/lib/active_agent/providers/ollama/chat/requests/messages/user.rb +0 -19
- data/lib/active_agent/providers/ollama/embedding/requests/_types.rb +0 -83
- data/lib/active_agent/providers/ollama/embedding/requests/options.rb +0 -104
- data/lib/active_agent/providers/open_ai/chat/requests/_types.rb +0 -229
- data/lib/active_agent/providers/open_ai/chat/requests/audio.rb +0 -24
- data/lib/active_agent/providers/open_ai/chat/requests/messages/_types.rb +0 -123
- data/lib/active_agent/providers/open_ai/chat/requests/messages/assistant.rb +0 -42
- data/lib/active_agent/providers/open_ai/chat/requests/messages/base.rb +0 -78
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/_types.rb +0 -133
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/audio.rb +0 -35
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/base.rb +0 -24
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/file.rb +0 -26
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/files/_types.rb +0 -60
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/files/details.rb +0 -41
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/image.rb +0 -37
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/refusal.rb +0 -25
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/text.rb +0 -25
- data/lib/active_agent/providers/open_ai/chat/requests/messages/developer.rb +0 -25
- data/lib/active_agent/providers/open_ai/chat/requests/messages/function.rb +0 -25
- data/lib/active_agent/providers/open_ai/chat/requests/messages/system.rb +0 -25
- data/lib/active_agent/providers/open_ai/chat/requests/messages/tool.rb +0 -26
- data/lib/active_agent/providers/open_ai/chat/requests/messages/user.rb +0 -32
- data/lib/active_agent/providers/open_ai/chat/requests/prediction.rb +0 -46
- data/lib/active_agent/providers/open_ai/chat/requests/response_format.rb +0 -53
- data/lib/active_agent/providers/open_ai/chat/requests/stream_options.rb +0 -24
- data/lib/active_agent/providers/open_ai/chat/requests/tool_choice.rb +0 -26
- data/lib/active_agent/providers/open_ai/chat/requests/tools/_types.rb +0 -5
- data/lib/active_agent/providers/open_ai/chat/requests/tools/base.rb +0 -22
- data/lib/active_agent/providers/open_ai/chat/requests/tools/custom_tool.rb +0 -41
- data/lib/active_agent/providers/open_ai/chat/requests/tools/function_tool.rb +0 -51
- data/lib/active_agent/providers/open_ai/chat/requests/web_search_options.rb +0 -45
- data/lib/active_agent/providers/open_ai/embedding/requests/_types.rb +0 -49
- data/lib/active_agent/providers/open_ai/responses/requests/_types.rb +0 -231
- data/lib/active_agent/providers/open_ai/responses/requests/conversation.rb +0 -23
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/_types.rb +0 -264
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/assistant_message.rb +0 -22
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/base.rb +0 -89
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/code_interpreter_tool_call.rb +0 -30
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/computer_tool_call.rb +0 -28
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/computer_tool_call_output.rb +0 -33
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/_types.rb +0 -207
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/base.rb +0 -22
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_audio.rb +0 -26
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_file.rb +0 -28
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_image.rb +0 -28
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_text.rb +0 -25
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/custom_tool_call.rb +0 -28
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/custom_tool_call_output.rb +0 -27
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/developer_message.rb +0 -20
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/file_search_tool_call.rb +0 -25
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/function_call_output.rb +0 -32
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/function_tool_call.rb +0 -28
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/image_gen_tool_call.rb +0 -27
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/input_message.rb +0 -31
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/item_reference.rb +0 -23
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/local_shell_tool_call.rb +0 -26
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/local_shell_tool_call_output.rb +0 -33
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_approval_request.rb +0 -30
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_approval_response.rb +0 -28
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_list_tools.rb +0 -29
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_tool_call.rb +0 -35
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/output_message.rb +0 -35
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/reasoning.rb +0 -33
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/system_message.rb +0 -20
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/tool_call_base.rb +0 -27
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/tool_message.rb +0 -23
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/user_message.rb +0 -20
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/web_search_tool_call.rb +0 -24
- data/lib/active_agent/providers/open_ai/responses/requests/prompt_reference.rb +0 -23
- data/lib/active_agent/providers/open_ai/responses/requests/reasoning.rb +0 -23
- data/lib/active_agent/providers/open_ai/responses/requests/stream_options.rb +0 -20
- data/lib/active_agent/providers/open_ai/responses/requests/text/_types.rb +0 -89
- data/lib/active_agent/providers/open_ai/responses/requests/text/base.rb +0 -22
- data/lib/active_agent/providers/open_ai/responses/requests/text/json_object.rb +0 -20
- data/lib/active_agent/providers/open_ai/responses/requests/text/json_schema.rb +0 -48
- data/lib/active_agent/providers/open_ai/responses/requests/text/plain.rb +0 -20
- data/lib/active_agent/providers/open_ai/responses/requests/text.rb +0 -41
- data/lib/active_agent/providers/open_ai/responses/requests/tool_choice.rb +0 -26
- data/lib/active_agent/providers/open_ai/responses/requests/tools/_types.rb +0 -112
- data/lib/active_agent/providers/open_ai/responses/requests/tools/base.rb +0 -25
- data/lib/active_agent/providers/open_ai/responses/requests/tools/code_interpreter_tool.rb +0 -23
- data/lib/active_agent/providers/open_ai/responses/requests/tools/computer_tool.rb +0 -27
- data/lib/active_agent/providers/open_ai/responses/requests/tools/custom_tool.rb +0 -28
- data/lib/active_agent/providers/open_ai/responses/requests/tools/file_search_tool.rb +0 -27
- data/lib/active_agent/providers/open_ai/responses/requests/tools/function_tool.rb +0 -29
- data/lib/active_agent/providers/open_ai/responses/requests/tools/image_generation_tool.rb +0 -37
- data/lib/active_agent/providers/open_ai/responses/requests/tools/local_shell_tool.rb +0 -21
- data/lib/active_agent/providers/open_ai/responses/requests/tools/mcp_tool.rb +0 -41
- data/lib/active_agent/providers/open_ai/responses/requests/tools/web_search_preview_tool.rb +0 -24
- data/lib/active_agent/providers/open_ai/responses/requests/tools/web_search_tool.rb +0 -25
- data/lib/active_agent/providers/open_ai/schema.yml +0 -65937
- data/lib/active_agent/providers/open_router/requests/message.rb +0 -1
- data/lib/active_agent/providers/open_router/requests/messages/assistant.rb +0 -20
- data/lib/active_agent/providers/open_router/requests/messages/user.rb +0 -30
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6ee3a092c5c836febf3c2e3045a1c1b2cd448edc18f3e76e4ee1ebc181f895b8
|
|
4
|
+
data.tar.gz: 9850ab912eedaac0a57f9a954648d096d6aa70ad470ff9aa7c84a18183ab76be
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 199061594f115a823037504f84daf5ebc79b084c8a835b3e67f5427a19ffe33bbe208bb627dc26b1abf977c4d35a2977defcfb59e9128e60d94c6a3dc0ce5259
|
|
7
|
+
data.tar.gz: 661bf403014e2a0d1156614249b9fcdc352b8124e63457071ce75399ac69d089cf2d43d8b571e41614d811a5e6dc4ebc9072dfe38d912bc122672bf9823bb331
|
data/CHANGELOG.md
CHANGED
|
@@ -5,11 +5,82 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [1.0.0] -
|
|
8
|
+
## [1.0.0] - 2025-11-21
|
|
9
9
|
|
|
10
10
|
Major refactor with breaking changes. Complete provider rewrite. New modular architecture.
|
|
11
11
|
|
|
12
12
|
**Requirements:** Ruby 3.1+, Rails 7.0+/8.0+/8.1+
|
|
13
|
+
## What's Changed
|
|
14
|
+
* Major Framework Refactor: ActiveAgent v1.0.0 by @sirwolfgang in https://github.com/activeagents/activeagent/pull/259
|
|
15
|
+
* Add API gem version testing and fix Anthropic 1.14.0 compatibility by @sirwolfgang in https://github.com/activeagents/activeagent/pull/265
|
|
16
|
+
* Fix version compatiblity issue for vitepress by @sirwolfgang in https://github.com/activeagents/activeagent/pull/266
|
|
17
|
+
* Add missing API Keys by @sirwolfgang in https://github.com/activeagents/activeagent/pull/267
|
|
18
|
+
* Fix website links by @sirwolfgang in https://github.com/activeagents/activeagent/pull/268
|
|
19
|
+
* chore: remove `standard` from dev dependencies by @okuramasafumi in https://github.com/activeagents/activeagent/pull/272
|
|
20
|
+
* Add thread safety tests by @sirwolfgang in https://github.com/activeagents/activeagent/pull/275
|
|
21
|
+
* Refactor: Leverage Native Gem Types Across All Providers by @sirwolfgang in https://github.com/activeagents/activeagent/pull/271
|
|
22
|
+
* Improved Usage Tracking by @sirwolfgang in https://github.com/activeagents/activeagent/pull/274
|
|
23
|
+
|
|
24
|
+
## New Contributors
|
|
25
|
+
* @okuramasafumi made their first contribution in https://github.com/activeagents/activeagent/pull/272
|
|
26
|
+
|
|
27
|
+
**Full Changelog**: https://github.com/activeagents/activeagent/compare/v0.6.3...v1.0.0
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
**Universal Tools Format**
|
|
32
|
+
```ruby
|
|
33
|
+
# Single format works across all providers (Anthropic, OpenAI, OpenRouter, Ollama, Mock)
|
|
34
|
+
tools: [{
|
|
35
|
+
name: "get_weather",
|
|
36
|
+
description: "Get current weather",
|
|
37
|
+
parameters: {
|
|
38
|
+
type: "object",
|
|
39
|
+
properties: {
|
|
40
|
+
location: { type: "string", description: "City and state" }
|
|
41
|
+
},
|
|
42
|
+
required: ["location"]
|
|
43
|
+
}
|
|
44
|
+
}]
|
|
45
|
+
|
|
46
|
+
# Tool choice normalization
|
|
47
|
+
tool_choice: "auto" # Let model decide
|
|
48
|
+
tool_choice: "required" # Force tool use
|
|
49
|
+
tool_choice: { name: "get_weather" } # Force specific tool
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Automatic conversion to provider-specific formats. Old formats still work (backward compatible).
|
|
53
|
+
|
|
54
|
+
**Model Context Protocol (MCP) Support**
|
|
55
|
+
```ruby
|
|
56
|
+
# Universal MCP format works across providers (Anthropic, OpenAI)
|
|
57
|
+
class MyAgent < ActiveAgent::Base
|
|
58
|
+
generate_with :anthropic, model: "claude-haiku-4-5"
|
|
59
|
+
|
|
60
|
+
def research
|
|
61
|
+
prompt(
|
|
62
|
+
message: "Research AI developments",
|
|
63
|
+
mcps: [{
|
|
64
|
+
name: "github",
|
|
65
|
+
url: "https://api.githubcopilot.com/mcp/",
|
|
66
|
+
authorization: ENV["GITHUB_MCP_TOKEN"]
|
|
67
|
+
}]
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
- Common format: `{name: "server", url: "https://...", authorization: "token"}`
|
|
74
|
+
- Auto-converts to provider native formats
|
|
75
|
+
- Anthropic: Beta API support, up to 20 servers per request
|
|
76
|
+
- OpenAI: Responses API with pre-built connectors (Dropbox, Google Drive, etc.)
|
|
77
|
+
- Backwards compatible: accepts both `mcps` and `mcp_servers` parameters
|
|
78
|
+
- Comprehensive documentation with tested examples
|
|
79
|
+
- Full VCR test coverage with real MCP endpoints
|
|
80
|
+
|
|
81
|
+
### Changed
|
|
82
|
+
|
|
83
|
+
- Shared `ToolChoiceClearing` concern eliminates duplication across providers
|
|
13
84
|
|
|
14
85
|
### Breaking Changes
|
|
15
86
|
|
|
@@ -148,6 +219,35 @@ response = MyAgent.embed(inputs: ["Text 1", "Text 2"]).embed_now
|
|
|
148
219
|
vectors = response.data.map { |d| d[:embedding] }
|
|
149
220
|
```
|
|
150
221
|
|
|
222
|
+
**Normalized Usage Statistics**
|
|
223
|
+
```ruby
|
|
224
|
+
response = MyAgent.prompt("Hello").generate_now
|
|
225
|
+
|
|
226
|
+
# Works across all providers
|
|
227
|
+
response.usage.input_tokens
|
|
228
|
+
response.usage.output_tokens
|
|
229
|
+
response.usage.total_tokens
|
|
230
|
+
|
|
231
|
+
# Provider-specific fields when available
|
|
232
|
+
response.usage.cached_tokens # OpenAI, Anthropic
|
|
233
|
+
response.usage.reasoning_tokens # OpenAI o1 models
|
|
234
|
+
response.usage.service_tier # Anthropic
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Enhanced Instrumentation for APM Integration**
|
|
238
|
+
- Unified event structure: `prompt.active_agent` and `embed.active_agent` (top-level) plus `prompt.provider.active_agent` and `embed.provider.active_agent` (per-API-call)
|
|
239
|
+
- Event payloads include comprehensive data for monitoring tools (New Relic, DataDog, etc.):
|
|
240
|
+
- Request parameters: `model`, `temperature`, `max_tokens`, `top_p`, `stream`, `message_count`, `has_tools`
|
|
241
|
+
- Usage data: `input_tokens`, `output_tokens`, `total_tokens`, `cached_tokens`, `reasoning_tokens`, `audio_tokens`, `cache_creation_tokens` (critical for cost tracking)
|
|
242
|
+
- Response metadata: `finish_reason`, `response_model`, `response_id`, `embedding_count`
|
|
243
|
+
- Top-level events report cumulative usage across all API calls in multi-turn conversations
|
|
244
|
+
- Provider-level events report per-call usage for granular tracking
|
|
245
|
+
|
|
246
|
+
**Multi-Turn Usage Tracking**
|
|
247
|
+
- `response.usage` now returns cumulative token counts across all API calls during tool calling
|
|
248
|
+
- New `response.usages` array contains individual usage objects from each API call
|
|
249
|
+
- `Usage` objects support addition: `usage1 + usage2` for combining statistics
|
|
250
|
+
|
|
151
251
|
**Provider Enhancements**
|
|
152
252
|
- OpenAI Responses API: `api: :responses` or `api: :chat`
|
|
153
253
|
- Anthropic JSON object mode with automatic extraction
|
|
@@ -195,6 +295,7 @@ vectors = response.data.map { |d| d[:embedding] }
|
|
|
195
295
|
- Template rendering without blocks
|
|
196
296
|
- Schema generator key symbolization
|
|
197
297
|
- Rails 8.0 and 8.1 compatibility
|
|
298
|
+
- Usage extraction across OpenAI/Anthropic response formats
|
|
198
299
|
|
|
199
300
|
### Removed
|
|
200
301
|
|
|
@@ -2,21 +2,22 @@ require "active_support/delegation"
|
|
|
2
2
|
|
|
3
3
|
require_relative "common/response"
|
|
4
4
|
require_relative "concerns/exception_handler"
|
|
5
|
+
require_relative "concerns/instrumentation"
|
|
5
6
|
require_relative "concerns/previewable"
|
|
7
|
+
require_relative "concerns/tool_choice_clearing"
|
|
6
8
|
|
|
7
|
-
# Maps provider types to their gem dependencies.
|
|
8
9
|
# @private
|
|
9
10
|
GEM_LOADERS = {
|
|
10
11
|
anthropic: [ "anthropic", "~> 1.12", "anthropic" ],
|
|
11
12
|
openai: [ "openai", "~> 0.34", "openai" ]
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
#
|
|
15
|
+
# Requires a provider's gem dependency.
|
|
15
16
|
#
|
|
16
17
|
# @param type [Symbol] provider type (:anthropic, :openai)
|
|
17
|
-
# @param file_name [String]
|
|
18
|
+
# @param file_name [String] for error context
|
|
18
19
|
# @return [void]
|
|
19
|
-
# @raise [LoadError] when
|
|
20
|
+
# @raise [LoadError] when required gem is not installed
|
|
20
21
|
def require_gem!(type, file_name)
|
|
21
22
|
gem_name, requirement, package_name = GEM_LOADERS.fetch(type)
|
|
22
23
|
provider_name = file_name.split("/").last.delete_suffix(".rb").camelize
|
|
@@ -31,9 +32,8 @@ end
|
|
|
31
32
|
|
|
32
33
|
module ActiveAgent
|
|
33
34
|
module Providers
|
|
34
|
-
#
|
|
35
|
+
# Orchestrates LLM provider API requests, streaming, and multi-turn tool calling.
|
|
35
36
|
#
|
|
36
|
-
# Orchestrates API requests, streaming responses, and multi-turn tool calling.
|
|
37
37
|
# Each provider (OpenAI, Anthropic, etc.) subclasses this to implement
|
|
38
38
|
# provider-specific API interactions.
|
|
39
39
|
#
|
|
@@ -44,41 +44,44 @@ module ActiveAgent
|
|
|
44
44
|
extend ActiveSupport::Delegation
|
|
45
45
|
|
|
46
46
|
include ExceptionHandler
|
|
47
|
+
include Instrumentation
|
|
47
48
|
include Previewable
|
|
49
|
+
include ToolChoiceClearing
|
|
48
50
|
|
|
49
51
|
class ProvidersError < StandardError; end
|
|
50
52
|
|
|
51
53
|
attr_internal :options, :context, :trace_id, # Setup
|
|
52
54
|
:request, :message_stack, # Runtime
|
|
53
55
|
:stream_broadcaster, :streaming, # Callback (Streams)
|
|
54
|
-
:tools_function
|
|
56
|
+
:tools_function, # Callback (Tools)
|
|
57
|
+
:usage_stack # Usage Tracking
|
|
55
58
|
|
|
56
|
-
# @return [String]
|
|
59
|
+
# @return [String] e.g., "Anthropic", "OpenAI"
|
|
57
60
|
def self.service_name
|
|
58
61
|
name.split("::").last.delete_suffix("Provider")
|
|
59
62
|
end
|
|
60
63
|
|
|
61
|
-
# @return [String]
|
|
64
|
+
# @return [String] e.g., "Anthropic", "OpenAI::Chat"
|
|
62
65
|
def self.tag_name
|
|
63
66
|
name.delete_prefix("ActiveAgent::Providers::").delete_suffix("Provider")
|
|
64
67
|
end
|
|
65
68
|
|
|
66
|
-
# @return [Module]
|
|
69
|
+
# @return [Module] e.g., ActiveAgent::Providers::OpenAI
|
|
67
70
|
def self.namespace
|
|
68
71
|
"#{name.deconstantize}::#{service_name}".safe_constantize
|
|
69
72
|
end
|
|
70
73
|
|
|
71
|
-
# @return [Class]
|
|
74
|
+
# @return [Class]
|
|
72
75
|
def self.options_klass
|
|
73
76
|
namespace::Options
|
|
74
77
|
end
|
|
75
78
|
|
|
76
|
-
# @return [ActiveModel::Type::Value]
|
|
79
|
+
# @return [ActiveModel::Type::Value] for prompt casting/serialization
|
|
77
80
|
def self.prompt_request_type
|
|
78
81
|
namespace::RequestType.new
|
|
79
82
|
end
|
|
80
83
|
|
|
81
|
-
# @return [ActiveModel::Type::Value]
|
|
84
|
+
# @return [ActiveModel::Type::Value] for embedding casting/serialization
|
|
82
85
|
# @raise [NotImplementedError] when provider doesn't support embeddings
|
|
83
86
|
def self.embed_request_type
|
|
84
87
|
fail(NotImplementedError)
|
|
@@ -86,12 +89,10 @@ module ActiveAgent
|
|
|
86
89
|
|
|
87
90
|
delegate :service_name, :tag_name, :namespace, :options_klass, :prompt_request_type, :embed_request_type, to: :class
|
|
88
91
|
|
|
89
|
-
# Initializes a provider instance.
|
|
90
|
-
#
|
|
91
92
|
# @param kwargs [Hash] configuration and callbacks
|
|
92
93
|
# @option kwargs [Symbol] :service validates against provider's service name
|
|
93
|
-
# @option kwargs [Proc] :stream_broadcaster
|
|
94
|
-
# @option kwargs [Proc] :tools_function
|
|
94
|
+
# @option kwargs [Proc] :stream_broadcaster for streaming events (:open, :update, :close)
|
|
95
|
+
# @option kwargs [Proc] :tools_function to execute tool/function calls
|
|
95
96
|
# @raise [RuntimeError] when service name doesn't match provider
|
|
96
97
|
def initialize(kwargs = {})
|
|
97
98
|
assert_service!(kwargs.delete(:service))
|
|
@@ -107,21 +108,10 @@ module ActiveAgent
|
|
|
107
108
|
self.options = options_klass.new(kwargs.extract!(*options_klass.keys))
|
|
108
109
|
self.context = kwargs
|
|
109
110
|
self.message_stack = []
|
|
111
|
+
self.usage_stack = []
|
|
110
112
|
end
|
|
111
113
|
|
|
112
|
-
#
|
|
113
|
-
#
|
|
114
|
-
# @return [ActiveAgent::Providers::Common::PromptResponse]
|
|
115
|
-
def prompt
|
|
116
|
-
instrument("prompt_start.provider.active_agent") do
|
|
117
|
-
self.request = prompt_request_type.cast(context.except(:trace_id))
|
|
118
|
-
resolve_prompt
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
# Generates a preview of the prompt without executing the API call.
|
|
123
|
-
#
|
|
124
|
-
# Casts context into a request object and renders it as markdown for inspection.
|
|
114
|
+
# Generates prompt preview without executing the API call.
|
|
125
115
|
#
|
|
126
116
|
# @return [String] markdown-formatted preview
|
|
127
117
|
def preview
|
|
@@ -129,15 +119,31 @@ module ActiveAgent
|
|
|
129
119
|
preview_prompt
|
|
130
120
|
end
|
|
131
121
|
|
|
132
|
-
# Executes
|
|
122
|
+
# Executes prompt request with error handling and instrumentation.
|
|
133
123
|
#
|
|
134
|
-
#
|
|
124
|
+
# @return [ActiveAgent::Providers::Common::PromptResponse]
|
|
125
|
+
def prompt
|
|
126
|
+
self.request = prompt_request_type.cast(context.except(:trace_id))
|
|
127
|
+
|
|
128
|
+
instrument("prompt.active_agent") do |payload|
|
|
129
|
+
response = resolve_prompt
|
|
130
|
+
instrumentation_prompt_payload(payload, request, response)
|
|
131
|
+
|
|
132
|
+
response
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Executes embedding request with error handling and instrumentation.
|
|
135
137
|
#
|
|
136
138
|
# @return [ActiveAgent::Providers::Common::EmbedResponse]
|
|
137
139
|
def embed
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
self.request = embed_request_type.cast(context.except(:trace_id))
|
|
141
|
+
|
|
142
|
+
instrument("embed.active_agent") do |payload|
|
|
143
|
+
response = resolve_embed
|
|
144
|
+
instrumentation_embed_payload(payload, request, response)
|
|
145
|
+
|
|
146
|
+
response
|
|
141
147
|
end
|
|
142
148
|
end
|
|
143
149
|
|
|
@@ -149,8 +155,6 @@ module ActiveAgent
|
|
|
149
155
|
fail "Unexpected Service Name: #{name} != #{service_name}" if name && name != service_name
|
|
150
156
|
end
|
|
151
157
|
|
|
152
|
-
# Instruments an event for logging and metrics.
|
|
153
|
-
#
|
|
154
158
|
# @param name [String]
|
|
155
159
|
# @param payload [Hash]
|
|
156
160
|
# @yield block to instrument
|
|
@@ -160,34 +164,42 @@ module ActiveAgent
|
|
|
160
164
|
ActiveSupport::Notifications.instrument(name, full_payload, &block)
|
|
161
165
|
end
|
|
162
166
|
|
|
163
|
-
# Orchestrates
|
|
167
|
+
# Orchestrates complete prompt request lifecycle.
|
|
164
168
|
#
|
|
165
|
-
#
|
|
166
|
-
# recursive tool/function calling until completion.
|
|
169
|
+
# Handles recursive tool/function calling until completion.
|
|
167
170
|
#
|
|
168
171
|
# @return [ActiveAgent::Providers::Common::PromptResponse]
|
|
169
172
|
def resolve_prompt
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
173
|
+
api_parameters = api_request_build(prepare_prompt_request, prompt_request_type)
|
|
174
|
+
api_response = instrument("prompt.provider.active_agent") do |payload|
|
|
175
|
+
raw_response = with_exception_handling { api_prompt_execute(api_parameters) }
|
|
176
|
+
|
|
177
|
+
# Instrumentation Context Building
|
|
178
|
+
# Normalize response for instrumentation (providers may return gem objects)
|
|
179
|
+
normalized_response = api_response_normalize(raw_response)
|
|
180
|
+
common_response = Common::PromptResponse.new(raw_response: normalized_response)
|
|
181
|
+
instrumentation_prompt_payload(payload, self.request, common_response)
|
|
182
|
+
usage_stack.push(common_response.usage) if common_response&.usage
|
|
183
|
+
|
|
184
|
+
raw_response
|
|
178
185
|
end
|
|
179
186
|
|
|
180
|
-
process_prompt_finished(api_response
|
|
187
|
+
process_prompt_finished(api_response)
|
|
181
188
|
end
|
|
182
189
|
|
|
183
|
-
# Orchestrates
|
|
190
|
+
# Orchestrates complete embedding request lifecycle.
|
|
184
191
|
#
|
|
185
192
|
# @return [ActiveAgent::Providers::Common::EmbedResponse]
|
|
186
193
|
def resolve_embed
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
194
|
+
api_parameters = api_request_build(self.request, embed_request_type)
|
|
195
|
+
api_response = instrument("embed.provider.active_agent") do |payload|
|
|
196
|
+
raw_response = with_exception_handling { api_embed_execute(api_parameters) }
|
|
197
|
+
|
|
198
|
+
# Instrumentation Context Building
|
|
199
|
+
common_response = Common::EmbedResponse.new(raw_response:)
|
|
200
|
+
instrumentation_embed_payload(payload, self.request, common_response)
|
|
201
|
+
|
|
202
|
+
raw_response
|
|
191
203
|
end
|
|
192
204
|
|
|
193
205
|
process_embed_finished(api_response)
|
|
@@ -195,7 +207,7 @@ module ActiveAgent
|
|
|
195
207
|
|
|
196
208
|
# Prepares request for next iteration in multi-turn conversation.
|
|
197
209
|
#
|
|
198
|
-
# Appends accumulated messages
|
|
210
|
+
# Appends accumulated messages and resets buffer for next cycle.
|
|
199
211
|
#
|
|
200
212
|
# @return [Request]
|
|
201
213
|
def prepare_prompt_request
|
|
@@ -205,11 +217,9 @@ module ActiveAgent
|
|
|
205
217
|
self.request
|
|
206
218
|
end
|
|
207
219
|
|
|
208
|
-
# Builds API request parameters from request object.
|
|
209
|
-
#
|
|
210
220
|
# @param request [Request]
|
|
211
|
-
# @param request_type [ActiveModel::Type::Value]
|
|
212
|
-
# @return [Hash]
|
|
221
|
+
# @param request_type [ActiveModel::Type::Value] for serialization
|
|
222
|
+
# @return [Hash] API request parameters
|
|
213
223
|
def api_request_build(request, request_type)
|
|
214
224
|
parameters = request_type.serialize(request)
|
|
215
225
|
parameters[:stream] = process_stream if request.try(:stream)
|
|
@@ -221,7 +231,7 @@ module ActiveAgent
|
|
|
221
231
|
parameters
|
|
222
232
|
end
|
|
223
233
|
|
|
224
|
-
# @return [Proc]
|
|
234
|
+
# @return [Proc] for each response chunk
|
|
225
235
|
def process_stream
|
|
226
236
|
proc do |api_response_chunk|
|
|
227
237
|
process_stream_chunk(api_response_chunk)
|
|
@@ -231,12 +241,10 @@ module ActiveAgent
|
|
|
231
241
|
# Executes prompt request against provider's API.
|
|
232
242
|
#
|
|
233
243
|
# @abstract
|
|
234
|
-
# @param
|
|
244
|
+
# @param parameters [Hash]
|
|
235
245
|
# @return [Object] provider-specific API response
|
|
236
246
|
# @raise [NotImplementedError]
|
|
237
247
|
def api_prompt_execute(parameters)
|
|
238
|
-
instrument("api_request.provider.active_agent", model: parameters[:model], streaming: !!parameters[:stream])
|
|
239
|
-
|
|
240
248
|
unless parameters[:stream]
|
|
241
249
|
api_prompt_executer.create(**parameters)
|
|
242
250
|
else
|
|
@@ -257,6 +265,18 @@ module ActiveAgent
|
|
|
257
265
|
fail NotImplementedError, "Subclass expected to implement"
|
|
258
266
|
end
|
|
259
267
|
|
|
268
|
+
# Normalizes API response for instrumentation.
|
|
269
|
+
#
|
|
270
|
+
# Providers that return gem objects (like Anthropic::Models::Message) should
|
|
271
|
+
# override this to convert to a hash so usage data can be extracted.
|
|
272
|
+
# By default, returns the response as-is (for providers returning hashes).
|
|
273
|
+
#
|
|
274
|
+
# @param api_response [Object] provider-specific API response
|
|
275
|
+
# @return [Hash, Object] normalized response (preferably hash)
|
|
276
|
+
def api_response_normalize(api_response)
|
|
277
|
+
api_response
|
|
278
|
+
end
|
|
279
|
+
|
|
260
280
|
# Executes embedding request against provider's API.
|
|
261
281
|
#
|
|
262
282
|
# @abstract
|
|
@@ -278,21 +298,21 @@ module ActiveAgent
|
|
|
278
298
|
|
|
279
299
|
# Broadcasts stream open event.
|
|
280
300
|
#
|
|
281
|
-
# Fires once per request cycle even during multi-turn tool calling.
|
|
301
|
+
# Fires once per request cycle, even during multi-turn tool calling.
|
|
282
302
|
#
|
|
283
303
|
# @return [void]
|
|
284
304
|
def broadcast_stream_open
|
|
285
305
|
return if streaming
|
|
286
306
|
self.streaming = true
|
|
287
307
|
|
|
288
|
-
instrument("stream_open.
|
|
308
|
+
instrument("stream_open.active_agent")
|
|
289
309
|
stream_broadcaster.call(nil, nil, :open)
|
|
290
310
|
end
|
|
291
311
|
|
|
292
312
|
# Broadcasts stream update with message content delta.
|
|
293
313
|
#
|
|
294
314
|
# @param message [Hash, Object]
|
|
295
|
-
# @param delta [String, nil]
|
|
315
|
+
# @param delta [String, nil]
|
|
296
316
|
# @return [void]
|
|
297
317
|
def broadcast_stream_update(message, delta = nil)
|
|
298
318
|
stream_broadcaster.call(message, delta, :update)
|
|
@@ -300,35 +320,31 @@ module ActiveAgent
|
|
|
300
320
|
|
|
301
321
|
# Broadcasts stream close event.
|
|
302
322
|
#
|
|
303
|
-
# Fires once per request cycle even during multi-turn tool calling.
|
|
323
|
+
# Fires once per request cycle, even during multi-turn tool calling.
|
|
304
324
|
#
|
|
305
325
|
# @return [void]
|
|
306
326
|
def broadcast_stream_close
|
|
307
327
|
return unless streaming
|
|
308
328
|
self.streaming = false
|
|
309
329
|
|
|
310
|
-
instrument("stream_close.
|
|
330
|
+
instrument("stream_close.active_agent")
|
|
311
331
|
stream_broadcaster.call(message_stack.last, nil, :close)
|
|
312
332
|
end
|
|
313
333
|
|
|
314
334
|
# Processes completed API response and handles tool calling recursion.
|
|
315
335
|
#
|
|
316
|
-
# Extracts messages and function calls
|
|
317
|
-
# executes them and recursively continues
|
|
336
|
+
# Extracts messages and function calls. If tools were invoked,
|
|
337
|
+
# executes them and recursively continues until completion.
|
|
318
338
|
#
|
|
319
339
|
# @param api_response [Object, nil] provider-specific response
|
|
320
340
|
# @return [Common::PromptResponse, nil]
|
|
321
341
|
def process_prompt_finished(api_response = nil)
|
|
322
342
|
if (api_messages = process_prompt_finished_extract_messages(api_response))
|
|
323
|
-
instrument("messages_extracted.provider.active_agent", message_count: api_messages.size)
|
|
324
343
|
message_stack.push(*api_messages)
|
|
325
344
|
end
|
|
326
345
|
|
|
327
346
|
if (tool_calls = process_prompt_finished_extract_function_calls)&.any?
|
|
328
|
-
instrument("tool_calls_processing.provider.active_agent", tool_count: tool_calls.size)
|
|
329
347
|
process_function_calls(tool_calls)
|
|
330
|
-
|
|
331
|
-
instrument("multi_turn_continue.provider.active_agent")
|
|
332
348
|
resolve_prompt
|
|
333
349
|
else
|
|
334
350
|
|
|
@@ -337,27 +353,25 @@ module ActiveAgent
|
|
|
337
353
|
# as they continue to work.
|
|
338
354
|
broadcast_stream_close
|
|
339
355
|
|
|
340
|
-
instrument("prompt_complete.provider.active_agent", message_count: message_stack.size)
|
|
341
|
-
|
|
342
356
|
# To convert the messages into common format we first need to merge the current
|
|
343
357
|
# stack and then cast them to the provider type, so we can cast them out to common.
|
|
344
358
|
messages = prompt_request_type.cast(
|
|
345
359
|
messages: [ *request.messages, *message_stack ]
|
|
346
360
|
).messages
|
|
347
361
|
|
|
362
|
+
# Create response object with usage_stack array for multi-turn cumulative tracking.
|
|
348
363
|
# This will returned as it closes up the recursive stack
|
|
349
364
|
Common::PromptResponse.new(
|
|
350
365
|
context:,
|
|
366
|
+
format: request.response_format,
|
|
367
|
+
messages:,
|
|
351
368
|
raw_request: prompt_request_type.serialize(request),
|
|
352
369
|
raw_response: api_response,
|
|
353
|
-
|
|
354
|
-
format: request.response_format
|
|
370
|
+
usages: usage_stack
|
|
355
371
|
)
|
|
356
372
|
end
|
|
357
373
|
end
|
|
358
374
|
|
|
359
|
-
# Extracts messages from API response.
|
|
360
|
-
#
|
|
361
375
|
# @abstract
|
|
362
376
|
# @param api_response [Object]
|
|
363
377
|
# @return [Array<Message>, nil]
|
|
@@ -366,8 +380,6 @@ module ActiveAgent
|
|
|
366
380
|
fail NotImplementedError, "Subclass expected to implement"
|
|
367
381
|
end
|
|
368
382
|
|
|
369
|
-
# Extracts tool/function calls from API response.
|
|
370
|
-
#
|
|
371
383
|
# @abstract
|
|
372
384
|
# @return [Array<Hash>, nil]
|
|
373
385
|
# @raise [NotImplementedError]
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "requests/_types"
|
|
4
|
-
|
|
5
3
|
require_relative "options"
|
|
6
4
|
require_relative "request"
|
|
7
5
|
|
|
@@ -11,6 +9,8 @@ module ActiveAgent
|
|
|
11
9
|
# ActiveModel type for casting and serializing Anthropic Request objects.
|
|
12
10
|
#
|
|
13
11
|
# Handles conversion between Hash, Request, and serialized formats for API calls.
|
|
12
|
+
# The Request class now delegates to the official Anthropic gem model, eliminating
|
|
13
|
+
# the need for maintaining nested type definitions.
|
|
14
14
|
class RequestType < ActiveModel::Type::Value
|
|
15
15
|
# Casts input to Request object.
|
|
16
16
|
#
|
|
@@ -28,15 +28,13 @@ module ActiveAgent
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def serialize
|
|
31
|
-
super.except(:anthropic_beta)
|
|
32
|
-
hash[:extra_headers] = extra_headers unless extra_headers.blank?
|
|
33
|
-
end
|
|
31
|
+
super.except(:anthropic_beta)
|
|
34
32
|
end
|
|
35
33
|
|
|
34
|
+
# Anthropic gem handles beta headers differently via client.beta
|
|
35
|
+
# rather than via extra_headers in request_options
|
|
36
36
|
def extra_headers
|
|
37
|
-
|
|
38
|
-
"anthropic-beta" => anthropic_beta.presence,
|
|
39
|
-
)
|
|
37
|
+
{}
|
|
40
38
|
end
|
|
41
39
|
|
|
42
40
|
private
|