language-operator 0.1.30 → 0.1.31
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/CHANGELOG.md +35 -0
- data/Gemfile.lock +1 -1
- data/Makefile +7 -2
- data/Rakefile +29 -0
- data/docs/dsl/SCHEMA_VERSION.md +250 -0
- data/docs/dsl/agent-reference.md +13 -0
- data/lib/language_operator/agent/safety/safe_executor.rb +12 -0
- data/lib/language_operator/cli/commands/agent.rb +54 -101
- data/lib/language_operator/cli/commands/cluster.rb +37 -1
- data/lib/language_operator/cli/commands/persona.rb +2 -5
- data/lib/language_operator/cli/commands/status.rb +5 -18
- data/lib/language_operator/cli/commands/system.rb +772 -0
- data/lib/language_operator/cli/formatters/code_formatter.rb +3 -7
- data/lib/language_operator/cli/formatters/log_formatter.rb +3 -5
- data/lib/language_operator/cli/formatters/progress_formatter.rb +3 -7
- data/lib/language_operator/cli/formatters/status_formatter.rb +37 -0
- data/lib/language_operator/cli/formatters/table_formatter.rb +10 -26
- data/lib/language_operator/cli/helpers/pastel_helper.rb +24 -0
- data/lib/language_operator/cli/main.rb +4 -0
- data/lib/language_operator/dsl/schema.rb +1102 -0
- data/lib/language_operator/dsl.rb +1 -0
- data/lib/language_operator/logger.rb +4 -4
- data/lib/language_operator/templates/README.md +23 -0
- data/lib/language_operator/templates/examples/agent_synthesis.tmpl +115 -0
- data/lib/language_operator/templates/examples/persona_distillation.tmpl +19 -0
- data/lib/language_operator/templates/schema/.gitkeep +0 -0
- data/lib/language_operator/templates/schema/CHANGELOG.md +93 -0
- data/lib/language_operator/templates/schema/agent_dsl_openapi.yaml +306 -0
- data/lib/language_operator/templates/schema/agent_dsl_schema.json +452 -0
- data/lib/language_operator/version.rb +1 -1
- data/requirements/tasks/iterate.md +2 -2
- metadata +13 -9
- data/examples/README.md +0 -569
- data/examples/agent_example.rb +0 -86
- data/examples/chat_endpoint_agent.rb +0 -118
- data/examples/github_webhook_agent.rb +0 -171
- data/examples/mcp_agent.rb +0 -158
- data/examples/oauth_callback_agent.rb +0 -296
- data/examples/stripe_webhook_agent.rb +0 -219
- data/examples/webhook_agent.rb +0 -80
|
@@ -4,10 +4,13 @@ require 'thor'
|
|
|
4
4
|
require_relative '../formatters/progress_formatter'
|
|
5
5
|
require_relative '../formatters/table_formatter'
|
|
6
6
|
require_relative '../formatters/value_formatter'
|
|
7
|
+
require_relative '../formatters/log_formatter'
|
|
8
|
+
require_relative '../formatters/status_formatter'
|
|
7
9
|
require_relative '../helpers/cluster_validator'
|
|
8
10
|
require_relative '../helpers/cluster_context'
|
|
9
11
|
require_relative '../helpers/user_prompts'
|
|
10
12
|
require_relative '../helpers/editor_helper'
|
|
13
|
+
require_relative '../helpers/pastel_helper'
|
|
11
14
|
require_relative '../errors/handler'
|
|
12
15
|
require_relative '../../config/cluster_config'
|
|
13
16
|
require_relative '../../kubernetes/client'
|
|
@@ -19,6 +22,7 @@ module LanguageOperator
|
|
|
19
22
|
# Agent management commands
|
|
20
23
|
class Agent < Thor
|
|
21
24
|
include Helpers::ClusterValidator
|
|
25
|
+
include Helpers::PastelHelper
|
|
22
26
|
|
|
23
27
|
desc 'create [DESCRIPTION]', 'Create a new agent with natural language description'
|
|
24
28
|
long_desc <<-DESC
|
|
@@ -69,9 +73,9 @@ module LanguageOperator
|
|
|
69
73
|
cluster = Helpers::ClusterValidator.get_cluster(options[:cluster])
|
|
70
74
|
end
|
|
71
75
|
|
|
72
|
-
|
|
76
|
+
ctx = Helpers::ClusterContext.from_options(options.merge(cluster: cluster))
|
|
73
77
|
|
|
74
|
-
Formatters::ProgressFormatter.info("Creating agent in cluster '#{
|
|
78
|
+
Formatters::ProgressFormatter.info("Creating agent in cluster '#{ctx.name}'")
|
|
75
79
|
puts
|
|
76
80
|
|
|
77
81
|
# Generate agent name from description if not provided
|
|
@@ -80,18 +84,17 @@ module LanguageOperator
|
|
|
80
84
|
# Get models: use specified models, or default to all available models in cluster
|
|
81
85
|
models = options[:models]
|
|
82
86
|
if models.nil? || models.empty?
|
|
83
|
-
|
|
84
|
-
available_models = k8s.list_resources('LanguageModel', namespace: cluster_config[:namespace])
|
|
87
|
+
available_models = ctx.client.list_resources('LanguageModel', namespace: ctx.namespace)
|
|
85
88
|
models = available_models.map { |m| m.dig('metadata', 'name') }
|
|
86
89
|
|
|
87
|
-
Errors::Handler.handle_no_models_available(cluster:
|
|
90
|
+
Errors::Handler.handle_no_models_available(cluster: ctx.name) if models.empty?
|
|
88
91
|
end
|
|
89
92
|
|
|
90
93
|
# Build LanguageAgent resource
|
|
91
94
|
agent_resource = Kubernetes::ResourceBuilder.language_agent(
|
|
92
95
|
agent_name,
|
|
93
96
|
instructions: description,
|
|
94
|
-
cluster:
|
|
97
|
+
cluster: ctx.namespace,
|
|
95
98
|
persona: options[:persona],
|
|
96
99
|
tools: options[:tools] || [],
|
|
97
100
|
models: models
|
|
@@ -99,29 +102,26 @@ module LanguageOperator
|
|
|
99
102
|
|
|
100
103
|
# Dry-run mode: preview without applying
|
|
101
104
|
if options[:dry_run]
|
|
102
|
-
display_dry_run_preview(agent_resource,
|
|
105
|
+
display_dry_run_preview(agent_resource, ctx.name, description)
|
|
103
106
|
return
|
|
104
107
|
end
|
|
105
108
|
|
|
106
|
-
# Connect to Kubernetes
|
|
107
|
-
k8s = Helpers::ClusterValidator.kubernetes_client(options[:cluster])
|
|
108
|
-
|
|
109
109
|
# Apply resource to cluster
|
|
110
110
|
Formatters::ProgressFormatter.with_spinner("Creating agent '#{agent_name}'") do
|
|
111
|
-
|
|
111
|
+
ctx.client.apply_resource(agent_resource)
|
|
112
112
|
end
|
|
113
113
|
|
|
114
114
|
# Watch synthesis status
|
|
115
|
-
synthesis_result = watch_synthesis_status(
|
|
115
|
+
synthesis_result = watch_synthesis_status(ctx.client, agent_name, ctx.namespace)
|
|
116
116
|
|
|
117
117
|
# Exit if synthesis failed
|
|
118
118
|
exit 1 unless synthesis_result[:success]
|
|
119
119
|
|
|
120
120
|
# Fetch the updated agent to get complete details
|
|
121
|
-
agent =
|
|
121
|
+
agent = ctx.client.get_resource('LanguageAgent', agent_name, ctx.namespace)
|
|
122
122
|
|
|
123
123
|
# Display enhanced success output
|
|
124
|
-
display_agent_created(agent,
|
|
124
|
+
display_agent_created(agent, ctx.name, description, synthesis_result)
|
|
125
125
|
rescue StandardError => e
|
|
126
126
|
Formatters::ProgressFormatter.error("Failed to create agent: #{e.message}")
|
|
127
127
|
raise if ENV['DEBUG']
|
|
@@ -136,8 +136,8 @@ module LanguageOperator
|
|
|
136
136
|
if options[:all_clusters]
|
|
137
137
|
list_all_clusters
|
|
138
138
|
else
|
|
139
|
-
|
|
140
|
-
list_cluster_agents(
|
|
139
|
+
ctx = Helpers::ClusterContext.from_options(options)
|
|
140
|
+
list_cluster_agents(ctx.name)
|
|
141
141
|
end
|
|
142
142
|
rescue StandardError => e
|
|
143
143
|
Formatters::ProgressFormatter.error("Failed to list agents: #{e.message}")
|
|
@@ -149,16 +149,13 @@ module LanguageOperator
|
|
|
149
149
|
desc 'inspect NAME', 'Show detailed agent information'
|
|
150
150
|
option :cluster, type: :string, desc: 'Override current cluster context'
|
|
151
151
|
def inspect(name)
|
|
152
|
-
|
|
153
|
-
cluster_config = Helpers::ClusterValidator.get_cluster_config(cluster)
|
|
154
|
-
|
|
155
|
-
k8s = Helpers::ClusterValidator.kubernetes_client(options[:cluster])
|
|
152
|
+
ctx = Helpers::ClusterContext.from_options(options)
|
|
156
153
|
|
|
157
|
-
agent =
|
|
154
|
+
agent = ctx.client.get_resource('LanguageAgent', name, ctx.namespace)
|
|
158
155
|
|
|
159
156
|
puts "Agent: #{name}"
|
|
160
|
-
puts " Cluster: #{
|
|
161
|
-
puts " Namespace: #{
|
|
157
|
+
puts " Cluster: #{ctx.name}"
|
|
158
|
+
puts " Namespace: #{ctx.namespace}"
|
|
162
159
|
puts
|
|
163
160
|
|
|
164
161
|
# Status
|
|
@@ -234,7 +231,7 @@ module LanguageOperator
|
|
|
234
231
|
# Recent events (if available)
|
|
235
232
|
# This would require querying events, which we can add later
|
|
236
233
|
rescue K8s::Error::NotFound
|
|
237
|
-
handle_agent_not_found(name,
|
|
234
|
+
handle_agent_not_found(name, ctx)
|
|
238
235
|
rescue StandardError => e
|
|
239
236
|
Formatters::ProgressFormatter.error("Failed to inspect agent: #{e.message}")
|
|
240
237
|
raise if ENV['DEBUG']
|
|
@@ -292,25 +289,22 @@ module LanguageOperator
|
|
|
292
289
|
option :follow, type: :boolean, aliases: '-f', default: false, desc: 'Follow logs'
|
|
293
290
|
option :tail, type: :numeric, default: 100, desc: 'Number of lines to show from the end'
|
|
294
291
|
def logs(name)
|
|
295
|
-
|
|
296
|
-
cluster_config = Helpers::ClusterValidator.get_cluster_config(cluster)
|
|
297
|
-
|
|
298
|
-
k8s = Helpers::ClusterValidator.kubernetes_client(options[:cluster])
|
|
292
|
+
ctx = Helpers::ClusterContext.from_options(options)
|
|
299
293
|
|
|
300
294
|
# Get agent to determine the pod name
|
|
301
295
|
begin
|
|
302
|
-
agent =
|
|
296
|
+
agent = ctx.client.get_resource('LanguageAgent', name, ctx.namespace)
|
|
303
297
|
rescue K8s::Error::NotFound
|
|
304
|
-
Formatters::ProgressFormatter.error("Agent '#{name}' not found in cluster '#{
|
|
298
|
+
Formatters::ProgressFormatter.error("Agent '#{name}' not found in cluster '#{ctx.name}'")
|
|
305
299
|
exit 1
|
|
306
300
|
end
|
|
307
301
|
|
|
308
302
|
mode = agent.dig('spec', 'mode') || 'autonomous'
|
|
309
303
|
|
|
310
304
|
# Build kubectl command for log streaming
|
|
311
|
-
kubeconfig_arg =
|
|
312
|
-
context_arg =
|
|
313
|
-
namespace_arg = "-n #{
|
|
305
|
+
kubeconfig_arg = ctx.config[:kubeconfig] ? "--kubeconfig=#{ctx.config[:kubeconfig]}" : ''
|
|
306
|
+
context_arg = ctx.config[:context] ? "--context=#{ctx.config[:context]}" : ''
|
|
307
|
+
namespace_arg = "-n #{ctx.namespace}"
|
|
314
308
|
tail_arg = "--tail=#{options[:tail]}"
|
|
315
309
|
follow_arg = options[:follow] ? '-f' : ''
|
|
316
310
|
|
|
@@ -367,15 +361,12 @@ module LanguageOperator
|
|
|
367
361
|
def code(name)
|
|
368
362
|
require_relative '../formatters/code_formatter'
|
|
369
363
|
|
|
370
|
-
|
|
371
|
-
cluster_config = Helpers::ClusterValidator.get_cluster_config(cluster)
|
|
372
|
-
|
|
373
|
-
k8s = Helpers::ClusterValidator.kubernetes_client(options[:cluster])
|
|
364
|
+
ctx = Helpers::ClusterContext.from_options(options)
|
|
374
365
|
|
|
375
366
|
# Get the code ConfigMap for this agent
|
|
376
367
|
configmap_name = "#{name}-code"
|
|
377
368
|
begin
|
|
378
|
-
configmap =
|
|
369
|
+
configmap = ctx.client.get_resource('ConfigMap', configmap_name, ctx.namespace)
|
|
379
370
|
rescue K8s::Error::NotFound
|
|
380
371
|
Formatters::ProgressFormatter.error("Synthesized code not found for agent '#{name}'")
|
|
381
372
|
puts
|
|
@@ -414,16 +405,13 @@ module LanguageOperator
|
|
|
414
405
|
desc 'edit NAME', 'Edit agent instructions'
|
|
415
406
|
option :cluster, type: :string, desc: 'Override current cluster context'
|
|
416
407
|
def edit(name)
|
|
417
|
-
|
|
418
|
-
cluster_config = Helpers::ClusterValidator.get_cluster_config(cluster)
|
|
419
|
-
|
|
420
|
-
k8s = Helpers::ClusterValidator.kubernetes_client(options[:cluster])
|
|
408
|
+
ctx = Helpers::ClusterContext.from_options(options)
|
|
421
409
|
|
|
422
410
|
# Get current agent
|
|
423
411
|
begin
|
|
424
|
-
agent =
|
|
412
|
+
agent = ctx.client.get_resource('LanguageAgent', name, ctx.namespace)
|
|
425
413
|
rescue K8s::Error::NotFound
|
|
426
|
-
Formatters::ProgressFormatter.error("Agent '#{name}' not found in cluster '#{
|
|
414
|
+
Formatters::ProgressFormatter.error("Agent '#{name}' not found in cluster '#{ctx.name}'")
|
|
427
415
|
exit 1
|
|
428
416
|
end
|
|
429
417
|
|
|
@@ -465,16 +453,13 @@ module LanguageOperator
|
|
|
465
453
|
desc 'pause NAME', 'Pause scheduled agent execution'
|
|
466
454
|
option :cluster, type: :string, desc: 'Override current cluster context'
|
|
467
455
|
def pause(name)
|
|
468
|
-
|
|
469
|
-
cluster_config = Helpers::ClusterValidator.get_cluster_config(cluster)
|
|
470
|
-
|
|
471
|
-
k8s = Helpers::ClusterValidator.kubernetes_client(options[:cluster])
|
|
456
|
+
ctx = Helpers::ClusterContext.from_options(options)
|
|
472
457
|
|
|
473
458
|
# Get agent
|
|
474
459
|
begin
|
|
475
|
-
agent =
|
|
460
|
+
agent = ctx.client.get_resource('LanguageAgent', name, ctx.namespace)
|
|
476
461
|
rescue K8s::Error::NotFound
|
|
477
|
-
Formatters::ProgressFormatter.error("Agent '#{name}' not found in cluster '#{
|
|
462
|
+
Formatters::ProgressFormatter.error("Agent '#{name}' not found in cluster '#{ctx.name}'")
|
|
478
463
|
exit 1
|
|
479
464
|
end
|
|
480
465
|
|
|
@@ -490,12 +475,12 @@ module LanguageOperator
|
|
|
490
475
|
# Suspend the CronJob by setting spec.suspend = true
|
|
491
476
|
# This is done by patching the underlying CronJob resource
|
|
492
477
|
cronjob_name = name
|
|
493
|
-
namespace =
|
|
478
|
+
namespace = ctx.namespace
|
|
494
479
|
|
|
495
480
|
Formatters::ProgressFormatter.with_spinner("Pausing agent '#{name}'") do
|
|
496
481
|
# Use kubectl to patch the cronjob
|
|
497
|
-
kubeconfig_arg =
|
|
498
|
-
context_arg =
|
|
482
|
+
kubeconfig_arg = ctx.config[:kubeconfig] ? "--kubeconfig=#{ctx.config[:kubeconfig]}" : ''
|
|
483
|
+
context_arg = ctx.config[:context] ? "--context=#{ctx.config[:context]}" : ''
|
|
499
484
|
|
|
500
485
|
cmd = "kubectl #{kubeconfig_arg} #{context_arg} -n #{namespace} patch cronjob #{cronjob_name} -p '{\"spec\":{\"suspend\":true}}'"
|
|
501
486
|
system(cmd)
|
|
@@ -517,16 +502,13 @@ module LanguageOperator
|
|
|
517
502
|
desc 'resume NAME', 'Resume paused agent'
|
|
518
503
|
option :cluster, type: :string, desc: 'Override current cluster context'
|
|
519
504
|
def resume(name)
|
|
520
|
-
|
|
521
|
-
cluster_config = Helpers::ClusterValidator.get_cluster_config(cluster)
|
|
522
|
-
|
|
523
|
-
k8s = Helpers::ClusterValidator.kubernetes_client(options[:cluster])
|
|
505
|
+
ctx = Helpers::ClusterContext.from_options(options)
|
|
524
506
|
|
|
525
507
|
# Get agent
|
|
526
508
|
begin
|
|
527
|
-
agent =
|
|
509
|
+
agent = ctx.client.get_resource('LanguageAgent', name, ctx.namespace)
|
|
528
510
|
rescue K8s::Error::NotFound
|
|
529
|
-
Formatters::ProgressFormatter.error("Agent '#{name}' not found in cluster '#{
|
|
511
|
+
Formatters::ProgressFormatter.error("Agent '#{name}' not found in cluster '#{ctx.name}'")
|
|
530
512
|
exit 1
|
|
531
513
|
end
|
|
532
514
|
|
|
@@ -540,12 +522,12 @@ module LanguageOperator
|
|
|
540
522
|
|
|
541
523
|
# Resume the CronJob by setting spec.suspend = false
|
|
542
524
|
cronjob_name = name
|
|
543
|
-
namespace =
|
|
525
|
+
namespace = ctx.namespace
|
|
544
526
|
|
|
545
527
|
Formatters::ProgressFormatter.with_spinner("Resuming agent '#{name}'") do
|
|
546
528
|
# Use kubectl to patch the cronjob
|
|
547
|
-
kubeconfig_arg =
|
|
548
|
-
context_arg =
|
|
529
|
+
kubeconfig_arg = ctx.config[:kubeconfig] ? "--kubeconfig=#{ctx.config[:kubeconfig]}" : ''
|
|
530
|
+
context_arg = ctx.config[:context] ? "--context=#{ctx.config[:context]}" : ''
|
|
549
531
|
|
|
550
532
|
cmd = "kubectl #{kubeconfig_arg} #{context_arg} -n #{namespace} patch cronjob #{cronjob_name} -p '{\"spec\":{\"suspend\":false}}'"
|
|
551
533
|
system(cmd)
|
|
@@ -619,24 +601,21 @@ module LanguageOperator
|
|
|
619
601
|
|
|
620
602
|
private
|
|
621
603
|
|
|
622
|
-
def handle_agent_not_found(name,
|
|
604
|
+
def handle_agent_not_found(name, ctx)
|
|
623
605
|
# Get available agents for fuzzy matching
|
|
624
|
-
agents =
|
|
606
|
+
agents = ctx.client.list_resources('LanguageAgent', namespace: ctx.namespace)
|
|
625
607
|
available_names = agents.map { |a| a.dig('metadata', 'name') }
|
|
626
608
|
|
|
627
609
|
error = K8s::Error::NotFound.new(404, 'Not Found', 'LanguageAgent')
|
|
628
610
|
Errors::Handler.handle_not_found(error,
|
|
629
611
|
resource_type: 'LanguageAgent',
|
|
630
612
|
resource_name: name,
|
|
631
|
-
cluster:
|
|
613
|
+
cluster: ctx.name,
|
|
632
614
|
available_resources: available_names)
|
|
633
615
|
end
|
|
634
616
|
|
|
635
617
|
def display_agent_created(agent, cluster, _description, synthesis_result)
|
|
636
|
-
require 'pastel'
|
|
637
618
|
require_relative '../formatters/code_formatter'
|
|
638
|
-
|
|
639
|
-
pastel = Pastel.new
|
|
640
619
|
agent_name = agent.dig('metadata', 'name')
|
|
641
620
|
|
|
642
621
|
puts
|
|
@@ -645,10 +624,9 @@ module LanguageOperator
|
|
|
645
624
|
|
|
646
625
|
# Get synthesized code if available
|
|
647
626
|
begin
|
|
648
|
-
|
|
649
|
-
k8s = Helpers::ClusterValidator.kubernetes_client(cluster)
|
|
627
|
+
ctx = Helpers::ClusterContext.from_options(cluster: cluster)
|
|
650
628
|
configmap_name = "#{agent_name}-code"
|
|
651
|
-
configmap =
|
|
629
|
+
configmap = ctx.client.get_resource('ConfigMap', configmap_name, ctx.namespace)
|
|
652
630
|
code_content = configmap.dig('data', 'agent.rb')
|
|
653
631
|
|
|
654
632
|
if code_content
|
|
@@ -832,21 +810,7 @@ module LanguageOperator
|
|
|
832
810
|
end
|
|
833
811
|
|
|
834
812
|
def format_status(status)
|
|
835
|
-
|
|
836
|
-
pastel = Pastel.new
|
|
837
|
-
|
|
838
|
-
case status.downcase
|
|
839
|
-
when 'ready', 'running', 'active'
|
|
840
|
-
"#{pastel.green('●')} #{status}"
|
|
841
|
-
when 'pending', 'creating', 'synthesizing'
|
|
842
|
-
"#{pastel.yellow('●')} #{status}"
|
|
843
|
-
when 'failed', 'error'
|
|
844
|
-
"#{pastel.red('●')} #{status}"
|
|
845
|
-
when 'paused', 'stopped'
|
|
846
|
-
"#{pastel.dim('●')} #{status}"
|
|
847
|
-
else
|
|
848
|
-
"#{pastel.dim('●')} #{status}"
|
|
849
|
-
end
|
|
813
|
+
Formatters::StatusFormatter.format(status)
|
|
850
814
|
end
|
|
851
815
|
|
|
852
816
|
def generate_agent_name(description)
|
|
@@ -940,13 +904,11 @@ module LanguageOperator
|
|
|
940
904
|
end
|
|
941
905
|
|
|
942
906
|
def list_cluster_agents(cluster)
|
|
943
|
-
|
|
907
|
+
ctx = Helpers::ClusterContext.from_options(cluster: cluster)
|
|
944
908
|
|
|
945
909
|
Formatters::ProgressFormatter.info("Agents in cluster '#{cluster}'")
|
|
946
910
|
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
agents = k8s.list_resources('LanguageAgent', namespace: cluster_config[:namespace])
|
|
911
|
+
agents = ctx.client.list_resources('LanguageAgent', namespace: ctx.namespace)
|
|
950
912
|
|
|
951
913
|
table_data = agents.map do |agent|
|
|
952
914
|
{
|
|
@@ -981,9 +943,9 @@ module LanguageOperator
|
|
|
981
943
|
all_agents = []
|
|
982
944
|
|
|
983
945
|
clusters.each do |cluster|
|
|
984
|
-
|
|
946
|
+
ctx = Helpers::ClusterContext.from_options(cluster: cluster[:name])
|
|
985
947
|
|
|
986
|
-
agents =
|
|
948
|
+
agents = ctx.client.list_resources('LanguageAgent', namespace: ctx.namespace)
|
|
987
949
|
|
|
988
950
|
agents.each do |agent|
|
|
989
951
|
all_agents << {
|
|
@@ -1059,9 +1021,6 @@ module LanguageOperator
|
|
|
1059
1021
|
end
|
|
1060
1022
|
|
|
1061
1023
|
def list_workspace_files(ctx, agent_name)
|
|
1062
|
-
require 'pastel'
|
|
1063
|
-
pastel = Pastel.new
|
|
1064
|
-
|
|
1065
1024
|
pod_name = get_agent_pod(ctx, agent_name)
|
|
1066
1025
|
|
|
1067
1026
|
# Check if workspace directory exists
|
|
@@ -1148,9 +1107,6 @@ module LanguageOperator
|
|
|
1148
1107
|
end
|
|
1149
1108
|
|
|
1150
1109
|
def view_workspace_file(ctx, agent_name, file_path)
|
|
1151
|
-
require 'pastel'
|
|
1152
|
-
pastel = Pastel.new
|
|
1153
|
-
|
|
1154
1110
|
pod_name = get_agent_pod(ctx, agent_name)
|
|
1155
1111
|
|
|
1156
1112
|
# Check if file exists
|
|
@@ -1191,9 +1147,6 @@ module LanguageOperator
|
|
|
1191
1147
|
end
|
|
1192
1148
|
|
|
1193
1149
|
def clean_workspace(ctx, agent_name)
|
|
1194
|
-
require 'pastel'
|
|
1195
|
-
pastel = Pastel.new
|
|
1196
|
-
|
|
1197
1150
|
pod_name = get_agent_pod(ctx, agent_name)
|
|
1198
1151
|
|
|
1199
1152
|
# Get current workspace usage
|
|
@@ -121,6 +121,7 @@ module LanguageOperator
|
|
|
121
121
|
end
|
|
122
122
|
|
|
123
123
|
# Build table data
|
|
124
|
+
# rubocop:disable Metrics/BlockLength
|
|
124
125
|
table_data = clusters.map do |cluster|
|
|
125
126
|
k8s = Helpers::ClusterValidator.kubernetes_client(cluster[:name])
|
|
126
127
|
|
|
@@ -144,9 +145,26 @@ module LanguageOperator
|
|
|
144
145
|
models: models.count,
|
|
145
146
|
status: status
|
|
146
147
|
}
|
|
148
|
+
rescue K8s::Error::NotFound
|
|
149
|
+
# Cluster exists in local config but not in Kubernetes
|
|
150
|
+
name_display = cluster[:name]
|
|
151
|
+
name_display += ' *' if cluster[:name] == current
|
|
152
|
+
|
|
153
|
+
{
|
|
154
|
+
name: name_display,
|
|
155
|
+
namespace: cluster[:namespace],
|
|
156
|
+
agents: '-',
|
|
157
|
+
tools: '-',
|
|
158
|
+
models: '-',
|
|
159
|
+
status: 'Not Found'
|
|
160
|
+
}
|
|
147
161
|
rescue StandardError
|
|
162
|
+
# Other errors (connection issues, auth problems, etc.)
|
|
163
|
+
name_display = cluster[:name]
|
|
164
|
+
name_display += ' *' if cluster[:name] == current
|
|
165
|
+
|
|
148
166
|
{
|
|
149
|
-
name:
|
|
167
|
+
name: name_display,
|
|
150
168
|
namespace: cluster[:namespace],
|
|
151
169
|
agents: '?',
|
|
152
170
|
tools: '?',
|
|
@@ -154,6 +172,7 @@ module LanguageOperator
|
|
|
154
172
|
status: 'Error'
|
|
155
173
|
}
|
|
156
174
|
end
|
|
175
|
+
# rubocop:enable Metrics/BlockLength
|
|
157
176
|
|
|
158
177
|
Formatters::TableFormatter.clusters(table_data)
|
|
159
178
|
|
|
@@ -162,6 +181,23 @@ module LanguageOperator
|
|
|
162
181
|
else
|
|
163
182
|
puts "\nNo cluster selected. Use 'aictl use <cluster>' to select one."
|
|
164
183
|
end
|
|
184
|
+
|
|
185
|
+
# Show helpful message if any clusters are not found
|
|
186
|
+
not_found_clusters = table_data.select { |c| c[:status] == 'Not Found' }
|
|
187
|
+
if not_found_clusters.any?
|
|
188
|
+
puts
|
|
189
|
+
Formatters::ProgressFormatter.warn('Some clusters exist in local config but not in Kubernetes')
|
|
190
|
+
puts
|
|
191
|
+
puts 'Clusters with "Not Found" status are defined in ~/.aictl/config.yaml'
|
|
192
|
+
puts 'but the corresponding LanguageCluster resource does not exist in Kubernetes.'
|
|
193
|
+
puts
|
|
194
|
+
puts 'To fix this:'
|
|
195
|
+
not_found_clusters.each do |cluster|
|
|
196
|
+
cluster_name = cluster[:name].gsub(' *', '')
|
|
197
|
+
puts " • Remove from config: aictl cluster delete #{cluster_name}"
|
|
198
|
+
puts " • Or recreate: aictl cluster create #{cluster_name}"
|
|
199
|
+
end
|
|
200
|
+
end
|
|
165
201
|
rescue StandardError => e
|
|
166
202
|
Formatters::ProgressFormatter.error("Failed to list clusters: #{e.message}")
|
|
167
203
|
raise if ENV['DEBUG']
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require 'thor'
|
|
4
4
|
require 'yaml'
|
|
5
|
-
require 'pastel'
|
|
6
5
|
require_relative '../formatters/progress_formatter'
|
|
7
6
|
require_relative '../formatters/table_formatter'
|
|
8
7
|
require_relative '../helpers/cluster_validator'
|
|
@@ -10,6 +9,7 @@ require_relative '../helpers/cluster_context'
|
|
|
10
9
|
require_relative '../helpers/user_prompts'
|
|
11
10
|
require_relative '../helpers/resource_dependency_checker'
|
|
12
11
|
require_relative '../helpers/editor_helper'
|
|
12
|
+
require_relative '../helpers/pastel_helper'
|
|
13
13
|
require_relative '../../config/cluster_config'
|
|
14
14
|
require_relative '../../kubernetes/client'
|
|
15
15
|
require_relative '../../kubernetes/resource_builder'
|
|
@@ -20,6 +20,7 @@ module LanguageOperator
|
|
|
20
20
|
# Persona management commands
|
|
21
21
|
class Persona < Thor
|
|
22
22
|
include Helpers::ClusterValidator
|
|
23
|
+
include Helpers::PastelHelper
|
|
23
24
|
|
|
24
25
|
desc 'list', 'List all personas in current cluster'
|
|
25
26
|
option :cluster, type: :string, desc: 'Override current cluster context'
|
|
@@ -386,10 +387,6 @@ module LanguageOperator
|
|
|
386
387
|
def edit_in_editor(content, filename_prefix)
|
|
387
388
|
Helpers::EditorHelper.edit_content(content, filename_prefix, '.txt')
|
|
388
389
|
end
|
|
389
|
-
|
|
390
|
-
def pastel
|
|
391
|
-
@pastel ||= Pastel.new
|
|
392
|
-
end
|
|
393
390
|
end
|
|
394
391
|
end
|
|
395
392
|
end
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
require 'thor'
|
|
4
4
|
require_relative '../formatters/progress_formatter'
|
|
5
5
|
require_relative '../formatters/table_formatter'
|
|
6
|
+
require_relative '../formatters/status_formatter'
|
|
7
|
+
require_relative '../helpers/pastel_helper'
|
|
6
8
|
require_relative '../../config/cluster_config'
|
|
7
9
|
require_relative '../../kubernetes/client'
|
|
8
10
|
require_relative '../helpers/cluster_validator'
|
|
@@ -12,13 +14,13 @@ module LanguageOperator
|
|
|
12
14
|
module Commands
|
|
13
15
|
# System status and overview command
|
|
14
16
|
class Status < Thor
|
|
17
|
+
include Helpers::PastelHelper
|
|
18
|
+
|
|
15
19
|
desc 'overview', 'Show system status and overview'
|
|
16
20
|
def overview
|
|
17
21
|
current_cluster = Config::ClusterConfig.current_cluster
|
|
18
22
|
clusters = Config::ClusterConfig.list_clusters
|
|
19
23
|
|
|
20
|
-
pastel = Pastel.new
|
|
21
|
-
|
|
22
24
|
# Current cluster context
|
|
23
25
|
if current_cluster
|
|
24
26
|
cluster_config = Config::ClusterConfig.get_cluster(current_cluster)
|
|
@@ -124,22 +126,7 @@ module LanguageOperator
|
|
|
124
126
|
private
|
|
125
127
|
|
|
126
128
|
def format_status(status)
|
|
127
|
-
|
|
128
|
-
pastel = Pastel.new
|
|
129
|
-
|
|
130
|
-
status_str = status.to_s
|
|
131
|
-
case status_str.downcase
|
|
132
|
-
when 'ready', 'running', 'active'
|
|
133
|
-
"#{pastel.green('●')} #{status_str}"
|
|
134
|
-
when 'pending', 'creating', 'synthesizing'
|
|
135
|
-
"#{pastel.yellow('●')} #{status_str}"
|
|
136
|
-
when 'failed', 'error'
|
|
137
|
-
"#{pastel.red('●')} #{status_str}"
|
|
138
|
-
when 'paused', 'stopped'
|
|
139
|
-
"#{pastel.dim('●')} #{status_str}"
|
|
140
|
-
else
|
|
141
|
-
"#{pastel.dim('●')} #{status_str}"
|
|
142
|
-
end
|
|
129
|
+
Formatters::StatusFormatter.format(status)
|
|
143
130
|
end
|
|
144
131
|
|
|
145
132
|
def categorize_by_status(resources)
|