@agimon-ai/model-proxy-mcp 0.8.3 → 0.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const e=require(`./stdio-
|
|
2
|
+
const e=require(`./stdio-L54-fUQ8.cjs`);let t=require(`@hono/node-server`),n=require(`node:path`);n=e.d(n,1);let r=require(`node:crypto`),i=require(`node:fs`),a=require(`node:url`),o=require(`node:fs/promises`);o=e.d(o,1);let s=require(`commander`),c=require(`node:child_process`),l=require(`node:util`),u=require(`@agimon-ai/foundation-port-registry`),d=require(`@agimon-ai/foundation-process-registry`);var f=class{async check(e){try{let t=await fetch(`http://127.0.0.1:${e}/health`);return t.ok?{healthy:!0,serviceName:(await t.json()).service}:{healthy:!1,error:`Health check failed with status ${t.status}`}}catch(e){return{healthy:!1,error:e instanceof Error?e.message:String(e)}}}};const p=[`pnpm-workspace.yaml`,`nx.json`,`.git`],m=`service`,h=(0,l.promisify)(c.execFile);function g(e=process.cwd()){let t=n.default.resolve(e);for(;;){for(let e of p)if((0,i.existsSync)(n.default.join(t,e)))return t;let e=n.default.dirname(t);if(e===t)return process.cwd();t=e}}var _=class{repositoryPath=g(process.cwd());serviceName=e.l;portRegistry;constructor(e=new f){this.healthCheck=e,this.portRegistry=new u.PortRegistryService(process.env.PORT_REGISTRY_PATH)}createEmptyStatus(e={}){return{running:!1,scope:`default`,activeProfileId:null,auth:{configured:!1,authFilePath:``},profiles:[],slotModels:{},...e}}async getRegistration(){let e=await this.portRegistry.getPort({repositoryPath:this.repositoryPath,serviceName:this.serviceName,serviceType:m});return!e.success||!e.record?null:{port:e.record.port,pid:e.record.pid}}async releaseService(e){await this.portRegistry.releasePort({repositoryPath:this.repositoryPath,serviceName:this.serviceName,serviceType:m,pid:e})}async listListeningProcesses(e){try{let{stdout:t}=await h(`sh`,[`-lc`,`lsof -n -P -sTCP:LISTEN -iTCP:${e} || true`],{encoding:`utf8`});return t.split(`
|
|
3
3
|
`).slice(1).map(e=>e.trim()).filter(Boolean).map(e=>e.split(/\s+/)).map(t=>({pid:Number.parseInt(t[1]||``,10),port:e})).filter(e=>Number.isInteger(e.pid)&&e.pid>0)}catch{return[]}}async findHealthyServicePort(){let e=await this.getRegistration();if(e){let t=await this.healthCheck.check(e.port);if(t.healthy&&t.serviceName===this.serviceName)return e.port}return null}async clearPortListeners(e,t){let n=await this.listListeningProcesses(e);for(let e of n)t&&e.pid===t||await this.killProcess(e.pid)}async registerService(e,t){await this.portRegistry.reservePort({repositoryPath:this.repositoryPath,serviceName:this.serviceName,serviceType:m,preferredPort:e,portRange:{min:e,max:e},pid:t,host:`127.0.0.1`,force:!0})}async findAvailablePort(t){let n=await this.portRegistry.findAvailablePort({repositoryPath:this.repositoryPath,serviceName:this.serviceName,serviceType:m,host:`127.0.0.1`,preferredPort:t,portRange:e.u});if(!n.success||n.port===void 0)throw Error(`No available port found from ${t}`);return n.port}async fileExists(e){try{return await o.default.access(e),!0}catch{return!1}}async resolveCliPath(){let e=n.default.dirname((0,a.fileURLToPath)(require(`url`).pathToFileURL(__filename).href)),t=n.default.resolve(e,`cli.mjs`);if(await this.fileExists(t))return{cliPath:t,runtime:`node`};let r=n.default.resolve(e,`..`,`cli.mjs`);if(await this.fileExists(r))return{cliPath:r,runtime:`node`};let i=n.default.join(this.repositoryPath,`packages`,`mcp`,`model-proxy-mcp`,`dist`,`cli.mjs`);if(await this.fileExists(i))return{cliPath:i,runtime:`node`};for(let t of[n.default.resolve(e,`cli.ts`),n.default.resolve(e,`..`,`cli.ts`)])if(await this.fileExists(t))return{cliPath:t,runtime:`bun`};let o=n.default.join(this.repositoryPath,`packages`,`mcp`,`model-proxy-mcp`,`src`,`cli.ts`);if(await this.fileExists(o))return{cliPath:o,runtime:`bun`};throw Error(`Cannot find model-proxy-mcp CLI`)}async startHttpServer(e){let{cliPath:t,runtime:n}=await this.resolveCliPath(),r=(0,c.spawn)(n===`bun`?process.versions.bun?process.execPath:`bun`:`node`,n===`bun`?[`run`,t,`http-serve`,`--port`,String(e)]:[t,`http-serve`,`--port`,String(e)],{detached:!0,stdio:`ignore`,env:{...process.env,NODE_ENV:process.env.NODE_ENV||`development`}});if(r.unref(),!r.pid)throw Error(`Failed to spawn HTTP server`);return r.pid}async killProcess(e){try{process.kill(e,`SIGTERM`),await new Promise(e=>setTimeout(e,1e3));try{process.kill(e,0),process.kill(e,`SIGKILL`)}catch{return}}catch{return}}async waitForHealthy(e){let t=Date.now()+5e3,n=`Server failed health check after startup`;for(;Date.now()<t;){let t=await this.healthCheck.check(e);if(t.healthy&&t.serviceName===this.serviceName)return{healthy:!0};n=t.error||`Unexpected service on port ${e}`,await new Promise(e=>setTimeout(e,250))}return{healthy:!1,error:n}}async ensureRunning(t=e.c){try{let e=await this.findHealthyServicePort();if(e!==null){let t=(await this.listListeningProcesses(e))[0]?.pid;return await this.registerService(e,t??process.pid),this.createEmptyStatus({running:!0,port:e,pid:t})}let n=await this.getRegistration();if(n){let e=await this.healthCheck.check(n.port);if(e.healthy&&e.serviceName===this.serviceName)return this.createEmptyStatus({running:!0,port:n.port,pid:n.pid});n.pid&&await this.killProcess(n.pid),await this.clearPortListeners(n.port,n.pid),await this.releaseService(n.pid)}await this.clearPortListeners(t);let r=await this.findAvailablePort(t),i=await this.startHttpServer(r),a=await this.waitForHealthy(r);return a.healthy?(await this.registerService(r,i),this.createEmptyStatus({running:!0,port:r,pid:i})):(await this.killProcess(i),await this.clearPortListeners(r,i),await this.releaseService(i),this.createEmptyStatus({error:a.error||`Server failed health check after startup`}))}catch(e){return this.createEmptyStatus({error:e instanceof Error?e.message:String(e)})}}startHealthMonitor(e,t=1e4){let n=!1,r=0,i=2e3,a=6e4,o=async()=>{if(!n)try{if((await this.getStatus()).running)r=0,n||setTimeout(()=>void o(),t);else{r++;let t=Math.min(i*2**(r-1),a);await this.ensureRunning(e),n||setTimeout(()=>void o(),t)}}catch{r++;let e=Math.min(i*2**(r-1),a);n||setTimeout(()=>void o(),e)}};return setTimeout(()=>void o(),t),()=>{n=!0}}async stop(){let e=await this.getRegistration(),t=!1;e?.pid&&(await this.killProcess(e.pid),t=!0),e&&(await this.clearPortListeners(e.port,e.pid),await this.releaseService(e.pid));let n=await this.findHealthyServicePort();if(n!==null){let e=await this.listListeningProcesses(n);for(let n of e)await this.killProcess(n.pid),t=!0;await this.releaseService()}return t}async getStatus(){let e=await this.getRegistration();if(e&&(await this.healthCheck.check(e.port)).healthy)return this.createEmptyStatus({running:!0,port:e.port,pid:e.pid});let t=await this.findHealthyServicePort();if(t!==null){let e=(await this.listListeningProcesses(t))[0]?.pid;return e&&await this.registerService(t,e),this.createEmptyStatus({running:!0,port:t,pid:e})}return this.createEmptyStatus({error:e?`Registered server is unhealthy`:`No HTTP server registered`})}};const v=`claude`,y=`utf8`,b=`[model-proxy-mcp]`,x=`Recovery: verify HOME, proxy port, and that \`${v}\` is on PATH.`;var S=class extends Error{constructor(e,t,n){super(e,n),this.code=t,this.name=`ClaudeCommandError`}},C=class extends S{constructor(e,t){super(e,`CLAUDE_COMMAND_CONFIG_ERROR`,t),this.name=`ClaudeCommandConfigError`}},w=class extends S{constructor(e,t){super(e,`CLAUDE_COMMAND_VALIDATION_ERROR`,t),this.name=`ClaudeCommandValidationError`}},T=class extends S{constructor(e,t){super(e,`CLAUDE_COMMAND_LAUNCH_ERROR`,t),this.name=`ClaudeCommandLaunchError`}};function E(e){return e.trim().replace(/[^a-zA-Z0-9._-]+/g,`-`).replace(/^-+|-+$/g,``)||`default`}function D(){return`scope-${(0,r.randomBytes)(3).toString(`hex`)}`}function O(e,t,n=process.env){return{...n,ANTHROPIC_BASE_URL:`http://127.0.0.1:${e}/scopes/${t}`,ANTHROPIC_DEFAULT_OPUS_MODEL:n.ANTHROPIC_DEFAULT_OPUS_MODEL||`ccproxy-opus`,ANTHROPIC_DEFAULT_SONNET_MODEL:n.ANTHROPIC_DEFAULT_SONNET_MODEL||`ccproxy-sonnet`,ANTHROPIC_DEFAULT_HAIKU_MODEL:n.ANTHROPIC_DEFAULT_HAIKU_MODEL||`ccproxy-haiku`,CLAUDE_CODE_SUBAGENT_MODEL:n.CLAUDE_CODE_SUBAGENT_MODEL||`ccproxy-subagent`,MODEL_PROXY_MCP_SCOPE:n.MODEL_PROXY_MCP_SCOPE||t,MODEL_PROXY_MCP_SLOT:n.MODEL_PROXY_MCP_SLOT||`default`}}async function k(e,t=process.cwd()){let r=e?n.default.resolve(t,e):n.default.join(t,`model-proxy-mcp.yaml`);try{if(!(await o.default.stat(r)).isFile()){if(e)throw new C(`Scope seed config path is not a file: ${r}`);return}return r}catch(t){if(t.code===`ENOENT`){if(e)throw new C(`Scope seed config file not found: ${r}`,{cause:t});return}throw t instanceof C?t:new C(`Failed to read scope seed config file: ${r}`,{cause:t})}}function A(){let e=process.env.HOME||process.env.USERPROFILE;if(!e)throw new C(`HOME or USERPROFILE is not set`);return n.default.join(e,`.claude-sessions`)}async function j(){let e=A();return await o.default.mkdir(e,{recursive:!0}),e}async function M(e){try{return(await o.default.readFile(e,y)).trim()||null}catch(t){if(t.code===`ENOENT`)return null;throw new C(`Failed to read Claude session file: ${e}`,{cause:t})}}async function N(e,t){let i=await j(),a=n.default.join(i,e);if(t)try{await o.default.rm(a,{force:!0})}catch(e){throw new C(`Failed to clear Claude session file: ${a}`,{cause:e})}let s=await M(a);if(s)return{sessionId:s,resume:!0};let c=(0,r.randomUUID)().toLowerCase();try{await o.default.writeFile(a,`${c}\n`,y)}catch(e){throw new C(`Failed to write Claude session file: ${a}`,{cause:e})}return{sessionId:c,resume:!1}}async function P(t,n,r,i,a){let o=await k(a);await new e.a().ensureConfig(t,o);let s=await new _().ensureRunning(n);if(!s.running||!s.port)throw new T(s.error||`Failed to start model proxy HTTP server`);let{sessionId:l,resume:u}=await N(t,r),d=O(s.port,t),f=[`--dangerously-skip-permissions`,...u?[`--resume`,l]:[`--session-id`,l],...i];return console.log(`${b} Scope: ${t}`),console.log(`${b} Proxy: ${d.ANTHROPIC_BASE_URL}`),console.log(`${b} Session: ${l}${u?` (resume)`:` (new)`}`),o&&console.log(`${b} Scope config seed: ${o}`),new Promise((e,t)=>{let n=(0,c.spawn)(v,f,{stdio:`inherit`,env:d});n.on(`error`,e=>{t(new T(`Failed to launch ${v}`,{cause:e}))}),n.on(`exit`,(n,r)=>{if(r){t(new T(`${v} exited with signal ${r}`));return}e(n??0)})})}const F=new s.Command(`claude`).description(`Launch Claude Code through the model proxy`).option(`-s, --scope <scope>`,`Proxy scope to use`).option(`-p, --port <port>`,`Preferred HTTP port for the proxy`,String(e.c)).option(`-c, --config-file <path>`,`Seed a new scope from the specified scope config file`).option(`--config <path>`,`Alias for --config-file`).option(`--clear-session`,`Start with a fresh Claude session for the selected scope`,!1).allowUnknownOption(!0).allowExcessArguments(!0).argument(`[claudeArgs...]`).action(async(e,t)=>{try{let n=E(t.scope||D()),r=Number.parseInt(t.port,10);if(!Number.isInteger(r)||r<=0)throw new w(`Invalid port: ${t.port}`);let i=await P(n,r,t.clearSession,e,t.configFile??t.config);process.exit(i)}catch(e){let t=e instanceof S?e:new T(`Failed to launch Claude`,{cause:e});console.error(`${b} ${t.code}: ${t.message}`),console.error(`${b} ${x}`),t.cause&&console.error(`${b} Cause:`,t.cause),process.exit(1)}}),I=`127.0.0.1`,L=[`pnpm-workspace.yaml`,`nx.json`,`.git`],R=`service`;function z(e=process.cwd()){let t=n.default.resolve(e);for(;;){for(let e of L)if((0,i.existsSync)(n.default.join(t,e)))return t;let e=n.default.dirname(t);if(e===t)return process.cwd();t=e}}const B=new s.Command(`http-serve`).description(`Start the Claude-compatible HTTP model proxy server`).option(`-p, --port <port>`,`Port to listen on`,String(e.c)).action(async n=>{let r;try{let i=Number.parseInt(n.port,10);if(!Number.isInteger(i)||i<=0)throw Error(`Invalid port: ${n.port}`);let a=new u.PortRegistryService(process.env.PORT_REGISTRY_PATH),o=z(),s=await a.reservePort({repositoryPath:o,serviceName:e.l,serviceType:R,preferredPort:i,portRange:e.u,pid:process.pid,host:I,force:!0});if(!s.success||!s.record)throw Error(s.error||`Failed to reserve port ${i}`);let c=s.record.port;r=await(0,d.createProcessLease)({repositoryPath:o,serviceName:e.l,serviceType:R,pid:process.pid,port:c,host:I,command:process.argv[1],args:process.argv.slice(2)});let l=new e.i;await l.ensureConfig();let f=(0,t.serve)({fetch:e.r(l).fetch,port:c,hostname:I});console.log(`model-proxy-mcp listening on http://${I}:${c}`),console.log(`Claude base URL: http://${I}:${c}`);let p=async t=>{console.log(`\n${t} received. Shutting down...`),f.close(),await r?.release(),await a.releasePort({repositoryPath:o,serviceName:e.l,serviceType:R,pid:process.pid}),process.exit(0)};process.once(`SIGINT`,()=>p(`SIGINT`)),process.once(`SIGTERM`,()=>p(`SIGTERM`))}catch(e){await r?.release(),console.error(`Failed to start HTTP server:`,e),process.exit(1)}}),V=new s.Command(`mcp-serve`).description(`Start MCP server with stdio transport`).option(`--cleanup`,`Stop HTTP server on shutdown`,!1).option(`-p, --port <port>`,`Port for HTTP server`,String(e.c)).action(async t=>{try{let n=Number.parseInt(t.port,10);if(!Number.isInteger(n)||n<=0)throw Error(`Invalid port: ${t.port}`);let r=new e.i;await r.ensureConfig(process.env.MODEL_PROXY_MCP_SCOPE||`default`);let i=new _,a=await i.ensureRunning(n);a.running||console.error(`Warning: HTTP server failed to start: ${a.error}`);let o;a.running&&(o=i.startHealthMonitor(n));let s=new e.t(e.n(r)),c=async e=>{console.error(`\nReceived ${e}, shutting down gracefully...`),o?.(),await s.stop(),t.cleanup&&a.running&&await i.stop(),process.exit(0)};process.once(`SIGINT`,()=>void c(`SIGINT`).catch(e=>{console.error(`Failed to shut down after SIGINT:`,e),process.exit(1)})),process.once(`SIGTERM`,()=>void c(`SIGTERM`).catch(e=>{console.error(`Failed to shut down after SIGTERM:`,e),process.exit(1)})),await s.start()}catch(e){console.error(`Failed to start MCP server:`,e),process.exit(1)}}),H=new s.Command(`start`).description(`Start HTTP and/or MCP server for the model proxy`).option(`--mcp-only`,`Start only the MCP server`,!1).option(`--http-only`,`Start only the HTTP server`,!1).option(`-p, --port <port>`,`Port for HTTP server`,String(e.c)).action(async t=>{try{let n=new _,r=Number.parseInt(t.port,10),i=!t.mcpOnly,a=!t.httpOnly;if(i){let e=await n.ensureRunning(r);e.running||(console.error(`HTTP server failed to start: ${e.error}`),process.exit(1)),console.log(`HTTP server running on http://127.0.0.1:${e.port}`)}if(a){let t=new e.t(e.n());await t.start();let n=async e=>{console.error(`\n${e} received. Shutting down...`),await t.stop(),process.exit(0)};process.on(`SIGINT`,()=>n(`SIGINT`)),process.on(`SIGTERM`,()=>n(`SIGTERM`))}else process.exit(0)}catch(e){console.error(`Failed to start services:`,e),process.exit(1)}}),U=`status`,W=`Failed to read status`;var G=class extends Error{code=`STATUS_CHECK_FAILED`;constructor(e){super(W,{cause:e instanceof Error?e:Error(String(e))}),this.name=`StatusCommandError`}};const K=new s.Command(U).description(`Show proxy server and profile status`).option(`-s, --scope <scope>`,`Configuration scope`,`default`).action(async t=>{try{let n=await new _().getStatus(),r=await new e.i().getStatus(t.scope,n.port,n.pid);r.running=n.running,r.error=n.error,e.s.info(JSON.stringify(r,null,2)),process.exit(0)}catch(n){let r=new G(n);e.s.error(W,{command:U,code:r.code,scope:t.scope,cause:r.cause}),process.exit(1)}}),q=new s.Command(`stop`).description(`Stop the background HTTP server`).action(async()=>{try{let e=await new _().stop();console.log(e?`HTTP server stopped`:`No HTTP server running`),process.exit(0)}catch(e){console.error(`Failed to stop HTTP server:`,e),process.exit(1)}}),J=(0,n.dirname)((0,a.fileURLToPath)(require(`url`).pathToFileURL(__filename).href)),Y=JSON.parse((0,i.readFileSync)((0,n.join)(J,`../package.json`),`utf-8`));async function X(){let e=new s.Command;e.name(`model-proxy-mcp`).description(`Claude-compatible model proxy MCP`).version(Y.version),e.addCommand(H),e.addCommand(q),e.addCommand(K),e.addCommand(F),e.addCommand(B),e.addCommand(V),await e.parseAsync(process.argv)}X();
|
package/dist/cli.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{a as e,c as t,i as n,l as r,n as i,r as a,s as o,t as s,u as c}from"./stdio-
|
|
2
|
+
import{a as e,c as t,i as n,l as r,n as i,r as a,s as o,t as s,u as c}from"./stdio-CzhlIG22.mjs";import{serve as l}from"@hono/node-server";import u,{dirname as d,join as f}from"node:path";import{randomBytes as p,randomUUID as m}from"node:crypto";import{existsSync as h,readFileSync as g}from"node:fs";import{fileURLToPath as _}from"node:url";import v from"node:fs/promises";import{Command as y}from"commander";import{execFile as ee,spawn as b}from"node:child_process";import{promisify as x}from"node:util";import{PortRegistryService as S}from"@agimon-ai/foundation-port-registry";import{createProcessLease as C}from"@agimon-ai/foundation-process-registry";var w=class{async check(e){try{let t=await fetch(`http://127.0.0.1:${e}/health`);return t.ok?{healthy:!0,serviceName:(await t.json()).service}:{healthy:!1,error:`Health check failed with status ${t.status}`}}catch(e){return{healthy:!1,error:e instanceof Error?e.message:String(e)}}}};const T=[`pnpm-workspace.yaml`,`nx.json`,`.git`],E=`service`,D=x(ee);function O(e=process.cwd()){let t=u.resolve(e);for(;;){for(let e of T)if(h(u.join(t,e)))return t;let e=u.dirname(t);if(e===t)return process.cwd();t=e}}var k=class{repositoryPath=O(process.cwd());serviceName=r;portRegistry;constructor(e=new w){this.healthCheck=e,this.portRegistry=new S(process.env.PORT_REGISTRY_PATH)}createEmptyStatus(e={}){return{running:!1,scope:`default`,activeProfileId:null,auth:{configured:!1,authFilePath:``},profiles:[],slotModels:{},...e}}async getRegistration(){let e=await this.portRegistry.getPort({repositoryPath:this.repositoryPath,serviceName:this.serviceName,serviceType:E});return!e.success||!e.record?null:{port:e.record.port,pid:e.record.pid}}async releaseService(e){await this.portRegistry.releasePort({repositoryPath:this.repositoryPath,serviceName:this.serviceName,serviceType:E,pid:e})}async listListeningProcesses(e){try{let{stdout:t}=await D(`sh`,[`-lc`,`lsof -n -P -sTCP:LISTEN -iTCP:${e} || true`],{encoding:`utf8`});return t.split(`
|
|
3
3
|
`).slice(1).map(e=>e.trim()).filter(Boolean).map(e=>e.split(/\s+/)).map(t=>({pid:Number.parseInt(t[1]||``,10),port:e})).filter(e=>Number.isInteger(e.pid)&&e.pid>0)}catch{return[]}}async findHealthyServicePort(){let e=await this.getRegistration();if(e){let t=await this.healthCheck.check(e.port);if(t.healthy&&t.serviceName===this.serviceName)return e.port}return null}async clearPortListeners(e,t){let n=await this.listListeningProcesses(e);for(let e of n)t&&e.pid===t||await this.killProcess(e.pid)}async registerService(e,t){await this.portRegistry.reservePort({repositoryPath:this.repositoryPath,serviceName:this.serviceName,serviceType:E,preferredPort:e,portRange:{min:e,max:e},pid:t,host:`127.0.0.1`,force:!0})}async findAvailablePort(e){let t=await this.portRegistry.findAvailablePort({repositoryPath:this.repositoryPath,serviceName:this.serviceName,serviceType:E,host:`127.0.0.1`,preferredPort:e,portRange:c});if(!t.success||t.port===void 0)throw Error(`No available port found from ${e}`);return t.port}async fileExists(e){try{return await v.access(e),!0}catch{return!1}}async resolveCliPath(){let e=u.dirname(_(import.meta.url)),t=u.resolve(e,`cli.mjs`);if(await this.fileExists(t))return{cliPath:t,runtime:`node`};let n=u.resolve(e,`..`,`cli.mjs`);if(await this.fileExists(n))return{cliPath:n,runtime:`node`};let r=u.join(this.repositoryPath,`packages`,`mcp`,`model-proxy-mcp`,`dist`,`cli.mjs`);if(await this.fileExists(r))return{cliPath:r,runtime:`node`};for(let t of[u.resolve(e,`cli.ts`),u.resolve(e,`..`,`cli.ts`)])if(await this.fileExists(t))return{cliPath:t,runtime:`bun`};let i=u.join(this.repositoryPath,`packages`,`mcp`,`model-proxy-mcp`,`src`,`cli.ts`);if(await this.fileExists(i))return{cliPath:i,runtime:`bun`};throw Error(`Cannot find model-proxy-mcp CLI`)}async startHttpServer(e){let{cliPath:t,runtime:n}=await this.resolveCliPath(),r=b(n===`bun`?process.versions.bun?process.execPath:`bun`:`node`,n===`bun`?[`run`,t,`http-serve`,`--port`,String(e)]:[t,`http-serve`,`--port`,String(e)],{detached:!0,stdio:`ignore`,env:{...process.env,NODE_ENV:process.env.NODE_ENV||`development`}});if(r.unref(),!r.pid)throw Error(`Failed to spawn HTTP server`);return r.pid}async killProcess(e){try{process.kill(e,`SIGTERM`),await new Promise(e=>setTimeout(e,1e3));try{process.kill(e,0),process.kill(e,`SIGKILL`)}catch{return}}catch{return}}async waitForHealthy(e){let t=Date.now()+5e3,n=`Server failed health check after startup`;for(;Date.now()<t;){let t=await this.healthCheck.check(e);if(t.healthy&&t.serviceName===this.serviceName)return{healthy:!0};n=t.error||`Unexpected service on port ${e}`,await new Promise(e=>setTimeout(e,250))}return{healthy:!1,error:n}}async ensureRunning(e=t){try{let t=await this.findHealthyServicePort();if(t!==null){let e=(await this.listListeningProcesses(t))[0]?.pid;return await this.registerService(t,e??process.pid),this.createEmptyStatus({running:!0,port:t,pid:e})}let n=await this.getRegistration();if(n){let e=await this.healthCheck.check(n.port);if(e.healthy&&e.serviceName===this.serviceName)return this.createEmptyStatus({running:!0,port:n.port,pid:n.pid});n.pid&&await this.killProcess(n.pid),await this.clearPortListeners(n.port,n.pid),await this.releaseService(n.pid)}await this.clearPortListeners(e);let r=await this.findAvailablePort(e),i=await this.startHttpServer(r),a=await this.waitForHealthy(r);return a.healthy?(await this.registerService(r,i),this.createEmptyStatus({running:!0,port:r,pid:i})):(await this.killProcess(i),await this.clearPortListeners(r,i),await this.releaseService(i),this.createEmptyStatus({error:a.error||`Server failed health check after startup`}))}catch(e){return this.createEmptyStatus({error:e instanceof Error?e.message:String(e)})}}startHealthMonitor(e,t=1e4){let n=!1,r=0,i=2e3,a=6e4,o=async()=>{if(!n)try{if((await this.getStatus()).running)r=0,n||setTimeout(()=>void o(),t);else{r++;let t=Math.min(i*2**(r-1),a);await this.ensureRunning(e),n||setTimeout(()=>void o(),t)}}catch{r++;let e=Math.min(i*2**(r-1),a);n||setTimeout(()=>void o(),e)}};return setTimeout(()=>void o(),t),()=>{n=!0}}async stop(){let e=await this.getRegistration(),t=!1;e?.pid&&(await this.killProcess(e.pid),t=!0),e&&(await this.clearPortListeners(e.port,e.pid),await this.releaseService(e.pid));let n=await this.findHealthyServicePort();if(n!==null){let e=await this.listListeningProcesses(n);for(let n of e)await this.killProcess(n.pid),t=!0;await this.releaseService()}return t}async getStatus(){let e=await this.getRegistration();if(e&&(await this.healthCheck.check(e.port)).healthy)return this.createEmptyStatus({running:!0,port:e.port,pid:e.pid});let t=await this.findHealthyServicePort();if(t!==null){let e=(await this.listListeningProcesses(t))[0]?.pid;return e&&await this.registerService(t,e),this.createEmptyStatus({running:!0,port:t,pid:e})}return this.createEmptyStatus({error:e?`Registered server is unhealthy`:`No HTTP server registered`})}};const A=`claude`,j=`utf8`,M=`[model-proxy-mcp]`,te=`Recovery: verify HOME, proxy port, and that \`${A}\` is on PATH.`;var N=class extends Error{constructor(e,t,n){super(e,n),this.code=t,this.name=`ClaudeCommandError`}},P=class extends N{constructor(e,t){super(e,`CLAUDE_COMMAND_CONFIG_ERROR`,t),this.name=`ClaudeCommandConfigError`}},F=class extends N{constructor(e,t){super(e,`CLAUDE_COMMAND_VALIDATION_ERROR`,t),this.name=`ClaudeCommandValidationError`}},I=class extends N{constructor(e,t){super(e,`CLAUDE_COMMAND_LAUNCH_ERROR`,t),this.name=`ClaudeCommandLaunchError`}};function L(e){return e.trim().replace(/[^a-zA-Z0-9._-]+/g,`-`).replace(/^-+|-+$/g,``)||`default`}function R(){return`scope-${p(3).toString(`hex`)}`}function z(e,t,n=process.env){return{...n,ANTHROPIC_BASE_URL:`http://127.0.0.1:${e}/scopes/${t}`,ANTHROPIC_DEFAULT_OPUS_MODEL:n.ANTHROPIC_DEFAULT_OPUS_MODEL||`ccproxy-opus`,ANTHROPIC_DEFAULT_SONNET_MODEL:n.ANTHROPIC_DEFAULT_SONNET_MODEL||`ccproxy-sonnet`,ANTHROPIC_DEFAULT_HAIKU_MODEL:n.ANTHROPIC_DEFAULT_HAIKU_MODEL||`ccproxy-haiku`,CLAUDE_CODE_SUBAGENT_MODEL:n.CLAUDE_CODE_SUBAGENT_MODEL||`ccproxy-subagent`,MODEL_PROXY_MCP_SCOPE:n.MODEL_PROXY_MCP_SCOPE||t,MODEL_PROXY_MCP_SLOT:n.MODEL_PROXY_MCP_SLOT||`default`}}async function B(e,t=process.cwd()){let n=e?u.resolve(t,e):u.join(t,`model-proxy-mcp.yaml`);try{if(!(await v.stat(n)).isFile()){if(e)throw new P(`Scope seed config path is not a file: ${n}`);return}return n}catch(t){if(t.code===`ENOENT`){if(e)throw new P(`Scope seed config file not found: ${n}`,{cause:t});return}throw t instanceof P?t:new P(`Failed to read scope seed config file: ${n}`,{cause:t})}}function V(){let e=process.env.HOME||process.env.USERPROFILE;if(!e)throw new P(`HOME or USERPROFILE is not set`);return u.join(e,`.claude-sessions`)}async function H(){let e=V();return await v.mkdir(e,{recursive:!0}),e}async function U(e){try{return(await v.readFile(e,j)).trim()||null}catch(t){if(t.code===`ENOENT`)return null;throw new P(`Failed to read Claude session file: ${e}`,{cause:t})}}async function W(e,t){let n=await H(),r=u.join(n,e);if(t)try{await v.rm(r,{force:!0})}catch(e){throw new P(`Failed to clear Claude session file: ${r}`,{cause:e})}let i=await U(r);if(i)return{sessionId:i,resume:!0};let a=m().toLowerCase();try{await v.writeFile(r,`${a}\n`,j)}catch(e){throw new P(`Failed to write Claude session file: ${r}`,{cause:e})}return{sessionId:a,resume:!1}}async function G(t,n,r,i,a){let o=await B(a);await new e().ensureConfig(t,o);let s=await new k().ensureRunning(n);if(!s.running||!s.port)throw new I(s.error||`Failed to start model proxy HTTP server`);let{sessionId:c,resume:l}=await W(t,r),u=z(s.port,t),d=[`--dangerously-skip-permissions`,...l?[`--resume`,c]:[`--session-id`,c],...i];return console.log(`${M} Scope: ${t}`),console.log(`${M} Proxy: ${u.ANTHROPIC_BASE_URL}`),console.log(`${M} Session: ${c}${l?` (resume)`:` (new)`}`),o&&console.log(`${M} Scope config seed: ${o}`),new Promise((e,t)=>{let n=b(A,d,{stdio:`inherit`,env:u});n.on(`error`,e=>{t(new I(`Failed to launch ${A}`,{cause:e}))}),n.on(`exit`,(n,r)=>{if(r){t(new I(`${A} exited with signal ${r}`));return}e(n??0)})})}const K=new y(`claude`).description(`Launch Claude Code through the model proxy`).option(`-s, --scope <scope>`,`Proxy scope to use`).option(`-p, --port <port>`,`Preferred HTTP port for the proxy`,String(t)).option(`-c, --config-file <path>`,`Seed a new scope from the specified scope config file`).option(`--config <path>`,`Alias for --config-file`).option(`--clear-session`,`Start with a fresh Claude session for the selected scope`,!1).allowUnknownOption(!0).allowExcessArguments(!0).argument(`[claudeArgs...]`).action(async(e,t)=>{try{let n=L(t.scope||R()),r=Number.parseInt(t.port,10);if(!Number.isInteger(r)||r<=0)throw new F(`Invalid port: ${t.port}`);let i=await G(n,r,t.clearSession,e,t.configFile??t.config);process.exit(i)}catch(e){let t=e instanceof N?e:new I(`Failed to launch Claude`,{cause:e});console.error(`${M} ${t.code}: ${t.message}`),console.error(`${M} ${te}`),t.cause&&console.error(`${M} Cause:`,t.cause),process.exit(1)}}),q=`127.0.0.1`,J=[`pnpm-workspace.yaml`,`nx.json`,`.git`],Y=`service`;function X(e=process.cwd()){let t=u.resolve(e);for(;;){for(let e of J)if(h(u.join(t,e)))return t;let e=u.dirname(t);if(e===t)return process.cwd();t=e}}const Z=new y(`http-serve`).description(`Start the Claude-compatible HTTP model proxy server`).option(`-p, --port <port>`,`Port to listen on`,String(t)).action(async e=>{let t;try{let i=Number.parseInt(e.port,10);if(!Number.isInteger(i)||i<=0)throw Error(`Invalid port: ${e.port}`);let o=new S(process.env.PORT_REGISTRY_PATH),s=X(),u=await o.reservePort({repositoryPath:s,serviceName:r,serviceType:Y,preferredPort:i,portRange:c,pid:process.pid,host:q,force:!0});if(!u.success||!u.record)throw Error(u.error||`Failed to reserve port ${i}`);let d=u.record.port;t=await C({repositoryPath:s,serviceName:r,serviceType:Y,pid:process.pid,port:d,host:q,command:process.argv[1],args:process.argv.slice(2)});let f=new n;await f.ensureConfig();let p=l({fetch:a(f).fetch,port:d,hostname:q});console.log(`model-proxy-mcp listening on http://${q}:${d}`),console.log(`Claude base URL: http://${q}:${d}`);let m=async e=>{console.log(`\n${e} received. Shutting down...`),p.close(),await t?.release(),await o.releasePort({repositoryPath:s,serviceName:r,serviceType:Y,pid:process.pid}),process.exit(0)};process.once(`SIGINT`,()=>m(`SIGINT`)),process.once(`SIGTERM`,()=>m(`SIGTERM`))}catch(e){await t?.release(),console.error(`Failed to start HTTP server:`,e),process.exit(1)}}),ne=new y(`mcp-serve`).description(`Start MCP server with stdio transport`).option(`--cleanup`,`Stop HTTP server on shutdown`,!1).option(`-p, --port <port>`,`Port for HTTP server`,String(t)).action(async e=>{try{let t=Number.parseInt(e.port,10);if(!Number.isInteger(t)||t<=0)throw Error(`Invalid port: ${e.port}`);let r=new n;await r.ensureConfig(process.env.MODEL_PROXY_MCP_SCOPE||`default`);let a=new k,o=await a.ensureRunning(t);o.running||console.error(`Warning: HTTP server failed to start: ${o.error}`);let c;o.running&&(c=a.startHealthMonitor(t));let l=new s(i(r)),u=async t=>{console.error(`\nReceived ${t}, shutting down gracefully...`),c?.(),await l.stop(),e.cleanup&&o.running&&await a.stop(),process.exit(0)};process.once(`SIGINT`,()=>void u(`SIGINT`).catch(e=>{console.error(`Failed to shut down after SIGINT:`,e),process.exit(1)})),process.once(`SIGTERM`,()=>void u(`SIGTERM`).catch(e=>{console.error(`Failed to shut down after SIGTERM:`,e),process.exit(1)})),await l.start()}catch(e){console.error(`Failed to start MCP server:`,e),process.exit(1)}}),re=new y(`start`).description(`Start HTTP and/or MCP server for the model proxy`).option(`--mcp-only`,`Start only the MCP server`,!1).option(`--http-only`,`Start only the HTTP server`,!1).option(`-p, --port <port>`,`Port for HTTP server`,String(t)).action(async e=>{try{let t=new k,n=Number.parseInt(e.port,10),r=!e.mcpOnly,a=!e.httpOnly;if(r){let e=await t.ensureRunning(n);e.running||(console.error(`HTTP server failed to start: ${e.error}`),process.exit(1)),console.log(`HTTP server running on http://127.0.0.1:${e.port}`)}if(a){let e=new s(i());await e.start();let t=async t=>{console.error(`\n${t} received. Shutting down...`),await e.stop(),process.exit(0)};process.on(`SIGINT`,()=>t(`SIGINT`)),process.on(`SIGTERM`,()=>t(`SIGTERM`))}else process.exit(0)}catch(e){console.error(`Failed to start services:`,e),process.exit(1)}}),Q=`status`,$=`Failed to read status`;var ie=class extends Error{code=`STATUS_CHECK_FAILED`;constructor(e){super($,{cause:e instanceof Error?e:Error(String(e))}),this.name=`StatusCommandError`}};const ae=new y(Q).description(`Show proxy server and profile status`).option(`-s, --scope <scope>`,`Configuration scope`,`default`).action(async e=>{try{let t=await new k().getStatus(),r=await new n().getStatus(e.scope,t.port,t.pid);r.running=t.running,r.error=t.error,o.info(JSON.stringify(r,null,2)),process.exit(0)}catch(t){let n=new ie(t);o.error($,{command:Q,code:n.code,scope:e.scope,cause:n.cause}),process.exit(1)}}),oe=new y(`stop`).description(`Stop the background HTTP server`).action(async()=>{try{let e=await new k().stop();console.log(e?`HTTP server stopped`:`No HTTP server running`),process.exit(0)}catch(e){console.error(`Failed to stop HTTP server:`,e),process.exit(1)}}),se=d(_(import.meta.url)),ce=JSON.parse(g(f(se,`../package.json`),`utf-8`));async function le(){let e=new y;e.name(`model-proxy-mcp`).description(`Claude-compatible model proxy MCP`).version(ce.version),e.addCommand(re),e.addCommand(oe),e.addCommand(ae),e.addCommand(K),e.addCommand(Z),e.addCommand(ne),await e.parseAsync(process.argv)}le();export{};
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./stdio-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./stdio-L54-fUQ8.cjs`);exports.ConversationHistoryService=e.o,exports.GatewayService=e.i,exports.ProfileStore=e.a,exports.StdioTransportHandler=e.t,exports.createHttpServer=e.r,exports.createServer=e.n;
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,i as t,n,o as r,r as i,t as a}from"./stdio-
|
|
1
|
+
import{a as e,i as t,n,o as r,r as i,t as a}from"./stdio-CzhlIG22.mjs";export{r as ConversationHistoryService,t as GatewayService,e as ProfileStore,a as StdioTransportHandler,i as createHttpServer,n as createServer};
|
|
@@ -11,7 +11,7 @@ import"@hono/node-server";import{Hono as e}from"hono";import{ZodError as t,z as
|
|
|
11
11
|
|
|
12
12
|
`),a=r?``:i.pop()??``;for(let e of i)this.processSseChunk(e,t,n);return r&&a.trim()&&this.processSseChunk(a,t,n),a}processSseChunk(e,t,n){let r=e.split(`
|
|
13
13
|
`),i=``,a=[];for(let e of r){let t=e.replace(/\r$/,``);t.startsWith(`event:`)?i=t.slice(6).trim():t.startsWith(`data:`)&&a.push(t.slice(5).trim())}let o=a.join(`
|
|
14
|
-
`).trim();if(!(!o||o===`[DONE]`))try{let e=JSON.parse(o),r=typeof e?.type==`string`?e.type:i,a=r.startsWith(`response.`)||i.startsWith(`response.`);if(e?.error||r===`response.error`){let r=e?.error?.message||e?.error?.error||e?.message||(typeof e?.error==`string`?e.error:`Unexpected API error`);this.emitStreamingError(n,t,r);return}if(a){this.processResponsesStreamingEvent(r,e,t,n);return}this.processChatCompletionStreamingChunk(e,t,n)}catch{}}processResponsesStreamingEvent(e,t,n,r){switch(t?.model&&typeof t.model==`string`&&(n.model=t.model),e){case`response.created`:typeof t?.response?.model==`string`&&(n.model=t.response.model);break;case`response.reasoning.delta`:case`response.reasoning_summary_text.delta`:{let e=[];this.markStreamedContentKey(t,n.streamedReasoningKeys,`reasoning`),this.collectTextFromNode(t?.delta??t?.text??t?.summary_text,e);for(let t of e)this.emitThinkingDelta(r,n,t);break}case`response.output_text.delta`:case`response.delta`:{let e=[];this.markStreamedContentKey(t,n.streamedTextKeys,`text`),this.collectTextFromNode(t?.delta??t?.output_text,e);for(let t of e)this.emitTextDelta(r,n,t);t?.delta?.tool_calls&&this.collectToolCalls(t.delta.tool_calls,n.toolCalls);break}case`response.function_call_arguments.delta`:case`response.function_call_arguments.done`:case`response.output_item.added`:case`response.output_item.done`:if(t?.item?.type===`message`){if(this.shouldEmitTerminalContent(t,n.streamedTextKeys,`text`,n.emittedText)){let e=[];this.collectTextFromNode(t.item.content,e);let i=e.join(``);if(i&&i===n.lastTextChunk)break;for(let t of e)this.emitTextDelta(r,n,t)}}else if(t?.item?.type===`reasoning`){if(this.shouldEmitTerminalContent(t,n.streamedReasoningKeys,`reasoning`,n.emittedThinking)){let e=[];this.collectTextFromNode(t.item.summary??t.item.content,e);let i=e.join(``);if(i&&i===n.lastThinkingChunk)break;for(let t of e)this.emitThinkingDelta(r,n,t)}}else this.collectResponsesToolCallDelta(t,n.toolCalls);break;case`response.output_text.done`:case`response.content_part.done`:if(n.textBlockStarted)break;if(this.shouldEmitTerminalContent(t,n.streamedTextKeys,`text`,n.emittedText)){let e=[];this.collectTextFromNode(t?.delta??t?.output_text??t?.text??t?.part,e);let i=e.join(``);if(i&&i===n.lastTextChunk)break;for(let t of e)this.emitTextDelta(r,n,t)}break;case`response.completed`:case`response.done`:{let e={textSegments:[],thinkingSegments:[],toolCalls:new Map(n.toolCalls),streamedReasoningKeys:new Set(n.streamedReasoningKeys),streamedTextKeys:new Set(n.streamedTextKeys),model:n.model,inputTokens:n.inputTokens,outputTokens:n.outputTokens,cachedTokens:n.cachedTokens,reasoningTokens:n.reasoningTokens,reasoningEffort:n.reasoningEffort,stopReason:n.stopReason};if(this.collectCompletedResponse(t,e),n.model=e.model,n.inputTokens=e.inputTokens,n.outputTokens=e.outputTokens,n.cachedTokens=e.cachedTokens,n.reasoningTokens=e.reasoningTokens,n.reasoningEffort=e.reasoningEffort,n.stopReason=e.stopReason,n.toolCalls=e.toolCalls,!n.emittedThinking)for(let t of e.thinkingSegments)this.emitThinkingDelta(r,n,t);if(!n.emittedText)for(let t of e.textSegments)this.emitTextDelta(r,n,t);this.emitPendingToolCalls(r,n),this.finishStreamingResponse(r,n);break}default:break}}processChatCompletionStreamingChunk(e,t,n){if(e&&(typeof e.model==`string`&&(t.model=e.model),e.usage&&(t.inputTokens=e.usage.prompt_tokens??t.inputTokens,t.outputTokens=e.usage.completion_tokens??t.outputTokens),Array.isArray(e.choices)))for(let r of e.choices){let e=[];this.collectTextFromNode(r?.delta??r?.message?.content,e);for(let r of e)this.emitTextDelta(n,t,r);r?.delta?.tool_calls&&this.collectToolCalls(r.delta.tool_calls,t.toolCalls),r?.finish_reason&&(t.stopReason=this.mapFinishReason(r.finish_reason))}}emitPendingToolCalls(e,t){let n=Array.from(t.toolCalls.entries()).sort((e,t)=>e[0]-t[0]).map(([e,t])=>({index:e,id:t.id||`tool_${s()}`,name:t.name,arguments:t.argumentChunks.join(``)})).filter(e=>e.name&&!t.emittedToolCallIndexes.has(e.index));for(let r of n){this.stopOpenContentBlocks(e,t);let n=this.getNextToolBlockIndex(r.index);e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_start`,{type:`content_block_start`,index:n,content_block:{type:`tool_use`,id:r.id,name:r.name,input:{}}})+(r.arguments?this.formatSseEvent(`content_block_delta`,{type:`content_block_delta`,index:n,delta:{type:`input_json_delta`,partial_json:r.arguments}}):``)+this.formatSseEvent(`content_block_stop`,{type:`content_block_stop`,index:n}))),t.emittedToolCallIndexes.add(r.index)}}emitThinkingDelta(e,t,n){this.thinkingDisabled||!n||(this.ensureMessageStarted(e,t),t.textBlockStarted&&this.stopTextBlock(e,t),t.thinkingBlockStarted||=(e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_start`,{type:`content_block_start`,index:0,content_block:{type:`thinking`,thinking:``}}))),!0),e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_delta`,{type:`content_block_delta`,index:0,delta:{type:`thinking_delta`,thinking:n}}))),t.emittedThinking=!0,t.lastThinkingChunk=n)}emitTextDelta(e,t,n){n&&(this.ensureMessageStarted(e,t),t.textBlockStarted||=(t.thinkingBlockStarted&&this.stopThinkingBlock(e,t),e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_start`,{type:`content_block_start`,index:this.getTextBlockIndex(),content_block:{type:`text`,text:``}}))),!0),e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_delta`,{type:`content_block_delta`,index:this.getTextBlockIndex(),delta:{type:`text_delta`,text:n}}))),t.emittedText=!0,t.lastTextChunk=n)}emitStreamingError(e,t,n){if(!t.messageStarted){e.enqueue(t.encoder.encode(this.createClaudeErrorStream(n))),t.messageStarted=!0,t.messageStopped=!0;return}!t.textBlockStarted&&!t.thinkingBlockStarted&&this.emitTextDelta(e,t,n),t.stopReason=`error`,this.finishStreamingResponse(e,t)}finishStreamingResponse(e,t){if(t.messageStopped)return;this.stopOpenContentBlocks(e,t);let n={output_tokens:t.outputTokens??0};if(t.cachedTokens||t.reasoningTokens||t.reasoningEffort){n.metadata={};let e=n.metadata;t.cachedTokens&&(e.cached_tokens=t.cachedTokens),t.reasoningTokens&&(e.reasoning_tokens=t.reasoningTokens),t.reasoningEffort&&(e.reasoning_effort=t.reasoningEffort)}e.enqueue(t.encoder.encode(this.formatSseEvent(`message_delta`,{type:`message_delta`,delta:{stop_reason:t.stopReason||`end_turn`,stop_sequence:null},usage:n})+this.formatSseEvent(`message_stop`,{type:`message_stop`}))),t.messageStopped=!0}ensureMessageStarted(e,t){t.messageStarted||=(e.enqueue(t.encoder.encode(this.formatSseEvent(`message_start`,{type:`message_start`,message:{id:t.messageId,type:`message`,role:`assistant`,content:[],model:t.model,stop_reason:null,stop_sequence:null,usage:{input_tokens:t.inputTokens??0,output_tokens:0}}}))),!0)}stopOpenContentBlocks(e,t){this.stopTextBlock(e,t),this.stopThinkingBlock(e,t)}stopThinkingBlock(e,t){t.thinkingBlockStarted&&=(e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_stop`,{type:`content_block_stop`,index:0}))),!1)}stopTextBlock(e,t){t.textBlockStarted&&=(e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_stop`,{type:`content_block_stop`,index:this.getTextBlockIndex()}))),!1)}getTextBlockIndex(){return this.thinkingDisabled?0:1}getNextToolBlockIndex(e){return(this.thinkingDisabled?1:2)+e}};const ve=new Set([`type`,`format`,`description`,`nullable`,`enum`,`items`,`maxItems`,`minItems`,`properties`,`required`,`propertyOrdering`,`maxProperties`,`minProperties`,`minimum`,`maximum`,`minLength`,`maxLength`,`pattern`,`example`,`anyOf`,`title`]);var ye=class{transform(e,t,n,r=!1){let i=this.toGeminiContents(e.messages),a=this.toSystemInstruction(e.system),o=this.toGeminiTools(e.tools);return{modelPath:this.toGeminiModelPath(t),body:{contents:i,system_instruction:a,tools:o,tool_config:{function_calling_config:{mode:o.length>0?`AUTO`:`NONE`}},generationConfig:{maxOutputTokens:this.resolveMaxOutputTokens(e.max_tokens,n,r)}}}}toGeminiModelPath(e){return e.startsWith(`models/`)?e:`models/${e}`}toSystemInstruction(e){let t=this.extractTextParts(e);if(t.length!==0)return{parts:t.map(e=>({text:e}))}}toGeminiContents(e){let t=[];for(let n of e){let e=this.toGeminiParts(n.content);e.length!==0&&t.push({role:n.role===`assistant`?`model`:`user`,parts:e})}return t}toGeminiParts(e){if(typeof e==`string`)return e.trim()?[{text:e}]:[];if(!Array.isArray(e))return[];let t=[];for(let n of e)n.type===`text`&&n.text&&t.push({text:n.text}),n.type===`tool_use`&&t.push({functionCall:{name:n.name,args:n.input}}),n.type===`tool_result`&&t.push({functionResponse:{name:n.tool_use_id,response:{content:typeof n.content==`string`?n.content:JSON.stringify(n.content??{})}}});return t}toGeminiTools(e){return!e||e.length===0?[]:[{function_declarations:e.map(e=>({name:e.name,description:e.description,parameters:this.toGeminiParameters(e.input_schema)}))}]}toGeminiParameters(e){if(e)return this.sanitizeGeminiSchema(e)}sanitizeGeminiSchema(e){if(Array.isArray(e))return e.map(e=>this.sanitizeGeminiSchema(e));if(!e||typeof e!=`object`)return e;let t=Object.entries(e).flatMap(([e,t])=>{if(!ve.has(e))return[];if(e===`properties`&&t&&typeof t==`object`&&!Array.isArray(t)){let n=Object.entries(t).map(([e,t])=>[e,this.sanitizeGeminiSchema(t)]);return[[e,Object.fromEntries(n)]]}return[[e,this.sanitizeGeminiSchema(t)]]});return Object.fromEntries(t)}extractTextParts(e){return typeof e==`string`?e.trim()?[e]:[]:Array.isArray(e)?e.map(e=>typeof e==`string`?e:e&&typeof e==`object`&&`text`in e&&typeof e.text==`string`?e.text:null).filter(e=>!!e?.trim()):[]}resolveMaxOutputTokens(e,t,n){return typeof e==`number`&&e>0?e:n||t===`minimal`?2048:4096}};const C=`GEMINI_AUTH_CONFIG_ERROR`;var w=class extends Error{constructor(e,t){super(e),this.code=t,this.name=`GeminiAuthError`}},be=class{constructor(e=x,t=process.env){this.logger=e,this.env=t}async resolveHeaders(e){let t=e.authMode??`auto`;return t===`api-key`?this.resolveApiKeyHeaders(e):t===`oauth`?this.resolveOAuthHeaders():await this.tryResolveApiKeyHeaders(e)??this.resolveOAuthHeaders()}getGeminiDirectory(){let e=this.env.GEMINI_CLI_HOME||r.homedir();return i.join(e,`.gemini`)}getSettingsPath(){return i.join(this.getGeminiDirectory(),`settings.json`)}getOAuthPath(){return i.join(this.getGeminiDirectory(),`oauth_creds.json`)}async tryResolveApiKeyHeaders(e){try{return await this.resolveApiKeyHeaders(e)}catch{return null}}async resolveApiKeyHeaders(e){let t=e.apiKeyEnvVar??e.authTokenEnvVar??`GEMINI_API_KEY`,n=this.env[t]?.trim();if(!n)throw new w(`Missing Gemini API key. Set ${t}.`,C);return{headers:{"x-goog-api-key":n},authMode:`api-key`,authSource:`env`}}async resolveOAuthHeaders(){let e=await this.readSettings(),t=await this.readOAuthCredentials(),n=await this.refreshOAuthCredentialsIfNeeded(t),r=e?.security?.auth?.selectedType??null,i=n.access_token?.trim();if(!i)throw new w(`Missing Gemini OAuth credentials. Expected ${this.getOAuthPath()} or GEMINI_API_KEY.`,C);return{headers:{Authorization:`Bearer ${i}`},authMode:`oauth`,authSource:`gemini-home`,authType:r}}async readOAuthCredentials(){try{let e=await u.readFile(this.getOAuthPath(),`utf8`);return JSON.parse(e)}catch(e){throw this.logger.warn(`[GeminiAuth] Failed to read oauth credentials`,{oauthPath:this.getOAuthPath(),cause:e}),new w(`Unable to read Gemini OAuth credentials from ${this.getOAuthPath()}.`,C)}}async readSettings(){try{let e=await u.readFile(this.getSettingsPath(),`utf8`);return JSON.parse(e)}catch(e){return e?.code===`ENOENT`||this.logger.warn(`[GeminiAuth] Failed to read settings`,{settingsPath:this.getSettingsPath(),cause:e}),null}}async refreshOAuthCredentialsIfNeeded(e){if(!this.shouldRefreshCredentials(e))return e;let t=e.refresh_token?.trim();if(!t)return e;let n=new URLSearchParams({client_id:`681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com`,client_secret:`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`,grant_type:`refresh_token`,refresh_token:t}),r=await fetch(`https://oauth2.googleapis.com/token`,{method:`POST`,headers:{"content-type":`application/x-www-form-urlencoded`},body:n});if(!r.ok)return this.logger.warn(`[GeminiAuth] Failed to refresh oauth credentials`,{status:r.status,oauthPath:this.getOAuthPath()}),e;let i=await r.json(),a={...e,access_token:i.access_token??e.access_token,token_type:i.token_type??e.token_type,scope:i.scope??e.scope,expiry_date:typeof i.expires_in==`number`?Date.now()+i.expires_in*1e3:e.expiry_date};return await u.writeFile(this.getOAuthPath(),`${JSON.stringify(a,null,2)}\n`,`utf8`),a}shouldRefreshCredentials(e){let t=e.access_token?.trim(),n=e.expiry_date;return t?typeof n==`number`?n<=Date.now()+6e4:!1:!0}};const T=`event: `,E=`data: `,xe=`message_start`,Se=`content_block_start`,Ce=`content_block_delta`,we=`content_block_stop`,Te=`message_delta`,Ee=`message_stop`,De=`end_turn`;var Oe=class{transformBuffered(e,t){let n=JSON.parse(e);return this.toClaudeStream([n],t)}transformStreaming(e,t){let n=[];for(let t of e.split(`
|
|
14
|
+
`).trim();if(!(!o||o===`[DONE]`))try{let e=JSON.parse(o),r=typeof e?.type==`string`?e.type:i,a=r.startsWith(`response.`)||i.startsWith(`response.`);if(e?.error||r===`response.error`){let r=e?.error?.message||e?.error?.error||e?.message||(typeof e?.error==`string`?e.error:`Unexpected API error`);this.emitStreamingError(n,t,r);return}if(a){this.processResponsesStreamingEvent(r,e,t,n);return}this.processChatCompletionStreamingChunk(e,t,n)}catch{}}processResponsesStreamingEvent(e,t,n,r){switch(t?.model&&typeof t.model==`string`&&(n.model=t.model),e){case`response.created`:typeof t?.response?.model==`string`&&(n.model=t.response.model);break;case`response.reasoning.delta`:case`response.reasoning_summary_text.delta`:{let e=[];this.markStreamedContentKey(t,n.streamedReasoningKeys,`reasoning`),this.collectTextFromNode(t?.delta??t?.text??t?.summary_text,e);for(let t of e)this.emitThinkingDelta(r,n,t);break}case`response.output_text.delta`:case`response.delta`:{let e=[];this.markStreamedContentKey(t,n.streamedTextKeys,`text`),this.collectTextFromNode(t?.delta??t?.output_text,e);for(let t of e)this.emitTextDelta(r,n,t);t?.delta?.tool_calls&&this.collectToolCalls(t.delta.tool_calls,n.toolCalls);break}case`response.function_call_arguments.delta`:case`response.function_call_arguments.done`:case`response.output_item.added`:case`response.output_item.done`:if(t?.item?.type===`message`){if(this.shouldEmitTerminalContent(t,n.streamedTextKeys,`text`,n.emittedText)){let e=[];this.collectTextFromNode(t.item.content,e);let i=e.join(``);if(i&&i===n.lastTextChunk)break;for(let t of e)this.emitTextDelta(r,n,t)}}else if(t?.item?.type===`reasoning`){if(this.shouldEmitTerminalContent(t,n.streamedReasoningKeys,`reasoning`,n.emittedThinking)){let e=[];this.collectTextFromNode(t.item.summary??t.item.content,e);let i=e.join(``);if(i&&i===n.lastThinkingChunk)break;for(let t of e)this.emitThinkingDelta(r,n,t)}}else this.collectResponsesToolCallDelta(t,n.toolCalls);break;case`response.output_text.done`:case`response.content_part.done`:if(n.textBlockStarted)break;if(this.shouldEmitTerminalContent(t,n.streamedTextKeys,`text`,n.emittedText)){let e=[];this.collectTextFromNode(t?.delta??t?.output_text??t?.text??t?.part,e);let i=e.join(``);if(i&&i===n.lastTextChunk)break;for(let t of e)this.emitTextDelta(r,n,t)}break;case`response.completed`:case`response.done`:{let e={textSegments:[],thinkingSegments:[],toolCalls:new Map(n.toolCalls),streamedReasoningKeys:new Set(n.streamedReasoningKeys),streamedTextKeys:new Set(n.streamedTextKeys),model:n.model,inputTokens:n.inputTokens,outputTokens:n.outputTokens,cachedTokens:n.cachedTokens,reasoningTokens:n.reasoningTokens,reasoningEffort:n.reasoningEffort,stopReason:n.stopReason};if(this.collectCompletedResponse(t,e),n.model=e.model,n.inputTokens=e.inputTokens,n.outputTokens=e.outputTokens,n.cachedTokens=e.cachedTokens,n.reasoningTokens=e.reasoningTokens,n.reasoningEffort=e.reasoningEffort,n.stopReason=e.stopReason,n.toolCalls=e.toolCalls,!n.emittedThinking)for(let t of e.thinkingSegments)this.emitThinkingDelta(r,n,t);if(!n.emittedText)for(let t of e.textSegments)this.emitTextDelta(r,n,t);this.emitPendingToolCalls(r,n),this.finishStreamingResponse(r,n);break}default:break}}processChatCompletionStreamingChunk(e,t,n){if(e&&(typeof e.model==`string`&&(t.model=e.model),e.usage&&(t.inputTokens=e.usage.prompt_tokens??t.inputTokens,t.outputTokens=e.usage.completion_tokens??t.outputTokens),Array.isArray(e.choices)))for(let r of e.choices){let e=[];this.collectTextFromNode(r?.delta??r?.message?.content,e);for(let r of e)this.emitTextDelta(n,t,r);r?.delta?.tool_calls&&this.collectToolCalls(r.delta.tool_calls,t.toolCalls),r?.finish_reason&&(t.stopReason=this.mapFinishReason(r.finish_reason))}}emitPendingToolCalls(e,t){let n=Array.from(t.toolCalls.entries()).sort((e,t)=>e[0]-t[0]).map(([e,t])=>({index:e,id:t.id||`tool_${s()}`,name:t.name,arguments:t.argumentChunks.join(``)})).filter(e=>e.name&&!t.emittedToolCallIndexes.has(e.index));for(let r of n){this.stopOpenContentBlocks(e,t);let n=this.getNextToolBlockIndex(r.index);e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_start`,{type:`content_block_start`,index:n,content_block:{type:`tool_use`,id:r.id,name:r.name,input:{}}})+(r.arguments?this.formatSseEvent(`content_block_delta`,{type:`content_block_delta`,index:n,delta:{type:`input_json_delta`,partial_json:r.arguments}}):``)+this.formatSseEvent(`content_block_stop`,{type:`content_block_stop`,index:n}))),t.emittedToolCallIndexes.add(r.index)}}emitThinkingDelta(e,t,n){this.thinkingDisabled||!n||(this.ensureMessageStarted(e,t),t.textBlockStarted&&this.stopTextBlock(e,t),t.thinkingBlockStarted||=(e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_start`,{type:`content_block_start`,index:0,content_block:{type:`thinking`,thinking:``}}))),!0),e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_delta`,{type:`content_block_delta`,index:0,delta:{type:`thinking_delta`,thinking:n}}))),t.emittedThinking=!0,t.lastThinkingChunk=n)}emitTextDelta(e,t,n){n&&(this.ensureMessageStarted(e,t),t.textBlockStarted||=(t.thinkingBlockStarted&&this.stopThinkingBlock(e,t),e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_start`,{type:`content_block_start`,index:this.getTextBlockIndex(),content_block:{type:`text`,text:``}}))),!0),e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_delta`,{type:`content_block_delta`,index:this.getTextBlockIndex(),delta:{type:`text_delta`,text:n}}))),t.emittedText=!0,t.lastTextChunk=n)}emitStreamingError(e,t,n){if(!t.messageStarted){e.enqueue(t.encoder.encode(this.createClaudeErrorStream(n))),t.messageStarted=!0,t.messageStopped=!0;return}!t.textBlockStarted&&!t.thinkingBlockStarted&&this.emitTextDelta(e,t,n),t.stopReason=`error`,this.finishStreamingResponse(e,t)}finishStreamingResponse(e,t){if(t.messageStopped)return;this.stopOpenContentBlocks(e,t);let n={output_tokens:t.outputTokens??0};if(t.cachedTokens||t.reasoningTokens||t.reasoningEffort){n.metadata={};let e=n.metadata;t.cachedTokens&&(e.cached_tokens=t.cachedTokens),t.reasoningTokens&&(e.reasoning_tokens=t.reasoningTokens),t.reasoningEffort&&(e.reasoning_effort=t.reasoningEffort)}e.enqueue(t.encoder.encode(this.formatSseEvent(`message_delta`,{type:`message_delta`,delta:{stop_reason:t.stopReason||`end_turn`,stop_sequence:null},usage:n})+this.formatSseEvent(`message_stop`,{type:`message_stop`}))),t.messageStopped=!0}ensureMessageStarted(e,t){t.messageStarted||=(e.enqueue(t.encoder.encode(this.formatSseEvent(`message_start`,{type:`message_start`,message:{id:t.messageId,type:`message`,role:`assistant`,content:[],model:t.model,stop_reason:null,stop_sequence:null,usage:{input_tokens:t.inputTokens??0,output_tokens:0}}}))),!0)}stopOpenContentBlocks(e,t){this.stopTextBlock(e,t),this.stopThinkingBlock(e,t)}stopThinkingBlock(e,t){t.thinkingBlockStarted&&=(e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_stop`,{type:`content_block_stop`,index:0}))),!1)}stopTextBlock(e,t){t.textBlockStarted&&=(e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_stop`,{type:`content_block_stop`,index:this.getTextBlockIndex()}))),!1)}getTextBlockIndex(){return+!this.thinkingDisabled}getNextToolBlockIndex(e){return(this.thinkingDisabled?1:2)+e}};const ve=new Set([`type`,`format`,`description`,`nullable`,`enum`,`items`,`maxItems`,`minItems`,`properties`,`required`,`propertyOrdering`,`maxProperties`,`minProperties`,`minimum`,`maximum`,`minLength`,`maxLength`,`pattern`,`example`,`anyOf`,`title`]);var ye=class{transform(e,t,n,r=!1){let i=this.toGeminiContents(e.messages),a=this.toSystemInstruction(e.system),o=this.toGeminiTools(e.tools);return{modelPath:this.toGeminiModelPath(t),body:{contents:i,system_instruction:a,tools:o,tool_config:{function_calling_config:{mode:o.length>0?`AUTO`:`NONE`}},generationConfig:{maxOutputTokens:this.resolveMaxOutputTokens(e.max_tokens,n,r)}}}}toGeminiModelPath(e){return e.startsWith(`models/`)?e:`models/${e}`}toSystemInstruction(e){let t=this.extractTextParts(e);if(t.length!==0)return{parts:t.map(e=>({text:e}))}}toGeminiContents(e){let t=[];for(let n of e){let e=this.toGeminiParts(n.content);e.length!==0&&t.push({role:n.role===`assistant`?`model`:`user`,parts:e})}return t}toGeminiParts(e){if(typeof e==`string`)return e.trim()?[{text:e}]:[];if(!Array.isArray(e))return[];let t=[];for(let n of e)n.type===`text`&&n.text&&t.push({text:n.text}),n.type===`tool_use`&&t.push({functionCall:{name:n.name,args:n.input}}),n.type===`tool_result`&&t.push({functionResponse:{name:n.tool_use_id,response:{content:typeof n.content==`string`?n.content:JSON.stringify(n.content??{})}}});return t}toGeminiTools(e){return!e||e.length===0?[]:[{function_declarations:e.map(e=>({name:e.name,description:e.description,parameters:this.toGeminiParameters(e.input_schema)}))}]}toGeminiParameters(e){if(e)return this.sanitizeGeminiSchema(e)}sanitizeGeminiSchema(e){if(Array.isArray(e))return e.map(e=>this.sanitizeGeminiSchema(e));if(!e||typeof e!=`object`)return e;let t=Object.entries(e).flatMap(([e,t])=>{if(!ve.has(e))return[];if(e===`properties`&&t&&typeof t==`object`&&!Array.isArray(t)){let n=Object.entries(t).map(([e,t])=>[e,this.sanitizeGeminiSchema(t)]);return[[e,Object.fromEntries(n)]]}return[[e,this.sanitizeGeminiSchema(t)]]});return Object.fromEntries(t)}extractTextParts(e){return typeof e==`string`?e.trim()?[e]:[]:Array.isArray(e)?e.map(e=>typeof e==`string`?e:e&&typeof e==`object`&&`text`in e&&typeof e.text==`string`?e.text:null).filter(e=>!!e?.trim()):[]}resolveMaxOutputTokens(e,t,n){return typeof e==`number`&&e>0?e:n||t===`minimal`?2048:4096}};const C=`GEMINI_AUTH_CONFIG_ERROR`;var w=class extends Error{constructor(e,t){super(e),this.code=t,this.name=`GeminiAuthError`}},be=class{constructor(e=x,t=process.env){this.logger=e,this.env=t}async resolveHeaders(e){let t=e.authMode??`auto`;return t===`api-key`?this.resolveApiKeyHeaders(e):t===`oauth`?this.resolveOAuthHeaders():await this.tryResolveApiKeyHeaders(e)??this.resolveOAuthHeaders()}getGeminiDirectory(){let e=this.env.GEMINI_CLI_HOME||r.homedir();return i.join(e,`.gemini`)}getSettingsPath(){return i.join(this.getGeminiDirectory(),`settings.json`)}getOAuthPath(){return i.join(this.getGeminiDirectory(),`oauth_creds.json`)}async tryResolveApiKeyHeaders(e){try{return await this.resolveApiKeyHeaders(e)}catch{return null}}async resolveApiKeyHeaders(e){let t=e.apiKeyEnvVar??e.authTokenEnvVar??`GEMINI_API_KEY`,n=this.env[t]?.trim();if(!n)throw new w(`Missing Gemini API key. Set ${t}.`,C);return{headers:{"x-goog-api-key":n},authMode:`api-key`,authSource:`env`}}async resolveOAuthHeaders(){let e=await this.readSettings(),t=await this.readOAuthCredentials(),n=await this.refreshOAuthCredentialsIfNeeded(t),r=e?.security?.auth?.selectedType??null,i=n.access_token?.trim();if(!i)throw new w(`Missing Gemini OAuth credentials. Expected ${this.getOAuthPath()} or GEMINI_API_KEY.`,C);return{headers:{Authorization:`Bearer ${i}`},authMode:`oauth`,authSource:`gemini-home`,authType:r}}async readOAuthCredentials(){try{let e=await u.readFile(this.getOAuthPath(),`utf8`);return JSON.parse(e)}catch(e){throw this.logger.warn(`[GeminiAuth] Failed to read oauth credentials`,{oauthPath:this.getOAuthPath(),cause:e}),new w(`Unable to read Gemini OAuth credentials from ${this.getOAuthPath()}.`,C)}}async readSettings(){try{let e=await u.readFile(this.getSettingsPath(),`utf8`);return JSON.parse(e)}catch(e){return e?.code===`ENOENT`||this.logger.warn(`[GeminiAuth] Failed to read settings`,{settingsPath:this.getSettingsPath(),cause:e}),null}}async refreshOAuthCredentialsIfNeeded(e){if(!this.shouldRefreshCredentials(e))return e;let t=e.refresh_token?.trim();if(!t)return e;let n=new URLSearchParams({client_id:`681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com`,client_secret:`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`,grant_type:`refresh_token`,refresh_token:t}),r=await fetch(`https://oauth2.googleapis.com/token`,{method:`POST`,headers:{"content-type":`application/x-www-form-urlencoded`},body:n});if(!r.ok)return this.logger.warn(`[GeminiAuth] Failed to refresh oauth credentials`,{status:r.status,oauthPath:this.getOAuthPath()}),e;let i=await r.json(),a={...e,access_token:i.access_token??e.access_token,token_type:i.token_type??e.token_type,scope:i.scope??e.scope,expiry_date:typeof i.expires_in==`number`?Date.now()+i.expires_in*1e3:e.expiry_date};return await u.writeFile(this.getOAuthPath(),`${JSON.stringify(a,null,2)}\n`,`utf8`),a}shouldRefreshCredentials(e){let t=e.access_token?.trim(),n=e.expiry_date;return t?typeof n==`number`?n<=Date.now()+6e4:!1:!0}};const T=`event: `,E=`data: `,xe=`message_start`,Se=`content_block_start`,Ce=`content_block_delta`,we=`content_block_stop`,Te=`message_delta`,Ee=`message_stop`,De=`end_turn`;var Oe=class{transformBuffered(e,t){let n=JSON.parse(e);return this.toClaudeStream([n],t)}transformStreaming(e,t){let n=[];for(let t of e.split(`
|
|
15
15
|
|
|
16
16
|
`)){let e=t.split(`
|
|
17
17
|
`).find(e=>e.startsWith(E))?.slice(6).trim();!e||e===`[DONE]`||n.push(JSON.parse(e))}return this.toClaudeStream(n,t)}toClaudeStream(e,t){let n=e.flatMap(e=>e.candidates??[]).flatMap(e=>e.content?.parts??[]).map(e=>`text`in e&&typeof e.text==`string`?e.text:``).join(``),r=e.map(e=>e.candidates?.[0]?.finishReason).find(e=>typeof e==`string`),i=e.find(e=>e.usageMetadata)?.usageMetadata,a=`msg_${s()}`,o=[];return o.push(`${T}${xe}`),o.push(`${E}${JSON.stringify({type:xe,message:{id:a,type:`message`,role:`assistant`,content:[],model:t,stop_reason:null,stop_sequence:null,usage:{input_tokens:i?.promptTokenCount??0,output_tokens:0}}})}`),o.push(``),o.push(`${T}${Se}`),o.push(`${E}${JSON.stringify({type:Se,index:0,content_block:{type:`text`,text:``}})}`),o.push(``),n&&(o.push(`${T}${Ce}`),o.push(`${E}${JSON.stringify({type:Ce,index:0,delta:{type:`text_delta`,text:n}})}`),o.push(``)),o.push(`${T}${we}`),o.push(`${E}${JSON.stringify({type:we,index:0})}`),o.push(``),o.push(`${T}${Te}`),o.push(`${E}${JSON.stringify({type:Te,delta:{stop_reason:this.mapStopReason(r),stop_sequence:null},usage:{output_tokens:i?.candidatesTokenCount??0}})}`),o.push(``),o.push(`${T}${Ee}`),o.push(`${E}${JSON.stringify({type:Ee})}`),o.push(``),o.join(`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));require(`@hono/node-server`);let c=require(`hono`),l=require(`zod`),u=require(`node:os`);u=s(u);let d=require(`node:path`);d=s(d);let f=require(`node:crypto`),p=require(`ulidx`),m=require(`node:fs`);m=s(m);let h=require(`node:url`),g=require(`node:fs/promises`);g=s(g);let _=require(`better-sqlite3`);_=s(_);let v=require(`yaml`),ee=require(`@modelcontextprotocol/sdk/server/index.js`),te=require(`@modelcontextprotocol/sdk/types.js`),ne=require(`@modelcontextprotocol/sdk/server/stdio.js`);const y=d.default.join(u.default.homedir(),`.model-proxy`),b=d.default.join(y,`model-provider.yaml`),re=d.default.join(y,`model-list.yaml`),ie=d.default.join(y,`scopes`),ae=d.default.join(y,`history.sqlite`),oe=d.default.join(u.default.homedir(),`.codex`,`auth.json`),x=`model-proxy-mcp-http`,se={min:43e3,max:44e3},ce={"chatgpt-codex":{type:`chatgpt-codex`,endpoint:`https://chatgpt.com/backend-api/codex/responses`,authTokenEnvVar:null,apiTimeoutMs:null},"zai-anthropic-compat":{type:`anthropic-compatible`,endpoint:`https://api.z.ai/api/anthropic/v1/messages`,authTokenEnvVar:`ZAI_ANTHROPIC_AUTH_TOKEN`,apiTimeoutMs:3e6},"google-gemini-direct":{type:`gemini-direct`,endpoint:`https://generativelanguage.googleapis.com`,authTokenEnvVar:`GEMINI_API_KEY`,apiTimeoutMs:3e5,authMode:`auto`,apiKeyEnvVar:`GEMINI_API_KEY`,project:null,location:`global`,apiVersion:`v1beta`}},le=[{id:`chatgpt-codex-gpt-5.3-codex`,label:`ChatGPT Codex GPT-5.3 Codex`,provider:`chatgpt-codex`,model:`gpt-5.3-codex`,reasoningEffort:`medium`,enabled:!0},{id:`chatgpt-codex-gpt-5.3-codex-low`,label:`ChatGPT Codex GPT-5.3 Codex Low`,provider:`chatgpt-codex`,model:`gpt-5.3-codex`,reasoningEffort:`low`,enabled:!0},{id:`chatgpt-codex-gpt-5.4`,label:`ChatGPT Codex GPT-5.4`,provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`medium`,enabled:!0},{id:`chatgpt-codex-gpt-5.2`,label:`ChatGPT Codex GPT-5.2`,provider:`chatgpt-codex`,model:`gpt-5.2`,reasoningEffort:`medium`,enabled:!0},{id:`zai-anthropic-compat-glm-4.7`,label:`Z.ai GLM-4.7`,provider:`zai-anthropic-compat`,model:`GLM-4.7`,reasoningEffort:`high`,enabled:!0},{id:`zai-anthropic-compat-glm-5`,label:`Z.ai GLM-5`,provider:`zai-anthropic-compat`,model:`glm-5`,reasoningEffort:`high`,enabled:!0},{id:`zai-anthropic-compat-glm-4.5-air`,label:`Z.ai GLM-4.5-Air`,provider:`zai-anthropic-compat`,model:`GLM-4.5-Air`,reasoningEffort:`medium`,enabled:!0},{id:`google-gemini-direct-gemini-2.5-flash`,label:`Google Gemini 2.5 Flash`,provider:`google-gemini-direct`,model:`gemini-2.5-flash`,reasoningEffort:`medium`,enabled:!0},{id:`google-gemini-direct-gemini-3-flash-preview`,label:`Google Gemini 3 Flash Preview`,provider:`google-gemini-direct`,model:`gemini-3-flash-preview`,reasoningEffort:`medium`,enabled:!0},{id:`google-gemini-direct-gemini-3.1-pro-preview`,label:`Google Gemini 3.1 Pro Preview`,provider:`google-gemini-direct`,model:`gemini-3.1-pro-preview`,reasoningEffort:`high`,enabled:!0}],ue={models:{default:{main:{provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`medium`},fallbacks:[{provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`low`}]},sonnet:{main:{provider:`chatgpt-codex`,model:`gpt-5.3-codex`,reasoningEffort:`medium`},fallbacks:[{provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`medium`}]},opus:{main:{provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`medium`},fallbacks:[{provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`low`}]},haiku:{main:{provider:`chatgpt-codex`,model:`gpt-5.3-codex`,reasoningEffort:`low`},fallbacks:[{provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`medium`}]},subagent:{main:{provider:`chatgpt-codex`,model:`gpt-5.3-codex`,reasoningEffort:`low`},fallbacks:[{provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`medium`}]}}},de=(0,h.fileURLToPath)(require(`url`).pathToFileURL(__filename).href),fe=d.default.dirname(de),pe=d.default.join(fe,`codex.md`);let S=null;const me=e=>typeof e==`object`&&!!e&&!Array.isArray(e);var he=class{config;codexInstructions;constructor(e){this.config=e,this.codexInstructions=this.loadCodexInstructions()}loadCodexInstructions(){if(S!==null)return S;try{return S=m.default.readFileSync(pe,`utf-8`),S}catch{return console.warn(`Warning: Could not load codex.md from ${pe}`),S=``,``}}async transform(e,t){try{let e=JSON.parse(t);this.config.logger?.debug(`[ClaudeToOpenAI] ===== ORIGINAL CLAUDE REQUEST =====`),this.config.logger?.debug(`[ClaudeToOpenAI] Original body`,{body:JSON.stringify(e,null,2)});let n=this.config.sessionId||(0,f.randomUUID)(),r=n,i=this.config.sessionReasoningEffort,a=e.model&&e.model.toLowerCase().includes(`haiku`),o=i||(a?`minimal`:`medium`);this.config.logger?.debug(`[ClaudeToOpenAI] Model detection and reasoning effort`,{originalModel:e.model,isHaikuModel:a,sessionReasoningEffort:i||`none`,finalReasoningEffort:o,source:i?`session override`:`model-based`});let s={model:this.config.toModel||`gpt-5`,stream:!0,store:!1,tool_choice:`auto`,parallel_tool_calls:!1,prompt_cache_key:n};this.config.thinkingDisabled||(s.reasoning={effort:o,summary:`auto`},s.include=[`reasoning.encrypted_content`]),this.config.logger?.debug(`[ClaudeToOpenAI] Thinking mode`,{thinkingDisabled:this.config.thinkingDisabled??!1}),s.instructions=this.adaptInstructionsForChatGPT(this.codexInstructions);let c=[],l=``;if(e.system){let t=this.extractSystemMessages(e.system);t&&Array.isArray(t)&&t.length>0&&(l=t.map(e=>e.content).join(`
|
|
1
|
+
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));require(`@hono/node-server`);let c=require(`hono`),l=require(`zod`),u=require(`node:os`);u=s(u,1);let d=require(`node:path`);d=s(d,1);let f=require(`node:crypto`),p=require(`ulidx`),m=require(`node:fs`);m=s(m,1);let h=require(`node:url`),g=require(`node:fs/promises`);g=s(g,1);let _=require(`better-sqlite3`);_=s(_,1);let v=require(`yaml`),ee=require(`@modelcontextprotocol/sdk/server/index.js`),te=require(`@modelcontextprotocol/sdk/types.js`),ne=require(`@modelcontextprotocol/sdk/server/stdio.js`);const y=d.default.join(u.default.homedir(),`.model-proxy`),b=d.default.join(y,`model-provider.yaml`),re=d.default.join(y,`model-list.yaml`),ie=d.default.join(y,`scopes`),ae=d.default.join(y,`history.sqlite`),oe=d.default.join(u.default.homedir(),`.codex`,`auth.json`),x=`model-proxy-mcp-http`,se={min:43e3,max:44e3},ce={"chatgpt-codex":{type:`chatgpt-codex`,endpoint:`https://chatgpt.com/backend-api/codex/responses`,authTokenEnvVar:null,apiTimeoutMs:null},"zai-anthropic-compat":{type:`anthropic-compatible`,endpoint:`https://api.z.ai/api/anthropic/v1/messages`,authTokenEnvVar:`ZAI_ANTHROPIC_AUTH_TOKEN`,apiTimeoutMs:3e6},"google-gemini-direct":{type:`gemini-direct`,endpoint:`https://generativelanguage.googleapis.com`,authTokenEnvVar:`GEMINI_API_KEY`,apiTimeoutMs:3e5,authMode:`auto`,apiKeyEnvVar:`GEMINI_API_KEY`,project:null,location:`global`,apiVersion:`v1beta`}},le=[{id:`chatgpt-codex-gpt-5.3-codex`,label:`ChatGPT Codex GPT-5.3 Codex`,provider:`chatgpt-codex`,model:`gpt-5.3-codex`,reasoningEffort:`medium`,enabled:!0},{id:`chatgpt-codex-gpt-5.3-codex-low`,label:`ChatGPT Codex GPT-5.3 Codex Low`,provider:`chatgpt-codex`,model:`gpt-5.3-codex`,reasoningEffort:`low`,enabled:!0},{id:`chatgpt-codex-gpt-5.4`,label:`ChatGPT Codex GPT-5.4`,provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`medium`,enabled:!0},{id:`chatgpt-codex-gpt-5.2`,label:`ChatGPT Codex GPT-5.2`,provider:`chatgpt-codex`,model:`gpt-5.2`,reasoningEffort:`medium`,enabled:!0},{id:`zai-anthropic-compat-glm-4.7`,label:`Z.ai GLM-4.7`,provider:`zai-anthropic-compat`,model:`GLM-4.7`,reasoningEffort:`high`,enabled:!0},{id:`zai-anthropic-compat-glm-5`,label:`Z.ai GLM-5`,provider:`zai-anthropic-compat`,model:`glm-5`,reasoningEffort:`high`,enabled:!0},{id:`zai-anthropic-compat-glm-4.5-air`,label:`Z.ai GLM-4.5-Air`,provider:`zai-anthropic-compat`,model:`GLM-4.5-Air`,reasoningEffort:`medium`,enabled:!0},{id:`google-gemini-direct-gemini-2.5-flash`,label:`Google Gemini 2.5 Flash`,provider:`google-gemini-direct`,model:`gemini-2.5-flash`,reasoningEffort:`medium`,enabled:!0},{id:`google-gemini-direct-gemini-3-flash-preview`,label:`Google Gemini 3 Flash Preview`,provider:`google-gemini-direct`,model:`gemini-3-flash-preview`,reasoningEffort:`medium`,enabled:!0},{id:`google-gemini-direct-gemini-3.1-pro-preview`,label:`Google Gemini 3.1 Pro Preview`,provider:`google-gemini-direct`,model:`gemini-3.1-pro-preview`,reasoningEffort:`high`,enabled:!0}],ue={models:{default:{main:{provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`medium`},fallbacks:[{provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`low`}]},sonnet:{main:{provider:`chatgpt-codex`,model:`gpt-5.3-codex`,reasoningEffort:`medium`},fallbacks:[{provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`medium`}]},opus:{main:{provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`medium`},fallbacks:[{provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`low`}]},haiku:{main:{provider:`chatgpt-codex`,model:`gpt-5.3-codex`,reasoningEffort:`low`},fallbacks:[{provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`medium`}]},subagent:{main:{provider:`chatgpt-codex`,model:`gpt-5.3-codex`,reasoningEffort:`low`},fallbacks:[{provider:`chatgpt-codex`,model:`gpt-5.4`,reasoningEffort:`medium`}]}}},de=(0,h.fileURLToPath)(require(`url`).pathToFileURL(__filename).href),fe=d.default.dirname(de),pe=d.default.join(fe,`codex.md`);let S=null;const me=e=>typeof e==`object`&&!!e&&!Array.isArray(e);var he=class{config;codexInstructions;constructor(e){this.config=e,this.codexInstructions=this.loadCodexInstructions()}loadCodexInstructions(){if(S!==null)return S;try{return S=m.default.readFileSync(pe,`utf-8`),S}catch{return console.warn(`Warning: Could not load codex.md from ${pe}`),S=``,``}}async transform(e,t){try{let e=JSON.parse(t);this.config.logger?.debug(`[ClaudeToOpenAI] ===== ORIGINAL CLAUDE REQUEST =====`),this.config.logger?.debug(`[ClaudeToOpenAI] Original body`,{body:JSON.stringify(e,null,2)});let n=this.config.sessionId||(0,f.randomUUID)(),r=n,i=this.config.sessionReasoningEffort,a=e.model&&e.model.toLowerCase().includes(`haiku`),o=i||(a?`minimal`:`medium`);this.config.logger?.debug(`[ClaudeToOpenAI] Model detection and reasoning effort`,{originalModel:e.model,isHaikuModel:a,sessionReasoningEffort:i||`none`,finalReasoningEffort:o,source:i?`session override`:`model-based`});let s={model:this.config.toModel||`gpt-5`,stream:!0,store:!1,tool_choice:`auto`,parallel_tool_calls:!1,prompt_cache_key:n};this.config.thinkingDisabled||(s.reasoning={effort:o,summary:`auto`},s.include=[`reasoning.encrypted_content`]),this.config.logger?.debug(`[ClaudeToOpenAI] Thinking mode`,{thinkingDisabled:this.config.thinkingDisabled??!1}),s.instructions=this.adaptInstructionsForChatGPT(this.codexInstructions);let c=[],l=``;if(e.system){let t=this.extractSystemMessages(e.system);t&&Array.isArray(t)&&t.length>0&&(l=t.map(e=>e.content).join(`
|
|
2
2
|
|
|
3
3
|
`))}if(l=this.removeClaudeCodeInstructions(l),l&&c.push({type:`message`,role:`user`,content:[{type:`input_text`,text:l}]}),e.messages&&Array.isArray(e.messages))for(let t of e.messages){let e=this.convertMessageToInput(t);Array.isArray(e)?c.push(...e):e&&c.push(e)}if(s.input=c,e.tools&&Array.isArray(e.tools)){this.config.logger?.debug(`[ClaudeToOpenAI] Original Claude tools`,{tools:JSON.stringify(e.tools,null,2)});let t=this.convertTools(e.tools);this.config.logger?.debug(`[ClaudeToOpenAI] Converted tools`,{tools:JSON.stringify(t,null,2)}),t.length>0?(s.tools=t,this.config.logger?.debug(`[ClaudeToOpenAI] Added tools to responsesRequest`,{toolCount:t.length}),this.config.logger?.debug(`[ClaudeToOpenAI] Verify responsesRequest.tools exists`,{hasTools:!!s.tools,toolsLength:s.tools?.length,keys:Object.keys(s)})):this.config.logger?.warn(`[ClaudeToOpenAI] No valid tools after conversion, omitting tools field`)}else this.config.logger?.debug(`[ClaudeToOpenAI] No tools in Claude request`,{hasTools:!!e.tools,isArray:Array.isArray(e.tools)});let u=this.config.toEndpoint||`https://chatgpt.com/backend-api/codex/responses`,d={version:`0.46.0`,"openai-beta":`responses=experimental`,conversation_id:r,session_id:n,accept:`text/event-stream`,"content-type":`application/json`,"user-agent":`codex_cli_rs/0.46.0 (Mac OS 15.6.0; arm64) iTerm.app/3.6.2`,originator:`codex_cli_rs`},p=this.config.resolvedAuth;return p?.accessToken?(this.config.logger?.debug(`[ClaudeToOpenAI] Raw access token`,{token:`${p.accessToken.substring(0,30)}...`}),d.authorization=p.accessToken.startsWith(`Bearer `)?p.accessToken:`Bearer ${p.accessToken}`,p.accountId&&(d[`chatgpt-account-id`]=p.accountId)):this.config.toApiKey&&(d.authorization=`Bearer ${this.config.toApiKey}`),d.authorization?.startsWith(`Bearer `)&&this.config.logger?.debug(`[ClaudeToOpenAI] Added Bearer auth header`),this.config.logger?.debug(`[ClaudeToOpenAI] ===== REQUEST DETAILS =====`),this.config.logger?.debug(`[ClaudeToOpenAI] Target URL`,{targetUrl:u}),this.config.logger?.debug(`[ClaudeToOpenAI] Headers`,{headers:{...d,authorization:d.authorization?`${d.authorization.substring(0,30)}...`:void 0}}),this.config.logger?.debug(`[ClaudeToOpenAI] Body`,{body:JSON.stringify(s,null,2)}),this.config.logger?.debug(`[ClaudeToOpenAI] ===============================`),this.config.logger?.debug(`[ClaudeToOpenAI] ===== FINAL TRANSFORMED REQUEST =====`),this.config.logger?.debug(`[ClaudeToOpenAI] Pre-final check - responsesRequest.tools`,{hasTools:!!s.tools,toolsLength:s.tools?.length,keys:Object.keys(s)}),this.config.logger?.debug(`[ClaudeToOpenAI] Final body`,{body:JSON.stringify(s,null,2)}),this.config.logger?.debug(`[ClaudeToOpenAI] ===== END FINAL TRANSFORMED REQUEST =====`),{url:u,body:JSON.stringify(s),headers:d}}catch(e){throw Error(`Failed to transform Claude request to OpenAI: ${e instanceof Error?e.message:String(e)}`,{cause:e})}}adaptInstructionsForChatGPT(e){let t=e;return t=t.replace(/You are powered by the model named Sonnet 4\.5\. The exact model ID is claude-sonnet-4-5-\d+\./g,`You are powered by ChatGPT (GPT-5 reasoning model).`),t=t.replace(/Assistant knowledge cutoff is January 2025/g,`Assistant knowledge cutoff is October 2023`),t=t.replace(/\bClaude\b/g,`ChatGPT`),t=t.replace(/\bAnthropic\b/g,`OpenAI`),t}removeClaudeCodeInstructions(e){let t=[/You are Claude Code, Anthropic's official CLI for Claude\.[\s\S]*?claude_code_docs_map\.md/,/You are Claude Code[\s\S]*?using Claude Code\n/],n=e;for(let e of t)n=n.replace(e,``);return n=n.replace(/\n{3,}/g,`
|
|
4
4
|
|
|
@@ -11,7 +11,7 @@ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=
|
|
|
11
11
|
|
|
12
12
|
`),a=r?``:i.pop()??``;for(let e of i)this.processSseChunk(e,t,n);return r&&a.trim()&&this.processSseChunk(a,t,n),a}processSseChunk(e,t,n){let r=e.split(`
|
|
13
13
|
`),i=``,a=[];for(let e of r){let t=e.replace(/\r$/,``);t.startsWith(`event:`)?i=t.slice(6).trim():t.startsWith(`data:`)&&a.push(t.slice(5).trim())}let o=a.join(`
|
|
14
|
-
`).trim();if(!(!o||o===`[DONE]`))try{let e=JSON.parse(o),r=typeof e?.type==`string`?e.type:i,a=r.startsWith(`response.`)||i.startsWith(`response.`);if(e?.error||r===`response.error`){let r=e?.error?.message||e?.error?.error||e?.message||(typeof e?.error==`string`?e.error:`Unexpected API error`);this.emitStreamingError(n,t,r);return}if(a){this.processResponsesStreamingEvent(r,e,t,n);return}this.processChatCompletionStreamingChunk(e,t,n)}catch{}}processResponsesStreamingEvent(e,t,n,r){switch(t?.model&&typeof t.model==`string`&&(n.model=t.model),e){case`response.created`:typeof t?.response?.model==`string`&&(n.model=t.response.model);break;case`response.reasoning.delta`:case`response.reasoning_summary_text.delta`:{let e=[];this.markStreamedContentKey(t,n.streamedReasoningKeys,`reasoning`),this.collectTextFromNode(t?.delta??t?.text??t?.summary_text,e);for(let t of e)this.emitThinkingDelta(r,n,t);break}case`response.output_text.delta`:case`response.delta`:{let e=[];this.markStreamedContentKey(t,n.streamedTextKeys,`text`),this.collectTextFromNode(t?.delta??t?.output_text,e);for(let t of e)this.emitTextDelta(r,n,t);t?.delta?.tool_calls&&this.collectToolCalls(t.delta.tool_calls,n.toolCalls);break}case`response.function_call_arguments.delta`:case`response.function_call_arguments.done`:case`response.output_item.added`:case`response.output_item.done`:if(t?.item?.type===`message`){if(this.shouldEmitTerminalContent(t,n.streamedTextKeys,`text`,n.emittedText)){let e=[];this.collectTextFromNode(t.item.content,e);let i=e.join(``);if(i&&i===n.lastTextChunk)break;for(let t of e)this.emitTextDelta(r,n,t)}}else if(t?.item?.type===`reasoning`){if(this.shouldEmitTerminalContent(t,n.streamedReasoningKeys,`reasoning`,n.emittedThinking)){let e=[];this.collectTextFromNode(t.item.summary??t.item.content,e);let i=e.join(``);if(i&&i===n.lastThinkingChunk)break;for(let t of e)this.emitThinkingDelta(r,n,t)}}else this.collectResponsesToolCallDelta(t,n.toolCalls);break;case`response.output_text.done`:case`response.content_part.done`:if(n.textBlockStarted)break;if(this.shouldEmitTerminalContent(t,n.streamedTextKeys,`text`,n.emittedText)){let e=[];this.collectTextFromNode(t?.delta??t?.output_text??t?.text??t?.part,e);let i=e.join(``);if(i&&i===n.lastTextChunk)break;for(let t of e)this.emitTextDelta(r,n,t)}break;case`response.completed`:case`response.done`:{let e={textSegments:[],thinkingSegments:[],toolCalls:new Map(n.toolCalls),streamedReasoningKeys:new Set(n.streamedReasoningKeys),streamedTextKeys:new Set(n.streamedTextKeys),model:n.model,inputTokens:n.inputTokens,outputTokens:n.outputTokens,cachedTokens:n.cachedTokens,reasoningTokens:n.reasoningTokens,reasoningEffort:n.reasoningEffort,stopReason:n.stopReason};if(this.collectCompletedResponse(t,e),n.model=e.model,n.inputTokens=e.inputTokens,n.outputTokens=e.outputTokens,n.cachedTokens=e.cachedTokens,n.reasoningTokens=e.reasoningTokens,n.reasoningEffort=e.reasoningEffort,n.stopReason=e.stopReason,n.toolCalls=e.toolCalls,!n.emittedThinking)for(let t of e.thinkingSegments)this.emitThinkingDelta(r,n,t);if(!n.emittedText)for(let t of e.textSegments)this.emitTextDelta(r,n,t);this.emitPendingToolCalls(r,n),this.finishStreamingResponse(r,n);break}default:break}}processChatCompletionStreamingChunk(e,t,n){if(e&&(typeof e.model==`string`&&(t.model=e.model),e.usage&&(t.inputTokens=e.usage.prompt_tokens??t.inputTokens,t.outputTokens=e.usage.completion_tokens??t.outputTokens),Array.isArray(e.choices)))for(let r of e.choices){let e=[];this.collectTextFromNode(r?.delta??r?.message?.content,e);for(let r of e)this.emitTextDelta(n,t,r);r?.delta?.tool_calls&&this.collectToolCalls(r.delta.tool_calls,t.toolCalls),r?.finish_reason&&(t.stopReason=this.mapFinishReason(r.finish_reason))}}emitPendingToolCalls(e,t){let n=Array.from(t.toolCalls.entries()).sort((e,t)=>e[0]-t[0]).map(([e,t])=>({index:e,id:t.id||`tool_${(0,p.ulid)()}`,name:t.name,arguments:t.argumentChunks.join(``)})).filter(e=>e.name&&!t.emittedToolCallIndexes.has(e.index));for(let r of n){this.stopOpenContentBlocks(e,t);let n=this.getNextToolBlockIndex(r.index);e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_start`,{type:`content_block_start`,index:n,content_block:{type:`tool_use`,id:r.id,name:r.name,input:{}}})+(r.arguments?this.formatSseEvent(`content_block_delta`,{type:`content_block_delta`,index:n,delta:{type:`input_json_delta`,partial_json:r.arguments}}):``)+this.formatSseEvent(`content_block_stop`,{type:`content_block_stop`,index:n}))),t.emittedToolCallIndexes.add(r.index)}}emitThinkingDelta(e,t,n){this.thinkingDisabled||!n||(this.ensureMessageStarted(e,t),t.textBlockStarted&&this.stopTextBlock(e,t),t.thinkingBlockStarted||=(e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_start`,{type:`content_block_start`,index:0,content_block:{type:`thinking`,thinking:``}}))),!0),e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_delta`,{type:`content_block_delta`,index:0,delta:{type:`thinking_delta`,thinking:n}}))),t.emittedThinking=!0,t.lastThinkingChunk=n)}emitTextDelta(e,t,n){n&&(this.ensureMessageStarted(e,t),t.textBlockStarted||=(t.thinkingBlockStarted&&this.stopThinkingBlock(e,t),e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_start`,{type:`content_block_start`,index:this.getTextBlockIndex(),content_block:{type:`text`,text:``}}))),!0),e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_delta`,{type:`content_block_delta`,index:this.getTextBlockIndex(),delta:{type:`text_delta`,text:n}}))),t.emittedText=!0,t.lastTextChunk=n)}emitStreamingError(e,t,n){if(!t.messageStarted){e.enqueue(t.encoder.encode(this.createClaudeErrorStream(n))),t.messageStarted=!0,t.messageStopped=!0;return}!t.textBlockStarted&&!t.thinkingBlockStarted&&this.emitTextDelta(e,t,n),t.stopReason=`error`,this.finishStreamingResponse(e,t)}finishStreamingResponse(e,t){if(t.messageStopped)return;this.stopOpenContentBlocks(e,t);let n={output_tokens:t.outputTokens??0};if(t.cachedTokens||t.reasoningTokens||t.reasoningEffort){n.metadata={};let e=n.metadata;t.cachedTokens&&(e.cached_tokens=t.cachedTokens),t.reasoningTokens&&(e.reasoning_tokens=t.reasoningTokens),t.reasoningEffort&&(e.reasoning_effort=t.reasoningEffort)}e.enqueue(t.encoder.encode(this.formatSseEvent(`message_delta`,{type:`message_delta`,delta:{stop_reason:t.stopReason||`end_turn`,stop_sequence:null},usage:n})+this.formatSseEvent(`message_stop`,{type:`message_stop`}))),t.messageStopped=!0}ensureMessageStarted(e,t){t.messageStarted||=(e.enqueue(t.encoder.encode(this.formatSseEvent(`message_start`,{type:`message_start`,message:{id:t.messageId,type:`message`,role:`assistant`,content:[],model:t.model,stop_reason:null,stop_sequence:null,usage:{input_tokens:t.inputTokens??0,output_tokens:0}}}))),!0)}stopOpenContentBlocks(e,t){this.stopTextBlock(e,t),this.stopThinkingBlock(e,t)}stopThinkingBlock(e,t){t.thinkingBlockStarted&&=(e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_stop`,{type:`content_block_stop`,index:0}))),!1)}stopTextBlock(e,t){t.textBlockStarted&&=(e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_stop`,{type:`content_block_stop`,index:this.getTextBlockIndex()}))),!1)}getTextBlockIndex(){return this.thinkingDisabled?0:1}getNextToolBlockIndex(e){return(this.thinkingDisabled?1:2)+e}};const ye=new Set([`type`,`format`,`description`,`nullable`,`enum`,`items`,`maxItems`,`minItems`,`properties`,`required`,`propertyOrdering`,`maxProperties`,`minProperties`,`minimum`,`maximum`,`minLength`,`maxLength`,`pattern`,`example`,`anyOf`,`title`]);var be=class{transform(e,t,n,r=!1){let i=this.toGeminiContents(e.messages),a=this.toSystemInstruction(e.system),o=this.toGeminiTools(e.tools);return{modelPath:this.toGeminiModelPath(t),body:{contents:i,system_instruction:a,tools:o,tool_config:{function_calling_config:{mode:o.length>0?`AUTO`:`NONE`}},generationConfig:{maxOutputTokens:this.resolveMaxOutputTokens(e.max_tokens,n,r)}}}}toGeminiModelPath(e){return e.startsWith(`models/`)?e:`models/${e}`}toSystemInstruction(e){let t=this.extractTextParts(e);if(t.length!==0)return{parts:t.map(e=>({text:e}))}}toGeminiContents(e){let t=[];for(let n of e){let e=this.toGeminiParts(n.content);e.length!==0&&t.push({role:n.role===`assistant`?`model`:`user`,parts:e})}return t}toGeminiParts(e){if(typeof e==`string`)return e.trim()?[{text:e}]:[];if(!Array.isArray(e))return[];let t=[];for(let n of e)n.type===`text`&&n.text&&t.push({text:n.text}),n.type===`tool_use`&&t.push({functionCall:{name:n.name,args:n.input}}),n.type===`tool_result`&&t.push({functionResponse:{name:n.tool_use_id,response:{content:typeof n.content==`string`?n.content:JSON.stringify(n.content??{})}}});return t}toGeminiTools(e){return!e||e.length===0?[]:[{function_declarations:e.map(e=>({name:e.name,description:e.description,parameters:this.toGeminiParameters(e.input_schema)}))}]}toGeminiParameters(e){if(e)return this.sanitizeGeminiSchema(e)}sanitizeGeminiSchema(e){if(Array.isArray(e))return e.map(e=>this.sanitizeGeminiSchema(e));if(!e||typeof e!=`object`)return e;let t=Object.entries(e).flatMap(([e,t])=>{if(!ye.has(e))return[];if(e===`properties`&&t&&typeof t==`object`&&!Array.isArray(t)){let n=Object.entries(t).map(([e,t])=>[e,this.sanitizeGeminiSchema(t)]);return[[e,Object.fromEntries(n)]]}return[[e,this.sanitizeGeminiSchema(t)]]});return Object.fromEntries(t)}extractTextParts(e){return typeof e==`string`?e.trim()?[e]:[]:Array.isArray(e)?e.map(e=>typeof e==`string`?e:e&&typeof e==`object`&&`text`in e&&typeof e.text==`string`?e.text:null).filter(e=>!!e?.trim()):[]}resolveMaxOutputTokens(e,t,n){return typeof e==`number`&&e>0?e:n||t===`minimal`?2048:4096}};const xe=`GEMINI_AUTH_CONFIG_ERROR`;var T=class extends Error{constructor(e,t){super(e),this.code=t,this.name=`GeminiAuthError`}},Se=class{constructor(e=C,t=process.env){this.logger=e,this.env=t}async resolveHeaders(e){let t=e.authMode??`auto`;return t===`api-key`?this.resolveApiKeyHeaders(e):t===`oauth`?this.resolveOAuthHeaders():await this.tryResolveApiKeyHeaders(e)??this.resolveOAuthHeaders()}getGeminiDirectory(){let e=this.env.GEMINI_CLI_HOME||u.default.homedir();return d.default.join(e,`.gemini`)}getSettingsPath(){return d.default.join(this.getGeminiDirectory(),`settings.json`)}getOAuthPath(){return d.default.join(this.getGeminiDirectory(),`oauth_creds.json`)}async tryResolveApiKeyHeaders(e){try{return await this.resolveApiKeyHeaders(e)}catch{return null}}async resolveApiKeyHeaders(e){let t=e.apiKeyEnvVar??e.authTokenEnvVar??`GEMINI_API_KEY`,n=this.env[t]?.trim();if(!n)throw new T(`Missing Gemini API key. Set ${t}.`,xe);return{headers:{"x-goog-api-key":n},authMode:`api-key`,authSource:`env`}}async resolveOAuthHeaders(){let e=await this.readSettings(),t=await this.readOAuthCredentials(),n=await this.refreshOAuthCredentialsIfNeeded(t),r=e?.security?.auth?.selectedType??null,i=n.access_token?.trim();if(!i)throw new T(`Missing Gemini OAuth credentials. Expected ${this.getOAuthPath()} or GEMINI_API_KEY.`,xe);return{headers:{Authorization:`Bearer ${i}`},authMode:`oauth`,authSource:`gemini-home`,authType:r}}async readOAuthCredentials(){try{let e=await g.default.readFile(this.getOAuthPath(),`utf8`);return JSON.parse(e)}catch(e){throw this.logger.warn(`[GeminiAuth] Failed to read oauth credentials`,{oauthPath:this.getOAuthPath(),cause:e}),new T(`Unable to read Gemini OAuth credentials from ${this.getOAuthPath()}.`,xe)}}async readSettings(){try{let e=await g.default.readFile(this.getSettingsPath(),`utf8`);return JSON.parse(e)}catch(e){return e?.code===`ENOENT`||this.logger.warn(`[GeminiAuth] Failed to read settings`,{settingsPath:this.getSettingsPath(),cause:e}),null}}async refreshOAuthCredentialsIfNeeded(e){if(!this.shouldRefreshCredentials(e))return e;let t=e.refresh_token?.trim();if(!t)return e;let n=new URLSearchParams({client_id:`681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com`,client_secret:`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`,grant_type:`refresh_token`,refresh_token:t}),r=await fetch(`https://oauth2.googleapis.com/token`,{method:`POST`,headers:{"content-type":`application/x-www-form-urlencoded`},body:n});if(!r.ok)return this.logger.warn(`[GeminiAuth] Failed to refresh oauth credentials`,{status:r.status,oauthPath:this.getOAuthPath()}),e;let i=await r.json(),a={...e,access_token:i.access_token??e.access_token,token_type:i.token_type??e.token_type,scope:i.scope??e.scope,expiry_date:typeof i.expires_in==`number`?Date.now()+i.expires_in*1e3:e.expiry_date};return await g.default.writeFile(this.getOAuthPath(),`${JSON.stringify(a,null,2)}\n`,`utf8`),a}shouldRefreshCredentials(e){let t=e.access_token?.trim(),n=e.expiry_date;return t?typeof n==`number`?n<=Date.now()+6e4:!1:!0}};const E=`event: `,D=`data: `,Ce=`message_start`,we=`content_block_start`,Te=`content_block_delta`,Ee=`content_block_stop`,De=`message_delta`,Oe=`message_stop`,ke=`end_turn`;var Ae=class{transformBuffered(e,t){let n=JSON.parse(e);return this.toClaudeStream([n],t)}transformStreaming(e,t){let n=[];for(let t of e.split(`
|
|
14
|
+
`).trim();if(!(!o||o===`[DONE]`))try{let e=JSON.parse(o),r=typeof e?.type==`string`?e.type:i,a=r.startsWith(`response.`)||i.startsWith(`response.`);if(e?.error||r===`response.error`){let r=e?.error?.message||e?.error?.error||e?.message||(typeof e?.error==`string`?e.error:`Unexpected API error`);this.emitStreamingError(n,t,r);return}if(a){this.processResponsesStreamingEvent(r,e,t,n);return}this.processChatCompletionStreamingChunk(e,t,n)}catch{}}processResponsesStreamingEvent(e,t,n,r){switch(t?.model&&typeof t.model==`string`&&(n.model=t.model),e){case`response.created`:typeof t?.response?.model==`string`&&(n.model=t.response.model);break;case`response.reasoning.delta`:case`response.reasoning_summary_text.delta`:{let e=[];this.markStreamedContentKey(t,n.streamedReasoningKeys,`reasoning`),this.collectTextFromNode(t?.delta??t?.text??t?.summary_text,e);for(let t of e)this.emitThinkingDelta(r,n,t);break}case`response.output_text.delta`:case`response.delta`:{let e=[];this.markStreamedContentKey(t,n.streamedTextKeys,`text`),this.collectTextFromNode(t?.delta??t?.output_text,e);for(let t of e)this.emitTextDelta(r,n,t);t?.delta?.tool_calls&&this.collectToolCalls(t.delta.tool_calls,n.toolCalls);break}case`response.function_call_arguments.delta`:case`response.function_call_arguments.done`:case`response.output_item.added`:case`response.output_item.done`:if(t?.item?.type===`message`){if(this.shouldEmitTerminalContent(t,n.streamedTextKeys,`text`,n.emittedText)){let e=[];this.collectTextFromNode(t.item.content,e);let i=e.join(``);if(i&&i===n.lastTextChunk)break;for(let t of e)this.emitTextDelta(r,n,t)}}else if(t?.item?.type===`reasoning`){if(this.shouldEmitTerminalContent(t,n.streamedReasoningKeys,`reasoning`,n.emittedThinking)){let e=[];this.collectTextFromNode(t.item.summary??t.item.content,e);let i=e.join(``);if(i&&i===n.lastThinkingChunk)break;for(let t of e)this.emitThinkingDelta(r,n,t)}}else this.collectResponsesToolCallDelta(t,n.toolCalls);break;case`response.output_text.done`:case`response.content_part.done`:if(n.textBlockStarted)break;if(this.shouldEmitTerminalContent(t,n.streamedTextKeys,`text`,n.emittedText)){let e=[];this.collectTextFromNode(t?.delta??t?.output_text??t?.text??t?.part,e);let i=e.join(``);if(i&&i===n.lastTextChunk)break;for(let t of e)this.emitTextDelta(r,n,t)}break;case`response.completed`:case`response.done`:{let e={textSegments:[],thinkingSegments:[],toolCalls:new Map(n.toolCalls),streamedReasoningKeys:new Set(n.streamedReasoningKeys),streamedTextKeys:new Set(n.streamedTextKeys),model:n.model,inputTokens:n.inputTokens,outputTokens:n.outputTokens,cachedTokens:n.cachedTokens,reasoningTokens:n.reasoningTokens,reasoningEffort:n.reasoningEffort,stopReason:n.stopReason};if(this.collectCompletedResponse(t,e),n.model=e.model,n.inputTokens=e.inputTokens,n.outputTokens=e.outputTokens,n.cachedTokens=e.cachedTokens,n.reasoningTokens=e.reasoningTokens,n.reasoningEffort=e.reasoningEffort,n.stopReason=e.stopReason,n.toolCalls=e.toolCalls,!n.emittedThinking)for(let t of e.thinkingSegments)this.emitThinkingDelta(r,n,t);if(!n.emittedText)for(let t of e.textSegments)this.emitTextDelta(r,n,t);this.emitPendingToolCalls(r,n),this.finishStreamingResponse(r,n);break}default:break}}processChatCompletionStreamingChunk(e,t,n){if(e&&(typeof e.model==`string`&&(t.model=e.model),e.usage&&(t.inputTokens=e.usage.prompt_tokens??t.inputTokens,t.outputTokens=e.usage.completion_tokens??t.outputTokens),Array.isArray(e.choices)))for(let r of e.choices){let e=[];this.collectTextFromNode(r?.delta??r?.message?.content,e);for(let r of e)this.emitTextDelta(n,t,r);r?.delta?.tool_calls&&this.collectToolCalls(r.delta.tool_calls,t.toolCalls),r?.finish_reason&&(t.stopReason=this.mapFinishReason(r.finish_reason))}}emitPendingToolCalls(e,t){let n=Array.from(t.toolCalls.entries()).sort((e,t)=>e[0]-t[0]).map(([e,t])=>({index:e,id:t.id||`tool_${(0,p.ulid)()}`,name:t.name,arguments:t.argumentChunks.join(``)})).filter(e=>e.name&&!t.emittedToolCallIndexes.has(e.index));for(let r of n){this.stopOpenContentBlocks(e,t);let n=this.getNextToolBlockIndex(r.index);e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_start`,{type:`content_block_start`,index:n,content_block:{type:`tool_use`,id:r.id,name:r.name,input:{}}})+(r.arguments?this.formatSseEvent(`content_block_delta`,{type:`content_block_delta`,index:n,delta:{type:`input_json_delta`,partial_json:r.arguments}}):``)+this.formatSseEvent(`content_block_stop`,{type:`content_block_stop`,index:n}))),t.emittedToolCallIndexes.add(r.index)}}emitThinkingDelta(e,t,n){this.thinkingDisabled||!n||(this.ensureMessageStarted(e,t),t.textBlockStarted&&this.stopTextBlock(e,t),t.thinkingBlockStarted||=(e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_start`,{type:`content_block_start`,index:0,content_block:{type:`thinking`,thinking:``}}))),!0),e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_delta`,{type:`content_block_delta`,index:0,delta:{type:`thinking_delta`,thinking:n}}))),t.emittedThinking=!0,t.lastThinkingChunk=n)}emitTextDelta(e,t,n){n&&(this.ensureMessageStarted(e,t),t.textBlockStarted||=(t.thinkingBlockStarted&&this.stopThinkingBlock(e,t),e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_start`,{type:`content_block_start`,index:this.getTextBlockIndex(),content_block:{type:`text`,text:``}}))),!0),e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_delta`,{type:`content_block_delta`,index:this.getTextBlockIndex(),delta:{type:`text_delta`,text:n}}))),t.emittedText=!0,t.lastTextChunk=n)}emitStreamingError(e,t,n){if(!t.messageStarted){e.enqueue(t.encoder.encode(this.createClaudeErrorStream(n))),t.messageStarted=!0,t.messageStopped=!0;return}!t.textBlockStarted&&!t.thinkingBlockStarted&&this.emitTextDelta(e,t,n),t.stopReason=`error`,this.finishStreamingResponse(e,t)}finishStreamingResponse(e,t){if(t.messageStopped)return;this.stopOpenContentBlocks(e,t);let n={output_tokens:t.outputTokens??0};if(t.cachedTokens||t.reasoningTokens||t.reasoningEffort){n.metadata={};let e=n.metadata;t.cachedTokens&&(e.cached_tokens=t.cachedTokens),t.reasoningTokens&&(e.reasoning_tokens=t.reasoningTokens),t.reasoningEffort&&(e.reasoning_effort=t.reasoningEffort)}e.enqueue(t.encoder.encode(this.formatSseEvent(`message_delta`,{type:`message_delta`,delta:{stop_reason:t.stopReason||`end_turn`,stop_sequence:null},usage:n})+this.formatSseEvent(`message_stop`,{type:`message_stop`}))),t.messageStopped=!0}ensureMessageStarted(e,t){t.messageStarted||=(e.enqueue(t.encoder.encode(this.formatSseEvent(`message_start`,{type:`message_start`,message:{id:t.messageId,type:`message`,role:`assistant`,content:[],model:t.model,stop_reason:null,stop_sequence:null,usage:{input_tokens:t.inputTokens??0,output_tokens:0}}}))),!0)}stopOpenContentBlocks(e,t){this.stopTextBlock(e,t),this.stopThinkingBlock(e,t)}stopThinkingBlock(e,t){t.thinkingBlockStarted&&=(e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_stop`,{type:`content_block_stop`,index:0}))),!1)}stopTextBlock(e,t){t.textBlockStarted&&=(e.enqueue(t.encoder.encode(this.formatSseEvent(`content_block_stop`,{type:`content_block_stop`,index:this.getTextBlockIndex()}))),!1)}getTextBlockIndex(){return+!this.thinkingDisabled}getNextToolBlockIndex(e){return(this.thinkingDisabled?1:2)+e}};const ye=new Set([`type`,`format`,`description`,`nullable`,`enum`,`items`,`maxItems`,`minItems`,`properties`,`required`,`propertyOrdering`,`maxProperties`,`minProperties`,`minimum`,`maximum`,`minLength`,`maxLength`,`pattern`,`example`,`anyOf`,`title`]);var be=class{transform(e,t,n,r=!1){let i=this.toGeminiContents(e.messages),a=this.toSystemInstruction(e.system),o=this.toGeminiTools(e.tools);return{modelPath:this.toGeminiModelPath(t),body:{contents:i,system_instruction:a,tools:o,tool_config:{function_calling_config:{mode:o.length>0?`AUTO`:`NONE`}},generationConfig:{maxOutputTokens:this.resolveMaxOutputTokens(e.max_tokens,n,r)}}}}toGeminiModelPath(e){return e.startsWith(`models/`)?e:`models/${e}`}toSystemInstruction(e){let t=this.extractTextParts(e);if(t.length!==0)return{parts:t.map(e=>({text:e}))}}toGeminiContents(e){let t=[];for(let n of e){let e=this.toGeminiParts(n.content);e.length!==0&&t.push({role:n.role===`assistant`?`model`:`user`,parts:e})}return t}toGeminiParts(e){if(typeof e==`string`)return e.trim()?[{text:e}]:[];if(!Array.isArray(e))return[];let t=[];for(let n of e)n.type===`text`&&n.text&&t.push({text:n.text}),n.type===`tool_use`&&t.push({functionCall:{name:n.name,args:n.input}}),n.type===`tool_result`&&t.push({functionResponse:{name:n.tool_use_id,response:{content:typeof n.content==`string`?n.content:JSON.stringify(n.content??{})}}});return t}toGeminiTools(e){return!e||e.length===0?[]:[{function_declarations:e.map(e=>({name:e.name,description:e.description,parameters:this.toGeminiParameters(e.input_schema)}))}]}toGeminiParameters(e){if(e)return this.sanitizeGeminiSchema(e)}sanitizeGeminiSchema(e){if(Array.isArray(e))return e.map(e=>this.sanitizeGeminiSchema(e));if(!e||typeof e!=`object`)return e;let t=Object.entries(e).flatMap(([e,t])=>{if(!ye.has(e))return[];if(e===`properties`&&t&&typeof t==`object`&&!Array.isArray(t)){let n=Object.entries(t).map(([e,t])=>[e,this.sanitizeGeminiSchema(t)]);return[[e,Object.fromEntries(n)]]}return[[e,this.sanitizeGeminiSchema(t)]]});return Object.fromEntries(t)}extractTextParts(e){return typeof e==`string`?e.trim()?[e]:[]:Array.isArray(e)?e.map(e=>typeof e==`string`?e:e&&typeof e==`object`&&`text`in e&&typeof e.text==`string`?e.text:null).filter(e=>!!e?.trim()):[]}resolveMaxOutputTokens(e,t,n){return typeof e==`number`&&e>0?e:n||t===`minimal`?2048:4096}};const xe=`GEMINI_AUTH_CONFIG_ERROR`;var T=class extends Error{constructor(e,t){super(e),this.code=t,this.name=`GeminiAuthError`}},Se=class{constructor(e=C,t=process.env){this.logger=e,this.env=t}async resolveHeaders(e){let t=e.authMode??`auto`;return t===`api-key`?this.resolveApiKeyHeaders(e):t===`oauth`?this.resolveOAuthHeaders():await this.tryResolveApiKeyHeaders(e)??this.resolveOAuthHeaders()}getGeminiDirectory(){let e=this.env.GEMINI_CLI_HOME||u.default.homedir();return d.default.join(e,`.gemini`)}getSettingsPath(){return d.default.join(this.getGeminiDirectory(),`settings.json`)}getOAuthPath(){return d.default.join(this.getGeminiDirectory(),`oauth_creds.json`)}async tryResolveApiKeyHeaders(e){try{return await this.resolveApiKeyHeaders(e)}catch{return null}}async resolveApiKeyHeaders(e){let t=e.apiKeyEnvVar??e.authTokenEnvVar??`GEMINI_API_KEY`,n=this.env[t]?.trim();if(!n)throw new T(`Missing Gemini API key. Set ${t}.`,xe);return{headers:{"x-goog-api-key":n},authMode:`api-key`,authSource:`env`}}async resolveOAuthHeaders(){let e=await this.readSettings(),t=await this.readOAuthCredentials(),n=await this.refreshOAuthCredentialsIfNeeded(t),r=e?.security?.auth?.selectedType??null,i=n.access_token?.trim();if(!i)throw new T(`Missing Gemini OAuth credentials. Expected ${this.getOAuthPath()} or GEMINI_API_KEY.`,xe);return{headers:{Authorization:`Bearer ${i}`},authMode:`oauth`,authSource:`gemini-home`,authType:r}}async readOAuthCredentials(){try{let e=await g.default.readFile(this.getOAuthPath(),`utf8`);return JSON.parse(e)}catch(e){throw this.logger.warn(`[GeminiAuth] Failed to read oauth credentials`,{oauthPath:this.getOAuthPath(),cause:e}),new T(`Unable to read Gemini OAuth credentials from ${this.getOAuthPath()}.`,xe)}}async readSettings(){try{let e=await g.default.readFile(this.getSettingsPath(),`utf8`);return JSON.parse(e)}catch(e){return e?.code===`ENOENT`||this.logger.warn(`[GeminiAuth] Failed to read settings`,{settingsPath:this.getSettingsPath(),cause:e}),null}}async refreshOAuthCredentialsIfNeeded(e){if(!this.shouldRefreshCredentials(e))return e;let t=e.refresh_token?.trim();if(!t)return e;let n=new URLSearchParams({client_id:`681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com`,client_secret:`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`,grant_type:`refresh_token`,refresh_token:t}),r=await fetch(`https://oauth2.googleapis.com/token`,{method:`POST`,headers:{"content-type":`application/x-www-form-urlencoded`},body:n});if(!r.ok)return this.logger.warn(`[GeminiAuth] Failed to refresh oauth credentials`,{status:r.status,oauthPath:this.getOAuthPath()}),e;let i=await r.json(),a={...e,access_token:i.access_token??e.access_token,token_type:i.token_type??e.token_type,scope:i.scope??e.scope,expiry_date:typeof i.expires_in==`number`?Date.now()+i.expires_in*1e3:e.expiry_date};return await g.default.writeFile(this.getOAuthPath(),`${JSON.stringify(a,null,2)}\n`,`utf8`),a}shouldRefreshCredentials(e){let t=e.access_token?.trim(),n=e.expiry_date;return t?typeof n==`number`?n<=Date.now()+6e4:!1:!0}};const E=`event: `,D=`data: `,Ce=`message_start`,we=`content_block_start`,Te=`content_block_delta`,Ee=`content_block_stop`,De=`message_delta`,Oe=`message_stop`,ke=`end_turn`;var Ae=class{transformBuffered(e,t){let n=JSON.parse(e);return this.toClaudeStream([n],t)}transformStreaming(e,t){let n=[];for(let t of e.split(`
|
|
15
15
|
|
|
16
16
|
`)){let e=t.split(`
|
|
17
17
|
`).find(e=>e.startsWith(D))?.slice(6).trim();!e||e===`[DONE]`||n.push(JSON.parse(e))}return this.toClaudeStream(n,t)}toClaudeStream(e,t){let n=e.flatMap(e=>e.candidates??[]).flatMap(e=>e.content?.parts??[]).map(e=>`text`in e&&typeof e.text==`string`?e.text:``).join(``),r=e.map(e=>e.candidates?.[0]?.finishReason).find(e=>typeof e==`string`),i=e.find(e=>e.usageMetadata)?.usageMetadata,a=`msg_${(0,p.ulid)()}`,o=[];return o.push(`${E}${Ce}`),o.push(`${D}${JSON.stringify({type:Ce,message:{id:a,type:`message`,role:`assistant`,content:[],model:t,stop_reason:null,stop_sequence:null,usage:{input_tokens:i?.promptTokenCount??0,output_tokens:0}}})}`),o.push(``),o.push(`${E}${we}`),o.push(`${D}${JSON.stringify({type:we,index:0,content_block:{type:`text`,text:``}})}`),o.push(``),n&&(o.push(`${E}${Te}`),o.push(`${D}${JSON.stringify({type:Te,index:0,delta:{type:`text_delta`,text:n}})}`),o.push(``)),o.push(`${E}${Ee}`),o.push(`${D}${JSON.stringify({type:Ee,index:0})}`),o.push(``),o.push(`${E}${De}`),o.push(`${D}${JSON.stringify({type:De,delta:{stop_reason:this.mapStopReason(r),stop_sequence:null},usage:{output_tokens:i?.candidatesTokenCount??0}})}`),o.push(``),o.push(`${E}${Oe}`),o.push(`${D}${JSON.stringify({type:Oe})}`),o.push(``),o.join(`
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/model-proxy-mcp",
|
|
3
3
|
"description": "Claude-compatible model proxy MCP with ChatGPT Codex upstream support",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.5",
|
|
5
5
|
"license": "AGPL-3.0",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mcp",
|
|
@@ -20,24 +20,24 @@
|
|
|
20
20
|
"README.md"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@hono/node-server": "
|
|
23
|
+
"@hono/node-server": "2.0.1",
|
|
24
24
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
25
|
-
"better-sqlite3": "12.
|
|
25
|
+
"better-sqlite3": "12.9.0",
|
|
26
26
|
"commander": "14.0.3",
|
|
27
|
-
"hono": "4.12.
|
|
27
|
+
"hono": "4.12.16",
|
|
28
28
|
"reflect-metadata": "0.2.2",
|
|
29
29
|
"ulidx": "2.4.1",
|
|
30
30
|
"yaml": "2.8.3",
|
|
31
|
-
"zod": "4.
|
|
32
|
-
"@agimon-ai/foundation-
|
|
33
|
-
"@agimon-ai/foundation-
|
|
31
|
+
"zod": "4.4.1",
|
|
32
|
+
"@agimon-ai/foundation-port-registry": "0.8.5",
|
|
33
|
+
"@agimon-ai/foundation-process-registry": "0.8.5"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/better-sqlite3": "7.6.13",
|
|
37
37
|
"@types/node": "25.6.0",
|
|
38
|
-
"tsdown": "0.21.
|
|
39
|
-
"typescript": "6.0.
|
|
40
|
-
"vitest": "4.1.
|
|
38
|
+
"tsdown": "0.21.10",
|
|
39
|
+
"typescript": "6.0.3",
|
|
40
|
+
"vitest": "4.1.5"
|
|
41
41
|
},
|
|
42
42
|
"type": "module",
|
|
43
43
|
"exports": {
|