activeagent 1.0.0.rc1 → 1.0.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 +31 -1
- data/lib/active_agent/providers/_base_provider.rb +92 -82
- data/lib/active_agent/providers/anthropic/_types.rb +2 -2
- data/lib/active_agent/providers/anthropic/request.rb +135 -81
- data/lib/active_agent/providers/anthropic/transforms.rb +353 -0
- data/lib/active_agent/providers/anthropic_provider.rb +96 -53
- data/lib/active_agent/providers/common/messages/_types.rb +37 -1
- 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/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 +364 -0
- data/lib/active_agent/providers/open_ai/chat_provider.rb +57 -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 +100 -134
- data/lib/active_agent/providers/open_ai/responses/transforms.rb +228 -0
- data/lib/active_agent/providers/open_ai/responses_provider.rb +77 -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 +232 -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 +134 -0
- data/lib/active_agent/providers/open_router_provider.rb +9 -0
- data/lib/active_agent/version.rb +1 -1
- metadata +15 -159
- 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: 330c02d2e1ac16e72413f22401dbc6899f652b794d34090b0f499a37b901fbaf
|
|
4
|
+
data.tar.gz: a492f5c88db1f217fe47f9de1477f195c6b150b5dc5ce5791c66fe0f63b0b028
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d8dac6789ba1f3685c24d711aace46ad5b681e9c795a975e61f07ee3c7d9a9bc44c2fd0568fabcabd739df5efd13b222c5fa6e954384bacb8bbcfdaaab0d7182
|
|
7
|
+
data.tar.gz: 8a0f61b2b5a9375c8f1b090bca29af077384079ba008622a1a510d8190acdff034c7f6b8065c1c752a2cee00dabd35d00f017db28954aacc17386fb06be63d50
|
data/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,7 @@ 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
|
|
|
@@ -148,6 +148,35 @@ response = MyAgent.embed(inputs: ["Text 1", "Text 2"]).embed_now
|
|
|
148
148
|
vectors = response.data.map { |d| d[:embedding] }
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
+
**Normalized Usage Statistics**
|
|
152
|
+
```ruby
|
|
153
|
+
response = MyAgent.prompt("Hello").generate_now
|
|
154
|
+
|
|
155
|
+
# Works across all providers
|
|
156
|
+
response.usage.input_tokens
|
|
157
|
+
response.usage.output_tokens
|
|
158
|
+
response.usage.total_tokens
|
|
159
|
+
|
|
160
|
+
# Provider-specific fields when available
|
|
161
|
+
response.usage.cached_tokens # OpenAI, Anthropic
|
|
162
|
+
response.usage.reasoning_tokens # OpenAI o1 models
|
|
163
|
+
response.usage.service_tier # Anthropic
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Enhanced Instrumentation for APM Integration**
|
|
167
|
+
- 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)
|
|
168
|
+
- Event payloads include comprehensive data for monitoring tools (New Relic, DataDog, etc.):
|
|
169
|
+
- Request parameters: `model`, `temperature`, `max_tokens`, `top_p`, `stream`, `message_count`, `has_tools`
|
|
170
|
+
- Usage data: `input_tokens`, `output_tokens`, `total_tokens`, `cached_tokens`, `reasoning_tokens`, `audio_tokens`, `cache_creation_tokens` (critical for cost tracking)
|
|
171
|
+
- Response metadata: `finish_reason`, `response_model`, `response_id`, `embedding_count`
|
|
172
|
+
- Top-level events report cumulative usage across all API calls in multi-turn conversations
|
|
173
|
+
- Provider-level events report per-call usage for granular tracking
|
|
174
|
+
|
|
175
|
+
**Multi-Turn Usage Tracking**
|
|
176
|
+
- `response.usage` now returns cumulative token counts across all API calls during tool calling
|
|
177
|
+
- New `response.usages` array contains individual usage objects from each API call
|
|
178
|
+
- `Usage` objects support addition: `usage1 + usage2` for combining statistics
|
|
179
|
+
|
|
151
180
|
**Provider Enhancements**
|
|
152
181
|
- OpenAI Responses API: `api: :responses` or `api: :chat`
|
|
153
182
|
- Anthropic JSON object mode with automatic extraction
|
|
@@ -195,6 +224,7 @@ vectors = response.data.map { |d| d[:embedding] }
|
|
|
195
224
|
- Template rendering without blocks
|
|
196
225
|
- Schema generator key symbolization
|
|
197
226
|
- Rails 8.0 and 8.1 compatibility
|
|
227
|
+
- Usage extraction across OpenAI/Anthropic response formats
|
|
198
228
|
|
|
199
229
|
### Removed
|
|
200
230
|
|
|
@@ -2,21 +2,21 @@ 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"
|
|
6
7
|
|
|
7
|
-
# Maps provider types to their gem dependencies.
|
|
8
8
|
# @private
|
|
9
9
|
GEM_LOADERS = {
|
|
10
10
|
anthropic: [ "anthropic", "~> 1.12", "anthropic" ],
|
|
11
11
|
openai: [ "openai", "~> 0.34", "openai" ]
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
#
|
|
14
|
+
# Requires a provider's gem dependency.
|
|
15
15
|
#
|
|
16
16
|
# @param type [Symbol] provider type (:anthropic, :openai)
|
|
17
|
-
# @param file_name [String]
|
|
17
|
+
# @param file_name [String] for error context
|
|
18
18
|
# @return [void]
|
|
19
|
-
# @raise [LoadError] when
|
|
19
|
+
# @raise [LoadError] when required gem is not installed
|
|
20
20
|
def require_gem!(type, file_name)
|
|
21
21
|
gem_name, requirement, package_name = GEM_LOADERS.fetch(type)
|
|
22
22
|
provider_name = file_name.split("/").last.delete_suffix(".rb").camelize
|
|
@@ -31,9 +31,8 @@ end
|
|
|
31
31
|
|
|
32
32
|
module ActiveAgent
|
|
33
33
|
module Providers
|
|
34
|
-
#
|
|
34
|
+
# Orchestrates LLM provider API requests, streaming, and multi-turn tool calling.
|
|
35
35
|
#
|
|
36
|
-
# Orchestrates API requests, streaming responses, and multi-turn tool calling.
|
|
37
36
|
# Each provider (OpenAI, Anthropic, etc.) subclasses this to implement
|
|
38
37
|
# provider-specific API interactions.
|
|
39
38
|
#
|
|
@@ -44,6 +43,7 @@ module ActiveAgent
|
|
|
44
43
|
extend ActiveSupport::Delegation
|
|
45
44
|
|
|
46
45
|
include ExceptionHandler
|
|
46
|
+
include Instrumentation
|
|
47
47
|
include Previewable
|
|
48
48
|
|
|
49
49
|
class ProvidersError < StandardError; end
|
|
@@ -51,34 +51,35 @@ module ActiveAgent
|
|
|
51
51
|
attr_internal :options, :context, :trace_id, # Setup
|
|
52
52
|
:request, :message_stack, # Runtime
|
|
53
53
|
:stream_broadcaster, :streaming, # Callback (Streams)
|
|
54
|
-
:tools_function
|
|
54
|
+
:tools_function, # Callback (Tools)
|
|
55
|
+
:usage_stack # Usage Tracking
|
|
55
56
|
|
|
56
|
-
# @return [String]
|
|
57
|
+
# @return [String] e.g., "Anthropic", "OpenAI"
|
|
57
58
|
def self.service_name
|
|
58
59
|
name.split("::").last.delete_suffix("Provider")
|
|
59
60
|
end
|
|
60
61
|
|
|
61
|
-
# @return [String]
|
|
62
|
+
# @return [String] e.g., "Anthropic", "OpenAI::Chat"
|
|
62
63
|
def self.tag_name
|
|
63
64
|
name.delete_prefix("ActiveAgent::Providers::").delete_suffix("Provider")
|
|
64
65
|
end
|
|
65
66
|
|
|
66
|
-
# @return [Module]
|
|
67
|
+
# @return [Module] e.g., ActiveAgent::Providers::OpenAI
|
|
67
68
|
def self.namespace
|
|
68
69
|
"#{name.deconstantize}::#{service_name}".safe_constantize
|
|
69
70
|
end
|
|
70
71
|
|
|
71
|
-
# @return [Class]
|
|
72
|
+
# @return [Class]
|
|
72
73
|
def self.options_klass
|
|
73
74
|
namespace::Options
|
|
74
75
|
end
|
|
75
76
|
|
|
76
|
-
# @return [ActiveModel::Type::Value]
|
|
77
|
+
# @return [ActiveModel::Type::Value] for prompt casting/serialization
|
|
77
78
|
def self.prompt_request_type
|
|
78
79
|
namespace::RequestType.new
|
|
79
80
|
end
|
|
80
81
|
|
|
81
|
-
# @return [ActiveModel::Type::Value]
|
|
82
|
+
# @return [ActiveModel::Type::Value] for embedding casting/serialization
|
|
82
83
|
# @raise [NotImplementedError] when provider doesn't support embeddings
|
|
83
84
|
def self.embed_request_type
|
|
84
85
|
fail(NotImplementedError)
|
|
@@ -86,12 +87,10 @@ module ActiveAgent
|
|
|
86
87
|
|
|
87
88
|
delegate :service_name, :tag_name, :namespace, :options_klass, :prompt_request_type, :embed_request_type, to: :class
|
|
88
89
|
|
|
89
|
-
# Initializes a provider instance.
|
|
90
|
-
#
|
|
91
90
|
# @param kwargs [Hash] configuration and callbacks
|
|
92
91
|
# @option kwargs [Symbol] :service validates against provider's service name
|
|
93
|
-
# @option kwargs [Proc] :stream_broadcaster
|
|
94
|
-
# @option kwargs [Proc] :tools_function
|
|
92
|
+
# @option kwargs [Proc] :stream_broadcaster for streaming events (:open, :update, :close)
|
|
93
|
+
# @option kwargs [Proc] :tools_function to execute tool/function calls
|
|
95
94
|
# @raise [RuntimeError] when service name doesn't match provider
|
|
96
95
|
def initialize(kwargs = {})
|
|
97
96
|
assert_service!(kwargs.delete(:service))
|
|
@@ -107,21 +106,10 @@ module ActiveAgent
|
|
|
107
106
|
self.options = options_klass.new(kwargs.extract!(*options_klass.keys))
|
|
108
107
|
self.context = kwargs
|
|
109
108
|
self.message_stack = []
|
|
109
|
+
self.usage_stack = []
|
|
110
110
|
end
|
|
111
111
|
|
|
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.
|
|
112
|
+
# Generates prompt preview without executing the API call.
|
|
125
113
|
#
|
|
126
114
|
# @return [String] markdown-formatted preview
|
|
127
115
|
def preview
|
|
@@ -129,15 +117,31 @@ module ActiveAgent
|
|
|
129
117
|
preview_prompt
|
|
130
118
|
end
|
|
131
119
|
|
|
132
|
-
# Executes
|
|
120
|
+
# Executes prompt request with error handling and instrumentation.
|
|
133
121
|
#
|
|
134
|
-
#
|
|
122
|
+
# @return [ActiveAgent::Providers::Common::PromptResponse]
|
|
123
|
+
def prompt
|
|
124
|
+
self.request = prompt_request_type.cast(context.except(:trace_id))
|
|
125
|
+
|
|
126
|
+
instrument("prompt.active_agent") do |payload|
|
|
127
|
+
response = resolve_prompt
|
|
128
|
+
instrumentation_prompt_payload(payload, request, response)
|
|
129
|
+
|
|
130
|
+
response
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Executes embedding request with error handling and instrumentation.
|
|
135
135
|
#
|
|
136
136
|
# @return [ActiveAgent::Providers::Common::EmbedResponse]
|
|
137
137
|
def embed
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
self.request = embed_request_type.cast(context.except(:trace_id))
|
|
139
|
+
|
|
140
|
+
instrument("embed.active_agent") do |payload|
|
|
141
|
+
response = resolve_embed
|
|
142
|
+
instrumentation_embed_payload(payload, request, response)
|
|
143
|
+
|
|
144
|
+
response
|
|
141
145
|
end
|
|
142
146
|
end
|
|
143
147
|
|
|
@@ -149,8 +153,6 @@ module ActiveAgent
|
|
|
149
153
|
fail "Unexpected Service Name: #{name} != #{service_name}" if name && name != service_name
|
|
150
154
|
end
|
|
151
155
|
|
|
152
|
-
# Instruments an event for logging and metrics.
|
|
153
|
-
#
|
|
154
156
|
# @param name [String]
|
|
155
157
|
# @param payload [Hash]
|
|
156
158
|
# @yield block to instrument
|
|
@@ -160,34 +162,42 @@ module ActiveAgent
|
|
|
160
162
|
ActiveSupport::Notifications.instrument(name, full_payload, &block)
|
|
161
163
|
end
|
|
162
164
|
|
|
163
|
-
# Orchestrates
|
|
165
|
+
# Orchestrates complete prompt request lifecycle.
|
|
164
166
|
#
|
|
165
|
-
#
|
|
166
|
-
# recursive tool/function calling until completion.
|
|
167
|
+
# Handles recursive tool/function calling until completion.
|
|
167
168
|
#
|
|
168
169
|
# @return [ActiveAgent::Providers::Common::PromptResponse]
|
|
169
170
|
def resolve_prompt
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
171
|
+
api_parameters = api_request_build(prepare_prompt_request, prompt_request_type)
|
|
172
|
+
api_response = instrument("prompt.provider.active_agent") do |payload|
|
|
173
|
+
raw_response = with_exception_handling { api_prompt_execute(api_parameters) }
|
|
174
|
+
|
|
175
|
+
# Instrumentation Context Building
|
|
176
|
+
# Normalize response for instrumentation (providers may return gem objects)
|
|
177
|
+
normalized_response = api_response_normalize(raw_response)
|
|
178
|
+
common_response = Common::PromptResponse.new(raw_response: normalized_response)
|
|
179
|
+
instrumentation_prompt_payload(payload, self.request, common_response)
|
|
180
|
+
usage_stack.push(common_response.usage) if common_response&.usage
|
|
181
|
+
|
|
182
|
+
raw_response
|
|
178
183
|
end
|
|
179
184
|
|
|
180
|
-
process_prompt_finished(api_response
|
|
185
|
+
process_prompt_finished(api_response)
|
|
181
186
|
end
|
|
182
187
|
|
|
183
|
-
# Orchestrates
|
|
188
|
+
# Orchestrates complete embedding request lifecycle.
|
|
184
189
|
#
|
|
185
190
|
# @return [ActiveAgent::Providers::Common::EmbedResponse]
|
|
186
191
|
def resolve_embed
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
192
|
+
api_parameters = api_request_build(self.request, embed_request_type)
|
|
193
|
+
api_response = instrument("embed.provider.active_agent") do |payload|
|
|
194
|
+
raw_response = with_exception_handling { api_embed_execute(api_parameters) }
|
|
195
|
+
|
|
196
|
+
# Instrumentation Context Building
|
|
197
|
+
common_response = Common::EmbedResponse.new(raw_response:)
|
|
198
|
+
instrumentation_embed_payload(payload, self.request, common_response)
|
|
199
|
+
|
|
200
|
+
raw_response
|
|
191
201
|
end
|
|
192
202
|
|
|
193
203
|
process_embed_finished(api_response)
|
|
@@ -195,7 +205,7 @@ module ActiveAgent
|
|
|
195
205
|
|
|
196
206
|
# Prepares request for next iteration in multi-turn conversation.
|
|
197
207
|
#
|
|
198
|
-
# Appends accumulated messages
|
|
208
|
+
# Appends accumulated messages and resets buffer for next cycle.
|
|
199
209
|
#
|
|
200
210
|
# @return [Request]
|
|
201
211
|
def prepare_prompt_request
|
|
@@ -205,11 +215,9 @@ module ActiveAgent
|
|
|
205
215
|
self.request
|
|
206
216
|
end
|
|
207
217
|
|
|
208
|
-
# Builds API request parameters from request object.
|
|
209
|
-
#
|
|
210
218
|
# @param request [Request]
|
|
211
|
-
# @param request_type [ActiveModel::Type::Value]
|
|
212
|
-
# @return [Hash]
|
|
219
|
+
# @param request_type [ActiveModel::Type::Value] for serialization
|
|
220
|
+
# @return [Hash] API request parameters
|
|
213
221
|
def api_request_build(request, request_type)
|
|
214
222
|
parameters = request_type.serialize(request)
|
|
215
223
|
parameters[:stream] = process_stream if request.try(:stream)
|
|
@@ -221,7 +229,7 @@ module ActiveAgent
|
|
|
221
229
|
parameters
|
|
222
230
|
end
|
|
223
231
|
|
|
224
|
-
# @return [Proc]
|
|
232
|
+
# @return [Proc] for each response chunk
|
|
225
233
|
def process_stream
|
|
226
234
|
proc do |api_response_chunk|
|
|
227
235
|
process_stream_chunk(api_response_chunk)
|
|
@@ -231,12 +239,10 @@ module ActiveAgent
|
|
|
231
239
|
# Executes prompt request against provider's API.
|
|
232
240
|
#
|
|
233
241
|
# @abstract
|
|
234
|
-
# @param
|
|
242
|
+
# @param parameters [Hash]
|
|
235
243
|
# @return [Object] provider-specific API response
|
|
236
244
|
# @raise [NotImplementedError]
|
|
237
245
|
def api_prompt_execute(parameters)
|
|
238
|
-
instrument("api_request.provider.active_agent", model: parameters[:model], streaming: !!parameters[:stream])
|
|
239
|
-
|
|
240
246
|
unless parameters[:stream]
|
|
241
247
|
api_prompt_executer.create(**parameters)
|
|
242
248
|
else
|
|
@@ -257,6 +263,18 @@ module ActiveAgent
|
|
|
257
263
|
fail NotImplementedError, "Subclass expected to implement"
|
|
258
264
|
end
|
|
259
265
|
|
|
266
|
+
# Normalizes API response for instrumentation.
|
|
267
|
+
#
|
|
268
|
+
# Providers that return gem objects (like Anthropic::Models::Message) should
|
|
269
|
+
# override this to convert to a hash so usage data can be extracted.
|
|
270
|
+
# By default, returns the response as-is (for providers returning hashes).
|
|
271
|
+
#
|
|
272
|
+
# @param api_response [Object] provider-specific API response
|
|
273
|
+
# @return [Hash, Object] normalized response (preferably hash)
|
|
274
|
+
def api_response_normalize(api_response)
|
|
275
|
+
api_response
|
|
276
|
+
end
|
|
277
|
+
|
|
260
278
|
# Executes embedding request against provider's API.
|
|
261
279
|
#
|
|
262
280
|
# @abstract
|
|
@@ -278,21 +296,21 @@ module ActiveAgent
|
|
|
278
296
|
|
|
279
297
|
# Broadcasts stream open event.
|
|
280
298
|
#
|
|
281
|
-
# Fires once per request cycle even during multi-turn tool calling.
|
|
299
|
+
# Fires once per request cycle, even during multi-turn tool calling.
|
|
282
300
|
#
|
|
283
301
|
# @return [void]
|
|
284
302
|
def broadcast_stream_open
|
|
285
303
|
return if streaming
|
|
286
304
|
self.streaming = true
|
|
287
305
|
|
|
288
|
-
instrument("stream_open.
|
|
306
|
+
instrument("stream_open.active_agent")
|
|
289
307
|
stream_broadcaster.call(nil, nil, :open)
|
|
290
308
|
end
|
|
291
309
|
|
|
292
310
|
# Broadcasts stream update with message content delta.
|
|
293
311
|
#
|
|
294
312
|
# @param message [Hash, Object]
|
|
295
|
-
# @param delta [String, nil]
|
|
313
|
+
# @param delta [String, nil]
|
|
296
314
|
# @return [void]
|
|
297
315
|
def broadcast_stream_update(message, delta = nil)
|
|
298
316
|
stream_broadcaster.call(message, delta, :update)
|
|
@@ -300,35 +318,31 @@ module ActiveAgent
|
|
|
300
318
|
|
|
301
319
|
# Broadcasts stream close event.
|
|
302
320
|
#
|
|
303
|
-
# Fires once per request cycle even during multi-turn tool calling.
|
|
321
|
+
# Fires once per request cycle, even during multi-turn tool calling.
|
|
304
322
|
#
|
|
305
323
|
# @return [void]
|
|
306
324
|
def broadcast_stream_close
|
|
307
325
|
return unless streaming
|
|
308
326
|
self.streaming = false
|
|
309
327
|
|
|
310
|
-
instrument("stream_close.
|
|
328
|
+
instrument("stream_close.active_agent")
|
|
311
329
|
stream_broadcaster.call(message_stack.last, nil, :close)
|
|
312
330
|
end
|
|
313
331
|
|
|
314
332
|
# Processes completed API response and handles tool calling recursion.
|
|
315
333
|
#
|
|
316
|
-
# Extracts messages and function calls
|
|
317
|
-
# executes them and recursively continues
|
|
334
|
+
# Extracts messages and function calls. If tools were invoked,
|
|
335
|
+
# executes them and recursively continues until completion.
|
|
318
336
|
#
|
|
319
337
|
# @param api_response [Object, nil] provider-specific response
|
|
320
338
|
# @return [Common::PromptResponse, nil]
|
|
321
339
|
def process_prompt_finished(api_response = nil)
|
|
322
340
|
if (api_messages = process_prompt_finished_extract_messages(api_response))
|
|
323
|
-
instrument("messages_extracted.provider.active_agent", message_count: api_messages.size)
|
|
324
341
|
message_stack.push(*api_messages)
|
|
325
342
|
end
|
|
326
343
|
|
|
327
344
|
if (tool_calls = process_prompt_finished_extract_function_calls)&.any?
|
|
328
|
-
instrument("tool_calls_processing.provider.active_agent", tool_count: tool_calls.size)
|
|
329
345
|
process_function_calls(tool_calls)
|
|
330
|
-
|
|
331
|
-
instrument("multi_turn_continue.provider.active_agent")
|
|
332
346
|
resolve_prompt
|
|
333
347
|
else
|
|
334
348
|
|
|
@@ -337,27 +351,25 @@ module ActiveAgent
|
|
|
337
351
|
# as they continue to work.
|
|
338
352
|
broadcast_stream_close
|
|
339
353
|
|
|
340
|
-
instrument("prompt_complete.provider.active_agent", message_count: message_stack.size)
|
|
341
|
-
|
|
342
354
|
# To convert the messages into common format we first need to merge the current
|
|
343
355
|
# stack and then cast them to the provider type, so we can cast them out to common.
|
|
344
356
|
messages = prompt_request_type.cast(
|
|
345
357
|
messages: [ *request.messages, *message_stack ]
|
|
346
358
|
).messages
|
|
347
359
|
|
|
360
|
+
# Create response object with usage_stack array for multi-turn cumulative tracking.
|
|
348
361
|
# This will returned as it closes up the recursive stack
|
|
349
362
|
Common::PromptResponse.new(
|
|
350
363
|
context:,
|
|
364
|
+
format: request.response_format,
|
|
365
|
+
messages:,
|
|
351
366
|
raw_request: prompt_request_type.serialize(request),
|
|
352
367
|
raw_response: api_response,
|
|
353
|
-
|
|
354
|
-
format: request.response_format
|
|
368
|
+
usages: usage_stack
|
|
355
369
|
)
|
|
356
370
|
end
|
|
357
371
|
end
|
|
358
372
|
|
|
359
|
-
# Extracts messages from API response.
|
|
360
|
-
#
|
|
361
373
|
# @abstract
|
|
362
374
|
# @param api_response [Object]
|
|
363
375
|
# @return [Array<Message>, nil]
|
|
@@ -366,8 +378,6 @@ module ActiveAgent
|
|
|
366
378
|
fail NotImplementedError, "Subclass expected to implement"
|
|
367
379
|
end
|
|
368
380
|
|
|
369
|
-
# Extracts tool/function calls from API response.
|
|
370
|
-
#
|
|
371
381
|
# @abstract
|
|
372
382
|
# @return [Array<Hash>, nil]
|
|
373
383
|
# @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
|
#
|