From 1833ebfbad53ff33e59b36b0b520155f131a38cc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 13:01:59 +0000 Subject: [PATCH 1/7] Initial plan From cec98726e3c43fbda57ce2f0eb4f093f0cef7157 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 13:07:13 +0000 Subject: [PATCH 2/7] Add OpenRouter support as fallback to Gemini in chatActions Co-authored-by: na-trium-144 <100704180+na-trium-144@users.noreply.github.com> --- app/actions/chatActions.ts | 10 ++- app/actions/openrouter.ts | 47 +++++++++++ package-lock.json | 158 ++++++------------------------------- 3 files changed, 81 insertions(+), 134 deletions(-) create mode 100644 app/actions/openrouter.ts diff --git a/app/actions/chatActions.ts b/app/actions/chatActions.ts index 9efcb89..ad684e2 100644 --- a/app/actions/chatActions.ts +++ b/app/actions/chatActions.ts @@ -1,12 +1,20 @@ "use server"; // import { z } from "zod"; -import { generateContent } from "./gemini"; +import { generateContent as generateContentGemini } from "./gemini"; +import { generateContent as generateContentOpenRouter } from "./openrouter"; import { DynamicMarkdownSection } from "../[lang]/[pageId]/pageContent"; import { ReplCommand, ReplOutput } from "@my-code/runtime/interface"; import { addChat, ChatWithMessages } from "@/lib/chatHistory"; import { getPagesList, introSectionId, PagePath, SectionId } from "@/lib/docs"; +function generateContent(prompt: string, systemInstruction?: string) { + if (process.env.OPENROUTER_API_KEY && process.env.OPENROUTER_MODEL) { + return generateContentOpenRouter(prompt, systemInstruction); + } + return generateContentGemini(prompt, systemInstruction); +} + type ChatResult = | { error: string; diff --git a/app/actions/openrouter.ts b/app/actions/openrouter.ts new file mode 100644 index 0000000..ccb3d3a --- /dev/null +++ b/app/actions/openrouter.ts @@ -0,0 +1,47 @@ +"use server"; + +export async function generateContent( + prompt: string, + systemInstruction?: string +): Promise<{ text: string }> { + const apiKey = process.env.OPENROUTER_API_KEY; + const model = process.env.OPENROUTER_MODEL; + + if (!apiKey || !model) { + throw new Error( + "OPENROUTER_API_KEY and OPENROUTER_MODEL environment variables must be set" + ); + } + + const messages: { role: string; content: string }[] = []; + if (systemInstruction) { + messages.push({ role: "system", content: systemInstruction }); + } + messages.push({ role: "user", content: prompt }); + + const response = await fetch("https://openrouter.ai/api/v1/chat/completions", { + method: "POST", + headers: { + Authorization: `Bearer ${apiKey}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ model, messages }), + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error( + `OpenRouter API error: ${response.status} ${response.statusText} - ${errorText}` + ); + } + + const data = (await response.json()) as { + choices: { message: { content: string } }[]; + }; + + const text = data.choices[0]?.message?.content; + if (!text) { + throw new Error("OpenRouterからの応答が空でした"); + } + return { text }; +} diff --git a/package-lock.json b/package-lock.json index 2ee3504..c66f141 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1958,7 +1958,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1975,7 +1974,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1992,7 +1990,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2009,7 +2006,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2026,7 +2022,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2043,7 +2038,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2060,7 +2054,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2077,7 +2070,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2094,7 +2086,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2111,7 +2102,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2128,7 +2118,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2145,7 +2134,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2162,7 +2150,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2179,7 +2166,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2196,7 +2182,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2213,7 +2198,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2230,7 +2214,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2247,7 +2230,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2264,7 +2246,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2281,7 +2262,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2298,7 +2278,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2315,7 +2294,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4854,8 +4832,7 @@ "optional": true, "os": [ "android" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-android-arm64": { "version": "4.59.0", @@ -4868,8 +4845,7 @@ "optional": true, "os": [ "android" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.59.0", @@ -4882,8 +4858,7 @@ "optional": true, "os": [ "darwin" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-darwin-x64": { "version": "4.59.0", @@ -4896,8 +4871,7 @@ "optional": true, "os": [ "darwin" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.59.0", @@ -4910,8 +4884,7 @@ "optional": true, "os": [ "freebsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-freebsd-x64": { "version": "4.59.0", @@ -4924,8 +4897,7 @@ "optional": true, "os": [ "freebsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.59.0", @@ -4938,8 +4910,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.59.0", @@ -4952,8 +4923,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.59.0", @@ -4966,8 +4936,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.59.0", @@ -4980,8 +4949,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { "version": "4.59.0", @@ -4994,8 +4962,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { "version": "4.59.0", @@ -5008,8 +4975,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { "version": "4.59.0", @@ -5022,8 +4988,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { "version": "4.59.0", @@ -5036,8 +5001,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.59.0", @@ -5050,8 +5014,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { "version": "4.59.0", @@ -5064,8 +5027,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.59.0", @@ -5078,8 +5040,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.59.0", @@ -5092,8 +5053,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-x64-musl": { "version": "4.59.0", @@ -5106,8 +5066,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-openbsd-x64": { "version": "4.59.0", @@ -5120,8 +5079,7 @@ "optional": true, "os": [ "openbsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-openharmony-arm64": { "version": "4.59.0", @@ -5134,8 +5092,7 @@ "optional": true, "os": [ "openharmony" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.59.0", @@ -5148,8 +5105,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { "version": "4.59.0", @@ -5162,8 +5118,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { "version": "4.59.0", @@ -5176,8 +5131,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.59.0", @@ -5190,8 +5144,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rtsao/scc": { "version": "1.1.0", @@ -13980,7 +13933,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14001,7 +13953,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14022,7 +13973,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14043,7 +13993,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14064,7 +14013,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14085,7 +14033,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14106,7 +14053,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14127,7 +14073,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14148,7 +14093,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14169,7 +14113,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14190,7 +14133,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -19441,7 +19383,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19458,7 +19399,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19475,7 +19415,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19492,7 +19431,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19509,7 +19447,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19526,7 +19463,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19543,7 +19479,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19560,7 +19495,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19577,7 +19511,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19594,7 +19527,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19611,7 +19543,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19628,7 +19559,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19645,7 +19575,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19662,7 +19591,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19679,7 +19607,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19696,7 +19623,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19713,7 +19639,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19730,7 +19655,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19747,7 +19671,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19764,7 +19687,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19781,7 +19703,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19798,7 +19719,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19815,7 +19735,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19832,7 +19751,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19849,7 +19767,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -20408,7 +20325,6 @@ "os": [ "aix" ], - "peer": true, "engines": { "node": ">=18" } @@ -20425,7 +20341,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -20442,7 +20357,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -20459,7 +20373,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -20476,7 +20389,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -20493,7 +20405,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -20510,7 +20421,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -20527,7 +20437,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -20544,7 +20453,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -20561,7 +20469,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -20578,7 +20485,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -20595,7 +20501,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -20612,7 +20517,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -20629,7 +20533,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -20646,7 +20549,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -20663,7 +20565,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -20680,7 +20581,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -20697,7 +20597,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -20714,7 +20613,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -20731,7 +20629,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -20748,7 +20645,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -20765,7 +20661,6 @@ "os": [ "sunos" ], - "peer": true, "engines": { "node": ">=18" } @@ -20782,7 +20677,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -20799,7 +20693,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -20816,7 +20709,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } From 0e190c70b71ac89de6679293082e42155d1fd060 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 13:56:14 +0000 Subject: [PATCH 3/7] Use openai SDK for OpenRouter integration instead of direct fetch Co-authored-by: na-trium-144 <100704180+na-trium-144@users.noreply.github.com> --- app/actions/openrouter.ts | 31 ++++++++++--------------------- package-lock.json | 22 ++++++++++++++++++++++ package.json | 1 + 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/app/actions/openrouter.ts b/app/actions/openrouter.ts index ccb3d3a..acc3cf0 100644 --- a/app/actions/openrouter.ts +++ b/app/actions/openrouter.ts @@ -1,5 +1,7 @@ "use server"; +import OpenAI from "openai"; + export async function generateContent( prompt: string, systemInstruction?: string @@ -13,33 +15,20 @@ export async function generateContent( ); } - const messages: { role: string; content: string }[] = []; + const client = new OpenAI({ + apiKey, + baseURL: "https://openrouter.ai/api/v1", + }); + + const messages: OpenAI.Chat.ChatCompletionMessageParam[] = []; if (systemInstruction) { messages.push({ role: "system", content: systemInstruction }); } messages.push({ role: "user", content: prompt }); - const response = await fetch("https://openrouter.ai/api/v1/chat/completions", { - method: "POST", - headers: { - Authorization: `Bearer ${apiKey}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ model, messages }), - }); - - if (!response.ok) { - const errorText = await response.text(); - throw new Error( - `OpenRouter API error: ${response.status} ${response.statusText} - ${errorText}` - ); - } - - const data = (await response.json()) as { - choices: { message: { content: string } }[]; - }; + const completion = await client.chat.completions.create({ model, messages }); - const text = data.choices[0]?.message?.content; + const text = completion.choices[0]?.message?.content; if (!text) { throw new Error("OpenRouterからの応答が空でした"); } diff --git a/package-lock.json b/package-lock.json index c66f141..8015909 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "js-yaml": "^4.1.1", "mocha": "^11.7.4", "next": "^15.5.11", + "openai": "^6.27.0", "pg": "^8.16.3", "prismjs": "^1.30.0", "react": "^19", @@ -16407,6 +16408,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openai": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.27.0.tgz", + "integrity": "sha512-osTKySlrdYrLYTt0zjhY8yp0JUBmWDCN+Q+QxsV4xMQnnoVFpylgKGgxwN8sSdTNw0G4y+WUXs4eCMWpyDNWZQ==", + "license": "Apache-2.0", + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", diff --git a/package.json b/package.json index af5b2dc..bc1bcc0 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "js-yaml": "^4.1.1", "mocha": "^11.7.4", "next": "^15.5.11", + "openai": "^6.27.0", "pg": "^8.16.3", "prismjs": "^1.30.0", "react": "^19", From 9a28d39e13805e240e968bb2b7a97568693a528c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 14:08:20 +0000 Subject: [PATCH 4/7] Consolidate gemini.ts and openrouter.ts into a single generateContent function Co-authored-by: na-trium-144 <100704180+na-trium-144@users.noreply.github.com> --- app/actions/chatActions.ts | 10 +------- app/actions/gemini.ts | 49 ++++++++++++++++++++++++++++++++++---- app/actions/openrouter.ts | 36 ---------------------------- 3 files changed, 46 insertions(+), 49 deletions(-) delete mode 100644 app/actions/openrouter.ts diff --git a/app/actions/chatActions.ts b/app/actions/chatActions.ts index ad684e2..9efcb89 100644 --- a/app/actions/chatActions.ts +++ b/app/actions/chatActions.ts @@ -1,20 +1,12 @@ "use server"; // import { z } from "zod"; -import { generateContent as generateContentGemini } from "./gemini"; -import { generateContent as generateContentOpenRouter } from "./openrouter"; +import { generateContent } from "./gemini"; import { DynamicMarkdownSection } from "../[lang]/[pageId]/pageContent"; import { ReplCommand, ReplOutput } from "@my-code/runtime/interface"; import { addChat, ChatWithMessages } from "@/lib/chatHistory"; import { getPagesList, introSectionId, PagePath, SectionId } from "@/lib/docs"; -function generateContent(prompt: string, systemInstruction?: string) { - if (process.env.OPENROUTER_API_KEY && process.env.OPENROUTER_MODEL) { - return generateContentOpenRouter(prompt, systemInstruction); - } - return generateContentGemini(prompt, systemInstruction); -} - type ChatResult = | { error: string; diff --git a/app/actions/gemini.ts b/app/actions/gemini.ts index 8dc7539..15fc63b 100644 --- a/app/actions/gemini.ts +++ b/app/actions/gemini.ts @@ -1,20 +1,56 @@ "use server"; import { GoogleGenAI } from "@google/genai"; +import OpenAI from "openai"; + +export async function generateContent( + prompt: string, + systemInstruction?: string +): Promise<{ text: string }> { + const openRouterApiKey = process.env.OPENROUTER_API_KEY; + const openRouterModel = process.env.OPENROUTER_MODEL; + + if (openRouterApiKey && openRouterModel) { + const client = new OpenAI({ + apiKey: openRouterApiKey, + baseURL: "https://openrouter.ai/api/v1", + }); + + const messages: OpenAI.Chat.ChatCompletionMessageParam[] = []; + if (systemInstruction) { + messages.push({ role: "system", content: systemInstruction }); + } + messages.push({ role: "user", content: prompt }); + + const completion = await client.chat.completions.create({ + model: openRouterModel, + messages, + }); + + const text = completion.choices[0]?.message?.content; + if (!text) { + throw new Error("OpenRouterからの応答が空でした"); + } + return { text }; + } -export async function generateContent(prompt: string, systemInstruction?: string) { const params = { model: "gemini-2.5-flash", contents: prompt, config: { systemInstruction, - } + }, }; const ai = new GoogleGenAI({ apiKey: process.env.API_KEY! }); try { - return await ai.models.generateContent(params); + const result = await ai.models.generateContent(params); + const text = result.text; + if (!text) { + throw new Error("Geminiからの応答が空でした"); + } + return { text }; } catch (e: unknown) { if (String(e).includes("User location is not supported")) { // For the new API, we can use httpOptions to set a custom baseUrl @@ -24,7 +60,12 @@ export async function generateContent(prompt: string, systemInstruction?: string baseUrl: "https://gemini-proxy.utcode.net", }, }); - return await aiWithProxy.models.generateContent(params); + const result = await aiWithProxy.models.generateContent(params); + const text = result.text; + if (!text) { + throw new Error("Geminiからの応答が空でした"); + } + return { text }; } else { throw e; } diff --git a/app/actions/openrouter.ts b/app/actions/openrouter.ts deleted file mode 100644 index acc3cf0..0000000 --- a/app/actions/openrouter.ts +++ /dev/null @@ -1,36 +0,0 @@ -"use server"; - -import OpenAI from "openai"; - -export async function generateContent( - prompt: string, - systemInstruction?: string -): Promise<{ text: string }> { - const apiKey = process.env.OPENROUTER_API_KEY; - const model = process.env.OPENROUTER_MODEL; - - if (!apiKey || !model) { - throw new Error( - "OPENROUTER_API_KEY and OPENROUTER_MODEL environment variables must be set" - ); - } - - const client = new OpenAI({ - apiKey, - baseURL: "https://openrouter.ai/api/v1", - }); - - const messages: OpenAI.Chat.ChatCompletionMessageParam[] = []; - if (systemInstruction) { - messages.push({ role: "system", content: systemInstruction }); - } - messages.push({ role: "user", content: prompt }); - - const completion = await client.chat.completions.create({ model, messages }); - - const text = completion.choices[0]?.message?.content; - if (!text) { - throw new Error("OpenRouterからの応答が空でした"); - } - return { text }; -} From a259c8b9350119a3037ccedf1695864c6b8dbb79 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 15:43:11 +0000 Subject: [PATCH 5/7] Support multiple OpenRouter models with semicolon separator and automatic fallback Co-authored-by: na-trium-144 <100704180+na-trium-144@users.noreply.github.com> --- app/actions/gemini.ts | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/app/actions/gemini.ts b/app/actions/gemini.ts index 15fc63b..50fe707 100644 --- a/app/actions/gemini.ts +++ b/app/actions/gemini.ts @@ -1,7 +1,6 @@ "use server"; import { GoogleGenAI } from "@google/genai"; -import OpenAI from "openai"; export async function generateContent( prompt: string, @@ -11,23 +10,36 @@ export async function generateContent( const openRouterModel = process.env.OPENROUTER_MODEL; if (openRouterApiKey && openRouterModel) { - const client = new OpenAI({ - apiKey: openRouterApiKey, - baseURL: "https://openrouter.ai/api/v1", - }); + // Support semicolon-separated list of models for automatic fallback via + // OpenRouter's `models` array parameter. + const models = openRouterModel.split(";").map((m) => m.trim()).filter(Boolean); - const messages: OpenAI.Chat.ChatCompletionMessageParam[] = []; + const messages: { role: string; content: string }[] = []; if (systemInstruction) { messages.push({ role: "system", content: systemInstruction }); } messages.push({ role: "user", content: prompt }); - const completion = await client.chat.completions.create({ - model: openRouterModel, - messages, + const response = await fetch("https://openrouter.ai/api/v1/chat/completions", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${openRouterApiKey}`, + }, + body: JSON.stringify({ models, messages }), }); - const text = completion.choices[0]?.message?.content; + if (!response.ok) { + const body = await response.text(); + throw new Error( + `OpenRouter APIエラー: ${response.status} ${response.statusText} - ${body}` + ); + } + + const data = (await response.json()) as { + choices?: { message?: { content?: string | null } }[]; + }; + const text = data.choices?.[0]?.message?.content; if (!text) { throw new Error("OpenRouterからの応答が空でした"); } From f4cad2f598058b3e04a997425e6e0f3609fa6544 Mon Sep 17 00:00:00 2001 From: na-trium-144 <100704180+na-trium-144@users.noreply.github.com> Date: Sat, 14 Mar 2026 00:46:57 +0900 Subject: [PATCH 6/7] =?UTF-8?q?openai=20sdk=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 180 ++++++++++++++++++++++++++++++++++------------ package.json | 1 - 2 files changed, 133 insertions(+), 48 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8015909..2ee3504 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,6 @@ "js-yaml": "^4.1.1", "mocha": "^11.7.4", "next": "^15.5.11", - "openai": "^6.27.0", "pg": "^8.16.3", "prismjs": "^1.30.0", "react": "^19", @@ -1959,6 +1958,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1975,6 +1975,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1991,6 +1992,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2007,6 +2009,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2023,6 +2026,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2039,6 +2043,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2055,6 +2060,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2071,6 +2077,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2087,6 +2094,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2103,6 +2111,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2119,6 +2128,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2135,6 +2145,7 @@ "cpu": [ "mips64el" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2151,6 +2162,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2167,6 +2179,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2183,6 +2196,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2199,6 +2213,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2215,6 +2230,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2231,6 +2247,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2247,6 +2264,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2263,6 +2281,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2279,6 +2298,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2295,6 +2315,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4833,7 +4854,8 @@ "optional": true, "os": [ "android" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-android-arm64": { "version": "4.59.0", @@ -4846,7 +4868,8 @@ "optional": true, "os": [ "android" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.59.0", @@ -4859,7 +4882,8 @@ "optional": true, "os": [ "darwin" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-darwin-x64": { "version": "4.59.0", @@ -4872,7 +4896,8 @@ "optional": true, "os": [ "darwin" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.59.0", @@ -4885,7 +4910,8 @@ "optional": true, "os": [ "freebsd" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-freebsd-x64": { "version": "4.59.0", @@ -4898,7 +4924,8 @@ "optional": true, "os": [ "freebsd" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.59.0", @@ -4911,7 +4938,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.59.0", @@ -4924,7 +4952,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.59.0", @@ -4937,7 +4966,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.59.0", @@ -4950,7 +4980,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-loong64-gnu": { "version": "4.59.0", @@ -4963,7 +4994,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-loong64-musl": { "version": "4.59.0", @@ -4976,7 +5008,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { "version": "4.59.0", @@ -4989,7 +5022,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-ppc64-musl": { "version": "4.59.0", @@ -5002,7 +5036,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.59.0", @@ -5015,7 +5050,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-riscv64-musl": { "version": "4.59.0", @@ -5028,7 +5064,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.59.0", @@ -5041,7 +5078,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.59.0", @@ -5054,7 +5092,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-x64-musl": { "version": "4.59.0", @@ -5067,7 +5106,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-openbsd-x64": { "version": "4.59.0", @@ -5080,7 +5120,8 @@ "optional": true, "os": [ "openbsd" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-openharmony-arm64": { "version": "4.59.0", @@ -5093,7 +5134,8 @@ "optional": true, "os": [ "openharmony" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.59.0", @@ -5106,7 +5148,8 @@ "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-ia32-msvc": { "version": "4.59.0", @@ -5119,7 +5162,8 @@ "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-x64-gnu": { "version": "4.59.0", @@ -5132,7 +5176,8 @@ "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.59.0", @@ -5145,7 +5190,8 @@ "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@rtsao/scc": { "version": "1.1.0", @@ -13934,6 +13980,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -13954,6 +14001,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -13974,6 +14022,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -13994,6 +14043,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14014,6 +14064,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14034,6 +14085,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14054,6 +14106,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14074,6 +14127,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14094,6 +14148,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14114,6 +14169,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -14134,6 +14190,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -16408,27 +16465,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/openai": { - "version": "6.27.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-6.27.0.tgz", - "integrity": "sha512-osTKySlrdYrLYTt0zjhY8yp0JUBmWDCN+Q+QxsV4xMQnnoVFpylgKGgxwN8sSdTNw0G4y+WUXs4eCMWpyDNWZQ==", - "license": "Apache-2.0", - "bin": { - "openai": "bin/cli" - }, - "peerDependencies": { - "ws": "^8.18.0", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "ws": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -19405,6 +19441,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19421,6 +19458,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19437,6 +19475,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19453,6 +19492,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19469,6 +19509,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19485,6 +19526,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19501,6 +19543,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19517,6 +19560,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19533,6 +19577,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19549,6 +19594,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19565,6 +19611,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19581,6 +19628,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19597,6 +19645,7 @@ "cpu": [ "mips64el" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19613,6 +19662,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19629,6 +19679,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19645,6 +19696,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19661,6 +19713,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19677,6 +19730,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19693,6 +19747,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19709,6 +19764,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19725,6 +19781,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19741,6 +19798,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19757,6 +19815,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19773,6 +19832,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19789,6 +19849,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -20347,6 +20408,7 @@ "os": [ "aix" ], + "peer": true, "engines": { "node": ">=18" } @@ -20363,6 +20425,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -20379,6 +20442,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -20395,6 +20459,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -20411,6 +20476,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -20427,6 +20493,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -20443,6 +20510,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -20459,6 +20527,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -20475,6 +20544,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -20491,6 +20561,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -20507,6 +20578,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -20523,6 +20595,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -20539,6 +20612,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -20555,6 +20629,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -20571,6 +20646,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -20587,6 +20663,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -20603,6 +20680,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -20619,6 +20697,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -20635,6 +20714,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -20651,6 +20731,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -20667,6 +20748,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -20683,6 +20765,7 @@ "os": [ "sunos" ], + "peer": true, "engines": { "node": ">=18" } @@ -20699,6 +20782,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -20715,6 +20799,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -20731,6 +20816,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } diff --git a/package.json b/package.json index bc1bcc0..af5b2dc 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ "js-yaml": "^4.1.1", "mocha": "^11.7.4", "next": "^15.5.11", - "openai": "^6.27.0", "pg": "^8.16.3", "prismjs": "^1.30.0", "react": "^19", From f7185cd3e6460f0331c9e6f75cd54679461c6a1c Mon Sep 17 00:00:00 2001 From: na-trium-144 <100704180+na-trium-144@users.noreply.github.com> Date: Sat, 14 Mar 2026 00:50:54 +0900 Subject: [PATCH 7/7] update readme --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 45763f8..eeb1aa7 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ npx prisma dev ルートディレクトリに .env または .env.local という名前のファイルを作成し、以下の内容を記述 ```dotenv API_KEY=GeminiAPIキー +OPENROUTER_API_KEY=OpenRouterAPIキー +OPENROUTER_MODEL=foo;bar BETTER_AUTH_URL=http://localhost:3000 DATABASE_URL="postgres://... (prisma devの出力)" GOOGLE_CLIENT_ID= @@ -26,7 +28,9 @@ GITHUB_CLIENT_ID= GITHUB_CLIENT_SECRET= ``` -* `API_KEY` はGeminiのAPIキーを作成して設定します。未設定の場合チャットが使えません +* チャット用にGeminiのAPIキーまたはOpenRouterのAPIキーのいずれかが必要です。未設定の場合チャットが使えません + * OpenRouterを使う場合は使用するモデルをセミコロン区切りで `OPENROUTER_MODEL` に設定してください (エラー時に2番目以降にフォールバックします) + * 両方設定されている場合はOpenRouterが使われます * `GITHUB_CLIENT_ID` `GITHUB_CLIENT_SECRET` はGitHub OAuthのクライアントIDとシークレットを設定します。未設定の場合「GitHubでログイン」が使えません。 作り方については https://www.better-auth.com/docs/authentication/github を参照 * `GOOGLE_CLIENT_ID` `GOOGLE_CLIENT_SECRET` はGoogle OAuthのクライアントIDとシークレットを設定します。未設定の場合「Googleでログイン」が使えません。