little_ghost 0.3.0 → 0.5.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 (122) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +90 -84
  3. data/docs/guides/assemblies.md +412 -0
  4. data/docs/guides/code_mode.md +275 -0
  5. data/docs/guides/core_concepts.md +150 -239
  6. data/docs/guides/getting_started.md +125 -87
  7. data/docs/guides/integrations.md +217 -0
  8. data/docs/guides/models_and_providers.md +125 -0
  9. data/docs/guides/production.md +253 -0
  10. data/docs/guides/prompt_views.md +139 -0
  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 +329 -0
  15. data/lib/little_ghost/ag_ui/adapter.rb +5 -5
  16. data/lib/little_ghost/agent/delegation.rb +3 -3
  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 +411 -214
  20. data/lib/little_ghost/agent_builder.rb +61 -22
  21. data/lib/little_ghost/{agent_interruptions.rb → agent_interjections.rb} +12 -12
  22. data/lib/little_ghost/agent_stream_source.rb +262 -0
  23. data/lib/little_ghost/artifact.rb +182 -0
  24. data/lib/little_ghost/artifacts/presentation_budget.rb +44 -0
  25. data/lib/little_ghost/artifacts/workspace_store.rb +370 -0
  26. data/lib/little_ghost/artifacts.rb +11 -0
  27. data/lib/little_ghost/assembly.rb +110 -30
  28. data/lib/little_ghost/assembly_builder.rb +59 -21
  29. data/lib/little_ghost/assembly_execution.rb +110 -6
  30. data/lib/little_ghost/code_mode/broker.rb +164 -0
  31. data/lib/little_ghost/code_mode/catalog.rb +54 -0
  32. data/lib/little_ghost/code_mode/engine.rb +58 -0
  33. data/lib/little_ghost/code_mode/javascript/catalog.rb +118 -0
  34. data/lib/little_ghost/code_mode/javascript/client.rb +550 -0
  35. data/lib/little_ghost/code_mode/javascript/host.rb +347 -0
  36. data/lib/little_ghost/code_mode/javascript/session.rb +579 -0
  37. data/lib/little_ghost/code_mode/javascript_engine.rb +172 -0
  38. data/lib/little_ghost/code_mode/protocol.rb +78 -0
  39. data/lib/little_ghost/code_mode/ruby/catalog.rb +80 -0
  40. data/lib/little_ghost/code_mode/ruby/host.rb +102 -0
  41. data/lib/little_ghost/code_mode/ruby/session.rb +508 -0
  42. data/lib/little_ghost/code_mode/ruby_engine.rb +86 -0
  43. data/lib/little_ghost/code_mode/runtime.rb +335 -0
  44. data/lib/little_ghost/code_mode/session.rb +61 -0
  45. data/lib/little_ghost/code_mode/types.rb +58 -0
  46. data/lib/little_ghost/code_mode.rb +53 -0
  47. data/lib/little_ghost/configuration.rb +366 -47
  48. data/lib/little_ghost/content.rb +24 -13
  49. data/lib/little_ghost/data_map.rb +209 -0
  50. data/lib/little_ghost/errors.rb +28 -9
  51. data/lib/little_ghost/execution.rb +33 -34
  52. data/lib/little_ghost/graph.rb +376 -197
  53. data/lib/little_ghost/mcp/client.rb +487 -88
  54. data/lib/little_ghost/mcp/toolset.rb +210 -0
  55. data/lib/little_ghost/mcp/types.rb +216 -0
  56. data/lib/little_ghost/mcp.rb +3 -0
  57. data/lib/little_ghost/message.rb +4 -4
  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 +15 -5
  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 +98 -0
  64. data/lib/little_ghost/network/envoy_config.rb +362 -0
  65. data/lib/little_ghost/network/envoy_gateway.rb +409 -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 +9 -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 +162 -54
  74. data/lib/little_ghost/run_context.rb +42 -20
  75. data/lib/little_ghost/run_result.rb +0 -7
  76. data/lib/little_ghost/runtime/hook.rb +8 -3
  77. data/lib/little_ghost/runtime/hooks/artifacts.rb +338 -0
  78. data/lib/little_ghost/runtime.rb +160 -52
  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 +241 -0
  95. data/lib/little_ghost/session.rb +39 -26
  96. data/lib/little_ghost/session_store.rb +9 -5
  97. data/lib/little_ghost/session_stores/agent_core_memory.rb +64 -56
  98. data/lib/little_ghost/session_stores/filesystem.rb +261 -0
  99. data/lib/little_ghost/session_stores/memory.rb +7 -0
  100. data/lib/little_ghost/skills/catalog.rb +94 -14
  101. data/lib/little_ghost/skills/resource_root.rb +42 -0
  102. data/lib/little_ghost/skills/skill.rb +0 -3
  103. data/lib/little_ghost/stream_event.rb +8 -13
  104. data/lib/little_ghost/subagents/control_tool.rb +8 -0
  105. data/lib/little_ghost/subagents/manager.rb +53 -50
  106. data/lib/little_ghost/support/callbacks.rb +3 -1
  107. data/lib/little_ghost/support/content_capture.rb +3 -3
  108. data/lib/little_ghost/support/http_client.rb +2 -2
  109. data/lib/little_ghost/support/redactor.rb +1 -1
  110. data/lib/little_ghost/swarm.rb +13 -5
  111. data/lib/little_ghost/tool.rb +157 -64
  112. data/lib/little_ghost/tool_registry.rb +1 -1
  113. data/lib/little_ghost/tools/filesystem.rb +1 -1
  114. data/lib/little_ghost/tools/shell.rb +4 -3
  115. data/lib/little_ghost/tools/write_todos.rb +6 -1
  116. data/lib/little_ghost/tracing/open_telemetry.rb +1 -1
  117. data/lib/little_ghost/version.rb +1 -1
  118. data/lib/little_ghost/workflow.rb +30 -21
  119. data/lib/little_ghost/workspace.rb +222 -8
  120. data/lib/little_ghost.rb +40 -27
  121. metadata +104 -3
  122. data/lib/little_ghost/unrestricted_sandbox.rb +0 -306
