little_ghost 0.4.0 → 0.6.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 (124) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +28 -6
  3. data/docs/guides/assemblies.md +143 -17
  4. data/docs/guides/code_mode.md +276 -0
  5. data/docs/guides/core_concepts.md +46 -30
  6. data/docs/guides/getting_started.md +17 -6
  7. data/docs/guides/integrations.md +217 -0
  8. data/docs/guides/models_and_providers.md +125 -0
  9. data/docs/guides/production.md +190 -17
  10. data/docs/guides/prompt_views.md +14 -7
  11. data/docs/guides/sandboxing.md +282 -0
  12. data/docs/guides/skills.md +141 -0
  13. data/docs/guides/structured_outputs_and_content.md +135 -0
  14. data/docs/guides/tools.md +355 -0
  15. data/lib/little_ghost/ag_ui/adapter.rb +2 -2
  16. data/lib/little_ghost/agent/delegation.rb +2 -2
  17. data/lib/little_ghost/agent/skills.rb +6 -1
  18. data/lib/little_ghost/agent/tool_loop.rb +6 -2
  19. data/lib/little_ghost/agent.rb +250 -48
  20. data/lib/little_ghost/agent_builder.rb +61 -22
  21. data/lib/little_ghost/agent_stream_source.rb +262 -0
  22. data/lib/little_ghost/artifact.rb +182 -0
  23. data/lib/little_ghost/artifacts/presentation_budget.rb +44 -0
  24. data/lib/little_ghost/artifacts/workspace_store.rb +370 -0
  25. data/lib/little_ghost/artifacts.rb +11 -0
  26. data/lib/little_ghost/assembly.rb +64 -20
  27. data/lib/little_ghost/assembly_builder.rb +26 -26
  28. data/lib/little_ghost/assembly_execution.rb +23 -11
  29. data/lib/little_ghost/code_mode/broker.rb +168 -0
  30. data/lib/little_ghost/code_mode/catalog.rb +54 -0
  31. data/lib/little_ghost/code_mode/engine.rb +58 -0
  32. data/lib/little_ghost/code_mode/javascript/catalog.rb +118 -0
  33. data/lib/little_ghost/code_mode/javascript/client.rb +550 -0
  34. data/lib/little_ghost/code_mode/javascript/host.rb +347 -0
  35. data/lib/little_ghost/code_mode/javascript/session.rb +578 -0
  36. data/lib/little_ghost/code_mode/javascript_engine.rb +172 -0
  37. data/lib/little_ghost/code_mode/protocol.rb +78 -0
  38. data/lib/little_ghost/code_mode/ruby/catalog.rb +80 -0
  39. data/lib/little_ghost/code_mode/ruby/host.rb +102 -0
  40. data/lib/little_ghost/code_mode/ruby/session.rb +508 -0
  41. data/lib/little_ghost/code_mode/ruby_engine.rb +86 -0
  42. data/lib/little_ghost/code_mode/runtime.rb +335 -0
  43. data/lib/little_ghost/code_mode/session.rb +61 -0
  44. data/lib/little_ghost/code_mode/types.rb +58 -0
  45. data/lib/little_ghost/code_mode.rb +53 -0
  46. data/lib/little_ghost/configuration.rb +208 -21
  47. data/lib/little_ghost/content.rb +19 -8
  48. data/lib/little_ghost/data_map.rb +2 -2
  49. data/lib/little_ghost/errors.rb +26 -7
  50. data/lib/little_ghost/execution.rb +32 -27
  51. data/lib/little_ghost/execution_state.rb +3 -3
  52. data/lib/little_ghost/graph.rb +373 -210
  53. data/lib/little_ghost/instrumentation.rb +2 -1
  54. data/lib/little_ghost/mcp/client.rb +487 -88
  55. data/lib/little_ghost/mcp/toolset.rb +210 -0
  56. data/lib/little_ghost/mcp/types.rb +216 -0
  57. data/lib/little_ghost/mcp.rb +3 -0
  58. data/lib/little_ghost/model_capabilities.rb +9 -6
  59. data/lib/little_ghost/model_request.rb +0 -12
  60. data/lib/little_ghost/model_resolver.rb +13 -3
  61. data/lib/little_ghost/model_response.rb +3 -7
  62. data/lib/little_ghost/network/authorizer_server.rb +162 -0
  63. data/lib/little_ghost/network/certificate_authority.rb +104 -0
  64. data/lib/little_ghost/network/envoy_config.rb +362 -0
  65. data/lib/little_ghost/network/envoy_gateway.rb +418 -0
  66. data/lib/little_ghost/network/external_gateway.rb +68 -0
  67. data/lib/little_ghost/network.rb +96 -0
  68. data/lib/little_ghost/prompt_resolver.rb +7 -7
  69. data/lib/little_ghost/provider_registry.rb +3 -3
  70. data/lib/little_ghost/providers/anthropic.rb +8 -1
  71. data/lib/little_ghost/providers/gemini.rb +10 -1
  72. data/lib/little_ghost/providers/vertex_ai.rb +6 -1
  73. data/lib/little_ghost/run.rb +89 -25
  74. data/lib/little_ghost/run_context.rb +11 -1
  75. data/lib/little_ghost/run_result.rb +0 -7
  76. data/lib/little_ghost/runtime/hook.rb +5 -0
  77. data/lib/little_ghost/runtime/hooks/artifacts.rb +338 -0
  78. data/lib/little_ghost/runtime.rb +111 -34
  79. data/lib/little_ghost/sandbox/capabilities.rb +68 -0
  80. data/lib/little_ghost/sandbox/environment_policy.rb +41 -0
  81. data/lib/little_ghost/sandbox/filesystem.rb +377 -0
  82. data/lib/little_ghost/sandbox/isolated_backend.rb +163 -0
  83. data/lib/little_ghost/sandbox/limits.rb +48 -0
  84. data/lib/little_ghost/sandbox/mount.rb +129 -0
  85. data/lib/little_ghost/sandbox/network_policy.rb +108 -0
  86. data/lib/little_ghost/sandbox/policy.rb +88 -0
  87. data/lib/little_ghost/sandbox/process_runner.rb +103 -0
  88. data/lib/little_ghost/sandbox/process_session.rb +335 -0
  89. data/lib/little_ghost/sandbox/scope.rb +304 -0
  90. data/lib/little_ghost/sandbox.rb +158 -32
  91. data/lib/little_ghost/sandboxes/bubblewrap.rb +351 -0
  92. data/lib/little_ghost/sandboxes/native.rb +51 -0
  93. data/lib/little_ghost/sandboxes/seatbelt.rb +261 -0
  94. data/lib/little_ghost/sandboxes/unrestricted.rb +240 -0
  95. data/lib/little_ghost/session.rb +30 -6
  96. data/lib/little_ghost/session_stores/filesystem.rb +29 -13
  97. data/lib/little_ghost/skills/catalog.rb +94 -14
  98. data/lib/little_ghost/skills/resource_root.rb +42 -0
  99. data/lib/little_ghost/skills/skill.rb +0 -3
  100. data/lib/little_ghost/stream_event.rb +8 -13
  101. data/lib/little_ghost/subagents/control_tool.rb +8 -0
  102. data/lib/little_ghost/subagents/manager.rb +182 -79
  103. data/lib/little_ghost/support/callbacks.rb +3 -1
  104. data/lib/little_ghost/support/cancellation_token.rb +2 -2
  105. data/lib/little_ghost/support/content_capture.rb +3 -3
  106. data/lib/little_ghost/support/executor.rb +84 -15
  107. data/lib/little_ghost/support/http_client.rb +11 -4
  108. data/lib/little_ghost/support/interruptible_stream.rb +4 -2
  109. data/lib/little_ghost/support/pooled_thread_runner.rb +126 -0
  110. data/lib/little_ghost/support/redactor.rb +1 -1
  111. data/lib/little_ghost/support/serialized_dispatcher.rb +84 -0
  112. data/lib/little_ghost/support/task.rb +126 -0
  113. data/lib/little_ghost/support/task_runner.rb +74 -0
  114. data/lib/little_ghost/support.rb +4 -0
  115. data/lib/little_ghost/tool.rb +104 -53
  116. data/lib/little_ghost/tool_registry.rb +1 -1
  117. data/lib/little_ghost/tools/filesystem.rb +1 -1
  118. data/lib/little_ghost/tools/shell.rb +4 -3
  119. data/lib/little_ghost/version.rb +1 -1
  120. data/lib/little_ghost/workflow.rb +3 -3
  121. data/lib/little_ghost/workspace.rb +222 -8
  122. data/lib/little_ghost.rb +38 -12
  123. metadata +116 -2
  124. data/lib/little_ghost/unrestricted_sandbox.rb +0 -306
@@ -1,6 +1,6 @@
1
1
  # Core Concepts
2
2
 
3
- Build one model-driven behavior in a Ruby class, then call it like Ruby. That is the idea LittleGhost grows from.
3
+ Define an Agent in a Ruby class, then call it with `.ask`.
4
4
 
5
5
  ```ruby
6
6
  class CustomerSupportAgent < LittleGhost::Agent
@@ -29,7 +29,8 @@ CustomerSupportAgent
29
29
  └── limits and optional capabilities
30
30
  ```
31
31
 
32
- An Agent can return text or checked, structured data. Later, you can add streaming, sessions, or callbacks. None of them are required to begin.
32
+ An Agent can return text or checked, structured data. You can add streaming,
33
+ saved conversations, or callbacks later. None of them are required to begin.
33
34
 
34
35
  ## A Tool connects the model to Ruby
35
36
 
@@ -52,7 +53,12 @@ class HelpCenterLookupTool < LittleGhost::Tool
52
53
  end
53
54
  ```
54
55
 
55
- LittleGhost checks the model's arguments, calls the tool, and gives the result back to the model. The schema checks shape, not permission. Authorize sensitive reads and actions inside the tool with trusted application context.
56
+ LittleGhost checks the model's arguments, calls the Tool, and gives the result
57
+ back to the model. The schema checks shape, not permission. Check permission
58
+ inside the Tool using identity and account information from your application.
59
+
60
+ [Tools](tools.md) follows that path from model input to application code,
61
+ including run-scoped bindings, concurrency, retries, and sandbox delegation.
56
62
 
57
63
  ## A Run owns one top-level execution
58
64
 
@@ -81,11 +87,21 @@ Run
81
87
  └── Agent and Tools ──> RunResult
82
88
  ```
