UNPKG

copilot-proxy-api

Version:

Self-hosted GitHub Copilot bridge for Claude Code and Codex CLI with OpenAI Responses, Anthropic Messages, streaming resilience, and context management.

33 lines 58.3 kB
#!/usr/bin/env node
import{n as e,t}from"./error-wiGHep5P.mjs";import{defineCommand as n,runMain as r}from"citty";import i from"consola";import a from"node:fs/promises";import o from"node:os";import s from"node:path";import{createHash as c,randomUUID as l}from"node:crypto";import u from"clipboardy";import{serve as ee}from"srvx";import te from"tiny-invariant";import{getProxyForUrl as ne}from"proxy-from-env";import{Agent as re,ProxyAgent as ie,setGlobalDispatcher as ae}from"undici";import{execSync as oe}from"node:child_process";import se from"node:process";import{Hono as d}from"hono";import{cors as ce}from"hono/cors";import{logger as le}from"hono/logger";import{streamSSE as f}from"hono/streaming";import{events as ue}from"fetch-event-stream";const de=s.join(o.homedir(),`.local`,`share`,`copilot-proxy-api`),p={APP_DIR:de,GITHUB_TOKEN_PATH:s.join(de,`github_token`)};async function m(){await a.mkdir(p.APP_DIR,{recursive:!0}),await fe(p.GITHUB_TOKEN_PATH)}async function fe(e){try{await a.access(e,a.constants.W_OK)}catch{await a.writeFile(e,``),await a.chmod(e,384)}}const h={accountType:`individual`,manualApprove:!1,rateLimitWait:!1,showToken:!1,localApiKeys:[]},g=()=>({"content-type":`application/json`,accept:`application/json`}),pe=`0.53.0`,me=`copilot-chat/${pe}`,he=`GitHubCopilotChat/${pe}`,ge=`2025-04-01`,_=e=>e.accountType===`individual`?`https://api.githubcopilot.com`:`https://api.${e.accountType}.githubcopilot.com`,v=(e,t=!1)=>{let n={Authorization:`Bearer ${e.copilotToken}`,"content-type":g()[`content-type`],"copilot-integration-id":`vscode-chat`,"editor-version":`vscode/${e.vsCodeVersion}`,"editor-plugin-version":me,"user-agent":he,"openai-intent":`conversation-panel`,"x-github-api-version":ge,"x-request-id":l(),"x-vscode-user-agent-library-version":`electron-fetch`};return t&&(n[`copilot-vision-request`]=`true`),n},y=`https://api.github.com`,_e=e=>({...g(),authorization:`token ${e.githubToken}`,"editor-version":`vscode/${e.vsCodeVersion}`,"editor-plugin-version":me,"user-agent":he,"x-github-api-version":ge,"x-vscode-user-agent-library-version":`electron-fetch`}),ve=`https://github.com`,ye=`Iv1.b507a08c87ecfe98`,be=[`read:user`].join(` `),xe=async()=>{let e=await fetch(`${y}/copilot_internal/v2/token`,{headers:_e(h)});if(!e.ok)throw new t(`Failed to get Copilot token`,e);return await e.json()};async function Se(){let e=await fetch(`${ve}/login/device/code`,{method:`POST`,headers:g(),body:JSON.stringify({client_id:ye,scope:be})});if(!e.ok)throw new t(`Failed to get device code`,e);return await e.json()}async function Ce(){let e=await fetch(`${y}/user`,{headers:{authorization:`token ${h.githubToken}`,...g()}});if(!e.ok)throw new t(`Failed to get GitHub user`,e);return await e.json()}const we=async()=>{let e=await fetch(`${_(h)}/models`,{headers:v(h)});if(!e.ok)throw new t(`Failed to get models`,e);return await e.json()},Te=`1.128.0`;async function Ee(){let e=new AbortController,t=setTimeout(()=>{e.abort()},5e3);try{let t=(await(await fetch(`https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=visual-studio-code-bin`,{signal:e.signal})).text()).match(/pkgver=([0-9.]+)/);return t?t[1]:Te}catch{return Te}finally{clearTimeout(t)}}await Ee();const b=e=>new Promise(t=>{setTimeout(t,e)}),De=e=>e==null;async function Oe(){h.models=await we()}const ke=async()=>{let e=await Ee();h.vsCodeVersion=e,i.info(`Using VSCode version: ${e}`)};async function Ae(e){let t=(e.interval+1)*1e3;for(i.debug(`Polling access token with interval of ${t}ms`);;){let n=await fetch(`${ve}/login/oauth/access_token`,{method:`POST`,headers:g(),body:JSON.stringify({client_id:ye,device_code:e.device_code,grant_type:`urn:ietf:params:oauth:grant-type:device_code`})});if(!n.ok){await b(t),i.error(`Failed to poll access token:`,await n.text());continue}let r=await n.json();i.debug(`Polling access token response:`,r);let{access_token:a}=r;if(a)return a;await b(t)}}const je=()=>a.readFile(p.GITHUB_TOKEN_PATH,`utf8`),Me=e=>a.writeFile(p.GITHUB_TOKEN_PATH,e);let x;function S(e){return e&&h.copilotToken&&h.copilotToken!==e?Promise.resolve(h.copilotToken):(x??=xe().then(({token:e})=>(h.copilotToken=e,i.debug(`Copilot token refreshed`),h.showToken&&i.info(`Refreshed Copilot token:`,e),e)).finally(()=>{x=void 0}),x)}const Ne=async()=>{let{token:e,refresh_in:t}=await xe();h.copilotToken=e,i.debug(`GitHub Copilot Token fetched successfully!`),h.showToken&&i.info(`Copilot token:`,e);let n=(t-60)*1e3,r=async(e=5,t=1e3)=>{for(let n=1;n<=e;n++)try{await S();return}catch(r){if(i.error(`Failed to refresh Copilot token (attempt ${n}/${e}):`,r),n<e){let e=t*2**(n-1);i.info(`Retrying in ${e/1e3} seconds...`),await new Promise(t=>setTimeout(t,e))}else i.error(`Max retries reached. Token refresh failed, but keeping server alive.`)}};setInterval(()=>{i.debug(`Refreshing Copilot token`),r()},n)};async function C(e){try{let t=await je();if(t&&!e?.force){h.githubToken=t,h.showToken&&i.info(`GitHub token:`,t),await w();return}i.info(`Not logged in, getting new access token`);let n=await Se();i.debug(`Device code response:`,n),i.info(`Please enter the code "${n.user_code}" in ${n.verification_uri}`);let r=await Ae(n);await Me(r),h.githubToken=r,h.showToken&&i.info(`GitHub token:`,r),await w()}catch(e){throw e instanceof t?(i.error(`Failed to get GitHub token:`,await e.response.json()),e):(i.error(`Failed to get GitHub token:`,e),e)}}async function w(){let e=await Ce();i.info(`Logged in as ${e.login}`)}async function Pe(e){e.verbose&&(i.level=5,i.info(`Verbose logging enabled`)),h.showToken=e.showToken,await m(),await C({force:!0}),i.success(`GitHub token written to`,p.GITHUB_TOKEN_PATH)}const Fe=n({meta:{name:`auth`,description:`Run GitHub auth flow without running the server`},args:{verbose:{alias:`v`,type:`boolean`,default:!1,description:`Enable verbose logging`},"show-token":{type:`boolean`,default:!1,description:`Show GitHub token on auth`}},run({args:e}){return Pe({verbose:e.verbose,showToken:e[`show-token`]})}}),Ie=async()=>{let e=await fetch(`${y}/copilot_internal/user`,{headers:_e(h)});if(!e.ok)throw new t(`Failed to get Copilot usage`,e);return await e.json()},Le=n({meta:{name:`check-usage`,description:`Show current GitHub Copilot usage/quota information`},async run(){await m(),await C();try{let e=await Ie(),t=e.quota_snapshots.premium_interactions,n=t.entitlement,r=n-t.remaining,a=n>0?r/n*100:0,o=t.percent_remaining;function s(e,t){if(!t)return`${e}: N/A`;let n=t.entitlement,r=n-t.remaining,i=n>0?r/n*100:0,a=t.percent_remaining;return`${e}: ${r}/${n} used (${i.toFixed(1)}% used, ${a.toFixed(1)}% remaining)`}let c=`Premium: ${r}/${n} used (${a.toFixed(1)}% used, ${o.toFixed(1)}% remaining)`,l=s(`Chat`,e.quota_snapshots.chat),u=s(`Completions`,e.quota_snapshots.completions);i.box(`Copilot Usage (plan: ${e.copilot_plan})\nQuota resets: ${e.quota_reset_date}\n\nQuotas:\n  ${c}\n  ${l}\n  ${u}`)}catch(e){i.error(`Failed to fetch Copilot usage:`,e),process.exit(1)}}});async function Re(){try{let e=new URL(`../package.json`,import.meta.url).pathname;return JSON.parse(await a.readFile(e)).version}catch{return`unknown`}}function ze(){let e=typeof Bun<`u`;return{name:e?`bun`:`node`,version:e?Bun.version:process.version.slice(1),platform:o.platform(),arch:o.arch()}}async function Be(){try{return(await a.stat(p.GITHUB_TOKEN_PATH)).isFile()?(await a.readFile(p.GITHUB_TOKEN_PATH,`utf8`)).trim().length>0:!1}catch{return!1}}async function Ve(){let[e,t]=await Promise.all([Re(),Be()]);return{version:e,runtime:ze(),paths:{APP_DIR:p.APP_DIR,GITHUB_TOKEN_PATH:p.GITHUB_TOKEN_PATH},tokenExists:t}}function He(e){i.info(`copilot-proxy-api debug

Version: ${e.version}
Runtime: ${e.runtime.name} ${e.runtime.version} (${e.runtime.platform} ${e.runtime.arch})

Paths:
- APP_DIR: ${e.paths.APP_DIR}
- GITHUB_TOKEN_PATH: ${e.paths.GITHUB_TOKEN_PATH}

Token exists: ${e.tokenExists?`Yes`:`No`}`)}function Ue(e){console.log(JSON.stringify(e,null,2))}async function We(e){let t=await Ve();e.json?Ue(t):He(t)}const Ge=n({meta:{name:`debug`,description:`Print debug information about the application`},args:{json:{type:`boolean`,default:!1,description:`Output debug information as JSON`}},run({args:e}){return We({json:e.json})}});function Ke(e){return e?e.split(`,`).map(e=>e.trim()).filter(e=>e.length>0):[]}const qe=async(e,t)=>{if(h.localApiKeys.length===0||e.req.method===`OPTIONS`){await t();return}let n=Je(e.req.header(`authorization`)),r=e.req.header(`x-api-key`)?.trim();if(n&&h.localApiKeys.includes(n)||r&&h.localApiKeys.includes(r)){await t();return}return e.json({error:{message:`Missing or invalid API key`,type:`authentication_error`}},401)};function Je(e){if(!e||!e.toLowerCase().startsWith(`bearer `))return;let t=e.slice(7).trim();return t.length>0?t:void 0}function Ye(){if(!(typeof Bun<`u`))try{let e=new re,t=new Map;ae({dispatch(n,r){try{let a=typeof n.origin==`string`?new URL(n.origin):n.origin,o=ne(a.toString()),s=o&&o.length>0?o:void 0;if(!s)return i.debug(`HTTP proxy bypass: ${a.hostname}`),e.dispatch(n,r);let c=t.get(s);c||(c=new ie(s),t.set(s,c));let l=s;try{let e=new URL(s);l=`${e.protocol}//${e.host}`}catch{}return i.debug(`HTTP proxy route: ${a.hostname} via ${l}`),c.dispatch(n,r)}catch{return e.dispatch(n,r)}},close(){return e.close()},destroy(){return e.destroy()}}),i.debug(`HTTP proxy configured from environment (per-URL)`)}catch(e){i.debug(`Proxy setup skipped:`,e)}}function Xe(){let{platform:e,ppid:t,env:n}=se;if(e===`win32`){try{if(oe(`wmic process get ParentProcessId,Name | findstr "${t}"`,{stdio:`pipe`}).toString().toLowerCase().includes(`powershell.exe`))return`powershell`}catch{return`cmd`}return`cmd`}else{let e=n.SHELL;if(e){if(e.endsWith(`zsh`))return`zsh`;if(e.endsWith(`fish`))return`fish`;if(e.endsWith(`bash`))return`bash`}return`sh`}}function Ze(e,t=``){let n=Xe(),r=Object.entries(e).filter(([,e])=>e!==void 0),i;switch(n){case`powershell`:i=r.map(([e,t])=>`$env:${e} = ${t}`).join(`; `);break;case`cmd`:i=r.map(([e,t])=>`set ${e}=${t}`).join(` & `);break;case`fish`:i=r.map(([e,t])=>`set -gx ${e} ${t}`).join(`; `);break;default:{let e=r.map(([e,t])=>`${e}=${t}`).join(` `);i=r.length>0?`export ${e}`:``;break}}return i&&t?`${i}${n===`cmd`?` & `:` && `}${t}`:i||t}const T=[];function Qe(){return`req_${l().replaceAll(`-`,``)}`}function $e(e){return e instanceof Error?e.message:`Unknown error`}function et(e){T.unshift(e),T.length>100&&(T.length=100)}function tt(){return[...T]}const nt=async(e,t)=>{let n=Date.now(),r=new Date(n).toISOString(),i=e.req.header(`x-client-request-id`)??e.req.header(`x-request-id`)??Qe();e.header(`request-id`,i),e.header(`x-request-id`,i);let a;try{await t()}catch(e){throw a=$e(e),e}finally{let t=e.res.headers.get(`x-request-id`)??e.res.headers.get(`request-id`)??i,o=a?500:e.res.status;et({id:t,method:e.req.method,path:e.req.path,status:o,ok:!a&&o<400,durationMs:Date.now()-n,startedAt:r,error:a})}},E=async()=>{if(!await i.prompt(`Accept incoming request?`,{type:`confirm`}))throw new t(`Request rejected`,Response.json({message:`Request rejected`},{status:403}))};async function D(e){if(e.rateLimitSeconds===void 0)return;let n=Date.now();if(!e.lastRequestTimestamp){e.lastRequestTimestamp=n;return}let r=(n-e.lastRequestTimestamp)/1e3;if(r>e.rateLimitSeconds){e.lastRequestTimestamp=n;return}let a=Math.ceil(e.rateLimitSeconds-r);if(!e.rateLimitWait)throw i.warn(`Rate limit exceeded. Need to wait ${a} more seconds.`),new t(`Rate limit exceeded`,Response.json({message:`Rate limit exceeded`},{status:429}));let o=a*1e3;i.warn(`Rate limit reached. Waiting ${a} seconds before proceeding...`),await b(o),e.lastRequestTimestamp=n,i.info(`Rate limit wait completed, proceeding with request`)}const O={o200k_base:()=>import(`gpt-tokenizer/encoding/o200k_base`),cl100k_base:()=>import(`gpt-tokenizer/encoding/cl100k_base`),p50k_base:()=>import(`gpt-tokenizer/encoding/p50k_base`),p50k_edit:()=>import(`gpt-tokenizer/encoding/p50k_edit`),r50k_base:()=>import(`gpt-tokenizer/encoding/r50k_base`)},k=new Map,rt=(e,t,n)=>{let r=0;for(let i of e)r+=n.funcInit,r+=t.encode(JSON.stringify(i)).length;return r+=n.funcEnd,r},it=(e,t)=>{let n=0;for(let r of e)r.type===`image_url`?n+=t.encode(r.image_url.url).length+85:r.text&&(n+=t.encode(r.text).length);return n},at=(e,t,n)=>{let r=3;for(let[i,a]of Object.entries(e))typeof a==`string`&&(r+=t.encode(a).length),i===`name`&&(r+=1),i===`tool_calls`&&(r+=rt(a,t,n)),i===`content`&&Array.isArray(a)&&(r+=it(a,t));return r},ot=(e,t,n)=>{if(e.length===0)return 0;let r=0;for(let i of e)r+=at(i,t,n);return r+=3,r},st=async e=>{if(k.has(e)){let t=k.get(e);if(t)return t}let t=e;if(!(t in O)){let t=await O.o200k_base();return k.set(e,t),t}let n=await O[t]();return k.set(e,n),n},ct=e=>e.capabilities.tokenizer||`o200k_base`,lt=e=>e.id===`gpt-3.5-turbo`||e.id===`gpt-4`?{funcInit:10,propInit:3,propKey:3,enumInit:-3,enumItem:3,funcEnd:12}:{funcInit:7,propInit:3,propKey:3,enumInit:-3,enumItem:3,funcEnd:12},ut=(e,t,n)=>{let{encoder:r,constants:i}=n,a=i.propKey;if(typeof t!=`object`||!t)return a;let o=t,s=e,c=o.type||`string`,l=o.description||``;if(o.enum&&Array.isArray(o.enum)){a+=i.enumInit;for(let e of o.enum)a+=i.enumItem,a+=r.encode(String(e)).length}l.endsWith(`.`)&&(l=l.slice(0,-1));let u=`${s}:${c}:${l}`;a+=r.encode(u).length;let ee=new Set([`type`,`description`,`enum`]);for(let e of Object.keys(o))if(!ee.has(e)){let t=o[e],n=typeof t==`string`?t:JSON.stringify(t);a+=r.encode(`${e}:${n}`).length}return a},dt=(e,t,n)=>{if(!e||typeof e!=`object`)return 0;let r=e,i=0;for(let[e,a]of Object.entries(r))if(e===`properties`){let e=a;if(Object.keys(e).length>0){i+=n.propInit;for(let r of Object.keys(e))i+=ut(r,e[r],{encoder:t,constants:n})}}else{let n=typeof a==`string`?a:JSON.stringify(a);i+=t.encode(`${e}:${n}`).length}return i},ft=(e,t,n)=>{let r=n.funcInit,i=e.function,a=i.name,o=i.description||``;o.endsWith(`.`)&&(o=o.slice(0,-1));let s=a+`:`+o;return r+=t.encode(s).length,typeof i.parameters==`object`&&i.parameters!==null&&(r+=dt(i.parameters,t,n)),r},pt=(e,t,n)=>{let r=0;for(let i of e)r+=ft(i,t,n);return r+=n.funcEnd,r},mt=async(e,t)=>{let n=await st(ct(t)),r=e.messages,i=r.filter(e=>e.role!==`assistant`),a=r.filter(e=>e.role===`assistant`),o=lt(t),s=ot(i,n,o);e.tools&&e.tools.length>0&&(s+=pt(e.tools,n,o));let c=ot(a,n,o);return{input:s,output:c}},ht=2e6;async function A(e,t){let{attempts:n=3,retryDelayMs:r=250,...a}=t,o=typeof a.body==`string`?a.body.length:0,s=yt(e,a.method),c=!0,l;for(let t=1;t<=n;t++){try{let r=await fetch(e,a);if(c&&gt(r)&&(c=!1,r=await _t(e,a,r)),!xt(r,o)||t===n)return r;i.warn(`Copilot ${s} returned ${r.status}; retrying (${t}/${n})`)}catch(e){if(l=e,t===n||St(e,o))throw e;i.warn(`Copilot ${s} failed (${bt(e)}); retrying (${t}/${n})`)}await b(r*t)}throw l instanceof Error?l:Error(`Copilot request failed`)}function gt(e){return e.status===401||e.status===403}async function _t(e,t,n){let r=vt(t.headers),a=yt(e,t.method);try{let o=await S(r),s=new Headers(t.headers);return s.set(`Authorization`,`Bearer ${o}`),t.headers=s,i.warn(`Copilot ${a} returned ${n.status}; refreshed token and retrying`),await fetch(e,t)}catch(e){return i.warn(`Copilot token refresh failed after ${a} returned ${n.status}: ${bt(e)}`),n}}function vt(e){let t=new Headers(e).get(`Authorization`);if(t?.toLowerCase().startsWith(`bearer `))return t.slice(7)}function yt(e,t){let n=t?.toUpperCase()??`GET`;try{return`${n} ${new URL(e).pathname}`}catch{return`${n} ${e}`}}function bt(e){return e instanceof Error&&e.message?e.message:`unknown error`}function xt(e,t){return e.status>=500&&t>ht?!1:e.status===408||e.status===409||e.status===425||e.status===429||e.status===499||e.status===500||e.status===502||e.status===503||e.status===504}function St(e,t){return t>ht&&e instanceof Error&&/operation timed out|timed out/i.test(e.message)}function Ct(e,t){return j(e,t)??2e5}function j(e,t){return t?.max_prompt_tokens?t.max_prompt_tokens:wt(e)?936e3:t?.max_context_window_tokens}function wt(e){return/(?:^|[-_.])1m(?:$|[-_.])/i.test(e)}function M(e,n){let r=Math.ceil(n/4),a=h.models?.data.find(t=>t.id===e.model)?.capabilities.limits,o=Ct(e.model,a),s=e.max_tokens??0;return i.warn(`Context overflow -> returning 400 prompt-too-long (~${r} + ${s} > ${o}) to trigger Claude Code reactive compaction`),new t(`Prompt too long`,new Response(JSON.stringify({type:`error`,error:{type:`invalid_request_error`,message:`prompt is too long: input length and \`max_tokens\` exceed context limit: ${r} + ${s} > ${o} tokens`}}),{status:400,statusText:`Bad Request`,headers:{"content-type":`application/json`}}))}const N=async e=>{if(!h.copilotToken)throw Error(`Copilot token not found`);let n=e.messages.some(e=>typeof e.content!=`string`&&e.content?.some(e=>e.type===`image_url`)),r=e.messages.some(e=>[`assistant`,`tool`].includes(e.role)),a={...v(h,n),"X-Initiator":r?`agent`:`user`},o=JSON.stringify(e);i.info(`Sending payload: ${o.length} bytes, ${e.messages.length} messages, model: ${e.model}`);let s;try{s=await A(`${_(h)}/chat/completions`,{method:`POST`,headers:a,body:o})}catch(t){throw St(t,o.length)?M(e,o.length):t}if(!s.ok){let n=await s.text();throw i.error(`Failed to create chat completions - Status: ${s.status} ${s.statusText}`),i.error(`Response body: ${n}`),i.error(`Request payload size: ${o.length} bytes`),s.status===413||/request entity too large/i.test(n)||/exceeds the limit of \d+/i.test(n)||/context_length_exceeded/i.test(n)||/operation timed out/i.test(n)||/payload too large/i.test(n)||/maximum context length/i.test(n)||s.status>=500&&s.status<600&&o.length>2e6?M(e,o.length):new t(`Failed to create chat completions`,new Response(n,{status:s.status,statusText:s.statusText,headers:s.headers}))}return e.stream?ue(s):await s.json()};async function Tt(e){await D(h);let t=await e.req.json();i.debug(`Request payload:`,JSON.stringify(t).slice(-400));let n=h.models?.data.find(e=>e.id===t.model);try{if(n){let e=await mt(t,n);i.info(`Current token count:`,e)}else i.warn(`No model selected, skipping token count calculation`)}catch(e){i.warn(`Failed to calculate token count:`,e)}h.manualApprove&&await E(),De(t.max_tokens)&&(t={...t,max_tokens:n?.capabilities.limits.max_output_tokens},i.debug(`Set max_tokens to:`,JSON.stringify(t.max_tokens)));let r=await N(t);return Et(r)?(i.debug(`Non-streaming response:`,JSON.stringify(r)),e.json(r)):(i.debug(`Streaming response`),f(e,async e=>{try{for await(let t of r)i.debug(`Streaming chunk:`,JSON.stringify(t)),await e.writeSSE(t)}catch(t){i.error(`Streaming error:`,t),await e.writeSSE({data:JSON.stringify({error:{message:t instanceof Error?t.message:`Stream interrupted`,type:`server_error`}})})}}))}const Et=e=>Object.hasOwn(e,`choices`),P=new d;P.post(`/`,async t=>{try{return await Tt(t)}catch(n){return await e(t,n)}});const Dt=new d;Dt.get(`/requests`,e=>e.json({object:`list`,data:tt()}));const Ot=async e=>{if(!h.copilotToken)throw Error(`Copilot token not found`);let n=await A(`${_(h)}/embeddings`,{method:`POST`,headers:v(h),body:JSON.stringify(e)});if(!n.ok)throw new t(`Failed to create embeddings`,n);return await n.json()},F=new d;F.post(`/`,async t=>{try{let e=await Ot(await t.req.json());return t.json(e)}catch(n){return await e(t,n)}});function kt(e){return e===null?null:{stop:`end_turn`,length:`max_tokens`,tool_calls:`tool_use`,content_filter:`refusal`}[e]}function At(e){let t=Mt(Ut(e.messages,e.system)),n=Ht(e.model);return{model:n,messages:t,max_tokens:e.max_tokens,stop:e.stop_sequences,stream:e.stream,temperature:e.temperature,top_p:e.top_p,user:e.metadata?.user_id,tools:Yt(e.tools),tool_choice:Zt(e.tool_choice),thinking:Xt(e.thinking),reasoning_effort:jt(n,e.output_config?.effort)}}function jt(e,t){if(!t)return;let n=h.models?.data.find(t=>t.id===e);if(!n)return t;let r=n.capabilities.supports.reasoning_effort;if(r?.length)return r.includes(t)?t:void 0}function Mt(e){let t=e.length;for(;t>0&&e[t-1].role===`assistant`;)t--;return t===e.length?e:(i.warn(`Stripped ${e.length-t} trailing assistant prefill message(s) unsupported by Copilot chat completions`),e.slice(0,t))}async function Nt(e){if(!e.messages.some(e=>Array.isArray(e.content)&&e.content.some(e=>e.type===`document`)))return e;let t=[];for(let n of e.messages){if(n.role!==`user`||!Array.isArray(n.content)){t.push(n);continue}let e=[];for(let t of n.content)t.type===`document`?e.push(...await Pt(t)):e.push(t);t.push({role:`user`,content:e})}return{...e,messages:t}}async function Pt(e){if(e.source.type===`text`)return[{type:`text`,text:I(e)+e.source.data}];if(e.source.type===`url`)return[{type:`text`,text:I(e)+`[document at ${e.source.url} not inlined — proxy does not fetch external URLs]`}];let{extractPdfText:t}=await import(`./pdf-3rCh0vDg.mjs`),n=await t(e.source.data);return[{type:`text`,text:I(e)+`[Extracted text from PDF (${n.pageCount} page${n.pageCount===1?``:`s`}${n.truncated?`, truncated`:``}):]\n\n`+n.text}]}function I(e){let t=[];return e.title&&t.push(`Document: ${e.title}`),e.context&&t.push(`Context: ${e.context}`),t.length>0?t.join(`
`)+`

`:``}const L={haiku:`claude-haiku-4.5`,sonnet:`claude-sonnet-5`,opus:`claude-opus-5`},Ft=[`opus`,`sonnet`,`haiku`];function It(e){let t=e.toLowerCase();for(let e of Ft)if(t.includes(e))return e;return null}function R(e){let t=/(?:opus|sonnet|haiku)-(\d{1,2})(?:[.-](\d{1,2}))?(?:$|[-_.])/i.exec(e);return t?[Number(t[1]),t[2]?Number(t[2]):0]:[0,0]}function Lt(e,t){let n=h.models?.data.filter(n=>n.id.toLowerCase().includes(e)&&(t===void 0||R(n.id)[0]===t))??[];if(n.length===0)return null;let r=n[0],i=R(r.id),a=r.id.includes(`-1m`);for(let e of n.slice(1)){let t=R(e.id),n=e.id.includes(`-1m`),o=t[0]>i[0]||t[0]===i[0]&&t[1]>i[1],s=t[0]===i[0]&&t[1]===i[1]&&n&&!a;(o||s)&&(r=e,i=t,a=n)}return r.id}function Rt(e,t){let n=RegExp(`${t}-(\\d{1,2})(?:[.-](\\d{1,2}))?(?:$|[-@:.])`).exec(e.toLowerCase());return n?[Number(n[1]),n[2]?Number(n[2]):0]:null}function zt(e){let t=/^claude-(?:opus|sonnet|haiku)-(\d{1,2})(?:\.(\d{1,2})(?:-.+)?)?$/i.exec(e);return t?!!t[2]||Number(t[1])>=5:!1}function Bt(e,t,n){return t===`opus`&&n[0]===5&&n[1]===0?L.opus:t===`opus`&&n[0]===4?`claude-opus-4.8`:!h.models&&zt(e)?e:null}function Vt(e,t){let n=h.models?.data.filter(n=>{let r=R(n.id);return n.id.toLowerCase().includes(e)&&r[0]===t[0]&&r[1]===t[1]})??[];if(n.length===0)return null;let r=n[0],i=r.id.includes(`-1m`);for(let e of n.slice(1)){let t=e.id.includes(`-1m`);t&&!i&&(r=e,i=t)}return r.id}function Ht(e){let t=It(e);if(t){let e=process.env[`COPILOT_OVERRIDE_${t.toUpperCase()}`];if(e)return e}if(h.models?.data.some(t=>t.id===e))return e;if(L[e])return L[e];if(t){let n=Rt(e,t);if(n){let r=Vt(t,n);if(r)return r;let i=Lt(t,n[0]);if(i)return i;let a=Bt(e,t,n);if(a)return a}return Lt(t)||L[t]}return e}function Ut(e,t){let n=Kt(t),r=e.flatMap(e=>e.role===`user`?qt(e):Jt(e));return[...n,...r]}const Wt=[/x-anthropic-billing-header/gi,/anthropic-billing-header/gi,/x-anthropic-/gi];function Gt(e){let t=e;for(let e of Wt)t=t.replaceAll(e,``);return t}function Kt(e){return e?typeof e==`string`?[{role:`system`,content:Gt(e)}]:[{role:`system`,content:Gt(e.map(e=>e.text).join(`

`))}]:[]}function qt(e){let t=[];if(Array.isArray(e.content)){let n=e.content.filter(e=>e.type===`tool_result`),r=e.content.filter(e=>e.type!==`tool_result`);for(let e of n)t.push({role:`tool`,tool_call_id:e.tool_use_id,content:z(e.content)});r.length>0&&t.push({role:`user`,content:z(r)})}else t.push({role:`user`,content:z(e.content)});return t}function Jt(e){if(!Array.isArray(e.content))return[{role:`assistant`,content:z(e.content)}];let t=e.content.filter(e=>e.type===`tool_use`),n=e.content.filter(e=>e.type===`text`).map(e=>e.text).join(`

`);return t.length>0?[{role:`assistant`,content:n||null,tool_calls:t.map(e=>({id:e.id,type:`function`,function:{name:e.name,arguments:JSON.stringify(e.input)}}))}]:[{role:`assistant`,content:z(e.content)}]}function z(e){if(typeof e==`string`)return e;if(!Array.isArray(e))return null;if(!e.some(e=>e.type===`image`))return e.filter(e=>e.type===`text`).map(e=>e.text).join(`

`);let t=[];for(let n of e)switch(n.type){case`text`:t.push({type:`text`,text:n.text});break;case`image`:t.push({type:`image_url`,image_url:{url:`data:${n.source.media_type};base64,${n.source.data}`}});break}return t}function Yt(e){if(e)return e.map(e=>({type:`function`,function:{name:e.name,description:e.description,parameters:e.input_schema}}))}function Xt(e){if(e)return{type:`enabled`}}function Zt(e){if(e)switch(e.type){case`auto`:return`auto`;case`any`:return`required`;case`tool`:return e.name?{type:`function`,function:{name:e.name}}:void 0;case`none`:return`none`;default:return}}function Qt(e,t){let n=[],r=[],i=null;i=e.choices[0]?.finish_reason??i;for(let t of e.choices){let e=$t(t.message.content),a=en(t.message.tool_calls);n.push(...e),r.push(...a),(t.finish_reason===`tool_calls`||i===`stop`)&&(i=t.finish_reason)}return{id:e.id,type:`message`,role:`assistant`,model:t??e.model,content:[...n,...r],stop_reason:kt(i),stop_sequence:null,usage:{input_tokens:(e.usage?.prompt_tokens??0)-(e.usage?.prompt_tokens_details?.cached_tokens??0),output_tokens:e.usage?.completion_tokens??0,...e.usage?.prompt_tokens_details?.cached_tokens!==void 0&&{cache_read_input_tokens:e.usage.prompt_tokens_details.cached_tokens}}}}function $t(e){return typeof e==`string`?[{type:`text`,text:e}]:Array.isArray(e)?e.filter(e=>e.type===`text`).map(e=>({type:`text`,text:e.text})):[]}function en(e){return e?e.map(e=>{let t={};try{let n=JSON.parse(e.function.arguments);n&&typeof n==`object`&&!Array.isArray(n)&&(t=n)}catch{}return{type:`tool_use`,id:e.id,name:e.function.name,input:t}}):[]}async function tn(e){try{let t=e.req.header(`anthropic-beta`),n=await e.req.json(),r=At(n),a=h.models?.data.find(e=>e.id===r.model);if(!a)return i.warn(`Model not found, returning default token count`),e.json({type:`error`,error:{type:`not_found_error`,message:`Model '${r.model}' not found`}},404);let o=await mt(r,a);if(n.tools&&n.tools.length>0){let e=!1;t?.startsWith(`claude-code`)&&(e=n.tools.some(e=>e.name.startsWith(`mcp__`))),e||(n.model.startsWith(`claude`)?o.input+=346:n.model.startsWith(`grok`)&&(o.input+=480))}let s=o.input;return n.model.startsWith(`claude`)?s=Math.round(s*1.15):n.model.startsWith(`grok`)&&(s=Math.round(s*1.03)),i.info(`Token count:`,s),e.json({input_tokens:s})}catch(t){return i.error(`Error counting tokens:`,t),e.json({type:`error`,error:{type:`api_error`,message:t instanceof Error?t.message:`Failed to count tokens`}},500)}}const nn=5e6,rn=19e5,an=1e5,on=`[image removed to save context]`;function sn(e){let t=j(e.id,e.capabilities.limits);if(!t)return nn;let n=Math.floor((t-8e3)*3.5);return Math.min(nn,n)}function cn(e,t){return dn(e,sn(t))}function ln(e){return dn(e,rn)}function un(e){return V(e)>rn}function dn(e,t){let n=V(e);if(n<=t)return e;i.info(`Context fit: payload ${B(n)} exceeds ${B(t)} ceiling — reducing`);let r=fn(e),a=V(r);return a<=t?(i.info(`Context fit: ${B(n)} → ${B(a)} after tool pruning`),r):(r=pn(r),a=V(r),a<=t?(i.info(`Context fit: ${B(n)} → ${B(a)} after stripping old images`),r):(r=mn(r),a=V(r),a<=t?(i.warn(`Context fit: ${B(n)} → ${B(a)} after stripping ALL images`),r):(r=hn(r),a=V(r),a<=t?(i.warn(`Context fit: ${B(n)} → ${B(a)} after truncating oversized tool outputs`),r):(r=gn(r,t),a=V(r),i.warn(`Context fit: ${B(n)} → ${B(a)} after dropping old messages`),r))))}function B(e){return e<1024?`${e}B`:e<1024*1024?`${(e/1024).toFixed(1)}KB`:`${(e/1024/1024).toFixed(2)}MB`}function V(e){let t=200;for(let n of e.messages)t+=H(n);if(e.tools)for(let n of e.tools)t+=JSON.stringify(n).length+20;return t}function H(e){let t=40;if(typeof e.content==`string`)t+=e.content.length;else if(Array.isArray(e.content))for(let n of e.content)`text`in n&&typeof n.text==`string`?t+=n.text.length+20:`type`in n&&n.type===`image_url`&&(t+=n.image_url.url.length+40);if(e.tool_calls)for(let n of e.tool_calls)t+=n.function.name.length+n.function.arguments.length+80;return e.tool_call_id&&(t+=e.tool_call_id.length+20),t}function fn(e){let t=e.messages,n=0,r=0,a=[];for(let e=t.length-1;e>=0;e--){let i=t[e];if(i.role!==`tool`)continue;let o=H(i);n<2e5?n+=o:(r+=o,a.push(e))}if(r<5e4)return e;let o=[...t];for(let e of a)o[e]={...o[e],content:`[content pruned — tool output was too old]`};return i.info(`Pruned ${a.length} old tool outputs (~${r} bytes reclaimed)`),{...e,messages:o}}function pn(e){let t=e.messages,n=[...t],r=0,a=0,o=Math.max(0,t.length-4);for(let e=0;e<o;e++){let i=t[e];if(!Array.isArray(i.content))continue;let o=r,s=i.content.map(e=>`type`in e&&e.type===`image_url`?(r++,a+=e.image_url.url.length,{type:`text`,text:on}):e);r>o&&(n[e]={...i,content:s})}return r>0&&i.info(`Stripped ${r} base64 images (~${a} bytes reclaimed)`),{...e,messages:n}}function mn(e){let t=0,n=0,r=e.messages.map(e=>{if(!Array.isArray(e.content))return e;let r=t,i=e.content.map(e=>`type`in e&&e.type===`image_url`?(t++,n+=e.image_url.url.length,{type:`text`,text:on}):e);return t>r?{...e,content:i}:e});return t>0&&i.warn(`Stripped ${t} ALL images (~${n} bytes reclaimed)`),{...e,messages:r}}function hn(e){let t=0,n=0,r=e.messages.map(e=>{if(e.role!==`tool`||typeof e.content!=`string`||e.content.length<=an)return e;let r=e.content.length,i=e.content.slice(0,an)+`

[…tool output truncated to fit context]`;return t++,n+=r-i.length,{...e,content:i}});return t>0&&i.warn(`Truncated ${t} oversized tool outputs (~${n} bytes reclaimed)`),{...e,messages:r}}function gn(e,t){let n=e.messages.filter(e=>e.role===`system`||e.role===`developer`),r=e.messages.filter(e=>e.role!==`system`&&e.role!==`developer`),a=200;for(let e of n)a+=H(e);if(e.tools)for(let t of e.tools)a+=JSON.stringify(t).length+20;let o=r.map(e=>H(e)),s=a+o.reduce((e,t)=>e+t,0),c=0;for(;r.length>2&&s>t;){let e=o.shift()??0;r.shift(),s-=e,c++}let l=0;for(;r.length>2&&r[0].role===`tool`;){let e=o.shift()??0;r.shift(),s-=e,l++}return(c>0||l>0)&&i.warn(`Dropped ${c} oldest conversation messages + ${l} orphaned tool results (~${s} bytes remaining, limit ${t})`),s>t&&i.error(`Payload still over ${t}B after all reductions (${s}B). Forwarding anyway — Copilot will likely return 413 → 400 prompt-too-long for reactive compaction.`),{...e,messages:[...n,...r]}}const _n=`Encrypted function output content could not be decrypted or decoded.`,U=new Map;function vn(e,t,n){return An(`${e}\0${t}\0${n}`)}function yn(e,t){return e.status===400&&t.includes(_n)}async function bn(e){if(!e.body||!e.headers.get(`content-type`)?.includes(`text/event-stream`))return!1;let t=e.clone().body?.getReader();if(!t)return!1;try{return await wn(t)}catch(e){i.debug(`Failed to inspect Copilot Responses stream:`,e)}finally{t.cancel().catch(()=>void 0)}return!1}function xn(e,t){if(typeof e.input==`string`)return{count:0,fingerprints:[],payload:e};let n=0,r=[],i;for(let[a,o]of e.input.entries()){if(!Array.isArray(o.content)||!o.content.some(e=>(e.type===`input_text`||e.type===`output_text`)&&typeof e.text==`string`))continue;let s=o.content.filter(e=>{if(e.type!==`encrypted_content`||typeof e.encrypted_content!=`string`)return!0;let n=An(e.encrypted_content);return t&&!t(n)?!0:(r.push(n),!1)});s.length===o.content.length||s.length===0||(n+=o.content.length-s.length,i??=[...e.input],i[a]={...o,content:s})}return{count:n,fingerprints:r,payload:i?{...e,input:i}:e}}function Sn(e,t){let n=jn(e,t),r=U.get(n);return r?r>Date.now()?!0:(U.delete(n),!1):!1}function Cn(e,t){if(t.length!==1)return;let n=jn(e,t[0]);for(U.delete(n),U.set(n,Date.now()+18e5);U.size>256;){let e=U.keys().next().value;if(!e)break;U.delete(e)}}async function wn(e){let t=new TextDecoder,n=performance.now()+100,r=``,i=0,a=0;for(;;){let o=n-performance.now();if(o<=0)return!1;let s=await Tn(e,o);if(!s)return!1;let{done:c,value:l}=s;if(l){if(i+=l.byteLength,i>65536)return!1;r+=t.decode(l,{stream:!c})}else c&&(r+=t.decode());for(;;){let e=En(r);if(!e)break;r=e.remaining;let t=Dn(e.block);if(t){if(a++,On(t))return!0;if(!kn(t)||a>=8)return!1}}if(c){let e=Dn(r);return e?On(e):!1}}}async function Tn(e,t){return await Promise.race([e.read(),new Promise(e=>{setTimeout(e,t)})])}function En(e){let t=/\r\n\r\n|\r\r|\n\n/.exec(e);if(t?.index!==void 0)return{block:e.slice(0,t.index),remaining:e.slice(t.index+t[0].length)}}function Dn(e){let t=e.split(/\r\n|\r|\n/).filter(e=>e.startsWith(`data:`)).map(e=>e.slice(5).trimStart()).join(`
`);if(!(!t||t===`[DONE]`))try{let e=JSON.parse(t);return e&&typeof e==`object`?e:void 0}catch{return}}function On(e){return e.type===`response.failed`&&JSON.stringify(e).includes(_n)}function kn(e){return e.type===`response.created`||e.type===`response.in_progress`}function An(e){return c(`sha256`).update(e).digest(`base64url`)}function jn(e,t){return`${e}:${t}`}const Mn=5e6,Nn=`[older response input omitted to stay under context limit]`,Pn=`[older response input truncated to stay under context limit]

`,Fn=new Set([`call_id`,`id`,`model`,`name`,`previous_response_id`,`role`,`status`,`tool_call_id`,`type`]);async function W(e){if(!h.copilotToken)throw Error(`Copilot token not found`);let n=`${_(h)}/responses`,r=vn(n,e.model,h.githubToken??h.copilotToken),a=Ln(xn(er(e),e=>Sn(r,e)).payload,Rn(e.model)),o={...v(h,cr(a)),accept:a.stream?`text/event-stream`:`application/json`,"X-Initiator":`agent`},s=JSON.stringify(a).length;i.info(`Sending responses payload: ${s} bytes, model: ${e.model}`);let c=await In({url:n,headers:o,encryptedOutputScope:r},a),{response:l}=c;if(!l.ok){let n=c.errorBody??await l.text();if(i.error(`Failed to create responses - Status: ${l.status} ${l.statusText}`),i.error(`Response body: ${n}`),i.error(`Request payload size: ${c.body.length} bytes`),$n(l,n,c.body.length)){let n=Math.ceil(c.body.length/4),r=h.models?.data.find(t=>t.id===e.model)?.capabilities.limits,a=Ct(e.model,r),o=e.max_output_tokens??0;throw i.warn(`Responses context overflow -> returning 400 prompt-too-long (~${n} + ${o} > ${a})`),new t(`Prompt too long`,new Response(JSON.stringify({type:`error`,error:{type:`invalid_request_error`,message:`prompt is too long: input length and \`max_tokens\` exceed context limit: ${n} + ${o} > ${a} tokens`}}),{status:400,statusText:`Bad Request`,headers:{"content-type":`application/json`}}))}throw new t(`Failed to create responses`,new Response(n,{status:l.status,statusText:l.statusText,headers:l.headers}))}return l}async function In(e,t){let{encryptedOutputScope:n,headers:r,url:a}=e,o=xn(t),s=await G(a,r,t);return o.count===0?s:!s.response.ok&&s.errorBody&&yn(s.response,s.errorBody)?(i.warn(`Copilot could not decrypt ${o.count} encrypted output part(s); retrying without them`),Cn(n,o.fingerprints),G(a,r,o.payload)):s.response.ok&&t.stream&&await bn(s.response)?(s.response.body?.cancel().catch(()=>void 0),i.warn(`Copilot stream failed before output; retrying without ${o.count} encrypted output part(s)`),Cn(n,o.fingerprints),G(a,r,o.payload)):s}async function G(e,t,n){let r=JSON.stringify(n),i=await A(e,{method:`POST`,headers:t,body:r});return{body:r,errorBody:i.ok?void 0:await i.text(),response:i}}function Ln(e,t){let n=JSON.stringify(e);if(n.length<=t)return e;if(i.info(`Responses context fit: payload ${n.length} bytes exceeds ${t} byte ceiling - reducing`),typeof e.input==`string`){let r=K(e,t),a=JSON.stringify(r).length;return i.warn(`Responses context fit: truncated string input (${n.length} -> ${a} bytes)`),r}let r=e,a=n.length,o=zn(e),s=0;for(let e of o)if(r=Bn(r,e),s++,a=JSON.stringify(r).length,a<=t)break;if(s>0&&i.warn(`Responses context fit: stripped ${s} images (${n.length} -> ${a} bytes)`),a<=t)return r;let c=Vn(r,t);return r=Un(c.payload),a=JSON.stringify(r).length,c.count>0&&i.warn(`Responses context fit: dropped ${c.count} old input items (${n.length} -> ${a} bytes)`),a<=t||(r=qn(r,t),a=JSON.stringify(r).length,i.warn(`Responses context fit: truncated input content (${n.length} -> ${a} bytes)`),a<=t)||(r=Xn(r,t),a=JSON.stringify(r).length,i.warn(`Responses context fit: minimized input history (${n.length} -> ${a} bytes)`),a<=t)?r:(r=Zn(r,t),a=JSON.stringify(r).length,i.warn(`Responses context fit: truncated payload strings (${n.length} -> ${a} bytes)`),r)}function Rn(e){let t=h.models?.data.find(t=>t.id===e)?.capabilities.limits,n=j(e,t);if(!n)return Mn;let r=Math.floor((n-8e3)*3.5);return Math.min(Mn,r)}function K(e,t){if(typeof e.input!=`string`)return e;let n=JSON.stringify({...e,input:``}).length,r=Math.max(62,t-n),i=Math.max(0,r-62);return{...e,input:Pn+e.input.slice(-i)}}function zn(e){if(typeof e.input==`string`)return[];let t=[];for(let[n,r]of e.input.entries())if(Array.isArray(r.content))for(let[e,i]of r.content.entries())i.type===`input_image`&&t.push({contentIndex:e,inputIndex:n});return t}function Bn(e,t){if(typeof e.input==`string`)return e;let n=[...e.input],r=n[t.inputIndex];if(!Array.isArray(r.content))return e;let i=[...r.content];return i[t.contentIndex]={type:`input_text`,text:`[image removed to stay under upstream payload limit]`},n[t.inputIndex]={...r,content:i},{...e,input:n}}function Vn(e,t){if(typeof e.input==`string`)return{bodyLength:JSON.stringify(e).length,count:0,payload:e};let n=[...e.input],r=JSON.stringify({...e,input:n}).length,i=0;for(let a=0;a<n.length&&r>t;a++){let t=n[a];t.role===`system`||t.role===`developer`||Kn(n,a)<=2||(n[a]=Hn(t),i++,r=JSON.stringify({...e,input:n}).length)}return{bodyLength:r,count:i,payload:{...e,input:n}}}function Hn(e){return{role:e.role===`assistant`?`assistant`:`user`,content:Nn}}function Un(e){if(typeof e.input==`string`)return e;let t=new Set(e.input.filter(e=>Wn(e)&&e.call_id).map(e=>e.call_id)),n=0,r=e.input.map(e=>!Gn(e)||!e.call_id||t.has(e.call_id)?e:(n++,Hn(e)));return n===0?e:(i.warn(`Responses context fit: dropped ${n} orphaned tool call outputs`),{...e,input:r})}function Wn(e){return typeof e.type==`string`&&e.type.endsWith(`_call`)}function Gn(e){return typeof e.type==`string`&&e.type.endsWith(`_call_output`)}function Kn(e,t){let n=0;for(let r=t;r<e.length;r++)e[r].role!==`system`&&e[r].role!==`developer`&&n++;return n}function qn(e,t){if(typeof e.input==`string`)return K(e,t);let n=e,r=JSON.stringify(n).length;for(;r>t;){let e=Jn(n);if(!e)return n;n=Yn(n,e,r-t);let i=JSON.stringify(n).length;if(i>=r)return n;r=i}return n}function Jn(e){if(typeof e.input==`string`)return null;let t=null;for(let[n,r]of e.input.entries()){if(r.role===`system`||r.role===`developer`)continue;let e=q(r,[]);e&&(!t||e.length>t.length)&&(t={inputIndex:n,...e})}return t}function Yn(e,t,n){if(typeof e.input==`string`)return e;let r=[...e.input],i=r[t.inputIndex],a=Math.max(0,t.length-n-62-1e4);return r[t.inputIndex]=J(i,t.path,a),{...e,input:r}}function q(e,t){if(typeof e==`string`){let n=t.at(-1);return typeof n==`string`&&Fn.has(n)?null:{length:e.length,path:t}}if(Array.isArray(e))return e.reduce((e,n,r)=>{let i=q(n,[...t,r]);return i&&(!e||i.length>e.length)?i:e},null);if(!Qn(e))return null;let n=null;for(let[r,i]of Object.entries(e)){let e=q(i,[...t,r]);e&&(!n||e.length>n.length)&&(n=e)}return n}function J(e,t,n){if(t.length===0)return typeof e==`string`?Pn+e.slice(-n):e;let[r,...i]=t;if(Array.isArray(e)&&typeof r==`number`){let t=[...e];return t[r]=J(t[r],i,n),t}return Qn(e)&&typeof r==`string`?{...e,[r]:J(e[r],i,n)}:e}function Xn(e,t){if(typeof e.input==`string`)return K(e,t);let n=e.input.filter(e=>e.role===`system`||e.role===`developer`),r=[...e.input].reverse().find(e=>e.role!==`system`&&e.role!==`developer`);return{...e,input:[...n,{role:r?.role===`assistant`?`assistant`:`user`,content:Nn}]}}function Zn(e,t){let n=e,r=JSON.stringify(n).length;for(;r>t;){let e=q(n,[]);if(!e)return n;n=J(n,e.path,r-t);let i=JSON.stringify(n).length;if(i>=r)return n;r=i}return n}function Qn(e){return typeof e==`object`&&!!e}function $n(e,t,n){return e.status===413||/request entity too large/i.test(t)||/exceeds the limit of \d+/i.test(t)||/context_length_exceeded/i.test(t)||/operation timed out/i.test(t)||/payload too large/i.test(t)||/maximum context length/i.test(t)||e.status>=500&&e.status<600&&n>2e6}function er(e){let t=tr(rr(e));return delete t.service_tier,t.tools?.some(e=>e.type===`image_generation`)?{...t,tools:t.tools.filter(e=>e.type!==`image_generation`)}:t}function tr(e){let t=nr(e.tools),n=t===e.tools?e:{...e,tools:t};if(typeof e.input==`string`)return n;let r;for(let[t,n]of e.input.entries()){let i=nr(n.tools,!0);i!==n.tools&&(r??=[...e.input],r[t]={...n,tools:i})}return r&&(n={...n,input:r}),n}function nr(e,t=!1){return!Array.isArray(e)||!e.some(e=>t&&!Y(e.description)||e.description!==void 0&&!Y(e.description)||e.function?.description!==void 0&&!Y(e.function.description))?e:e.map(e=>{let n={...e};if(t&&!Y(n.description)){let e=n.function?.description,t;Y(n.name)?t=n.name:Y(n.function?.name)&&(t=n.function.name),n.description=t?`Tool ${t}`:`Tool`,Y(e)&&(n.description=e)}else n.description!==void 0&&!Y(n.description)&&delete n.description;return n.function?.description!==void 0&&!Y(n.function.description)&&(n.function={...n.function},delete n.function.description),n})}function Y(e){return typeof e==`string`&&e.trim().length>0}function rr(e){if(typeof e.input==`string`)return e;let t;for(let[n,r]of e.input.entries()){if(!Array.isArray(r.output))continue;let i=ir(r.output);i!==r.output&&(t??=[...e.input],t[n]={...r,output:i})}return t?{...e,input:t}:e}function ir(e){if(typeof e==`string`)return e;let t=e.map(e=>ar(e));return t.some((t,n)=>t!==e[n])?t:e}function ar(e){return or(e)?{type:`input_text`,text:`[image output removed because its URL is not valid for Copilot Responses]`}:typeof e.image_url==`string`&&e.type!==`input_image`?{type:`input_image`,image_url:e.image_url,detail:e.detail}:e.type===`output_text`?{type:`input_text`,text:e.text??``}:e}function or(e){return!(`image_url`in e)||e.image_url===null||e.image_url===void 0?!1:typeof e.image_url!=`string`||!sr(e.image_url)}function sr(e){try{let t=new URL(e);return t.protocol===`http:`||t.protocol===`https:`}catch{return!1}}function cr(e){return typeof e.input==`string`?!1:e.input.some(e=>Array.isArray(e.content)&&e.content.some(e=>e.type===`input_image`))}function lr(e,t){return{model:t,input:e.messages.flatMap(e=>pr(e)),instructions:fr(e.system),max_output_tokens:e.max_tokens,temperature:e.temperature,top_p:e.top_p,stream:!1,tools:e.tools?.map(e=>({type:`function`,name:e.name,description:e.description,parameters:e.input_schema})),tool_choice:vr(e.tool_choice)}}function ur(e,t){let n=e.output.flatMap(e=>br(e)),r=n.some(e=>e.type===`tool_use`);return{id:e.id,type:`message`,role:`assistant`,content:n,model:t,stop_reason:r?`tool_use`:`end_turn`,stop_sequence:null,usage:{input_tokens:e.usage?.input_tokens??0,output_tokens:e.usage?.output_tokens??0}}}async function dr(e,t,n){let r=ur(t,n);await e.writeSSE({event:`message_start`,data:JSON.stringify({type:`message_start`,message:{...r,content:[],stop_reason:null,stop_sequence:null,usage:{...r.usage,output_tokens:0}}})});for(let[t,n]of r.content.entries())n.type===`text`?await Sr(e,t,n.text):n.type===`tool_use`&&await Cr(e,t,n);await e.writeSSE({event:`message_delta`,data:JSON.stringify({type:`message_delta`,delta:{stop_reason:r.stop_reason,stop_sequence:null},usage:{output_tokens:r.usage.output_tokens}})}),await e.writeSSE({event:`message_stop`,data:JSON.stringify({type:`message_stop`})})}function fr(e){if(e)return typeof e==`string`?e:e.map(e=>e.text).join(`

`)}function pr(e){return e.role===`user`?mr(e.content):hr(e.content)}function mr(e){if(typeof e==`string`)return[{role:`user`,content:e}];let t=[],n=[];for(let r of e)r.type===`tool_result`?t.push({type:`function_call_output`,call_id:r.tool_use_id,output:yr(r.content)}):n.push(r);let r=gr(n);return r&&t.push({role:`user`,content:r}),t}function hr(e){if(typeof e==`string`)return[{role:`assistant`,content:e}];let t=[],n=e.filter(e=>e.type===`text`).map(e=>e.text).join(`

`);n&&t.push({role:`assistant`,content:n});for(let n of e)n.type===`tool_use`&&t.push({type:`function_call`,call_id:n.id,name:n.name,arguments:JSON.stringify(n.input)});return t}function gr(e){if(!e.some(e=>e.type===`image`))return e.filter(e=>e.type===`text`).map(e=>e.text).join(`

`)||null;let t=[];for(let n of e)n.type===`text`?t.push({type:`input_text`,text:n.text}):n.type===`image`&&t.push(_r(n));return t.length>0?t:null}function _r(e){return{type:`input_image`,image_url:`data:${e.source.media_type};base64,${e.source.data}`}}function vr(e){if(e){if(e.type===`auto`||e.type===`none`)return e.type;if(e.type===`any`)return`required`;if(e.name)return{type:`function`,name:e.name}}}function yr(e){return typeof e==`string`?e:JSON.stringify(e)}function br(e){return e.type===`function_call`&&e.name&&e.call_id?[{type:`tool_use`,id:e.call_id,name:e.name,input:xr(e.arguments)}]:e.type!==`message`||!e.content?[]:e.content.flatMap(e=>e.type!==`output_text`||!e.text?[]:[{type:`text`,text:e.text}])}function xr(e){if(!e)return{};try{let t=JSON.parse(e);if(t&&typeof t==`object`&&!Array.isArray(t))return t}catch{return{}}return{}}async function Sr(e,t,n){await e.writeSSE({event:`content_block_start`,data:JSON.stringify({type:`content_block_start`,index:t,content_block:{type:`text`,text:``}})}),await e.writeSSE({event:`content_block_delta`,data:JSON.stringify({type:`content_block_delta`,index:t,delta:{type:`text_delta`,text:n}})}),await e.writeSSE({event:`content_block_stop`,data:JSON.stringify({type:`content_block_stop`,index:t})})}async function Cr(e,t,n){await e.writeSSE({event:`content_block_start`,data:JSON.stringify({type:`content_block_start`,index:t,content_block:{type:`tool_use`,id:n.id,name:n.name,input:{}}})}),await e.writeSSE({event:`content_block_delta`,data:JSON.stringify({type:`content_block_delta`,index:t,delta:{type:`input_json_delta`,partial_json:JSON.stringify(n.input)}})}),await e.writeSSE({event:`content_block_stop`,data:JSON.stringify({type:`content_block_stop`,index:t})})}function wr(e){return e.contentBlockOpen?Object.values(e.toolCalls).some(t=>t.anthropicBlockIndex===e.contentBlockIndex):!1}function Tr(e,t){let n=[];if(e.choices.length===0)return n;let r=e.choices[0],{delta:i}=r;if(t.messageStartSent||=(n.push({type:`message_start`,message:{id:e.id,type:`message`,role:`assistant`,content:[],model:e.model,stop_reason:null,stop_sequence:null,usage:{input_tokens:(e.usage?.prompt_tokens??0)-(e.usage?.prompt_tokens_details?.cached_tokens??0),output_tokens:0,...e.usage?.prompt_tokens_details?.cached_tokens!==void 0&&{cache_read_input_tokens:e.usage.prompt_tokens_details.cached_tokens}}}}),!0),i.content&&(wr(t)&&(n.push({type:`content_block_stop`,index:t.contentBlockIndex}),t.contentBlockIndex++,t.contentBlockOpen=!1),t.contentBlockOpen||=(n.push({type:`content_block_start`,index:t.contentBlockIndex,content_block:{type:`text`,text:``}}),!0),n.push({type:`content_block_delta`,index:t.contentBlockIndex,delta:{type:`text_delta`,text:i.content}})),i.tool_calls)for(let e of i.tool_calls){if(e.id&&e.function?.name){t.contentBlockOpen&&=(n.push({type:`content_block_stop`,index:t.contentBlockIndex}),t.contentBlockIndex++,!1);let r=t.contentBlockIndex;t.toolCalls[e.index]={id:e.id,name:e.function.name,anthropicBlockIndex:r},n.push({type:`content_block_start`,index:r,content_block:{type:`tool_use`,id:e.id,name:e.function.name,input:{}}}),t.contentBlockOpen=!0}if(e.function?.arguments){let r=t.toolCalls[e.index];r&&n.push({type:`content_block_delta`,index:r.anthropicBlockIndex,delta:{type:`input_json_delta`,partial_json:e.function.arguments}})}}return r.finish_reason&&(t.contentBlockOpen&&=(n.push({type:`content_block_stop`,index:t.contentBlockIndex}),!1),n.push({type:`message_delta`,delta:{stop_reason:kt(r.finish_reason),stop_sequence:null},usage:{input_tokens:(e.usage?.prompt_tokens??0)-(e.usage?.prompt_tokens_details?.cached_tokens??0),output_tokens:e.usage?.completion_tokens??0,...e.usage?.prompt_tokens_details?.cached_tokens!==void 0&&{cache_read_input_tokens:e.usage.prompt_tokens_details.cached_tokens}}},{type:`message_stop`})),n}function Er(e){return Dr(e)?{type:`error`,error:{type:`invalid_request_error`,message:`prompt is too long: upstream operation timed out while streaming the response`}}:{type:`error`,error:{type:`api_error`,message:e??`An unexpected error occurred during streaming.`}}}function Dr(e){return e!==void 0&&(/prompt is too long/i.test(e)||/operation timed out/i.test(e)||/request entity too large/i.test(e)||/context_length_exceeded/i.test(e)||/payload too large/i.test(e)||/maximum context length/i.test(e))}function Or(){return`req_${crypto.randomUUID().replaceAll(`-`,``)}`}async function kr(e){await D(h);let t=e.req.header(`x-client-request-id`)??Or();e.header(`request-id`,t),e.header(`x-request-id`,t);let n=await e.req.json();i.level>=4&&i.debug(`[${t}] Anthropic request payload:`,JSON.stringify(n).slice(0,2e3));let r=n.model,a=await Nt(n),o=At(a),s=h.models?.data.find(e=>e.id===o.model);return Mr(s)?await jr(e,a,{clientModel:r,model:o.model,requestId:t}):await Ar(e,o,{clientModel:r,requestId:t})}async function Ar(e,t,n){i.level>=4&&i.debug(`[${n.requestId}] Translated OpenAI request payload:`,JSON.stringify(t));let r=h.models?.data.find(e=>e.id===t.model),a=r?cn(t,r):ln(t);if(!r&&un(a))throw M(a,JSON.stringify(a).length);if(a.messages.length!==t.messages.length&&i.info(`[${n.requestId}] Context management: ${t.messages.length} → ${a.messages.length} messages`),h.manualApprove&&await E(),a.stream)return i.debug(`[${n.requestId}] Streaming response from Copilot`),Fr(e,()=>N(a),n);let o=await N(a);if(!Gr(o))throw Error(`Expected non-streaming response from Copilot`);return Nr(e,o,n)}async function jr(e,t,n){h.manualApprove&&await E();let r=lr(t,n.model);if(t.stream)return f(e,async e=>{let t=X(e);try{await dr(e,await(await W(r)).json(),n.clientModel)}catch(t){await e.writeSSE({event:`error`,data:JSON.stringify(Er(t instanceof Error?t.message:void 0))})}finally{t()}});let i=await(await W(r)).json();return e.json(ur(i,n.clientModel))}function Mr(e){return e?.supported_endpoints?e.supported_endpoints.includes(`/responses`)&&!e.supported_endpoints.includes(`/chat/completions`):!1}function Nr(e,t,n){i.level>=4&&i.debug(`[${n.requestId}] Non-streaming response from Copilot:`,JSON.stringify(t).slice(-400));try{let r=Qt(t,n.clientModel);return i.level>=4&&i.debug(`[${n.requestId}] Translated Anthropic response:`,JSON.stringify(r)),e.json(r)}catch(t){return e.json(Pr(t,n.requestId),500)}}function Pr(e,t){return i.error(`[${t}] Failed to translate non-streaming response:`,e),{type:`error`,error:{type:`api_error`,message:e instanceof Error?`Translation failed: ${e.message}`:`Translation failed`}}}function Fr(e,t,n){return f(e,async e=>{let r={messageStartSent:!1,contentBlockIndex:0,contentBlockOpen:!1,toolCalls:{}},i=X(e);try{await Ir(e),await Lr(e,{...n,createResponse:t,streamState:r})}catch(t){await zr(e,{error:t,requestId:n.requestId,streamState:r})}finally{i()}})}function X(e){let t=setInterval(()=>{Ir(e).catch(()=>{})},15e3);return()=>clearInterval(t)}async function Ir(e){await e.writeSSE({event:`ping`,data:JSON.stringify({type:`ping`})})}async function Lr(e,t){let n=await t.createResponse();if(Gr(n))throw Error(`Expected streaming response from Copilot`);for await(let r of n){if(r.data===`[DONE]`)break;if(!r.data)continue;let n=Rr(r.data,t.requestId);if(n){t.streamState.messageStartSent||(n.model=t.clientModel);for(let r of Tr(n,t.streamState))await e.writeSSE({event:r.type,data:JSON.stringify(r)})}}}function Rr(e,t){try{return JSON.parse(e)}catch(e){return i.warn(`[${t}] Skipping unparseable Copilot chunk:`,e),null}}async function zr(e,t){i.error(`[${t.requestId}] Streaming error:`,t.error);try{let n=await Br(t.error);await Ur(e,t.streamState),await Wr(e,t.streamState),await e.writeSSE({event:`error`,data:JSON.stringify(Er(n))})}catch(e){i.error(`[${t.requestId}] Failed to emit stream cleanup events:`,e)}}async function Br(e){if(e instanceof t)try{return Vr(await e.response.text())}catch{return e.message}return e instanceof Error?e.message:void 0}function Vr(e){try{let t=Hr(JSON.parse(e));if(t)return t}catch{return e}return e}function Hr(e){if(typeof e==`string`)return e;if(typeof e!=`object`||!e)return;let t=e,n=t.error;if(typeof n==`string`)return n;if(typeof n==`object`&&n){let e=n;if(typeof e.message==`string`)return e.message}if(typeof t.message==`string`)return t.message}async function Ur(e,t){t.contentBlockOpen&&await e.writeSSE({event:`content_block_stop`,data:JSON.stringify({type:`content_block_stop`,index:t.contentBlockIndex})})}async function Wr(e,t){t.messageStartSent&&(await e.writeSSE({event:`message_delta`,data:JSON.stringify({type:`message_delta`,delta:{stop_reason:`end_turn`,stop_sequence:null},usage:{output_tokens:0}})}),await e.writeSSE({event:`message_stop`,data:JSON.stringify({type:`message_stop`})}))}const Gr=e=>Object.hasOwn(e,`choices`),Z=new d;Z.post(`/`,async t=>{try{return await kr(t)}catch(n){return await e(t,n)}}),Z.post(`/count_tokens`,async t=>{try{return await tn(t)}catch(n){return await e(t,n)}});const Q=new d;Q.get(`/`,async t=>{try{if(t.req.query(`client_version`)!==void 0)return t.json({models:[]});h.models||await Oe();let e=h.models?.data.map(e=>({id:e.id,object:`model`,type:`model`,created:0,created_at:new Date(0).toISOString(),owned_by:e.vendor,display_name:e.name,capabilities:e.capabilities,supported_capabilities:Kr(e)}));return t.json({object:`list`,data:e,has_more:!1})}catch(n){return await e(t,n)}});function Kr(e){let t=new Set,n=e.capabilities.supports;return n.reasoning_effort?.length&&(t.add(`effort`),n.reasoning_effort.includes(`xhigh`)&&t.add(`xhigh_effort`),n.reasoning_effort.includes(`max`)&&t.add(`max_effort`)),n.adaptive_thinking&&(t.add(`thinking`),t.add(`adaptive_thinking`),t.add(`interleaved_thinking`)),[...t]}async function qr(e){await D(h);let t=await e.req.json();return i.debug(`Responses API request:`,JSON.stringify(t).slice(-400)),h.manualApprove&&await E(),W(t)}const Jr=new d;Jr.post(`/`,async n=>{try{return await qr(n)}catch(r){if(r instanceof t){let e=await r.response.text(),t;try{t=JSON.parse(e)}catch{t=e}return i.error(`Responses HTTP error body:`,t),new Response(e,{status:r.response.status,statusText:r.response.statusText,headers:{"content-type":r.response.headers.get(`content-type`)??`application/json`}})}return await e(n,r)}});const Yr=new d;Yr.get(`/`,e=>{try{return e.json({token:h.copilotToken})}catch(t){return i.error(`Error fetching token:`,t),e.json({error:`Failed to fetch token`,token:null},500)}});const Xr=new d;Xr.get(`/`,async e=>{try{let t=await Ie();return e.json(t)}catch(t){return i.error(`Error fetching Copilot usage:`,t),e.json({error:`Failed to fetch Copilot usage`},500)}});const $=new d;$.use(le()),$.use(ce()),$.use(nt),$.get(`/`,e=>e.text(`Server running`)),$.use(qe),$.route(`/chat/completions`,P),$.route(`/debug`,Dt),$.route(`/models`,Q),$.route(`/embeddings`,F),$.route(`/usage`,Xr),$.route(`/token`,Yr),$.route(`/v1/chat/completions`,P),$.route(`/v1/models`,Q),$.route(`/v1/embeddings`,F),$.route(`/v1/responses`,Jr),$.route(`/v1/messages`,Z);async function Zr(e){e.proxyEnv&&Ye(),e.verbose&&(i.level=5,i.info(`Verbose logging enabled`)),h.accountType=e.accountType,e.accountType!==`individual`&&i.info(`Using ${e.accountType} plan GitHub account`),h.manualApprove=e.manual,h.rateLimitSeconds=e.rateLimit,h.rateLimitWait=e.rateLimitWait,h.showToken=e.showToken,h.localApiKeys=Ke(e.apiKey),h.localApiKeys.length>0&&i.info(`Local API-key auth enabled`),e.githubToken&&(h.githubToken=e.githubToken,i.info(`Using provided GitHub token`)),await m(),await ke(),e.githubToken||await C(),await Ne(),await Oe(),i.info(`Available models: \n${h.models?.data.map(e=>`- ${e.id}`).join(`
`)}`);let t=`http://localhost:${e.port}`;if(e.claudeCode){te(h.models,`Models should be loaded by now`);let e=await i.prompt(`Select a model to use with Claude Code`,{type:`select`,options:h.models.data.map(e=>e.id)}),n=await i.prompt(`Select a small model to use with Claude Code`,{type:`select`,options:h.models.data.map(e=>e.id)}),r=Ze({ANTHROPIC_BASE_URL:t,ANTHROPIC_AUTH_TOKEN:`dummy`,ANTHROPIC_MODEL:e,ANTHROPIC_DEFAULT_SONNET_MODEL:e,ANTHROPIC_SMALL_FAST_MODEL:n,ANTHROPIC_DEFAULT_HAIKU_MODEL:n,DISABLE_NON_ESSENTIAL_MODEL_CALLS:`1`,CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:`1`},`claude`);try{u.writeSync(r),i.success(`Copied Claude Code command to clipboard!`)}catch{i.warn(`Failed to copy to clipboard. Here is the Claude Code command:`),i.log(r)}}i.box(`🌐 Usage Viewer: https://voidsteed.github.io/copilot-proxy-api/dashboard.html?endpoint=${t}/usage`),ee({fetch:$.fetch,port:e.port,bun:{idleTimeout:0}})}await r(n({meta:{name:`copilot-proxy-api`,description:`A wrapper around GitHub Copilot API to make it OpenAI compatible, making it usable for other tools.`},subCommands:{auth:Fe,start:n({meta:{name:`start`,description:`Start the Copilot API server`},args:{port:{alias:`p`,type:`string`,default:`4141`,description:`Port to listen on`},verbose:{alias:`v`,type:`boolean`,default:!1,description:`Enable verbose logging`},"account-type":{alias:`a`,type:`string`,default:`individual`,description:`Account type to use (individual, business, enterprise)`},manual:{type:`boolean`,default:!1,description:`Enable manual request approval`},"rate-limit":{alias:`r`,type:`string`,description:`Rate limit in seconds between requests`},wait:{alias:`w`,type:`boolean`,default:!1,description:`Wait instead of error when rate limit is hit. Has no effect if rate limit is not set`},"github-token":{alias:`g`,type:`string`,description:"Provide GitHub token directly (must be generated using the `auth` subcommand)"},"claude-code":{alias:`c`,type:`boolean`,default:!1,description:`Generate a command to launch Claude Code with Copilot API config`},"show-token":{type:`boolean`,default:!1,description:`Show GitHub and Copilot tokens on fetch and refresh`},"proxy-env":{type:`boolean`,default:!1,description:`Initialize proxy from environment variables`},"api-key":{type:`string`,description:`Require one of these comma-separated local API keys for proxy routes`}},run({args:e}){let t=e[`rate-limit`],n=t===void 0?void 0:Number.parseInt(t,10);return Zr({port:Number.parseInt(e.port,10),verbose:e.verbose,accountType:e[`account-type`],manual:e.manual,rateLimit:n,rateLimitWait:e.wait,githubToken:e[`github-token`],claudeCode:e[`claude-code`],showToken:e[`show-token`],proxyEnv:e[`proxy-env`],apiKey:e[`api-key`]})}}),"check-usage":Le,debug:Ge}}));export{};
//# sourceMappingURL=main.mjs.map