diff --git a/apps/gui/src/lib/simulation/provider-resolver.ts b/apps/gui/src/lib/simulation/provider-resolver.ts
index bdb22fb..47a2993 100644
--- a/apps/gui/src/lib/simulation/provider-resolver.ts
+++ b/apps/gui/src/lib/simulation/provider-resolver.ts
@@ -6,6 +6,8 @@ import {
ProviderManager,
OpenRouterProvider,
AnthropicProvider,
+ OpenAIProvider,
+ OpenAIEmbeddingProvider,
GeminiEmbeddingProvider,
MockEmbeddingProvider,
} from "@omnia/llm";
@@ -75,6 +77,13 @@ function buildLLMProvider(inst: ModelProviderInstance): ILLMProvider {
inst.name,
inst.maxContext,
);
+ } else if (inst.providerName === "openai") {
+ return new OpenAIProvider(
+ inst.apiKey,
+ inst.modelName,
+ inst.name,
+ inst.maxContext,
+ );
}
return new MockLLMProvider([]);
}
@@ -86,6 +95,8 @@ function buildEmbeddingProvider(
return new GeminiEmbeddingProvider(inst.apiKey, inst.modelName);
} else if (inst.providerName === "ollama") {
return new OllamaEmbeddingProvider(inst.endpointUrl, inst.modelName);
+ } else if (inst.providerName === "openai") {
+ return new OpenAIEmbeddingProvider(inst.apiKey, inst.modelName);
}
return new MockEmbeddingProvider(inst.modelName);
}
diff --git a/package.json b/package.json
index f4d1a3d..9989e42 100644
--- a/package.json
+++ b/package.json
@@ -50,6 +50,7 @@
"@langchain/anthropic": "^0.3.11",
"@langchain/google-genai": "^2.2.0",
"@langchain/ollama": "^0.2.3",
+ "@langchain/openai": "^0.3.17",
"@langchain/openrouter": "^0.4.3",
"@types/node": "^20.19.43",
"dotenv": "^17.4.2"
diff --git a/packages/llm/README.md b/packages/llm/README.md
index 4f0fea8..5d71278 100644
--- a/packages/llm/README.md
+++ b/packages/llm/README.md
@@ -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
diff --git a/packages/llm/chat-openai.md b/packages/llm/chat-openai.md
new file mode 100644
index 0000000..ac1c5ba
--- /dev/null
+++ b/packages/llm/chat-openai.md
@@ -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).
+
+
+ See [this section for general instructions on installing LangChain packages](/oss/javascript/langchain/install).
+
+
+```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
+
+
+ Learn more about [OpenAI's moderation models](https://platform.openai.com/docs/guides/moderation) and categories.
+
+
+**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",
+ }),
+ ],
+});
+```
+
+
+
+ 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.
+
+
+
+ OpenAI moderation model to use. Options: `'omni-moderation-latest'`, `'omni-moderation-2024-09-26'`, `'text-moderation-latest'`, `'text-moderation-stable'`
+
+
+
+ Whether to check user input messages before the model is called
+
+
+
+ Whether to check model output messages after the model is called
+
+
+
+ Whether to check tool result messages before the model is called
+
+
+
+ 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
+
+
+
+
+ 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}."`
+
+
+
+
+
+ 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]",
+ }),
+ ],
+});
+```
+
+
+
+---
+
+
+
+ [Connect these docs](/use-these-docs) to Claude, VSCode, and more via MCP for real-time answers.
+
+
+
+ [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).
+
+
diff --git a/packages/llm/src/config.ts b/packages/llm/src/config.ts
index dad9d7b..f3b3b7f 100644
--- a/packages/llm/src/config.ts
+++ b/packages/llm/src/config.ts
@@ -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);
diff --git a/packages/llm/src/index.ts b/packages/llm/src/index.ts
index bb0aee7..b6452b0 100644
--- a/packages/llm/src/index.ts
+++ b/packages/llm/src/index.ts
@@ -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";
diff --git a/packages/llm/src/llm.ts b/packages/llm/src/llm.ts
index ea850c9..98f7614 100644
--- a/packages/llm/src/llm.ts
+++ b/packages/llm/src/llm.ts
@@ -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",
diff --git a/packages/llm/src/provider-manager.ts b/packages/llm/src/provider-manager.ts
index 4fc572d..e8b5693 100644
--- a/packages/llm/src/provider-manager.ts
+++ b/packages/llm/src/provider-manager.ts
@@ -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 {
diff --git a/packages/llm/src/providers/openai.ts b/packages/llm/src/providers/openai.ts
new file mode 100644
index 0000000..0565504
--- /dev/null
+++ b/packages/llm/src/providers/openai.ts
@@ -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(
+ request: LLMRequest,
+ ): Promise>> {
+ 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;
+ 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 {
+ return this.model.embedQuery(text);
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 63145f6..13ed722 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -269,6 +269,9 @@ importers:
"@langchain/ollama":
specifier: ^0.2.3
version: 0.2.4
+ "@langchain/openai":
+ specifier: ^0.3.17
+ version: 0.3.17(ws@8.21.0)
"@langchain/openrouter":
specifier: ^0.4.3
version: 0.4.3(ws@8.21.0)(zod@4.4.3)
@@ -2101,6 +2104,15 @@ packages:
peerDependencies:
"@langchain/core": ">=0.3.58 <0.4.0"
+ "@langchain/openai@0.3.17":
+ resolution:
+ {
+ integrity: sha512-uw4po32OKptVjq+CYHrumgbfh4NuD7LqyE+ZgqY9I/LrLc6bHLMc+sisHmI17vgek0K/yqtarI0alPJbzrwyag==,
+ }
+ engines: { node: ">=18" }
+ peerDependencies:
+ "@langchain/core": ">=0.3.29 <0.4.0"
+
"@langchain/openai@1.5.3":
resolution:
{
@@ -3894,6 +3906,18 @@ packages:
integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==,
}
+ "@types/node-fetch@2.6.13":
+ resolution:
+ {
+ integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==,
+ }
+
+ "@types/node@18.19.130":
+ resolution:
+ {
+ integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==,
+ }
+
"@types/node@20.19.43":
resolution:
{
@@ -4107,6 +4131,13 @@ packages:
integrity: sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==,
}
+ abort-controller@3.0.0:
+ resolution:
+ {
+ integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==,
+ }
+ engines: { node: ">=6.5" }
+
accepts@2.0.0:
resolution:
{
@@ -4130,6 +4161,13 @@ packages:
engines: { node: ">=0.4.0" }
hasBin: true
+ agentkeepalive@4.6.0:
+ resolution:
+ {
+ integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==,
+ }
+ engines: { node: ">= 8.0.0" }
+
ajv-formats@2.1.1:
resolution:
{
@@ -4286,6 +4324,12 @@ packages:
"@astrojs/markdown-remark":
optional: true
+ asynckit@0.4.0:
+ resolution:
+ {
+ integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==,
+ }
+
atomically@1.7.0:
resolution:
{
@@ -4591,6 +4635,13 @@ packages:
}
engines: { node: ">=12.5.0" }
+ combined-stream@1.0.8:
+ resolution:
+ {
+ integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==,
+ }
+ engines: { node: ">= 0.8" }
+
comma-separated-tokens@2.0.3:
resolution:
{
@@ -5173,6 +5224,13 @@ packages:
integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==,
}
+ delayed-stream@1.0.0:
+ resolution:
+ {
+ integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==,
+ }
+ engines: { node: ">=0.4.0" }
+
depd@2.0.0:
resolution:
{
@@ -5396,6 +5454,13 @@ packages:
}
engines: { node: ">= 0.4" }
+ es-set-tostringtag@2.1.0:
+ resolution:
+ {
+ integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==,
+ }
+ engines: { node: ">= 0.4" }
+
es-toolkit@1.49.0:
resolution:
{
@@ -5590,6 +5655,13 @@ packages:
}
engines: { node: ">= 0.6" }
+ event-target-shim@5.0.1:
+ resolution:
+ {
+ integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==,
+ }
+ engines: { node: ">=6" }
+
eventemitter3@4.0.7:
resolution:
{
@@ -5827,6 +5899,26 @@ packages:
}
engines: { node: ">=20" }
+ form-data-encoder@1.7.2:
+ resolution:
+ {
+ integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==,
+ }
+
+ form-data@4.0.6:
+ resolution:
+ {
+ integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==,
+ }
+ engines: { node: ">= 6" }
+
+ formdata-node@4.4.1:
+ resolution:
+ {
+ integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==,
+ }
+ engines: { node: ">= 12.20" }
+
forwarded@0.2.0:
resolution:
{
@@ -6008,6 +6100,13 @@ packages:
}
engines: { node: ">= 0.4" }
+ has-tostringtag@1.0.2:
+ resolution:
+ {
+ integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==,
+ }
+ engines: { node: ">= 0.4" }
+
hasown@2.0.4:
resolution:
{
@@ -6187,6 +6286,12 @@ packages:
}
engines: { node: ">=18.18.0" }
+ humanize-ms@1.2.1:
+ resolution:
+ {
+ integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==,
+ }
+
i18next@26.3.4:
resolution:
{
@@ -7272,6 +7377,13 @@ packages:
}
engines: { node: ">=8.6" }
+ mime-db@1.52.0:
+ resolution:
+ {
+ integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==,
+ }
+ engines: { node: ">= 0.6" }
+
mime-db@1.54.0:
resolution:
{
@@ -7279,6 +7391,13 @@ packages:
}
engines: { node: ">= 0.6" }
+ mime-types@2.1.35:
+ resolution:
+ {
+ integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==,
+ }
+ engines: { node: ">= 0.6" }
+
mime-types@3.0.2:
resolution:
{
@@ -7432,12 +7551,32 @@ packages:
}
engines: { node: ">=10" }
+ node-domexception@1.0.0:
+ resolution:
+ {
+ integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==,
+ }
+ engines: { node: ">=10.5.0" }
+ deprecated: Use your platform's native DOMException instead
+
node-fetch-native@1.6.7:
resolution:
{
integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==,
}
+ node-fetch@2.7.0:
+ resolution:
+ {
+ integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==,
+ }
+ engines: { node: 4.x || >=6.0.0 }
+ peerDependencies:
+ encoding: ^0.1.0
+ peerDependenciesMeta:
+ encoding:
+ optional: true
+
node-mock-http@1.0.4:
resolution:
{
@@ -7577,6 +7716,21 @@ packages:
}
engines: { node: ">=12" }
+ openai@4.104.0:
+ resolution:
+ {
+ integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==,
+ }
+ hasBin: true
+ peerDependencies:
+ ws: ^8.18.0
+ zod: ^3.23.8
+ peerDependenciesMeta:
+ ws:
+ optional: true
+ zod:
+ optional: true
+
openai@6.45.0:
resolution:
{
@@ -8844,6 +8998,12 @@ packages:
}
engines: { node: ">=0.6" }
+ tr46@0.0.3:
+ resolution:
+ {
+ integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==,
+ }
+
trim-lines@3.0.1:
resolution:
{
@@ -8953,6 +9113,12 @@ packages:
integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==,
}
+ undici-types@5.26.5:
+ resolution:
+ {
+ integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==,
+ }
+
undici-types@6.21.0:
resolution:
{
@@ -9358,12 +9524,31 @@ packages:
integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==,
}
+ web-streams-polyfill@4.0.0-beta.3:
+ resolution:
+ {
+ integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==,
+ }
+ engines: { node: ">= 14" }
+
+ webidl-conversions@3.0.1:
+ resolution:
+ {
+ integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==,
+ }
+
whatwg-fetch@3.6.20:
resolution:
{
integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==,
}
+ whatwg-url@5.0.0:
+ resolution:
+ {
+ integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==,
+ }
+
which@2.0.2:
resolution:
{
@@ -10456,6 +10641,16 @@ snapshots:
ollama: 0.5.18
uuid: 10.0.0
+ "@langchain/openai@0.3.17(ws@8.21.0)":
+ dependencies:
+ js-tiktoken: 1.0.21
+ openai: 4.104.0(ws@8.21.0)(zod@3.25.76)
+ zod: 3.25.76
+ zod-to-json-schema: 3.25.2(zod@3.25.76)
+ transitivePeerDependencies:
+ - encoding
+ - ws
+
"@langchain/openai@1.5.3(ws@8.21.0)":
dependencies:
js-tiktoken: 1.0.21
@@ -11720,6 +11915,15 @@ snapshots:
dependencies:
"@types/unist": 3.0.3
+ "@types/node-fetch@2.6.13":
+ dependencies:
+ "@types/node": 26.1.0
+ form-data: 4.0.6
+
+ "@types/node@18.19.130":
+ dependencies:
+ undici-types: 5.26.5
+
"@types/node@20.19.43":
dependencies:
undici-types: 6.21.0
@@ -11892,6 +12096,10 @@ snapshots:
convert-source-map: 2.0.0
tinyrainbow: 3.1.0
+ abort-controller@3.0.0:
+ dependencies:
+ event-target-shim: 5.0.1
+
accepts@2.0.0:
dependencies:
mime-types: 3.0.2
@@ -11903,6 +12111,10 @@ snapshots:
acorn@8.17.0: {}
+ agentkeepalive@4.6.0:
+ dependencies:
+ humanize-ms: 1.2.1
+
ajv-formats@2.1.1(ajv@8.20.0):
optionalDependencies:
ajv: 8.20.0
@@ -12067,6 +12279,8 @@ snapshots:
- uploadthing
- yaml
+ asynckit@0.4.0: {}
+
atomically@1.7.0: {}
autoprefixer@10.5.2(postcss@8.5.16):
@@ -12226,6 +12440,10 @@ snapshots:
color-convert: 2.0.1
color-string: 1.9.1
+ combined-stream@1.0.8:
+ dependencies:
+ delayed-stream: 1.0.0
+
comma-separated-tokens@2.0.3: {}
commander@11.1.0: {}
@@ -12556,6 +12774,8 @@ snapshots:
dependencies:
robust-predicates: 3.0.3
+ delayed-stream@1.0.0: {}
+
depd@2.0.0: {}
dequal@2.0.3: {}
@@ -12656,6 +12876,13 @@ snapshots:
dependencies:
es-errors: 1.3.0
+ es-set-tostringtag@2.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ has-tostringtag: 1.0.2
+ hasown: 2.0.4
+
es-toolkit@1.49.0: {}
esast-util-from-estree@2.0.0:
@@ -12818,6 +13045,8 @@ snapshots:
etag@1.8.1: {}
+ event-target-shim@5.0.1: {}
+
eventemitter3@4.0.7: {}
eventemitter3@5.0.4: {}
@@ -12995,6 +13224,21 @@ snapshots:
dependencies:
tiny-inflate: 1.0.3
+ form-data-encoder@1.7.2: {}
+
+ form-data@4.0.6:
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ es-set-tostringtag: 2.1.0
+ hasown: 2.0.4
+ mime-types: 2.1.35
+
+ formdata-node@4.4.1:
+ dependencies:
+ node-domexception: 1.0.0
+ web-streams-polyfill: 4.0.0-beta.3
+
forwarded@0.2.0: {}
fraction.js@5.3.4: {}
@@ -13087,6 +13331,10 @@ snapshots:
has-symbols@1.1.0: {}
+ has-tostringtag@1.0.2:
+ dependencies:
+ has-symbols: 1.1.0
+
hasown@2.0.4:
dependencies:
function-bind: 1.1.2
@@ -13302,6 +13550,10 @@ snapshots:
human-signals@8.0.1: {}
+ humanize-ms@1.2.1:
+ dependencies:
+ ms: 2.1.3
+
i18next@26.3.4(typescript@6.0.3):
optionalDependencies:
typescript: 6.0.3
@@ -14084,8 +14336,14 @@ snapshots:
braces: 3.0.3
picomatch: 2.3.2
+ mime-db@1.52.0: {}
+
mime-db@1.54.0: {}
+ mime-types@2.1.35:
+ dependencies:
+ mime-db: 1.52.0
+
mime-types@3.0.2:
dependencies:
mime-db: 1.54.0
@@ -14166,8 +14424,14 @@ snapshots:
dependencies:
semver: 7.8.5
+ node-domexception@1.0.0: {}
+
node-fetch-native@1.6.7: {}
+ node-fetch@2.7.0:
+ dependencies:
+ whatwg-url: 5.0.0
+
node-mock-http@1.0.4: {}
node-releases@2.0.51: {}
@@ -14246,6 +14510,21 @@ snapshots:
is-docker: 2.2.1
is-wsl: 2.2.0
+ openai@4.104.0(ws@8.21.0)(zod@3.25.76):
+ dependencies:
+ "@types/node": 18.19.130
+ "@types/node-fetch": 2.6.13
+ abort-controller: 3.0.0
+ agentkeepalive: 4.6.0
+ form-data-encoder: 1.7.2
+ formdata-node: 4.4.1
+ node-fetch: 2.7.0
+ optionalDependencies:
+ ws: 8.21.0
+ zod: 3.25.76
+ transitivePeerDependencies:
+ - encoding
+
openai@6.45.0(ws@8.21.0)(zod@4.4.3):
optionalDependencies:
ws: 8.21.0
@@ -15205,6 +15484,8 @@ snapshots:
toidentifier@1.0.1: {}
+ tr46@0.0.3: {}
+
trim-lines@3.0.1: {}
trough@2.2.0: {}
@@ -15263,6 +15544,8 @@ snapshots:
uncrypto@0.1.3: {}
+ undici-types@5.26.5: {}
+
undici-types@6.21.0: {}
undici-types@7.18.2: {}
@@ -15469,8 +15752,17 @@ snapshots:
web-namespaces@2.0.1: {}
+ web-streams-polyfill@4.0.0-beta.3: {}
+
+ webidl-conversions@3.0.1: {}
+
whatwg-fetch@3.6.20: {}
+ whatwg-url@5.0.0:
+ dependencies:
+ tr46: 0.0.3
+ webidl-conversions: 3.0.1
+
which@2.0.2:
dependencies:
isexe: 2.0.0