language-operator 0.1.38 → 0.1.40

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4476732244850657fb5161189ad68010e2ffdef4f4949361786893d119f0de89
4
- data.tar.gz: 5755720ffc0df24c88c5ec5ea223a4f8899c604f938422e420e878833d172de5
3
+ metadata.gz: 6e670a07610f07576228d91fbe02a1ac45e5ce43633bc9b4fc9974db52a04b08
4
+ data.tar.gz: ed8ef8e1e9a9a132582a734676f7aff1745565690fbbe40d7046fc058a3f3b6e
5
5
  SHA512:
6
- metadata.gz: a4408235ba4cc775fc175f7760e0632e78457630b263690efeb3ddc772c58facfcd7b7e0780a38d33bda5c4f9d3d12b46eed0f83d43631c94f1ddfe7180be61d
7
- data.tar.gz: 3ccbd9c8c91ef1d19ae467cafe3740cc84586853692cf46569d77b692b1cddf682fb21300bbb75244e71335b84a10fde768f6baff1016d18acf8b4c31a869862
6
+ metadata.gz: f6b727e3736603600df84f13c9c0ea3b3bb98335fc1eabcd20669ccc8908b3b13c631125fe6362bb5f3f13218f4f558c4b37b224d04d2d36bdc32059c8234b18
7
+ data.tar.gz: 8f0ff851ae3cb6b573b315c35e1158db30ec066d74861968be6751a8bb47a99259a28320c553f56face105e17893d81f6e9946ccac8d7f85dfce0b83084862b6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- language-operator (0.1.38)
4
+ language-operator (0.1.40)
5
5
  faraday (~> 2.0)
6
6
  k8s-ruby (~> 0.17)
7
7
  mcp (~> 0.4)
@@ -445,15 +445,16 @@ module LanguageOperator
445
445
 
446
446
  # Execute the actual task implementation (neural or symbolic)
447
447
  #
448
+ # For hybrid tasks (both neural and symbolic), prefer symbolic execution
449
+ # as it's more efficient and deterministic.
450
+ #
448
451
  # @param task [TaskDefinition] The task definition
449
452
  # @param inputs [Hash] Input parameters
450
453
  # @return [Hash] Task outputs
451
454
  def execute_task_implementation(task, inputs)
452
- if task.neural?
453
- # Neural execution: LLM with tool access
454
- execute_neural(task, inputs)
455
- else
455
+ if task.symbolic?
456
456
  # Symbolic execution: Direct Ruby code within traced span
457
+ # This takes precedence over neural for hybrid tasks
457
458
  tracer.in_span('task_executor.symbolic', attributes: symbolic_task_attributes(task)) do |span|
458
459
  validated_inputs = task.validate_inputs(inputs)
459
460
  span.set_attribute('task.input.keys', validated_inputs.keys.map(&:to_s).join(','))
@@ -465,6 +466,12 @@ module LanguageOperator
465
466
  record_output_metadata(outputs, span) if outputs.is_a?(Hash)
466
467
  outputs
467
468
  end
469
+ elsif task.neural?
470
+ # Neural execution: LLM with tool access
471
+ # Only used for pure neural tasks (no symbolic implementation)
472
+ execute_neural(task, inputs)
473
+ else
474
+ raise ArgumentError, "Task '#{task.name}' has neither neural nor symbolic implementation"
468
475
  end
469
476
  end
470
477
 
@@ -50,6 +50,27 @@ module LanguageOperator
50
50
  load_and_run(agent)
51
51
  end
52
52
 
