|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +class Agent |
| 4 | + # Agent::ArtifactRepair — persisted artifact repair flow with bounded retry budget. |
| 5 | + module ArtifactRepair |
| 6 | + private |
| 7 | + |
| 8 | + def _repair_persisted_artifact( |
| 9 | + method_name:, |
| 10 | + args:, |
| 11 | + kwargs:, |
| 12 | + persisted_artifact:, |
| 13 | + failure_class:, |
| 14 | + failure_message:, |
| 15 | + state: |
| 16 | + ) |
| 17 | + return nil unless _toolstore_repair_enabled? |
| 18 | + return nil unless _artifact_repair_budget_available?(persisted_artifact) |
| 19 | + |
| 20 | + state.repair_attempted = true |
| 21 | + repair_user_prompt = _artifact_repair_user_prompt( |
| 22 | + method_name: method_name, |
| 23 | + args: args, |
| 24 | + kwargs: kwargs, |
| 25 | + persisted_artifact: persisted_artifact, |
| 26 | + failure_class: failure_class, |
| 27 | + failure_message: failure_message |
| 28 | + ) |
| 29 | + repair_system_prompt = _build_system_prompt(call_context: _call_stack.last) |
| 30 | + |
| 31 | + repaired_program, state.generation_attempt = _generate_program_with_retry( |
| 32 | + method_name, |
| 33 | + repair_system_prompt, |
| 34 | + repair_user_prompt |
| 35 | + ) |
| 36 | + _capture_generated_program_state!(state, repaired_program) |
| 37 | + _mark_repaired_program_state!(state, trigger: _repair_trigger_for(failure_class)) |
| 38 | + environment_info = _prepare_dependency_environment!( |
| 39 | + method_name: method_name, |
| 40 | + normalized_dependencies: state.normalized_dependencies |
| 41 | + ) |
| 42 | + _capture_environment_state!(state, environment_info) |
| 43 | + |
| 44 | + _execute_generated_program( |
| 45 | + method_name, |
| 46 | + state.code, |
| 47 | + args, |
| 48 | + kwargs, |
| 49 | + normalized_dependencies: state.normalized_dependencies, |
| 50 | + environment_info: environment_info, |
| 51 | + state: state |
| 52 | + ) |
| 53 | + rescue ProviderError, ExecutionError, WorkerCrashError, NonSerializableResultError, |
| 54 | + InvalidDependencyManifestError, DependencyManifestIncompatibleError, |
| 55 | + DependencyPolicyViolationError, DependencyResolutionError, |
| 56 | + DependencyInstallError, DependencyActivationError => e |
| 57 | + warn "[AGENT REPAIR #{@role}.#{method_name}] repair attempt failed: #{e.class}: #{e.message}" if @debug |
| 58 | + nil |
| 59 | + end |
| 60 | + |
| 61 | + def _artifact_repair_budget_available?(artifact) |
| 62 | + repair_count = artifact.fetch("repair_count_since_regen", 0).to_i |
| 63 | + repair_count < Agent::MAX_REPAIRS_BEFORE_REGEN |
| 64 | + end |
| 65 | + |
| 66 | + def _repair_trigger_for(failure_class) |
| 67 | + case failure_class |
| 68 | + when "adaptive" |
| 69 | + "repair:adaptive_failure" |
| 70 | + when "intrinsic" |
| 71 | + "repair:intrinsic_failure" |
| 72 | + else |
| 73 | + "repair:unknown_failure" |
| 74 | + end |
| 75 | + end |
| 76 | + |
| 77 | + def _artifact_repair_user_prompt(method_name:, args:, kwargs:, persisted_artifact:, failure_class:, failure_message:) |
| 78 | + <<~PROMPT |
| 79 | + <repair_invocation> |
| 80 | + <method>#{method_name}</method> |
| 81 | + <args>#{args.inspect}</args> |
| 82 | + <kwargs>#{kwargs.inspect}</kwargs> |
| 83 | + <failure_class>#{failure_class}</failure_class> |
| 84 | + <failure_message>#{failure_message}</failure_message> |
| 85 | + <existing_code> |
| 86 | + #{persisted_artifact.fetch("code", "")} |
| 87 | + </existing_code> |
| 88 | + <artifact_metadata> |
| 89 | + <prompt_version>#{persisted_artifact["prompt_version"]}</prompt_version> |
| 90 | + <contract_fingerprint>#{persisted_artifact["contract_fingerprint"]}</contract_fingerprint> |
| 91 | + </artifact_metadata> |
| 92 | + </repair_invocation> |
| 93 | +
|
| 94 | + <repair_goal> |
| 95 | + Repair this existing method implementation. Preserve intent and contract compatibility. |
| 96 | + Do not invent new capabilities. Ensure returned code executes for the provided args/kwargs. |
| 97 | + </repair_goal> |
| 98 | +
|
| 99 | + <response_contract> |
| 100 | + - Return a GeneratedProgram payload with `code` and optional `dependencies`. |
| 101 | + - Set `result` to the raw domain value, or use `return` in generated code. |
| 102 | + </response_contract> |
| 103 | + PROMPT |
| 104 | + end |
| 105 | + end |
| 106 | +end |
0 commit comments