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,192 @@
1
+ / File: lib/legate/web/views/chat.slim
2
+ / Agent chat / run view — 3 zones: header (name·model·status·sessions) ·
3
+ / transcript + composer · Run Details inspector. HTMX wires preserved.
4
+ - agent_name = @agent_data[:name]
5
+ - is_running = @agent_data[:running]
6
+ - chat_model = (@agent_data[:model] && !@agent_data[:model].to_s.empty?) ? @agent_data[:model] : Legate::Agent::DEFAULT_MODEL
7
+ - configured_tools = @agent_data[:configured_tools] || []
8
+ - sessions_to_list = (@previous_sessions_list || []).reject { |s| @active_session_details && s.id == @active_session_details.id }
9
+
10
+ div#chat_interface_wrapper
11
+ .chat-shell
12
+ .chat-main
13
+ / --- Header bar ---
14
+ .chat-header
15
+ a.chat-back(href="/agents/#{agent_name}" title="Back to agent")
16
+ span.icon
17
+ i.fas.fa-arrow-left
18
+ .chat-header-titles
19
+ h2.chat-agent-name= agent_name
20
+ span.mono-chip.model-chip(title="Language model")
21
+ span.icon.is-small
22
+ i.fas.fa-microchip
23
+ span= chat_model
24
+ .chat-header-actions
25
+ div#agent-chat-panel-status-display
26
+ p
27
+ span.tag.is-rounded class=(is_running ? 'is-success' : 'is-danger')
28
+ = is_running ? 'Running' : 'Stopped'
29
+ button.chat-new-session-btn#start-new-chat-button(hx-post="/agents/#{agent_name}/chat/session/new" hx-target="#chat_interface_wrapper" hx-indicator="#start-new-chat-button")
30
+ span.icon.is-small
31
+ i.fas.fa-plus
32
+ span New Session
33
+ span.icon.is-small.htmx-indicator
34
+ i.fas.fa-spinner.fa-pulse
35
+ .dropdown.is-right.chat-sessions-dropdown(_="on click toggle .is-active on the closest .dropdown")
36
+ .dropdown-trigger
37
+ button.chat-sessions-btn(type="button" aria-haspopup="true")
38
+ span.icon.is-small
39
+ i.fas.fa-clock-rotate-left
40
+ span Sessions
41
+ span.icon.is-small
42
+ i.fas.fa-angle-down
43
+ .dropdown-menu(role="menu")
44
+ .dropdown-content
45
+ - if @active_session_details
46
+ .chat-session-current
47
+ .chat-session-line
48
+ span.chat-session-tag Current session
49
+ form(hx-delete="/agents/#{agent_name}/chat/session/#{@active_session_details.id}" hx-target="#chat_interface_wrapper" hx-confirm="Delete this chat session? This cannot be undone.")
50
+ button.chat-session-del(type="submit" title="Delete session")
51
+ i.fas.fa-trash-alt
52
+ p.chat-session-summary= summarize_session(@active_session_details)
53
+ - if sessions_to_list.any?
54
+ hr.dropdown-divider
55
+ - sessions_to_list.each do |session_item|
56
+ form.chat-session-switch(hx-post="/agents/#{agent_name}/chat/session/switch" hx-target="#chat_interface_wrapper")
57
+ input type="hidden" name="legate_session_to_switch_to" value="#{session_item.id}"
58
+ button.chat-session-switch-btn(type="submit")
59
+ span.icon.is-small
60
+ i.fas.fa-comment-dots
61
+ span= summarize_session(session_item)
62
+ - elsif !@active_session_details
63
+ p.dropdown-item.has-text-grey No previous sessions.
64
+
65
+ / Session operation error display (hidden until HTMX swaps an error in)
66
+ div#session-operation-error.notification.is-danger.is-hidden.mb-3
67
+
68
+ / --- Transcript ---
69
+ #chat-log-container.chat-transcript(
70
+ hx-on::after-swap="this.scrollTop = this.scrollHeight"
71
+ _="init set my scrollTop to my scrollHeight end"
72
+ )
73
+ - if @chat_history_events && !@chat_history_events.empty?
74
+ - @chat_history_events.each do |event|
75
+ - if event.role == :user
76
+ .message.is-link.is-small.mb-2.user-message(id="event-#{event.event_id}")
77
+ .message-header
78
+ p You
79
+ .message-body= event.content
80
+ - elsif event.role == :agent
81
+ - agent_response_content = event.content
82
+ - is_complex_content = (agent_response_content.is_a?(Hash) && agent_response_content.key?(:status)) || (agent_response_content.is_a?(Array) && agent_response_content.first.is_a?(Hash) && agent_response_content.first.key?(:status))
83
+ - msg_class = 'is-light'
84
+ - if is_complex_content
85
+ - status = agent_response_content.is_a?(Array) ? agent_response_content.first[:status] : agent_response_content[:status]
86
+ - case status
87
+ - when :error
88
+ - msg_class = 'is-danger'
89
+ - when :pending
90
+ - msg_class = 'is-warning'
91
+ - else
92
+ - msg_class = 'is-success'
93
+ - else
94
+ - msg_class = 'is-success'
95
+
96
+ .message class="#{msg_class} agent-message is-small mb-4" id="event-#{event.event_id}"
97
+ .message-header
98
+ p Agent (#{@agent_data[:name]})
99
+ - raw_json_content = agent_response_content.to_json rescue "{}"
100
+ - unless raw_json_content.empty? || raw_json_content == "{}"
101
+ button.button.is-light.is-small.ml-auto( onclick="var el = document.getElementById('raw-#{event.event_id}'); el.style.display = (el.style.display == 'none' ? 'block' : 'none');" )
102
+ | Raw JSON
103
+ .message-body
104
+ div style="white-space: pre-wrap; word-break: break-word; margin-bottom: 0.5rem;" = format_historical_agent_content(agent_response_content)
105
+
106
+ - if agent_response_content.is_a?(Hash) && agent_response_content[:plan_details].is_a?(Array) && !agent_response_content[:plan_details].empty?
107
+ details.execution-plan-details
108
+ summary.execution-plan-summary
109
+ | Execution Plan (#{agent_response_content[:plan_details].size} step#{'s' if agent_response_content[:plan_details].size != 1})
110
+ .execution-plan-steps
111
+ - agent_response_content[:plan_details].each_with_index do |step_detail, index|
112
+ .execution-plan-step
113
+ p.step-title Step #{index + 1}: #{step_detail[:tool_name]}
114
+ p.step-params-label Parameters:
115
+ pre.step-params-pre= JSON.pretty_generate(step_detail[:params] || {})
116
+
117
+ - result_status = step_detail.dig(:result, :status)
118
+ - result_class = case result_status when :success then 'has-text-success-dark' when :error then 'has-text-danger-dark' when :pending then 'has-text-warning-dark' else 'has-text-grey' end
119
+
120
+ p class="step-result-label #{result_class}" Result (#{result_status || "unknown"}):
121
+ pre class="step-result-pre #{result_class}"= JSON.pretty_generate(step_detail[:result] || {}) rescue "{}"
122
+
123
+ - raw_json_content = agent_response_content.to_json rescue "{}"
124
+ - unless raw_json_content.empty? || raw_json_content == "{}"
125
+ div.raw-json-container id="raw-#{event.event_id}" style="display: none;"
126
+ pre.raw-json-pre= raw_json_content
127
+ - elsif event.role == :tool_request || event.role == :tool_result
128
+ / Hidden for a cleaner history; details live in the agent message's execution plan.
129
+ - else
130
+ p.notification.is-warning.is-light Unknown event role: #{event.role}
131
+ - else
132
+ .chat-empty-state
133
+ .chat-empty-emblem
134
+ i.fas.fa-gem
135
+ p.chat-empty-title Start a conversation
136
+ p.chat-empty-hint
137
+ - if is_running
138
+ = "Send a message to #{agent_name} below to begin."
139
+ - else
140
+ | Start the agent from its page to begin chatting.
141
+
142
+ / --- Composer ---
143
+ .chat-composer
144
+ form#chat-form(
145
+ hx-post="/agents/#{agent_name}/chat"
146
+ hx-target="#chat-log-container"
147
+ hx-swap="beforeend"
148
+ hx-indicator="#send-button-indicator"
149
+ _="on htmx:afterRequest call me.reset() then get #chat-log-container then set its scrollTop to its scrollHeight"
150
+ )
151
+ .chat-composer-row
152
+ .control.is-expanded.chat-input-wrap
153
+ input.input#chat-input(
154
+ type="text"
155
+ name="message"
156
+ placeholder="Message #{agent_name}…"
157
+ required=true
158
+ autofocus
159
+ disabled=(!is_running || !@active_session_details)
160
+ )
161
+ span.icon.is-small.is-right.htmx-indicator.chat-input-spinner
162
+ i.fas.fa-spinner.fa-spin
163
+ button.button.is-primary#send-button(
164
+ type="submit"
165
+ disabled=(!is_running || !@active_session_details)
166
+ )
167
+ span Send
168
+ span.icon.is-small.ml-1
169
+ i.fas.fa-paper-plane
170
+ span.icon.is-small#send-button-indicator.htmx-indicator.ml-1
171
+ i.fas.fa-spinner.fa-pulse
172
+
173
+ #chat-status-help-container.mt-2
174
+ - if @agent_data && !is_running
175
+ p.help.is-danger#chat-not-running-help Agent must be running to chat.
176
+ - elsif @agent_data && is_running && !@active_session_details
177
+ p.help.is-warning#chat-no-active-session-help No active chat session. Start a new session above.
178
+ - else
179
+ p.help.is-hidden No issues.
180
+
181
+ / --- Run Details inspector ---
182
+ aside.chat-inspector
183
+ h3.inspector-title Run Details
184
+ == slim :_active_session_info, locals: { active_session_details: @active_session_details }
185
+ .inspector-section
186
+ .inspector-label Available Tools
187
+ - if configured_tools.any?
188
+ .inspector-tools
189
+ - configured_tools.each do |t|
190
+ span.tool-chip= t
191
+ - else
192
+ p.inspector-empty No tools configured
@@ -0,0 +1,105 @@
1
+ / File: lib/legate/web/views/docs_index.slim
2
+
3
+ .content.mb-5
4
+ h1.title.is-2 Legate Documentation
5
+ p.subtitle Browse available documentation for Legate.
6
+
7
+ - if @categorized_documents.nil? || @categorized_documents.empty?
8
+ .notification.is-warning
9
+ p No documentation files found in
10
+ code public/docs
11
+ p or an error occurred while listing them.
12
+ - else
13
+ .field.mb-4
14
+ .control.has-icons-left.search-with-shortcut
15
+ input.input#doc-search-input type="text" placeholder="Search documentation..." onkeyup="filterDocs()"
16
+ span.icon.is-left
17
+ i.fas.fa-search
18
+ span.keyboard-hint
19
+ kbd ⌘K
20
+
21
+ - @categorized_documents.each do |category, documents|
22
+ - unless documents.empty?
23
+ h3.title.is-4.mt-5 = category
24
+ .box.p-0
25
+ .table-container
26
+ table.table.is-fullwidth.is-hoverable.is-striped.documentation-index-table
27
+ thead
28
+ tr
29
+ th Document
30
+ th Description
31
+ th.has-text-centered.action-column
32
+ tbody class="doc-category-body" data-category=category.downcase
33
+ - documents.each do |doc|
34
+ tr.doc-row data-title=doc[:title].downcase data-summary=doc[:summary].downcase data-path=doc[:path]
35
+ td
36
+ a.doc-title href="/docs/#{doc[:path]}" = doc[:title]
37
+ td
38
+ .doc-summary
39
+ = doc[:summary]
40
+ - if doc[:summary].empty?
41
+ em.has-text-grey-light [No summary available]
42
+ td.has-text-centered
43
+ a.button.is-small.is-link.is-outlined href="/docs/#{doc[:path]}"
44
+ span.icon.is-small
45
+ i.fas.fa-book
46
+ span Read
47
+
48
+ javascript:
49
+ function filterDocs() {
50
+ const input = document.getElementById('doc-search-input');
51
+ const filter = input.value.toLowerCase().trim();
52
+ const allRows = document.querySelectorAll('#doc-table-body .doc-row, .doc-category-body .doc-row'); // Select all rows
53
+ const categoryTitles = document.querySelectorAll('h3.title.is-4'); // Select all category titles
54
+
55
+ if (filter === '') {
56
+ // Show all rows and categories if search is empty
57
+ allRows.forEach(row => {
58
+ row.style.display = '';
59
+ });
60
+ categoryTitles.forEach(title => {
61
+ title.style.display = '';
62
+ const table = title.nextElementSibling.querySelector('table');
63
+ if(table) table.style.display = '';
64
+ });
65
+ input.placeholder = 'Search documentation...';
66
+ return;
67
+ }
68
+
69
+ let totalFoundCount = 0;
70
+
71
+ document.querySelectorAll('.doc-category-body').forEach(tableBody => {
72
+ let categoryFoundCount = 0;
73
+ const categoryRows = tableBody.querySelectorAll('.doc-row');
74
+ const selector = 'h3.title.is-4[data-category="' + tableBody.dataset.category + '"]';
75
+ const categoryTitleElement = document.querySelector(selector) ||
76
+ Array.from(categoryTitles).find(ct => ct.textContent.toLowerCase() === tableBody.dataset.category);
77
+
78
+ categoryRows.forEach(row => {
79
+ const title = row.getAttribute('data-title');
80
+ const summary = row.getAttribute('data-summary');
81
+
82
+ if (title.includes(filter) || summary.includes(filter)) {
83
+ row.style.display = '';
84
+ categoryFoundCount++;
85
+ totalFoundCount++;
86
+ } else {
87
+ row.style.display = 'none';
88
+ }
89
+ });
90
+
91
+ // Show/hide category title and table based on whether any docs in it matched
92
+ if (categoryTitleElement) {
93
+ const associatedTableContainer = categoryTitleElement.nextElementSibling; // Assuming .box.p-0 is next
94
+ if (categoryFoundCount > 0) {
95
+ categoryTitleElement.style.display = '';
96
+ if (associatedTableContainer) associatedTableContainer.style.display = '';
97
+ } else {
98
+ categoryTitleElement.style.display = 'none';
99
+ if (associatedTableContainer) associatedTableContainer.style.display = 'none';
100
+ }
101
+ }
102
+ });
103
+
104
+ input.placeholder = `${totalFoundCount} result${totalFoundCount !== 1 ? 's' : ''} found`;
105
+ }
@@ -0,0 +1,105 @@
1
+ / File: lib/legate/web/views/docs_show.slim
2
+
3
+ .container
4
+ nav.breadcrumb.has-arrow-separator.p-4.has-background-info-light
5
+ ul
6
+ li
7
+ a href="/docs" Documentation
8
+ li.is-active
9
+ a href="#" aria-current="page" = @doc_title || "Document"
10
+
11
+ .content.mb-5
12
+ h1.title.is-2.mt-4 = @doc_title || "Document"
13
+
14
+ .box.documentation-content
15
+ / Add a table of contents for longer documents
16
+ - if @doc_html_content && !@doc_html_content.empty?
17
+ .columns
18
+ .column.is-9.pr-5
19
+ .content
20
+ == @doc_html_content
21
+ .column.is-3.is-hidden-mobile
22
+ .toc-container.is-sticky style="top: 80px; max-height: calc(100vh - 100px); overflow-y: auto; padding-right: 15px;"
23
+ .has-text-weight-bold.mb-2 Table of Contents
24
+ .table-of-contents
25
+ / This will be populated by JavaScript
26
+ - else
27
+ .notification.is-danger
28
+ p Error: Document content could not be loaded or rendered.
29
+
30
+ / Add JavaScript to generate a table of contents from headings
31
+ javascript:
32
+ document.addEventListener('DOMContentLoaded', function() {
33
+ // Generate table of contents from headings
34
+ const content = document.querySelector('.documentation-content .content');
35
+ const toc = document.querySelector('.table-of-contents');
36
+
37
+ if (content && toc) {
38
+ const headings = content.querySelectorAll('h2, h3, h4');
39
+
40
+ if (headings.length > 0) {
41
+ const tocList = document.createElement('ul');
42
+ tocList.className = 'toc-list';
43
+
44
+ headings.forEach((heading, index) => {
45
+ // Add ID to heading if it doesn't have one
46
+ if (!heading.id) {
47
+ heading.id = 'heading-' + index;
48
+ }
49
+
50
+ const listItem = document.createElement('li');
51
+ listItem.className = 'toc-item toc-' + heading.tagName.toLowerCase();
52
+
53
+ const link = document.createElement('a');
54
+ link.href = '#' + heading.id;
55
+ link.textContent = heading.textContent;
56
+
57
+ listItem.appendChild(link);
58
+ tocList.appendChild(listItem);
59
+ });
60
+
61
+ toc.appendChild(tocList);
62
+
63
+ // Add styles for TOC items
64
+ const style = document.createElement('style');
65
+ style.textContent = `
66
+ .toc-list {
67
+ list-style: none;
68
+ padding-left: 0;
69
+ margin-top: 0.5rem;
70
+ }
71
+ .toc-item {
72
+ margin-bottom: 0.5rem;
73
+ font-size: 0.9rem;
74
+ }
75
+ .toc-h3 {
76
+ padding-left: 1rem;
77
+ font-size: 0.85rem;
78
+ }
79
+ .toc-h4 {
80
+ padding-left: 2rem;
81
+ font-size: 0.8rem;
82
+ }
83
+ .toc-item a {
84
+ color: #4a4a4a;
85
+ text-decoration: none;
86
+ display: block;
87
+ padding: 0.2rem 0;
88
+ border-left: 2px solid transparent;
89
+ padding-left: 0.5rem;
90
+ }
91
+ .toc-item a:hover {
92
+ color: #3273dc;
93
+ border-left: 2px solid #3273dc;
94
+ }
95
+ .is-sticky {
96
+ position: sticky;
97
+ }
98
+ `;
99
+ document.head.appendChild(style);
100
+ } else {
101
+ // If no headings, hide the TOC
102
+ document.querySelector('.toc-container').style.display = 'none';
103
+ }
104
+ }
105
+ });
@@ -0,0 +1,5 @@
1
+ .content
2
+ h1.title.is-danger= locals[:title] || "Error"
3
+ p= locals[:message] || "The requested page could not be found."
4
+ .mt-4
5
+ a.button href="/agents" Back to Agents List
@@ -0,0 +1,148 @@
1
+ / File: lib/legate/web/views/index.slim
2
+
3
+ / Hero Welcome Section
4
+ section.hero-welcome.mb-6
5
+ .hero-content
6
+ .hero-main
7
+ .hero-badge
8
+ i.fas.fa-gem
9
+ .hero-text
10
+ p.hero-eyebrow Legion Commander
11
+ h1.hero-title Command your AI legion
12
+ p.hero-subtitle Build, orchestrate, and run powerful AI agents in elegant Ruby.
13
+ button.hero-pronounce(type="button" title="Say it out loud" aria-label="Pronounce Legate")
14
+ span.respell
15
+ strong Legate
16
+ span.phon= "/ˈle·jit/"
17
+ span.pronounce-wink yep, like “legit” 😎
18
+ span.icon.pronounce-speaker
19
+ i.fas.fa-volume-up
20
+ .hero-actions
21
+ a.button.is-hero-primary.is-medium(href="/agents")
22
+ span.icon
23
+ i.fas.fa-plus
24
+ span Create Agent
25
+ a.button.is-hero-secondary.is-medium(href="/docs")
26
+ span.icon
27
+ i.fas.fa-book
28
+ span Documentation
29
+
30
+ .columns.is-centered.is-multiline.index-dashboard-cards
31
+ .column.is-one-quarter
32
+ .card.dashboard-card.agents-card.has-text-centered
33
+ .card-content
34
+ span.icon.is-large.mb-3
35
+ i.fas.fa-robot.fa-3x style="color: var(--color-primary);"
36
+ h2.title.is-4 Agents
37
+ - if @running_count && @running_count > 0
38
+ p.is-size-2.has-text-weight-bold style="color: var(--color-primary);"
39
+ = @running_count
40
+ p.subtitle.is-6.mb-2 Running
41
+ p.is-size-7.has-text-grey
42
+ = "#{@agent_count} total defined"
43
+ - elsif @agent_count && @agent_count > 0
44
+ p.is-size-2.has-text-weight-bold style="color: var(--color-text-muted);"
45
+ = @agent_count
46
+ p.subtitle.is-6.mb-2 Defined
47
+ p.is-size-7.has-text-grey None running
48
+ - else
49
+ p.has-text-grey-light.is-italic.mb-2 No agents defined yet
50
+ p.is-size-7.has-text-grey Create your first agent
51
+ .card-footer
52
+ a.card-footer-item(href="/agents")
53
+ span View Agents
54
+ span.icon.is-small.ml-1
55
+ i.fas.fa-arrow-right
56
+ a.card-footer-item.quick-action(href="/agents" title="Create new agent")
57
+ span.icon
58
+ i.fas.fa-plus
59
+
60
+ .column.is-one-quarter
61
+ .card.dashboard-card.tools-card.has-text-centered
62
+ .card-content
63
+ span.icon.is-large.mb-3
64
+ i.fas.fa-wrench.fa-3x style="color: var(--color-primary);"
65
+ h2.title.is-4 Tools
66
+ - if @tool_count && @tool_count > 0
67
+ p.is-size-2.has-text-weight-bold style="color: var(--color-primary);"
68
+ = @tool_count
69
+ p.subtitle.is-6.mb-2 Available
70
+ - else
71
+ p.has-text-grey-light.is-italic.mb-2 No tools loaded
72
+ .card-footer
73
+ a.card-footer-item(href="/tools")
74
+ span View Tools
75
+ span.icon.is-small.ml-1
76
+ i.fas.fa-arrow-right
77
+ a.card-footer-item.quick-action(href="/tools" title="Build new tool with AI")
78
+ span.icon
79
+ i.fas.fa-plus
80
+
81
+ .column.is-one-quarter
82
+ .card.dashboard-card.auth-card.has-text-centered
83
+ .card-content
84
+ span.icon.is-large.mb-3
85
+ i.fas.fa-key.fa-3x style="color: var(--color-primary);"
86
+ h2.title.is-4 Authentication
87
+ - if @auth_scheme_count && @auth_scheme_count > 0
88
+ p.is-size-2.has-text-weight-bold style="color: var(--color-primary);"
89
+ = @auth_scheme_count
90
+ p.subtitle.is-6.mb-2 Schemes
91
+ - else
92
+ p.has-text-grey-light.is-italic.mb-2 Configure auth
93
+ .card-footer
94
+ a.card-footer-item(href="/auth")
95
+ span View Authentication
96
+ span.icon.is-small.ml-1
97
+ i.fas.fa-arrow-right
98
+
99
+ .column.is-one-quarter
100
+ .card.dashboard-card.docs-card.has-text-centered
101
+ .card-content
102
+ span.icon.is-large.mb-3
103
+ i.fas.fa-book-open.fa-3x style="color: var(--color-primary);"
104
+ h2.title.is-4 Documentation
105
+ p.has-text-grey Read guides and concepts about Legate.
106
+ .card-footer
107
+ a.card-footer-item(href="/docs")
108
+ span Read Docs
109
+ span.icon.is-small.ml-1
110
+ i.fas.fa-arrow-right
111
+
112
+ / Activity Stream Section
113
+ .box.activity-stream-box.mt-5
114
+ .level.mb-4
115
+ .level-left
116
+ h3.title.is-5.mb-0
117
+ span.icon.mr-2
118
+ i.fas.fa-stream
119
+ | Recent Activity
120
+ .level-right
121
+ button.button.is-small.is-light(hx-get="/activity/recent" hx-target="#activity-list" hx-swap="innerHTML" title="Refresh activity")
122
+ span.icon.is-small
123
+ i.fas.fa-sync-alt
124
+
125
+ #activity-list
126
+ == slim :_activity_list
127
+
128
+ javascript:
129
+ (function () {
130
+ var btn = document.querySelector('.hero-pronounce');
131
+ if (!btn) return;
132
+ btn.addEventListener('click', function () {
133
+ btn.classList.remove('is-saying');
134
+ // restart the wink animation
135
+ void btn.offsetWidth;
136
+ btn.classList.add('is-saying');
137
+ try {
138
+ if ('speechSynthesis' in window) {
139
+ window.speechSynthesis.cancel();
140
+ var u = new SpeechSynthesisUtterance('Legate. Say it like legit.');
141
+ u.rate = 0.95;
142
+ u.pitch = 1.05;
143
+ window.speechSynthesis.speak(u);
144
+ }
145
+ } catch (e) { /* no audio, the wink still fires */ }
146
+ setTimeout(function () { btn.classList.remove('is-saying'); }, 900);
147
+ });
148
+ })();