activeagent 0.6.3 → 1.0.0.rc1
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 +210 -2
- data/README.md +15 -24
- data/lib/active_agent/base.rb +389 -39
- data/lib/active_agent/concerns/callbacks.rb +251 -0
- data/lib/active_agent/concerns/observers.rb +147 -0
- data/lib/active_agent/concerns/parameterized.rb +292 -0
- data/lib/active_agent/concerns/provider.rb +120 -0
- data/lib/active_agent/concerns/queueing.rb +36 -0
- data/lib/active_agent/concerns/rescue.rb +64 -0
- data/lib/active_agent/concerns/streaming.rb +282 -0
- data/lib/active_agent/concerns/tooling.rb +23 -0
- data/lib/active_agent/concerns/view.rb +150 -0
- data/lib/active_agent/configuration.rb +442 -20
- data/lib/active_agent/generation.rb +141 -47
- data/lib/active_agent/generation_provider/open_router/types.rb +505 -0
- data/lib/active_agent/generation_provider/xai_provider.rb +144 -0
- data/lib/active_agent/providers/_base_provider.rb +410 -0
- data/lib/active_agent/providers/anthropic/_types.rb +63 -0
- data/lib/active_agent/providers/anthropic/options.rb +53 -0
- data/lib/active_agent/providers/anthropic/request.rb +109 -0
- data/lib/active_agent/providers/anthropic/requests/_types.rb +190 -0
- data/lib/active_agent/providers/anthropic/requests/container_params.rb +19 -0
- data/lib/active_agent/providers/anthropic/requests/content/base.rb +21 -0
- data/lib/active_agent/providers/anthropic/requests/content/sources/base.rb +22 -0
- data/lib/active_agent/providers/anthropic/requests/context_management_config.rb +18 -0
- data/lib/active_agent/providers/anthropic/requests/messages/_types.rb +189 -0
- data/lib/active_agent/providers/anthropic/requests/messages/assistant.rb +23 -0
- data/lib/active_agent/providers/anthropic/requests/messages/base.rb +63 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/_types.rb +143 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/base.rb +21 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/document.rb +26 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/image.rb +23 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/redacted_thinking.rb +21 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/search_result.rb +27 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/_types.rb +171 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/base.rb +22 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_base64.rb +25 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_file.rb +23 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_text.rb +25 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_url.rb +23 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_base64.rb +27 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_file.rb +23 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_url.rb +23 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/text.rb +22 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/thinking.rb +23 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/tool_result.rb +24 -0
- data/lib/active_agent/providers/anthropic/requests/messages/content/tool_use.rb +28 -0
- data/lib/active_agent/providers/anthropic/requests/messages/user.rb +21 -0
- data/lib/active_agent/providers/anthropic/requests/metadata.rb +18 -0
- data/lib/active_agent/providers/anthropic/requests/response_format.rb +22 -0
- data/lib/active_agent/providers/anthropic/requests/thinking_config/_types.rb +60 -0
- data/lib/active_agent/providers/anthropic/requests/thinking_config/base.rb +20 -0
- data/lib/active_agent/providers/anthropic/requests/thinking_config/disabled.rb +16 -0
- data/lib/active_agent/providers/anthropic/requests/thinking_config/enabled.rb +20 -0
- data/lib/active_agent/providers/anthropic/requests/tool_choice/_types.rb +78 -0
- data/lib/active_agent/providers/anthropic/requests/tool_choice/any.rb +17 -0
- data/lib/active_agent/providers/anthropic/requests/tool_choice/auto.rb +17 -0
- data/lib/active_agent/providers/anthropic/requests/tool_choice/base.rb +20 -0
- data/lib/active_agent/providers/anthropic/requests/tool_choice/none.rb +16 -0
- data/lib/active_agent/providers/anthropic/requests/tool_choice/tool.rb +20 -0
- data/lib/active_agent/providers/anthropic_provider.rb +211 -0
- data/lib/active_agent/providers/common/messages/_types.rb +124 -0
- data/lib/active_agent/providers/common/messages/assistant.rb +57 -0
- data/lib/active_agent/providers/common/messages/base.rb +17 -0
- data/lib/active_agent/providers/common/messages/system.rb +20 -0
- data/lib/active_agent/providers/common/messages/tool.rb +21 -0
- data/lib/active_agent/providers/common/messages/user.rb +20 -0
- data/lib/active_agent/providers/common/model.rb +361 -0
- data/lib/active_agent/providers/common/response.rb +13 -0
- data/lib/active_agent/providers/common/responses/_types.rb +51 -0
- data/lib/active_agent/providers/common/responses/base.rb +151 -0
- data/lib/active_agent/providers/common/responses/embed.rb +33 -0
- data/lib/active_agent/providers/common/responses/format.rb +31 -0
- data/lib/active_agent/providers/common/responses/message.rb +3 -0
- data/lib/active_agent/providers/common/responses/prompt.rb +42 -0
- data/lib/active_agent/providers/concerns/exception_handler.rb +72 -0
- data/lib/active_agent/providers/concerns/previewable.rb +150 -0
- data/lib/active_agent/providers/log_subscriber.rb +360 -0
- data/lib/active_agent/providers/mock/_types.rb +77 -0
- data/lib/active_agent/providers/mock/embedding_request.rb +17 -0
- data/lib/active_agent/providers/mock/messages/_types.rb +103 -0
- data/lib/active_agent/providers/mock/messages/assistant.rb +26 -0
- data/lib/active_agent/providers/mock/messages/base.rb +63 -0
- data/lib/active_agent/providers/mock/messages/user.rb +18 -0
- data/lib/active_agent/providers/mock/options.rb +30 -0
- data/lib/active_agent/providers/mock/request.rb +38 -0
- data/lib/active_agent/providers/mock_provider.rb +311 -0
- data/lib/active_agent/providers/ollama/_types.rb +5 -0
- data/lib/active_agent/providers/ollama/chat/_types.rb +44 -0
- data/lib/active_agent/providers/ollama/chat/request.rb +70 -0
- data/lib/active_agent/providers/ollama/chat/requests/_types.rb +3 -0
- data/lib/active_agent/providers/ollama/chat/requests/messages/_types.rb +116 -0
- data/lib/active_agent/providers/ollama/chat/requests/messages/assistant.rb +19 -0
- data/lib/active_agent/providers/ollama/chat/requests/messages/user.rb +19 -0
- data/lib/active_agent/providers/ollama/embedding/_types.rb +44 -0
- data/lib/active_agent/providers/ollama/embedding/request.rb +77 -0
- data/lib/active_agent/providers/ollama/embedding/requests/_types.rb +83 -0
- data/lib/active_agent/providers/ollama/embedding/requests/options.rb +104 -0
- data/lib/active_agent/providers/ollama/options.rb +27 -0
- data/lib/active_agent/providers/ollama_provider.rb +95 -0
- data/lib/active_agent/providers/open_ai/_base.rb +58 -0
- data/lib/active_agent/providers/open_ai/_types.rb +5 -0
- data/lib/active_agent/providers/open_ai/chat/_types.rb +44 -0
- data/lib/active_agent/providers/open_ai/chat/request.rb +215 -0
- data/lib/active_agent/providers/open_ai/chat/requests/_types.rb +229 -0
- data/lib/active_agent/providers/open_ai/chat/requests/audio.rb +24 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/_types.rb +123 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/assistant.rb +42 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/base.rb +78 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/_types.rb +133 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/audio.rb +35 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/base.rb +24 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/file.rb +26 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/files/_types.rb +60 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/files/details.rb +41 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/image.rb +37 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/refusal.rb +25 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/text.rb +25 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/developer.rb +25 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/function.rb +25 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/system.rb +25 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/tool.rb +26 -0
- data/lib/active_agent/providers/open_ai/chat/requests/messages/user.rb +32 -0
- data/lib/active_agent/providers/open_ai/chat/requests/prediction.rb +46 -0
- data/lib/active_agent/providers/open_ai/chat/requests/response_format.rb +53 -0
- data/lib/active_agent/providers/open_ai/chat/requests/stream_options.rb +24 -0
- data/lib/active_agent/providers/open_ai/chat/requests/tool_choice.rb +26 -0
- data/lib/active_agent/providers/open_ai/chat/requests/tools/_types.rb +5 -0
- data/lib/active_agent/providers/open_ai/chat/requests/tools/base.rb +22 -0
- data/lib/active_agent/providers/open_ai/chat/requests/tools/custom_tool.rb +41 -0
- data/lib/active_agent/providers/open_ai/chat/requests/tools/function_tool.rb +51 -0
- data/lib/active_agent/providers/open_ai/chat/requests/web_search_options.rb +45 -0
- data/lib/active_agent/providers/open_ai/chat_provider.rb +198 -0
- data/lib/active_agent/providers/open_ai/embedding/_types.rb +45 -0
- data/lib/active_agent/providers/open_ai/embedding/request.rb +85 -0
- data/lib/active_agent/providers/open_ai/embedding/requests/_types.rb +49 -0
- data/lib/active_agent/providers/open_ai/options.rb +74 -0
- data/lib/active_agent/providers/open_ai/responses/_types.rb +50 -0
- data/lib/active_agent/providers/open_ai/responses/request.rb +163 -0
- data/lib/active_agent/providers/open_ai/responses/requests/_types.rb +231 -0
- data/lib/active_agent/providers/open_ai/responses/requests/conversation.rb +23 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/_types.rb +264 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/assistant_message.rb +22 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/base.rb +89 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/code_interpreter_tool_call.rb +30 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/computer_tool_call.rb +28 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/computer_tool_call_output.rb +33 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/_types.rb +207 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/base.rb +22 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_audio.rb +26 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_file.rb +28 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_image.rb +28 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_text.rb +25 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/custom_tool_call.rb +28 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/custom_tool_call_output.rb +27 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/developer_message.rb +20 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/file_search_tool_call.rb +25 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/function_call_output.rb +32 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/function_tool_call.rb +28 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/image_gen_tool_call.rb +27 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/input_message.rb +31 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/item_reference.rb +23 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/local_shell_tool_call.rb +26 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/local_shell_tool_call_output.rb +33 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_approval_request.rb +30 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_approval_response.rb +28 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_list_tools.rb +29 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_tool_call.rb +35 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/output_message.rb +35 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/reasoning.rb +33 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/system_message.rb +20 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/tool_call_base.rb +27 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/tool_message.rb +23 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/user_message.rb +20 -0
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/web_search_tool_call.rb +24 -0
- data/lib/active_agent/providers/open_ai/responses/requests/prompt_reference.rb +23 -0
- data/lib/active_agent/providers/open_ai/responses/requests/reasoning.rb +23 -0
- data/lib/active_agent/providers/open_ai/responses/requests/stream_options.rb +20 -0
- data/lib/active_agent/providers/open_ai/responses/requests/text/_types.rb +89 -0
- data/lib/active_agent/providers/open_ai/responses/requests/text/base.rb +22 -0
- data/lib/active_agent/providers/open_ai/responses/requests/text/json_object.rb +20 -0
- data/lib/active_agent/providers/open_ai/responses/requests/text/json_schema.rb +48 -0
- data/lib/active_agent/providers/open_ai/responses/requests/text/plain.rb +20 -0
- data/lib/active_agent/providers/open_ai/responses/requests/text.rb +41 -0
- data/lib/active_agent/providers/open_ai/responses/requests/tool_choice.rb +26 -0
- data/lib/active_agent/providers/open_ai/responses/requests/tools/_types.rb +112 -0
- data/lib/active_agent/providers/open_ai/responses/requests/tools/base.rb +25 -0
- data/lib/active_agent/providers/open_ai/responses/requests/tools/code_interpreter_tool.rb +23 -0
- data/lib/active_agent/providers/open_ai/responses/requests/tools/computer_tool.rb +27 -0
- data/lib/active_agent/providers/open_ai/responses/requests/tools/custom_tool.rb +28 -0
- data/lib/active_agent/providers/open_ai/responses/requests/tools/file_search_tool.rb +27 -0
- data/lib/active_agent/providers/open_ai/responses/requests/tools/function_tool.rb +29 -0
- data/lib/active_agent/providers/open_ai/responses/requests/tools/image_generation_tool.rb +37 -0
- data/lib/active_agent/providers/open_ai/responses/requests/tools/local_shell_tool.rb +21 -0
- data/lib/active_agent/providers/open_ai/responses/requests/tools/mcp_tool.rb +41 -0
- data/lib/active_agent/providers/open_ai/responses/requests/tools/web_search_preview_tool.rb +24 -0
- data/lib/active_agent/providers/open_ai/responses/requests/tools/web_search_tool.rb +25 -0
- data/lib/active_agent/providers/open_ai/responses_provider.rb +153 -0
- data/lib/active_agent/providers/open_ai/schema.yml +65937 -0
- data/lib/active_agent/providers/open_ai_provider.rb +97 -0
- data/lib/active_agent/providers/open_router/_types.rb +45 -0
- data/lib/active_agent/providers/open_router/options.rb +93 -0
- data/lib/active_agent/providers/open_router/request.rb +83 -0
- data/lib/active_agent/providers/open_router/requests/_types.rb +198 -0
- data/lib/active_agent/providers/open_router/requests/message.rb +1 -0
- data/lib/active_agent/providers/open_router/requests/messages/_types.rb +59 -0
- data/lib/active_agent/providers/open_router/requests/messages/assistant.rb +20 -0
- data/lib/active_agent/providers/open_router/requests/messages/content/_types.rb +97 -0
- data/lib/active_agent/providers/open_router/requests/messages/content/file.rb +27 -0
- data/lib/active_agent/providers/open_router/requests/messages/content/files/_types.rb +61 -0
- data/lib/active_agent/providers/open_router/requests/messages/content/files/details.rb +26 -0
- data/lib/active_agent/providers/open_router/requests/messages/user.rb +30 -0
- data/lib/active_agent/providers/open_router/requests/plugin.rb +25 -0
- data/lib/active_agent/providers/open_router/requests/plugins/_types.rb +46 -0
- data/lib/active_agent/providers/open_router/requests/plugins/pdf_config.rb +29 -0
- data/lib/active_agent/providers/open_router/requests/prediction.rb +17 -0
- data/lib/active_agent/providers/open_router/requests/provider_preferences/_types.rb +44 -0
- data/lib/active_agent/providers/open_router/requests/provider_preferences/max_price.rb +30 -0
- data/lib/active_agent/providers/open_router/requests/provider_preferences.rb +64 -0
- data/lib/active_agent/providers/open_router/requests/response_format.rb +49 -0
- data/lib/active_agent/providers/open_router_provider.rb +53 -0
- data/lib/active_agent/providers/openai_provider.rb +2 -0
- data/lib/active_agent/providers/openrouter_provider.rb +2 -0
- data/lib/active_agent/railtie.rb +8 -6
- data/lib/active_agent/schema_generator.rb +333 -166
- data/lib/active_agent/version.rb +1 -1
- data/lib/active_agent.rb +112 -36
- data/lib/generators/active_agent/agent/USAGE +78 -0
- data/lib/generators/active_agent/{agent_generator.rb → agent/agent_generator.rb} +14 -4
- data/lib/generators/active_agent/install/USAGE +25 -0
- data/lib/generators/active_agent/{install_generator.rb → install/install_generator.rb} +1 -19
- data/lib/generators/active_agent/templates/agent.rb.tt +7 -3
- data/lib/generators/active_agent/templates/application_agent.rb.tt +0 -2
- data/lib/generators/erb/agent_generator.rb +31 -16
- data/lib/generators/erb/templates/instructions.md.erb.tt +3 -0
- data/lib/generators/erb/templates/instructions.md.tt +3 -0
- data/lib/generators/erb/templates/instructions.text.tt +1 -0
- data/lib/generators/erb/templates/message.md.erb.tt +5 -0
- data/lib/generators/erb/templates/schema.json.tt +10 -0
- data/lib/generators/test_unit/agent_generator.rb +1 -1
- data/lib/generators/test_unit/templates/functional_test.rb.tt +4 -2
- metadata +320 -65
- data/lib/active_agent/action_prompt/action.rb +0 -13
- data/lib/active_agent/action_prompt/base.rb +0 -623
- data/lib/active_agent/action_prompt/message.rb +0 -126
- data/lib/active_agent/action_prompt/prompt.rb +0 -136
- data/lib/active_agent/action_prompt.rb +0 -19
- data/lib/active_agent/callbacks.rb +0 -33
- data/lib/active_agent/generation_provider/anthropic_provider.rb +0 -163
- data/lib/active_agent/generation_provider/base.rb +0 -55
- data/lib/active_agent/generation_provider/base_adapter.rb +0 -19
- data/lib/active_agent/generation_provider/error_handling.rb +0 -167
- data/lib/active_agent/generation_provider/log_subscriber.rb +0 -92
- data/lib/active_agent/generation_provider/message_formatting.rb +0 -107
- data/lib/active_agent/generation_provider/ollama_provider.rb +0 -66
- data/lib/active_agent/generation_provider/open_ai_provider.rb +0 -279
- data/lib/active_agent/generation_provider/open_router_provider.rb +0 -385
- data/lib/active_agent/generation_provider/parameter_builder.rb +0 -119
- data/lib/active_agent/generation_provider/response.rb +0 -75
- data/lib/active_agent/generation_provider/responses_adapter.rb +0 -44
- data/lib/active_agent/generation_provider/stream_processing.rb +0 -58
- data/lib/active_agent/generation_provider/tool_management.rb +0 -142
- data/lib/active_agent/generation_provider.rb +0 -67
- data/lib/active_agent/log_subscriber.rb +0 -44
- data/lib/active_agent/parameterized.rb +0 -75
- data/lib/active_agent/prompt_helper.rb +0 -19
- data/lib/active_agent/queued_generation.rb +0 -12
- data/lib/active_agent/rescuable.rb +0 -34
- data/lib/active_agent/sanitizers.rb +0 -40
- data/lib/active_agent/streaming.rb +0 -34
- data/lib/active_agent/test_case.rb +0 -125
- data/lib/generators/USAGE +0 -47
- data/lib/generators/active_agent/USAGE +0 -56
- data/lib/generators/erb/install_generator.rb +0 -44
- data/lib/generators/erb/templates/layout.html.erb.tt +0 -1
- data/lib/generators/erb/templates/layout.json.erb.tt +0 -1
- data/lib/generators/erb/templates/layout.text.erb.tt +0 -1
- data/lib/generators/erb/templates/view.html.erb.tt +0 -5
- data/lib/generators/erb/templates/view.json.erb.tt +0 -16
- /data/lib/active_agent/{preview.rb → concerns/preview.rb} +0 -0
- /data/lib/generators/erb/templates/{view.text.erb.tt → message.text.erb.tt} +0 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveAgent
|
|
4
|
+
# Provides streaming callback support for agent classes.
|
|
5
|
+
#
|
|
6
|
+
# Callbacks can be registered for three points in the streaming lifecycle:
|
|
7
|
+
# - {on_stream_open} - invoked before the first chunk
|
|
8
|
+
# - {on_stream} - invoked for every chunk received
|
|
9
|
+
# - {on_stream_close} - invoked after the final chunk
|
|
10
|
+
#
|
|
11
|
+
# Callbacks automatically receive a {StreamChunk} parameter if they accept arguments.
|
|
12
|
+
#
|
|
13
|
+
# @example Basic usage with chunk parameter
|
|
14
|
+
# class MyPrompt < ActiveAgent::Base
|
|
15
|
+
# on_stream_open :setup_stream
|
|
16
|
+
# on_stream :log_chunk
|
|
17
|
+
# on_stream_close :cleanup_stream
|
|
18
|
+
#
|
|
19
|
+
# private
|
|
20
|
+
#
|
|
21
|
+
# def setup_stream(chunk)
|
|
22
|
+
# puts "Stream opening..."
|
|
23
|
+
# puts "First message: #{chunk.message}"
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# def log_chunk(chunk)
|
|
27
|
+
# print chunk.delta if chunk.delta
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# def cleanup_stream(chunk)
|
|
31
|
+
# puts "\nStream complete!"
|
|
32
|
+
# end
|
|
33
|
+
# end
|
|
34
|
+
#
|
|
35
|
+
# @example Usage without chunk parameter
|
|
36
|
+
# class MyPrompt < ActiveAgent::Base
|
|
37
|
+
# on_stream_open :initialize_counter
|
|
38
|
+
# on_stream :increment_counter
|
|
39
|
+
# on_stream_close :log_total
|
|
40
|
+
#
|
|
41
|
+
# private
|
|
42
|
+
#
|
|
43
|
+
# def initialize_counter
|
|
44
|
+
# @count = 0
|
|
45
|
+
# end
|
|
46
|
+
#
|
|
47
|
+
# def increment_counter
|
|
48
|
+
# @count += 1
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# def log_total
|
|
52
|
+
# puts "Total chunks: #{@count}"
|
|
53
|
+
# end
|
|
54
|
+
# end
|
|
55
|
+
#
|
|
56
|
+
# @example Using blocks
|
|
57
|
+
# class MyPrompt < ActiveAgent::Base
|
|
58
|
+
# on_stream do |chunk|
|
|
59
|
+
# Rails.logger.info("Received: #{chunk.delta}")
|
|
60
|
+
# end
|
|
61
|
+
# end
|
|
62
|
+
#
|
|
63
|
+
# @example With callback options
|
|
64
|
+
# class MyPrompt < ActiveAgent::Base
|
|
65
|
+
# on_stream :log_chunk, if: :debug_mode?
|
|
66
|
+
# on_stream_close :save_response, unless: :test_environment?
|
|
67
|
+
# end
|
|
68
|
+
module Streaming
|
|
69
|
+
extend ActiveSupport::Concern
|
|
70
|
+
|
|
71
|
+
# Data object representing a chunk of streamed content.
|
|
72
|
+
#
|
|
73
|
+
# @!attribute [r] message
|
|
74
|
+
# @return [Object] the complete message object from the provider
|
|
75
|
+
# @!attribute [r] delta
|
|
76
|
+
# @return [String, nil] the incremental content delta for this chunk
|
|
77
|
+
class StreamChunk < Data.define(:message, :delta); end
|
|
78
|
+
|
|
79
|
+
included do
|
|
80
|
+
include AbstractController::Callbacks
|
|
81
|
+
|
|
82
|
+
define_callbacks :stream_open
|
|
83
|
+
define_callbacks :stream
|
|
84
|
+
define_callbacks :stream_close
|
|
85
|
+
|
|
86
|
+
# Internal attribute to store the current streaming chunk.
|
|
87
|
+
#
|
|
88
|
+
# @api private
|
|
89
|
+
attr_internal :stream_chunk
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
class_methods do
|
|
93
|
+
# Defines a callback for when streaming opens.
|
|
94
|
+
#
|
|
95
|
+
# Invoked before the first chunk. Callbacks receive a {StreamChunk}
|
|
96
|
+
# if they accept arguments.
|
|
97
|
+
#
|
|
98
|
+
# @param names [Symbol] method names to call as callbacks
|
|
99
|
+
# @param block [Proc] optional block to execute as a callback
|
|
100
|
+
# @yield [chunk] passes the {StreamChunk} if the block accepts parameters
|
|
101
|
+
# @yieldparam chunk [StreamChunk] current stream chunk
|
|
102
|
+
# @option options [Symbol, Proc] :if condition for running the callback
|
|
103
|
+
# @option options [Symbol, Proc] :unless condition for skipping the callback
|
|
104
|
+
# @return [void]
|
|
105
|
+
#
|
|
106
|
+
# @example With method that accepts chunk
|
|
107
|
+
# on_stream_open :setup_streaming
|
|
108
|
+
#
|
|
109
|
+
# def setup_streaming(chunk)
|
|
110
|
+
# @buffer = []
|
|
111
|
+
# Rails.logger.info("Starting: #{chunk.message}")
|
|
112
|
+
# end
|
|
113
|
+
#
|
|
114
|
+
# @example With method that doesn't need chunk
|
|
115
|
+
# on_stream_open :initialize_buffer
|
|
116
|
+
#
|
|
117
|
+
# def initialize_buffer
|
|
118
|
+
# @buffer = []
|
|
119
|
+
# end
|
|
120
|
+
#
|
|
121
|
+
# @example With a block
|
|
122
|
+
# on_stream_open do |chunk|
|
|
123
|
+
# Rails.logger.info("Stream opening with message: #{chunk.message}")
|
|
124
|
+
# end
|
|
125
|
+
#
|
|
126
|
+
# @example With conditions
|
|
127
|
+
# on_stream_open :log_open, if: :logging_enabled?
|
|
128
|
+
def on_stream_open(*names, &block)
|
|
129
|
+
_stream_define_callback(:stream_open, *names, &block)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Defines a callback for handling streaming responses.
|
|
133
|
+
#
|
|
134
|
+
# Invoked for every chunk received. Callbacks receive a {StreamChunk}
|
|
135
|
+
# if they accept arguments.
|
|
136
|
+
#
|
|
137
|
+
# @param names [Symbol] method names to call as callbacks
|
|
138
|
+
# @param block [Proc] optional block to execute as a callback
|
|
139
|
+
# @yield [chunk] passes the {StreamChunk} if the block accepts parameters
|
|
140
|
+
# @yieldparam chunk [StreamChunk] current stream chunk
|
|
141
|
+
# @option options [Symbol, Proc] :if condition for running the callback
|
|
142
|
+
# @option options [Symbol, Proc] :unless condition for skipping the callback
|
|
143
|
+
# @return [void]
|
|
144
|
+
#
|
|
145
|
+
# @example With method that accepts chunk
|
|
146
|
+
# on_stream :process_chunk
|
|
147
|
+
#
|
|
148
|
+
# def process_chunk(chunk)
|
|
149
|
+
# print chunk.delta if chunk.delta
|
|
150
|
+
# end
|
|
151
|
+
#
|
|
152
|
+
# @example With method that doesn't need chunk
|
|
153
|
+
# on_stream :increment_counter
|
|
154
|
+
#
|
|
155
|
+
# def increment_counter
|
|
156
|
+
# @chunk_count += 1
|
|
157
|
+
# end
|
|
158
|
+
#
|
|
159
|
+
# @example With a block
|
|
160
|
+
# on_stream do |chunk|
|
|
161
|
+
# print chunk.delta if chunk.delta
|
|
162
|
+
# end
|
|
163
|
+
#
|
|
164
|
+
# @example With conditions
|
|
165
|
+
# on_stream :buffer_chunk, unless: :direct_output?
|
|
166
|
+
def on_stream(*names, &block)
|
|
167
|
+
_stream_define_callback(:stream, *names, &block)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Defines a callback for when streaming closes.
|
|
171
|
+
#
|
|
172
|
+
# Invoked after the final chunk. Callbacks receive a {StreamChunk}
|
|
173
|
+
# if they accept arguments.
|
|
174
|
+
#
|
|
175
|
+
# @param names [Symbol] method names to call as callbacks
|
|
176
|
+
# @param block [Proc] optional block to execute as a callback
|
|
177
|
+
# @yield [chunk] passes the {StreamChunk} if the block accepts parameters
|
|
178
|
+
# @yieldparam chunk [StreamChunk] current stream chunk
|
|
179
|
+
# @option options [Symbol, Proc] :if condition for running the callback
|
|
180
|
+
# @option options [Symbol, Proc] :unless condition for skipping the callback
|
|
181
|
+
# @return [void]
|
|
182
|
+
#
|
|
183
|
+
# @example With method that accepts chunk
|
|
184
|
+
# on_stream_close :save_response
|
|
185
|
+
#
|
|
186
|
+
# def save_response(chunk)
|
|
187
|
+
# Rails.logger.info("Complete: #{chunk.message}")
|
|
188
|
+
# end
|
|
189
|
+
#
|
|
190
|
+
# @example With method that doesn't need chunk
|
|
191
|
+
# on_stream_close :cleanup
|
|
192
|
+
#
|
|
193
|
+
# def cleanup
|
|
194
|
+
# @buffer = nil
|
|
195
|
+
# end
|
|
196
|
+
#
|
|
197
|
+
# @example With a block
|
|
198
|
+
# on_stream_close do |chunk|
|
|
199
|
+
# Rails.logger.info("Stream complete")
|
|
200
|
+
# end
|
|
201
|
+
#
|
|
202
|
+
# @example With conditions
|
|
203
|
+
# on_stream_close :persist_response, if: :should_save?
|
|
204
|
+
def on_stream_close(*names, &block)
|
|
205
|
+
_stream_define_callback(:stream_close, *names, &block)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# @api private
|
|
209
|
+
# @param callback_name [Symbol] callback type (:stream_open, :stream, :stream_close)
|
|
210
|
+
# @param names [Array<Symbol>] method names or procs to register
|
|
211
|
+
# @param block [Proc] optional block to register
|
|
212
|
+
# @return [void]
|
|
213
|
+
def _stream_define_callback(callback_name, *names, &block)
|
|
214
|
+
_insert_callbacks(names, block) do |name, options|
|
|
215
|
+
wrapper = _stream_define_callback_wrapper(callback_name, name)
|
|
216
|
+
set_callback(callback_name, :before, wrapper, **options)
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# @api private
|
|
221
|
+
# @param callback_name [Symbol] callback type
|
|
222
|
+
# @param method_ref [Symbol, Proc] method name or proc to wrap
|
|
223
|
+
# @return [Symbol] wrapper method name
|
|
224
|
+
def _stream_define_callback_wrapper(callback_name, method_ref)
|
|
225
|
+
if method_ref.is_a?(Proc)
|
|
226
|
+
_stream_define_callback_wrapper_proc(callback_name, method_ref)
|
|
227
|
+
else
|
|
228
|
+
_stream_define_callback_wrapper_name(callback_name, method_ref)
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# @api private
|
|
233
|
+
# @param callback_name [Symbol] callback type
|
|
234
|
+
# @param method_name [Symbol] method name to wrap
|
|
235
|
+
# @return [Symbol] wrapper method name
|
|
236
|
+
def _stream_define_callback_wrapper_name(callback_name, method_name)
|
|
237
|
+
define_method(:"_#{callback_name}_#{method_name}") do
|
|
238
|
+
if method(method_name).arity.zero?
|
|
239
|
+
send(method_name)
|
|
240
|
+
else
|
|
241
|
+
send(method_name, stream_chunk)
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# @api private
|
|
247
|
+
# @param callback_name [Symbol] callback type
|
|
248
|
+
# @param method_proc [Proc] proc to wrap
|
|
249
|
+
# @return [Symbol] wrapper method name
|
|
250
|
+
def _stream_define_callback_wrapper_proc(callback_name, method_proc)
|
|
251
|
+
define_method(:"_#{callback_name}_#{method_proc.object_id}") do
|
|
252
|
+
if method_proc.arity.zero?
|
|
253
|
+
instance_exec(&method_proc)
|
|
254
|
+
else
|
|
255
|
+
instance_exec(stream_chunk, &method_proc)
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
private
|
|
262
|
+
|
|
263
|
+
# Returns a proc that runs streaming callbacks for provider execution.
|
|
264
|
+
#
|
|
265
|
+
# The returned proc creates a {StreamChunk} and triggers callbacks
|
|
266
|
+
# based on the type parameter (`:open`, `:update`, or `:close`).
|
|
267
|
+
#
|
|
268
|
+
# @return [Proc] callback proc that accepts (message, delta, type)
|
|
269
|
+
def stream_broadcaster
|
|
270
|
+
proc do |message, delta, type|
|
|
271
|
+
self.stream_chunk = StreamChunk.new(message, delta)
|
|
272
|
+
|
|
273
|
+
run_callbacks(:stream_open) if type == :open
|
|
274
|
+
run_callbacks(:stream)
|
|
275
|
+
run_callbacks(:stream_close) if type == :close
|
|
276
|
+
|
|
277
|
+
# Don't leak dirty context between callbacks or into userspace
|
|
278
|
+
self.stream_chunk = nil
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveAgent
|
|
4
|
+
# Provides tool/function calling support for agent classes.
|
|
5
|
+
#
|
|
6
|
+
# Enables agent classes to respond to tool calls from providers
|
|
7
|
+
# by routing them to the appropriate action methods.
|
|
8
|
+
module Tooling
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
11
|
+
# Returns a proc that handles tool/function calls from providers.
|
|
12
|
+
#
|
|
13
|
+
# The proc routes tool calls to the appropriate action method using
|
|
14
|
+
# the {#process} method.
|
|
15
|
+
#
|
|
16
|
+
# @return [Proc] callback proc that accepts (action_name, *args, **kwargs)
|
|
17
|
+
def tools_function
|
|
18
|
+
proc do |action_name, *args, **kwargs|
|
|
19
|
+
process(action_name, *args, **kwargs)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveAgent
|
|
4
|
+
# Provides template lookup and rendering for agent classes.
|
|
5
|
+
#
|
|
6
|
+
# Enables agents to render instructions, schemas, and messages from
|
|
7
|
+
# ERB templates with flexible directory structures and fallback paths.
|
|
8
|
+
module View
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
11
|
+
included do
|
|
12
|
+
include ActionView::Layouts
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Builds template lookup paths supporting both flat and nested directory structures.
|
|
16
|
+
#
|
|
17
|
+
# Templates are searched in priority order:
|
|
18
|
+
# - `app/views/{agent_name}/` (e.g., `app/views/support_agent/`)
|
|
19
|
+
# - `app/views/agents/{agent_without_suffix}/` (e.g., `app/views/agents/support/`)
|
|
20
|
+
#
|
|
21
|
+
# With action_name present:
|
|
22
|
+
# - `app/views/agents/{agent_without_suffix}/{action_name}/`
|
|
23
|
+
# - `app/views/{agent_name}/{action_name}/`
|
|
24
|
+
# - `app/views/{agent_name}/`
|
|
25
|
+
# - `app/views/agents/{agent_without_suffix}/`
|
|
26
|
+
#
|
|
27
|
+
# @return [Array<String>] ordered prefixes for template lookup
|
|
28
|
+
def _prefixes
|
|
29
|
+
@_prefixes ||= begin
|
|
30
|
+
# Get the base agent name (e.g., "statements_agent" or "view_test/test_agent")
|
|
31
|
+
base = agent_name
|
|
32
|
+
|
|
33
|
+
# Build the nested structure under agents/
|
|
34
|
+
# e.g., "agents/statements" for StatementsAgent
|
|
35
|
+
nested = "agents/#{base.delete_suffix("_agent")}"
|
|
36
|
+
|
|
37
|
+
# Build prefixes with action_name if present
|
|
38
|
+
if action_name.present?
|
|
39
|
+
# Priority order: nested/action, base/action, base, nested
|
|
40
|
+
[ "#{nested}/#{action_name}", "#{base}/#{action_name}", base, nested ]
|
|
41
|
+
else
|
|
42
|
+
# Priority order: base, nested
|
|
43
|
+
[ nested, base ]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
##### Instructions Templating ###########################################
|
|
49
|
+
|
|
50
|
+
# Prepares instructions from various input formats.
|
|
51
|
+
#
|
|
52
|
+
# Supported formats:
|
|
53
|
+
# - `String`: returned as-is
|
|
54
|
+
# - `Symbol`: invokes method with that name (like ActiveRecord callbacks)
|
|
55
|
+
# - `Array<String>`: returned as-is if all elements are strings
|
|
56
|
+
# - `Hash`: requires `:template` key, optional `:locals`
|
|
57
|
+
# - `nil` or `true`: renders default "instructions" template
|
|
58
|
+
#
|
|
59
|
+
# @param value [Hash, String, Symbol, Array<String>, Boolean, nil]
|
|
60
|
+
# @return [String, Array<String>, nil] nil if template not found
|
|
61
|
+
# @raise [ArgumentError] if format is invalid or Hash missing :template key
|
|
62
|
+
def prompt_view_instructions(value)
|
|
63
|
+
case value
|
|
64
|
+
when String
|
|
65
|
+
value.presence
|
|
66
|
+
|
|
67
|
+
when Symbol
|
|
68
|
+
send(value)
|
|
69
|
+
|
|
70
|
+
when Array
|
|
71
|
+
raise ArgumentError, "Instructions array must contain only strings" unless value.all?(String)
|
|
72
|
+
value.presence
|
|
73
|
+
|
|
74
|
+
when Hash
|
|
75
|
+
view_render_template(value[:template] || "instructions", strict: true, **value[:locals])
|
|
76
|
+
|
|
77
|
+
when nil, true
|
|
78
|
+
view_render_template("instructions", strict: value == true, **(params.dig(:instructions, :locals) || {}))
|
|
79
|
+
|
|
80
|
+
else
|
|
81
|
+
raise ArgumentError, "Instructions must be Hash, String, Symbol or nil"
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
##### Action Templating #################################################
|
|
86
|
+
|
|
87
|
+
# Renders template for a prompt action or message.
|
|
88
|
+
#
|
|
89
|
+
# @param action_name [String, Symbol]
|
|
90
|
+
# @param locals [Hash]
|
|
91
|
+
# @return [String, nil]
|
|
92
|
+
def prompt_view_message(action_name, strict:, **locals)
|
|
93
|
+
view_render_template(action_name, strict:, **locals)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Renders JSON schema from template or returns Hash directly.
|
|
97
|
+
#
|
|
98
|
+
# Schema templates are looked up as `{name}.json`:
|
|
99
|
+
# - When value is `true` or `nil`: looks for `{action_name}.json`
|
|
100
|
+
# - When value is a String/Symbol: looks for `{value}.json`
|
|
101
|
+
# - When value is a Hash: returns the Hash directly
|
|
102
|
+
#
|
|
103
|
+
# @param value [Hash, String, Symbol, Boolean, nil]
|
|
104
|
+
# @return [Hash, String, nil]
|
|
105
|
+
def prompt_view_schema(value)
|
|
106
|
+
case value
|
|
107
|
+
when Hash
|
|
108
|
+
value
|
|
109
|
+
when String, Symbol
|
|
110
|
+
JSON.parse(view_render_template(value, strict: true, formats: [ :json ]), symbolize_names: true)
|
|
111
|
+
when true, nil
|
|
112
|
+
JSON.parse(view_render_template(action_name, strict: true, formats: [ :json ]), symbolize_names: true)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Renders template for embedding input.
|
|
117
|
+
#
|
|
118
|
+
# @param action_name [String, Symbol]
|
|
119
|
+
# @param locals [Hash]
|
|
120
|
+
# @return [String, nil]
|
|
121
|
+
def embed_view_input(action_name, **locals)
|
|
122
|
+
view_render_template(action_name, **locals)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
##### Shared Helpers ####################################################
|
|
128
|
+
|
|
129
|
+
# Renders a template if it exists in any supported ERB format.
|
|
130
|
+
#
|
|
131
|
+
# Templates are looked up using the prefixes defined in `_prefixes`:
|
|
132
|
+
# 1. `app/views/{agent_name}/` (e.g., `app/views/statements_agent/`)
|
|
133
|
+
# 2. `app/views/agents/{agent_without_suffix}/` (e.g., `app/views/agents/statements/`)
|
|
134
|
+
#
|
|
135
|
+
# @param template_name [String, Symbol] template file name without extension
|
|
136
|
+
# @param strict [Boolean] if true, raises error when template not found
|
|
137
|
+
# @param format [Symbol, nil] specific format to look for (e.g., :json, :html)
|
|
138
|
+
# @param locals [Hash] local variables passed to template
|
|
139
|
+
# @return [String, nil] nil if template not found and not strict
|
|
140
|
+
def view_render_template(template_name, strict: false, formats: nil, **locals)
|
|
141
|
+
options = { formats: }.compact
|
|
142
|
+
|
|
143
|
+
return if !strict && !lookup_context.exists?(template_name, _prefixes, false, [], **options)
|
|
144
|
+
|
|
145
|
+
template = lookup_context.find_template(template_name, _prefixes, false, [], **options)
|
|
146
|
+
|
|
147
|
+
render_to_string(template: template.virtual_path, locals:, layout: false).chomp.presence
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|