language-operator 0.1.31 → 0.1.36
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/.rubocop.yml +7 -8
- data/CHANGELOG.md +14 -0
- data/CI_STATUS.md +56 -0
- data/Gemfile.lock +2 -2
- data/Makefile +22 -6
- data/lib/language_operator/agent/base.rb +10 -6
- data/lib/language_operator/agent/executor.rb +19 -97
- data/lib/language_operator/agent/safety/ast_validator.rb +62 -43
- data/lib/language_operator/agent/safety/safe_executor.rb +27 -2
- data/lib/language_operator/agent/scheduler.rb +60 -0
- data/lib/language_operator/agent/task_executor.rb +548 -0
- data/lib/language_operator/agent.rb +90 -27
- data/lib/language_operator/cli/base_command.rb +117 -0
- data/lib/language_operator/cli/commands/agent.rb +339 -407
- data/lib/language_operator/cli/commands/cluster.rb +274 -290
- data/lib/language_operator/cli/commands/install.rb +110 -119
- data/lib/language_operator/cli/commands/model.rb +284 -184
- data/lib/language_operator/cli/commands/persona.rb +218 -284
- data/lib/language_operator/cli/commands/quickstart.rb +4 -5
- data/lib/language_operator/cli/commands/status.rb +31 -35
- data/lib/language_operator/cli/commands/system.rb +221 -233
- data/lib/language_operator/cli/commands/tool.rb +356 -422
- data/lib/language_operator/cli/commands/use.rb +19 -22
- data/lib/language_operator/cli/helpers/resource_dependency_checker.rb +0 -18
- data/lib/language_operator/cli/wizards/quickstart_wizard.rb +0 -1
- data/lib/language_operator/client/config.rb +20 -21
- data/lib/language_operator/config.rb +115 -3
- data/lib/language_operator/constants.rb +54 -0
- data/lib/language_operator/dsl/agent_context.rb +7 -7
- data/lib/language_operator/dsl/agent_definition.rb +111 -26
- data/lib/language_operator/dsl/config.rb +30 -66
- data/lib/language_operator/dsl/main_definition.rb +114 -0
- data/lib/language_operator/dsl/schema.rb +84 -43
- data/lib/language_operator/dsl/task_definition.rb +315 -0
- data/lib/language_operator/dsl.rb +0 -1
- data/lib/language_operator/instrumentation/task_tracer.rb +285 -0
- data/lib/language_operator/logger.rb +4 -4
- data/lib/language_operator/synthesis_test_harness.rb +324 -0
- data/lib/language_operator/templates/examples/agent_synthesis.tmpl +26 -8
- data/lib/language_operator/templates/schema/CHANGELOG.md +26 -0
- data/lib/language_operator/templates/schema/agent_dsl_openapi.yaml +1 -1
- data/lib/language_operator/templates/schema/agent_dsl_schema.json +84 -42
- data/lib/language_operator/type_coercion.rb +250 -0
- data/lib/language_operator/ux/base.rb +81 -0
- data/lib/language_operator/ux/concerns/README.md +155 -0
- data/lib/language_operator/ux/concerns/headings.rb +90 -0
- data/lib/language_operator/ux/concerns/input_validation.rb +146 -0
- data/lib/language_operator/ux/concerns/provider_helpers.rb +167 -0
- data/lib/language_operator/ux/create_agent.rb +252 -0
- data/lib/language_operator/ux/create_model.rb +267 -0
- data/lib/language_operator/ux/quickstart.rb +594 -0
- data/lib/language_operator/version.rb +1 -1
- data/lib/language_operator.rb +2 -0
- data/synth/001/Makefile +90 -0
- data/synth/001/agent.rb +26 -0
- data/synth/001/agent.yaml +7 -0
- data/synth/001/output.log +44 -0
- data/synth/Makefile +39 -0
- data/synth/README.md +342 -0
- metadata +31 -14
- data/lib/language_operator/dsl/workflow_definition.rb +0 -259
- data/requirements/tasks/challenge.md +0 -9
- data/requirements/tasks/iterate.md +0 -36
- data/requirements/tasks/optimize.md +0 -21
- data/requirements/tasks/tag.md +0 -5
- data/test_agent_dsl.rb +0 -108
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../logger'
|
|
4
|
-
require_relative '../loggable'
|
|
5
|
-
|
|
6
|
-
module LanguageOperator
|
|
7
|
-
module Dsl
|
|
8
|
-
# Workflow definition for agent execution
|
|
9
|
-
#
|
|
10
|
-
# Defines a series of steps that an agent executes to achieve objectives.
|
|
11
|
-
# Steps can depend on other steps, call tools, or perform LLM processing.
|
|
12
|
-
#
|
|
13
|
-
# @example Define a workflow
|
|
14
|
-
# workflow do
|
|
15
|
-
# step :search do
|
|
16
|
-
# tool "web_search"
|
|
17
|
-
# params query: "latest news"
|
|
18
|
-
# end
|
|
19
|
-
#
|
|
20
|
-
# step :summarize do
|
|
21
|
-
# depends_on :search
|
|
22
|
-
# prompt "Summarize: {search.output}"
|
|
23
|
-
# end
|
|
24
|
-
# end
|
|
25
|
-
class WorkflowDefinition
|
|
26
|
-
include LanguageOperator::Loggable
|
|
27
|
-
|
|
28
|
-
attr_reader :steps, :step_order
|
|
29
|
-
|
|
30
|
-
def initialize
|
|
31
|
-
@steps = {}
|
|
32
|
-
@step_order = []
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# Define a workflow step
|
|
36
|
-
#
|
|
37
|
-
# @param name [Symbol] Step name
|
|
38
|
-
# @param tool [String, nil] Tool to use (optional)
|
|
39
|
-
# @param params [Hash] Tool parameters (optional)
|
|
40
|
-
# @param depends_on [Symbol, Array<Symbol>] Dependencies (optional)
|
|
41
|
-
# @yield Step definition block
|
|
42
|
-
# @return [void]
|
|
43
|
-
def step(name, tool: nil, params: {}, depends_on: nil, &block)
|
|
44
|
-
step_def = StepDefinition.new(name, logger: @logger)
|
|
45
|
-
|
|
46
|
-
if tool
|
|
47
|
-
step_def.tool(tool)
|
|
48
|
-
step_def.params(params) unless params.empty?
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
step_def.depends_on(depends_on) if depends_on
|
|
52
|
-
|
|
53
|
-
step_def.instance_eval(&block) if block
|
|
54
|
-
@steps[name] = step_def
|
|
55
|
-
@step_order << name
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Execute the workflow
|
|
59
|
-
#
|
|
60
|
-
# @param context [Object] Execution context
|
|
61
|
-
# @return [Hash] Results from each step
|
|
62
|
-
def execute(context = nil)
|
|
63
|
-
results = {}
|
|
64
|
-
|
|
65
|
-
logger.info('Executing workflow', step_count: @steps.size)
|
|
66
|
-
|
|
67
|
-
@step_order.each do |step_name|
|
|
68
|
-
step_def = @steps[step_name]
|
|
69
|
-
|
|
70
|
-
# Check dependencies
|
|
71
|
-
if step_def.dependencies.any?
|
|
72
|
-
logger.debug('Checking dependencies',
|
|
73
|
-
step: step_name,
|
|
74
|
-
dependencies: step_def.dependencies)
|
|
75
|
-
step_def.dependencies.each do |dep|
|
|
76
|
-
next if results.key?(dep)
|
|
77
|
-
|
|
78
|
-
logger.error('Dependency not satisfied',
|
|
79
|
-
step: step_name,
|
|
80
|
-
missing_dependency: dep)
|
|
81
|
-
raise "Step #{step_name} depends on #{dep}, but #{dep} has not been executed"
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Execute step
|
|
86
|
-
logger.info('Executing step',
|
|
87
|
-
step: step_name,
|
|
88
|
-
tool: step_def.tool_name,
|
|
89
|
-
has_prompt: !step_def.prompt_template.nil?)
|
|
90
|
-
|
|
91
|
-
result = logger.timed('Step execution') do
|
|
92
|
-
step_def.execute(results, context)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
results[step_name] = result
|
|
96
|
-
logger.info('Step completed', step: step_name)
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
logger.info('Workflow execution completed', total_steps: @steps.size)
|
|
100
|
-
results
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
private
|
|
104
|
-
|
|
105
|
-
def logger_component
|
|
106
|
-
'Workflow'
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
# Individual step definition
|
|
111
|
-
class StepDefinition
|
|
112
|
-
include LanguageOperator::Loggable
|
|
113
|
-
|
|
114
|
-
attr_reader :name, :dependencies, :tool_name, :tool_params, :prompt_template
|
|
115
|
-
|
|
116
|
-
def initialize(name, logger: nil)
|
|
117
|
-
@name = name
|
|
118
|
-
@tool_name = nil
|
|
119
|
-
@tool_params = {}
|
|
120
|
-
@prompt_template = nil
|
|
121
|
-
@dependencies = []
|
|
122
|
-
@execute_block = nil
|
|
123
|
-
@parent_logger = logger
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
# Set the tool to use
|
|
127
|
-
#
|
|
128
|
-
# @param name [String] Tool name
|
|
129
|
-
# @return [void]
|
|
130
|
-
def tool(name = nil)
|
|
131
|
-
return @tool_name if name.nil?
|
|
132
|
-
|
|
133
|
-
@tool_name = name
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# Set tool parameters
|
|
137
|
-
#
|
|
138
|
-
# @param hash [Hash] Parameters
|
|
139
|
-
# @return [Hash] Current parameters
|
|
140
|
-
def params(hash = nil)
|
|
141
|
-
return @tool_params if hash.nil?
|
|
142
|
-
|
|
143
|
-
@tool_params = hash
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
# Set prompt template (for LLM processing)
|
|
147
|
-
#
|
|
148
|
-
# @param template [String] Prompt template
|
|
149
|
-
# @return [String] Current prompt
|
|
150
|
-
def prompt(template = nil)
|
|
151
|
-
return @prompt_template if template.nil?
|
|
152
|
-
|
|
153
|
-
@prompt_template = template
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
# Declare dependencies on other steps
|
|
157
|
-
#
|
|
158
|
-
# @param steps [Symbol, Array<Symbol>] Step names this depends on
|
|
159
|
-
# @return [Array<Symbol>] Current dependencies
|
|
160
|
-
def depends_on(*steps)
|
|
161
|
-
return @dependencies if steps.empty?
|
|
162
|
-
|
|
163
|
-
@dependencies = steps.flatten
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
# Define custom execution logic
|
|
167
|
-
#
|
|
168
|
-
# @yield Execution block
|
|
169
|
-
# @return [void]
|
|
170
|
-
def execute(&block)
|
|
171
|
-
@execute_block = block if block
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
# Execute this step
|
|
175
|
-
#
|
|
176
|
-
# @param results [Hash] Results from previous steps
|
|
177
|
-
# @param context [Object] Execution context
|
|
178
|
-
# @return [Object] Step result
|
|
179
|
-
def execute_step(results, context)
|
|
180
|
-
if @execute_block
|
|
181
|
-
# Custom execution logic
|
|
182
|
-
logger.debug('Executing custom logic', step: @name)
|
|
183
|
-
@execute_block.call(results, context)
|
|
184
|
-
elsif @tool_name
|
|
185
|
-
# Tool execution
|
|
186
|
-
params = interpolate_params(@tool_params, results)
|
|
187
|
-
logger.info('Calling tool',
|
|
188
|
-
step: @name,
|
|
189
|
-
tool: @tool_name,
|
|
190
|
-
params: params)
|
|
191
|
-
# In real implementation, this would call the actual tool
|
|
192
|
-
"Tool #{@tool_name} executed with #{params.inspect}"
|
|
193
|
-
elsif @prompt_template
|
|
194
|
-
# LLM processing
|
|
195
|
-
prompt = interpolate_template(@prompt_template, results)
|
|
196
|
-
logger.debug('LLM prompt',
|
|
197
|
-
step: @name,
|
|
198
|
-
prompt: prompt[0..200])
|
|
199
|
-
# In real implementation, this would call the LLM
|
|
200
|
-
"LLM processed: #{prompt}"
|
|
201
|
-
else
|
|
202
|
-
# No-op step
|
|
203
|
-
logger.debug('No execution logic defined', step: @name)
|
|
204
|
-
nil
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
alias execute execute_step
|
|
209
|
-
|
|
210
|
-
private
|
|
211
|
-
|
|
212
|
-
def logger
|
|
213
|
-
@parent_logger || super
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
def logger_component
|
|
217
|
-
"Step:#{@name}"
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
# Interpolate parameters with results from previous steps
|
|
221
|
-
#
|
|
222
|
-
# @param params [Hash] Parameter template
|
|
223
|
-
# @param results [Hash] Previous results
|
|
224
|
-
# @return [Hash] Interpolated parameters
|
|
225
|
-
def interpolate_params(params, results)
|
|
226
|
-
params.transform_values do |value|
|
|
227
|
-
if value.is_a?(String) && value.match?(/\{(\w+)\.(\w+)\}/)
|
|
228
|
-
# Replace {step.field} with actual value
|
|
229
|
-
value.gsub(/\{(\w+)\.(\w+)\}/) do
|
|
230
|
-
step_name = Regexp.last_match(1).to_sym
|
|
231
|
-
field = Regexp.last_match(2)
|
|
232
|
-
results.dig(step_name, field) || value
|
|
233
|
-
end
|
|
234
|
-
else
|
|
235
|
-
value
|
|
236
|
-
end
|
|
237
|
-
end
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
# Interpolate template string with results
|
|
241
|
-
#
|
|
242
|
-
# @param template [String] Template string
|
|
243
|
-
# @param results [Hash] Previous results
|
|
244
|
-
# @return [String] Interpolated string
|
|
245
|
-
def interpolate_template(template, results)
|
|
246
|
-
template.gsub(/\{(\w+)(?:\.(\w+))?\}/) do
|
|
247
|
-
step_name = Regexp.last_match(1).to_sym
|
|
248
|
-
field = Regexp.last_match(2)
|
|
249
|
-
|
|
250
|
-
if field
|
|
251
|
-
results.dig(step_name, field)&.to_s || "{#{step_name}.#{field}}"
|
|
252
|
-
else
|
|
253
|
-
results[step_name]&.to_s || "{#{step_name}}"
|
|
254
|
-
end
|
|
255
|
-
end
|
|
256
|
-
end
|
|
257
|
-
end
|
|
258
|
-
end
|
|
259
|
-
end
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
You are the public face, the user interface, of an extremely ambitious project called the Language Operator.
|
|
2
|
-
|
|
3
|
-
It synthesizes code *in production* securely from any arbitrary instructions written in plain text.
|
|
4
|
-
|
|
5
|
-
Read ../language-operator/README.md to understand your significance.
|
|
6
|
-
|
|
7
|
-
In that light, I challenge you to ensure that we're matching that vision in quality and supporting the full power of its CRDs.
|
|
8
|
-
|
|
9
|
-
Dive into this code, maybe into the language-operator itself. What can **this gem** do better at?
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# Task
|
|
2
|
-
|
|
3
|
-
## Persona
|
|
4
|
-
|
|
5
|
-
Adopt the [ruby-engineer](../../../requirements/personas/ruby-engineer.md) persona while executing these instructions, please.
|
|
6
|
-
|
|
7
|
-
## Inputs
|
|
8
|
-
|
|
9
|
-
- id int -- A GitHub issue index ID.
|
|
10
|
-
|
|
11
|
-
## Background
|
|
12
|
-
|
|
13
|
-
This is a early-phase project that works exclusively in main.
|
|
14
|
-
Issues are found using the `gh` command for this project:
|
|
15
|
-
- Owner: language-operator
|
|
16
|
-
- Repository: language-operator-gem
|
|
17
|
-
|
|
18
|
-
## Instructions
|
|
19
|
-
|
|
20
|
-
Follow these directions closely:
|
|
21
|
-
|
|
22
|
-
1. Use the ForgeJo tool to find the top issue for this repository.
|
|
23
|
-
2. Investigate if it's valid, or a mis-use of the intended feature.
|
|
24
|
-
3. **CRITICAL:** Switch to plan mode, and propose an implementation plan. Await my feedback.
|
|
25
|
-
4. Add your implementation plan as a comment on the issue.
|
|
26
|
-
5. Implement the changes.
|
|
27
|
-
6. Run existing tests, and add new ones if necessary. Remember to include CI. Remember the linter and that bundler will fail if it's out of sync with its lockfile.
|
|
28
|
-
7. **CRITICAL:** Test the actual functionality manually before committing. If it's a CLI command, run it. If it's library code, test it in the appropriate context. Never commit untested code.
|
|
29
|
-
8. Commit the change and push to origin.
|
|
30
|
-
9. **CRITICAL:** Halt while CI runs and await my feedback.
|
|
31
|
-
10. Comment on your solution in the ForgeJo issue.
|
|
32
|
-
11. Resolve the issue.
|
|
33
|
-
|
|
34
|
-
## Output
|
|
35
|
-
|
|
36
|
-
An implementation, test coverage, updated CI, and a closed ticket.
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
# Task
|
|
3
|
-
|
|
4
|
-
## Name
|
|
5
|
-
|
|
6
|
-
Optimize
|
|
7
|
-
|
|
8
|
-
## Persona
|
|
9
|
-
|
|
10
|
-
Adopt the [ruby-engineer](../requirements/personas/ruby-engineer.md) persona while executing these instructions, please.
|
|
11
|
-
|
|
12
|
-
## Instructions
|
|
13
|
-
|
|
14
|
-
Suggest an improvement that could improve the quality of the codebase or developer experience. Things like opportunities to reduce lines of code, DRYing up code, or eliminating dead code paths.
|
|
15
|
-
|
|
16
|
-
An important thing to consider is that this code has been written by different agents with different contexts, who may not have been aware of overall patterns. These kinds of optimizations are high priority.
|
|
17
|
-
|
|
18
|
-
## Output
|
|
19
|
-
|
|
20
|
-
Switch to Plan mode.
|
|
21
|
-
A proposed list of three concrete optimizations.
|
data/requirements/tasks/tag.md
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
Time to release a new version!
|
|
2
|
-
|
|
3
|
-
1. Update the patch version in lib/language_operator/version.rb and re-run bundler to update the lockfile.
|
|
4
|
-
2. Commit the version with the message "vX.Y.Z" and push to origin.
|
|
5
|
-
3. Tag the new version and push to origin with the --tags argument.
|
data/test_agent_dsl.rb
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Quick test of the agent DSL without requiring full langop gem dependencies
|
|
5
|
-
|
|
6
|
-
require_relative 'lib/langop/dsl/agent_definition'
|
|
7
|
-
require_relative 'lib/langop/dsl/agent_context'
|
|
8
|
-
require_relative 'lib/langop/dsl/workflow_definition'
|
|
9
|
-
|
|
10
|
-
puts '=' * 70
|
|
11
|
-
puts 'Agent DSL Test'
|
|
12
|
-
puts '=' * 70
|
|
13
|
-
puts
|
|
14
|
-
|
|
15
|
-
# Create registry and context
|
|
16
|
-
registry = Langop::Dsl::AgentRegistry.new
|
|
17
|
-
context = Langop::Dsl::AgentContext.new(registry)
|
|
18
|
-
|
|
19
|
-
# Define an agent using the DSL (this is what the operator will synthesize)
|
|
20
|
-
context.agent 'kubernetes-news' do
|
|
21
|
-
description 'Daily Kubernetes news summarization agent'
|
|
22
|
-
|
|
23
|
-
# Persona (distilled by operator from LanguagePersona)
|
|
24
|
-
persona <<~PERSONA
|
|
25
|
-
You are a technical writer specializing in Kubernetes. When researching and
|
|
26
|
-
summarizing news, maintain a clear and precise tone, always cite your sources,
|
|
27
|
-
use proper technical terminology, and make complex topics accessible without
|
|
28
|
-
unnecessary jargon. Your summaries should be educational and well-structured.
|
|
29
|
-
PERSONA
|
|
30
|
-
|
|
31
|
-
# Schedule (extracted from: "once a day, preferably around lunchtime")
|
|
32
|
-
schedule '0 12 * * *'
|
|
33
|
-
|
|
34
|
-
# Objectives (extracted from instructions)
|
|
35
|
-
objectives [
|
|
36
|
-
'Search for recent Kubernetes news using web_search tool',
|
|
37
|
-
'Provide a concise summary of findings'
|
|
38
|
-
]
|
|
39
|
-
|
|
40
|
-
# Workflow (synthesized by operator)
|
|
41
|
-
workflow do
|
|
42
|
-
step :search do
|
|
43
|
-
tool 'web_search'
|
|
44
|
-
params query: 'Kubernetes news latest'
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
step :summarize do
|
|
48
|
-
depends_on :search
|
|
49
|
-
prompt 'Provide a concise summary of these Kubernetes news items: {search.output}'
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Constraints (inferred by operator)
|
|
54
|
-
constraints do
|
|
55
|
-
max_iterations 20
|
|
56
|
-
timeout '5m'
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# Output (inferred from workspace settings)
|
|
60
|
-
output do
|
|
61
|
-
workspace 'summaries/kubernetes-{date}.md'
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
# Retrieve and display the agent
|
|
66
|
-
agent = registry.get('kubernetes-news')
|
|
67
|
-
|
|
68
|
-
if agent
|
|
69
|
-
puts '✅ Agent Definition Loaded'
|
|
70
|
-
puts
|
|
71
|
-
puts "Name: #{agent.name}"
|
|
72
|
-
puts "Description: #{agent.description}"
|
|
73
|
-
puts "Mode: #{agent.execution_mode}"
|
|
74
|
-
puts "Schedule: #{agent.schedule}"
|
|
75
|
-
puts
|
|
76
|
-
puts '📋 Persona:'
|
|
77
|
-
puts agent.persona.lines.map { |l| " #{l}" }.join
|
|
78
|
-
puts
|
|
79
|
-
puts "🎯 Objectives (#{agent.objectives.size}):"
|
|
80
|
-
agent.objectives.each_with_index do |obj, i|
|
|
81
|
-
puts " #{i + 1}. #{obj}"
|
|
82
|
-
end
|
|
83
|
-
puts
|
|
84
|
-
puts "⚙️ Workflow Steps (#{agent.workflow.steps.size}):"
|
|
85
|
-
agent.workflow.steps.each do |name, step|
|
|
86
|
-
deps = step.dependencies.empty? ? '' : " [depends on: #{step.dependencies.join(', ')}]"
|
|
87
|
-
tool_info = step.tool ? " (tool: #{step.tool})" : ''
|
|
88
|
-
prompt_info = step.prompt ? " (prompt: #{step.prompt[0..50]}...)" : ''
|
|
89
|
-
puts " - #{name}#{deps}#{tool_info}#{prompt_info}"
|
|
90
|
-
end
|
|
91
|
-
puts
|
|
92
|
-
puts '📊 Constraints:'
|
|
93
|
-
agent.constraints.each do |key, value|
|
|
94
|
-
puts " #{key}: #{value}"
|
|
95
|
-
end
|
|
96
|
-
puts
|
|
97
|
-
puts '📤 Output:'
|
|
98
|
-
agent.output_config.each do |key, value|
|
|
99
|
-
puts " #{key}: #{value}"
|
|
100
|
-
end
|
|
101
|
-
puts
|
|
102
|
-
puts '=' * 70
|
|
103
|
-
puts '✅ DSL Test Complete - Agent ready for execution!'
|
|
104
|
-
puts '=' * 70
|
|
105
|
-
else
|
|
106
|
-
puts '❌ Failed to load agent'
|
|
107
|
-
exit 1
|
|
108
|
-
end
|