xc-copilot-api
Advanced tools
+17
-15
| #!/usr/bin/env node | ||
| import{defineCommand as e,runMain as t}from"citty";import n from"consola";import r,{copyFile as i,mkdir as a,readFile as o,writeFile as s}from"node:fs/promises";import c,{homedir as l}from"node:os";import u,{join as d}from"node:path";import{randomUUID as ee}from"node:crypto";import{serve as f}from"srvx";import{getProxyForUrl as te}from"proxy-from-env";import{Agent as ne,ProxyAgent as re,setGlobalDispatcher as ie}from"undici";import{Hono as p}from"hono";import{cors as ae}from"hono/cors";import{streamSSE as m}from"hono/streaming";import{events as oe}from"fetch-event-stream";var se=`xc-copilot-api`,ce=`1.2.4`,le=`Turn GitHub Copilot into OpenAI/Anthropic API compatible server. Usable with Claude Code and Codex`,ue=[`proxy`,`github-copilot`,`openai-compatible`],de=`https://github.com/billxc/copilot-api`,fe=`https://github.com/billxc/copilot-api/issues`,pe={type:`git`,url:`git+https://github.com/billxc/copilot-api.git`},me=`Xiaochen <wxc9312@gmail.com>`,he=`module`,ge={"xc-copilot-api":`./dist/main.js`},_e=[`dist`],ve={build:`bun run scripts/generate-page.ts && tsdown`,dev:`bun run scripts/generate-page.ts && bun run --watch ./src/main.ts start`,knip:`knip-bun`,lint:`eslint --cache`,"lint:all":`eslint --cache .`,prepack:`bun run build`,prepare:`simple-git-hooks`,release:`bumpp && bun publish --access public`,start:`NODE_ENV=production bun run ./src/main.ts start`,typecheck:`tsc`},ye={},be={},xe={citty:`^0.1.6`,consola:`^3.4.2`,"fetch-event-stream":`^0.1.5`,"gpt-tokenizer":`^3.0.1`,hono:`^4.9.9`,"proxy-from-env":`^1.1.0`,srvx:`^0.8.9`,undici:`^7.16.0`},Se={"@echristian/eslint-config":`^0.0.54`,"@types/bun":`^1.2.23`,"@types/proxy-from-env":`^1.0.4`,bumpp:`^10.2.3`,eslint:`^9.37.0`,knip:`^5.64.1`,"simple-git-hooks":`^2.13.1`,tsdown:`^0.15.6`,typescript:`^5.9.3`},h={name:se,version:ce,description:le,keywords:ue,homepage:de,bugs:fe,repository:pe,author:me,type:he,bin:ge,files:_e,scripts:ve,"simple-git-hooks":ye,"lint-staged":be,dependencies:xe,devDependencies:Se};const g=u.join(c.homedir(),`.local`,`share`,`copilot-api`),Ce=u.join(g,`github_token`),_={APP_DIR:g,GITHUB_TOKEN_PATH:Ce};async function v(){await r.mkdir(_.APP_DIR,{recursive:!0}),await we(_.GITHUB_TOKEN_PATH)}async function we(e){try{await r.access(e,r.constants.W_OK)}catch{await r.writeFile(e,``),await r.chmod(e,384)}}const y={accountType:`individual`,manualApprove:!1,rateLimitWait:!1,showToken:!1},b=()=>({"content-type":`application/json`,accept:`application/json`}),x=`0.26.7`,Te=`copilot-chat/${x}`,Ee=`GitHubCopilotChat/${x}`,De=`2025-04-01`,S=e=>e.accountType===`individual`?`https://api.githubcopilot.com`:`https://api.${e.accountType}.githubcopilot.com`,C=(e,t=!1)=>{let n={Authorization:`Bearer ${e.copilotToken}`,"content-type":b()[`content-type`],"copilot-integration-id":`vscode-chat`,"editor-version":`vscode/${e.vsCodeVersion}`,"editor-plugin-version":Te,"user-agent":Ee,"openai-intent":`conversation-panel`,"x-github-api-version":De,"x-request-id":ee(),"x-vscode-user-agent-library-version":`electron-fetch`};return t&&(n[`copilot-vision-request`]=`true`),n},w=`https://api.github.com`,Oe=e=>({...b(),authorization:`token ${e.githubToken}`,"editor-version":`vscode/${e.vsCodeVersion}`,"editor-plugin-version":Te,"user-agent":Ee,"x-github-api-version":De,"x-vscode-user-agent-library-version":`electron-fetch`}),T=`https://github.com`,E=`Iv1.b507a08c87ecfe98`,ke=[`read:user`].join(` `);var D=class extends Error{response;constructor(e,t){super(e),this.response=t}};async function O(e,t){if(n.error(`Error occurred:`,t),t instanceof D){let r=await t.response.text(),i;try{i=JSON.parse(r)}catch{i=r}return n.error(`HTTP error:`,i),e.json({error:{message:r,type:`error`}},t.response.status)}return e.json({error:{message:t.message,type:`error`}},500)}const Ae=async()=>{let e=await fetch(`${w}/copilot_internal/v2/token`,{headers:Oe(y)});if(!e.ok)throw new D(`Failed to get Copilot token`,e);return await e.json()};async function je(){let e=await fetch(`${T}/login/device/code`,{method:`POST`,headers:b(),body:JSON.stringify({client_id:E,scope:ke})});if(!e.ok)throw new D(`Failed to get device code`,e);return await e.json()}async function Me(){let e=await fetch(`${w}/user`,{headers:{authorization:`token ${y.githubToken}`,...b()}});if(!e.ok)throw new D(`Failed to get GitHub user`,e);return await e.json()}const Ne=async()=>{let e=await fetch(`${S(y)}/models`,{headers:C(y)});if(!e.ok)throw new D(`Failed to get models`,e);return await e.json()},Pe=`1.104.3`;async function Fe(){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]:Pe}catch{return Pe}finally{clearTimeout(t)}}await Fe();const k=e=>new Promise(t=>{setTimeout(t,e)}),Ie=e=>e==null;async function A(){y.models=await Ne()}const Le=async()=>{let e=await Fe();y.vsCodeVersion=e,n.info(`Using VSCode version: ${e}`)};async function Re(e){let t=(e.interval+1)*1e3;for(n.debug(`Polling access token with interval of ${t}ms`);;){let r=await fetch(`${T}/login/oauth/access_token`,{method:`POST`,headers:b(),body:JSON.stringify({client_id:E,device_code:e.device_code,grant_type:`urn:ietf:params:oauth:grant-type:device_code`})});if(!r.ok){await k(t),n.error(`Failed to poll access token:`,await r.text());continue}let i=await r.json();n.debug(`Polling access token response:`,i);let{access_token:a}=i;if(a)return a;await k(t)}}const ze=()=>r.readFile(_.GITHUB_TOKEN_PATH,`utf8`),Be=e=>r.writeFile(_.GITHUB_TOKEN_PATH,e),Ve=e=>new Promise(t=>{setTimeout(t,e)}),j=async(e=3,t=1e3)=>{let r=null;for(let i=0;i<e;i++)try{return await Ae()}catch(a){r=a;let o=t*2**i;n.warn(`Token refresh attempt ${i+1}/${e} failed, retrying in ${o}ms:`,r.message),i<e-1&&await Ve(o)}throw r||Error(`Failed to refresh Copilot token`)},M=async()=>{try{n.debug(`Force refreshing Copilot token due to 401 response`);let{token:e}=await j();y.copilotToken=e,n.debug(`Copilot token force refreshed successfully`)}catch(e){n.error(`Failed to force refresh Copilot token:`,e)}},He=async()=>{let{token:e,refresh_in:t}=await Ae();y.copilotToken=e,n.debug(`GitHub Copilot Token fetched successfully!`),y.showToken&&n.info(`Copilot token:`,e);let r=(t-60)*1e3;setInterval(async()=>{try{n.debug(`Refreshing Copilot token`);let{token:e}=await j();y.copilotToken=e,n.debug(`Copilot token refreshed successfully`),y.showToken&&n.info(`Refreshed Copilot token:`,e)}catch(e){n.error(`Failed to refresh Copilot token, will retry on next interval:`,e)}},r)};async function N(e){try{let t=await ze();if(t&&!e?.force){y.githubToken=t,y.showToken&&n.info(`GitHub token:`,t),await P();return}n.info(`Not logged in, getting new access token`);let r=await je();n.debug(`Device code response:`,r),n.info(`Please enter the code "${r.user_code}" in ${r.verification_uri}`);let i=await Re(r);await Be(i),y.githubToken=i,y.showToken&&n.info(`GitHub token:`,i),await P()}catch(e){throw e instanceof D?(n.error(`Failed to get GitHub token:`,await e.response.json()),e):(n.error(`Failed to get GitHub token:`,e),e)}}async function P(){let e=await Me();y.githubLogin=e.login,n.info(`Logged in as ${e.login}`)}async function Ue(e){e.verbose&&(n.level=5,n.info(`Verbose logging enabled`)),y.showToken=e.showToken,await v(),await N({force:!0}),n.success(`GitHub token written to`,_.GITHUB_TOKEN_PATH)}const We=e({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 Ue({verbose:e.verbose,showToken:e[`show-token`]})}}),F=async()=>{let e=await fetch(`${w}/copilot_internal/user`,{headers:Oe(y)});if(!e.ok)throw new D(`Failed to get Copilot usage`,e);return await e.json()},Ge=e({meta:{name:`check-usage`,description:`Show current GitHub Copilot usage/quota information`},async run(){await v(),await N();try{let e=await F(),t=e.quota_snapshots.premium_interactions,r=t.entitlement,i=r-t.remaining,a=r>0?i/r*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: ${i}/${r} used (${a.toFixed(1)}% used, ${o.toFixed(1)}% remaining)`,l=s(`Chat`,e.quota_snapshots.chat),u=s(`Completions`,e.quota_snapshots.completions);n.box(`Copilot Usage (plan: ${e.copilot_plan})\nQuota resets: ${e.quota_reset_date}\n\nQuotas:\n ${c}\n ${l}\n ${u}`)}catch(e){n.error(`Failed to fetch Copilot usage:`,e),process.exit(1)}}});async function I(e){try{let t=`${e}.bak`;await i(e,t),n.info(`Backup saved: ${t}`)}catch{}}const L={"4.7":`claude-opus-4.7-1m-internal`,"4.6":`claude-opus-4.6-1m`};async function Ke(e,t){let r=L[t];r||(n.error(`Unknown Claude model version: ${t}. Supported: ${Object.keys(L).join(`, `)}`),process.exit(1));let i=d(l(),`.claude`),c=d(i,`settings.json`);await a(i,{recursive:!0});let u={};try{let e=await o(c,`utf-8`);u=JSON.parse(e)}catch(e){e.code!==`ENOENT`&&(n.error(`Failed to parse ${c}. Please fix it manually.`),process.exit(1))}let ee=typeof u.env==`object`&&u.env!==null?u.env:{},f={...u,env:{...ee,ANTHROPIC_BASE_URL:`http://localhost:${e}`,ANTHROPIC_AUTH_TOKEN:`Powered by xc copilot`,ANTHROPIC_DEFAULT_OPUS_MODEL:r,CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS:`1`},model:`opus[1m]`};await I(c),await s(c,JSON.stringify(f,null,2)+` | ||
| import{defineCommand as e,runMain as t}from"citty";import n from"consola";import r,{copyFile as i,mkdir as a,readFile as o,writeFile as s}from"node:fs/promises";import c,{homedir as l}from"node:os";import u,{join as d}from"node:path";import{randomUUID as ee}from"node:crypto";import{serve as f}from"srvx";import{getProxyForUrl as te}from"proxy-from-env";import{Agent as ne,ProxyAgent as re,setGlobalDispatcher as ie}from"undici";import{Hono as p}from"hono";import{cors as ae}from"hono/cors";import{streamSSE as m}from"hono/streaming";import{events as oe}from"fetch-event-stream";var se=`xc-copilot-api`,ce=`1.2.5`,le=`Turn GitHub Copilot into OpenAI/Anthropic API compatible server. Usable with Claude Code and Codex`,ue=[`proxy`,`github-copilot`,`openai-compatible`],de=`https://github.com/billxc/copilot-api`,fe=`https://github.com/billxc/copilot-api/issues`,pe={type:`git`,url:`git+https://github.com/billxc/copilot-api.git`},me=`Xiaochen <wxc9312@gmail.com>`,he=`module`,ge={"xc-copilot-api":`./dist/main.js`},_e=[`dist`],ve={build:`bun run scripts/generate-page.ts && tsdown`,dev:`bun run scripts/generate-page.ts && bun run --watch ./src/main.ts start`,knip:`knip-bun`,lint:`eslint --cache`,"lint:all":`eslint --cache .`,prepack:`bun run build`,prepare:`simple-git-hooks`,release:`bumpp && bun publish --access public`,start:`NODE_ENV=production bun run ./src/main.ts start`,typecheck:`tsc`},ye={},be={},xe={citty:`^0.1.6`,consola:`^3.4.2`,"fetch-event-stream":`^0.1.5`,"gpt-tokenizer":`^3.0.1`,hono:`^4.9.9`,"proxy-from-env":`^1.1.0`,srvx:`^0.8.9`,undici:`^7.16.0`},Se={"@echristian/eslint-config":`^0.0.54`,"@types/bun":`^1.2.23`,"@types/proxy-from-env":`^1.0.4`,bumpp:`^10.2.3`,eslint:`^9.37.0`,knip:`^5.64.1`,"simple-git-hooks":`^2.13.1`,tsdown:`^0.15.6`,typescript:`^5.9.3`},h={name:se,version:ce,description:le,keywords:ue,homepage:de,bugs:fe,repository:pe,author:me,type:he,bin:ge,files:_e,scripts:ve,"simple-git-hooks":ye,"lint-staged":be,dependencies:xe,devDependencies:Se};const g=u.join(c.homedir(),`.local`,`share`,`copilot-api`),Ce=u.join(g,`github_token`),_={APP_DIR:g,GITHUB_TOKEN_PATH:Ce};async function v(){await r.mkdir(_.APP_DIR,{recursive:!0}),await we(_.GITHUB_TOKEN_PATH)}async function we(e){try{await r.access(e,r.constants.W_OK)}catch{await r.writeFile(e,``),await r.chmod(e,384)}}const y={accountType:`individual`,manualApprove:!1,rateLimitWait:!1,showToken:!1},b=()=>({"content-type":`application/json`,accept:`application/json`}),x=`0.26.7`,Te=`copilot-chat/${x}`,Ee=`GitHubCopilotChat/${x}`,De=`2025-04-01`,S=e=>e.accountType===`individual`?`https://api.githubcopilot.com`:`https://api.${e.accountType}.githubcopilot.com`,C=(e,t=!1)=>{let n={Authorization:`Bearer ${e.copilotToken}`,"content-type":b()[`content-type`],"copilot-integration-id":`vscode-chat`,"editor-version":`vscode/${e.vsCodeVersion}`,"editor-plugin-version":Te,"user-agent":Ee,"openai-intent":`conversation-panel`,"x-github-api-version":De,"x-request-id":ee(),"x-vscode-user-agent-library-version":`electron-fetch`};return t&&(n[`copilot-vision-request`]=`true`),n},w=`https://api.github.com`,Oe=e=>({...b(),authorization:`token ${e.githubToken}`,"editor-version":`vscode/${e.vsCodeVersion}`,"editor-plugin-version":Te,"user-agent":Ee,"x-github-api-version":De,"x-vscode-user-agent-library-version":`electron-fetch`}),T=`https://github.com`,E=`Iv1.b507a08c87ecfe98`,ke=[`read:user`].join(` `);var D=class extends Error{response;constructor(e,t){super(e),this.response=t}};async function O(e,t){if(n.error(`Error occurred:`,t),t instanceof D){let r=await t.response.text(),i;try{i=JSON.parse(r)}catch{i=r}return n.error(`HTTP error:`,i),e.json({error:{message:r,type:`error`}},t.response.status)}return e.json({error:{message:t.message,type:`error`}},500)}const Ae=async()=>{let e=await fetch(`${w}/copilot_internal/v2/token`,{headers:Oe(y)});if(!e.ok)throw new D(`Failed to get Copilot token`,e);return await e.json()};async function je(){let e=await fetch(`${T}/login/device/code`,{method:`POST`,headers:b(),body:JSON.stringify({client_id:E,scope:ke})});if(!e.ok)throw new D(`Failed to get device code`,e);return await e.json()}async function Me(){let e=await fetch(`${w}/user`,{headers:{authorization:`token ${y.githubToken}`,...b()}});if(!e.ok)throw new D(`Failed to get GitHub user`,e);return await e.json()}const Ne=async()=>{let e=await fetch(`${S(y)}/models`,{headers:C(y)});if(!e.ok)throw new D(`Failed to get models`,e);return await e.json()},Pe=`1.104.3`;async function Fe(){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]:Pe}catch{return Pe}finally{clearTimeout(t)}}await Fe();const k=e=>new Promise(t=>{setTimeout(t,e)}),Ie=e=>e==null;async function A(){y.models=await Ne()}const Le=async()=>{let e=await Fe();y.vsCodeVersion=e,n.info(`Using VSCode version: ${e}`)};async function Re(e){let t=(e.interval+1)*1e3;for(n.debug(`Polling access token with interval of ${t}ms`);;){let r=await fetch(`${T}/login/oauth/access_token`,{method:`POST`,headers:b(),body:JSON.stringify({client_id:E,device_code:e.device_code,grant_type:`urn:ietf:params:oauth:grant-type:device_code`})});if(!r.ok){await k(t),n.error(`Failed to poll access token:`,await r.text());continue}let i=await r.json();n.debug(`Polling access token response:`,i);let{access_token:a}=i;if(a)return a;await k(t)}}const ze=()=>r.readFile(_.GITHUB_TOKEN_PATH,`utf8`),Be=e=>r.writeFile(_.GITHUB_TOKEN_PATH,e),Ve=e=>new Promise(t=>{setTimeout(t,e)}),j=async(e=3,t=1e3)=>{let r=null;for(let i=0;i<e;i++)try{return await Ae()}catch(a){r=a;let o=t*2**i;n.warn(`Token refresh attempt ${i+1}/${e} failed, retrying in ${o}ms:`,r.message),i<e-1&&await Ve(o)}throw r||Error(`Failed to refresh Copilot token`)},M=async()=>{try{n.debug(`Force refreshing Copilot token due to 401 response`);let{token:e}=await j();y.copilotToken=e,n.debug(`Copilot token force refreshed successfully`)}catch(e){n.error(`Failed to force refresh Copilot token:`,e)}},He=async()=>{let{token:e,refresh_in:t}=await Ae();y.copilotToken=e,n.debug(`GitHub Copilot Token fetched successfully!`),y.showToken&&n.info(`Copilot token:`,e);let r=(t-60)*1e3;setInterval(async()=>{try{n.debug(`Refreshing Copilot token`);let{token:e}=await j();y.copilotToken=e,n.debug(`Copilot token refreshed successfully`),y.showToken&&n.info(`Refreshed Copilot token:`,e)}catch(e){n.error(`Failed to refresh Copilot token, will retry on next interval:`,e)}},r)};async function N(e){try{let t=await ze();if(t&&!e?.force){y.githubToken=t,y.showToken&&n.info(`GitHub token:`,t),await P();return}n.info(`Not logged in, getting new access token`);let r=await je();n.debug(`Device code response:`,r),n.info(`Please enter the code "${r.user_code}" in ${r.verification_uri}`);let i=await Re(r);await Be(i),y.githubToken=i,y.showToken&&n.info(`GitHub token:`,i),await P()}catch(e){throw e instanceof D?(n.error(`Failed to get GitHub token:`,await e.response.json()),e):(n.error(`Failed to get GitHub token:`,e),e)}}async function P(){let e=await Me();y.githubLogin=e.login,n.info(`Logged in as ${e.login}`)}async function Ue(e){e.verbose&&(n.level=5,n.info(`Verbose logging enabled`)),y.showToken=e.showToken,await v(),await N({force:!0}),n.success(`GitHub token written to`,_.GITHUB_TOKEN_PATH)}const We=e({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 Ue({verbose:e.verbose,showToken:e[`show-token`]})}}),F=async()=>{let e=await fetch(`${w}/copilot_internal/user`,{headers:Oe(y)});if(!e.ok)throw new D(`Failed to get Copilot usage`,e);return await e.json()},Ge=e({meta:{name:`check-usage`,description:`Show current GitHub Copilot usage/quota information`},async run(){await v(),await N();try{let e=await F(),t=e.quota_snapshots.premium_interactions,r=t.entitlement,i=r-t.remaining,a=r>0?i/r*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: ${i}/${r} used (${a.toFixed(1)}% used, ${o.toFixed(1)}% remaining)`,l=s(`Chat`,e.quota_snapshots.chat),u=s(`Completions`,e.quota_snapshots.completions);n.box(`Copilot Usage (plan: ${e.copilot_plan})\nQuota resets: ${e.quota_reset_date}\n\nQuotas:\n ${c}\n ${l}\n ${u}`)}catch(e){n.error(`Failed to fetch Copilot usage:`,e),process.exit(1)}}});async function I(e){try{let t=`${e}.bak`;await i(e,t),n.info(`Backup saved: ${t}`)}catch{}}const L={"4.7":`claude-opus-4.7-1m-internal`,"4.6":`claude-opus-4.6-1m`};async function Ke(e,t){let r=L[t];r||(n.error(`Unknown Claude model version: ${t}. Supported: ${Object.keys(L).join(`, `)}`),process.exit(1));let i=d(l(),`.claude`),c=d(i,`settings.json`);await a(i,{recursive:!0});let u={};try{let e=await o(c,`utf-8`);u=JSON.parse(e)}catch(e){e.code!==`ENOENT`&&(n.error(`Failed to parse ${c}. Please fix it manually.`),process.exit(1))}let ee=typeof u.env==`object`&&u.env!==null?u.env:{},f={...u,env:{...ee,ANTHROPIC_BASE_URL:`http://localhost:${e}`,ANTHROPIC_AUTH_TOKEN:`Powered by xc copilot`,ANTHROPIC_DEFAULT_OPUS_MODEL:r,CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS:`1`},model:`opus[1m]`};await I(c),await s(c,JSON.stringify(f,null,2)+` | ||
| `,`utf-8`),n.success(`Claude Code configured: ${c}`)}function R(e,t,n){let r=RegExp(`^${t}\\s*=.*$`,`m`),i=`${t} = ${JSON.stringify(n)}`;if(r.test(e))return e.replace(r,i);let a=e.match(/^\[/m);return a?.index===void 0?e.trimEnd()+` | ||
@@ -17,3 +17,3 @@ `+i+` | ||
| Token exists: ${e.tokenExists?`Yes`:`No`}`)}function tt(e){console.log(JSON.stringify(e,null,2))}async function nt(e){let t=await $e();e.json?tt(t):et(t)}const rt=e({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 nt({json:e.json})}});function it(){if(!(typeof Bun<`u`))try{let e=new ne,t=new Map;ie({dispatch(r,i){try{let a=typeof r.origin==`string`?new URL(r.origin):r.origin,o=te(a.toString()),s=o&&o.length>0?o:void 0;if(!s)return n.debug(`HTTP proxy bypass: ${a.hostname}`),e.dispatch(r,i);let c=t.get(s);c||(c=new re(s),t.set(s,c));let l=s;try{let e=new URL(s);l=`${e.protocol}//${e.host}`}catch{}return n.debug(`HTTP proxy route: ${a.hostname} via ${l}`),c.dispatch(r,i)}catch{return e.dispatch(r,i)}},close(){return e.close()},destroy(){return e.destroy()}}),n.debug(`HTTP proxy configured from environment (per-URL)`)}catch(e){n.debug(`Proxy setup skipped:`,e)}}function z(){return new Date().toISOString()}function at(){return async function(e,t){let n=performance.now();await t();let r=(performance.now()-n).toFixed(1),i=e.req.method,a=e.req.path,o=e.res.status;console.log(`[${z()}] ${i} ${a} ${o} ${r}ms`)}}function B(e,t){console.error(`[${z()}] ${e}`,t)}const V=async()=>{if(!await n.prompt(`Accept incoming request?`,{type:`confirm`}))throw new D(`Request rejected`,Response.json({message:`Request rejected`},{status:403}))};async function H(e){if(e.rateLimitSeconds===void 0)return;let t=Date.now();if(!e.lastRequestTimestamp){e.lastRequestTimestamp=t;return}let r=(t-e.lastRequestTimestamp)/1e3;if(r>e.rateLimitSeconds){e.lastRequestTimestamp=t;return}let i=Math.ceil(e.rateLimitSeconds-r);if(!e.rateLimitWait)throw n.warn(`Rate limit exceeded. Need to wait ${i} more seconds.`),new D(`Rate limit exceeded`,Response.json({message:`Rate limit exceeded`},{status:429}));let a=i*1e3;n.warn(`Rate limit reached. Waiting ${i} seconds before proceeding...`),await k(a),e.lastRequestTimestamp=t,n.info(`Rate limit wait completed, proceeding with request`)}const U={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`)},W=new Map,ot=(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},st=(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},ct=(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+=ot(a,t,n)),i===`content`&&Array.isArray(a)&&(r+=st(a,t));return r},G=(e,t,n)=>{if(e.length===0)return 0;let r=0;for(let i of e)r+=ct(i,t,n);return r+=3,r},lt=async e=>{if(W.has(e)){let t=W.get(e);if(t)return t}let t=e;if(!(t in U)){let t=await U.o200k_base();return W.set(e,t),t}let n=await U[t]();return W.set(e,n),n},ut=e=>e.capabilities.tokenizer||`o200k_base`,dt=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},ft=(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 d=new Set([`type`,`description`,`enum`]);for(let e of Object.keys(o))if(!d.has(e)){let t=o[e],n=typeof t==`string`?t:JSON.stringify(t);a+=r.encode(`${e}:${n}`).length}return a},pt=(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+=ft(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},mt=(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+=pt(i.parameters,t,n)),r},ht=(e,t,n)=>{let r=0;for(let i of e)r+=mt(i,t,n);return r+=n.funcEnd,r},gt=async(e,t)=>{let n=ut(t),r=await lt(n),i=e.messages,a=i.filter(e=>e.role!==`assistant`),o=i.filter(e=>e.role===`assistant`),s=dt(t),c=G(a,r,s);e.tools&&e.tools.length>0&&(c+=ht(e.tools,r,s));let l=G(o,r,s);return{input:c,output:l}},K=async e=>{if(!y.copilotToken)throw Error(`Copilot token not found`);let t=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)),i=()=>({...C(y,t),"X-Initiator":r?`agent`:`user`}),a=await fetch(`${S(y)}/chat/completions`,{method:`POST`,headers:i(),body:JSON.stringify(e)});if(a.status===401&&(n.warn(`Received 401, attempting to refresh token and retry`),await M(),a=await fetch(`${S(y)}/chat/completions`,{method:`POST`,headers:i(),body:JSON.stringify(e)})),!a.ok)throw n.error(`Failed to create chat completions`,a),new D(`Failed to create chat completions`,a);return e.stream?oe(a):await a.json()};async function _t(e){await H(y);let t=await e.req.json();n.debug(`Request payload:`,JSON.stringify(t).slice(-400));let r=y.models?.data.find(e=>e.id===t.model);try{if(r){let e=await gt(t,r);n.info(`Current token count:`,e)}else n.warn(`No model selected, skipping token count calculation`)}catch(e){n.warn(`Failed to calculate token count:`,e)}y.manualApprove&&await V(),Ie(t.max_tokens)&&(t={...t,max_tokens:r?.capabilities.limits.max_output_tokens},n.debug(`Set max_tokens to:`,JSON.stringify(t.max_tokens)));let i=await K(t);return vt(i)?(n.debug(`Non-streaming response:`,JSON.stringify(i)),e.json(i)):(n.debug(`Streaming response`),m(e,async e=>{for await(let t of i)n.debug(`Streaming chunk:`,JSON.stringify(t)),await e.writeSSE(t)}))}const vt=e=>Object.hasOwn(e,`choices`),q=new p;q.post(`/`,async e=>{try{return await _t(e)}catch(t){return await O(e,t)}});const yt=async e=>{if(!y.copilotToken)throw Error(`Copilot token not found`);let t=await fetch(`${S(y)}/embeddings`,{method:`POST`,headers:C(y),body:JSON.stringify(e)});if(!t.ok)throw new D(`Failed to create embeddings`,t);return await t.json()},J=new p;J.post(`/`,async e=>{try{let t=await e.req.json(),n=await yt(t);return e.json(n)}catch(t){return await O(e,t)}});const bt=new p;bt.get(`/`,e=>{let t=process.env.npm_package_version??h.version,n=y.githubLogin??`unknown`,r=y.accountType,i=e.req.query(`format`),a=e.req.header(`accept`)??``;return i===`json`||a.includes(`application/json`)?e.json({version:t,login:n,accountType:r}):i===`text`||!a.includes(`text/html`)?e.text(`Copilot API v${t} - running\nUser: ${n} (${r})`):e.html(`<!doctype html> | ||
| Token exists: ${e.tokenExists?`Yes`:`No`}`)}function tt(e){console.log(JSON.stringify(e,null,2))}async function nt(e){let t=await $e();e.json?tt(t):et(t)}const rt=e({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 nt({json:e.json})}});function it(){if(!(typeof Bun<`u`))try{let e=new ne,t=new Map;ie({dispatch(r,i){try{let a=typeof r.origin==`string`?new URL(r.origin):r.origin,o=te(a.toString()),s=o&&o.length>0?o:void 0;if(!s)return n.debug(`HTTP proxy bypass: ${a.hostname}`),e.dispatch(r,i);let c=t.get(s);c||(c=new re(s),t.set(s,c));let l=s;try{let e=new URL(s);l=`${e.protocol}//${e.host}`}catch{}return n.debug(`HTTP proxy route: ${a.hostname} via ${l}`),c.dispatch(r,i)}catch{return e.dispatch(r,i)}},close(){return e.close()},destroy(){return e.destroy()}}),n.debug(`HTTP proxy configured from environment (per-URL)`)}catch(e){n.debug(`Proxy setup skipped:`,e)}}function z(){return new Date().toISOString()}function at(){return async function(e,t){let n=performance.now();await t();let r=(performance.now()-n).toFixed(1),i=e.req.method,a=e.req.path,o=e.res.status;console.log(`[${z()}] ${i} ${a} ${o} ${r}ms`)}}function B(e,t){console.error(`[${z()}] ${e}`,t)}const V=async()=>{if(!await n.prompt(`Accept incoming request?`,{type:`confirm`}))throw new D(`Request rejected`,Response.json({message:`Request rejected`},{status:403}))};async function H(e){if(e.rateLimitSeconds===void 0)return;let t=Date.now();if(!e.lastRequestTimestamp){e.lastRequestTimestamp=t;return}let r=(t-e.lastRequestTimestamp)/1e3;if(r>e.rateLimitSeconds){e.lastRequestTimestamp=t;return}let i=Math.ceil(e.rateLimitSeconds-r);if(!e.rateLimitWait)throw n.warn(`Rate limit exceeded. Need to wait ${i} more seconds.`),new D(`Rate limit exceeded`,Response.json({message:`Rate limit exceeded`},{status:429}));let a=i*1e3;n.warn(`Rate limit reached. Waiting ${i} seconds before proceeding...`),await k(a),e.lastRequestTimestamp=t,n.info(`Rate limit wait completed, proceeding with request`)}const U={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`)},W=new Map,ot=(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},st=(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},ct=(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+=ot(a,t,n)),i===`content`&&Array.isArray(a)&&(r+=st(a,t));return r},G=(e,t,n)=>{if(e.length===0)return 0;let r=0;for(let i of e)r+=ct(i,t,n);return r+=3,r},lt=async e=>{if(W.has(e)){let t=W.get(e);if(t)return t}let t=e;if(!(t in U)){let t=await U.o200k_base();return W.set(e,t),t}let n=await U[t]();return W.set(e,n),n},ut=e=>e.capabilities.tokenizer||`o200k_base`,dt=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},ft=(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 d=new Set([`type`,`description`,`enum`]);for(let e of Object.keys(o))if(!d.has(e)){let t=o[e],n=typeof t==`string`?t:JSON.stringify(t);a+=r.encode(`${e}:${n}`).length}return a},pt=(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+=ft(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},mt=(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+=pt(i.parameters,t,n)),r},ht=(e,t,n)=>{let r=0;for(let i of e)r+=mt(i,t,n);return r+=n.funcEnd,r},gt=async(e,t)=>{let n=ut(t),r=await lt(n),i=e.messages,a=i.filter(e=>e.role!==`assistant`),o=i.filter(e=>e.role===`assistant`),s=dt(t),c=G(a,r,s);e.tools&&e.tools.length>0&&(c+=ht(e.tools,r,s));let l=G(o,r,s);return{input:c,output:l}},K=async e=>{if(!y.copilotToken)throw Error(`Copilot token not found`);let t=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)),i=()=>({...C(y,t),"X-Initiator":r?`agent`:`user`}),a=await fetch(`${S(y)}/chat/completions`,{method:`POST`,headers:i(),body:JSON.stringify(e)});if(a.status===401&&(n.warn(`Received 401, attempting to refresh token and retry`),await M(),a=await fetch(`${S(y)}/chat/completions`,{method:`POST`,headers:i(),body:JSON.stringify(e)})),!a.ok)throw n.error(`Failed to create chat completions`,a),new D(`Failed to create chat completions`,a);return e.stream?oe(a):await a.json()};async function _t(e){await H(y);let t=await e.req.json();n.debug(`Request payload:`,JSON.stringify(t).slice(-400));let r=y.models?.data.find(e=>e.id===t.model);try{if(r){let e=await gt(t,r);n.info(`Current token count:`,e)}else n.warn(`No model selected, skipping token count calculation`)}catch(e){n.warn(`Failed to calculate token count:`,e)}y.manualApprove&&await V(),Ie(t.max_tokens)&&(t={...t,max_tokens:r?.capabilities.limits.max_output_tokens},n.debug(`Set max_tokens to:`,JSON.stringify(t.max_tokens)));let i=await K(t);return vt(i)?(n.debug(`Non-streaming response:`,JSON.stringify(i)),e.json(i)):(n.debug(`Streaming response`),m(e,async e=>{for await(let t of i)n.debug(`Streaming chunk:`,JSON.stringify(t)),await e.writeSSE(t)}))}const vt=e=>Object.hasOwn(e,`choices`),q=new p;q.post(`/`,async e=>{try{return await _t(e)}catch(t){return await O(e,t)}});const yt=async e=>{if(!y.copilotToken)throw Error(`Copilot token not found`);let t=await fetch(`${S(y)}/embeddings`,{method:`POST`,headers:C(y),body:JSON.stringify(e)});if(!t.ok)throw new D(`Failed to create embeddings`,t);return await t.json()},J=new p;J.post(`/`,async e=>{try{let t=await e.req.json(),n=await yt(t);return e.json(n)}catch(t){return await O(e,t)}});const bt=e=>`<!doctype html> | ||
| <html lang="en"> | ||
@@ -248,3 +248,3 @@ <head> | ||
| <h1 class="text-xl font-semibold tracking-tight">Copilot API</h1> | ||
| <span id="version-badge" class="text-xs px-2 py-0.5 rounded-full font-mono" style="background: var(--bg-hover); color: var(--fg-muted); display: none"></span> | ||
| <span id="version-slot">${e}</span> | ||
| </div> | ||
@@ -378,6 +378,5 @@ <p class="text-sm" style="color: var(--fg-subtle)">Monitor usage, browse models, and configure clients</p> | ||
| try { | ||
| const [usageRes, modelsRes, infoRes] = await Promise.all([ | ||
| const [usageRes, modelsRes] = await Promise.all([ | ||
| fetch(base + "/usage"), | ||
| fetch(base + "/models"), | ||
| fetch(base + "/?format=json").catch(() => null), | ||
| ]); | ||
@@ -388,9 +387,12 @@ if (!usageRes.ok) throw new Error("Usage: " + usageRes.status); | ||
| modelsData = await modelsRes.json(); | ||
| if (infoRes && infoRes.ok) { | ||
| // Populate version badge if it wasn't server-rendered. | ||
| const slot = document.getElementById("version-slot"); | ||
| if (slot && !slot.firstElementChild) { | ||
| try { | ||
| const info = await infoRes.json(); | ||
| const badge = document.getElementById("version-badge"); | ||
| if (info && info.version) { | ||
| badge.textContent = "v" + info.version; | ||
| badge.style.display = ""; | ||
| const r = await fetch(base + "/?format=json"); | ||
| if (r.ok) { | ||
| const info = await r.json(); | ||
| if (info && info.version) { | ||
| slot.innerHTML = \`<span class="text-xs px-2 py-0.5 rounded-full font-mono" style="background: var(--bg-hover); color: var(--fg-muted)">v\${info.version}</span>\`; | ||
| } | ||
| } | ||
@@ -676,10 +678,10 @@ } catch {} | ||
| </html> | ||
| `)});const xt=new Set([`connection`,`content-length`,`keep-alive`,`proxy-authenticate`,`proxy-authorization`,`te`,`trailer`,`transfer-encoding`,`upgrade`]);async function St({path:e,body:t,requestHeaders:r,forwardRequestHeaders:i,initiator:a,enableVision:o=!1,errorMessage:s,throwOnError:c=!1}){if(!y.copilotToken)throw Error(`Copilot token not found`);let l=await u();if(l.status===401&&(n.warn(`Received 401, attempting to refresh Copilot token and retry`),await M(),l=await u()),n.debug(`Passthrough response:`,{path:e,status:l.status,ok:l.ok}),!l.ok&&(n.error(s,l),c))throw new D(s,l);return l;async function u(){let s=Ct({requestHeaders:r,forwardRequestHeaders:i,initiator:a,enableVision:o});return n.debug(`Passthrough request:`,{method:`POST`,path:e,bodyLength:t.length}),fetch(`${S(y)}${e}`,{method:`POST`,headers:s,body:t})}}function Ct({requestHeaders:e,forwardRequestHeaders:t=[],initiator:n,enableVision:r=!1}){let i={...C(y,r),"X-Initiator":n};if(!e)return i;for(let n of t){let t=e.get(n);t&&(i[n]=t)}return i}function wt(e,t){let n=new Headers;if(t){for(let r of t){let t=e.get(r);t&&n.set(r,t)}return n}for(let[t,r]of e.entries())xt.has(t.toLowerCase())||n.set(t,r);return n}const Tt=[`accept`,`anthropic-beta`,`anthropic-version`],Et=`context-1m-2025-08-07`,Dt=new Set([Et]);function Ot(e){let t=e.get(`anthropic-beta`);return t?t.split(`,`).map(e=>e.trim()).includes(Et):!1}function kt(e){let t=e.get(`anthropic-beta`);if(!t)return e;let n=t.split(`,`).map(e=>e.trim()).filter(e=>!Dt.has(e)).join(`,`),r=new Headers(e);return n?r.set(`anthropic-beta`,n):r.delete(`anthropic-beta`),r}function At(e){let t={modified:!1};try{let n=JSON.parse(e,(e,n)=>{if(e===`cache_control`&&typeof n==`object`&&n&&!Array.isArray(n)){let e=n,r=Object.keys(e);if(r.length>1||r.length===1&&!r.includes(`type`))return t.modified=!0,{type:e.type}}return n});return t.modified?JSON.stringify(n):e}catch{return e}}async function jt(e,t,r=`/v1/messages`){return n.debug(`Original request headers: ${JSON.stringify([...t])}`),Ot(t)&&(n.debug(`Request includes unsupported beta features. Stripping unsupported beta flags and fields.`),t=kt(t)),St({path:r,body:At(e),requestHeaders:t,forwardRequestHeaders:Tt,initiator:`user`,errorMessage:`Upstream ${r} request failed`})}function Mt(e){return Pt(e)?.model?.startsWith(`claude`)??!1}function Nt(e){return wt(e)}function Pt(e){try{return JSON.parse(e)}catch{return}}function Ft(e){return e===null?null:{stop:`end_turn`,length:`max_tokens`,tool_calls:`tool_use`,content_filter:`end_turn`}[e]}function It(e){return{model:Lt(e.model),messages:Rt(e.messages,e.system),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:Ht(e.tools),tool_choice:Ut(e.tool_choice)}}function Lt(e){return e.startsWith(`claude-sonnet-4-`)?e.replace(/^claude-sonnet-4-.*/,`claude-sonnet-4`):e.startsWith(`claude-opus-`)?e.replace(/^claude-opus-4-.*/,`claude-opus-4`):e}function Rt(e,t){let n=zt(t),r=e.flatMap(e=>e.role===`user`?Bt(e):Vt(e));return[...n,...r]}function zt(e){if(!e)return[];if(typeof e==`string`)return[{role:`system`,content:e}];let t=e;return Array.isArray(e)&&(t=e.filter(e=>!e.text.includes(`x-anthropic-billing-header:`))),[{role:`system`,content:t.map(e=>e.text).join(` | ||
| `,xt=new p;xt.get(`/`,e=>{let t=process.env.npm_package_version??h.version,n=y.githubLogin??`unknown`,r=y.accountType,i=e.req.query(`format`),a=e.req.header(`accept`)??``;if(i===`json`||a.includes(`application/json`))return e.json({version:t,login:n,accountType:r});if(i===`text`||!a.includes(`text/html`))return e.text(`Copilot API v${t} - running\nUser: ${n} (${r})`);let o=`<span class="text-xs px-2 py-0.5 rounded-full font-mono" style="background: var(--bg-hover); color: var(--fg-muted)">v${t}</span>`;return e.html(bt(o))});const St=new Set([`connection`,`content-length`,`keep-alive`,`proxy-authenticate`,`proxy-authorization`,`te`,`trailer`,`transfer-encoding`,`upgrade`]);async function Ct({path:e,body:t,requestHeaders:r,forwardRequestHeaders:i,initiator:a,enableVision:o=!1,errorMessage:s,throwOnError:c=!1}){if(!y.copilotToken)throw Error(`Copilot token not found`);let l=await u();if(l.status===401&&(n.warn(`Received 401, attempting to refresh Copilot token and retry`),await M(),l=await u()),n.debug(`Passthrough response:`,{path:e,status:l.status,ok:l.ok}),!l.ok&&(n.error(s,l),c))throw new D(s,l);return l;async function u(){let s=wt({requestHeaders:r,forwardRequestHeaders:i,initiator:a,enableVision:o});return n.debug(`Passthrough request:`,{method:`POST`,path:e,bodyLength:t.length}),fetch(`${S(y)}${e}`,{method:`POST`,headers:s,body:t})}}function wt({requestHeaders:e,forwardRequestHeaders:t=[],initiator:n,enableVision:r=!1}){let i={...C(y,r),"X-Initiator":n};if(!e)return i;for(let n of t){let t=e.get(n);t&&(i[n]=t)}return i}function Tt(e,t){let n=new Headers;if(t){for(let r of t){let t=e.get(r);t&&n.set(r,t)}return n}for(let[t,r]of e.entries())St.has(t.toLowerCase())||n.set(t,r);return n}const Et=[`accept`,`anthropic-beta`,`anthropic-version`],Dt=`context-1m-2025-08-07`,Ot=new Set([Dt]);function kt(e){let t=e.get(`anthropic-beta`);return t?t.split(`,`).map(e=>e.trim()).includes(Dt):!1}function At(e){let t=e.get(`anthropic-beta`);if(!t)return e;let n=t.split(`,`).map(e=>e.trim()).filter(e=>!Ot.has(e)).join(`,`),r=new Headers(e);return n?r.set(`anthropic-beta`,n):r.delete(`anthropic-beta`),r}function jt(e){let t={modified:!1};try{let n=JSON.parse(e,(e,n)=>{if(e===`cache_control`&&typeof n==`object`&&n&&!Array.isArray(n)){let e=n,r=Object.keys(e);if(r.length>1||r.length===1&&!r.includes(`type`))return t.modified=!0,{type:e.type}}return n});return t.modified?JSON.stringify(n):e}catch{return e}}async function Mt(e,t,r=`/v1/messages`){return n.debug(`Original request headers: ${JSON.stringify([...t])}`),kt(t)&&(n.debug(`Request includes unsupported beta features. Stripping unsupported beta flags and fields.`),t=At(t)),Ct({path:r,body:jt(e),requestHeaders:t,forwardRequestHeaders:Et,initiator:`user`,errorMessage:`Upstream ${r} request failed`})}function Nt(e){return Ft(e)?.model?.startsWith(`claude`)??!1}function Pt(e){return Tt(e)}function Ft(e){try{return JSON.parse(e)}catch{return}}function It(e){return e===null?null:{stop:`end_turn`,length:`max_tokens`,tool_calls:`tool_use`,content_filter:`end_turn`}[e]}function Lt(e){return{model:Rt(e.model),messages:zt(e.messages,e.system),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:Ut(e.tools),tool_choice:Wt(e.tool_choice)}}function Rt(e){return e.startsWith(`claude-sonnet-4-`)?e.replace(/^claude-sonnet-4-.*/,`claude-sonnet-4`):e.startsWith(`claude-opus-`)?e.replace(/^claude-opus-4-.*/,`claude-opus-4`):e}function zt(e,t){let n=Bt(t),r=e.flatMap(e=>e.role===`user`?Vt(e):Ht(e));return[...n,...r]}function Bt(e){if(!e)return[];if(typeof e==`string`)return[{role:`system`,content:e}];let t=e;return Array.isArray(e)&&(t=e.filter(e=>!e.text.includes(`x-anthropic-billing-header:`))),[{role:`system`,content:t.map(e=>e.text).join(` | ||
| `)}]}function Bt(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:Y(e.content)});r.length>0&&t.push({role:`user`,content:Y(r)})}else t.push({role:`user`,content:Y(e.content)});return t}function Vt(e){if(!Array.isArray(e.content))return[{role:`assistant`,content:Y(e.content)}];let t=e.content.filter(e=>e.type===`tool_use`),n=e.content.filter(e=>e.type===`text`),r=e.content.filter(e=>e.type===`thinking`),i=[...n.map(e=>e.text),...r.map(e=>e.thinking)].join(` | ||
| `)}]}function Vt(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:Y(e.content)});r.length>0&&t.push({role:`user`,content:Y(r)})}else t.push({role:`user`,content:Y(e.content)});return t}function Ht(e){if(!Array.isArray(e.content))return[{role:`assistant`,content:Y(e.content)}];let t=e.content.filter(e=>e.type===`tool_use`),n=e.content.filter(e=>e.type===`text`),r=e.content.filter(e=>e.type===`thinking`),i=[...n.map(e=>e.text),...r.map(e=>e.thinking)].join(` | ||
| `);return t.length>0?[{role:`assistant`,content:i||null,tool_calls:t.map(e=>({id:e.id,type:`function`,function:{name:e.name,arguments:JSON.stringify(e.input)}}))}]:[{role:`assistant`,content:Y(e.content)}]}function Y(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`||e.type===`thinking`).map(e=>e.type===`text`?e.text:e.thinking).join(` | ||
| `);let t=[];for(let n of e)switch(n.type){case`text`:t.push({type:`text`,text:n.text});break;case`thinking`:t.push({type:`text`,text:n.thinking});break;case`image`:t.push({type:`image_url`,image_url:{url:`data:${n.source.media_type};base64,${n.source.data}`}});break}return t}function Ht(e){if(e)return e.map(e=>({type:`function`,function:{name:e.name,description:e.description,parameters:e.input_schema}}))}function Ut(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 Wt(e){let t=[],n=[],r=null;r=e.choices[0]?.finish_reason??r;for(let i of e.choices){let e=Gt(i.message.content),a=Kt(i.message.tool_calls);t.push(...e),n.push(...a),(i.finish_reason===`tool_calls`||r===`stop`)&&(r=i.finish_reason)}return{id:e.id,type:`message`,role:`assistant`,model:e.model,content:[...t,...n],stop_reason:Ft(r),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 Gt(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 Kt(e){return e?e.map(e=>({type:`tool_use`,id:e.id,name:e.function.name,input:JSON.parse(e.function.arguments)})):[]}async function qt(e){try{let t=await e.req.text();if(n.debug(`Anthropic count_tokens payload:`,t.slice(0,1e3)),Mt(t)){let n=await jt(t,e.req.raw.headers,`/v1/messages/count_tokens`);return new Response(n.body,{status:n.status,headers:Nt(n.headers)})}let r=e.req.header(`anthropic-beta`),i=JSON.parse(t),a=It(i),o=y.models?.data.find(e=>e.id===i.model);if(!o)return n.warn(`Model not found, returning default token count`),e.json({input_tokens:1});let s=await gt(a,o);if(i.tools&&i.tools.length>0){let e=!1;r?.startsWith(`claude-code`)&&(e=i.tools.some(e=>e.name.startsWith(`mcp__`))),e||(i.model.startsWith(`claude`)?s.input+=346:i.model.startsWith(`grok`)&&(s.input+=480))}let c=s.input+s.output;return i.model.startsWith(`claude`)?c=Math.round(c*1.15):i.model.startsWith(`grok`)&&(c=Math.round(c*1.03)),n.info(`Token count:`,c),e.json({input_tokens:c})}catch(t){return n.error(`Error counting tokens:`,t),e.json({input_tokens:1})}}function Jt(e){return e.contentBlockOpen?Object.values(e.toolCalls).some(t=>t.anthropicBlockIndex===e.contentBlockIndex):!1}function Yt(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&&(Jt(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:Ft(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}async function Xt(e){await H(y);let t=await e.req.text();if(n.debug(`Anthropic request payload:`,t.slice(0,1e3)),Mt(t)){y.manualApprove&&await V();let n=await jt(t,e.req.raw.headers);return new Response(n.body,{status:n.status,headers:Nt(n.headers)})}let r=JSON.parse(t);n.debug(`Anthropic request payload:`,JSON.stringify(r));let i=It(r);n.debug(`Translated OpenAI request payload:`,JSON.stringify(i)),y.manualApprove&&await V();let a=await K(i);if(Zt(a)){n.debug(`Non-streaming response from Copilot:`,JSON.stringify(a).slice(-400));let t=Wt(a);return n.debug(`Translated Anthropic response:`,JSON.stringify(t)),e.json(t)}return n.debug(`Streaming response from Copilot`),m(e,async e=>{let t={messageStartSent:!1,contentBlockIndex:0,contentBlockOpen:!1,toolCalls:{}};for await(let r of a){if(n.debug(`Copilot raw stream event:`,JSON.stringify(r)),r.data===`[DONE]`)break;if(!r.data)continue;let i=JSON.parse(r.data),a=Yt(i,t);for(let t of a)n.debug(`Translated Anthropic event:`,JSON.stringify(t)),await e.writeSSE({event:t.type,data:JSON.stringify(t)})}})}const Zt=e=>Object.hasOwn(e,`choices`),X=new p;X.post(`/`,async e=>{try{return await Xt(e)}catch(t){return await O(e,t)}}),X.post(`/count_tokens`,async e=>{try{return await qt(e)}catch(t){return await O(e,t)}});const Z=new p;Z.get(`/`,async e=>{try{y.models||await A();let t=y.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}));return e.json({object:`list`,data:t,has_more:!1})}catch(t){return await O(e,t)}});const Qt=[`content-type`,`cache-control`,`x-request-id`];function $t(e){return en(e)?.model?.startsWith(`gpt`)??!1}function en(e){try{return JSON.parse(e)}catch{return}}const tn=async(e,t)=>{let n=nn(e);return St({path:`/responses`,body:n,requestHeaders:t,initiator:`user`,errorMessage:`Failed to create responses`,throwOnError:!0})};function nn(e){let t=en(e);if(!t?.tools||!Array.isArray(t.tools))return e;let n=new Set([`image_generation`]),r=t.tools.filter(e=>!n.has(e.type??``));return r.length===t.tools.length?e:(t.tools=r,JSON.stringify(t))}function rn(e){return wt(e,Qt)}async function an(e){await H(y);let t=await e.req.text();if(!$t(t))return e.json({error:{message:`Responses API is only enabled for GPT models.`,type:`invalid_request_error`}},400);y.manualApprove&&await V();let n=await tn(t,e.req.raw.headers);return new Response(n.body,{status:n.status,headers:rn(n.headers)})}const Q=new p;Q.post(`/`,async e=>{try{return await an(e)}catch(t){return await O(e,t)}});const on=new p;on.get(`/`,e=>{try{return e.json({token:y.copilotToken})}catch(t){return B(`Error fetching token:`,t),e.json({error:`Failed to fetch token`,token:null},500)}});const sn=new p;sn.get(`/`,async e=>{try{let t=await F();return e.json(t)}catch(t){return B(`Error fetching Copilot usage:`,t),e.json({error:`Failed to fetch Copilot usage`},500)}});const $=new p;$.use(at()),$.use(ae()),$.route(`/`,bt),$.route(`/chat/completions`,q),$.route(`/models`,Z),$.route(`/embeddings`,J),$.route(`/responses`,Q),$.route(`/usage`,sn),$.route(`/token`,on),$.route(`/v1/chat/completions`,q),$.route(`/v1/models`,Z),$.route(`/v1/embeddings`,J),$.route(`/v1/responses`,Q),$.route(`/v1/messages`,X);async function cn(e){e.proxyEnv&&it(),e.verbose&&(n.level=5,n.info(`Verbose logging enabled`)),y.accountType=e.accountType,e.accountType!==`individual`&&n.info(`Using ${e.accountType} plan GitHub account`),y.manualApprove=e.manual,y.rateLimitSeconds=e.rateLimit,y.rateLimitWait=e.rateLimitWait,y.showToken=e.showToken,await v(),await Le(),e.githubToken?(y.githubToken=e.githubToken,n.info(`Using provided GitHub token`)):await N(),await He(),await A(),n.info(`Available models: \n${y.models?.data.map(e=>`- ${e.id}`).join(` | ||
| `)}`);let t=`http://localhost:${e.port}`;n.box(`🌐 Usage Viewer: https://billxc.github.io/copilot-api?endpoint=${t}/usage`),f({fetch:$.fetch,port:e.port,idleTimeout:255})}const ln=e({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)"},"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`}},run({args:e}){let t=e[`rate-limit`],n=t===void 0?void 0:Number.parseInt(t,10);return cn({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`],showToken:e[`show-token`],proxyEnv:e[`proxy-env`]})}}),un=e({meta:{name:`xc-copilot-api`,version:h.version,description:`A wrapper around GitHub Copilot API to make it OpenAI compatible, making it usable for other tools.`},args:{version:{type:`boolean`,alias:`V`,description:`Show version number`}},run({args:e}){e.version&&(console.log(h.version),process.exit(0))},subCommands:{auth:We,start:ln,config:Ye,"check-usage":Ge,debug:rt}});await t(un);export{}; | ||
| `);let t=[];for(let n of e)switch(n.type){case`text`:t.push({type:`text`,text:n.text});break;case`thinking`:t.push({type:`text`,text:n.thinking});break;case`image`:t.push({type:`image_url`,image_url:{url:`data:${n.source.media_type};base64,${n.source.data}`}});break}return t}function Ut(e){if(e)return e.map(e=>({type:`function`,function:{name:e.name,description:e.description,parameters:e.input_schema}}))}function Wt(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 Gt(e){let t=[],n=[],r=null;r=e.choices[0]?.finish_reason??r;for(let i of e.choices){let e=Kt(i.message.content),a=qt(i.message.tool_calls);t.push(...e),n.push(...a),(i.finish_reason===`tool_calls`||r===`stop`)&&(r=i.finish_reason)}return{id:e.id,type:`message`,role:`assistant`,model:e.model,content:[...t,...n],stop_reason:It(r),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 Kt(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 qt(e){return e?e.map(e=>({type:`tool_use`,id:e.id,name:e.function.name,input:JSON.parse(e.function.arguments)})):[]}async function Jt(e){try{let t=await e.req.text();if(n.debug(`Anthropic count_tokens payload:`,t.slice(0,1e3)),Nt(t)){let n=await Mt(t,e.req.raw.headers,`/v1/messages/count_tokens`);return new Response(n.body,{status:n.status,headers:Pt(n.headers)})}let r=e.req.header(`anthropic-beta`),i=JSON.parse(t),a=Lt(i),o=y.models?.data.find(e=>e.id===i.model);if(!o)return n.warn(`Model not found, returning default token count`),e.json({input_tokens:1});let s=await gt(a,o);if(i.tools&&i.tools.length>0){let e=!1;r?.startsWith(`claude-code`)&&(e=i.tools.some(e=>e.name.startsWith(`mcp__`))),e||(i.model.startsWith(`claude`)?s.input+=346:i.model.startsWith(`grok`)&&(s.input+=480))}let c=s.input+s.output;return i.model.startsWith(`claude`)?c=Math.round(c*1.15):i.model.startsWith(`grok`)&&(c=Math.round(c*1.03)),n.info(`Token count:`,c),e.json({input_tokens:c})}catch(t){return n.error(`Error counting tokens:`,t),e.json({input_tokens:1})}}function Yt(e){return e.contentBlockOpen?Object.values(e.toolCalls).some(t=>t.anthropicBlockIndex===e.contentBlockIndex):!1}function Xt(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&&(Yt(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:It(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}async function Zt(e){await H(y);let t=await e.req.text();if(n.debug(`Anthropic request payload:`,t.slice(0,1e3)),Nt(t)){y.manualApprove&&await V();let n=await Mt(t,e.req.raw.headers);return new Response(n.body,{status:n.status,headers:Pt(n.headers)})}let r=JSON.parse(t);n.debug(`Anthropic request payload:`,JSON.stringify(r));let i=Lt(r);n.debug(`Translated OpenAI request payload:`,JSON.stringify(i)),y.manualApprove&&await V();let a=await K(i);if(Qt(a)){n.debug(`Non-streaming response from Copilot:`,JSON.stringify(a).slice(-400));let t=Gt(a);return n.debug(`Translated Anthropic response:`,JSON.stringify(t)),e.json(t)}return n.debug(`Streaming response from Copilot`),m(e,async e=>{let t={messageStartSent:!1,contentBlockIndex:0,contentBlockOpen:!1,toolCalls:{}};for await(let r of a){if(n.debug(`Copilot raw stream event:`,JSON.stringify(r)),r.data===`[DONE]`)break;if(!r.data)continue;let i=JSON.parse(r.data),a=Xt(i,t);for(let t of a)n.debug(`Translated Anthropic event:`,JSON.stringify(t)),await e.writeSSE({event:t.type,data:JSON.stringify(t)})}})}const Qt=e=>Object.hasOwn(e,`choices`),X=new p;X.post(`/`,async e=>{try{return await Zt(e)}catch(t){return await O(e,t)}}),X.post(`/count_tokens`,async e=>{try{return await Jt(e)}catch(t){return await O(e,t)}});const Z=new p;Z.get(`/`,async e=>{try{y.models||await A();let t=y.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}));return e.json({object:`list`,data:t,has_more:!1})}catch(t){return await O(e,t)}});const $t=[`content-type`,`cache-control`,`x-request-id`];function en(e){return tn(e)?.model?.startsWith(`gpt`)??!1}function tn(e){try{return JSON.parse(e)}catch{return}}const nn=async(e,t)=>{let n=rn(e);return Ct({path:`/responses`,body:n,requestHeaders:t,initiator:`user`,errorMessage:`Failed to create responses`,throwOnError:!0})};function rn(e){let t=tn(e);if(!t?.tools||!Array.isArray(t.tools))return e;let n=new Set([`image_generation`]),r=t.tools.filter(e=>!n.has(e.type??``));return r.length===t.tools.length?e:(t.tools=r,JSON.stringify(t))}function an(e){return Tt(e,$t)}async function on(e){await H(y);let t=await e.req.text();if(!en(t))return e.json({error:{message:`Responses API is only enabled for GPT models.`,type:`invalid_request_error`}},400);y.manualApprove&&await V();let n=await nn(t,e.req.raw.headers);return new Response(n.body,{status:n.status,headers:an(n.headers)})}const Q=new p;Q.post(`/`,async e=>{try{return await on(e)}catch(t){return await O(e,t)}});const sn=new p;sn.get(`/`,e=>{try{return e.json({token:y.copilotToken})}catch(t){return B(`Error fetching token:`,t),e.json({error:`Failed to fetch token`,token:null},500)}});const cn=new p;cn.get(`/`,async e=>{try{let t=await F();return e.json(t)}catch(t){return B(`Error fetching Copilot usage:`,t),e.json({error:`Failed to fetch Copilot usage`},500)}});const $=new p;$.use(at()),$.use(ae()),$.route(`/`,xt),$.route(`/chat/completions`,q),$.route(`/models`,Z),$.route(`/embeddings`,J),$.route(`/responses`,Q),$.route(`/usage`,cn),$.route(`/token`,sn),$.route(`/v1/chat/completions`,q),$.route(`/v1/models`,Z),$.route(`/v1/embeddings`,J),$.route(`/v1/responses`,Q),$.route(`/v1/messages`,X);async function ln(e){e.proxyEnv&&it(),e.verbose&&(n.level=5,n.info(`Verbose logging enabled`)),y.accountType=e.accountType,e.accountType!==`individual`&&n.info(`Using ${e.accountType} plan GitHub account`),y.manualApprove=e.manual,y.rateLimitSeconds=e.rateLimit,y.rateLimitWait=e.rateLimitWait,y.showToken=e.showToken,await v(),await Le(),e.githubToken?(y.githubToken=e.githubToken,n.info(`Using provided GitHub token`)):await N(),await He(),await A(),n.info(`Available models: \n${y.models?.data.map(e=>`- ${e.id}`).join(` | ||
| `)}`);let t=`http://localhost:${e.port}`;n.box(`🌐 Usage Viewer: https://billxc.github.io/copilot-api?endpoint=${t}/usage`),f({fetch:$.fetch,port:e.port,idleTimeout:255})}const un=e({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)"},"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`}},run({args:e}){let t=e[`rate-limit`],n=t===void 0?void 0:Number.parseInt(t,10);return ln({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`],showToken:e[`show-token`],proxyEnv:e[`proxy-env`]})}}),dn=e({meta:{name:`xc-copilot-api`,version:h.version,description:`A wrapper around GitHub Copilot API to make it OpenAI compatible, making it usable for other tools.`},args:{version:{type:`boolean`,alias:`V`,description:`Show version number`}},run({args:e}){e.version&&(console.log(h.version),process.exit(0))},subCommands:{auth:We,start:un,config:Ye,"check-usage":Ge,debug:rt}});await t(dn);export{}; | ||
| //# sourceMappingURL=main.js.map |
+1
-1
| { | ||
| "name": "xc-copilot-api", | ||
| "version": "1.2.4", | ||
| "version": "1.2.5", | ||
| "description": "Turn GitHub Copilot into OpenAI/Anthropic API compatible server. Usable with Claude Code and Codex", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
Sorry, the diff of this file is too big to display
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
741
0.41%233586
-0.52%4
33.33%