@arizeai/phoenix-client
Version:
A client for the Phoenix API
160 lines (146 loc) • 5.35 kB
text/typescript
import type {
ChatCompletionCreateParams,
ChatCompletionMessageParam,
ResponseFormatJSONSchema,
} from "openai/resources";
import invariant from "tiny-invariant";
import {
safelyConvertMessageToProvider,
safelyConvertToolChoiceToProvider,
safelyConvertToolDefinitionToProvider,
} from "../../schemas/llm/converters";
import type { OpenaiToolChoice } from "../../schemas/llm/openai/toolChoiceSchemas";
import { phoenixResponseFormatToOpenAI } from "../../schemas/llm/phoenixPrompt/converters";
import { isPromptToolRaw } from "../../types/prompts";
import { formatPromptMessages } from "../../utils/formatPromptMessages";
import type { toSDKParamsBase, Variables } from "./types";
// We must re-export these types so that they are included in the phoenix-client distribution
export type {
ChatCompletionCreateParams,
ChatCompletionMessageParam,
ResponseFormatJSONSchema,
};
export type ToOpenAIParams<PromptVariables extends Variables> =
toSDKParamsBase<PromptVariables>;
/**
* Convert a Phoenix prompt to OpenAI client sdk's chat completion parameters
*
* @returns The converted chat completion parameters
*/
export const toOpenAI = <PromptVariables extends Variables = Variables>({
prompt,
variables,
}: ToOpenAIParams<PromptVariables>): ChatCompletionCreateParams | null => {
try {
let invocationParameters: Partial<ChatCompletionCreateParams>;
switch (prompt.invocation_parameters.type) {
case "openai":
invocationParameters = prompt.invocation_parameters.openai;
break;
case "azure_openai":
invocationParameters = prompt.invocation_parameters.azure_openai;
break;
case "deepseek":
invocationParameters = prompt.invocation_parameters.deepseek;
break;
case "xai":
invocationParameters = prompt.invocation_parameters.xai;
break;
case "ollama":
invocationParameters = prompt.invocation_parameters.ollama;
break;
case "cerebras":
invocationParameters = prompt.invocation_parameters.cerebras;
break;
case "fireworks":
invocationParameters = prompt.invocation_parameters.fireworks;
break;
case "groq":
invocationParameters = prompt.invocation_parameters.groq;
break;
case "moonshot":
invocationParameters = prompt.invocation_parameters.moonshot;
break;
case "perplexity":
invocationParameters = prompt.invocation_parameters.perplexity;
break;
case "together":
invocationParameters = prompt.invocation_parameters.together;
break;
default:
// eslint-disable-next-line no-console
console.warn(
"Prompt is not an OpenAI-family prompt, falling back to default OpenAI invocation parameters"
);
invocationParameters = {};
break;
}
// parts of the prompt that can be directly converted to OpenAI params
const baseCompletionParams = {
model: prompt.model_name,
// Invocation parameters are validated on the phoenix-side
...invocationParameters,
} satisfies Partial<ChatCompletionCreateParams>;
if (!("messages" in prompt.template)) {
return null;
}
let formattedMessages = prompt.template.messages;
if (variables) {
formattedMessages = formatPromptMessages(
prompt.template_format,
formattedMessages,
variables
);
}
const messages = formattedMessages.map((message) => {
const openAIMessage = safelyConvertMessageToProvider({
message,
targetProvider: "OPENAI",
});
invariant(openAIMessage, "Message is not valid");
return openAIMessage;
});
const toolsList = prompt.tools?.tools ?? [];
// Cast: raw tools are `Record<string, unknown>` straight from the prompt
// store. We trust the upstream caller to have stored a shape OpenAI's
// SDK accepts; no validation here.
const tools =
toolsList.length === 0
? undefined
: (toolsList.map((tool) => {
if (isPromptToolRaw(tool)) {
return tool.raw;
}
const openAIToolDefinition = safelyConvertToolDefinitionToProvider({
toolDefinition: tool,
targetProvider: "OPENAI",
});
invariant(openAIToolDefinition, "Tool definition is not valid");
return openAIToolDefinition;
}) as unknown as ChatCompletionCreateParams["tools"]);
const tool_choice: OpenaiToolChoice | undefined = tools
? (safelyConvertToolChoiceToProvider({
toolChoice: prompt?.tools?.tool_choice,
targetProvider: "OPENAI",
}) ?? undefined)
: undefined;
const response_format = prompt.response_format
? phoenixResponseFormatToOpenAI.parse(prompt.response_format)
: undefined;
// combine base and computed params
const completionParams = {
...baseCompletionParams,
messages,
tools,
tool_choice,
response_format,
} satisfies Partial<ChatCompletionCreateParams>;
return completionParams;
} catch (e) {
// eslint-disable-next-line no-console
console.warn(`Failed to convert prompt to OpenAI params`);
// eslint-disable-next-line no-console
console.error(e);
return null;
}
};