feat(ai): enabled container-to-string coercion for union branches
- Enable stringification repairs for expected types in union branches. - Update test to expect successful string coercion for objects in string union branches.
This commit is contained in:
@@ -1593,12 +1593,9 @@ function coerceArgsFromIssues(args: unknown, issues: FlatIssue[]): { value: unkn
|
||||
// a type coercion actually needs to write into a leaf.
|
||||
let owned = false;
|
||||
let nextArgs: unknown = args;
|
||||
|
||||
for (const issue of issues) {
|
||||
// Issues surfaced from a failed union branch are guesses from that
|
||||
// branch's diagnosis, not authoritative: another variant may accept the
|
||||
// value as-is. Lossy repairs (key deletion, container stringification,
|
||||
// singleton wrapping) stay off for them; lossless repairs still apply.
|
||||
// Failed union branches still contribute schema-directed type repairs.
|
||||
// Container-to-string conversion remains enabled for string branches.
|
||||
if (issue.keyword === "unrecognized") {
|
||||
if (issue.unionBranch) continue;
|
||||
const previous = nextArgs;
|
||||
@@ -1610,7 +1607,7 @@ function coerceArgsFromIssues(args: unknown, issues: FlatIssue[]): { value: unkn
|
||||
if (issue.expectedTypes.length === 0) continue;
|
||||
|
||||
const currentValue = getValueAtPointer(nextArgs, issue.instancePath);
|
||||
const result = tryCoerceForExpectedTypes(currentValue, issue.expectedTypes, !issue.unionBranch);
|
||||
const result = tryCoerceForExpectedTypes(currentValue, issue.expectedTypes, true);
|
||||
let coercedValue = result.changed ? result.value : undefined;
|
||||
if (
|
||||
coercedValue === undefined &&
|
||||
|
||||
@@ -56,11 +56,7 @@ describe("Tool argument coercion", () => {
|
||||
|
||||
expect(result.payload).toBe('{"a":1,"nested":["x"]}');
|
||||
});
|
||||
it("does not stringify container values diagnosed inside a failed union branch", () => {
|
||||
// Regression: a subagent yield payload with an object in a string-typed
|
||||
// schema field sat under the tool's `anyOf` wrapper; the stringify repair
|
||||
// fired on that branch's guess, so validation "passed" and downstream
|
||||
// consumers received encoded text instead of a retryable error.
|
||||
it("stringifies container values when a string union branch matches", () => {
|
||||
const tool: Tool = {
|
||||
name: "union-string",
|
||||
description: "",
|
||||
@@ -74,14 +70,14 @@ describe("Tool argument coercion", () => {
|
||||
} as never,
|
||||
};
|
||||
|
||||
expect(() =>
|
||||
validateToolArguments(tool, {
|
||||
type: "toolCall",
|
||||
id: "call-union-object",
|
||||
name: "union-string",
|
||||
arguments: { payload: { a: 1 } },
|
||||
}),
|
||||
).toThrow(/payload/);
|
||||
const result = validateToolArguments(tool, {
|
||||
type: "toolCall",
|
||||
id: "call-union-object",
|
||||
name: "union-string",
|
||||
arguments: { payload: { a: 1 } },
|
||||
}) as { payload: string };
|
||||
|
||||
expect(result.payload).toBe('{"a":1}');
|
||||
});
|
||||
|
||||
it("does not delete unrecognized keys diagnosed inside a failed union branch", () => {
|
||||
|
||||
Reference in New Issue
Block a user