u
This commit is contained in:
@@ -345,6 +345,12 @@ export class ConversationManager {
|
||||
if (conversation.provider !== 'openrouter') {
|
||||
throw new Error(`Unsupported provider: ${conversation.provider}`);
|
||||
}
|
||||
// Fall back to the configured default when the stored model is missing or blank, so
|
||||
// an old or malformed conversation row cannot send an empty `model` and make the
|
||||
// provider return an empty response.
|
||||
const model = (typeof conversation.model === 'string' && conversation.model.trim())
|
||||
? conversation.model.trim()
|
||||
: env.defaultModel;
|
||||
const apiKey = await resolveOpenRouterKey(googleAuthId);
|
||||
|
||||
// Transcript comes from the database (includes user, assistant, tool, reasoning).
|
||||
@@ -459,16 +465,37 @@ export class ConversationManager {
|
||||
}
|
||||
},
|
||||
onUsage: (u) => {
|
||||
// A call that consumed 0 input tokens AND produced 0 output means the
|
||||
// provider returned nothing at all — not a real generation. LLMOrbiter
|
||||
// treats "no content and no tool calls" as "keep looping", so several of
|
||||
// these in a row burn iterations for nothing. Flag them loudly so the
|
||||
// cause is visible instead of showing up as a silent weird loop.
|
||||
if (u.input === 0 && u.output === 0) {
|
||||
console.warn(
|
||||
`[conversation ${this.conversationId}] EMPTY LLM RESPONSE ` +
|
||||
`(iteration reported no usage at all). The provider returned no content ` +
|
||||
`and no tool calls, so the orchestrator will retry. ` +
|
||||
`If this repeats, the upstream model/API is failing — check the model id ` +
|
||||
`and the key.`
|
||||
);
|
||||
}
|
||||
console.log(
|
||||
`[conversation ${this.conversationId}] usage: input=${u.input}, cached=${u.cached}, output=${u.output}` +
|
||||
(u.cost != null ? `, cost=$${u.cost.toFixed(4)}` : '')
|
||||
);
|
||||
},
|
||||
onLLMCall: (call) => {
|
||||
console.log(
|
||||
`[conversation ${this.conversationId}] LLM call #${call.iteration}: ` +
|
||||
`model=${call.model}, messages=${call.messageCount}, flow=${call.messages}, ` +
|
||||
`promptChars=${call.promptSize}`
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const result = await this.orbiter.run({
|
||||
messages,
|
||||
model: conversation.model,
|
||||
model,
|
||||
tools: [
|
||||
createDashbackRequestTool({ googleAuthId }),
|
||||
createAskUserTool(),
|
||||
@@ -481,7 +508,7 @@ export class ConversationManager {
|
||||
createPatchTool({ googleAuthId }),
|
||||
createRmTool({ googleAuthId }),
|
||||
createSearchImagesTool({ googleAuthId }),
|
||||
createAnalyzeImageTool({ googleAuthId, model: conversation.model }),
|
||||
createAnalyzeImageTool({ googleAuthId, model }),
|
||||
createResetVfsTool({ googleAuthId }),
|
||||
createApiSuggestionsOrIssuesTool({ googleAuthId, companyId: this.companyId }),
|
||||
],
|
||||
@@ -489,6 +516,17 @@ export class ConversationManager {
|
||||
|
||||
if (this.destroyed) return;
|
||||
|
||||
// Log the shape of every run, including degenerate ones. When nothing comes back
|
||||
// there is nothing persisted and the UI just sits there — this line is the only
|
||||
// clue, so make it explicit about which field was empty.
|
||||
console.log(
|
||||
`[conversation ${this.conversationId}] run finished: ` +
|
||||
`iterations=${result?.iterations}, ` +
|
||||
`content=${result?.content ? `${result.content.length} chars` : 'EMPTY'}, ` +
|
||||
`toolCalls=${result?.toolResults ? Object.keys(result.toolResults).length : 0}, ` +
|
||||
`directReturn=${result?.directReturn === true}`
|
||||
);
|
||||
|
||||
// Direct return (e.g. from ask_user) halts without adding an additional assistant message.
|
||||
if (result?.directReturn) {
|
||||
return;
|
||||
@@ -500,6 +538,16 @@ export class ConversationManager {
|
||||
: undefined;
|
||||
const finalReasoning = result.reasoning || currentReasoning.trim() || undefined;
|
||||
|
||||
// Nothing came back at all: no content, no reasoning. Surface it to the user rather
|
||||
// than silently returning to `idle` with an empty turn, which reads as a hang.
|
||||
if (!content && !finalReasoningDetails && !finalReasoning) {
|
||||
console.error(
|
||||
`[conversation ${this.conversationId}] generation produced no content after ` +
|
||||
`${result?.iterations ?? 0} iteration(s). The model returned neither text nor tool calls.`
|
||||
);
|
||||
error = 'The model returned an empty response. Please try again.';
|
||||
}
|
||||
|
||||
if (content || finalReasoningDetails || finalReasoning) {
|
||||
const assistantMsg = await db.addMessage(googleAuthId, this.conversationId, {
|
||||
message: JSON.stringify({
|
||||
|
||||
Reference in New Issue
Block a user