diff --git a/package-lock.json b/package-lock.json index 3297ce9..9f21c39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -171,7 +171,9 @@ } }, "node_modules/@agentworkforce/persona-kit": { - "version": "4.1.38", + "version": "4.1.39", + "resolved": "https://registry.npmjs.org/@agentworkforce/persona-kit/-/persona-kit-4.1.39.tgz", + "integrity": "sha512-65JuQlACfMipKbpq81xW9DxCPcyJcemiT4tHOcC/86phhy+Y6eojX3wOLN9xWa8Cr/KnFRmERTOYjA8tR3RSIw==", "dependencies": { "@relaycast/a2a": "^6.2.0", "@relayfile/adapter-core": "^0.5.1", @@ -179,16 +181,20 @@ } }, "node_modules/@agentworkforce/persona-registry": { - "version": "4.1.38", + "version": "4.1.39", + "resolved": "https://registry.npmjs.org/@agentworkforce/persona-registry/-/persona-registry-4.1.39.tgz", + "integrity": "sha512-MrcAfACx04zFm0a2gLQ3IM6/xnuGKmRp5KdPbMfRuCbHYBx+JlbI47ETA+7qJkFHGCrYkAPpDlEOQO06PFJiug==", "dependencies": { - "@agentworkforce/persona-kit": "4.1.38", - "@agentworkforce/workload-router": "4.1.38" + "@agentworkforce/persona-kit": "4.1.39", + "@agentworkforce/workload-router": "4.1.39" } }, "node_modules/@agentworkforce/workload-router": { - "version": "4.1.38", + "version": "4.1.39", + "resolved": "https://registry.npmjs.org/@agentworkforce/workload-router/-/workload-router-4.1.39.tgz", + "integrity": "sha512-H+0P911TfRzIOScSzmld7fLz0Sp4gZ2hqsPVPBrjpdNKwwGKw+5Gd9owY+yDjgneFwp1rQtBKeBej5bsQQfv3A==", "dependencies": { - "@agentworkforce/persona-kit": "4.1.38" + "@agentworkforce/persona-kit": "4.1.39" } }, "node_modules/@aws-crypto/crc32": { @@ -5308,8 +5314,8 @@ "@agent-relay/harness-driver": "^8.2.0", "@agent-relay/harnesses": "^8.2.0", "@agent-relay/sdk": "^8.2.0", - "@agentworkforce/persona-kit": "^4.1.38", - "@agentworkforce/persona-registry": "^4.1.38", + "@agentworkforce/persona-kit": "^4.1.39", + "@agentworkforce/persona-registry": "^4.1.39", "@relaycast/sdk": "^1.1.0", "@relayfile/sdk": "^0.8.0", "@relayflows/browser-primitive": "1.0.5", diff --git a/packages/core/package.json b/packages/core/package.json index d845471..115dfc0 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -57,8 +57,8 @@ "@agent-relay/harness-driver": "^8.2.0", "@agent-relay/harnesses": "^8.2.0", "@agent-relay/sdk": "^8.2.0", - "@agentworkforce/persona-kit": "^4.1.38", - "@agentworkforce/persona-registry": "^4.1.38", + "@agentworkforce/persona-kit": "^4.1.39", + "@agentworkforce/persona-registry": "^4.1.39", "@relaycast/sdk": "^1.1.0", "@relayfile/sdk": "^0.8.0", "@relayflows/browser-primitive": "1.0.5", diff --git a/packages/core/src/__tests__/e2e-owner-review.test.ts b/packages/core/src/__tests__/e2e-owner-review.test.ts index 4ca6409..c27781f 100644 --- a/packages/core/src/__tests__/e2e-owner-review.test.ts +++ b/packages/core/src/__tests__/e2e-owner-review.test.ts @@ -629,7 +629,9 @@ describe('PR #511 E2E: Auto Step Owner + Review Gating', () => { const spawnResults = (mockRelayInstance.spawnPty as any).mock.results; const reviewAgent = await spawnResults[spawnResults.length - 1].value; - expect(reviewAgent.waitForExit).toHaveBeenCalledWith(600_000); + const [[reviewWaitMs]] = reviewAgent.waitForExit.mock.calls; + expect(reviewWaitMs).toBeGreaterThanOrEqual(599_000); + expect(reviewWaitMs).toBeLessThanOrEqual(600_000); }, 15000); }); diff --git a/packages/core/src/__tests__/workflow-runner.test.ts b/packages/core/src/__tests__/workflow-runner.test.ts index fab2b20..0c336da 100644 --- a/packages/core/src/__tests__/workflow-runner.test.ts +++ b/packages/core/src/__tests__/workflow-runner.test.ts @@ -555,6 +555,7 @@ agents: agent: 'integration-expert', task: 'Fix the failed sync', timeoutMs: 1, + retries: 0, }, ], }, diff --git a/packages/core/src/builder.ts b/packages/core/src/builder.ts index 75a1acc..948a5c3 100644 --- a/packages/core/src/builder.ts +++ b/packages/core/src/builder.ts @@ -5,6 +5,7 @@ import type { RuntimeSpawnOptions } from '@agent-relay/harness-driver'; import type { AgentCli, AgentCredentialConfig, + AgentConstraints, AgentDefinition, AgentPermissions, AgentPreset, @@ -332,11 +333,11 @@ export class WorkflowBuilder { /** Add an agent definition. */ agent(name: string, options: AgentOptions): this { - const def: AgentDefinition = { + const def = { name, ...(options.cli ? { cli: options.cli } : {}), ...(options.persona ? { persona: options.persona } : {}), - }; + } as AgentDefinition; if (options.role !== undefined) def.role = options.role; if (options.task !== undefined) def.task = options.task; @@ -362,13 +363,14 @@ export class WorkflowBuilder { options.retries !== undefined || options.idleThresholdSecs !== undefined ) { - def.constraints = {}; - if (options.model !== undefined) def.constraints.model = options.model; - if (options.maxTokens !== undefined) def.constraints.maxTokens = options.maxTokens; - if (options.timeoutMs !== undefined) def.constraints.timeoutMs = options.timeoutMs; - if (options.retries !== undefined) def.constraints.retries = options.retries; + const constraints: AgentConstraints = {}; + if (options.model !== undefined) constraints.model = options.model; + if (options.maxTokens !== undefined) constraints.maxTokens = options.maxTokens; + if (options.timeoutMs !== undefined) constraints.timeoutMs = options.timeoutMs; + if (options.retries !== undefined) constraints.retries = options.retries; if (options.idleThresholdSecs !== undefined) - def.constraints.idleThresholdSecs = options.idleThresholdSecs; + constraints.idleThresholdSecs = options.idleThresholdSecs; + def.constraints = constraints; } this._agents.push(def); diff --git a/packages/core/src/persona-runtime.ts b/packages/core/src/persona-runtime.ts index 7b28153..27297d1 100644 --- a/packages/core/src/persona-runtime.ts +++ b/packages/core/src/persona-runtime.ts @@ -38,7 +38,7 @@ export function resolveWorkflowPersona(reference: string, cwd: string): Resolved ? built : { ...built, mount: { ignoredPatterns: [], readonlyPatterns: [] } }; const args = plan.initialPrompt ? [...plan.args, plan.initialPrompt] : [...plan.args]; - if (plan.cli === 'api' || !getCliDefinition(plan.cli)) { + if (!getCliDefinition(plan.cli)) { throw new Error( `Persona "${resolved.spec.id}" resolves to unsupported interactive CLI "${plan.cli}"` ); diff --git a/packages/core/src/runner.ts b/packages/core/src/runner.ts index 3e691ef..375f9f2 100644 --- a/packages/core/src/runner.ts +++ b/packages/core/src/runner.ts @@ -2125,7 +2125,7 @@ export class WorkflowRunner { return explicitProvider; } - const model = agentDef.constraints?.model?.trim().toLowerCase() ?? ''; + const model = WorkflowRunner.agentConstraintModel(agentDef)?.trim().toLowerCase() ?? ''; if (model.includes('openrouter')) { return 'openrouter'; } @@ -4566,8 +4566,12 @@ export class WorkflowRunner { } private async runDeterministicRepairAgent(context: DeterministicRepairContext): Promise { - const repairAgent: AgentDefinition = { + if (!context.agentDef.cli) { + throw new Error(`Repair agent "${context.agentDef.name}" must be a raw CLI agent`); + } + const repairAgent: Extract = { ...context.agentDef, + cli: context.agentDef.cli, interactive: false, }; const repairPrompt = this.buildDeterministicRepairPrompt(context); @@ -4661,8 +4665,12 @@ export class WorkflowRunner { } private async runAgentStepRepairAgent(context: AgentStepRepairContext): Promise { - const repairAgent: AgentDefinition = { + if (!context.agentDef.cli) { + throw new Error(`Repair agent "${context.agentDef.name}" must be a raw CLI agent`); + } + const repairAgent: Extract = { ...context.agentDef, + cli: context.agentDef.cli, interactive: false, }; const repairPrompt = this.buildAgentStepRepairPrompt(context); @@ -7056,6 +7064,10 @@ export class WorkflowRunner { return { ...defaults, ...def, cli: resolvedCli } as AgentDefinition; } + private static agentConstraintModel(def: AgentDefinition): string | undefined { + return def.cli ? def.constraints?.model : undefined; + } + /** * Returns a preset-specific prefix that is prepended to the non-interactive * enforcement block in execNonInteractive. @@ -7459,7 +7471,7 @@ export class WorkflowRunner { : undefined; const spawnOptions = { name: agentName, - model: personaResolution?.model ?? agentDef.constraints?.model, + model: personaResolution?.model ?? WorkflowRunner.agentConstraintModel(agentDef), args: personaResolution?.args ?? interactiveSpawnPolicy.args, channels: agentChannels, task: preparedTask.spawnTaskText,