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,108 @@
|
|
|
1
|
+
# File: lib/legate/cli/output_helper.rb
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
module Legate
|
|
7
|
+
module CLI
|
|
8
|
+
# Helper module for CLI output control.
|
|
9
|
+
# Provides methods to conditionally output status messages and format results
|
|
10
|
+
# based on --quiet and --json flags.
|
|
11
|
+
module OutputHelper
|
|
12
|
+
# Write status/progress message (suppressed in quiet or json mode)
|
|
13
|
+
# @param message [String] The status message to display
|
|
14
|
+
# @param color [Symbol, nil] Optional color for Thor's say method
|
|
15
|
+
def status_message(message, color = nil)
|
|
16
|
+
return if quiet_mode?
|
|
17
|
+
|
|
18
|
+
say message, color
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Output final result (JSON format in --json mode, otherwise uses format_method or default)
|
|
22
|
+
# @param data [Object] The result data to output
|
|
23
|
+
# @param metadata [Hash] Additional metadata to include (e.g., session_id)
|
|
24
|
+
# @param format_method [Symbol] Method name to call for human-friendly formatting
|
|
25
|
+
def output_result(data, metadata: {}, format_method: nil)
|
|
26
|
+
if json_mode?
|
|
27
|
+
output_json(data, metadata)
|
|
28
|
+
elsif format_method && respond_to?(format_method, true)
|
|
29
|
+
send(format_method, data)
|
|
30
|
+
else
|
|
31
|
+
say data.inspect
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Output error (JSON format in --json mode, otherwise text to stderr)
|
|
36
|
+
# @param error [Exception, String] The error to output
|
|
37
|
+
# @param metadata [Hash] Additional metadata to include
|
|
38
|
+
def output_error(error, metadata: {})
|
|
39
|
+
if json_mode?
|
|
40
|
+
error_data = {
|
|
41
|
+
status: 'error',
|
|
42
|
+
error_class: error.is_a?(Exception) ? error.class.name : 'Error',
|
|
43
|
+
error_message: error.is_a?(Exception) ? error.message : error.to_s
|
|
44
|
+
}
|
|
45
|
+
error_data.merge!(metadata) unless metadata.empty?
|
|
46
|
+
puts JSON.generate(error_data)
|
|
47
|
+
else
|
|
48
|
+
message = error.is_a?(Exception) ? "#{error.class} - #{error.message}" : error.to_s
|
|
49
|
+
say message, :red
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
# Check if quiet mode is enabled (--quiet or --json)
|
|
56
|
+
# Thor options may use string or symbol keys depending on how they're accessed
|
|
57
|
+
def quiet_mode?
|
|
58
|
+
options['quiet'] || options[:quiet] || options['json'] || options[:json]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Check if JSON output mode is enabled
|
|
62
|
+
def json_mode?
|
|
63
|
+
options['json'] || options[:json]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Output data as JSON
|
|
67
|
+
def output_json(data, metadata)
|
|
68
|
+
result = normalize_for_json(data)
|
|
69
|
+
output = metadata.empty? ? result : metadata.merge(result: result)
|
|
70
|
+
puts JSON.generate(output)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Normalize various data types to JSON-serializable format
|
|
74
|
+
def normalize_for_json(data)
|
|
75
|
+
case data
|
|
76
|
+
when Legate::Event
|
|
77
|
+
normalize_event(data)
|
|
78
|
+
when Hash
|
|
79
|
+
normalize_hash(data)
|
|
80
|
+
when Array
|
|
81
|
+
data.map { |item| normalize_for_json(item) }
|
|
82
|
+
else
|
|
83
|
+
data
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def normalize_event(event)
|
|
88
|
+
{
|
|
89
|
+
role: event.role.to_s,
|
|
90
|
+
content: normalize_for_json(event.content),
|
|
91
|
+
tool_name: event.tool_name&.to_s,
|
|
92
|
+
timestamp: event.timestamp
|
|
93
|
+
}.compact
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def normalize_hash(hash)
|
|
97
|
+
hash.transform_keys(&:to_s).transform_values do |v|
|
|
98
|
+
case v
|
|
99
|
+
when Symbol then v.to_s
|
|
100
|
+
when Hash then normalize_hash(v)
|
|
101
|
+
when Array then v.map { |item| normalize_for_json(item) }
|
|
102
|
+
else v
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# File: lib/legate/cli/session_commands.rb
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'thor'
|
|
5
|
+
require_relative 'base_command'
|
|
6
|
+
require 'json'
|
|
7
|
+
require_relative '../session'
|
|
8
|
+
require_relative '../session_service/in_memory'
|
|
9
|
+
|
|
10
|
+
module Legate
|
|
11
|
+
module CLI
|
|
12
|
+
# CLI commands for session management
|
|
13
|
+
class SessionCommands < BaseCommand
|
|
14
|
+
desc 'list [APP_NAME] [USER_ID]', 'List all sessions or filter by app_name and/or user_id'
|
|
15
|
+
method_option :app_name, type: :string, desc: 'Filter sessions by application name'
|
|
16
|
+
method_option :user_id, type: :string, desc: 'Filter sessions by user ID'
|
|
17
|
+
def list(*args)
|
|
18
|
+
# Parse positional arguments if provided
|
|
19
|
+
app_name = options[:app_name] || args[0]
|
|
20
|
+
user_id = options[:user_id] || args[1]
|
|
21
|
+
|
|
22
|
+
session_service = Legate::SessionService::InMemory.new
|
|
23
|
+
sessions = session_service.list_sessions(app_name: app_name, user_id: user_id)
|
|
24
|
+
|
|
25
|
+
if sessions.empty?
|
|
26
|
+
say "No sessions found#{app_name ? " for app '#{app_name}'" : ''}#{user_id ? " and user '#{user_id}'" : ''}.",
|
|
27
|
+
:yellow
|
|
28
|
+
return
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
say "Found #{sessions.length} session(s):", :bold
|
|
32
|
+
sessions.each do |session|
|
|
33
|
+
created_at = session.created_at.strftime('%Y-%m-%d %H:%M:%S')
|
|
34
|
+
say " ID: #{session.id}", :cyan
|
|
35
|
+
say " App: #{session.app_name}"
|
|
36
|
+
say " User: #{session.user_id}"
|
|
37
|
+
say " Created: #{created_at}"
|
|
38
|
+
say " Events: #{session.events.length}"
|
|
39
|
+
say ''
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
desc 'show SESSION_ID', 'Show details of a specific session including events'
|
|
44
|
+
def show(session_id)
|
|
45
|
+
session_service = Legate::SessionService::InMemory.new
|
|
46
|
+
session = session_service.get_session(session_id: session_id)
|
|
47
|
+
|
|
48
|
+
unless session
|
|
49
|
+
say "Session '#{session_id}' not found.", :red
|
|
50
|
+
return
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
created_at = session.created_at.strftime('%Y-%m-%d %H:%M:%S')
|
|
54
|
+
say 'Session Details:', :bold
|
|
55
|
+
say " ID: #{session.id}", :cyan
|
|
56
|
+
say " App: #{session.app_name}"
|
|
57
|
+
say " User: #{session.user_id}"
|
|
58
|
+
say " Created: #{created_at}"
|
|
59
|
+
say " Events: #{session.events.length}"
|
|
60
|
+
|
|
61
|
+
if session.events.empty?
|
|
62
|
+
say "\nNo events in this session.", :yellow
|
|
63
|
+
return
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
say "\nEvents:", :bold
|
|
67
|
+
session.events.each_with_index do |event, index|
|
|
68
|
+
say " #{index + 1}. [#{event.role}] #{event.content.inspect}"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
desc 'delete SESSION_ID', 'Delete a specific session'
|
|
73
|
+
def delete(session_id)
|
|
74
|
+
session_service = Legate::SessionService::InMemory.new
|
|
75
|
+
|
|
76
|
+
# Check if session exists first
|
|
77
|
+
session = session_service.get_session(session_id: session_id)
|
|
78
|
+
unless session
|
|
79
|
+
say "Session '#{session_id}' not found.", :red
|
|
80
|
+
return
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Confirm deletion
|
|
84
|
+
if yes?("Are you sure you want to delete session '#{session_id}'? (y/n)")
|
|
85
|
+
if session_service.delete_session(session_id: session_id)
|
|
86
|
+
say "Session '#{session_id}' deleted successfully.", :green
|
|
87
|
+
else
|
|
88
|
+
say "Failed to delete session '#{session_id}'.", :red
|
|
89
|
+
end
|
|
90
|
+
else
|
|
91
|
+
say 'Deletion cancelled.', :yellow
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
desc 'execute AGENT_NAME TASK --session-id=SESSION_ID',
|
|
96
|
+
'Execute a task using an agent with a specific session'
|
|
97
|
+
method_option :session_id, type: :string, desc: 'ID of an existing session to use'
|
|
98
|
+
method_option :user_id, type: :string, default: 'cli_user', desc: 'User ID for the session'
|
|
99
|
+
def execute(agent_name, task)
|
|
100
|
+
# First, check if the agent exists in the GlobalDefinitionRegistry
|
|
101
|
+
name_sym = agent_name.to_sym
|
|
102
|
+
agent_definition = Legate::GlobalDefinitionRegistry.find(name_sym)
|
|
103
|
+
|
|
104
|
+
unless agent_definition
|
|
105
|
+
say "Error: Agent definition '#{agent_name}' not found.", :red
|
|
106
|
+
exit(1)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Use in-memory session service
|
|
110
|
+
session_service = Legate::SessionService::InMemory.new
|
|
111
|
+
session_id = options[:session_id]
|
|
112
|
+
legate_session = nil
|
|
113
|
+
|
|
114
|
+
if session_id
|
|
115
|
+
legate_session = session_service.get_session(session_id: session_id)
|
|
116
|
+
if legate_session
|
|
117
|
+
say "Using existing session: #{session_id}", :cyan
|
|
118
|
+
else
|
|
119
|
+
say "Warning: Session ID '#{session_id}' provided but not found. Starting a new session.", :yellow
|
|
120
|
+
session_id = nil # Force creation below
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
unless legate_session
|
|
125
|
+
# Create a new session
|
|
126
|
+
legate_session = session_service.create_session(app_name: agent_name, user_id: options[:user_id])
|
|
127
|
+
session_id = legate_session.id
|
|
128
|
+
say "Started new session: #{session_id}", :cyan
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Now execute the task using the agent_commands implementation
|
|
132
|
+
agent_commands = Legate::CLI::AgentCommands.new
|
|
133
|
+
agent_commands.invoke(:execute, [agent_name, task],
|
|
134
|
+
{ session_id: session_id, session_service: session_service })
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# File: lib/legate/cli/skaffold_commands.rb
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'thor'
|
|
5
|
+
require_relative 'base_command'
|
|
6
|
+
require 'fileutils'
|
|
7
|
+
|
|
8
|
+
module Legate
|
|
9
|
+
module CLI
|
|
10
|
+
class SkaffoldCommands < BaseCommand
|
|
11
|
+
default_task :generate
|
|
12
|
+
|
|
13
|
+
desc 'generate [PROJECT_NAME]', 'Generate a new Legate project structure'
|
|
14
|
+
method_option :dir, type: :string, desc: 'Target directory (defaults to current or project_name)'
|
|
15
|
+
|
|
16
|
+
def generate(project_name = nil)
|
|
17
|
+
target_dir = options[:dir] || project_name || '.'
|
|
18
|
+
target_dir = File.expand_path(target_dir)
|
|
19
|
+
|
|
20
|
+
say "Skaffolding new Legate project in '#{target_dir}'...", :green
|
|
21
|
+
|
|
22
|
+
unless Dir.exist?(target_dir)
|
|
23
|
+
FileUtils.mkdir_p(target_dir)
|
|
24
|
+
say "Created directory: #{target_dir}", :cyan
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# 1. Gemfile
|
|
28
|
+
create_file(File.join(target_dir, 'Gemfile'), <<~GEMFILE)
|
|
29
|
+
source 'https://rubygems.org'
|
|
30
|
+
|
|
31
|
+
gem 'legate'
|
|
32
|
+
gem 'dotenv' # For loading .env files
|
|
33
|
+
gem 'puma' # App server for the Web UI
|
|
34
|
+
|
|
35
|
+
group :test do
|
|
36
|
+
gem 'rspec'
|
|
37
|
+
end
|
|
38
|
+
GEMFILE
|
|
39
|
+
|
|
40
|
+
# 2. config.ru
|
|
41
|
+
create_file(File.join(target_dir, 'config.ru'), <<~CONFIGRU)
|
|
42
|
+
# frozen_string_literal: true
|
|
43
|
+
|
|
44
|
+
require 'rubygems'
|
|
45
|
+
require 'bundler/setup'
|
|
46
|
+
|
|
47
|
+
# Load environment variables early
|
|
48
|
+
require 'dotenv/load' if File.exist?('.env')
|
|
49
|
+
|
|
50
|
+
require 'legate'
|
|
51
|
+
|
|
52
|
+
# Configure Legate
|
|
53
|
+
Legate.configure do |config|
|
|
54
|
+
# Set your global configuration here
|
|
55
|
+
# config.default_model_name = 'gemini-3.5-flash'
|
|
56
|
+
#{' '}
|
|
57
|
+
# config.session_service = Legate::SessionService::InMemory.new
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Helper to recursively require files in specific directories
|
|
61
|
+
def recursive_require(base_dir, sub_dirs)
|
|
62
|
+
sub_dirs.each do |dir|
|
|
63
|
+
full_path = File.join(base_dir, dir)
|
|
64
|
+
next unless Dir.exist?(full_path)
|
|
65
|
+
|
|
66
|
+
Dir.glob(File.join(full_path, '**', '*.rb')).sort.each do |file|
|
|
67
|
+
# Skip tests/specs and tools inside agent directories if loading agents
|
|
68
|
+
next if file.include?('_spec.rb') || file.include?('_test.rb')
|
|
69
|
+
next if dir.include?('agents') && file.include?('/tools/')
|
|
70
|
+
|
|
71
|
+
begin
|
|
72
|
+
require file
|
|
73
|
+
rescue LoadError => e
|
|
74
|
+
puts "WARN: Failed to load \#{file}: \#{e.message}"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Load Agents
|
|
81
|
+
recursive_require(__dir__, ['lib/agents', 'agents/lib/agents', 'agents'])
|
|
82
|
+
|
|
83
|
+
# Load Tools
|
|
84
|
+
recursive_require(__dir__, ['lib/tools', 'agents/lib/tools', 'tools'])
|
|
85
|
+
|
|
86
|
+
# Check for Legate configuration for webhooks
|
|
87
|
+
if Legate.config.respond_to?(:webhooks) && Legate.config.webhooks.listener_enabled
|
|
88
|
+
require 'legate/web/webhook_listener'
|
|
89
|
+
# Mount the webhook listener if enabled
|
|
90
|
+
map Legate.config.webhooks.base_path do
|
|
91
|
+
run Legate::Web::WebhookListener.new
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Run the Legate Web UI
|
|
96
|
+
require 'legate/web/app'
|
|
97
|
+
run Legate::Web::App.new
|
|
98
|
+
CONFIGRU
|
|
99
|
+
|
|
100
|
+
# 3. Agents Directory & Sample Agent
|
|
101
|
+
agents_dir = File.join(target_dir, 'agents')
|
|
102
|
+
FileUtils.mkdir_p(agents_dir)
|
|
103
|
+
create_file(File.join(agents_dir, 'hello_world_agent.rb'), <<~RUBY)
|
|
104
|
+
require 'legate'
|
|
105
|
+
|
|
106
|
+
Legate::Agent.define do |a|
|
|
107
|
+
a.name :hello_world
|
|
108
|
+
a.description "A friendly agent that helps you verify your setup."
|
|
109
|
+
a.instruction "You are a helpful assistant. When asked to say hello, you should reply enthusiastically."
|
|
110
|
+
#{' '}
|
|
111
|
+
# Use built-in tools
|
|
112
|
+
a.use_tool :echo#{' '}
|
|
113
|
+
a.use_tool :sample_tool
|
|
114
|
+
#{' '}
|
|
115
|
+
# a.model_name 'gemini-1.5-pro'
|
|
116
|
+
end
|
|
117
|
+
RUBY
|
|
118
|
+
|
|
119
|
+
# A real, useful starter agent built on the SSRF-safe HTTP tools.
|
|
120
|
+
create_file(File.join(agents_dir, 'research_assistant_agent.rb'), <<~RUBY)
|
|
121
|
+
require 'legate'
|
|
122
|
+
|
|
123
|
+
# A research assistant that can look things up on the web and reason about
|
|
124
|
+
# what it finds. It uses Legate's built-in, SSRF-safe HTTP tools — no extra
|
|
125
|
+
# setup required beyond a GOOGLE_API_KEY for the LLM.
|
|
126
|
+
Legate::Agent.define do |a|
|
|
127
|
+
a.name :research_assistant
|
|
128
|
+
a.description "Researches a question by fetching and reading web pages, then summarizes the findings."
|
|
129
|
+
a.instruction <<~INSTRUCTION
|
|
130
|
+
You are a thorough research assistant.
|
|
131
|
+
|
|
132
|
+
When given a question or topic:
|
|
133
|
+
1. Use read_webpage to fetch and read relevant pages the user provides
|
|
134
|
+
or that you can construct URLs for (e.g. documentation or APIs).
|
|
135
|
+
2. Use http_request when you need a raw API response (JSON, status checks).
|
|
136
|
+
3. Use current_time when the answer depends on today's date.
|
|
137
|
+
|
|
138
|
+
Always cite the URLs you read, distinguish facts from inference, and say
|
|
139
|
+
clearly when a source could not be reached or did not answer the question.
|
|
140
|
+
INSTRUCTION
|
|
141
|
+
|
|
142
|
+
a.use_tool :read_webpage
|
|
143
|
+
a.use_tool :http_request
|
|
144
|
+
a.use_tool :current_time
|
|
145
|
+
|
|
146
|
+
# a.model_name 'gemini-1.5-pro'
|
|
147
|
+
end
|
|
148
|
+
RUBY
|
|
149
|
+
|
|
150
|
+
# 4. Tools Directory
|
|
151
|
+
tools_dir = File.join(target_dir, 'tools')
|
|
152
|
+
FileUtils.mkdir_p(tools_dir)
|
|
153
|
+
create_file(File.join(tools_dir, '.keep'), '')
|
|
154
|
+
create_file(File.join(tools_dir, 'sample_tool.rb'), <<~RUBY)
|
|
155
|
+
require 'legate/tool'
|
|
156
|
+
|
|
157
|
+
class SampleTool < Legate::Tool
|
|
158
|
+
tool_description "Greets a user by name."
|
|
159
|
+
#{' '}
|
|
160
|
+
parameter :name,#{' '}
|
|
161
|
+
type: :string,#{' '}
|
|
162
|
+
description: "The name of the user to greet",#{' '}
|
|
163
|
+
required: true
|
|
164
|
+
|
|
165
|
+
private
|
|
166
|
+
|
|
167
|
+
def perform_execution(params, _context)
|
|
168
|
+
name = params[:name] || params['name']
|
|
169
|
+
{ status: :success, result: "Hello, \#{name}! This is a custom tool." }
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
Legate::GlobalToolManager.register_tool(SampleTool)
|
|
174
|
+
RUBY
|
|
175
|
+
|
|
176
|
+
# 5. .env.example
|
|
177
|
+
create_file(File.join(target_dir, '.env.example'), <<~ENV)
|
|
178
|
+
# Copy this to .env and set your values
|
|
179
|
+
GOOGLE_API_KEY=your_api_key_here
|
|
180
|
+
LEGATE_LOG_LEVEL=INFO
|
|
181
|
+
ENV
|
|
182
|
+
|
|
183
|
+
# 6. bin/console (Optional helper)
|
|
184
|
+
bin_dir = File.join(target_dir, 'bin')
|
|
185
|
+
FileUtils.mkdir_p(bin_dir)
|
|
186
|
+
console_path = File.join(bin_dir, 'console')
|
|
187
|
+
create_file(console_path, <<~RUBY)
|
|
188
|
+
#!/usr/bin/env ruby
|
|
189
|
+
require 'bundler/setup'
|
|
190
|
+
require 'irb'
|
|
191
|
+
require 'dotenv/load'
|
|
192
|
+
require 'legate'
|
|
193
|
+
|
|
194
|
+
# Load agents/tools
|
|
195
|
+
Dir[File.join(__dir__, '..', 'agents', '*.rb')].each { |file| require file }
|
|
196
|
+
Dir[File.join(__dir__, '..', 'tools', '*.rb')].each { |file| require file }
|
|
197
|
+
|
|
198
|
+
puts "Legate Console loaded."
|
|
199
|
+
IRB.start
|
|
200
|
+
RUBY
|
|
201
|
+
FileUtils.chmod(0o755, console_path)
|
|
202
|
+
|
|
203
|
+
say "\nSkaffolding complete!", :green
|
|
204
|
+
say 'Next steps:', :yellow
|
|
205
|
+
say " 1. cd #{target_dir}", :cyan
|
|
206
|
+
say ' 2. cp .env.example .env (and configure it)', :cyan
|
|
207
|
+
say ' 3. bundle install', :cyan
|
|
208
|
+
say ' 4. bundle exec rackup (to start the Web UI)', :cyan
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
private
|
|
212
|
+
|
|
213
|
+
def create_file(path, content)
|
|
214
|
+
if File.exist?(path)
|
|
215
|
+
say "Skipping existing file: #{path}", :yellow
|
|
216
|
+
else
|
|
217
|
+
File.write(path, content)
|
|
218
|
+
say "Created file: #{path}", :green
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|