revert
This commit is contained in:
@@ -147,7 +147,7 @@ function contentToText(content: string | Array<TextContent | ImageContent>): str
|
||||
.join("\n");
|
||||
}
|
||||
|
||||
function assistantContentToText(content: Array<TextContent | ThinkingContent | ImageContent | ToolCall>): string {
|
||||
function assistantContentToText(content: Array<TextContent | ThinkingContent | ToolCall>): string {
|
||||
return content
|
||||
.map((block) => {
|
||||
if (block.type === "text") {
|
||||
@@ -156,9 +156,6 @@ function assistantContentToText(content: Array<TextContent | ThinkingContent | I
|
||||
if (block.type === "thinking") {
|
||||
return block.thinking;
|
||||
}
|
||||
if (block.type === "image") {
|
||||
return `[image:${block.mimeType}]`;
|
||||
}
|
||||
return `${block.name}:${JSON.stringify(block.arguments)}`;
|
||||
})
|
||||
.join("\n");
|
||||
@@ -365,13 +362,6 @@ async function streamWithDeltas(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (block.type === "image") {
|
||||
partial.content = [...partial.content, block];
|
||||
stream.push({ type: "image_start", contentIndex: index, partial: { ...partial } });
|
||||
stream.push({ type: "image_end", contentIndex: index, image: block, partial: { ...partial } });
|
||||
continue;
|
||||
}
|
||||
|
||||
partial.content = [...partial.content, { type: "toolCall", id: block.id, name: block.name, arguments: {} }];
|
||||
stream.push({ type: "toolcall_start", contentIndex: index, partial: { ...partial } });
|
||||
for (const chunk of splitStringByTokenSize(JSON.stringify(block.arguments), minTokenSize, maxTokenSize)) {
|
||||
|
||||
@@ -10,7 +10,6 @@ import type {
|
||||
Api,
|
||||
AssistantMessage,
|
||||
Context,
|
||||
ImageContent,
|
||||
Model,
|
||||
SimpleStreamOptions,
|
||||
StreamFunction,
|
||||
@@ -154,43 +153,6 @@ export const streamGoogle: StreamFunction<"google-generative-ai", GoogleOptions>
|
||||
}
|
||||
}
|
||||
|
||||
if (part.inlineData) {
|
||||
if (currentBlock) {
|
||||
if (currentBlock.type === "text") {
|
||||
stream.push({
|
||||
type: "text_end",
|
||||
contentIndex: blockIndex(),
|
||||
content: currentBlock.text,
|
||||
partial: output,
|
||||
});
|
||||
} else {
|
||||
stream.push({
|
||||
type: "thinking_end",
|
||||
contentIndex: blockIndex(),
|
||||
content: currentBlock.thinking,
|
||||
partial: output,
|
||||
});
|
||||
}
|
||||
currentBlock = null;
|
||||
}
|
||||
|
||||
if (part.inlineData.data && part.inlineData.mimeType) {
|
||||
const imageBlock: ImageContent = {
|
||||
type: "image",
|
||||
data: part.inlineData.data,
|
||||
mimeType: part.inlineData.mimeType,
|
||||
};
|
||||
output.content.push(imageBlock);
|
||||
stream.push({ type: "image_start", contentIndex: blockIndex(), partial: output });
|
||||
stream.push({
|
||||
type: "image_end",
|
||||
contentIndex: blockIndex(),
|
||||
image: imageBlock,
|
||||
partial: output,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (part.functionCall) {
|
||||
if (currentBlock) {
|
||||
if (currentBlock.type === "text") {
|
||||
|
||||
@@ -524,9 +524,6 @@ function toChatMessages(messages: Message[], supportsImages: boolean): ChatCompl
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (block.type !== "toolCall") {
|
||||
continue;
|
||||
}
|
||||
toolCalls.push({
|
||||
id: block.id,
|
||||
type: "function",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import OpenAI from "openai";
|
||||
import type {
|
||||
ChatCompletion,
|
||||
ChatCompletionAssistantMessageParam,
|
||||
ChatCompletionChunk,
|
||||
ChatCompletionContentPart,
|
||||
@@ -99,26 +98,6 @@ type ChatCompletionToolWithCacheControl = OpenAI.Chat.Completions.ChatCompletion
|
||||
cache_control?: OpenAICompatCacheControl;
|
||||
};
|
||||
|
||||
interface OpenRouterGeneratedImage {
|
||||
image_url?: string | { url?: string };
|
||||
}
|
||||
|
||||
type OpenRouterImageGenerationMessage = ChatCompletion["choices"][number]["message"] & {
|
||||
images?: OpenRouterGeneratedImage[];
|
||||
};
|
||||
|
||||
type OpenRouterImageGenerationChoice = ChatCompletion["choices"][number] & {
|
||||
message: OpenRouterImageGenerationMessage;
|
||||
};
|
||||
|
||||
type OpenRouterImageGenerationResponse = ChatCompletion & {
|
||||
choices: OpenRouterImageGenerationChoice[];
|
||||
};
|
||||
|
||||
function isOpenRouterImageGenerationModel(model: Model<"openai-completions">): boolean {
|
||||
return model.provider === "openrouter" && model.compat?.openRouterImageGeneration === true;
|
||||
}
|
||||
|
||||
function resolveCacheRetention(cacheRetention?: CacheRetention): CacheRetention {
|
||||
if (cacheRetention) {
|
||||
return cacheRetention;
|
||||
@@ -171,75 +150,6 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions", OpenA
|
||||
...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),
|
||||
...(options?.maxRetries !== undefined ? { maxRetries: options.maxRetries } : {}),
|
||||
};
|
||||
if (isOpenRouterImageGenerationModel(model)) {
|
||||
const { stream_options: _streamOptions, ...nonStreamingBaseParams } = params;
|
||||
const nonStreamingParams = {
|
||||
...nonStreamingBaseParams,
|
||||
stream: false,
|
||||
} as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming;
|
||||
const { data: response, response: rawResponse } = await client.chat.completions
|
||||
.create(nonStreamingParams, requestOptions)
|
||||
.withResponse();
|
||||
await options?.onResponse?.(
|
||||
{ status: rawResponse.status, headers: headersToRecord(rawResponse.headers) },
|
||||
model,
|
||||
);
|
||||
stream.push({ type: "start", partial: output });
|
||||
|
||||
const imageResponse = response as OpenRouterImageGenerationResponse;
|
||||
output.responseId ||= imageResponse.id;
|
||||
output.usage = parseChunkUsage(imageResponse.usage ?? {}, model);
|
||||
|
||||
const choice = imageResponse.choices[0];
|
||||
if (choice) {
|
||||
const text = choice.message.content;
|
||||
if (text) {
|
||||
const textBlock: TextContent = { type: "text", text };
|
||||
output.content.push(textBlock);
|
||||
const contentIndex = output.content.length - 1;
|
||||
stream.push({ type: "text_start", contentIndex, partial: output });
|
||||
stream.push({ type: "text_delta", contentIndex, delta: text, partial: output });
|
||||
stream.push({ type: "text_end", contentIndex, content: text, partial: output });
|
||||
}
|
||||
|
||||
for (const image of choice.message.images ?? []) {
|
||||
const imageUrl = typeof image.image_url === "string" ? image.image_url : image.image_url?.url;
|
||||
if (!imageUrl?.startsWith("data:")) {
|
||||
continue;
|
||||
}
|
||||
const matches = imageUrl.match(/^data:([^;]+);base64,(.+)$/);
|
||||
if (!matches) {
|
||||
continue;
|
||||
}
|
||||
const imageBlock: ImageContent = {
|
||||
type: "image",
|
||||
mimeType: matches[1],
|
||||
data: matches[2],
|
||||
};
|
||||
output.content.push(imageBlock);
|
||||
const contentIndex = output.content.length - 1;
|
||||
stream.push({ type: "image_start", contentIndex, partial: output });
|
||||
stream.push({ type: "image_end", contentIndex, image: imageBlock, partial: output });
|
||||
}
|
||||
|
||||
if (choice.finish_reason) {
|
||||
const finishReasonResult = mapStopReason(choice.finish_reason);
|
||||
output.stopReason = finishReasonResult.stopReason;
|
||||
if (finishReasonResult.errorMessage) {
|
||||
output.errorMessage = finishReasonResult.errorMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (output.stopReason === "stop" || output.stopReason === "length" || output.stopReason === "toolUse") {
|
||||
stream.push({ type: "done", reason: output.stopReason, message: output });
|
||||
} else {
|
||||
stream.push({ type: "error", reason: output.stopReason, error: output });
|
||||
}
|
||||
stream.end();
|
||||
return;
|
||||
}
|
||||
|
||||
const { data: openaiStream, response } = await client.chat.completions
|
||||
.create(params, requestOptions)
|
||||
.withResponse();
|
||||
@@ -575,10 +485,6 @@ function buildParams(
|
||||
prompt_cache_retention: cacheRetention === "long" && compat.supportsLongCacheRetention ? "24h" : undefined,
|
||||
};
|
||||
|
||||
if (isOpenRouterImageGenerationModel(model)) {
|
||||
Reflect.set(params, "modalities", ["image"]);
|
||||
}
|
||||
|
||||
if (compat.supportsUsageInStreaming !== false) {
|
||||
(params as any).stream_options = { include_usage: true };
|
||||
}
|
||||
@@ -599,12 +505,12 @@ function buildParams(
|
||||
params.temperature = options.temperature;
|
||||
}
|
||||
|
||||
if (!isOpenRouterImageGenerationModel(model) && context.tools && context.tools.length > 0) {
|
||||
if (context.tools && context.tools.length > 0) {
|
||||
params.tools = convertTools(context.tools, compat);
|
||||
if (compat.zaiToolStream) {
|
||||
(params as any).tool_stream = true;
|
||||
}
|
||||
} else if (!isOpenRouterImageGenerationModel(model) && hasToolHistory(context.messages)) {
|
||||
} else if (hasToolHistory(context.messages)) {
|
||||
// Anthropic (via LiteLLM/proxy) requires tools param when conversation has tool_calls/tool_results
|
||||
params.tools = [];
|
||||
}
|
||||
@@ -1174,7 +1080,6 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet
|
||||
? "openrouter"
|
||||
: "openai",
|
||||
openRouterRouting: {},
|
||||
openRouterImageGeneration: false,
|
||||
vercelGatewayRouting: {},
|
||||
zaiToolStream: false,
|
||||
supportsStrictMode: true,
|
||||
@@ -1208,7 +1113,6 @@ function getCompat(model: Model<"openai-completions">): ResolvedOpenAICompletion
|
||||
detected.requiresReasoningContentOnAssistantMessages,
|
||||
thinkingFormat: model.compat.thinkingFormat ?? detected.thinkingFormat,
|
||||
openRouterRouting: model.compat.openRouterRouting ?? {},
|
||||
openRouterImageGeneration: model.compat.openRouterImageGeneration ?? detected.openRouterImageGeneration,
|
||||
vercelGatewayRouting: model.compat.vercelGatewayRouting ?? detected.vercelGatewayRouting,
|
||||
zaiToolStream: model.compat.zaiToolStream ?? detected.zaiToolStream,
|
||||
supportsStrictMode: model.compat.supportsStrictMode ?? detected.supportsStrictMode,
|
||||
|
||||
@@ -212,7 +212,7 @@ export interface UserMessage {
|
||||
|
||||
export interface AssistantMessage {
|
||||
role: "assistant";
|
||||
content: (TextContent | ThinkingContent | ImageContent | ToolCall)[];
|
||||
content: (TextContent | ThinkingContent | ToolCall)[];
|
||||
api: Api;
|
||||
provider: Provider;
|
||||
model: string;
|
||||
@@ -265,8 +265,6 @@ export type AssistantMessageEvent =
|
||||
| { type: "thinking_start"; contentIndex: number; partial: AssistantMessage }
|
||||
| { type: "thinking_delta"; contentIndex: number; delta: string; partial: AssistantMessage }
|
||||
| { type: "thinking_end"; contentIndex: number; content: string; partial: AssistantMessage }
|
||||
| { type: "image_start"; contentIndex: number; partial: AssistantMessage }
|
||||
| { type: "image_end"; contentIndex: number; image: ImageContent; partial: AssistantMessage }
|
||||
| { type: "toolcall_start"; contentIndex: number; partial: AssistantMessage }
|
||||
| { type: "toolcall_delta"; contentIndex: number; delta: string; partial: AssistantMessage }
|
||||
| { type: "toolcall_end"; contentIndex: number; toolCall: ToolCall; partial: AssistantMessage }
|
||||
@@ -302,8 +300,6 @@ export interface OpenAICompletionsCompat {
|
||||
thinkingFormat?: "openai" | "openrouter" | "deepseek" | "zai" | "qwen" | "qwen-chat-template";
|
||||
/** OpenRouter-specific routing preferences. Only used when baseUrl points to OpenRouter. */
|
||||
openRouterRouting?: OpenRouterRouting;
|
||||
/** Whether the model uses OpenRouter's image-generation response shape with assistant `message.images`. */
|
||||
openRouterImageGeneration?: boolean;
|
||||
/** Vercel AI Gateway routing preferences. Only used when baseUrl points to Vercel AI Gateway. */
|
||||
vercelGatewayRouting?: VercelGatewayRouting;
|
||||
/** Whether z.ai supports top-level `tool_stream: true` for streaming tool call deltas. Default: false. */
|
||||
|
||||
Reference in New Issue
Block a user