aidp 0.34.1 → 0.39.4

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.
Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -14
  3. data/lib/aidp/agent_harness_adapter.rb +309 -0
  4. data/lib/aidp/cli/issue_importer.rb +20 -6
  5. data/lib/aidp/cli/jobs_command.rb +1 -1
  6. data/lib/aidp/cli/models_command.rb +9 -16
  7. data/lib/aidp/cli/prompts_command.rb +253 -0
  8. data/lib/aidp/cli/security_command.rb +4 -10
  9. data/lib/aidp/cli/storage_command.rb +277 -0
  10. data/lib/aidp/cli/temporal_command.rb +460 -0
  11. data/lib/aidp/cli.rb +24 -2
  12. data/lib/aidp/config.rb +15 -0
  13. data/lib/aidp/config_paths.rb +12 -2
  14. data/lib/aidp/database/migrations.rb +114 -0
  15. data/lib/aidp/database/repositories/checkpoint_repository.rb +174 -0
  16. data/lib/aidp/database/repositories/deprecated_models_repository.rb +206 -0
  17. data/lib/aidp/database/repositories/evaluation_repository.rb +208 -0
  18. data/lib/aidp/database/repositories/harness_state_repository.rb +140 -0
  19. data/lib/aidp/database/repositories/job_repository.rb +278 -0
  20. data/lib/aidp/database/repositories/model_cache_repository.rb +194 -0
  21. data/lib/aidp/database/repositories/progress_repository.rb +210 -0
  22. data/lib/aidp/database/repositories/prompt_archive_repository.rb +195 -0
  23. data/lib/aidp/database/repositories/prompt_feedback_repository.rb +266 -0
  24. data/lib/aidp/database/repositories/provider_info_cache_repository.rb +208 -0
  25. data/lib/aidp/database/repositories/provider_metrics_repository.rb +245 -0
  26. data/lib/aidp/database/repositories/secrets_repository.rb +187 -0
  27. data/lib/aidp/database/repositories/task_repository.rb +231 -0
  28. data/lib/aidp/database/repositories/template_version_repository.rb +383 -0
  29. data/lib/aidp/database/repositories/watch_state_repository.rb +472 -0
  30. data/lib/aidp/database/repositories/workstream_repository.rb +310 -0
  31. data/lib/aidp/database/repositories/worktree_repository.rb +240 -0
  32. data/lib/aidp/database/repository.rb +166 -0
  33. data/lib/aidp/database/schema.rb +347 -0
  34. data/lib/aidp/database/storage_migrator.rb +693 -0
  35. data/lib/aidp/database.rb +139 -0
  36. data/lib/aidp/debug_mixin.rb +2 -2
  37. data/lib/aidp/execute/checkpoint.rb +26 -0
  38. data/lib/aidp/execute/checkpoint_display.rb +16 -0
  39. data/lib/aidp/execute/prompt_evaluator.rb +30 -57
  40. data/lib/aidp/execute/work_loop_runner.rb +294 -46
  41. data/lib/aidp/firewall/provider_requirements_collector.rb +7 -23
  42. data/lib/aidp/harness/agent_harness_provider_manager.rb +275 -0
  43. data/lib/aidp/harness/ai_decision_engine.rb +78 -296
  44. data/lib/aidp/harness/config_schema.rb +59 -0
  45. data/lib/aidp/harness/configuration.rb +229 -10
  46. data/lib/aidp/harness/deprecation_cache.rb +53 -11
  47. data/lib/aidp/harness/enhanced_runner.rb +1 -1
  48. data/lib/aidp/harness/error_handler.rb +11 -5
  49. data/lib/aidp/harness/provider_config.rb +36 -0
  50. data/lib/aidp/harness/provider_factory.rb +26 -24
  51. data/lib/aidp/harness/provider_info.rb +9 -5
  52. data/lib/aidp/harness/provider_manager.rb +2 -2
  53. data/lib/aidp/harness/provider_metrics.rb +103 -1
  54. data/lib/aidp/harness/rspec_command_optimizer.rb +166 -0
  55. data/lib/aidp/harness/ruby_llm_registry.rb +97 -8
  56. data/lib/aidp/harness/runner.rb +7 -2
  57. data/lib/aidp/harness/state_manager.rb +1 -1
  58. data/lib/aidp/harness/test_runner.rb +167 -11
  59. data/lib/aidp/harness/thinking_depth_manager.rb +564 -5
  60. data/lib/aidp/harness/usage_limit.rb +179 -0
  61. data/lib/aidp/harness/usage_limit_enforcer.rb +240 -0
  62. data/lib/aidp/harness/usage_limit_tracker.rb +308 -0
  63. data/lib/aidp/harness/usage_period.rb +234 -0
  64. data/lib/aidp/init/agent_instructions_generator.rb +317 -0
  65. data/lib/aidp/init/runner.rb +25 -4
  66. data/lib/aidp/interfaces/activity_monitor_interface.rb +234 -0
  67. data/lib/aidp/interfaces/binary_checker_interface.rb +232 -0
  68. data/lib/aidp/interfaces/command_executor_interface.rb +216 -0
  69. data/lib/aidp/interfaces/logger_interface.rb +150 -0
  70. data/lib/aidp/interfaces/ui_interface.rb +254 -0
  71. data/lib/aidp/logger.rb +25 -7
  72. data/lib/aidp/orchestration_adapter.rb +279 -0
  73. data/lib/aidp/pr_worktree_manager.rb +4 -15
  74. data/lib/aidp/prompts/feedback_collector.rb +198 -0
  75. data/lib/aidp/prompts/prompt_template_manager.rb +415 -0
  76. data/lib/aidp/prompts/template_evolver.rb +305 -0
  77. data/lib/aidp/prompts/template_version_manager.rb +325 -0
  78. data/lib/aidp/setup/in_memory_config_adapter.rb +257 -0
  79. data/lib/aidp/setup/in_memory_config_manager.rb +262 -0
  80. data/lib/aidp/setup/wizard.rb +616 -176
  81. data/lib/aidp/shell_executor.rb +58 -0
  82. data/lib/aidp/style_guide/selector.rb +56 -1
  83. data/lib/aidp/temporal/activities/analyze_issue_activity.rb +198 -0
  84. data/lib/aidp/temporal/activities/analyze_sub_task_activity.rb +163 -0
  85. data/lib/aidp/temporal/activities/base_activity.rb +78 -0
  86. data/lib/aidp/temporal/activities/create_plan_activity.rb +115 -0
  87. data/lib/aidp/temporal/activities/create_pr_activity.rb +193 -0
  88. data/lib/aidp/temporal/activities/create_prompt_activity.rb +118 -0
  89. data/lib/aidp/temporal/activities/diagnose_failure_activity.rb +228 -0
  90. data/lib/aidp/temporal/activities/prepare_next_iteration_activity.rb +147 -0
  91. data/lib/aidp/temporal/activities/record_checkpoint_activity.rb +81 -0
  92. data/lib/aidp/temporal/activities/run_agent_activity.rb +139 -0
  93. data/lib/aidp/temporal/activities/run_tests_activity.rb +114 -0
  94. data/lib/aidp/temporal/activities/run_work_loop_iteration_activity.rb +249 -0
  95. data/lib/aidp/temporal/configuration.rb +169 -0
  96. data/lib/aidp/temporal/connection.rb +93 -0
  97. data/lib/aidp/temporal/worker.rb +119 -0
  98. data/lib/aidp/temporal/workflow_client.rb +171 -0
  99. data/lib/aidp/temporal/workflows/base_workflow.rb +73 -0
  100. data/lib/aidp/temporal/workflows/issue_to_pr_workflow.rb +278 -0
  101. data/lib/aidp/temporal/workflows/sub_issue_workflow.rb +253 -0
  102. data/lib/aidp/temporal/workflows/work_loop_workflow.rb +321 -0
  103. data/lib/aidp/temporal.rb +120 -0
  104. data/lib/aidp/version.rb +1 -1
  105. data/lib/aidp/watch/base_processor.rb +35 -0
  106. data/lib/aidp/watch/build_processor.rb +132 -0
  107. data/lib/aidp/watch/github_state_extractor.rb +0 -8
  108. data/lib/aidp/watch/rebase_processor.rb +245 -0
  109. data/lib/aidp/watch/round_robin_scheduler.rb +150 -0
  110. data/lib/aidp/watch/runner.rb +366 -285
  111. data/lib/aidp/watch/state_store.rb +80 -0
  112. data/lib/aidp/watch/work_item.rb +96 -0
  113. data/lib/aidp/watch/worktree_cleanup_job.rb +226 -0
  114. data/lib/aidp/watch/worktree_reconciler.rb +643 -0
  115. data/lib/aidp/workflows/guided_agent.rb +1 -1
  116. data/lib/aidp/worktree.rb +62 -0
  117. data/templates/aidp.yml.example +70 -0
  118. metadata +117 -16
  119. data/lib/aidp/analyze/json_file_storage.rb +0 -292
  120. data/lib/aidp/execute/future_work_backlog.rb +0 -411
  121. data/lib/aidp/providers/adapter.rb +0 -239
  122. data/lib/aidp/providers/aider.rb +0 -264
  123. data/lib/aidp/providers/anthropic.rb +0 -614
  124. data/lib/aidp/providers/base.rb +0 -617
  125. data/lib/aidp/providers/capability_registry.rb +0 -204
  126. data/lib/aidp/providers/codex.rb +0 -267
  127. data/lib/aidp/providers/cursor.rb +0 -304
  128. data/lib/aidp/providers/error_taxonomy.rb +0 -195
  129. data/lib/aidp/providers/gemini.rb +0 -110
  130. data/lib/aidp/providers/github_copilot.rb +0 -227
  131. data/lib/aidp/providers/kilocode.rb +0 -157
  132. data/lib/aidp/providers/opencode.rb +0 -139
