format decomp files

This commit is contained in:
perf3ct 2025-04-17 17:50:16 +00:00
parent 19c36b18a6
commit d83cce88cb
No known key found for this signature in database
GPG Key ID: 569C4EEC436F5232
4 changed files with 400 additions and 321 deletions

View File

@ -100,7 +100,8 @@ Format your answer as a valid JSON array without markdown code blocks, like this
maxTokens: SEARCH_CONSTANTS.LIMITS.QUERY_PROCESSOR_MAX_TOKENS, maxTokens: SEARCH_CONSTANTS.LIMITS.QUERY_PROCESSOR_MAX_TOKENS,
bypassFormatter: true, bypassFormatter: true,
expectsJsonResponse: true, expectsJsonResponse: true,
_bypassContextProcessing: true // Prevent recursive calls _bypassContextProcessing: true, // Prevent recursive calls
enableTools: false // Explicitly disable tools for this request
}; };
// Get the response from the LLM // Get the response from the LLM
@ -167,69 +168,33 @@ Format your answer as a valid JSON array without markdown code blocks, like this
// Try to get LLM service if not provided // Try to get LLM service if not provided
const service = llmService || await this.getLLMService(); const service = llmService || await this.getLLMService();
// For when no LLM service is available, use the basic approach // If no LLM service is available, use basic decomposition
if (!service) { if (!service) {
if (!service) { log.info(`No LLM service available for query decomposition, using original query`);
log.info(`No LLM service available for query decomposition, using original query`); return this.createBasicDecomposition(query, complexity);
}
log.info(`Using basic decomposition approach (complexity: ${complexity})`);
const mainSubQuery = {
id: this.generateSubQueryId(),
text: query,
reason: "Direct question that can be answered without decomposition",
isAnswered: false
};
// Add a generic exploration query for context
const genericQuery = {
id: this.generateSubQueryId(),
text: `What information is related to ${query}?`,
reason: "General exploration to find related content",
isAnswered: false
};
return {
originalQuery: query,
subQueries: [mainSubQuery, genericQuery],
status: 'pending',
complexity
};
} }
// For when the LLM available, we can use more advanced decomposition // With LLM service available, always use advanced decomposition regardless of complexity
if (service) { try {
try { log.info(`Using advanced LLM-based decomposition for query (complexity: ${complexity})`);
// Try to use LLM for advanced decomposition const enhancedSubQueries = await this.createLLMSubQueries(query, context, service);
log.info(`Using advanced LLM-based decomposition for complex query (complexity: ${complexity})`);
const enhancedSubQueries = await this.createLLMSubQueries(query, context, service);
if (enhancedSubQueries && enhancedSubQueries.length > 0) { if (enhancedSubQueries && enhancedSubQueries.length > 0) {
log.info(`LLM decomposed query into ${enhancedSubQueries.length} sub-queries: ${JSON.stringify(enhancedSubQueries)}`); log.info(`LLM decomposed query into ${enhancedSubQueries.length} sub-queries`);
return { return {
originalQuery: query, originalQuery: query,
subQueries: enhancedSubQueries, subQueries: enhancedSubQueries,
status: 'pending', status: 'pending',
complexity complexity
}; };
}
} catch (error: any) {
log.error(`Error during LLM-based decomposition: ${error.message}, falling back to basic decomposition`);
// Continue to fallback with basic decomposition
} }
} catch (error: any) {
log.error(`Error during LLM-based decomposition: ${error.message}, falling back to basic decomposition`);
// Fall through to basic decomposition
} }
// Fallback to basic decomposition // Fallback to basic decomposition
const subQueries = this.createSubQueries(query, context); return this.createBasicDecomposition(query, complexity);
log.info(`Decomposed query into ${subQueries.length} sub-queries`);
return {
originalQuery: query,
subQueries,
status: 'pending',
complexity
};
} catch (error: any) { } catch (error: any) {
log.error(`Error decomposing query: ${error.message}`); log.error(`Error decomposing query: ${error.message}`);
@ -248,6 +213,39 @@ Format your answer as a valid JSON array without markdown code blocks, like this
} }
} }
/**
* Create a basic decomposition of a query without using LLM
*
* @param query The original query
* @param complexity The assessed complexity
* @returns A basic decomposed query
*/
private createBasicDecomposition(query: string, complexity: number): DecomposedQuery {
log.info(`Using basic decomposition approach (complexity: ${complexity})`);
const mainSubQuery = {
id: this.generateSubQueryId(),
text: query,
reason: "Direct question that can be answered without decomposition",
isAnswered: false
};
// Add a generic exploration query for context
const genericQuery = {
id: this.generateSubQueryId(),
text: `What information is related to ${query}?`,
reason: "General exploration to find related content",
isAnswered: false
};
return {
originalQuery: query,
subQueries: [mainSubQuery, genericQuery],
status: 'pending',
complexity
};
}
/** /**
* Use LLM to create advanced sub-queries from a complex query * Use LLM to create advanced sub-queries from a complex query
* *
@ -267,25 +265,42 @@ Format your answer as a valid JSON array without markdown code blocks, like this
} }
try { try {
// Build a prompt from existing templates in the constants // Create a much better prompt for more effective query decomposition
const contextPart = context ? `\nContext: ${context}` : ''; const prompt = `Decompose the following query into 3-5 specific search queries that would help find comprehensive information.
// Use existing templates from QUERY_DECOMPOSITION_STRINGS to build the prompt Your task is to identify the main concepts and break them down into specific, targeted search queries.
const prompt = `I need to break down a complex query into sub-queries.
Query: ${query}${contextPart}
Please analyze this query and identify the key aspects that need to be addressed.`; DO NOT simply rephrase the original query or create a generic "what's related to X" pattern.
DO create specific queries that explore different aspects of the topic.
For example:
If the query is "How does Docker compare to Kubernetes?", good sub-queries would be:
- "Docker container architecture and features"
- "Kubernetes container orchestration capabilities"
- "Docker vs Kubernetes performance comparison"
- "When to use Docker versus Kubernetes"
Format your response as a JSON array of objects with 'text' and 'reason' properties.
Example: [
{"text": "Docker container architecture", "reason": "Understanding Docker's core technology"},
{"text": "Kubernetes orchestration features", "reason": "Exploring Kubernetes' main capabilities"}
]
${context ? `\nContext: ${context}` : ''}
Query: ${query}`;
const messages = [ const messages = [
{ role: "system" as const, content: prompt } { role: "system" as const, content: prompt }
]; ];
const options = { const options = {
temperature: SEARCH_CONSTANTS.TEMPERATURE.QUERY_PROCESSOR, temperature: 0.7, // Higher temperature for more creative decomposition
maxTokens: SEARCH_CONSTANTS.LIMITS.QUERY_PROCESSOR_MAX_TOKENS, maxTokens: SEARCH_CONSTANTS.LIMITS.QUERY_PROCESSOR_MAX_TOKENS,
bypassFormatter: true, bypassFormatter: true,
expectsJsonResponse: true, expectsJsonResponse: true,
_bypassContextProcessing: true // Prevent recursive calls _bypassContextProcessing: true, // Prevent recursive calls
enableTools: false // Explicitly disable tools for this request
}; };
// Get the response from the LLM // Get the response from the LLM
@ -300,6 +315,11 @@ Please analyze this query and identify the key aspects that need to be addressed
reason?: string; reason?: string;
} }
// Log the response for debugging
log.info(`Received response from LLM for query decomposition, extracting JSON...`);
log.info(`Response: ${responseText}`);
// Extract JSON from the response // Extract JSON from the response
const extractedData = JsonExtractor.extract<RawSubQuery[]>(responseText, { const extractedData = JsonExtractor.extract<RawSubQuery[]>(responseText, {
extractArrays: true, extractArrays: true,
@ -307,15 +327,74 @@ Please analyze this query and identify the key aspects that need to be addressed
useFallbacks: true useFallbacks: true
}); });
if (Array.isArray(extractedData) && extractedData.length > 0) { // Validate the extracted data
// Convert the raw data to SubQuery objects if (!Array.isArray(extractedData)) {
return extractedData.map(item => ({ log.error(`Failed to extract array from LLM response, got: ${typeof extractedData}`);
id: this.generateSubQueryId(), return this.createSubQueries(query, context);
text: item.text,
reason: item.reason || "Sub-aspect of the main question",
isAnswered: false
}));
} }
if (extractedData.length === 0) {
log.error(`Extracted array is empty, falling back to basic decomposition`);
return this.createSubQueries(query, context);
}
log.info(`Successfully extracted ${extractedData.length} items using regex pattern`);
// Validate each sub-query to ensure it has a text property
const validSubQueries = extractedData.filter(item => {
if (!item || typeof item !== 'object') {
log.error(`Invalid sub-query item: ${JSON.stringify(item)}`);
return false;
}
if (!item.text || typeof item.text !== 'string') {
log.error(`Sub-query missing text property: ${JSON.stringify(item)}`);
return false;
}
return true;
});
if (validSubQueries.length === 0) {
log.error(`No valid sub-queries found after validation, falling back to basic decomposition`);
return this.createSubQueries(query, context);
}
if (validSubQueries.length < extractedData.length) {
log.info(`Some invalid sub-queries were filtered out: ${extractedData.length} -> ${validSubQueries.length}`);
}
// Convert the raw data to SubQuery objects
let subQueries = validSubQueries.map(item => ({
id: this.generateSubQueryId(),
text: item.text,
reason: item.reason || "Sub-aspect of the main question",
isAnswered: false
}));
// Make sure we have at least the original query
const hasOriginalQuery = subQueries.some(sq => {
// Check if either sq.text or query is null/undefined before using toLowerCase
if (!sq.text) return false;
const sqText = sq.text.toLowerCase();
const originalQuery = query.toLowerCase();
return sqText.includes(originalQuery) || originalQuery.includes(sqText);
});
if (!hasOriginalQuery) {
subQueries.unshift({
id: this.generateSubQueryId(),
text: query,
reason: "Original query",
isAnswered: false
});
}
// Log the extracted sub-queries for debugging
log.info(`Successfully extracted ${subQueries.length} sub-queries from LLM response`);
return subQueries;
} catch (error: any) { } catch (error: any) {
log.error(`Error extracting sub-queries from LLM response: ${error.message}`); log.error(`Error extracting sub-queries from LLM response: ${error.message}`);
// Fall through to traditional decomposition // Fall through to traditional decomposition

View File

@ -9,139 +9,139 @@ import type BAttribute from '../../../becca/entities/battribute.js';
* Interface for the AI service used by agent tools * Interface for the AI service used by agent tools
*/ */
export interface LLMServiceInterface { export interface LLMServiceInterface {
generateChatCompletion(messages: Array<{ generateChatCompletion(messages: Array<{
role: 'user' | 'assistant' | 'system'; role: 'user' | 'assistant' | 'system';
content: string; content: string;
}>, options?: { }>, options?: {
temperature?: number; temperature?: number;
maxTokens?: number; maxTokens?: number;
model?: string; model?: string;
stream?: boolean; stream?: boolean;
systemPrompt?: string; systemPrompt?: string;
}): Promise<ChatResponse>; }): Promise<ChatResponse>;
} }
/** /**
* Interface for tool initialization * Interface for tool initialization
*/ */
export interface AgentToolInitializationParams { export interface AgentToolInitializationParams {
aiServiceManager: LLMServiceInterface; aiServiceManager: LLMServiceInterface;
} }
/** /**
* Interface for agent tool manager * Interface for agent tool manager
*/ */
export interface IAgentToolsManager { export interface IAgentToolsManager {
initialize(aiServiceManager: LLMServiceInterface): Promise<void>; initialize(aiServiceManager: LLMServiceInterface): Promise<void>;
isInitialized(): boolean; isInitialized(): boolean;
getAllTools(): { getAllTools(): {
vectorSearch: IVectorSearchTool; vectorSearch: IVectorSearchTool;
noteNavigator: INoteNavigatorTool; noteNavigator: INoteNavigatorTool;
queryDecomposition: IQueryDecompositionTool; queryDecomposition: IQueryDecompositionTool;
contextualThinking: IContextualThinkingTool; contextualThinking: IContextualThinkingTool;
}; };
getVectorSearchTool(): IVectorSearchTool; getVectorSearchTool(): IVectorSearchTool;
getNoteNavigatorTool(): INoteNavigatorTool; getNoteNavigatorTool(): INoteNavigatorTool;
getQueryDecompositionTool(): IQueryDecompositionTool; getQueryDecompositionTool(): IQueryDecompositionTool;
getContextualThinkingTool(): IContextualThinkingTool; getContextualThinkingTool(): IContextualThinkingTool;
} }
/** /**
* Interface for context service used by vector search * Interface for context service used by vector search
*/ */
export interface IContextService { export interface IContextService {
findRelevantNotesMultiQuery(queries: string[], contextNoteId: string | null, limit: number): Promise<VectorSearchResult[]>; findRelevantNotesMultiQuery(queries: string[], contextNoteId: string | null, limit: number): Promise<VectorSearchResult[]>;
processQuery(userQuestion: string, llmService: LLMServiceInterface, contextNoteId: string | null, showThinking: boolean): Promise<{ processQuery(userQuestion: string, llmService: LLMServiceInterface, contextNoteId: string | null, showThinking: boolean): Promise<{
context: string; context: string;
sources: Array<{ sources: Array<{
noteId: string; noteId: string;
title: string; title: string;
similarity: number; similarity: number;
}>;
thinking?: string;
}>; }>;
thinking?: string;
}>;
} }
/** /**
* Interface for vector search tool * Interface for vector search tool
*/ */
export interface IVectorSearchTool { export interface IVectorSearchTool {
setContextService(contextService: IContextService): void; setContextService(contextService: IContextService): void;
search( search(
query: string, query: string,
contextNoteId?: string, contextNoteId?: string,
searchOptions?: { searchOptions?: {
limit?: number; limit?: number;
threshold?: number; threshold?: number;
includeContent?: boolean; includeContent?: boolean;
} }
): Promise<VectorSearchResult[]>; ): Promise<VectorSearchResult[]>;
searchNotes(query: string, options?: { searchNotes(query: string, options?: {
parentNoteId?: string; parentNoteId?: string;
maxResults?: number; maxResults?: number;
similarityThreshold?: number; similarityThreshold?: number;
}): Promise<VectorSearchResult[]>; }): Promise<VectorSearchResult[]>;
searchContentChunks(query: string, options?: { searchContentChunks(query: string, options?: {
noteId?: string; noteId?: string;
maxResults?: number; maxResults?: number;
similarityThreshold?: number; similarityThreshold?: number;
}): Promise<VectorSearchResult[]>; }): Promise<VectorSearchResult[]>;
explainResults(query: string, results: VectorSearchResult[]): string; explainResults(query: string, results: VectorSearchResult[]): string;
} }
/** /**
* Interface for note navigator tool * Interface for note navigator tool
*/ */
export interface INoteNavigatorTool { export interface INoteNavigatorTool {
getNoteInfo(noteId: string): NoteInfo | null; getNoteInfo(noteId: string): NoteInfo | null;
getNotePathsFromRoot(noteId: string): NotePathInfo[]; getNotePathsFromRoot(noteId: string): NotePathInfo[];
getNoteHierarchy(noteId: string, depth?: number): NoteHierarchyLevel | null; getNoteHierarchy(noteId: string, depth?: number): NoteHierarchyLevel | null;
getNoteAttributes(noteId: string): BAttribute[]; getNoteAttributes(noteId: string): BAttribute[];
findPathBetweenNotes(fromNoteId: string, toNoteId: string): NotePathInfo | null; findPathBetweenNotes(fromNoteId: string, toNoteId: string): NotePathInfo | null;
searchNotesByTitle(searchTerm: string, limit?: number): NoteInfo[]; searchNotesByTitle(searchTerm: string, limit?: number): NoteInfo[];
getNoteClones(noteId: string): Promise<NoteInfo[]>; getNoteClones(noteId: string): Promise<NoteInfo[]>;
getNoteContextDescription(noteId: string): Promise<string>; getNoteContextDescription(noteId: string): Promise<string>;
getNoteStructure(noteId: string): Promise<{ getNoteStructure(noteId: string): Promise<{
noteId: string; noteId: string;
title: string; title: string;
type: string; type: string;
childCount: number; childCount: number;
attributes: Array<{name: string, value: string}>; attributes: Array<{ name: string, value: string }>;
parentPath: Array<{title: string, noteId: string}>; parentPath: Array<{ title: string, noteId: string }>;
}>; }>;
getChildNotes(noteId: string, limit?: number): Promise<Array<{noteId: string, title: string}>>; getChildNotes(noteId: string, limit?: number): Promise<Array<{ noteId: string, title: string }>>;
getParentNotes(noteId: string): Promise<Array<{noteId: string, title: string}>>; getParentNotes(noteId: string): Promise<Array<{ noteId: string, title: string }>>;
getLinkedNotes(noteId: string, limit?: number): Promise<Array<{noteId: string, title: string, direction: 'from'|'to'}>>; getLinkedNotes(noteId: string, limit?: number): Promise<Array<{ noteId: string, title: string, direction: 'from' | 'to' }>>;
getNotePath(noteId: string): Promise<string>; getNotePath(noteId: string): Promise<string>;
} }
/** /**
* Interface for query decomposition tool * Interface for query decomposition tool
*/ */
export interface IQueryDecompositionTool { export interface IQueryDecompositionTool {
decomposeQuery(query: string, context?: string): DecomposedQuery; decomposeQuery(query: string, context?: string): DecomposedQuery;
updateSubQueryAnswer(decomposedQuery: DecomposedQuery, subQueryId: string, answer: string): DecomposedQuery; updateSubQueryAnswer(decomposedQuery: DecomposedQuery, subQueryId: string, answer: string): DecomposedQuery;
synthesizeAnswer(decomposedQuery: DecomposedQuery): string; synthesizeAnswer(decomposedQuery: DecomposedQuery): string;
getQueryStatus(decomposedQuery: DecomposedQuery): string; getQueryStatus(decomposedQuery: DecomposedQuery): string;
assessQueryComplexity(query: string): number; assessQueryComplexity(query: string): number;
generateSubQueryId(): string; generateSubQueryId(): string;
createSubQueries(query: string, context?: string): SubQuery[]; createSubQueries(query: string, context?: string): SubQuery[];
} }
/** /**
* Interface for contextual thinking tool * Interface for contextual thinking tool
*/ */
export interface IContextualThinkingTool { export interface IContextualThinkingTool {
startThinking(query: string): string; startThinking(query: string): string;
addThinkingStep( addThinkingStep(
processId: string, processId: string,
step: Omit<ThinkingStep, 'id'>, step: Omit<ThinkingStep, 'id'>,
parentId?: string parentId?: string
): string; ): string;
completeThinking(processId?: string): ThinkingProcess | null; completeThinking(processId?: string): ThinkingProcess | null;
getThinkingProcess(processId: string): ThinkingProcess | null; getThinkingProcess(processId: string): ThinkingProcess | null;
getActiveThinkingProcess(): ThinkingProcess | null; getActiveThinkingProcess(): ThinkingProcess | null;
visualizeThinking(thinkingId: string): string; visualizeThinking(thinkingId: string): string;
getThinkingSummary(thinkingId: string): string; getThinkingSummary(thinkingId: string): string;
resetActiveThinking(): void; resetActiveThinking(): void;
} }