@@ -1,31 +1,245 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pathname"
4
+ require "fileutils"
5
+
3
6
  module LittleGhost
4
- # A Workspace gives an agent a concrete home for files. Pair it with a Sandbox
5
- # to decide how those files may be read, changed, or used by commands.
7
+ # A Workspace names the host paths associated with a Run. Pair it with a
8
+ # Sandbox to decide how those paths may be read, changed, or used by commands.
6
9
  #
7
10
  # workspace = LittleGhost::Workspace.new(root: "./tmp/support-run")
8
11
  # workspace.root # => an absolute path ending in "/tmp/support-run"
9
12
  #
10
- # Workspaces participate in the run resource lifecycle. A custom workspace can
11
- # provision storage in #open and release it in #close.
13
+ # Workspaces participate in the Run resource lifecycle, but object lifetime
14
+ # and file lifetime are separate. Opening creates +root+ and relative named
15
+ # paths, but does not delete them by default. Absolute named paths are trusted
16
+ # references that must already exist. Setup and teardown callbacks let trusted
17
+ # application configuration provision run-scoped resources without a
18
+ # Workspace subclass. Applications that share a writable root between Runs
19
+ # must provide their own concurrency and tenant isolation.
20
+ #
21
+ # See the {Workspaces and Sandboxes guide}[rdoc-ref:docs/guides/sandboxing.md]
22
+ # for logical paths, Sandbox policy, process ownership, and networking.
12
23
  class Workspace
