mirror of
https://github.com/larsbaunwall/vscode-copilot-bridge.git
synced 2025-10-05 22:22:59 +00:00
Copilot access auto-reacquire: per-request getAccess(), healthz best-effort under verbose, live status/log updates
Co-Authored-By: Lars Baunwall <larslb@thinkability.dk>
This commit is contained in:
parent
71bf0e1422
commit
862eab2a4a
2 changed files with 42 additions and 0 deletions
|
|
@ -25,6 +25,11 @@ Prerequisites:
|
||||||
- Node.js 18+ (recommended)
|
- Node.js 18+ (recommended)
|
||||||
- npm
|
- npm
|
||||||
|
|
||||||
|
- Auto-recovery: the bridge re-requests Copilot access on each chat request if missing; no restart required after signing in. `/healthz` will best-effort recheck only when `bridge.verbose` is true.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Steps:
|
Steps:
|
||||||
1) Install deps and compile:
|
1) Install deps and compile:
|
||||||
npm install
|
npm install
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,11 @@ async function startBridge() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.method === 'GET' && req.url === '/healthz') {
|
if (req.method === 'GET' && req.url === '/healthz') {
|
||||||
|
const cfgNow = vscode.workspace.getConfiguration('bridge');
|
||||||
|
const verboseNow = cfgNow.get<boolean>('verbose') ?? false;
|
||||||
|
if (!access && verboseNow) {
|
||||||
|
await getAccess();
|
||||||
|
}
|
||||||
writeJson(res, 200, { ok: true, copilot: access ? 'ok' : 'unavailable', version: vscode.version });
|
writeJson(res, 200, { ok: true, copilot: access ? 'ok' : 'unavailable', version: vscode.version });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -85,6 +90,14 @@ async function startBridge() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.method === 'POST' && req.url?.startsWith('/v1/chat/completions')) {
|
if (req.method === 'POST' && req.url?.startsWith('/v1/chat/completions')) {
|
||||||
|
if (!access) {
|
||||||
|
if (verbose) output?.appendLine('Copilot access missing; attempting to acquire...');
|
||||||
|
await getAccess();
|
||||||
|
}
|
||||||
|
if (!access) {
|
||||||
|
if (verbose) output?.appendLine('Copilot access missing; attempting to acquire...');
|
||||||
|
await getAccess();
|
||||||
|
}
|
||||||
if (!access) {
|
if (!access) {
|
||||||
writeJson(res, 503, { error: { message: 'Copilot unavailable', type: 'server_error', code: 'copilot_unavailable' } });
|
writeJson(res, 503, { error: { message: 'Copilot unavailable', type: 'server_error', code: 'copilot_unavailable' } });
|
||||||
return;
|
return;
|
||||||
|
|
@ -106,6 +119,7 @@ async function startBridge() {
|
||||||
const prompt = normalizeMessages(messages, hist);
|
const prompt = normalizeMessages(messages, hist);
|
||||||
const streamMode = body?.stream !== false;
|
const streamMode = body?.stream !== false;
|
||||||
|
|
||||||
|
if (verbose) output?.appendLine('Starting Copilot chat session...');
|
||||||
const session = await access.startSession();
|
const session = await access.startSession();
|
||||||
const chatStream = await session.sendRequest({ prompt, attachments: [] });
|
const chatStream = await session.sendRequest({ prompt, attachments: [] });
|
||||||
|
|
||||||
|
|
@ -162,6 +176,7 @@ async function startBridge() {
|
||||||
res.writeHead(404).end();
|
res.writeHead(404).end();
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
output?.appendLine(`Error: ${e?.stack || e?.message || String(e)}`);
|
output?.appendLine(`Error: ${e?.stack || e?.message || String(e)}`);
|
||||||
|
access = undefined;
|
||||||
writeJson(res, 500, { error: { message: e?.message ?? 'internal_error', type: 'server_error', code: 'internal_error' } });
|
writeJson(res, 500, { error: { message: e?.message ?? 'internal_error', type: 'server_error', code: 'internal_error' } });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -216,6 +231,28 @@ function normalizeMessages(messages: any[], histWindow: number): string {
|
||||||
const sysPart = sys ? `[SYSTEM]\n${toText(sys.content)}\n\n` : '';
|
const sysPart = sys ? `[SYSTEM]\n${toText(sys.content)}\n\n` : '';
|
||||||
return `${sysPart}[DIALOG]\n${dialog}`;
|
return `${sysPart}[DIALOG]\n${dialog}`;
|
||||||
}
|
}
|
||||||
|
async function getAccess(force = false): Promise<vscode.ChatAccess | undefined> {
|
||||||
|
if (!force && access) return access;
|
||||||
|
const cfg = vscode.workspace.getConfiguration('bridge');
|
||||||
|
const verbose = cfg.get<boolean>('verbose') ?? false;
|
||||||
|
try {
|
||||||
|
const newAccess = await vscode.chat.requestChatAccess('copilot');
|
||||||
|
access = newAccess;
|
||||||
|
const info = server ? server.address() : undefined;
|
||||||
|
const bound = info && typeof info === 'object' ? `${info.address}:${info.port}` : '';
|
||||||
|
statusItem && (statusItem.text = `Copilot Bridge: OK ${bound ? `@ ${bound}` : ''}`);
|
||||||
|
if (verbose) output?.appendLine('Copilot access acquired.');
|
||||||
|
return access;
|
||||||
|
} catch (e: any) {
|
||||||
|
access = undefined;
|
||||||
|
const info = server ? server.address() : undefined;
|
||||||
|
const bound = info && typeof info === 'object' ? `${info.address}:${info.port}` : '';
|
||||||
|
statusItem && (statusItem.text = `Copilot Bridge: Unavailable ${bound ? `@ ${bound}` : ''}`);
|
||||||
|
if (verbose) output?.appendLine(`Copilot access request failed: ${e?.message || String(e)}`);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function readJson(req: http.IncomingMessage): Promise<any> {
|
function readJson(req: http.IncomingMessage): Promise<any> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue