language-operator 0.1.31 → 0.1.35

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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -8
  3. data/CHANGELOG.md +14 -0
  4. data/CI_STATUS.md +56 -0
  5. data/Gemfile.lock +2 -2
  6. data/Makefile +22 -6
  7. data/lib/language_operator/agent/base.rb +10 -6
  8. data/lib/language_operator/agent/executor.rb +19 -97
  9. data/lib/language_operator/agent/safety/ast_validator.rb +62 -43
  10. data/lib/language_operator/agent/safety/safe_executor.rb +27 -2
  11. data/lib/language_operator/agent/scheduler.rb +60 -0
  12. data/lib/language_operator/agent/task_executor.rb +548 -0
  13. data/lib/language_operator/agent.rb +90 -27
  14. data/lib/language_operator/cli/base_command.rb +117 -0
  15. data/lib/language_operator/cli/commands/agent.rb +339 -407
  16. data/lib/language_operator/cli/commands/cluster.rb +274 -290
  17. data/lib/language_operator/cli/commands/install.rb +110 -119
  18. data/lib/language_operator/cli/commands/model.rb +284 -184
  19. data/lib/language_operator/cli/commands/persona.rb +218 -284
  20. data/lib/language_operator/cli/commands/quickstart.rb +4 -5
  21. data/lib/language_operator/cli/commands/status.rb +31 -35
  22. data/lib/language_operator/cli/commands/system.rb +221 -233
  23. data/lib/language_operator/cli/commands/tool.rb +356 -422
  24. data/lib/language_operator/cli/commands/use.rb +19 -22
  25. data/lib/language_operator/cli/helpers/resource_dependency_checker.rb +0 -18
  26. data/lib/language_operator/cli/wizards/quickstart_wizard.rb +0 -1
  27. data/lib/language_operator/client/config.rb +20 -21
  28. data/lib/language_operator/config.rb +115 -3
  29. data/lib/language_operator/constants.rb +54 -0
  30. data/lib/language_operator/dsl/agent_context.rb +7 -7
  31. data/lib/language_operator/dsl/agent_definition.rb +111 -26
  32. data/lib/language_operator/dsl/config.rb +30 -66
  33. data/lib/language_operator/dsl/main_definition.rb +114 -0
  34. data/lib/language_operator/dsl/schema.rb +84 -43
  35. data/lib/language_operator/dsl/task_definition.rb +315 -0
  36. data/lib/language_operator/dsl.rb +0 -1
  37. data/lib/language_operator/instrumentation/task_tracer.rb +285 -0
  38. data/lib/language_operator/logger.rb +4 -4
  39. data/lib/language_operator/synthesis_test_harness.rb +324 -0
  40. data/lib/language_operator/templates/examples/agent_synthesis.tmpl +26 -8
  41. data/lib/language_operator/templates/schema/CHANGELOG.md +26 -0
  42. data/lib/language_operator/templates/schema/agent_dsl_openapi.yaml +1 -1
  43. data/lib/language_operator/templates/schema/agent_dsl_schema.json +84 -42
  44. data/lib/language_operator/type_coercion.rb +250 -0
  45. data/lib/language_operator/ux/base.rb +81 -0
  46. data/lib/language_operator/ux/concerns/README.md +155 -0
  47. data/lib/language_operator/ux/concerns/headings.rb +90 -0
  48. data/lib/language_operator/ux/concerns/input_validation.rb +146 -0
  49. data/lib/language_operator/ux/concerns/provider_helpers.rb +167 -0
  50. data/lib/language_operator/ux/create_agent.rb +252 -0
  51. data/lib/language_operator/ux/create_model.rb +267 -0
  52. data/lib/language_operator/ux/quickstart.rb +594 -0
  53. data/lib/language_operator/version.rb +1 -1
  54. data/lib/language_operator.rb +2 -0
  55. data/requirements/ARCHITECTURE.md +1 -0
  56. data/requirements/SCRATCH.md +153 -0
  57. data/requirements/dsl.md +0 -0
  58. data/requirements/features +1 -0
  59. data/requirements/personas +1 -0
  60. data/requirements/proposals +1 -0
  61. data/requirements/tasks/iterate.md +14 -15
  62. data/requirements/tasks/optimize.md +13 -4
  63. data/synth/001/Makefile +90 -0
  64. data/synth/001/agent.rb +26 -0
  65. data/synth/001/agent.yaml +7 -0
  66. data/synth/001/output.log +44 -0
  67. data/synth/Makefile +39 -0
  68. data/synth/README.md +342 -0
  69. metadata +37 -10
  70. data/lib/language_operator/dsl/workflow_definition.rb +0 -259
  71. 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
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