little_ghost 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/README.md +19 -5
- data/docs/guides/core_concepts.md +167 -38
- data/docs/guides/getting_started.md +8 -4
- data/lib/little_ghost/agent/delegation.rb +34 -7
- data/lib/little_ghost/agent/tool_loop.rb +2 -1
- data/lib/little_ghost/agent.rb +115 -156
- data/lib/little_ghost/agent_builder.rb +20 -4
- data/lib/little_ghost/agent_factory.rb +3 -0
- data/lib/little_ghost/assembly.rb +311 -0
- data/lib/little_ghost/assembly_builder.rb +459 -0
- data/lib/little_ghost/assembly_execution.rb +452 -0
- data/lib/little_ghost/errors.rb +8 -0
- data/lib/little_ghost/execution.rb +206 -0
- data/lib/little_ghost/graph.rb +911 -0
- data/lib/little_ghost/run.rb +120 -32
- data/lib/little_ghost/run_result.rb +22 -11
- data/lib/little_ghost/runtime/hook.rb +7 -2
- data/lib/little_ghost/runtime.rb +64 -6
- data/lib/little_ghost/sandbox.rb +1 -1
- data/lib/little_ghost/support/executor.rb +14 -2
- data/lib/little_ghost/support/loader.rb +2 -2
- data/lib/little_ghost/support.rb +15 -3
- data/lib/little_ghost/swarm.rb +431 -0
- data/lib/little_ghost/tool.rb +32 -6
- data/lib/little_ghost/tracing/open_telemetry.rb +13 -2
- data/lib/little_ghost/unrestricted_sandbox.rb +1 -1
- data/lib/little_ghost/version.rb +1 -1
- data/lib/little_ghost/workflow.rb +198 -73
- data/lib/little_ghost.rb +11 -4
- metadata +11 -4
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "assembly"
|
|
4
|
+
|
|
3
5
|
module LittleGhost
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
6
|
+
# Coordinates Assembly participants with ordinary Ruby control flow.
|
|
7
|
+
#
|
|
8
|
+
# A workflow is an Assembly whose +perform+ method controls ordering,
|
|
9
|
+
# branching, parallel work, and local variables. Each participant may be an
|
|
10
|
+
# Agent or another coordinated Assembly. The workflow consumes intermediate
|
|
11
|
+
# answers and streams one final participant response.
|
|
7
12
|
#
|
|
8
13
|
# A support workflow can route a difficult request through research before the
|
|
9
14
|
# responder writes the caller-visible answer:
|
|
@@ -25,11 +30,7 @@ module LittleGhost
|
|
|
25
30
|
# end
|
|
26
31
|
# end
|
|
27
32
|
#
|
|
28
|
-
# run =
|
|
29
|
-
# {message: "Why is transfer 481 pending?"},
|
|
30
|
-
# agent_class: CustomerSupportAgent,
|
|
31
|
-
# entrypoint_class: ResponseWorkflow
|
|
32
|
-
# ).call
|
|
33
|
+
# run = ResponseWorkflow.ask("Why is transfer 481 pending?")
|
|
33
34
|
# run.response # => "Transfer 481 is waiting for the receiving bank."
|
|
34
35
|
#
|
|
35
36
|
# +invoke+ returns a lazy Workflow::Invocation. Reading +output+ consumes an
|
|
@@ -45,22 +46,25 @@ module LittleGhost
|
|
|
45
46
|
#
|
|
46
47
|
# A workflow instance streams once. Returning the wrong value, returning an
|
|
47
48
|
# already consumed invocation, or consuming an invocation twice raises
|
|
48
|
-
# ProtocolError.
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
|
|
49
|
+
# ProtocolError. Each child assembly closes after its execution attempt;
|
|
50
|
+
# cleanup failures surface from that attempt. Closing the Workflow closes its
|
|
51
|
+
# lightweight invocation wrappers in reverse declaration order. Composition
|
|
52
|
+
# errors emit an +invocation_error+ event and then re-raise.
|
|
53
|
+
class Workflow < Assembly
|
|
52
54
|
# Hold one lazy agent call inside a workflow composition.
|
|
53
55
|
# Workflow implementations normally use only its output method or return the
|
|
54
56
|
# object as the final invocation.
|
|
55
57
|
class Invocation
|
|
56
58
|
attr_reader :result # :nodoc:
|
|
57
59
|
|
|
58
|
-
def initialize(input:, history:, context:,
|
|
60
|
+
def initialize(reference:, participant:, input:, history:, context:, policies:, owner:) # :nodoc:
|
|
61
|
+
@reference = reference
|
|
62
|
+
@participant = participant
|
|
59
63
|
@input = input
|
|
60
64
|
@history = history
|
|
61
65
|
@context = context
|
|
62
|
-
@
|
|
63
|
-
@
|
|
66
|
+
@policies = policies
|
|
67
|
+
@owner = owner
|
|
64
68
|
@mutex = Mutex.new
|
|
65
69
|
@consumed = false
|
|
66
70
|
@closed = false
|
|
@@ -69,30 +73,29 @@ module LittleGhost
|
|
|
69
73
|
def each(checkpoint: nil) # :nodoc:
|
|
70
74
|
return enum_for(__method__, checkpoint:) unless block_given?
|
|
71
75
|
|
|
72
|
-
|
|
76
|
+
@mutex.synchronize do
|
|
73
77
|
raise Error, "workflow invocation is already closed" if @closed
|
|
74
78
|
raise ProtocolError, "workflow invocation was already consumed" if @consumed
|
|
75
79
|
|
|
76
80
|
@consumed = true
|
|
77
|
-
@agent, options = @build.call
|
|
78
|
-
[@agent, options]
|
|
79
81
|
end
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
82
|
+
execution = @owner.send(
|
|
83
|
+
:execute_workflow_invocation,
|
|
84
|
+
reference: @reference,
|
|
85
|
+
participant: @participant,
|
|
86
|
+
input: @input,
|
|
87
|
+
history: @history,
|
|
88
|
+
context: @context,
|
|
89
|
+
policies: @policies,
|
|
90
|
+
checkpoint:
|
|
91
|
+
) { |event| yield event }
|
|
92
|
+
@result = execution.result
|
|
93
|
+
@step = execution.step
|
|
94
|
+
@steps = execution.result.steps
|
|
95
|
+
execution.events.each do |event|
|
|
96
|
+
yield event
|
|
95
97
|
end
|
|
98
|
+
@result
|
|
96
99
|
end
|
|
97
100
|
|
|
98
101
|
# Consumes this invocation when necessary and returns RunResult#output.
|
|
@@ -101,7 +104,12 @@ module LittleGhost
|
|
|
101
104
|
# response text. Intermediate usage is recorded for the workflow total.
|
|
102
105
|
def output
|
|
103
106
|
@intermediate = true
|
|
104
|
-
|
|
107
|
+
unless consumed?
|
|
108
|
+
each do |event|
|
|
109
|
+
@owner.send(:emit_workflow_event, event) if event.type.to_s.start_with?("assembly_")
|
|
110
|
+
end
|
|
111
|
+
@owner.send(:record_workflow_steps, @steps)
|
|
112
|
+
end
|
|
105
113
|
result&.output
|
|
106
114
|
end
|
|
107
115
|
|
|
@@ -110,29 +118,19 @@ module LittleGhost
|
|
|
110
118
|
end
|
|
111
119
|
|
|
112
120
|
def close # :nodoc:
|
|
113
|
-
|
|
121
|
+
@mutex.synchronize do
|
|
114
122
|
return if @closed
|
|
115
123
|
|
|
116
124
|
@closed = true
|
|
117
|
-
@agent
|
|
118
125
|
end
|
|
119
|
-
agent&.close
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
private
|
|
123
|
-
|
|
124
|
-
def report_usage
|
|
125
|
-
usage = result&.usage || @usage
|
|
126
|
-
@on_usage.call(usage) if usage
|
|
127
126
|
end
|
|
128
127
|
end
|
|
129
128
|
|
|
130
129
|
# Owning run and the runtime used to resolve workflow agents.
|
|
131
130
|
attr_reader :run, :runtime
|
|
132
131
|
|
|
133
|
-
def initialize(run
|
|
134
|
-
|
|
135
|
-
@runtime = runtime
|
|
132
|
+
def initialize(run: nil, runtime: nil) # :nodoc:
|
|
133
|
+
super(run:, runtime:, standalone: run.nil?)
|
|
136
134
|
@mutex = Mutex.new
|
|
137
135
|
@closed = false
|
|
138
136
|
@started = false
|
|
@@ -162,6 +160,17 @@ module LittleGhost
|
|
|
162
160
|
)
|
|
163
161
|
raise ArgumentError, "input is required" if input.nil?
|
|
164
162
|
|
|
163
|
+
if standalone?
|
|
164
|
+
return build_run(entrypoint_payload(input, {
|
|
165
|
+
history:,
|
|
166
|
+
context:,
|
|
167
|
+
settings:,
|
|
168
|
+
template_paths:,
|
|
169
|
+
deadline_at: deadline,
|
|
170
|
+
cancellation_token:
|
|
171
|
+
}.compact)).each
|
|
172
|
+
end
|
|
173
|
+
|
|
165
174
|
@mutex.synchronize do
|
|
166
175
|
raise Error, "workflow is already closed" if @closed
|
|
167
176
|
raise Error, "workflow instances can only be streamed once" if @started
|
|
@@ -178,11 +187,14 @@ module LittleGhost
|
|
|
178
187
|
@parent_operation_id = parent_operation_id
|
|
179
188
|
@checkpoint = checkpoint
|
|
180
189
|
@intermediate_usage = Usage.new
|
|
190
|
+
@workflow_steps = []
|
|
191
|
+
@workflow_events = nil
|
|
181
192
|
end
|
|
182
193
|
|
|
183
194
|
Enumerator.new do |events|
|
|
184
195
|
error_emitted = false
|
|
185
196
|
observed_usage = nil
|
|
197
|
+
@workflow_events = events
|
|
186
198
|
ensure_open!
|
|
187
199
|
final_invocation = perform
|
|
188
200
|
unless final_invocation.is_a?(Invocation) && !final_invocation.consumed?
|
|
@@ -197,6 +209,8 @@ module LittleGhost
|
|
|
197
209
|
event.data.fetch(:result).usage
|
|
198
210
|
when :invocation_error
|
|
199
211
|
event.data[:usage] || observed_usage
|
|
212
|
+
when :assembly_step_error
|
|
213
|
+
event.data[:usage] || observed_usage
|
|
200
214
|
else
|
|
201
215
|
observed_usage
|
|
202
216
|
end
|
|
@@ -212,10 +226,12 @@ module LittleGhost
|
|
|
212
226
|
)
|
|
213
227
|
end
|
|
214
228
|
raise
|
|
229
|
+
ensure
|
|
230
|
+
@workflow_events = nil
|
|
215
231
|
end
|
|
216
232
|
end
|
|
217
233
|
|
|
218
|
-
# Closes all
|
|
234
|
+
# Closes all declared invocations in reverse order.
|
|
219
235
|
#
|
|
220
236
|
# The operation is idempotent, attempts every close, and raises the first
|
|
221
237
|
# cleanup failure.
|
|
@@ -250,35 +266,30 @@ module LittleGhost
|
|
|
250
266
|
end
|
|
251
267
|
|
|
252
268
|
# :doc:
|
|
253
|
-
# Creates a lazy invocation for +
|
|
269
|
+
# Creates a lazy invocation for +assembly+.
|
|
254
270
|
#
|
|
255
271
|
# Intermediate calls may use +output+; the final call must be returned from
|
|
256
272
|
# +perform+ without being consumed.
|
|
257
|
-
def invoke(
|
|
273
|
+
def invoke(
|
|
274
|
+
assembly,
|
|
275
|
+
as: nil,
|
|
276
|
+
input: self.input,
|
|
277
|
+
history: self.history,
|
|
278
|
+
context: self.context,
|
|
279
|
+
timeout: nil,
|
|
280
|
+
retries: 0,
|
|
281
|
+
retry_on: nil,
|
|
282
|
+
retry_delay: 0
|
|
283
|
+
)
|
|
284
|
+
participant = as || assembly_identity(assembly)
|
|
258
285
|
invocation = Invocation.new(
|
|
286
|
+
reference: assembly,
|
|
287
|
+
participant:,
|
|
259
288
|
input:,
|
|
260
289
|
history:,
|
|
261
290
|
context: isolated_state(context),
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
begin
|
|
265
|
-
[
|
|
266
|
-
agent,
|
|
267
|
-
{
|
|
268
|
-
cancellation_token: @cancellation_token,
|
|
269
|
-
deadline: @deadline,
|
|
270
|
-
settings: @settings,
|
|
271
|
-
template_locals: template_locals_for(agent),
|
|
272
|
-
template_paths: @template_paths,
|
|
273
|
-
parent_operation_id: @parent_operation_id
|
|
274
|
-
}
|
|
275
|
-
]
|
|
276
|
-
rescue
|
|
277
|
-
agent.close
|
|
278
|
-
raise
|
|
279
|
-
end
|
|
280
|
-
},
|
|
281
|
-
on_usage: ->(usage) { record_intermediate_usage(usage) }
|
|
291
|
+
policies: {timeout:, retries:, retry_on:, retry_delay:},
|
|
292
|
+
owner: self
|
|
282
293
|
)
|
|
283
294
|
@mutex.synchronize do
|
|
284
295
|
raise Error, "workflow is already closed" if @closed
|
|
@@ -288,8 +299,112 @@ module LittleGhost
|
|
|
288
299
|
invocation
|
|
289
300
|
end
|
|
290
301
|
|
|
291
|
-
|
|
292
|
-
|
|
302
|
+
# Consumes independent invocations concurrently and returns their outputs in
|
|
303
|
+
# declaration order.
|
|
304
|
+
def parallel(*invocations, max_concurrency: 8)
|
|
305
|
+
raise ArgumentError, "parallel requires at least one invocation" if invocations.empty?
|
|
306
|
+
unless invocations.all? { |invocation| invocation.is_a?(Invocation) && !invocation.consumed? }
|
|
307
|
+
raise ArgumentError, "parallel accepts unconsumed workflow invocations"
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
token = @cancellation_token.child
|
|
311
|
+
queue = SizedQueue.new(1_000)
|
|
312
|
+
worker = Thread.new do
|
|
313
|
+
results = Support::Executor.new(max_concurrency:).map(
|
|
314
|
+
invocations,
|
|
315
|
+
cancellation_token: token,
|
|
316
|
+
on_result: ->(_index, execution) { record_workflow_steps(execution.fetch(:steps)) }
|
|
317
|
+
) do |invocation|
|
|
318
|
+
invocation.each do |event|
|
|
319
|
+
if event.type.to_s.start_with?("assembly_")
|
|
320
|
+
enqueue_assembly_event(queue, [:event, event], token)
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
{output: invocation.result&.output, steps: invocation.instance_variable_get(:@steps)}
|
|
324
|
+
end
|
|
325
|
+
enqueue_assembly_event(queue, [:done, results], token)
|
|
326
|
+
rescue => error
|
|
327
|
+
token.cancel
|
|
328
|
+
enqueue_assembly_terminal(queue, [:error, error])
|
|
329
|
+
end
|
|
330
|
+
executions = loop do
|
|
331
|
+
type, value = queue.pop
|
|
332
|
+
emit_workflow_event(value) if type == :event
|
|
333
|
+
raise value if type == :error
|
|
334
|
+
break value if type == :done
|
|
335
|
+
end
|
|
336
|
+
executions.map { |execution| execution.fetch(:output) }
|
|
337
|
+
ensure
|
|
338
|
+
token&.cancel
|
|
339
|
+
worker&.join
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def execute_workflow_invocation(reference:, participant:, input:, history:, context:, policies:, checkpoint:)
|
|
343
|
+
step_id = SecureRandom.uuid
|
|
344
|
+
predecessor_id = @mutex.synchronize do
|
|
345
|
+
@workflow_steps.reverse.find { |step| step.parent_id.nil? }&.id
|
|
346
|
+
end
|
|
347
|
+
yield StreamEvent.build(
|
|
348
|
+
:assembly_step_start,
|
|
349
|
+
assembly_id: self.class.assembly_id,
|
|
350
|
+
assembly_kind: :workflow,
|
|
351
|
+
participant: participant.to_s,
|
|
352
|
+
step_id:
|
|
353
|
+
)
|
|
354
|
+
execution = execute_assembly_step(
|
|
355
|
+
reference:,
|
|
356
|
+
participant:,
|
|
357
|
+
input:,
|
|
358
|
+
history:,
|
|
359
|
+
context:,
|
|
360
|
+
cancellation_token: @cancellation_token,
|
|
361
|
+
deadline: @deadline,
|
|
362
|
+
settings: @settings,
|
|
363
|
+
template_locals: @template_locals,
|
|
364
|
+
template_paths: @template_paths,
|
|
365
|
+
parent_operation_id: @parent_operation_id,
|
|
366
|
+
policies:,
|
|
367
|
+
predecessor_ids: Array(predecessor_id),
|
|
368
|
+
checkpoint:,
|
|
369
|
+
step_id:
|
|
370
|
+
) { |event| yield event }
|
|
371
|
+
yield StreamEvent.build(
|
|
372
|
+
:assembly_step_stop,
|
|
373
|
+
assembly_id: self.class.assembly_id,
|
|
374
|
+
assembly_kind: :workflow,
|
|
375
|
+
participant: participant.to_s,
|
|
376
|
+
step_id: execution.step.id,
|
|
377
|
+
usage: execution.step.usage
|
|
378
|
+
)
|
|
379
|
+
execution
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def record_workflow_steps(steps)
|
|
383
|
+
@mutex.synchronize do
|
|
384
|
+
@workflow_steps.concat(steps)
|
|
385
|
+
@intermediate_usage += steps.first.usage
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def emit_workflow_event(event)
|
|
390
|
+
sink = @mutex.synchronize do
|
|
391
|
+
if event.type == :assembly_step_error && event.data[:terminal] && event.data[:usage]
|
|
392
|
+
@intermediate_usage += event.data.fetch(:usage)
|
|
393
|
+
end
|
|
394
|
+
@workflow_events
|
|
395
|
+
end
|
|
396
|
+
sink << event if sink
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def assembly_identity(reference)
|
|
400
|
+
case reference
|
|
401
|
+
when AssemblyBuilder, AssemblyDefinition
|
|
402
|
+
reference.assembly_id
|
|
403
|
+
when Class
|
|
404
|
+
(reference <= Assembly) ? reference.assembly_id : reference.to_s
|
|
405
|
+
else
|
|
406
|
+
reference.to_s
|
|
407
|
+
end
|
|
293
408
|
end
|
|
294
409
|
|
|
295
410
|
def aggregate_usage(event)
|
|
@@ -302,13 +417,19 @@ module LittleGhost
|
|
|
302
417
|
usage: workflow_usage + result.usage,
|
|
303
418
|
messages: result.messages,
|
|
304
419
|
state: result.state,
|
|
305
|
-
structured_result: result.structured_result
|
|
420
|
+
structured_result: result.structured_result,
|
|
421
|
+
steps: workflow_steps + result.steps
|
|
306
422
|
)
|
|
307
423
|
StreamEvent.build(event.type, **event.data.merge(result: combined))
|
|
308
424
|
when :invocation_error
|
|
309
425
|
usage = event.data[:usage]
|
|
310
426
|
return event unless usage
|
|
311
427
|
|
|
428
|
+
StreamEvent.build(event.type, **event.data.merge(usage: workflow_usage + usage))
|
|
429
|
+
when :assembly_step_error
|
|
430
|
+
usage = event.data[:usage]
|
|
431
|
+
return event unless usage
|
|
432
|
+
|
|
312
433
|
StreamEvent.build(event.type, **event.data.merge(usage: workflow_usage + usage))
|
|
313
434
|
else
|
|
314
435
|
event
|
|
@@ -338,6 +459,10 @@ module LittleGhost
|
|
|
338
459
|
@mutex.synchronize { @intermediate_usage }
|
|
339
460
|
end
|
|
340
461
|
|
|
462
|
+
def workflow_steps
|
|
463
|
+
@mutex.synchronize { @workflow_steps.dup.freeze }
|
|
464
|
+
end
|
|
465
|
+
|
|
341
466
|
def ensure_open!
|
|
342
467
|
@mutex.synchronize { raise Error, "workflow is already closed" if @closed }
|
|
343
468
|
end
|
data/lib/little_ghost.rb
CHANGED
|
@@ -54,17 +54,23 @@ require_relative "little_ghost/session"
|
|
|
54
54
|
require_relative "little_ghost/skills"
|
|
55
55
|
require_relative "little_ghost/tools/write_todos"
|
|
56
56
|
require_relative "little_ghost/run"
|
|
57
|
+
require_relative "little_ghost/execution"
|
|
57
58
|
require_relative "little_ghost/subagents/definition"
|
|
58
59
|
require_relative "little_ghost/subagents/agent_path"
|
|
59
60
|
require_relative "little_ghost/subagents/manager"
|
|
60
61
|
require_relative "little_ghost/agent_interruptions"
|
|
62
|
+
require_relative "little_ghost/assembly"
|
|
63
|
+
require_relative "little_ghost/assembly_execution"
|
|
61
64
|
require_relative "little_ghost/agent"
|
|
62
|
-
require_relative "little_ghost/agent_builder"
|
|
63
65
|
require_relative "little_ghost/workflow"
|
|
66
|
+
require_relative "little_ghost/swarm"
|
|
67
|
+
require_relative "little_ghost/graph"
|
|
68
|
+
require_relative "little_ghost/assembly_builder"
|
|
69
|
+
require_relative "little_ghost/agent_factory"
|
|
64
70
|
require_relative "little_ghost/runtime/hook"
|
|
65
71
|
require_relative "little_ghost/runtime"
|
|
66
72
|
|
|
67
|
-
# Build AI features with reusable agents and
|
|
73
|
+
# Build AI features with reusable agents and composable assemblies. LittleGhost can
|
|
68
74
|
# sit inside an existing Ruby system or support a dedicated AI service, keeping
|
|
69
75
|
# models, prompts, tools, sessions, streaming, and instrumentation behind a
|
|
70
76
|
# cohesive set of Ruby conventions.
|
|
@@ -89,8 +95,9 @@ require_relative "little_ghost/runtime"
|
|
|
89
95
|
# run.response # => "Transfer 481 is waiting for the receiving bank."
|
|
90
96
|
#
|
|
91
97
|
# Agent subclasses hold reusable behavior; Invocation objects carry one request,
|
|
92
|
-
# and Run objects own execution and cleanup.
|
|
93
|
-
#
|
|
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.
|
|
94
101
|
#
|
|
95
102
|
# LittleGhost.configuration is process-wide unless LittleGhost.with_configuration
|
|
96
103
|
# supplies an execution-scoped replacement. Configuration is loaded lazily and
|
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.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matt Robinson
|
|
@@ -107,8 +107,8 @@ dependencies:
|
|
|
107
107
|
- - "~>"
|
|
108
108
|
- !ruby/object:Gem::Version
|
|
109
109
|
version: '1.9'
|
|
110
|
-
description: Add agents, tools, and
|
|
111
|
-
dedicated AI services.
|
|
110
|
+
description: Add agents, tools, workflows, swarms, and graphs to existing Ruby systems
|
|
111
|
+
or dedicated AI services.
|
|
112
112
|
email:
|
|
113
113
|
- robinson.matty@gmail.com
|
|
114
114
|
executables: []
|
|
@@ -128,13 +128,19 @@ files:
|
|
|
128
128
|
- lib/little_ghost/agent/skills.rb
|
|
129
129
|
- lib/little_ghost/agent/tool_loop.rb
|
|
130
130
|
- lib/little_ghost/agent_builder.rb
|
|
131
|
+
- lib/little_ghost/agent_factory.rb
|
|
131
132
|
- lib/little_ghost/agent_interruptions.rb
|
|
133
|
+
- lib/little_ghost/assembly.rb
|
|
134
|
+
- lib/little_ghost/assembly_builder.rb
|
|
135
|
+
- lib/little_ghost/assembly_execution.rb
|
|
132
136
|
- lib/little_ghost/configuration.rb
|
|
133
137
|
- lib/little_ghost/content.rb
|
|
134
138
|
- lib/little_ghost/data/model_catalog.json
|
|
135
139
|
- lib/little_ghost/errors.rb
|
|
136
140
|
- lib/little_ghost/events.rb
|
|
141
|
+
- lib/little_ghost/execution.rb
|
|
137
142
|
- lib/little_ghost/execution_state.rb
|
|
143
|
+
- lib/little_ghost/graph.rb
|
|
138
144
|
- lib/little_ghost/instrumentation.rb
|
|
139
145
|
- lib/little_ghost/invocation.rb
|
|
140
146
|
- lib/little_ghost/lookup.rb
|
|
@@ -203,6 +209,7 @@ files:
|
|
|
203
209
|
- lib/little_ghost/support/output_truncation.rb
|
|
204
210
|
- lib/little_ghost/support/redactor.rb
|
|
205
211
|
- lib/little_ghost/support/sse_parser.rb
|
|
212
|
+
- lib/little_ghost/swarm.rb
|
|
206
213
|
- lib/little_ghost/tool.rb
|
|
207
214
|
- lib/little_ghost/tool_execution.rb
|
|
208
215
|
- lib/little_ghost/tool_registry.rb
|
|
@@ -242,5 +249,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
242
249
|
requirements: []
|
|
243
250
|
rubygems_version: 4.0.10
|
|
244
251
|
specification_version: 4
|
|
245
|
-
summary: A Ruby framework for AI features with agents and
|
|
252
|
+
summary: A Ruby framework for AI features with agents and composable assemblies
|
|
246
253
|
test_files: []
|