legate 0.1.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +345 -0
- data/bin/legate +13 -0
- data/examples/00_quickstart.rb +51 -0
- data/examples/01_simple_agent.rb +105 -0
- data/examples/02_multi_tool_agent.rb +140 -0
- data/examples/03_custom_tool.rb +93 -0
- data/examples/04_agent_instructions.rb +84 -0
- data/examples/05_state_and_sessions.rb +91 -0
- data/examples/06_callbacks.rb +186 -0
- data/examples/07_async_jobs.rb +112 -0
- data/examples/08_loop_agent.rb +197 -0
- data/examples/09_sequential_workflow.rb +40 -0
- data/examples/10_parallel_workflow.rb +34 -0
- data/examples/11_agent_delegation.rb +24 -0
- data/examples/12_http_client_tool.rb +156 -0
- data/examples/13_authentication.rb +220 -0
- data/examples/14_mcp_client.rb +154 -0
- data/examples/15_mcp_server.rb +79 -0
- data/examples/16_webhooks.rb +91 -0
- data/examples/README_sequential_agents.md +164 -0
- data/examples/advanced/auth/cookie_auth_tool.rb +146 -0
- data/examples/advanced/auth/custom_auth_flows_example.rb +626 -0
- data/examples/advanced/auth/excon_middleware.rb +317 -0
- data/examples/advanced/auth/excon_middleware_auth.rb +399 -0
- data/examples/advanced/auth/fiber_auth_example.rb +281 -0
- data/examples/advanced/auth/fiber_oidc_example.rb +403 -0
- data/examples/advanced/auth/httpbin_bearer_tool.rb +159 -0
- data/examples/advanced/auth/oauth2_auth.rb +419 -0
- data/examples/advanced/auth/oidc_auth.rb +514 -0
- data/examples/advanced/auth/openweather_api.rb +251 -0
- data/examples/advanced/auth/openweather_tool.rb +153 -0
- data/examples/advanced/auth/query_param_middleware_test.rb +138 -0
- data/examples/advanced/auth/service_account.rb +135 -0
- data/examples/advanced/auth/test_with_httpbin.rb +202 -0
- data/examples/advanced/auth/token_lifecycle_example.rb +428 -0
- data/examples/advanced/callback_monitoring.rb +679 -0
- data/examples/advanced/mas/fixed_delegation_example.rb +191 -0
- data/examples/advanced/mas/loop_workflow.rb +28 -0
- data/examples/advanced/mas/mock_planner.rb +77 -0
- data/examples/advanced/mas/proper_delegation_example.rb +276 -0
- data/examples/advanced/mcp/legate_mcp_server_resource_example.rb +182 -0
- data/examples/advanced/mcp/mcp_resource_server_example.rb +309 -0
- data/examples/advanced/mcp/mcp_server_async.rb +76 -0
- data/examples/advanced/mcp/mcp_server_async_tools.rb +122 -0
- data/examples/advanced/mcp/mcp_server_legate_agent.rb +95 -0
- data/examples/advanced/mcp/mcp_server_rack.rb +89 -0
- data/examples/advanced/random_calculator.rb +104 -0
- data/examples/advanced/sleep_agent.rb +153 -0
- data/examples/advanced/webhooks/webhook_e2e_runner.rb +110 -0
- data/examples/advanced/webhooks/webhook_receiver_agent.rb +58 -0
- data/examples/advanced/workflows/task_refinement_loop_agent.rb +278 -0
- data/examples/advanced/workflows/travel_planner_auto_sequential.rb +444 -0
- data/examples/advanced/workflows/travel_planner_parallel.rb +656 -0
- data/examples/advanced/workflows/travel_planner_sequential.rb +512 -0
- data/examples/tools/oauth2_example.rb +136 -0
- data/examples/tools/sleepy_tool.rb +42 -0
- data/lib/legate/activity_log.rb +71 -0
- data/lib/legate/agent.rb +959 -0
- data/lib/legate/agent_code_generator.rb +185 -0
- data/lib/legate/agent_definition.rb +812 -0
- data/lib/legate/agentic/decision.rb +49 -0
- data/lib/legate/agentic/loop.rb +134 -0
- data/lib/legate/agentic.rb +5 -0
- data/lib/legate/agents/loop_agent.rb +248 -0
- data/lib/legate/agents/parallel_agent.rb +163 -0
- data/lib/legate/agents/sequential_agent.rb +190 -0
- data/lib/legate/agents.rb +14 -0
- data/lib/legate/auth/config.rb +148 -0
- data/lib/legate/auth/coordinator.rb +218 -0
- data/lib/legate/auth/coordinators/oauth2_coordinator.rb +99 -0
- data/lib/legate/auth/coordinators/oidc_coordinator.rb +68 -0
- data/lib/legate/auth/coordinators/service_account_coordinator.rb +122 -0
- data/lib/legate/auth/credential.rb +157 -0
- data/lib/legate/auth/encryption.rb +108 -0
- data/lib/legate/auth/error.rb +94 -0
- data/lib/legate/auth/exchanged_credential.rb +180 -0
- data/lib/legate/auth/excon_middleware.rb +285 -0
- data/lib/legate/auth/http_client_utils.rb +364 -0
- data/lib/legate/auth/manager.rb +531 -0
- data/lib/legate/auth/manager_store.rb +394 -0
- data/lib/legate/auth/middleware_factory.rb +290 -0
- data/lib/legate/auth/runner.rb +279 -0
- data/lib/legate/auth/scheme.rb +125 -0
- data/lib/legate/auth/schemes/api_key.rb +212 -0
- data/lib/legate/auth/schemes/google_service_account.rb +108 -0
- data/lib/legate/auth/schemes/http_bearer.rb +98 -0
- data/lib/legate/auth/schemes/oauth2.rb +396 -0
- data/lib/legate/auth/schemes/openid_connect.rb +346 -0
- data/lib/legate/auth/schemes/service_account.rb +388 -0
- data/lib/legate/auth/schemes.rb +40 -0
- data/lib/legate/auth/token_manager.rb +362 -0
- data/lib/legate/auth/token_store.rb +86 -0
- data/lib/legate/auth/tool_context_extension.rb +97 -0
- data/lib/legate/auth/tool_integration.rb +188 -0
- data/lib/legate/auth/url_guard.rb +81 -0
- data/lib/legate/auth.rb +453 -0
- data/lib/legate/callbacks/callback_context.rb +71 -0
- data/lib/legate/cli/agent_commands.rb +950 -0
- data/lib/legate/cli/auth_commands.rb +520 -0
- data/lib/legate/cli/base_command.rb +24 -0
- data/lib/legate/cli/deployment_commands.rb +934 -0
- data/lib/legate/cli/output_helper.rb +108 -0
- data/lib/legate/cli/session_commands.rb +138 -0
- data/lib/legate/cli/skaffold_commands.rb +223 -0
- data/lib/legate/cli/tool_commands.rb +261 -0
- data/lib/legate/cli/web_commands.rb +182 -0
- data/lib/legate/cli.rb +40 -0
- data/lib/legate/configuration/webhooks.rb +113 -0
- data/lib/legate/configuration.rb +39 -0
- data/lib/legate/definition_store.rb +23 -0
- data/lib/legate/errors.rb +118 -0
- data/lib/legate/event.rb +161 -0
- data/lib/legate/gemini_ai_beta_patch.rb +39 -0
- data/lib/legate/generators/agent_generator.rb +412 -0
- data/lib/legate/generators/code_validator.rb +48 -0
- data/lib/legate/generators/legate/install_generator.rb +35 -0
- data/lib/legate/generators/legate/templates/create_legate_tables.rb.tt +36 -0
- data/lib/legate/generators/legate/templates/initializer.rb +18 -0
- data/lib/legate/generators/runtime_tool_loader.rb +76 -0
- data/lib/legate/generators/tool_generator.rb +408 -0
- data/lib/legate/generators.rb +11 -0
- data/lib/legate/global_definition_registry.rb +506 -0
- data/lib/legate/global_tool_manager.rb +135 -0
- data/lib/legate/llm/adapter.rb +69 -0
- data/lib/legate/llm/gemini.rb +172 -0
- data/lib/legate/llm/ollama.rb +80 -0
- data/lib/legate/llm.rb +34 -0
- data/lib/legate/mcp/client.rb +320 -0
- data/lib/legate/mcp/connection/sse.rb +292 -0
- data/lib/legate/mcp/connection/stdio.rb +273 -0
- data/lib/legate/mcp/connection_manager.rb +103 -0
- data/lib/legate/mcp/server/legate_agent_adapter.rb +170 -0
- data/lib/legate/mcp/server/legate_direct_agent_adapter.rb +140 -0
- data/lib/legate/mcp/server/legate_tool_adapter.rb +119 -0
- data/lib/legate/mcp/tool_wrapper.rb +138 -0
- data/lib/legate/mcp/util/schema_converter.rb +134 -0
- data/lib/legate/mcp.rb +23 -0
- data/lib/legate/plan_executor.rb +375 -0
- data/lib/legate/planner.rb +839 -0
- data/lib/legate/rails/railtie.rb +43 -0
- data/lib/legate/rails.rb +9 -0
- data/lib/legate/redaction.rb +32 -0
- data/lib/legate/session.rb +299 -0
- data/lib/legate/session_service/active_record.rb +300 -0
- data/lib/legate/session_service/base.rb +68 -0
- data/lib/legate/session_service/event_broadcast.rb +74 -0
- data/lib/legate/session_service/in_memory.rb +188 -0
- data/lib/legate/tool/metadata_dsl.rb +122 -0
- data/lib/legate/tool.rb +276 -0
- data/lib/legate/tool_code_generator.rb +103 -0
- data/lib/legate/tool_context.rb +350 -0
- data/lib/legate/tool_loader.rb +39 -0
- data/lib/legate/tool_registry.rb +73 -0
- data/lib/legate/tool_result.rb +61 -0
- data/lib/legate/tools/agent_tool.rb +187 -0
- data/lib/legate/tools/base/http_client.rb +319 -0
- data/lib/legate/tools/base/safe_url.rb +56 -0
- data/lib/legate/tools/base_async_job_tool.rb +91 -0
- data/lib/legate/tools/calculator.rb +89 -0
- data/lib/legate/tools/cat_facts.rb +81 -0
- data/lib/legate/tools/check_job_status_tool.rb +48 -0
- data/lib/legate/tools/current_time_tool.rb +64 -0
- data/lib/legate/tools/echo.rb +43 -0
- data/lib/legate/tools/http_request_tool.rb +105 -0
- data/lib/legate/tools/random_number_tool.rb +64 -0
- data/lib/legate/tools/read_webpage_tool.rb +92 -0
- data/lib/legate/tools/sleepy_tool.rb +74 -0
- data/lib/legate/tools/webhook_tool.rb +146 -0
- data/lib/legate/version.rb +5 -0
- data/lib/legate/web/app.rb +984 -0
- data/lib/legate/web/public/css/main.css +4980 -0
- data/lib/legate/web/public/images/favicon-256.png +0 -0
- data/lib/legate/web/public/images/favicon-32.png +0 -0
- data/lib/legate/web/public/images/legate-logo-dark.png +0 -0
- data/lib/legate/web/public/images/legate-logo-light.png +0 -0
- data/lib/legate/web/public/js/legate.js +616 -0
- data/lib/legate/web/public/styles/main.scss +4402 -0
- data/lib/legate/web/routes/agent_authentication_routes.rb +530 -0
- data/lib/legate/web/routes/agent_definition_routes.rb +803 -0
- data/lib/legate/web/routes/agent_generator_routes.rb +80 -0
- data/lib/legate/web/routes/agent_interaction_routes.rb +734 -0
- data/lib/legate/web/routes/agent_runtime_routes.rb +323 -0
- data/lib/legate/web/routes/api_routes.rb +56 -0
- data/lib/legate/web/routes/authentication_routes.rb +1541 -0
- data/lib/legate/web/routes/core_routes.rb +111 -0
- data/lib/legate/web/routes/documentation_routes.rb +220 -0
- data/lib/legate/web/routes/tool_generator_routes.rb +81 -0
- data/lib/legate/web/routes/tools_ui_routes.rb +207 -0
- data/lib/legate/web/sass_compiler.rb +73 -0
- data/lib/legate/web/views/_active_session_info.slim +25 -0
- data/lib/legate/web/views/_activity_list.slim +55 -0
- data/lib/legate/web/views/_agent_card.slim +56 -0
- data/lib/legate/web/views/_agent_generator_modal.slim +382 -0
- data/lib/legate/web/views/_agent_status_controls.slim +71 -0
- data/lib/legate/web/views/_agent_tool_table.slim +74 -0
- data/lib/legate/web/views/_chat_message.slim +95 -0
- data/lib/legate/web/views/_display_agent_configuration.slim +26 -0
- data/lib/legate/web/views/_display_agent_description.slim +11 -0
- data/lib/legate/web/views/_display_agent_fallback.slim +15 -0
- data/lib/legate/web/views/_display_agent_hierarchy.slim +93 -0
- data/lib/legate/web/views/_display_agent_instruction.slim +17 -0
- data/lib/legate/web/views/_display_agent_mcp.slim +13 -0
- data/lib/legate/web/views/_display_agent_model.slim +17 -0
- data/lib/legate/web/views/_display_agent_name.slim +42 -0
- data/lib/legate/web/views/_display_agent_output_key.slim +26 -0
- data/lib/legate/web/views/_display_agent_type.slim +65 -0
- data/lib/legate/web/views/_edit_agent_configuration.slim +74 -0
- data/lib/legate/web/views/_edit_agent_description.slim +16 -0
- data/lib/legate/web/views/_edit_agent_fallback.slim +25 -0
- data/lib/legate/web/views/_edit_agent_hierarchy.slim +98 -0
- data/lib/legate/web/views/_edit_agent_instruction.slim +49 -0
- data/lib/legate/web/views/_edit_agent_mcp.slim +33 -0
- data/lib/legate/web/views/_edit_agent_model.slim +23 -0
- data/lib/legate/web/views/_edit_agent_output_key.slim +36 -0
- data/lib/legate/web/views/_edit_agent_tools.slim +40 -0
- data/lib/legate/web/views/_edit_agent_type.slim +67 -0
- data/lib/legate/web/views/_session_error.slim +4 -0
- data/lib/legate/web/views/_skeleton.slim +69 -0
- data/lib/legate/web/views/_tool_card.slim +9 -0
- data/lib/legate/web/views/_tool_generator_modal.slim +311 -0
- data/lib/legate/web/views/agent.slim +436 -0
- data/lib/legate/web/views/agent_auth.slim +562 -0
- data/lib/legate/web/views/agents.slim +369 -0
- data/lib/legate/web/views/auth.slim +112 -0
- data/lib/legate/web/views/auth_credential_detail.slim +327 -0
- data/lib/legate/web/views/auth_credentials.slim +261 -0
- data/lib/legate/web/views/auth_debug.slim +94 -0
- data/lib/legate/web/views/auth_mapping_detail.slim +151 -0
- data/lib/legate/web/views/auth_mapping_new.slim +123 -0
- data/lib/legate/web/views/auth_mappings.slim +120 -0
- data/lib/legate/web/views/auth_scheme_detail.slim +274 -0
- data/lib/legate/web/views/auth_schemes.slim +259 -0
- data/lib/legate/web/views/auth_test.slim +418 -0
- data/lib/legate/web/views/chat.slim +192 -0
- data/lib/legate/web/views/docs_index.slim +105 -0
- data/lib/legate/web/views/docs_show.slim +105 -0
- data/lib/legate/web/views/error_404.slim +5 -0
- data/lib/legate/web/views/index.slim +148 -0
- data/lib/legate/web/views/layout.slim +144 -0
- data/lib/legate/web/views/tool_detail.slim +87 -0
- data/lib/legate/web/views/tools.slim +50 -0
- data/lib/legate/web/webhook_listener.rb +367 -0
- data/lib/legate/web.rb +9 -0
- data/lib/legate.rb +220 -0
- data/public/docs/advanced/callbacks.md +828 -0
- data/public/docs/advanced/mcp_schema_conversion.md +59 -0
- data/public/docs/authentication/api_reference/config.md +210 -0
- data/public/docs/authentication/api_reference/credential.md +246 -0
- data/public/docs/authentication/api_reference/encryption.md +218 -0
- data/public/docs/authentication/api_reference/exchanged_credential.md +271 -0
- data/public/docs/authentication/api_reference/excon_middleware.md +175 -0
- data/public/docs/authentication/api_reference/index.md +30 -0
- data/public/docs/authentication/api_reference/scheme.md +250 -0
- data/public/docs/authentication/api_reference/schemes/api_key.md +175 -0
- data/public/docs/authentication/api_reference/schemes/google_service_account.md +221 -0
- data/public/docs/authentication/api_reference/schemes/http_bearer.md +169 -0
- data/public/docs/authentication/api_reference/schemes/oauth2.md +343 -0
- data/public/docs/authentication/api_reference/schemes/oidc.md +73 -0
- data/public/docs/authentication/api_reference/schemes/openid_connect.md +311 -0
- data/public/docs/authentication/api_reference/schemes/service_account.md +287 -0
- data/public/docs/authentication/api_reference/token_manager.md +221 -0
- data/public/docs/authentication/api_reference/token_store.md +146 -0
- data/public/docs/authentication/api_reference/tool_context_extension.md +166 -0
- data/public/docs/authentication/guides/api_key.md +190 -0
- data/public/docs/authentication/guides/bearer.md +172 -0
- data/public/docs/authentication/guides/configuration.md +255 -0
- data/public/docs/authentication/guides/custom_flow.md +523 -0
- data/public/docs/authentication/guides/index.md +24 -0
- data/public/docs/authentication/guides/migration.md +435 -0
- data/public/docs/authentication/guides/oauth2.md +252 -0
- data/public/docs/authentication/guides/oidc.md +241 -0
- data/public/docs/authentication/guides/overview.md +155 -0
- data/public/docs/authentication/guides/secure_storage.md +301 -0
- data/public/docs/authentication/guides/service_account.md +228 -0
- data/public/docs/authentication/guides/token_lifecycle.md +295 -0
- data/public/docs/authentication/guides/web_ui_integration.md +504 -0
- data/public/docs/authentication/index.md +58 -0
- data/public/docs/authentication/troubleshooting/credential_storage.md +550 -0
- data/public/docs/authentication/troubleshooting/environment_variables.md +540 -0
- data/public/docs/authentication/troubleshooting/index.md +11 -0
- data/public/docs/authentication/troubleshooting/oauth2_issues.md +220 -0
- data/public/docs/authentication/troubleshooting/oidc_issues.md +412 -0
- data/public/docs/authentication/troubleshooting/token_refresh.md +338 -0
- data/public/docs/cli/legate_cli_usage.md +363 -0
- data/public/docs/core_concepts/legate_agent_lifecycle.md +124 -0
- data/public/docs/core_concepts/legate_architecture_overview.md +110 -0
- data/public/docs/core_concepts/legate_configuration.md +116 -0
- data/public/docs/core_concepts/legate_definition_store.md +102 -0
- data/public/docs/core_concepts/legate_planner.md +94 -0
- data/public/docs/core_concepts/legate_session_service.md +104 -0
- data/public/docs/error_handling/legate_error_handling.md +122 -0
- data/public/docs/examples.md +199 -0
- data/public/docs/getting_started.md +111 -0
- data/public/docs/guides/agentic_agents.md +137 -0
- data/public/docs/guides/ai_code_generators.md +437 -0
- data/public/docs/guides/auto_loading.md +326 -0
- data/public/docs/guides/configuring_agent_webhooks.md +219 -0
- data/public/docs/guides/http_client_usage.md +264 -0
- data/public/docs/guides/llm_providers.md +137 -0
- data/public/docs/guides/mcp_client_integration.md +232 -0
- data/public/docs/guides/mcp_server_exposure.md +206 -0
- data/public/docs/guides/rails_integration.md +128 -0
- data/public/docs/guides/sending_outbound_webhooks.md +227 -0
- data/public/docs/guides/streaming.md +112 -0
- data/public/docs/guides/webhooks.md +288 -0
- data/public/docs/introduction.md +51 -0
- data/public/docs/multi_agent_systems/advanced_features.md +57 -0
- data/public/docs/multi_agent_systems/agent_delegation.md +190 -0
- data/public/docs/multi_agent_systems/agent_hierarchy.md +49 -0
- data/public/docs/multi_agent_systems/state_management.md +47 -0
- data/public/docs/multi_agent_systems/workflow_agents.md +72 -0
- data/public/docs/tools/legate_built_in_tools.md +332 -0
- data/public/docs/tools/legate_tools_and_registry.md +263 -0
- data/public/docs/web_ui/legate_web_ui.md +137 -0
- metadata +823 -0
|
@@ -0,0 +1,812 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'forwardable'
|
|
4
|
+
require 'json'
|
|
5
|
+
require_relative 'errors'
|
|
6
|
+
|
|
7
|
+
module Legate
|
|
8
|
+
class AgentDefinition
|
|
9
|
+
extend Forwardable
|
|
10
|
+
|
|
11
|
+
# @return [Symbol] The unique name identifying this agent definition.
|
|
12
|
+
attr_reader :name
|
|
13
|
+
# @return [String] A description of the agent's purpose.
|
|
14
|
+
attr_reader :description
|
|
15
|
+
# @return [String] The core instructions given to the language model.
|
|
16
|
+
attr_reader :instruction
|
|
17
|
+
# @return [Set<Symbol>] A set of names of the tools available to this agent.
|
|
18
|
+
attr_reader :tool_names
|
|
19
|
+
# @return [String, nil] The specific model name to use (e.g., "gpt-4-turbo"). Overrides global default.
|
|
20
|
+
attr_reader :model_name
|
|
21
|
+
# @return [Float, nil] The temperature setting for the model. Overrides global default.
|
|
22
|
+
attr_reader :temperature
|
|
23
|
+
# @return [Boolean] Whether this agent can be triggered by webhooks. Defaults to false.
|
|
24
|
+
attr_reader :webhook_enabled
|
|
25
|
+
# @return [Symbol, Proc, nil] The validator (name or proc) for webhook requests.
|
|
26
|
+
attr_reader :webhook_validator
|
|
27
|
+
# @return [String, nil] The secret key for webhook validation.
|
|
28
|
+
attr_reader :webhook_secret
|
|
29
|
+
# @return [Proc, nil] The transformer proc for webhook payloads.
|
|
30
|
+
attr_reader :webhook_transformer
|
|
31
|
+
# @return [Proc, nil] The session extractor proc for webhook requests.
|
|
32
|
+
attr_reader :webhook_session_extractor
|
|
33
|
+
# @return [Symbol] The fallback mode (:error or :echo). Defaults to :error.
|
|
34
|
+
attr_reader :fallback_mode
|
|
35
|
+
# @return [Array<Hash>] Configuration for MCP servers. Defaults to [].
|
|
36
|
+
attr_reader :mcp_servers
|
|
37
|
+
# @return [Set<Symbol>] A set of names of sub-agent definitions to instantiate.
|
|
38
|
+
attr_reader :sub_agent_names
|
|
39
|
+
# @return [Symbol, nil] The key under which the agent's final output should be stored in the session state.
|
|
40
|
+
attr_reader :output_key
|
|
41
|
+
# @return [Symbol] The type of agent (:llm, :sequential, :parallel, :loop). Defaults to :llm.
|
|
42
|
+
attr_reader :agent_type
|
|
43
|
+
# @return [Symbol] Planning strategy for :llm agents — :plan (one upfront plan, default)
|
|
44
|
+
# or :react (agentic observe->think->act loop).
|
|
45
|
+
attr_reader :planning_strategy
|
|
46
|
+
# @return [Set<Symbol>] A set of names of sub-agents to execute in sequence (for SequentialAgent).
|
|
47
|
+
attr_reader :sequential_sub_agent_names
|
|
48
|
+
# @return [Set<Symbol>] A set of names of sub-agents to execute in parallel (for ParallelAgent).
|
|
49
|
+
attr_reader :parallel_sub_agent_names
|
|
50
|
+
# @return [Set<Symbol>] A set of names of sub-agents to execute in each loop iteration (for LoopAgent).
|
|
51
|
+
attr_reader :loop_sub_agent_names
|
|
52
|
+
# @return [Integer, nil] The maximum number of loop iterations (for LoopAgent).
|
|
53
|
+
attr_reader :loop_max_iterations
|
|
54
|
+
# @return [Integer, nil] Wall-clock timeout in seconds for the entire loop (for LoopAgent).
|
|
55
|
+
attr_reader :loop_timeout_seconds
|
|
56
|
+
# @return [Symbol, nil] The key in the session state to check for loop condition (for LoopAgent).
|
|
57
|
+
attr_reader :loop_condition_state_key
|
|
58
|
+
# @return [Object, nil] The expected value for loop condition (for LoopAgent).
|
|
59
|
+
attr_reader :loop_condition_expected_value
|
|
60
|
+
# @return [Integer, nil] Timeout in seconds for each parallel sub-agent (for ParallelAgent). Defaults to 120.
|
|
61
|
+
attr_reader :parallel_timeout_seconds
|
|
62
|
+
# @return [Set<Symbol>] A set of names of agents that this agent can delegate tasks to via LLM planning.
|
|
63
|
+
attr_reader :delegation_targets
|
|
64
|
+
|
|
65
|
+
# --- Authentication Attributes ---
|
|
66
|
+
# @return [Set<Symbol>] A set of credential names this agent can use.
|
|
67
|
+
attr_reader :auth_credential_names
|
|
68
|
+
# @return [Array<Hash>] URL pattern to scheme/credential mappings for this agent.
|
|
69
|
+
attr_reader :auth_url_mappings
|
|
70
|
+
# @return [Hash<Symbol, Symbol>] Service to scheme name assignments.
|
|
71
|
+
attr_reader :auth_scheme_assignments
|
|
72
|
+
# @return [Hash<Symbol, Symbol>] Service to credential name assignments.
|
|
73
|
+
attr_reader :auth_credential_assignments
|
|
74
|
+
|
|
75
|
+
# --- Callback Attributes ---
|
|
76
|
+
# @return [Proc, nil] Callback run before agent execution begins
|
|
77
|
+
attr_reader :before_agent_callback
|
|
78
|
+
# @return [Proc, nil] Callback run after agent execution completes
|
|
79
|
+
attr_reader :after_agent_callback
|
|
80
|
+
# @return [Proc, nil] Callback run before LLM model interaction
|
|
81
|
+
attr_reader :before_model_callback
|
|
82
|
+
# @return [Proc, nil] Callback run after LLM model interaction
|
|
83
|
+
attr_reader :after_model_callback
|
|
84
|
+
# @return [Proc, nil] Callback run before any tool execution
|
|
85
|
+
attr_reader :before_tool_callback
|
|
86
|
+
# @return [Proc, nil] Callback run after any tool execution
|
|
87
|
+
attr_reader :after_tool_callback
|
|
88
|
+
|
|
89
|
+
# --- End Callback Attributes ---
|
|
90
|
+
|
|
91
|
+
# Delegate common attributes to the definition proxy for easier access during definition
|
|
92
|
+
# Only delegate methods needed *within* the define block
|
|
93
|
+
def_delegators :@proxy, :use_tool
|
|
94
|
+
|
|
95
|
+
def initialize
|
|
96
|
+
@name = nil
|
|
97
|
+
@description = ''
|
|
98
|
+
@instruction = ''
|
|
99
|
+
@tool_names = Set.new
|
|
100
|
+
@model_name = nil
|
|
101
|
+
@temperature = nil
|
|
102
|
+
# --- Webhook Defaults ---
|
|
103
|
+
@webhook_enabled = false
|
|
104
|
+
@webhook_validator = nil
|
|
105
|
+
@webhook_secret = nil
|
|
106
|
+
@webhook_transformer = nil
|
|
107
|
+
@webhook_session_extractor = nil
|
|
108
|
+
@fallback_mode = :error # Default fallback mode
|
|
109
|
+
@mcp_servers = [] # Default MCP servers
|
|
110
|
+
@sub_agent_names = Set.new # MAS attribute for sub-agent definitions
|
|
111
|
+
@output_key = nil # MAS attribute for state management
|
|
112
|
+
# --- MAS Workflow Agent Attributes ---
|
|
113
|
+
@agent_type = :llm # Default agent type
|
|
114
|
+
@planning_strategy = :plan # :plan (upfront plan) or :react (agentic loop)
|
|
115
|
+
@sequential_sub_agent_names = Set.new # For SequentialAgent
|
|
116
|
+
@parallel_sub_agent_names = Set.new # For ParallelAgent
|
|
117
|
+
@loop_sub_agent_names = Set.new # For LoopAgent
|
|
118
|
+
@loop_max_iterations = nil # Maximum number of loop iterations
|
|
119
|
+
@loop_timeout_seconds = nil
|
|
120
|
+
@parallel_timeout_seconds = nil
|
|
121
|
+
@loop_condition_state_key = nil
|
|
122
|
+
@loop_condition_expected_value = nil # Expected value for loop condition
|
|
123
|
+
@delegation_targets = Set.new # Agent names that this agent can delegate to
|
|
124
|
+
# -----------------------
|
|
125
|
+
|
|
126
|
+
# --- Authentication Attributes ---
|
|
127
|
+
@auth_credential_names = Set.new # Credential names this agent can use
|
|
128
|
+
@auth_url_mappings = [] # URL pattern to scheme/credential mappings
|
|
129
|
+
@auth_scheme_assignments = {} # Service to scheme assignments
|
|
130
|
+
@auth_credential_assignments = {} # Service to credential assignments
|
|
131
|
+
# -----------------------
|
|
132
|
+
|
|
133
|
+
@proxy = DefinitionProxy.new(self)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# DSL method used within `Agent.define` block.
|
|
137
|
+
# @param block [Proc] The block containing the definition DSL calls.
|
|
138
|
+
def define(&block)
|
|
139
|
+
@proxy.instance_eval(&block)
|
|
140
|
+
validate!
|
|
141
|
+
self
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Validates that the definition has all required fields.
|
|
145
|
+
# @raise [ArgumentError] If validation fails.
|
|
146
|
+
def validate!
|
|
147
|
+
raise ArgumentError, 'Agent definition must have a name.' if @name.nil? || @name.to_s.strip.empty?
|
|
148
|
+
raise ArgumentError, 'Agent name must be a Symbol.' unless @name.is_a?(Symbol)
|
|
149
|
+
|
|
150
|
+
# Instruction is optional: a tool-only agent doesn't need a hand-written
|
|
151
|
+
# system prompt, so derive a sensible default from the name/description
|
|
152
|
+
# rather than failing the build.
|
|
153
|
+
if @instruction.nil? || @instruction.strip.empty?
|
|
154
|
+
description = @description.to_s.strip
|
|
155
|
+
@instruction = "You are the #{@name} agent.#{description.empty? ? '' : " #{description}"} " \
|
|
156
|
+
'Use the available tools to help the user.'
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Explicitly check instance variable to bypass potential method resolution issues
|
|
160
|
+
return unless @webhook_enabled
|
|
161
|
+
|
|
162
|
+
# raise ArgumentError, "Agent '#{@name}' enabled for webhooks must define a webhook_transformer." unless @webhook_transformer.is_a?(Proc)
|
|
163
|
+
# raise ArgumentError, "Agent '#{@name}' enabled for webhooks must define a webhook_session_extractor." unless @webhook_session_extractor.is_a?(Proc)
|
|
164
|
+
Legate.logger.warn { "Agent '#{@name}' is webhook_enabled but lacks a valid :webhook_transformer Proc." } unless @webhook_transformer.is_a?(Proc)
|
|
165
|
+
return if @webhook_session_extractor.is_a?(Proc)
|
|
166
|
+
|
|
167
|
+
Legate.logger.warn { "Agent '#{@name}' is webhook_enabled but lacks a valid :webhook_session_extractor Proc." }
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Returns a hash representation suitable for logging or inspection.
|
|
171
|
+
# @return [Hash]
|
|
172
|
+
def to_h
|
|
173
|
+
{
|
|
174
|
+
name: @name,
|
|
175
|
+
description: @description,
|
|
176
|
+
instruction: @instruction,
|
|
177
|
+
tool_names: @tool_names.to_a,
|
|
178
|
+
model_name: @model_name,
|
|
179
|
+
temperature: @temperature,
|
|
180
|
+
webhook_enabled: @webhook_enabled,
|
|
181
|
+
webhook_validator: @webhook_validator.is_a?(Proc) ? '<Proc>' : @webhook_validator,
|
|
182
|
+
webhook_secret: @webhook_secret ? '<present>' : nil,
|
|
183
|
+
webhook_transformer: @webhook_transformer.is_a?(Proc) ? '<Proc>' : nil,
|
|
184
|
+
webhook_session_extractor: @webhook_session_extractor.is_a?(Proc) ? '<Proc>' : nil,
|
|
185
|
+
fallback_mode: @fallback_mode,
|
|
186
|
+
mcp_servers: @mcp_servers,
|
|
187
|
+
sub_agent_names: @sub_agent_names.to_a, # MAS attribute
|
|
188
|
+
output_key: @output_key, # MAS attribute
|
|
189
|
+
# Adding new MAS attributes for agent hierarchy and workflow
|
|
190
|
+
agent_type: @agent_type || :llm, # Default to :llm if not set
|
|
191
|
+
planning_strategy: @planning_strategy || :plan, # :plan (default) or :react
|
|
192
|
+
sequential_sub_agent_names: @sequential_sub_agent_names&.to_a || [],
|
|
193
|
+
parallel_sub_agent_names: @parallel_sub_agent_names&.to_a || [],
|
|
194
|
+
loop_sub_agent_names: @loop_sub_agent_names&.to_a || [],
|
|
195
|
+
loop_max_iterations: @loop_max_iterations,
|
|
196
|
+
loop_condition_state_key: @loop_condition_state_key,
|
|
197
|
+
loop_condition_expected_value: @loop_condition_expected_value,
|
|
198
|
+
delegation_targets: @delegation_targets&.to_a || [],
|
|
199
|
+
# --- Authentication fields ---
|
|
200
|
+
auth_credential_names: @auth_credential_names&.to_a || [],
|
|
201
|
+
auth_url_mappings: (@auth_url_mappings || []).map do |m|
|
|
202
|
+
{
|
|
203
|
+
pattern: m[:pattern].is_a?(Regexp) ? m[:pattern].source : m[:pattern],
|
|
204
|
+
pattern_type: m[:pattern].is_a?(Regexp) ? 'regexp' : 'string',
|
|
205
|
+
scheme_name: m[:scheme_name]&.to_s,
|
|
206
|
+
credential_name: m[:credential_name]&.to_s
|
|
207
|
+
}
|
|
208
|
+
end,
|
|
209
|
+
auth_scheme_assignments: (@auth_scheme_assignments || {}).transform_keys(&:to_s).transform_values(&:to_s),
|
|
210
|
+
auth_credential_assignments: (@auth_credential_assignments || {}).transform_keys(&:to_s).transform_values(&:to_s)
|
|
211
|
+
}
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Internal proxy class to provide a clean DSL within the `define` block.
|
|
215
|
+
class DefinitionProxy
|
|
216
|
+
def initialize(definition)
|
|
217
|
+
@definition = definition
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Sets the agent name.
|
|
221
|
+
# @param name [Symbol] Unique identifier for the agent.
|
|
222
|
+
def name(name)
|
|
223
|
+
raise ArgumentError, 'Agent name must be a Symbol.' unless name.is_a?(Symbol)
|
|
224
|
+
|
|
225
|
+
@definition.instance_variable_set(:@name, name)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Sets the agent description.
|
|
229
|
+
# @param description [String]
|
|
230
|
+
def description(description)
|
|
231
|
+
@definition.instance_variable_set(:@description, description.to_s)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# Sets the agent's core instruction.
|
|
235
|
+
# @param instruction [String]
|
|
236
|
+
def instruction(instruction)
|
|
237
|
+
@definition.instance_variable_set(:@instruction, instruction.to_s)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Selects a tool for the agent to use. Accepts the tool's registered name
|
|
241
|
+
# (Symbol or String, coerced to a Symbol) or a Legate::Tool subclass — the
|
|
242
|
+
# class is registered globally and selected by its metadata name in one
|
|
243
|
+
# step, so you don't have to call GlobalToolManager.register_tool yourself.
|
|
244
|
+
# @param tool [Symbol, String, Class<Legate::Tool>]
|
|
245
|
+
# @param options [Hash] Tool-specific options (currently unused).
|
|
246
|
+
def use_tool(tool, _options = {})
|
|
247
|
+
names = @definition.instance_variable_get(:@tool_names)
|
|
248
|
+
if tool.is_a?(Class) && tool < Legate::Tool
|
|
249
|
+
Legate::GlobalToolManager.register_tool(tool)
|
|
250
|
+
registered_name = tool.tool_metadata[:name]
|
|
251
|
+
raise ArgumentError, "Tool class #{tool} has no resolvable name to register." if registered_name.nil?
|
|
252
|
+
|
|
253
|
+
names << registered_name.to_sym
|
|
254
|
+
elsif tool.is_a?(Symbol) || tool.is_a?(String)
|
|
255
|
+
names << tool.to_sym
|
|
256
|
+
else
|
|
257
|
+
raise ArgumentError,
|
|
258
|
+
"use_tool expects a tool name (Symbol/String) or a Legate::Tool subclass, got #{tool.class}."
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Sets the specific model name for this agent.
|
|
263
|
+
# @param model_name [String, Symbol]
|
|
264
|
+
def model_name(model_name)
|
|
265
|
+
@definition.instance_variable_set(:@model_name, model_name.to_sym)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Sets the temperature for this agent.
|
|
269
|
+
# @param temperature [Float]
|
|
270
|
+
def temperature(temperature)
|
|
271
|
+
@definition.instance_variable_set(:@temperature, temperature.to_f)
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# --- Webhook Configuration DSL ---
|
|
275
|
+
|
|
276
|
+
# Enables or disables webhook triggering for this agent.
|
|
277
|
+
# @param enabled [Boolean]
|
|
278
|
+
def webhook_enabled(enabled)
|
|
279
|
+
@definition.instance_variable_set(:@webhook_enabled, !!enabled)
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Sets the validator for webhook requests.
|
|
283
|
+
# @param validator [Symbol, Proc, nil] The name of a registered validator, a Proc, or nil.
|
|
284
|
+
def webhook_validator(validator)
|
|
285
|
+
# Allow nil, Symbol, or Proc
|
|
286
|
+
raise ArgumentError, 'webhook_validator must be a Symbol, a Proc, or nil.' unless validator.nil? || validator.is_a?(Symbol) || validator.is_a?(Proc)
|
|
287
|
+
|
|
288
|
+
@definition.instance_variable_set(:@webhook_validator, validator)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Sets the secret key for webhook validation.
|
|
292
|
+
# @param secret [String]
|
|
293
|
+
def webhook_secret(secret)
|
|
294
|
+
@definition.instance_variable_set(:@webhook_secret, secret)
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Sets the transformer proc for webhook payloads.
|
|
298
|
+
# @param transformer_proc [Proc, nil] The transformer proc or nil.
|
|
299
|
+
def webhook_transformer(transformer_proc)
|
|
300
|
+
# Allow nil or Proc
|
|
301
|
+
unless transformer_proc.nil? || transformer_proc.is_a?(Proc)
|
|
302
|
+
raise ArgumentError,
|
|
303
|
+
'webhook_transformer must be a Proc or nil.'
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
@definition.instance_variable_set(:@webhook_transformer, transformer_proc)
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# Sets the session extractor proc for webhook requests.
|
|
310
|
+
# @param extractor_proc [Proc, nil] The extractor proc or nil.
|
|
311
|
+
def webhook_session_extractor(extractor_proc)
|
|
312
|
+
# Allow nil or Proc
|
|
313
|
+
unless extractor_proc.nil? || extractor_proc.is_a?(Proc)
|
|
314
|
+
raise ArgumentError,
|
|
315
|
+
'webhook_session_extractor must be a Proc or nil.'
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
@definition.instance_variable_set(:@webhook_session_extractor, extractor_proc)
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Sets the fallback mode for the agent.
|
|
322
|
+
# @param mode [Symbol] :error or :echo.
|
|
323
|
+
def fallback_mode(mode)
|
|
324
|
+
valid_modes = %i[error echo]
|
|
325
|
+
raise ArgumentError, "Invalid fallback_mode '#{mode}'. Must be one of: #{valid_modes.join(', ')}." unless valid_modes.include?(mode)
|
|
326
|
+
|
|
327
|
+
@definition.instance_variable_set(:@fallback_mode, mode)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# Configures MCP servers for the agent.
|
|
331
|
+
# @param server_configs [Hash, Array<Hash>] MCP server configuration(s).
|
|
332
|
+
def mcp_servers(*server_configs)
|
|
333
|
+
configs = Array(server_configs).flatten.compact
|
|
334
|
+
# Basic validation: Ensure it's an array of hashes?
|
|
335
|
+
raise ArgumentError, 'MCP server configurations must be provided as Hashes.' unless configs.all? { |c| c.is_a?(Hash) }
|
|
336
|
+
|
|
337
|
+
@definition.instance_variable_set(:@mcp_servers, configs)
|
|
338
|
+
end
|
|
339
|
+
# -----------------------------
|
|
340
|
+
|
|
341
|
+
# --- MAS Attributes DSL ---
|
|
342
|
+
# Defines the names of sub-agents that should be instantiated under this agent.
|
|
343
|
+
# @param names [Array<Symbol>] An array of sub-agent definition names.
|
|
344
|
+
def sub_agents_define(*names)
|
|
345
|
+
flat_names = names.flatten.map(&:to_sym)
|
|
346
|
+
invalid_names = flat_names.reject { |n| n.is_a?(Symbol) }
|
|
347
|
+
raise ArgumentError, "Sub-agent names must all be Symbols. Invalid names: #{invalid_names.join(', ')}" unless invalid_names.empty?
|
|
348
|
+
|
|
349
|
+
@definition.instance_variable_set(:@sub_agent_names, @definition.instance_variable_get(:@sub_agent_names).merge(flat_names))
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# Sets the key under which the agent's final output should be stored in session state.
|
|
353
|
+
# @param key_name [Symbol] The key name.
|
|
354
|
+
def output_key(key_name)
|
|
355
|
+
raise ArgumentError, 'Output key must be a Symbol.' unless key_name.is_a?(Symbol)
|
|
356
|
+
|
|
357
|
+
@definition.instance_variable_set(:@output_key, key_name)
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# --- MAS Workflow Agent Type ---
|
|
361
|
+
# Sets the agent type
|
|
362
|
+
# @param type [Symbol] The agent type (:llm, :sequential, :parallel, :loop)
|
|
363
|
+
def agent_type(type)
|
|
364
|
+
valid_types = %i[llm sequential parallel loop]
|
|
365
|
+
raise ArgumentError, "Agent type must be one of: #{valid_types.join(', ')}. Got: #{type}" unless valid_types.include?(type.to_sym)
|
|
366
|
+
|
|
367
|
+
@definition.instance_variable_set(:@agent_type, type.to_sym)
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
# Sets the planning strategy for an :llm agent.
|
|
371
|
+
# @param strategy [Symbol] :plan (one upfront plan, the default) or
|
|
372
|
+
# :react (agentic observe->think->act loop that reacts to tool results).
|
|
373
|
+
def planning_strategy(strategy)
|
|
374
|
+
valid = %i[plan react]
|
|
375
|
+
raise ArgumentError, "Planning strategy must be one of: #{valid.join(', ')}. Got: #{strategy}" unless valid.include?(strategy.to_sym)
|
|
376
|
+
|
|
377
|
+
@definition.instance_variable_set(:@planning_strategy, strategy.to_sym)
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# --- SequentialAgent Configuration ---
|
|
381
|
+
# Define sequential sub-agent names in order of execution
|
|
382
|
+
# @param names [Array<Symbol>] Names of sub-agents to execute in sequence
|
|
383
|
+
def sequential_sub_agents(*names)
|
|
384
|
+
flat_names = names.flatten.map(&:to_sym)
|
|
385
|
+
# Log a warning if the array is empty but don't raise an error
|
|
386
|
+
Legate.logger.warn("Empty sequential sub-agents list for agent '#{@definition.name}'") if flat_names.empty?
|
|
387
|
+
|
|
388
|
+
@definition.instance_variable_set(:@sequential_sub_agent_names, Set.new(flat_names))
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# --- ParallelAgent Configuration ---
|
|
392
|
+
# Define parallel sub-agent names to execute concurrently
|
|
393
|
+
# @param names [Array<Symbol>] Names of sub-agents to execute in parallel
|
|
394
|
+
def parallel_sub_agents(*names)
|
|
395
|
+
flat_names = names.flatten.map(&:to_sym)
|
|
396
|
+
# Log a warning if the array is empty but don't raise an error
|
|
397
|
+
Legate.logger.warn("Empty parallel sub-agents list for agent '#{@definition.name}'") if flat_names.empty?
|
|
398
|
+
|
|
399
|
+
@definition.instance_variable_set(:@parallel_sub_agent_names, Set.new(flat_names))
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# --- LoopAgent Configuration ---
|
|
403
|
+
# Define loop sub-agent names in order of execution within each loop iteration
|
|
404
|
+
# @param names [Array<Symbol>] Names of sub-agents to execute in each loop iteration
|
|
405
|
+
def loop_sub_agents(*names)
|
|
406
|
+
flat_names = names.flatten.map(&:to_sym)
|
|
407
|
+
# Log a warning if the array is empty but don't raise an error
|
|
408
|
+
Legate.logger.warn("Empty loop sub-agents list for agent '#{@definition.name}'") if flat_names.empty?
|
|
409
|
+
|
|
410
|
+
@definition.instance_variable_set(:@loop_sub_agent_names, Set.new(flat_names))
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
# Set maximum number of loop iterations
|
|
414
|
+
# @param max [Integer] The maximum number of iterations
|
|
415
|
+
def loop_max_iterations(max)
|
|
416
|
+
raise ArgumentError, "Maximum iterations must be a positive integer. Got: #{max}" unless max.is_a?(Integer) && max > 0
|
|
417
|
+
|
|
418
|
+
@definition.instance_variable_set(:@loop_max_iterations, max)
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
# Set wall-clock timeout for the entire loop execution
|
|
422
|
+
# @param seconds [Integer] The timeout in seconds
|
|
423
|
+
def loop_timeout_seconds(seconds)
|
|
424
|
+
raise ArgumentError, "Loop timeout must be a positive integer (seconds). Got: #{seconds}" unless seconds.is_a?(Integer) && seconds > 0
|
|
425
|
+
|
|
426
|
+
@definition.instance_variable_set(:@loop_timeout_seconds, seconds)
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
# Set timeout for each parallel sub-agent
|
|
430
|
+
# @param seconds [Integer] The timeout in seconds (default: 120)
|
|
431
|
+
def parallel_timeout_seconds(seconds)
|
|
432
|
+
raise ArgumentError, "Parallel timeout must be a positive integer (seconds). Got: #{seconds}" unless seconds.is_a?(Integer) && seconds > 0
|
|
433
|
+
|
|
434
|
+
@definition.instance_variable_set(:@parallel_timeout_seconds, seconds)
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
# Set the loop condition state key and expected value
|
|
438
|
+
# @param key [Symbol] The key in the session state to check
|
|
439
|
+
# @param value [Object] The expected value that indicates loop completion
|
|
440
|
+
def loop_condition(key, value)
|
|
441
|
+
raise ArgumentError, 'Loop condition key must be a Symbol.' unless key.is_a?(Symbol)
|
|
442
|
+
|
|
443
|
+
@definition.instance_variable_set(:@loop_condition_state_key, key)
|
|
444
|
+
@definition.instance_variable_set(:@loop_condition_expected_value, value)
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
# --- Delegation Configuration ---
|
|
448
|
+
# Define agent names that this agent can delegate tasks to via LLM planning
|
|
449
|
+
# @param names [Array<Symbol>] Names of agents that can be delegation targets
|
|
450
|
+
def can_delegate_to(*names)
|
|
451
|
+
flat_names = names.flatten.map(&:to_sym)
|
|
452
|
+
# Log a warning if the array is empty but don't raise an error
|
|
453
|
+
Legate.logger.warn("Empty delegation targets list for agent '#{@definition.name}'") if flat_names.empty?
|
|
454
|
+
|
|
455
|
+
@definition.instance_variable_set(:@delegation_targets, Set.new(flat_names))
|
|
456
|
+
end
|
|
457
|
+
# --- End MAS Attributes DSL ---
|
|
458
|
+
|
|
459
|
+
# --- Authentication DSL Methods ---
|
|
460
|
+
|
|
461
|
+
# Associate a registered credential with this agent
|
|
462
|
+
# @param credential_name [Symbol] Name of a registered credential
|
|
463
|
+
# @example
|
|
464
|
+
# use_credential :google_maps_api
|
|
465
|
+
# use_credential :openai_key
|
|
466
|
+
def use_credential(credential_name)
|
|
467
|
+
raise ArgumentError, 'Credential name must be a Symbol.' unless credential_name.is_a?(Symbol)
|
|
468
|
+
|
|
469
|
+
@definition.instance_variable_get(:@auth_credential_names) << credential_name
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
# Map a URL pattern to an authentication scheme and credential
|
|
473
|
+
# @param url_pattern [String, Regexp] URL pattern to match
|
|
474
|
+
# @param scheme [Symbol] Scheme type or name to use
|
|
475
|
+
# @param credential [Symbol] Credential name to use
|
|
476
|
+
# @example
|
|
477
|
+
# auth_mapping 'https://maps.googleapis.com/*', scheme: :api_key, credential: :google_maps_api
|
|
478
|
+
# auth_mapping /api\.openai\.com/, scheme: :http_bearer, credential: :openai_key
|
|
479
|
+
def auth_mapping(url_pattern, scheme:, credential:)
|
|
480
|
+
raise ArgumentError, 'URL pattern must be a String or Regexp.' unless url_pattern.is_a?(String) || url_pattern.is_a?(Regexp)
|
|
481
|
+
raise ArgumentError, 'Scheme must be a Symbol.' unless scheme.is_a?(Symbol)
|
|
482
|
+
raise ArgumentError, 'Credential must be a Symbol.' unless credential.is_a?(Symbol)
|
|
483
|
+
|
|
484
|
+
@definition.instance_variable_get(:@auth_url_mappings) << {
|
|
485
|
+
pattern: url_pattern,
|
|
486
|
+
scheme_name: scheme,
|
|
487
|
+
credential_name: credential
|
|
488
|
+
}
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
# Assign a scheme for a named service
|
|
492
|
+
# @param service [Symbol] Service identifier (e.g., :google_maps, :openai)
|
|
493
|
+
# @param scheme [Symbol] Scheme name to use for this service
|
|
494
|
+
# @example
|
|
495
|
+
# auth_scheme :google_maps, :api_key
|
|
496
|
+
# auth_scheme :openai, :http_bearer
|
|
497
|
+
def auth_scheme(service, scheme)
|
|
498
|
+
raise ArgumentError, 'Service must be a Symbol.' unless service.is_a?(Symbol)
|
|
499
|
+
raise ArgumentError, 'Scheme must be a Symbol.' unless scheme.is_a?(Symbol)
|
|
500
|
+
|
|
501
|
+
@definition.instance_variable_get(:@auth_scheme_assignments)[service] = scheme
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
# Assign a credential for a named service
|
|
505
|
+
# @param service [Symbol] Service identifier (e.g., :google_maps, :openai)
|
|
506
|
+
# @param credential [Symbol] Credential name to use for this service
|
|
507
|
+
# @example
|
|
508
|
+
# auth_credential :google_maps, :google_maps_api
|
|
509
|
+
# auth_credential :openai, :openai_key
|
|
510
|
+
def auth_credential(service, credential)
|
|
511
|
+
raise ArgumentError, 'Service must be a Symbol.' unless service.is_a?(Symbol)
|
|
512
|
+
raise ArgumentError, 'Credential must be a Symbol.' unless credential.is_a?(Symbol)
|
|
513
|
+
|
|
514
|
+
@definition.instance_variable_get(:@auth_credential_assignments)[service] = credential
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
# --- End Authentication DSL Methods ---
|
|
518
|
+
|
|
519
|
+
# --- Callback DSL Methods ---
|
|
520
|
+
|
|
521
|
+
# Sets the callback to run before agent execution
|
|
522
|
+
# @param block [Proc] The callback code to run
|
|
523
|
+
# @yieldparam context [Legate::Callbacks::CallbackContext] Context for state management
|
|
524
|
+
# @yieldreturn [Hash, nil] Optional hash to override normal execution
|
|
525
|
+
def before_agent_callback(&block)
|
|
526
|
+
raise ArgumentError, 'Callback must be a Proc or lambda.' unless block.is_a?(Proc)
|
|
527
|
+
|
|
528
|
+
@definition.instance_variable_set(:@before_agent_callback, block)
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
# Sets the callback to run after agent execution
|
|
532
|
+
# @param block [Proc] The callback code to run
|
|
533
|
+
# @yieldparam context [Legate::Callbacks::CallbackContext] Context for state management
|
|
534
|
+
# @yieldparam result [Hash] The agent's result hash that can be modified
|
|
535
|
+
# @yieldreturn [Hash, nil] Optional hash to replace the agent's result
|
|
536
|
+
def after_agent_callback(&block)
|
|
537
|
+
raise ArgumentError, 'Callback must be a Proc or lambda.' unless block.is_a?(Proc)
|
|
538
|
+
|
|
539
|
+
@definition.instance_variable_set(:@after_agent_callback, block)
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
# Sets the callback to run before model interaction
|
|
543
|
+
# @param block [Proc] The callback code to run
|
|
544
|
+
# @yieldparam context [Legate::Callbacks::CallbackContext] Context for state management
|
|
545
|
+
# @yieldparam llm_request [Hash] The request parameters being sent to the model
|
|
546
|
+
# @yieldreturn [Hash, nil] Optional hash to override normal model execution
|
|
547
|
+
def before_model_callback(&block)
|
|
548
|
+
raise ArgumentError, 'Callback must be a Proc or lambda.' unless block.is_a?(Proc)
|
|
549
|
+
|
|
550
|
+
@definition.instance_variable_set(:@before_model_callback, block)
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
# Sets the callback to run after model interaction
|
|
554
|
+
# @param block [Proc] The callback code to run
|
|
555
|
+
# @yieldparam context [Legate::Callbacks::CallbackContext] Context for state management
|
|
556
|
+
# @yieldparam plan [Hash] The plan returned by the model that can be modified
|
|
557
|
+
# @yieldreturn [Hash, nil] Optional hash to replace the model's plan
|
|
558
|
+
def after_model_callback(&block)
|
|
559
|
+
raise ArgumentError, 'Callback must be a Proc or lambda.' unless block.is_a?(Proc)
|
|
560
|
+
|
|
561
|
+
@definition.instance_variable_set(:@after_model_callback, block)
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
# Sets the callback to run before tool execution
|
|
565
|
+
# @param block [Proc] The callback code to run
|
|
566
|
+
# @yieldparam tool [Legate::Tool] The tool instance being executed
|
|
567
|
+
# @yieldparam params [Hash] The parameters being passed to the tool
|
|
568
|
+
# @yieldparam context [Legate::ToolContext] Context for tool execution and state management
|
|
569
|
+
# @yieldreturn [Hash, nil] Optional hash to override normal tool execution
|
|
570
|
+
def before_tool_callback(&block)
|
|
571
|
+
raise ArgumentError, 'Callback must be a Proc or lambda.' unless block.is_a?(Proc)
|
|
572
|
+
|
|
573
|
+
@definition.instance_variable_set(:@before_tool_callback, block)
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
# Sets the callback to run after tool execution
|
|
577
|
+
# @param block [Proc] The callback code to run
|
|
578
|
+
# @yieldparam tool [Legate::Tool] The tool instance that was executed
|
|
579
|
+
# @yieldparam params [Hash] The parameters that were passed to the tool
|
|
580
|
+
# @yieldparam context [Legate::ToolContext] Context for tool execution and state management
|
|
581
|
+
# @yieldparam result [Hash] The tool's result hash that can be modified
|
|
582
|
+
# @yieldreturn [Hash, nil] Optional hash to replace the tool's result
|
|
583
|
+
def after_tool_callback(&block)
|
|
584
|
+
raise ArgumentError, 'Callback must be a Proc or lambda.' unless block.is_a?(Proc)
|
|
585
|
+
|
|
586
|
+
@definition.instance_variable_set(:@after_tool_callback, block)
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
# --- End Callback DSL Methods ---
|
|
590
|
+
end
|
|
591
|
+
private_constant :DefinitionProxy
|
|
592
|
+
|
|
593
|
+
# Class method to create an AgentDefinition instance from a hash.
|
|
594
|
+
# This is typically used when loading a definition from a persistent store.
|
|
595
|
+
# @param hash_data [Hash] The hash containing agent definition attributes.
|
|
596
|
+
# @return [Legate::AgentDefinition, nil] A new AgentDefinition instance or nil on error.
|
|
597
|
+
def self.from_hash(hash_data)
|
|
598
|
+
return nil unless hash_data.is_a?(Hash)
|
|
599
|
+
|
|
600
|
+
definition = new
|
|
601
|
+
|
|
602
|
+
# Helper method to convert array values to Sets if present in the source hash
|
|
603
|
+
convert_to_set = lambda do |key, default = nil|
|
|
604
|
+
if hash_data.key?(key)
|
|
605
|
+
val = hash_data[key]
|
|
606
|
+
if val.is_a?(Array)
|
|
607
|
+
Set.new(val.map(&:to_sym))
|
|
608
|
+
else
|
|
609
|
+
(val.nil? ? default : Set.new([val.to_sym]))
|
|
610
|
+
end
|
|
611
|
+
else
|
|
612
|
+
default || Set.new
|
|
613
|
+
end
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
# Map string or symbol keys to our keys
|
|
617
|
+
definition.instance_variable_set(:@name, hash_data[:name]&.to_sym || hash_data['name']&.to_sym)
|
|
618
|
+
definition.instance_variable_set(:@description, hash_data[:description]&.to_s || hash_data['description']&.to_s || '')
|
|
619
|
+
definition.instance_variable_set(:@instruction, hash_data[:instruction]&.to_s || hash_data['instruction']&.to_s || '')
|
|
620
|
+
|
|
621
|
+
# Handle tools/tool_names (expected to be an array of strings or symbols)
|
|
622
|
+
tool_names = nil
|
|
623
|
+
if hash_data.key?(:tool_names) || hash_data.key?('tool_names')
|
|
624
|
+
tool_names = hash_data[:tool_names] || hash_data['tool_names']
|
|
625
|
+
elsif hash_data.key?(:tools) || hash_data.key?('tools')
|
|
626
|
+
tool_names = hash_data[:tools] || hash_data['tools']
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
# Convert tool_names to a Set of symbols (always ensure it's a Set)
|
|
630
|
+
if tool_names.is_a?(Array)
|
|
631
|
+
definition.instance_variable_set(:@tool_names, Set.new(tool_names.map(&:to_sym)))
|
|
632
|
+
elsif tool_names.is_a?(String)
|
|
633
|
+
# Special case: if it's a JSON string, try to parse it
|
|
634
|
+
begin
|
|
635
|
+
parsed_tools = JSON.parse(tool_names)
|
|
636
|
+
if parsed_tools.is_a?(Array)
|
|
637
|
+
definition.instance_variable_set(:@tool_names, Set.new(parsed_tools.map(&:to_sym)))
|
|
638
|
+
else
|
|
639
|
+
definition.instance_variable_set(:@tool_names, Set.new)
|
|
640
|
+
end
|
|
641
|
+
rescue JSON::ParserError
|
|
642
|
+
Legate.logger.warn("AgentDefinition.from_hash: tool_names string is not valid JSON, ignoring: #{tool_names.inspect}")
|
|
643
|
+
definition.instance_variable_set(:@tool_names, Set.new)
|
|
644
|
+
end
|
|
645
|
+
else
|
|
646
|
+
# No valid tools provided, use empty set
|
|
647
|
+
definition.instance_variable_set(:@tool_names, Set.new)
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
# Process model_name (string or symbol)
|
|
651
|
+
model_name = hash_data[:model_name] || hash_data['model_name'] || hash_data[:model] || hash_data['model']
|
|
652
|
+
definition.instance_variable_set(:@model_name, model_name&.to_sym)
|
|
653
|
+
|
|
654
|
+
# Process temperature (float)
|
|
655
|
+
temp_value = hash_data[:temperature] || hash_data['temperature']
|
|
656
|
+
definition.instance_variable_set(:@temperature, temp_value&.to_f)
|
|
657
|
+
|
|
658
|
+
# --- Process webhook fields ---
|
|
659
|
+
# Boolean conversion helper for webhook_enabled
|
|
660
|
+
wb_enabled = hash_data[:webhook_enabled] || hash_data['webhook_enabled']
|
|
661
|
+
wb_enabled = wb_enabled.to_s.downcase == 'true' if wb_enabled.is_a?(String)
|
|
662
|
+
definition.instance_variable_set(:@webhook_enabled, !!wb_enabled) # Force to boolean
|
|
663
|
+
|
|
664
|
+
# webhook_validator can be symbol or nil
|
|
665
|
+
wb_validator = hash_data[:webhook_validator] || hash_data['webhook_validator']
|
|
666
|
+
definition.instance_variable_set(:@webhook_validator, wb_validator.is_a?(Symbol) ? wb_validator : nil)
|
|
667
|
+
|
|
668
|
+
# webhook_secret is a string or nil
|
|
669
|
+
wb_secret = hash_data[:webhook_secret] || hash_data['webhook_secret']
|
|
670
|
+
# Special case: '<present>' is a placeholder used in to_h when the secret exists
|
|
671
|
+
definition.instance_variable_set(:@webhook_secret, wb_secret == '<present>' ? wb_secret : wb_secret)
|
|
672
|
+
|
|
673
|
+
# webhook_transformer and webhook_session_extractor are Procs (can't be serialized)
|
|
674
|
+
# Always nil when recreated from a hash
|
|
675
|
+
definition.instance_variable_set(:@webhook_transformer, nil)
|
|
676
|
+
definition.instance_variable_set(:@webhook_session_extractor, nil)
|
|
677
|
+
|
|
678
|
+
# --- Process MCP servers ---
|
|
679
|
+
# MCP servers can be array of hashes, or JSON string
|
|
680
|
+
mcp_value = hash_data[:mcp_servers] || hash_data['mcp_servers'] || hash_data[:mcp_servers_json] || hash_data['mcp_servers_json']
|
|
681
|
+
if mcp_value.is_a?(String)
|
|
682
|
+
begin
|
|
683
|
+
parsed_mcp = JSON.parse(mcp_value)
|
|
684
|
+
definition.instance_variable_set(:@mcp_servers, parsed_mcp.is_a?(Array) ? parsed_mcp : [])
|
|
685
|
+
rescue JSON::ParserError
|
|
686
|
+
# Not valid JSON, use empty array
|
|
687
|
+
definition.instance_variable_set(:@mcp_servers, [])
|
|
688
|
+
end
|
|
689
|
+
elsif mcp_value.is_a?(Array)
|
|
690
|
+
definition.instance_variable_set(:@mcp_servers, mcp_value)
|
|
691
|
+
else
|
|
692
|
+
definition.instance_variable_set(:@mcp_servers, [])
|
|
693
|
+
end
|
|
694
|
+
|
|
695
|
+
# --- Process fallback_mode (convert to symbol) ---
|
|
696
|
+
fallback = hash_data[:fallback_mode] || hash_data['fallback_mode']
|
|
697
|
+
if fallback.is_a?(String) || fallback.is_a?(Symbol)
|
|
698
|
+
fb_sym = fallback.to_sym
|
|
699
|
+
definition.instance_variable_set(:@fallback_mode, fb_sym == :echo ? :echo : :error)
|
|
700
|
+
else
|
|
701
|
+
definition.instance_variable_set(:@fallback_mode, :error) # Default
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
# --- Process MAS attributes ---
|
|
705
|
+
# Sub-agent names (convert to Set of symbols)
|
|
706
|
+
definition.instance_variable_set(:@sub_agent_names, convert_to_set.call(:sub_agent_names))
|
|
707
|
+
|
|
708
|
+
# Output key (convert to symbol if present)
|
|
709
|
+
output_key = hash_data[:output_key] || hash_data['output_key']
|
|
710
|
+
definition.instance_variable_set(:@output_key, output_key&.to_sym)
|
|
711
|
+
|
|
712
|
+
# --- MAS Workflow Agent Attributes ---
|
|
713
|
+
# Agent type (convert to symbol, default to :llm)
|
|
714
|
+
agent_type = hash_data[:agent_type] || hash_data['agent_type'] || :llm
|
|
715
|
+
if agent_type.is_a?(String) || agent_type.is_a?(Symbol)
|
|
716
|
+
agent_type_sym = agent_type.to_sym
|
|
717
|
+
valid_types = %i[llm sequential parallel loop]
|
|
718
|
+
# If invalid type, use default :llm
|
|
719
|
+
agent_type_sym = :llm unless valid_types.include?(agent_type_sym)
|
|
720
|
+
definition.instance_variable_set(:@agent_type, agent_type_sym)
|
|
721
|
+
else
|
|
722
|
+
definition.instance_variable_set(:@agent_type, :llm) # Default
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
# Planning strategy (:plan default, :react opt-in)
|
|
726
|
+
strategy = (hash_data[:planning_strategy] || hash_data['planning_strategy'] || :plan).to_sym
|
|
727
|
+
strategy = :plan unless %i[plan react].include?(strategy)
|
|
728
|
+
definition.instance_variable_set(:@planning_strategy, strategy)
|
|
729
|
+
|
|
730
|
+
# Workflow-specific sub-agent lists
|
|
731
|
+
definition.instance_variable_set(:@sequential_sub_agent_names, convert_to_set.call(:sequential_sub_agent_names))
|
|
732
|
+
definition.instance_variable_set(:@parallel_sub_agent_names, convert_to_set.call(:parallel_sub_agent_names))
|
|
733
|
+
definition.instance_variable_set(:@loop_sub_agent_names, convert_to_set.call(:loop_sub_agent_names))
|
|
734
|
+
|
|
735
|
+
# Loop configuration
|
|
736
|
+
loop_max = hash_data[:loop_max_iterations] || hash_data['loop_max_iterations']
|
|
737
|
+
definition.instance_variable_set(:@loop_max_iterations, loop_max&.to_i)
|
|
738
|
+
|
|
739
|
+
loop_key = hash_data[:loop_condition_state_key] || hash_data['loop_condition_state_key']
|
|
740
|
+
definition.instance_variable_set(:@loop_condition_state_key, loop_key&.to_sym)
|
|
741
|
+
|
|
742
|
+
loop_value = hash_data[:loop_condition_expected_value] || hash_data['loop_condition_expected_value']
|
|
743
|
+
definition.instance_variable_set(:@loop_condition_expected_value, loop_value)
|
|
744
|
+
|
|
745
|
+
# Delegation targets
|
|
746
|
+
definition.instance_variable_set(:@delegation_targets, convert_to_set.call(:delegation_targets))
|
|
747
|
+
|
|
748
|
+
# --- Authentication fields ---
|
|
749
|
+
# Auth credential names (convert to Set of symbols)
|
|
750
|
+
definition.instance_variable_set(:@auth_credential_names, convert_to_set.call(:auth_credential_names))
|
|
751
|
+
|
|
752
|
+
# Auth URL mappings (array of hashes)
|
|
753
|
+
auth_mappings_raw = hash_data[:auth_url_mappings] || hash_data['auth_url_mappings'] || []
|
|
754
|
+
if auth_mappings_raw.is_a?(String)
|
|
755
|
+
begin
|
|
756
|
+
auth_mappings_raw = JSON.parse(auth_mappings_raw)
|
|
757
|
+
rescue JSON::ParserError
|
|
758
|
+
auth_mappings_raw = []
|
|
759
|
+
end
|
|
760
|
+
end
|
|
761
|
+
auth_url_mappings = (auth_mappings_raw || []).map do |m|
|
|
762
|
+
pattern = m['pattern'] || m[:pattern]
|
|
763
|
+
pattern_type = m['pattern_type'] || m[:pattern_type]
|
|
764
|
+
# Convert back to Regexp if it was serialized as such
|
|
765
|
+
if pattern_type == 'regexp' && pattern.is_a?(String)
|
|
766
|
+
if pattern.length > 500
|
|
767
|
+
Legate.logger.warn("AgentDefinition.from_h: Rejecting oversized regex pattern (#{pattern.length} chars)")
|
|
768
|
+
else
|
|
769
|
+
begin
|
|
770
|
+
pattern = Regexp.new(pattern, timeout: 1)
|
|
771
|
+
rescue RegexpError
|
|
772
|
+
# Keep as string if invalid regexp
|
|
773
|
+
end
|
|
774
|
+
end
|
|
775
|
+
end
|
|
776
|
+
{
|
|
777
|
+
pattern: pattern,
|
|
778
|
+
scheme_name: (m['scheme_name'] || m[:scheme_name])&.to_sym,
|
|
779
|
+
credential_name: (m['credential_name'] || m[:credential_name])&.to_sym
|
|
780
|
+
}
|
|
781
|
+
end
|
|
782
|
+
definition.instance_variable_set(:@auth_url_mappings, auth_url_mappings)
|
|
783
|
+
|
|
784
|
+
# Auth scheme assignments (hash of symbol -> symbol)
|
|
785
|
+
auth_scheme_raw = hash_data[:auth_scheme_assignments] || hash_data['auth_scheme_assignments'] || {}
|
|
786
|
+
if auth_scheme_raw.is_a?(String)
|
|
787
|
+
begin
|
|
788
|
+
auth_scheme_raw = JSON.parse(auth_scheme_raw)
|
|
789
|
+
rescue JSON::ParserError
|
|
790
|
+
auth_scheme_raw = {}
|
|
791
|
+
end
|
|
792
|
+
end
|
|
793
|
+
auth_scheme_assignments = (auth_scheme_raw || {}).transform_keys(&:to_sym).transform_values(&:to_sym)
|
|
794
|
+
definition.instance_variable_set(:@auth_scheme_assignments, auth_scheme_assignments)
|
|
795
|
+
|
|
796
|
+
# Auth credential assignments (hash of symbol -> symbol)
|
|
797
|
+
auth_cred_raw = hash_data[:auth_credential_assignments] || hash_data['auth_credential_assignments'] || {}
|
|
798
|
+
if auth_cred_raw.is_a?(String)
|
|
799
|
+
begin
|
|
800
|
+
auth_cred_raw = JSON.parse(auth_cred_raw)
|
|
801
|
+
rescue JSON::ParserError
|
|
802
|
+
auth_cred_raw = {}
|
|
803
|
+
end
|
|
804
|
+
end
|
|
805
|
+
auth_credential_assignments = (auth_cred_raw || {}).transform_keys(&:to_sym).transform_values(&:to_sym)
|
|
806
|
+
definition.instance_variable_set(:@auth_credential_assignments, auth_credential_assignments)
|
|
807
|
+
|
|
808
|
+
definition.validate!
|
|
809
|
+
definition
|
|
810
|
+
end
|
|
811
|
+
end
|
|
812
|
+
end
|