import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { getToken } from './token'; interface CopilotConfig { copilot_tokens?: Record; } /** * Read the GitHub Copilot OAuth token from the CLI config file. * Stored at ~/.copilot/config.json under copilot_tokens["{host}:{login}"]. * Returns the first available token, or null if unavailable. */ function readCopilotToken(): string | null { try { const raw = fs.readFileSync( path.join(os.homedir(), '.copilot', 'config.json'), 'utf-8', ); const cfg = JSON.parse(raw) as CopilotConfig; const vals = Object.values(cfg.copilot_tokens ?? {}); return vals[0] ?? null; } catch { return null; } } /** * Embed a single text string using the best available credentials. * * Priority: * 1. GitHub Copilot CLI token → OpenAI-compatible embeddings endpoint at * https://api.githubcopilot.com * 2. Stored OpenAI token → standard OpenAI embeddings API * * Throws if no credentials are available or the API call fails. * Callers must .catch() this and handle the error without rejecting * the surrounding tRPC mutation. */ export async function embedText(text: string): Promise { const { OpenAIEmbeddings } = await import('@langchain/openai'); const copilotToken = readCopilotToken(); let embeddingsInstance; if (copilotToken) { embeddingsInstance = new OpenAIEmbeddings({ apiKey: copilotToken, model: 'text-embedding-3-small', configuration: { baseURL: 'https://api.githubcopilot.com' }, }); } else { const openaiToken = await getToken('openai'); if (!openaiToken) { throw new Error( '[Embeddings] No credentials available. Authenticate with Copilot CLI or add an OpenAI token in Settings.', ); } embeddingsInstance = new OpenAIEmbeddings({ apiKey: openaiToken, model: 'text-embedding-3-small', }); } // embedDocuments returns number[][] — cast explicitly to satisfy strict TS const results = (await embeddingsInstance.embedDocuments([text])) as number[][]; const vector = results[0] as number[] | undefined; if (!vector || vector.length === 0) { throw new Error('[Embeddings] Empty vector returned from embedding API'); } return vector; }