83
89
 
84
- An **Invocation** is the request in LittleGhost's standard shape. Its `context` contains current request values supplied by your application. A Tool can read those values through `run.invocation.context` when it authorizes work.
90
+ An **Invocation** is the request in LittleGhost's standard shape. Its `context`
91
+ contains current request values supplied by your application. A Tool can read
92
+ those values through `run.invocation.context` when it checks permission.
85
93
 
86
- The **RunContext** carries mutable working state in `context.state`. At the top level, saved Session state is loaded first, then current Invocation context is added. Child Assemblies may receive a copy, a mapped value, or no context at all. Recheck saved values before using them for permission decisions.
94
+ A **Session** stores conversation state between Runs when persistence is
95
+ configured. The **RunContext** carries mutable working state in `context.state`
96
+ during one Run. LittleGhost loads saved Session state before adding the current
97
+ Invocation context. Recheck saved values before using them for permission
98
+ decisions.
87
99
 
88
- A Tool's **Binding** gives the Tool access to objects created for this run, including the Agent, Run, workspace, and sandbox. These objects are separate from the arguments chosen by the model.
100
+ A Tool's **Binding** gives the Tool access to objects created for this run,
101
+ including the Agent, Run, Workspace, and Sandbox. These objects are separate
102
+ from arguments chosen by the model. [Tools](tools.md) explains the binding;
103
+ [Workspaces and Sandboxes](sandboxing.md) explains delegated files and child
104
+ processes.
89
105
 
90
106
  The final **RunResult** keeps the complete assembly result. Its `text` is the final text answer. Its `output` returns structured data when the Agent declared a result schema, and text otherwise. The top-level `Run#response` is always the caller-facing text.
91
107
 
@@ -102,9 +118,13 @@ Top-level calls normally return a Run, even when execution fails. The terminal e
102
118
  | Tool input or a `ToolError` failed | The model may recover | No terminal event by itself | Gives a safe error result back to the model |
103
119
  | Input, configuration, or resources failed before a Run could start | No Run exists | None | Raises the exception |
104
120
 
105
- Unexpected Tool exception messages are hidden from the model. The original exception remains available to trusted application callbacks and diagnostics.
121
+ Unexpected Tool exception messages are hidden from the model. The original
122
+ exception remains available to application callbacks and diagnostics.
106
123
 
107
- Failures while closing resources, delivering events, or reporting instrumentation sit outside the normal result path. They raise a Ruby exception because LittleGhost can no longer promise that it delivered a clean ending. [Running in Production](production.md) covers that boundary where applications supervise and shut down work.
124
+ Failures while closing resources, delivering events, or reporting
125
+ instrumentation sit outside the normal result path. They raise a Ruby exception
126
+ because LittleGhost can no longer promise that it delivered a clean ending.
127
+ [Running in Production](production.md) covers supervision and shutdown.
108
128
 
