fix(chatbot): disable thinking + use non-streaming LLM call
- Set stream:false on the /chat/completions request so the bot gets one complete response instead of an SSE token stream. - Add reasoning_effort:"none" to suppress extended-thinking/reasoning tokens (ignored by non-reasoning models like gemini-flash-lite). - Add parseResponse(): handles both the JSON object 9router returns for stream:false and the SSE text it may still emit, delegating SSE to parseSse. Verified live: omniroute returns 200 application/json with message.content.
This commit is contained in:
@@ -158,7 +158,13 @@ Gaya ngobrol:
|
|||||||
tool_choice: "auto",
|
tool_choice: "auto",
|
||||||
max_tokens: 600,
|
max_tokens: 600,
|
||||||
temperature: 0.4,
|
temperature: 0.4,
|
||||||
stream: true,
|
// Non-streaming: request a single complete response. 9router may
|
||||||
|
// still emit SSE even with stream:false, so the parser below
|
||||||
|
// handle both raw-JSON and SSE bodies.
|
||||||
|
stream: false,
|
||||||
|
// Disable extended thinking / reasoning tokens so the bot answers
|
||||||
|
// directly (ignored by non-reasoning models).
|
||||||
|
reasoning_effort: "none",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -166,14 +172,14 @@ Gaya ngobrol:
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
timeout: 45_000,
|
timeout: 45_000,
|
||||||
// 9router returns SSE even without stream:true; force stream:true
|
|
||||||
// in the body and read the raw SSE text.
|
|
||||||
responseType: "text",
|
responseType: "text",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Parse SSE `data:` lines → content + tool_calls.
|
// Parse the body into content + tool_calls. 9router may return either
|
||||||
const { content, toolCalls } = this.parseSse(response.data as string);
|
// a single JSON object (stream:false honored) or SSE text (stream
|
||||||
|
// implied) — parseResponse handles both.
|
||||||
|
const { content, toolCalls } = this.parseResponse(response.data as string);
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
{
|
{
|
||||||
@@ -242,6 +248,60 @@ Gaya ngobrol:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an LLM HTTP body into content + tool_calls. Handles both shapes
|
||||||
|
* 9router can return: a single JSON object (stream:false honored) or SSE
|
||||||
|
* text (stream implied). For SSE we delegate to parseSse.
|
||||||
|
*/
|
||||||
|
private parseResponse(body: string): {
|
||||||
|
content: string;
|
||||||
|
toolCalls: Array<{
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
arguments: string;
|
||||||
|
args: Record<string, unknown>;
|
||||||
|
}>;
|
||||||
|
} {
|
||||||
|
const trimmed = body.trim();
|
||||||
|
// Non-streaming response: a single JSON object.
|
||||||
|
if (trimmed.startsWith("{")) {
|
||||||
|
try {
|
||||||
|
const json = JSON.parse(trimmed) as {
|
||||||
|
choices?: Array<{
|
||||||
|
message?: {
|
||||||
|
content?: string | null;
|
||||||
|
tool_calls?: Array<{
|
||||||
|
id?: string;
|
||||||
|
type?: string;
|
||||||
|
function?: { name?: string; arguments?: string };
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
delta?: unknown;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
const msg = json.choices?.[0]?.message;
|
||||||
|
// If the router returned SSE-style shape under `choices[].delta`
|
||||||
|
// (rare), fall through to the SSE parser.
|
||||||
|
if (msg) {
|
||||||
|
const content = msg.content ?? "";
|
||||||
|
const toolCalls = (msg.tool_calls ?? []).map((tc, i) => {
|
||||||
|
const id = tc.id || `tool_${i}_${Date.now()}`;
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
name: tc.function?.name ?? "",
|
||||||
|
arguments: tc.function?.arguments ?? "",
|
||||||
|
args: this.safeJsonParse(tc.function?.arguments ?? ""),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return { content: content.trim(), toolCalls };
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Not valid JSON after all — treat as SSE below.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.parseSse(body);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse an SSE stream body into accumulated content + any tool_calls.
|
* Parse an SSE stream body into accumulated content + any tool_calls.
|
||||||
* 9router (and most OpenAI-compatible routers) emit `data: {json}` lines
|
* 9router (and most OpenAI-compatible routers) emit `data: {json}` lines
|
||||||
|
|||||||
Reference in New Issue
Block a user