remove empty content continue; prettier then reformatted many things

This commit is contained in:
Rob Colbert 2026-05-19 11:48:56 -04:00
parent 1758bb2db7
commit d47ef96916

View File

@ -199,30 +199,33 @@ export class OpenAiApi extends AiApi {
} }
const startTime = Date.now(); const startTime = Date.now();
const response = await this.client.chat.completions.create({ const response = await this.client.chat.completions.create(
model: model.modelId, {
messages: [ model: model.modelId,
...(options.systemPrompt messages: [
? [{ role: "system" as const, content: options.systemPrompt }] ...(options.systemPrompt
: []), ? [{ role: "system" as const, content: options.systemPrompt }]
{ role: "user" as const, content: options.prompt }, : []),
], { role: "user" as const, content: options.prompt },
stream: true, ],
stream_options: { include_usage: true }, stream: true,
...(model.params.maxCompletionTokens stream_options: { include_usage: true },
? { max_completion_tokens: model.params.maxCompletionTokens } ...(model.params.maxCompletionTokens
: {}), ? { max_completion_tokens: model.params.maxCompletionTokens }
temperature: model.params.temperature, : {}),
top_p: model.params.topP, temperature: model.params.temperature,
...(typeof model.params.reasoning === "string" top_p: model.params.topP,
? { ...(typeof model.params.reasoning === "string"
reasoning_effort: model.params.reasoning as ? {
| "low" reasoning_effort: model.params.reasoning as
| "medium" | "low"
| "high", | "medium"
} | "high",
: {}), }
}, options.signal ? { signal: options.signal } : undefined); : {}),
},
options.signal ? { signal: options.signal } : undefined,
);
let accumulatedResponse = ""; let accumulatedResponse = "";
let accumulatedThinking = ""; let accumulatedThinking = "";
@ -300,7 +303,12 @@ export class OpenAiApi extends AiApi {
); );
if (this.isEmptyIteration(iteration)) { if (this.isEmptyIteration(iteration)) {
iteration = await this.readNonStreamingChatCompletion(model, messages, tools, options.signal); iteration = await this.readNonStreamingChatCompletion(
model,
messages,
tools,
options.signal,
);
if (streamCallback && iteration.response) { if (streamCallback && iteration.response) {
await streamCallback({ type: "response", data: iteration.response }); await streamCallback({ type: "response", data: iteration.response });
} }
@ -321,14 +329,19 @@ export class OpenAiApi extends AiApi {
done: true, done: true,
response: iteration.response, response: iteration.response,
thinking: iteration.thinking, thinking: iteration.thinking,
toolCalls: iteration.toolCalls.length > 0 ? iteration.toolCalls : undefined, toolCalls:
iteration.toolCalls.length > 0 ? iteration.toolCalls : undefined,
stats: this.buildStats(startTime, iteration.usage), stats: this.buildStats(startTime, iteration.usage),
}; };
this.assertNonEmptyChatResponse(finalResponse); this.assertNonEmptyChatResponse(finalResponse);
return finalResponse; return finalResponse;
} }
private extractUsage(usage: { prompt_tokens: number; completion_tokens: number; completion_tokens_details?: { reasoning_tokens?: number } }): OpenAiUsage { private extractUsage(usage: {
prompt_tokens: number;
completion_tokens: number;
completion_tokens_details?: { reasoning_tokens?: number };
}): OpenAiUsage {
return { return {
promptTokens: usage.prompt_tokens, promptTokens: usage.prompt_tokens,
completionTokens: usage.completion_tokens, completionTokens: usage.completion_tokens,
@ -342,7 +355,6 @@ export class OpenAiApi extends AiApi {
messages.push({ role: "system", content: options.systemPrompt }); messages.push({ role: "system", content: options.systemPrompt });
} }
for (const msg of options.context || []) { for (const msg of options.context || []) {
if (!msg.content?.trim()) continue;
if (msg.role === "tool") { if (msg.role === "tool") {
messages.push({ messages.push({
role: "tool", role: "tool",
@ -351,7 +363,11 @@ export class OpenAiApi extends AiApi {
}); });
continue; continue;
} }
if (msg.role === "assistant" && msg.toolCalls && msg.toolCalls.length > 0) { if (
msg.role === "assistant" &&
msg.toolCalls &&
msg.toolCalls.length > 0
) {
messages.push({ messages.push({
role: "assistant", role: "assistant",
content: msg.content, content: msg.content,
@ -371,14 +387,16 @@ export class OpenAiApi extends AiApi {
} }
private buildTools(options: IAiChatOptions): ChatCompletionTool[] { private buildTools(options: IAiChatOptions): ChatCompletionTool[] {
return (options.tools || []).map((tool): ChatCompletionFunctionTool => ({ return (options.tools || []).map(
type: tool.definition.type, (tool): ChatCompletionFunctionTool => ({
function: { type: tool.definition.type,
name: tool.definition.function.name, function: {
description: tool.definition.function.description, name: tool.definition.function.name,
parameters: tool.definition.function.parameters, description: tool.definition.function.description,
}, parameters: tool.definition.function.parameters,
})); },
}),
);
} }
private async readStreamingChatCompletion( private async readStreamingChatCompletion(
@ -392,26 +410,29 @@ export class OpenAiApi extends AiApi {
throw new DOMException("The operation was aborted", "AbortError"); throw new DOMException("The operation was aborted", "AbortError");
} }
const response = await this.client.chat.completions.create({ const response = await this.client.chat.completions.create(
model: model.modelId, {
messages, model: model.modelId,
tools, messages,
stream: true, tools,
stream_options: { include_usage: true }, stream: true,
...(model.params.maxCompletionTokens stream_options: { include_usage: true },
? { max_completion_tokens: model.params.maxCompletionTokens } ...(model.params.maxCompletionTokens
: {}), ? { max_completion_tokens: model.params.maxCompletionTokens }
temperature: model.params.temperature, : {}),
top_p: model.params.topP, temperature: model.params.temperature,
...(typeof model.params.reasoning === "string" top_p: model.params.topP,
? { ...(typeof model.params.reasoning === "string"
reasoning_effort: model.params.reasoning as ? {
| "low" reasoning_effort: model.params.reasoning as
| "medium" | "low"
| "high", | "medium"
} | "high",
: {}), }
}, signal ? { signal } : undefined); : {}),
},
signal ? { signal } : undefined,
);
let content = ""; let content = "";
let thinking = ""; let thinking = "";
@ -448,7 +469,10 @@ export class OpenAiApi extends AiApi {
if ("reasoning" in delta && delta.reasoning) { if ("reasoning" in delta && delta.reasoning) {
thinking += delta.reasoning as string; thinking += delta.reasoning as string;
if (streamCallback) { if (streamCallback) {
await streamCallback({ type: "thinking", data: delta.reasoning as string }); await streamCallback({
type: "thinking",
data: delta.reasoning as string,
});
} }
} }
if (delta.tool_calls) { if (delta.tool_calls) {
@ -481,30 +505,35 @@ export class OpenAiApi extends AiApi {
throw new DOMException("The operation was aborted", "AbortError"); throw new DOMException("The operation was aborted", "AbortError");
} }
const response = await this.client.chat.completions.create({ const response = await this.client.chat.completions.create(
model: model.modelId, {
messages, model: model.modelId,
tools, messages,
stream: false, tools,
...(model.params.maxCompletionTokens stream: false,
? { max_completion_tokens: model.params.maxCompletionTokens } ...(model.params.maxCompletionTokens
: {}), ? { max_completion_tokens: model.params.maxCompletionTokens }
temperature: model.params.temperature, : {}),
top_p: model.params.topP, temperature: model.params.temperature,
...(typeof model.params.reasoning === "string" top_p: model.params.topP,
? { ...(typeof model.params.reasoning === "string"
reasoning_effort: model.params.reasoning as ? {
| "low" reasoning_effort: model.params.reasoning as
| "medium" | "low"
| "high", | "medium"
} | "high",
: {}), }
}, signal ? { signal } : undefined); : {}),
},
signal ? { signal } : undefined,
);
const choice = response.choices[0]; const choice = response.choices[0];
const message = choice?.message; const message = choice?.message;
const content = typeof message?.content === "string" ? message.content : ""; const content = typeof message?.content === "string" ? message.content : "";
const usage = response.usage ? this.extractUsage(response.usage) : undefined; const usage = response.usage
? this.extractUsage(response.usage)
: undefined;
const assistantToolCalls = (message?.tool_calls || []) const assistantToolCalls = (message?.tool_calls || [])
.filter((tc) => tc.type === "function") .filter((tc) => tc.type === "function")
.map((tc) => ({ .map((tc) => ({
@ -516,12 +545,12 @@ export class OpenAiApi extends AiApi {
}, },
})); }));
const toolCalls: IToolCall[] = assistantToolCalls.map((tc) => ({ const toolCalls: IToolCall[] = assistantToolCalls.map((tc) => ({
callId: tc.id, callId: tc.id,
function: { function: {
name: tc.function.name, name: tc.function.name,
arguments: tc.function.arguments, arguments: tc.function.arguments,
}, },
})); }));
return { return {
response: content, response: content,