@agent-relay/sdk 6.0.10 → 6.0.12

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 (45) hide show
  1. package/bin/agent-relay-broker-darwin-arm64 +0 -0
  2. package/bin/agent-relay-broker-darwin-x64 +0 -0
  3. package/bin/agent-relay-broker-linux-arm64 +0 -0
  4. package/bin/agent-relay-broker-linux-x64 +0 -0
  5. package/bin/agent-relay-broker-win32-x64.exe +0 -0
  6. package/dist/client.d.ts.map +1 -1
  7. package/dist/client.js +25 -5
  8. package/dist/client.js.map +1 -1
  9. package/dist/examples/persona-spawn.d.ts +2 -0
  10. package/dist/examples/persona-spawn.d.ts.map +1 -0
  11. package/dist/examples/persona-spawn.js +44 -0
  12. package/dist/examples/persona-spawn.js.map +1 -0
  13. package/dist/github.d.ts +9 -1
  14. package/dist/github.d.ts.map +1 -1
  15. package/dist/github.js +9 -1
  16. package/dist/github.js.map +1 -1
  17. package/dist/index.d.ts +3 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +3 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/personas.d.ts +160 -0
  22. package/dist/personas.d.ts.map +1 -0
  23. package/dist/personas.js +401 -0
  24. package/dist/personas.js.map +1 -0
  25. package/dist/relay.d.ts +76 -6
  26. package/dist/relay.d.ts.map +1 -1
  27. package/dist/relay.js +82 -1
  28. package/dist/relay.js.map +1 -1
  29. package/dist/types.d.ts +21 -6
  30. package/dist/types.d.ts.map +1 -1
  31. package/dist/workflows/__tests__/workflow-reliability-contract.test.d.ts +2 -0
  32. package/dist/workflows/__tests__/workflow-reliability-contract.test.d.ts.map +1 -0
  33. package/dist/workflows/__tests__/workflow-reliability-contract.test.js +337 -0
  34. package/dist/workflows/__tests__/workflow-reliability-contract.test.js.map +1 -0
  35. package/dist/workflows/builder.d.ts +2 -0
  36. package/dist/workflows/builder.d.ts.map +1 -1
  37. package/dist/workflows/builder.js +4 -0
  38. package/dist/workflows/builder.js.map +1 -1
  39. package/dist/workflows/runner.d.ts +4 -0
  40. package/dist/workflows/runner.d.ts.map +1 -1
  41. package/dist/workflows/runner.js +151 -3
  42. package/dist/workflows/runner.js.map +1 -1
  43. package/dist/workflows/types.d.ts +4 -0
  44. package/dist/workflows/types.d.ts.map +1 -1
  45. package/package.json +18 -11
