Skip to content

LangChain JS ​

ChatOpenAI and ChatOpenAICompletions from @langchain/openai. For Claude through the Messages API use LangChain JS (ChatAnthropic).

Connect ​

Pass configuration: { baseURL: "http://127.0.0.1:4010/v1" } and your plugboard key as apiKey. The snippets take client ({ baseURL, apiKey }) and model, an alias such as "fast" or any allowed provider/model[#variant].

Chat ​

ts
const options = { model, apiKey: client.apiKey, configuration: { baseURL: client.baseURL }, maxTokens: 1024, maxRetries: 0 }
const llm = variant === "chat" ? new ChatOpenAICompletions(options) : new ChatOpenAI(options)
const reply = await llm.invoke("Reply with exactly: pong")

Tool calls ​

ts
const PROMPT = "What is the weather in Paris? Use the tool."
const TOOL_RESULT = readFileSync(new URL("../_shared/get_weather.result.json", import.meta.url), "utf8").trim()
const getWeather = tool(async () => TOOL_RESULT, {
  name: "get_weather",
  description: "Current weather for a city",
  schema: z.object({ city: z.string() }),
})
const options = { model, apiKey: client.apiKey, configuration: { baseURL: client.baseURL }, maxTokens: 1024, maxRetries: 0 }
const llm = (variant === "chat" ? new ChatOpenAICompletions(options) : new ChatOpenAI(options)).bindTools([getWeather])
const first = await llm.invoke([new HumanMessage(PROMPT)])
const call = first.tool_calls![0]!
// Send the assistant turn back as LangChain built it, then the result under the same call id.
const second = await llm.invoke([
  new HumanMessage(PROMPT),
  first,
  new ToolMessage({ content: TOOL_RESULT, tool_call_id: call.id! }),
])

Structured output ​

ts
const PROMPT = "Estimate: 2 boiled eggs and a slice of toast."
const Meal = z.object({ calories: z.number(), protein_g: z.number() }).describe("Meal nutrition estimate.")
const llm = new ChatOpenAI({
  model,
  apiKey: client.apiKey,
  configuration: { baseURL: client.baseURL },
  maxTokens: 1024,
  maxRetries: 0,
})
// includeRaw keeps the model's own text, before zod drops any keys it does not know.
const { parsed: meal, raw } = await llm.withStructuredOutput(Meal, { method: "jsonSchema", name: "Meal", includeRaw: true }).invoke(PROMPT)

withStructuredOutput(Meal, { method: "jsonSchema" }) and method: "functionCalling" both work. Avoid jsonMode: it sends no schema, so the model can return {}.

Limits ​

  • ChatOpenAI always uses the Responses API for ids containing gpt-5.6, codex or a -pro model, and useResponsesApi: false does not change that. On that route LangChain exposes no finish_reason; read response_metadata.status. To keep such a model on Chat Completions, use new ChatOpenAICompletions({ model, apiKey, configuration: { baseURL } }).
  • There is no model-list call. Use the openai SDK.