13
- # Expands +root+ to an absolute path.
14
- def initialize(root:)
24
+ @providers = {}
25
+
26
+ class << self
27
+ # Registers a trusted workspace provider under a configuration symbol.
28
+ def register_provider(name, implementation)
29
+ unless implementation.is_a?(Class) && implementation <= Workspace
30
+ raise ArgumentError, "workspace provider must be a Workspace class"
31
+ end
32
+
33
+ Workspace.providers[name.to_sym] = implementation
34
+ end
35
+
36
+ # Resolves an explicitly selected provider without changing its meaning.
37
+ def resolve_provider(name)
38
+ Workspace.providers.fetch(name.to_sym) do
39
+ raise DependencyError, "workspace provider :#{name} is not available"
40
+ end
41
+ end
42
+
43
+ def providers # :nodoc:
44
+ @providers ||= {}
45
+ end
46
+ end
47
+
48
+ # Expands +root+ and every named path to absolute paths. Relative named paths
49
+ # must remain beneath +root+; absolute named paths deliberately refer outside
50
+ # it. +setup+ receives +workspace:+ and +run:+ when the Run opens. +teardown+
51
+ # receives the same values when it closes, including after partial setup.
52
+ def initialize(root:, paths: {}, setup: nil, teardown: nil)
15
53
  @root = File.expand_path(root)
54
+ @paths = normalize_paths(paths)
55
+ @setup = validate_callback(setup, :setup)
56
+ @teardown = validate_callback(teardown, :teardown)
57
+ @opened = false
58
+ @active = false
59
+ @run = nil
60
+ @identities = nil
16
61
  end
17
62
 
18
63
  # Absolute filesystem root assigned to this workspace.
19
64
  attr_reader :root
20
65
 
21
- # Opens any run-scoped resources and yields this workspace to the run.
66
+ # Immutable named absolute paths owned by this workspace declaration.
67
+ attr_reader :paths
68
+
69
+ # Returns a configured named path, raising KeyError when it is absent.
70
+ def path(name)
71
+ paths.fetch(name.to_sym)
72
+ end
73
+
74
+ # Converts a logical path to its physical workspace path. This method checks
75
+ # lexical containment but does not make direct filesystem access safe for
76
+ # untrusted input. Pass model-selected paths through Sandbox file operations,
77
+ # which reject symlinks while opening each path component.
78
+ #
79
+ # Relative paths belong to +root+; named paths use
80
+ # <tt>workspace://name/path</tt>. Physical absolute paths are deliberately
81
+ # rejected so brokered tools do not teach callers host filesystem layout.
82
+ def resolve(reference)
83
+ validate! if @identities
84
+ value = String(reference)
85
+ raise ArgumentError, "workspace paths must be relative or use workspace://" if Pathname.new(value).absolute?
86
+
87
+ base, relative = if value.start_with?("workspace://")
88
+ logical = value.delete_prefix("workspace://")
89
+ name, separator, child = logical.partition("/")
90
+ raise ArgumentError, "workspace path must name a configured path" if name.empty?
91
+
92
+ [path(name), separator.empty? ? "." : child]
93
+ else
94
+ [root, value]
95
+ end
96
+ resolve_beneath(base, relative)
97
+ end
98
+
99
+ # Returns the stable logical reference for a physical workspace path.
100
+ def reference(physical_path)
101
+ candidate = File.expand_path(physical_path)
102
+ named = paths.sort_by { |_, path| -path.length }.find { |_, path| beneath?(candidate, path) }
103
+ if named
104
+ name, base = named
105
+ relative = candidate.delete_prefix(base).delete_prefix(File::SEPARATOR)
106
+ return relative.empty? ? "workspace://#{name}" : "workspace://#{name}/#{relative}"
107
+ end
108
+ raise ArgumentError, "path is outside the workspace" unless beneath?(candidate, root)
109
+
110
+ candidate.delete_prefix(root).delete_prefix(File::SEPARATOR).then { |value| value.empty? ? "." : value }
111
+ end
112
+
113
+ # Environment variables supplied to sandboxed programs. These values are
114
+ # trusted process configuration and are never returned by filesystem tools.
115
+ def environment
116
+ {"LITTLE_GHOST_WORKSPACE_ROOT" => root}.merge(paths.to_h do |name, path|
117
+ ["LITTLE_GHOST_WORKSPACE_#{name.to_s.upcase.gsub(/[^A-Z0-9]/, "_")}", path]
118
+ end).freeze
119
+ end
120
+
121
+ # Verifies that no configured directory was replaced after #open.
122
+ def validate!
123
+ return self unless @identities
124
+
125
+ {root: root}.merge(paths).each do |name, path|
126
+ realpath = File.realpath(path)
127
+ stat = File.stat(realpath)
128
+ expected = @identities.fetch(name)
129
+ unless [realpath, stat.dev, stat.ino] == expected
130
+ raise ToolError, "workspace path changed after opening: #{name}"
131
+ end
132
+ end
133
+ self
134
+ rescue Errno::ENOENT
135
+ raise ToolError, "workspace path changed after opening: #{name}"
136
+ end
137
+
138
+ # Calls the application setup callback once and returns this workspace.
22
139
  def open(run: nil)
