From abcf8497a26cf6c970827648b5923b6a3d113e93 Mon Sep 17 00:00:00 2001 From: p-sw Date: Sun, 31 May 2026 23:20:29 +0900 Subject: [PATCH] feat: add basic openrouter client --- src/openrouter/index.ts | 61 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/openrouter/index.ts diff --git a/src/openrouter/index.ts b/src/openrouter/index.ts new file mode 100644 index 0000000..3c28b03 --- /dev/null +++ b/src/openrouter/index.ts @@ -0,0 +1,61 @@ +import { config } from "@/config"; +import { OpenRouter } from "@openrouter/sdk"; +import type { ChatRequestEffort } from "@openrouter/sdk/models"; + +const CONVERSATION_MODEL = "x-ai/grok-4.3" as const; +const IDENTITY_MODEL = "openai/gpt-5.4-mini" as const; +type MODELS = typeof CONVERSATION_MODEL | typeof IDENTITY_MODEL; + +interface StructuredOptions { + instruction: string; + message: string; + reasoningEffort: ChatRequestEffort; + jsonSchemaName: string; + jsonSchema: + | { + [k: string]: any; + } + | undefined; +} + +export class LLMExecutor { + private apiKey: string; + client: OpenRouter; + + constructor(apiKey: string) { + this.apiKey = apiKey; + this.client = new OpenRouter({ apiKey: this.apiKey, appTitle: "boxbrain" }); + } + + private structuredCall(model: MODELS, options: StructuredOptions) { + this.client.chat.send({ + chatRequest: { + model, + messages: [ + { + role: "system", + content: options.instruction, + }, + { + role: "user", + content: options.message, + }, + ], + reasoning: { + effort: options.reasoningEffort, + }, + responseFormat: { + type: "json_schema", + jsonSchema: { + name: options.jsonSchemaName, + schema: options.jsonSchema, + strict: true, + }, + }, + stream: false, + }, + }); + } +} + +export const llm = new LLMExecutor(config.openrouterApiKey);