109
129
  ## An Assembly can look like one Agent
110
130
 
@@ -146,6 +166,10 @@ end
146
166
 
147
167
  Use a subagent when delegation is part of one model's decision-making. Use a Workflow when application code must guarantee that a step happens.
148
168
 
169
+ When an Agent also uses code mode, subagent controls stay in the Agent's
170
+ conversation. Code-mode programs can compose ordinary Tools, while spawning,
171
+ messaging, and checking on subagents remain decisions for the parent model.
172
+
149
173
  ### Workflows make Ruby the coordinator
150
174
 
151
175
  A **Workflow** coordinates work with ordinary Ruby. Its `perform` method can call an Agent or another Assembly, read a result, choose a branch, or run independent steps together.
@@ -185,7 +209,10 @@ class ProblemSolverSwarm < LittleGhost::Swarm
185
209
  end
186
210
  ```
187
211
 
188
- A Swarm is intentionally agent-to-agent. Its members are Agents, not other kinds of Assembly. Caller history and application context stay hidden unless a member opts in. Treat every handoff message as untrusted model input.
212
+ A Swarm is intentionally agent-to-agent. Its members are Agents, not other
213
+ kinds of Assembly. Caller history and application context stay hidden unless a
214
+ member opts in. A handoff message comes from another model, so a receiving
215
+ Agent should use it as context rather than proof that an action is permitted.
189
216
 
190
217
  ### Graphs make routes visible
191
218
 
@@ -209,26 +236,12 @@ class SupportFlowGraph < LittleGhost::Graph
209
236
  end
210
237
  ```
211
238
 
212
- Graph nodes do not receive caller history or application context unless they opt in. They still receive the original request and the outputs routed to them. Use edge input mappers to choose or redact what moves forward.
213
-
214
- ## Class definitions first, builders when needed
215
-
216
- Named classes are the default way to organize reusable behavior. They are readable, load through normal Ruby conventions, and give the coordination style a visible name such as `ResponseWorkflow` or `SupportFlowGraph`.
217
-
218
- Every assembly class can also produce a mutable builder:
219
-
220
- ```ruby
221
- graph = SupportFlowGraph.to_builder
222
- graph.node :audit, AuditAgent
223
- graph.edge :respond, :audit
224
- graph.finish :audit
225
- graph.validate!
226
- run = graph.ask("Review order 481")
227
- ```
228
-
229
- Use a builder when trusted application configuration decides the participants or routes. Each run gets a fixed copy of the builder as it looked when the run began, so later edits affect later runs. Ruby callbacks still see any application objects they captured.
239
+ Graph nodes receive the original task and results from the nodes immediately
240
+ before them. They do not receive caller history or application context unless
241
+ their declarations opt in. [Compose Agents](assemblies.md) explains parallel
242
+ routes, joins, input mapping, and data boundaries.
230
243
 
231
- ## One result, including the journey
244
+ ## One result, even when several agents help
232
245
 
233
246
  Every assembly produces the same top-level `Run` and final `RunResult`. Composite assemblies also keep a size-limited record of the participants that ran:
234
247
 
@@ -240,8 +253,11 @@ run.result.steps
240
253
  run.result.trajectory.transitions
241
254
  ```
242
255
 
243
- This shows callers which participants ran without including raw provider responses. A Swarm or Graph may hide intermediate model events from the public stream so the response stays coherent. That is a presentation choice, not a privacy boundary: routed outputs and step summaries still exist.
256
+ This record shows which participants ran. [Compose Agents](assemblies.md)
257
+ explains builders, detailed routing records, and live events from nested Agents.
244
258
 
245
259
  The pieces now fit together: Agents define behavior. Tools connect them to Ruby. Runs record one execution. Assemblies let the system grow without changing the caller.
246
260
 
247
- Continue with [Compose Agents](assemblies.md) to put several agents to work together. If you are ready to connect the feature to a real application, jump to [Running in Production](production.md).
261
+ Continue with [Models and Providers](models_and_providers.md) to choose model
262
+ targets and configure provider connections. When you need several agents to
263
+ work together, [Compose Agents](assemblies.md) builds on the same concepts.
@@ -48,7 +48,7 @@ $ ruby customer_support_agent.rb
48
48
 
49
49
  `CustomerSupportAgent.ask` creates a `LittleGhost::Run` for this request. When the work finishes, the Run holds the outcome and response.
50
50
 
51
- The inline prompt keeps this first example easy to see in one place. When the instructions grow, [Prompts as Views](prompt_views.md) moves them into a conventional ERB file without adding setup to the Agent.
51
+ The inline prompt keeps this first example visible in one place. When the instructions grow, [Prompts as Views](prompt_views.md) moves them into a conventional ERB file without adding setup to the Agent.
52
52
 
53
53
  The selected external provider may receive system instructions, caller input, conversation history, tool results, and attachments. Model wording can vary, so use application code—not a prompt—when a rule must always hold.
54
54
 
@@ -101,13 +101,18 @@ run.response
101
101
  # Refunds are available within 30 days, so your purchase is eligible.
102
102
  ```
