From 13155cba23924447b236eeb66dbfdd5b7a65d00e Mon Sep 17 00:00:00 2001 From: Aditya Gupta Date: Thu, 16 Jul 2026 13:29:21 +0530 Subject: [PATCH] feat(llm): Added OpenAI provider --- .../src/lib/simulation/provider-resolver.ts | 11 + package.json | 1 + packages/llm/README.md | 26 ++ packages/llm/chat-openai.md | 225 ++++++++++++++ packages/llm/src/config.ts | 1 + packages/llm/src/index.ts | 1 + packages/llm/src/llm.ts | 7 + packages/llm/src/provider-manager.ts | 120 +++++++ packages/llm/src/providers/openai.ts | 160 ++++++++++ pnpm-lock.yaml | 292 ++++++++++++++++++ 10 files changed, 844 insertions(+) create mode 100644 packages/llm/chat-openai.md create mode 100644 packages/llm/src/providers/openai.ts 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