diff --git a/app/src/pages/playground/__tests__/playgroundUtils.test.ts b/app/src/pages/playground/__tests__/playgroundUtils.test.ts index 4ed94250cc..2b108d1814 100644 --- a/app/src/pages/playground/__tests__/playgroundUtils.test.ts +++ b/app/src/pages/playground/__tests__/playgroundUtils.test.ts @@ -375,7 +375,7 @@ describe("transformSpanAttributesToPlaygroundInstance", () => { playgroundInstance: { ...expectedPlaygroundInstanceWithIO, }, - parsingErrors: [], + parsingErrors: [MODEL_CONFIG_WITH_INVOCATION_PARAMETERS_PARSING_ERROR], }); }); @@ -398,6 +398,23 @@ describe("transformSpanAttributesToPlaygroundInstance", () => { parsingErrors: [MODEL_CONFIG_WITH_INVOCATION_PARAMETERS_PARSING_ERROR], }); }); + + it("should return invocation parameters parsing errors if they are malformed", () => { + const parsedAttributes = { + llm: { + model_name: "gpt-3.5-turbo", + invocation_parameters: '"invalid"', + }, + }; + expect(getModelConfigFromAttributes(parsedAttributes)).toEqual({ + modelConfig: { + modelName: "gpt-3.5-turbo", + provider: "OPENAI", + invocationParameters: {}, + }, + parsingErrors: [MODEL_CONFIG_WITH_INVOCATION_PARAMETERS_PARSING_ERROR], + }); + }); }); describe("getChatRole", () => { diff --git a/app/src/pages/playground/schemas.ts b/app/src/pages/playground/schemas.ts index 04b81143e9..0b8a7687d7 100644 --- a/app/src/pages/playground/schemas.ts +++ b/app/src/pages/playground/schemas.ts @@ -7,7 +7,7 @@ import { } from "@arizeai/openinference-semantic-conventions"; import { ChatMessage } from "@phoenix/store"; -import { Mutable, schemaForType } from "@phoenix/typeUtils"; +import { isObject, Mutable, schemaForType } from "@phoenix/typeUtils"; import { safelyParseJSON } from "@phoenix/utils/jsonUtils"; import { InvocationParameters } from "./__generated__/PlaygroundOutputSubscription.graphql"; @@ -136,8 +136,8 @@ const stringToInvocationParametersSchema = z .string() .transform((s) => { const { json } = safelyParseJSON(s); - if (json == null) { - return {}; + if (!isObject(json)) { + return null; } // using the invocationParameterSchema as a base, // apply all matching keys from the input string, @@ -156,10 +156,23 @@ const stringToInvocationParametersSchema = z ), })) // reparse the object to ensure the mapped keys are also validated - .transform(invocationParameterSchema.parse) .parse(json) ); }) + .transform((v, ctx) => { + const result = invocationParameterSchema.safeParse(v); + if (!result.success) { + // bubble errors up to the original schema + result.error.issues.forEach((issue) => { + ctx.addIssue(issue); + }); + // https://zod.dev/?id=validating-during-transform + // ensures that this schema still infers the "success" type + // errors will throw instead + return z.NEVER; + } + return result.data; + }) .default("{}"); /** * The zod schema for llm model config