103
103
 
104
- LittleGhost checks the model's arguments before it calls `HelpCenterLookupTool#call`. The schema checks shape, not permission. If a tool reads customer data or changes something, authorize that work from trusted application context. The tool's result then becomes context for the model.
104
+ LittleGhost checks the model's arguments before it calls
105
+ `HelpCenterLookupTool#call`. The Tool's result then becomes context for the
106
+ model.
105
107
 
106
- ### Use trusted context for private data
108
+ ### Use application context for private data
107
109
 
108
- Model tool arguments are untrusted, even after their shape has been checked. Pass identity and permissions from your application's authentication boundary instead.
110
+ The schema checks shape, not permission. When a Tool reads private data or
111
+ changes something, use identity and account information established by your
112
+ application rather than asking the model to supply it.
109
113
 
110
- While an Agent is working, LittleGhost binds each Tool instance to the current Run. The Tool can read trusted request values through its `run` accessor:
114
+ While an Agent is working, LittleGhost binds each Tool instance to the current
115
+ Run. The Tool can read request values through its `run` accessor:
111
116
 
112
117
  ```ruby
113
118
  class OrderStatusTool < LittleGhost::Tool
@@ -147,7 +152,13 @@ run = CustomerSupportAgent.ask(
147
152
  )
148
153
  ```
149
154
 
150
- Here, `order_number` came from the model. The application supplied `actor_id` and `account_id` after authenticating the caller. LittleGhost places those request values on `run.invocation`; context keys become strings. The model cannot replace them through its tool arguments.
155
+ Here, `order_number` came from the model. The application supplied `actor_id`
156
+ and `account_id` after authenticating the caller. LittleGhost places those
157
+ request values on `run.invocation`; context keys become strings.
158
+
159
+ > **Safety note:** Treat model-selected Tool arguments like any other external
160
+ > input. Check permission using the current user and account before returning
161
+ > private data or performing a write.
151
162
 
152
163
  That is enough to authorize the first Tool safely. [Core Concepts](core_concepts.md) names the request and working-state objects behind `run`, and [Running in Production](production.md) explains what changes when you add saved conversations.
153
164
 
