Skip to content

Commit 1f7274b

Browse files
Claudeclaude
authored andcommitted
fix: coerce array values to strings in session_close closing_reflection
Agents frequently pass arrays instead of strings for institutional_memory_items, collaborative_dynamic, and rapport_notes. Rather than rejecting with a schema error (wasting tokens on every session close), accept both formats and auto-join arrays with ". " separator. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f6aa4e3 commit 1f7274b

2 files changed

Lines changed: 47 additions & 3 deletions

File tree

src/schemas/session-close.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ export const ClosingReflectionSchema = z.object({
1717
wrong_assumption: z.string(),
1818
scars_applied: z.union([z.string(), z.array(z.string())]),
1919
/** Q7: What from this session should be captured as institutional memory? */
20-
institutional_memory_items: z.string().optional(),
20+
institutional_memory_items: z.union([z.string(), z.array(z.string()).transform((arr) => arr.join(". "))]).optional(),
2121
/** Q8: How did the human prefer to work this session? */
22-
collaborative_dynamic: z.string().optional(),
22+
collaborative_dynamic: z.union([z.string(), z.array(z.string()).transform((arr) => arr.join(". "))]).optional(),
2323
/** Q9: What collaborative dynamic worked or didn't work? */
24-
rapport_notes: z.string().optional(),
24+
rapport_notes: z.union([z.string(), z.array(z.string()).transform((arr) => arr.join(". "))]).optional(),
2525
});
2626

2727
export type ClosingReflection = z.infer<typeof ClosingReflectionSchema>;

tests/unit/schemas/session-close.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,5 +426,49 @@ describe("ClosingReflectionSchema", () => {
426426
expect(result.data?.collaborative_dynamic).toBe("Directive style");
427427
expect(result.data?.rapport_notes).toBe("High-energy iteration");
428428
});
429+
430+
it("coerces institutional_memory_items array to joined string", () => {
431+
const result = ClosingReflectionSchema.safeParse({
432+
what_broke: "Nothing",
433+
what_took_longer: "Tests",
434+
do_differently: "Plan better",
435+
what_worked: "Communication",
436+
wrong_assumption: "None",
437+
scars_applied: [],
438+
institutional_memory_items: ["pool.map pickles args", "use globals for COW"],
439+
});
440+
expect(result.success).toBe(true);
441+
expect(result.data?.institutional_memory_items).toBe(
442+
"pool.map pickles args. use globals for COW"
443+
);
444+
});
445+
446+
it("coerces collaborative_dynamic array to joined string", () => {
447+
const result = ClosingReflectionSchema.safeParse({
448+
what_broke: "Nothing",
449+
what_took_longer: "Tests",
450+
do_differently: "Plan better",
451+
what_worked: "Communication",
452+
wrong_assumption: "None",
453+
scars_applied: [],
454+
collaborative_dynamic: ["Direct style", "Fast iteration"],
455+
});
456+
expect(result.success).toBe(true);
457+
expect(result.data?.collaborative_dynamic).toBe("Direct style. Fast iteration");
458+
});
459+
460+
it("coerces rapport_notes array to joined string", () => {
461+
const result = ClosingReflectionSchema.safeParse({
462+
what_broke: "Nothing",
463+
what_took_longer: "Tests",
464+
do_differently: "Plan better",
465+
what_worked: "Communication",
466+
wrong_assumption: "None",
467+
scars_applied: [],
468+
rapport_notes: ["Push-back welcomed", "High-energy"],
469+
});
470+
expect(result.success).toBe(true);
471+
expect(result.data?.rapport_notes).toBe("Push-back welcomed. High-energy");
472+
});
429473
});
430474
});

0 commit comments

Comments
 (0)