langchain
Version:
Typescript bindings for langchain
71 lines (70 loc) • 3.05 kB
JavaScript
const require_middleware = require("../../../middleware.cjs");
const require_chat_models_universal = require("../../../../chat_models/universal.cjs");
const require_decisions = require("./decisions.cjs");
let _langchain_core_messages = require("@langchain/core/messages");
let zod_v4 = require("zod/v4");
// src/agents/middleware/provider/openai/modelRouter.ts
const routeSchema = zod_v4.z.object({
choice: zod_v4.z.string(),
confidence: zod_v4.z.number(),
probabilities: zod_v4.z.array(zod_v4.z.object({
value: zod_v4.z.string(),
probability: zod_v4.z.number()
}))
});
/**
* Routes each agent run to one of several models with the OpenAI Decisions API
* (beta).
*
* Classifies the latest human message once per run and stores the answer in
* `modelRoute`, then uses the chosen model for every model call in that run. With
* no human message, or a refusal, the agent's own model is used.
*/
function openAIModelRouterMiddleware(options) {
const routes = Object.keys(options.choices);
if (!routes.length) throw new Error("openAIModelRouterMiddleware requires at least one choice.");
if (!options.instructions.trim()) throw new Error("openAIModelRouterMiddleware instructions must not be empty.");
const decide = require_decisions.decider(options.model, { model_route: {
type: "choice",
instructions: options.instructions,
choices: Object.fromEntries(routes.map((route) => [route, options.choices[route].criteria]))
} });
const models = /* @__PURE__ */ new Map();
const modelFor = (route) => {
if (!Object.hasOwn(options.choices, route)) throw new Error(`Unknown model route "${route}".`);
if (!models.has(route)) {
const choice = options.choices[route];
const pending = Promise.resolve(typeof choice.model === "string" ? require_chat_models_universal.initChatModel(choice.model) : choice.model);
pending.catch(() => models.delete(route));
models.set(route, pending);
}
return models.get(route);
};
return require_middleware.createMiddleware({
name: "OpenAIModelRouterMiddleware",
stateSchema: zod_v4.z.object({ modelRoute: routeSchema.nullable().optional() }),
async beforeAgent(state, runtime) {
const message = [...state.messages].reverse().find((message) => _langchain_core_messages.HumanMessage.isInstance(message));
if (!message) return { modelRoute: null };
const answer = await decide(message, runtime.signal);
if (answer?.type !== "choice") return { modelRoute: null };
if (!Object.hasOwn(options.choices, answer.choice)) throw new Error(`OpenAI Decisions selected unknown model route "${answer.choice}".`);
const { choice, confidence, probabilities } = answer;
return { modelRoute: {
choice,
confidence,
probabilities
} };
},
async wrapModelCall(request, handler) {
const route = request.state.modelRoute;
if (!route) return handler(request);
return handler({
...request,
model: await modelFor(route.choice)
});
}
});
}
exports.openAIModelRouterMiddleware = openAIModelRouterMiddleware;
//# sourceMappingURL=modelRouter.cjs.map