Merge branch 'canary'

This commit is contained in:
ItzCrazyKns
2025-12-27 20:52:56 +05:30
132 changed files with 9699 additions and 4342 deletions

View File

@@ -0,0 +1,9 @@
import { Chunk } from '@/lib/types';
abstract class BaseEmbedding<CONFIG> {
constructor(protected config: CONFIG) {}
abstract embedText(texts: string[]): Promise<number[][]>;
abstract embedChunks(chunks: Chunk[]): Promise<number[][]>;
}
export default BaseEmbedding;

View File

@@ -0,0 +1,22 @@
import z from 'zod';
import {
GenerateObjectInput,
GenerateOptions,
GenerateTextInput,
GenerateTextOutput,
StreamTextOutput,
} from '../types';
abstract class BaseLLM<CONFIG> {
constructor(protected config: CONFIG) {}
abstract generateText(input: GenerateTextInput): Promise<GenerateTextOutput>;
abstract streamText(
input: GenerateTextInput,
): AsyncGenerator<StreamTextOutput>;
abstract generateObject<T>(input: GenerateObjectInput): Promise<z.infer<T>>;
abstract streamObject<T>(
input: GenerateObjectInput,
): AsyncGenerator<Partial<z.infer<T>>>;
}
export default BaseLLM;

View File

