diff --git a/crates/fabric-core/src/agent_execution.rs b/crates/fabric-core/src/agent_execution.rs index 7f9780f4c..5f8111c2c 100644 --- a/crates/fabric-core/src/agent_execution.rs +++ b/crates/fabric-core/src/agent_execution.rs @@ -239,7 +239,7 @@ fn agent_run_result_schema(schema: &mut Schema) { "properties": {"status": {"const": "succeeded"}}, "required": ["status"] }, - "then": {"not": {"required": ["error"]}} + "then": {"properties": {"error": {"type": "null"}}} } ]), ); diff --git a/crates/fabric-core/src/schema.rs b/crates/fabric-core/src/schema.rs index 39812e50f..83a399336 100644 --- a/crates/fabric-core/src/schema.rs +++ b/crates/fabric-core/src/schema.rs @@ -447,6 +447,15 @@ mod tests { "output": null, "error": {"code": "target_error", "message": "target failed"} }))); + assert!(validator.is_valid(&serde_json::json!({ + "status": "succeeded", + "output": null + }))); + assert!(validator.is_valid(&serde_json::json!({ + "status": "succeeded", + "output": null, + "error": null + }))); for path in [ " \t", "nested/../output", diff --git a/docs/adapter-contract/results.md b/docs/adapter-contract/results.md index 145245ce0..cde614ff2 100644 --- a/docs/adapter-contract/results.md +++ b/docs/adapter-contract/results.md @@ -31,10 +31,10 @@ Use the generated [`AgentRunResult` JSON Schema](https://github.com/NVIDIA/NeMo-Fabric/blob/main/schemas/adapter-contract/agent-run-result.schema.json) for exact fields and constraints. -A failed result must contain `error`. A succeeded result must not contain -`error`. Do not infer status from arbitrary fields in `output`. Exactly one -terminal result is produced for an invocation, and its status is immutable -once returned. +A failed result must contain `error`. A succeeded result can omit `error` or +set it to `null`; it must not contain a non-null error. Do not infer status +from arbitrary fields in `output`. Exactly one terminal result is produced for +an invocation, and its status is immutable once returned. ## Failure Classes diff --git a/schemas/adapter-contract/agent-run-result.schema.json b/schemas/adapter-contract/agent-run-result.schema.json index c6ac4081e..94704b106 100644 --- a/schemas/adapter-contract/agent-run-result.schema.json +++ b/schemas/adapter-contract/agent-run-result.schema.json @@ -199,10 +199,10 @@ ] }, "then": { - "not": { - "required": [ - "error" - ] + "properties": { + "error": { + "type": "null" + } } } } diff --git a/typescript/adapter-contract/schemas/agent-run-result.schema.json b/typescript/adapter-contract/schemas/agent-run-result.schema.json index c6ac4081e..94704b106 100644 --- a/typescript/adapter-contract/schemas/agent-run-result.schema.json +++ b/typescript/adapter-contract/schemas/agent-run-result.schema.json @@ -199,10 +199,10 @@ ] }, "then": { - "not": { - "required": [ - "error" - ] + "properties": { + "error": { + "type": "null" + } } } } diff --git a/typescript/adapter-contract/scripts/generate.mjs b/typescript/adapter-contract/scripts/generate.mjs index a0a117dac..ef796c27e 100644 --- a/typescript/adapter-contract/scripts/generate.mjs +++ b/typescript/adapter-contract/scripts/generate.mjs @@ -282,10 +282,10 @@ export type AgentRunResult = | AgentRunFailed | AgentRunCancelled; -/** Successful terminal result. Successful results cannot carry an error. */ +/** Successful terminal result. Successful results can carry only a null error. */ export interface AgentRunSucceeded extends AgentRunResultCommon { status: "succeeded"; - error?: never; + error?: null; } /** Failed terminal result. Failed results must carry a non-null error. */ diff --git a/typescript/adapter-contract/scripts/projection-guards.mjs b/typescript/adapter-contract/scripts/projection-guards.mjs index b6dd7de99..b009e6541 100644 --- a/typescript/adapter-contract/scripts/projection-guards.mjs +++ b/typescript/adapter-contract/scripts/projection-guards.mjs @@ -19,7 +19,7 @@ const supportedRunResultConditionals = [ properties: { status: { const: "succeeded" } }, required: ["status"], }, - then: { not: { required: ["error"] } }, + then: { properties: { error: { type: "null" } } }, }, ]; diff --git a/typescript/adapter-contract/src/generated/agent-run-result.ts b/typescript/adapter-contract/src/generated/agent-run-result.ts index 43a604ebb..db771c8f7 100644 --- a/typescript/adapter-contract/src/generated/agent-run-result.ts +++ b/typescript/adapter-contract/src/generated/agent-run-result.ts @@ -12,10 +12,10 @@ export type AgentRunResult = | AgentRunFailed | AgentRunCancelled; -/** Successful terminal result. Successful results cannot carry an error. */ +/** Successful terminal result. Successful results can carry only a null error. */ export interface AgentRunSucceeded extends AgentRunResultCommon { status: "succeeded"; - error?: never; + error?: null; } /** Failed terminal result. Failed results must carry a non-null error. */ diff --git a/typescript/adapter-contract/test/execution.test.ts b/typescript/adapter-contract/test/execution.test.ts index 0cb4fdfab..e658dd874 100644 --- a/typescript/adapter-contract/test/execution.test.ts +++ b/typescript/adapter-contract/test/execution.test.ts @@ -19,6 +19,7 @@ const requests: AgentRunRequest[] = [ const results: AgentRunResult[] = [ { output: null, status: "succeeded" }, + { error: null, output: null, status: "succeeded" }, { error: { code: "target_error", message: "target failed" }, output: { partial: true },