mirror of
https://github.com/sortedcord/omnia.git
synced 2026-07-22 12:02:49 +05:30
feat(llm): Added OpenAI provider
This commit is contained in:
@@ -279,6 +279,29 @@ Also exports `GeminiEmbeddingProvider` (implements `IEmbeddingProvider`) using t
|
||||
4. None found → throw Error
|
||||
```
|
||||
|
||||
### OpenAI — `OpenAIProvider`
|
||||
|
||||
| Property | Value |
|
||||
| --------------------------- | ------------------------------------------------------ |
|
||||
| **File** | [`providers/openai.ts`](src/providers/openai.ts) |
|
||||
| **Provider ID** | `openai` |
|
||||
| **SDK** | `@langchain/openai` (`ChatOpenAI`, `OpenAIEmbeddings`) |
|
||||
| **Default Model** | `gpt-4o-mini` |
|
||||
| **Default Embedding Model** | `text-embedding-3-small` |
|
||||
| **Default Max Context** | `128000` |
|
||||
| **Type** | Generative + Embedding |
|
||||
|
||||
**Key resolution** in the constructor follows this cascade:
|
||||
|
||||
```
|
||||
1. Explicit apiKey argument → use it
|
||||
2. ProviderManager.getActive() → if providerName matches "openai"
|
||||
3. OPENAI_API_KEY env var → final fallback
|
||||
4. None found → throw Error
|
||||
```
|
||||
|
||||
Also exports `OpenAIEmbeddingProvider` (implements `IEmbeddingProvider`) using the same key resolution pattern against the `"embedding"` type instance. The default embedding model is `text-embedding-3-small`.
|
||||
|
||||
### OpenRouter — `OpenRouterProvider`
|
||||
|
||||
| Property | Value |
|
||||
@@ -377,6 +400,7 @@ The `buildLLMProvider()` and `buildEmbeddingProvider()` functions perform the fi
|
||||
| `providerName` | Generative Class | Embedding Class |
|
||||
| ----------------- | -------------------- | ------------------------- |
|
||||
| `"google-genai"` | `GeminiProvider` | `GeminiEmbeddingProvider` |
|
||||
| `"openai"` | `OpenAIProvider` | `OpenAIEmbeddingProvider` |
|
||||
| `"openrouter"` | `OpenRouterProvider` | _(falls through to mock)_ |
|
||||
| `"ollama"` | `OllamaProvider` | `OllamaEmbeddingProvider` |
|
||||
| `"anthropic"` | `AnthropicProvider` | _(falls through to mock)_ |
|
||||
@@ -405,6 +429,7 @@ This sends the Zod schema to the model as a structured output constraint. The re
|
||||
| Variable | Required | Description |
|
||||
| -------------------- | -------- | ------------------------ |
|
||||
| `GOOGLE_API_KEY` | No | Google Gemini API key |
|
||||
| `OPENAI_API_KEY` | No | OpenAI API key |
|
||||
| `OPENROUTER_API_KEY` | No | OpenRouter API key |
|
||||
| `ANTHROPIC_API_KEY` | No | Anthropic Claude API key |
|
||||
|
||||
@@ -424,6 +449,7 @@ packages/llm/
|
||||
│ ├── ollama.ts # OllamaProvider + OllamaEmbeddingProvider
|
||||
│ ├── openrouter.ts # OpenRouterProvider
|
||||
│ ├── anthropic.ts # AnthropicProvider
|
||||
│ ├── openai.ts # OpenAIProvider + OpenAIEmbeddingProvider
|
||||
│ └── mock.ts # MockLLMProvider + MockEmbeddingProvider
|
||||
├── tests/
|
||||
│ ├── mock.test.ts
|
||||
|
||||
225
packages/llm/chat-openai.md
Normal file
225
packages/llm/chat-openai.md
Normal file
@@ -0,0 +1,225 @@
|
||||
> ## Documentation Index
|
||||
>
|
||||
> Fetch the complete documentation index at: https://docs.langchain.com/llms.txt
|
||||
> Use this file to discover all available pages before exploring further.
|
||||
|
||||
# OpenAI integrations
|
||||
|
||||
> Integrate with OpenAI using LangChain JavaScript.
|
||||
|
||||
LangChain integrates with OpenAI and Azure OpenAI through the `@langchain/openai` package.
|
||||
|
||||
> [OpenAI](https://en.wikipedia.org/wiki/OpenAI) is American artificial intelligence (AI) research laboratory
|
||||
> consisting of the non-profit `OpenAI Incorporated`
|
||||
> and its for-profit subsidiary corporation `OpenAI Limited Partnership`.
|
||||
> OpenAI conducts AI research with the declared intention of promoting and developing a friendly AI.
|
||||
> OpenAI systems run on an `Azure`-based supercomputing platform from `Microsoft`.
|
||||
|
||||
> The [OpenAI API](https://platform.openai.com/docs/models) is powered by a diverse set of models with different capabilities and price points.
|
||||
>
|
||||
> [ChatGPT](https://chat.openai.com) is the Artificial Intelligence (AI) chatbot developed by `OpenAI`.
|
||||
|
||||
## Installation and setup
|
||||
|
||||
- Get an OpenAI api key and set it as an environment variable (`OPENAI_API_KEY`)
|
||||
|
||||
## Chat model
|
||||
|
||||
See a [usage example](/oss/javascript/integrations/chat/openai).
|
||||
|
||||
```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
```
|
||||
|
||||
## LLM
|
||||
|
||||
See a [usage example](/oss/javascript/integrations/llms/openai).
|
||||
|
||||
<Tip>
|
||||
See [this section for general instructions on installing LangChain packages](/oss/javascript/langchain/install).
|
||||
</Tip>
|
||||
|
||||
```bash npm theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
|
||||
npm install @langchain/openai @langchain/core
|
||||
```
|
||||
|
||||
```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
|
||||
import { OpenAI } from "@langchain/openai";
|
||||
```
|
||||
|
||||
## Text embedding model
|
||||
|
||||
See a [usage example](/oss/javascript/integrations/embeddings/openai)
|
||||
|
||||
```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
|
||||
import { OpenAIEmbeddings } from "@langchain/openai";
|
||||
```
|
||||
|
||||
## Chain
|
||||
|
||||
```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
|
||||
import { OpenAIModerationChain } from "@langchain/classic/chains";
|
||||
```
|
||||
|
||||
## Middleware
|
||||
|
||||
Middleware specifically designed for OpenAI models. Learn more about [middleware](/oss/javascript/langchain/middleware/overview).
|
||||
|
||||
| Middleware | Description |
|
||||
| ----------------------------------------- | --------------------------------------------------------- |
|
||||
| [Content moderation](#content-moderation) | Moderate agent traffic using OpenAI's moderation endpoint |
|
||||
|
||||
### Content moderation
|
||||
|
||||
Moderate agent traffic (user input, model output, and tool results) using OpenAI's moderation endpoint to detect and handle unsafe content. Content moderation is useful for the following:
|
||||
|
||||
- Applications requiring content safety and compliance
|
||||
- Filtering harmful, hateful, or inappropriate content
|
||||
- Customer-facing agents that need safety guardrails
|
||||
- Meeting platform moderation requirements
|
||||
|
||||
<Info>
|
||||
Learn more about [OpenAI's moderation models](https://platform.openai.com/docs/guides/moderation) and categories.
|
||||
</Info>
|
||||
|
||||
**API reference:** [`openAIModerationMiddleware`](https://reference.langchain.com/javascript/langchain/index/openAIModerationMiddleware)
|
||||
|
||||
```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
|
||||
import { createAgent, openAIModerationMiddleware } from "langchain";
|
||||
|
||||
const agent = createAgent({
|
||||
model: "openai:gpt-5.5",
|
||||
tools: [searchTool, databaseTool],
|
||||
middleware: [
|
||||
openAIModerationMiddleware({
|
||||
model: "openai:gpt-5.5",
|
||||
moderationModel: "omni-moderation-latest",
|
||||
checkInput: true,
|
||||
checkOutput: true,
|
||||
exitBehavior: "end",
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
<Accordion title="Configuration options">
|
||||
<ParamField body="model" type="string | BaseChatModel" required>
|
||||
OpenAI model to use for moderation. Can be either a model name string (e.g., `"openai:gpt-5.5"`) or a `BaseChatModel` instance. The middleware will use this model's client to access the moderation endpoint.
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="moderationModel" type="ModerationModel" default="omni-moderation-latest">
|
||||
OpenAI moderation model to use. Options: `'omni-moderation-latest'`, `'omni-moderation-2024-09-26'`, `'text-moderation-latest'`, `'text-moderation-stable'`
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="checkInput" type="boolean" default="true">
|
||||
Whether to check user input messages before the model is called
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="checkOutput" type="boolean" default="true">
|
||||
Whether to check model output messages after the model is called
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="checkToolResults" type="boolean" default="false">
|
||||
Whether to check tool result messages before the model is called
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="exitBehavior" type="'error' | 'end' | 'replace'" default="'end'">
|
||||
How to handle violations when content is flagged. Options:
|
||||
|
||||
* `'end'` - End agent execution immediately with a violation message
|
||||
* `'error'` - Throw `OpenAIModerationError` exception
|
||||
* `'replace'` - Replace the flagged content with the violation message and continue
|
||||
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="violationMessage" type="string | undefined">
|
||||
Custom template for violation messages. Supports template variables:
|
||||
|
||||
* `{categories}` - Comma-separated list of flagged categories
|
||||
* `{category_scores}` - JSON string of category scores
|
||||
* `{original_content}` - The original flagged content
|
||||
|
||||
Default: `"I'm sorry, but I can't comply with that request. It was flagged for {categories}."`
|
||||
|
||||
</ParamField>
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Full example">
|
||||
The middleware integrates OpenAI's moderation endpoint to check content at different stages:
|
||||
|
||||
**Moderation stages:**
|
||||
|
||||
- `checkInput` - User messages before model call
|
||||
- `checkOutput` - AI messages after model call
|
||||
- `checkToolResults` - Tool outputs before model call
|
||||
|
||||
**Exit behaviors:**
|
||||
|
||||
- `'end'` (default) - Stop execution with violation message
|
||||
- `'error'` - Throw exception for application handling
|
||||
- `'replace'` - Replace flagged content and continue
|
||||
|
||||
```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
|
||||
import { createAgent, openAIModerationMiddleware } from "langchain";
|
||||
|
||||
// Basic moderation
|
||||
const agent = createAgent({
|
||||
model: "openai:gpt-5.5",
|
||||
tools: [searchTool, customerDataTool],
|
||||
middleware: [
|
||||
openAIModerationMiddleware({
|
||||
model: "openai:gpt-5.5",
|
||||
moderationModel: "omni-moderation-latest",
|
||||
checkInput: true,
|
||||
checkOutput: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// Strict moderation with custom message
|
||||
const agentStrict = createAgent({
|
||||
model: "openai:gpt-5.5",
|
||||
tools: [searchTool, customerDataTool],
|
||||
middleware: [
|
||||
openAIModerationMiddleware({
|
||||
model: "openai:gpt-5.5",
|
||||
moderationModel: "omni-moderation-latest",
|
||||
checkInput: true,
|
||||
checkOutput: true,
|
||||
checkToolResults: true,
|
||||
exitBehavior: "error",
|
||||
violationMessage:
|
||||
"Content policy violation detected: {categories}. " +
|
||||
"Please rephrase your request.",
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// Moderation with replacement behavior
|
||||
const agentReplace = createAgent({
|
||||
model: "openai:gpt-5.5",
|
||||
tools: [searchTool],
|
||||
middleware: [
|
||||
openAIModerationMiddleware({
|
||||
model: "openai:gpt-5.5",
|
||||
checkInput: true,
|
||||
exitBehavior: "replace",
|
||||
violationMessage: "[Content removed due to safety policies]",
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
---
|
||||
|
||||
<div className="source-links">
|
||||
<Callout icon="terminal-2">
|
||||
[Connect these docs](/use-these-docs) to Claude, VSCode, and more via MCP for real-time answers.
|
||||
</Callout>
|
||||
|
||||
<Callout icon="edit">
|
||||
[Edit this page on GitHub](https://github.com/langchain-ai/docs/edit/main/src/oss/javascript/integrations/providers/openai.mdx) or [file an issue](https://github.com/langchain-ai/docs/issues/new/choose).
|
||||
</Callout>
|
||||
</div>
|
||||
@@ -4,6 +4,7 @@ const LLMConfigSchema = z.object({
|
||||
GOOGLE_API_KEY: z.string().optional(),
|
||||
OPENROUTER_API_KEY: z.string().optional(),
|
||||
ANTHROPIC_API_KEY: z.string().optional(),
|
||||
OPENAI_API_KEY: z.string().optional(),
|
||||
});
|
||||
|
||||
export const llmConfig = LLMConfigSchema.parse(process.env);
|
||||
|
||||
@@ -5,4 +5,5 @@ export * from "./providers/mock.js";
|
||||
export * from "./providers/ollama.js";
|
||||
export * from "./providers/openrouter.js";
|
||||
export * from "./providers/anthropic.js";
|
||||
export * from "./providers/openai.js";
|
||||
export * from "./provider-manager.js";
|
||||
|
||||
@@ -76,6 +76,13 @@ export const AVAILABLE_PROVIDERS: ModelProviderMeta[] = [
|
||||
defaultModel: "gemini-2.5-flash",
|
||||
defaultEmbeddingModel: "gemini-embedding-001",
|
||||
},
|
||||
{
|
||||
id: "openai",
|
||||
displayName: "OpenAI",
|
||||
description: "Official OpenAI integration using @langchain/openai SDK",
|
||||
defaultModel: "gpt-4o-mini",
|
||||
defaultEmbeddingModel: "text-embedding-3-small",
|
||||
},
|
||||
{
|
||||
id: "anthropic",
|
||||
displayName: "Anthropic Claude",
|
||||
|
||||
@@ -100,7 +100,9 @@ function getSettingsDb() {
|
||||
const googleKey = process.env.GOOGLE_API_KEY;
|
||||
const openRouterKey = process.env.OPENROUTER_API_KEY;
|
||||
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
||||
const openaiKey = process.env.OPENAI_API_KEY;
|
||||
let hasInsertedGenerative = false;
|
||||
let hasInsertedEmbedding = false;
|
||||
|
||||
if (googleKey && googleKey.trim()) {
|
||||
const id = "provider-default-google";
|
||||
@@ -137,6 +139,7 @@ function getSettingsDb() {
|
||||
"embedding",
|
||||
0,
|
||||
);
|
||||
hasInsertedEmbedding = true;
|
||||
}
|
||||
|
||||
if (anthropicKey && anthropicKey.trim()) {
|
||||
@@ -162,6 +165,50 @@ function getSettingsDb() {
|
||||
}
|
||||
}
|
||||
|
||||
if (openaiKey && openaiKey.trim()) {
|
||||
const id = "provider-default-openai";
|
||||
const isActive = hasInsertedGenerative ? 0 : 1;
|
||||
db.prepare(
|
||||
`
|
||||
INSERT INTO provider_instances (id, name, providerName, apiKey, isActive, modelName, type, maxContext)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`,
|
||||
).run(
|
||||
id,
|
||||
"OpenAI (Env)",
|
||||
"openai",
|
||||
openaiKey.trim(),
|
||||
isActive,
|
||||
"gpt-4o-mini",
|
||||
"generative",
|
||||
128000,
|
||||
);
|
||||
if (isActive === 1) {
|
||||
hasInsertedGenerative = true;
|
||||
}
|
||||
|
||||
const embedId = "provider-default-openai-embed";
|
||||
const isEmbedActive = hasInsertedEmbedding ? 0 : 1;
|
||||
db.prepare(
|
||||
`
|
||||
INSERT INTO provider_instances (id, name, providerName, apiKey, isActive, modelName, type, maxContext)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`,
|
||||
).run(
|
||||
embedId,
|
||||
"OpenAI Embed (Env)",
|
||||
"openai",
|
||||
openaiKey.trim(),
|
||||
isEmbedActive,
|
||||
"text-embedding-3-small",
|
||||
"embedding",
|
||||
0,
|
||||
);
|
||||
if (isEmbedActive === 1) {
|
||||
hasInsertedEmbedding = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (openRouterKey && openRouterKey.trim()) {
|
||||
const id = "provider-default-openrouter";
|
||||
const isActive = hasInsertedGenerative ? 0 : 1;
|
||||
@@ -416,7 +463,9 @@ export class ProviderManager {
|
||||
const googleKey = process.env.GOOGLE_API_KEY;
|
||||
const openRouterKey = process.env.OPENROUTER_API_KEY;
|
||||
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
||||
const openaiKey = process.env.OPENAI_API_KEY;
|
||||
let hasInsertedGenerative = false;
|
||||
let hasInsertedEmbedding = false;
|
||||
|
||||
if (googleKey && googleKey.trim()) {
|
||||
const id = "provider-default-google";
|
||||
@@ -453,6 +502,7 @@ export class ProviderManager {
|
||||
"embedding",
|
||||
0,
|
||||
);
|
||||
hasInsertedEmbedding = true;
|
||||
}
|
||||
|
||||
if (anthropicKey && anthropicKey.trim()) {
|
||||
@@ -478,6 +528,50 @@ export class ProviderManager {
|
||||
}
|
||||
}
|
||||
|
||||
if (openaiKey && openaiKey.trim()) {
|
||||
const id = "provider-default-openai";
|
||||
const isActive = hasInsertedGenerative ? 0 : 1;
|
||||
db.prepare(
|
||||
`
|
||||
INSERT INTO provider_instances (id, name, providerName, apiKey, isActive, modelName, type, maxContext)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`,
|
||||
).run(
|
||||
id,
|
||||
"OpenAI (Env)",
|
||||
"openai",
|
||||
openaiKey.trim(),
|
||||
isActive,
|
||||
"gpt-4o-mini",
|
||||
"generative",
|
||||
128000,
|
||||
);
|
||||
if (isActive === 1) {
|
||||
hasInsertedGenerative = true;
|
||||
}
|
||||
|
||||
const embedId = "provider-default-openai-embed";
|
||||
const isEmbedActive = hasInsertedEmbedding ? 0 : 1;
|
||||
db.prepare(
|
||||
`
|
||||
INSERT INTO provider_instances (id, name, providerName, apiKey, isActive, modelName, type, maxContext)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`,
|
||||
).run(
|
||||
embedId,
|
||||
"OpenAI Embed (Env)",
|
||||
"openai",
|
||||
openaiKey.trim(),
|
||||
isEmbedActive,
|
||||
"text-embedding-3-small",
|
||||
"embedding",
|
||||
0,
|
||||
);
|
||||
if (isEmbedActive === 1) {
|
||||
hasInsertedEmbedding = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (openRouterKey && openRouterKey.trim()) {
|
||||
const id = "provider-default-openrouter";
|
||||
const isActive = hasInsertedGenerative ? 0 : 1;
|
||||
@@ -608,6 +702,19 @@ export class ProviderManager {
|
||||
maxContext: 0,
|
||||
};
|
||||
}
|
||||
const openaiKey = process.env.OPENAI_API_KEY;
|
||||
if (openaiKey && openaiKey.trim()) {
|
||||
return {
|
||||
id: "provider-default-env-embed-fallback",
|
||||
name: "OpenAI Embed (Env Fallback)",
|
||||
providerName: "openai",
|
||||
apiKey: openaiKey.trim(),
|
||||
isActive: true,
|
||||
modelName: "text-embedding-3-small",
|
||||
type: "embedding",
|
||||
maxContext: 0,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -624,6 +731,19 @@ export class ProviderManager {
|
||||
maxContext: 32768,
|
||||
};
|
||||
}
|
||||
const openaiKey = process.env.OPENAI_API_KEY;
|
||||
if (openaiKey && openaiKey.trim()) {
|
||||
return {
|
||||
id: "provider-default-env-fallback",
|
||||
name: "OpenAI (Env Fallback)",
|
||||
providerName: "openai",
|
||||
apiKey: openaiKey.trim(),
|
||||
isActive: true,
|
||||
modelName: "gpt-4o-mini",
|
||||
type: "generative",
|
||||
maxContext: 128000,
|
||||
};
|
||||
}
|
||||
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
||||
if (anthropicKey && anthropicKey.trim()) {
|
||||
return {
|
||||
|
||||
160
packages/llm/src/providers/openai.ts
Normal file
160
packages/llm/src/providers/openai.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
import { z } from "zod";
|
||||
import { ChatOpenAI, OpenAIEmbeddings } from "@langchain/openai";
|
||||
import {
|
||||
ILLMProvider,
|
||||
LLMRequest,
|
||||
LLMResponse,
|
||||
LLMCallRecord,
|
||||
IEmbeddingProvider,
|
||||
} from "../llm.js";
|
||||
import { llmConfig } from "../config.js";
|
||||
import { ProviderManager } from "../provider-manager.js";
|
||||
|
||||
export class OpenAIProvider implements ILLMProvider {
|
||||
static readonly providerId = "openai";
|
||||
static readonly displayName = "OpenAI";
|
||||
static readonly description =
|
||||
"Official OpenAI integration using @langchain/openai SDK";
|
||||
static readonly defaultModel = "gpt-4o-mini";
|
||||
|
||||
providerName = "OpenAI";
|
||||
private model: ChatOpenAI;
|
||||
private modelNameUsed: string;
|
||||
private providerInstanceName?: string;
|
||||
private maxContextUsed?: number;
|
||||
lastCalls: LLMCallRecord[] = [];
|
||||
|
||||
constructor(
|
||||
apiKey?: string,
|
||||
modelName?: string,
|
||||
providerInstanceName?: string,
|
||||
maxContext?: number,
|
||||
) {
|
||||
let key = apiKey;
|
||||
let model = modelName;
|
||||
this.providerInstanceName = providerInstanceName;
|
||||
this.maxContextUsed = maxContext;
|
||||
|
||||
if (!key) {
|
||||
const active = ProviderManager.getActive("generative");
|
||||
if (active && active.providerName === OpenAIProvider.providerId) {
|
||||
key = active.apiKey;
|
||||
if (!model) {
|
||||
model = active.modelName;
|
||||
}
|
||||
if (!this.providerInstanceName) {
|
||||
this.providerInstanceName = active.name;
|
||||
}
|
||||
if (this.maxContextUsed === undefined) {
|
||||
this.maxContextUsed = active.maxContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
key = llmConfig.OPENAI_API_KEY;
|
||||
if (!this.providerInstanceName && key) {
|
||||
this.providerInstanceName = "Environment Variable";
|
||||
}
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
throw new Error(
|
||||
"OPENAI_API_KEY is required to initialize OpenAIProvider",
|
||||
);
|
||||
}
|
||||
|
||||
this.modelNameUsed = model || OpenAIProvider.defaultModel;
|
||||
this.model = new ChatOpenAI({
|
||||
apiKey: key,
|
||||
model: this.modelNameUsed,
|
||||
});
|
||||
}
|
||||
|
||||
async generateStructuredResponse<T extends z.ZodTypeAny>(
|
||||
request: LLMRequest<T>,
|
||||
): Promise<LLMResponse<z.infer<T>>> {
|
||||
const structuredModel = this.model.withStructuredOutput(request.schema, {
|
||||
includeRaw: true,
|
||||
});
|
||||
const result = (await structuredModel.invoke([
|
||||
{ role: "system", content: request.systemPrompt },
|
||||
{ role: "user", content: request.userContext },
|
||||
])) as unknown as {
|
||||
parsed?: z.infer<T>;
|
||||
raw?: {
|
||||
usage_metadata?: {
|
||||
input_tokens?: number;
|
||||
output_tokens?: number;
|
||||
total_tokens?: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
const parsed = result?.parsed;
|
||||
const raw = result?.raw;
|
||||
|
||||
const usage = {
|
||||
inputTokens: raw?.usage_metadata?.input_tokens || 0,
|
||||
outputTokens: raw?.usage_metadata?.output_tokens || 0,
|
||||
totalTokens: raw?.usage_metadata?.total_tokens || 0,
|
||||
modelName: this.modelNameUsed,
|
||||
providerInstanceName: this.providerInstanceName || "Default",
|
||||
maxContext:
|
||||
this.maxContextUsed !== undefined ? this.maxContextUsed : 128000,
|
||||
};
|
||||
|
||||
this.lastCalls.push({
|
||||
systemPrompt: request.systemPrompt,
|
||||
userContext: request.userContext,
|
||||
usage,
|
||||
});
|
||||
|
||||
return { success: true, data: parsed, usage };
|
||||
}
|
||||
}
|
||||
|
||||
export class OpenAIEmbeddingProvider implements IEmbeddingProvider {
|
||||
static readonly providerId = "openai";
|
||||
static readonly displayName = "OpenAI Embeddings";
|
||||
|
||||
providerName = "OpenAI";
|
||||
private model: OpenAIEmbeddings;
|
||||
|
||||
constructor(apiKey?: string, modelName?: string) {
|
||||
let key = apiKey;
|
||||
let model = modelName;
|
||||
|
||||
if (!key) {
|
||||
const active = ProviderManager.getActive("embedding");
|
||||
if (
|
||||
active &&
|
||||
active.providerName === OpenAIEmbeddingProvider.providerId
|
||||
) {
|
||||
key = active.apiKey;
|
||||
if (!model) {
|
||||
model = active.modelName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
key = llmConfig.OPENAI_API_KEY;
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
throw new Error(
|
||||
"OPENAI_API_KEY is required to initialize OpenAIEmbeddingProvider",
|
||||
);
|
||||
}
|
||||
|
||||
this.model = new OpenAIEmbeddings({
|
||||
apiKey: key,
|
||||
model: model || "text-embedding-3-small",
|
||||
});
|
||||
}
|
||||
|
||||
async embed(text: string): Promise<number[]> {
|
||||
return this.model.embedQuery(text);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user