140
+ return self if @opened
141
+
142
+ @run = run
143
+ @active = true
144
+ @setup&.call(workspace: self, run:)
145
+ materialize!
146
+ capture_identities!
147
+ @opened = true
23
148
  self
149
+ rescue
150
+ close
151
+ raise
24
152
  end
25
153
 
26
- # Releases workspace resources. The default workspace has nothing to close.
154
+ # Calls the application teardown callback once. The default does not remove
155
+ # files or directories.
27
156
  def close
157
+ return nil unless @active
158
+
159
+ @teardown&.call(workspace: self, run: @run)
28
160
  nil
161
+ ensure
162
+ @opened = false
163
+ @active = false
164
+ @run = nil
165
+ @identities = nil
166
+ end
167
+
168
+ private
169
+
170
+ def materialize!
171
+ FileUtils.mkdir_p(root)
172
+ paths.each do |name, directory|
173
+ if @relative_path_names.include?(name)
174
+ FileUtils.mkdir_p(directory)
175
+ elsif !File.directory?(directory)
176
+ raise ArgumentError, "absolute workspace path :#{name} must already exist"
177
+ end
178
+ end
179
+ end
180
+
181
+ def capture_identities!
182
+ entries = {root: root}.merge(paths)
183
+ identities = entries.to_h do |name, path|
184
+ realpath = File.realpath(path)
185
+ stat = File.stat(realpath)
186
+ [name, [realpath, stat.dev, stat.ino].freeze]
187
+ end
188
+ duplicates = identities.group_by { |_, identity| identity.drop(1) }.select { |_, values| values.length > 1 }
189
+ unless duplicates.empty?
190
+ names = duplicates.values.flat_map { |values| values.map(&:first) }
191
+ raise ArgumentError, "workspace paths must not alias the same directory: #{names.join(", ")}"
192
+ end
193
+ @identities = identities.freeze
194
+ end
195
+
196
+ def resolve_beneath(base, relative)
197
+ raise ArgumentError, "workspace path must not be empty" if relative.empty?
198
+ components = Pathname.new(relative).each_filename.to_a
199
+ raise ArgumentError, "workspace path traversal is not allowed" if components.include?("..")
200
+
201
+ expanded = File.expand_path(relative, base)
202
+ raise ArgumentError, "workspace path escapes its root" unless beneath?(expanded, base)
203
+
204
+ expanded
205
+ end
206
+
207
+ def beneath?(candidate, base)
208
+ candidate == base || candidate.start_with?(base.end_with?(File::SEPARATOR) ? base : "#{base}#{File::SEPARATOR}")
209
+ end
210
+
211
+ def normalize_paths(values)
212
+ unless values.respond_to?(:each_pair)
213
+ raise ArgumentError, "workspace paths must be a Hash"
214
+ end
215
+
216
+ relative_names = []
217
+ normalized = values.each_pair.to_h do |name, value|
218
+ key = name.to_sym
219
+ path = value.to_s
220
+ raise ArgumentError, "workspace path :#{key} must not be empty" if path.empty?
221
+
222
+ expanded = File.expand_path(path, root)
223
+ root_prefix = root.end_with?(File::SEPARATOR) ? root : "#{root}#{File::SEPARATOR}"
224
+ relative = !Pathname.new(path).absolute?
225
+ if relative && expanded != root && !expanded.start_with?(root_prefix)
226
+ raise ArgumentError, "relative workspace path :#{key} must remain beneath the workspace root"
227
+ end
228
+ relative_names << key if relative
229
+
230
+ [key, expanded.freeze]
231
+ end.freeze
232
+ @relative_path_names = relative_names.freeze
233
+ normalized
234
+ end
235
+
236
+ def validate_callback(callback, name)
237
+ return unless callback
238
+ raise ArgumentError, "workspace #{name} must be callable" unless callback.respond_to?(:call)
239
+
240
+ callback
29
241
  end
