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,261 @@
|
|
|
1
|
+
# File: lib/legate/cli/tool_commands.rb
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'thor'
|
|
5
|
+
require_relative 'base_command'
|
|
6
|
+
require_relative 'output_helper' # OutputHelper is included below
|
|
7
|
+
require_relative '../global_tool_manager' # Require the global manager
|
|
8
|
+
require_relative '../tool_context' # <--- ADDED require
|
|
9
|
+
require 'securerandom' # <-- ADDED require for dummy context
|
|
10
|
+
|
|
11
|
+
module Legate
|
|
12
|
+
module CLI
|
|
13
|
+
# CLI commands for tool management using ToolRegistry
|
|
14
|
+
class ToolCommands < BaseCommand
|
|
15
|
+
include OutputHelper
|
|
16
|
+
|
|
17
|
+
desc 'list', 'List available tools from the registry'
|
|
18
|
+
method_option :json, type: :boolean, default: false,
|
|
19
|
+
desc: 'Output result in JSON format'
|
|
20
|
+
def list
|
|
21
|
+
tools = Legate::GlobalToolManager.list_all_tools
|
|
22
|
+
if json_mode?
|
|
23
|
+
puts JSON.generate({ tools: tools.map { |t| { name: t[:name].to_s, description: t[:description] } } })
|
|
24
|
+
elsif tools.empty?
|
|
25
|
+
say 'No tools registered.'
|
|
26
|
+
else
|
|
27
|
+
say 'Available tools:', :bold
|
|
28
|
+
tools.each do |tool_info|
|
|
29
|
+
say "- #{tool_info[:name]}: #{tool_info[:description]}"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
desc 'info NAME', 'Show information about a tool from the registry'
|
|
35
|
+
def info(name)
|
|
36
|
+
tool_name_sym = name.to_sym
|
|
37
|
+
tool = Legate::GlobalToolManager.create_instance(tool_name_sym) # Create instance to get params
|
|
38
|
+
|
|
39
|
+
if tool
|
|
40
|
+
say "Tool: #{tool.name}"
|
|
41
|
+
say "Description: #{tool.description}"
|
|
42
|
+
if tool.parameters.empty?
|
|
43
|
+
say "\nParameters: None"
|
|
44
|
+
else
|
|
45
|
+
say "\nParameters:"
|
|
46
|
+
tool.parameters.each do |param_name, param_info|
|
|
47
|
+
required = param_info[:required] ? 'required' : 'optional'
|
|
48
|
+
type = param_info[:type] || 'any'
|
|
49
|
+
say " - #{param_name} (#{type}, #{required})"
|
|
50
|
+
say " #{param_info[:description]}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
else
|
|
54
|
+
say "Tool '#{name}' not found in registry.", :red
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
desc 'execute NAME [param1=value1 param2=value2 ...]', 'Execute a tool directly using key=value arguments'
|
|
59
|
+
long_desc <<-LONGDESC
|
|
60
|
+
Executes a specified tool directly with key=value pair arguments.
|
|
61
|
+
|
|
62
|
+
Example:
|
|
63
|
+
legate tool execute calculator operand1=10 operand2=5 operation=add
|
|
64
|
+
|
|
65
|
+
Arguments should be provided as `key=value`. If a value contains spaces,
|
|
66
|
+
it might need quoting depending on your shell.
|
|
67
|
+
|
|
68
|
+
If the tool execution results in a :pending status (e.g., for an async job),
|
|
69
|
+
the job_id will be printed. Use the check_job_status tool
|
|
70
|
+
in a subsequent call to get the final result.
|
|
71
|
+
LONGDESC
|
|
72
|
+
method_option :quiet, type: :boolean, default: false, aliases: '-q',
|
|
73
|
+
desc: 'Suppress status messages, only output result'
|
|
74
|
+
method_option :json, type: :boolean, default: false,
|
|
75
|
+
desc: 'Output result in JSON format (implies --quiet)'
|
|
76
|
+
method_option :user_id, type: :string, default: 'cli_user', desc: 'User ID for the tool context'
|
|
77
|
+
def execute(name, *args)
|
|
78
|
+
# Suppress all logging in JSON mode for clean output
|
|
79
|
+
Legate.logger.level = Logger::FATAL if json_mode?
|
|
80
|
+
|
|
81
|
+
tool_name_sym = name.to_sym
|
|
82
|
+
tool = Legate::GlobalToolManager.create_instance(tool_name_sym)
|
|
83
|
+
|
|
84
|
+
unless tool
|
|
85
|
+
output_error("Tool '#{name}' not found in registry.", metadata: { tool: name })
|
|
86
|
+
exit(1)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
params_to_execute = {}
|
|
90
|
+
valid_param_names = tool.parameters.keys.map(&:to_s)
|
|
91
|
+
|
|
92
|
+
args.each do |arg|
|
|
93
|
+
parts = arg.split('=', 2)
|
|
94
|
+
if parts.length == 2
|
|
95
|
+
key = parts[0].strip
|
|
96
|
+
value = parts[1]
|
|
97
|
+
|
|
98
|
+
unless valid_param_names.include?(key)
|
|
99
|
+
status_message("Warning: Provided parameter '#{key}' is not defined for tool '#{name}'. Ignoring.", :yellow)
|
|
100
|
+
next
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
params_to_execute[key.to_sym] = value # Store as symbol key
|
|
104
|
+
status_message(" Parsed: #{key} = '#{value}'")
|
|
105
|
+
elsif args.length == 1 && tool.parameters.length == 1 && tool.parameters.values.first[:required]
|
|
106
|
+
# Simplified single arg handling
|
|
107
|
+
single_key = tool.parameters.keys.first
|
|
108
|
+
status_message("Info: Assuming single argument '#{arg}' maps to required parameter '#{single_key}'.", :cyan)
|
|
109
|
+
params_to_execute[single_key] = arg
|
|
110
|
+
elsif !args.empty?
|
|
111
|
+
status_message("Warning: Argument '#{arg}' ignored. Please use 'key=value' format for parameters.", :yellow)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
begin
|
|
116
|
+
status_message("Executing tool '#{name}' with parsed params: #{params_to_execute.inspect}")
|
|
117
|
+
# --- Create a dummy context for direct tool execution ---
|
|
118
|
+
dummy_context = Legate::ToolContext.new(session_id: "cli_direct_#{SecureRandom.hex(4)}", user_id: options[:user_id],
|
|
119
|
+
app_name: 'cli_tool_exec')
|
|
120
|
+
|
|
121
|
+
# --- Call execute with context ---
|
|
122
|
+
result_hash = tool.execute(params_to_execute, dummy_context)
|
|
123
|
+
|
|
124
|
+
status_message("\nResult:", :bold)
|
|
125
|
+
output_result(result_hash, metadata: { tool: name }, format_method: :format_tool_result)
|
|
126
|
+
rescue Legate::Error, ArgumentError => e
|
|
127
|
+
output_error(e, metadata: { tool: name })
|
|
128
|
+
exit(1)
|
|
129
|
+
rescue StandardError => e
|
|
130
|
+
output_error(e, metadata: { tool: name })
|
|
131
|
+
puts e.backtrace.first(5).join("\n") unless json_mode?
|
|
132
|
+
exit(1)
|
|
133
|
+
end
|
|
134
|
+
end # end execute
|
|
135
|
+
|
|
136
|
+
no_commands do
|
|
137
|
+
# Format tool result in human-readable format
|
|
138
|
+
def format_tool_result(result_hash)
|
|
139
|
+
if result_hash.is_a?(Hash) && result_hash.key?(:status)
|
|
140
|
+
case result_hash[:status]
|
|
141
|
+
when :success
|
|
142
|
+
say 'Success:', :green
|
|
143
|
+
say " Output: #{result_hash[:result]}"
|
|
144
|
+
when :pending
|
|
145
|
+
say 'Pending:', :yellow
|
|
146
|
+
say " Job ID: #{result_hash[:job_id]}"
|
|
147
|
+
say " Message: #{result_hash[:message]}" if result_hash[:message]
|
|
148
|
+
when :error
|
|
149
|
+
say 'Error:', :red
|
|
150
|
+
say " Message: #{result_hash[:error_message]}"
|
|
151
|
+
else
|
|
152
|
+
say 'Unknown Status:', :yellow
|
|
153
|
+
say " Data: #{result_hash.inspect}"
|
|
154
|
+
end
|
|
155
|
+
else
|
|
156
|
+
say 'Unknown Result Format:', :yellow
|
|
157
|
+
say " Data: #{result_hash.inspect}"
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
desc 'ai_generate', 'Generate tool class code using AI from a natural language description'
|
|
163
|
+
long_desc <<-LONGDESC
|
|
164
|
+
Uses AI (Gemini LLM) to generate a production-ready tool class based on
|
|
165
|
+
your natural language description. The AI automatically determines if the
|
|
166
|
+
tool should be a simple tool, HTTP API tool, or async tool.
|
|
167
|
+
|
|
168
|
+
Input sources (in priority order):
|
|
169
|
+
1. --description / -d : Inline description
|
|
170
|
+
2. --prompt-file / -f : Read description from a file
|
|
171
|
+
3. stdin : Pipe description via stdin (auto-enables stdout output)
|
|
172
|
+
|
|
173
|
+
Output destinations:
|
|
174
|
+
- Default: Writes to ./<suggested_name>.rb
|
|
175
|
+
- --output / -o : Custom output file path
|
|
176
|
+
- --stdout : Output to stdout instead of file
|
|
177
|
+
- When reading from stdin: Auto-outputs to stdout
|
|
178
|
+
|
|
179
|
+
Examples:
|
|
180
|
+
legate tool ai_generate -d "A tool that converts temperatures between Celsius and Fahrenheit"
|
|
181
|
+
legate tool ai_generate -d "A tool that checks if a URL is reachable" -o ./tools/url_checker.rb
|
|
182
|
+
echo "A calculator that adds two numbers" | legate tool ai_generate
|
|
183
|
+
echo "A weather API tool" | legate tool ai_generate > weather_tool.rb
|
|
184
|
+
|
|
185
|
+
Requires GOOGLE_API_KEY environment variable to be set.
|
|
186
|
+
LONGDESC
|
|
187
|
+
method_option :description, aliases: '-d', type: :string, desc: 'Description of the tool to generate'
|
|
188
|
+
method_option :prompt_file, aliases: '-f', type: :string, desc: 'Read description from a file'
|
|
189
|
+
method_option :output, aliases: '-o', type: :string, desc: 'Output file path (default: ./<suggested_name>.rb)'
|
|
190
|
+
method_option :stdout, type: :boolean, default: false, desc: 'Output to stdout instead of file'
|
|
191
|
+
method_option :force, type: :boolean, default: false, desc: 'Overwrite existing file without prompting'
|
|
192
|
+
def ai_generate
|
|
193
|
+
require_relative '../generators'
|
|
194
|
+
|
|
195
|
+
description = nil
|
|
196
|
+
from_stdin = false
|
|
197
|
+
|
|
198
|
+
# Priority: --description > --prompt-file > stdin
|
|
199
|
+
if options[:description] && !options[:description].strip.empty?
|
|
200
|
+
description = options[:description].strip
|
|
201
|
+
elsif options[:prompt_file]
|
|
202
|
+
unless File.exist?(options[:prompt_file])
|
|
203
|
+
say "Error: Prompt file '#{options[:prompt_file]}' not found.", :red
|
|
204
|
+
exit(1)
|
|
205
|
+
end
|
|
206
|
+
description = File.read(options[:prompt_file]).strip
|
|
207
|
+
elsif !$stdin.tty?
|
|
208
|
+
# Reading from stdin (piped input)
|
|
209
|
+
description = $stdin.read.strip
|
|
210
|
+
from_stdin = true
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
if description.nil? || description.empty?
|
|
214
|
+
say 'Error: No description provided. Use --description, --prompt-file, or pipe via stdin.', :red
|
|
215
|
+
exit(1)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Determine output mode
|
|
219
|
+
output_to_stdout = options[:stdout] || from_stdin
|
|
220
|
+
|
|
221
|
+
say 'Generating tool code via AI...', :cyan unless output_to_stdout
|
|
222
|
+
|
|
223
|
+
begin
|
|
224
|
+
result = Legate::Generators::ToolGenerator.generate(description: description)
|
|
225
|
+
code = result[:code]
|
|
226
|
+
suggested_name = result[:suggested_name]
|
|
227
|
+
tool_type = result[:tool_type]
|
|
228
|
+
|
|
229
|
+
if output_to_stdout
|
|
230
|
+
puts code
|
|
231
|
+
else
|
|
232
|
+
# Write to file
|
|
233
|
+
file_path = options[:output] || "./#{suggested_name}.rb"
|
|
234
|
+
|
|
235
|
+
if File.exist?(file_path) && !options[:force] && !yes?("File '#{file_path}' already exists. Overwrite? [y/N]", :yellow)
|
|
236
|
+
say 'Generation cancelled.', :yellow
|
|
237
|
+
exit(0)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
File.write(file_path, code)
|
|
241
|
+
say "Tool code generated and saved to '#{file_path}'", :green
|
|
242
|
+
say " Suggested name: #{suggested_name}", :cyan
|
|
243
|
+
say " Tool type: #{tool_type}", :cyan
|
|
244
|
+
end
|
|
245
|
+
rescue Legate::Generators::ToolGenerator::ApiKeyMissingError => e
|
|
246
|
+
say "Error: #{e.message}", :red
|
|
247
|
+
exit(1)
|
|
248
|
+
rescue Legate::Generators::ToolGenerator::ApiError => e
|
|
249
|
+
say "Error: #{e.message}", :red
|
|
250
|
+
exit(1)
|
|
251
|
+
rescue Legate::Generators::ToolGenerator::GenerationError => e
|
|
252
|
+
say "Error: #{e.message}", :red
|
|
253
|
+
exit(1)
|
|
254
|
+
rescue StandardError => e
|
|
255
|
+
say "Unexpected error: #{e.class} - #{e.message}", :red
|
|
256
|
+
exit(1)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack' # Required for Rack::Builder
|
|
4
|
+
require 'rack/handler/puma' # Use Rack::Handler for Rack 2.x compatibility
|
|
5
|
+
require_relative '../web' # Loads the web UI (and core, if not already loaded)
|
|
6
|
+
require_relative 'base_command'
|
|
7
|
+
# Webhook listener required conditionally below
|
|
8
|
+
|
|
9
|
+
module Legate
|
|
10
|
+
module CLI
|
|
11
|
+
# CLI commands for web interface
|
|
12
|
+
class WebCommands < BaseCommand
|
|
13
|
+
# Conventional directories to scan for custom tools and agents
|
|
14
|
+
TOOL_DIRECTORIES = [
|
|
15
|
+
'lib/tools',
|
|
16
|
+
'agents/lib/tools',
|
|
17
|
+
'tools'
|
|
18
|
+
].freeze
|
|
19
|
+
|
|
20
|
+
AGENT_DIRECTORIES = [
|
|
21
|
+
'lib/agents',
|
|
22
|
+
'agents/lib/agents',
|
|
23
|
+
'agents'
|
|
24
|
+
].freeze
|
|
25
|
+
|
|
26
|
+
# Optional initializer file that runs before auto-loading
|
|
27
|
+
INIT_FILES = [
|
|
28
|
+
'legate_init.rb',
|
|
29
|
+
'config/legate_init.rb',
|
|
30
|
+
'agents/legate_init.rb'
|
|
31
|
+
].freeze
|
|
32
|
+
|
|
33
|
+
desc 'start', 'Start the web interface'
|
|
34
|
+
method_option :port, type: :numeric, default: 4567, desc: 'Port to listen on'
|
|
35
|
+
method_option :host, type: :string, default: 'localhost', desc: 'Host to bind to'
|
|
36
|
+
method_option :no_autoload, type: :boolean, default: false, desc: 'Disable auto-loading of custom tools and agents'
|
|
37
|
+
def start
|
|
38
|
+
# Auto-load custom tools and agents unless disabled
|
|
39
|
+
unless options[:no_autoload]
|
|
40
|
+
load_custom_initializer
|
|
41
|
+
load_custom_tools
|
|
42
|
+
load_custom_agents
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Access config early
|
|
46
|
+
webhook_config = Legate.config.webhooks
|
|
47
|
+
listener_enabled = webhook_config.listener_enabled
|
|
48
|
+
listener_base_path = webhook_config.base_path
|
|
49
|
+
|
|
50
|
+
# Build the Rack application stack
|
|
51
|
+
app = Rack::Builder.new do
|
|
52
|
+
# Conditionally mount the Webhook Listener
|
|
53
|
+
if listener_enabled
|
|
54
|
+
Legate.logger.info "Webhook listener enabled, mounting at #{listener_base_path}"
|
|
55
|
+
begin
|
|
56
|
+
require_relative '../web/webhook_listener'
|
|
57
|
+
map listener_base_path do
|
|
58
|
+
run Legate::Web::WebhookListener.new
|
|
59
|
+
end
|
|
60
|
+
rescue LoadError => e
|
|
61
|
+
Legate.logger.error "Failed to load WebhookListener: #{e.message}. Listener will not be mounted."
|
|
62
|
+
rescue StandardError => e
|
|
63
|
+
Legate.logger.error "Error initializing WebhookListener: #{e.message}. Listener will not be mounted."
|
|
64
|
+
end
|
|
65
|
+
else
|
|
66
|
+
Legate.logger.debug 'Webhook listener is disabled.'
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Mount the main Legate Web App at the root
|
|
70
|
+
run Legate::Web::App.new
|
|
71
|
+
end.to_app # Convert builder block to a Rack app
|
|
72
|
+
|
|
73
|
+
# Start the server using Rack::Handler::Puma (Rack 2.x compatible)
|
|
74
|
+
say "Starting Legate web interface on http://#{options[:host]}:#{options[:port]}"
|
|
75
|
+
Rack::Handler::Puma.run(
|
|
76
|
+
app,
|
|
77
|
+
Host: options[:host],
|
|
78
|
+
Port: options[:port],
|
|
79
|
+
Silent: false
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
# Load optional initializer file if present
|
|
86
|
+
def load_custom_initializer
|
|
87
|
+
INIT_FILES.each do |init_file|
|
|
88
|
+
full_path = File.expand_path(init_file, Dir.pwd)
|
|
89
|
+
next unless File.exist?(full_path)
|
|
90
|
+
|
|
91
|
+
Legate.logger.info "Loading custom initializer: #{full_path}"
|
|
92
|
+
begin
|
|
93
|
+
require full_path
|
|
94
|
+
Legate.logger.info "Successfully loaded initializer: #{init_file}"
|
|
95
|
+
break # Only load the first one found
|
|
96
|
+
rescue LoadError, StandardError => e
|
|
97
|
+
Legate.logger.error "Error loading initializer #{init_file}: #{e.class} - #{e.message}"
|
|
98
|
+
Legate.logger.debug e.backtrace.first(5).join("\n") if e.backtrace
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Auto-discover and load custom tools from conventional directories
|
|
104
|
+
def load_custom_tools
|
|
105
|
+
tools_loaded = 0
|
|
106
|
+
base_dir = Dir.pwd
|
|
107
|
+
|
|
108
|
+
TOOL_DIRECTORIES.each do |tool_dir|
|
|
109
|
+
full_dir = File.join(base_dir, tool_dir)
|
|
110
|
+
next unless Dir.exist?(full_dir)
|
|
111
|
+
|
|
112
|
+
# Find all .rb files in the directory (and subdirectories)
|
|
113
|
+
Dir.glob(File.join(full_dir, '**', '*.rb')).sort.each do |tool_file|
|
|
114
|
+
# Skip files that look like tests or specs
|
|
115
|
+
next if tool_file.include?('_spec.rb') || tool_file.include?('_test.rb')
|
|
116
|
+
|
|
117
|
+
begin
|
|
118
|
+
require tool_file
|
|
119
|
+
tools_loaded += 1
|
|
120
|
+
Legate.logger.debug "Loaded custom tool file: #{tool_file}"
|
|
121
|
+
rescue LoadError, StandardError => e
|
|
122
|
+
Legate.logger.warn "Failed to load tool file #{tool_file}: #{e.class} - #{e.message}"
|
|
123
|
+
Legate.logger.debug e.backtrace.first(3).join("\n") if e.backtrace
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
return unless tools_loaded.positive?
|
|
129
|
+
|
|
130
|
+
Legate.logger.info "Auto-loaded #{tools_loaded} custom tool file(s). " \
|
|
131
|
+
"Registered tools: #{Legate::GlobalToolManager.registered_tool_names.inspect}"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Auto-discover and load custom agent definitions from conventional directories
|
|
135
|
+
def load_custom_agents
|
|
136
|
+
agents_loaded = 0
|
|
137
|
+
base_dir = Dir.pwd
|
|
138
|
+
|
|
139
|
+
AGENT_DIRECTORIES.each do |agent_dir|
|
|
140
|
+
full_dir = File.join(base_dir, agent_dir)
|
|
141
|
+
next unless Dir.exist?(full_dir)
|
|
142
|
+
|
|
143
|
+
# Find all .rb files in the directory (and subdirectories)
|
|
144
|
+
Dir.glob(File.join(full_dir, '**', '*.rb')).sort.each do |agent_file|
|
|
145
|
+
# Skip files that look like tests, specs, or tools
|
|
146
|
+
next if agent_file.include?('_spec.rb') || agent_file.include?('_test.rb')
|
|
147
|
+
next if agent_file.include?('/tools/') # Don't load tools from agent directories
|
|
148
|
+
|
|
149
|
+
begin
|
|
150
|
+
require agent_file
|
|
151
|
+
agents_loaded += 1
|
|
152
|
+
Legate.logger.debug "Loaded custom agent file: #{agent_file}"
|
|
153
|
+
rescue LoadError, StandardError => e
|
|
154
|
+
Legate.logger.warn "Failed to load agent file #{agent_file}: #{e.class} - #{e.message}"
|
|
155
|
+
Legate.logger.debug e.backtrace.first(3).join("\n") if e.backtrace
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
return unless agents_loaded.positive?
|
|
161
|
+
|
|
162
|
+
registered_agents = begin
|
|
163
|
+
Legate::GlobalDefinitionRegistry.all.keys
|
|
164
|
+
rescue StandardError
|
|
165
|
+
[]
|
|
166
|
+
end
|
|
167
|
+
Legate.logger.info "Auto-loaded #{agents_loaded} custom agent file(s). " \
|
|
168
|
+
"Registered agents: #{registered_agents.inspect}"
|
|
169
|
+
|
|
170
|
+
# Sync loaded agents to the definition store so they appear in the Web UI
|
|
171
|
+
sync_agents_to_definition_store
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Agents auto-loaded from files are already in GlobalDefinitionRegistry,
|
|
175
|
+
# which serves as the definition store. No sync needed.
|
|
176
|
+
def sync_agents_to_definition_store
|
|
177
|
+
# No-op: GlobalDefinitionRegistry is the sole definition store.
|
|
178
|
+
Legate.logger.debug 'Agents are already in GlobalDefinitionRegistry (in-memory definition store).'
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
data/lib/legate/cli.rb
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# File: lib/legate/cli.rb
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'thor'
|
|
5
|
+
# Require the files that DEFINE the command classes first
|
|
6
|
+
require_relative 'cli/base_command'
|
|
7
|
+
require_relative 'cli/output_helper'
|
|
8
|
+
require_relative 'cli/agent_commands'
|
|
9
|
+
require_relative 'cli/tool_commands'
|
|
10
|
+
require_relative 'cli/web_commands'
|
|
11
|
+
require_relative 'cli/session_commands'
|
|
12
|
+
require_relative 'cli/deployment_commands'
|
|
13
|
+
require_relative 'cli/skaffold_commands'
|
|
14
|
+
require_relative 'cli/auth_commands'
|
|
15
|
+
|
|
16
|
+
module Legate
|
|
17
|
+
module CLI
|
|
18
|
+
# Main CLI class that provides the entry point for all Legate commands
|
|
19
|
+
class Main < BaseCommand
|
|
20
|
+
desc 'version', 'Display the Legate version'
|
|
21
|
+
def version
|
|
22
|
+
puts "Legate version #{Legate::VERSION}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Register subcommands
|
|
26
|
+
register(AgentCommands, 'agent', 'agent <command>',
|
|
27
|
+
'Manage Legate agents and execution (list, save, delete, generate, execute, start)')
|
|
28
|
+
register(ToolCommands, 'tool', 'tool <command>', 'Manage Legate tools')
|
|
29
|
+
register(WebCommands, 'web', 'web <command>', 'Manage Legate web interface')
|
|
30
|
+
register(SessionCommands, 'session', 'session <command>', 'Manage Legate sessions')
|
|
31
|
+
register(DeploymentCommands, 'deployment', 'deployment <command>',
|
|
32
|
+
'Generate deployment assets for cloud platforms')
|
|
33
|
+
register(SkaffoldCommands, 'skaffold', 'skaffold [PROJECT_NAME]',
|
|
34
|
+
'Generate a new Legate project structure (alias: new, init)')
|
|
35
|
+
register(AuthCommands, 'auth', 'auth <command>',
|
|
36
|
+
'Manage authentication schemes, credentials, and URL mappings')
|
|
37
|
+
end
|
|
38
|
+
# --- End Main class definition ---
|
|
39
|
+
end # End CLI module
|
|
40
|
+
end # End Legate module
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legate/session_service/base'
|
|
4
|
+
|
|
5
|
+
module Legate
|
|
6
|
+
class Configuration
|
|
7
|
+
# Configuration settings for the inbound webhook listener and processing.
|
|
8
|
+
class Webhooks
|
|
9
|
+
# @return [Boolean] Whether the webhook listener is enabled. Defaults to false.
|
|
10
|
+
attr_accessor :listener_enabled
|
|
11
|
+
|
|
12
|
+
# @return [String] The IP address the listener should bind to. Defaults to '127.0.0.1'.
|
|
13
|
+
attr_accessor :listen_address
|
|
14
|
+
|
|
15
|
+
# @return [Integer] The port the listener should bind to. Defaults to 9292.
|
|
16
|
+
attr_accessor :listen_port
|
|
17
|
+
|
|
18
|
+
# @return [String] The base path for all webhook routes. Defaults to '/webhooks'.
|
|
19
|
+
attr_accessor :base_path
|
|
20
|
+
|
|
21
|
+
# @return [Boolean] Whether the dynamic agent handler route is enabled. Defaults to false.
|
|
22
|
+
attr_accessor :enable_dynamic_agent_handler
|
|
23
|
+
|
|
24
|
+
# @return [String] The path pattern for the dynamic agent handler. Defaults to '/agents/:agent_name/trigger'.
|
|
25
|
+
attr_accessor :dynamic_agent_route_pattern
|
|
26
|
+
|
|
27
|
+
# @return [Symbol, Proc, nil] A global validator to apply if an agent doesn't specify one.
|
|
28
|
+
attr_accessor :global_validator
|
|
29
|
+
|
|
30
|
+
# @return [String, nil] The secret key used by the global validator (e.g., for HMAC).
|
|
31
|
+
attr_accessor :global_secret
|
|
32
|
+
|
|
33
|
+
# @return [Legate::SessionService::Base, nil] The default session service instance to use in the webhook worker.
|
|
34
|
+
attr_accessor :default_session_service
|
|
35
|
+
|
|
36
|
+
def initialize
|
|
37
|
+
@listener_enabled = true # Enable listener by default for easier testing/use
|
|
38
|
+
@listen_address = '127.0.0.1' # Default to loopback for security
|
|
39
|
+
@listen_port = 9292
|
|
40
|
+
@base_path = '/webhooks'
|
|
41
|
+
@enable_dynamic_agent_handler = true # Enable dynamic handler by default for easier testing
|
|
42
|
+
@dynamic_agent_route_pattern = '/agents/:agent_name/trigger'
|
|
43
|
+
@global_validator = nil
|
|
44
|
+
@global_secret = nil
|
|
45
|
+
@default_session_service = nil
|
|
46
|
+
@validators = {}
|
|
47
|
+
@static_routes = {} # Store static routes: path -> RouteConfig
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Registers a named validator proc/lambda.
|
|
51
|
+
#
|
|
52
|
+
# @param name [Symbol] The name to register the validator under.
|
|
53
|
+
# @yield [request, secret] The block that performs validation.
|
|
54
|
+
# @yieldparam request The Rack request object.
|
|
55
|
+
# @yieldparam secret [String, nil] The secret associated with the route/agent.
|
|
56
|
+
# @yieldreturn [Boolean] True if the request is valid, false otherwise.
|
|
57
|
+
# @raise [ArgumentError] If the name is already registered or no block is given.
|
|
58
|
+
def register_validator(name, &block)
|
|
59
|
+
raise ArgumentError, "Validator name :#{name} is already registered." if @validators.key?(name)
|
|
60
|
+
raise ArgumentError, 'Validator requires a block.' unless block_given?
|
|
61
|
+
|
|
62
|
+
@validators[name] = block
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Finds a registered validator by name.
|
|
66
|
+
#
|
|
67
|
+
# @param name [Symbol] The name of the validator.
|
|
68
|
+
# @return [Proc, nil] The validator proc or nil if not found.
|
|
69
|
+
def find_validator(name)
|
|
70
|
+
@validators[name]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Registers a static webhook route.
|
|
74
|
+
# Primarily intended for simple, non-agent-related endpoints like health checks.
|
|
75
|
+
# Agent-related webhooks should typically use the dynamic agent handler.
|
|
76
|
+
#
|
|
77
|
+
# @param path [String] The HTTP method and path pattern (e.g., "GET /system/health", "POST /simple").
|
|
78
|
+
# @yield [route_config] The block to configure the route.
|
|
79
|
+
# @yieldparam route_config [RouteConfig] The configuration object for this route.
|
|
80
|
+
# @raise [ArgumentError] If the path is already registered or no block is given.
|
|
81
|
+
def register_route(path)
|
|
82
|
+
raise ArgumentError, "Route path \"#{path}\" is already registered." if @static_routes.key?(path)
|
|
83
|
+
raise ArgumentError, 'Route registration requires a block.' unless block_given?
|
|
84
|
+
|
|
85
|
+
config = RouteConfig.new
|
|
86
|
+
yield config
|
|
87
|
+
@static_routes[path] = config
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Retrieves the configurations for all registered static routes.
|
|
91
|
+
# @return [Hash{String => RouteConfig}] A hash mapping path patterns to their configurations.
|
|
92
|
+
def static_routes
|
|
93
|
+
@static_routes.dup # Return a copy to prevent external modification
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Internal class to hold configuration for a single static route.
|
|
97
|
+
class RouteConfig
|
|
98
|
+
# @return [Proc, nil] The handler proc for the route. Should return a Rack response array.
|
|
99
|
+
attr_accessor :handler
|
|
100
|
+
# @return [Symbol, Proc, nil] A specific validator for this static route.
|
|
101
|
+
attr_accessor :validator
|
|
102
|
+
# @return [String, nil] The secret key for this static route's validator.
|
|
103
|
+
attr_accessor :secret
|
|
104
|
+
|
|
105
|
+
def initialize
|
|
106
|
+
@handler = nil
|
|
107
|
+
@validator = nil
|
|
108
|
+
@secret = nil
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legate/agent'
|
|
4
|
+
require_relative 'session_service/in_memory'
|
|
5
|
+
require 'legate/configuration/webhooks'
|
|
6
|
+
|
|
7
|
+
module Legate
|
|
8
|
+
# Central configuration object for the Legate framework.
|
|
9
|
+
# Access via `Legate.config` after calling `Legate.configure`.
|
|
10
|
+
class Configuration
|
|
11
|
+
# @return [Legate::SessionService::Base] The service used to manage agent session state.
|
|
12
|
+
attr_accessor :session_service
|
|
13
|
+
|
|
14
|
+
# @return [Symbol] Default model name to use if not specified in agent definition.
|
|
15
|
+
attr_accessor :default_model_name
|
|
16
|
+
|
|
17
|
+
# @return [Float] Default temperature to use if not specified in agent definition.
|
|
18
|
+
attr_accessor :default_temperature
|
|
19
|
+
|
|
20
|
+
# @return [Legate::Configuration::Webhooks] Webhook configuration.
|
|
21
|
+
attr_reader :webhooks
|
|
22
|
+
|
|
23
|
+
# @return [Boolean] Whether the web UI may load AI-generated custom tools into
|
|
24
|
+
# the running process (this executes LLM-generated Ruby — see
|
|
25
|
+
# Legate::Generators::RuntimeToolLoader). Defaults to ON outside production
|
|
26
|
+
# and OFF in production. Override explicitly via
|
|
27
|
+
# `Legate.configure { |c| c.allow_runtime_tool_load = true/false }`.
|
|
28
|
+
attr_accessor :allow_runtime_tool_load
|
|
29
|
+
|
|
30
|
+
def initialize
|
|
31
|
+
# Always use in-memory session service (Redis dependency removed)
|
|
32
|
+
@session_service = Legate::SessionService::InMemory.new
|
|
33
|
+
@default_model_name = 'gemini-3.5-flash'
|
|
34
|
+
@default_temperature = 0.7
|
|
35
|
+
@webhooks = Legate::Configuration::Webhooks.new
|
|
36
|
+
@allow_runtime_tool_load = ENV['RACK_ENV'] != 'production'
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# File: lib/legate/definition_store.rb
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Legate
|
|
5
|
+
# Module responsible for persisting and retrieving agent definitions.
|
|
6
|
+
# Implementations should provide methods for CRUD operations on definitions.
|
|
7
|
+
module DefinitionStore
|
|
8
|
+
# NOTE: Base error classes (Error, ConfigurationError, StoreError)
|
|
9
|
+
# are defined in lib/legate/errors.rb and inherit from Legate::Error.
|
|
10
|
+
|
|
11
|
+
# Error raised when a definition is not found
|
|
12
|
+
# Inherits from Legate::DefinitionStore::Error defined in errors.rb
|
|
13
|
+
class NotFoundError < Error; end # Use the base Error defined in errors.rb (Legate::DefinitionStore::Error)
|
|
14
|
+
|
|
15
|
+
# Removing redundant/conflicting definitions:
|
|
16
|
+
# class StoreError < StandardError; end
|
|
17
|
+
# class ConfigurationError < StoreError; end
|
|
18
|
+
|
|
19
|
+
# Potential future: Define abstract methods or rely on duck typing for implementations.
|
|
20
|
+
|
|
21
|
+
# Definitions are stored in-memory via GlobalDefinitionRegistry.
|
|
22
|
+
end
|
|
23
|
+
end
|