@@ -1,7 +1,7 @@
import { Embeddings } from '@langchain/core/embeddings';
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Model, ModelList, ProviderMetadata } from '../types';
import { ModelList, ProviderMetadata } from '../types';
import { UIConfigField } from '@/lib/config/types';
import BaseLLM from './llm';
import BaseEmbedding from './embedding';
abstract class BaseModelProvider<CONFIG> {
constructor(
@@ -11,8 +11,8 @@ abstract class BaseModelProvider<CONFIG> {
) {}
abstract getDefaultModels(): Promise<ModelList>;
abstract getModelList(): Promise<ModelList>;
abstract loadChatModel(modelName: string): Promise<BaseChatModel>;
abstract loadEmbeddingModel(modelName: string): Promise<Embeddings>;
abstract loadChatModel(modelName: string): Promise<BaseLLM<any>>;
abstract loadEmbeddingModel(modelName: string): Promise<BaseEmbedding<any>>;
static getProviderConfigFields(): UIConfigField[] {
throw new Error('Method not implemented.');
}

View File

@@ -1,152 +0,0 @@
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Model, ModelList, ProviderMetadata } from '../types';
import BaseModelProvider from './baseProvider';
import { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai';
import { Embeddings } from '@langchain/core/embeddings';
import { UIConfigField } from '@/lib/config/types';
import { getConfiguredModelProviderById } from '@/lib/config/serverRegistry';
interface AimlConfig {
apiKey: string;
}
const providerConfigFields: UIConfigField[] = [
{
type: 'password',
name: 'API Key',
key: 'apiKey',
description: 'Your AI/ML API key',
required: true,
placeholder: 'AI/ML API Key',
env: 'AIML_API_KEY',
scope: 'server',
},
];
class AimlProvider extends BaseModelProvider<AimlConfig> {
constructor(id: string, name: string, config: AimlConfig) {
super(id, name, config);
}
async getDefaultModels(): Promise<ModelList> {
try {
const res = await fetch('https://api.aimlapi.com/models', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.config.apiKey}`,
},
});
const data = await res.json();
const chatModels: Model[] = data.data
.filter((m: any) => m.type === 'chat-completion')
.map((m: any) => {
return {
name: m.id,
key: m.id,
};
});
const embeddingModels: Model[] = data.data
.filter((m: any) => m.type === 'embedding')
.map((m: any) => {
return {
name: m.id,
key: m.id,
};
});
return {
embedding: embeddingModels,
chat: chatModels,
};
} catch (err) {
if (err instanceof TypeError) {
throw new Error(
'Error connecting to AI/ML API. Please ensure your API key is correct and the service is available.',
);
}
throw err;
}
}
async getModelList(): Promise<ModelList> {
const defaultModels = await this.getDefaultModels();
const configProvider = getConfiguredModelProviderById(this.id)!;
return {
embedding: [
...defaultModels.embedding,
...configProvider.embeddingModels,
],
chat: [...defaultModels.chat, ...configProvider.chatModels],
};
}
async loadChatModel(key: string): Promise<BaseChatModel> {
const modelList = await this.getModelList();
const exists = modelList.chat.find((m) => m.key === key);
if (!exists) {
throw new Error(
'Error Loading AI/ML API Chat Model. Invalid Model Selected',
);
}
return new ChatOpenAI({
apiKey: this.config.apiKey,
temperature: 0.7,
model: key,
configuration: {
baseURL: 'https://api.aimlapi.com',
},
});
}
async loadEmbeddingModel(key: string): Promise<Embeddings> {
const modelList = await this.getModelList();
const exists = modelList.embedding.find((m) => m.key === key);
if (!exists) {
throw new Error(
'Error Loading AI/ML API Embedding Model. Invalid Model Selected.',
);
}
return new OpenAIEmbeddings({
apiKey: this.config.apiKey,
model: key,
configuration: {
baseURL: 'https://api.aimlapi.com',
},
});
}
static parseAndValidate(raw: any): AimlConfig {
if (!raw || typeof raw !== 'object')
throw new Error('Invalid config provided. Expected object');
if (!raw.apiKey)
throw new Error('Invalid config provided. API key must be provided');
return {
apiKey: String(raw.apiKey),
};
}
static getProviderConfigFields(): UIConfigField[] {
return providerConfigFields;
}
static getProviderMetadata(): ProviderMetadata {
return {
key: 'aiml',
name: 'AI/ML API',
};
}
}
export default AimlProvider;

View File

@@ -0,0 +1,5 @@
import OpenAILLM from '../openai/openaiLLM';
class AnthropicLLM extends OpenAILLM {}
export default AnthropicLLM;

View File

@@ -1,10 +1,10 @@
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Model, ModelList, ProviderMetadata } from '../types';
import BaseModelProvider from './baseProvider';
import { ChatAnthropic } from '@langchain/anthropic';
import { Embeddings } from '@langchain/core/embeddings';
import { UIConfigField } from '@/lib/config/types';
import { getConfiguredModelProviderById } from '@/lib/config/serverRegistry';
import { Model, ModelList, ProviderMetadata } from '../../types';
import BaseEmbedding from '../../base/embedding';
import BaseModelProvider from '../../base/provider';
import BaseLLM from '../../base/llm';
import AnthropicLLM from './anthropicLLM';
interface AnthropicConfig {
apiKey: string;
@@ -67,7 +67,7 @@ class AnthropicProvider extends BaseModelProvider<AnthropicConfig> {
};
}
async loadChatModel(key: string): Promise<BaseChatModel> {
async loadChatModel(key: string): Promise<BaseLLM<any>> {
const modelList = await this.getModelList();
const exists = modelList.chat.find((m) => m.key === key);
@@ -78,14 +78,14 @@ class AnthropicProvider extends BaseModelProvider<AnthropicConfig> {
);
}
return new ChatAnthropic({
return new AnthropicLLM({
apiKey: this.config.apiKey,
temperature: 0.7,
model: key,
baseURL: 'https://api.anthropic.com/v1',
});
}
async loadEmbeddingModel(key: string): Promise<Embeddings> {
async loadEmbeddingModel(key: string): Promise<BaseEmbedding<any>> {
throw new Error('Anthropic provider does not support embedding models.');
}

View File

@@ -1,107 +0,0 @@
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Model, ModelList, ProviderMetadata } from '../types';
import BaseModelProvider from './baseProvider';
import { ChatOpenAI } from '@langchain/openai';
import { Embeddings } from '@langchain/core/embeddings';
import { UIConfigField } from '@/lib/config/types';
import { getConfiguredModelProviderById } from '@/lib/config/serverRegistry';
interface DeepSeekConfig {
apiKey: string;
}
const defaultChatModels: Model[] = [
{
name: 'Deepseek Chat / DeepSeek V3.2 Exp',
key: 'deepseek-chat',
},
{
name: 'Deepseek Reasoner / DeepSeek V3.2 Exp',
key: 'deepseek-reasoner',
},
];
const providerConfigFields: UIConfigField[] = [
{
type: 'password',
name: 'API Key',
key: 'apiKey',
description: 'Your DeepSeek API key',
required: true,
placeholder: 'DeepSeek API Key',
env: 'DEEPSEEK_API_KEY',
scope: 'server',
},
];
class DeepSeekProvider extends BaseModelProvider<DeepSeekConfig> {
constructor(id: string, name: string, config: DeepSeekConfig) {
super(id, name, config);
}
async getDefaultModels(): Promise<ModelList> {
return {
embedding: [],
chat: defaultChatModels,
};
}
async getModelList(): Promise<ModelList> {
const defaultModels = await this.getDefaultModels();
const configProvider = getConfiguredModelProviderById(this.id)!;
return {
embedding: [],
chat: [...defaultModels.chat, ...configProvider.chatModels],
};
}
async loadChatModel(key: string): Promise<BaseChatModel> {
const modelList = await this.getModelList();
const exists = modelList.chat.find((m) => m.key === key);
if (!exists) {
throw new Error(
'Error Loading DeepSeek Chat Model. Invalid Model Selected',
);
}
return new ChatOpenAI({
apiKey: this.config.apiKey,
temperature: 0.7,
model: key,
configuration: {
baseURL: 'https://api.deepseek.com',
},
});
}
async loadEmbeddingModel(key: string): Promise<Embeddings> {
throw new Error('DeepSeek provider does not support embedding models.');
}
static parseAndValidate(raw: any): DeepSeekConfig {
if (!raw || typeof raw !== 'object')
throw new Error('Invalid config provided. Expected object');
if (!raw.apiKey)
throw new Error('Invalid config provided. API key must be provided');
return {
apiKey: String(raw.apiKey),
};
}
static getProviderConfigFields(): UIConfigField[] {
return providerConfigFields;
}
static getProviderMetadata(): ProviderMetadata {
return {
key: 'deepseek',
name: 'Deepseek AI',
};
}
}
export default DeepSeekProvider;

View File

@@ -0,0 +1,5 @@
import OpenAIEmbedding from '../openai/openaiEmbedding';
class GeminiEmbedding extends OpenAIEmbedding {}
export default GeminiEmbedding;

View File

@@ -0,0 +1,5 @@
import OpenAILLM from '../openai/openaiLLM';
class GeminiLLM extends OpenAILLM {}
export default GeminiLLM;

View File

@@ -1,13 +1,11 @@
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Model, ModelList, ProviderMetadata } from '../types';
import BaseModelProvider from './baseProvider';
import {
ChatGoogleGenerativeAI,
GoogleGenerativeAIEmbeddings,
} from '@langchain/google-genai';
import { Embeddings } from '@langchain/core/embeddings';
import { UIConfigField } from '@/lib/config/types';
import { getConfiguredModelProviderById } from '@/lib/config/serverRegistry';
import { Model, ModelList, ProviderMetadata } from '../../types';
import GeminiEmbedding from './geminiEmbedding';
import BaseEmbedding from '../../base/embedding';
import BaseModelProvider from '../../base/provider';
import BaseLLM from '../../base/llm';
import GeminiLLM from './geminiLLM';
interface GeminiConfig {
apiKey: string;
@@ -18,9 +16,9 @@ const providerConfigFields: UIConfigField[] = [
type: 'password',
name: 'API Key',
key: 'apiKey',
description: 'Your Google Gemini API key',
description: 'Your Gemini API key',
required: true,
placeholder: 'Google Gemini API Key',
placeholder: 'Gemini API Key',
env: 'GEMINI_API_KEY',
scope: 'server',
},
@@ -85,7 +83,7 @@ class GeminiProvider extends BaseModelProvider<GeminiConfig> {
};
}
async loadChatModel(key: string): Promise<BaseChatModel> {
async loadChatModel(key: string): Promise<BaseLLM<any>> {
const modelList = await this.getModelList();
const exists = modelList.chat.find((m) => m.key === key);
@@ -96,14 +94,14 @@ class GeminiProvider extends BaseModelProvider<GeminiConfig> {
);
}
return new ChatGoogleGenerativeAI({
return new GeminiLLM({
apiKey: this.config.apiKey,
temperature: 0.7,
model: key,
baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai',
});
}
async loadEmbeddingModel(key: string): Promise<Embeddings> {
async loadEmbeddingModel(key: string): Promise<BaseEmbedding<any>> {
const modelList = await this.getModelList();
const exists = modelList.embedding.find((m) => m.key === key);
@@ -113,9 +111,10 @@ class GeminiProvider extends BaseModelProvider<GeminiConfig> {
);
}
return new GoogleGenerativeAIEmbeddings({
return new GeminiEmbedding({
apiKey: this.config.apiKey,
model: key,
baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai',
});
}
@@ -137,7 +136,7 @@ class GeminiProvider extends BaseModelProvider<GeminiConfig> {
static getProviderMetadata(): ProviderMetadata {
return {
key: 'gemini',
name: 'Google Gemini',
name: 'Gemini',
};
}
}

View File

@@ -0,0 +1,5 @@
import OpenAILLM from '../openai/openaiLLM';
class GroqLLM extends OpenAILLM {}
export default GroqLLM;

View File

@@ -1,10 +1,10 @@
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Model, ModelList, ProviderMetadata } from '../types';
import BaseModelProvider from './baseProvider';
import { ChatGroq } from '@langchain/groq';
import { Embeddings } from '@langchain/core/embeddings';
import { UIConfigField } from '@/lib/config/types';
import { getConfiguredModelProviderById } from '@/lib/config/serverRegistry';
import { Model, ModelList, ProviderMetadata } from '../../types';
import BaseEmbedding from '../../base/embedding';
import BaseModelProvider from '../../base/provider';
import BaseLLM from '../../base/llm';
import GroqLLM from './groqLLM';
interface GroqConfig {
apiKey: string;
@@ -29,37 +29,29 @@ class GroqProvider extends BaseModelProvider<GroqConfig> {
}
async getDefaultModels(): Promise<ModelList> {
try {
const res = await fetch('https://api.groq.com/openai/v1/models', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.config.apiKey}`,
},
const res = await fetch(`https://api.groq.com/openai/v1/models`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.config.apiKey}`,
},
});
const data = await res.json();
const defaultChatModels: Model[] = [];
data.data.forEach((m: any) => {
defaultChatModels.push({
key: m.id,
name: m.id,
});
});
const data = await res.json();
const models: Model[] = data.data.map((m: any) => {
return {
name: m.id,
key: m.id,
};
});
return {
embedding: [],
chat: models,
};
} catch (err) {
if (err instanceof TypeError) {
throw new Error(
'Error connecting to Groq API. Please ensure your API key is correct and the Groq service is available.',
);
}
throw err;
}
return {
embedding: [],
chat: defaultChatModels,
};
}
async getModelList(): Promise<ModelList> {
@@ -67,12 +59,15 @@ class GroqProvider extends BaseModelProvider<GroqConfig> {
const configProvider = getConfiguredModelProviderById(this.id)!;
return {
embedding: [],
embedding: [
...defaultModels.embedding,
...configProvider.embeddingModels,
],
chat: [...defaultModels.chat, ...configProvider.chatModels],
};
}
async loadChatModel(key: string): Promise<BaseChatModel> {
async loadChatModel(key: string): Promise<BaseLLM<any>> {
const modelList = await this.getModelList();
const exists = modelList.chat.find((m) => m.key === key);
@@ -81,15 +76,15 @@ class GroqProvider extends BaseModelProvider<GroqConfig> {
throw new Error('Error Loading Groq Chat Model. Invalid Model Selected');
}
return new ChatGroq({
return new GroqLLM({
apiKey: this.config.apiKey,
temperature: 0.7,
model: key,
baseURL: 'https://api.groq.com/openai/v1',
});
}
async loadEmbeddingModel(key: string): Promise<Embeddings> {
throw new Error('Groq provider does not support embedding models.');
async loadEmbeddingModel(key: string): Promise<BaseEmbedding<any>> {
throw new Error('Groq Provider does not support embedding models.');
}
static parseAndValidate(raw: any): GroqConfig {

View File

@@ -1,27 +1,21 @@
import { ModelProviderUISection } from '@/lib/config/types';
import { ProviderConstructor } from './baseProvider';
import { ProviderConstructor } from '../base/provider';
import OpenAIProvider from './openai';
import OllamaProvider from './ollama';
import TransformersProvider from './transformers';
import AnthropicProvider from './anthropic';
import GeminiProvider from './gemini';
import TransformersProvider from './transformers';
import GroqProvider from './groq';
import DeepSeekProvider from './deepseek';
import LMStudioProvider from './lmstudio';
import LemonadeProvider from './lemonade';
import AimlProvider from '@/lib/models/providers/aiml';
import AnthropicProvider from './anthropic';
export const providers: Record<string, ProviderConstructor<any>> = {
openai: OpenAIProvider,
ollama: OllamaProvider,
transformers: TransformersProvider,
anthropic: AnthropicProvider,
gemini: GeminiProvider,
transformers: TransformersProvider,
groq: GroqProvider,
deepseek: DeepSeekProvider,
aiml: AimlProvider,
lmstudio: LMStudioProvider,
lemonade: LemonadeProvider,
anthropic: AnthropicProvider,
};
export const getModelProvidersUIConfigSection =

View File

@@ -1,10 +1,11 @@
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Model, ModelList, ProviderMetadata } from '../types';
import BaseModelProvider from './baseProvider';
import { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai';
import { Embeddings } from '@langchain/core/embeddings';
import { UIConfigField } from '@/lib/config/types';
import { getConfiguredModelProviderById } from '@/lib/config/serverRegistry';
import BaseModelProvider from '../../base/provider';
import { Model, ModelList, ProviderMetadata } from '../../types';
import BaseLLM from '../../base/llm';
import LemonadeLLM from './lemonadeLLM';
import BaseEmbedding from '../../base/embedding';
import LemonadeEmbedding from './lemonadeEmbedding';
interface LemonadeConfig {
baseURL: string;
@@ -41,27 +42,26 @@ class LemonadeProvider extends BaseModelProvider<LemonadeConfig> {
async getDefaultModels(): Promise<ModelList> {
try {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
if (this.config.apiKey) {
headers['Authorization'] = `Bearer ${this.config.apiKey}`;
}
const res = await fetch(`${this.config.baseURL}/models`, {
method: 'GET',
headers,
headers: {
'Content-Type': 'application/json',
...(this.config.apiKey
? { Authorization: `Bearer ${this.config.apiKey}` }
: {}),
},
});
const data = await res.json();
const models: Model[] = data.data.map((m: any) => {
return {
name: m.id,
key: m.id,
};
});
const models: Model[] = data.data
.filter((m: any) => m.recipe === 'llamacpp')
.map((m: any) => {
return {
name: m.id,
key: m.id,
};
});
return {
embedding: models,
@@ -91,7 +91,7 @@ class LemonadeProvider extends BaseModelProvider<LemonadeConfig> {
};
}
async loadChatModel(key: string): Promise<BaseChatModel> {
async loadChatModel(key: string): Promise<BaseLLM<any>> {
const modelList = await this.getModelList();
const exists = modelList.chat.find((m) => m.key === key);
@@ -102,17 +102,14 @@ class LemonadeProvider extends BaseModelProvider<LemonadeConfig> {
);
}
return new ChatOpenAI({
return new LemonadeLLM({
apiKey: this.config.apiKey || 'not-needed',
temperature: 0.7,
model: key,
configuration: {
baseURL: this.config.baseURL,
},
baseURL: this.config.baseURL,
});
}
async loadEmbeddingModel(key: string): Promise<Embeddings> {
async loadEmbeddingModel(key: string): Promise<BaseEmbedding<any>> {
const modelList = await this.getModelList();
const exists = modelList.embedding.find((m) => m.key === key);
@@ -122,12 +119,10 @@ class LemonadeProvider extends BaseModelProvider<LemonadeConfig> {
);
}
return new OpenAIEmbeddings({
return new LemonadeEmbedding({
apiKey: this.config.apiKey || 'not-needed',
model: key,
configuration: {
baseURL: this.config.baseURL,
},
baseURL: this.config.baseURL,
});
}

View File

@@ -0,0 +1,5 @@
import OpenAIEmbedding from '../openai/openaiEmbedding';
class LemonadeEmbedding extends OpenAIEmbedding {}
export default LemonadeEmbedding;

View File

@@ -0,0 +1,5 @@
import OpenAILLM from '../openai/openaiLLM';
class LemonadeLLM extends OpenAILLM {}
export default LemonadeLLM;

View File

@@ -1,148 +0,0 @@
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Model, ModelList, ProviderMetadata } from '../types';
import BaseModelProvider from './baseProvider';
import { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai';
import { Embeddings } from '@langchain/core/embeddings';
import { UIConfigField } from '@/lib/config/types';
import { getConfiguredModelProviderById } from '@/lib/config/serverRegistry';
interface LMStudioConfig {
baseURL: string;
}
const providerConfigFields: UIConfigField[] = [
{
type: 'string',
name: 'Base URL',
key: 'baseURL',
description: 'The base URL for LM Studio server',
required: true,
placeholder: 'http://localhost:1234',
env: 'LM_STUDIO_BASE_URL',
scope: 'server',
},
];
class LMStudioProvider extends BaseModelProvider<LMStudioConfig> {
constructor(id: string, name: string, config: LMStudioConfig) {
super(id, name, config);
}
private normalizeBaseURL(url: string): string {
const trimmed = url.trim().replace(/\/+$/, '');
return trimmed.endsWith('/v1') ? trimmed : `${trimmed}/v1`;
}
async getDefaultModels(): Promise<ModelList> {
try {
const baseURL = this.normalizeBaseURL(this.config.baseURL);
const res = await fetch(`${baseURL}/models`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
const data = await res.json();
const models: Model[] = data.data.map((m: any) => {
return {
name: m.id,
key: m.id,
};
});
return {
embedding: models,
chat: models,
};
} catch (err) {
if (err instanceof TypeError) {
throw new Error(
'Error connecting to LM Studio. Please ensure the base URL is correct and the LM Studio server is running.',
);
}
throw err;
}
}
async getModelList(): Promise<ModelList> {
const defaultModels = await this.getDefaultModels();
const configProvider = getConfiguredModelProviderById(this.id)!;
return {
embedding: [
...defaultModels.embedding,
...configProvider.embeddingModels,
],
chat: [...defaultModels.chat, ...configProvider.chatModels],
};
}
async loadChatModel(key: string): Promise<BaseChatModel> {
const modelList = await this.getModelList();
const exists = modelList.chat.find((m) => m.key === key);
if (!exists) {
throw new Error(
'Error Loading LM Studio Chat Model. Invalid Model Selected',
);
}
return new ChatOpenAI({
apiKey: 'lm-studio',
temperature: 0.7,
model: key,
streaming: true,
configuration: {
baseURL: this.normalizeBaseURL(this.config.baseURL),
},
});
}
async loadEmbeddingModel(key: string): Promise<Embeddings> {
const modelList = await this.getModelList();
const exists = modelList.embedding.find((m) => m.key === key);
if (!exists) {
throw new Error(
'Error Loading LM Studio Embedding Model. Invalid Model Selected.',
);
}
return new OpenAIEmbeddings({
apiKey: 'lm-studio',
model: key,
configuration: {
baseURL: this.normalizeBaseURL(this.config.baseURL),
},
});
}
static parseAndValidate(raw: any): LMStudioConfig {
if (!raw || typeof raw !== 'object')
throw new Error('Invalid config provided. Expected object');
if (!raw.baseURL)
throw new Error('Invalid config provided. Base URL must be provided');
return {
baseURL: String(raw.baseURL),
};
}
static getProviderConfigFields(): UIConfigField[] {
return providerConfigFields;
}
static getProviderMetadata(): ProviderMetadata {
return {
key: 'lmstudio',
name: 'LM Studio',
};
}
}
export default LMStudioProvider;

View File

@@ -1,10 +1,11 @@
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Model, ModelList, ProviderMetadata } from '../types';
import BaseModelProvider from './baseProvider';
import { ChatOllama, OllamaEmbeddings } from '@langchain/ollama';
import { Embeddings } from '@langchain/core/embeddings';
import { UIConfigField } from '@/lib/config/types';
import { getConfiguredModelProviderById } from '@/lib/config/serverRegistry';
import BaseModelProvider from '../../base/provider';
import { Model, ModelList, ProviderMetadata } from '../../types';
import BaseLLM from '../../base/llm';
import BaseEmbedding from '../../base/embedding';
import OllamaLLM from './ollamaLLM';
import OllamaEmbedding from './ollamaEmbedding';
interface OllamaConfig {
baseURL: string;
@@ -76,7 +77,7 @@ class OllamaProvider extends BaseModelProvider<OllamaConfig> {
};
}
async loadChatModel(key: string): Promise<BaseChatModel> {
async loadChatModel(key: string): Promise<BaseLLM<any>> {
const modelList = await this.getModelList();
const exists = modelList.chat.find((m) => m.key === key);
@@ -87,14 +88,13 @@ class OllamaProvider extends BaseModelProvider<OllamaConfig> {
);
}
return new ChatOllama({
temperature: 0.7,
return new OllamaLLM({
baseURL: this.config.baseURL,
model: key,
baseUrl: this.config.baseURL,
});
}
async loadEmbeddingModel(key: string): Promise<Embeddings> {
async loadEmbeddingModel(key: string): Promise<BaseEmbedding<any>> {
const modelList = await this.getModelList();
const exists = modelList.embedding.find((m) => m.key === key);
@@ -104,9 +104,9 @@ class OllamaProvider extends BaseModelProvider<OllamaConfig> {
);
}
return new OllamaEmbeddings({
return new OllamaEmbedding({
model: key,
baseUrl: this.config.baseURL,
baseURL: this.config.baseURL,
});
}

View File

@@ -0,0 +1,40 @@
import { Ollama } from 'ollama';
import BaseEmbedding from '../../base/embedding';
import { Chunk } from '@/lib/types';
type OllamaConfig = {
model: string;
baseURL?: string;
};
class OllamaEmbedding extends BaseEmbedding<OllamaConfig> {
ollamaClient: Ollama;
constructor(protected config: OllamaConfig) {
super(config);
this.ollamaClient = new Ollama({
host: this.config.baseURL || 'http://localhost:11434',
});
}
async embedText(texts: string[]): Promise<number[][]> {
const response = await this.ollamaClient.embed({
input: texts,
model: this.config.model,
});
return response.embeddings;
}
async embedChunks(chunks: Chunk[]): Promise<number[][]> {
const response = await this.ollamaClient.embed({
input: chunks.map((c) => c.content),
model: this.config.model,
});
return response.embeddings;
}
}
export default OllamaEmbedding;

View File

@@ -0,0 +1,254 @@
import z from 'zod';
import BaseLLM from '../../base/llm';
import {
GenerateObjectInput,
GenerateOptions,
GenerateTextInput,
GenerateTextOutput,
StreamTextOutput,
} from '../../types';
import { Ollama, Tool as OllamaTool, Message as OllamaMessage } from 'ollama';
import { parse } from 'partial-json';
import crypto from 'crypto';
import { Message } from '@/lib/types';
type OllamaConfig = {
baseURL: string;
model: string;
options?: GenerateOptions;
};
const reasoningModels = [
'gpt-oss',
'deepseek-r1',
'qwen3',
'deepseek-v3.1',
'magistral',
'nemotron-3-nano',
];
class OllamaLLM extends BaseLLM<OllamaConfig> {
ollamaClient: Ollama;
constructor(protected config: OllamaConfig) {
super(config);
this.ollamaClient = new Ollama({
host: this.config.baseURL || 'http://localhost:11434',
});
}
convertToOllamaMessages(messages: Message[]): OllamaMessage[] {
return messages.map((msg) => {
if (msg.role === 'tool') {
return {
role: 'tool',
tool_name: msg.name,
content: msg.content,
} as OllamaMessage;
} else if (msg.role === 'assistant') {
return {
role: 'assistant',
content: msg.content,
tool_calls:
msg.tool_calls?.map((tc, i) => ({
function: {
index: i,
name: tc.name,
arguments: tc.arguments,
},
})) || [],
};
}
return msg;
});
}
async generateText(input: GenerateTextInput): Promise<GenerateTextOutput> {
const ollamaTools: OllamaTool[] = [];
input.tools?.forEach((tool) => {
ollamaTools.push({
type: 'function',
function: {
name: tool.name,
description: tool.description,
parameters: z.toJSONSchema(tool.schema).properties,
},
});
});
const res = await this.ollamaClient.chat({
model: this.config.model,
messages: this.convertToOllamaMessages(input.messages),
tools: ollamaTools.length > 0 ? ollamaTools : undefined,
...(reasoningModels.find((m) => this.config.model.includes(m))
? { think: false }
: {}),
options: {
top_p: input.options?.topP ?? this.config.options?.topP,
temperature:
input.options?.temperature ?? this.config.options?.temperature ?? 0.7,
num_predict: input.options?.maxTokens ?? this.config.options?.maxTokens,
num_ctx: 32000,
frequency_penalty:
input.options?.frequencyPenalty ??
this.config.options?.frequencyPenalty,
presence_penalty:
input.options?.presencePenalty ??
this.config.options?.presencePenalty,
stop:
input.options?.stopSequences ?? this.config.options?.stopSequences,
},
});
return {
content: res.message.content,
toolCalls:
res.message.tool_calls?.map((tc) => ({
id: crypto.randomUUID(),
name: tc.function.name,
arguments: tc.function.arguments,
})) || [],
additionalInfo: {
reasoning: res.message.thinking,
},
};
}
async *streamText(
input: GenerateTextInput,
): AsyncGenerator<StreamTextOutput> {
const ollamaTools: OllamaTool[] = [];
input.tools?.forEach((tool) => {
ollamaTools.push({
type: 'function',
function: {
name: tool.name,
description: tool.description,
parameters: z.toJSONSchema(tool.schema) as any,
},
});
});
const stream = await this.ollamaClient.chat({
model: this.config.model,
messages: this.convertToOllamaMessages(input.messages),
stream: true,
...(reasoningModels.find((m) => this.config.model.includes(m))
? { think: false }
: {}),
tools: ollamaTools.length > 0 ? ollamaTools : undefined,
options: {
top_p: input.options?.topP ?? this.config.options?.topP,
temperature:
input.options?.temperature ?? this.config.options?.temperature ?? 0.7,
num_ctx: 32000,
num_predict: input.options?.maxTokens ?? this.config.options?.maxTokens,
frequency_penalty:
input.options?.frequencyPenalty ??
this.config.options?.frequencyPenalty,
presence_penalty:
input.options?.presencePenalty ??
this.config.options?.presencePenalty,
stop:
input.options?.stopSequences ?? this.config.options?.stopSequences,
},
});
for await (const chunk of stream) {
yield {
contentChunk: chunk.message.content,
toolCallChunk:
chunk.message.tool_calls?.map((tc, i) => ({
id: crypto
.createHash('sha256')
.update(
`${i}-${tc.function.name}`,
) /* Ollama currently doesn't return a tool call ID so we're creating one based on the index and tool call name */
.digest('hex'),
name: tc.function.name,
arguments: tc.function.arguments,
})) || [],
done: chunk.done,
additionalInfo: {
reasoning: chunk.message.thinking,
},
};
}
}
async generateObject<T>(input: GenerateObjectInput): Promise<T> {
const response = await this.ollamaClient.chat({
model: this.config.model,
messages: this.convertToOllamaMessages(input.messages),
format: z.toJSONSchema(input.schema),
...(reasoningModels.find((m) => this.config.model.includes(m))
? { think: false }
: {}),
options: {
top_p: input.options?.topP ?? this.config.options?.topP,
temperature:
input.options?.temperature ?? this.config.options?.temperature ?? 0.7,
num_predict: input.options?.maxTokens ?? this.config.options?.maxTokens,
frequency_penalty:
input.options?.frequencyPenalty ??
this.config.options?.frequencyPenalty,
presence_penalty:
input.options?.presencePenalty ??
this.config.options?.presencePenalty,
stop:
input.options?.stopSequences ?? this.config.options?.stopSequences,
},
});
try {
return input.schema.parse(JSON.parse(response.message.content)) as T;
} catch (err) {
throw new Error(`Error parsing response from Ollama: ${err}`);
}
}
async *streamObject<T>(input: GenerateObjectInput): AsyncGenerator<T> {
let recievedObj: string = '';
const stream = await this.ollamaClient.chat({
model: this.config.model,
messages: this.convertToOllamaMessages(input.messages),
format: z.toJSONSchema(input.schema),
stream: true,
...(reasoningModels.find((m) => this.config.model.includes(m))
? { think: false }
: {}),
options: {
top_p: input.options?.topP ?? this.config.options?.topP,
temperature:
input.options?.temperature ?? this.config.options?.temperature ?? 0.7,
num_predict: input.options?.maxTokens ?? this.config.options?.maxTokens,
frequency_penalty:
input.options?.frequencyPenalty ??
this.config.options?.frequencyPenalty,
presence_penalty:
input.options?.presencePenalty ??
this.config.options?.presencePenalty,
stop:
input.options?.stopSequences ?? this.config.options?.stopSequences,
},
});
for await (const chunk of stream) {
recievedObj += chunk.message.content;
try {
yield parse(recievedObj) as T;
} catch (err) {
console.log('Error parsing partial object from Ollama:', err);
yield {} as T;
}
}
}
}
export default OllamaLLM;

View File

@@ -1,10 +1,11 @@
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Model, ModelList, ProviderMetadata } from '../types';
import BaseModelProvider from './baseProvider';
import { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai';
import { Embeddings } from '@langchain/core/embeddings';
import { UIConfigField } from '@/lib/config/types';
import { getConfiguredModelProviderById } from '@/lib/config/serverRegistry';
import { Model, ModelList, ProviderMetadata } from '../../types';
import OpenAIEmbedding from './openaiEmbedding';
import BaseEmbedding from '../../base/embedding';
import BaseModelProvider from '../../base/provider';
import BaseLLM from '../../base/llm';
import OpenAILLM from './openaiLLM';
interface OpenAIConfig {
apiKey: string;
@@ -161,7 +162,7 @@ class OpenAIProvider extends BaseModelProvider<OpenAIConfig> {
};
}
async loadChatModel(key: string): Promise<BaseChatModel> {
async loadChatModel(key: string): Promise<BaseLLM<any>> {
const modelList = await this.getModelList();
const exists = modelList.chat.find((m) => m.key === key);
@@ -172,17 +173,14 @@ class OpenAIProvider extends BaseModelProvider<OpenAIConfig> {
);
}
return new ChatOpenAI({
return new OpenAILLM({
apiKey: this.config.apiKey,
temperature: 0.7,
model: key,
configuration: {
baseURL: this.config.baseURL,
},
baseURL: this.config.baseURL,
});
}
async loadEmbeddingModel(key: string): Promise<Embeddings> {
async loadEmbeddingModel(key: string): Promise<BaseEmbedding<any>> {
const modelList = await this.getModelList();
const exists = modelList.embedding.find((m) => m.key === key);
@@ -192,12 +190,10 @@ class OpenAIProvider extends BaseModelProvider<OpenAIConfig> {
);
}
return new OpenAIEmbeddings({
return new OpenAIEmbedding({
apiKey: this.config.apiKey,
model: key,
configuration: {
baseURL: this.config.baseURL,
},
baseURL: this.config.baseURL,
});
}

View File

@@ -0,0 +1,42 @@
import OpenAI from 'openai';
import BaseEmbedding from '../../base/embedding';
import { Chunk } from '@/lib/types';
type OpenAIConfig = {
apiKey: string;
model: string;
baseURL?: string;
};
class OpenAIEmbedding extends BaseEmbedding<OpenAIConfig> {
openAIClient: OpenAI;
constructor(protected config: OpenAIConfig) {
super(config);
this.openAIClient = new OpenAI({
apiKey: config.apiKey,
baseURL: config.baseURL,
});
}
async embedText(texts: string[]): Promise<number[][]> {
const response = await this.openAIClient.embeddings.create({
model: this.config.model,
input: texts,
});
return response.data.map((embedding) => embedding.embedding);
}
async embedChunks(chunks: Chunk[]): Promise<number[][]> {
const response = await this.openAIClient.embeddings.create({
model: this.config.model,
input: chunks.map((c) => c.content),
});
return response.data.map((embedding) => embedding.embedding);
}
}
export default OpenAIEmbedding;

View File

@@ -0,0 +1,268 @@
import OpenAI from 'openai';
import BaseLLM from '../../base/llm';
import { zodTextFormat, zodResponseFormat } from 'openai/helpers/zod';
import {
GenerateObjectInput,
GenerateOptions,
GenerateTextInput,
GenerateTextOutput,
StreamTextOutput,
ToolCall,
} from '../../types';
import { parse } from 'partial-json';
import z from 'zod';
import {
ChatCompletionAssistantMessageParam,
ChatCompletionMessageParam,
ChatCompletionTool,
ChatCompletionToolMessageParam,
} from 'openai/resources/index.mjs';
import { Message } from '@/lib/types';
type OpenAIConfig = {
apiKey: string;
model: string;
baseURL?: string;
options?: GenerateOptions;
};
class OpenAILLM extends BaseLLM<OpenAIConfig> {
openAIClient: OpenAI;
constructor(protected config: OpenAIConfig) {
super(config);
this.openAIClient = new OpenAI({
apiKey: this.config.apiKey,
baseURL: this.config.baseURL || 'https://api.openai.com/v1',
});
}
convertToOpenAIMessages(messages: Message[]): ChatCompletionMessageParam[] {
return messages.map((msg) => {
if (msg.role === 'tool') {
return {
role: 'tool',
tool_call_id: msg.id,
content: msg.content,
} as ChatCompletionToolMessageParam;
} else if (msg.role === 'assistant') {
return {
role: 'assistant',
content: msg.content,
...(msg.tool_calls &&
msg.tool_calls.length > 0 && {
tool_calls: msg.tool_calls?.map((tc) => ({
id: tc.id,
type: 'function',
function: {
name: tc.name,
arguments: JSON.stringify(tc.arguments),
},
})),
}),
} as ChatCompletionAssistantMessageParam;
}
return msg;
});
}
async generateText(input: GenerateTextInput): Promise<GenerateTextOutput> {
const openaiTools: ChatCompletionTool[] = [];
input.tools?.forEach((tool) => {
openaiTools.push({
type: 'function',
function: {
name: tool.name,
description: tool.description,
parameters: z.toJSONSchema(tool.schema),
},
});
});
const response = await this.openAIClient.chat.completions.create({
model: this.config.model,
tools: openaiTools.length > 0 ? openaiTools : undefined,
messages: this.convertToOpenAIMessages(input.messages),
temperature:
input.options?.temperature ?? this.config.options?.temperature ?? 1.0,
top_p: input.options?.topP ?? this.config.options?.topP,
max_completion_tokens:
input.options?.maxTokens ?? this.config.options?.maxTokens,
stop: input.options?.stopSequences ?? this.config.options?.stopSequences,
frequency_penalty:
input.options?.frequencyPenalty ??
this.config.options?.frequencyPenalty,
presence_penalty:
input.options?.presencePenalty ?? this.config.options?.presencePenalty,
});
if (response.choices && response.choices.length > 0) {
return {
content: response.choices[0].message.content!,
toolCalls:
response.choices[0].message.tool_calls
?.map((tc) => {
if (tc.type === 'function') {
return {
name: tc.function.name,
id: tc.id,
arguments: JSON.parse(tc.function.arguments),
};
}
})
.filter((tc) => tc !== undefined) || [],
additionalInfo: {
finishReason: response.choices[0].finish_reason,
},
};
}
throw new Error('No response from OpenAI');
}
async *streamText(
input: GenerateTextInput,
): AsyncGenerator<StreamTextOutput> {
const openaiTools: ChatCompletionTool[] = [];
input.tools?.forEach((tool) => {
openaiTools.push({
type: 'function',
function: {
name: tool.name,
description: tool.description,
parameters: z.toJSONSchema(tool.schema),
},
});
});
const stream = await this.openAIClient.chat.completions.create({
model: this.config.model,
messages: this.convertToOpenAIMessages(input.messages),
tools: openaiTools.length > 0 ? openaiTools : undefined,
temperature:
input.options?.temperature ?? this.config.options?.temperature ?? 1.0,
top_p: input.options?.topP ?? this.config.options?.topP,
max_completion_tokens:
input.options?.maxTokens ?? this.config.options?.maxTokens,
stop: input.options?.stopSequences ?? this.config.options?.stopSequences,
frequency_penalty:
input.options?.frequencyPenalty ??
this.config.options?.frequencyPenalty,
presence_penalty:
input.options?.presencePenalty ?? this.config.options?.presencePenalty,
stream: true,
});
let recievedToolCalls: { name: string; id: string; arguments: string }[] =
[];
for await (const chunk of stream) {
if (chunk.choices && chunk.choices.length > 0) {
const toolCalls = chunk.choices[0].delta.tool_calls;
yield {
contentChunk: chunk.choices[0].delta.content || '',
toolCallChunk:
toolCalls?.map((tc) => {
if (tc.type === 'function') {
const call = {
name: tc.function?.name!,
id: tc.id!,
arguments: tc.function?.arguments || '',
};
recievedToolCalls.push(call);
return { ...call, arguments: parse(call.arguments || '{}') };
} else {
const existingCall = recievedToolCalls[tc.index];
existingCall.arguments += tc.function?.arguments || '';
return {
...existingCall,
arguments: parse(existingCall.arguments),
};
}
}) || [],
done: chunk.choices[0].finish_reason !== null,
additionalInfo: {
finishReason: chunk.choices[0].finish_reason,
},
};
}
}
}
async generateObject<T>(input: GenerateObjectInput): Promise<T> {
const response = await this.openAIClient.chat.completions.parse({
messages: this.convertToOpenAIMessages(input.messages),
model: this.config.model,
temperature:
input.options?.temperature ?? this.config.options?.temperature ?? 1.0,
top_p: input.options?.topP ?? this.config.options?.topP,
max_completion_tokens:
input.options?.maxTokens ?? this.config.options?.maxTokens,
stop: input.options?.stopSequences ?? this.config.options?.stopSequences,
frequency_penalty:
input.options?.frequencyPenalty ??
this.config.options?.frequencyPenalty,
presence_penalty:
input.options?.presencePenalty ?? this.config.options?.presencePenalty,
response_format: zodResponseFormat(input.schema, 'object'),
});
if (response.choices && response.choices.length > 0) {
try {
return input.schema.parse(response.choices[0].message.parsed) as T;
} catch (err) {
throw new Error(`Error parsing response from OpenAI: ${err}`);
}
}
throw new Error('No response from OpenAI');
}
async *streamObject<T>(input: GenerateObjectInput): AsyncGenerator<T> {
let recievedObj: string = '';
const stream = this.openAIClient.responses.stream({
model: this.config.model,
input: input.messages,
temperature:
input.options?.temperature ?? this.config.options?.temperature ?? 1.0,
top_p: input.options?.topP ?? this.config.options?.topP,
max_completion_tokens:
input.options?.maxTokens ?? this.config.options?.maxTokens,
stop: input.options?.stopSequences ?? this.config.options?.stopSequences,
frequency_penalty:
input.options?.frequencyPenalty ??
this.config.options?.frequencyPenalty,
presence_penalty:
input.options?.presencePenalty ?? this.config.options?.presencePenalty,
text: {
format: zodTextFormat(input.schema, 'object'),
},
});
for await (const chunk of stream) {
if (chunk.type === 'response.output_text.delta' && chunk.delta) {
recievedObj += chunk.delta;
try {
yield parse(recievedObj) as T;
} catch (err) {
console.log('Error parsing partial object from OpenAI:', err);
yield {} as T;
}
} else if (chunk.type === 'response.output_text.done' && chunk.text) {
try {
yield parse(chunk.text) as T;
} catch (err) {
throw new Error(`Error parsing response from OpenAI: ${err}`);
}
}
}
}
}
export default OpenAILLM;

View File

@@ -1,10 +1,11 @@
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Model, ModelList, ProviderMetadata } from '../types';
import BaseModelProvider from './baseProvider';
import { Embeddings } from '@langchain/core/embeddings';
import { UIConfigField } from '@/lib/config/types';
import { getConfiguredModelProviderById } from '@/lib/config/serverRegistry';
import { HuggingFaceTransformersEmbeddings } from '@langchain/community/embeddings/huggingface_transformers';
import { Model, ModelList, ProviderMetadata } from '../../types';
import BaseModelProvider from '../../base/provider';
import BaseLLM from '../../base/llm';
import BaseEmbedding from '../../base/embedding';
import TransformerEmbedding from './transformerEmbedding';
interface TransformersConfig {}
const defaultEmbeddingModels: Model[] = [
@@ -49,11 +50,11 @@ class TransformersProvider extends BaseModelProvider<TransformersConfig> {
};
}
async loadChatModel(key: string): Promise<BaseChatModel> {
async loadChatModel(key: string): Promise<BaseLLM<any>> {
throw new Error('Transformers Provider does not support chat models.');
}
async loadEmbeddingModel(key: string): Promise<Embeddings> {
async loadEmbeddingModel(key: string): Promise<BaseEmbedding<any>> {
const modelList = await this.getModelList();
const exists = modelList.embedding.find((m) => m.key === key);
@@ -63,7 +64,7 @@ class TransformersProvider extends BaseModelProvider<TransformersConfig> {
);
}
return new HuggingFaceTransformersEmbeddings({
return new TransformerEmbedding({
model: key,
});
}

View File

@@ -0,0 +1,41 @@
import { Chunk } from '@/lib/types';
import BaseEmbedding from '../../base/embedding';
import { FeatureExtractionPipeline } from '@huggingface/transformers';
type TransformerConfig = {
model: string;
};
class TransformerEmbedding extends BaseEmbedding<TransformerConfig> {
private pipelinePromise: Promise<FeatureExtractionPipeline> | null = null;
constructor(protected config: TransformerConfig) {
super(config);
}
async embedText(texts: string[]): Promise<number[][]> {
return this.embed(texts);
}
async embedChunks(chunks: Chunk[]): Promise<number[][]> {
return this.embed(chunks.map((c) => c.content));
}
private async embed(texts: string[]) {
if (!this.pipelinePromise) {
this.pipelinePromise = (async () => {
const { pipeline } = await import('@huggingface/transformers');
const result = await pipeline('feature-extraction', this.config.model, {
dtype: 'fp32',
});
return result as FeatureExtractionPipeline;
})();
}
const pipe = await this.pipelinePromise;
const output = await pipe(texts, { pooling: 'mean', normalize: true });
return output.tolist() as number[][];
}
}
export default TransformerEmbedding;

View File

@@ -1,7 +1,5 @@
import { ConfigModelProvider } from '../config/types';
import BaseModelProvider, {
createProviderInstance,
} from './providers/baseProvider';
import BaseModelProvider, { createProviderInstance } from './base/provider';
import { getConfiguredModelProviders } from '../config/serverRegistry';
import { providers } from './providers';
import { MinimalProvider, ModelList } from './types';

View File

@@ -1,3 +1,6 @@
import z from 'zod';
import { Message } from '../types';
type Model = {
name: string;
key: string;
@@ -25,10 +28,76 @@ type ModelWithProvider = {
providerId: string;
};
type GenerateOptions = {
temperature?: number;
maxTokens?: number;
topP?: number;
stopSequences?: string[];
frequencyPenalty?: number;
presencePenalty?: number;
};
type Tool = {
name: string;
description: string;
schema: z.ZodObject<any>;
};
type ToolCall = {
id: string;
name: string;
arguments: Record<string, any>;
};
type GenerateTextInput = {
messages: Message[];
tools?: Tool[];
options?: GenerateOptions;
};
type GenerateTextOutput = {
content: string;
toolCalls: ToolCall[];
additionalInfo?: Record<string, any>;
};
type StreamTextOutput = {
contentChunk: string;
toolCallChunk: ToolCall[];
additionalInfo?: Record<string, any>;
done?: boolean;
};
type GenerateObjectInput = {
schema: z.ZodTypeAny;
messages: Message[];
options?: GenerateOptions;
};
type GenerateObjectOutput<T> = {
object: T;
additionalInfo?: Record<string, any>;
};
type StreamObjectOutput<T> = {
objectChunk: Partial<T>;
additionalInfo?: Record<string, any>;
done?: boolean;
};
export type {
Model,
ModelList,
ProviderMetadata,
MinimalProvider,
ModelWithProvider,
GenerateOptions,
GenerateTextInput,
GenerateTextOutput,
StreamTextOutput,
GenerateObjectInput,
GenerateObjectOutput,
StreamObjectOutput,
Tool,
ToolCall,
};