language-operator 0.1.37 → 0.1.38
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/Gemfile.lock +1 -1
- data/lib/language_operator/agent/executor.rb +0 -34
- data/lib/language_operator/dsl/agent_definition.rb +81 -33
- data/lib/language_operator/templates/schema/agent_dsl_openapi.yaml +1 -1
- data/lib/language_operator/templates/schema/agent_dsl_schema.json +1 -1
- data/lib/language_operator/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4476732244850657fb5161189ad68010e2ffdef4f4949361786893d119f0de89
|
|
4
|
+
data.tar.gz: 5755720ffc0df24c88c5ec5ea223a4f8899c604f938422e420e878833d172de5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a4408235ba4cc775fc175f7760e0632e78457630b263690efeb3ddc772c58facfcd7b7e0780a38d33bda5c4f9d3d12b46eed0f83d43631c94f1ddfe7180be61d
|
|
7
|
+
data.tar.gz: 3ccbd9c8c91ef1d19ae467cafe3740cc84586853692cf46569d77b692b1cddf682fb21300bbb75244e71335b84a10fde768f6baff1016d18acf8b4c31a869862
|
data/Gemfile.lock
CHANGED
|
@@ -203,40 +203,6 @@ module LanguageOperator
|
|
|
203
203
|
reason: 'Hit max_iterations limit')
|
|
204
204
|
end
|
|
205
205
|
|
|
206
|
-
# Write output to configured destinations
|
|
207
|
-
#
|
|
208
|
-
# @param agent_def [LanguageOperator::Dsl::AgentDefinition] The agent definition
|
|
209
|
-
# @param result [RubyLLM::Message] The result to write
|
|
210
|
-
def write_output(agent_def, result)
|
|
211
|
-
return unless agent_def.output_config
|
|
212
|
-
|
|
213
|
-
content = result.is_a?(String) ? result : result.content
|
|
214
|
-
|
|
215
|
-
if (workspace_path = agent_def.output_config[:workspace])
|
|
216
|
-
full_path = File.join(@agent.workspace_path, workspace_path)
|
|
217
|
-
|
|
218
|
-
begin
|
|
219
|
-
FileUtils.mkdir_p(File.dirname(full_path))
|
|
220
|
-
File.write(full_path, content)
|
|
221
|
-
logger.info("📝 Wrote output to #{workspace_path}")
|
|
222
|
-
rescue Errno::EACCES, Errno::EPERM
|
|
223
|
-
# Permission denied - try writing to workspace root
|
|
224
|
-
fallback_path = File.join(@agent.workspace_path, 'output.txt')
|
|
225
|
-
begin
|
|
226
|
-
File.write(fallback_path, content)
|
|
227
|
-
logger.warn("Could not write to #{workspace_path}, wrote to output.txt instead")
|
|
228
|
-
rescue StandardError => e2
|
|
229
|
-
logger.warn("Could not write output to workspace: #{e2.message}")
|
|
230
|
-
logger.info("Output (first 500 chars): #{content[0..500]}")
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
# Future: Handle Slack, email outputs
|
|
236
|
-
rescue StandardError => e
|
|
237
|
-
logger.warn('Output writing failed', error: e.message)
|
|
238
|
-
end
|
|
239
|
-
|
|
240
206
|
private
|
|
241
207
|
|
|
242
208
|
def logger_component
|
|
@@ -60,7 +60,7 @@ module LanguageOperator
|
|
|
60
60
|
@main = nil
|
|
61
61
|
@tasks = {}
|
|
62
62
|
@constraints = {}
|
|
63
|
-
@output_config =
|
|
63
|
+
@output_config = nil
|
|
64
64
|
@execution_mode = :autonomous
|
|
65
65
|
@webhooks = []
|
|
66
66
|
@mcp_server = nil
|
|
@@ -223,16 +223,58 @@ module LanguageOperator
|
|
|
223
223
|
@constraints = constraint_builder.to_h
|
|
224
224
|
end
|
|
225
225
|
|
|
226
|
-
# Define output
|
|
226
|
+
# Define output handler (organic function) - DSL v1
|
|
227
227
|
#
|
|
228
|
-
#
|
|
229
|
-
#
|
|
230
|
-
|
|
231
|
-
|
|
228
|
+
# The output is an organic function that receives the final outputs from main execution
|
|
229
|
+
# and handles them (logging, saving to workspace, notifications, etc.). Like tasks,
|
|
230
|
+
# it can be neural (instructions-based), symbolic (code block), or hybrid (both).
|
|
231
|
+
#
|
|
232
|
+
# @param options [Hash] Output configuration
|
|
233
|
+
# @option options [String] :instructions Natural language instructions (neural)
|
|
234
|
+
# @yield [outputs] Symbolic implementation block (optional)
|
|
235
|
+
# @yieldparam outputs [Hash] The outputs returned from main execution
|
|
236
|
+
# @return [TaskDefinition] The output task definition
|
|
237
|
+
#
|
|
238
|
+
# @example Neural output
|
|
239
|
+
# output instructions: "save results to workspace as JSON"
|
|
240
|
+
#
|
|
241
|
+
# @example Symbolic output
|
|
242
|
+
# output do |outputs|
|
|
243
|
+
# File.write("/workspace/result.json", JSON.pretty_generate(outputs))
|
|
244
|
+
# end
|
|
245
|
+
#
|
|
246
|
+
# @example Hybrid output
|
|
247
|
+
# output instructions: "save results to workspace" do |outputs|
|
|
248
|
+
# File.write("/workspace/result.json", outputs.to_json)
|
|
249
|
+
# end
|
|
250
|
+
def output(**options, &block)
|
|
251
|
+
return @output_config if options.empty? && block.nil?
|
|
252
|
+
|
|
253
|
+
# Create a TaskDefinition for output (it's an organic function)
|
|
254
|
+
output_task = TaskDefinition.new(:output)
|
|
255
|
+
|
|
256
|
+
# Output task always receives main's outputs as inputs (type: any)
|
|
257
|
+
# No need to specify inputs - they come from main
|
|
258
|
+
|
|
259
|
+
# Configure instructions if provided (neural)
|
|
260
|
+
output_task.instructions(options[:instructions]) if options[:instructions]
|
|
261
|
+
|
|
262
|
+
# Symbolic implementation (if block provided)
|
|
263
|
+
output_task.execute(&block) if block
|
|
264
|
+
|
|
265
|
+
@output_config = output_task
|
|
266
|
+
|
|
267
|
+
task_type = if output_task.neural? && output_task.symbolic?
|
|
268
|
+
'hybrid'
|
|
269
|
+
elsif output_task.neural?
|
|
270
|
+
'neural'
|
|
271
|
+
else
|
|
272
|
+
'symbolic'
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
logger.debug('Output defined', type: task_type)
|
|
232
276
|
|
|
233
|
-
|
|
234
|
-
output_builder.instance_eval(&block) if block
|
|
235
|
-
@output_config = output_builder.to_h
|
|
277
|
+
output_task
|
|
236
278
|
end
|
|
237
279
|
|
|
238
280
|
# Set execution mode
|
|
@@ -408,9 +450,15 @@ module LanguageOperator
|
|
|
408
450
|
|
|
409
451
|
# If main defined, execute it; otherwise just log
|
|
410
452
|
if @main
|
|
411
|
-
logger.timed('Objective main execution') do
|
|
453
|
+
outputs = logger.timed('Objective main execution') do
|
|
412
454
|
@main.call({ objective: objective })
|
|
413
455
|
end
|
|
456
|
+
|
|
457
|
+
# Call output handler if defined (it's an organic function)
|
|
458
|
+
if @output_config.is_a?(TaskDefinition)
|
|
459
|
+
logger.debug('Executing output handler', outputs: outputs)
|
|
460
|
+
execute_output_handler(outputs)
|
|
461
|
+
end
|
|
414
462
|
else
|
|
415
463
|
logger.warn('No main block defined, skipping execution')
|
|
416
464
|
end
|
|
@@ -418,6 +466,29 @@ module LanguageOperator
|
|
|
418
466
|
|
|
419
467
|
logger.info('All objectives completed', total: @objectives.size)
|
|
420
468
|
end
|
|
469
|
+
|
|
470
|
+
# Execute the output handler (neural or symbolic)
|
|
471
|
+
#
|
|
472
|
+
# @param outputs [Hash] The outputs from main execution
|
|
473
|
+
def execute_output_handler(outputs)
|
|
474
|
+
# If symbolic implementation exists, use it
|
|
475
|
+
if @output_config.symbolic?
|
|
476
|
+
logger.debug('Executing symbolic output handler')
|
|
477
|
+
# execute_symbolic takes (inputs, context) - outputs are the inputs, context is nil
|
|
478
|
+
@output_config.execute_symbolic(outputs, nil)
|
|
479
|
+
elsif @output_config.neural?
|
|
480
|
+
# Neural output - would need LLM access to execute
|
|
481
|
+
# For now, just log the instruction
|
|
482
|
+
logger.info('Neural output handler',
|
|
483
|
+
instruction: @output_config.instructions_text,
|
|
484
|
+
outputs: outputs)
|
|
485
|
+
logger.warn('Neural output execution not yet implemented - instruction logged only')
|
|
486
|
+
end
|
|
487
|
+
rescue StandardError => e
|
|
488
|
+
logger.error('Output handler failed',
|
|
489
|
+
error: e.message,
|
|
490
|
+
backtrace: e.backtrace[0..5])
|
|
491
|
+
end
|
|
421
492
|
end
|
|
422
493
|
|
|
423
494
|
# Helper class for building constraints
|
|
@@ -485,28 +556,5 @@ module LanguageOperator
|
|
|
485
556
|
@constraints
|
|
486
557
|
end
|
|
487
558
|
end
|
|
488
|
-
|
|
489
|
-
# Helper class for building output configuration
|
|
490
|
-
class OutputBuilder
|
|
491
|
-
def initialize
|
|
492
|
-
@config = {}
|
|
493
|
-
end
|
|
494
|
-
|
|
495
|
-
def workspace(path)
|
|
496
|
-
@config[:workspace] = path
|
|
497
|
-
end
|
|
498
|
-
|
|
499
|
-
def slack(channel:)
|
|
500
|
-
@config[:slack] = { channel: channel }
|
|
501
|
-
end
|
|
502
|
-
|
|
503
|
-
def email(to:)
|
|
504
|
-
@config[:email] = { to: to }
|
|
505
|
-
end
|
|
506
|
-
|
|
507
|
-
def to_h
|
|
508
|
-
@config
|
|
509
|
-
end
|
|
510
|
-
end
|
|
511
559
|
end
|
|
512
560
|
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"$id": "https://github.com/language-operator/language-operator-gem/schema/agent-dsl.json",
|
|
4
4
|
"title": "Language Operator Agent DSL",
|
|
5
5
|
"description": "Schema for defining autonomous AI agents using the Language Operator DSL",
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.38",
|
|
7
7
|
"type": "object",
|
|
8
8
|
"properties": {
|
|
9
9
|
"name": {
|