refactor(core): migrate MessageV2 tool state schemas to Effect Schema (#23752)
This commit is contained in:
@@ -15,8 +15,9 @@ import { isMedia } from "@/util/media"
|
|||||||
import type { SystemError } from "bun"
|
import type { SystemError } from "bun"
|
||||||
import type { Provider } from "@/provider"
|
import type { Provider } from "@/provider"
|
||||||
import { ModelID, ProviderID } from "@/provider/schema"
|
import { ModelID, ProviderID } from "@/provider/schema"
|
||||||
import { Effect, Schema } from "effect"
|
import { Effect, Schema, Types } from "effect"
|
||||||
import { zod } from "@/util/effect-zod"
|
import { zod, ZodOverride } from "@/util/effect-zod"
|
||||||
|
import { withStatics } from "@/util/schema"
|
||||||
import { EffectLogger } from "@/effect"
|
import { EffectLogger } from "@/effect"
|
||||||
|
|
||||||
/** Error shape thrown by Bun's fetch() when gzip/br decompression fails mid-stream */
|
/** Error shape thrown by Bun's fetch() when gzip/br decompression fails mid-stream */
|
||||||
@@ -272,79 +273,84 @@ export const StepFinishPart = PartBase.extend({
|
|||||||
})
|
})
|
||||||
export type StepFinishPart = z.infer<typeof StepFinishPart>
|
export type StepFinishPart = z.infer<typeof StepFinishPart>
|
||||||
|
|
||||||
export const ToolStatePending = z
|
export const ToolStatePending = Schema.Struct({
|
||||||
.object({
|
status: Schema.Literal("pending"),
|
||||||
status: z.literal("pending"),
|
input: Schema.Record(Schema.String, Schema.Any),
|
||||||
input: z.record(z.string(), z.any()),
|
raw: Schema.String,
|
||||||
raw: z.string(),
|
})
|
||||||
})
|
.annotate({ identifier: "ToolStatePending" })
|
||||||
.meta({
|
.pipe(withStatics((s) => ({ zod: zod(s) })))
|
||||||
ref: "ToolStatePending",
|
export type ToolStatePending = Types.DeepMutable<Schema.Schema.Type<typeof ToolStatePending>>
|
||||||
})
|
|
||||||
|
|
||||||
export type ToolStatePending = z.infer<typeof ToolStatePending>
|
export const ToolStateRunning = Schema.Struct({
|
||||||
|
status: Schema.Literal("running"),
|
||||||
|
input: Schema.Record(Schema.String, Schema.Any),
|
||||||
|
title: Schema.optional(Schema.String),
|
||||||
|
metadata: Schema.optional(Schema.Record(Schema.String, Schema.Any)),
|
||||||
|
time: Schema.Struct({
|
||||||
|
start: Schema.Number,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.annotate({ identifier: "ToolStateRunning" })
|
||||||
|
.pipe(withStatics((s) => ({ zod: zod(s) })))
|
||||||
|
export type ToolStateRunning = Types.DeepMutable<Schema.Schema.Type<typeof ToolStateRunning>>
|
||||||
|
|
||||||
export const ToolStateRunning = z
|
export const ToolStateCompleted = Schema.Struct({
|
||||||
.object({
|
status: Schema.Literal("completed"),
|
||||||
status: z.literal("running"),
|
input: Schema.Record(Schema.String, Schema.Any),
|
||||||
input: z.record(z.string(), z.any()),
|
output: Schema.String,
|
||||||
title: z.string().optional(),
|
title: Schema.String,
|
||||||
metadata: z.record(z.string(), z.any()).optional(),
|
metadata: Schema.Record(Schema.String, Schema.Any),
|
||||||
time: z.object({
|
time: Schema.Struct({
|
||||||
start: z.number(),
|
start: Schema.Number,
|
||||||
}),
|
end: Schema.Number,
|
||||||
})
|
compacted: Schema.optional(Schema.Number),
|
||||||
.meta({
|
}),
|
||||||
ref: "ToolStateRunning",
|
// FilePart is still Zod-first this slice; bridge via ZodOverride so the
|
||||||
})
|
// derived Zod + JSON Schema still emit `$ref: FilePart` array items.
|
||||||
export type ToolStateRunning = z.infer<typeof ToolStateRunning>
|
attachments: Schema.optional(Schema.Any.annotate({ [ZodOverride]: FilePart.array() })),
|
||||||
|
})
|
||||||
|
.annotate({ identifier: "ToolStateCompleted" })
|
||||||
|
.pipe(withStatics((s) => ({ zod: zod(s) })))
|
||||||
|
export type ToolStateCompleted = Omit<
|
||||||
|
Types.DeepMutable<Schema.Schema.Type<typeof ToolStateCompleted>>,
|
||||||
|
"attachments"
|
||||||
|
> & {
|
||||||
|
attachments?: FilePart[]
|
||||||
|
}
|
||||||
|
|
||||||
export const ToolStateCompleted = z
|
export const ToolStateError = Schema.Struct({
|
||||||
.object({
|
status: Schema.Literal("error"),
|
||||||
status: z.literal("completed"),
|
input: Schema.Record(Schema.String, Schema.Any),
|
||||||
input: z.record(z.string(), z.any()),
|
error: Schema.String,
|
||||||
output: z.string(),
|
metadata: Schema.optional(Schema.Record(Schema.String, Schema.Any)),
|
||||||
title: z.string(),
|
time: Schema.Struct({
|
||||||
metadata: z.record(z.string(), z.any()),
|
start: Schema.Number,
|
||||||
time: z.object({
|
end: Schema.Number,
|
||||||
start: z.number(),
|
}),
|
||||||
end: z.number(),
|
})
|
||||||
compacted: z.number().optional(),
|
.annotate({ identifier: "ToolStateError" })
|
||||||
}),
|
.pipe(withStatics((s) => ({ zod: zod(s) })))
|
||||||
attachments: FilePart.array().optional(),
|
export type ToolStateError = Types.DeepMutable<Schema.Schema.Type<typeof ToolStateError>>
|
||||||
})
|
|
||||||
.meta({
|
|
||||||
ref: "ToolStateCompleted",
|
|
||||||
})
|
|
||||||
export type ToolStateCompleted = z.infer<typeof ToolStateCompleted>
|
|
||||||
|
|
||||||
export const ToolStateError = z
|
const _ToolState = Schema.Union([ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError]).annotate({
|
||||||
.object({
|
discriminator: "status",
|
||||||
status: z.literal("error"),
|
identifier: "ToolState",
|
||||||
input: z.record(z.string(), z.any()),
|
})
|
||||||
error: z.string(),
|
// Cast the derived zod so downstream z.infer sees the same mutable shape that
|
||||||
metadata: z.record(z.string(), z.any()).optional(),
|
// our exported TS types expose (the pre-migration Zod inferences were mutable).
|
||||||
time: z.object({
|
export const ToolState = Object.assign(_ToolState, {
|
||||||
start: z.number(),
|
zod: zod(_ToolState) as unknown as z.ZodType<
|
||||||
end: z.number(),
|
ToolStatePending | ToolStateRunning | ToolStateCompleted | ToolStateError
|
||||||
}),
|
>,
|
||||||
})
|
})
|
||||||
.meta({
|
export type ToolState = ToolStatePending | ToolStateRunning | ToolStateCompleted | ToolStateError
|
||||||
ref: "ToolStateError",
|
|
||||||
})
|
|
||||||
export type ToolStateError = z.infer<typeof ToolStateError>
|
|
||||||
|
|
||||||
export const ToolState = z
|
|
||||||
.discriminatedUnion("status", [ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError])
|
|
||||||
.meta({
|
|
||||||
ref: "ToolState",
|
|
||||||
})
|
|
||||||
|
|
||||||
export const ToolPart = PartBase.extend({
|
export const ToolPart = PartBase.extend({
|
||||||
type: z.literal("tool"),
|
type: z.literal("tool"),
|
||||||
callID: z.string(),
|
callID: z.string(),
|
||||||
tool: z.string(),
|
tool: z.string(),
|
||||||
state: ToolState,
|
state: ToolState.zod,
|
||||||
metadata: z.record(z.string(), z.any()).optional(),
|
metadata: z.record(z.string(), z.any()).optional(),
|
||||||
}).meta({
|
}).meta({
|
||||||
ref: "ToolPart",
|
ref: "ToolPart",
|
||||||
|
|||||||
Reference in New Issue
Block a user