mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-29 19:12:27 +08:00
hmm
This commit is contained in:
parent
6bba1be5f4
commit
263c869091
@ -99,6 +99,18 @@ export interface ChatCompletionOptions {
|
||||
useAdvancedContext?: boolean; // Whether to use advanced context enrichment
|
||||
toolExecutionStatus?: any[]; // Status information about executed tools for feedback
|
||||
providerMetadata?: ModelMetadata; // Metadata about the provider and model capabilities
|
||||
|
||||
/**
|
||||
* Maximum number of tool execution iterations
|
||||
* Used to prevent infinite loops in tool execution
|
||||
*/
|
||||
maxToolIterations?: number;
|
||||
|
||||
/**
|
||||
* Current tool execution iteration counter
|
||||
* Internal use for tracking nested tool executions
|
||||
*/
|
||||
currentToolIteration?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -328,7 +328,7 @@ export class OllamaService extends BaseAIService {
|
||||
responseToolCalls = toolCalls;
|
||||
}
|
||||
|
||||
// Send to callback
|
||||
// Send to callback - directly pass the content without accumulating
|
||||
await callback({
|
||||
text: chunk.message?.content || '',
|
||||
done: false, // Add done property to satisfy StreamChunk
|
||||
|
@ -145,24 +145,20 @@ export class StreamProcessor {
|
||||
*/
|
||||
export function createStreamHandler(
|
||||
options: StreamProcessingOptions,
|
||||
streamImplementation: (callback: (chunk: StreamChunk) => Promise<void>) => Promise<string>
|
||||
) {
|
||||
// Return a standard stream handler function that providers can use
|
||||
return async (callback: (chunk: BaseStreamChunk) => Promise<void>): Promise<string> => {
|
||||
let completeText = '';
|
||||
processFn: (
|
||||
callback: (chunk: StreamChunk) => Promise<void> | void
|
||||
) => Promise<string>
|
||||
): (callback: (chunk: StreamChunk) => Promise<void> | void) => Promise<string> {
|
||||
return async (callback) => {
|
||||
let chunkCount = 0;
|
||||
|
||||
try {
|
||||
// Call the provided implementation
|
||||
return await streamImplementation(async (chunk: StreamChunk) => {
|
||||
// Run the processor function with our callback
|
||||
return await processFn(async (chunk) => {
|
||||
chunkCount++;
|
||||
|
||||
// Process the chunk
|
||||
if (chunk.text) {
|
||||
completeText += chunk.text;
|
||||
}
|
||||
|
||||
// Forward to callback - ensure done is always boolean for BaseStreamChunk
|
||||
// Pass each chunk directly to the callback as it arrives
|
||||
// without modifying or accumulating its content
|
||||
await callback({
|
||||
text: chunk.text || '',
|
||||
done: !!chunk.done, // Ensure done is boolean
|
||||
|
@ -939,12 +939,182 @@ class RestChatService {
|
||||
tool_calls: response.tool_calls
|
||||
}, ...toolResults];
|
||||
|
||||
// Use non-streaming for the follow-up to get a complete response
|
||||
const followUpOptions = { ...chatOptions, stream: false, enableTools: false };
|
||||
// Preserve streaming for follow-up if it was enabled in the original request
|
||||
const followUpOptions = {
|
||||
...chatOptions,
|
||||
// Only disable streaming if it wasn't explicitly requested
|
||||
stream: chatOptions.stream === true,
|
||||
// Allow tools but track iterations to prevent infinite loops
|
||||
enableTools: true,
|
||||
maxToolIterations: chatOptions.maxToolIterations || 5,
|
||||
currentToolIteration: 1 // Start counting tool iterations
|
||||
};
|
||||
|
||||
const followUpResponse = await service.generateChatCompletion(toolMessages, followUpOptions);
|
||||
|
||||
// Handle streaming follow-up response if streaming is enabled
|
||||
if (followUpOptions.stream && followUpResponse.stream) {
|
||||
log.info(`Streaming follow-up response after tool execution`);
|
||||
let followUpContent = '';
|
||||
|
||||
// Process the streaming response
|
||||
await followUpResponse.stream(async (chunk: StreamChunk) => {
|
||||
if (chunk.text) {
|
||||
followUpContent += chunk.text;
|
||||
|
||||
// Send each chunk via WebSocket
|
||||
wsService.sendMessageToAllClients({
|
||||
type: 'llm-stream',
|
||||
sessionId,
|
||||
content: chunk.text
|
||||
} as LLMStreamMessage);
|
||||
}
|
||||
|
||||
// Signal completion when done
|
||||
if (chunk.done) {
|
||||
// Check if there are more tool calls to execute
|
||||
if (followUpResponse.tool_calls && followUpResponse.tool_calls.length > 0 &&
|
||||
followUpOptions.currentToolIteration < followUpOptions.maxToolIterations) {
|
||||
|
||||
log.info(`Found ${followUpResponse.tool_calls.length} more tool calls in iteration ${followUpOptions.currentToolIteration}`);
|
||||
|
||||
// Execute these tool calls in another iteration
|
||||
// First, capture the current content for the assistant message
|
||||
const assistantMessage = {
|
||||
role: 'assistant' as const,
|
||||
content: followUpContent,
|
||||
tool_calls: followUpResponse.tool_calls
|
||||
};
|
||||
|
||||
// Execute the tools from this follow-up
|
||||
const nextToolResults = await this.executeToolCalls(followUpResponse);
|
||||
|
||||
// Create a new messages array with the latest tool results
|
||||
const nextToolMessages = [...toolMessages, assistantMessage, ...nextToolResults];
|
||||
|
||||
// Increment the tool iteration counter for the next call
|
||||
const nextFollowUpOptions = {
|
||||
...followUpOptions,
|
||||
currentToolIteration: followUpOptions.currentToolIteration + 1
|
||||
};
|
||||
|
||||
log.info(`Making another follow-up request with ${nextToolResults.length} tool results (iteration ${nextFollowUpOptions.currentToolIteration}/${nextFollowUpOptions.maxToolIterations})`);
|
||||
|
||||
// Make another follow-up request
|
||||
const nextResponse = await service.generateChatCompletion(nextToolMessages, nextFollowUpOptions);
|
||||
|
||||
// Handle this new response (recursive streaming if needed)
|
||||
if (nextFollowUpOptions.stream && nextResponse.stream) {
|
||||
let nextContent = followUpContent; // Start with the existing content
|
||||
|
||||
await nextResponse.stream(async (nextChunk: StreamChunk) => {
|
||||
if (nextChunk.text) {
|
||||
nextContent += nextChunk.text;
|
||||
|
||||
// Stream this content to the client
|
||||
wsService.sendMessageToAllClients({
|
||||
type: 'llm-stream',
|
||||
sessionId,
|
||||
content: nextChunk.text
|
||||
} as LLMStreamMessage);
|
||||
}
|
||||
|
||||
if (nextChunk.done) {
|
||||
// Final completion message
|
||||
wsService.sendMessageToAllClients({
|
||||
type: 'llm-stream',
|
||||
sessionId,
|
||||
done: true
|
||||
} as LLMStreamMessage);
|
||||
|
||||
// Update message content with the complete response after all iterations
|
||||
messageContent = nextContent;
|
||||
|
||||
// Store in session history
|
||||
session.messages.push({
|
||||
role: 'assistant',
|
||||
content: messageContent,
|
||||
timestamp: new Date()
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// For non-streaming next response
|
||||
messageContent = nextResponse.text || "";
|
||||
|
||||
// Send the final complete message
|
||||
wsService.sendMessageToAllClients({
|
||||
type: 'llm-stream',
|
||||
sessionId,
|
||||
content: messageContent,
|
||||
done: true
|
||||
} as LLMStreamMessage);
|
||||
|
||||
// Store in session
|
||||
session.messages.push({
|
||||
role: 'assistant',
|
||||
content: messageContent,
|
||||
timestamp: new Date()
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// No more tool calls or reached iteration limit
|
||||
wsService.sendMessageToAllClients({
|
||||
type: 'llm-stream',
|
||||
sessionId,
|
||||
done: true
|
||||
} as LLMStreamMessage);
|
||||
|
||||
// Update message content for session storage
|
||||
messageContent = followUpContent;
|
||||
|
||||
// Store the final response in the session
|
||||
session.messages.push({
|
||||
role: 'assistant',
|
||||
content: messageContent,
|
||||
timestamp: new Date()
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Non-streaming follow-up handling (original behavior)
|
||||
messageContent = followUpResponse.text || "";
|
||||
|
||||
// Check if there are more tool calls to execute
|
||||
if (followUpResponse.tool_calls && followUpResponse.tool_calls.length > 0 &&
|
||||
followUpOptions.currentToolIteration < (followUpOptions.maxToolIterations || 5)) {
|
||||
|
||||
log.info(`Found ${followUpResponse.tool_calls.length} more tool calls in non-streaming follow-up (iteration ${followUpOptions.currentToolIteration})`);
|
||||
|
||||
// Execute these tool calls in another iteration
|
||||
const assistantMessage = {
|
||||
role: 'assistant' as const,
|
||||
content: messageContent,
|
||||
tool_calls: followUpResponse.tool_calls
|
||||
};
|
||||
|
||||
// Execute the next round of tools
|
||||
const nextToolResults = await this.executeToolCalls(followUpResponse);
|
||||
|
||||
// Create a new messages array with the latest tool results
|
||||
const nextToolMessages = [...toolMessages, assistantMessage, ...nextToolResults];
|
||||
|
||||
// Increment the tool iteration counter for the next call
|
||||
const nextFollowUpOptions = {
|
||||
...followUpOptions,
|
||||
currentToolIteration: followUpOptions.currentToolIteration + 1
|
||||
};
|
||||
|
||||
log.info(`Making another non-streaming follow-up request (iteration ${nextFollowUpOptions.currentToolIteration}/${nextFollowUpOptions.maxToolIterations || 5})`);
|
||||
|
||||
// Make another follow-up request
|
||||
const nextResponse = await service.generateChatCompletion(nextToolMessages, nextFollowUpOptions);
|
||||
|
||||
// Update the message content with the final response
|
||||
messageContent = nextResponse.text || "";
|
||||
}
|
||||
|
||||
// Send the complete response with done flag in the same message
|
||||
wsService.sendMessageToAllClients({
|
||||
type: 'llm-stream',
|
||||
@ -959,6 +1129,14 @@ class RestChatService {
|
||||
content: messageContent,
|
||||
timestamp: new Date()
|
||||
});
|
||||
}
|
||||
|
||||
// Store the response in the session
|
||||
session.messages.push({
|
||||
role: 'assistant',
|
||||
content: messageContent,
|
||||
timestamp: new Date()
|
||||
});
|
||||
|
||||
return;
|
||||
} catch (toolError) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user