30
242
  end
243
+
244
+ Workspace.register_provider(:directory, Workspace)
31
245
  end
data/lib/little_ghost.rb CHANGED
@@ -4,6 +4,9 @@ require_relative "little_ghost/version"
4
4
  require_relative "little_ghost/errors"
5
5
  require_relative "little_ghost/execution_state"
6
6
  require_relative "little_ghost/support"
7
+ require_relative "little_ghost/data_map"
8
+ require_relative "little_ghost/artifact"
9
+ require_relative "little_ghost/artifacts"
7
10
  require_relative "little_ghost/events"
8
11
  require_relative "little_ghost/instrumentation"
9
12
  require_relative "little_ghost/tracing/open_telemetry"
@@ -14,6 +17,7 @@ require_relative "little_ghost/usage"
14
17
  require_relative "little_ghost/content"
15
18
  require_relative "little_ghost/message"
16
19
  require_relative "little_ghost/stream_event"
20
+ require_relative "little_ghost/agent_stream_source"
17
21
  require_relative "little_ghost/model_request"
18
22
  require_relative "little_ghost/model_response"
19
23
  require_relative "little_ghost/run_result"
@@ -42,14 +46,22 @@ require_relative "little_ghost/model_resolver"
42
46
  require_relative "little_ghost/run_context"
43
47
  require_relative "little_ghost/workspace"
44
48
  require_relative "little_ghost/sandbox"
45
- require_relative "little_ghost/unrestricted_sandbox"
49
+ require_relative "little_ghost/sandbox/process_session"
50
+ require_relative "little_ghost/sandboxes/unrestricted"
51
+ require_relative "little_ghost/sandboxes/bubblewrap"
52
+ require_relative "little_ghost/sandboxes/seatbelt"
53
+ require_relative "little_ghost/sandboxes/native"
46
54
  require_relative "little_ghost/tool"
47
55
  require_relative "little_ghost/tool_execution"
48
56
  require_relative "little_ghost/tool_registry"
57
+ require_relative "little_ghost/code_mode"
58
+ require_relative "little_ghost/code_mode/ruby_engine"
59
+ require_relative "little_ghost/code_mode/runtime"
49
60
  require_relative "little_ghost/structured_output"
50
61
  require_relative "little_ghost/prompt_resolver"
51
62
  require_relative "little_ghost/session_store"
52
63
  require_relative "little_ghost/session_stores/memory"
64
+ require_relative "little_ghost/session_stores/filesystem"
53
65
  require_relative "little_ghost/session"
54
66
  require_relative "little_ghost/skills"
55
67
  require_relative "little_ghost/tools/write_todos"
@@ -58,7 +70,7 @@ require_relative "little_ghost/execution"
58
70
  require_relative "little_ghost/subagents/definition"
59
71
  require_relative "little_ghost/subagents/agent_path"
60
72
  require_relative "little_ghost/subagents/manager"
61
- require_relative "little_ghost/agent_interruptions"
73
+ require_relative "little_ghost/agent_interjections"
62
74
  require_relative "little_ghost/assembly"
63
75
  require_relative "little_ghost/assembly_execution"
64
76
  require_relative "little_ghost/agent"
@@ -68,41 +80,33 @@ require_relative "little_ghost/graph"
68
80
  require_relative "little_ghost/assembly_builder"
69
81
  require_relative "little_ghost/agent_factory"
70
82
  require_relative "little_ghost/runtime/hook"
83
+ require_relative "little_ghost/runtime/hooks/artifacts"
71
84
  require_relative "little_ghost/runtime"
