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,288 @@
1
+ # Using Inbound Webhooks in Legate
2
+
3
+ This document explains how to configure and use the inbound webhook feature in the Legate framework to trigger agent tasks from external systems.
4
+
5
+ ## Goal
6
+
7
+ The primary goal of this feature is to allow external events (e.g., Git pushes, CI/CD notifications, CRM updates, IoT alerts) to initiate specific agent workflows asynchronously without requiring direct code integration or constantly running agent processes.
8
+
9
+ ## Architecture Overview
10
+
11
+ The following diagram illustrates the flow of an inbound webhook request triggering an agent task:
12
+
13
+ ```mermaid
14
+ graph LR
15
+ Ext[External System] -- HTTP Request --> Listen[Webhook Listener]
16
+ Listen -- Raw Request --> Router
17
+ Router -- Route Match --> Handler[Dynamic Agent Handler]
18
+ Handler -- Load Definition & Metadata --> Store[(Agent Definition Store)]
19
+ Handler -- Validation/Transform/Extract --> ThreadPool[Threaded Execution]
20
+ ThreadPool -- Concurrent::Promises.future --> AgentExec[Agent Execution]
21
+ AgentExec -- Load Definition --> Store
22
+ AgentExec -- Get Session --> SessionSvc[(Session Service)]
23
+ AgentExec -- Instantiate Agent --> AgentDef[Agent Definition]
24
+ AgentDef -- Uses --> SessionSvc
25
+ AgentExec -- Calls run_task --> AgentInst[Agent Instance]
26
+ AgentInst -- Logs Events --> SessionSvc
27
+ AgentInst -- Task Result --> AgentExec
28
+ AgentExec -- Logs Outcome --> Log[(Logs)]
29
+
30
+ subgraph "Webhook Listener Process"
31
+ Listen
32
+ Router
33
+ Handler
34
+ end
35
+
36
+ subgraph "In-Process Threaded Execution"
37
+ AgentExec
38
+ AgentInst
39
+ Log
40
+ end
41
+
42
+ style Store fill:#f9f,stroke:#333,stroke-width:2px
43
+ style SessionSvc fill:#f9f,stroke:#333,stroke-width:2px
44
+ style JobQueue fill:#ccf,stroke:#333,stroke-width:2px
45
+ ```
46
+
47
+ **Key Components:**
48
+
49
+ * **Webhook Listener:** Receives HTTP requests, performs initial routing.
50
+ * **Dynamic Agent Handler:** Looks up agent definitions, validates, transforms, extracts session IDs based on agent metadata, and enqueues jobs.
51
+ * **Threaded Execution (`Concurrent::Promises.future`):** Runs webhook tasks asynchronously in background threads within the same process.
52
+ * **Agent Execution:** Loads definitions, instantiates agents, interacts with the Session Service, and executes `agent.run_task`.
53
+ * **Agent Definition Store:** Stores agent configurations, including webhook metadata.
54
+ * **Session Service:** Manages agent conversation state.
55
+
56
+ ## Enabling the Webhook Listener
57
+
58
+ To receive webhooks, you first need to enable the built-in listener application within your Legate configuration (e.g., in `config/initializers/legate.rb` or your main setup file).
59
+
60
+ ```ruby
61
+ # config/initializers/legate.rb or similar
62
+ require 'legate'
63
+
64
+ Legate.configure do |config|
65
+ # --- Enable the listener ---
66
+ config.webhooks.listener_enabled = true
67
+
68
+ # --- Optional Listener Settings ---
69
+ # Address to bind to (default: '127.0.0.1')
70
+ # Use '0.0.0.0' to listen on all interfaces (common for containers/production)
71
+ config.webhooks.listen_address = "0.0.0.0"
72
+
73
+ # Port to listen on (default: 9292)
74
+ config.webhooks.listen_port = 9293
75
+
76
+ # Base path for all webhook routes (default: '/webhooks')
77
+ config.webhooks.base_path = "/myhooks"
78
+
79
+ # ... other Legate configurations ...
80
+ end
81
+ ```
82
+
83
+ When `listener_enabled` is `true`, the `legate web start` command will automatically mount the listener alongside the main Web UI (in development/test environments). For production, see the Deployment section.
84
+
85
+ ## Triggering Agents via Webhook
86
+
87
+ The recommended way to trigger specific agents is using the dynamic agent route handler.
88
+
89
+ ### Enabling the Dynamic Handler
90
+
91
+ Enable the dynamic route in your Legate configuration:
92
+
93
+ ```ruby
94
+ Legate.configure do |config|
95
+ config.webhooks.listener_enabled = true
96
+ # ... other listener settings ...
97
+
98
+ # --- Enable the dynamic route ---
99
+ config.webhooks.enable_dynamic_agent_handler = true
100
+
101
+ # --- Optional: Customize the route pattern ---
102
+ # The default pattern includes :agent_name parameter.
103
+ # config.webhooks.dynamic_agent_route_pattern = '/invoke/:agent_name' # Example override
104
+
105
+ # ... other Legate configurations ...
106
+ end
107
+ ```
108
+
109
+ With the default settings (`base_path = '/webhooks'`, `dynamic_agent_route_pattern = '/agents/:agent_name/trigger'`), you can trigger an agent named `:my_cool_agent` by sending a `POST` request to:
110
+
111
+ `POST /webhooks/agents/my_cool_agent/trigger`
112
+
113
+ ### Configuring an Agent to Receive Webhooks
114
+
115
+ For an agent to be triggerable via the dynamic route, you **must** configure specific metadata within its definition:
116
+
117
+ ```ruby
118
+ # app/agents/my_webhook_agent.rb (or loaded via DefinitionStore)
119
+ require 'legate'
120
+
121
+ Legate::Agent.define do |a|
122
+ a.name :my_webhook_agent
123
+ a.description "Processes incoming data from external service X."
124
+ a.instruction "Summarize the provided data."
125
+ # ... other agent settings (tools, model) ...
126
+
127
+ # --- Webhook Configuration Metadata ---
128
+
129
+ # 1. Enable Webhook Triggering (REQUIRED)
130
+ # MUST be true for the dynamic route to work for this agent.
131
+ a.webhook_enabled true
132
+
133
+ # 2. Define Payload Transformation (REQUIRED if enabled)
134
+ # A Proc that takes the parsed request body (Hash/Array) and returns
135
+ # the specific String or Hash expected by this agent's `run_task` `user_input`.
136
+ a.webhook_transformer ->(request_body) do
137
+ # Example: Extract data from a specific key
138
+ data = request_body['important_data']
139
+ unless data
140
+ # You can raise errors for invalid payloads
141
+ raise Legate::WebhookConfigurationError, "Missing 'important_data' in webhook payload."
142
+ end
143
+ "Summarize this: #{data}" # Return the user_input for run_task
144
+ end
145
+
146
+ # 3. Define Session ID Extraction (REQUIRED if enabled)
147
+ # A Proc that takes the parsed request body and returns a String
148
+ # to be used as the session_id for this task.
149
+ # Allows grouping related events (e.g., multiple events for the same resource).
150
+ a.webhook_session_extractor ->(request_body) do
151
+ # Example: Use a resource ID from the payload
152
+ resource_id = request_body.dig('resource', 'id')
153
+ raise Legate::WebhookConfigurationError, "Missing resource ID in payload." unless resource_id
154
+ "external_resource_#{resource_id}" # Return the session_id string
155
+ end
156
+
157
+ # 4. Configure Validation (Optional, but Recommended)
158
+ # Option A: Use a globally registered named validator (see below)
159
+ a.webhook_validator :hmac_sha256
160
+ # Option B: Provide a custom Proc directly
161
+ # a.webhook_validator ->(request, secret) { request.params['token'] == secret }
162
+
163
+ # 5. Provide a Secret for the Validator (Optional)
164
+ # Used by the validator logic (e.g., the HMAC key or the token).
165
+ a.webhook_secret ENV['MY_SERVICE_X_WEBHOOK_SECRET']
166
+ end
167
+ ```
168
+
169
+ **Key Requirements:**
170
+ * `webhook_enabled` **must** be set to `true`.
171
+ * `webhook_transformer` Proc **must** be defined.
172
+ * `webhook_session_extractor` Proc **must** be defined.
173
+
174
+ If these are not met, the dynamic route handler will return an error (likely 404 or 500) when a request for that agent is received.
175
+
176
+ ## Request Validation
177
+
178
+ It's highly recommended to validate incoming webhooks to ensure they originate from the expected source.
179
+
180
+ ### Using Named Validators (HMAC Example)
181
+
182
+ You can define reusable validation logic globally in your Legate configuration and reference it by name in your agent definitions.
183
+
184
+ > **Note:** Legate already ships with a built-in `:hmac_sha256` validator (registered automatically), so you can reference `a.webhook_validator :hmac_sha256` without defining it yourself. The example below shows how an equivalent validator is implemented if you want to register your own.
185
+
186
+ ```ruby
187
+ # config/initializers/legate.rb or similar
188
+ require 'openssl'
189
+
190
+ Legate.configure do |config|
191
+ # ... listener config ...
192
+ config.webhooks.enable_dynamic_agent_handler = true
193
+
194
+ # --- Define a named HMAC SHA256 validator ---
195
+ config.webhooks.register_validator(:hmac_sha256) do |request, secret|
196
+ # Ensure a secret is configured for the agent/route
197
+ return false unless secret
198
+ # GitHub example: X-Hub-Signature-256: sha256=...
199
+ signature_header = request.env['HTTP_X_HUB_SIGNATURE_256']
200
+ return false unless signature_header&.start_with?('sha256=')
201
+
202
+ expected_signature = signature_header.delete_prefix('sha256=')
203
+
204
+ request.body.rewind # Read body for calculation
205
+ payload_body = request.body.read
206
+ request.body.rewind # Rewind for transformer
207
+
208
+ calculated_signature = OpenSSL::HMAC.hexdigest('sha256', secret, payload_body)
209
+
210
+ # Compare in constant time to prevent timing attacks. A length check is
211
+ # required first because OpenSSL.fixed_length_secure_compare raises on
212
+ # unequal-length inputs.
213
+ calculated_signature.bytesize == expected_signature.bytesize &&
214
+ OpenSSL.fixed_length_secure_compare(calculated_signature, expected_signature)
215
+ end
216
+
217
+ # Optional: Define a global secret if many agents share one
218
+ # config.webhooks.global_secret = ENV['LEGATE_GLOBAL_WEBHOOK_SECRET']
219
+
220
+ # Optional: Set a default validator if an agent doesn't define one
221
+ # config.webhooks.global_validator = :hmac_sha256
222
+ end
223
+ ```
224
+
225
+ Then, in your agent definition, reference the validator and provide the secret:
226
+
227
+ ```ruby
228
+ Legate::Agent.define do |a|
229
+ # ... name, description, transformer, extractor ...
230
+ a.webhook_enabled true
231
+ a.webhook_validator :hmac_sha256 # Use the named validator
232
+ a.webhook_secret ENV['SPECIFIC_AGENT_WEBHOOK_SECRET'] # Provide the secret
233
+ end
234
+ ```
235
+
236
+ ### Using Custom Validator Procs
237
+
238
+ For unique validation logic, provide a Proc directly in the agent definition:
239
+
240
+ ```ruby
241
+ Legate::Agent.define do |a|
242
+ # ... name, description, transformer, extractor ...
243
+ a.webhook_enabled true
244
+ a.webhook_validator ->(request, secret) do
245
+ # Example: Check a query parameter against the secret
246
+ request.params['auth_token'] == secret
247
+ end
248
+ a.webhook_secret ENV['AGENT_AUTH_TOKEN']
249
+ end
250
+ ```
251
+
252
+ The validator proc receives the Rack `request` object and the configured `secret` string (or `nil` if none is set).
253
+
254
+ ## Workflow Overview
255
+
256
+ 1. **External System** sends `POST /webhooks/agents/agent_name/trigger` with a JSON payload.
257
+ 2. **WebhookListener** receives the request.
258
+ 3. **Dynamic Handler** matches the route pattern (`/agents/:agent_name/trigger`).
259
+ 4. Handler loads the `:agent_name` **Agent Definition**.
260
+ 5. Checks `webhook_enabled` (must be `true`).
261
+ 6. Performs **Validation** using `webhook_validator` and `webhook_secret`.
262
+ 7. If valid, performs **Transformation** using `webhook_transformer` to get `user_input`.
263
+ 8. Extracts **Session ID** using `webhook_session_extractor`.
264
+ 9. Constructs a **Job Payload** (`agent_name`, `session_id`, `user_input`, session service config).
265
+ 10. Dispatches the task via `Concurrent::Promises.future` for **threaded execution**.
266
+ 11. Listener returns **`202 Accepted`** to the external system.
267
+ 12. The background thread instantiates the **Session Service**.
268
+ 13. The thread loads the **Agent Definition**.
269
+ 14. The thread instantiates the **Agent** using the definition.
270
+ 15. The thread calls `agent.run_task(session_id:, user_input:, session_service:)`.
271
+ 16. `run_task` executes the agent logic (planning, tool use).
272
+ 17. The thread logs the outcome.
273
+
274
+ ## Security Considerations
275
+
276
+ * **HTTPS:** Always serve the webhook listener over HTTPS in production.
277
+ * **Secret Management:** Use environment variables or a secure secret management system for `webhook_secret` values. Never hardcode secrets.
278
+ * **Validation:** Strongly recommend validation (e.g., HMAC) for all webhooks triggering actions or handling sensitive data.
279
+ * **Input Sanitization:** Be mindful of how the `transformed_user_input` is used within your agent's instructions and tools to prevent potential injection issues.
280
+ * **Rate Limiting:** Consider adding rate limiting middleware (e.g., `rack-attack`) in front of the listener endpoint to prevent abuse.
281
+
282
+ ## Deployment
283
+
284
+ * **Development:** Run `bundle exec legate web start`. If `listener_enabled` is true, the listener will be mounted automatically within the main web server process.
285
+ * **Production:**
286
+ * You can continue running the combined app as in development.
287
+ * Alternatively, for better isolation and scaling, you can create a separate `config.ru` and Procfile entry to run the `Legate::Web::WebhookListener` Rack app as a standalone process using a server like Puma or Unicorn.
288
+ * Webhook jobs run in-process via background threads using `Concurrent::Promises.future`, so no separate worker process is needed.
@@ -0,0 +1,51 @@
1
+ # Welcome to the Legate Documentation
2
+
3
+ Legate — AI Agent Framework for Ruby — is a comprehensive framework designed to simplify the creation, management, and deployment of sophisticated AI agents. Whether you're building simple task-oriented bots or complex, multi-tool agents capable of intricate planning, the Legate provides the foundational components and a streamlined workflow to accelerate your development process.
4
+
5
+ This documentation will guide you through understanding the core principles of Legate, setting up your development environment, utilizing its built-in features, and extending its capabilities to suit your specific needs.
6
+
7
+ ## What is Legate?
8
+
9
+ Legate is a Ruby-based toolkit that empowers developers to:
10
+
11
+ * **Define Agent Capabilities:** Easily specify an agent's instructions, the tools it can use, the AI model it leverages (e.g., from Google's Gemini family), and its operational parameters.
12
+ * **Manage Agent Lifecycle:** Control how agents are started, how they process tasks, and how they are stopped or updated.
13
+ * **Utilize a Rich Toolset:** Leverage a variety of built-in tools (like calculators, webhooks, and even tools that delegate tasks to other agents) or create your own custom tools.
14
+ * **Handle Complex Interactions:** Employ a planner that enables agents to break down complex requests into a sequence of tool calls.
15
+ * **Persist and Manage State:** Use session services and definition stores to manage conversational history and agent configurations.
16
+ * **Integrate with External Systems:** Expose agents via web UIs, connect them to messaging platforms, or trigger them with webhooks.
17
+ * **Deploy with Ease:** Generate deployment assets (like Dockerfiles and cloud configuration scripts) to run your Legate applications in various environments.
18
+
19
+ ## Getting Started
20
+
21
+ To begin your journey with Legate, we recommend the following steps:
22
+
23
+ 1. **Understand the Fundamentals:** Familiarize yourself with the [Core Concepts](./core_concepts/legate_architecture_overview) that underpin the Legate, such as the [Agent Lifecycle](./core_concepts/legate_agent_lifecycle), [Tools and Registry](./tools/legate_tools_and_registry), and [Session Management](./core_concepts/legate_session_service).
24
+ 2. **Setup Your Environment:** Ensure you have Ruby and Bundler installed. Most Legate projects will start by adding `legate` to their `Gemfile`.
25
+ 3. **Explore the Configuration:** Learn how to configure Legate globally and per agent by reviewing the [Legate Configuration](./core_concepts/legate_configuration) guide.
26
+ 4. **Try the CLI:** Use the [Legate Command-Line Interface](./cli/legate_cli_usage) to manage agent definitions, run the web UI, and interact with other Legate components.
27
+ 5. **Run an Example:** Browse the [Examples Guide](./examples) for 16 hands-on examples covering every major feature, from basic agents to MCP integration.
28
+
29
+ ## Key Features
30
+
31
+ * **Modular Architecture:** Easily extendable and customizable.
32
+ * **Powerful Planner:** Enables multi-step reasoning and tool usage.
33
+ * **Rich Tool Ecosystem:** Comes with several built-in tools and a clear interface for adding new ones.
34
+ * **Agent Definition Store:** Persistently store and manage your agent configurations.
35
+ * **Session Management:** Track conversation history and agent state.
36
+ * **Web UI:** A built-in Sinatra application for managing agents and viewing sessions.
37
+ * **CLI for Management:** Robust command-line tools for development and administration.
38
+ * **Deployment Assistance:** Tools to generate Dockerfiles and deployment scripts.
39
+
40
+ ## Navigating these Docs
41
+
42
+ This documentation is organized into several key areas:
43
+
44
+ * **[Core Concepts](./core_concepts/):** Deep dives into the fundamental building blocks and architecture of Legate.
45
+ * **[Guides](./guides/):** Practical step-by-step instructions for common tasks and integrations.
46
+ * **[CLI Reference](./cli/legate_cli_usage):** Detailed information on using the `legate` command-line tool.
47
+ * **[Web UI Overview](./web_ui/legate_web_ui):** Information about the built-in web interface.
48
+ * **[Built-in Tools Reference](./tools/legate_built_in_tools):** Documentation for the tools that come packaged with Legate.
49
+ * **[Error Handling](./error_handling/legate_error_handling):** Guidance on understanding and managing errors within Legate.
50
+
51
+ We hope this documentation helps you build amazing AI agents with Legate!
@@ -0,0 +1,57 @@
1
+ # Advanced Features
2
+
3
+ ## Agent Delegation
4
+
5
+ Agents can dynamically delegate tasks to other specialized agents during execution. This allows an agent to "ask for help" or hand off a sub-task.
6
+
7
+ ### Configuration
8
+
9
+ Use `can_delegate_to` to specify which agents are available for delegation.
10
+
11
+ ```ruby
12
+ Legate::Agent.define do |agent|
13
+ agent.name :manager
14
+ agent.instruction "Manage the project and delegate tasks."
15
+
16
+ # Allow delegation to these agents
17
+ agent.can_delegate_to :researcher, :coder
18
+ end
19
+ ```
20
+
21
+ ### How it Works
22
+
23
+ 1. **Planning**: The `Legate::Planner` sees the available delegation targets as "tools" (e.g., `agent_transfer_to_researcher`).
24
+ 2. **Execution**: If the agent decides to delegate, it invokes the delegation tool.
25
+ 3. **Transfer**: The `Legate::Agent` intercepts this call and executes the target agent with the specified task.
26
+ 4. **Session Reuse**: `can_delegate_to` / `Agent#transfer_to` delegation **reuses the calling session** — the same `session_id` is passed to the target agent, so both agents share session state. It does *not* create a new isolated session.
27
+
28
+ ### Delegation vs. `AgentTool`
29
+
30
+ A separate mechanism, the `AgentTool` (registered as the `:delegate_task` tool), runs another agent from within a tool call. Unlike `transfer_to`, `AgentTool` defaults to a **new isolated session**. It exposes a `use_calling_session` parameter (default `false`) that, when set to `true`, makes it reuse the caller's session and share state instead.
31
+
32
+ ## Callbacks
33
+
34
+ You can hook into the agent's lifecycle to execute custom logic.
35
+
36
+ ```ruby
37
+ Legate::Agent.define do |agent|
38
+ # ...
39
+
40
+ agent.before_agent_callback do |context|
41
+ Legate.logger.info "Agent starting for session #{context.session_id}"
42
+ end
43
+
44
+ agent.after_tool_callback do |tool, params, context, result|
45
+ # Modify result or log execution
46
+ Legate.logger.info "Tool #{tool.name} executed."
47
+ end
48
+ end
49
+ ```
50
+
51
+ Available callbacks:
52
+ - `before_agent_callback`
53
+ - `after_agent_callback`
54
+ - `before_model_callback`
55
+ - `after_model_callback`
56
+ - `before_tool_callback`
57
+ - `after_tool_callback`
@@ -0,0 +1,190 @@
1
+ # Agent Delegation in Legate
2
+
3
+ ## Overview
4
+
5
+ Agent delegation is a powerful feature in Legate that allows one agent to dynamically transfer control to another specialized agent during execution. This enables complex workflows where a coordinator agent can make decisions about which specialized agent should handle a particular task.
6
+
7
+ Unlike the `AgentTool` approach, which creates a new isolated session for the target agent, delegation maintains the same session context. This ensures continuity and allows agents to share state through the session.
8
+
9
+ ## Key Concepts
10
+
11
+ ### Delegation Targets
12
+
13
+ For an agent to delegate to another agent, the target agents must be explicitly defined as "delegation targets" in the delegating agent's definition:
14
+
15
+ ```ruby
16
+ coordinator_agent = Legate::Agent.define do |a|
17
+ a.name :coordinator_agent
18
+ a.description 'A coordinator agent that delegates tasks'
19
+ a.instruction 'You are a coordinator. Analyze tasks and delegate to specialists.'
20
+
21
+ # Define which agents this agent can delegate to
22
+ a.can_delegate_to :math_agent, :research_agent, :translation_agent
23
+
24
+ # ... other configuration ...
25
+ end
26
+ ```
27
+
28
+ ### Agent Hierarchy
29
+
30
+ Delegation works within the agent hierarchy. An agent can:
31
+
32
+ 1. **Delegate to direct sub-agents**: When agents are organized in a parent-child relationship.
33
+ 2. **Delegate to any agent in the hierarchy**: By searching up and down the agent tree.
34
+ 3. **Delegate to registered agents**: Even agents not directly in the hierarchy can be delegated to if their definitions are registered globally.
35
+
36
+ ### Session State Continuity
37
+
38
+ When delegation occurs:
39
+
40
+ - The same session ID is used across all agents
41
+ - The session state is shared, allowing agents to read and write state
42
+ - The `output_key` feature can be used by each agent to store its results in the session state
43
+
44
+ ## Implementation Methods
45
+
46
+ ### 1. LLM-Driven Delegation
47
+
48
+ The primary way delegation happens is through the LLM planner, which can generate plan steps with special "agent_transfer_to_X" tool names:
49
+
50
+ ```json
51
+ {
52
+ "thought_process": "This is a math question, should delegate to math agent",
53
+ "plan": [
54
+ {
55
+ "step": 1,
56
+ "type": "tool_use",
57
+ "tool_name": "agent_transfer_to_math_agent",
58
+ "tool_input": {
59
+ "task": "Calculate the square root of 144"
60
+ },
61
+ "reason": "This is a mathematical calculation"
62
+ }
63
+ ]
64
+ }
65
+ ```
66
+
67
+ When the agent executes this plan, it recognizes the `agent_transfer_to_` prefix and performs delegation to the specified agent.
68
+
69
+ ### 2. Direct Transfer Method
70
+
71
+ You can also programmatically delegate using the `transfer_to` method:
72
+
73
+ ```ruby
74
+ result = agent.transfer_to(
75
+ :math_agent, # Target agent name
76
+ "Calculate 2 + 2", # Task to delegate
77
+ session_id, # Current session ID
78
+ session_service # Session service instance
79
+ )
80
+ ```
81
+
82
+ This returns a standard result hash:
83
+
84
+ ```ruby
85
+ {
86
+ status: :success,
87
+ target_agent: "math_agent",
88
+ result: { status: :success, result: "4" }
89
+ }
90
+ ```
91
+
92
+ ## Code Examples
93
+
94
+ ### Basic Delegation Setup
95
+
96
+ ```ruby
97
+ # Define a math specialist agent
98
+ math_agent = Legate::Agent.define do |a|
99
+ a.name :math_agent
100
+ a.description 'Specialized in calculations'
101
+ a.instruction 'You are a math expert. Solve calculations accurately.'
102
+ a.use_tool :calculate
103
+ a.output_key :calculation_result
104
+ end
105
+
106
+ # Define a coordinator that can delegate to the math agent
107
+ coordinator = Legate::Agent.define do |a|
108
+ a.name :coordinator
109
+ a.description 'Coordinates tasks between agents'
110
+ a.instruction 'Analyze the task and delegate to specialists.'
111
+ a.can_delegate_to :math_agent
112
+ a.use_tool :echo
113
+ end
114
+
115
+ # Create and link the agents
116
+ coordinator_instance = Legate::Agent.new(definition: coordinator)
117
+ math_instance = Legate::Agent.new(definition: math_agent)
118
+
119
+ # Establish parent-child relationship
120
+ math_instance.instance_variable_set(:@parent_agent, coordinator_instance)
121
+ coordinator_instance.instance_variable_set(:@sub_agents, [math_instance])
122
+
123
+ # Start the agents
124
+ coordinator_instance.start
125
+ math_instance.start
126
+
127
+ # Run a task that might be delegated
128
+ result = coordinator_instance.run_task(
129
+ session_id: session_id,
130
+ user_input: "What is 125 * 45?",
131
+ session_service: session_service
132
+ )
133
+ ```
134
+
135
+ ### Working with Session State
136
+
137
+ ```ruby
138
+ # The delegated agent can store its result in the session state
139
+ math_agent = Legate::Agent.define do |a|
140
+ a.name :math_agent
141
+ a.description 'Specialized in calculations'
142
+ a.instruction 'You are a math expert. Solve calculations accurately.'
143
+ a.use_tool :calculate
144
+ a.output_key :calculation_result # Will store results with this key
145
+ end
146
+
147
+ # Later, another agent can access this result
148
+ translator_agent = Legate::Agent.define do |a|
149
+ a.name :translator_agent
150
+ a.description 'Translates content'
151
+ a.instruction <<~INSTRUCTION
152
+ You are a translator. Translate text using the calculation results
153
+ from the math agent if available in the session state.
154
+ INSTRUCTION
155
+ a.use_tool :translate
156
+ end
157
+ ```
158
+
159
+ ## Comparison: Delegation vs. AgentTool
160
+
161
+ | Feature | Agent Delegation | AgentTool |
162
+ |---------|-----------------|-----------|
163
+ | **Session Context** | Maintains the same session | Creates a new session |
164
+ | **State Sharing** | Shared session state | No state sharing, isolated execution |
165
+ | **Agent Registration** | Uses agent hierarchy and registry | Uses agent definitions from store |
166
+ | **Use Case** | Complex workflows with state continuity | Isolated, independent agent operations |
167
+ | **Implementation** | Direct `transfer_to` or LLM-driven | Tool execution via `tool_registry` |
168
+
169
+ ## Best Practices
170
+
171
+ 1. **Be Specific with Instructions**: Provide clear guidelines in your coordinator agent's instructions about when to delegate and which specialized agent to use for different tasks.
172
+
173
+ 2. **Use `output_key`**: Have specialized agents store their results using the `output_key` feature to make them available in the session state.
174
+
175
+ 3. **Validate Delegation Targets**: Ensure all agents defined in `can_delegate_to` actually exist. The system will warn you about missing targets, but it's best to address these warnings.
176
+
177
+ 4. **Avoid Circular Delegation**: The system prevents direct circular dependencies, but complex cascading delegation chains should be avoided.
178
+
179
+ 5. **Consider Agent Hierarchy**: Organize your agents in a logical hierarchy that reflects your delegation patterns, with coordinator agents at the top and specialists as sub-agents.
180
+
181
+ ## Implementation Details
182
+
183
+ Under the hood, delegation is implemented through:
184
+
185
+ 1. The `agent_transfer_to_` special tool name pattern recognized by `execute_step`
186
+ 2. The `transfer_to` method that handles the delegation logic
187
+ 3. Agent hierarchy navigation through `root_agent` and `find_agent` methods
188
+ 4. Session state persistence across agent boundaries
189
+
190
+ For detailed implementation examples, see `examples/11_agent_delegation.rb` (and `examples/advanced/mas/proper_delegation_example.rb`) in the Legate codebase.
@@ -0,0 +1,49 @@
1
+ # Agent Hierarchy
2
+
3
+ The Legate supports a hierarchical agent structure, allowing agents to be composed of other agents (sub-agents). This enables the creation of complex systems where a parent agent coordinates the work of specialized child agents.
4
+
5
+ ## Core Concepts
6
+
7
+ ### Parent and Sub-Agents
8
+
9
+ - **Parent Agent**: An agent that contains and manages other agents.
10
+ - **Sub-Agent**: An agent that is managed by another agent. A sub-agent can also be a parent to other agents, creating a multi-level hierarchy.
11
+
12
+ ### Definition
13
+
14
+ You can define sub-agents within an `Legate::AgentDefinition` using the `sub_agents_define` DSL method.
15
+
16
+ ```ruby
17
+ Legate::Agent.define do |agent|
18
+ agent.name :parent_agent
19
+ agent.description "A parent agent that manages sub-agents"
20
+ agent.instruction "You are a manager. Delegate tasks to your sub-agents."
21
+
22
+ # Define sub-agents by name
23
+ agent.sub_agents_define :researcher_agent, :writer_agent
24
+ end
25
+ ```
26
+
27
+ The sub-agents must be defined and registered in the `GlobalDefinitionRegistry` so they can be instantiated when the parent agent is initialized.
28
+
29
+ ## Runtime Structure
30
+
31
+ When a parent agent is initialized, it attempts to instantiate its defined sub-agents.
32
+
33
+ - **`agent.sub_agents`**: Returns a collection of initialized sub-agent instances.
34
+ - **`agent.parent_agent`**: Returns the parent agent instance (if any).
35
+ - **`agent.root_agent`**: Returns the top-level agent in the hierarchy.
36
+
37
+ ### Navigation
38
+
39
+ You can navigate the hierarchy at runtime:
40
+
41
+ - **`agent.find_sub_agent(name)`**: Finds a direct sub-agent by name.
42
+ - **`agent.find_agent(name)`**: Finds an agent anywhere in the hierarchy (depth-first search).
43
+
44
+ ## Usage
45
+
46
+ Hierarchies are fundamental to **Workflow Agents** (Sequential, Parallel, Loop) and **Delegation**.
47
+
48
+ - **Workflow Agents**: Use sub-agents as steps in a predefined process.
49
+ - **Delegation**: Uses sub-agents (or other agents in the hierarchy) as targets for dynamic task delegation.
@@ -0,0 +1,47 @@
1
+ # State Management
2
+
3
+ The Legate provides a robust state management system to share data between agents and persist execution context across sessions.
4
+
5
+ ## Session State
6
+
7
+ Every agent execution happens within a `Session`. The session maintains:
8
+ - **Event History**: A log of all interactions (user messages, agent responses, tool calls).
9
+ - **State**: A key-value store for persisting data.
10
+
11
+ ## Output Keys
12
+
13
+ Agents can automatically store their final result into the session state using the `output_key` definition.
14
+
15
+ ```ruby
16
+ Legate::Agent.define do |agent|
17
+ agent.name :researcher
18
+ # ...
19
+ agent.output_key :research_summary # Result will be saved to state key :research_summary
20
+ end
21
+ ```
22
+
23
+ When this agent finishes execution, its result is saved to the session state under `:research_summary`.
24
+
25
+ ## Accessing State
26
+
27
+ ### In Other Agents
28
+ Subsequent agents in a workflow (e.g., in a `SequentialAgent`) can access this state. The Legate automatically injects relevant state information or allows agents to query it.
29
+
30
+ ### In Tools
31
+ Tools can access the session state via the `Legate::ToolContext`.
32
+
33
+ ```ruby
34
+ def perform_execution(params, context)
35
+ # Read from state
36
+ previous_result = context.state_get(:research_summary)
37
+
38
+ # Write to state (pending until tool completion)
39
+ context.state_set(:new_data, "value")
40
+
41
+ # ...
42
+ end
43
+ ```
44
+
45
+ ## Session Service
46
+
47
+ The `Legate::SessionService` (e.g., `InMemory`) handles the actual storage and retrieval of state within the current process.