@@ -0,0 +1,278 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "temporalio/workflow"
4
+ require_relative "base_workflow"
5
+
6
+ module Aidp
7
+ module Temporal
8
+ module Workflows
9
+ # Workflow that orchestrates the full issue-to-PR pipeline
10
+ # Handles: issue analysis, planning, implementation, testing, and PR creation
11
+ #
12
+ # State machine:
13
+ # INIT → ANALYZE → PLAN → IMPLEMENT → TEST → {PASS → CREATE_PR | FAIL → IMPLEMENT} → COMPLETE
14
+ class IssueToPrWorkflow < BaseWorkflow
15
+ # Query handlers for workflow state
16
+ workflow_query
17
+ def current_state
18
+ @state
19
+ end
20
+
21
+ workflow_query
22
+ def iteration_count
23
+ @iteration
24
+ end
25
+
26
+ workflow_query
27
+ def progress
28
+ {
29
+ state: @state,
30
+ iteration: @iteration,
31
+ max_iterations: @max_iterations,
32
+ issue_number: @issue_number,
33
+ started_at: @started_at,
34
+ last_activity: @last_activity
35
+ }
36
+ end
37
+
38
+ # Signal handlers for external control
39
+ workflow_signal
40
+ def pause
41
+ @paused = true
42
+ log_workflow("paused")
43
+ end
44
+
45
+ workflow_signal
46
+ def resume
47
+ @paused = false
48
+ log_workflow("resumed")
49
+ end
50
+
51
+ workflow_signal
52
+ def inject_instruction(instruction)
53
+ @injected_instructions ||= []
54
+ @injected_instructions << instruction
55
+ log_workflow("instruction_injected", instruction_length: instruction.length)
56
+ end
57
+
58
+ # Main workflow execution
59
+ def execute(input)
60
+ initialize_state(input)
61
+ log_workflow("started",
62
+ issue_number: @issue_number,
63
+ project_dir: @project_dir,
64
+ max_iterations: @max_iterations)
65
+
66
+ begin
67
+ # Phase 1: Analyze the issue
68
+ transition_to(:analyzing)
69
+ analysis = run_analysis_phase
70
+
71
+ return build_error_result("Analysis failed") unless analysis[:success]
72
+
73
+ # Phase 2: Create implementation plan
74
+ transition_to(:planning)
75
+ plan = run_planning_phase(analysis)
76
+
77
+ return build_error_result("Planning failed") unless plan[:success]
78
+
79
+ # Phase 3: Implementation loop (fix-forward pattern)
80
+ transition_to(:implementing)
81
+ implementation = run_implementation_loop(plan)
82
+
83
+ return build_error_result("Implementation failed: max iterations reached") unless implementation[:success]
84
+
85
+ # Phase 4: Create PR
86
+ transition_to(:creating_pr)
87
+ pr_result = run_create_pr_phase(implementation)
88
+
89
+ transition_to(:completed)
90
+ build_success_result(pr_result)
91
+ rescue Temporalio::Error::CanceledError
92
+ log_workflow("canceled", state: @state, iteration: @iteration)
93
+ transition_to(:canceled)
94
+ build_canceled_result
95
+ end
96
+ end
97
+
98
+ private
99
+
100
+ def initialize_state(input)
101
+ @project_dir = input[:project_dir]
102
+ @issue_number = input[:issue_number]
103
+ @issue_url = input[:issue_url]
104
+ @max_iterations = input[:max_iterations] || 50
105
+ @options = input[:options] || {}
106
+
107
+ @state = :init
108
+ @iteration = 0
109
+ @paused = false
110
+ @started_at = Time.now.iso8601
111
+ @last_activity = nil
112
+ @injected_instructions = []
113
+ end
114
+
115
+ def transition_to(new_state)
116
+ old_state = @state
117
+ @state = new_state
118
+ log_workflow("state_transition", from: old_state, to: new_state)
119
+ end
120
+
121
+ def run_analysis_phase
122
+ @last_activity = :analyze_issue
123
+
124
+ result = Temporalio::Workflow.execute_activity(
125
+ Activities::AnalyzeIssueActivity,
126
+ {
127
+ project_dir: @project_dir,
128
+ issue_number: @issue_number,
129
+ issue_url: @issue_url
130
+ },
131
+ **activity_options(start_to_close_timeout: 300)
132
+ )
133
+
134
+ log_workflow("analysis_complete", success: result[:success])
135
+ result
136
+ end
137
+
138
+ def run_planning_phase(analysis)
139
+ @last_activity = :create_plan
140
+
141
+ result = Temporalio::Workflow.execute_activity(
142
+ Activities::CreatePlanActivity,
143
+ {
144
+ project_dir: @project_dir,
145
+ issue_number: @issue_number,
146
+ analysis: analysis[:result]
147
+ },
148
+ **activity_options(start_to_close_timeout: 300)
149
+ )
150
+
151
+ log_workflow("planning_complete", success: result[:success])
152
+ result
153
+ end
154
+
155
+ def run_implementation_loop(plan)
156
+ loop do
157
+ # Check for pause signal
158
+ while @paused
159
+ workflow_sleep(1)
160
+ end
161
+
162
+ # Check for cancellation
163
+ return build_canceled_result if cancellation_requested?
164
+
165
+ @iteration += 1
166
+ log_workflow("implementation_iteration", iteration: @iteration, max: @max_iterations)
167
+
168
+ if @iteration > @max_iterations
169
+ return {success: false, reason: "max_iterations_exceeded", iteration: @iteration}
170
+ end
171
+
172
+ # Run single implementation iteration
173
+ @last_activity = :run_work_loop_iteration
174
+
175
+ iteration_input = {
176
+ project_dir: @project_dir,
177
+ issue_number: @issue_number,
178
+ plan: plan[:result],
179
+ iteration: @iteration,
180
+ injected_instructions: drain_injected_instructions
181
+ }
182
+
183
+ result = Temporalio::Workflow.execute_activity(
184
+ Activities::RunWorkLoopIterationActivity,
185
+ iteration_input,
186
+ **activity_options(
187
+ start_to_close_timeout: 900, # 15 minutes per iteration
188
+ heartbeat_timeout: 120 # 2 minute heartbeat
189
+ )
190
+ )
191
+
192
+ log_workflow("iteration_complete",
193
+ iteration: @iteration,
194
+ success: result[:success],
195
+ tests_passing: result[:tests_passing])
196
+
197
+ # Check completion
198
+ if result[:success] && result[:tests_passing]
199
+ return {
200
+ success: true,
201
+ iterations: @iteration,
202
+ result: result[:result]
203
+ }
204
+ end
205
+
206
+ # Continue to next iteration (fix-forward)
207
+ end
208
+ end
209
+
210
+ def run_create_pr_phase(implementation)
211
+ @last_activity = :create_pr
212
+
213
+ result = Temporalio::Workflow.execute_activity(
214
+ Activities::CreatePrActivity,
215
+ {
216
+ project_dir: @project_dir,
217
+ issue_number: @issue_number,
218
+ implementation: implementation[:result],
219
+ iterations: implementation[:iterations]
220
+ },
221
+ **activity_options(start_to_close_timeout: 300)
222
+ )
223
+
224
+ log_workflow("pr_created",
225
+ success: result[:success],
226
+ pr_url: result[:pr_url])
227
+
228
+ result
229
+ end
230
+
231
+ def drain_injected_instructions
232
+ instructions = @injected_instructions.dup
233
+ @injected_instructions.clear
234
+ instructions
235
+ end
236
+
237
+ def activity_options(overrides = {})
238
+ self.class.activity_options(overrides)
239
+ end
240
+
241
+ def build_success_result(pr_result)
242
+ {
243
+ status: "completed",
244
+ issue_number: @issue_number,
245
+ pr_url: pr_result[:pr_url],
246
+ pr_number: pr_result[:pr_number],
247
+ iterations: @iteration,
248
+ started_at: @started_at,
249
+ completed_at: Time.now.iso8601
250
+ }
251
+ end
252
+
253
+ def build_error_result(message)
254
+ {
255
+ status: "error",
256
+ issue_number: @issue_number,
257
+ error: message,
258
+ state: @state,
259
+ iteration: @iteration,
260
+ started_at: @started_at,
261
+ completed_at: Time.now.iso8601
262
+ }
263
+ end
264
+
265
+ def build_canceled_result
266
+ {
267
+ status: "canceled",
268
+ issue_number: @issue_number,
269
+ state: @state,
270
+ iteration: @iteration,
271
+ started_at: @started_at,
272
+ completed_at: Time.now.iso8601
273
+ }
274
+ end
275
+ end
276
+ end
277
+ end
278
+ end
@@ -0,0 +1,253 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "temporalio/workflow"
4
+ require_relative "base_workflow"
5
+
6
+ module Aidp
7
+ module Temporal
8
+ module Workflows
9
+ # Child workflow for handling decomposed sub-tasks
10
+ # Supports recursive decomposition when a task is too large
11
+ #
12
+ # Used by IssueToPrWorkflow to break down complex issues
13
+ # into smaller, manageable sub-tasks executed in parallel
14
+ class SubIssueWorkflow < BaseWorkflow
15
+ # Maximum depth for recursive decomposition
16
+ MAX_RECURSION_DEPTH = 3
17
+
18
+ # Query handlers
19
+ workflow_query
20
+ def current_state
21
+ @state
22
+ end
23
+
24
+ workflow_query
25
+ def progress
26
+ {
27
+ state: @state,
28
+ sub_issue_id: @sub_issue_id,
29
+ parent_workflow_id: @parent_workflow_id,
30
+ depth: @depth,
31
+ iteration: @iteration,
32
+ started_at: @started_at
33
+ }
34
+ end
35
+
36
+ # Signal handlers
37
+ workflow_signal
38
+ def pause
39
+ @paused = true
40
+ log_workflow("paused")
41
+ end
42
+
43
+ workflow_signal
44
+ def resume
45
+ @paused = false
46
+ log_workflow("resumed")
47
+ end
48
+
49
+ # Main workflow execution
50
+ def execute(input)
51
+ initialize_state(input)
52
+ log_workflow("started",
53
+ sub_issue_id: @sub_issue_id,
54
+ depth: @depth,
55
+ parent: @parent_workflow_id)
56
+
57
+ # Check recursion depth limit
58
+ if @depth >= MAX_RECURSION_DEPTH
59
+ log_workflow("max_depth_reached", depth: @depth)
60
+ return build_error_result("Maximum recursion depth reached")
61
+ end
62
+
63
+ begin
64
+ # Analyze the sub-task
65
+ transition_to(:analyzing)
66
+ analysis = analyze_sub_task
67
+
68
+ return build_error_result("Analysis failed") unless analysis[:success]
69
+
70
+ # Check if further decomposition needed
71
+ if needs_decomposition?(analysis)
72
+ transition_to(:decomposing)
73
+ result = execute_child_workflows(analysis)
74
+ else
75
+ # Execute directly
76
+ transition_to(:implementing)
77
+ result = execute_implementation(analysis)
78
+ end
79
+
80
+ transition_to(:completed)
81
+ build_success_result(result)
82
+ rescue Temporalio::Error::CanceledError
83
+ log_workflow("canceled", state: @state)
84
+ transition_to(:canceled)
85
+ build_canceled_result
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def initialize_state(input)
92
+ @project_dir = input[:project_dir]
93
+ @sub_issue_id = input[:sub_issue_id]
94
+ @task_description = input[:task_description]
95
+ @context = input[:context] || {}
96
+ @parent_workflow_id = input[:parent_workflow_id]
97
+ @depth = input[:depth] || 0
98
+ @max_iterations = input[:max_iterations] || 20
99
+
100
+ @state = :init
101
+ @iteration = 0
102
+ @paused = false
103
+ @started_at = Time.now.iso8601
104
+ end
105
+
106
+ def transition_to(new_state)
107
+ old_state = @state
108
+ @state = new_state
109
+ log_workflow("state_transition", from: old_state, to: new_state)
110
+ end
111
+
112
+ def analyze_sub_task
113
+ Temporalio::Workflow.execute_activity(
114
+ Activities::AnalyzeSubTaskActivity,
115
+ {
116
+ project_dir: @project_dir,
117
+ sub_issue_id: @sub_issue_id,
118
+ task_description: @task_description,
119
+ context: @context
120
+ },
121
+ **activity_options(start_to_close_timeout: 120)
122
+ )
123
+ end
124
+
125
+ def needs_decomposition?(analysis)
126
+ # Heuristics for when to decompose further
127
+ result = analysis[:result] || {}
128
+
129
+ # Check estimated complexity
130
+ estimated_iterations = result[:estimated_iterations] || 0
131
+ return true if estimated_iterations > @max_iterations
132
+
133
+ # Check if multiple independent tasks identified
134
+ sub_tasks = result[:sub_tasks] || []
135
+ return true if sub_tasks.length >= 3
136
+
137
+ false
138
+ end
139
+
140
+ def execute_child_workflows(analysis)
141
+ sub_tasks = analysis[:result][:sub_tasks] || []
142
+
143
+ log_workflow("spawning_children",
144
+ count: sub_tasks.length,
145
+ depth: @depth + 1)
146
+
147
+ # Start child workflows in parallel
148
+ child_handles = sub_tasks.map.with_index do |task, idx|
149
+ child_id = "#{@sub_issue_id}_sub_#{idx}"
150
+
151
+ Temporalio::Workflow.execute_child_workflow(
152
+ SubIssueWorkflow,
153
+ {
154
+ project_dir: @project_dir,
155
+ sub_issue_id: child_id,
156
+ task_description: task[:description],
157
+ context: @context.merge(parent_task: @task_description),
158
+ parent_workflow_id: workflow_info.workflow_id,
159
+ depth: @depth + 1,
160
+ max_iterations: task[:estimated_iterations] || 10
161
+ },
162
+ id: child_id,
163
+ **child_workflow_options
164
+ )
165
+ end
166
+
167
+ # Wait for all children to complete
168
+ results = child_handles.map(&:result)
169
+
170
+ # Aggregate results
171
+ {
172
+ strategy: :decomposed,
173
+ child_count: results.length,
174
+ all_successful: results.all? { |r| r[:status] == "completed" },
175
+ child_results: results
176
+ }
177
+ end
178
+
179
+ def execute_implementation(analysis)
180
+ # Create work loop for this sub-task
181
+ work_loop_result = Temporalio::Workflow.execute_child_workflow(
182
+ WorkLoopWorkflow,
183
+ {
184
+ project_dir: @project_dir,
185
+ step_name: "sub_issue_#{@sub_issue_id}",
186
+ step_spec: {
187
+ description: @task_description
188
+ },
189
+ context: @context.merge(analysis: analysis[:result]),
190
+ max_iterations: @max_iterations
191
+ },
192
+ id: "workloop_#{@sub_issue_id}",
193
+ **child_workflow_options
194
+ ).result
195
+
196
+ {
197
+ strategy: :direct,
198
+ work_loop_result: work_loop_result
199
+ }
200
+ end
201
+
202
+ def activity_options(overrides = {})
203
+ self.class.activity_options(overrides)
204
+ end
205
+
206
+ def child_workflow_options
207
+ {
208
+ task_queue: Temporalio::Workflow.info.task_queue,
209
+ execution_timeout: 3600, # 1 hour per child
210
+ retry_policy: build_retry_policy(
211
+ initial_interval: 1,
212
+ maximum_attempts: 2
213
+ )
214
+ }
215
+ end
216
+
217
+ def build_success_result(result)
218
+ {
219
+ status: "completed",
220
+ sub_issue_id: @sub_issue_id,
221
+ depth: @depth,
222
+ result: result,
223
+ started_at: @started_at,
224
+ completed_at: Time.now.iso8601
225
+ }
226
+ end
227
+
228
+ def build_error_result(message)
229
+ {
230
+ status: "error",
231
+ sub_issue_id: @sub_issue_id,
232
+ depth: @depth,
233
+ error: message,
234
+ state: @state,
235
+ started_at: @started_at,
236
+ completed_at: Time.now.iso8601
237
+ }
238
+ end
239
+
240
+ def build_canceled_result
241
+ {
242
+ status: "canceled",
243
+ sub_issue_id: @sub_issue_id,
244
+ depth: @depth,
245
+ state: @state,
246
+ started_at: @started_at,
247
+ completed_at: Time.now.iso8601
248
+ }
249
+ end
250
+ end
251
+ end
252
+ end
253
+ end