72
85
 
73
- # Build AI features with reusable agents and composable assemblies. LittleGhost can
74
- # sit inside an existing Ruby system or support a dedicated AI service, keeping
75
- # models, prompts, tools, sessions, streaming, and instrumentation behind a
76
- # cohesive set of Ruby conventions.
86
+ # Build AI features as ordinary Ruby classes. An Agent owns one model
87
+ # conversation. Larger units called Assemblies coordinate several Agents while
88
+ # keeping the same +ask+ and +stream_ask+ entrypoints.
77
89
  #
78
- # A customer support agent can answer directly, use an application tool, or ask a
79
- # specialist for research while the caller observes one run:
80
- #
81
- # class ResearchAgent < LittleGhost::Agent
82
- # description "Researches difficult support questions"
83
- # model "openai:gpt-5.6-luna"
84
- # end
90
+ # Start with one model-driven behavior:
85
91
  #
86
92
  # class CustomerSupportAgent < LittleGhost::Agent
87
93
  # description "Handles support requests"
88
- # model "openai:gpt-5.6-luna"
89
- # tools AccountTool
90
- # subagent ResearchAgent, kind: "research"
94
+ # model "openrouter:openai/gpt-5.6-luna"
95
+ # system_prompt "Answer customer questions clearly."
91
96
  # end
92
97
  #
93
98
  # run = CustomerSupportAgent.ask("Why is transfer 481 still pending?")
94
99
  # run.completed? # => true
95
- # run.response # => "Transfer 481 is waiting for the receiving bank."
100
+ # run.response
101
+ # # One possible response: Transfer 481 is waiting for the receiving bank.
96
102
  #
97
- # Agent subclasses hold reusable behavior; Invocation objects carry one request,
98
- # and Run objects own execution and cleanup. Assembly gives Agent, Workflow,
99
- # Swarm, and Graph the same caller interface while each type owns a different
100
- # coordination policy.
103
+ # The class holds reusable behavior. Each call creates a Run, which records the
104
+ # result and closes the resources opened for that request. Workflow, Swarm, and
105
+ # Graph are Assembly types for coordinating more than one participant.
101
106
  #
102
- # LittleGhost.configuration is process-wide unless LittleGhost.with_configuration
103
- # supplies an execution-scoped replacement. Configuration is loaded lazily and
104
- # snapshotted into a Runtime, so make application changes before the first agent
105
- # runtime is built.
107
+ # Configure LittleGhost before the first call. The first standalone call builds
108
+ # a shared Runtime from that configuration. +with_configuration+ can select an
109
+ # independent configuration for one execution context.
106
110
  module LittleGhost
107
111
  class << self
108
112
  # The configuration active in the current execution context, falling back to
@@ -114,15 +118,24 @@ module LittleGhost
114
118
  # Opens the active Configuration for application setup and returns it.
115
119
  #
116
120
  # Configuration files are loaded lazily when a runtime is first built, so
117
- # make application-level changes before invoking an agent.
121
+ # make application-level changes before invoking an agent. Once the shared
122
+ # Runtime is ready, later mutations raise ConfigurationError.
118
123
  def configure(&block)
119
124
  configuration.configure(&block)
120
125
  end
121
126
 
127
+ # Returns the shared Runtime for the active Configuration.
128
+ #
129
+ # Most applications do not need to call this method. Standalone Agent and
130
+ # Assembly entrypoints use it automatically. Runtime construction is lazy,
131
+ # thread-safe, and locks the active Configuration after it succeeds.
132
+ def runtime = configuration.runtime
133
+
122
134
  # Returns the model resolver owned by the active process configuration.
123
135
  def model_resolver = configuration.model_resolver
124
136
 
125
- # Makes +configuration+ current only while the block runs.
137
+ # Makes +configuration+ and its independent shared Runtime current only
138
+ # while the block runs.
126
139
  #
127
140
  # Execution state restores the previous configuration even when the block
