u
This commit is contained in:
@@ -183,17 +183,16 @@ class LLMOrbiter {
|
||||
tools: toolSpecs.length ? toolSpecs : undefined,
|
||||
signal: runSignal,
|
||||
extraBody,
|
||||
onStatus: (s) => call(onStatus, s),
|
||||
onStatus: (...args) => call(onStatus, ...args),
|
||||
onContent: (...args) => call(onContent, ...args),
|
||||
onReasoning: (r) => call(onReasoning, r),
|
||||
});
|
||||
|
||||
// Accumulate usage & emit event per LLM call completed
|
||||
// Accumulate usage per LLM call completed
|
||||
const callUsage = this._addUsage(usage, completion.usage);
|
||||
if (completion.usage) {
|
||||
rawUsages.push(completion.usage);
|
||||
}
|
||||
await call(onUsage, callUsage);
|
||||
|
||||
const toolCalls = completion.tool_calls;
|
||||
const content = completion.content;
|
||||
@@ -202,6 +201,7 @@ class LLMOrbiter {
|
||||
|
||||
// When there is no response (neither tool calls nor content), the loop shall continue.
|
||||
if (!hasToolCalls && !hasContent) {
|
||||
await call(onUsage, callUsage);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -217,6 +217,7 @@ class LLMOrbiter {
|
||||
// No tool calls → done
|
||||
if (!hasToolCalls) {
|
||||
finalContent = content;
|
||||
await call(onUsage, callUsage);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -318,6 +319,8 @@ class LLMOrbiter {
|
||||
recordToolResult(callItem, result);
|
||||
}
|
||||
|
||||
await call(onUsage, callUsage);
|
||||
|
||||
if (hasDirectReturn) break;
|
||||
|
||||
if (pendingAppendedMessages.length > 0) {
|
||||
|
||||
@@ -31,7 +31,7 @@ class OpenRouterProvider {
|
||||
constructor({ apiKey, apiUrl, siteUrl, siteName, sessionId } = {}) {
|
||||
if (!apiKey) throw new Error('OpenRouterProvider requires an apiKey');
|
||||
this.apiKey = apiKey;
|
||||
this.apiUrl = apiUrl || DEFAULT_API_URL;
|
||||
this.apiUrl = apiUrl || process.env.OPENROUTER_API_URL || DEFAULT_API_URL;
|
||||
this.siteUrl = siteUrl || '';
|
||||
this.siteName = siteName || '';
|
||||
this.sessionId = sessionId || PROCESS_SESSION_ID;
|
||||
@@ -48,8 +48,9 @@ class OpenRouterProvider {
|
||||
model,
|
||||
messages,
|
||||
reasoning: {
|
||||
effort: 'minimal'
|
||||
effort: 'max'
|
||||
},
|
||||
include: ["reasoning.encrypted_content"],
|
||||
stream: true,
|
||||
...(effectiveSessionId ? { session_id: effectiveSessionId } : {}),
|
||||
...extraBody,
|
||||
@@ -90,8 +91,12 @@ class OpenRouterProvider {
|
||||
const decoder = new TextDecoder();
|
||||
let buffer = '';
|
||||
const result = {};
|
||||
const state = { workingSent: false };
|
||||
let firstPayload = true;
|
||||
const state = {
|
||||
firstEventSent: false,
|
||||
reasoningSent: false,
|
||||
contentSent: false,
|
||||
workingSent: false,
|
||||
};
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
@@ -103,20 +108,34 @@ class OpenRouterProvider {
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed || !trimmed.startsWith('data:')) continue;
|
||||
if (!trimmed) continue;
|
||||
|
||||
if (!state.firstEventSent) {
|
||||
state.firstEventSent = true;
|
||||
handlers.onStatus?.('firstevent');
|
||||
}
|
||||
|
||||
if (!trimmed.startsWith('data:')) continue;
|
||||
const payload = trimmed.slice(5).trim();
|
||||
if (payload === '[DONE]') continue;
|
||||
|
||||
if (firstPayload) {
|
||||
firstPayload = false;
|
||||
handlers.onStatus?.('streaming');
|
||||
}
|
||||
|
||||
this._processChunk(payload, result, handlers, state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const remaining = buffer.trim();
|
||||
if (remaining) {
|
||||
if (!state.firstEventSent) {
|
||||
state.firstEventSent = true;
|
||||
handlers.onStatus?.('firstevent');
|
||||
}
|
||||
if (remaining.startsWith('data:')) {
|
||||
const payload = remaining.slice(5).trim();
|
||||
if (payload !== '[DONE]') {
|
||||
this._processChunk(payload, result, handlers, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -138,6 +157,10 @@ class OpenRouterProvider {
|
||||
|
||||
// Content
|
||||
if (choice.delta?.content) {
|
||||
if (!state.contentSent) {
|
||||
state.contentSent = true;
|
||||
onStatus?.('content');
|
||||
}
|
||||
result.content = (result.content || '') + choice.delta.content;
|
||||
onContent?.(choice.delta.content, result.content);
|
||||
}
|
||||
@@ -181,6 +204,18 @@ class OpenRouterProvider {
|
||||
}
|
||||
}
|
||||
|
||||
const hasReasoningDelta = Boolean(
|
||||
reasoningText ||
|
||||
choice.delta?.reasoning ||
|
||||
choice.delta?.reasoning_content ||
|
||||
(Array.isArray(choice.delta?.reasoning_details) && choice.delta.reasoning_details.length > 0)
|
||||
);
|
||||
|
||||
if (hasReasoningDelta && !state.reasoningSent) {
|
||||
state.reasoningSent = true;
|
||||
onStatus?.('reasoning');
|
||||
}
|
||||
|
||||
if (reasoningText) {
|
||||
result.reasoning = (result.reasoning || '') + reasoningText;
|
||||
onReasoning?.(result.reasoning);
|
||||
|
||||
Reference in New Issue
Block a user