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
data/lib/legate/auth.rb
ADDED
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
# File: lib/legate/auth.rb
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative 'auth/error'
|
|
5
|
+
require_relative 'auth/scheme'
|
|
6
|
+
require_relative 'auth/credential'
|
|
7
|
+
require_relative 'auth/config'
|
|
8
|
+
require_relative 'auth/exchanged_credential'
|
|
9
|
+
require_relative 'auth/encryption'
|
|
10
|
+
require_relative 'auth/token_store'
|
|
11
|
+
require_relative 'auth/schemes'
|
|
12
|
+
require_relative 'auth/coordinator'
|
|
13
|
+
require_relative 'auth/coordinators/oauth2_coordinator'
|
|
14
|
+
require_relative 'auth/coordinators/oidc_coordinator'
|
|
15
|
+
require_relative 'auth/coordinators/service_account_coordinator'
|
|
16
|
+
require_relative 'auth/excon_middleware'
|
|
17
|
+
require_relative 'auth/middleware_factory'
|
|
18
|
+
require_relative 'auth/http_client_utils'
|
|
19
|
+
|
|
20
|
+
module Legate
|
|
21
|
+
# The Auth module provides authentication capabilities for Legate tools.
|
|
22
|
+
# It supports various authentication schemes such as API Key, Bearer Token,
|
|
23
|
+
# OAuth2, OpenID Connect, and Service Accounts.
|
|
24
|
+
#
|
|
25
|
+
# @example Configure a tool with authentication
|
|
26
|
+
# credential = Legate::Auth::Credential.new(
|
|
27
|
+
# auth_type: :api_key,
|
|
28
|
+
# api_key: ENV['API_KEY']
|
|
29
|
+
# )
|
|
30
|
+
#
|
|
31
|
+
# scheme = Legate::Auth::Schemes::ApiKey.new(
|
|
32
|
+
# location: :header,
|
|
33
|
+
# name: 'X-API-Key'
|
|
34
|
+
# )
|
|
35
|
+
#
|
|
36
|
+
# # Configure the tool with authentication
|
|
37
|
+
# tool.configure(auth: {
|
|
38
|
+
# scheme: scheme,
|
|
39
|
+
# credential: credential
|
|
40
|
+
# })
|
|
41
|
+
module Auth
|
|
42
|
+
# Version of the authentication module
|
|
43
|
+
VERSION = '0.1.0'
|
|
44
|
+
|
|
45
|
+
# Global mutex for access to the OAuth callback state
|
|
46
|
+
@oauth_mutex = Mutex.new
|
|
47
|
+
|
|
48
|
+
# Condition variable for OAuth callbacks
|
|
49
|
+
@oauth_condition = ConditionVariable.new
|
|
50
|
+
|
|
51
|
+
# OAuth callback response URI
|
|
52
|
+
@oauth_response_uri = nil
|
|
53
|
+
|
|
54
|
+
# Configuration store for Auth sessions
|
|
55
|
+
@config_store = {}
|
|
56
|
+
|
|
57
|
+
# Token store for credentials - initialize with a default in-memory session service
|
|
58
|
+
@token_store = begin
|
|
59
|
+
session_service = Legate::SessionService::InMemory.new
|
|
60
|
+
TokenStore.new(session_service)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
class << self
|
|
64
|
+
# Generate a unique request ID
|
|
65
|
+
# @return [String] A unique request ID
|
|
66
|
+
def generate_request_id
|
|
67
|
+
require 'securerandom'
|
|
68
|
+
SecureRandom.uuid
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Apply authentication to a request
|
|
72
|
+
# @param request [Hash] The request to apply authentication to
|
|
73
|
+
# @param credential [Legate::Auth::Credential, Legate::Auth::ExchangedCredential] The credential to use
|
|
74
|
+
# @param scheme [Legate::Auth::Scheme, nil] The authentication scheme (if not using a stored config)
|
|
75
|
+
# @return [Hash] The authenticated request
|
|
76
|
+
# @raise [Legate::Auth::CredentialError] If the credential is invalid or missing required fields
|
|
77
|
+
def apply_authentication(request, credential, scheme = nil)
|
|
78
|
+
if credential.is_a?(ExchangedCredential) && credential.provider_id
|
|
79
|
+
# Look up the scheme from the stored config
|
|
80
|
+
scheme ||= get_scheme_for_provider(credential.provider_id)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
raise Legate::Auth::CredentialError, 'Authentication scheme is required' unless scheme
|
|
84
|
+
|
|
85
|
+
# Apply the authentication to the request
|
|
86
|
+
scheme.apply_to_request(request, credential)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Authenticate using a coordinator
|
|
90
|
+
# @param coordinator [Legate::Auth::Coordinator] The authentication coordinator
|
|
91
|
+
# @return [Legate::Auth::ExchangedCredential] The authenticated credential
|
|
92
|
+
# @raise [Legate::Auth::Error] If authentication fails
|
|
93
|
+
def authenticate_with_coordinator(coordinator)
|
|
94
|
+
# Start the authentication flow
|
|
95
|
+
auth_request = coordinator.start
|
|
96
|
+
|
|
97
|
+
# For non-interactive coordinators, the result might be available immediately
|
|
98
|
+
if coordinator.complete?
|
|
99
|
+
return coordinator.result if coordinator.success?
|
|
100
|
+
|
|
101
|
+
raise coordinator.error || Legate::Auth::Error.new('Authentication failed')
|
|
102
|
+
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# For interactive coordinators, we need to wait for user interaction
|
|
106
|
+
# This method should only be used with non-interactive coordinators
|
|
107
|
+
# or in testing scenarios where we can directly resume the coordinator
|
|
108
|
+
raise Legate::Auth::Error.new('Coordinator requires interaction but no handler provided')
|
|
109
|
+
rescue StandardError => e
|
|
110
|
+
# Wrap any errors that aren't already Legate::Auth::Error
|
|
111
|
+
raise e.is_a?(Legate::Auth::Error) ? e : Legate::Auth::Error.new(e.message)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Start the OAuth2 authentication flow
|
|
115
|
+
# @param provider_id [String] A unique identifier for the provider
|
|
116
|
+
# @param scheme [Legate::Auth::Scheme] The authentication scheme
|
|
117
|
+
# @param credential [Legate::Auth::Credential] The credential to use
|
|
118
|
+
# @param redirect_uri [String, nil] The redirect URI for the authorization request
|
|
119
|
+
# @param options [Hash, nil] Additional options for the authentication process
|
|
120
|
+
# @return [String] The authorization URI to redirect the user to
|
|
121
|
+
# @raise [Legate::Auth::ConfigurationError] If the configuration is invalid
|
|
122
|
+
def start_oauth_flow(provider_id, scheme, credential, redirect_uri = nil, options = {})
|
|
123
|
+
# Create a new config
|
|
124
|
+
config = Config.new(scheme: scheme, credential: credential, options: options)
|
|
125
|
+
|
|
126
|
+
# Build the authorization URI
|
|
127
|
+
auth_uri = config.build_authorization_uri(redirect_uri)
|
|
128
|
+
|
|
129
|
+
# Store the config
|
|
130
|
+
@config_store[provider_id] = config
|
|
131
|
+
|
|
132
|
+
auth_uri
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Handle an OAuth callback
|
|
136
|
+
# @param response_uri [String] The callback URI from the OAuth provider
|
|
137
|
+
# @return [Boolean] True if the callback was successfully handled
|
|
138
|
+
# @raise [Legate::Auth::ConfigurationError] If the response is invalid
|
|
139
|
+
def handle_oauth_callback(response_uri)
|
|
140
|
+
@oauth_mutex.synchronize do
|
|
141
|
+
@oauth_response_uri = response_uri
|
|
142
|
+
@oauth_condition.signal
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
true
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Wait for the OAuth callback to be received
|
|
149
|
+
# @param timeout [Integer, nil] The timeout in seconds (nil for no timeout)
|
|
150
|
+
# @return [String, nil] The response URI from the OAuth provider
|
|
151
|
+
def wait_for_oauth_callback(timeout = nil)
|
|
152
|
+
response_uri = nil
|
|
153
|
+
|
|
154
|
+
@oauth_mutex.synchronize do
|
|
155
|
+
if timeout
|
|
156
|
+
# Wait with timeout
|
|
157
|
+
@oauth_condition.wait(@oauth_mutex, timeout) if @oauth_response_uri.nil?
|
|
158
|
+
else
|
|
159
|
+
# Wait indefinitely
|
|
160
|
+
@oauth_condition.wait(@oauth_mutex) while @oauth_response_uri.nil?
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
response_uri = @oauth_response_uri
|
|
164
|
+
@oauth_response_uri = nil
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
response_uri
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Exchange an authorization code for tokens
|
|
171
|
+
# @param provider_id [String] The provider ID
|
|
172
|
+
# @param response_uri [String] The callback URI from the OAuth provider
|
|
173
|
+
# @return [Legate::Auth::ExchangedCredential] The exchanged credential with tokens
|
|
174
|
+
# @raise [Legate::Auth::ConfigurationError] If the configuration is invalid
|
|
175
|
+
# @raise [Legate::Auth::TokenExchangeError] If the token exchange fails
|
|
176
|
+
def exchange_oauth_code(provider_id, response_uri)
|
|
177
|
+
config = @config_store[provider_id]
|
|
178
|
+
|
|
179
|
+
raise Legate::Auth::ConfigurationError, "No stored configuration for provider #{provider_id}" unless config
|
|
180
|
+
|
|
181
|
+
# Create a response config with the response URI
|
|
182
|
+
response_config = Config.new(
|
|
183
|
+
scheme: config.scheme,
|
|
184
|
+
credential: config.credential,
|
|
185
|
+
auth_request_id: config.auth_request_id
|
|
186
|
+
)
|
|
187
|
+
response_config.response_uri = response_uri
|
|
188
|
+
response_config.state = config.state
|
|
189
|
+
|
|
190
|
+
# Validate the response
|
|
191
|
+
config.validate_response!(response_config)
|
|
192
|
+
|
|
193
|
+
# Exchange the code for tokens
|
|
194
|
+
exchanged_credential = config.scheme.exchange_token(response_config, config.credential)
|
|
195
|
+
|
|
196
|
+
# Add the provider ID to the credential
|
|
197
|
+
exchanged_credential.provider_id = provider_id
|
|
198
|
+
|
|
199
|
+
# Store the credential in the token store
|
|
200
|
+
@token_store.store(provider_id, exchanged_credential)
|
|
201
|
+
|
|
202
|
+
exchanged_credential
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Get a stored exchanged credential for a provider
|
|
206
|
+
# @param provider_id [String] The provider ID
|
|
207
|
+
# @return [Legate::Auth::ExchangedCredential, nil] The stored credential or nil if not found
|
|
208
|
+
def get_exchanged_credential(provider_id)
|
|
209
|
+
@token_store.retrieve(provider_id)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Complete the OAuth2 flow with a callback URI
|
|
213
|
+
# @param provider_id [String] The provider ID
|
|
214
|
+
# @param response_uri [String, nil] The callback URI from the OAuth provider
|
|
215
|
+
# @return [Legate::Auth::ExchangedCredential] The exchanged credential with tokens
|
|
216
|
+
# @raise [Legate::Auth::ConfigurationError] If the configuration is invalid
|
|
217
|
+
# @raise [Legate::Auth::TokenExchangeError] If the token exchange fails
|
|
218
|
+
def complete_oauth_flow(provider_id, response_uri = nil)
|
|
219
|
+
# If no response URI is provided, wait for the callback
|
|
220
|
+
response_uri ||= wait_for_oauth_callback
|
|
221
|
+
|
|
222
|
+
raise Legate::Auth::ConfigurationError, 'No response URI provided or received' unless response_uri
|
|
223
|
+
|
|
224
|
+
# Exchange the code for tokens
|
|
225
|
+
exchange_oauth_code(provider_id, response_uri)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Refresh an access token
|
|
229
|
+
# @param provider_id [String] The provider ID
|
|
230
|
+
# @return [Legate::Auth::ExchangedCredential] The refreshed credential
|
|
231
|
+
# @raise [Legate::Auth::TokenRefreshError] If the token refresh fails
|
|
232
|
+
def refresh_token(provider_id)
|
|
233
|
+
# Get the stored credential
|
|
234
|
+
exchanged_credential = get_exchanged_credential(provider_id)
|
|
235
|
+
|
|
236
|
+
raise Legate::Auth::TokenRefreshError, "No stored credential for provider #{provider_id}" unless exchanged_credential
|
|
237
|
+
|
|
238
|
+
# Get the scheme
|
|
239
|
+
scheme = get_scheme_for_provider(provider_id)
|
|
240
|
+
|
|
241
|
+
raise Legate::Auth::TokenRefreshError, "Scheme for provider #{provider_id} does not support token refresh" unless scheme && scheme.supports_refresh?
|
|
242
|
+
|
|
243
|
+
# Get the original credential
|
|
244
|
+
config = @config_store[provider_id]
|
|
245
|
+
|
|
246
|
+
raise Legate::Auth::TokenRefreshError, "No stored configuration for provider #{provider_id}" unless config
|
|
247
|
+
|
|
248
|
+
# Refresh the token
|
|
249
|
+
refreshed_credential = scheme.refresh_token(exchanged_credential, config.credential)
|
|
250
|
+
|
|
251
|
+
# Add the provider ID to the credential
|
|
252
|
+
refreshed_credential.provider_id = provider_id
|
|
253
|
+
|
|
254
|
+
# Store the refreshed credential
|
|
255
|
+
@token_store.store(provider_id, refreshed_credential)
|
|
256
|
+
|
|
257
|
+
refreshed_credential
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Get the scheme for a provider
|
|
261
|
+
# @param provider_id [String] The provider ID
|
|
262
|
+
# @return [Legate::Auth::Scheme, nil] The scheme or nil if not found
|
|
263
|
+
private def get_scheme_for_provider(provider_id)
|
|
264
|
+
config = @config_store[provider_id]
|
|
265
|
+
config&.scheme
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Get the global token store instance
|
|
269
|
+
# @return [Legate::Auth::TokenStore] The global token store
|
|
270
|
+
attr_accessor :token_store
|
|
271
|
+
|
|
272
|
+
# Set the global token store instance
|
|
273
|
+
# @param store [Legate::Auth::TokenStore] The token store to use
|
|
274
|
+
# @return [Legate::Auth::TokenStore] The token store
|
|
275
|
+
|
|
276
|
+
# Create an authentication middleware for the specified scheme and credential
|
|
277
|
+
# @param scheme [Legate::Auth::Scheme] The authentication scheme to use
|
|
278
|
+
# @param credential [Legate::Auth::Credential] The credential to use
|
|
279
|
+
# @param options [Hash] Additional options for the middleware
|
|
280
|
+
# @return [Legate::Auth::ExconMiddleware] The configured middleware
|
|
281
|
+
def create_middleware(scheme:, credential:, **options)
|
|
282
|
+
Legate::Auth::MiddlewareFactory.create(
|
|
283
|
+
scheme: scheme,
|
|
284
|
+
credential: credential,
|
|
285
|
+
token_store: options[:token_store] || token_store,
|
|
286
|
+
token_manager: options[:token_manager],
|
|
287
|
+
**options
|
|
288
|
+
)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Configure an existing Excon connection with authentication
|
|
292
|
+
# @param connection [Excon::Connection] The connection to configure
|
|
293
|
+
# @param scheme [Legate::Auth::Scheme] The authentication scheme to use
|
|
294
|
+
# @param credential [Legate::Auth::Credential] The credential to use
|
|
295
|
+
# @param options [Hash] Additional options for the middleware
|
|
296
|
+
# @return [Excon::Connection] The configured connection
|
|
297
|
+
def configure_connection(connection, scheme:, credential:, **options)
|
|
298
|
+
Legate::Auth::HttpClientUtils.configure_connection(
|
|
299
|
+
connection,
|
|
300
|
+
scheme: scheme,
|
|
301
|
+
credential: credential,
|
|
302
|
+
token_store: options[:token_store] || token_store,
|
|
303
|
+
token_manager: options[:token_manager],
|
|
304
|
+
**options
|
|
305
|
+
)
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# Create a new Excon connection with authentication
|
|
309
|
+
# @param url [String] The URL for the connection
|
|
310
|
+
# @param scheme [Legate::Auth::Scheme] The authentication scheme to use
|
|
311
|
+
# @param credential [Legate::Auth::Credential] The credential to use
|
|
312
|
+
# @param options [Hash] Additional options for the connection and middleware
|
|
313
|
+
# @return [Excon::Connection] The configured connection
|
|
314
|
+
def create_connection(url, scheme:, credential:, **options)
|
|
315
|
+
Legate::Auth::HttpClientUtils.create_connection(
|
|
316
|
+
url,
|
|
317
|
+
scheme: scheme,
|
|
318
|
+
credential: credential,
|
|
319
|
+
token_store: options[:token_store] || token_store,
|
|
320
|
+
token_manager: options[:token_manager],
|
|
321
|
+
**options
|
|
322
|
+
)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# Create a new Excon connection with API key authentication
|
|
326
|
+
# @param url [String] The URL for the connection
|
|
327
|
+
# @param api_key [String] The API key to use
|
|
328
|
+
# @param location [String] Where to place the API key ('header', 'query', 'cookie')
|
|
329
|
+
# @param name [String] The name of the parameter/header
|
|
330
|
+
# @param options [Hash] Additional options for the connection and middleware
|
|
331
|
+
# @return [Excon::Connection] The configured connection
|
|
332
|
+
def create_api_key_connection(url, api_key:, location: 'header', name: 'X-API-Key', **options)
|
|
333
|
+
Legate::Auth::HttpClientUtils.create_api_key_connection(
|
|
334
|
+
url,
|
|
335
|
+
api_key: api_key,
|
|
336
|
+
location: location,
|
|
337
|
+
name: name,
|
|
338
|
+
token_store: options[:token_store] || token_store,
|
|
339
|
+
token_manager: options[:token_manager],
|
|
340
|
+
**options
|
|
341
|
+
)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Create a new Excon connection with bearer token authentication
|
|
345
|
+
# @param url [String] The URL for the connection
|
|
346
|
+
# @param token [String] The bearer token to use
|
|
347
|
+
# @param options [Hash] Additional options for the connection and middleware
|
|
348
|
+
# @return [Excon::Connection] The configured connection
|
|
349
|
+
def create_bearer_connection(url, token:, **options)
|
|
350
|
+
Legate::Auth::HttpClientUtils.create_bearer_connection(
|
|
351
|
+
url,
|
|
352
|
+
token: token,
|
|
353
|
+
token_store: options[:token_store] || token_store,
|
|
354
|
+
token_manager: options[:token_manager],
|
|
355
|
+
**options
|
|
356
|
+
)
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
# Create a new Excon connection with OAuth2 authentication
|
|
360
|
+
# @param url [String] The URL for the connection
|
|
361
|
+
# @param client_id [String] The OAuth client ID
|
|
362
|
+
# @param client_secret [String] The OAuth client secret
|
|
363
|
+
# @param authorization_url [String] The authorization URL for the OAuth provider
|
|
364
|
+
# @param token_url [String] The token URL for the OAuth provider
|
|
365
|
+
# @param scopes [Array<String>, String, nil] The scopes to request
|
|
366
|
+
# @param options [Hash] Additional options for the connection and middleware
|
|
367
|
+
# @return [Excon::Connection] The configured connection
|
|
368
|
+
def create_oauth2_connection(url, client_id:, client_secret:, authorization_url:, token_url:, scopes: nil, **options)
|
|
369
|
+
Legate::Auth::HttpClientUtils.create_oauth2_connection(
|
|
370
|
+
url,
|
|
371
|
+
client_id: client_id,
|
|
372
|
+
client_secret: client_secret,
|
|
373
|
+
authorization_url: authorization_url,
|
|
374
|
+
token_url: token_url,
|
|
375
|
+
scopes: scopes,
|
|
376
|
+
token_store: options[:token_store] || token_store,
|
|
377
|
+
token_manager: options[:token_manager],
|
|
378
|
+
**options
|
|
379
|
+
)
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
# Create a new Excon connection with OpenID Connect authentication
|
|
383
|
+
# @param url [String] The URL for the connection
|
|
384
|
+
# @param client_id [String] The client ID to use
|
|
385
|
+
# @param client_secret [String] The client secret to use
|
|
386
|
+
# @param discovery_url [String] The OIDC discovery URL
|
|
387
|
+
# @param options [Hash] Additional options for the connection and middleware
|
|
388
|
+
# @return [Excon::Connection] The configured connection
|
|
389
|
+
def create_oidc_connection(url, client_id:, client_secret:, discovery_url:, **options)
|
|
390
|
+
Legate::Auth::HttpClientUtils.create_oidc_connection(
|
|
391
|
+
url,
|
|
392
|
+
client_id: client_id,
|
|
393
|
+
client_secret: client_secret,
|
|
394
|
+
discovery_url: discovery_url,
|
|
395
|
+
token_store: options[:token_store] || token_store,
|
|
396
|
+
token_manager: options[:token_manager],
|
|
397
|
+
**options
|
|
398
|
+
)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
# Create a new Excon connection with service account authentication
|
|
402
|
+
# @param url [String] The URL for the connection
|
|
403
|
+
# @param service_account_key [String, Hash] The service account key as JSON string or Hash
|
|
404
|
+
# @param scopes [Array<String>, String, nil] The scopes to request
|
|
405
|
+
# @param audience [String, nil] The audience for the token
|
|
406
|
+
# @param options [Hash] Additional options for the connection and middleware
|
|
407
|
+
# @return [Excon::Connection] The configured connection
|
|
408
|
+
def create_service_account_connection(url, service_account_key:, scopes: nil, audience: nil, **options)
|
|
409
|
+
Legate::Auth::HttpClientUtils.create_service_account_connection(
|
|
410
|
+
url,
|
|
411
|
+
service_account_key: service_account_key,
|
|
412
|
+
scopes: scopes,
|
|
413
|
+
audience: audience,
|
|
414
|
+
token_store: options[:token_store] || token_store,
|
|
415
|
+
token_manager: options[:token_manager],
|
|
416
|
+
**options
|
|
417
|
+
)
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
# Create a new Excon connection with Basic authentication
|
|
421
|
+
# @param url [String] The URL for the connection
|
|
422
|
+
# @param username [String] The username to use
|
|
423
|
+
# @param password [String] The password to use
|
|
424
|
+
# @param options [Hash] Additional options for the connection and middleware
|
|
425
|
+
# @return [Excon::Connection] The configured connection
|
|
426
|
+
def create_basic_auth_connection(url, username:, password:, **options)
|
|
427
|
+
Legate::Auth::HttpClientUtils.create_basic_auth_connection(
|
|
428
|
+
url,
|
|
429
|
+
username: username,
|
|
430
|
+
password: password,
|
|
431
|
+
token_store: options[:token_store] || token_store,
|
|
432
|
+
token_manager: options[:token_manager],
|
|
433
|
+
**options
|
|
434
|
+
)
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
# Create a new Excon connection using a previously configured provider
|
|
438
|
+
# @param url [String] The URL for the connection
|
|
439
|
+
# @param provider_id [String] The provider ID to use
|
|
440
|
+
# @param options [Hash] Additional options for the connection and middleware
|
|
441
|
+
# @return [Excon::Connection] The configured connection
|
|
442
|
+
def create_connection_from_provider(url, provider_id, **options)
|
|
443
|
+
Legate::Auth::HttpClientUtils.create_connection_from_provider(
|
|
444
|
+
url,
|
|
445
|
+
provider_id,
|
|
446
|
+
token_store: options[:token_store] || token_store,
|
|
447
|
+
token_manager: options[:token_manager],
|
|
448
|
+
**options
|
|
449
|
+
)
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
end
|
|
453
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# File: lib/legate/callbacks/callback_context.rb
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'securerandom'
|
|
5
|
+
require_relative '../session_service/base' # For type hinting if used
|
|
6
|
+
|
|
7
|
+
module Legate
|
|
8
|
+
module Callbacks
|
|
9
|
+
# Context object passed to agent lifecycle and model interaction callbacks.
|
|
10
|
+
class CallbackContext
|
|
11
|
+
attr_reader :agent_name, :invocation_id, :session_id, :user_id, :app_name, :session_service, :logger
|
|
12
|
+
|
|
13
|
+
# Expose pending state delta for inspection but not direct modification
|
|
14
|
+
attr_reader :pending_state_delta
|
|
15
|
+
|
|
16
|
+
# @param agent_name [Symbol]
|
|
17
|
+
# @param invocation_id [String]
|
|
18
|
+
# @param session_id [String]
|
|
19
|
+
# @param user_id [String]
|
|
20
|
+
# @param app_name [String]
|
|
21
|
+
# @param session_service [Legate::SessionService::Base]
|
|
22
|
+
# @param logger [Logger]
|
|
23
|
+
def initialize(agent_name:, invocation_id:, session_id:, user_id:, app_name:, session_service:, logger: Legate.logger)
|
|
24
|
+
@agent_name = agent_name
|
|
25
|
+
@invocation_id = invocation_id
|
|
26
|
+
@session_id = session_id
|
|
27
|
+
@user_id = user_id
|
|
28
|
+
@app_name = app_name
|
|
29
|
+
@session_service = session_service
|
|
30
|
+
@pending_state_delta = {} # Internal mutable hash
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Retrieves a value from the session state.
|
|
34
|
+
# @param key [Symbol, String] The key to retrieve
|
|
35
|
+
# @return [Object, nil] The value or nil if not found
|
|
36
|
+
def state_get(key)
|
|
37
|
+
Legate.logger.debug { "[CallbackContext] state_get for key: #{key} in session: #{@session_id}" }
|
|
38
|
+
@session_service.get_state(session_id: @session_id, key: key)
|
|
39
|
+
rescue StandardError => e
|
|
40
|
+
Legate.logger.error { "[CallbackContext] Error in state_get for key '#{key}': #{e.message}" }
|
|
41
|
+
nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Sets a value in the pending state delta. This change will be applied
|
|
45
|
+
# to the session state by the Legate framework after the callback completes.
|
|
46
|
+
# @param key [Symbol, String] The key to set
|
|
47
|
+
# @param value [Object] The value to store (should be serializable)
|
|
48
|
+
def state_set(key, value)
|
|
49
|
+
Legate.logger.debug { "[CallbackContext] state_set for key: #{key} to value: #{value.inspect} (pending)" }
|
|
50
|
+
@pending_state_delta[key.to_sym] = value
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Merges a hash into the pending state delta.
|
|
54
|
+
# @param hash_to_merge [Hash] The hash to merge into the pending state delta
|
|
55
|
+
def state_update(hash_to_merge)
|
|
56
|
+
unless hash_to_merge.is_a?(Hash)
|
|
57
|
+
Legate.logger.warn { "[CallbackContext] state_update called with non-hash: #{hash_to_merge.class}" }
|
|
58
|
+
return
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
Legate.logger.debug { "[CallbackContext] state_update with hash: #{hash_to_merge.inspect} (pending)" }
|
|
62
|
+
@pending_state_delta.merge!(hash_to_merge.transform_keys(&:to_sym))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Clears any accumulated pending state changes within this context instance.
|
|
66
|
+
def clear_pending_state_delta!
|
|
67
|
+
@pending_state_delta = {}
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|