@@ -0,0 +1,217 @@
1
+ # Connect MCP, AG-UI, and OpenTelemetry
2
+
3
+ LittleGhost can load Tools from an MCP server, translate a Run stream for an
4
+ interactive interface, and publish traces. Each integration uses the same
5
+ Agents and Runs you already have.
6
+
7
+ ## Load Tools from an MCP server
8
+
9
+ An MCP Toolset connects to one server and turns its published operations into
10
+ LittleGhost Tool classes. Add the Toolset through the same Agent `tools`
11
+ declaration used for local Tools:
12
+
13
+ ```ruby
14
+ require "little_ghost/mcp"
15
+
16
+ class HelpCenterTools < LittleGhost::MCP::Toolset
17
+ connection url: "https://mcp.example/rpc", timeout: 20
18
+ end
19
+
20
+ class CustomerSupportAgent < LittleGhost::Agent
21
+ system_prompt "Use help-center tools for published guidance."
22
+ tools HelpCenterTools
23
+ end
24
+
25
+ run = CustomerSupportAgent.ask("How long do refunds take?")
26
+ run.response
27
+ ```
28
+
29
+ `connection` requires `url` and also accepts `headers`, `timeout`, `signer`,
30
+ `allow_insecure_http`, and `max_response_bytes`. Pass a block when credentials
31
+ depend on the current Agent run:
32
+
33
+ ```ruby
34
+ connection do |binding|
35
+ token = McpAccessTokens.for_actor(binding.run.invocation.actor_id)
36
+ {
37
+ url: "https://mcp.example/rpc",
38
+ headers: {"Authorization" => "Bearer #{token}"},
39
+ timeout: 20
40
+ }
41
+ end
42
+ ```
43
+
44
+ The block's `binding` gives it access to the current Run. LittleGhost evaluates
45
+ the block before opening the MCP session, so each Agent run can use credentials
46
+ for its authenticated caller.
47
+
48
+ By default, the Agent receives every operation published by the server. Their
49
+ normalized server names, such as `search` and `fetch`, become Tool names.
50
+
51
+ Use `map_tool` when the Agent should receive only part of the server catalog or
52
+ when a generated Tool needs a different name or configuration:
53
+
54
+ ```ruby
55
+ class CuratedHelpCenterTools < LittleGhost::MCP::Toolset
56
+ connection url: "https://mcp.example/rpc", timeout: 20
57
+
58
+ map_tool do |tool_class, definition:, binding:|
59
+ next unless %w[search fetch].include?(definition.source_name)
60
+
61
+ tool_class.tool_name "help_center_#{definition.source_name}"
62
+ tool_class
63
+ end
64
+ end
65
+ ```
66
+
67
+ `definition` describes the operation published by the server, and `binding`
68
+ identifies the current Agent run. Return the class after configuring it, or
69
+ return `nil` to omit the operation. Renaming a generated Tool does not change
70
+ the original `Definition#source_name` sent back to the server.
71
+
72
+ The Agent can call the generated Tools like local Tools. LittleGhost uses one
73
+ local client and transport for the Toolset during the Agent run. The built-in
74
+ HTTP transport does not send an MCP session-termination request. Configure
75
+ server-side expiry, or arrange explicit remote cleanup when the server requires
76
+ it.
77
+
78
+ Most MCP results need no mapping. LittleGhost returns `structuredContent` as a
79
+ Ruby Hash when present, otherwise it returns the server's text. Server images
80
+ become Artifacts.
81
+
82
+ Use `map_result` when one operation needs application-specific conversion. This
83
+ example turns the server's download identifier into a deferred Artifact:
84
+
85
+ ```ruby
86
+ map_result do |result, call:, binding:|
87
+ next result unless call.definition.source_name == "export"
88
+
89
+ LittleGhost::Tool::Result.new(
90
+ value: result.structured_content,
91
+ artifacts: [
92
+ LittleGhost::Artifact.deferred(
93
+ reference: result.metadata.fetch("download_id"),
94
+ media_type: "application/octet-stream"
95
+ )
96
+ ]
97
+ )
98
+ end
99
+ ```
100
+
101
+ `map_result` receives the complete `MCP::Result`, the `MCP::Call` that produced
102
+ it, and the current binding. Return any Ruby value or `Tool::Result`. Returning
103
+ the supplied result unchanged keeps the default conversion described above.
104
+ MCP images and local Tool artifacts use the same storage and presentation
105
+ rules when `Configuration#artifacts` is enabled. Images and documents are sent
106
+ as model content; their stored references are fallback information rather than
107
+ a second representation. LittleGhost also checks results against
108
+ server-advertised JSON Schema Draft 2020-12 output schemas.
109
+
110
+ An optional server can fail discovery without preventing Agent construction:
111
+
112
+ ```ruby
113
+ class HelpCenterTools < LittleGhost::MCP::Toolset
114
+ connection { |binding| McpConnections.help_center(binding) }
115
+ optional true
116
+ on_error do |error, binding:|
117
+ McpAvailability.report(error, run_id: binding.run.invocation.run_id)
118
+ end
119
+ end
120
+ ```
121
+
122
+ `optional true` converts expected provider and protocol discovery failures
123
+ into an empty Tool set. `on_error` observes only those caught failures.
124
+ Cancellation, deadlines, configuration errors, and application callback
125
+ failures still propagate.
126
+
127
+ LittleGhost limits the number and total size of discovered operations, the
128
+ complexity of their schemas, and the size and number of returned images.
129
+ `HTTPTransport` also limits each HTTP response and requires HTTPS unless local
130
+ HTTP is explicitly enabled.
131
+
132
+ > **Safety note:** An MCP server supplies descriptions and results that the model
133
+ > can see. Structural validation does not make that content trustworthy or
134
+ > authorize an operation it suggests. Expose only the operations the Agent
135
+ > needs, use narrowly scoped credentials, and have the server authorize every
136
+ > sensitive call. If a result becomes a deferred Artifact, its resolver must
137
+ > verify that the referenced file belongs to the authenticated caller, fetch
138
+ > only from an intended service, and limit the response size before returning
139
+ > bytes to LittleGhost.
140
+
141
+ LittleGhost implements its documented client behavior for the [MCP 2025-06-18
142
+ specification](https://modelcontextprotocol.io/specification/2025-06-18).
143
+
144
+ Use `LittleGhost::MCP::HTTPTransport` and `LittleGhost::MCP::Client` directly
145
+ when you need a custom transport. They produce the same generated Tool classes
146
+ and accept the same mapping callbacks as Toolset.
147
+
148
+ ## Send a Run stream through AG-UI
149
+
150
+ The AG-UI adapter converts LittleGhost events into protocol event hashes:
151
+
152
+ ```ruby
153
+ require "json"
154
+ require "little_ghost/ag_ui"
155
+
156
+ source = CustomerSupportAgent.stream_ask(
157
+ question,
158
+ actor_id: authenticated_user.id,
159
+ context: {account_id: authenticated_user.account_id}
160
+ )
161
+
162
+ events = LittleGhost::AGUI::Adapter.new.stream(
163
+ source,
164
+ thread_id: conversation.id,
165
+ run_id: request.request_id
166
+ )
167
+
168
+ events.each { |event| websocket.write(JSON.generate(event)) }
169
+ ```
170
+
171
+ The adapter translates text, reasoning, Tool activity, usage, retries, trace
172
+ context, subagent activity, and terminal outcomes. It is stateless between
173
+ calls. Your application still owns the connection, backpressure, disconnect
174
+ behavior, and any request state its callbacks need.
175
+
176
+ LittleGhost also emits namespaced custom events. Consumers should preserve or
177
+ deliberately ignore event types they don't recognize. See the [AG-UI event
178
+ documentation](https://docs.ag-ui.com/concepts/events) when implementing the
179
+ client.
180
+
181
+ > **Safety note:** A Run stream can include model output, Tool arguments and
182
+ > results, errors, and participant activity. Check that the connected user may
183
+ > see the complete Run, then filter fields before sending or storing events.
184
+
185
+ Calling `each` drives the source stream on the caller's fiber or thread. When a
186
+ client disconnects, stop enumerating and apply the cancellation behavior your
187
+ application needs. Closing the socket can't undo Tool work that already ran.
188
+
189
+ ## Trace Runs with OpenTelemetry
190
+
191
+ Configure an OpenTelemetry SDK and exporter in the application, then register
192
+ the LittleGhost subscriber before the first Agent call:
193
+
194
+ ```ruby
195
+ LittleGhost.configure do |config|
196
+ config.instrument LittleGhost::Tracing::OpenTelemetry.new
197
+ end
198
+ ```
199
+
200
+ LittleGhost depends on `opentelemetry-api`, leaving the SDK, processor, and
201
+ exporter up to the application. It emits spans and events for Runs, Agents,
202
+ model calls, Tools, assemblies, sessions, usage, and failures. Active operations
203
+ can propagate W3C `traceparent` and `tracestate` fields.
204
+
205
+ Prompts, messages, responses, Tool arguments, and exception content are omitted
206
+ by default. If you intentionally need some of that content, install a
207
+ `LittleGhost::Support::ContentCapture` with a scrubber before enabling capture.
208
+ Avoid putting raw user, order, session, or request IDs in span attributes.
209
+
210
+ Attribute names follow the evolving [OpenTelemetry GenAI semantic
211
+ conventions](https://opentelemetry.io/docs/specs/semconv/gen-ai/) where they
212
+ apply. Flush or shut down `LittleGhost::Instrumentation` during application
213
+ shutdown when your backend buffers data.
214
+
215
+ See [Running in Production](production.md) for startup, shutdown, and observability,
216
+ [Tools](tools.md) for local and remote Tool behavior, and [Workspaces and
217
+ Sandboxes](sandboxing.md) for child processes and files.
@@ -0,0 +1,125 @@
1
+ # Choose Models and Providers
2
+
3
+ An Agent needs a model target: a configured provider connection plus the
4
+ provider's model identifier. You can write that target directly while getting
5
+ started, then give it an application-facing name when several Agents share it.
6
+
7
+ ## Start with one direct target
8
+
9
+ A direct target has the form `connection:model-id`:
10
+
11
+ ```ruby
12
+ class CustomerSupportAgent < LittleGhost::Agent
13
+ model "openrouter:openai/gpt-5.6-luna"
14
+ system_prompt "Answer customer questions clearly and concisely."
15
+ end
16
+ ```
17
+
18
+ `openrouter` names a connection configured by the application. The remainder
19
+ is the model identifier understood by that provider. This is a good fit when
20
+ one Agent owns one stable choice.
21
+
22
+ ## Give shared choices a role
23
+
24
+ A model role lets several Agents share a choice without knowing its provider
25
+ or model identifier:
26
+
27
+ ```ruby
28
+ LittleGhost.configure do |config|
29
+ config.providers = {
30
+ primary: {
31
+ adapter: :openrouter,
32
+ api_key: ENV.fetch("OPENROUTER_API_KEY")
33
+ }
34
+ }
35
+ config.models = {
36
+ customer_support: {
37
+ target: "primary:openai/gpt-5.6-luna",
38
+ settings: {temperature: 0.2}
39
+ }
40
+ }
41
+ config.default_model = :customer_support
42
+ end
43
+
44
+ class CustomerSupportAgent < LittleGhost::Agent
45
+ model :customer_support
46
+ end
47
+ ```
48
+
49
+ Here `customer_support` is the role, `primary` is the connection, and
50
+ `openrouter` is the adapter. You can move the role to another model or provider
51
+ without editing the Agent.
52
+
53
+ Profile settings are defaults. An individual call can override them:
54
+
55
+ ```ruby
56
+ run = CustomerSupportAgent.ask(
57
+ "Explain the refund decision.",
58
+ settings: {temperature: 0.0}
59
+ )
60
+ ```
61
+
62
+ Build these settings in application code instead of passing request parameters
63
+ through unchanged. Settings can affect cost, latency, and model behavior.
64
+
65
+ ## Configure connections in one place
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`.
70
+
71
+ Keep credentials in your application's secret manager. Agents refer to a role
72
+ or configured connection; they don't need to contain credentials. If your
73
+ application obtains short-lived credentials at runtime, configure a credential
74
+ resolver that returns them for the selected connection.
75
+
76
+ > **Safety note:** The selected provider may receive system instructions,
77
+ > caller input, conversation history, Tool results, schemas, and attachments.
78
+ > Choose a provider that is appropriate for that data, and keep credentials and
79
+ > provider endpoints under application control.
80
+
81
+ ## Choose a role for each request
82
+
83
+ An Agent can select between configured roles using its `Invocation`:
84
+
85
+ ```ruby
86
+ class CustomerSupportAgent < LittleGhost::Agent
87
+ model do |invocation|
88
+ invocation.fetch(:premium_account, false) ? :premium_support : :customer_support
89
+ end
90
+ end
91
+ ```
92
+
93
+ Set `premium_account` from application state when creating the invocation. If
94
+ a public request offers a model choice, map that choice to one of your
95
+ configured roles rather than accepting an arbitrary provider target.
96
+
97
+ Trusted application code may also declare a selection inline:
98
+
99
+ ```ruby
100
+ class ResearchAgent < LittleGhost::Agent
101
+ model(
102
+ provider: "primary",
103
+ model: "openai/gpt-5.6-luna",
104
+ reasoning_effort: "high"
105
+ )
106
+ end
107
+ ```
108
+
109
+ `provider` still names a configured connection. The inline settings change the
110
+ selection; they don't create a new connection.
111
+
112
+ ## Use model capabilities
113
+
114
+ `LittleGhost::ModelResolver` turns a role or target into an executable
115
+ `LittleGhost::Model`. Its catalog describes capabilities such as supported
116
+ input types, output limits, and structured results. LittleGhost uses that
117
+ information to reject unsupported attachments, constrain output limits, and
118
+ choose a structured-result strategy.
119
+
120
+ Provider capabilities can change. Handle failed Runs and provider errors even
121
+ when the catalog says a feature is supported.
122
+
123
+ Continue with [Prompts as Views](prompt_views.md) when an Agent's instructions
124
+ outgrow one string. See [Structured Results and Content](structured_outputs_and_content.md)
125
+ when you need checked result shapes, images, or documents.