View File

@ -5,19 +5,19 @@ import type { ToolCall } from '../tools/tool_interfaces.js';
* Model metadata interface to track provider information * Model metadata interface to track provider information
*/ */
export interface ModelMetadata { export interface ModelMetadata {
// The provider that supports this model // The provider that supports this model
provider: 'openai' | 'anthropic' | 'ollama' | 'local'; provider: 'openai' | 'anthropic' | 'ollama' | 'local';
// The actual model identifier used by the provider's API // The actual model identifier used by the provider's API
modelId: string; modelId: string;
// Display name for UI (optional) // Display name for UI (optional)
displayName?: string; displayName?: string;
// Model capabilities // Model capabilities
capabilities?: { capabilities?: {
contextWindow?: number; contextWindow?: number;
supportsTools?: boolean; supportsTools?: boolean;
supportsVision?: boolean; supportsVision?: boolean;
supportsStreaming?: boolean; supportsStreaming?: boolean;
}; };
} }
/** /**
@ -25,196 +25,196 @@ export interface ModelMetadata {
* but not necessarily sent directly to APIs * but not necessarily sent directly to APIs
*/ */
export interface ProviderConfig { export interface ProviderConfig {
// Internal configuration // Internal configuration
systemPrompt?: string; systemPrompt?: string;
// Provider metadata for model routing // Provider metadata for model routing
providerMetadata?: ModelMetadata; providerMetadata?: ModelMetadata;
} }
/** /**
* OpenAI-specific options, structured to match the OpenAI API * OpenAI-specific options, structured to match the OpenAI API
*/ */
export interface OpenAIOptions extends ProviderConfig { export interface OpenAIOptions extends ProviderConfig {
// Connection settings (not sent to API) // Connection settings (not sent to API)
apiKey: string; apiKey: string;
baseUrl: string; baseUrl: string;
// Direct API parameters as they appear in requests // Direct API parameters as they appear in requests
model: string; model: string;
messages?: Message[]; messages?: Message[];
temperature?: number; temperature?: number;
max_tokens?: number; max_tokens?: number;
stream?: boolean; stream?: boolean;
top_p?: number; top_p?: number;
frequency_penalty?: number; frequency_penalty?: number;
presence_penalty?: number; presence_penalty?: number;
tools?: any[]; tools?: any[];
tool_choice?: string | object; tool_choice?: string | object;
// Internal control flags (not sent directly to API) // Internal control flags (not sent directly to API)
enableTools?: boolean; enableTools?: boolean;
// Streaming callback handler // Streaming callback handler
streamCallback?: (text: string, isDone: boolean, originalChunk?: any) => Promise<void> | void; streamCallback?: (text: string, isDone: boolean, originalChunk?: any) => Promise<void> | void;
} }
/** /**
* Anthropic-specific options, structured to match the Anthropic API * Anthropic-specific options, structured to match the Anthropic API
*/ */
export interface AnthropicOptions extends ProviderConfig { export interface AnthropicOptions extends ProviderConfig {
// Connection settings (not sent to API) // Connection settings (not sent to API)
apiKey: string; apiKey: string;
baseUrl: string; baseUrl: string;
apiVersion?: string; apiVersion?: string;
betaVersion?: string; betaVersion?: string;
// Direct API parameters as they appear in requests // Direct API parameters as they appear in requests
model: string; model: string;
messages?: any[]; messages?: any[];
system?: string; system?: string;
temperature?: number; temperature?: number;
max_tokens?: number; max_tokens?: number;
stream?: boolean; stream?: boolean;
top_p?: number; top_p?: number;
// Internal parameters (not sent directly to API) // Internal parameters (not sent directly to API)
formattedMessages?: { messages: any[], system: string }; formattedMessages?: { messages: any[], system: string };
// Streaming callback handler // Streaming callback handler
streamCallback?: (text: string, isDone: boolean, originalChunk?: any) => Promise<void> | void; streamCallback?: (text: string, isDone: boolean, originalChunk?: any) => Promise<void> | void;
} }
/** /**
* Ollama-specific options, structured to match the Ollama API * Ollama-specific options, structured to match the Ollama API
*/ */
export interface OllamaOptions extends ProviderConfig { export interface OllamaOptions extends ProviderConfig {
// Connection settings (not sent to API) // Connection settings (not sent to API)
baseUrl: string; baseUrl: string;
// Direct API parameters as they appear in requests // Direct API parameters as they appear in requests
model: string; model: string;
messages?: Message[]; messages?: Message[];
stream?: boolean; stream?: boolean;
options?: { options?: {
temperature?: number; temperature?: number;
num_ctx?: number; num_ctx?: number;
top_p?: number; top_p?: number;
top_k?: number; top_k?: number;
num_predict?: number; // equivalent to max_tokens num_predict?: number; // equivalent to max_tokens
response_format?: { type: string }; response_format?: { type: string };
}; };
tools?: any[]; tools?: any[];
// Internal control flags (not sent directly to API) // Internal control flags (not sent directly to API)
enableTools?: boolean; enableTools?: boolean;
bypassFormatter?: boolean; bypassFormatter?: boolean;
preserveSystemPrompt?: boolean; preserveSystemPrompt?: boolean;
expectsJsonResponse?: boolean; expectsJsonResponse?: boolean;
toolExecutionStatus?: any[]; toolExecutionStatus?: any[];
// Streaming callback handler // Streaming callback handler
streamCallback?: (text: string, isDone: boolean, originalChunk?: any) => Promise<void> | void; streamCallback?: (text: string, isDone: boolean, originalChunk?: any) => Promise<void> | void;
} }
/** /**
* Create OpenAI options from generic options and config * Create OpenAI options from generic options and config
*/ */
export function createOpenAIOptions( export function createOpenAIOptions(
opts: ChatCompletionOptions = {}, opts: ChatCompletionOptions = {},
apiKey: string, apiKey: string,
baseUrl: string, baseUrl: string,
defaultModel: string defaultModel: string
): OpenAIOptions { ): OpenAIOptions {
return { return {
// Connection settings // Connection settings
apiKey, apiKey,
baseUrl, baseUrl,
// API parameters // API parameters
model: opts.model || defaultModel, model: opts.model || defaultModel,
temperature: opts.temperature, temperature: opts.temperature,
max_tokens: opts.maxTokens, max_tokens: opts.maxTokens,
stream: opts.stream, stream: opts.stream,
top_p: opts.topP, top_p: opts.topP,
frequency_penalty: opts.frequencyPenalty, frequency_penalty: opts.frequencyPenalty,
presence_penalty: opts.presencePenalty, presence_penalty: opts.presencePenalty,
tools: opts.tools, tools: opts.tools,
// Internal configuration // Internal configuration
systemPrompt: opts.systemPrompt, systemPrompt: opts.systemPrompt,
enableTools: opts.enableTools, enableTools: opts.enableTools,
// Pass through streaming callback // Pass through streaming callback
streamCallback: opts.streamCallback, streamCallback: opts.streamCallback,
// Include provider metadata // Include provider metadata
providerMetadata: opts.providerMetadata, providerMetadata: opts.providerMetadata,
}; };
} }
/** /**
* Create Anthropic options from generic options and config * Create Anthropic options from generic options and config
*/ */
export function createAnthropicOptions( export function createAnthropicOptions(
opts: ChatCompletionOptions = {}, opts: ChatCompletionOptions = {},
apiKey: string, apiKey: string,
baseUrl: string, baseUrl: string,
defaultModel: string, defaultModel: string,
apiVersion: string, apiVersion: string,
betaVersion: string betaVersion: string
): AnthropicOptions { ): AnthropicOptions {
return { return {
// Connection settings // Connection settings
apiKey, apiKey,
baseUrl, baseUrl,
apiVersion, apiVersion,
betaVersion, betaVersion,
// API parameters // API parameters
model: opts.model || defaultModel, model: opts.model || defaultModel,
temperature: opts.temperature, temperature: opts.temperature,
max_tokens: opts.maxTokens, max_tokens: opts.maxTokens,
stream: opts.stream, stream: opts.stream,
top_p: opts.topP, top_p: opts.topP,
// Internal configuration // Internal configuration
systemPrompt: opts.systemPrompt, systemPrompt: opts.systemPrompt,
// Pass through streaming callback // Pass through streaming callback
streamCallback: opts.streamCallback, streamCallback: opts.streamCallback,
// Include provider metadata // Include provider metadata
providerMetadata: opts.providerMetadata, providerMetadata: opts.providerMetadata,
}; };
} }
/** /**
* Create Ollama options from generic options and config * Create Ollama options from generic options and config
*/ */
export function createOllamaOptions( export function createOllamaOptions(
opts: ChatCompletionOptions = {}, opts: ChatCompletionOptions = {},
baseUrl: string, baseUrl: string,
defaultModel: string, defaultModel: string,
contextWindow: number contextWindow: number
): OllamaOptions { ): OllamaOptions {
return { return {
// Connection settings // Connection settings
baseUrl, baseUrl,
// API parameters // API parameters
model: opts.model || defaultModel, model: opts.model || defaultModel,
stream: opts.stream, stream: opts.stream,
options: { options: {
temperature: opts.temperature, temperature: opts.temperature,
num_ctx: contextWindow, num_ctx: contextWindow,
num_predict: opts.maxTokens, num_predict: opts.maxTokens,
response_format: opts.expectsJsonResponse ? { type: "json_object" } : undefined response_format: opts.expectsJsonResponse ? { type: "json_object" } : undefined
}, },
tools: opts.tools, tools: opts.tools,
// Internal configuration // Internal configuration
systemPrompt: opts.systemPrompt, systemPrompt: opts.systemPrompt,
enableTools: opts.enableTools, enableTools: opts.enableTools,
bypassFormatter: opts.bypassFormatter, bypassFormatter: opts.bypassFormatter,
preserveSystemPrompt: opts.preserveSystemPrompt, preserveSystemPrompt: opts.preserveSystemPrompt,
expectsJsonResponse: opts.expectsJsonResponse, expectsJsonResponse: opts.expectsJsonResponse,
toolExecutionStatus: opts.toolExecutionStatus, toolExecutionStatus: opts.toolExecutionStatus,
// Pass through streaming callback // Pass through streaming callback
streamCallback: opts.streamCallback, streamCallback: opts.streamCallback,
// Include provider metadata // Include provider metadata
providerMetadata: opts.providerMetadata, providerMetadata: opts.providerMetadata,
}; };
} }

View File

@ -153,7 +153,7 @@ export async function createEmbeddingProviderConfig(
dateCreated, utcDateCreated, dateModified, utcDateModified) dateCreated, utcDateCreated, dateModified, utcDateModified)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
[providerId, name, priority, JSON.stringify(config), [providerId, name, priority, JSON.stringify(config),
now, utcNow, now, utcNow] now, utcNow, now, utcNow]
); );
return providerId; return providerId;
@ -460,8 +460,8 @@ export function getAnthropicOptions(
supportsStreaming: true, supportsStreaming: true,
// Anthropic models typically have large context windows // Anthropic models typically have large context windows
contextWindow: modelName.includes('claude-3-opus') ? 200000 : contextWindow: modelName.includes('claude-3-opus') ? 200000 :
modelName.includes('claude-3-sonnet') ? 180000 : modelName.includes('claude-3-sonnet') ? 180000 :
modelName.includes('claude-3.5-sonnet') ? 200000 : 100000 modelName.includes('claude-3.5-sonnet') ? 200000 : 100000
} }
}; };