53
+ # Load and run agent from a specific file path
54
+ #
55
+ # @param code_path [String] Path to agent DSL code file
56
+ # @param agent_name [String, nil] Name of the agent definition to run
57
+ # @param config_path [String, nil] Path to configuration file
58
+ # @return [void]
59
+ def self.load_and_run_from_file(code_path, agent_name = nil, config_path: nil)
60
+ # Disable stdout buffering for real-time logging in containers
61
+ $stdout.sync = true
62
+ $stderr.sync = true
63
+
64
+ config_path ||= ENV.fetch('CONFIG_PATH', 'config.yaml')
65
+ config = LanguageOperator::Client::Config.load_with_fallback(config_path)
66
+
67
+ # Create agent instance
68
+ agent = LanguageOperator::Agent::Base.new(config)
69
+
70
+ # Load and run the specified agent code
71
+ load_synthesized_agent(agent, code_path, agent_name)
72
+ end
73
+
53
74
  # Load synthesized agent code and run with definition if available
54
75
  #
55
76
  # @param agent [LanguageOperator::Agent::Base] The agent instance
@@ -191,9 +212,43 @@ module LanguageOperator
191
212
  logger.info('Main block execution completed',
192
213
  result: result)
193
214
 
215
+ # Call output handler if defined
216
+ if agent_def.output
217
+ logger.debug('Executing output handler', outputs: result)
218
+ execute_output_handler(agent_def, result, task_executor)
219
+ end
220
+
194
221
  result
195
222
  end
196
223
 
224
+ # Execute the output handler (neural or symbolic)
225
+ #
226
+ # @param agent_def [LanguageOperator::Dsl::AgentDefinition] The agent definition
227
+ # @param outputs [Hash] The outputs from main execution
228
+ # @param task_executor [LanguageOperator::Agent::TaskExecutor] Task executor for context
229
+ # @return [void]
230
+ def self.execute_output_handler(agent_def, outputs, task_executor)
231
+ output_config = agent_def.output
232
+
233
+ # If symbolic implementation exists, use it
234
+ if output_config.symbolic?
235
+ logger.debug('Executing symbolic output handler')
236
+ # execute_symbolic takes (inputs, context) - outputs are the inputs, task_executor is context
237
+ output_config.execute_symbolic(outputs, task_executor)
238
+ elsif output_config.neural?
239
+ # Neural output - would need LLM access to execute
240
+ # For now, just log the instruction
241
+ logger.info('Neural output handler',
242
+ instruction: output_config.instructions_text,
243
+ outputs: outputs)
244
+ logger.warn('Neural output execution not yet implemented - instruction logged only')
245
+ end
246
+ rescue StandardError => e
247
+ logger.error('Output handler failed',
248
+ error: e.message,
249
+ backtrace: e.backtrace[0..5])
250
+ end
251
+
197
252
  # Build executor configuration from agent definition constraints
198
253
  #
199
254
  # @param agent_def [LanguageOperator::Dsl::AgentDefinition] The agent definition
@@ -97,7 +97,14 @@ module LanguageOperator
97
97
  def create_resource(resource)
98
98
  resource_client = resource_client_for_resource(resource)
99
99
  # Convert hash to K8s::Resource if needed
100
- k8s_resource = resource.is_a?(K8s::Resource) ? resource : K8s::Resource.new(resource)
100
+ k8s_resource = if resource.is_a?(K8s::Resource)
101
+ resource
102
+ else
103
+ # Remove resourceVersion if present - it should not be set on new resources
104
+ resource_hash = resource.dup
105
+ resource_hash['metadata']&.delete('resourceVersion')
106
+ K8s::Resource.new(resource_hash)
107
+ end
101
108
  resource_client.create_resource(k8s_resource)
102
109
  end
103
110
 
@@ -2,7 +2,7 @@
2
2
  :openapi: 3.0.3
3
3
  :info:
4
4
  :title: Language Operator Agent API
5
- :version: 0.1.38
5
+ :version: 0.1.40
6
6
  :description: HTTP API endpoints exposed by Language Operator reactive agents
7
7
  :contact:
8
8
  :name: Language Operator
@@ -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.38",
6
+ "version": "0.1.40",
7
7
  "type": "object",
8
8
  "properties": {
9
9
  "name": {
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LanguageOperator
4
- VERSION = '0.1.38'
4
+ VERSION = '0.1.40'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: language-operator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.38
4
+ version: 0.1.40
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Ryan