language-operator 0.0.1 → 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/.rubocop.yml +125 -0
- data/CHANGELOG.md +88 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +284 -0
- data/LICENSE +229 -21
- data/Makefile +82 -0
- data/README.md +3 -11
- data/Rakefile +63 -0
- data/bin/aictl +7 -0
- data/completions/_aictl +232 -0
- data/completions/aictl.bash +121 -0
- data/completions/aictl.fish +114 -0
- data/docs/architecture/agent-runtime.md +585 -0
- data/docs/dsl/SCHEMA_VERSION.md +250 -0
- data/docs/dsl/agent-reference.md +604 -0
- data/docs/dsl/best-practices.md +1078 -0
- data/docs/dsl/chat-endpoints.md +895 -0
- data/docs/dsl/constraints.md +671 -0
- data/docs/dsl/mcp-integration.md +1177 -0
- data/docs/dsl/webhooks.md +932 -0
- data/docs/dsl/workflows.md +744 -0
- data/lib/language_operator/agent/base.rb +110 -0
- data/lib/language_operator/agent/executor.rb +440 -0
- data/lib/language_operator/agent/instrumentation.rb +54 -0
- data/lib/language_operator/agent/metrics_tracker.rb +183 -0
- data/lib/language_operator/agent/safety/ast_validator.rb +272 -0
- data/lib/language_operator/agent/safety/audit_logger.rb +104 -0
- data/lib/language_operator/agent/safety/budget_tracker.rb +175 -0
- data/lib/language_operator/agent/safety/content_filter.rb +93 -0
- data/lib/language_operator/agent/safety/manager.rb +207 -0
- data/lib/language_operator/agent/safety/rate_limiter.rb +150 -0
- data/lib/language_operator/agent/safety/safe_executor.rb +127 -0
- data/lib/language_operator/agent/scheduler.rb +183 -0
- data/lib/language_operator/agent/telemetry.rb +116 -0
- data/lib/language_operator/agent/web_server.rb +610 -0
- data/lib/language_operator/agent/webhook_authenticator.rb +226 -0
- data/lib/language_operator/agent.rb +149 -0
- data/lib/language_operator/cli/commands/agent.rb +1205 -0
- data/lib/language_operator/cli/commands/cluster.rb +371 -0
- data/lib/language_operator/cli/commands/install.rb +404 -0
- data/lib/language_operator/cli/commands/model.rb +266 -0
- data/lib/language_operator/cli/commands/persona.rb +393 -0
- data/lib/language_operator/cli/commands/quickstart.rb +22 -0
- data/lib/language_operator/cli/commands/status.rb +143 -0
- data/lib/language_operator/cli/commands/system.rb +772 -0
- data/lib/language_operator/cli/commands/tool.rb +537 -0
- data/lib/language_operator/cli/commands/use.rb +47 -0
- data/lib/language_operator/cli/errors/handler.rb +180 -0
- data/lib/language_operator/cli/errors/suggestions.rb +176 -0
- data/lib/language_operator/cli/formatters/code_formatter.rb +77 -0
- data/lib/language_operator/cli/formatters/log_formatter.rb +288 -0
- data/lib/language_operator/cli/formatters/progress_formatter.rb +49 -0
- data/lib/language_operator/cli/formatters/status_formatter.rb +37 -0
- data/lib/language_operator/cli/formatters/table_formatter.rb +163 -0
- data/lib/language_operator/cli/formatters/value_formatter.rb +113 -0
- data/lib/language_operator/cli/helpers/cluster_context.rb +62 -0
- data/lib/language_operator/cli/helpers/cluster_validator.rb +101 -0
- data/lib/language_operator/cli/helpers/editor_helper.rb +58 -0
- data/lib/language_operator/cli/helpers/kubeconfig_validator.rb +167 -0
- data/lib/language_operator/cli/helpers/pastel_helper.rb +24 -0
- data/lib/language_operator/cli/helpers/resource_dependency_checker.rb +74 -0
- data/lib/language_operator/cli/helpers/schedule_builder.rb +108 -0
- data/lib/language_operator/cli/helpers/user_prompts.rb +69 -0
- data/lib/language_operator/cli/main.rb +236 -0
- data/lib/language_operator/cli/templates/tools/generic.yaml +66 -0
- data/lib/language_operator/cli/wizards/agent_wizard.rb +246 -0
- data/lib/language_operator/cli/wizards/quickstart_wizard.rb +588 -0
- data/lib/language_operator/client/base.rb +214 -0
- data/lib/language_operator/client/config.rb +136 -0
- data/lib/language_operator/client/cost_calculator.rb +37 -0
- data/lib/language_operator/client/mcp_connector.rb +123 -0
- data/lib/language_operator/client.rb +19 -0
- data/lib/language_operator/config/cluster_config.rb +101 -0
- data/lib/language_operator/config/tool_patterns.yaml +57 -0
- data/lib/language_operator/config/tool_registry.rb +96 -0
- data/lib/language_operator/config.rb +138 -0
- data/lib/language_operator/dsl/adapter.rb +124 -0
- data/lib/language_operator/dsl/agent_context.rb +90 -0
- data/lib/language_operator/dsl/agent_definition.rb +427 -0
- data/lib/language_operator/dsl/chat_endpoint_definition.rb +115 -0
- data/lib/language_operator/dsl/config.rb +119 -0
- data/lib/language_operator/dsl/context.rb +50 -0
- data/lib/language_operator/dsl/execution_context.rb +47 -0
- data/lib/language_operator/dsl/helpers.rb +109 -0
- data/lib/language_operator/dsl/http.rb +184 -0
- data/lib/language_operator/dsl/mcp_server_definition.rb +73 -0
- data/lib/language_operator/dsl/parameter_definition.rb +124 -0
- data/lib/language_operator/dsl/registry.rb +36 -0
- data/lib/language_operator/dsl/schema.rb +1102 -0
- data/lib/language_operator/dsl/shell.rb +125 -0
- data/lib/language_operator/dsl/tool_definition.rb +112 -0
- data/lib/language_operator/dsl/webhook_authentication.rb +114 -0
- data/lib/language_operator/dsl/webhook_definition.rb +106 -0
- data/lib/language_operator/dsl/workflow_definition.rb +259 -0
- data/lib/language_operator/dsl.rb +161 -0
- data/lib/language_operator/errors.rb +60 -0
- data/lib/language_operator/kubernetes/client.rb +279 -0
- data/lib/language_operator/kubernetes/resource_builder.rb +194 -0
- data/lib/language_operator/loggable.rb +47 -0
- data/lib/language_operator/logger.rb +141 -0
- data/lib/language_operator/retry.rb +123 -0
- data/lib/language_operator/retryable.rb +132 -0
- 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/tool_loader.rb +242 -0
- data/lib/language_operator/validators.rb +170 -0
- data/lib/language_operator/version.rb +1 -1
- data/lib/language_operator.rb +65 -3
- data/requirements/tasks/challenge.md +9 -0
- data/requirements/tasks/iterate.md +36 -0
- data/requirements/tasks/optimize.md +21 -0
- data/requirements/tasks/tag.md +5 -0
- data/test_agent_dsl.rb +108 -0
- metadata +507 -20
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'openssl'
|
|
4
|
+
require 'base64'
|
|
5
|
+
|
|
6
|
+
module LanguageOperator
|
|
7
|
+
module Agent
|
|
8
|
+
# Executes webhook authentication checks
|
|
9
|
+
class WebhookAuthenticator
|
|
10
|
+
# Authenticate a webhook request
|
|
11
|
+
#
|
|
12
|
+
# @param authentication [LanguageOperator::Dsl::WebhookAuthentication] Authentication definition
|
|
13
|
+
# @param context [Hash] Request context with :headers, :body, etc.
|
|
14
|
+
# @return [Boolean] true if authenticated, false otherwise
|
|
15
|
+
def self.authenticate(authentication, context)
|
|
16
|
+
return true unless authentication # No authentication required
|
|
17
|
+
|
|
18
|
+
case authentication.type
|
|
19
|
+
when :signature
|
|
20
|
+
verify_signature(authentication.config, context)
|
|
21
|
+
when :api_key
|
|
22
|
+
verify_api_key(authentication.config, context)
|
|
23
|
+
when :bearer_token
|
|
24
|
+
verify_bearer_token(authentication.config, context)
|
|
25
|
+
when :basic_auth
|
|
26
|
+
verify_basic_auth(authentication.config, context)
|
|
27
|
+
when :custom
|
|
28
|
+
verify_custom(authentication.config, context)
|
|
29
|
+
when :any_of
|
|
30
|
+
verify_any_of(authentication.config, context)
|
|
31
|
+
when :all_of
|
|
32
|
+
verify_all_of(authentication.config, context)
|
|
33
|
+
else
|
|
34
|
+
false
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Verify HMAC signature
|
|
39
|
+
def self.verify_signature(config, context)
|
|
40
|
+
header = config[:header]
|
|
41
|
+
secret = config[:secret]
|
|
42
|
+
algorithm = config[:algorithm] || :sha256
|
|
43
|
+
prefix = config[:prefix]
|
|
44
|
+
|
|
45
|
+
signature = get_header(context, header)
|
|
46
|
+
return false unless signature
|
|
47
|
+
|
|
48
|
+
# Remove prefix if specified (e.g., "sha256=")
|
|
49
|
+
signature = signature.sub(/^#{Regexp.escape(prefix)}/, '') if prefix
|
|
50
|
+
|
|
51
|
+
# Compute expected signature
|
|
52
|
+
body = context[:body] || ''
|
|
53
|
+
expected = OpenSSL::HMAC.hexdigest(algorithm.to_s, secret, body)
|
|
54
|
+
|
|
55
|
+
# Constant-time comparison to prevent timing attacks
|
|
56
|
+
secure_compare(signature, expected)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Verify API key from header
|
|
60
|
+
def self.verify_api_key(config, context)
|
|
61
|
+
header = config[:header]
|
|
62
|
+
expected_key = config[:key]
|
|
63
|
+
|
|
64
|
+
actual_key = get_header(context, header)
|
|
65
|
+
return false unless actual_key
|
|
66
|
+
|
|
67
|
+
secure_compare(actual_key, expected_key)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Verify bearer token
|
|
71
|
+
def self.verify_bearer_token(config, context)
|
|
72
|
+
expected_token = config[:token]
|
|
73
|
+
|
|
74
|
+
auth_header = get_header(context, 'Authorization')
|
|
75
|
+
return false unless auth_header
|
|
76
|
+
|
|
77
|
+
# Extract token from "Bearer <token>"
|
|
78
|
+
match = auth_header.match(/^Bearer\s+(.+)$/i)
|
|
79
|
+
return false unless match
|
|
80
|
+
|
|
81
|
+
actual_token = match[1]
|
|
82
|
+
secure_compare(actual_token, expected_token)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Verify basic auth credentials
|
|
86
|
+
def self.verify_basic_auth(config, context)
|
|
87
|
+
expected_username = config[:username]
|
|
88
|
+
expected_password = config[:password]
|
|
89
|
+
|
|
90
|
+
auth_header = get_header(context, 'Authorization')
|
|
91
|
+
return false unless auth_header
|
|
92
|
+
|
|
93
|
+
# Extract credentials from "Basic <base64>"
|
|
94
|
+
match = auth_header.match(/^Basic\s+(.+)$/i)
|
|
95
|
+
return false unless match
|
|
96
|
+
|
|
97
|
+
begin
|
|
98
|
+
credentials = Base64.decode64(match[1])
|
|
99
|
+
username, password = credentials.split(':', 2)
|
|
100
|
+
|
|
101
|
+
secure_compare(username, expected_username) &&
|
|
102
|
+
secure_compare(password, expected_password)
|
|
103
|
+
rescue StandardError
|
|
104
|
+
false
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Verify using custom callback
|
|
109
|
+
def self.verify_custom(config, context)
|
|
110
|
+
callback = config[:callback]
|
|
111
|
+
return false unless callback
|
|
112
|
+
|
|
113
|
+
begin
|
|
114
|
+
result = callback.call(context)
|
|
115
|
+
result == true # Explicit true check
|
|
116
|
+
rescue StandardError
|
|
117
|
+
# Silently fail on callback errors for security
|
|
118
|
+
false
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Verify any of multiple authentication methods
|
|
123
|
+
def self.verify_any_of(config, context)
|
|
124
|
+
methods = config[:methods] || []
|
|
125
|
+
return false if methods.empty?
|
|
126
|
+
|
|
127
|
+
methods.any? { |auth| authenticate(auth, context) }
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Verify all of multiple authentication methods
|
|
131
|
+
def self.verify_all_of(config, context)
|
|
132
|
+
methods = config[:methods] || []
|
|
133
|
+
return false if methods.empty?
|
|
134
|
+
|
|
135
|
+
methods.all? { |auth| authenticate(auth, context) }
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Execute validations
|
|
139
|
+
#
|
|
140
|
+
# @param validations [Array<Hash>] Validation definitions
|
|
141
|
+
# @param context [Hash] Request context
|
|
142
|
+
# @return [Array<String>] Validation errors (empty if valid)
|
|
143
|
+
def self.validate(validations, context)
|
|
144
|
+
errors = []
|
|
145
|
+
|
|
146
|
+
validations.each do |validation|
|
|
147
|
+
case validation[:type]
|
|
148
|
+
when :headers
|
|
149
|
+
errors.concat(validate_headers(validation[:config], context))
|
|
150
|
+
when :content_type
|
|
151
|
+
errors.concat(validate_content_type(validation[:config], context))
|
|
152
|
+
when :custom
|
|
153
|
+
result = validation[:config].call(context)
|
|
154
|
+
errors << result unless result == true
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
errors.compact
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Validate required headers
|
|
162
|
+
def self.validate_headers(required_headers, context)
|
|
163
|
+
errors = []
|
|
164
|
+
context[:headers] || {}
|
|
165
|
+
|
|
166
|
+
required_headers.each do |header_name, expected_value|
|
|
167
|
+
actual_value = get_header(context, header_name)
|
|
168
|
+
|
|
169
|
+
if actual_value.nil?
|
|
170
|
+
errors << "Missing required header: #{header_name}"
|
|
171
|
+
elsif expected_value && actual_value != expected_value
|
|
172
|
+
errors << "Invalid value for header #{header_name}"
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
errors
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Validate content type
|
|
180
|
+
def self.validate_content_type(allowed_types, context)
|
|
181
|
+
content_type = get_header(context, 'Content-Type')
|
|
182
|
+
return ['Missing Content-Type header'] unless content_type
|
|
183
|
+
|
|
184
|
+
# Extract media type (ignore charset, boundary, etc.)
|
|
185
|
+
media_type = content_type.split(';').first.strip.downcase
|
|
186
|
+
|
|
187
|
+
return [] if allowed_types.any? { |type| media_type == type.downcase }
|
|
188
|
+
|
|
189
|
+
["Invalid Content-Type: expected #{allowed_types.join(' or ')}, got #{media_type}"]
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Get header value (case-insensitive)
|
|
193
|
+
def self.get_header(context, name)
|
|
194
|
+
headers = context[:headers] || {}
|
|
195
|
+
name_lower = name.downcase
|
|
196
|
+
|
|
197
|
+
# Try exact match first
|
|
198
|
+
return headers[name] if headers.key?(name)
|
|
199
|
+
|
|
200
|
+
# Try case-insensitive match
|
|
201
|
+
headers.each do |key, value|
|
|
202
|
+
return value if key.downcase == name_lower
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
nil
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Constant-time string comparison to prevent timing attacks
|
|
209
|
+
def self.secure_compare(a, b)
|
|
210
|
+
return false if a.nil? || b.nil?
|
|
211
|
+
return false unless a.bytesize == b.bytesize
|
|
212
|
+
|
|
213
|
+
l = a.unpack('C*')
|
|
214
|
+
r = b.unpack('C*')
|
|
215
|
+
|
|
216
|
+
res = 0
|
|
217
|
+
l.zip(r) { |x, y| res |= x ^ y }
|
|
218
|
+
res.zero?
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
private_class_method :verify_signature, :verify_api_key, :verify_bearer_token,
|
|
222
|
+
:verify_basic_auth, :verify_custom, :verify_any_of, :verify_all_of,
|
|
223
|
+
:validate_headers, :validate_content_type, :get_header, :secure_compare
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'agent/base'
|
|
4
|
+
require_relative 'agent/executor'
|
|
5
|
+
require_relative 'agent/scheduler'
|
|
6
|
+
require_relative 'agent/web_server'
|
|
7
|
+
require_relative 'dsl'
|
|
8
|
+
require_relative 'logger'
|
|
9
|
+
|
|
10
|
+
module LanguageOperator
|
|
11
|
+
# Agent Framework
|
|
12
|
+
#
|
|
13
|
+
# Provides autonomous execution capabilities for language agents.
|
|
14
|
+
# Extends LanguageOperator::Client with agent-specific features like scheduling,
|
|
15
|
+
# goal evaluation, and workspace integration.
|
|
16
|
+
#
|
|
17
|
+
# @example Running an agent
|
|
18
|
+
# config = LanguageOperator::Client::Config.from_env
|
|
19
|
+
# agent = LanguageOperator::Agent::Base.new(config)
|
|
20
|
+
# agent.run
|
|
21
|
+
#
|
|
22
|
+
# @example Creating a custom agent
|
|
23
|
+
# agent = LanguageOperator::Agent::Base.new(config)
|
|
24
|
+
# agent.execute_goal("Summarize daily news")
|
|
25
|
+
module Agent
|
|
26
|
+
# Run the default agent based on environment configuration
|
|
27
|
+
#
|
|
28
|
+
# @param config_path [String] Path to configuration file
|
|
29
|
+
# @return [void]
|
|
30
|
+
def self.run(config_path: nil)
|
|
31
|
+
# Disable stdout buffering for real-time logging in containers
|
|
32
|
+
$stdout.sync = true
|
|
33
|
+
$stderr.sync = true
|
|
34
|
+
|
|
35
|
+
config_path ||= ENV.fetch('CONFIG_PATH', 'config.yaml')
|
|
36
|
+
config = LanguageOperator::Client::Config.load_with_fallback(config_path)
|
|
37
|
+
|
|
38
|
+
# Create agent instance
|
|
39
|
+
agent = LanguageOperator::Agent::Base.new(config)
|
|
40
|
+
|
|
41
|
+
# Load and run with synthesized code if available
|
|
42
|
+
load_and_run(agent)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Load synthesized agent code and run with definition if available
|
|
46
|
+
#
|
|
47
|
+
# @param agent [LanguageOperator::Agent::Base] The agent instance
|
|
48
|
+
# @return [void]
|
|
49
|
+
def self.load_and_run(agent)
|
|
50
|
+
agent_code_path = ENV.fetch('AGENT_CODE_PATH', nil)
|
|
51
|
+
agent_name = ENV.fetch('AGENT_NAME', nil)
|
|
52
|
+
|
|
53
|
+
if agent_code_path && File.exist?(agent_code_path)
|
|
54
|
+
load_synthesized_agent(agent, agent_code_path, agent_name)
|
|
55
|
+
else
|
|
56
|
+
LanguageOperator::Logger.info('No synthesized code found, running in standard mode',
|
|
57
|
+
component: 'Agent',
|
|
58
|
+
agent_code_path: agent_code_path)
|
|
59
|
+
agent.run
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Load synthesized agent code and execute
|
|
64
|
+
#
|
|
65
|
+
# @param agent [LanguageOperator::Agent::Base] The agent instance
|
|
66
|
+
# @param code_path [String] Path to synthesized code
|
|
67
|
+
# @param agent_name [String] Name of agent definition
|
|
68
|
+
# @return [void]
|
|
69
|
+
def self.load_synthesized_agent(agent, code_path, agent_name)
|
|
70
|
+
LanguageOperator::Logger.info('DSL code loading',
|
|
71
|
+
component: 'Agent',
|
|
72
|
+
path: code_path,
|
|
73
|
+
agent_name: agent_name)
|
|
74
|
+
|
|
75
|
+
# Load synthesized DSL code
|
|
76
|
+
LanguageOperator::Dsl.load_agent_file(code_path)
|
|
77
|
+
|
|
78
|
+
# Get agent definition from registry
|
|
79
|
+
agent_def = LanguageOperator::Dsl.agent_registry.get(agent_name) if agent_name
|
|
80
|
+
|
|
81
|
+
if agent_def
|
|
82
|
+
LanguageOperator::Logger.info('Agent definition loaded',
|
|
83
|
+
component: 'Agent',
|
|
84
|
+
agent_name: agent_name,
|
|
85
|
+
has_workflow: !agent_def.workflow.nil?)
|
|
86
|
+
run_with_definition(agent, agent_def)
|
|
87
|
+
else
|
|
88
|
+
log_definition_not_found(agent_name)
|
|
89
|
+
agent.run
|
|
90
|
+
end
|
|
91
|
+
rescue StandardError => e
|
|
92
|
+
log_load_error(e)
|
|
93
|
+
agent.run
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Log when agent definition is not found
|
|
97
|
+
#
|
|
98
|
+
# @param agent_name [String] Name of agent
|
|
99
|
+
# @return [void]
|
|
100
|
+
def self.log_definition_not_found(agent_name)
|
|
101
|
+
LanguageOperator::Logger.warn('Agent definition not found in registry',
|
|
102
|
+
component: 'Agent',
|
|
103
|
+
agent_name: agent_name,
|
|
104
|
+
available: LanguageOperator::Dsl.agent_registry.all.map(&:name))
|
|
105
|
+
LanguageOperator::Logger.info('Falling back to autonomous mode', component: 'Agent')
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Log agent code loading error
|
|
109
|
+
#
|
|
110
|
+
# @param error [StandardError] The error
|
|
111
|
+
# @return [void]
|
|
112
|
+
def self.log_load_error(error)
|
|
113
|
+
LanguageOperator::Logger.error('Failed to load agent code',
|
|
114
|
+
component: 'Agent',
|
|
115
|
+
error: error.message,
|
|
116
|
+
backtrace: error.backtrace[0..3])
|
|
117
|
+
LanguageOperator::Logger.info('Falling back to autonomous mode', component: 'Agent')
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Run agent with a loaded definition
|
|
121
|
+
#
|
|
122
|
+
# @param agent [LanguageOperator::Agent::Base] The agent instance
|
|
123
|
+
# @param agent_def [LanguageOperator::Dsl::AgentDefinition] The agent definition
|
|
124
|
+
# @return [void]
|
|
125
|
+
def self.run_with_definition(agent, agent_def)
|
|
126
|
+
agent.connect!
|
|
127
|
+
|
|
128
|
+
case agent.mode
|
|
129
|
+
when 'autonomous', 'interactive'
|
|
130
|
+
# Execute workflow in autonomous mode
|
|
131
|
+
executor = LanguageOperator::Agent::Executor.new(agent)
|
|
132
|
+
executor.execute_workflow(agent_def)
|
|
133
|
+
when 'scheduled', 'event-driven'
|
|
134
|
+
# Schedule workflow execution
|
|
135
|
+
scheduler = LanguageOperator::Agent::Scheduler.new(agent)
|
|
136
|
+
scheduler.start_with_workflow(agent_def)
|
|
137
|
+
when 'reactive', 'http', 'webhook'
|
|
138
|
+
# Start web server with webhooks, MCP tools, and chat endpoint
|
|
139
|
+
web_server = LanguageOperator::Agent::WebServer.new(agent)
|
|
140
|
+
agent_def.webhooks.each { |webhook_def| webhook_def.register(web_server) }
|
|
141
|
+
web_server.register_mcp_tools(agent_def.mcp_server) if agent_def.mcp_server&.tools?
|
|
142
|
+
web_server.register_chat_endpoint(agent_def.chat_endpoint, agent) if agent_def.chat_endpoint
|
|
143
|
+
web_server.start
|
|
144
|
+
else
|
|
145
|
+
raise "Unknown agent mode: #{agent.mode}"
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|