fix(data): canonicalize operation json fields
This commit is contained in:
1 parent
10c1f6d103
commit
b92cf62c4c
10 files changed
+246
-21
No files matched your search
@@ -1,5 +1,6 @@
|
||||
export * from "./contracts/channels";
|
||||
export * from "./contracts/helpers";
|
||||
export * from "./contracts/json-fields";
|
||||
export * from "./contracts/schemas-company";
|
||||
export * from "./contracts/schemas-agents";
|
||||
export * from "./contracts/schemas-tasks";
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export type JsonValue =
|
||||
| null
|
||||
| boolean
|
||||
| number
|
||||
| string
|
||||
| JsonValue[]
|
||||
| { [key: string]: JsonValue };
|
||||
|
||||
export const jsonValueSchema: z.ZodType<JsonValue> = z.lazy(() => z.union([
|
||||
z.null(),
|
||||
z.boolean(),
|
||||
z.number(),
|
||||
z.string(),
|
||||
z.array(jsonValueSchema),
|
||||
z.record(z.string(), jsonValueSchema),
|
||||
]));
|
||||
|
||||
export const jsonStringArraySchema = z.array(z.string());
|
||||
export const jsonArraySchema = z.array(jsonValueSchema);
|
||||
|
||||
export const meetingActionItemArraySchema = z.array(z.object({
|
||||
title: z.string().optional(),
|
||||
assigneeAgentId: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
}).catchall(jsonValueSchema));
|
||||
|
||||
export function canonicalizeJsonString<T>(value: string | null | undefined, schema: z.ZodType<T>, fallback: T): string {
|
||||
const raw = value ?? JSON.stringify(fallback);
|
||||
const parsed = JSON.parse(raw);
|
||||
return JSON.stringify(schema.parse(parsed));
|
||||
}
|
||||
|
||||
export function canonicalJsonString<T>(schema: z.ZodType<T>, fallback: T) {
|
||||
const fallbackJson = JSON.stringify(fallback);
|
||||
return z.string().default(fallbackJson).superRefine((value, ctx) => {
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = JSON.parse(value);
|
||||
} catch {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "Must be valid JSON.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const result = schema.safeParse(parsed);
|
||||
if (!result.success) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "JSON value does not match the expected shape.",
|
||||
});
|
||||
}
|
||||
}).transform((value) => canonicalizeJsonString(value, schema, fallback));
|
||||
}
|
||||
|
||||
export function canonicalOptionalJsonString<T>(schema: z.ZodType<T>) {
|
||||
return z.string().superRefine((value, ctx) => {
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = JSON.parse(value);
|
||||
} catch {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "Must be valid JSON.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const result = schema.safeParse(parsed);
|
||||
if (!result.success) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "JSON value does not match the expected shape.",
|
||||
});
|
||||
}
|
||||
}).transform((value) => JSON.stringify(schema.parse(JSON.parse(value))));
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { z } from "zod";
|
||||
import { canonicalJsonString, jsonArraySchema, jsonStringArraySchema, meetingActionItemArraySchema } from "./json-fields";
|
||||
import { MESSAGE_CHANNELS, optionalId } from "./helpers";
|
||||
|
||||
export const agentMessageInputSchema = z.object({
|
||||
@@ -86,7 +87,7 @@ export const documentInputSchema = z.object({
|
||||
parentDocId: optionalId,
|
||||
version: z.number().int().min(1).default(1),
|
||||
status: z.enum(["draft", "in_review", "approved", "archived", "superseded"]).default("draft"),
|
||||
tagsJson: z.string().default("[]"),
|
||||
tagsJson: canonicalJsonString(jsonStringArraySchema, []),
|
||||
});
|
||||
|
||||
export const knowledgeEntryInputSchema = z.object({
|
||||
@@ -97,7 +98,7 @@ export const knowledgeEntryInputSchema = z.object({
|
||||
content: z.string().min(1),
|
||||
authorAgentId: optionalId,
|
||||
importance: z.enum(["critical", "high", "medium", "low"]).default("medium"),
|
||||
tagsJson: z.string().default("[]"),
|
||||
tagsJson: canonicalJsonString(jsonStringArraySchema, []),
|
||||
referencedEntityType: z.enum([
|
||||
"agents",
|
||||
"goals",
|
||||
@@ -122,13 +123,13 @@ export const meetingInputSchema = z.object({
|
||||
type: z.enum(["standup", "sprint_planning", "sprint_review", "retrospective", "one_on_one", "all_hands", "department_sync", "incident_review", "hiring_committee", "budget_review", "design_review", "architecture_review"]),
|
||||
title: z.string().min(2).max(160),
|
||||
organizerAgentId: optionalId,
|
||||
participantAgentIds: z.string().default("[]"),
|
||||
participantAgentIds: canonicalJsonString(jsonStringArraySchema, []),
|
||||
scheduledAt: z.string(),
|
||||
durationMinutes: z.number().int().min(5).max(480).default(30),
|
||||
agendaJson: z.string().default("[]"),
|
||||
notesJson: z.string().default("[]"),
|
||||
decisionsJson: z.string().default("[]"),
|
||||
actionItemsJson: z.string().default("[]"),
|
||||
agendaJson: canonicalJsonString(jsonArraySchema, []),
|
||||
notesJson: canonicalJsonString(jsonArraySchema, []),
|
||||
decisionsJson: canonicalJsonString(jsonArraySchema, []),
|
||||
actionItemsJson: canonicalJsonString(meetingActionItemArraySchema, []),
|
||||
status: z.enum(["scheduled", "in_progress", "completed", "cancelled"]).default("scheduled"),
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user