(overrides = {})
| 127 | } |
| 128 | |
| 129 | export async function startGatewayServer(overrides = {}) { |
| 130 | const config = resolveGatewayConfig(overrides) |
| 131 | if (!config.upstreamBaseUrl) { |
| 132 | throw new Error('OPENAI_COMPAT_BASE_URL is required') |
| 133 | } |
| 134 | |
| 135 | const server = http.createServer(async (req, res) => { |
| 136 | try { |
| 137 | const requestUrl = new URL(req.url || '/', `http://${config.host}:${config.port}`) |
| 138 | const pathname = requestUrl.pathname |
| 139 | |
| 140 | if (req.method === 'GET' && pathname === '/health') { |
| 141 | writeJson(res, 200, { |
| 142 | ok: true, |
| 143 | upstreamBaseUrl: config.upstreamBaseUrl, |
| 144 | upstreamChatPath: config.upstreamChatPath, |
| 145 | }) |
| 146 | return |
| 147 | } |
| 148 | |
| 149 | if (req.method === 'POST' && pathname === '/v1/messages') { |
| 150 | const body = await readJson(req) |
| 151 | |
| 152 | // ── Passthrough API key from request headers ── |
| 153 | if (!config.upstreamApiKey) { |
| 154 | const incomingKey = req.headers['x-api-key'] || '' |
| 155 | if (incomingKey && incomingKey !== 'dummy' && incomingKey !== 'unused') { |
| 156 | config = { ...config, upstreamApiKey: incomingKey } |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | // ── Soul + Memory injection (can be disabled via CLAW_ENABLE_SOUL=0) ── |
| 161 | const soulEnabled = process.env.CLAW_ENABLE_SOUL !== '0' |
| 162 | const soulPrefix = soulEnabled ? loadSoulPrefix(config) : '' |
| 163 | const memPrefix = soulEnabled ? loadMemoryPrefix(config) : '' |
| 164 | const injected = [soulPrefix, memPrefix].filter(Boolean).join('\n\n') |
| 165 | if (injected) { |
| 166 | const existing = typeof body.system === 'string' ? body.system : '' |
| 167 | body.system = injected + (existing ? '\n\n' + existing : '') |
| 168 | } |
| 169 | |
| 170 | if (config.textMode === 'anthropic') { |
| 171 | await handleAnthropicPassthrough(body, res, config) |
| 172 | return |
| 173 | } |
| 174 | if (config.textMode === 'gemini') { |
| 175 | if (body.stream) { |
| 176 | await handleGeminiStream(body, res, config) |
| 177 | } else { |
| 178 | await handleGeminiNonStream(body, res, config) |
| 179 | } |
| 180 | return |
| 181 | } |
| 182 | if (body.stream) { |
| 183 | await handleStream(body, res, config) |
| 184 | } else { |
| 185 | await handleNonStream(body, res, config) |
| 186 | } |
no test coverage detected