@@ -2799,7 +2799,7 @@ export class WorkflowRunner {
2799
2799
  async executeStep(step, state, stepStates, agentMap, errorHandling, runId, lifecycle) {
2800
2800
  // Branch: deterministic steps execute shell commands
2801
2801
  if (this.isDeterministicStep(step)) {
2802
- return this.executeDeterministicStep(step, state, stepStates, runId, errorHandling, lifecycle);
2802
+ return this.executeDeterministicStep(step, state, stepStates, agentMap, runId, errorHandling, lifecycle);
2803
2803
  }
2804
2804
  // Branch: worktree steps set up git worktrees
2805
2805
  if (this.isWorktreeStep(step)) {
@@ -2816,13 +2816,20 @@ export class WorkflowRunner {
2816
2816
  * Execute a deterministic step (shell command).
2817
2817
  * Fast, reliable, $0 LLM cost.
2818
2818
  */
2819
- async executeDeterministicStep(step, state, stepStates, runId, errorHandling, lifecycle) {
2820
- const maxRetries = step.retries ?? errorHandling?.maxRetries ?? 0;
2819
+ async executeDeterministicStep(step, state, stepStates, agentMap, runId, errorHandling, lifecycle) {
2820
+ const repairRetries = errorHandling?.strategy === 'retry' ? errorHandling.repairRetries ?? 0 : 0;
2821
+ const repairAgent = repairRetries > 0
2822
+ ? this.resolveDeterministicRepairAgent(step, stepStates, agentMap, errorHandling)
2823
+ : undefined;
2824
+ const maxRetries = step.retries ?? errorHandling?.maxRetries ?? (repairAgent ? repairRetries : 0);
2821
2825
  const retryDelay = errorHandling?.retryDelayMs ?? 1000;
2822
2826
  let lastError = 'Unknown error';
2823
2827
  let lastCompletionReason;
2824
2828
  let lastExitCode;
2825
2829
  let lastExitSignal;
2830
+ let lastResolvedCommand = step.command ?? '';
2831
+ let lastStepCwd = this.cwd;
2832
+ let lastCommandOutput = '';
2826
2833
  const result = await lifecycle.monitorStep(step, state, {
2827
2834
  maxRetries,
2828
2835
  retryDelayMs: retryDelay,
@@ -2835,6 +2842,20 @@ export class WorkflowRunner {
2835
2842
  detail: `Retrying attempt ${attempt + 1}/${total + 1}`,
2836
2843
  raw: { attempt, maxRetries: total },
2837
2844
  });
2845
+ if (repairAgent) {
2846
+ await this.runDeterministicRepairAgent({
2847
+ step,
2848
+ agentDef: repairAgent,
2849
+ attempt,
2850
+ maxRetries: total,
2851
+ command: lastResolvedCommand,
2852
+ cwd: lastStepCwd,
2853
+ error: lastError,
2854
+ output: lastCommandOutput,
2855
+ exitCode: lastExitCode,
2856
+ exitSignal: lastExitSignal,
2857
+ });
2858
+ }
2838
2859
  },
2839
2860
  execute: async () => {
2840
2861
  const stepOutputContext = this.buildStepOutputContext(stepStates, runId);
@@ -2846,12 +2867,15 @@ export class WorkflowRunner {
2846
2867
  return value !== undefined ? String(value) : _match;
2847
2868
  });
2848
2869
  const stepCwd = this.resolveEffectiveCwd(step);
2870
+ lastResolvedCommand = resolvedCommand;
2871
+ lastStepCwd = stepCwd;
2849
2872
  this.beginStepEvidence(step.name, [stepCwd], state.row.startedAt);
2850
2873
  this.log(`[${step.name}] Running: ${resolvedCommand.slice(0, 200)}${resolvedCommand.length > 200 ? '...' : ''}`);
2851
2874
  if (this.executor?.executeDeterministicStep) {
2852
2875
  const executorResult = await this.executor.executeDeterministicStep(step, resolvedCommand, stepCwd);
2853
2876
  lastExitCode = executorResult.exitCode;
2854
2877
  lastExitSignal = undefined;
2878
+ lastCommandOutput = executorResult.output;
2855
2879
  const failOnError = step.failOnError !== false;
2856
2880
  if (failOnError && executorResult.exitCode !== 0) {
2857
2881
  this.log(`[${step.name}] Command failed (exit code ${executorResult.exitCode})`);
@@ -2926,6 +2950,7 @@ export class WorkflowRunner {
2926
2950
  commandStderr = stderr;
2927
2951
  lastExitCode = code ?? undefined;
2928
2952
  lastExitSignal = signal ?? undefined;
2953
+ lastCommandOutput = [stdout, stderr].filter(Boolean).join('\n');
2929
2954
  const failOnError = step.failOnError !== false;
2930
2955
  if (failOnError && code !== 0 && code !== null) {
2931
2956
  this.log(`[${step.name}] Command failed (exit code ${code})`);
@@ -2957,6 +2982,7 @@ export class WorkflowRunner {
2957
2982
  const verificationResult = step.verification
2958
2983
  ? this.runVerification(step.verification, output, step.name)
2959
2984
  : undefined;
2985
+ lastCommandOutput = [commandStdout || output, commandStderr].filter(Boolean).join('\n');
2960
2986
  return {
2961
2987
  output,
2962
2988
  completionReason: verificationResult?.completionReason,
@@ -2989,6 +3015,128 @@ export class WorkflowRunner {
2989
3015
  throw new Error(`Step "${step.name}" failed: ${result.error ?? 'Unknown error'}`);
2990
3016
  }
2991
3017
  }
3018
+ resolveDeterministicRepairAgent(step, stepStates, agentMap, errorHandling) {
3019
+ const explicitName = errorHandling?.repairAgent?.trim();
3020
+ if (explicitName) {
3021
+ const explicitAgent = agentMap.get(explicitName);
3022
+ if (explicitAgent)
3023
+ return WorkflowRunner.resolveAgentDef(explicitAgent);
3024
+ this.log(`[${step.name}] repairAgent "${explicitName}" not found; falling back to workflow agents`);
3025
+ }
3026
+ if (step.agent) {
3027
+ const stepAgent = agentMap.get(step.agent);
3028
+ if (stepAgent)
3029
+ return WorkflowRunner.resolveAgentDef(stepAgent);
3030
+ }
3031
+ for (const dependency of [...(step.dependsOn ?? [])].reverse()) {
3032
+ const dependencyAgent = stepStates.get(dependency)?.row.agentName;
3033
+ if (!dependencyAgent)
3034
+ continue;
3035
+ const agent = agentMap.get(dependencyAgent);
3036
+ if (agent)
3037
+ return WorkflowRunner.resolveAgentDef(agent);
3038
+ }
3039
+ const candidates = [...agentMap.values()].map((agent) => WorkflowRunner.resolveAgentDef(agent));
3040
+ candidates.sort((a, b) => this.scoreRepairAgent(b) - this.scoreRepairAgent(a));
3041
+ return candidates[0];
3042
+ }
3043
+ scoreRepairAgent(agent) {
3044
+ const text = `${agent.name} ${agent.role ?? ''} ${agent.preset ?? ''}`.toLowerCase();
3045
+ let score = 0;
3046
+ if (/\b(repair|fix|implement|implementation|engineer|developer|coder|worker|owner|lead|coordinator)\b/.test(text)) {
3047
+ score += 10;
3048
+ }
3049
+ if (agent.interactive === false || ['worker', 'analyst'].includes(agent.preset ?? '')) {
3050
+ score += 2;
3051
+ }
3052
+ if (/\b(review|reviewer|audit|security|analyst)\b/.test(text)) {
3053
+ score -= 4;
3054
+ }
3055
+ if (agent.permissions?.access === 'readonly') {
3056
+ score -= 20;
3057
+ }
3058
+ return score;
3059
+ }
3060
+ async runDeterministicRepairAgent(context) {
3061
+ const repairAgent = {
3062
+ ...context.agentDef,
3063
+ interactive: false,
3064
+ };
3065
+ const repairPrompt = this.buildDeterministicRepairPrompt(context);
3066
+ const repairStep = {
3067
+ name: `${context.step.name}-repair-${context.attempt}`,
3068
+ type: 'agent',
3069
+ agent: repairAgent.name,
3070
+ task: repairPrompt,
3071
+ cwd: context.cwd,
3072
+ workdir: undefined,
3073
+ retries: 0,
3074
+ };
3075
+ const timeoutMs = repairAgent.constraints?.timeoutMs ?? context.step.timeoutMs ?? this.currentConfig?.swarm?.timeoutMs;
3076
+ this.log(`[${context.step.name}] Deterministic gate failed; asking "${repairAgent.name}" to repair before retry ${context.attempt + 1}/${context.maxRetries + 1}`);
3077
+ this.postToChannel(`**[${context.step.name}]** Deterministic gate failed; assigning repair to \`${repairAgent.name}\``);
3078
+ this.recordStepToolSideEffect(context.step.name, {
3079
+ type: 'custom',
3080
+ detail: `Assigned deterministic gate repair to ${repairAgent.name}`,
3081
+ raw: {
3082
+ repairAgent: repairAgent.name,
3083
+ attempt: context.attempt,
3084
+ maxRetries: context.maxRetries,
3085
+ exitCode: context.exitCode,
3086
+ exitSignal: context.exitSignal,
3087
+ },
3088
+ });
3089
+ try {
3090
+ this.ensureBudgetAllowsSpawn(context.step.name, repairAgent.name);
3091
+ let repairOutput;
3092
+ if (this.executor) {
3093
+ repairOutput = await this.executor.executeAgentStep(repairStep, repairAgent, repairPrompt, timeoutMs);
3094
+ }
3095
+ else if (repairAgent.cli === 'api') {
3096
+ repairOutput = await executeApiStep(repairAgent.constraints?.model ?? 'claude-sonnet-4-20250514', repairPrompt, {
3097
+ envSecrets: this.envSecrets,
3098
+ skills: repairAgent.skills,
3099
+ defaultMaxTokens: repairAgent.constraints?.maxTokens,
3100
+ });
3101
+ }
3102
+ else {
3103
+ const result = await this.execNonInteractive(repairAgent, repairStep, timeoutMs);
3104
+ repairOutput = result.output;
3105
+ }
3106
+ this.recordStepToolSideEffect(context.step.name, {
3107
+ type: 'custom',
3108
+ detail: `Repair agent ${repairAgent.name} completed before deterministic retry`,
3109
+ raw: { repairAgent: repairAgent.name, output: repairOutput.slice(0, 1000) },
3110
+ });
3111
+ }
3112
+ catch (error) {
3113
+ if (error instanceof BudgetExceededError || this.abortController?.signal.aborted) {
3114
+ throw error;
3115
+ }
3116
+ const message = error instanceof Error ? error.message : String(error);
3117
+ this.log(`[${context.step.name}] Repair agent "${repairAgent.name}" failed: ${message}`);
3118
+ this.postToChannel(`**[${context.step.name}]** Repair agent \`${repairAgent.name}\` failed; retrying gate anyway`);
3119
+ this.recordStepToolSideEffect(context.step.name, {
3120
+ type: 'custom',
3121
+ detail: `Repair agent ${repairAgent.name} failed before deterministic retry: ${message}`,
3122
+ raw: { repairAgent: repairAgent.name, error: message },
3123
+ });
3124
+ }
3125
+ }
3126
+ buildDeterministicRepairPrompt(context) {
3127
+ const output = context.output.trim();
3128
+ const clippedOutput = output.length > 4000 ? output.slice(-4000) : output;
3129
+ return (`A deterministic workflow gate failed after an agent/team step. Fix the repository or workflow state so the same gate passes on the next retry.\n\n` +
3130
+ `Step: ${context.step.name}\n` +
3131
+ `Working directory: ${context.cwd}\n` +
3132
+ `Command:\n${context.command}\n\n` +
3133
+ `Failure:\n${context.error}\n` +
3134
+ `Exit code: ${context.exitCode ?? 'unknown'}\n` +
3135
+ `Exit signal: ${context.exitSignal ?? 'none'}\n\n` +
3136
+ `Command output:\n${clippedOutput || '(no output captured)'}\n\n` +
3137
+ `Repair only what is needed for this gate to pass. Preserve unrelated user changes. ` +
3138
+ `After making the fix, report the files changed and the reason the gate should pass.`);
3139
+ }
2992
3140
  /**
2993
3141
  * Execute a worktree step (git worktree setup).
2994
3142
  * Fast, reliable, $0 LLM cost.