Module: LanguageOperator::CLI::Commands::System::Exec

Included in:
Base
Defined in:
lib/language_operator/cli/commands/system/exec.rb

Overview

Agent execution in test pod

Class Method Summary collapse

Class Method Details

.included(base) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/language_operator/cli/commands/system/exec.rb', line 9

def self.included(base)
  base.class_eval do
    desc 'exec [AGENT_FILE]', 'Execute an agent file in a test pod on the cluster'
    long_desc "      Deploy and execute an agent file in a temporary test pod on the Kubernetes cluster.\n\n      This command creates a ConfigMap with the agent code, deploys a test pod,\n      streams the logs until completion, and cleans up all resources.\n\n      The agent code is mounted at /etc/agent/code/agent.rb as expected by the agent runtime.\n\n      Agent code can be provided either as a file path or via STDIN.\n      If no file path is provided, the command will read from STDIN.\n\n      Examples:\n        # Execute a synthesized agent file\n        langop system exec agent.rb\n\n        # Execute with a custom agent name\n        langop system exec agent.rb --agent-name my-test\n\n        # Keep the pod after execution for debugging\n        langop system exec agent.rb --keep-pod\n\n        # Use a different agent image\n        langop system exec agent.rb --image ghcr.io/language-operator/agent:v0.1.0\n\n        # Read agent code from STDIN\n        cat agent.rb | langop system exec\n\n        # Pipe synthesized code directly to execution\n        cat agent.txt | langop system synthesize | langop system exec\n    DESC\n    option :agent_name, type: :string, default: 'test-agent', desc: 'Name for the test agent pod'\n    option :keep_pod, type: :boolean, default: false, desc: 'Keep the pod after execution (for debugging)'\n    option :image, type: :string, default: 'ghcr.io/language-operator/agent:latest', desc: 'Agent container image'\n    option :timeout, type: :numeric, default: 300, desc: 'Timeout in seconds for agent execution'\n    def exec(agent_file = nil)\n      handle_command_error('exec agent') do\n        # Verify cluster is selected\n        unless ctx.client\n          Formatters::ProgressFormatter.error('No cluster context available')\n          puts\n          puts 'Please configure kubectl with a valid cluster context:'\n          puts '  kubectl config get-contexts'\n          puts '  kubectl config use-context <context-name>'\n          exit 1\n        end\n\n        # Read agent code from file or STDIN\n        agent_code = if agent_file && !agent_file.strip.empty?\n                       # Read from file\n                       unless File.exist?(agent_file)\n                         Formatters::ProgressFormatter.error(\"Agent file not found: \#{agent_file}\")\n                         exit 1\n                       end\n                       File.read(agent_file)\n                     elsif $stdin.tty?\n                       # Read from STDIN\n                       Formatters::ProgressFormatter.error('No agent code provided')\n                       puts\n                       puts 'Provide agent code either as a file or via STDIN:'\n                       puts '  langop system exec agent.rb'\n                       puts '  cat agent.rb | langop system exec'\n                       exit 1\n                     else\n                       code = $stdin.read.strip\n                       if code.empty?\n                         Formatters::ProgressFormatter.error('No agent code provided')\n                         puts\n                         puts 'Provide agent code either as a file or via STDIN:'\n                         puts '  langop system exec agent.rb'\n                         puts '  cat agent.rb | langop system exec'\n                         exit 1\n                       end\n                       code\n                     end\n\n        # Generate unique names\n        timestamp = Time.now.to_i\n        configmap_name = \"\#{options[:agent_name]}-code-\#{timestamp}\"\n        pod_name = \"\#{options[:agent_name]}-\#{timestamp}\"\n\n        begin\n          # Create ConfigMap with agent code\n          Formatters::ProgressFormatter.with_spinner('Creating ConfigMap with agent code') do\n            create_agent_configmap(configmap_name, agent_code)\n          end\n\n          # Create test pod\n          Formatters::ProgressFormatter.with_spinner('Creating test pod') do\n            create_test_pod(pod_name, configmap_name, options[:image])\n          end\n\n          # Wait for pod to be ready or running\n          Formatters::ProgressFormatter.with_spinner('Waiting for pod to start') do\n            wait_for_pod_start(pod_name, timeout: 60)\n          end\n\n          # Stream logs until pod completes\n          stream_pod_logs(pod_name, timeout: options[:timeout])\n\n          # Wait for pod to fully terminate and get final status\n          exit_code = wait_for_pod_termination(pod_name)\n\n          if exit_code&.zero?\n            Formatters::ProgressFormatter.success('Agent completed successfully')\n          elsif exit_code\n            Formatters::ProgressFormatter.error(\"Agent failed with exit code: \#{exit_code}\")\n          else\n            Formatters::ProgressFormatter.warn('Unable to determine pod exit status')\n          end\n        ensure\n          # Clean up resources unless --keep-pod\n          puts\n          puts\n          if options[:keep_pod]\n            Formatters::ProgressFormatter.info('Resources kept for debugging:')\n            puts \"  Pod: \#{pod_name}\"\n            puts \"  ConfigMap: \#{configmap_name}\"\n            puts\n            puts \"To view logs: kubectl logs -n \#{ctx.namespace} \#{pod_name}\"\n            puts \"To delete:    kubectl delete pod,configmap -n \#{ctx.namespace} \#{pod_name} \#{configmap_name}\"\n          else\n            Formatters::ProgressFormatter.with_spinner('Cleaning up resources') do\n              delete_pod(pod_name)\n              delete_configmap(configmap_name)\n            end\n          end\n        end\n      end\n    end\n  end\nend\n"