little_ghost 0.7.0 → 0.9.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 (270) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +34 -6
  3. data/docs/guides/assemblies.md +21 -9
  4. data/docs/guides/code_mode.md +2 -2
  5. data/docs/guides/getting_started.md +27 -2
  6. data/docs/guides/integrations.md +20 -161
  7. data/docs/guides/mcp.md +288 -0
  8. data/docs/guides/models_and_providers.md +21 -54
  9. data/docs/guides/production.md +14 -5
  10. data/docs/guides/prompt_views.md +234 -27
  11. data/docs/guides/providers.md +275 -0
  12. data/docs/guides/sandboxing.md +42 -7
  13. data/docs/guides/skills.md +1 -3
  14. data/docs/guides/tools.md +2 -0
  15. data/exe/little_ghost +12 -0
  16. data/lib/little_ghost/agent/context_management.rb +2 -13
  17. data/lib/little_ghost/agent/delegation.rb +7 -4
  18. data/lib/little_ghost/agent/skills.rb +8 -6
  19. data/lib/little_ghost/agent/tool_loop.rb +4 -4
  20. data/lib/little_ghost/agent.rb +230 -70
  21. data/lib/little_ghost/agent_builder.rb +16 -4
  22. data/lib/little_ghost/artifacts/workspace_store.rb +16 -14
  23. data/lib/little_ghost/assembly.rb +48 -7
  24. data/lib/little_ghost/assembly_builder.rb +3 -3
  25. data/lib/little_ghost/cli.rb +429 -0
  26. data/lib/little_ghost/code_mode/broker.rb +11 -3
  27. data/lib/little_ghost/code_mode/javascript/client.rb +58 -11
  28. data/lib/little_ghost/code_mode/javascript/host.rb +37 -13
  29. data/lib/little_ghost/code_mode/javascript/session.rb +21 -9
  30. data/lib/little_ghost/code_mode/javascript_engine.rb +21 -42
  31. data/lib/little_ghost/code_mode/ruby/host.rb +8 -4
  32. data/lib/little_ghost/code_mode/ruby/session.rb +41 -14
  33. data/lib/little_ghost/code_mode/ruby_engine.rb +6 -36
  34. data/lib/little_ghost/code_mode/runtime.rb +57 -24
  35. data/lib/little_ghost/console.rb +17 -0
  36. data/lib/little_ghost/errors.rb +20 -2
  37. data/lib/little_ghost/framework_prompts.rb +376 -0
  38. data/lib/little_ghost/generators/application_generator.rb +179 -0
  39. data/lib/little_ghost/generators/templates/application/Gemfile.tt +3 -0
  40. data/lib/little_ghost/generators/templates/application/README.md.tt +29 -0
  41. data/lib/little_ghost/generators/templates/application/app/agents/application_agent.rb.tt +5 -0
  42. data/lib/little_ghost/generators/templates/application/app/prompts/application/system_prompt.erb.tt +1 -0
  43. data/lib/little_ghost/generators/templates/application/bin/application.tt +10 -0
  44. data/lib/little_ghost/generators/templates/application/config/little_ghost.rb.tt +5 -0
  45. data/lib/little_ghost/generators/templates/application/gitignore.tt +2 -0
  46. data/lib/little_ghost/generators/templates/application/keep.tt +0 -0
  47. data/lib/little_ghost/graph.rb +24 -5
  48. data/lib/little_ghost/mcp/client.rb +307 -610
  49. data/lib/little_ghost/mcp/toolset.rb +133 -95
  50. data/lib/little_ghost/mcp.rb +21 -3
  51. data/lib/little_ghost/model_operations.rb +103 -36
  52. data/lib/little_ghost/model_resolver.rb +2 -0
  53. data/lib/little_ghost/models/catalog/models_dev_source.rb +4 -1
  54. data/lib/little_ghost/prompt_resolver.rb +61 -27
  55. data/lib/little_ghost/prompts/little_ghost/agent/interjections/instructions.erb +12 -0
  56. data/lib/little_ghost/prompts/little_ghost/agent/system/default.erb +10 -0
  57. data/lib/little_ghost/prompts/little_ghost/artifacts/batch/feedback/batch_too_large.erb +10 -0
  58. data/lib/little_ghost/prompts/little_ghost/artifacts/batch/feedback/batch_too_many.erb +10 -0
  59. data/lib/little_ghost/prompts/little_ghost/artifacts/batch/feedback/item_too_large.erb +10 -0
  60. data/lib/little_ghost/prompts/little_ghost/artifacts/errors/preparation_failed.erb +10 -0
  61. data/lib/little_ghost/prompts/little_ghost/artifacts/errors/resolver_invalid.erb +10 -0
  62. data/lib/little_ghost/prompts/little_ghost/artifacts/errors/value_unstorable.erb +10 -0
  63. data/lib/little_ghost/prompts/little_ghost/artifacts/presentation/format/reference.erb +13 -0
  64. data/lib/little_ghost/prompts/little_ghost/artifacts/presentation/format/references.erb +12 -0
  65. data/lib/little_ghost/prompts/little_ghost/artifacts/presentation/format/workspace_references.erb +12 -0
  66. data/lib/little_ghost/prompts/little_ghost/artifacts/presentation/notices/full_result.erb +14 -0
  67. data/lib/little_ghost/prompts/little_ghost/artifacts/presentation/notices/storage_failed.erb +13 -0
  68. data/lib/little_ghost/prompts/little_ghost/artifacts/storage/errors/destination_unsafe.erb +10 -0
  69. data/lib/little_ghost/prompts/little_ghost/artifacts/storage/errors/secure_unavailable.erb +10 -0
  70. data/lib/little_ghost/prompts/little_ghost/artifacts/storage/errors/workspace_changed.erb +10 -0
  71. data/lib/little_ghost/prompts/little_ghost/artifacts/storage/errors/workspace_unavailable.erb +10 -0
  72. data/lib/little_ghost/prompts/little_ghost/artifacts/storage/errors/workspace_unsafe.erb +10 -0
  73. data/lib/little_ghost/prompts/little_ghost/artifacts/storage/feedback/count_limit.erb +10 -0
  74. data/lib/little_ghost/prompts/little_ghost/artifacts/storage/feedback/destination_exists.erb +10 -0
  75. data/lib/little_ghost/prompts/little_ghost/artifacts/storage/feedback/too_large.erb +10 -0
  76. data/lib/little_ghost/prompts/little_ghost/artifacts/storage/feedback/total_limit.erb +10 -0
  77. data/lib/little_ghost/prompts/little_ghost/assembly/feedback/transition_only.erb +10 -0
  78. data/lib/little_ghost/prompts/little_ghost/assembly/tools/fallback/description.erb +10 -0
  79. data/lib/little_ghost/prompts/little_ghost/code_mode/artifacts/format/references.erb +12 -0
  80. data/lib/little_ghost/prompts/little_ghost/code_mode/errors/brokered_close.erb +10 -0
  81. data/lib/little_ghost/prompts/little_ghost/code_mode/errors/cleanup_failed.erb +10 -0
  82. data/lib/little_ghost/prompts/little_ghost/code_mode/errors/execution_failed.erb +11 -0
  83. data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/arguments_object.erb +10 -0
  84. data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/closed.erb +10 -0
  85. data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/control_active.erb +10 -0
  86. data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/limit_exceeded.erb +10 -0
  87. data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/not_active.erb +10 -0
  88. data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/program_active.erb +10 -0
  89. data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/program_timed_out.erb +10 -0
  90. data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/unavailable_tool.erb +10 -0
  91. data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/unknown_program.erb +10 -0
  92. data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/active_programs_limit.erb +10 -0
  93. data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/cleanup_failed.erb +10 -0
  94. data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/execution_limit.erb +10 -0
  95. data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/invalid_request.erb +10 -0
  96. data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/memory_limit.erb +10 -0
  97. data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/pending_calls_limit.erb +10 -0
  98. data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/source_size_limit.erb +10 -0
  99. data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/tools_array.erb +10 -0
  100. data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/instructions.erb +35 -0
  101. data/lib/little_ghost/prompts/little_ghost/code_mode/ruby/feedback/parallel_callables.erb +10 -0
  102. data/lib/little_ghost/prompts/little_ghost/code_mode/ruby/instructions.erb +40 -0
  103. data/lib/little_ghost/prompts/little_ghost/code_mode/tools/exec/description.erb +10 -0
  104. data/lib/little_ghost/prompts/little_ghost/code_mode/tools/stop/description.erb +10 -0
  105. data/lib/little_ghost/prompts/little_ghost/code_mode/tools/stop/inputs/max_output_tokens/description.erb +10 -0
  106. data/lib/little_ghost/prompts/little_ghost/code_mode/tools/wait/description.erb +10 -0
  107. data/lib/little_ghost/prompts/little_ghost/code_mode/tools/wait/inputs/max_output_tokens/description.erb +10 -0
  108. data/lib/little_ghost/prompts/little_ghost/context_management/summary/request.erb +10 -0
  109. data/lib/little_ghost/prompts/little_ghost/context_management/summary/system_instruction.erb +16 -0
  110. data/lib/little_ghost/prompts/little_ghost/graph/context/format/failed_input.erb +11 -0
  111. data/lib/little_ghost/prompts/little_ghost/graph/context/format/previous_input.erb +13 -0
  112. data/lib/little_ghost/prompts/little_ghost/graph/context/headings/original_task.erb +10 -0
  113. data/lib/little_ghost/prompts/little_ghost/graph/context/headings/previous_inputs.erb +10 -0
  114. data/lib/little_ghost/prompts/little_ghost/mcp/errors/request_failed.erb +10 -0
  115. data/lib/little_ghost/prompts/little_ghost/mcp/errors/transformation_unserializable.erb +10 -0
  116. data/lib/little_ghost/prompts/little_ghost/mcp/tools/fallback/description.erb +10 -0
  117. data/lib/little_ghost/prompts/little_ghost/output/truncation/marker.erb +11 -0
  118. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/errors/mount_changed.erb +10 -0
  119. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/errors/secure_traversal_unavailable.erb +10 -0
  120. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/errors/workspace_root_changed.erb +10 -0
  121. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/directory_listing_limit.erb +10 -0
  122. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/entry_required.erb +10 -0
  123. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/file_read_limit.erb +10 -0
  124. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/invalid_utf8.erb +10 -0
  125. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/mount_escape.erb +10 -0
  126. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/mount_missing.erb +10 -0
  127. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/multiply_linked.erb +10 -0
  128. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/not_directory.erb +10 -0
  129. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/not_file.erb +10 -0
  130. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/null_byte.erb +10 -0
  131. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/outside_scope.erb +10 -0
  132. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/parent_escape.erb +10 -0
  133. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/path_missing.erb +10 -0
  134. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/path_traverses_symlink.erb +10 -0
  135. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/read_only.erb +10 -0
  136. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/replace_empty.erb +10 -0
  137. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/symlink_path.erb +10 -0
  138. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/text_multiple.erb +10 -0
  139. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/text_not_found.erb +10 -0
  140. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/write_limit.erb +10 -0
  141. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/write_parent_missing.erb +10 -0
  142. data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/write_target_symlink.erb +10 -0
  143. data/lib/little_ghost/prompts/little_ghost/sandbox/policy/feedback/feature_denied.erb +10 -0
  144. data/lib/little_ghost/prompts/little_ghost/sandbox/process/errors/program_supervisor_failed.erb +10 -0
  145. data/lib/little_ghost/prompts/little_ghost/sandbox/process/feedback/command_timed_out.erb +10 -0
  146. data/lib/little_ghost/prompts/little_ghost/sandbox/process/feedback/executable_required.erb +10 -0
  147. data/lib/little_ghost/prompts/little_ghost/sandbox/process/feedback/program_memory_exceeded.erb +10 -0
  148. data/lib/little_ghost/prompts/little_ghost/sandbox/process/feedback/program_output_exceeded.erb +10 -0
  149. data/lib/little_ghost/prompts/little_ghost/sandbox/process/feedback/program_timed_out.erb +10 -0
  150. data/lib/little_ghost/prompts/little_ghost/skills/discovery/instructions.erb +18 -0
  151. data/lib/little_ghost/prompts/little_ghost/skills/feedback/unknown.erb +11 -0
  152. data/lib/little_ghost/prompts/little_ghost/skills/resources/notices/truncated.erb +10 -0
  153. data/lib/little_ghost/prompts/little_ghost/skills/tools/activate/content.erb +28 -0
  154. data/lib/little_ghost/prompts/little_ghost/skills/tools/activate/description.erb +10 -0
  155. data/lib/little_ghost/prompts/little_ghost/skills/tools/activate/inputs/name/description.erb +10 -0
  156. data/lib/little_ghost/prompts/little_ghost/structured_output/persistence/format/redaction.erb +12 -0
  157. data/lib/little_ghost/prompts/little_ghost/structured_output/repair/feedback/invalid_result.erb +11 -0
  158. data/lib/little_ghost/prompts/little_ghost/structured_output/repair/feedback/schema_errors.erb +11 -0
  159. data/lib/little_ghost/prompts/little_ghost/structured_output/repair/request.erb +14 -0
  160. data/lib/little_ghost/prompts/little_ghost/structured_output/tools/result/description.erb +11 -0
  161. data/lib/little_ghost/prompts/little_ghost/structured_output/validation/feedback/invalid_json.erb +11 -0
  162. data/lib/little_ghost/prompts/little_ghost/structured_output/validation/feedback/missing_tool.erb +11 -0
  163. data/lib/little_ghost/prompts/little_ghost/structured_output/validation/feedback/multiple_tools.erb +11 -0
  164. data/lib/little_ghost/prompts/little_ghost/structured_output/validation/feedback/too_complex.erb +11 -0
  165. data/lib/little_ghost/prompts/little_ghost/structured_output/validation/feedback/too_deep.erb +11 -0
  166. data/lib/little_ghost/prompts/little_ghost/structured_output/validation/feedback/too_large.erb +11 -0
  167. data/lib/little_ghost/prompts/little_ghost/structured_output/validation/feedback/tool_not_exclusive.erb +11 -0
  168. data/lib/little_ghost/prompts/little_ghost/subagents/errors/create_failed.erb +10 -0
  169. data/lib/little_ghost/prompts/little_ghost/subagents/errors/previous_turn_failed.erb +10 -0
  170. data/lib/little_ghost/prompts/little_ghost/subagents/errors/restore_failed.erb +10 -0
  171. data/lib/little_ghost/prompts/little_ghost/subagents/errors/turn_failed.erb +10 -0
  172. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/duplicate_ids.erb +10 -0
  173. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/duplicate_path.erb +10 -0
  174. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/identity_capacity.erb +10 -0
  175. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/inactive.erb +10 -0
  176. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/interjection_chars_limit.erb +10 -0
  177. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/interjection_limit.erb +10 -0
  178. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/interjection_unsupported.erb +10 -0
  179. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/invalid_cursor.erb +10 -0
  180. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/invalid_mode.erb +10 -0
  181. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/list_limit.erb +10 -0
  182. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/message_limit.erb +10 -0
  183. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/message_type.erb +10 -0
  184. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/not_running.erb +10 -0
  185. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/queue_capacity.erb +10 -0
  186. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/task_name_invalid.erb +10 -0
  187. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/task_name_limit.erb +10 -0
  188. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/terminal_identity.erb +11 -0
  189. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/turn_capacity.erb +10 -0
  190. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/unknown_id.erb +10 -0
  191. data/lib/little_ghost/prompts/little_ghost/subagents/feedback/unknown_kind.erb +10 -0
  192. data/lib/little_ghost/prompts/little_ghost/subagents/notices/turn_cancelled.erb +10 -0
  193. data/lib/little_ghost/prompts/little_ghost/subagents/tools/interject/description.erb +10 -0
  194. data/lib/little_ghost/prompts/little_ghost/subagents/tools/interject/inputs/active_id/description.erb +10 -0
  195. data/lib/little_ghost/prompts/little_ghost/subagents/tools/interject/inputs/message/description.erb +10 -0
  196. data/lib/little_ghost/prompts/little_ghost/subagents/tools/list/description.erb +10 -0
  197. data/lib/little_ghost/prompts/little_ghost/subagents/tools/send/description.erb +10 -0
  198. data/lib/little_ghost/prompts/little_ghost/subagents/tools/send/inputs/id/description.erb +10 -0
  199. data/lib/little_ghost/prompts/little_ghost/subagents/tools/send/inputs/message/description.erb +10 -0
  200. data/lib/little_ghost/prompts/little_ghost/subagents/tools/send/inputs/send_mode/description.erb +10 -0
  201. data/lib/little_ghost/prompts/little_ghost/subagents/tools/spawn/description.erb +10 -0
  202. data/lib/little_ghost/prompts/little_ghost/subagents/tools/spawn/inputs/kind/description.erb +11 -0
  203. data/lib/little_ghost/prompts/little_ghost/subagents/tools/spawn/inputs/spawn_mode/description.erb +10 -0
  204. data/lib/little_ghost/prompts/little_ghost/subagents/tools/spawn/inputs/task/description.erb +10 -0
  205. data/lib/little_ghost/prompts/little_ghost/subagents/tools/spawn/inputs/task_name/description.erb +10 -0
  206. data/lib/little_ghost/prompts/little_ghost/subagents/tools/wait/description.erb +10 -0
  207. data/lib/little_ghost/prompts/little_ghost/subagents/tools/wait/inputs/ids/description.erb +10 -0
  208. data/lib/little_ghost/prompts/little_ghost/swarm/handoff/notice.erb +10 -0
  209. data/lib/little_ghost/prompts/little_ghost/swarm/handoff/request.erb +16 -0
  210. data/lib/little_ghost/prompts/little_ghost/swarm/tools/handoff/description.erb +10 -0
  211. data/lib/little_ghost/prompts/little_ghost/tools/built_in/list_files/description.erb +10 -0
  212. data/lib/little_ghost/prompts/little_ghost/tools/built_in/read_file/description.erb +10 -0
  213. data/lib/little_ghost/prompts/little_ghost/tools/built_in/replace_in_file/description.erb +10 -0
  214. data/lib/little_ghost/prompts/little_ghost/tools/built_in/shell/description.erb +10 -0
  215. data/lib/little_ghost/prompts/little_ghost/tools/built_in/write_file/description.erb +10 -0
  216. data/lib/little_ghost/prompts/little_ghost/tools/built_in/write_todos/description.erb +10 -0
  217. data/lib/little_ghost/prompts/little_ghost/tools/built_in/write_todos/feedback/single_progress.erb +10 -0
  218. data/lib/little_ghost/prompts/little_ghost/tools/built_in/write_todos/feedback/unique_ids.erb +10 -0
  219. data/lib/little_ghost/prompts/little_ghost/tools/errors/unexpected_failure.erb +10 -0
  220. data/lib/little_ghost/prompts/little_ghost/tools/errors/unserializable_result.erb +10 -0
  221. data/lib/little_ghost/prompts/little_ghost/tools/feedback/invalid_input.erb +10 -0
  222. data/lib/little_ghost/prompts/little_ghost/tools/feedback/unknown.erb +10 -0
  223. data/lib/little_ghost/prompts/little_ghost/tools/loop/notices/final_warning.erb +10 -0
  224. data/lib/little_ghost/prompts/little_ghost/tools/loop/notices/termination.erb +10 -0
  225. data/lib/little_ghost/prompts/little_ghost/tools/loop/notices/warning.erb +10 -0
  226. data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/additional_property.erb +10 -0
  227. data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/enum.erb +11 -0
  228. data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/invalid_format.erb +10 -0
  229. data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/invalid_pattern.erb +10 -0
  230. data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/max_items.erb +11 -0
  231. data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/max_length.erb +11 -0
  232. data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/maximum.erb +11 -0
  233. data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/min_items.erb +11 -0
  234. data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/min_length.erb +11 -0
  235. data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/minimum.erb +11 -0
  236. data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/required.erb +10 -0
  237. data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/type.erb +11 -0
  238. data/lib/little_ghost/prompts/little_ghost/workspace/feedback/path_changed.erb +10 -0
  239. data/lib/little_ghost/provider_registry.rb +1 -0
  240. data/lib/little_ghost/providers/lm_studio/catalog_source.rb +201 -0
  241. data/lib/little_ghost/providers/lm_studio.rb +52 -0
  242. data/lib/little_ghost/providers/openai.rb +3 -75
  243. data/lib/little_ghost/providers/openai_compatible.rb +78 -1
  244. data/lib/little_ghost/runtime/hooks/artifacts.rb +58 -22
  245. data/lib/little_ghost/runtime.rb +8 -3
  246. data/lib/little_ghost/sandbox/environment_policy.rb +29 -4
  247. data/lib/little_ghost/sandbox/filesystem.rb +51 -33
  248. data/lib/little_ghost/sandbox/policy.rb +28 -6
  249. data/lib/little_ghost/sandbox/process_runner.rb +6 -2
  250. data/lib/little_ghost/sandbox/process_session.rb +8 -4
  251. data/lib/little_ghost/sandbox/scope.rb +4 -1
  252. data/lib/little_ghost/sandboxes/seatbelt.rb +3 -1
  253. data/lib/little_ghost/sandboxes/unrestricted.rb +17 -9
  254. data/lib/little_ghost/skills/catalog.rb +41 -36
  255. data/lib/little_ghost/structured_output.rb +6 -6
  256. data/lib/little_ghost/subagents/control_tool.rb +58 -0
  257. data/lib/little_ghost/subagents/manager.rb +99 -74
  258. data/lib/little_ghost/support/output_truncation.rb +28 -4
  259. data/lib/little_ghost/swarm.rb +20 -7
  260. data/lib/little_ghost/tool.rb +47 -20
  261. data/lib/little_ghost/tool_registry.rb +2 -2
  262. data/lib/little_ghost/tools/filesystem.rb +12 -4
  263. data/lib/little_ghost/tools/shell.rb +5 -1
  264. data/lib/little_ghost/tools/write_todos.rb +9 -9
  265. data/lib/little_ghost/version.rb +1 -1
  266. data/lib/little_ghost/workflow.rb +199 -27
  267. data/lib/little_ghost/workspace.rb +2 -2
  268. data/lib/little_ghost.rb +6 -2
  269. metadata +222 -7
  270. data/lib/little_ghost/mcp/types.rb +0 -216
