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,326 @@
1
+ # Auto-Loading Custom Tools and Agents
2
+
3
+ This guide explains how Legate automatically discovers and loads your custom tools and agent definitions when starting the web server.
4
+
5
+ ## Overview
6
+
7
+ When you run `legate web start`, Legate automatically scans conventional directories for Ruby files containing custom tools and agents. This means you can:
8
+
9
+ - Drop a tool file in `lib/tools/` and it's automatically available
10
+ - Drop an agent file in `lib/agents/` and it appears in the Web UI
11
+ - No manual configuration required
12
+
13
+ > The Web UI [AI builders](ai_code_generators) write to `tools/` and `agents/` for
14
+ > you (when installing a tool live, or via an agent's **Save to `agents/`** action),
15
+ > so those generated files are picked up here on the next start too.
16
+
17
+ ## Directory Structure
18
+
19
+ Legate scans the following directories relative to where you run `legate web start`:
20
+
21
+ ### For Tools
22
+
23
+ ```
24
+ ./lib/tools/ # Primary location
25
+ ./agents/lib/tools/ # Alternative (nested project)
26
+ ./tools/ # Simple projects
27
+ ```
28
+
29
+ ### For Agents
30
+
31
+ ```
32
+ ./lib/agents/ # Primary location
33
+ ./agents/lib/agents/ # Alternative (nested project)
34
+ ./agents/ # Simple projects (excludes /tools/ subdirs)
35
+ ```
36
+
37
+ ### Recommended Structure
38
+
39
+ ```
40
+ your_project/
41
+ ├── Gemfile
42
+ ├── .env # Environment variables (GOOGLE_API_KEY, etc.)
43
+ ├── lib/
44
+ │ ├── tools/
45
+ │ │ ├── weather_tool.rb
46
+ │ │ ├── email_validator_tool.rb
47
+ │ │ └── custom_api_tool.rb
48
+ │ └── agents/
49
+ │ ├── customer_support_agent.rb
50
+ │ ├── data_processor_agent.rb
51
+ │ └── notification_agent.rb
52
+ └── legate_init.rb # Optional: custom initialization
53
+ ```
54
+
55
+ ## Creating Auto-Loadable Tools
56
+
57
+ Your tool file should:
58
+
59
+ 1. Define the tool class
60
+ 2. Register it with `GlobalToolManager`
61
+
62
+ **Example: `lib/tools/greeting_tool.rb`**
63
+
64
+ ```ruby
65
+ # frozen_string_literal: true
66
+
67
+ require 'legate/tool'
68
+
69
+ class GreetingTool < Legate::Tool
70
+ tool_description 'Generates a personalized greeting'
71
+
72
+ parameter :name,
73
+ type: :string,
74
+ description: 'Name of the person to greet',
75
+ required: true
76
+
77
+ parameter :style,
78
+ type: :string,
79
+ description: 'Greeting style: formal, casual, or enthusiastic',
80
+ required: false
81
+
82
+ private
83
+
84
+ def perform_execution(params, context)
85
+ name = params[:name]
86
+ style = params[:style] || 'casual'
87
+
88
+ greeting = case style
89
+ when 'formal'
90
+ "Good day, #{name}. How may I assist you?"
91
+ when 'enthusiastic'
92
+ "Hey #{name}! Great to see you! 🎉"
93
+ else
94
+ "Hello, #{name}!"
95
+ end
96
+
97
+ { status: :success, result: greeting }
98
+ end
99
+ end
100
+
101
+ # This line makes the tool available to agents
102
+ Legate::GlobalToolManager.register_tool(GreetingTool)
103
+ ```
104
+
105
+ ## Creating Auto-Loadable Agents
106
+
107
+ Your agent file should:
108
+
109
+ 1. Define the agent using `AgentDefinition`
110
+ 2. Register it with `GlobalDefinitionRegistry`
111
+
112
+ **Example: `lib/agents/greeter_agent.rb`**
113
+
114
+ ```ruby
115
+ # frozen_string_literal: true
116
+
117
+ require 'legate'
118
+
119
+ definition = Legate::AgentDefinition.new.define do |a|
120
+ a.name :greeter
121
+ a.description 'A friendly agent that greets users'
122
+
123
+ a.instruction <<~INSTRUCTION
124
+ You are a friendly greeter agent.
125
+
126
+ When a user introduces themselves or asks for a greeting,
127
+ use the greeting_tool to generate an appropriate response.
128
+
129
+ Match the greeting style to the user's tone:
130
+ - Formal requests get formal greetings
131
+ - Casual messages get casual greetings
132
+ - Excited users get enthusiastic greetings
133
+ INSTRUCTION
134
+
135
+ a.use_tool :greeting_tool
136
+ a.model_name 'gemini-2.0-flash'
137
+ a.temperature 0.7
138
+ end
139
+
140
+ # This line makes the agent appear in the Web UI
141
+ Legate::GlobalDefinitionRegistry.register(definition)
142
+ ```
143
+
144
+ ## Load Order
145
+
146
+ Legate loads files in this order:
147
+
148
+ 1. **Initializer** (if present) - `legate_init.rb`, `config/legate_init.rb`, or `agents/legate_init.rb`
149
+ 2. **Tools** - All `.rb` files in tool directories
150
+ 3. **Agents** - All `.rb` files in agent directories
151
+ 4. **Register Definitions** - Agents are registered in the `GlobalDefinitionRegistry` for the Web UI
152
+
153
+ This order ensures tools are available before agents that reference them.
154
+
155
+ ## Custom Initializer
156
+
157
+ For advanced setup, create a `legate_init.rb` file in your project root:
158
+
159
+ ```ruby
160
+ # legate_init.rb
161
+
162
+ # Set up environment
163
+ ENV['MY_CUSTOM_VAR'] ||= 'default_value'
164
+
165
+ # Configure Legate
166
+ Legate.configure do |config|
167
+ config.default_model_name = 'gemini-2.0-flash'
168
+ config.default_temperature = 0.5
169
+ end
170
+
171
+ # Pre-load specific dependencies
172
+ require 'some_custom_gem'
173
+
174
+ # Log that initialization completed
175
+ Legate.logger.info "Custom initialization complete"
176
+ ```
177
+
178
+ The initializer runs before auto-loading, so you can set up anything your tools/agents need.
179
+
180
+ ## Startup Logs
181
+
182
+ When auto-loading works correctly, you'll see log messages like:
183
+
184
+ ```
185
+ INFO: Auto-loaded 3 custom tool file(s). Registered tools: [:echo, :calculator, ..., :greeting_tool, :weather_tool, :email_validator_tool]
186
+ INFO: Auto-loaded 2 custom agent file(s). Registered agents: [:greeter, :data_processor]
187
+ INFO: Synced agent 'greeter' to definition store for Web UI
188
+ INFO: Synced agent 'data_processor' to definition store for Web UI
189
+ ```
190
+
191
+ ## Disabling Auto-Loading
192
+
193
+ If you need to disable auto-loading (e.g., for testing):
194
+
195
+ ```bash
196
+ bundle exec legate web start --no-autoload
197
+ ```
198
+
199
+ ## Excluding Files
200
+
201
+ The auto-loader automatically skips:
202
+
203
+ - Test files (`*_spec.rb`, `*_test.rb`)
204
+ - Files in `/tools/` subdirectories when loading agents (to avoid double-loading)
205
+
206
+ ## Common Issues
207
+
208
+ ### Tool Not Appearing
209
+
210
+ 1. **Check the file location** - Must be in one of the scanned directories
211
+ 2. **Check registration** - File must call `Legate::GlobalToolManager.register_tool(YourTool)`
212
+ 3. **Check for errors** - Look at startup logs for load failures
213
+
214
+ ### Agent Not Appearing in Web UI
215
+
216
+ 1. **Check registration** - File must call `Legate::GlobalDefinitionRegistry.register(definition)`
217
+ 2. **Don't run the agent** - The file should only define and register, not execute
218
+ 3. **Check registration** - Agents must be registered in `GlobalDefinitionRegistry`
219
+
220
+ ### Load Errors
221
+
222
+ If a file fails to load, you'll see:
223
+
224
+ ```
225
+ WARN: Failed to load tool file /path/to/file.rb: SomeError - error message
226
+ ```
227
+
228
+ Check the file for syntax errors or missing dependencies.
229
+
230
+ ### Wrong require_relative Paths
231
+
232
+ **Don't use `require_relative` for other auto-loaded files.** Since tools load before agents, your agent can reference tools by symbol name without requiring them:
233
+
234
+ ```ruby
235
+ # DON'T do this:
236
+ require_relative '../tools/my_tool' # Wrong!
237
+
238
+ # DO this:
239
+ a.use_tool :my_tool # The tool is already loaded
240
+ ```
241
+
242
+ ## Running from Different Directories
243
+
244
+ The auto-loader scans relative to the current working directory. Always run `legate web start` from your project root:
245
+
246
+ ```bash
247
+ cd /path/to/your/project
248
+ bundle exec legate web start
249
+ ```
250
+
251
+ ## Example Project
252
+
253
+ Here's a complete example project structure:
254
+
255
+ ```
256
+ my_legate_project/
257
+ ├── Gemfile
258
+ │ # source 'https://rubygems.org'
259
+ │ # gem 'legate'
260
+
261
+ ├── .env
262
+ │ # GOOGLE_API_KEY=your_api_key_here
263
+
264
+ ├── lib/
265
+ │ ├── tools/
266
+ │ │ └── math_helper_tool.rb
267
+ │ └── agents/
268
+ │ └── math_tutor_agent.rb
269
+
270
+ └── README.md
271
+ ```
272
+
273
+ **`lib/tools/math_helper_tool.rb`:**
274
+ ```ruby
275
+ require 'legate/tool'
276
+
277
+ class MathHelperTool < Legate::Tool
278
+ tool_description 'Explains math concepts step by step'
279
+
280
+ parameter :problem, type: :string, required: true,
281
+ description: 'The math problem or concept to explain'
282
+
283
+ private
284
+
285
+ def perform_execution(params, context)
286
+ { status: :success, result: "Let me explain: #{params[:problem]}" }
287
+ end
288
+ end
289
+
290
+ Legate::GlobalToolManager.register_tool(MathHelperTool)
291
+ ```
292
+
293
+ **`lib/agents/math_tutor_agent.rb`:**
294
+ ```ruby
295
+ require 'legate'
296
+
297
+ definition = Legate::AgentDefinition.new.define do |a|
298
+ a.name :math_tutor
299
+ a.description 'A patient math tutor that explains concepts'
300
+ a.instruction 'You are a patient math tutor. Use the math_helper_tool to explain concepts.'
301
+ a.use_tool :math_helper_tool
302
+ a.use_tool :calculator
303
+ a.model_name 'gemini-2.0-flash'
304
+ end
305
+
306
+ Legate::GlobalDefinitionRegistry.register(definition)
307
+ ```
308
+
309
+ **Start the server:**
310
+ ```bash
311
+ cd my_legate_project
312
+ bundle install
313
+ bundle exec legate web start
314
+ ```
315
+
316
+ Your math tutor agent will automatically appear in the Web UI!
317
+
318
+ ## Related Documentation
319
+
320
+ - [AI Code Generators](ai_code_generators) - Generate tools and agents with AI
321
+ - [Built-in Tools](../tools/legate_built_in_tools) - Available built-in tools
322
+ - [Agent Lifecycle](../core_concepts/legate_agent_lifecycle) - How agents work
323
+
324
+
325
+
326
+
@@ -0,0 +1,219 @@
1
+ # Configuring an Agent for Inbound Webhooks
2
+
3
+ This guide details how to configure a specific Legate Agent Definition to be triggered by external systems using the Legate's inbound webhook feature.
4
+
5
+ **Prerequisite:** Ensure the Legate Webhook Listener and the Dynamic Agent Handler are enabled in your global Legate configuration. See the main [`webhooks`](./webhooks) documentation for details on setting up `Legate.configure`:
6
+
7
+ ```ruby
8
+ # config/initializers/legate.rb (or similar)
9
+ Legate.configure do |config|
10
+ config.webhooks.listener_enabled = true
11
+ config.webhooks.enable_dynamic_agent_handler = true
12
+ # ... other listener settings (port, base_path) ...
13
+ end
14
+ ```
15
+
16
+ With the dynamic handler enabled (defaulting to the route `/agents/:agent_name/trigger` under the configured `base_path`), you can configure individual agents to respond to requests matching this pattern.
17
+
18
+ ## Agent Definition Webhook Metadata
19
+
20
+ To make an agent triggerable via the dynamic route, you must define specific metadata within its definition block (`Legate::Agent.define do |a| ... end`).
21
+
22
+ ### 1. Enable Webhook Triggering (`webhook_enabled`)
23
+
24
+ This is the master switch for exposing the agent via the dynamic webhook route.
25
+
26
+ * **Required:** Yes, if you want the agent triggerable by webhook.
27
+ * **Type:** Boolean
28
+ * **Default:** `false`
29
+
30
+ ```ruby
31
+ Legate::Agent.define do |a|
32
+ a.name :my_webhook_enabled_agent
33
+ # ... other config ...
34
+
35
+ a.webhook_enabled true # MUST be true
36
+ end
37
+ ```
38
+
39
+ If `webhook_enabled` is not explicitly set to `true`, requests targeting this agent via the dynamic route will result in a `404 Not Found` response.
40
+
41
+ ### 2. Define Payload Transformation (`webhook_transformer`)
42
+
43
+ This Proc defines how the incoming webhook request payload is converted into the `user_input` expected by your agent's `run_task` method.
44
+
45
+ * **Required:** Yes, if `webhook_enabled` is `true`.
46
+ * **Type:** `Proc` (or Lambda)
47
+ * **Signature:** `lambda { |request_body| }`
48
+ * `request_body`: The parsed request body (typically a Hash if the request Content-Type was `application/json`, otherwise the raw String body).
49
+ * **Return Value:** The `String` or `Hash` that will be passed as the `user_input` parameter to `agent.run_task` by the background worker.
50
+ * **Error Handling:** If the payload is invalid or missing expected data, the Proc should raise an `Legate::WebhookConfigurationError` with a descriptive message. This will cause the listener to return a `400 Bad Request`.
51
+
52
+ ```ruby
53
+ Legate::Agent.define do |a|
54
+ # ... name, webhook_enabled true ...
55
+
56
+ a.webhook_transformer ->(request_body) do
57
+ # Example: Expecting JSON: { "event_type": "...", "data": { ... } }
58
+ event_type = request_body['event_type']
59
+ event_data = request_body['data']
60
+
61
+ unless event_type && event_data
62
+ raise Legate::WebhookConfigurationError, "Payload missing 'event_type' or 'data'."
63
+ end
64
+
65
+ # Construct the input for the agent task
66
+ "Process event '#{event_type}' with data: #{event_data.to_json}"
67
+ end
68
+ end
69
+ ```
70
+
71
+ ### 3. Define Session ID Extraction (`webhook_session_extractor`)
72
+
73
+ This Proc determines the `session_id` to use for the agent task triggered by the webhook. This allows grouping related events into the same agent conversation history.
74
+
75
+ * **Required:** Yes, if `webhook_enabled` is `true`.
76
+ * **Type:** `Proc` (or Lambda)
77
+ * **Signature:** `lambda { |request_body| }`
78
+ * `request_body`: The parsed request body (Hash or String).
79
+ * **Return Value:** A non-empty `String` representing the `session_id`.
80
+ * **Error Handling:** If a suitable ID cannot be extracted, raise `Legate::WebhookConfigurationError`. This results in a `400 Bad Request`.
81
+
82
+ ```ruby
83
+ Legate::Agent.define do |a|
84
+ # ... name, webhook_enabled true, transformer ...
85
+
86
+ a.webhook_session_extractor ->(request_body) do
87
+ # Example: Use a resource ID from the payload
88
+ resource_id = request_body.dig('resource', 'id')
89
+ unless resource_id.is_a?(String) && !resource_id.empty?
90
+ raise Legate::WebhookConfigurationError, "Missing or invalid 'resource.id' in payload."
91
+ end
92
+ "resource_session_#{resource_id}" # e.g., "resource_session_proj-abc-123"
93
+ end
94
+ end
95
+ ```
96
+
97
+ ### 4. Configure Validation (`webhook_validator`)
98
+
99
+ Specify how incoming requests should be validated for authenticity. This is highly recommended.
100
+
101
+ * **Required:** No (but strongly recommended).
102
+ * **Type:** `Symbol` (referencing a globally registered validator) or `Proc` (for custom logic).
103
+ * **Default:** `nil` (no validation applied unless a global validator is configured).
104
+
105
+ **Option A: Using a Named Global Validator**
106
+
107
+ First, register a validator globally (see `webhooks.md`):
108
+
109
+ ```ruby
110
+ # config/initializers/legate.rb
111
+ Legate.configure do |config|
112
+ # ...
113
+ config.webhooks.register_validator(:hmac_sha256) do |request, secret|
114
+ # ... HMAC validation logic using request and secret ...
115
+ end
116
+ end
117
+ ```
118
+
119
+ Then, reference it in the agent definition:
120
+
121
+ ```ruby
122
+ Legate::Agent.define do |a|
123
+ # ... name, webhook_enabled true, transformer, extractor ...
124
+
125
+ a.webhook_validator :hmac_sha256 # Use the named validator
126
+ a.webhook_secret ENV['MY_AGENT_WEBHOOK_SECRET'] # Provide the secret for this agent
127
+ end
128
+ ```
129
+
130
+ **Option B: Providing a Custom Proc**
131
+
132
+ Define the validation logic directly within the agent definition.
133
+
134
+ ```ruby
135
+ Legate::Agent.define do |a|
136
+ # ... name, webhook_enabled true, transformer, extractor ...
137
+
138
+ a.webhook_validator ->(request, secret) do
139
+ # Example: Check for a specific token in headers or params
140
+ # 'secret' here is the value from a.webhook_secret below
141
+ request.params['auth_token'] == secret || request.env['HTTP_X_AUTH_TOKEN'] == secret
142
+ end
143
+ a.webhook_secret ENV['MY_AGENT_AUTH_TOKEN']
144
+ end
145
+ ```
146
+
147
+ * **Validator Proc Signature:** `lambda { |request, secret| }`
148
+ * `request`: The full Rack request object.
149
+ * `secret`: The value defined by `a.webhook_secret` (or `nil`).
150
+ * **Return Value:** `true` if valid, `false` otherwise.
151
+ * **Error Handling:** If validation fails (returns `false`), the listener returns a `401 Unauthorized` response. If the validator Proc itself raises an error, a `500 Internal Server Error` is returned.
152
+
153
+ ### 5. Provide Validation Secret (`webhook_secret`)
154
+
155
+ Provides the secret key or token needed by the configured `webhook_validator`.
156
+
157
+ * **Required:** Only if the chosen validator logic requires a secret.
158
+ * **Type:** `String`
159
+ * **Default:** `nil`
160
+
161
+ ```ruby
162
+ Legate::Agent.define do |a|
163
+ # ... name, webhook_enabled true, transformer, extractor, validator ...
164
+
165
+ # Use environment variables for secrets!
166
+ a.webhook_secret ENV['MY_AGENT_WEBHOOK_SECRET']
167
+ end
168
+ ```
169
+
170
+ ## Example: Fully Configured Agent
171
+
172
+ ```ruby
173
+ # app/agents/github_issue_agent.rb
174
+ require 'legate'
175
+ require 'json'
176
+ require 'openssl' # Needed if validator uses it
177
+
178
+ Legate::Agent.define do |a|
179
+ a.name :github_issue_agent
180
+ a.description "Processes updates for GitHub issues via webhooks."
181
+ a.instruction "Analyze the GitHub issue event and associated data."
182
+ # ... add tools, model ...
183
+
184
+ # -- Webhook Settings --
185
+ a.webhook_enabled true
186
+ a.webhook_validator :hmac_sha256 # Assumes :hmac_sha256 is registered globally
187
+ a.webhook_secret ENV['GITHUB_ISSUE_WEBHOOK_SECRET']
188
+
189
+ a.webhook_session_extractor ->(payload) do
190
+ issue_id = payload.dig('issue', 'id')
191
+ repo_id = payload.dig('repository', 'id')
192
+ unless issue_id && repo_id
193
+ raise Legate::WebhookConfigurationError, "Missing issue or repository ID in payload."
194
+ end
195
+ "github_issue_#{repo_id}_#{issue_id}"
196
+ end
197
+
198
+ a.webhook_transformer ->(payload) do
199
+ action = payload['action']
200
+ issue_title = payload.dig('issue', 'title')
201
+ issue_body = payload.dig('issue', 'body')
202
+ sender = payload.dig('sender', 'login')
203
+
204
+ unless action && issue_title && sender
205
+ raise Legate::WebhookConfigurationError, "Missing required fields (action, issue.title, sender.login)."
206
+ end
207
+
208
+ # Return a hash as input for the agent task
209
+ {
210
+ event_type: "github_issue_#{action}",
211
+ title: issue_title,
212
+ body: issue_body,
213
+ triggered_by: sender
214
+ }
215
+ end
216
+ end
217
+ ```
218
+
219
+ By defining this metadata, your agent can securely and reliably be triggered by external webhook events, leveraging the Legate's asynchronous processing capabilities.