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.
Files changed (317) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +345 -0
  4. data/bin/legate +13 -0
  5. data/examples/00_quickstart.rb +51 -0
  6. data/examples/01_simple_agent.rb +105 -0
  7. data/examples/02_multi_tool_agent.rb +140 -0
  8. data/examples/03_custom_tool.rb +93 -0
  9. data/examples/04_agent_instructions.rb +84 -0
  10. data/examples/05_state_and_sessions.rb +91 -0
  11. data/examples/06_callbacks.rb +186 -0
  12. data/examples/07_async_jobs.rb +112 -0
  13. data/examples/08_loop_agent.rb +197 -0
  14. data/examples/09_sequential_workflow.rb +40 -0
  15. data/examples/10_parallel_workflow.rb +34 -0
  16. data/examples/11_agent_delegation.rb +24 -0
  17. data/examples/12_http_client_tool.rb +156 -0
  18. data/examples/13_authentication.rb +220 -0
  19. data/examples/14_mcp_client.rb +154 -0
  20. data/examples/15_mcp_server.rb +79 -0
  21. data/examples/16_webhooks.rb +91 -0
  22. data/examples/README_sequential_agents.md +164 -0
  23. data/examples/advanced/auth/cookie_auth_tool.rb +146 -0
  24. data/examples/advanced/auth/custom_auth_flows_example.rb +626 -0
  25. data/examples/advanced/auth/excon_middleware.rb +317 -0
  26. data/examples/advanced/auth/excon_middleware_auth.rb +399 -0
  27. data/examples/advanced/auth/fiber_auth_example.rb +281 -0
  28. data/examples/advanced/auth/fiber_oidc_example.rb +403 -0
  29. data/examples/advanced/auth/httpbin_bearer_tool.rb +159 -0
  30. data/examples/advanced/auth/oauth2_auth.rb +419 -0
  31. data/examples/advanced/auth/oidc_auth.rb +514 -0
  32. data/examples/advanced/auth/openweather_api.rb +251 -0
  33. data/examples/advanced/auth/openweather_tool.rb +153 -0
  34. data/examples/advanced/auth/query_param_middleware_test.rb +138 -0
  35. data/examples/advanced/auth/service_account.rb +135 -0
  36. data/examples/advanced/auth/test_with_httpbin.rb +202 -0
  37. data/examples/advanced/auth/token_lifecycle_example.rb +428 -0
  38. data/examples/advanced/callback_monitoring.rb +679 -0
  39. data/examples/advanced/mas/fixed_delegation_example.rb +191 -0
  40. data/examples/advanced/mas/loop_workflow.rb +28 -0
  41. data/examples/advanced/mas/mock_planner.rb +77 -0
  42. data/examples/advanced/mas/proper_delegation_example.rb +276 -0
  43. data/examples/advanced/mcp/legate_mcp_server_resource_example.rb +182 -0
  44. data/examples/advanced/mcp/mcp_resource_server_example.rb +309 -0
  45. data/examples/advanced/mcp/mcp_server_async.rb +76 -0
  46. data/examples/advanced/mcp/mcp_server_async_tools.rb +122 -0
  47. data/examples/advanced/mcp/mcp_server_legate_agent.rb +95 -0
  48. data/examples/advanced/mcp/mcp_server_rack.rb +89 -0
  49. data/examples/advanced/random_calculator.rb +104 -0
  50. data/examples/advanced/sleep_agent.rb +153 -0
  51. data/examples/advanced/webhooks/webhook_e2e_runner.rb +110 -0
  52. data/examples/advanced/webhooks/webhook_receiver_agent.rb +58 -0
  53. data/examples/advanced/workflows/task_refinement_loop_agent.rb +278 -0
  54. data/examples/advanced/workflows/travel_planner_auto_sequential.rb +444 -0
  55. data/examples/advanced/workflows/travel_planner_parallel.rb +656 -0
  56. data/examples/advanced/workflows/travel_planner_sequential.rb +512 -0
  57. data/examples/tools/oauth2_example.rb +136 -0
  58. data/examples/tools/sleepy_tool.rb +42 -0
  59. data/lib/legate/activity_log.rb +71 -0
  60. data/lib/legate/agent.rb +959 -0
  61. data/lib/legate/agent_code_generator.rb +185 -0
  62. data/lib/legate/agent_definition.rb +812 -0
  63. data/lib/legate/agentic/decision.rb +49 -0
  64. data/lib/legate/agentic/loop.rb +134 -0
  65. data/lib/legate/agentic.rb +5 -0
  66. data/lib/legate/agents/loop_agent.rb +248 -0
  67. data/lib/legate/agents/parallel_agent.rb +163 -0
  68. data/lib/legate/agents/sequential_agent.rb +190 -0
  69. data/lib/legate/agents.rb +14 -0
  70. data/lib/legate/auth/config.rb +148 -0
  71. data/lib/legate/auth/coordinator.rb +218 -0
  72. data/lib/legate/auth/coordinators/oauth2_coordinator.rb +99 -0
  73. data/lib/legate/auth/coordinators/oidc_coordinator.rb +68 -0
  74. data/lib/legate/auth/coordinators/service_account_coordinator.rb +122 -0
  75. data/lib/legate/auth/credential.rb +157 -0
  76. data/lib/legate/auth/encryption.rb +108 -0
  77. data/lib/legate/auth/error.rb +94 -0
  78. data/lib/legate/auth/exchanged_credential.rb +180 -0
  79. data/lib/legate/auth/excon_middleware.rb +285 -0
  80. data/lib/legate/auth/http_client_utils.rb +364 -0
  81. data/lib/legate/auth/manager.rb +531 -0
  82. data/lib/legate/auth/manager_store.rb +394 -0
  83. data/lib/legate/auth/middleware_factory.rb +290 -0
  84. data/lib/legate/auth/runner.rb +279 -0
  85. data/lib/legate/auth/scheme.rb +125 -0
  86. data/lib/legate/auth/schemes/api_key.rb +212 -0
  87. data/lib/legate/auth/schemes/google_service_account.rb +108 -0
  88. data/lib/legate/auth/schemes/http_bearer.rb +98 -0
  89. data/lib/legate/auth/schemes/oauth2.rb +396 -0
  90. data/lib/legate/auth/schemes/openid_connect.rb +346 -0
  91. data/lib/legate/auth/schemes/service_account.rb +388 -0
  92. data/lib/legate/auth/schemes.rb +40 -0
  93. data/lib/legate/auth/token_manager.rb +362 -0
  94. data/lib/legate/auth/token_store.rb +86 -0
  95. data/lib/legate/auth/tool_context_extension.rb +97 -0
  96. data/lib/legate/auth/tool_integration.rb +188 -0
  97. data/lib/legate/auth/url_guard.rb +81 -0
  98. data/lib/legate/auth.rb +453 -0
  99. data/lib/legate/callbacks/callback_context.rb +71 -0
  100. data/lib/legate/cli/agent_commands.rb +950 -0
  101. data/lib/legate/cli/auth_commands.rb +520 -0
  102. data/lib/legate/cli/base_command.rb +24 -0
  103. data/lib/legate/cli/deployment_commands.rb +934 -0
  104. data/lib/legate/cli/output_helper.rb +108 -0
  105. data/lib/legate/cli/session_commands.rb +138 -0
  106. data/lib/legate/cli/skaffold_commands.rb +223 -0
  107. data/lib/legate/cli/tool_commands.rb +261 -0
  108. data/lib/legate/cli/web_commands.rb +182 -0
  109. data/lib/legate/cli.rb +40 -0
  110. data/lib/legate/configuration/webhooks.rb +113 -0
  111. data/lib/legate/configuration.rb +39 -0
  112. data/lib/legate/definition_store.rb +23 -0
  113. data/lib/legate/errors.rb +118 -0
  114. data/lib/legate/event.rb +161 -0
  115. data/lib/legate/gemini_ai_beta_patch.rb +39 -0
  116. data/lib/legate/generators/agent_generator.rb +412 -0
  117. data/lib/legate/generators/code_validator.rb +48 -0
  118. data/lib/legate/generators/legate/install_generator.rb +35 -0
  119. data/lib/legate/generators/legate/templates/create_legate_tables.rb.tt +36 -0
  120. data/lib/legate/generators/legate/templates/initializer.rb +18 -0
  121. data/lib/legate/generators/runtime_tool_loader.rb +76 -0
  122. data/lib/legate/generators/tool_generator.rb +408 -0
  123. data/lib/legate/generators.rb +11 -0
  124. data/lib/legate/global_definition_registry.rb +506 -0
  125. data/lib/legate/global_tool_manager.rb +135 -0
  126. data/lib/legate/llm/adapter.rb +69 -0
  127. data/lib/legate/llm/gemini.rb +172 -0
  128. data/lib/legate/llm/ollama.rb +80 -0
  129. data/lib/legate/llm.rb +34 -0
  130. data/lib/legate/mcp/client.rb +320 -0
  131. data/lib/legate/mcp/connection/sse.rb +292 -0
  132. data/lib/legate/mcp/connection/stdio.rb +273 -0
  133. data/lib/legate/mcp/connection_manager.rb +103 -0
  134. data/lib/legate/mcp/server/legate_agent_adapter.rb +170 -0
  135. data/lib/legate/mcp/server/legate_direct_agent_adapter.rb +140 -0
  136. data/lib/legate/mcp/server/legate_tool_adapter.rb +119 -0
  137. data/lib/legate/mcp/tool_wrapper.rb +138 -0
  138. data/lib/legate/mcp/util/schema_converter.rb +134 -0
  139. data/lib/legate/mcp.rb +23 -0
  140. data/lib/legate/plan_executor.rb +375 -0
  141. data/lib/legate/planner.rb +839 -0
  142. data/lib/legate/rails/railtie.rb +43 -0
  143. data/lib/legate/rails.rb +9 -0
  144. data/lib/legate/redaction.rb +32 -0
  145. data/lib/legate/session.rb +299 -0
  146. data/lib/legate/session_service/active_record.rb +300 -0
  147. data/lib/legate/session_service/base.rb +68 -0
  148. data/lib/legate/session_service/event_broadcast.rb +74 -0
  149. data/lib/legate/session_service/in_memory.rb +188 -0
  150. data/lib/legate/tool/metadata_dsl.rb +122 -0
  151. data/lib/legate/tool.rb +276 -0
  152. data/lib/legate/tool_code_generator.rb +103 -0
  153. data/lib/legate/tool_context.rb +350 -0
  154. data/lib/legate/tool_loader.rb +39 -0
  155. data/lib/legate/tool_registry.rb +73 -0
  156. data/lib/legate/tool_result.rb +61 -0
  157. data/lib/legate/tools/agent_tool.rb +187 -0
  158. data/lib/legate/tools/base/http_client.rb +319 -0
  159. data/lib/legate/tools/base/safe_url.rb +56 -0
  160. data/lib/legate/tools/base_async_job_tool.rb +91 -0
  161. data/lib/legate/tools/calculator.rb +89 -0
  162. data/lib/legate/tools/cat_facts.rb +81 -0
  163. data/lib/legate/tools/check_job_status_tool.rb +48 -0
  164. data/lib/legate/tools/current_time_tool.rb +64 -0
  165. data/lib/legate/tools/echo.rb +43 -0
  166. data/lib/legate/tools/http_request_tool.rb +105 -0
  167. data/lib/legate/tools/random_number_tool.rb +64 -0
  168. data/lib/legate/tools/read_webpage_tool.rb +92 -0
  169. data/lib/legate/tools/sleepy_tool.rb +74 -0
  170. data/lib/legate/tools/webhook_tool.rb +146 -0
  171. data/lib/legate/version.rb +5 -0
  172. data/lib/legate/web/app.rb +984 -0
  173. data/lib/legate/web/public/css/main.css +4980 -0
  174. data/lib/legate/web/public/images/favicon-256.png +0 -0
  175. data/lib/legate/web/public/images/favicon-32.png +0 -0
  176. data/lib/legate/web/public/images/legate-logo-dark.png +0 -0
  177. data/lib/legate/web/public/images/legate-logo-light.png +0 -0
  178. data/lib/legate/web/public/js/legate.js +616 -0
  179. data/lib/legate/web/public/styles/main.scss +4402 -0
  180. data/lib/legate/web/routes/agent_authentication_routes.rb +530 -0
  181. data/lib/legate/web/routes/agent_definition_routes.rb +803 -0
  182. data/lib/legate/web/routes/agent_generator_routes.rb +80 -0
  183. data/lib/legate/web/routes/agent_interaction_routes.rb +734 -0
  184. data/lib/legate/web/routes/agent_runtime_routes.rb +323 -0
  185. data/lib/legate/web/routes/api_routes.rb +56 -0
  186. data/lib/legate/web/routes/authentication_routes.rb +1541 -0
  187. data/lib/legate/web/routes/core_routes.rb +111 -0
  188. data/lib/legate/web/routes/documentation_routes.rb +220 -0
  189. data/lib/legate/web/routes/tool_generator_routes.rb +81 -0
  190. data/lib/legate/web/routes/tools_ui_routes.rb +207 -0
  191. data/lib/legate/web/sass_compiler.rb +73 -0
  192. data/lib/legate/web/views/_active_session_info.slim +25 -0
  193. data/lib/legate/web/views/_activity_list.slim +55 -0
  194. data/lib/legate/web/views/_agent_card.slim +56 -0
  195. data/lib/legate/web/views/_agent_generator_modal.slim +382 -0
  196. data/lib/legate/web/views/_agent_status_controls.slim +71 -0
  197. data/lib/legate/web/views/_agent_tool_table.slim +74 -0
  198. data/lib/legate/web/views/_chat_message.slim +95 -0
  199. data/lib/legate/web/views/_display_agent_configuration.slim +26 -0
  200. data/lib/legate/web/views/_display_agent_description.slim +11 -0
  201. data/lib/legate/web/views/_display_agent_fallback.slim +15 -0
  202. data/lib/legate/web/views/_display_agent_hierarchy.slim +93 -0
  203. data/lib/legate/web/views/_display_agent_instruction.slim +17 -0
  204. data/lib/legate/web/views/_display_agent_mcp.slim +13 -0
  205. data/lib/legate/web/views/_display_agent_model.slim +17 -0
  206. data/lib/legate/web/views/_display_agent_name.slim +42 -0
  207. data/lib/legate/web/views/_display_agent_output_key.slim +26 -0
  208. data/lib/legate/web/views/_display_agent_type.slim +65 -0
  209. data/lib/legate/web/views/_edit_agent_configuration.slim +74 -0
  210. data/lib/legate/web/views/_edit_agent_description.slim +16 -0
  211. data/lib/legate/web/views/_edit_agent_fallback.slim +25 -0
  212. data/lib/legate/web/views/_edit_agent_hierarchy.slim +98 -0
  213. data/lib/legate/web/views/_edit_agent_instruction.slim +49 -0
  214. data/lib/legate/web/views/_edit_agent_mcp.slim +33 -0
  215. data/lib/legate/web/views/_edit_agent_model.slim +23 -0
  216. data/lib/legate/web/views/_edit_agent_output_key.slim +36 -0
  217. data/lib/legate/web/views/_edit_agent_tools.slim +40 -0
  218. data/lib/legate/web/views/_edit_agent_type.slim +67 -0
  219. data/lib/legate/web/views/_session_error.slim +4 -0
  220. data/lib/legate/web/views/_skeleton.slim +69 -0
  221. data/lib/legate/web/views/_tool_card.slim +9 -0
  222. data/lib/legate/web/views/_tool_generator_modal.slim +311 -0
  223. data/lib/legate/web/views/agent.slim +436 -0
  224. data/lib/legate/web/views/agent_auth.slim +562 -0
  225. data/lib/legate/web/views/agents.slim +369 -0
  226. data/lib/legate/web/views/auth.slim +112 -0
  227. data/lib/legate/web/views/auth_credential_detail.slim +327 -0
  228. data/lib/legate/web/views/auth_credentials.slim +261 -0
  229. data/lib/legate/web/views/auth_debug.slim +94 -0
  230. data/lib/legate/web/views/auth_mapping_detail.slim +151 -0
  231. data/lib/legate/web/views/auth_mapping_new.slim +123 -0
  232. data/lib/legate/web/views/auth_mappings.slim +120 -0
  233. data/lib/legate/web/views/auth_scheme_detail.slim +274 -0
  234. data/lib/legate/web/views/auth_schemes.slim +259 -0
  235. data/lib/legate/web/views/auth_test.slim +418 -0
  236. data/lib/legate/web/views/chat.slim +192 -0
  237. data/lib/legate/web/views/docs_index.slim +105 -0
  238. data/lib/legate/web/views/docs_show.slim +105 -0
  239. data/lib/legate/web/views/error_404.slim +5 -0
  240. data/lib/legate/web/views/index.slim +148 -0
  241. data/lib/legate/web/views/layout.slim +144 -0
  242. data/lib/legate/web/views/tool_detail.slim +87 -0
  243. data/lib/legate/web/views/tools.slim +50 -0
  244. data/lib/legate/web/webhook_listener.rb +367 -0
  245. data/lib/legate/web.rb +9 -0
  246. data/lib/legate.rb +220 -0
  247. data/public/docs/advanced/callbacks.md +828 -0
  248. data/public/docs/advanced/mcp_schema_conversion.md +59 -0
  249. data/public/docs/authentication/api_reference/config.md +210 -0
  250. data/public/docs/authentication/api_reference/credential.md +246 -0
  251. data/public/docs/authentication/api_reference/encryption.md +218 -0
  252. data/public/docs/authentication/api_reference/exchanged_credential.md +271 -0
  253. data/public/docs/authentication/api_reference/excon_middleware.md +175 -0
  254. data/public/docs/authentication/api_reference/index.md +30 -0
  255. data/public/docs/authentication/api_reference/scheme.md +250 -0
  256. data/public/docs/authentication/api_reference/schemes/api_key.md +175 -0
  257. data/public/docs/authentication/api_reference/schemes/google_service_account.md +221 -0
  258. data/public/docs/authentication/api_reference/schemes/http_bearer.md +169 -0
  259. data/public/docs/authentication/api_reference/schemes/oauth2.md +343 -0
  260. data/public/docs/authentication/api_reference/schemes/oidc.md +73 -0
  261. data/public/docs/authentication/api_reference/schemes/openid_connect.md +311 -0
  262. data/public/docs/authentication/api_reference/schemes/service_account.md +287 -0
  263. data/public/docs/authentication/api_reference/token_manager.md +221 -0
  264. data/public/docs/authentication/api_reference/token_store.md +146 -0
  265. data/public/docs/authentication/api_reference/tool_context_extension.md +166 -0
  266. data/public/docs/authentication/guides/api_key.md +190 -0
  267. data/public/docs/authentication/guides/bearer.md +172 -0
  268. data/public/docs/authentication/guides/configuration.md +255 -0
  269. data/public/docs/authentication/guides/custom_flow.md +523 -0
  270. data/public/docs/authentication/guides/index.md +24 -0
  271. data/public/docs/authentication/guides/migration.md +435 -0
  272. data/public/docs/authentication/guides/oauth2.md +252 -0
  273. data/public/docs/authentication/guides/oidc.md +241 -0
  274. data/public/docs/authentication/guides/overview.md +155 -0
  275. data/public/docs/authentication/guides/secure_storage.md +301 -0
  276. data/public/docs/authentication/guides/service_account.md +228 -0
  277. data/public/docs/authentication/guides/token_lifecycle.md +295 -0
  278. data/public/docs/authentication/guides/web_ui_integration.md +504 -0
  279. data/public/docs/authentication/index.md +58 -0
  280. data/public/docs/authentication/troubleshooting/credential_storage.md +550 -0
  281. data/public/docs/authentication/troubleshooting/environment_variables.md +540 -0
  282. data/public/docs/authentication/troubleshooting/index.md +11 -0
  283. data/public/docs/authentication/troubleshooting/oauth2_issues.md +220 -0
  284. data/public/docs/authentication/troubleshooting/oidc_issues.md +412 -0
  285. data/public/docs/authentication/troubleshooting/token_refresh.md +338 -0
  286. data/public/docs/cli/legate_cli_usage.md +363 -0
  287. data/public/docs/core_concepts/legate_agent_lifecycle.md +124 -0
  288. data/public/docs/core_concepts/legate_architecture_overview.md +110 -0
  289. data/public/docs/core_concepts/legate_configuration.md +116 -0
  290. data/public/docs/core_concepts/legate_definition_store.md +102 -0
  291. data/public/docs/core_concepts/legate_planner.md +94 -0
  292. data/public/docs/core_concepts/legate_session_service.md +104 -0
  293. data/public/docs/error_handling/legate_error_handling.md +122 -0
  294. data/public/docs/examples.md +199 -0
  295. data/public/docs/getting_started.md +111 -0
  296. data/public/docs/guides/agentic_agents.md +137 -0
  297. data/public/docs/guides/ai_code_generators.md +437 -0
  298. data/public/docs/guides/auto_loading.md +326 -0
  299. data/public/docs/guides/configuring_agent_webhooks.md +219 -0
  300. data/public/docs/guides/http_client_usage.md +264 -0
  301. data/public/docs/guides/llm_providers.md +137 -0
  302. data/public/docs/guides/mcp_client_integration.md +232 -0
  303. data/public/docs/guides/mcp_server_exposure.md +206 -0
  304. data/public/docs/guides/rails_integration.md +128 -0
  305. data/public/docs/guides/sending_outbound_webhooks.md +227 -0
  306. data/public/docs/guides/streaming.md +112 -0
  307. data/public/docs/guides/webhooks.md +288 -0
  308. data/public/docs/introduction.md +51 -0
  309. data/public/docs/multi_agent_systems/advanced_features.md +57 -0
  310. data/public/docs/multi_agent_systems/agent_delegation.md +190 -0
  311. data/public/docs/multi_agent_systems/agent_hierarchy.md +49 -0
  312. data/public/docs/multi_agent_systems/state_management.md +47 -0
  313. data/public/docs/multi_agent_systems/workflow_agents.md +72 -0
  314. data/public/docs/tools/legate_built_in_tools.md +332 -0
  315. data/public/docs/tools/legate_tools_and_registry.md +263 -0
  316. data/public/docs/web_ui/legate_web_ui.md +137 -0
  317. metadata +823 -0
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Example of using HTTP Bearer authentication with Legate
5
+ #
6
+ # This example demonstrates how to use HTTP Bearer authentication to make authenticated requests
7
+ # to an API that requires a bearer token in the Authorization header.
8
+ #
9
+ # Usage:
10
+ # ruby examples/13_authentication.rb [token]
11
+
12
+ require 'bundler/setup'
13
+ require 'legate'
14
+
15
+ # Load .env and map GEMINI_API_KEY -> GOOGLE_API_KEY (as the `legate` CLI does).
16
+ # The library never reads .env on its own; an application must opt in.
17
+ Legate.load_environment
18
+ require 'legate/auth'
19
+ require 'legate/auth/schemes/http_bearer'
20
+ require 'json'
21
+
22
+ # Check if a bearer token was provided
23
+ bearer_token = ARGV[0] || ENV['BEARER_TOKEN']
24
+ unless bearer_token
25
+ puts 'Error: Please provide a bearer token as an argument'
26
+ puts 'Usage: ruby examples/13_authentication.rb [token]'
27
+ puts 'Alternatively, set the BEARER_TOKEN environment variable'
28
+ exit 1
29
+ end
30
+
31
+ puts "Using Bearer Token: #{bearer_token[0..5]}..." + ('*' * 10)
32
+
33
+ # Create the Auth::Credential with the bearer token
34
+ credential = Legate::Auth::Credential.new(
35
+ auth_type: :http_bearer,
36
+ bearer_token: bearer_token
37
+ )
38
+
39
+ # Create a session service to manage authentication state
40
+ session_service = Legate::SessionService::InMemory.new
41
+
42
+ # Create a token store (optional but recommended for consistency)
43
+ token_store = Legate::Auth::TokenStore.new(session_service: session_service)
44
+
45
+ puts "\n=== Example 1: Basic HTTP Bearer Authentication ==="
46
+ # Create an HTTP Bearer scheme
47
+ bearer_scheme = Legate::Auth::Schemes::HTTPBearer.new
48
+
49
+ # For simple non-interactive schemes like HTTP Bearer, we can use the token directly
50
+ exchanged_token = bearer_scheme.exchange_token(credential)
51
+ puts 'Generated token for HTTP Bearer authentication'
52
+
53
+ # Example of making a request with the bearer token
54
+ require 'excon'
55
+ conn = Excon.new('https://httpbin.org')
56
+
57
+ # Prepare request with authentication
58
+ request = {
59
+ path: '/headers',
60
+ headers: {
61
+ 'Accept' => 'application/json'
62
+ }
63
+ }
64
+
65
+ # Apply authentication
66
+ request = bearer_scheme.apply_to_request(request, exchanged_token)
67
+
68
+ begin
69
+ response = conn.get(request)
70
+
71
+ if response.status == 200
72
+ puts "Request succeeded with status: #{response.status}"
73
+ puts 'Headers received by server:'
74
+ JSON.parse(response.body)['headers'].each do |name, value|
75
+ puts " #{name}: #{value}"
76
+ end
77
+ else
78
+ puts "Request failed with status: #{response.status}"
79
+ puts "Error: #{response.body}"
80
+ end
81
+ rescue StandardError => e
82
+ puts "Request failed: #{e.message}"
83
+ end
84
+
85
+ puts "\n=== Example 2: HTTP Bearer with Expiry Simulation ==="
86
+ # In real-world scenarios, bearer tokens often expire
87
+ # This example simulates a token with expiry information
88
+
89
+ # Create a token with expiry information
90
+ expiring_token = Legate::Auth::ExchangedCredential.new(
91
+ auth_type: :http_bearer,
92
+ access_token: bearer_token,
93
+ bearer_token: bearer_token,
94
+ expires_in: 3600, # Token expires in 1 hour
95
+ token_type: 'Bearer'
96
+ )
97
+
98
+ puts "Token expires in: #{expiring_token[:expires_in]} seconds"
99
+
100
+ # Example of checking token expiry
101
+ if expiring_token.expired?
102
+ puts 'Token has expired and needs to be refreshed'
103
+ else
104
+ remaining = expiring_token.expires_at - Time.now
105
+ puts "Token is still valid for #{remaining.to_i} seconds"
106
+ end
107
+
108
+ puts "\n=== Example 3: Using with the Legate Excon Middleware ==="
109
+
110
+ # Create the Excon middleware for HTTP Bearer authentication
111
+ middleware = Legate::Auth.create_middleware(
112
+ scheme: bearer_scheme,
113
+ credential: credential
114
+ )
115
+
116
+ # Create an Excon connection with the middleware
117
+ connection = Legate::Auth.create_connection(
118
+ 'https://httpbin.org',
119
+ scheme: bearer_scheme,
120
+ credential: credential
121
+ )
122
+
123
+ begin
124
+ response = connection.get(
125
+ path: '/headers',
126
+ headers: { 'Accept' => 'application/json' }
127
+ )
128
+
129
+ if response.status == 200
130
+ puts "Excon request succeeded with status: #{response.status}"
131
+ headers = JSON.parse(response.body)['headers']
132
+ puts 'Headers received by server:'
133
+ headers.each do |name, value|
134
+ puts " #{name}: #{value}"
135
+ end
136
+ else
137
+ puts "Excon request failed with status: #{response.status}"
138
+ puts "Error: #{response.body}"
139
+ end
140
+ rescue StandardError => e
141
+ puts "Excon request failed: #{e.message}"
142
+ end
143
+
144
+ puts "\n=== Example 4: Using with the Legate Tooling System ==="
145
+ # Example of a tool using bearer authentication
146
+ class BearerAuthExampleTool < Legate::Tool
147
+ include Legate::Tools::Base::HttpClient
148
+
149
+ tool_description 'Example tool demonstrating HTTP Bearer authentication'
150
+
151
+ parameter :endpoint,
152
+ type: :string,
153
+ description: 'API endpoint to call',
154
+ required: true
155
+
156
+ def initialize(options = {})
157
+ super()
158
+ @auth_scheme = options[:auth_scheme]
159
+ @auth_credential = options[:auth_credential]
160
+ setup_http_client(
161
+ base_url: 'https://httpbin.org',
162
+ options: {
163
+ connect_timeout: 3,
164
+ read_timeout: 3,
165
+ write_timeout: 3
166
+ }
167
+ )
168
+ end
169
+
170
+ private
171
+
172
+ def perform_execution(params, _context)
173
+ # Prepare request with authentication
174
+ request = {
175
+ method: :get,
176
+ path: "/#{params[:endpoint]}",
177
+ headers: {
178
+ 'Accept' => 'application/json'
179
+ }
180
+ }
181
+
182
+ # Apply authentication if configured
183
+ request = @auth_scheme.apply_to_request(request, @auth_credential) if @auth_scheme && @auth_credential
184
+
185
+ # Make the request
186
+ response = http_get(
187
+ request[:path],
188
+ headers: request[:headers]
189
+ )
190
+
191
+ # Parse and return the response
192
+ data = JSON.parse(response.body)
193
+ {
194
+ status: :success,
195
+ endpoint: params[:endpoint],
196
+ headers: data['headers'],
197
+ data: data
198
+ }
199
+ end
200
+ end
201
+
202
+ # Create and use the example tool
203
+ example_tool = BearerAuthExampleTool.new(
204
+ auth_scheme: bearer_scheme,
205
+ auth_credential: credential
206
+ )
207
+
208
+ puts "\nTesting bearer auth tool with endpoint: headers"
209
+ begin
210
+ result = example_tool.execute(endpoint: 'headers')
211
+ puts 'Tool execution succeeded!'
212
+ puts 'Response headers:'
213
+ result[:headers].each do |name, value|
214
+ puts " #{name}: #{value}"
215
+ end
216
+ rescue StandardError => e
217
+ puts "Tool execution failed: #{e.message}"
218
+ end
219
+
220
+ puts "\nHTTP Bearer authentication example completed successfully!"
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Example: Using an Legate Agent as an MCP Client
5
+ #
6
+ # This example demonstrates how to configure an Legate::Agent to connect to an
7
+ # external MCP server (like the @modelcontextprotocol/server-filesystem) and use its tools.
8
+ #
9
+ # Key Concepts:
10
+ # - MCP Server Configuration: Defining how to connect to the external server (e.g., via stdio).
11
+ # - Selected Tool Names: Explicitly telling the agent which tools from the MCP server it is allowed to use.
12
+ # The names provided in `selected_tool_names` MUST exactly match the tool names exposed by the specific
13
+ # MCP server you are connecting to (check server logs or capabilities if unsure).
14
+ # - Runtime Start/Stop: Managing the connection lifecycle to the MCP server.
15
+ # - Using External Tools: Making requests that the agent's planner can map to the available MCP tools.
16
+ #
17
+ # Requires:
18
+ # - legate gem with MCP support installed
19
+ # - An external MCP server running. For testing, you can use:
20
+ # `npx @modelcontextprotocol/server-filesystem --stdio path/to/a/directory`
21
+ # (Replace `path/to/a/directory` with a real directory the server can access)
22
+ #
23
+ # To Run:
24
+ # 1. Start the external MCP server in one terminal (e.g., the filesystem server command above).
25
+ # 2. Ensure the directory specified in `mcp_server_config[:args]` exists and is accessible.
26
+ # 3. Run this script in another terminal: `bundle exec ruby examples/14_mcp_client.rb`
27
+ # 4. Observe the logs: The agent should initialize, connect to the MCP server, and list available tools
28
+ # (including the ones explicitly selected via `selected_tool_names`, like `:read_file` in this example).
29
+ # 5. The script will then attempt to run a task using the `read_file` tool from the MCP server.
30
+
31
+ $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
32
+ require 'legate'
33
+ Legate.load_environment # Handle Bundler, Dotenv, etc.
34
+
35
+ require 'legate/mcp' # Ensure MCP modules are loaded
36
+
37
+ # Configure Legate logger
38
+ ENV['LEGATE_LOG_LEVEL'] = 'DEBUG'
39
+ dirname = File.expand_path(File.dirname(File.dirname(__FILE__)))
40
+
41
+ # --- 1. Define a Native Legate Tool (Optional) ---
42
+ class NativeEchoTool < Legate::Tool
43
+ define_metadata(
44
+ name: :native_echo,
45
+ description: 'Echoes back the provided message (native Legate tool).',
46
+ parameters: {
47
+ message: { type: :string, required: true, description: 'Message to echo' }
48
+ }
49
+ )
50
+ def perform_execution(params, _context)
51
+ Legate.logger.info("[NativeEchoTool] Echoing: #{params[:message]}")
52
+ { status: :success, result: "Native echo: #{params[:message]}" }
53
+ end
54
+ end
55
+
56
+ # Register the native tool globally so it can be found by its name.
57
+ Legate::GlobalToolManager.register_tool(NativeEchoTool)
58
+
59
+ # --- 2. Configure the External MCP Server Connection ---
60
+ # NOTE: Adjust the command and args based on how you run *your* external server.
61
+ # This example assumes the filesystem server.
62
+ # Make sure the directory path exists and is accessible!
63
+ mcp_server_config = {
64
+ type: 'stdio',
65
+ command: 'npx', # Command to start the server
66
+ args: [ # Arguments for the command
67
+ '--',
68
+ '@modelcontextprotocol/server-filesystem',
69
+ # '--stdio',
70
+ dirname # <<< IMPORTANT: Change this to a real, accessible directory!
71
+ # Create this directory before running: mkdir /tmp/mcp_fs_test_dir
72
+ ]
73
+ }
74
+ # Check if args include a placeholder path and warn if so
75
+ if mcp_server_config[:args].any? { |arg| arg.include?('path/to/') || arg.include?('tmp/mcp_fs_test_dir') }
76
+ Legate.logger.warn('MCP server config in example still uses a placeholder directory.')
77
+ Legate.logger.warn('Please edit examples/14_mcp_client.rb and set a real directory path in `mcp_server_config[:args]`.')
78
+ # Optionally exit if you want to enforce configuration
79
+ # exit(1)
80
+ end
81
+
82
+ # --- 3. Initialize the Legate Agent ---
83
+ Legate.logger.info('Initializing agent...')
84
+
85
+ mcp_client_agent_definition = Legate::AgentDefinition.new.define do |a|
86
+ a.name :mcp_client_agent
87
+ a.description 'An agent using native and external MCP tools.'
88
+ a.instruction 'You can echo messages natively and use filesystem tools from an MCP server, such as reading files.'
89
+ a.use_tool :native_echo # Native tool defined above
90
+ a.use_tool :read_file # Tool expected from the MCP server (e.g., from server-filesystem)
91
+ # Add MCP server configuration
92
+ a.mcp_servers mcp_server_config
93
+ # model_name: 'gemini-pro-1.5' # Optional: Specify model via a.model_name 'gemini-pro-1.5'
94
+ end
95
+
96
+ my_agent = Legate::Agent.new(definition: mcp_client_agent_definition)
97
+
98
+ # --- 4. Start the Agent Runtime ---
99
+ # This connects to the MCP server and registers its tools.
100
+ Legate.logger.info('Starting agent runtime...')
101
+ my_agent.start
102
+ Legate.logger.info("Agent started. Available tool names: #{my_agent.tool_registry.tools.keys}")
103
+ Legate.logger.info("Full metadata: #{my_agent.available_tools_metadata.inspect}")
104
+
105
+ # --- 5. Run a Task (Optional Example) ---
106
+ # Uncomment this section to try running a task.
107
+ # Requires setting up a session service and ensuring the external server
108
+ # provides the tool mentioned in the user_input (e.g., `filesystem/readFile`).
109
+
110
+ puts "\n--- Running Task Example ---"
111
+ begin
112
+ session_service = Legate::SessionService::InMemory.new
113
+ session = session_service.create_session(app_name: 'mcp_client_test', user_id: 'test_user')
114
+ puts "Created session: #{session.id}"
115
+
116
+ # Create a dummy file for the filesystem tool to read
117
+ # Ensure the directory matches the one in mcp_server_config[:args]
118
+ dummy_file_path = "#{dirname}/hello.txt"
119
+ begin
120
+ File.write(dummy_file_path, 'Hello from Legate client example!')
121
+ puts "Created dummy file: #{dummy_file_path}"
122
+ rescue StandardError => e
123
+ puts "Warning: Could not create dummy file '#{dummy_file_path}': #{e.message}"
124
+ puts 'Filesystem tool example might fail.'
125
+ end
126
+
127
+ # Input asking to use a tool likely provided by the filesystem server
128
+ # user_input = "What files are in the #{dirname}? What are the contents of hello.txt in #{dirname}?"
129
+ user_input = "Read the content of the file named 'hello.txt' in #{dirname} using the filesystem tool." # <<< MODIFIED: More specific input
130
+ puts "User Input: #{user_input}"
131
+
132
+ final_event = my_agent.run_task(
133
+ session_id: session.id,
134
+ user_input: user_input,
135
+ session_service: session_service
136
+ )
137
+
138
+ puts 'Final Agent Event:'
139
+ require 'pp' # Pretty print
140
+ pp final_event
141
+ rescue StandardError => e
142
+ puts "Error running task: #{e.message}"
143
+ puts e.backtrace
144
+ end
145
+ puts "--------------------------\n"
146
+
147
+ # Delete the dummy file after the task is complete
148
+ File.delete(dummy_file_path) if File.exist?(dummy_file_path)
149
+
150
+ #--- 6. Stop the Agent Runtime ---
151
+ # This disconnects from the MCP server.
152
+ Legate.logger.info('Stopping agent runtime...')
153
+ my_agent.stop
154
+ Legate.logger.info('Agent stopped.')
@@ -0,0 +1,79 @@
1
+ # File: examples/15_mcp_server.rb
2
+ # frozen_string_literal: true
3
+
4
+ # --- Example: Exposing an Legate::Tool via MCP using fast-mcp ---
5
+ #
6
+ # This script demonstrates how to wrap an existing Legate::Tool
7
+ # (in this case, the built-in Calculator tool) and expose it
8
+ # on an MCP server run over STDIO using the fast-mcp gem.
9
+ #
10
+ # Prerequisites:
11
+ # - Run `bundle install` in the legate directory.
12
+ # - Ensure the `fast-mcp` gem is available (e.g., via Gemfile path).
13
+ #
14
+ # Usage:
15
+ # 1. Run this script from the legate root directory:
16
+ # `bundle exec ruby examples/15_mcp_server.rb`
17
+ # 2. The script will start and wait for MCP JSON-RPC messages on STDIN.
18
+ # 3. Use an MCP client (like `mcp-client`, `mcp-inspector`, or another script
19
+ # using Legate::Mcp::Client) connected to this script's STDIO to interact.
20
+ #
21
+ # Example Interaction (using a generic client):
22
+ # -> {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"capabilities":{}}}
23
+ # <- {"jsonrpc":"2.0","id":1,"result":{"capabilities":{},"serverInfo":{"name":"Legate Tool Server","version":"1.0"}}}
24
+ # -> {"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
25
+ # <- {"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"calculator","description":"Performs basic arithmetic operations.","inputSchema":{"type":"object","properties":{"a":{"type":"number","description":"First operand"},"b":{"type":"number","description":"Second operand"},"op":{"type":"string","description":"Operator (+, -, *, /)"}},"required":["a","b","op"]}}]}}
26
+ # -> {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"calculator","arguments":{"a":10,"b":5,"op":"*"}}}
27
+ # <- {"jsonrpc":"2.0","id":3,"result":50.0}
28
+ #
29
+ # -------------------------------------------------------------
30
+
31
+ $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
32
+ require 'legate'
33
+ Legate.load_environment # Handle Bundler, Dotenv, etc.
34
+
35
+ require 'legate/mcp' # Load Legate MCP modules
36
+ require 'legate/mcp/server/legate_tool_adapter' # Load the Tool adapter
37
+ require 'legate/tools/calculator' # Load the specific Legate tool we want to expose
38
+ require 'fast_mcp' # Load the fast-mcp library
39
+
40
+ Legate.configure do |config|
41
+ # Configure Legate logger level if desired (e.g., :debug for more verbose MCP logs)
42
+ # config.log_level = :debug
43
+ end
44
+
45
+ # --- 1. Wrap the Legate::Tool ---
46
+ # Use the LegateToolAdapter to create a fast-mcp compatible class
47
+ begin
48
+ AdaptedCalculator = Legate::Mcp::Server::LegateToolAdapter.wrap(Legate::Tools::Calculator)
49
+ Legate.logger.info('Successfully wrapped Legate::Tools::Calculator for MCP.')
50
+ rescue StandardError => e
51
+ Legate.logger.fatal("Failed to wrap Legate Tool: #{e.message}")
52
+ exit(1)
53
+ end
54
+
55
+ # --- 2. Create fast-mcp Server Instance ---
56
+ # FastMcp::Server uses STDIO transport by default when calling #start
57
+ mcp_server = FastMcp::Server.new(
58
+ name: 'Legate Tool Server',
59
+ version: Legate::VERSION # Use Legate version
60
+ )
61
+ Legate.logger.info('Initialized FastMcp::Server.')
62
+
63
+ # --- 3. Register the Wrapped Tool ---
64
+ mcp_server.register_tool(AdaptedCalculator)
65
+ Legate.logger.info("Registered adapted '#{AdaptedCalculator.tool_name}' tool with fast-mcp server.")
66
+
67
+ # --- 4. Start the Server ---
68
+ Legate.logger.info('Starting MCP server on STDIO. Waiting for requests...')
69
+ puts '--- Legate MCP Tool Server (STDIO) Ready --- ' # Signal readiness besides logs
70
+ begin
71
+ mcp_server.start # This method typically blocks, listening on STDIN
72
+ rescue Interrupt
73
+ Legate.logger.info('Received interrupt, shutting down server.')
74
+ rescue StandardError => e
75
+ Legate.logger.fatal("MCP server crashed: #{e.class} - #{e.message}")
76
+ Legate.logger.fatal(e.backtrace.join("\n"))
77
+ ensure
78
+ Legate.logger.info('MCP server stopped.')
79
+ end
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Example: Sending Webhooks with HMAC Signing
5
+ #
6
+ # This example demonstrates how to use the built-in WebhookTool to send
7
+ # an HMAC-signed webhook payload to an external URL.
8
+ #
9
+ # Setup:
10
+ # 1. Go to https://webhook.site and copy your unique URL
11
+ # 2. Run: WEBHOOK_URL=https://webhook.site/your-uuid WEBHOOK_SECRET=my-secret \
12
+ # bundle exec ruby examples/16_webhooks.rb
13
+ # 3. Check webhook.site to see the received payload and signature header
14
+ #
15
+ # Run with: bundle exec ruby examples/16_webhooks.rb
16
+
17
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
18
+
19
+ require 'legate'
20
+
21
+ # Load .env and map GEMINI_API_KEY -> GOOGLE_API_KEY (as the `legate` CLI does).
22
+ # The library never reads .env on its own; an application must opt in.
23
+ Legate.load_environment
24
+ require 'legate/tools/webhook_tool'
25
+ require 'openssl'
26
+ require 'json'
27
+
28
+ puts '--- Webhook Example ---'
29
+
30
+ # 1. Configuration
31
+ webhook_url = ENV['WEBHOOK_URL']
32
+ secret_key = ENV.fetch('WEBHOOK_SECRET', 'example-secret-key')
33
+
34
+ unless webhook_url
35
+ puts "\nUsage: WEBHOOK_URL=https://webhook.site/your-uuid bundle exec ruby examples/16_webhooks.rb"
36
+ puts "\nGet a free URL at https://webhook.site — then check the site to see your payload arrive."
37
+ puts "You can also set WEBHOOK_SECRET (defaults to 'example-secret-key')."
38
+ exit(1)
39
+ end
40
+
41
+ puts "Target URL: #{webhook_url}"
42
+
43
+ # 2. Build the payload
44
+ payload_data = {
45
+ message: 'Hello from Legate!',
46
+ timestamp: Time.now.iso8601,
47
+ source: 'legate-webhook-example'
48
+ }
49
+ payload_json = payload_data.to_json
50
+
51
+ # 3. Calculate HMAC signature (SHA-256)
52
+ # The receiver can verify the payload integrity using the same secret
53
+ calculated_signature = OpenSSL::HMAC.hexdigest('sha256', secret_key, payload_json)
54
+ signature_header_value = "sha256=#{calculated_signature}"
55
+
56
+ puts "Payload: #{payload_json}"
57
+ puts "HMAC Signature: #{signature_header_value}"
58
+
59
+ # 4. Build headers
60
+ custom_headers = {
61
+ 'Content-Type' => 'application/json',
62
+ 'X-Hub-Signature-256' => signature_header_value
63
+ }
64
+
65
+ # 5. Send the webhook using the built-in WebhookTool
66
+ webhook_tool = Legate::Tools::WebhookTool.new
67
+
68
+ begin
69
+ puts "\nSending webhook..."
70
+ result = webhook_tool.execute(
71
+ url: webhook_url,
72
+ payload: payload_json,
73
+ headers: custom_headers
74
+ )
75
+
76
+ if result[:status] == :success
77
+ response_status = result.dig(:result, :response_status)
78
+ response_body = result.dig(:result, :response_body)
79
+ puts 'Webhook sent successfully!'
80
+ puts " Response status: #{response_status}"
81
+ puts " Response body: #{response_body}"
82
+ else
83
+ puts "Webhook failed: #{result[:error_message]}"
84
+ end
85
+ rescue Legate::ToolError => e
86
+ puts "Tool error: #{e.message}"
87
+ rescue StandardError => e
88
+ puts "Unexpected error: #{e.message}"
89
+ end
90
+
91
+ puts "\n--- Example Complete ---"