From 023fbb8c8029cecd6dd25d6794592df7491cc85c Mon Sep 17 00:00:00 2001 From: Caitlin Pinn Date: Tue, 23 Dec 2025 13:31:50 -0800 Subject: [PATCH 1/7] update zod 4 --- packages/proxy/schema/audio.ts | 4 +- packages/proxy/schema/index.ts | 6 +- packages/proxy/schema/models.test.ts | 2 +- packages/proxy/schema/models.ts | 2 +- packages/proxy/schema/openai-realtime.ts | 2 +- packages/proxy/schema/secrets.ts | 220 +++++++------ packages/proxy/scripts/sync_models.ts | 8 +- packages/proxy/src/generated_types.ts | 372 ++++++++++------------ packages/proxy/src/providers/anthropic.ts | 2 +- packages/proxy/src/providers/google.ts | 24 +- packages/proxy/types/anthropic.ts | 8 +- packages/proxy/types/google.ts | 8 +- 12 files changed, 316 insertions(+), 342 deletions(-) diff --git a/packages/proxy/schema/audio.ts b/packages/proxy/schema/audio.ts index 15c636f7..74bd1aa7 100644 --- a/packages/proxy/schema/audio.ts +++ b/packages/proxy/schema/audio.ts @@ -25,8 +25,8 @@ export const pcmAudioFormatSchema = z .discriminatedUnion("name", [ z.object({ name: z.literal("pcm"), - byte_order: z.enum(["little", "big"]).default("little"), - number_encoding: z.enum(["int", "float"]).default("int"), + byte_order: z.enum(["little", "big"]).prefault("little"), + number_encoding: z.enum(["int", "float"]).prefault("int"), bits_per_sample: z.union([z.literal(8), z.literal(16)]), }), z.object({ diff --git a/packages/proxy/schema/index.ts b/packages/proxy/schema/index.ts index ee93455e..f7bafea5 100644 --- a/packages/proxy/schema/index.ts +++ b/packages/proxy/schema/index.ts @@ -690,14 +690,14 @@ export const anthropicSupportedMediaTypes = [ export const anthropicTextBlockSchema = z.object({ type: z.literal("text").optional(), - text: z.string().default(""), + text: z.string().prefault(""), }); export const anthropicImageBlockSchema = z.object({ type: z.literal("image").optional(), source: z.object({ type: z.enum(["base64"]).optional(), media_type: z.enum(["image/jpeg", "image/png", "image/gif", "image/webp"]), - data: z.string().default(""), + data: z.string().prefault(""), }), }); const anthropicContentBlockSchema = z.union([ @@ -706,7 +706,7 @@ const anthropicContentBlockSchema = z.union([ ]); const anthropicContentBlocksSchema = z.array(anthropicContentBlockSchema); const anthropicContentSchema = z.union([ - z.string().default(""), + z.string().prefault(""), anthropicContentBlocksSchema, ]); diff --git a/packages/proxy/schema/models.test.ts b/packages/proxy/schema/models.test.ts index d6d22400..de148633 100644 --- a/packages/proxy/schema/models.test.ts +++ b/packages/proxy/schema/models.test.ts @@ -5,7 +5,7 @@ import { ModelSchema } from "./models"; import { z } from "zod"; it("parse model list", () => { - const models = z.record(z.unknown()).parse(raw_models); + const models = z.record(z.string(), z.unknown()).parse(raw_models); for (const [key, value] of Object.entries(models)) { const result = ModelSchema.safeParse(value); if (!result.success) { diff --git a/packages/proxy/schema/models.ts b/packages/proxy/schema/models.ts index 1e0e8e08..92dd93a6 100644 --- a/packages/proxy/schema/models.ts +++ b/packages/proxy/schema/models.ts @@ -87,7 +87,7 @@ export const ModelSchema = z.object({ export type ModelSpec = z.infer; import modelListJson from "./model_list.json"; -const modelListJsonTyped = z.record(ModelSchema).parse(modelListJson); +const modelListJsonTyped = z.record(z.string(), ModelSchema).parse(modelListJson); // Because this file can be included and bundled in various ways, it's important to // really inject these variables into the global scope, rather than let the bundler diff --git a/packages/proxy/schema/openai-realtime.ts b/packages/proxy/schema/openai-realtime.ts index d0a3f745..e6c8d202 100644 --- a/packages/proxy/schema/openai-realtime.ts +++ b/packages/proxy/schema/openai-realtime.ts @@ -29,7 +29,7 @@ export const toolDefinitionTypeSchema = z.object({ type: z.literal("function").optional(), name: z.string(), description: z.string(), - parameters: z.record(z.unknown()), + parameters: z.record(z.string(), z.unknown()), }); export const sessionResourceTypeSchema = z.object({ diff --git a/packages/proxy/schema/secrets.ts b/packages/proxy/schema/secrets.ts index 4ab582b8..59587d71 100644 --- a/packages/proxy/schema/secrets.ts +++ b/packages/proxy/schema/secrets.ts @@ -1,30 +1,28 @@ import { z } from "zod"; import { ModelSchema } from "./models"; -export const BaseMetadataSchema = z - .object({ +export const BaseMetadataSchema = z.strictObject({ models: z.array(z.string()).nullish(), - customModels: z.record(ModelSchema).nullish(), + customModels: z.record(z.string(), ModelSchema).nullish(), excludeDefaultModels: z.boolean().nullish(), additionalHeaders: z.record(z.string(), z.string()).nullish(), - supportsStreaming: z.boolean().default(true), - }) - .strict(); - -export const AzureMetadataSchema = BaseMetadataSchema.merge( - z.object({ - api_base: z.string().url(), - api_version: z.string().default("2023-07-01-preview"), - deployment: z.string().nullish(), - auth_type: z.enum(["api_key", "entra_api"]).default("api_key"), - no_named_deployment: z - .boolean() - .default(false) - .describe( - "If true, the deployment name will not be used in the request path.", - ), - }), -).strict(); + supportsStreaming: z.boolean().prefault(true), + }); + +export const AzureMetadataSchema = BaseMetadataSchema.extend( + z.strictObject({ + api_base: z.url(), + api_version: z.string().prefault("2023-07-01-preview"), + deployment: z.string().nullish(), + auth_type: z.enum(["api_key", "entra_api"]).prefault("api_key"), + no_named_deployment: z + .boolean() + .prefault(false) + .describe( + "If true, the deployment name will not be used in the request path.", + ), + }).shape +); export const AzureEntraSecretSchema = z.object({ client_id: z.string().min(1, "Client ID cannot be empty"), @@ -34,30 +32,30 @@ export const AzureEntraSecretSchema = z.object({ }); export type AzureEntraSecret = z.infer; -export const BedrockMetadataSchema = BaseMetadataSchema.merge( - z.object({ - region: z.string().min(1, "Region cannot be empty"), - access_key: z.string().min(1, "Access key cannot be empty"), - session_token: z.string().nullish(), - api_base: z.union([z.string().url(), z.string().length(0)]).nullish(), - }), -).strict(); +export const BedrockMetadataSchema = BaseMetadataSchema.extend( + z.strictObject({ + region: z.string().min(1, "Region cannot be empty"), + access_key: z.string().min(1, "Access key cannot be empty"), + session_token: z.string().nullish(), + api_base: z.union([z.url(), z.string().length(0)]).nullish(), + }).shape +); export type BedrockMetadata = z.infer; -export const VertexMetadataSchema = BaseMetadataSchema.merge( - z.object({ - project: z.string().min(1, "Project cannot be empty"), - authType: z.enum(["access_token", "service_account_key"]), - api_base: z.union([z.string().url(), z.string().length(0)]).nullish(), - }), -).strict(); - -export const DatabricksMetadataSchema = BaseMetadataSchema.merge( - z.object({ - api_base: z.string().url(), - auth_type: z.enum(["pat", "service_principal_oauth"]).default("pat"), - }), -).strict(); +export const VertexMetadataSchema = BaseMetadataSchema.extend( + z.strictObject({ + project: z.string().min(1, "Project cannot be empty"), + authType: z.enum(["access_token", "service_account_key"]), + api_base: z.union([z.url(), z.string().length(0)]).nullish(), + }).shape +); + +export const DatabricksMetadataSchema = BaseMetadataSchema.extend( + z.strictObject({ + api_base: z.url(), + auth_type: z.enum(["pat", "service_principal_oauth"]).prefault("pat"), + }).shape +); export const DatabricksOAuthSecretSchema = z.object({ client_id: z.string().min(1, "Client ID cannot be empty"), @@ -65,89 +63,87 @@ export const DatabricksOAuthSecretSchema = z.object({ }); export type DatabricksOAuthSecret = z.infer; -export const OpenAIMetadataSchema = BaseMetadataSchema.merge( - z.object({ - api_base: z.union([ - z.string().url().optional(), - z.string().length(0), - z.null(), - ]), - organization_id: z.string().nullish(), - }), -).strict(); - -export const MistralMetadataSchema = BaseMetadataSchema.merge( - z.object({ - api_base: z.union([z.string().url(), z.string().length(0)]).nullish(), - }), -).strict(); - -const APISecretBaseSchema = z - .object({ - id: z.string().uuid().nullish(), +export const OpenAIMetadataSchema = BaseMetadataSchema.extend( + z.strictObject({ + api_base: z.union([ + z.url().optional(), + z.string().length(0), + z.null(), + ]), + organization_id: z.string().nullish(), + }).shape +); + +export const MistralMetadataSchema = BaseMetadataSchema.extend( + z.strictObject({ + api_base: z.union([z.url(), z.string().length(0)]).nullish(), + }).shape +); + +const APISecretBaseSchema = z.strictObject({ + id: z.uuid().nullish(), org_name: z.string().nullish(), name: z.string().nullish(), secret: z.string(), - metadata: z.record(z.unknown()).nullish(), - }) - .strict(); + metadata: z.record(z.string(), z.unknown()).nullish(), + }); export const APISecretSchema = z.union([ - APISecretBaseSchema.merge( + APISecretBaseSchema.extend( z.object({ - type: z.enum([ - "perplexity", - "anthropic", - "google", - "replicate", - "together", - "baseten", - "ollama", - "groq", - "lepton", - "fireworks", - "cerebras", - "xAI", - "js", - ]), - metadata: BaseMetadataSchema.nullish(), - }), + type: z.enum([ + "perplexity", + "anthropic", + "google", + "replicate", + "together", + "baseten", + "ollama", + "groq", + "lepton", + "fireworks", + "cerebras", + "xAI", + "js", + ]), + metadata: BaseMetadataSchema.nullish(), + }).shape ), - APISecretBaseSchema.merge( + APISecretBaseSchema.extend( z.object({ - type: z.literal("openai"), - metadata: OpenAIMetadataSchema.nullish(), - }), + type: z.literal("openai"), + metadata: OpenAIMetadataSchema.nullish(), + }).shape ), - APISecretBaseSchema.merge( + APISecretBaseSchema.extend( z.object({ - type: z.literal("azure"), - metadata: AzureMetadataSchema.nullish(), - }), + type: z.literal("azure"), + metadata: AzureMetadataSchema.nullish(), + }).shape ), - APISecretBaseSchema.merge( + APISecretBaseSchema.extend( z.object({ - type: z.literal("bedrock"), - metadata: BedrockMetadataSchema.nullish(), - }), + type: z.literal("bedrock"), + metadata: BedrockMetadataSchema.nullish(), + }).shape ), - APISecretBaseSchema.merge( + APISecretBaseSchema.extend( z.object({ - type: z.literal("vertex"), - metadata: VertexMetadataSchema.nullish(), - }), + type: z.literal("vertex"), + metadata: VertexMetadataSchema.nullish(), + }).shape ), - APISecretBaseSchema.merge( + APISecretBaseSchema.extend( z.object({ - type: z.literal("databricks"), - metadata: DatabricksMetadataSchema.nullish(), - }), + type: z.literal("databricks"), + metadata: DatabricksMetadataSchema.nullish(), + }).shape ), - APISecretBaseSchema.merge( + APISecretBaseSchema.extend( z.object({ - type: z.literal("mistral"), - metadata: MistralMetadataSchema.nullish(), - }), + type: z.literal("mistral"), + metadata: MistralMetadataSchema.nullish(), + }).shape ), ]); @@ -157,11 +153,11 @@ export const proxyLoggingParamSchema = z .object({ parent: z.string().optional(), project_name: z.string().optional(), - compress_audio: z.boolean().default(true), + compress_audio: z.boolean().prefault(true), }) .refine((data) => data.parent || data.project_name, { - message: "Either 'parent' or 'project_name' must be provided", - }) + error: "Either 'parent' or 'project_name' must be provided" +}) .describe( "If present, proxy will log requests to the given Braintrust project or parent span.", ); @@ -179,7 +175,7 @@ export const credentialsRequestSchema = z ttl_seconds: z .number() .max(60 * 60 * 24) - .default(60 * 10) + .prefault(60 * 10) .describe("TTL of the temporary credential. 10 minutes by default."), logging: proxyLoggingParamSchema.nullish(), }) diff --git a/packages/proxy/scripts/sync_models.ts b/packages/proxy/scripts/sync_models.ts index f0fd5b77..6303ce05 100644 --- a/packages/proxy/scripts/sync_models.ts +++ b/packages/proxy/scripts/sync_models.ts @@ -75,7 +75,7 @@ const liteLLMModelDetailSchema = z }) .passthrough(); -const liteLLMModelListSchema = z.record(liteLLMModelDetailSchema); +const liteLLMModelListSchema = z.record(z.string(), liteLLMModelDetailSchema); type LiteLLMModelDetail = z.infer; type LiteLLMModelList = z.infer; @@ -114,7 +114,7 @@ async function fetchRemoteModels(url: string): Promise { if (error instanceof z.ZodError) { console.error( "Zod validation errors in remote data:", - error.errors, + error.issues, ); reject( new Error( @@ -142,12 +142,12 @@ async function readLocalModels(filePath: string): Promise { const fileContent = await fs.promises.readFile(filePath, "utf-8"); const localData = JSON.parse(fileContent); // Validate local data with the imported ModelSchema - return z.record(ModelSchema).parse(localData); + return z.record(z.string(), ModelSchema).parse(localData); } catch (error) { if (error instanceof z.ZodError) { console.error( "Zod validation errors in local model_list.json:", - error.errors, + error.issues, ); throw new Error("Local model_list.json failed Zod validation."); } diff --git a/packages/proxy/src/generated_types.ts b/packages/proxy/src/generated_types.ts index 8b8a40bf..2c1e4ec1 100644 --- a/packages/proxy/src/generated_types.ts +++ b/packages/proxy/src/generated_types.ts @@ -31,27 +31,27 @@ export const Permission = z.enum([ ]); export type PermissionType = z.infer; export const Acl = z.object({ - id: z.string().uuid(), + id: z.uuid(), object_type: AclObjectType.and(z.string()), - object_id: z.string().uuid(), + object_id: z.uuid(), user_id: z.union([z.string(), z.null()]).optional(), group_id: z.union([z.string(), z.null()]).optional(), permission: Permission.and(z.union([z.string(), z.null()])).optional(), restrict_object_type: AclObjectType.and(z.unknown()).optional(), role_id: z.union([z.string(), z.null()]).optional(), - _object_org_id: z.string().uuid(), + _object_org_id: z.uuid(), created: z.union([z.string(), z.null()]).optional(), }); export type AclType = z.infer; export const AISecret = z.object({ - id: z.string().uuid(), + id: z.uuid(), created: z.union([z.string(), z.null()]).optional(), updated_at: z.union([z.string(), z.null()]).optional(), - org_id: z.string().uuid(), + org_id: z.uuid(), name: z.string(), type: z.union([z.string(), z.null()]).optional(), metadata: z - .union([z.object({}).partial().passthrough(), z.null()]) + .union([z.looseObject({}).partial(), z.null()]) .optional(), preview_secret: z.union([z.string(), z.null()]).optional(), }); @@ -60,7 +60,7 @@ export const ResponseFormatJsonSchema = z.object({ name: z.string(), description: z.string().optional(), schema: z - .union([z.object({}).partial().passthrough(), z.string()]) + .union([z.looseObject({}).partial(), z.string()]) .optional(), strict: z.union([z.boolean(), z.null()]).optional(), }); @@ -119,7 +119,7 @@ export const AnyModelParams = z.object({ }); export type AnyModelParamsType = z.infer; export const ApiKey = z.object({ - id: z.string().uuid(), + id: z.uuid(), created: z.union([z.string(), z.null()]).optional(), name: z.string(), preview_name: z.string(), @@ -231,7 +231,7 @@ export const CallEvent = z.union([ ]); export type CallEventType = z.infer; export const ChatCompletionContentPartTextWithTitle = z.object({ - text: z.string().default(""), + text: z.string().prefault(""), type: z.literal("text"), cache_control: z.object({ type: z.literal("ephemeral") }).optional(), }); @@ -272,7 +272,7 @@ export type ChatCompletionContentPartType = z.infer< typeof ChatCompletionContentPart >; export const ChatCompletionContentPartText = z.object({ - text: z.string().default(""), + text: z.string().prefault(""), type: z.literal("text"), cache_control: z.object({ type: z.literal("ephemeral") }).optional(), }); @@ -319,7 +319,7 @@ export const ChatCompletionMessageParam = z.union([ z.object({ content: z.union([z.string(), z.array(ChatCompletionContentPartText)]), role: z.literal("tool"), - tool_call_id: z.string().default(""), + tool_call_id: z.string().prefault(""), }), z.object({ content: z.union([z.string(), z.null()]), @@ -365,7 +365,7 @@ export const ChatCompletionOpenAIMessageParam = z.union([ z.object({ content: z.union([z.string(), z.array(ChatCompletionContentPartText)]), role: z.literal("tool"), - tool_call_id: z.string().default(""), + tool_call_id: z.string().prefault(""), }), z.object({ content: z.union([z.string(), z.null()]), @@ -385,7 +385,7 @@ export const ChatCompletionTool = z.object({ function: z.object({ name: z.string(), description: z.string().optional(), - parameters: z.object({}).partial().passthrough().optional(), + parameters: z.looseObject({}).partial().optional(), }), type: z.literal("function"), }); @@ -401,25 +401,25 @@ export const CodeBundle = z.object({ eval_name: z.string(), position: z.union([ z.object({ type: z.literal("task") }), - z.object({ type: z.literal("scorer"), index: z.number().int().gte(0) }), + z.object({ type: z.literal("scorer"), index: z.int().gte(0) }), ]), }), - z.object({ type: z.literal("function"), index: z.number().int().gte(0) }), + z.object({ type: z.literal("function"), index: z.int().gte(0) }), ]), bundle_id: z.string(), preview: z.union([z.string(), z.null()]).optional(), }); export type CodeBundleType = z.infer; export const Dataset = z.object({ - id: z.string().uuid(), - project_id: z.string().uuid(), + id: z.uuid(), + project_id: z.uuid(), name: z.string(), description: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), deleted_at: z.union([z.string(), z.null()]).optional(), user_id: z.union([z.string(), z.null()]).optional(), metadata: z - .union([z.object({}).partial().passthrough(), z.null()]) + .union([z.looseObject({}).partial(), z.null()]) .optional(), }); export type DatasetType = z.infer; @@ -433,7 +433,7 @@ export const ObjectReferenceNullish = z.union([ "function", "prompt_session", ]), - object_id: z.string().uuid(), + object_id: z.uuid(), id: z.string(), _xact_id: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), @@ -444,18 +444,16 @@ export type ObjectReferenceNullishType = z.infer; export const DatasetEvent = z.object({ id: z.string(), _xact_id: z.string(), - created: z.string().datetime({ offset: true }), + created: z.iso.datetime({ offset: true }), _pagination_key: z.union([z.string(), z.null()]).optional(), - project_id: z.string().uuid(), - dataset_id: z.string().uuid(), + project_id: z.uuid(), + dataset_id: z.uuid(), input: z.unknown().optional(), expected: z.unknown().optional(), metadata: z .union([ - z - .object({ model: z.union([z.string(), z.null()]) }) - .partial() - .passthrough(), + z.looseObject({ model: z.union([z.string(), z.null()]) }) + .partial(), z.null(), ]) .optional(), @@ -469,9 +467,9 @@ export const DatasetEvent = z.object({ }); export type DatasetEventType = z.infer; export const EnvVar = z.object({ - id: z.string().uuid(), + id: z.uuid(), object_type: z.enum(["organization", "project", "function"]), - object_id: z.string().uuid(), + object_id: z.uuid(), name: z.string(), created: z.union([z.string(), z.null()]).optional(), used: z.union([z.string(), z.null()]).optional(), @@ -495,8 +493,8 @@ export const RepoInfo = z.union([ ]); export type RepoInfoType = z.infer; export const Experiment = z.object({ - id: z.string().uuid(), - project_id: z.string().uuid(), + id: z.uuid(), + project_id: z.uuid(), name: z.string(), description: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), @@ -509,7 +507,7 @@ export const Experiment = z.object({ public: z.boolean(), user_id: z.union([z.string(), z.null()]).optional(), metadata: z - .union([z.object({}).partial().passthrough(), z.null()]) + .union([z.looseObject({}).partial(), z.null()]) .optional(), tags: z.union([z.array(z.string()), z.null()]).optional(), }); @@ -520,48 +518,42 @@ export const SpanType = z.union([ ]); export type SpanTypeType = z.infer; export const SpanAttributes = z.union([ - z - .object({ name: z.union([z.string(), z.null()]), type: SpanType }) - .partial() - .passthrough(), + z.looseObject({ name: z.union([z.string(), z.null()]), type: SpanType }) + .partial(), z.null(), ]); export type SpanAttributesType = z.infer; export const ExperimentEvent = z.object({ id: z.string(), _xact_id: z.string(), - created: z.string().datetime({ offset: true }), + created: z.iso.datetime({ offset: true }), _pagination_key: z.union([z.string(), z.null()]).optional(), - project_id: z.string().uuid(), - experiment_id: z.string().uuid(), + project_id: z.uuid(), + experiment_id: z.uuid(), input: z.unknown().optional(), output: z.unknown().optional(), expected: z.unknown().optional(), error: z.unknown().optional(), scores: z - .union([z.record(z.union([z.number(), z.null()])), z.null()]) + .union([z.record(z.string(), z.union([z.number(), z.null()])), z.null()]) .optional(), metadata: z .union([ - z - .object({ model: z.union([z.string(), z.null()]) }) - .partial() - .passthrough(), + z.looseObject({ model: z.union([z.string(), z.null()]) }) + .partial(), z.null(), ]) .optional(), tags: z.union([z.array(z.string()), z.null()]).optional(), - metrics: z.union([z.record(z.number()), z.null()]).optional(), + metrics: z.union([z.record(z.string(), z.number()), z.null()]).optional(), context: z .union([ - z - .object({ - caller_functionname: z.union([z.string(), z.null()]), - caller_filename: z.union([z.string(), z.null()]), - caller_lineno: z.union([z.number(), z.null()]), - }) - .partial() - .passthrough(), + z.looseObject({ + caller_functionname: z.union([z.string(), z.null()]), + caller_filename: z.union([z.string(), z.null()]), + caller_lineno: z.union([z.number(), z.null()]), + }) + .partial(), z.null(), ]) .optional(), @@ -598,82 +590,72 @@ export const PromptBlockDataNullish = z.union([ ]); export type PromptBlockDataNullishType = z.infer; export const ModelParams = z.union([ - z - .object({ - use_cache: z.boolean(), - reasoning_enabled: z.boolean(), - reasoning_budget: z.number(), - temperature: z.number(), - top_p: z.number(), - max_tokens: z.number(), - max_completion_tokens: z.number(), - frequency_penalty: z.number(), - presence_penalty: z.number(), - response_format: ResponseFormatNullish, - tool_choice: z.union([ - z.literal("auto"), - z.literal("none"), - z.literal("required"), - z.object({ - type: z.literal("function"), - function: z.object({ name: z.string() }), + z.looseObject({ + use_cache: z.boolean(), + reasoning_enabled: z.boolean(), + reasoning_budget: z.number(), + temperature: z.number(), + top_p: z.number(), + max_tokens: z.number(), + max_completion_tokens: z.number(), + frequency_penalty: z.number(), + presence_penalty: z.number(), + response_format: ResponseFormatNullish, + tool_choice: z.union([ + z.literal("auto"), + z.literal("none"), + z.literal("required"), + z.looseObject({ + type: z.literal("function"), + function: z.looseObject({ name: z.string() }), + }), + ]), + function_call: z.union([ + z.literal("auto"), + z.literal("none"), + z.looseObject({ name: z.string() }), + ]), + n: z.number(), + stop: z.array(z.string()), + reasoning_effort: z.enum(["minimal", "low", "medium", "high"]), + verbosity: z.enum(["low", "medium", "high"]), + }) + .partial(), + z.looseObject({ + use_cache: z.boolean().optional(), + reasoning_enabled: z.boolean().optional(), + reasoning_budget: z.number().optional(), + max_tokens: z.number(), + temperature: z.number(), + top_p: z.number().optional(), + top_k: z.number().optional(), + stop_sequences: z.array(z.string()).optional(), + max_tokens_to_sample: z.number().optional(), }), - ]), - function_call: z.union([ - z.literal("auto"), - z.literal("none"), - z.object({ name: z.string() }), - ]), - n: z.number(), - stop: z.array(z.string()), - reasoning_effort: z.enum(["minimal", "low", "medium", "high"]), - verbosity: z.enum(["low", "medium", "high"]), - }) - .partial() - .passthrough(), - z - .object({ - use_cache: z.boolean().optional(), - reasoning_enabled: z.boolean().optional(), - reasoning_budget: z.number().optional(), - max_tokens: z.number(), - temperature: z.number(), - top_p: z.number().optional(), - top_k: z.number().optional(), - stop_sequences: z.array(z.string()).optional(), - max_tokens_to_sample: z.number().optional(), - }) - .passthrough(), - z - .object({ - use_cache: z.boolean(), - reasoning_enabled: z.boolean(), - reasoning_budget: z.number(), - temperature: z.number(), - maxOutputTokens: z.number(), - topP: z.number(), - topK: z.number(), - }) - .partial() - .passthrough(), - z - .object({ - use_cache: z.boolean(), - reasoning_enabled: z.boolean(), - reasoning_budget: z.number(), - temperature: z.number(), - topK: z.number(), - }) - .partial() - .passthrough(), - z - .object({ - use_cache: z.boolean(), - reasoning_enabled: z.boolean(), - reasoning_budget: z.number(), - }) - .partial() - .passthrough(), + z.looseObject({ + use_cache: z.boolean(), + reasoning_enabled: z.boolean(), + reasoning_budget: z.number(), + temperature: z.number(), + maxOutputTokens: z.number(), + topP: z.number(), + topK: z.number(), + }) + .partial(), + z.looseObject({ + use_cache: z.boolean(), + reasoning_enabled: z.boolean(), + reasoning_budget: z.number(), + temperature: z.number(), + topK: z.number(), + }) + .partial(), + z.looseObject({ + use_cache: z.boolean(), + reasoning_enabled: z.boolean(), + reasoning_budget: z.number(), + }) + .partial(), ]); export type ModelParamsType = z.infer; export const PromptOptionsNullish = z.union([ @@ -687,7 +669,7 @@ export const PromptParserNullish = z.union([ z.object({ type: z.literal("llm_classifier"), use_cot: z.boolean(), - choice_scores: z.record(z.number().gte(0).lte(1)), + choice_scores: z.record(z.string(), z.number().gte(0).lte(1)), }), z.null(), ]); @@ -726,7 +708,7 @@ export const FunctionTypeEnumNullish = z.union([ export type FunctionTypeEnumNullishType = z.infer< typeof FunctionTypeEnumNullish >; -export const FunctionIdRef = z.object({}).partial().passthrough(); +export const FunctionIdRef = z.looseObject({}).partial(); export type FunctionIdRefType = z.infer; export const PromptBlockData = z.union([ z.object({ @@ -809,8 +791,8 @@ export const GraphEdge = z.object({ export type GraphEdgeType = z.infer; export const GraphData = z.object({ type: z.literal("graph"), - nodes: z.record(GraphNode), - edges: z.record(GraphEdge), + nodes: z.record(z.string(), GraphNode), + edges: z.record(z.string(), GraphEdge), }); export type GraphDataType = z.infer; export const FunctionData = z.union([ @@ -834,17 +816,17 @@ export const FunctionData = z.union([ type: z.literal("remote_eval"), endpoint: z.string(), eval_name: z.string(), - parameters: z.object({}).partial().passthrough(), + parameters: z.looseObject({}).partial(), }), z.object({ type: z.literal("global"), name: z.string() }), ]); export type FunctionDataType = z.infer; export const Function = z.object({ - id: z.string().uuid(), + id: z.uuid(), _xact_id: z.string(), - project_id: z.string().uuid(), + project_id: z.uuid(), log_id: z.literal("p"), - org_id: z.string().uuid(), + org_id: z.uuid(), name: z.string(), slug: z.string(), description: z.union([z.string(), z.null()]).optional(), @@ -852,7 +834,7 @@ export const Function = z.object({ prompt_data: PromptDataNullish.optional(), tags: z.union([z.array(z.string()), z.null()]).optional(), metadata: z - .union([z.object({}).partial().passthrough(), z.null()]) + .union([z.looseObject({}).partial(), z.null()]) .optional(), function_type: FunctionTypeEnumNullish.optional(), function_data: FunctionData, @@ -860,7 +842,7 @@ export const Function = z.object({ .union([ z.object({ object_type: AclObjectType.and(z.string()), - object_id: z.string().uuid(), + object_id: z.uuid(), internal: z.union([z.boolean(), z.null()]).optional(), }), z.null(), @@ -920,7 +902,7 @@ export const FunctionId = z.union([ }), z.object({ inline_prompt: PromptData.optional(), - inline_function: z.object({}).partial().passthrough(), + inline_function: z.looseObject({}).partial(), function_type: FunctionTypeEnum.optional(), name: z.union([z.string(), z.null()]).optional(), }), @@ -961,15 +943,15 @@ export const GitMetadataSettings = z.object({ }); export type GitMetadataSettingsType = z.infer; export const Group = z.object({ - id: z.string().uuid(), - org_id: z.string().uuid(), + id: z.uuid(), + org_id: z.uuid(), user_id: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), name: z.string(), description: z.union([z.string(), z.null()]).optional(), deleted_at: z.union([z.string(), z.null()]).optional(), - member_users: z.union([z.array(z.string().uuid()), z.null()]).optional(), - member_groups: z.union([z.array(z.string().uuid()), z.null()]).optional(), + member_users: z.union([z.array(z.uuid()), z.null()]).optional(), + member_groups: z.union([z.array(z.uuid()), z.null()]).optional(), }); export type GroupType = z.infer; export const IfExists = z.enum(["error", "ignore", "replace"]); @@ -989,7 +971,7 @@ export const InvokeParent = z.union([ ]) .optional(), propagated_event: z - .union([z.object({}).partial().passthrough(), z.null()]) + .union([z.looseObject({}).partial(), z.null()]) .optional(), }), z.string(), @@ -1002,7 +984,7 @@ export const InvokeFunction = FunctionId.and( .object({ input: z.unknown(), expected: z.unknown(), - metadata: z.union([z.object({}).partial().passthrough(), z.null()]), + metadata: z.union([z.looseObject({}).partial(), z.null()]), tags: z.union([z.array(z.string()), z.null()]), messages: z.array(ChatCompletionMessageParam), parent: InvokeParent, @@ -1032,7 +1014,7 @@ export const ObjectReference = z.object({ "function", "prompt_session", ]), - object_id: z.string().uuid(), + object_id: z.uuid(), id: z.string(), _xact_id: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), @@ -1051,7 +1033,7 @@ export const OnlineScoreConfig = z.union([ ]); export type OnlineScoreConfigType = z.infer; export const Organization = z.object({ - id: z.string().uuid(), + id: z.uuid(), name: z.string(), api_url: z.union([z.string(), z.null()]).optional(), is_universal_api: z.union([z.boolean(), z.null()]).optional(), @@ -1095,8 +1077,8 @@ export const ProjectSettings = z.union([ ]); export type ProjectSettingsType = z.infer; export const Project = z.object({ - id: z.string().uuid(), - org_id: z.string().uuid(), + id: z.uuid(), + org_id: z.uuid(), name: z.string(), created: z.union([z.string(), z.null()]).optional(), deleted_at: z.union([z.string(), z.null()]).optional(), @@ -1111,8 +1093,8 @@ export const RetentionObjectType = z.enum([ ]); export type RetentionObjectTypeType = z.infer; export const ProjectAutomation = z.object({ - id: z.string().uuid(), - project_id: z.string().uuid(), + id: z.uuid(), + project_id: z.uuid(), user_id: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), name: z.string(), @@ -1153,38 +1135,34 @@ export const ProjectLogsEvent = z.object({ id: z.string(), _xact_id: z.string(), _pagination_key: z.union([z.string(), z.null()]).optional(), - created: z.string().datetime({ offset: true }), - org_id: z.string().uuid(), - project_id: z.string().uuid(), + created: z.iso.datetime({ offset: true }), + org_id: z.uuid(), + project_id: z.uuid(), log_id: z.literal("g"), input: z.unknown().optional(), output: z.unknown().optional(), expected: z.unknown().optional(), error: z.unknown().optional(), scores: z - .union([z.record(z.union([z.number(), z.null()])), z.null()]) + .union([z.record(z.string(), z.union([z.number(), z.null()])), z.null()]) .optional(), metadata: z .union([ - z - .object({ model: z.union([z.string(), z.null()]) }) - .partial() - .passthrough(), + z.looseObject({ model: z.union([z.string(), z.null()]) }) + .partial(), z.null(), ]) .optional(), tags: z.union([z.array(z.string()), z.null()]).optional(), - metrics: z.union([z.record(z.number()), z.null()]).optional(), + metrics: z.union([z.record(z.string(), z.number()), z.null()]).optional(), context: z .union([ - z - .object({ - caller_functionname: z.union([z.string(), z.null()]), - caller_filename: z.union([z.string(), z.null()]), - caller_lineno: z.union([z.number(), z.null()]), - }) - .partial() - .passthrough(), + z.looseObject({ + caller_functionname: z.union([z.string(), z.null()]), + caller_filename: z.union([z.string(), z.null()]), + caller_lineno: z.union([z.number(), z.null()]), + }) + .partial(), z.null(), ]) .optional(), @@ -1216,7 +1194,7 @@ export const ProjectScoreCategory = z.object({ export type ProjectScoreCategoryType = z.infer; export const ProjectScoreCategories = z.union([ z.array(ProjectScoreCategory), - z.record(z.number()), + z.record(z.string(), z.number()), z.array(z.string()), z.null(), ]); @@ -1233,9 +1211,9 @@ export const ProjectScoreConfig = z.union([ ]); export type ProjectScoreConfigType = z.infer; export const ProjectScore = z.object({ - id: z.string().uuid(), - project_id: z.string().uuid(), - user_id: z.string().uuid(), + id: z.uuid(), + project_id: z.uuid(), + user_id: z.uuid(), created: z.union([z.string(), z.null()]).optional(), name: z.string(), description: z.union([z.string(), z.null()]).optional(), @@ -1246,9 +1224,9 @@ export const ProjectScore = z.object({ }); export type ProjectScoreType = z.infer; export const ProjectTag = z.object({ - id: z.string().uuid(), - project_id: z.string().uuid(), - user_id: z.string().uuid(), + id: z.uuid(), + project_id: z.uuid(), + user_id: z.uuid(), created: z.union([z.string(), z.null()]).optional(), name: z.string(), description: z.union([z.string(), z.null()]).optional(), @@ -1257,11 +1235,11 @@ export const ProjectTag = z.object({ }); export type ProjectTagType = z.infer; export const Prompt = z.object({ - id: z.string().uuid(), + id: z.uuid(), _xact_id: z.string(), - project_id: z.string().uuid(), + project_id: z.uuid(), log_id: z.literal("p"), - org_id: z.string().uuid(), + org_id: z.uuid(), name: z.string(), slug: z.string(), description: z.union([z.string(), z.null()]).optional(), @@ -1269,7 +1247,7 @@ export const Prompt = z.object({ prompt_data: PromptDataNullish.optional(), tags: z.union([z.array(z.string()), z.null()]).optional(), metadata: z - .union([z.object({}).partial().passthrough(), z.null()]) + .union([z.looseObject({}).partial(), z.null()]) .optional(), function_type: FunctionTypeEnumNullish.optional(), }); @@ -1281,10 +1259,10 @@ export type PromptOptionsType = z.infer; export const PromptSessionEvent = z.object({ id: z.string(), _xact_id: z.string(), - created: z.string().datetime({ offset: true }), + created: z.iso.datetime({ offset: true }), _pagination_key: z.union([z.string(), z.null()]).optional(), - project_id: z.string().uuid(), - prompt_session_id: z.string().uuid(), + project_id: z.uuid(), + prompt_session_id: z.uuid(), prompt_session_data: z.unknown().optional(), prompt_data: z.unknown().optional(), function_data: z.unknown().optional(), @@ -1304,7 +1282,7 @@ export const ResponseFormat = z.union([ ]); export type ResponseFormatType = z.infer; export const Role = z.object({ - id: z.string().uuid(), + id: z.uuid(), org_id: z.union([z.string(), z.null()]).optional(), user_id: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), @@ -1322,7 +1300,7 @@ export const Role = z.object({ z.null(), ]) .optional(), - member_roles: z.union([z.array(z.string().uuid()), z.null()]).optional(), + member_roles: z.union([z.array(z.uuid()), z.null()]).optional(), }); export type RoleType = z.infer; export const RunEval = z.object({ @@ -1331,14 +1309,14 @@ export const RunEval = z.object({ z.object({ dataset_id: z.string(), _internal_btql: z - .union([z.object({}).partial().passthrough(), z.null()]) + .union([z.looseObject({}).partial(), z.null()]) .optional(), }), z.object({ project_name: z.string(), dataset_name: z.string(), _internal_btql: z - .union([z.object({}).partial().passthrough(), z.null()]) + .union([z.looseObject({}).partial(), z.null()]) .optional(), }), z.object({ data: z.array(z.unknown()) }), @@ -1346,13 +1324,13 @@ export const RunEval = z.object({ task: FunctionId.and(z.unknown()), scores: z.array(FunctionId), experiment_name: z.string().optional(), - metadata: z.object({}).partial().passthrough().optional(), + metadata: z.looseObject({}).partial().optional(), parent: InvokeParent.and(z.unknown()).optional(), stream: z.boolean().optional(), trial_count: z.union([z.number(), z.null()]).optional(), is_public: z.union([z.boolean(), z.null()]).optional(), timeout: z.union([z.number(), z.null()]).optional(), - max_concurrency: z.union([z.number(), z.null()]).optional().default(10), + max_concurrency: z.union([z.number(), z.null()]).optional().prefault(10), base_experiment_name: z.union([z.string(), z.null()]).optional(), base_experiment_id: z.union([z.string(), z.null()]).optional(), git_metadata_settings: GitMetadataSettings.and( @@ -1366,7 +1344,7 @@ export const RunEval = z.object({ }); export type RunEvalType = z.infer; export const ServiceToken = z.object({ - id: z.string().uuid(), + id: z.uuid(), created: z.union([z.string(), z.null()]).optional(), name: z.string(), preview_name: z.string(), @@ -1377,8 +1355,8 @@ export const ServiceToken = z.object({ }); export type ServiceTokenType = z.infer; export const SpanIFrame = z.object({ - id: z.string().uuid(), - project_id: z.string().uuid(), + id: z.uuid(), + project_id: z.uuid(), user_id: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), deleted_at: z.union([z.string(), z.null()]).optional(), @@ -1418,13 +1396,13 @@ export const ToolFunctionDefinition = z.object({ function: z.object({ name: z.string(), description: z.string().optional(), - parameters: z.object({}).partial().passthrough().optional(), + parameters: z.looseObject({}).partial().optional(), strict: z.union([z.boolean(), z.null()]).optional(), }), }); export type ToolFunctionDefinitionType = z.infer; export const User = z.object({ - id: z.string().uuid(), + id: z.uuid(), given_name: z.union([z.string(), z.null()]).optional(), family_name: z.union([z.string(), z.null()]).optional(), email: z.union([z.string(), z.null()]).optional(), @@ -1459,7 +1437,7 @@ export const ViewOptions = z.union([ frameStart: z.union([z.string(), z.null()]), frameEnd: z.union([z.string(), z.null()]), tzUTC: z.union([z.boolean(), z.null()]), - chartVisibility: z.union([z.record(z.boolean()), z.null()]), + chartVisibility: z.union([z.record(z.string(), z.boolean()), z.null()]), projectId: z.union([z.string(), z.null()]), type: z.union([z.enum(["project", "experiment"]), z.null()]), groupBy: z.union([z.string(), z.null()]), @@ -1468,9 +1446,9 @@ export const ViewOptions = z.union([ }), z .object({ - columnVisibility: z.union([z.record(z.boolean()), z.null()]), + columnVisibility: z.union([z.record(z.string(), z.boolean()), z.null()]), columnOrder: z.union([z.array(z.string()), z.null()]), - columnSizing: z.union([z.record(z.number()), z.null()]), + columnSizing: z.union([z.record(z.string(), z.number()), z.null()]), grouping: z.union([z.string(), z.null()]), rowHeight: z.union([z.string(), z.null()]), tallGroupRows: z.union([z.boolean(), z.null()]), @@ -1523,9 +1501,9 @@ export const ViewOptions = z.union([ ]); export type ViewOptionsType = z.infer; export const View = z.object({ - id: z.string().uuid(), + id: z.uuid(), object_type: AclObjectType.and(z.string()), - object_id: z.string().uuid(), + object_id: z.uuid(), view_type: z.enum([ "projects", "experiments", diff --git a/packages/proxy/src/providers/anthropic.ts b/packages/proxy/src/providers/anthropic.ts index 9aa32d52..174a0764 100644 --- a/packages/proxy/src/providers/anthropic.ts +++ b/packages/proxy/src/providers/anthropic.ts @@ -140,7 +140,7 @@ export const anthropicStreamEventSchema = z.discriminatedUnion("type", [ type: z.literal("tool_use"), id: z.string(), name: z.string(), - input: z.record(z.unknown()), + input: z.record(z.string(), z.unknown()), }), ]), }), diff --git a/packages/proxy/src/providers/google.ts b/packages/proxy/src/providers/google.ts index a6b9f923..d5ab4950 100644 --- a/packages/proxy/src/providers/google.ts +++ b/packages/proxy/src/providers/google.ts @@ -188,27 +188,27 @@ export async function openAIMessagesToGoogleMessages( return sortedContent; } -const finishReason = finishReasonSchema.Enum; +// finishReasonSchema.Enum (v3) is not available in Zod v4; switch on string literals instead function translateFinishReason( reason?: FinishReason | null, ): OpenAIChatCompletionChoice["finish_reason"] | null { // "length" | "stop" | "tool_calls" | "content_filter" | "function_call" switch (reason) { - case finishReason.MAX_TOKENS: + case "MAX_TOKENS": return "length"; - case finishReason.SAFETY: - case finishReason.PROHIBITED_CONTENT: - case finishReason.SPII: - case finishReason.BLOCKLIST: + case "SAFETY": + case "PROHIBITED_CONTENT": + case "SPII": + case "BLOCKLIST": return "content_filter"; - case finishReason.STOP: + case "STOP": return "stop"; - case finishReason.RECITATION: - case finishReason.LANGUAGE: - case finishReason.OTHER: - case finishReason.FINISH_REASON_UNSPECIFIED: - case finishReason.MALFORMED_FUNCTION_CALL: + case "RECITATION": + case "LANGUAGE": + case "OTHER": + case "FINISH_REASON_UNSPECIFIED": + case "MALFORMED_FUNCTION_CALL": return "content_filter"; case undefined: default: diff --git a/packages/proxy/types/anthropic.ts b/packages/proxy/types/anthropic.ts index 2f9b405b..f2f672df 100644 --- a/packages/proxy/types/anthropic.ts +++ b/packages/proxy/types/anthropic.ts @@ -51,7 +51,7 @@ const anthropicToolUseContentPartSchema = z.object({ type: z.literal("tool_use"), id: z.string(), name: z.string(), - input: z.record(z.any()), + input: z.record(z.string(), z.unknown()), cache_control: cacheControlSchema.optional(), }); @@ -59,7 +59,7 @@ const anthropicServerToolUseContentPartSchema = z.object({ type: z.literal("server_tool_use"), id: z.string(), name: z.enum(["web_search", "code_execution"]), - input: z.record(z.any()), + input: z.record(z.string(), z.unknown()), cache_control: cacheControlSchema.optional(), }); @@ -129,7 +129,7 @@ const anthropicMCPToolUseContentPartSchema = z.object({ type: z.literal("mcp_tool_use"), id: z.string(), name: z.string(), - input: z.record(z.any()), + input: z.record(z.string(), z.unknown()), server_name: z.string(), cache_control: cacheControlSchema.nullish(), }); @@ -145,7 +145,7 @@ const anthropicMCPToolResultContentPartSchema = z.object({ type: z.literal("text"), text: z.string(), // This is a simplification of the strict citation schema - citations: z.array(z.record(z.any())).nullish(), + citations: z.array(z.record(z.string(), z.unknown())).nullish(), cache_control: cacheControlSchema.nullish(), }), ), diff --git a/packages/proxy/types/google.ts b/packages/proxy/types/google.ts index 33795fc2..578d7951 100644 --- a/packages/proxy/types/google.ts +++ b/packages/proxy/types/google.ts @@ -101,14 +101,14 @@ const fileDataSchema = z.object({ const functionCallSchema = z.object({ id: z.string().nullish(), - args: z.record(z.unknown()).nullish(), + args: z.record(z.string(), z.unknown()).nullish(), name: z.string().nullish(), }); const functionResponseSchema = z.object({ id: z.string().nullish(), name: z.string().nullish(), - response: z.record(z.unknown()).nullish(), + response: z.record(z.string(), z.unknown()).nullish(), }); const blobSchema = z.object({ @@ -495,7 +495,7 @@ const schemaSchema: z.ZodSchema = z.object({ minimum: z.number().nullish(), nullable: z.boolean().nullish(), pattern: z.string().nullish(), - properties: z.lazy(() => z.record(schemaSchema)).nullish(), + properties: z.lazy(() => z.record(z.string(), schemaSchema)).nullish(), propertyOrdering: z.array(z.string()).nullish(), required: z.array(z.string()).nullish(), title: z.string().nullish(), @@ -627,7 +627,7 @@ const generateContentConfigSchema = z.object({ safetySettings: z.array(safetySettingSchema).nullish(), tools: toolListUnionSchema.nullish(), toolConfig: toolConfigSchema.nullish(), - labels: z.record(z.string()).nullish(), + labels: z.record(z.string(), z.string()).nullish(), cachedContent: z.string().nullish(), responseModalities: z.array(z.string()).nullish(), mediaResolution: mediaResolutionSchema.nullish(), From 65598876a895c552d6e41dd4d1d856377ee73776 Mon Sep 17 00:00:00 2001 From: Caitlin Pinn Date: Tue, 23 Dec 2025 15:32:32 -0800 Subject: [PATCH 2/7] fix package.json zod version --- apis/cloudflare/package.json | 2 +- apis/vercel/next-env.d.ts | 2 +- package.json | 2 +- packages/proxy/package.json | 2 +- packages/proxy/schema/secrets.ts | 62 ++++++++++++--------------- pnpm-lock.yaml | 72 ++++++++++++++++---------------- 6 files changed, 67 insertions(+), 75 deletions(-) diff --git a/apis/cloudflare/package.json b/apis/cloudflare/package.json index 8289c4ae..b5812a52 100644 --- a/apis/cloudflare/package.json +++ b/apis/cloudflare/package.json @@ -26,6 +26,6 @@ "@opentelemetry/resources": "^2.0.0", "@opentelemetry/sdk-metrics": "^2.1.0", "dotenv": "^16.3.1", - "zod": "3.25.34" + "zod": "4.2.1" } } diff --git a/apis/vercel/next-env.d.ts b/apis/vercel/next-env.d.ts index fd36f949..725dd6f2 100644 --- a/apis/vercel/next-env.d.ts +++ b/apis/vercel/next-env.d.ts @@ -3,4 +3,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. +// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. diff --git a/package.json b/package.json index 9d752ccd..1f4d4a97 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,6 @@ }, "packageManager": "pnpm@8.15.5", "resolutions": { - "zod": "3.25.34" + "zod": "4.2.1" } } diff --git a/packages/proxy/package.json b/packages/proxy/package.json index 8d4e1ef0..0dd82400 100644 --- a/packages/proxy/package.json +++ b/packages/proxy/package.json @@ -120,6 +120,6 @@ "openai": "4.104.0", "openapi-json-schema": "^2.0.0", "uuid": "^9.0.1", - "zod": "^3.25.34" + "zod": "4.2.1" } } diff --git a/packages/proxy/schema/secrets.ts b/packages/proxy/schema/secrets.ts index 59587d71..d121fbb4 100644 --- a/packages/proxy/schema/secrets.ts +++ b/packages/proxy/schema/secrets.ts @@ -9,20 +9,18 @@ export const BaseMetadataSchema = z.strictObject({ supportsStreaming: z.boolean().prefault(true), }); -export const AzureMetadataSchema = BaseMetadataSchema.extend( - z.strictObject({ - api_base: z.url(), - api_version: z.string().prefault("2023-07-01-preview"), - deployment: z.string().nullish(), - auth_type: z.enum(["api_key", "entra_api"]).prefault("api_key"), - no_named_deployment: z - .boolean() - .prefault(false) - .describe( - "If true, the deployment name will not be used in the request path.", - ), - }).shape -); +export const AzureMetadataSchema = BaseMetadataSchema.extend({ + api_base: z.url(), + api_version: z.string().prefault("2023-07-01-preview"), + deployment: z.string().nullish(), + auth_type: z.enum(["api_key", "entra_api"]).prefault("api_key"), + no_named_deployment: z + .boolean() + .prefault(false) + .describe( + "If true, the deployment name will not be used in the request path.", + ), +}); export const AzureEntraSecretSchema = z.object({ client_id: z.string().min(1, "Client ID cannot be empty"), @@ -32,30 +30,24 @@ export const AzureEntraSecretSchema = z.object({ }); export type AzureEntraSecret = z.infer; -export const BedrockMetadataSchema = BaseMetadataSchema.extend( - z.strictObject({ - region: z.string().min(1, "Region cannot be empty"), - access_key: z.string().min(1, "Access key cannot be empty"), - session_token: z.string().nullish(), - api_base: z.union([z.url(), z.string().length(0)]).nullish(), - }).shape -); +export const BedrockMetadataSchema = BaseMetadataSchema.extend({ + region: z.string().min(1, "Region cannot be empty"), + access_key: z.string().min(1, "Access key cannot be empty"), + session_token: z.string().nullish(), + api_base: z.union([z.url(), z.string().length(0)]).nullish(), +}); export type BedrockMetadata = z.infer; -export const VertexMetadataSchema = BaseMetadataSchema.extend( - z.strictObject({ - project: z.string().min(1, "Project cannot be empty"), - authType: z.enum(["access_token", "service_account_key"]), - api_base: z.union([z.url(), z.string().length(0)]).nullish(), - }).shape -); +export const VertexMetadataSchema = BaseMetadataSchema.extend({ + project: z.string().min(1, "Project cannot be empty"), + authType: z.enum(["access_token", "service_account_key"]), + api_base: z.union([z.url(), z.string().length(0)]).nullish(), +}); -export const DatabricksMetadataSchema = BaseMetadataSchema.extend( - z.strictObject({ - api_base: z.url(), - auth_type: z.enum(["pat", "service_principal_oauth"]).prefault("pat"), - }).shape -); +export const DatabricksMetadataSchema = BaseMetadataSchema.extend({ + api_base: z.url(), + auth_type: z.enum(["pat", "service_principal_oauth"]).prefault("pat"), +}); export const DatabricksOAuthSecretSchema = z.object({ client_id: z.string().min(1, "Client ID cannot be empty"), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8ee12257..12475bfb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,7 @@ settings: excludeLinksFromLockfile: false overrides: - zod: 3.25.34 + zod: 4.2.1 importers: @@ -49,16 +49,16 @@ importers: version: 2.1.0(@opentelemetry/api@1.9.0) braintrust: specifier: ^0.3.7 - version: 0.3.7(zod@3.25.34) + version: 0.3.7(zod@4.2.1) dotenv: specifier: ^16.3.1 version: 16.3.1 openai: specifier: ^6.3.0 - version: 6.3.0(zod@3.25.34) + version: 6.3.0(zod@4.2.1) zod: - specifier: 3.25.34 - version: 3.25.34 + specifier: 4.2.1 + version: 4.2.1 devDependencies: '@cloudflare/workers-types': specifier: ^4.20250810.0 @@ -116,7 +116,7 @@ importers: version: 4.19.2 openai: specifier: ^4.104.0 - version: 4.104.0(zod@3.25.34) + version: 4.104.0(zod@4.2.1) redis: specifier: ^4.6.8 version: 4.6.8 @@ -256,7 +256,7 @@ importers: version: 9.0.2 openai: specifier: 4.104.0 - version: 4.104.0(zod@3.25.34) + version: 4.104.0(zod@4.2.1) openapi-json-schema: specifier: ^2.0.0 version: 2.0.0 @@ -264,8 +264,8 @@ importers: specifier: ^9.0.1 version: 9.0.1 zod: - specifier: 3.25.34 - version: 3.25.34 + specifier: 4.2.1 + version: 4.2.1 devDependencies: '@types/content-disposition': specifier: ^0.5.8 @@ -317,7 +317,7 @@ importers: version: 17.7.2 zod-to-json-schema: specifier: ^3.24.6 - version: 3.24.6(zod@3.25.34) + version: 3.24.6(zod@4.2.1) packages: @@ -4561,7 +4561,7 @@ packages: dependencies: '@vue/compiler-ssr': 3.5.22 '@vue/shared': 3.5.22 - vue: 3.5.22(typescript@5.5.4) + vue: 3.5.22(typescript@5.3.3) dev: false /@vue/shared@3.5.13: @@ -4572,14 +4572,14 @@ packages: resolution: {integrity: sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==} dev: false - /@zodios/core@10.9.6(axios@1.13.1)(zod@3.25.34): + /@zodios/core@10.9.6(axios@1.13.1)(zod@4.2.1): resolution: {integrity: sha512-aH4rOdb3AcezN7ws8vDgBfGboZMk2JGGzEq/DtW65MhnRxyTGRuLJRWVQ/2KxDgWvV2F5oTkAS+5pnjKbl0n+A==} peerDependencies: axios: ^0.x || ^1.0.0 - zod: 3.25.34 + zod: 4.2.1 dependencies: axios: 1.13.1 - zod: 3.25.34 + zod: 4.2.1 dev: true /abbrev@1.1.1: @@ -5086,11 +5086,11 @@ packages: fill-range: 7.1.1 dev: true - /braintrust@0.3.7(zod@3.25.34): + /braintrust@0.3.7(zod@4.2.1): resolution: {integrity: sha512-P6nJLgM98IOiBvAsgfUn9dbrLhmTfvED/+2ouacImTgs9adlZoGrIib9BkRAm+keSTfKLBPFqMmUi7QZ4ClemQ==} hasBin: true peerDependencies: - zod: 3.25.34 + zod: 4.2.1 dependencies: '@ai-sdk/provider': 1.1.3 '@next/env': 14.2.3 @@ -5112,8 +5112,8 @@ packages: slugify: 1.6.6 source-map: 0.7.4 uuid: 9.0.1 - zod: 3.25.34 - zod-to-json-schema: 3.23.5(zod@3.25.34) + zod: 4.2.1 + zod-to-json-schema: 3.23.5(zod@4.2.1) transitivePeerDependencies: - '@aws-sdk/credential-provider-web-identity' - supports-color @@ -8070,7 +8070,7 @@ packages: workerd: 1.20251008.0 ws: 8.18.0 youch: 4.1.0-beta.10 - zod: 3.25.34 + zod: 4.2.1 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -8474,12 +8474,12 @@ packages: mimic-fn: 2.1.0 dev: true - /openai@4.104.0(zod@3.25.34): + /openai@4.104.0(zod@4.2.1): resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==} hasBin: true peerDependencies: ws: ^8.18.0 - zod: 3.25.34 + zod: 4.2.1 peerDependenciesMeta: ws: optional: true @@ -8493,24 +8493,24 @@ packages: form-data-encoder: 1.7.2 formdata-node: 4.4.1 node-fetch: 2.7.0 - zod: 3.25.34 + zod: 4.2.1 transitivePeerDependencies: - encoding dev: false - /openai@6.3.0(zod@3.25.34): + /openai@6.3.0(zod@4.2.1): resolution: {integrity: sha512-E6vOGtZvdcb4yXQ5jXvDlUG599OhIkb/GjBLZXS+qk0HF+PJReIldEc9hM8Ft81vn+N6dRdFRb7BZNK8bbvXrw==} hasBin: true peerDependencies: ws: ^8.18.0 - zod: 3.25.34 + zod: 4.2.1 peerDependenciesMeta: ws: optional: true zod: optional: true dependencies: - zod: 3.25.34 + zod: 4.2.1 dev: false /openapi-json-schema@2.0.0: @@ -8527,7 +8527,7 @@ packages: dependencies: '@apidevtools/swagger-parser': 10.1.1(openapi-types@12.1.3) '@liuli-util/fs-extra': 0.1.0 - '@zodios/core': 10.9.6(axios@1.13.1)(zod@3.25.34) + '@zodios/core': 10.9.6(axios@1.13.1)(zod@4.2.1) axios: 1.13.1 cac: 6.7.14 handlebars: 4.7.8 @@ -8538,7 +8538,7 @@ packages: tanu: 0.1.13 ts-pattern: 5.8.0 whence: 2.1.0 - zod: 3.25.34 + zod: 4.2.1 transitivePeerDependencies: - debug - react @@ -10002,7 +10002,7 @@ packages: peerDependencies: vue: '>=3.2.26 < 4' dependencies: - vue: 3.5.22(typescript@5.5.4) + vue: 3.5.22(typescript@5.3.3) dev: false /tailwindcss@3.2.7(postcss@8.4.38): @@ -11236,21 +11236,21 @@ packages: youch-core: 0.3.3 dev: true - /zod-to-json-schema@3.23.5(zod@3.25.34): + /zod-to-json-schema@3.23.5(zod@4.2.1): resolution: {integrity: sha512-5wlSS0bXfF/BrL4jPAbz9da5hDlDptdEppYfe+x4eIJ7jioqKG9uUxOwPzqof09u/XeVdrgFu29lZi+8XNDJtA==} peerDependencies: - zod: 3.25.34 + zod: 4.2.1 dependencies: - zod: 3.25.34 + zod: 4.2.1 dev: false - /zod-to-json-schema@3.24.6(zod@3.25.34): + /zod-to-json-schema@3.24.6(zod@4.2.1): resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==} peerDependencies: - zod: 3.25.34 + zod: 4.2.1 dependencies: - zod: 3.25.34 + zod: 4.2.1 dev: true - /zod@3.25.34: - resolution: {integrity: sha512-lZHvSc2PpWdcfpHlyB33HA9nqP16GpC9IpiG4lYq9jZCJVLZNnWd6Y1cj79bcLSBKTkxepfpjckPv5Y5VOPlwA==} + /zod@4.2.1: + resolution: {integrity: sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==} From 23b31a3a2a2a12097ada85d2dc1fe7a9a1073705 Mon Sep 17 00:00:00 2001 From: Caitlin Pinn Date: Tue, 23 Dec 2025 15:45:45 -0800 Subject: [PATCH 3/7] fix linting --- packages/proxy/schema/models.ts | 8 +- packages/proxy/schema/secrets.ts | 150 +++++++++++++------------------ 2 files changed, 71 insertions(+), 87 deletions(-) diff --git a/packages/proxy/schema/models.ts b/packages/proxy/schema/models.ts index 92dd93a6..c84936e4 100644 --- a/packages/proxy/schema/models.ts +++ b/packages/proxy/schema/models.ts @@ -87,14 +87,19 @@ export const ModelSchema = z.object({ export type ModelSpec = z.infer; import modelListJson from "./model_list.json"; -const modelListJsonTyped = z.record(z.string(), ModelSchema).parse(modelListJson); +const modelListJsonTyped = z + .record(z.string(), ModelSchema) + .parse(modelListJson); // Because this file can be included and bundled in various ways, it's important to // really inject these variables into the global scope, rather than let the bundler // have its way with them. declare global { + // eslint-disable-next-line no-var var _proxy_availableModels: { [name: string]: ModelSpec } | undefined; + // eslint-disable-next-line no-var var _proxy_cachedModels: { [name: string]: ModelSpec } | null; + // eslint-disable-next-line no-var var _proxy_cacheTimestamp: number | null; } @@ -158,6 +163,7 @@ async function loadModelsFromControlPlane( throw new Error(`Failed to fetch models: ${response.statusText}`); } const data = await response.json(); + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions globalThis._proxy_cachedModels = data as { [name: string]: ModelSpec }; globalThis._proxy_cacheTimestamp = Date.now(); } catch (error) { diff --git a/packages/proxy/schema/secrets.ts b/packages/proxy/schema/secrets.ts index d121fbb4..6a595246 100644 --- a/packages/proxy/schema/secrets.ts +++ b/packages/proxy/schema/secrets.ts @@ -2,12 +2,12 @@ import { z } from "zod"; import { ModelSchema } from "./models"; export const BaseMetadataSchema = z.strictObject({ - models: z.array(z.string()).nullish(), - customModels: z.record(z.string(), ModelSchema).nullish(), - excludeDefaultModels: z.boolean().nullish(), - additionalHeaders: z.record(z.string(), z.string()).nullish(), - supportsStreaming: z.boolean().prefault(true), - }); + models: z.array(z.string()).nullish(), + customModels: z.record(z.string(), ModelSchema).nullish(), + excludeDefaultModels: z.boolean().nullish(), + additionalHeaders: z.record(z.string(), z.string()).nullish(), + supportsStreaming: z.boolean().prefault(true), +}); export const AzureMetadataSchema = BaseMetadataSchema.extend({ api_base: z.url(), @@ -55,88 +55,66 @@ export const DatabricksOAuthSecretSchema = z.object({ }); export type DatabricksOAuthSecret = z.infer; -export const OpenAIMetadataSchema = BaseMetadataSchema.extend( - z.strictObject({ - api_base: z.union([ - z.url().optional(), - z.string().length(0), - z.null(), - ]), - organization_id: z.string().nullish(), - }).shape -); - -export const MistralMetadataSchema = BaseMetadataSchema.extend( - z.strictObject({ - api_base: z.union([z.url(), z.string().length(0)]).nullish(), - }).shape -); +export const OpenAIMetadataSchema = BaseMetadataSchema.extend({ + api_base: z.union([z.url().optional(), z.string().length(0), z.null()]), + organization_id: z.string().nullish(), +}); + +export const MistralMetadataSchema = BaseMetadataSchema.extend({ + api_base: z.union([z.url(), z.string().length(0)]).nullish(), +}); const APISecretBaseSchema = z.strictObject({ - id: z.uuid().nullish(), - org_name: z.string().nullish(), - name: z.string().nullish(), - secret: z.string(), - metadata: z.record(z.string(), z.unknown()).nullish(), - }); + id: z.uuid().nullish(), + org_name: z.string().nullish(), + name: z.string().nullish(), + secret: z.string(), + metadata: z.record(z.string(), z.unknown()).nullish(), +}); export const APISecretSchema = z.union([ - APISecretBaseSchema.extend( - z.object({ - type: z.enum([ - "perplexity", - "anthropic", - "google", - "replicate", - "together", - "baseten", - "ollama", - "groq", - "lepton", - "fireworks", - "cerebras", - "xAI", - "js", - ]), - metadata: BaseMetadataSchema.nullish(), - }).shape - ), - APISecretBaseSchema.extend( - z.object({ - type: z.literal("openai"), - metadata: OpenAIMetadataSchema.nullish(), - }).shape - ), - APISecretBaseSchema.extend( - z.object({ - type: z.literal("azure"), - metadata: AzureMetadataSchema.nullish(), - }).shape - ), - APISecretBaseSchema.extend( - z.object({ - type: z.literal("bedrock"), - metadata: BedrockMetadataSchema.nullish(), - }).shape - ), - APISecretBaseSchema.extend( - z.object({ - type: z.literal("vertex"), - metadata: VertexMetadataSchema.nullish(), - }).shape - ), - APISecretBaseSchema.extend( - z.object({ - type: z.literal("databricks"), - metadata: DatabricksMetadataSchema.nullish(), - }).shape - ), - APISecretBaseSchema.extend( - z.object({ - type: z.literal("mistral"), - metadata: MistralMetadataSchema.nullish(), - }).shape - ), + APISecretBaseSchema.extend({ + type: z.enum([ + "perplexity", + "anthropic", + "google", + "replicate", + "together", + "baseten", + "ollama", + "groq", + "lepton", + "fireworks", + "cerebras", + "xAI", + "js", + ]), + metadata: BaseMetadataSchema.nullish(), + }), + APISecretBaseSchema.extend({ + type: z.literal("openai"), + metadata: OpenAIMetadataSchema.nullish(), + }), + APISecretBaseSchema.extend({ + type: z.literal("azure"), + metadata: AzureMetadataSchema.nullish(), + }), + APISecretBaseSchema.extend({ + type: z.literal("bedrock"), + metadata: BedrockMetadataSchema.nullish(), + }), + APISecretBaseSchema.extend({ + type: z.literal("vertex"), + metadata: VertexMetadataSchema.nullish(), + }), + APISecretBaseSchema.extend({ + type: z.literal("databricks"), + metadata: DatabricksMetadataSchema.nullish(), + }), + APISecretBaseSchema.extend({ + type: z.literal("mistral"), + metadata: MistralMetadataSchema.nullish(), + }), ]); export type APISecret = z.infer; @@ -148,8 +126,8 @@ export const proxyLoggingParamSchema = z compress_audio: z.boolean().prefault(true), }) .refine((data) => data.parent || data.project_name, { - error: "Either 'parent' or 'project_name' must be provided" -}) + error: "Either 'parent' or 'project_name' must be provided", + }) .describe( "If present, proxy will log requests to the given Braintrust project or parent span.", ); From 813b1d6a59cc42b367c09279cde2ef26dbdcef35 Mon Sep 17 00:00:00 2001 From: Caitlin Pinn Date: Tue, 23 Dec 2025 15:52:08 -0800 Subject: [PATCH 4/7] fix linting --- packages/proxy/src/generated_types.ts | 372 ++++++++++--------- packages/proxy/utils/tempCredentials.test.ts | 2 +- 2 files changed, 198 insertions(+), 176 deletions(-) diff --git a/packages/proxy/src/generated_types.ts b/packages/proxy/src/generated_types.ts index 2c1e4ec1..8b8a40bf 100644 --- a/packages/proxy/src/generated_types.ts +++ b/packages/proxy/src/generated_types.ts @@ -31,27 +31,27 @@ export const Permission = z.enum([ ]); export type PermissionType = z.infer; export const Acl = z.object({ - id: z.uuid(), + id: z.string().uuid(), object_type: AclObjectType.and(z.string()), - object_id: z.uuid(), + object_id: z.string().uuid(), user_id: z.union([z.string(), z.null()]).optional(), group_id: z.union([z.string(), z.null()]).optional(), permission: Permission.and(z.union([z.string(), z.null()])).optional(), restrict_object_type: AclObjectType.and(z.unknown()).optional(), role_id: z.union([z.string(), z.null()]).optional(), - _object_org_id: z.uuid(), + _object_org_id: z.string().uuid(), created: z.union([z.string(), z.null()]).optional(), }); export type AclType = z.infer; export const AISecret = z.object({ - id: z.uuid(), + id: z.string().uuid(), created: z.union([z.string(), z.null()]).optional(), updated_at: z.union([z.string(), z.null()]).optional(), - org_id: z.uuid(), + org_id: z.string().uuid(), name: z.string(), type: z.union([z.string(), z.null()]).optional(), metadata: z - .union([z.looseObject({}).partial(), z.null()]) + .union([z.object({}).partial().passthrough(), z.null()]) .optional(), preview_secret: z.union([z.string(), z.null()]).optional(), }); @@ -60,7 +60,7 @@ export const ResponseFormatJsonSchema = z.object({ name: z.string(), description: z.string().optional(), schema: z - .union([z.looseObject({}).partial(), z.string()]) + .union([z.object({}).partial().passthrough(), z.string()]) .optional(), strict: z.union([z.boolean(), z.null()]).optional(), }); @@ -119,7 +119,7 @@ export const AnyModelParams = z.object({ }); export type AnyModelParamsType = z.infer; export const ApiKey = z.object({ - id: z.uuid(), + id: z.string().uuid(), created: z.union([z.string(), z.null()]).optional(), name: z.string(), preview_name: z.string(), @@ -231,7 +231,7 @@ export const CallEvent = z.union([ ]); export type CallEventType = z.infer; export const ChatCompletionContentPartTextWithTitle = z.object({ - text: z.string().prefault(""), + text: z.string().default(""), type: z.literal("text"), cache_control: z.object({ type: z.literal("ephemeral") }).optional(), }); @@ -272,7 +272,7 @@ export type ChatCompletionContentPartType = z.infer< typeof ChatCompletionContentPart >; export const ChatCompletionContentPartText = z.object({ - text: z.string().prefault(""), + text: z.string().default(""), type: z.literal("text"), cache_control: z.object({ type: z.literal("ephemeral") }).optional(), }); @@ -319,7 +319,7 @@ export const ChatCompletionMessageParam = z.union([ z.object({ content: z.union([z.string(), z.array(ChatCompletionContentPartText)]), role: z.literal("tool"), - tool_call_id: z.string().prefault(""), + tool_call_id: z.string().default(""), }), z.object({ content: z.union([z.string(), z.null()]), @@ -365,7 +365,7 @@ export const ChatCompletionOpenAIMessageParam = z.union([ z.object({ content: z.union([z.string(), z.array(ChatCompletionContentPartText)]), role: z.literal("tool"), - tool_call_id: z.string().prefault(""), + tool_call_id: z.string().default(""), }), z.object({ content: z.union([z.string(), z.null()]), @@ -385,7 +385,7 @@ export const ChatCompletionTool = z.object({ function: z.object({ name: z.string(), description: z.string().optional(), - parameters: z.looseObject({}).partial().optional(), + parameters: z.object({}).partial().passthrough().optional(), }), type: z.literal("function"), }); @@ -401,25 +401,25 @@ export const CodeBundle = z.object({ eval_name: z.string(), position: z.union([ z.object({ type: z.literal("task") }), - z.object({ type: z.literal("scorer"), index: z.int().gte(0) }), + z.object({ type: z.literal("scorer"), index: z.number().int().gte(0) }), ]), }), - z.object({ type: z.literal("function"), index: z.int().gte(0) }), + z.object({ type: z.literal("function"), index: z.number().int().gte(0) }), ]), bundle_id: z.string(), preview: z.union([z.string(), z.null()]).optional(), }); export type CodeBundleType = z.infer; export const Dataset = z.object({ - id: z.uuid(), - project_id: z.uuid(), + id: z.string().uuid(), + project_id: z.string().uuid(), name: z.string(), description: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), deleted_at: z.union([z.string(), z.null()]).optional(), user_id: z.union([z.string(), z.null()]).optional(), metadata: z - .union([z.looseObject({}).partial(), z.null()]) + .union([z.object({}).partial().passthrough(), z.null()]) .optional(), }); export type DatasetType = z.infer; @@ -433,7 +433,7 @@ export const ObjectReferenceNullish = z.union([ "function", "prompt_session", ]), - object_id: z.uuid(), + object_id: z.string().uuid(), id: z.string(), _xact_id: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), @@ -444,16 +444,18 @@ export type ObjectReferenceNullishType = z.infer; export const DatasetEvent = z.object({ id: z.string(), _xact_id: z.string(), - created: z.iso.datetime({ offset: true }), + created: z.string().datetime({ offset: true }), _pagination_key: z.union([z.string(), z.null()]).optional(), - project_id: z.uuid(), - dataset_id: z.uuid(), + project_id: z.string().uuid(), + dataset_id: z.string().uuid(), input: z.unknown().optional(), expected: z.unknown().optional(), metadata: z .union([ - z.looseObject({ model: z.union([z.string(), z.null()]) }) - .partial(), + z + .object({ model: z.union([z.string(), z.null()]) }) + .partial() + .passthrough(), z.null(), ]) .optional(), @@ -467,9 +469,9 @@ export const DatasetEvent = z.object({ }); export type DatasetEventType = z.infer; export const EnvVar = z.object({ - id: z.uuid(), + id: z.string().uuid(), object_type: z.enum(["organization", "project", "function"]), - object_id: z.uuid(), + object_id: z.string().uuid(), name: z.string(), created: z.union([z.string(), z.null()]).optional(), used: z.union([z.string(), z.null()]).optional(), @@ -493,8 +495,8 @@ export const RepoInfo = z.union([ ]); export type RepoInfoType = z.infer; export const Experiment = z.object({ - id: z.uuid(), - project_id: z.uuid(), + id: z.string().uuid(), + project_id: z.string().uuid(), name: z.string(), description: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), @@ -507,7 +509,7 @@ export const Experiment = z.object({ public: z.boolean(), user_id: z.union([z.string(), z.null()]).optional(), metadata: z - .union([z.looseObject({}).partial(), z.null()]) + .union([z.object({}).partial().passthrough(), z.null()]) .optional(), tags: z.union([z.array(z.string()), z.null()]).optional(), }); @@ -518,42 +520,48 @@ export const SpanType = z.union([ ]); export type SpanTypeType = z.infer; export const SpanAttributes = z.union([ - z.looseObject({ name: z.union([z.string(), z.null()]), type: SpanType }) - .partial(), + z + .object({ name: z.union([z.string(), z.null()]), type: SpanType }) + .partial() + .passthrough(), z.null(), ]); export type SpanAttributesType = z.infer; export const ExperimentEvent = z.object({ id: z.string(), _xact_id: z.string(), - created: z.iso.datetime({ offset: true }), + created: z.string().datetime({ offset: true }), _pagination_key: z.union([z.string(), z.null()]).optional(), - project_id: z.uuid(), - experiment_id: z.uuid(), + project_id: z.string().uuid(), + experiment_id: z.string().uuid(), input: z.unknown().optional(), output: z.unknown().optional(), expected: z.unknown().optional(), error: z.unknown().optional(), scores: z - .union([z.record(z.string(), z.union([z.number(), z.null()])), z.null()]) + .union([z.record(z.union([z.number(), z.null()])), z.null()]) .optional(), metadata: z .union([ - z.looseObject({ model: z.union([z.string(), z.null()]) }) - .partial(), + z + .object({ model: z.union([z.string(), z.null()]) }) + .partial() + .passthrough(), z.null(), ]) .optional(), tags: z.union([z.array(z.string()), z.null()]).optional(), - metrics: z.union([z.record(z.string(), z.number()), z.null()]).optional(), + metrics: z.union([z.record(z.number()), z.null()]).optional(), context: z .union([ - z.looseObject({ - caller_functionname: z.union([z.string(), z.null()]), - caller_filename: z.union([z.string(), z.null()]), - caller_lineno: z.union([z.number(), z.null()]), - }) - .partial(), + z + .object({ + caller_functionname: z.union([z.string(), z.null()]), + caller_filename: z.union([z.string(), z.null()]), + caller_lineno: z.union([z.number(), z.null()]), + }) + .partial() + .passthrough(), z.null(), ]) .optional(), @@ -590,72 +598,82 @@ export const PromptBlockDataNullish = z.union([ ]); export type PromptBlockDataNullishType = z.infer; export const ModelParams = z.union([ - z.looseObject({ - use_cache: z.boolean(), - reasoning_enabled: z.boolean(), - reasoning_budget: z.number(), - temperature: z.number(), - top_p: z.number(), - max_tokens: z.number(), - max_completion_tokens: z.number(), - frequency_penalty: z.number(), - presence_penalty: z.number(), - response_format: ResponseFormatNullish, - tool_choice: z.union([ - z.literal("auto"), - z.literal("none"), - z.literal("required"), - z.looseObject({ - type: z.literal("function"), - function: z.looseObject({ name: z.string() }), - }), - ]), - function_call: z.union([ - z.literal("auto"), - z.literal("none"), - z.looseObject({ name: z.string() }), - ]), - n: z.number(), - stop: z.array(z.string()), - reasoning_effort: z.enum(["minimal", "low", "medium", "high"]), - verbosity: z.enum(["low", "medium", "high"]), - }) - .partial(), - z.looseObject({ - use_cache: z.boolean().optional(), - reasoning_enabled: z.boolean().optional(), - reasoning_budget: z.number().optional(), - max_tokens: z.number(), - temperature: z.number(), - top_p: z.number().optional(), - top_k: z.number().optional(), - stop_sequences: z.array(z.string()).optional(), - max_tokens_to_sample: z.number().optional(), + z + .object({ + use_cache: z.boolean(), + reasoning_enabled: z.boolean(), + reasoning_budget: z.number(), + temperature: z.number(), + top_p: z.number(), + max_tokens: z.number(), + max_completion_tokens: z.number(), + frequency_penalty: z.number(), + presence_penalty: z.number(), + response_format: ResponseFormatNullish, + tool_choice: z.union([ + z.literal("auto"), + z.literal("none"), + z.literal("required"), + z.object({ + type: z.literal("function"), + function: z.object({ name: z.string() }), }), - z.looseObject({ - use_cache: z.boolean(), - reasoning_enabled: z.boolean(), - reasoning_budget: z.number(), - temperature: z.number(), - maxOutputTokens: z.number(), - topP: z.number(), - topK: z.number(), - }) - .partial(), - z.looseObject({ - use_cache: z.boolean(), - reasoning_enabled: z.boolean(), - reasoning_budget: z.number(), - temperature: z.number(), - topK: z.number(), - }) - .partial(), - z.looseObject({ - use_cache: z.boolean(), - reasoning_enabled: z.boolean(), - reasoning_budget: z.number(), - }) - .partial(), + ]), + function_call: z.union([ + z.literal("auto"), + z.literal("none"), + z.object({ name: z.string() }), + ]), + n: z.number(), + stop: z.array(z.string()), + reasoning_effort: z.enum(["minimal", "low", "medium", "high"]), + verbosity: z.enum(["low", "medium", "high"]), + }) + .partial() + .passthrough(), + z + .object({ + use_cache: z.boolean().optional(), + reasoning_enabled: z.boolean().optional(), + reasoning_budget: z.number().optional(), + max_tokens: z.number(), + temperature: z.number(), + top_p: z.number().optional(), + top_k: z.number().optional(), + stop_sequences: z.array(z.string()).optional(), + max_tokens_to_sample: z.number().optional(), + }) + .passthrough(), + z + .object({ + use_cache: z.boolean(), + reasoning_enabled: z.boolean(), + reasoning_budget: z.number(), + temperature: z.number(), + maxOutputTokens: z.number(), + topP: z.number(), + topK: z.number(), + }) + .partial() + .passthrough(), + z + .object({ + use_cache: z.boolean(), + reasoning_enabled: z.boolean(), + reasoning_budget: z.number(), + temperature: z.number(), + topK: z.number(), + }) + .partial() + .passthrough(), + z + .object({ + use_cache: z.boolean(), + reasoning_enabled: z.boolean(), + reasoning_budget: z.number(), + }) + .partial() + .passthrough(), ]); export type ModelParamsType = z.infer; export const PromptOptionsNullish = z.union([ @@ -669,7 +687,7 @@ export const PromptParserNullish = z.union([ z.object({ type: z.literal("llm_classifier"), use_cot: z.boolean(), - choice_scores: z.record(z.string(), z.number().gte(0).lte(1)), + choice_scores: z.record(z.number().gte(0).lte(1)), }), z.null(), ]); @@ -708,7 +726,7 @@ export const FunctionTypeEnumNullish = z.union([ export type FunctionTypeEnumNullishType = z.infer< typeof FunctionTypeEnumNullish >; -export const FunctionIdRef = z.looseObject({}).partial(); +export const FunctionIdRef = z.object({}).partial().passthrough(); export type FunctionIdRefType = z.infer; export const PromptBlockData = z.union([ z.object({ @@ -791,8 +809,8 @@ export const GraphEdge = z.object({ export type GraphEdgeType = z.infer; export const GraphData = z.object({ type: z.literal("graph"), - nodes: z.record(z.string(), GraphNode), - edges: z.record(z.string(), GraphEdge), + nodes: z.record(GraphNode), + edges: z.record(GraphEdge), }); export type GraphDataType = z.infer; export const FunctionData = z.union([ @@ -816,17 +834,17 @@ export const FunctionData = z.union([ type: z.literal("remote_eval"), endpoint: z.string(), eval_name: z.string(), - parameters: z.looseObject({}).partial(), + parameters: z.object({}).partial().passthrough(), }), z.object({ type: z.literal("global"), name: z.string() }), ]); export type FunctionDataType = z.infer; export const Function = z.object({ - id: z.uuid(), + id: z.string().uuid(), _xact_id: z.string(), - project_id: z.uuid(), + project_id: z.string().uuid(), log_id: z.literal("p"), - org_id: z.uuid(), + org_id: z.string().uuid(), name: z.string(), slug: z.string(), description: z.union([z.string(), z.null()]).optional(), @@ -834,7 +852,7 @@ export const Function = z.object({ prompt_data: PromptDataNullish.optional(), tags: z.union([z.array(z.string()), z.null()]).optional(), metadata: z - .union([z.looseObject({}).partial(), z.null()]) + .union([z.object({}).partial().passthrough(), z.null()]) .optional(), function_type: FunctionTypeEnumNullish.optional(), function_data: FunctionData, @@ -842,7 +860,7 @@ export const Function = z.object({ .union([ z.object({ object_type: AclObjectType.and(z.string()), - object_id: z.uuid(), + object_id: z.string().uuid(), internal: z.union([z.boolean(), z.null()]).optional(), }), z.null(), @@ -902,7 +920,7 @@ export const FunctionId = z.union([ }), z.object({ inline_prompt: PromptData.optional(), - inline_function: z.looseObject({}).partial(), + inline_function: z.object({}).partial().passthrough(), function_type: FunctionTypeEnum.optional(), name: z.union([z.string(), z.null()]).optional(), }), @@ -943,15 +961,15 @@ export const GitMetadataSettings = z.object({ }); export type GitMetadataSettingsType = z.infer; export const Group = z.object({ - id: z.uuid(), - org_id: z.uuid(), + id: z.string().uuid(), + org_id: z.string().uuid(), user_id: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), name: z.string(), description: z.union([z.string(), z.null()]).optional(), deleted_at: z.union([z.string(), z.null()]).optional(), - member_users: z.union([z.array(z.uuid()), z.null()]).optional(), - member_groups: z.union([z.array(z.uuid()), z.null()]).optional(), + member_users: z.union([z.array(z.string().uuid()), z.null()]).optional(), + member_groups: z.union([z.array(z.string().uuid()), z.null()]).optional(), }); export type GroupType = z.infer; export const IfExists = z.enum(["error", "ignore", "replace"]); @@ -971,7 +989,7 @@ export const InvokeParent = z.union([ ]) .optional(), propagated_event: z - .union([z.looseObject({}).partial(), z.null()]) + .union([z.object({}).partial().passthrough(), z.null()]) .optional(), }), z.string(), @@ -984,7 +1002,7 @@ export const InvokeFunction = FunctionId.and( .object({ input: z.unknown(), expected: z.unknown(), - metadata: z.union([z.looseObject({}).partial(), z.null()]), + metadata: z.union([z.object({}).partial().passthrough(), z.null()]), tags: z.union([z.array(z.string()), z.null()]), messages: z.array(ChatCompletionMessageParam), parent: InvokeParent, @@ -1014,7 +1032,7 @@ export const ObjectReference = z.object({ "function", "prompt_session", ]), - object_id: z.uuid(), + object_id: z.string().uuid(), id: z.string(), _xact_id: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), @@ -1033,7 +1051,7 @@ export const OnlineScoreConfig = z.union([ ]); export type OnlineScoreConfigType = z.infer; export const Organization = z.object({ - id: z.uuid(), + id: z.string().uuid(), name: z.string(), api_url: z.union([z.string(), z.null()]).optional(), is_universal_api: z.union([z.boolean(), z.null()]).optional(), @@ -1077,8 +1095,8 @@ export const ProjectSettings = z.union([ ]); export type ProjectSettingsType = z.infer; export const Project = z.object({ - id: z.uuid(), - org_id: z.uuid(), + id: z.string().uuid(), + org_id: z.string().uuid(), name: z.string(), created: z.union([z.string(), z.null()]).optional(), deleted_at: z.union([z.string(), z.null()]).optional(), @@ -1093,8 +1111,8 @@ export const RetentionObjectType = z.enum([ ]); export type RetentionObjectTypeType = z.infer; export const ProjectAutomation = z.object({ - id: z.uuid(), - project_id: z.uuid(), + id: z.string().uuid(), + project_id: z.string().uuid(), user_id: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), name: z.string(), @@ -1135,34 +1153,38 @@ export const ProjectLogsEvent = z.object({ id: z.string(), _xact_id: z.string(), _pagination_key: z.union([z.string(), z.null()]).optional(), - created: z.iso.datetime({ offset: true }), - org_id: z.uuid(), - project_id: z.uuid(), + created: z.string().datetime({ offset: true }), + org_id: z.string().uuid(), + project_id: z.string().uuid(), log_id: z.literal("g"), input: z.unknown().optional(), output: z.unknown().optional(), expected: z.unknown().optional(), error: z.unknown().optional(), scores: z - .union([z.record(z.string(), z.union([z.number(), z.null()])), z.null()]) + .union([z.record(z.union([z.number(), z.null()])), z.null()]) .optional(), metadata: z .union([ - z.looseObject({ model: z.union([z.string(), z.null()]) }) - .partial(), + z + .object({ model: z.union([z.string(), z.null()]) }) + .partial() + .passthrough(), z.null(), ]) .optional(), tags: z.union([z.array(z.string()), z.null()]).optional(), - metrics: z.union([z.record(z.string(), z.number()), z.null()]).optional(), + metrics: z.union([z.record(z.number()), z.null()]).optional(), context: z .union([ - z.looseObject({ - caller_functionname: z.union([z.string(), z.null()]), - caller_filename: z.union([z.string(), z.null()]), - caller_lineno: z.union([z.number(), z.null()]), - }) - .partial(), + z + .object({ + caller_functionname: z.union([z.string(), z.null()]), + caller_filename: z.union([z.string(), z.null()]), + caller_lineno: z.union([z.number(), z.null()]), + }) + .partial() + .passthrough(), z.null(), ]) .optional(), @@ -1194,7 +1216,7 @@ export const ProjectScoreCategory = z.object({ export type ProjectScoreCategoryType = z.infer; export const ProjectScoreCategories = z.union([ z.array(ProjectScoreCategory), - z.record(z.string(), z.number()), + z.record(z.number()), z.array(z.string()), z.null(), ]); @@ -1211,9 +1233,9 @@ export const ProjectScoreConfig = z.union([ ]); export type ProjectScoreConfigType = z.infer; export const ProjectScore = z.object({ - id: z.uuid(), - project_id: z.uuid(), - user_id: z.uuid(), + id: z.string().uuid(), + project_id: z.string().uuid(), + user_id: z.string().uuid(), created: z.union([z.string(), z.null()]).optional(), name: z.string(), description: z.union([z.string(), z.null()]).optional(), @@ -1224,9 +1246,9 @@ export const ProjectScore = z.object({ }); export type ProjectScoreType = z.infer; export const ProjectTag = z.object({ - id: z.uuid(), - project_id: z.uuid(), - user_id: z.uuid(), + id: z.string().uuid(), + project_id: z.string().uuid(), + user_id: z.string().uuid(), created: z.union([z.string(), z.null()]).optional(), name: z.string(), description: z.union([z.string(), z.null()]).optional(), @@ -1235,11 +1257,11 @@ export const ProjectTag = z.object({ }); export type ProjectTagType = z.infer; export const Prompt = z.object({ - id: z.uuid(), + id: z.string().uuid(), _xact_id: z.string(), - project_id: z.uuid(), + project_id: z.string().uuid(), log_id: z.literal("p"), - org_id: z.uuid(), + org_id: z.string().uuid(), name: z.string(), slug: z.string(), description: z.union([z.string(), z.null()]).optional(), @@ -1247,7 +1269,7 @@ export const Prompt = z.object({ prompt_data: PromptDataNullish.optional(), tags: z.union([z.array(z.string()), z.null()]).optional(), metadata: z - .union([z.looseObject({}).partial(), z.null()]) + .union([z.object({}).partial().passthrough(), z.null()]) .optional(), function_type: FunctionTypeEnumNullish.optional(), }); @@ -1259,10 +1281,10 @@ export type PromptOptionsType = z.infer; export const PromptSessionEvent = z.object({ id: z.string(), _xact_id: z.string(), - created: z.iso.datetime({ offset: true }), + created: z.string().datetime({ offset: true }), _pagination_key: z.union([z.string(), z.null()]).optional(), - project_id: z.uuid(), - prompt_session_id: z.uuid(), + project_id: z.string().uuid(), + prompt_session_id: z.string().uuid(), prompt_session_data: z.unknown().optional(), prompt_data: z.unknown().optional(), function_data: z.unknown().optional(), @@ -1282,7 +1304,7 @@ export const ResponseFormat = z.union([ ]); export type ResponseFormatType = z.infer; export const Role = z.object({ - id: z.uuid(), + id: z.string().uuid(), org_id: z.union([z.string(), z.null()]).optional(), user_id: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), @@ -1300,7 +1322,7 @@ export const Role = z.object({ z.null(), ]) .optional(), - member_roles: z.union([z.array(z.uuid()), z.null()]).optional(), + member_roles: z.union([z.array(z.string().uuid()), z.null()]).optional(), }); export type RoleType = z.infer; export const RunEval = z.object({ @@ -1309,14 +1331,14 @@ export const RunEval = z.object({ z.object({ dataset_id: z.string(), _internal_btql: z - .union([z.looseObject({}).partial(), z.null()]) + .union([z.object({}).partial().passthrough(), z.null()]) .optional(), }), z.object({ project_name: z.string(), dataset_name: z.string(), _internal_btql: z - .union([z.looseObject({}).partial(), z.null()]) + .union([z.object({}).partial().passthrough(), z.null()]) .optional(), }), z.object({ data: z.array(z.unknown()) }), @@ -1324,13 +1346,13 @@ export const RunEval = z.object({ task: FunctionId.and(z.unknown()), scores: z.array(FunctionId), experiment_name: z.string().optional(), - metadata: z.looseObject({}).partial().optional(), + metadata: z.object({}).partial().passthrough().optional(), parent: InvokeParent.and(z.unknown()).optional(), stream: z.boolean().optional(), trial_count: z.union([z.number(), z.null()]).optional(), is_public: z.union([z.boolean(), z.null()]).optional(), timeout: z.union([z.number(), z.null()]).optional(), - max_concurrency: z.union([z.number(), z.null()]).optional().prefault(10), + max_concurrency: z.union([z.number(), z.null()]).optional().default(10), base_experiment_name: z.union([z.string(), z.null()]).optional(), base_experiment_id: z.union([z.string(), z.null()]).optional(), git_metadata_settings: GitMetadataSettings.and( @@ -1344,7 +1366,7 @@ export const RunEval = z.object({ }); export type RunEvalType = z.infer; export const ServiceToken = z.object({ - id: z.uuid(), + id: z.string().uuid(), created: z.union([z.string(), z.null()]).optional(), name: z.string(), preview_name: z.string(), @@ -1355,8 +1377,8 @@ export const ServiceToken = z.object({ }); export type ServiceTokenType = z.infer; export const SpanIFrame = z.object({ - id: z.uuid(), - project_id: z.uuid(), + id: z.string().uuid(), + project_id: z.string().uuid(), user_id: z.union([z.string(), z.null()]).optional(), created: z.union([z.string(), z.null()]).optional(), deleted_at: z.union([z.string(), z.null()]).optional(), @@ -1396,13 +1418,13 @@ export const ToolFunctionDefinition = z.object({ function: z.object({ name: z.string(), description: z.string().optional(), - parameters: z.looseObject({}).partial().optional(), + parameters: z.object({}).partial().passthrough().optional(), strict: z.union([z.boolean(), z.null()]).optional(), }), }); export type ToolFunctionDefinitionType = z.infer; export const User = z.object({ - id: z.uuid(), + id: z.string().uuid(), given_name: z.union([z.string(), z.null()]).optional(), family_name: z.union([z.string(), z.null()]).optional(), email: z.union([z.string(), z.null()]).optional(), @@ -1437,7 +1459,7 @@ export const ViewOptions = z.union([ frameStart: z.union([z.string(), z.null()]), frameEnd: z.union([z.string(), z.null()]), tzUTC: z.union([z.boolean(), z.null()]), - chartVisibility: z.union([z.record(z.string(), z.boolean()), z.null()]), + chartVisibility: z.union([z.record(z.boolean()), z.null()]), projectId: z.union([z.string(), z.null()]), type: z.union([z.enum(["project", "experiment"]), z.null()]), groupBy: z.union([z.string(), z.null()]), @@ -1446,9 +1468,9 @@ export const ViewOptions = z.union([ }), z .object({ - columnVisibility: z.union([z.record(z.string(), z.boolean()), z.null()]), + columnVisibility: z.union([z.record(z.boolean()), z.null()]), columnOrder: z.union([z.array(z.string()), z.null()]), - columnSizing: z.union([z.record(z.string(), z.number()), z.null()]), + columnSizing: z.union([z.record(z.number()), z.null()]), grouping: z.union([z.string(), z.null()]), rowHeight: z.union([z.string(), z.null()]), tallGroupRows: z.union([z.boolean(), z.null()]), @@ -1501,9 +1523,9 @@ export const ViewOptions = z.union([ ]); export type ViewOptionsType = z.infer; export const View = z.object({ - id: z.uuid(), + id: z.string().uuid(), object_type: AclObjectType.and(z.string()), - object_id: z.uuid(), + object_id: z.string().uuid(), view_type: z.enum([ "projects", "experiments", diff --git a/packages/proxy/utils/tempCredentials.test.ts b/packages/proxy/utils/tempCredentials.test.ts index d441b532..d38c842e 100644 --- a/packages/proxy/utils/tempCredentials.test.ts +++ b/packages/proxy/utils/tempCredentials.test.ts @@ -162,7 +162,7 @@ test("verifyTempCredentials wrong payload type", async () => { }); await expect( verifyTempCredentials({ jwt: jwtWrongSchema, cacheGet }), - ).rejects.toThrow("invalid_literal"); + ).rejects.toThrow("invalid_value"); // Non object. const jwtWrongType = jwtSign("not an object", "auth token", { From 4df2dd69c68e92dda7f9216848598d4073ef2ceb Mon Sep 17 00:00:00 2001 From: Caitlin Pinn Date: Tue, 23 Dec 2025 16:06:46 -0800 Subject: [PATCH 5/7] fix generated_types --- packages/proxy/schema/secrets.ts | 2 +- packages/proxy/scripts/generate_types.ts | 295 ++++++++++++++++++++++- packages/proxy/src/generated_types.ts | 23 +- 3 files changed, 306 insertions(+), 14 deletions(-) diff --git a/packages/proxy/schema/secrets.ts b/packages/proxy/schema/secrets.ts index 6a595246..2d8d9cf8 100644 --- a/packages/proxy/schema/secrets.ts +++ b/packages/proxy/schema/secrets.ts @@ -65,7 +65,7 @@ export const MistralMetadataSchema = BaseMetadataSchema.extend({ }); const APISecretBaseSchema = z.strictObject({ - id: z.uuid().nullish(), + id: z.string().uuid().nullish(), org_name: z.string().nullish(), name: z.string().nullish(), secret: z.string(), diff --git a/packages/proxy/scripts/generate_types.ts b/packages/proxy/scripts/generate_types.ts index c6448c37..f8ab625b 100644 --- a/packages/proxy/scripts/generate_types.ts +++ b/packages/proxy/scripts/generate_types.ts @@ -5,6 +5,7 @@ import { } from "openapi-zod-client"; import * as fs from "fs/promises"; import path from "node:path"; +import * as ts from "typescript"; const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url)); const OPENAPI_SPEC_PATH = path.join(SCRIPT_DIR, "../generated_types.json"); @@ -17,6 +18,7 @@ const OUTPUT_PATH = path.join(SCRIPT_DIR, "../src/generated_types.ts"); async function main() { const openApiDoc = JSON.parse(await fs.readFile(OPENAPI_SPEC_PATH, "utf-8")); const handlebars = getHandlebars(); + // only outputs as zod v3, support for v4 still in progress. await generateZodClientFromOpenAPI({ openApiDoc, templatePath: TEMPLATE_PATH, @@ -28,11 +30,302 @@ async function main() { additionalPropertiesDefaultValue: false, }, }); + // Read generated code. Optionally skip post-processing when debugging raw output. + let code = await fs.readFile(OUTPUT_PATH, "utf8"); + + // If SKIP_CODMOD=1 is set in the environment, write the generated file as-is + // (with the generated banner) and exit. Useful to inspect upstream generator output + // before applying our v3->v4 codemod. + if (process.env.SKIP_CODMOD === "1") { + const internalGitSha = openApiDoc.info["x-internal-git-sha"] || "UNKNOWN"; + const banner = `// Auto-generated file (internal git SHA ${internalGitSha}) -- do not modify\n\n`; + await fs.writeFile(OUTPUT_PATH, banner + code); + return; + } + + const fixGenerated = (s: string) => { + // Robust AST transform using TypeScript Transformer API. This reliably + // rewrites single-arg `z.record(valueSchema)` into `z.record(z.string(), valueSchema)` + // and unwraps parenthesized expressions. If anything goes wrong, fall back to the cleaned string. + try { + const sf = ts.createSourceFile( + "generated_types.ts", + s, + ts.ScriptTarget.Latest, + /*setParentNodes*/ true, + ts.ScriptKind.TS, + ); + + const isZCall = (expr: ts.Expression, name: string) => + ts.isPropertyAccessExpression(expr) && + ts.isIdentifier(expr.expression) && + expr.expression.text === "z" && + expr.name.text === name; + + const makeZCallExpr = (name: string) => + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier("z"), + name, + ), + undefined, + [], + ); + + const transformer: ts.TransformerFactory = (context) => { + const visit: ts.Visitor = (node) => { + if (ts.isCallExpression(node)) { + const expr = node.expression; + + // Handle z.record(...) general case + if (isZCall(expr, "record")) { + const args = node.arguments.slice(); + if (args.length === 1) { + // single-arg -> insert z.string() as key schema + const valueArg = ts.isParenthesizedExpression(args[0]) + ? args[0].expression + : args[0]; + return ts.factory.updateCallExpression( + node, + node.expression, + node.typeArguments, + [makeZCallExpr("string"), valueArg], + ); + } + + // If call already has 2+ args, just unwrap parentheses on second arg + if (args.length >= 2) { + const second = args[1]; + const newSecond = ts.isParenthesizedExpression(second) + ? second.expression + : second; + const newArgs = [args[0], newSecond, ...args.slice(2)]; + return ts.factory.updateCallExpression( + node, + node.expression, + node.typeArguments, + newArgs, + ); + } + } + } + return ts.visitEachChild(node, visit, context); + }; + return (node) => ts.visitNode(node, visit) as ts.SourceFile; + }; + + const result = ts.transform(sf, [transformer]); + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Transformer API returns Node[]; we expect a SourceFile here + const transformed = result.transformed[0] as ts.SourceFile; + const printer = ts.createPrinter({ removeComments: false }); + const printed = printer.printFile(transformed); + result.dispose(); + return printed; + } catch { + return s; + } + }; + + // Token-level repair: balance parentheses for `z.record(...)` calls, insert missing + // `z.unknown()` value argument when the call only had a single key schema, and + // remove duplicated trailing ')' tokens following the call. + const repairRecordCalls = (src: string) => { + const needle = "z.record("; + let out = ""; + let i = 0; + while (true) { + const p = src.indexOf(needle, i); + if (p === -1) { + out += src.slice(i); + break; + } + out += src.slice(i, p); + let k = p + needle.length; + let depth = 1; + let inSingle = false; + let inDouble = false; + let inBack = false; + let escaped = false; + let end = -1; + for (; k < src.length; k++) { + const ch = src[k]; + if (escaped) { + escaped = false; + continue; + } + if (ch === "\\") { + escaped = true; + continue; + } + if (inSingle) { + if (ch === "'") { + inSingle = false; + } + continue; + } + if (inDouble) { + if (ch === '"') { + inDouble = false; + } + continue; + } + if (inBack) { + if (ch === "`") { + inBack = false; + } + continue; + } + if (ch === "'") { + inSingle = true; + continue; + } + if (ch === '"') { + inDouble = true; + continue; + } + if (ch === "`") { + inBack = true; + continue; + } + if (ch === "(") { + depth++; + continue; + } + if (ch === ")") { + depth--; + if (depth === 0) { + end = k; + break; + } + continue; + } + } + if (end === -1) { + // malformed remainder; append rest and break + out += src.slice(p); + break; + } + + const inner = src.slice(p + needle.length, end); + + // determine if there is a top-level comma in `inner` + let hasTopComma = false; + let pd = 0, + bd = 0, + cd = 0; // paren, bracket, brace depth for detection + inSingle = inDouble = inBack = escaped = false; + for (let m = 0; m < inner.length; m++) { + const ch = inner[m]; + if (escaped) { + escaped = false; + continue; + } + if (ch === "\\") { + escaped = true; + continue; + } + if (inSingle) { + if (ch === "'") inSingle = false; + continue; + } + if (inDouble) { + if (ch === '"') inDouble = false; + continue; + } + if (inBack) { + if (ch === "`") inBack = false; + continue; + } + if (ch === "'") { + inSingle = true; + continue; + } + if (ch === '"') { + inDouble = true; + continue; + } + if (ch === "`") { + inBack = true; + continue; + } + if (ch === "(") { + pd++; + continue; + } + if (ch === ")") { + if (pd > 0) pd--; + continue; + } + if (ch === "[") { + bd++; + continue; + } + if (ch === "]") { + if (bd > 0) bd--; + continue; + } + if (ch === "{") { + cd++; + continue; + } + if (ch === "}") { + if (cd > 0) cd--; + continue; + } + if (ch === "," && pd === 0 && bd === 0 && cd === 0) { + hasTopComma = true; + break; + } + } + + let replacedCall = null; + if (!hasTopComma) { + // single-arg form: insert z.unknown() as the second arg + replacedCall = `${needle}${inner.trim()}, z.unknown())`; + } else { + // keep original text for call + replacedCall = src.slice(p, end + 1); + } + + // append the replacement + out += replacedCall; + + // advance k to after end, and collapse any immediately following duplicated ')' tokens down to one + let j = end + 1; + // count consecutive ) characters + let closeCount = 0; + while (j < src.length && src[j] === ")") { + closeCount++; + j++; + } + if (closeCount > 0) { + // we already emitted one ')' as part of replacement; if extra ) found, skip them + // (effectively collapsing duplicates) + } + + i = j; + } + return out; + }; + + code = fixGenerated(code); + // Apply token-level repairs for z.record(...) cases + code = repairRecordCalls(code); - const code = await fs.readFile(OUTPUT_PATH, "utf8"); const internalGitSha = openApiDoc.info["x-internal-git-sha"] || "UNKNOWN"; const banner = `// Auto-generated file (internal git SHA ${internalGitSha}) -- do not modify\n\n`; await fs.writeFile(OUTPUT_PATH, banner + code); + + // Format the generated file with prettier + const { execSync } = await import("node:child_process"); + try { + execSync(`./node_modules/.bin/prettier --write "${OUTPUT_PATH}"`, { + cwd: path.join(SCRIPT_DIR, "../../.."), + stdio: "inherit", + }); + } catch (error) { + console.warn("Warning: Could not format generated file with prettier"); + } } main(); diff --git a/packages/proxy/src/generated_types.ts b/packages/proxy/src/generated_types.ts index 8b8a40bf..9004c0f3 100644 --- a/packages/proxy/src/generated_types.ts +++ b/packages/proxy/src/generated_types.ts @@ -1,7 +1,6 @@ // Auto-generated file (internal git SHA e6490ffb3d42f5dbc59d748bb5016f6d8f11cac2) -- do not modify import { z } from "zod"; - export const AclObjectType = z.union([ z.enum([ "organization", @@ -539,7 +538,7 @@ export const ExperimentEvent = z.object({ expected: z.unknown().optional(), error: z.unknown().optional(), scores: z - .union([z.record(z.union([z.number(), z.null()])), z.null()]) + .union([z.record(z.string(), z.union([z.number(), z.null()])), z.null()]) .optional(), metadata: z .union([ @@ -551,7 +550,7 @@ export const ExperimentEvent = z.object({ ]) .optional(), tags: z.union([z.array(z.string()), z.null()]).optional(), - metrics: z.union([z.record(z.number()), z.null()]).optional(), + metrics: z.union([z.record(z.string(), z.number()), z.null()]).optional(), context: z .union([ z @@ -687,7 +686,7 @@ export const PromptParserNullish = z.union([ z.object({ type: z.literal("llm_classifier"), use_cot: z.boolean(), - choice_scores: z.record(z.number().gte(0).lte(1)), + choice_scores: z.record(z.string(), z.number().gte(0).lte(1)), }), z.null(), ]); @@ -809,8 +808,8 @@ export const GraphEdge = z.object({ export type GraphEdgeType = z.infer; export const GraphData = z.object({ type: z.literal("graph"), - nodes: z.record(GraphNode), - edges: z.record(GraphEdge), + nodes: z.record(z.string(), GraphNode), + edges: z.record(z.string(), GraphEdge), }); export type GraphDataType = z.infer; export const FunctionData = z.union([ @@ -1162,7 +1161,7 @@ export const ProjectLogsEvent = z.object({ expected: z.unknown().optional(), error: z.unknown().optional(), scores: z - .union([z.record(z.union([z.number(), z.null()])), z.null()]) + .union([z.record(z.string(), z.union([z.number(), z.null()])), z.null()]) .optional(), metadata: z .union([ @@ -1174,7 +1173,7 @@ export const ProjectLogsEvent = z.object({ ]) .optional(), tags: z.union([z.array(z.string()), z.null()]).optional(), - metrics: z.union([z.record(z.number()), z.null()]).optional(), + metrics: z.union([z.record(z.string(), z.number()), z.null()]).optional(), context: z .union([ z @@ -1216,7 +1215,7 @@ export const ProjectScoreCategory = z.object({ export type ProjectScoreCategoryType = z.infer; export const ProjectScoreCategories = z.union([ z.array(ProjectScoreCategory), - z.record(z.number()), + z.record(z.string(), z.number()), z.array(z.string()), z.null(), ]); @@ -1459,7 +1458,7 @@ export const ViewOptions = z.union([ frameStart: z.union([z.string(), z.null()]), frameEnd: z.union([z.string(), z.null()]), tzUTC: z.union([z.boolean(), z.null()]), - chartVisibility: z.union([z.record(z.boolean()), z.null()]), + chartVisibility: z.union([z.record(z.string(), z.boolean()), z.null()]), projectId: z.union([z.string(), z.null()]), type: z.union([z.enum(["project", "experiment"]), z.null()]), groupBy: z.union([z.string(), z.null()]), @@ -1468,9 +1467,9 @@ export const ViewOptions = z.union([ }), z .object({ - columnVisibility: z.union([z.record(z.boolean()), z.null()]), + columnVisibility: z.union([z.record(z.string(), z.boolean()), z.null()]), columnOrder: z.union([z.array(z.string()), z.null()]), - columnSizing: z.union([z.record(z.number()), z.null()]), + columnSizing: z.union([z.record(z.string(), z.number()), z.null()]), grouping: z.union([z.string(), z.null()]), rowHeight: z.union([z.string(), z.null()]), tallGroupRows: z.union([z.boolean(), z.null()]), From 8ca8a9fd3ba7f7ebe9cbc8e312312f3772436db4 Mon Sep 17 00:00:00 2001 From: Caitlin Pinn Date: Sun, 28 Dec 2025 16:15:14 -0800 Subject: [PATCH 6/7] fix type error caused after ai upgrade --- packages/proxy/utils/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/proxy/utils/index.ts b/packages/proxy/utils/index.ts index ebcf2380..8d8775ce 100644 --- a/packages/proxy/utils/index.ts +++ b/packages/proxy/utils/index.ts @@ -18,10 +18,12 @@ export function getCurrentUnixTimestamp(): number { } export const effortToBudgetMultiplier = { + none: 0, minimal: 0, low: 0.2, medium: 0.5, high: 0.8, + xhigh: 1.0, } as const; export const getBudgetMultiplier = ( From b67caf65484fe99bfa2c5220ede70b78627dd665 Mon Sep 17 00:00:00 2001 From: Caitlin Pinn Date: Sun, 28 Dec 2025 16:29:25 -0800 Subject: [PATCH 7/7] fix proxy --- packages/proxy/src/providers/google.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/proxy/src/providers/google.ts b/packages/proxy/src/providers/google.ts index d5ab4950..7a4ae1c7 100644 --- a/packages/proxy/src/providers/google.ts +++ b/packages/proxy/src/providers/google.ts @@ -367,13 +367,10 @@ function convertGeminiPartsToOpenAIContent( } } - // If only text content (single part), return as string for backwards compatibility - if ( - !hasNonTextContent && - contentParts.length === 1 && - contentParts[0].type === "text" - ) { - return contentParts[0].text ?? ""; + // If only text content (no images), return as string for backwards compatibility + // Concatenate all text parts into a single string + if (!hasNonTextContent && contentParts.every((p) => p.type === "text")) { + return contentParts.map((p) => p.text ?? "").join(""); } // If no content parts, return empty string