128
141
  # raises. Other execution contexts continue to see their own configuration.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: little_ghost
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Robinson
@@ -23,6 +23,34 @@ dependencies:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
25
  version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: fiddle
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: json_schemer
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.5'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.5'
26
54
  - !ruby/object:Gem::Dependency
27
55
  name: opentelemetry-api
28
56
  requirement: !ruby/object:Gem::Requirement
@@ -51,6 +79,20 @@ dependencies:
51
79
  - - "~>"
52
80
  - !ruby/object:Gem::Version
53
81
  version: '5.25'
82
+ - !ruby/object:Gem::Dependency
83
+ name: mini_racer
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.21'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0.21'
54
96
  - !ruby/object:Gem::Dependency
55
97
  name: rake
56
98
  requirement: !ruby/object:Gem::Requirement
@@ -117,8 +159,18 @@ extra_rdoc_files: []
117
159
  files:
118
160
  - LICENSE.txt
119
161
  - README.md
162
+ - docs/guides/assemblies.md
163
+ - docs/guides/code_mode.md
120
164
  - docs/guides/core_concepts.md
121
165
  - docs/guides/getting_started.md
166
+ - docs/guides/integrations.md
167
+ - docs/guides/models_and_providers.md
168
+ - docs/guides/production.md
169
+ - docs/guides/prompt_views.md
170
+ - docs/guides/sandboxing.md
171
+ - docs/guides/skills.md
172
+ - docs/guides/structured_outputs_and_content.md
173
+ - docs/guides/tools.md
122
174
  - lib/little_ghost.rb
123
175
  - lib/little_ghost/ag_ui.rb
124
176
  - lib/little_ghost/ag_ui/adapter.rb
@@ -129,13 +181,36 @@ files:
129
181
  - lib/little_ghost/agent/tool_loop.rb
130
182
  - lib/little_ghost/agent_builder.rb
131
183
  - lib/little_ghost/agent_factory.rb
132
- - lib/little_ghost/agent_interruptions.rb
184
+ - lib/little_ghost/agent_interjections.rb
185
+ - lib/little_ghost/agent_stream_source.rb
186
+ - lib/little_ghost/artifact.rb
187
+ - lib/little_ghost/artifacts.rb
188
+ - lib/little_ghost/artifacts/presentation_budget.rb
189
+ - lib/little_ghost/artifacts/workspace_store.rb
133
190
  - lib/little_ghost/assembly.rb
134
191
  - lib/little_ghost/assembly_builder.rb
135
192
  - lib/little_ghost/assembly_execution.rb
193
+ - lib/little_ghost/code_mode.rb
194
+ - lib/little_ghost/code_mode/broker.rb
195
+ - lib/little_ghost/code_mode/catalog.rb
196
+ - lib/little_ghost/code_mode/engine.rb
197
+ - lib/little_ghost/code_mode/javascript/catalog.rb
198
+ - lib/little_ghost/code_mode/javascript/client.rb
199
+ - lib/little_ghost/code_mode/javascript/host.rb
200
+ - lib/little_ghost/code_mode/javascript/session.rb
201
+ - lib/little_ghost/code_mode/javascript_engine.rb
202
+ - lib/little_ghost/code_mode/protocol.rb
203
+ - lib/little_ghost/code_mode/ruby/catalog.rb
204
+ - lib/little_ghost/code_mode/ruby/host.rb
205
+ - lib/little_ghost/code_mode/ruby/session.rb
206
+ - lib/little_ghost/code_mode/ruby_engine.rb
207
+ - lib/little_ghost/code_mode/runtime.rb
208
+ - lib/little_ghost/code_mode/session.rb
209
+ - lib/little_ghost/code_mode/types.rb
136
210
  - lib/little_ghost/configuration.rb
137
211
  - lib/little_ghost/content.rb
138
212
  - lib/little_ghost/data/model_catalog.json
213
+ - lib/little_ghost/data_map.rb
139
214
  - lib/little_ghost/errors.rb
140
215
  - lib/little_ghost/events.rb
141
216
  - lib/little_ghost/execution.rb
@@ -146,6 +221,8 @@ files:
146
221
  - lib/little_ghost/lookup.rb
