@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.
- package/bin/agent-relay-broker-darwin-arm64 +0 -0
- package/bin/agent-relay-broker-darwin-x64 +0 -0
- package/bin/agent-relay-broker-linux-arm64 +0 -0
- package/bin/agent-relay-broker-linux-x64 +0 -0
- package/bin/agent-relay-broker-win32-x64.exe +0 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +25 -5
- package/dist/client.js.map +1 -1
- package/dist/examples/persona-spawn.d.ts +2 -0
- package/dist/examples/persona-spawn.d.ts.map +1 -0
- package/dist/examples/persona-spawn.js +44 -0
- package/dist/examples/persona-spawn.js.map +1 -0
- package/dist/github.d.ts +9 -1
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +9 -1
- package/dist/github.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/personas.d.ts +160 -0
- package/dist/personas.d.ts.map +1 -0
- package/dist/personas.js +401 -0
- package/dist/personas.js.map +1 -0
- package/dist/relay.d.ts +76 -6
- package/dist/relay.d.ts.map +1 -1
- package/dist/relay.js +82 -1
- package/dist/relay.js.map +1 -1
- package/dist/types.d.ts +21 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/workflows/__tests__/workflow-reliability-contract.test.d.ts +2 -0
- package/dist/workflows/__tests__/workflow-reliability-contract.test.d.ts.map +1 -0
- package/dist/workflows/__tests__/workflow-reliability-contract.test.js +337 -0
- package/dist/workflows/__tests__/workflow-reliability-contract.test.js.map +1 -0
- package/dist/workflows/builder.d.ts +2 -0
- package/dist/workflows/builder.d.ts.map +1 -1
- package/dist/workflows/builder.js +4 -0
- package/dist/workflows/builder.js.map +1 -1
- package/dist/workflows/runner.d.ts +4 -0
- package/dist/workflows/runner.d.ts.map +1 -1
- package/dist/workflows/runner.js +151 -3
- package/dist/workflows/runner.js.map +1 -1
- package/dist/workflows/types.d.ts +4 -0
- package/dist/workflows/types.d.ts.map +1 -1
- package/package.json +18 -11
package/dist/workflows/runner.js
CHANGED
|
@@ -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
|
|
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.
|