@@ -0,0 +1,288 @@
1
+ # Connect agents to MCP servers
2
+
3
+ Give an Agent access to operations published by a Model Context Protocol (MCP)
4
+ server without changing how your application calls the Agent.
5
+ `LittleGhost::MCP::Toolset` turns operations discovered by the official MCP Ruby
6
+ client into LittleGhost Tool classes, which join the same `tools` declaration as
7
+ local application Tools.
8
+
9
+ MCP support is opt-in. Requiring `little_ghost` alone does not install or load
10
+ the SDK or its transports.
11
+
12
+ ## Connect over Streamable HTTP
13
+
14
+ Add the official SDK and its HTTP dependencies to your bundle:
15
+
16
+ ```ruby
17
+ gem "mcp", "~> 1.3"
18
+ gem "faraday", "~> 2.0"
19
+ gem "event_stream_parser", "~> 1.0"
20
+ ```
21
+
22
+ Require the integration explicitly, then create a Toolset with a `client`
23
+ block. Return a new official client from the block:
24
+
25
+ ```ruby
26
+ require "little_ghost/mcp"
27
+
28
+ class HelpCenterTools < LittleGhost::MCP::Toolset
29
+ client do |_binding|
30
+ transport = MCP::Client::HTTP.new(
31
+ url: "https://mcp.example/rpc"
32
+ )
33
+ MCP::Client.new(transport:)
34
+ end
35
+ end
36
+
37
+ class CustomerSupportAgent < LittleGhost::Agent
38
+ system_prompt "Use help-center tools for published guidance."
39
+ tools HelpCenterTools
40
+ end
41
+
42
+ run = CustomerSupportAgent.ask("How long do refunds take?")
43
+ run.response
44
+ ```
45
+
46
+ LittleGhost calls the block once for each Agent run. It connects the client,
47
+ discovers the server's Tools, and closes the transport when the run ends.
48
+
49
+ The `client` block receives the current `Tool::Binding`. Use it to build headers
50
+ or credentials from authenticated application context without storing them on
51
+ the Toolset:
52
+
53
+ ```ruby
54
+ class AccountTools < LittleGhost::MCP::Toolset
55
+ client do |binding|
56
+ token = McpAccessTokens.for_actor(binding.run.invocation.actor_id)
57
+ transport = MCP::Client::HTTP.new(
58
+ url: "https://mcp.example/rpc",
59
+ headers: {"Authorization" => "Bearer #{token}"}
60
+ )
61
+ MCP::Client.new(transport:)
62
+ end
63
+ end
64
+ ```
65
+
66
+ ## Connect a local server over standard input and output
67
+
68
+ A standard input and output (stdio) connection needs only the official SDK:
69
+
70
+ ```ruby
71
+ gem "mcp", "~> 1.3"
72
+ ```
73
+
74
+ Construct the SDK transport in the same `client` block:
75
+
76
+ ```ruby
77
+ class LocalDatabaseTools < LittleGhost::MCP::Toolset
78
+ client do |_binding|
79
+ transport = MCP::Client::Stdio.new(
80
+ command: "bundle",
81
+ args: ["exec", "database-mcp"],
82
+ env: {"APP_ENV" => "production"},
83
+ read_timeout: 30
84
+ )
85
+ MCP::Client.new(transport:)
86
+ end
87
+ end
88
+ ```
89
+
90
+ A stdio server is a child process with the same operating-system permissions as
91
+ your Ruby process. It is not a sandbox. Use an operating-system sandbox when
92
+ you do not fully trust the executable.
93
+
94
+ The `env` Hash changes only the variables you name. The child inherits every
95
+ other variable from the parent process. Clear sensitive variables explicitly,
96
+ or launch the server through an isolated wrapper when it must not receive
97
+ ambient credentials.
98
+
99
+ ## Configure the official client
100
+
101
+ Set timeouts, message limits, OAuth, middleware, and other transport behavior
102
+ through the SDK. Keyword arguments on `client` go directly to
103
+ `MCP::Client#connect`; use them for an explicit protocol mode, version, or client
104
+ capability.
105
+
106
+ ### Respond to server requests
107
+
108
+ A server may need more information while handling a Tool call. MCP calls this
109
+ elicitation. Advertise the capability when connecting, then register a handler
110
+ on the client:
111
+
112
+ ```ruby
113
+ class InteractiveTools < LittleGhost::MCP::Toolset
114
+ client(capabilities: {elicitation: {}}) do |binding|
115
+ transport = MCP::Client::HTTP.new(url: "https://mcp.example/rpc")
116
+ MCP::Client.new(transport:).tap do |official_client|
117
+ official_client.on_elicitation do |request|
118
+ Elicitations.answer(request, run: binding.run)
119
+ end
120
+ end
121
+ end
122
+ end
123
+ ```
124
+
125
+ The handler can answer from the current Run or pass the request to an application
126
+ interface. Sampling similarly lets a server request a model call, while roots
127
+ tell a server which directories the application makes available. Configure
128
+ these features on the official client.
129
+
130
+ Treat every server-initiated handler request as untrusted. Authorize it against
131
+ the current run, restrict roots to intended paths, constrain model sampling and
132
+ its cost, and return only the application data that server is allowed to receive.
133
+
134
+ Return a new, unconnected client for every run. Building it should not start
135
+ remote work. LittleGhost closes transports that provide `close`, including when
136
+ connection or discovery fails. If a custom transport owns other resources, it
137
+ must release them itself.
138
+
139
+ Set transport timeouts to match the application's deadline. LittleGhost passes
140
+ Run cancellation and deadlines to Tool discovery and calls, but connection has
141
+ its own timeout behavior.
142
+
143
+ ## Plan concurrency and cancellation
144
+
145
+ Most applications only need transport timeouts. The details below matter when
146
+ the application uses a Fiber scheduler or runs independent Tools concurrently.
147
+
148
+ ### Connection
149
+
150
+ LittleGhost connects while it discovers the Agent's Tools. Run cancellation
151
+ does not interrupt connection, so the transport's connection and read timeouts
152
+ control how long it can wait. Choose a scheduler-compatible transport adapter
153
+ when other fibers must continue during that time.
154
+
155
+ ### Tool discovery and calls
156
+
157
+ Tool discovery and calls honor Run cancellation and deadlines. Cancelling an
158
+ HTTP call returns control to the Run, but the underlying request may continue
159
+ waiting until the server responds or the transport closes.
160
+
161
+ All Tools for one run share the same client. HTTP calls may overlap when
162
+ LittleGhost runs independent Tools concurrently, so choose a Faraday adapter
163
+ that supports overlapping calls. If the server or transport requires one call
164
+ at a time, mark the generated Tools exclusive:
165
+
166
+ ```ruby
167
+ map_tool do |tool_class, mcp_tool:, binding:|
168
+ tool_class.exclusive true
169
+ tool_class
170
+ end
171
+ ```
172
+
173
+ LittleGhost serializes calls through the official stdio transport. If one of
174
+ those calls is cancelled, it closes that run's session rather than risk reading
175
+ a late response as the answer to a later call. A custom or decorated stdio
176
+ transport must provide its own serialization, cancellation behavior, and
177
+ cleanup.
178
+
179
+ ### Server handlers
180
+
181
+ The server may invoke a handler while other work is active. Write handlers for
182
+ concurrent use and capture the application values they need when building the
183
+ client. Do not rely on fiber-local state inside a handler.
184
+
185
+ ## Select and map Tools
186
+
187
+ By default, the Agent receives every Tool published by the server. LittleGhost
188
+ normalizes each name for the model and keeps the server's original name for
189
+ calls. Discovery stops after 1,000 Tools or 100 pages, which bounds the work an
190
+ untrusted catalog can create in one run.
191
+
192
+ Use `map_tool` to omit operations or configure their generated classes:
193
+
194
+ ```ruby
195
+ class CuratedHelpCenterTools < HelpCenterTools
196
+ map_tool do |tool_class, mcp_tool:, binding:|
197
+ next unless %w[search fetch].include?(mcp_tool.name)
198
+
199
+ tool_class.tool_name "help_center_#{mcp_tool.name}"
200
+ tool_class
201
+ end
202
+ end
203
+ ```
204
+
205
+ `mcp_tool` is the Tool published by the official client. Return the generated
206
+ class, a subclass, or `nil` to omit it. Renaming the generated Tool changes the
207
+ name shown to the model, not the name sent back to the server.
208
+
209
+ LittleGhost sends the server's input schema to the model unchanged. It does not
210
+ validate arguments against that schema; the server must validate them before
211
+ performing an operation. LittleGhost limits schema depth and node count during
212
+ discovery. Configure the transport's message-size limit to bound the bytes
213
+ accepted from a server.
214
+
215
+ > **Safety note:** Server descriptions and results become visible to the model.
216
+ > Treat them as untrusted content. Expose only the operations the Agent needs,
217
+ > use narrowly scoped credentials, and have the server authorize every sensitive
218
+ > call.
219
+
220
+ ## Convert results
221
+
222
+ Without a mapping, LittleGhost returns `structuredContent` when the server sends
223
+ it. Otherwise, it returns the text or remaining visible content blocks. MCP
224
+ image blocks become Artifacts.
225
+
226
+ Suppose the help-center server returns `structuredContent` with an `articles`
227
+ array. Use `map_result` to present each article as a short line:
228
+
229
+ ```ruby
230
+ map_result do |value, mcp_tool:, **|
231
+ next value unless mcp_tool.name == "search"
232
+
233
+ value.fetch("articles").map do |article|
234
+ "#{article.fetch("title")}: #{article.fetch("url")}"
235
+ end
236
+ end
237
+ ```
238
+
239
+ `value` is LittleGhost's default conversion, and `mcp_tool` identifies the
240
+ server operation. Return `value` unchanged or replace it with any Ruby value or
241
+ `Tool::Result`. The block can also receive the raw result, sent arguments, and
242
+ current binding; see the [`MCP::Toolset`
243
+ API](rdoc-ref:LittleGhost::MCP::Toolset) for their exact shapes.
244
+
245
+ Image Artifacts remain attached to the mapped result. A server result marked
246
+ `isError` remains a model-visible Tool error.
247
+
248
+ For custom images, files, or deferred Artifacts, continue with [Structured
249
+ Results and Content](structured_outputs_and_content.md). A deferred resolver
250
+ must verify ownership, fetch only from the intended service, and limit response
251
+ size.
252
+
253
+ ## Keep an optional server from blocking a run
254
+
255
+ An optional server can fail discovery without preventing Agent construction:
256
+
257
+ ```ruby
258
+ class OptionalHelpCenterTools < HelpCenterTools
259
+ optional true
260
+ on_error do |error, binding:|
261
+ McpAvailability.report(error, run_id: binding.run.invocation.run_id)
262
+ end
263
+ end
264
+ ```
265
+
266
+ `optional true` turns an expected connection or protocol error during discovery
267
+ into an empty Tool set. Configuration errors, cancellation, deadlines, and
268
+ failures in application callbacks still stop the run.
269
+
270
+ ## Let the SDK negotiate the protocol version
271
+
272
+ The [official MCP Ruby SDK](https://github.com/modelcontextprotocol/ruby-sdk)
273
+ handles protocol negotiation and transport behavior. Without explicit connect
274
+ options, it negotiates with the server using a protocol version the installed
275
+ SDK supports. Pin `protocol_version` or `mode` only when interoperability
276
+ requires it.
277
+
278
+ Need sampling, roots, elicitation, or another client capability? Configure it
279
+ on the client you build above. The installed SDK and negotiated protocol version
280
+ determine what is available. Check the [Ruby SDK client
281
+ documentation](https://ruby.sdk.modelcontextprotocol.io/client/) and the
282
+ [versioned MCP specification](https://modelcontextprotocol.io/specification/)
283
+ for the capability you need.
284
+
285
+ Continue with [Tools](tools.md) for the local Tool boundary,
286
+ [Integrations](integrations.md) to send Runs through AG-UI or OpenTelemetry, or
287
+ the [`MCP::Toolset` API](rdoc-ref:LittleGhost::MCP::Toolset) for exact mapping
288
+ and ownership contracts.
@@ -62,11 +62,11 @@ run = CustomerSupportAgent.ask(
62
62
  Build these settings in application code instead of passing request parameters
63
63
  through unchanged. Settings can affect cost, latency, and model behavior.
64
64
 
65
- ## Configure connections in one place
65
+ ## Connect the provider you chose
66
66
 
67
- LittleGhost includes adapters for OpenRouter, OpenAI-compatible APIs,
68
- Anthropic, Gemini, Vertex AI, and Bedrock. Connections may live in an
69
- initializer or in the conventional files under `config/little_ghost`.
67
+ Connections may live in an initializer or in the conventional files under
68
+ `config/little_ghost`. [Provider Support](providers.md) has copyable settings
69
+ for each built-in adapter, compatible endpoints, Ollama, and LM Studio.
70
70
 
71
71
  Keep credentials in your application's secret manager. Agents refer to a role
72
72
  or configured connection; they don't need to contain credentials. If your
@@ -120,6 +120,11 @@ choose a structured-result strategy.
120
120
  Provider capabilities can change. Handle failed Runs and provider errors even
121
121
  when the catalog says a feature is supported.
122
122
 
123
+ Most application code does not call the resolver directly. Declaring an
124
+ Agent's model, or passing `model:` to generation or embedding, resolves the
125
+ selection for you. Inspect model details when an interface needs to explain
126
+ limits or your application wants to check an attachment before sending it.
127
+
123
128
  ## Call a model without an Agent
124
129
 
125
130
  Some application work needs one model response rather than an Agent. Use
@@ -141,57 +146,23 @@ response.usage.total_tokens
141
146
  ```
142
147
 
143
148
  The operation returns a `LittleGhost::RunResult`, the same result type returned
144
- by an Agent invocation, so
145
- application code can read `output`, `usage`, and the final message in the same
146
- way. Plain generation makes one model request without starting an Agent or
147
- creating a Run. Structured generation may make one additional repair request.
148
-
149
- Pass a strict object schema when application code needs checked JSON:
149
+ by an Agent invocation. Application code can read `output`, `usage`, and the
150
+ final message in the same way. Plain generation makes one model request without
151
+ starting an Agent or creating a Run.
150
152
 
151
- ```ruby
152
- response = LittleGhost.generate(
153
- model: :customer_support,
154
- messages: [{role: :user, content: "My transfer is still pending."}],
155
- result_schema: {
156
- name: "classification",
157
- description: "Classify one support request",
158
- schema: {
159
- type: "object",
160
- properties: {category: {type: "string"}},
161
- required: ["category"],
162
- additionalProperties: false
163
- }
164
- }
165
- )
166
-
167
- response.output
168
- ```
169
-
170
- LittleGhost checks the result against the schema and gives the model one repair
171
- attempt by default. Add `structured_result_repair_attempts: 3` to the call
172
- above when a checked result warrants additional attempts. The setting accepts
173
- integers from zero through three.
174
-
175
- Read the checked value through `response.output`. If every permitted attempt is
176
- invalid, the call raises `LittleGhost::StructuredResultError`.
177
-
178
- A schema checks the shape of a value, not whether your application should act
179
- on it. Check identifiers, permissions, and business rules before using the
180
- result to change application state.
153
+ Pass `result_schema:` when application code needs checked JSON. [Structured
154
+ Results and Content](structured_outputs_and_content.md) covers strict schemas,
155
+ provider strategies, repair behavior, and the application checks that still
156
+ belong outside the schema.
181
157
 
182
158
  ## Create embeddings
183
159
 
184
160
  Use `LittleGhost.embed` when your application needs numeric representations for
185
161
  search, clustering, or another similarity-based feature:
186
162
 
187
- The example assumes application startup maps `search_embeddings` to an
188
- embedding model, following the role configuration shown earlier on this page.
189
- The selected provider adapter's API reference lists the model-specific
190
- settings.
191
-
192
163
  ```ruby
193
164
  response = LittleGhost.embed(
194
- model: :search_embeddings,
165
+ model: "primary:openai/text-embedding-3-small",
195
166
  inputs: ["Reset a password", "Track a transfer"]
196
167
  )
197
168
 
@@ -202,14 +173,10 @@ response.usage.input_tokens
202
173
 
203
174
  The response keeps vectors in the same order as the inputs. LittleGhost rejects
204
175
  an incomplete or malformed response instead of returning a partial batch.
205
- Choose the embedding model and request settings in trusted application
206
- configuration, and keep each call within a workload size your application can
207
- retry safely.
208
-
209
- Embedding text is sent to the selected provider. Choose a provider that is
210
- appropriate for that data, just as you would for an Agent request. See
211
- `LittleGhost::Embeddings::Request` and your provider adapter's API reference for
212
- the supported settings and request bounds.
176
+ Embedding text is sent to the selected provider, so choose one appropriate for
177
+ that data. [Provider Support](providers.md) identifies adapters with embedding
178
+ support; `LittleGhost::Embeddings::Request` documents settings and request
179
+ bounds.
213
180
 
214
181
  Continue with [Prompts as Views](prompt_views.md) when an Agent's instructions
215
182
  outgrow one string. See [Structured Results and Content](structured_outputs_and_content.md)
@@ -37,7 +37,15 @@ class CustomerSupportAgent < LittleGhost::Agent
37
37
  end
38
38
  ```
39
39
 
40
- Provider connections and model roles can also live in YAML files under `config/little_ghost`, or in files you select explicitly. Values set in Ruby take priority. An explicitly selected file comes next, followed by conventional files and environment defaults. See `LittleGhost::Configuration` when you need every supported source and override.
40
+ Provider connections and model roles can live in the Ruby initializer or in
41
+ YAML under `config/little_ghost`. Values set in Ruby take priority. See
42
+ `LittleGhost::Configuration` for custom files and the full precedence order.
43
+
44
+ [Provider Support](providers.md) lists the credentials and endpoint settings
45
+ for hosted and local providers. Choose connection names, model identifiers,
46
+ and custom headers during application startup. Read secrets from deployment
47
+ configuration or a secret manager; do not copy request parameters into these
48
+ settings.
41
49
 
42
50
  Prompts, caller input and history, Tool results, and attachments may go to the
43
51
  selected provider. Choose configured providers that are appropriate for that
@@ -289,14 +297,15 @@ LittleGhost.configure do |config|
289
297
  end
290
298
  config.sandbox = {
291
299
  provider: :native,
292
- files: {root: :read_write},
293
- root_filesystem: :isolated,
294
- environment: {inherit: false, set: {"LANG" => "C.UTF-8"}},
295
- network: :none
300
+ files: {root: :read_write}
296
301
  }
297
302
  end
298
303
  ```
299
304
 
305
+ The native backend isolates the host root, removes child-process network
306
+ access, and starts with a scrubbed child environment unless you configure a
307
+ different policy.
308
+
300
309
  The temporary Workspace above is useful when files should live for one Run. Use application-managed storage, with tenant isolation and concurrency control, when files must persist or several Runs share a root.
301
310
 
302
311
  The Run opens a Runtime-created Workspace before its Sandbox and closes them in reverse order after every outcome. Closing a Workspace invokes its configured teardown; it does not delete files by default. Cleanup failures raise because LittleGhost cannot confirm a clean shutdown of every owned resource. Existing instances passed by the application remain caller-owned.