147
222
  - lib/little_ghost/mcp.rb
148
223
  - lib/little_ghost/mcp/client.rb
224
+ - lib/little_ghost/mcp/toolset.rb
225
+ - lib/little_ghost/mcp/types.rb
149
226
  - lib/little_ghost/message.rb
150
227
  - lib/little_ghost/model.rb
151
228
  - lib/little_ghost/model_capabilities.rb
@@ -159,6 +236,12 @@ files:
159
236
  - lib/little_ghost/models/configuration.rb
160
237
  - lib/little_ghost/models/details.rb
161
238
  - lib/little_ghost/models/target.rb
239
+ - lib/little_ghost/network.rb
240
+ - lib/little_ghost/network/authorizer_server.rb
241
+ - lib/little_ghost/network/certificate_authority.rb
242
+ - lib/little_ghost/network/envoy_config.rb
243
+ - lib/little_ghost/network/envoy_gateway.rb
244
+ - lib/little_ghost/network/external_gateway.rb
162
245
  - lib/little_ghost/path_set.rb
163
246
  - lib/little_ghost/prompt_resolver.rb
164
247
  - lib/little_ghost/provider_registry.rb
@@ -184,17 +267,36 @@ files:
184
267
  - lib/little_ghost/run_result.rb
185
268
  - lib/little_ghost/runtime.rb
186
269
  - lib/little_ghost/runtime/hook.rb
270
+ - lib/little_ghost/runtime/hooks/artifacts.rb
187
271
  - lib/little_ghost/sandbox.rb
272
+ - lib/little_ghost/sandbox/capabilities.rb
273
+ - lib/little_ghost/sandbox/environment_policy.rb
274
+ - lib/little_ghost/sandbox/filesystem.rb
275
+ - lib/little_ghost/sandbox/isolated_backend.rb
276
+ - lib/little_ghost/sandbox/limits.rb
277
+ - lib/little_ghost/sandbox/mount.rb
278
+ - lib/little_ghost/sandbox/network_policy.rb
279
+ - lib/little_ghost/sandbox/policy.rb
280
+ - lib/little_ghost/sandbox/process_runner.rb
281
+ - lib/little_ghost/sandbox/process_session.rb
282
+ - lib/little_ghost/sandbox/scope.rb
283
+ - lib/little_ghost/sandboxes/bubblewrap.rb
284
+ - lib/little_ghost/sandboxes/native.rb
285
+ - lib/little_ghost/sandboxes/seatbelt.rb
286
+ - lib/little_ghost/sandboxes/unrestricted.rb
188
287
  - lib/little_ghost/session.rb
189
288
  - lib/little_ghost/session_store.rb
190
289
  - lib/little_ghost/session_stores/agent_core_memory.rb
290
+ - lib/little_ghost/session_stores/filesystem.rb
191
291
  - lib/little_ghost/session_stores/memory.rb
192
292
  - lib/little_ghost/skills.rb
193
293
  - lib/little_ghost/skills/catalog.rb
294
+ - lib/little_ghost/skills/resource_root.rb
194
295
  - lib/little_ghost/skills/skill.rb
195
296
  - lib/little_ghost/stream_event.rb
196
297
  - lib/little_ghost/structured_output.rb
197
298
  - lib/little_ghost/subagents/agent_path.rb
299
+ - lib/little_ghost/subagents/control_tool.rb
198
300
  - lib/little_ghost/subagents/definition.rb
199
301
  - lib/little_ghost/subagents/manager.rb
200
302
  - lib/little_ghost/support.rb
@@ -218,7 +320,6 @@ files:
218
320
  - lib/little_ghost/tools/shell.rb
219
321
  - lib/little_ghost/tools/write_todos.rb
220
322
  - lib/little_ghost/tracing/open_telemetry.rb
221
- - lib/little_ghost/unrestricted_sandbox.rb
222
323
  - lib/little_ghost/usage.rb
223
324
  - lib/little_ghost/version.rb
224
325
  - lib/little_ghost/workflow.rb