aidp 0.34.1 ā 0.39.3
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/README.md +14 -14
- data/lib/aidp/agent_harness_adapter.rb +309 -0
- data/lib/aidp/cli/issue_importer.rb +20 -6
- data/lib/aidp/cli/jobs_command.rb +1 -1
- data/lib/aidp/cli/models_command.rb +9 -16
- data/lib/aidp/cli/prompts_command.rb +253 -0
- data/lib/aidp/cli/security_command.rb +4 -10
- data/lib/aidp/cli/storage_command.rb +277 -0
- data/lib/aidp/cli/temporal_command.rb +460 -0
- data/lib/aidp/cli.rb +24 -2
- data/lib/aidp/config.rb +15 -0
- data/lib/aidp/config_paths.rb +12 -2
- data/lib/aidp/database/migrations.rb +114 -0
- data/lib/aidp/database/repositories/checkpoint_repository.rb +174 -0
- data/lib/aidp/database/repositories/deprecated_models_repository.rb +206 -0
- data/lib/aidp/database/repositories/evaluation_repository.rb +208 -0
- data/lib/aidp/database/repositories/harness_state_repository.rb +140 -0
- data/lib/aidp/database/repositories/job_repository.rb +278 -0
- data/lib/aidp/database/repositories/model_cache_repository.rb +194 -0
- data/lib/aidp/database/repositories/progress_repository.rb +210 -0
- data/lib/aidp/database/repositories/prompt_archive_repository.rb +195 -0
- data/lib/aidp/database/repositories/prompt_feedback_repository.rb +266 -0
- data/lib/aidp/database/repositories/provider_info_cache_repository.rb +208 -0
- data/lib/aidp/database/repositories/provider_metrics_repository.rb +245 -0
- data/lib/aidp/database/repositories/secrets_repository.rb +187 -0
- data/lib/aidp/database/repositories/task_repository.rb +231 -0
- data/lib/aidp/database/repositories/template_version_repository.rb +383 -0
- data/lib/aidp/database/repositories/watch_state_repository.rb +472 -0
- data/lib/aidp/database/repositories/workstream_repository.rb +310 -0
- data/lib/aidp/database/repositories/worktree_repository.rb +240 -0
- data/lib/aidp/database/repository.rb +166 -0
- data/lib/aidp/database/schema.rb +347 -0
- data/lib/aidp/database/storage_migrator.rb +693 -0
- data/lib/aidp/database.rb +139 -0
- data/lib/aidp/debug_mixin.rb +2 -2
- data/lib/aidp/execute/checkpoint.rb +26 -0
- data/lib/aidp/execute/checkpoint_display.rb +16 -0
- data/lib/aidp/execute/prompt_evaluator.rb +30 -57
- data/lib/aidp/execute/work_loop_runner.rb +294 -46
- data/lib/aidp/firewall/provider_requirements_collector.rb +7 -23
- data/lib/aidp/harness/agent_harness_provider_manager.rb +275 -0
- data/lib/aidp/harness/ai_decision_engine.rb +78 -296
- data/lib/aidp/harness/config_schema.rb +59 -0
- data/lib/aidp/harness/configuration.rb +229 -10
- data/lib/aidp/harness/deprecation_cache.rb +53 -11
- data/lib/aidp/harness/enhanced_runner.rb +1 -1
- data/lib/aidp/harness/error_handler.rb +11 -5
- data/lib/aidp/harness/provider_config.rb +36 -0
- data/lib/aidp/harness/provider_factory.rb +26 -24
- data/lib/aidp/harness/provider_info.rb +9 -5
- data/lib/aidp/harness/provider_manager.rb +2 -2
- data/lib/aidp/harness/provider_metrics.rb +103 -1
- data/lib/aidp/harness/rspec_command_optimizer.rb +166 -0
- data/lib/aidp/harness/ruby_llm_registry.rb +97 -8
- data/lib/aidp/harness/runner.rb +7 -2
- data/lib/aidp/harness/state_manager.rb +1 -1
- data/lib/aidp/harness/test_runner.rb +167 -11
- data/lib/aidp/harness/thinking_depth_manager.rb +564 -5
- data/lib/aidp/harness/usage_limit.rb +179 -0
- data/lib/aidp/harness/usage_limit_enforcer.rb +240 -0
- data/lib/aidp/harness/usage_limit_tracker.rb +308 -0
- data/lib/aidp/harness/usage_period.rb +234 -0
- data/lib/aidp/init/agent_instructions_generator.rb +317 -0
- data/lib/aidp/init/runner.rb +25 -4
- data/lib/aidp/interfaces/activity_monitor_interface.rb +234 -0
- data/lib/aidp/interfaces/binary_checker_interface.rb +232 -0
- data/lib/aidp/interfaces/command_executor_interface.rb +216 -0
- data/lib/aidp/interfaces/logger_interface.rb +150 -0
- data/lib/aidp/interfaces/ui_interface.rb +254 -0
- data/lib/aidp/logger.rb +25 -7
- data/lib/aidp/orchestration_adapter.rb +279 -0
- data/lib/aidp/pr_worktree_manager.rb +4 -15
- data/lib/aidp/prompts/feedback_collector.rb +198 -0
- data/lib/aidp/prompts/prompt_template_manager.rb +415 -0
- data/lib/aidp/prompts/template_evolver.rb +305 -0
- data/lib/aidp/prompts/template_version_manager.rb +325 -0
- data/lib/aidp/setup/in_memory_config_adapter.rb +257 -0
- data/lib/aidp/setup/in_memory_config_manager.rb +262 -0
- data/lib/aidp/setup/wizard.rb +616 -176
- data/lib/aidp/shell_executor.rb +58 -0
- data/lib/aidp/style_guide/selector.rb +56 -1
- data/lib/aidp/temporal/activities/analyze_issue_activity.rb +198 -0
- data/lib/aidp/temporal/activities/analyze_sub_task_activity.rb +163 -0
- data/lib/aidp/temporal/activities/base_activity.rb +78 -0
- data/lib/aidp/temporal/activities/create_plan_activity.rb +115 -0
- data/lib/aidp/temporal/activities/create_pr_activity.rb +193 -0
- data/lib/aidp/temporal/activities/create_prompt_activity.rb +118 -0
- data/lib/aidp/temporal/activities/diagnose_failure_activity.rb +228 -0
- data/lib/aidp/temporal/activities/prepare_next_iteration_activity.rb +147 -0
- data/lib/aidp/temporal/activities/record_checkpoint_activity.rb +81 -0
- data/lib/aidp/temporal/activities/run_agent_activity.rb +139 -0
- data/lib/aidp/temporal/activities/run_tests_activity.rb +114 -0
- data/lib/aidp/temporal/activities/run_work_loop_iteration_activity.rb +249 -0
- data/lib/aidp/temporal/configuration.rb +169 -0
- data/lib/aidp/temporal/connection.rb +93 -0
- data/lib/aidp/temporal/worker.rb +119 -0
- data/lib/aidp/temporal/workflow_client.rb +171 -0
- data/lib/aidp/temporal/workflows/base_workflow.rb +73 -0
- data/lib/aidp/temporal/workflows/issue_to_pr_workflow.rb +278 -0
- data/lib/aidp/temporal/workflows/sub_issue_workflow.rb +253 -0
- data/lib/aidp/temporal/workflows/work_loop_workflow.rb +321 -0
- data/lib/aidp/temporal.rb +120 -0
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/base_processor.rb +35 -0
- data/lib/aidp/watch/build_processor.rb +132 -0
- data/lib/aidp/watch/github_state_extractor.rb +0 -8
- data/lib/aidp/watch/rebase_processor.rb +245 -0
- data/lib/aidp/watch/round_robin_scheduler.rb +150 -0
- data/lib/aidp/watch/runner.rb +366 -285
- data/lib/aidp/watch/state_store.rb +80 -0
- data/lib/aidp/watch/work_item.rb +96 -0
- data/lib/aidp/watch/worktree_cleanup_job.rb +226 -0
- data/lib/aidp/watch/worktree_reconciler.rb +643 -0
- data/lib/aidp/workflows/guided_agent.rb +1 -1
- data/lib/aidp/worktree.rb +62 -0
- data/templates/aidp.yml.example +70 -0
- metadata +117 -16
- data/lib/aidp/analyze/json_file_storage.rb +0 -292
- data/lib/aidp/execute/future_work_backlog.rb +0 -411
- data/lib/aidp/providers/adapter.rb +0 -239
- data/lib/aidp/providers/aider.rb +0 -264
- data/lib/aidp/providers/anthropic.rb +0 -614
- data/lib/aidp/providers/base.rb +0 -617
- data/lib/aidp/providers/capability_registry.rb +0 -204
- data/lib/aidp/providers/codex.rb +0 -267
- data/lib/aidp/providers/cursor.rb +0 -304
- data/lib/aidp/providers/error_taxonomy.rb +0 -195
- data/lib/aidp/providers/gemini.rb +0 -110
- data/lib/aidp/providers/github_copilot.rb +0 -227
- data/lib/aidp/providers/kilocode.rb +0 -157
- data/lib/aidp/providers/opencode.rb +0 -139
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Aidp
|
|
4
|
-
module Providers
|
|
5
|
-
# CapabilityRegistry maintains a queryable registry of provider capabilities
|
|
6
|
-
# and features. This enables runtime feature detection and provider selection
|
|
7
|
-
# based on required capabilities.
|
|
8
|
-
#
|
|
9
|
-
# @see https://github.com/viamin/aidp/issues/243
|
|
10
|
-
class CapabilityRegistry
|
|
11
|
-
# Standard capability keys
|
|
12
|
-
CAPABILITY_KEYS = [
|
|
13
|
-
:reasoning_tiers, # Array of supported reasoning tiers (mini, standard, thinking, etc.)
|
|
14
|
-
:context_window, # Maximum context window size in tokens
|
|
15
|
-
:supports_json_mode, # Boolean: supports JSON mode output
|
|
16
|
-
:supports_tool_use, # Boolean: supports tool/function calling
|
|
17
|
-
:supports_vision, # Boolean: supports image/vision inputs
|
|
18
|
-
:supports_file_upload, # Boolean: supports file uploads
|
|
19
|
-
:supports_mcp, # Boolean: supports Model Context Protocol
|
|
20
|
-
:max_tokens, # Maximum tokens per response
|
|
21
|
-
:supports_dangerous_mode # Boolean: supports elevated permissions mode
|
|
22
|
-
].freeze
|
|
23
|
-
|
|
24
|
-
def initialize
|
|
25
|
-
@capabilities = {}
|
|
26
|
-
@providers = {}
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Register a provider and its capabilities
|
|
30
|
-
# @param provider [Aidp::Providers::Base] provider instance
|
|
31
|
-
# @return [void]
|
|
32
|
-
def register(provider)
|
|
33
|
-
provider_name = provider.name
|
|
34
|
-
@providers[provider_name] = provider
|
|
35
|
-
|
|
36
|
-
# Collect capabilities from provider
|
|
37
|
-
caps = provider.capabilities.dup
|
|
38
|
-
caps[:supports_mcp] = provider.supports_mcp?
|
|
39
|
-
caps[:supports_dangerous_mode] = provider.supports_dangerous_mode?
|
|
40
|
-
|
|
41
|
-
@capabilities[provider_name] = caps
|
|
42
|
-
|
|
43
|
-
Aidp.log_debug("CapabilityRegistry", "registered provider",
|
|
44
|
-
provider: provider_name,
|
|
45
|
-
capabilities: caps.keys)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Unregister a provider
|
|
49
|
-
# @param provider_name [String] provider identifier
|
|
50
|
-
# @return [void]
|
|
51
|
-
def unregister(provider_name)
|
|
52
|
-
@capabilities.delete(provider_name)
|
|
53
|
-
@providers.delete(provider_name)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Get capabilities for a specific provider
|
|
57
|
-
# @param provider_name [String] provider identifier
|
|
58
|
-
# @return [Hash, nil] capabilities hash or nil if not found
|
|
59
|
-
def capabilities_for(provider_name)
|
|
60
|
-
@capabilities[provider_name]
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# Check if a provider has a specific capability
|
|
64
|
-
# @param provider_name [String] provider identifier
|
|
65
|
-
# @param capability [Symbol] capability key
|
|
66
|
-
# @param value [Object, nil] optional value to match
|
|
67
|
-
# @return [Boolean] true if provider has the capability
|
|
68
|
-
def has_capability?(provider_name, capability, value = nil)
|
|
69
|
-
caps = @capabilities[provider_name]
|
|
70
|
-
return false unless caps
|
|
71
|
-
|
|
72
|
-
if value.nil?
|
|
73
|
-
# Just check if capability exists and is truthy
|
|
74
|
-
caps.key?(capability) && caps[capability]
|
|
75
|
-
else
|
|
76
|
-
# Check if capability matches specific value
|
|
77
|
-
caps[capability] == value
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# Find providers that match capability requirements
|
|
82
|
-
# @param requirements [Hash] capability requirements
|
|
83
|
-
# @return [Array<String>] array of matching provider names
|
|
84
|
-
# @example
|
|
85
|
-
# registry.find_providers(supports_vision: true, min_context_window: 100_000)
|
|
86
|
-
def find_providers(**requirements)
|
|
87
|
-
matching = []
|
|
88
|
-
|
|
89
|
-
@capabilities.each do |provider_name, caps|
|
|
90
|
-
matches = requirements.all? do |key, required_value|
|
|
91
|
-
case key
|
|
92
|
-
when :min_context_window
|
|
93
|
-
caps[:context_window] && caps[:context_window] >= required_value
|
|
94
|
-
when :max_context_window
|
|
95
|
-
caps[:context_window] && caps[:context_window] <= required_value
|
|
96
|
-
when :reasoning_tier
|
|
97
|
-
caps[:reasoning_tiers]&.include?(required_value)
|
|
98
|
-
else
|
|
99
|
-
# Exact match for boolean and other values
|
|
100
|
-
caps[key] == required_value
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
matching << provider_name if matches
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
matching
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
# Get all registered providers
|
|
111
|
-
# @return [Array<String>] array of provider names
|
|
112
|
-
def registered_providers
|
|
113
|
-
@providers.keys
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
# Get detailed information about all registered providers
|
|
117
|
-
# @return [Hash] provider information indexed by provider name
|
|
118
|
-
def provider_info
|
|
119
|
-
info = {}
|
|
120
|
-
|
|
121
|
-
@providers.each do |provider_name, provider|
|
|
122
|
-
caps = @capabilities[provider_name] || {}
|
|
123
|
-
|
|
124
|
-
info[provider_name] = {
|
|
125
|
-
display_name: provider.display_name,
|
|
126
|
-
available: provider.available?,
|
|
127
|
-
capabilities: caps,
|
|
128
|
-
dangerous_mode_enabled: provider.dangerous_mode_enabled?,
|
|
129
|
-
health_status: provider.health_status
|
|
130
|
-
}
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
info
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# Check capability compatibility between providers
|
|
137
|
-
# @param provider_name1 [String] first provider
|
|
138
|
-
# @param provider_name2 [String] second provider
|
|
139
|
-
# @return [Hash] compatibility report
|
|
140
|
-
def compatibility_report(provider_name1, provider_name2)
|
|
141
|
-
caps1 = @capabilities[provider_name1]
|
|
142
|
-
caps2 = @capabilities[provider_name2]
|
|
143
|
-
|
|
144
|
-
return {error: "Provider not found"} unless caps1 && caps2
|
|
145
|
-
|
|
146
|
-
common = {}
|
|
147
|
-
differences = {}
|
|
148
|
-
|
|
149
|
-
all_keys = (caps1.keys + caps2.keys).uniq
|
|
150
|
-
|
|
151
|
-
all_keys.each do |key|
|
|
152
|
-
val1 = caps1[key]
|
|
153
|
-
val2 = caps2[key]
|
|
154
|
-
|
|
155
|
-
if val1 == val2
|
|
156
|
-
common[key] = val1
|
|
157
|
-
else
|
|
158
|
-
differences[key] = {provider_name1 => val1, provider_name2 => val2}
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
{
|
|
163
|
-
common_capabilities: common,
|
|
164
|
-
differences: differences,
|
|
165
|
-
compatibility_score: common.size.to_f / all_keys.size
|
|
166
|
-
}
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
# Get capability statistics across all providers
|
|
170
|
-
# @return [Hash] statistics about capability support
|
|
171
|
-
def capability_statistics
|
|
172
|
-
stats = {}
|
|
173
|
-
|
|
174
|
-
CAPABILITY_KEYS.each do |key|
|
|
175
|
-
stats[key] = {
|
|
176
|
-
total_providers: @providers.size,
|
|
177
|
-
supporting_providers: 0,
|
|
178
|
-
providers: []
|
|
179
|
-
}
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
@capabilities.each do |provider_name, caps|
|
|
183
|
-
caps.each do |key, value|
|
|
184
|
-
next unless stats.key?(key)
|
|
185
|
-
|
|
186
|
-
if value.is_a?(TrueClass) || (value.is_a?(Array) && !value.empty?) || (value.is_a?(Integer) && value > 0)
|
|
187
|
-
stats[key][:supporting_providers] += 1
|
|
188
|
-
stats[key][:providers] << provider_name
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
stats
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
# Clear all registered providers
|
|
197
|
-
# @return [void]
|
|
198
|
-
def clear
|
|
199
|
-
@capabilities.clear
|
|
200
|
-
@providers.clear
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
|
-
end
|
data/lib/aidp/providers/codex.rb
DELETED
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "timeout"
|
|
4
|
-
require_relative "base"
|
|
5
|
-
require_relative "../util"
|
|
6
|
-
require_relative "../debug_mixin"
|
|
7
|
-
|
|
8
|
-
module Aidp
|
|
9
|
-
module Providers
|
|
10
|
-
class Codex < Base
|
|
11
|
-
include Aidp::DebugMixin
|
|
12
|
-
|
|
13
|
-
# Model name pattern for OpenAI models (since Codex uses OpenAI)
|
|
14
|
-
MODEL_PATTERN = /^gpt-[\d.o-]+(?:-turbo)?(?:-mini)?$/i
|
|
15
|
-
LONG_PROMPT_THRESHOLD = 8000
|
|
16
|
-
LONG_PROMPT_TIMEOUT = 900 # 15 minutes for large prompts
|
|
17
|
-
|
|
18
|
-
def self.available?
|
|
19
|
-
!!Aidp::Util.which("codex")
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# Check if this provider supports a given model family
|
|
23
|
-
#
|
|
24
|
-
# @param family_name [String] The model family name
|
|
25
|
-
# @return [Boolean] True if it matches OpenAI model pattern
|
|
26
|
-
def self.supports_model_family?(family_name)
|
|
27
|
-
MODEL_PATTERN.match?(family_name)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Discover available models from registry
|
|
31
|
-
#
|
|
32
|
-
# Note: Codex CLI doesn't have a standard model listing command
|
|
33
|
-
# Returns registry-based models that match OpenAI patterns
|
|
34
|
-
#
|
|
35
|
-
# @return [Array<Hash>] Array of discovered models
|
|
36
|
-
def self.discover_models
|
|
37
|
-
return [] unless available?
|
|
38
|
-
|
|
39
|
-
discover_models_from_registry(MODEL_PATTERN, "codex")
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Get firewall requirements for Codex provider
|
|
43
|
-
# Codex uses OpenAI APIs
|
|
44
|
-
def self.firewall_requirements
|
|
45
|
-
{
|
|
46
|
-
domains: [
|
|
47
|
-
"api.openai.com",
|
|
48
|
-
"auth.openai.com",
|
|
49
|
-
"openai.com",
|
|
50
|
-
"chat.openai.com",
|
|
51
|
-
"chatgpt.com",
|
|
52
|
-
"cdn.openai.com",
|
|
53
|
-
"oaiusercontent.com"
|
|
54
|
-
],
|
|
55
|
-
ip_ranges: []
|
|
56
|
-
}
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def name
|
|
60
|
-
"codex"
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def display_name
|
|
64
|
-
"Codex CLI"
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def available?
|
|
68
|
-
return false unless self.class.available?
|
|
69
|
-
|
|
70
|
-
# Additional check to ensure the CLI is properly configured
|
|
71
|
-
begin
|
|
72
|
-
result = Aidp::Util.execute_command("codex", ["--version"], timeout: 10)
|
|
73
|
-
result.exit_status == 0
|
|
74
|
-
rescue
|
|
75
|
-
false
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def send_message(prompt:, session: nil, options: {})
|
|
80
|
-
raise "codex CLI not available" unless self.class.available?
|
|
81
|
-
|
|
82
|
-
# Smart timeout calculation (store prompt length for adaptive logic)
|
|
83
|
-
@current_codex_prompt_length = prompt.length
|
|
84
|
-
timeout_seconds = calculate_timeout
|
|
85
|
-
|
|
86
|
-
debug_provider("codex", "Starting execution", {timeout: timeout_seconds})
|
|
87
|
-
debug_log("š Sending prompt to codex (length: #{prompt.length})", level: :info)
|
|
88
|
-
|
|
89
|
-
# Set up activity monitoring
|
|
90
|
-
setup_activity_monitoring("codex", method(:activity_callback))
|
|
91
|
-
record_activity("Starting codex execution")
|
|
92
|
-
|
|
93
|
-
# Create a spinner for activity display
|
|
94
|
-
spinner = TTY::Spinner.new("[:spinner] :title", format: :dots, hide_cursor: true)
|
|
95
|
-
spinner.auto_spin
|
|
96
|
-
|
|
97
|
-
activity_display_thread = Thread.new do
|
|
98
|
-
start_time = Time.now
|
|
99
|
-
loop do
|
|
100
|
-
sleep 0.5 # Update every 500ms to reduce spam
|
|
101
|
-
elapsed = Time.now - start_time
|
|
102
|
-
|
|
103
|
-
# Break if we've been running too long or state changed
|
|
104
|
-
break if elapsed > timeout_seconds || @activity_state == :completed || @activity_state == :failed
|
|
105
|
-
|
|
106
|
-
update_spinner_status(spinner, elapsed, "š¤ Codex CLI")
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
begin
|
|
111
|
-
# Use non-interactive mode (exec) for automation
|
|
112
|
-
args = ["exec", prompt]
|
|
113
|
-
|
|
114
|
-
# Add model if configured
|
|
115
|
-
if @model && !@model.empty?
|
|
116
|
-
args += ["--model", @model]
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# Add session support if provided (codex may support session/thread continuation)
|
|
120
|
-
if session && !session.empty?
|
|
121
|
-
args += ["--session", session]
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
# In devcontainer, ensure sandbox mode and approval policy are set
|
|
125
|
-
# These are already set via environment variables in devcontainer.json
|
|
126
|
-
# but we verify and log them here for visibility
|
|
127
|
-
if in_devcontainer_or_codespace?
|
|
128
|
-
unless ENV["CODEX_SANDBOX_MODE"] == "danger-full-access"
|
|
129
|
-
ENV["CODEX_SANDBOX_MODE"] = "danger-full-access"
|
|
130
|
-
debug_log("š Set CODEX_SANDBOX_MODE=danger-full-access for devcontainer", level: :info)
|
|
131
|
-
end
|
|
132
|
-
unless ENV["CODEX_APPROVAL_POLICY"] == "never"
|
|
133
|
-
ENV["CODEX_APPROVAL_POLICY"] = "never"
|
|
134
|
-
debug_log("š Set CODEX_APPROVAL_POLICY=never for devcontainer", level: :info)
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
# Use debug_execute_command for better debugging
|
|
139
|
-
result = debug_execute_command("codex", args: args, timeout: timeout_seconds)
|
|
140
|
-
|
|
141
|
-
# Log the results
|
|
142
|
-
debug_command("codex", args: args, input: prompt, output: result.out, error: result.err, exit_code: result.exit_status)
|
|
143
|
-
|
|
144
|
-
if result.exit_status == 0
|
|
145
|
-
spinner.success("ā")
|
|
146
|
-
mark_completed
|
|
147
|
-
result.out
|
|
148
|
-
else
|
|
149
|
-
spinner.error("ā")
|
|
150
|
-
mark_failed("codex failed with exit code #{result.exit_status}")
|
|
151
|
-
debug_error(StandardError.new("codex failed"), {exit_code: result.exit_status, stderr: result.err})
|
|
152
|
-
raise "codex failed with exit code #{result.exit_status}: #{result.err}"
|
|
153
|
-
end
|
|
154
|
-
rescue => e
|
|
155
|
-
spinner&.error("ā")
|
|
156
|
-
mark_failed("codex execution failed: #{e.message}")
|
|
157
|
-
debug_error(e, {provider: "codex", prompt_length: prompt.length})
|
|
158
|
-
raise
|
|
159
|
-
ensure
|
|
160
|
-
cleanup_activity_display(activity_display_thread, spinner)
|
|
161
|
-
@current_codex_prompt_length = nil
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
# Enhanced send method with additional options
|
|
166
|
-
def send_with_options(prompt:, session: nil, model: nil, ask_for_approval: false)
|
|
167
|
-
args = ["exec", prompt]
|
|
168
|
-
|
|
169
|
-
# Add session support
|
|
170
|
-
if session && !session.empty?
|
|
171
|
-
args += ["--session", session]
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
# Add model selection (from parameter or configured model)
|
|
175
|
-
model_to_use = model || @model
|
|
176
|
-
if model_to_use
|
|
177
|
-
args += ["--model", model_to_use]
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
# Add approval flag - but warn about interactive behavior
|
|
181
|
-
if ask_for_approval
|
|
182
|
-
debug_log("ā ļø WARNING: --ask-for-approval flag may cause interactive prompts that could hang AIDP", level: :warn)
|
|
183
|
-
args += ["--ask-for-approval"]
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
# Use the enhanced version of send
|
|
187
|
-
send_with_custom_args(prompt: prompt, args: args)
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
# Override health check for Codex specific considerations
|
|
191
|
-
def harness_healthy?
|
|
192
|
-
return false unless super
|
|
193
|
-
|
|
194
|
-
# Additional health checks specific to Codex CLI
|
|
195
|
-
# Check if we can access the CLI (basic connectivity test)
|
|
196
|
-
begin
|
|
197
|
-
result = Aidp::Util.execute_command("codex", ["--help"], timeout: 5)
|
|
198
|
-
result.exit_status == 0
|
|
199
|
-
rescue
|
|
200
|
-
false
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
private
|
|
205
|
-
|
|
206
|
-
# Internal helper for send_with_options - executes with custom arguments
|
|
207
|
-
def send_with_custom_args(prompt:, args:)
|
|
208
|
-
@current_codex_prompt_length = prompt.length
|
|
209
|
-
timeout_seconds = calculate_timeout
|
|
210
|
-
|
|
211
|
-
debug_provider("codex", "Starting execution", {timeout: timeout_seconds, args: args})
|
|
212
|
-
debug_log("š Sending prompt to codex with custom args", level: :info)
|
|
213
|
-
|
|
214
|
-
setup_activity_monitoring("codex", method(:activity_callback))
|
|
215
|
-
record_activity("Starting codex execution with custom args")
|
|
216
|
-
|
|
217
|
-
begin
|
|
218
|
-
result = debug_execute_command("codex", args: args, timeout: timeout_seconds)
|
|
219
|
-
debug_command("codex", args: args, output: result.out, error: result.err, exit_code: result.exit_status)
|
|
220
|
-
|
|
221
|
-
if result.exit_status == 0
|
|
222
|
-
mark_completed
|
|
223
|
-
result.out
|
|
224
|
-
else
|
|
225
|
-
mark_failed("codex failed with exit code #{result.exit_status}")
|
|
226
|
-
debug_error(StandardError.new("codex failed"), {exit_code: result.exit_status, stderr: result.err})
|
|
227
|
-
raise "codex failed with exit code #{result.exit_status}: #{result.err}"
|
|
228
|
-
end
|
|
229
|
-
rescue => e
|
|
230
|
-
mark_failed("codex execution failed: #{e.message}")
|
|
231
|
-
debug_error(e, {provider: "codex", prompt_length: prompt.length})
|
|
232
|
-
raise
|
|
233
|
-
ensure
|
|
234
|
-
@current_codex_prompt_length = nil
|
|
235
|
-
end
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
def activity_callback(state, message, provider)
|
|
239
|
-
# Handle activity state changes
|
|
240
|
-
case state
|
|
241
|
-
when :stuck
|
|
242
|
-
display_message("\nā ļø Codex CLI appears stuck: #{message}", type: :warning)
|
|
243
|
-
when :completed
|
|
244
|
-
display_message("\nā
Codex CLI completed: #{message}", type: :success)
|
|
245
|
-
when :failed
|
|
246
|
-
display_message("\nā Codex CLI failed: #{message}", type: :error)
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
def calculate_timeout
|
|
251
|
-
env_override = ENV["AIDP_CODEX_TIMEOUT"]
|
|
252
|
-
return env_override.to_i if env_override&.match?(/^\d+$/)
|
|
253
|
-
|
|
254
|
-
base_timeout = super
|
|
255
|
-
|
|
256
|
-
prompt_length = @current_codex_prompt_length
|
|
257
|
-
return base_timeout unless prompt_length && prompt_length >= LONG_PROMPT_THRESHOLD
|
|
258
|
-
|
|
259
|
-
extended_timeout = [base_timeout, LONG_PROMPT_TIMEOUT].max
|
|
260
|
-
if extended_timeout > base_timeout
|
|
261
|
-
display_message("ā±ļø Codex prompt length #{prompt_length} detected - extending timeout to #{extended_timeout} seconds", type: :info)
|
|
262
|
-
end
|
|
263
|
-
extended_timeout
|
|
264
|
-
end
|
|
265
|
-
end
|
|
266
|
-
end
|
|
267
|
-
end
|