@wener/mcps 1.0.2 → 1.0.4

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.
Files changed (59) hide show
  1. package/README.md +144 -0
  2. package/dist/index.mjs +213076 -1
  3. package/dist/mcps-cli.mjs +102547 -59344
  4. package/lib/chat/handler.js +2 -2
  5. package/lib/chat/handler.js.map +1 -1
  6. package/lib/cli-start.js +36 -0
  7. package/lib/cli-start.js.map +1 -0
  8. package/lib/cli.js +19 -0
  9. package/lib/cli.js.map +1 -0
  10. package/lib/dev.server.js +7 -1
  11. package/lib/dev.server.js.map +1 -1
  12. package/lib/index.js +21 -3
  13. package/lib/index.js.map +1 -1
  14. package/lib/mcps-cli.js +6 -35
  15. package/lib/mcps-cli.js.map +1 -1
  16. package/lib/providers/feishu/def.js +35 -0
  17. package/lib/providers/feishu/def.js.map +1 -0
  18. package/lib/providers/findMcpServerDef.js +1 -0
  19. package/lib/providers/findMcpServerDef.js.map +1 -1
  20. package/lib/scripts/bundle.js +7 -1
  21. package/lib/scripts/bundle.js.map +1 -1
  22. package/lib/server/api-routes.js +7 -8
  23. package/lib/server/api-routes.js.map +1 -1
  24. package/lib/server/audit-db.js +64 -0
  25. package/lib/server/audit-db.js.map +1 -0
  26. package/lib/server/{audit.js → audit-plugin.js} +72 -126
  27. package/lib/server/audit-plugin.js.map +1 -0
  28. package/lib/server/events.js +13 -0
  29. package/lib/server/events.js.map +1 -0
  30. package/lib/server/mcp-routes.js +31 -60
  31. package/lib/server/mcp-routes.js.map +1 -1
  32. package/lib/server/mcps-router.js +19 -24
  33. package/lib/server/mcps-router.js.map +1 -1
  34. package/lib/server/schema.js +22 -2
  35. package/lib/server/schema.js.map +1 -1
  36. package/lib/server/server.js +142 -87
  37. package/lib/server/server.js.map +1 -1
  38. package/package.json +33 -6
  39. package/src/chat/handler.ts +2 -2
  40. package/src/cli-start.ts +43 -0
  41. package/src/cli.ts +45 -0
  42. package/src/dev.server.ts +8 -1
  43. package/src/index.ts +47 -1
  44. package/src/mcps-cli.ts +6 -48
  45. package/src/providers/feishu/def.ts +37 -0
  46. package/src/providers/findMcpServerDef.ts +1 -0
  47. package/src/scripts/bundle.ts +12 -1
  48. package/src/server/api-routes.ts +11 -8
  49. package/src/server/audit-db.ts +65 -0
  50. package/src/server/{audit.ts → audit-plugin.ts} +69 -142
  51. package/src/server/events.ts +29 -0
  52. package/src/server/mcp-routes.ts +30 -58
  53. package/src/server/mcps-router.ts +21 -29
  54. package/src/server/schema.ts +23 -2
  55. package/src/server/server.ts +149 -81
  56. package/lib/server/audit.js.map +0 -1
  57. package/lib/server/db.js +0 -97
  58. package/lib/server/db.js.map +0 -1
  59. package/src/server/db.ts +0 -115
@@ -634,7 +634,7 @@ const log = consola.withTag("chat");
634
634
  let previousContext = null;
635
635
  if (request.previous_response_id) {
636
636
  try {
637
- const { isDbInitialized, getEntityManager } = await import("../server/db.js");
637
+ const { isDbInitialized, getEntityManager } = await import("../server/audit-db.js");
638
638
  const { ResponseEntity } = await import("../entities/index.js");
639
639
  if (isDbInitialized()) {
640
640
  const em = getEntityManager().fork();
@@ -709,7 +709,7 @@ const log = consola.withTag("chat");
709
709
  const result = chatCompletionsToResponses(chatResponse, request.model);
710
710
  // Store response for future previous_response_id lookups
711
711
  try {
712
- const { isDbInitialized, getEntityManager } = await import("../server/db.js");
712
+ const { isDbInitialized, getEntityManager } = await import("../server/audit-db.js");
713
713
  const { ResponseEntity } = await import("../entities/index.js");
714
714
  if (isDbInitialized()) {
715
715
  const em = getEntityManager().fork();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/chat/handler.ts"],"sourcesContent":["/**\n * Chat API Handler\n * Provides unified AI model gateway with protocol conversion\n */\nimport consola from 'consola';\nimport { Hono } from 'hono';\nimport { streamSSE } from 'hono/streaming';\nimport type { ChatConfig, ModelConfig } from '../server/schema';\nimport { ChatProtocol, createAuditContext, extractClientIp } from './audit';\nimport {\n\topenaiToAnthropicRequest,\n\tanthropicToOpenaiResponse,\n\topenaiToGeminiRequest,\n\tgeminiToOpenaiResponse,\n} from './converters';\nimport {\n\tCreateChatCompletionRequestSchema,\n\ttype CreateChatCompletionRequest,\n\tCreateResponseRequestSchema,\n\ttype CreateResponseRequest,\n} from '@wener/ai/openai';\nimport { CreateMessageRequestSchema } from '@wener/ai/anthropic';\nimport { CreateGenerateContentRequestSchema } from '@wener/ai/google';\n\nconst log = consola.withTag('chat');\n\nexport interface ChatHandlerOptions {\n\tconfig?: ChatConfig;\n}\n\n/**\n * Create chat handler Hono app\n */\nexport function createChatHandler(options: ChatHandlerOptions = {}) {\n\tconst app = new Hono();\n\tconst { config = {} } = options;\n\n\t/**\n\t * Resolve model configuration\n\t */\n\tfunction resolveModelConfig(modelName: string): ModelConfig | null {\n\t\tconst models = config.models;\n\t\tif (!models || models.length === 0) return null;\n\n\t\t// First pass: exact match\n\t\tfor (const modelConfig of models) {\n\t\t\tif (modelConfig.name === modelName) {\n\t\t\t\treturn modelConfig;\n\t\t\t}\n\t\t}\n\n\t\t// Second pass: wildcard matches (e.g., \"gpt-*\" or \"claude-*\")\n\t\tfor (const modelConfig of models) {\n\t\t\tconst pattern = modelConfig.name;\n\t\t\tif (pattern.includes('*')) {\n\t\t\t\tconst regex = new RegExp(`^${pattern.replace(/\\*/g, '.*')}$`);\n\t\t\t\tif (regex.test(modelName)) {\n\t\t\t\t\treturn modelConfig;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Make request to upstream provider\n\t */\n\tasync function makeUpstreamRequest(\n\t\turl: string,\n\t\tbody: unknown,\n\t\theaders: Record<string, string>,\n\t\t_stream: boolean = false,\n\t): Promise<Response> {\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t...headers,\n\t\t\t},\n\t\t\tbody: JSON.stringify(body),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst errorText = await response.text();\n\t\t\tlog.error('Upstream error:', response.status, errorText);\n\t\t\tthrow new Error(`Upstream error: ${response.status} ${errorText}`);\n\t\t}\n\n\t\treturn response;\n\t}\n\n\t/**\n\t * Normalize base URL - strip trailing /v1 if present\n\t * This allows baseUrl to be specified as either \"http://example.com\" or \"http://example.com/v1\"\n\t */\n\tfunction normalizeBaseUrl(url: string): string {\n\t\treturn url.replace(/\\/v1\\/?$/, '');\n\t}\n\n\t/**\n\t * Build headers for upstream request\n\t */\n\tfunction buildUpstreamHeaders(\n\t\tmodelConfig: ModelConfig,\n\t\tadapter: 'openai' | 'anthropic' | 'gemini',\n\t): Record<string, string> {\n\t\tconst headers: Record<string, string> = {};\n\n\t\t// Add API key if configured\n\t\tif (modelConfig.apiKey) {\n\t\t\tif (adapter === 'anthropic') {\n\t\t\t\theaders['x-api-key'] = modelConfig.apiKey;\n\t\t\t\theaders['anthropic-version'] = '2023-06-01';\n\t\t\t} else {\n\t\t\t\theaders.Authorization = `Bearer ${modelConfig.apiKey}`;\n\t\t\t}\n\t\t}\n\n\t\t// Add custom headers\n\t\tif (modelConfig.headers) {\n\t\t\tObject.assign(headers, modelConfig.headers);\n\t\t}\n\n\t\t// Add adapter-specific headers\n\t\tif (modelConfig.adapters?.[adapter]?.headers) {\n\t\t\tObject.assign(headers, modelConfig.adapters[adapter]?.headers);\n\t\t}\n\n\t\treturn headers;\n\t}\n\n\t/**\n\t * Normalize OpenAI request for different providers\n\t * Handles max_tokens/max_completion_tokens compatibility and thinking parameters\n\t */\n\tfunction normalizeOpenAIRequest(request: CreateChatCompletionRequest): Record<string, unknown> {\n\t\tconst normalized: Record<string, unknown> = { ...request };\n\n\t\t// Handle max_tokens vs max_completion_tokens compatibility\n\t\t// Some providers only support max_tokens, others prefer max_completion_tokens\n\t\tif (request.max_completion_tokens && !request.max_tokens) {\n\t\t\tnormalized.max_tokens = request.max_completion_tokens;\n\t\t}\n\n\t\t// Handle enable_thinking parameter (used by Qwen, DeepSeek thinking models)\n\t\t// Convert to thinking object format if needed\n\t\tif (request.enable_thinking !== undefined && !request.thinking) {\n\t\t\tnormalized.thinking = {\n\t\t\t\ttype: request.enable_thinking ? 'enabled' : 'disabled',\n\t\t\t};\n\t\t}\n\n\t\treturn normalized;\n\t}\n\n\t// =========================================================================\n\t// OpenAI Chat Completions API\n\t// =========================================================================\n\n\tapp.post('/v1/chat/completions', async (c) => {\n\t\t// Create audit context early\n\t\tlet auditCtx: ReturnType<typeof createAuditContext> | null = null;\n\n\t\ttry {\n\t\t\tconst body = await c.req.json();\n\t\t\tconst parseResult = CreateChatCompletionRequestSchema.safeParse(body);\n\n\t\t\tif (!parseResult.success) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tmessage: 'Invalid request',\n\t\t\t\t\t\t\ttype: 'invalid_request_error',\n\t\t\t\t\t\t\tparam: null,\n\t\t\t\t\t\t\tcode: 'invalid_request',\n\t\t\t\t\t\t\tdetails: parseResult.error.issues,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst request = parseResult.data;\n\t\t\tconst modelConfig = resolveModelConfig(request.model);\n\n\t\t\tif (!modelConfig) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tmessage: `Model ${request.model} not configured`,\n\t\t\t\t\t\t\ttype: 'invalid_request_error',\n\t\t\t\t\t\t\tparam: 'model',\n\t\t\t\t\t\t\tcode: 'model_not_found',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t404,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Determine upstream adapter\n\t\t\tconst adapter = modelConfig.adapter || 'openai';\n\t\t\tconst baseUrl = normalizeBaseUrl(\n\t\t\t\tmodelConfig.adapters?.[adapter]?.baseUrl || modelConfig.baseUrl || 'https://api.openai.com',\n\t\t\t);\n\n\t\t\t// Create audit context\n\t\t\tconst outputProtocol =\n\t\t\t\tadapter === 'anthropic'\n\t\t\t\t\t? ChatProtocol.ANTHROPIC\n\t\t\t\t\t: adapter === 'gemini'\n\t\t\t\t\t\t? ChatProtocol.GEMINI\n\t\t\t\t\t\t: ChatProtocol.OPENAI;\n\n\t\t\tauditCtx = createAuditContext({\n\t\t\t\tmethod: 'POST',\n\t\t\t\tendpoint: '/v1/chat/completions',\n\t\t\t\tmodel: request.model,\n\t\t\t\tinputProtocol: ChatProtocol.OPENAI,\n\t\t\t\toutputProtocol,\n\t\t\t\tstreaming: request.stream || false,\n\t\t\t\tclientIp: extractClientIp(c),\n\t\t\t\tuserAgent: c.req.header('user-agent'),\n\t\t\t\trequestMeta: {\n\t\t\t\t\ttemperature: request.temperature,\n\t\t\t\t\tmax_tokens: request.max_tokens || request.max_completion_tokens,\n\t\t\t\t\ttop_p: request.top_p,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\t// Log incoming request\n\t\t\tlog.info(\n\t\t\t\t`→ POST /v1/chat/completions model=${request.model} stream=${request.stream || false} messages=${request.messages.length}`,\n\t\t\t);\n\n\t\t\t// Build upstream request based on protocol\n\t\t\tlet upstreamUrl: string;\n\t\t\tlet upstreamBody: unknown;\n\t\t\tlet upstreamHeaders: Record<string, string>;\n\n\t\t\tswitch (adapter) {\n\t\t\t\tcase 'anthropic': {\n\t\t\t\t\tupstreamUrl = `${baseUrl}/v1/messages`;\n\t\t\t\t\tupstreamBody = openaiToAnthropicRequest(request);\n\t\t\t\t\tupstreamHeaders = buildUpstreamHeaders(modelConfig, 'anthropic');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'gemini': {\n\t\t\t\t\tconst method = request.stream ? 'streamGenerateContent' : 'generateContent';\n\t\t\t\t\tupstreamUrl = `${baseUrl}/v1/models/${request.model}:${method}`;\n\t\t\t\t\tupstreamBody = openaiToGeminiRequest(request);\n\t\t\t\t\tupstreamHeaders = buildUpstreamHeaders(modelConfig, 'gemini');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\t// OpenAI adapter - passthrough with parameter normalization\n\t\t\t\t\tupstreamUrl = `${baseUrl}/v1/chat/completions`;\n\t\t\t\t\tupstreamBody = normalizeOpenAIRequest(request);\n\t\t\t\t\tupstreamHeaders = buildUpstreamHeaders(modelConfig, 'openai');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set provider info in audit context\n\t\t\tauditCtx.setProvider({\n\t\t\t\tprovider: adapter,\n\t\t\t\tupstreamUrl,\n\t\t\t});\n\n\t\t\t// Handle streaming\n\t\t\tif (request.stream) {\n\t\t\t\treturn handleStreamingRequest(c, upstreamUrl, upstreamBody, upstreamHeaders, adapter, request.model, auditCtx);\n\t\t\t}\n\n\t\t\t// Non-streaming request\n\t\t\tconst response = await makeUpstreamRequest(upstreamUrl, upstreamBody, upstreamHeaders);\n\t\t\tconst responseData = await response.json();\n\n\t\t\t// Convert response if needed\n\t\t\tlet result: any;\n\t\t\tswitch (adapter) {\n\t\t\t\tcase 'anthropic':\n\t\t\t\t\tresult = anthropicToOpenaiResponse(responseData, request.model);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'gemini':\n\t\t\t\t\tresult = geminiToOpenaiResponse(responseData, request.model);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tresult = responseData;\n\t\t\t}\n\n\t\t\t// Record token usage and complete audit\n\t\t\tif (result.usage) {\n\t\t\t\tauditCtx.setTokenUsage(result.usage.prompt_tokens || 0, result.usage.completion_tokens || 0);\n\t\t\t}\n\t\t\tauditCtx.setResponseMeta({\n\t\t\t\tfinish_reason: result.choices?.[0]?.finish_reason,\n\t\t\t\tmodel: result.model,\n\t\t\t});\n\t\t\tawait auditCtx.complete(200);\n\n\t\t\t// Log response\n\t\t\tconst usage = result.usage;\n\t\t\tlog.info(\n\t\t\t\t`← 200 /v1/chat/completions model=${result.model || request.model} tokens=${usage?.total_tokens || 0} (in=${usage?.prompt_tokens || 0} out=${usage?.completion_tokens || 0})`,\n\t\t\t);\n\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\t// Record error in audit\n\t\t\tif (auditCtx) {\n\t\t\t\tawait auditCtx.error(error instanceof Error ? error.message : 'Unknown error', 'internal_error', 500);\n\t\t\t}\n\t\t\tlog.error('Chat completion error:', error);\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\terror: {\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : 'Internal server error',\n\t\t\t\t\t\ttype: 'api_error',\n\t\t\t\t\t\tcode: 'internal_error',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t/**\n\t * Handle streaming request\n\t */\n\tasync function handleStreamingRequest(\n\t\tc: any,\n\t\tupstreamUrl: string,\n\t\tupstreamBody: unknown,\n\t\tupstreamHeaders: Record<string, string>,\n\t\tadapter: string,\n\t\tmodel: string,\n\t\tauditCtx?: ReturnType<typeof createAuditContext>,\n\t) {\n\t\tconst response = await makeUpstreamRequest(upstreamUrl, upstreamBody, upstreamHeaders, true);\n\n\t\tlet firstTokenRecorded = false;\n\t\tlet totalOutputTokens = 0;\n\n\t\t// For streaming, we need to convert events on the fly\n\t\treturn streamSSE(c, async (stream) => {\n\t\t\tconst reader = response.body?.getReader();\n\t\t\tif (!reader) {\n\t\t\t\tawait stream.writeSSE({ data: '[DONE]' });\n\t\t\t\tif (auditCtx) await auditCtx.complete(200);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buffer = '';\n\n\t\t\ttry {\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) break;\n\n\t\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\t\tconst lines = buffer.split('\\n');\n\t\t\t\t\tbuffer = lines.pop() || '';\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\tif (!line.trim()) continue;\n\n\t\t\t\t\t\tif (line.startsWith('data: ')) {\n\t\t\t\t\t\t\tconst data = line.slice(6);\n\t\t\t\t\t\t\tif (data === '[DONE]') {\n\t\t\t\t\t\t\t\tawait stream.writeSSE({ data: '[DONE]' });\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst parsed = JSON.parse(data);\n\t\t\t\t\t\t\t\tconst converted = convertStreamEvent(parsed, adapter, model);\n\t\t\t\t\t\t\t\tif (converted) {\n\t\t\t\t\t\t\t\t\t// Record first token for TTFT\n\t\t\t\t\t\t\t\t\tif (!firstTokenRecorded && auditCtx) {\n\t\t\t\t\t\t\t\t\t\tauditCtx.recordFirstToken();\n\t\t\t\t\t\t\t\t\t\tfirstTokenRecorded = true;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t// Track usage from stream events\n\t\t\t\t\t\t\t\t\tif (converted.usage) {\n\t\t\t\t\t\t\t\t\t\ttotalOutputTokens = converted.usage.completion_tokens || totalOutputTokens;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tawait stream.writeSSE({ data: JSON.stringify(converted) });\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// Skip invalid JSON\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (line.startsWith('event: ')) {\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Send done signal\n\t\t\t\tawait stream.writeSSE({ data: '[DONE]' });\n\n\t\t\t\t// Complete audit\n\t\t\t\tif (auditCtx) {\n\t\t\t\t\tauditCtx.setTokenUsage(0, totalOutputTokens); // Input tokens not available in streaming\n\t\t\t\t\tawait auditCtx.complete(200);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// Record streaming error\n\t\t\t\tif (auditCtx) {\n\t\t\t\t\tawait auditCtx.error(err instanceof Error ? err.message : 'Streaming error', 'streaming_error', 500);\n\t\t\t\t}\n\t\t\t\tthrow err;\n\t\t\t} finally {\n\t\t\t\treader.releaseLock();\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Convert stream event to OpenAI format\n\t */\n\tfunction convertStreamEvent(event: any, adapter: string, model: string): any {\n\t\tswitch (adapter) {\n\t\t\tcase 'anthropic':\n\t\t\t\treturn convertAnthropicStreamEvent(event, model);\n\t\t\tcase 'gemini':\n\t\t\t\treturn convertGeminiStreamEvent(event, model);\n\t\t\tdefault:\n\t\t\t\treturn event;\n\t\t}\n\t}\n\n\t/**\n\t * Convert Anthropic stream event to OpenAI format\n\t */\n\tfunction convertAnthropicStreamEvent(event: any, model: string): any {\n\t\tif (event.type === 'content_block_delta') {\n\t\t\tif (event.delta?.type === 'text_delta') {\n\t\t\t\treturn {\n\t\t\t\t\tid: `chatcmpl-${Date.now()}`,\n\t\t\t\t\tobject: 'chat.completion.chunk',\n\t\t\t\t\tcreated: Math.floor(Date.now() / 1000),\n\t\t\t\t\tmodel,\n\t\t\t\t\tchoices: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tindex: 0,\n\t\t\t\t\t\t\tdelta: { content: event.delta.text },\n\t\t\t\t\t\t\tfinish_reason: null,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t} else if (event.type === 'message_delta') {\n\t\t\tconst finishReason =\n\t\t\t\tevent.delta?.stop_reason === 'end_turn'\n\t\t\t\t\t? 'stop'\n\t\t\t\t\t: event.delta?.stop_reason === 'tool_use'\n\t\t\t\t\t\t? 'tool_calls'\n\t\t\t\t\t\t: null;\n\t\t\treturn {\n\t\t\t\tid: `chatcmpl-${Date.now()}`,\n\t\t\t\tobject: 'chat.completion.chunk',\n\t\t\t\tcreated: Math.floor(Date.now() / 1000),\n\t\t\t\tmodel,\n\t\t\t\tchoices: [\n\t\t\t\t\t{\n\t\t\t\t\t\tindex: 0,\n\t\t\t\t\t\tdelta: {},\n\t\t\t\t\t\tfinish_reason: finishReason,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tusage: event.usage\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tprompt_tokens: 0,\n\t\t\t\t\t\t\tcompletion_tokens: event.usage.output_tokens,\n\t\t\t\t\t\t\ttotal_tokens: event.usage.output_tokens,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t};\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Convert Gemini stream event to OpenAI format\n\t */\n\tfunction convertGeminiStreamEvent(event: any, model: string): any {\n\t\tif (event.candidates?.[0]?.content?.parts) {\n\t\t\tconst parts = event.candidates[0].content.parts;\n\t\t\tconst textParts = parts.filter((p: any) => p.text);\n\n\t\t\tif (textParts.length > 0) {\n\t\t\t\treturn {\n\t\t\t\t\tid: `chatcmpl-${Date.now()}`,\n\t\t\t\t\tobject: 'chat.completion.chunk',\n\t\t\t\t\tcreated: Math.floor(Date.now() / 1000),\n\t\t\t\t\tmodel,\n\t\t\t\t\tchoices: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tindex: 0,\n\t\t\t\t\t\t\tdelta: { content: textParts.map((p: any) => p.text).join('') },\n\t\t\t\t\t\t\tfinish_reason: event.candidates[0].finishReason === 'STOP' ? 'stop' : null,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t// =========================================================================\n\t// Anthropic Messages API\n\t// =========================================================================\n\n\tapp.post('/v1/messages', async (c) => {\n\t\ttry {\n\t\t\tconst body = await c.req.json();\n\t\t\tconst parseResult = CreateMessageRequestSchema.safeParse(body);\n\n\t\t\tif (!parseResult.success) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\ttype: 'invalid_request_error',\n\t\t\t\t\t\t\tmessage: 'Invalid request',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst request = parseResult.data;\n\t\t\tconst modelConfig = resolveModelConfig(request.model);\n\n\t\t\tif (!modelConfig) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\ttype: 'invalid_request_error',\n\t\t\t\t\t\t\tmessage: `Model ${request.model} not configured`,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t404,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// For Anthropic endpoint, we pass through to Anthropic or convert from OpenAI\n\t\t\tconst adapter = modelConfig.adapter || 'anthropic';\n\t\t\tconst baseUrl = normalizeBaseUrl(\n\t\t\t\tmodelConfig.adapters?.[adapter]?.baseUrl || modelConfig.baseUrl || 'https://api.anthropic.com',\n\t\t\t);\n\n\t\t\tconst upstreamUrl = `${baseUrl}/v1/messages`;\n\t\t\tconst upstreamHeaders = buildUpstreamHeaders(modelConfig, 'anthropic');\n\n\t\t\t// Log incoming request\n\t\t\tlog.info(`→ POST /v1/messages model=${request.model} messages=${request.messages.length}`);\n\n\t\t\tconst response = await makeUpstreamRequest(upstreamUrl, request, upstreamHeaders);\n\t\t\tconst responseData = await response.json();\n\n\t\t\t// Log response\n\t\t\tconst usage = responseData.usage;\n\t\t\tlog.info(\n\t\t\t\t`← 200 /v1/messages model=${responseData.model || request.model} tokens=${(usage?.input_tokens || 0) + (usage?.output_tokens || 0)} (in=${usage?.input_tokens || 0} out=${usage?.output_tokens || 0})`,\n\t\t\t);\n\n\t\t\treturn c.json(responseData);\n\t\t} catch (error) {\n\t\t\tlog.error('Messages error:', error);\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\terror: {\n\t\t\t\t\t\ttype: 'api_error',\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : 'Internal server error',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t// =========================================================================\n\t// Gemini Generate Content API\n\t// =========================================================================\n\n\tapp.post('/v1/models/:model\\\\:generateContent', async (c) => {\n\t\ttry {\n\t\t\tconst model = c.req.param('model');\n\t\t\tif (!model) {\n\t\t\t\treturn c.json({ error: { message: 'Model parameter is required' } }, 400);\n\t\t\t}\n\n\t\t\tconst body = await c.req.json();\n\t\t\tconst parseResult = CreateGenerateContentRequestSchema.safeParse(body);\n\n\t\t\tif (!parseResult.success) {\n\t\t\t\treturn c.json({ error: { message: 'Invalid request' } }, 400);\n\t\t\t}\n\n\t\t\tconst request = parseResult.data;\n\t\t\tconst modelConfig = resolveModelConfig(model);\n\n\t\t\tif (!modelConfig) {\n\t\t\t\treturn c.json({ error: { message: `Model ${model} not configured` } }, 404);\n\t\t\t}\n\n\t\t\tconst baseUrl = normalizeBaseUrl(\n\t\t\t\tmodelConfig.adapters?.gemini?.baseUrl || modelConfig.baseUrl || 'https://generativelanguage.googleapis.com',\n\t\t\t);\n\n\t\t\tconst upstreamUrl = `${baseUrl}/v1/models/${model}:generateContent`;\n\t\t\tconst upstreamHeaders = buildUpstreamHeaders(modelConfig, 'gemini');\n\n\t\t\t// Log incoming request\n\t\t\tlog.info(`→ POST /v1/models/${model}:generateContent contents=${request.contents?.length || 0}`);\n\n\t\t\tconst response = await makeUpstreamRequest(upstreamUrl, request, upstreamHeaders);\n\t\t\tconst responseData = await response.json();\n\n\t\t\t// Log response\n\t\t\tconst usage = responseData.usageMetadata;\n\t\t\tlog.info(\n\t\t\t\t`← 200 /v1/models/${model}:generateContent tokens=${usage?.totalTokenCount || 0} (in=${usage?.promptTokenCount || 0} out=${usage?.candidatesTokenCount || 0})`,\n\t\t\t);\n\n\t\t\treturn c.json(responseData);\n\t\t} catch (error) {\n\t\t\tlog.error('Generate content error:', error);\n\t\t\treturn c.json({ error: { message: error instanceof Error ? error.message : 'Internal server error' } }, 500);\n\t\t}\n\t});\n\n\t// =========================================================================\n\t// Gemini Streaming Generate Content API\n\t// =========================================================================\n\n\tapp.post('/v1/models/:model\\\\:streamGenerateContent', async (c) => {\n\t\ttry {\n\t\t\tconst model = c.req.param('model');\n\t\t\tif (!model) {\n\t\t\t\treturn c.json({ error: { message: 'Model parameter is required' } }, 400);\n\t\t\t}\n\n\t\t\tconst body = await c.req.json();\n\t\t\tconst parseResult = CreateGenerateContentRequestSchema.safeParse(body);\n\n\t\t\tif (!parseResult.success) {\n\t\t\t\treturn c.json({ error: { message: 'Invalid request' } }, 400);\n\t\t\t}\n\n\t\t\tconst request = parseResult.data;\n\n\t\t\t// Log incoming request\n\t\t\tlog.info(`→ POST /v1/models/${model}:streamGenerateContent contents=${request.contents?.length || 0}`);\n\n\t\t\tconst modelConfig = resolveModelConfig(model);\n\n\t\t\tif (!modelConfig) {\n\t\t\t\treturn c.json({ error: { message: `Model ${model} not configured` } }, 404);\n\t\t\t}\n\n\t\t\tconst baseUrl = normalizeBaseUrl(\n\t\t\t\tmodelConfig.adapters?.gemini?.baseUrl || modelConfig.baseUrl || 'https://generativelanguage.googleapis.com',\n\t\t\t);\n\n\t\t\tconst upstreamUrl = `${baseUrl}/v1/models/${model}:streamGenerateContent`;\n\t\t\tconst upstreamHeaders = buildUpstreamHeaders(modelConfig, 'gemini');\n\n\t\t\tconst response = await makeUpstreamRequest(upstreamUrl, request, upstreamHeaders, true);\n\n\t\t\t// Stream the response directly\n\t\t\treturn streamSSE(c, async (stream) => {\n\t\t\t\tconst reader = response.body?.getReader();\n\t\t\t\tif (!reader) {\n\t\t\t\t\tawait stream.writeSSE({ data: '[DONE]' });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst decoder = new TextDecoder();\n\t\t\t\tlet buffer = '';\n\n\t\t\t\ttry {\n\t\t\t\t\twhile (true) {\n\t\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\t\tif (done) break;\n\n\t\t\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\t\t\tconst lines = buffer.split('\\n');\n\t\t\t\t\t\tbuffer = lines.pop() || '';\n\n\t\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\t\tif (!line.trim()) continue;\n\n\t\t\t\t\t\t\tif (line.startsWith('data: ')) {\n\t\t\t\t\t\t\t\tconst data = line.slice(6);\n\t\t\t\t\t\t\t\tif (data === '[DONE]') {\n\t\t\t\t\t\t\t\t\tawait stream.writeSSE({ data: '[DONE]' });\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tawait stream.writeSSE({ data });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tawait stream.writeSSE({ data: '[DONE]' });\n\t\t\t\t} finally {\n\t\t\t\t\treader.releaseLock();\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tlog.error('Stream generate content error:', error);\n\t\t\treturn c.json({ error: { message: error instanceof Error ? error.message : 'Internal server error' } }, 500);\n\t\t}\n\t});\n\n\t// =========================================================================\n\t// OpenAI Responses API\n\t// =========================================================================\n\n\tapp.post('/v1/responses', async (c) => {\n\t\tlet auditCtx: ReturnType<typeof createAuditContext> | null = null;\n\n\t\ttry {\n\t\t\tconst body = await c.req.json();\n\t\t\tconst parseResult = CreateResponseRequestSchema.safeParse(body);\n\n\t\t\tif (!parseResult.success) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tmessage: 'Invalid request',\n\t\t\t\t\t\t\ttype: 'invalid_request_error',\n\t\t\t\t\t\t\tparam: null,\n\t\t\t\t\t\t\tcode: 'invalid_request',\n\t\t\t\t\t\t\tdetails: parseResult.error.issues,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst request = parseResult.data;\n\n\t\t\t// Handle previous_response_id - load previous context\n\t\t\tlet previousContext: { input: unknown; output: unknown[] } | null = null;\n\t\t\tif (request.previous_response_id) {\n\t\t\t\ttry {\n\t\t\t\t\tconst { isDbInitialized, getEntityManager } = await import('../server/db');\n\t\t\t\t\tconst { ResponseEntity } = await import('../entities');\n\t\t\t\t\tif (isDbInitialized()) {\n\t\t\t\t\t\tconst em = getEntityManager().fork();\n\t\t\t\t\t\tconst prevResponse = await em.findOne(ResponseEntity, { responseId: request.previous_response_id });\n\t\t\t\t\t\tif (prevResponse) {\n\t\t\t\t\t\t\tpreviousContext = {\n\t\t\t\t\t\t\t\tinput: prevResponse.input,\n\t\t\t\t\t\t\t\toutput: prevResponse.output,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tlog.info(`Loaded previous response: ${request.previous_response_id}`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlog.warn(`Previous response not found: ${request.previous_response_id}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tlog.warn('Failed to load previous response:', e);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst modelConfig = resolveModelConfig(request.model);\n\n\t\t\tif (!modelConfig) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tmessage: `Model ${request.model} not configured`,\n\t\t\t\t\t\t\ttype: 'invalid_request_error',\n\t\t\t\t\t\t\tparam: 'model',\n\t\t\t\t\t\t\tcode: 'model_not_found',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t404,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Determine adapter - for Responses API, we convert to Chat Completions\n\t\t\tconst adapter = modelConfig.adapter || 'openai';\n\t\t\tconst baseUrl = normalizeBaseUrl(\n\t\t\t\tmodelConfig.adapters?.[adapter]?.baseUrl || modelConfig.baseUrl || 'https://api.openai.com',\n\t\t\t);\n\n\t\t\t// Create audit context\n\t\t\tauditCtx = createAuditContext({\n\t\t\t\tmethod: 'POST',\n\t\t\t\tendpoint: '/v1/responses',\n\t\t\t\tmodel: request.model,\n\t\t\t\tinputProtocol: ChatProtocol.OPENAI,\n\t\t\t\toutputProtocol: ChatProtocol.OPENAI,\n\t\t\t\tstreaming: request.stream || false,\n\t\t\t\tclientIp: extractClientIp(c),\n\t\t\t\tuserAgent: c.req.header('user-agent'),\n\t\t\t\trequestMeta: {\n\t\t\t\t\ttemperature: request.temperature,\n\t\t\t\t\tmax_output_tokens: request.max_output_tokens,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\t// Log incoming request\n\t\t\tconst inputType =\n\t\t\t\ttypeof request.input === 'string'\n\t\t\t\t\t? 'string'\n\t\t\t\t\t: Array.isArray(request.input)\n\t\t\t\t\t\t? `array[${request.input.length}]`\n\t\t\t\t\t\t: 'object';\n\t\t\tlog.info(`→ POST /v1/responses model=${request.model} stream=${request.stream || false} input=${inputType}`);\n\n\t\t\t// Convert Responses API request to Chat Completions format\n\t\t\tconst chatRequest = responsesToChatCompletions(request, previousContext);\n\n\t\t\t// Build upstream request\n\t\t\tconst upstreamUrl = `${baseUrl}/v1/chat/completions`;\n\t\t\tconst upstreamHeaders = buildUpstreamHeaders(modelConfig, 'openai');\n\n\t\t\tauditCtx.setProvider({\n\t\t\t\tprovider: adapter,\n\t\t\t\tupstreamUrl,\n\t\t\t});\n\n\t\t\t// Handle streaming\n\t\t\tif (request.stream) {\n\t\t\t\treturn handleResponsesStreamingRequest(c, upstreamUrl, chatRequest, upstreamHeaders, request.model, auditCtx);\n\t\t\t}\n\n\t\t\t// Non-streaming request\n\t\t\tconst response = await makeUpstreamRequest(upstreamUrl, chatRequest, upstreamHeaders);\n\t\t\tconst chatResponse = await response.json();\n\n\t\t\t// Convert Chat Completions response to Responses format\n\t\t\tconst result = chatCompletionsToResponses(chatResponse, request.model);\n\n\t\t\t// Store response for future previous_response_id lookups\n\t\t\ttry {\n\t\t\t\tconst { isDbInitialized, getEntityManager } = await import('../server/db');\n\t\t\t\tconst { ResponseEntity } = await import('../entities');\n\t\t\t\tif (isDbInitialized()) {\n\t\t\t\t\tconst em = getEntityManager().fork();\n\t\t\t\t\tconst responseEntity = new ResponseEntity();\n\t\t\t\t\tresponseEntity.responseId = result.id;\n\t\t\t\t\tresponseEntity.model = result.model;\n\t\t\t\t\tresponseEntity.status = result.status;\n\t\t\t\t\tresponseEntity.input = request.input;\n\t\t\t\t\tresponseEntity.output = result.output;\n\t\t\t\t\tresponseEntity.usage = result.usage;\n\t\t\t\t\tresponseEntity.instructions = request.instructions ?? undefined;\n\t\t\t\t\tresponseEntity.previousResponseId = request.previous_response_id ?? undefined;\n\t\t\t\t\tresponseEntity.tools = request.tools ?? undefined;\n\t\t\t\t\tresponseEntity.toolChoice = request.tool_choice ?? undefined;\n\t\t\t\t\tresponseEntity.metadata = request.metadata as Record<string, unknown>;\n\t\t\t\t\tresponseEntity.durationMs = auditCtx?.getDuration();\n\t\t\t\t\tem.persist(responseEntity);\n\t\t\t\t\tawait em.flush();\n\t\t\t\t\tlog.debug(`Stored response: ${result.id}`);\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\tlog.warn('Failed to store response:', e);\n\t\t\t}\n\n\t\t\t// Record usage\n\t\t\tif (chatResponse.usage) {\n\t\t\t\tauditCtx.setTokenUsage(chatResponse.usage.prompt_tokens || 0, chatResponse.usage.completion_tokens || 0);\n\t\t\t}\n\t\t\tauditCtx.setResponseMeta({\n\t\t\t\tstatus: result.status,\n\t\t\t\toutput_items: result.output.length,\n\t\t\t});\n\t\t\tawait auditCtx.complete(200);\n\n\t\t\t// Log response\n\t\t\tconst usage = chatResponse.usage;\n\t\t\tlog.info(\n\t\t\t\t`← 200 /v1/responses model=${result.model || request.model} status=${result.status} tokens=${usage?.total_tokens || 0}`,\n\t\t\t);\n\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tif (auditCtx) {\n\t\t\t\tawait auditCtx.error(error instanceof Error ? error.message : 'Unknown error', 'internal_error', 500);\n\t\t\t}\n\t\t\tlog.error('Responses API error:', error);\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\terror: {\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : 'Internal server error',\n\t\t\t\t\t\ttype: 'api_error',\n\t\t\t\t\t\tcode: 'internal_error',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t/**\n\t * Convert Responses API request to Chat Completions format\n\t */\n\tfunction responsesToChatCompletions(\n\t\trequest: CreateResponseRequest,\n\t\tpreviousContext?: { input: unknown; output: unknown[] } | null,\n\t): CreateChatCompletionRequest {\n\t\tconst messages: CreateChatCompletionRequest['messages'] = [];\n\n\t\t// Add system instruction if present\n\t\tif (request.instructions) {\n\t\t\tmessages.push({\n\t\t\t\trole: 'system',\n\t\t\t\tcontent: request.instructions,\n\t\t\t});\n\t\t}\n\n\t\t// Add previous context if available (previous_response_id)\n\t\tif (previousContext) {\n\t\t\t// Add previous input\n\t\t\tconst prevInput = previousContext.input;\n\t\t\tif (typeof prevInput === 'string') {\n\t\t\t\tmessages.push({ role: 'user', content: prevInput });\n\t\t\t} else if (Array.isArray(prevInput)) {\n\t\t\t\tfor (const item of prevInput as any[]) {\n\t\t\t\t\tif (item.type === 'message') {\n\t\t\t\t\t\tmessages.push({\n\t\t\t\t\t\t\trole: item.role as 'user' | 'assistant' | 'system',\n\t\t\t\t\t\t\tcontent: typeof item.content === 'string' ? item.content : JSON.stringify(item.content),\n\t\t\t\t\t\t} as any);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add previous output as assistant messages\n\t\t\tfor (const item of previousContext.output as any[]) {\n\t\t\t\tif (item.type === 'message' && item.role === 'assistant') {\n\t\t\t\t\tconst textContent = item.content?.find((c: any) => c.type === 'text' || c.type === 'output_text');\n\t\t\t\t\tif (textContent) {\n\t\t\t\t\t\tmessages.push({\n\t\t\t\t\t\t\trole: 'assistant',\n\t\t\t\t\t\t\tcontent: textContent.text,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Convert current input to messages\n\t\tif (typeof request.input === 'string') {\n\t\t\tmessages.push({\n\t\t\t\trole: 'user',\n\t\t\t\tcontent: request.input,\n\t\t\t});\n\t\t} else if (Array.isArray(request.input)) {\n\t\t\tfor (const item of request.input) {\n\t\t\t\tif (item.type === 'message') {\n\t\t\t\t\tmessages.push({\n\t\t\t\t\t\trole: item.role as 'user' | 'assistant' | 'system',\n\t\t\t\t\t\tcontent: typeof item.content === 'string' ? item.content : JSON.stringify(item.content),\n\t\t\t\t\t} as any);\n\t\t\t\t}\n\t\t\t\t// item_reference is handled differently - would need to fetch the referenced item\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tmodel: request.model,\n\t\t\tmessages,\n\t\t\ttemperature: request.temperature,\n\t\t\ttop_p: request.top_p,\n\t\t\tmax_tokens: request.max_output_tokens,\n\t\t\tstream: request.stream,\n\t\t\ttools: request.tools,\n\t\t\ttool_choice: request.tool_choice,\n\t\t\tparallel_tool_calls: request.parallel_tool_calls,\n\t\t\tmetadata: request.metadata,\n\t\t\tstore: request.store,\n\t\t\tuser: request.user,\n\t\t} as CreateChatCompletionRequest;\n\t}\n\n\t/**\n\t * Convert Chat Completions response to Responses format\n\t */\n\tfunction chatCompletionsToResponses(chatResponse: any, model: string): any {\n\t\tconst responseId = `resp_${chatResponse.id || Date.now()}`;\n\t\tconst output: any[] = [];\n\n\t\tfor (const choice of chatResponse.choices || []) {\n\t\t\tconst message = choice.message;\n\t\t\tif (message) {\n\t\t\t\toutput.push({\n\t\t\t\t\tid: `item_${responseId}_${choice.index}`,\n\t\t\t\t\ttype: 'message',\n\t\t\t\t\trole: 'assistant',\n\t\t\t\t\tcontent: message.content ? [{ type: 'text', text: message.content }] : [],\n\t\t\t\t\tstatus: 'completed',\n\t\t\t\t});\n\n\t\t\t\t// Handle tool calls\n\t\t\t\tif (message.tool_calls) {\n\t\t\t\t\tfor (const toolCall of message.tool_calls) {\n\t\t\t\t\t\toutput.push({\n\t\t\t\t\t\t\tid: toolCall.id,\n\t\t\t\t\t\t\ttype: 'function_call',\n\t\t\t\t\t\t\tname: toolCall.function?.name,\n\t\t\t\t\t\t\targuments: toolCall.function?.arguments,\n\t\t\t\t\t\t\tstatus: 'completed',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tid: responseId,\n\t\t\tobject: 'response',\n\t\t\tcreated_at: chatResponse.created || Math.floor(Date.now() / 1000),\n\t\t\tmodel: chatResponse.model || model,\n\t\t\tstatus: 'completed',\n\t\t\toutput,\n\t\t\tusage: chatResponse.usage,\n\t\t\tmetadata: {},\n\t\t\terror: null,\n\t\t};\n\t}\n\n\t/**\n\t * Handle Responses API streaming\n\t */\n\tasync function handleResponsesStreamingRequest(\n\t\tc: any,\n\t\tupstreamUrl: string,\n\t\tupstreamBody: unknown,\n\t\tupstreamHeaders: Record<string, string>,\n\t\tmodel: string,\n\t\tauditCtx?: ReturnType<typeof createAuditContext>,\n\t) {\n\t\tconst response = await makeUpstreamRequest(\n\t\t\tupstreamUrl,\n\t\t\t{ ...(upstreamBody as any), stream: true },\n\t\t\tupstreamHeaders,\n\t\t\ttrue,\n\t\t);\n\n\t\tlet firstTokenRecorded = false;\n\t\tconst responseId = `resp_${Date.now()}`;\n\n\t\treturn streamSSE(c, async (stream) => {\n\t\t\tconst reader = response.body?.getReader();\n\t\t\tif (!reader) {\n\t\t\t\tawait stream.writeSSE({ event: 'response.done', data: JSON.stringify({ type: 'response.done' }) });\n\t\t\t\tif (auditCtx) await auditCtx.complete(200);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Send initial event\n\t\t\tawait stream.writeSSE({\n\t\t\t\tevent: 'response.created',\n\t\t\t\tdata: JSON.stringify({\n\t\t\t\t\ttype: 'response.created',\n\t\t\t\t\tresponse: {\n\t\t\t\t\t\tid: responseId,\n\t\t\t\t\t\tobject: 'response',\n\t\t\t\t\t\tcreated_at: Math.floor(Date.now() / 1000),\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tstatus: 'in_progress',\n\t\t\t\t\t\toutput: [],\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buffer = '';\n\t\t\tlet outputItemId = `item_${responseId}_0`;\n\n\t\t\ttry {\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) break;\n\n\t\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\t\tconst lines = buffer.split('\\n');\n\t\t\t\t\tbuffer = lines.pop() || '';\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\tif (!line.trim() || !line.startsWith('data: ')) continue;\n\n\t\t\t\t\t\tconst data = line.slice(6);\n\t\t\t\t\t\tif (data === '[DONE]') continue;\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst parsed = JSON.parse(data);\n\t\t\t\t\t\t\tconst delta = parsed.choices?.[0]?.delta;\n\n\t\t\t\t\t\t\tif (delta?.content) {\n\t\t\t\t\t\t\t\tif (!firstTokenRecorded && auditCtx) {\n\t\t\t\t\t\t\t\t\tauditCtx.recordFirstToken();\n\t\t\t\t\t\t\t\t\tfirstTokenRecorded = true;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tawait stream.writeSSE({\n\t\t\t\t\t\t\t\t\tevent: 'response.output_text.delta',\n\t\t\t\t\t\t\t\t\tdata: JSON.stringify({\n\t\t\t\t\t\t\t\t\t\ttype: 'response.output_text.delta',\n\t\t\t\t\t\t\t\t\t\toutput_index: 0,\n\t\t\t\t\t\t\t\t\t\tcontent_index: 0,\n\t\t\t\t\t\t\t\t\t\tdelta: delta.content,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Skip invalid JSON\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Send completion events\n\t\t\t\tawait stream.writeSSE({\n\t\t\t\t\tevent: 'response.output_item.done',\n\t\t\t\t\tdata: JSON.stringify({\n\t\t\t\t\t\ttype: 'response.output_item.done',\n\t\t\t\t\t\toutput_index: 0,\n\t\t\t\t\t\titem: {\n\t\t\t\t\t\t\tid: outputItemId,\n\t\t\t\t\t\t\ttype: 'message',\n\t\t\t\t\t\t\trole: 'assistant',\n\t\t\t\t\t\t\tstatus: 'completed',\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t});\n\n\t\t\t\tawait stream.writeSSE({\n\t\t\t\t\tevent: 'response.done',\n\t\t\t\t\tdata: JSON.stringify({\n\t\t\t\t\t\ttype: 'response.done',\n\t\t\t\t\t\tresponse: {\n\t\t\t\t\t\t\tid: responseId,\n\t\t\t\t\t\t\tstatus: 'completed',\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t});\n\n\t\t\t\tif (auditCtx) await auditCtx.complete(200);\n\t\t\t} catch (err) {\n\t\t\t\tif (auditCtx) {\n\t\t\t\t\tawait auditCtx.error(err instanceof Error ? err.message : 'Streaming error', 'streaming_error', 500);\n\t\t\t\t}\n\t\t\t\tthrow err;\n\t\t\t} finally {\n\t\t\t\treader.releaseLock();\n\t\t\t}\n\t\t});\n\t}\n\n\t// =========================================================================\n\t// Models endpoint\n\t// =========================================================================\n\n\tapp.get('/v1/models', async (c) => {\n\t\tconst fetchUpstream = c.req.query('fetch') === 'true';\n\t\tconst allModels: Array<{\n\t\t\tid: string;\n\t\t\tobject: string;\n\t\t\tcreated: number;\n\t\t\towned_by: string;\n\t\t\tcontext_window?: number;\n\t\t\tmax_input_tokens?: number;\n\t\t\tmax_output_tokens?: number;\n\t\t}> = [];\n\n\t\t// Add configured models\n\t\tfor (const m of config.models || []) {\n\t\t\tallModels.push({\n\t\t\t\tid: m.name,\n\t\t\t\tobject: 'model',\n\t\t\t\tcreated: Math.floor(Date.now() / 1000),\n\t\t\t\towned_by: 'mcps',\n\t\t\t\tcontext_window: m.contextWindow,\n\t\t\t\tmax_input_tokens: m.maxInputTokens,\n\t\t\t\tmax_output_tokens: m.maxOutputTokens,\n\t\t\t});\n\n\t\t\t// Fetch upstream models if enabled\n\t\t\tif (fetchUpstream && m.fetchUpstreamModels && m.baseUrl) {\n\t\t\t\ttry {\n\t\t\t\t\tconst headers: Record<string, string> = {\n\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t};\n\t\t\t\t\tif (m.apiKey) {\n\t\t\t\t\t\theaders.Authorization = `Bearer ${m.apiKey}`;\n\t\t\t\t\t}\n\t\t\t\t\tObject.assign(headers, m.headers || {});\n\n\t\t\t\t\tconst normalizedUrl = normalizeBaseUrl(m.baseUrl);\n\t\t\t\t\tconst upstreamUrl = `${normalizedUrl}/v1/models`;\n\n\t\t\t\t\tconst res = await fetch(upstreamUrl, { headers });\n\t\t\t\t\tif (res.ok) {\n\t\t\t\t\t\tconst data = await res.json();\n\t\t\t\t\t\tif (data.data && Array.isArray(data.data)) {\n\t\t\t\t\t\t\tfor (const model of data.data) {\n\t\t\t\t\t\t\t\t// Avoid duplicates\n\t\t\t\t\t\t\t\tif (!allModels.some((existing) => existing.id === model.id)) {\n\t\t\t\t\t\t\t\t\tallModels.push({\n\t\t\t\t\t\t\t\t\t\tid: model.id,\n\t\t\t\t\t\t\t\t\t\tobject: model.object || 'model',\n\t\t\t\t\t\t\t\t\t\tcreated: model.created || Math.floor(Date.now() / 1000),\n\t\t\t\t\t\t\t\t\t\towned_by: model.owned_by || m.name.split('/')[0] || 'upstream',\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tlog.warn(`Failed to fetch upstream models from ${m.baseUrl}: ${e}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlog.debug(`→ GET /v1/models count=${allModels.length} fetch=${fetchUpstream}`);\n\n\t\treturn c.json({\n\t\t\tobject: 'list',\n\t\t\tdata: allModels,\n\t\t});\n\t});\n\n\treturn app;\n}\n"],"names":["consola","Hono","streamSSE","ChatProtocol","createAuditContext","extractClientIp","openaiToAnthropicRequest","anthropicToOpenaiResponse","openaiToGeminiRequest","geminiToOpenaiResponse","CreateChatCompletionRequestSchema","CreateResponseRequestSchema","CreateMessageRequestSchema","CreateGenerateContentRequestSchema","log","withTag","createChatHandler","options","app","config","resolveModelConfig","modelName","models","length","modelConfig","name","pattern","includes","regex","RegExp","replace","test","makeUpstreamRequest","url","body","headers","_stream","response","fetch","method","JSON","stringify","ok","errorText","text","error","status","Error","normalizeBaseUrl","buildUpstreamHeaders","adapter","apiKey","Authorization","Object","assign","adapters","normalizeOpenAIRequest","request","normalized","max_completion_tokens","max_tokens","enable_thinking","undefined","thinking","type","post","c","auditCtx","req","json","parseResult","safeParse","success","message","param","code","details","issues","data","model","baseUrl","outputProtocol","ANTHROPIC","GEMINI","OPENAI","endpoint","inputProtocol","streaming","stream","clientIp","userAgent","header","requestMeta","temperature","top_p","info","messages","upstreamUrl","upstreamBody","upstreamHeaders","setProvider","provider","handleStreamingRequest","responseData","result","usage","setTokenUsage","prompt_tokens","completion_tokens","setResponseMeta","finish_reason","choices","complete","total_tokens","firstTokenRecorded","totalOutputTokens","reader","getReader","writeSSE","decoder","TextDecoder","buffer","done","value","read","decode","lines","split","pop","line","trim","startsWith","slice","parsed","parse","converted","convertStreamEvent","recordFirstToken","err","releaseLock","event","convertAnthropicStreamEvent","convertGeminiStreamEvent","delta","id","Date","now","object","created","Math","floor","index","content","finishReason","stop_reason","output_tokens","candidates","parts","textParts","filter","p","map","join","input_tokens","gemini","contents","usageMetadata","totalTokenCount","promptTokenCount","candidatesTokenCount","previousContext","previous_response_id","isDbInitialized","getEntityManager","ResponseEntity","em","fork","prevResponse","findOne","responseId","input","output","warn","e","max_output_tokens","inputType","Array","isArray","chatRequest","responsesToChatCompletions","handleResponsesStreamingRequest","chatResponse","chatCompletionsToResponses","responseEntity","instructions","previousResponseId","tools","toolChoice","tool_choice","metadata","durationMs","getDuration","persist","flush","debug","output_items","push","role","prevInput","item","textContent","find","parallel_tool_calls","store","user","choice","tool_calls","toolCall","function","arguments","created_at","outputItemId","output_index","content_index","get","fetchUpstream","query","allModels","m","owned_by","context_window","contextWindow","max_input_tokens","maxInputTokens","maxOutputTokens","fetchUpstreamModels","normalizedUrl","res","some","existing"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/chat/handler.ts"],"sourcesContent":["/**\n * Chat API Handler\n * Provides unified AI model gateway with protocol conversion\n */\nimport consola from 'consola';\nimport { Hono } from 'hono';\nimport { streamSSE } from 'hono/streaming';\nimport type { ChatConfig, ModelConfig } from '../server/schema';\nimport { ChatProtocol, createAuditContext, extractClientIp } from './audit';\nimport {\n\topenaiToAnthropicRequest,\n\tanthropicToOpenaiResponse,\n\topenaiToGeminiRequest,\n\tgeminiToOpenaiResponse,\n} from './converters';\nimport {\n\tCreateChatCompletionRequestSchema,\n\ttype CreateChatCompletionRequest,\n\tCreateResponseRequestSchema,\n\ttype CreateResponseRequest,\n} from '@wener/ai/openai';\nimport { CreateMessageRequestSchema } from '@wener/ai/anthropic';\nimport { CreateGenerateContentRequestSchema } from '@wener/ai/google';\n\nconst log = consola.withTag('chat');\n\nexport interface ChatHandlerOptions {\n\tconfig?: ChatConfig;\n}\n\n/**\n * Create chat handler Hono app\n */\nexport function createChatHandler(options: ChatHandlerOptions = {}) {\n\tconst app = new Hono();\n\tconst { config = {} } = options;\n\n\t/**\n\t * Resolve model configuration\n\t */\n\tfunction resolveModelConfig(modelName: string): ModelConfig | null {\n\t\tconst models = config.models;\n\t\tif (!models || models.length === 0) return null;\n\n\t\t// First pass: exact match\n\t\tfor (const modelConfig of models) {\n\t\t\tif (modelConfig.name === modelName) {\n\t\t\t\treturn modelConfig;\n\t\t\t}\n\t\t}\n\n\t\t// Second pass: wildcard matches (e.g., \"gpt-*\" or \"claude-*\")\n\t\tfor (const modelConfig of models) {\n\t\t\tconst pattern = modelConfig.name;\n\t\t\tif (pattern.includes('*')) {\n\t\t\t\tconst regex = new RegExp(`^${pattern.replace(/\\*/g, '.*')}$`);\n\t\t\t\tif (regex.test(modelName)) {\n\t\t\t\t\treturn modelConfig;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Make request to upstream provider\n\t */\n\tasync function makeUpstreamRequest(\n\t\turl: string,\n\t\tbody: unknown,\n\t\theaders: Record<string, string>,\n\t\t_stream: boolean = false,\n\t): Promise<Response> {\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t...headers,\n\t\t\t},\n\t\t\tbody: JSON.stringify(body),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst errorText = await response.text();\n\t\t\tlog.error('Upstream error:', response.status, errorText);\n\t\t\tthrow new Error(`Upstream error: ${response.status} ${errorText}`);\n\t\t}\n\n\t\treturn response;\n\t}\n\n\t/**\n\t * Normalize base URL - strip trailing /v1 if present\n\t * This allows baseUrl to be specified as either \"http://example.com\" or \"http://example.com/v1\"\n\t */\n\tfunction normalizeBaseUrl(url: string): string {\n\t\treturn url.replace(/\\/v1\\/?$/, '');\n\t}\n\n\t/**\n\t * Build headers for upstream request\n\t */\n\tfunction buildUpstreamHeaders(\n\t\tmodelConfig: ModelConfig,\n\t\tadapter: 'openai' | 'anthropic' | 'gemini',\n\t): Record<string, string> {\n\t\tconst headers: Record<string, string> = {};\n\n\t\t// Add API key if configured\n\t\tif (modelConfig.apiKey) {\n\t\t\tif (adapter === 'anthropic') {\n\t\t\t\theaders['x-api-key'] = modelConfig.apiKey;\n\t\t\t\theaders['anthropic-version'] = '2023-06-01';\n\t\t\t} else {\n\t\t\t\theaders.Authorization = `Bearer ${modelConfig.apiKey}`;\n\t\t\t}\n\t\t}\n\n\t\t// Add custom headers\n\t\tif (modelConfig.headers) {\n\t\t\tObject.assign(headers, modelConfig.headers);\n\t\t}\n\n\t\t// Add adapter-specific headers\n\t\tif (modelConfig.adapters?.[adapter]?.headers) {\n\t\t\tObject.assign(headers, modelConfig.adapters[adapter]?.headers);\n\t\t}\n\n\t\treturn headers;\n\t}\n\n\t/**\n\t * Normalize OpenAI request for different providers\n\t * Handles max_tokens/max_completion_tokens compatibility and thinking parameters\n\t */\n\tfunction normalizeOpenAIRequest(request: CreateChatCompletionRequest): Record<string, unknown> {\n\t\tconst normalized: Record<string, unknown> = { ...request };\n\n\t\t// Handle max_tokens vs max_completion_tokens compatibility\n\t\t// Some providers only support max_tokens, others prefer max_completion_tokens\n\t\tif (request.max_completion_tokens && !request.max_tokens) {\n\t\t\tnormalized.max_tokens = request.max_completion_tokens;\n\t\t}\n\n\t\t// Handle enable_thinking parameter (used by Qwen, DeepSeek thinking models)\n\t\t// Convert to thinking object format if needed\n\t\tif (request.enable_thinking !== undefined && !request.thinking) {\n\t\t\tnormalized.thinking = {\n\t\t\t\ttype: request.enable_thinking ? 'enabled' : 'disabled',\n\t\t\t};\n\t\t}\n\n\t\treturn normalized;\n\t}\n\n\t// =========================================================================\n\t// OpenAI Chat Completions API\n\t// =========================================================================\n\n\tapp.post('/v1/chat/completions', async (c) => {\n\t\t// Create audit context early\n\t\tlet auditCtx: ReturnType<typeof createAuditContext> | null = null;\n\n\t\ttry {\n\t\t\tconst body = await c.req.json();\n\t\t\tconst parseResult = CreateChatCompletionRequestSchema.safeParse(body);\n\n\t\t\tif (!parseResult.success) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tmessage: 'Invalid request',\n\t\t\t\t\t\t\ttype: 'invalid_request_error',\n\t\t\t\t\t\t\tparam: null,\n\t\t\t\t\t\t\tcode: 'invalid_request',\n\t\t\t\t\t\t\tdetails: parseResult.error.issues,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst request = parseResult.data;\n\t\t\tconst modelConfig = resolveModelConfig(request.model);\n\n\t\t\tif (!modelConfig) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tmessage: `Model ${request.model} not configured`,\n\t\t\t\t\t\t\ttype: 'invalid_request_error',\n\t\t\t\t\t\t\tparam: 'model',\n\t\t\t\t\t\t\tcode: 'model_not_found',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t404,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Determine upstream adapter\n\t\t\tconst adapter = modelConfig.adapter || 'openai';\n\t\t\tconst baseUrl = normalizeBaseUrl(\n\t\t\t\tmodelConfig.adapters?.[adapter]?.baseUrl || modelConfig.baseUrl || 'https://api.openai.com',\n\t\t\t);\n\n\t\t\t// Create audit context\n\t\t\tconst outputProtocol =\n\t\t\t\tadapter === 'anthropic'\n\t\t\t\t\t? ChatProtocol.ANTHROPIC\n\t\t\t\t\t: adapter === 'gemini'\n\t\t\t\t\t\t? ChatProtocol.GEMINI\n\t\t\t\t\t\t: ChatProtocol.OPENAI;\n\n\t\t\tauditCtx = createAuditContext({\n\t\t\t\tmethod: 'POST',\n\t\t\t\tendpoint: '/v1/chat/completions',\n\t\t\t\tmodel: request.model,\n\t\t\t\tinputProtocol: ChatProtocol.OPENAI,\n\t\t\t\toutputProtocol,\n\t\t\t\tstreaming: request.stream || false,\n\t\t\t\tclientIp: extractClientIp(c),\n\t\t\t\tuserAgent: c.req.header('user-agent'),\n\t\t\t\trequestMeta: {\n\t\t\t\t\ttemperature: request.temperature,\n\t\t\t\t\tmax_tokens: request.max_tokens || request.max_completion_tokens,\n\t\t\t\t\ttop_p: request.top_p,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\t// Log incoming request\n\t\t\tlog.info(\n\t\t\t\t`→ POST /v1/chat/completions model=${request.model} stream=${request.stream || false} messages=${request.messages.length}`,\n\t\t\t);\n\n\t\t\t// Build upstream request based on protocol\n\t\t\tlet upstreamUrl: string;\n\t\t\tlet upstreamBody: unknown;\n\t\t\tlet upstreamHeaders: Record<string, string>;\n\n\t\t\tswitch (adapter) {\n\t\t\t\tcase 'anthropic': {\n\t\t\t\t\tupstreamUrl = `${baseUrl}/v1/messages`;\n\t\t\t\t\tupstreamBody = openaiToAnthropicRequest(request);\n\t\t\t\t\tupstreamHeaders = buildUpstreamHeaders(modelConfig, 'anthropic');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'gemini': {\n\t\t\t\t\tconst method = request.stream ? 'streamGenerateContent' : 'generateContent';\n\t\t\t\t\tupstreamUrl = `${baseUrl}/v1/models/${request.model}:${method}`;\n\t\t\t\t\tupstreamBody = openaiToGeminiRequest(request);\n\t\t\t\t\tupstreamHeaders = buildUpstreamHeaders(modelConfig, 'gemini');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\t// OpenAI adapter - passthrough with parameter normalization\n\t\t\t\t\tupstreamUrl = `${baseUrl}/v1/chat/completions`;\n\t\t\t\t\tupstreamBody = normalizeOpenAIRequest(request);\n\t\t\t\t\tupstreamHeaders = buildUpstreamHeaders(modelConfig, 'openai');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set provider info in audit context\n\t\t\tauditCtx.setProvider({\n\t\t\t\tprovider: adapter,\n\t\t\t\tupstreamUrl,\n\t\t\t});\n\n\t\t\t// Handle streaming\n\t\t\tif (request.stream) {\n\t\t\t\treturn handleStreamingRequest(c, upstreamUrl, upstreamBody, upstreamHeaders, adapter, request.model, auditCtx);\n\t\t\t}\n\n\t\t\t// Non-streaming request\n\t\t\tconst response = await makeUpstreamRequest(upstreamUrl, upstreamBody, upstreamHeaders);\n\t\t\tconst responseData = await response.json();\n\n\t\t\t// Convert response if needed\n\t\t\tlet result: any;\n\t\t\tswitch (adapter) {\n\t\t\t\tcase 'anthropic':\n\t\t\t\t\tresult = anthropicToOpenaiResponse(responseData, request.model);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'gemini':\n\t\t\t\t\tresult = geminiToOpenaiResponse(responseData, request.model);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tresult = responseData;\n\t\t\t}\n\n\t\t\t// Record token usage and complete audit\n\t\t\tif (result.usage) {\n\t\t\t\tauditCtx.setTokenUsage(result.usage.prompt_tokens || 0, result.usage.completion_tokens || 0);\n\t\t\t}\n\t\t\tauditCtx.setResponseMeta({\n\t\t\t\tfinish_reason: result.choices?.[0]?.finish_reason,\n\t\t\t\tmodel: result.model,\n\t\t\t});\n\t\t\tawait auditCtx.complete(200);\n\n\t\t\t// Log response\n\t\t\tconst usage = result.usage;\n\t\t\tlog.info(\n\t\t\t\t`← 200 /v1/chat/completions model=${result.model || request.model} tokens=${usage?.total_tokens || 0} (in=${usage?.prompt_tokens || 0} out=${usage?.completion_tokens || 0})`,\n\t\t\t);\n\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\t// Record error in audit\n\t\t\tif (auditCtx) {\n\t\t\t\tawait auditCtx.error(error instanceof Error ? error.message : 'Unknown error', 'internal_error', 500);\n\t\t\t}\n\t\t\tlog.error('Chat completion error:', error);\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\terror: {\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : 'Internal server error',\n\t\t\t\t\t\ttype: 'api_error',\n\t\t\t\t\t\tcode: 'internal_error',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t/**\n\t * Handle streaming request\n\t */\n\tasync function handleStreamingRequest(\n\t\tc: any,\n\t\tupstreamUrl: string,\n\t\tupstreamBody: unknown,\n\t\tupstreamHeaders: Record<string, string>,\n\t\tadapter: string,\n\t\tmodel: string,\n\t\tauditCtx?: ReturnType<typeof createAuditContext>,\n\t) {\n\t\tconst response = await makeUpstreamRequest(upstreamUrl, upstreamBody, upstreamHeaders, true);\n\n\t\tlet firstTokenRecorded = false;\n\t\tlet totalOutputTokens = 0;\n\n\t\t// For streaming, we need to convert events on the fly\n\t\treturn streamSSE(c, async (stream) => {\n\t\t\tconst reader = response.body?.getReader();\n\t\t\tif (!reader) {\n\t\t\t\tawait stream.writeSSE({ data: '[DONE]' });\n\t\t\t\tif (auditCtx) await auditCtx.complete(200);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buffer = '';\n\n\t\t\ttry {\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) break;\n\n\t\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\t\tconst lines = buffer.split('\\n');\n\t\t\t\t\tbuffer = lines.pop() || '';\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\tif (!line.trim()) continue;\n\n\t\t\t\t\t\tif (line.startsWith('data: ')) {\n\t\t\t\t\t\t\tconst data = line.slice(6);\n\t\t\t\t\t\t\tif (data === '[DONE]') {\n\t\t\t\t\t\t\t\tawait stream.writeSSE({ data: '[DONE]' });\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst parsed = JSON.parse(data);\n\t\t\t\t\t\t\t\tconst converted = convertStreamEvent(parsed, adapter, model);\n\t\t\t\t\t\t\t\tif (converted) {\n\t\t\t\t\t\t\t\t\t// Record first token for TTFT\n\t\t\t\t\t\t\t\t\tif (!firstTokenRecorded && auditCtx) {\n\t\t\t\t\t\t\t\t\t\tauditCtx.recordFirstToken();\n\t\t\t\t\t\t\t\t\t\tfirstTokenRecorded = true;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t// Track usage from stream events\n\t\t\t\t\t\t\t\t\tif (converted.usage) {\n\t\t\t\t\t\t\t\t\t\ttotalOutputTokens = converted.usage.completion_tokens || totalOutputTokens;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tawait stream.writeSSE({ data: JSON.stringify(converted) });\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// Skip invalid JSON\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (line.startsWith('event: ')) {\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Send done signal\n\t\t\t\tawait stream.writeSSE({ data: '[DONE]' });\n\n\t\t\t\t// Complete audit\n\t\t\t\tif (auditCtx) {\n\t\t\t\t\tauditCtx.setTokenUsage(0, totalOutputTokens); // Input tokens not available in streaming\n\t\t\t\t\tawait auditCtx.complete(200);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// Record streaming error\n\t\t\t\tif (auditCtx) {\n\t\t\t\t\tawait auditCtx.error(err instanceof Error ? err.message : 'Streaming error', 'streaming_error', 500);\n\t\t\t\t}\n\t\t\t\tthrow err;\n\t\t\t} finally {\n\t\t\t\treader.releaseLock();\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Convert stream event to OpenAI format\n\t */\n\tfunction convertStreamEvent(event: any, adapter: string, model: string): any {\n\t\tswitch (adapter) {\n\t\t\tcase 'anthropic':\n\t\t\t\treturn convertAnthropicStreamEvent(event, model);\n\t\t\tcase 'gemini':\n\t\t\t\treturn convertGeminiStreamEvent(event, model);\n\t\t\tdefault:\n\t\t\t\treturn event;\n\t\t}\n\t}\n\n\t/**\n\t * Convert Anthropic stream event to OpenAI format\n\t */\n\tfunction convertAnthropicStreamEvent(event: any, model: string): any {\n\t\tif (event.type === 'content_block_delta') {\n\t\t\tif (event.delta?.type === 'text_delta') {\n\t\t\t\treturn {\n\t\t\t\t\tid: `chatcmpl-${Date.now()}`,\n\t\t\t\t\tobject: 'chat.completion.chunk',\n\t\t\t\t\tcreated: Math.floor(Date.now() / 1000),\n\t\t\t\t\tmodel,\n\t\t\t\t\tchoices: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tindex: 0,\n\t\t\t\t\t\t\tdelta: { content: event.delta.text },\n\t\t\t\t\t\t\tfinish_reason: null,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t} else if (event.type === 'message_delta') {\n\t\t\tconst finishReason =\n\t\t\t\tevent.delta?.stop_reason === 'end_turn'\n\t\t\t\t\t? 'stop'\n\t\t\t\t\t: event.delta?.stop_reason === 'tool_use'\n\t\t\t\t\t\t? 'tool_calls'\n\t\t\t\t\t\t: null;\n\t\t\treturn {\n\t\t\t\tid: `chatcmpl-${Date.now()}`,\n\t\t\t\tobject: 'chat.completion.chunk',\n\t\t\t\tcreated: Math.floor(Date.now() / 1000),\n\t\t\t\tmodel,\n\t\t\t\tchoices: [\n\t\t\t\t\t{\n\t\t\t\t\t\tindex: 0,\n\t\t\t\t\t\tdelta: {},\n\t\t\t\t\t\tfinish_reason: finishReason,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tusage: event.usage\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tprompt_tokens: 0,\n\t\t\t\t\t\t\tcompletion_tokens: event.usage.output_tokens,\n\t\t\t\t\t\t\ttotal_tokens: event.usage.output_tokens,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t};\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Convert Gemini stream event to OpenAI format\n\t */\n\tfunction convertGeminiStreamEvent(event: any, model: string): any {\n\t\tif (event.candidates?.[0]?.content?.parts) {\n\t\t\tconst parts = event.candidates[0].content.parts;\n\t\t\tconst textParts = parts.filter((p: any) => p.text);\n\n\t\t\tif (textParts.length > 0) {\n\t\t\t\treturn {\n\t\t\t\t\tid: `chatcmpl-${Date.now()}`,\n\t\t\t\t\tobject: 'chat.completion.chunk',\n\t\t\t\t\tcreated: Math.floor(Date.now() / 1000),\n\t\t\t\t\tmodel,\n\t\t\t\t\tchoices: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tindex: 0,\n\t\t\t\t\t\t\tdelta: { content: textParts.map((p: any) => p.text).join('') },\n\t\t\t\t\t\t\tfinish_reason: event.candidates[0].finishReason === 'STOP' ? 'stop' : null,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t// =========================================================================\n\t// Anthropic Messages API\n\t// =========================================================================\n\n\tapp.post('/v1/messages', async (c) => {\n\t\ttry {\n\t\t\tconst body = await c.req.json();\n\t\t\tconst parseResult = CreateMessageRequestSchema.safeParse(body);\n\n\t\t\tif (!parseResult.success) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\ttype: 'invalid_request_error',\n\t\t\t\t\t\t\tmessage: 'Invalid request',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst request = parseResult.data;\n\t\t\tconst modelConfig = resolveModelConfig(request.model);\n\n\t\t\tif (!modelConfig) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\ttype: 'invalid_request_error',\n\t\t\t\t\t\t\tmessage: `Model ${request.model} not configured`,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t404,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// For Anthropic endpoint, we pass through to Anthropic or convert from OpenAI\n\t\t\tconst adapter = modelConfig.adapter || 'anthropic';\n\t\t\tconst baseUrl = normalizeBaseUrl(\n\t\t\t\tmodelConfig.adapters?.[adapter]?.baseUrl || modelConfig.baseUrl || 'https://api.anthropic.com',\n\t\t\t);\n\n\t\t\tconst upstreamUrl = `${baseUrl}/v1/messages`;\n\t\t\tconst upstreamHeaders = buildUpstreamHeaders(modelConfig, 'anthropic');\n\n\t\t\t// Log incoming request\n\t\t\tlog.info(`→ POST /v1/messages model=${request.model} messages=${request.messages.length}`);\n\n\t\t\tconst response = await makeUpstreamRequest(upstreamUrl, request, upstreamHeaders);\n\t\t\tconst responseData = await response.json();\n\n\t\t\t// Log response\n\t\t\tconst usage = responseData.usage;\n\t\t\tlog.info(\n\t\t\t\t`← 200 /v1/messages model=${responseData.model || request.model} tokens=${(usage?.input_tokens || 0) + (usage?.output_tokens || 0)} (in=${usage?.input_tokens || 0} out=${usage?.output_tokens || 0})`,\n\t\t\t);\n\n\t\t\treturn c.json(responseData);\n\t\t} catch (error) {\n\t\t\tlog.error('Messages error:', error);\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\terror: {\n\t\t\t\t\t\ttype: 'api_error',\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : 'Internal server error',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t// =========================================================================\n\t// Gemini Generate Content API\n\t// =========================================================================\n\n\tapp.post('/v1/models/:model\\\\:generateContent', async (c) => {\n\t\ttry {\n\t\t\tconst model = c.req.param('model');\n\t\t\tif (!model) {\n\t\t\t\treturn c.json({ error: { message: 'Model parameter is required' } }, 400);\n\t\t\t}\n\n\t\t\tconst body = await c.req.json();\n\t\t\tconst parseResult = CreateGenerateContentRequestSchema.safeParse(body);\n\n\t\t\tif (!parseResult.success) {\n\t\t\t\treturn c.json({ error: { message: 'Invalid request' } }, 400);\n\t\t\t}\n\n\t\t\tconst request = parseResult.data;\n\t\t\tconst modelConfig = resolveModelConfig(model);\n\n\t\t\tif (!modelConfig) {\n\t\t\t\treturn c.json({ error: { message: `Model ${model} not configured` } }, 404);\n\t\t\t}\n\n\t\t\tconst baseUrl = normalizeBaseUrl(\n\t\t\t\tmodelConfig.adapters?.gemini?.baseUrl || modelConfig.baseUrl || 'https://generativelanguage.googleapis.com',\n\t\t\t);\n\n\t\t\tconst upstreamUrl = `${baseUrl}/v1/models/${model}:generateContent`;\n\t\t\tconst upstreamHeaders = buildUpstreamHeaders(modelConfig, 'gemini');\n\n\t\t\t// Log incoming request\n\t\t\tlog.info(`→ POST /v1/models/${model}:generateContent contents=${request.contents?.length || 0}`);\n\n\t\t\tconst response = await makeUpstreamRequest(upstreamUrl, request, upstreamHeaders);\n\t\t\tconst responseData = await response.json();\n\n\t\t\t// Log response\n\t\t\tconst usage = responseData.usageMetadata;\n\t\t\tlog.info(\n\t\t\t\t`← 200 /v1/models/${model}:generateContent tokens=${usage?.totalTokenCount || 0} (in=${usage?.promptTokenCount || 0} out=${usage?.candidatesTokenCount || 0})`,\n\t\t\t);\n\n\t\t\treturn c.json(responseData);\n\t\t} catch (error) {\n\t\t\tlog.error('Generate content error:', error);\n\t\t\treturn c.json({ error: { message: error instanceof Error ? error.message : 'Internal server error' } }, 500);\n\t\t}\n\t});\n\n\t// =========================================================================\n\t// Gemini Streaming Generate Content API\n\t// =========================================================================\n\n\tapp.post('/v1/models/:model\\\\:streamGenerateContent', async (c) => {\n\t\ttry {\n\t\t\tconst model = c.req.param('model');\n\t\t\tif (!model) {\n\t\t\t\treturn c.json({ error: { message: 'Model parameter is required' } }, 400);\n\t\t\t}\n\n\t\t\tconst body = await c.req.json();\n\t\t\tconst parseResult = CreateGenerateContentRequestSchema.safeParse(body);\n\n\t\t\tif (!parseResult.success) {\n\t\t\t\treturn c.json({ error: { message: 'Invalid request' } }, 400);\n\t\t\t}\n\n\t\t\tconst request = parseResult.data;\n\n\t\t\t// Log incoming request\n\t\t\tlog.info(`→ POST /v1/models/${model}:streamGenerateContent contents=${request.contents?.length || 0}`);\n\n\t\t\tconst modelConfig = resolveModelConfig(model);\n\n\t\t\tif (!modelConfig) {\n\t\t\t\treturn c.json({ error: { message: `Model ${model} not configured` } }, 404);\n\t\t\t}\n\n\t\t\tconst baseUrl = normalizeBaseUrl(\n\t\t\t\tmodelConfig.adapters?.gemini?.baseUrl || modelConfig.baseUrl || 'https://generativelanguage.googleapis.com',\n\t\t\t);\n\n\t\t\tconst upstreamUrl = `${baseUrl}/v1/models/${model}:streamGenerateContent`;\n\t\t\tconst upstreamHeaders = buildUpstreamHeaders(modelConfig, 'gemini');\n\n\t\t\tconst response = await makeUpstreamRequest(upstreamUrl, request, upstreamHeaders, true);\n\n\t\t\t// Stream the response directly\n\t\t\treturn streamSSE(c, async (stream) => {\n\t\t\t\tconst reader = response.body?.getReader();\n\t\t\t\tif (!reader) {\n\t\t\t\t\tawait stream.writeSSE({ data: '[DONE]' });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst decoder = new TextDecoder();\n\t\t\t\tlet buffer = '';\n\n\t\t\t\ttry {\n\t\t\t\t\twhile (true) {\n\t\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\t\tif (done) break;\n\n\t\t\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\t\t\tconst lines = buffer.split('\\n');\n\t\t\t\t\t\tbuffer = lines.pop() || '';\n\n\t\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\t\tif (!line.trim()) continue;\n\n\t\t\t\t\t\t\tif (line.startsWith('data: ')) {\n\t\t\t\t\t\t\t\tconst data = line.slice(6);\n\t\t\t\t\t\t\t\tif (data === '[DONE]') {\n\t\t\t\t\t\t\t\t\tawait stream.writeSSE({ data: '[DONE]' });\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tawait stream.writeSSE({ data });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tawait stream.writeSSE({ data: '[DONE]' });\n\t\t\t\t} finally {\n\t\t\t\t\treader.releaseLock();\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tlog.error('Stream generate content error:', error);\n\t\t\treturn c.json({ error: { message: error instanceof Error ? error.message : 'Internal server error' } }, 500);\n\t\t}\n\t});\n\n\t// =========================================================================\n\t// OpenAI Responses API\n\t// =========================================================================\n\n\tapp.post('/v1/responses', async (c) => {\n\t\tlet auditCtx: ReturnType<typeof createAuditContext> | null = null;\n\n\t\ttry {\n\t\t\tconst body = await c.req.json();\n\t\t\tconst parseResult = CreateResponseRequestSchema.safeParse(body);\n\n\t\t\tif (!parseResult.success) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tmessage: 'Invalid request',\n\t\t\t\t\t\t\ttype: 'invalid_request_error',\n\t\t\t\t\t\t\tparam: null,\n\t\t\t\t\t\t\tcode: 'invalid_request',\n\t\t\t\t\t\t\tdetails: parseResult.error.issues,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst request = parseResult.data;\n\n\t\t\t// Handle previous_response_id - load previous context\n\t\t\tlet previousContext: { input: unknown; output: unknown[] } | null = null;\n\t\t\tif (request.previous_response_id) {\n\t\t\t\ttry {\n\t\t\t\t\tconst { isDbInitialized, getEntityManager } = await import('../server/audit-db');\n\t\t\t\t\tconst { ResponseEntity } = await import('../entities');\n\t\t\t\t\tif (isDbInitialized()) {\n\t\t\t\t\t\tconst em = getEntityManager().fork();\n\t\t\t\t\t\tconst prevResponse = await em.findOne(ResponseEntity, { responseId: request.previous_response_id });\n\t\t\t\t\t\tif (prevResponse) {\n\t\t\t\t\t\t\tpreviousContext = {\n\t\t\t\t\t\t\t\tinput: prevResponse.input,\n\t\t\t\t\t\t\t\toutput: prevResponse.output,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tlog.info(`Loaded previous response: ${request.previous_response_id}`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlog.warn(`Previous response not found: ${request.previous_response_id}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tlog.warn('Failed to load previous response:', e);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst modelConfig = resolveModelConfig(request.model);\n\n\t\t\tif (!modelConfig) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tmessage: `Model ${request.model} not configured`,\n\t\t\t\t\t\t\ttype: 'invalid_request_error',\n\t\t\t\t\t\t\tparam: 'model',\n\t\t\t\t\t\t\tcode: 'model_not_found',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t404,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Determine adapter - for Responses API, we convert to Chat Completions\n\t\t\tconst adapter = modelConfig.adapter || 'openai';\n\t\t\tconst baseUrl = normalizeBaseUrl(\n\t\t\t\tmodelConfig.adapters?.[adapter]?.baseUrl || modelConfig.baseUrl || 'https://api.openai.com',\n\t\t\t);\n\n\t\t\t// Create audit context\n\t\t\tauditCtx = createAuditContext({\n\t\t\t\tmethod: 'POST',\n\t\t\t\tendpoint: '/v1/responses',\n\t\t\t\tmodel: request.model,\n\t\t\t\tinputProtocol: ChatProtocol.OPENAI,\n\t\t\t\toutputProtocol: ChatProtocol.OPENAI,\n\t\t\t\tstreaming: request.stream || false,\n\t\t\t\tclientIp: extractClientIp(c),\n\t\t\t\tuserAgent: c.req.header('user-agent'),\n\t\t\t\trequestMeta: {\n\t\t\t\t\ttemperature: request.temperature,\n\t\t\t\t\tmax_output_tokens: request.max_output_tokens,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\t// Log incoming request\n\t\t\tconst inputType =\n\t\t\t\ttypeof request.input === 'string'\n\t\t\t\t\t? 'string'\n\t\t\t\t\t: Array.isArray(request.input)\n\t\t\t\t\t\t? `array[${request.input.length}]`\n\t\t\t\t\t\t: 'object';\n\t\t\tlog.info(`→ POST /v1/responses model=${request.model} stream=${request.stream || false} input=${inputType}`);\n\n\t\t\t// Convert Responses API request to Chat Completions format\n\t\t\tconst chatRequest = responsesToChatCompletions(request, previousContext);\n\n\t\t\t// Build upstream request\n\t\t\tconst upstreamUrl = `${baseUrl}/v1/chat/completions`;\n\t\t\tconst upstreamHeaders = buildUpstreamHeaders(modelConfig, 'openai');\n\n\t\t\tauditCtx.setProvider({\n\t\t\t\tprovider: adapter,\n\t\t\t\tupstreamUrl,\n\t\t\t});\n\n\t\t\t// Handle streaming\n\t\t\tif (request.stream) {\n\t\t\t\treturn handleResponsesStreamingRequest(c, upstreamUrl, chatRequest, upstreamHeaders, request.model, auditCtx);\n\t\t\t}\n\n\t\t\t// Non-streaming request\n\t\t\tconst response = await makeUpstreamRequest(upstreamUrl, chatRequest, upstreamHeaders);\n\t\t\tconst chatResponse = await response.json();\n\n\t\t\t// Convert Chat Completions response to Responses format\n\t\t\tconst result = chatCompletionsToResponses(chatResponse, request.model);\n\n\t\t\t// Store response for future previous_response_id lookups\n\t\t\ttry {\n\t\t\t\tconst { isDbInitialized, getEntityManager } = await import('../server/audit-db');\n\t\t\t\tconst { ResponseEntity } = await import('../entities');\n\t\t\t\tif (isDbInitialized()) {\n\t\t\t\t\tconst em = getEntityManager().fork();\n\t\t\t\t\tconst responseEntity = new ResponseEntity();\n\t\t\t\t\tresponseEntity.responseId = result.id;\n\t\t\t\t\tresponseEntity.model = result.model;\n\t\t\t\t\tresponseEntity.status = result.status;\n\t\t\t\t\tresponseEntity.input = request.input;\n\t\t\t\t\tresponseEntity.output = result.output;\n\t\t\t\t\tresponseEntity.usage = result.usage;\n\t\t\t\t\tresponseEntity.instructions = request.instructions ?? undefined;\n\t\t\t\t\tresponseEntity.previousResponseId = request.previous_response_id ?? undefined;\n\t\t\t\t\tresponseEntity.tools = request.tools ?? undefined;\n\t\t\t\t\tresponseEntity.toolChoice = request.tool_choice ?? undefined;\n\t\t\t\t\tresponseEntity.metadata = request.metadata as Record<string, unknown>;\n\t\t\t\t\tresponseEntity.durationMs = auditCtx?.getDuration();\n\t\t\t\t\tem.persist(responseEntity);\n\t\t\t\t\tawait em.flush();\n\t\t\t\t\tlog.debug(`Stored response: ${result.id}`);\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\tlog.warn('Failed to store response:', e);\n\t\t\t}\n\n\t\t\t// Record usage\n\t\t\tif (chatResponse.usage) {\n\t\t\t\tauditCtx.setTokenUsage(chatResponse.usage.prompt_tokens || 0, chatResponse.usage.completion_tokens || 0);\n\t\t\t}\n\t\t\tauditCtx.setResponseMeta({\n\t\t\t\tstatus: result.status,\n\t\t\t\toutput_items: result.output.length,\n\t\t\t});\n\t\t\tawait auditCtx.complete(200);\n\n\t\t\t// Log response\n\t\t\tconst usage = chatResponse.usage;\n\t\t\tlog.info(\n\t\t\t\t`← 200 /v1/responses model=${result.model || request.model} status=${result.status} tokens=${usage?.total_tokens || 0}`,\n\t\t\t);\n\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\tif (auditCtx) {\n\t\t\t\tawait auditCtx.error(error instanceof Error ? error.message : 'Unknown error', 'internal_error', 500);\n\t\t\t}\n\t\t\tlog.error('Responses API error:', error);\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\terror: {\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : 'Internal server error',\n\t\t\t\t\t\ttype: 'api_error',\n\t\t\t\t\t\tcode: 'internal_error',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t});\n\n\t/**\n\t * Convert Responses API request to Chat Completions format\n\t */\n\tfunction responsesToChatCompletions(\n\t\trequest: CreateResponseRequest,\n\t\tpreviousContext?: { input: unknown; output: unknown[] } | null,\n\t): CreateChatCompletionRequest {\n\t\tconst messages: CreateChatCompletionRequest['messages'] = [];\n\n\t\t// Add system instruction if present\n\t\tif (request.instructions) {\n\t\t\tmessages.push({\n\t\t\t\trole: 'system',\n\t\t\t\tcontent: request.instructions,\n\t\t\t});\n\t\t}\n\n\t\t// Add previous context if available (previous_response_id)\n\t\tif (previousContext) {\n\t\t\t// Add previous input\n\t\t\tconst prevInput = previousContext.input;\n\t\t\tif (typeof prevInput === 'string') {\n\t\t\t\tmessages.push({ role: 'user', content: prevInput });\n\t\t\t} else if (Array.isArray(prevInput)) {\n\t\t\t\tfor (const item of prevInput as any[]) {\n\t\t\t\t\tif (item.type === 'message') {\n\t\t\t\t\t\tmessages.push({\n\t\t\t\t\t\t\trole: item.role as 'user' | 'assistant' | 'system',\n\t\t\t\t\t\t\tcontent: typeof item.content === 'string' ? item.content : JSON.stringify(item.content),\n\t\t\t\t\t\t} as any);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add previous output as assistant messages\n\t\t\tfor (const item of previousContext.output as any[]) {\n\t\t\t\tif (item.type === 'message' && item.role === 'assistant') {\n\t\t\t\t\tconst textContent = item.content?.find((c: any) => c.type === 'text' || c.type === 'output_text');\n\t\t\t\t\tif (textContent) {\n\t\t\t\t\t\tmessages.push({\n\t\t\t\t\t\t\trole: 'assistant',\n\t\t\t\t\t\t\tcontent: textContent.text,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Convert current input to messages\n\t\tif (typeof request.input === 'string') {\n\t\t\tmessages.push({\n\t\t\t\trole: 'user',\n\t\t\t\tcontent: request.input,\n\t\t\t});\n\t\t} else if (Array.isArray(request.input)) {\n\t\t\tfor (const item of request.input) {\n\t\t\t\tif (item.type === 'message') {\n\t\t\t\t\tmessages.push({\n\t\t\t\t\t\trole: item.role as 'user' | 'assistant' | 'system',\n\t\t\t\t\t\tcontent: typeof item.content === 'string' ? item.content : JSON.stringify(item.content),\n\t\t\t\t\t} as any);\n\t\t\t\t}\n\t\t\t\t// item_reference is handled differently - would need to fetch the referenced item\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tmodel: request.model,\n\t\t\tmessages,\n\t\t\ttemperature: request.temperature,\n\t\t\ttop_p: request.top_p,\n\t\t\tmax_tokens: request.max_output_tokens,\n\t\t\tstream: request.stream,\n\t\t\ttools: request.tools,\n\t\t\ttool_choice: request.tool_choice,\n\t\t\tparallel_tool_calls: request.parallel_tool_calls,\n\t\t\tmetadata: request.metadata,\n\t\t\tstore: request.store,\n\t\t\tuser: request.user,\n\t\t} as CreateChatCompletionRequest;\n\t}\n\n\t/**\n\t * Convert Chat Completions response to Responses format\n\t */\n\tfunction chatCompletionsToResponses(chatResponse: any, model: string): any {\n\t\tconst responseId = `resp_${chatResponse.id || Date.now()}`;\n\t\tconst output: any[] = [];\n\n\t\tfor (const choice of chatResponse.choices || []) {\n\t\t\tconst message = choice.message;\n\t\t\tif (message) {\n\t\t\t\toutput.push({\n\t\t\t\t\tid: `item_${responseId}_${choice.index}`,\n\t\t\t\t\ttype: 'message',\n\t\t\t\t\trole: 'assistant',\n\t\t\t\t\tcontent: message.content ? [{ type: 'text', text: message.content }] : [],\n\t\t\t\t\tstatus: 'completed',\n\t\t\t\t});\n\n\t\t\t\t// Handle tool calls\n\t\t\t\tif (message.tool_calls) {\n\t\t\t\t\tfor (const toolCall of message.tool_calls) {\n\t\t\t\t\t\toutput.push({\n\t\t\t\t\t\t\tid: toolCall.id,\n\t\t\t\t\t\t\ttype: 'function_call',\n\t\t\t\t\t\t\tname: toolCall.function?.name,\n\t\t\t\t\t\t\targuments: toolCall.function?.arguments,\n\t\t\t\t\t\t\tstatus: 'completed',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tid: responseId,\n\t\t\tobject: 'response',\n\t\t\tcreated_at: chatResponse.created || Math.floor(Date.now() / 1000),\n\t\t\tmodel: chatResponse.model || model,\n\t\t\tstatus: 'completed',\n\t\t\toutput,\n\t\t\tusage: chatResponse.usage,\n\t\t\tmetadata: {},\n\t\t\terror: null,\n\t\t};\n\t}\n\n\t/**\n\t * Handle Responses API streaming\n\t */\n\tasync function handleResponsesStreamingRequest(\n\t\tc: any,\n\t\tupstreamUrl: string,\n\t\tupstreamBody: unknown,\n\t\tupstreamHeaders: Record<string, string>,\n\t\tmodel: string,\n\t\tauditCtx?: ReturnType<typeof createAuditContext>,\n\t) {\n\t\tconst response = await makeUpstreamRequest(\n\t\t\tupstreamUrl,\n\t\t\t{ ...(upstreamBody as any), stream: true },\n\t\t\tupstreamHeaders,\n\t\t\ttrue,\n\t\t);\n\n\t\tlet firstTokenRecorded = false;\n\t\tconst responseId = `resp_${Date.now()}`;\n\n\t\treturn streamSSE(c, async (stream) => {\n\t\t\tconst reader = response.body?.getReader();\n\t\t\tif (!reader) {\n\t\t\t\tawait stream.writeSSE({ event: 'response.done', data: JSON.stringify({ type: 'response.done' }) });\n\t\t\t\tif (auditCtx) await auditCtx.complete(200);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Send initial event\n\t\t\tawait stream.writeSSE({\n\t\t\t\tevent: 'response.created',\n\t\t\t\tdata: JSON.stringify({\n\t\t\t\t\ttype: 'response.created',\n\t\t\t\t\tresponse: {\n\t\t\t\t\t\tid: responseId,\n\t\t\t\t\t\tobject: 'response',\n\t\t\t\t\t\tcreated_at: Math.floor(Date.now() / 1000),\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tstatus: 'in_progress',\n\t\t\t\t\t\toutput: [],\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buffer = '';\n\t\t\tlet outputItemId = `item_${responseId}_0`;\n\n\t\t\ttry {\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) break;\n\n\t\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\t\tconst lines = buffer.split('\\n');\n\t\t\t\t\tbuffer = lines.pop() || '';\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\tif (!line.trim() || !line.startsWith('data: ')) continue;\n\n\t\t\t\t\t\tconst data = line.slice(6);\n\t\t\t\t\t\tif (data === '[DONE]') continue;\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst parsed = JSON.parse(data);\n\t\t\t\t\t\t\tconst delta = parsed.choices?.[0]?.delta;\n\n\t\t\t\t\t\t\tif (delta?.content) {\n\t\t\t\t\t\t\t\tif (!firstTokenRecorded && auditCtx) {\n\t\t\t\t\t\t\t\t\tauditCtx.recordFirstToken();\n\t\t\t\t\t\t\t\t\tfirstTokenRecorded = true;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tawait stream.writeSSE({\n\t\t\t\t\t\t\t\t\tevent: 'response.output_text.delta',\n\t\t\t\t\t\t\t\t\tdata: JSON.stringify({\n\t\t\t\t\t\t\t\t\t\ttype: 'response.output_text.delta',\n\t\t\t\t\t\t\t\t\t\toutput_index: 0,\n\t\t\t\t\t\t\t\t\t\tcontent_index: 0,\n\t\t\t\t\t\t\t\t\t\tdelta: delta.content,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Skip invalid JSON\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Send completion events\n\t\t\t\tawait stream.writeSSE({\n\t\t\t\t\tevent: 'response.output_item.done',\n\t\t\t\t\tdata: JSON.stringify({\n\t\t\t\t\t\ttype: 'response.output_item.done',\n\t\t\t\t\t\toutput_index: 0,\n\t\t\t\t\t\titem: {\n\t\t\t\t\t\t\tid: outputItemId,\n\t\t\t\t\t\t\ttype: 'message',\n\t\t\t\t\t\t\trole: 'assistant',\n\t\t\t\t\t\t\tstatus: 'completed',\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t});\n\n\t\t\t\tawait stream.writeSSE({\n\t\t\t\t\tevent: 'response.done',\n\t\t\t\t\tdata: JSON.stringify({\n\t\t\t\t\t\ttype: 'response.done',\n\t\t\t\t\t\tresponse: {\n\t\t\t\t\t\t\tid: responseId,\n\t\t\t\t\t\t\tstatus: 'completed',\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t});\n\n\t\t\t\tif (auditCtx) await auditCtx.complete(200);\n\t\t\t} catch (err) {\n\t\t\t\tif (auditCtx) {\n\t\t\t\t\tawait auditCtx.error(err instanceof Error ? err.message : 'Streaming error', 'streaming_error', 500);\n\t\t\t\t}\n\t\t\t\tthrow err;\n\t\t\t} finally {\n\t\t\t\treader.releaseLock();\n\t\t\t}\n\t\t});\n\t}\n\n\t// =========================================================================\n\t// Models endpoint\n\t// =========================================================================\n\n\tapp.get('/v1/models', async (c) => {\n\t\tconst fetchUpstream = c.req.query('fetch') === 'true';\n\t\tconst allModels: Array<{\n\t\t\tid: string;\n\t\t\tobject: string;\n\t\t\tcreated: number;\n\t\t\towned_by: string;\n\t\t\tcontext_window?: number;\n\t\t\tmax_input_tokens?: number;\n\t\t\tmax_output_tokens?: number;\n\t\t}> = [];\n\n\t\t// Add configured models\n\t\tfor (const m of config.models || []) {\n\t\t\tallModels.push({\n\t\t\t\tid: m.name,\n\t\t\t\tobject: 'model',\n\t\t\t\tcreated: Math.floor(Date.now() / 1000),\n\t\t\t\towned_by: 'mcps',\n\t\t\t\tcontext_window: m.contextWindow,\n\t\t\t\tmax_input_tokens: m.maxInputTokens,\n\t\t\t\tmax_output_tokens: m.maxOutputTokens,\n\t\t\t});\n\n\t\t\t// Fetch upstream models if enabled\n\t\t\tif (fetchUpstream && m.fetchUpstreamModels && m.baseUrl) {\n\t\t\t\ttry {\n\t\t\t\t\tconst headers: Record<string, string> = {\n\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t};\n\t\t\t\t\tif (m.apiKey) {\n\t\t\t\t\t\theaders.Authorization = `Bearer ${m.apiKey}`;\n\t\t\t\t\t}\n\t\t\t\t\tObject.assign(headers, m.headers || {});\n\n\t\t\t\t\tconst normalizedUrl = normalizeBaseUrl(m.baseUrl);\n\t\t\t\t\tconst upstreamUrl = `${normalizedUrl}/v1/models`;\n\n\t\t\t\t\tconst res = await fetch(upstreamUrl, { headers });\n\t\t\t\t\tif (res.ok) {\n\t\t\t\t\t\tconst data = await res.json();\n\t\t\t\t\t\tif (data.data && Array.isArray(data.data)) {\n\t\t\t\t\t\t\tfor (const model of data.data) {\n\t\t\t\t\t\t\t\t// Avoid duplicates\n\t\t\t\t\t\t\t\tif (!allModels.some((existing) => existing.id === model.id)) {\n\t\t\t\t\t\t\t\t\tallModels.push({\n\t\t\t\t\t\t\t\t\t\tid: model.id,\n\t\t\t\t\t\t\t\t\t\tobject: model.object || 'model',\n\t\t\t\t\t\t\t\t\t\tcreated: model.created || Math.floor(Date.now() / 1000),\n\t\t\t\t\t\t\t\t\t\towned_by: model.owned_by || m.name.split('/')[0] || 'upstream',\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tlog.warn(`Failed to fetch upstream models from ${m.baseUrl}: ${e}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlog.debug(`→ GET /v1/models count=${allModels.length} fetch=${fetchUpstream}`);\n\n\t\treturn c.json({\n\t\t\tobject: 'list',\n\t\t\tdata: allModels,\n\t\t});\n\t});\n\n\treturn app;\n}\n"],"names":["consola","Hono","streamSSE","ChatProtocol","createAuditContext","extractClientIp","openaiToAnthropicRequest","anthropicToOpenaiResponse","openaiToGeminiRequest","geminiToOpenaiResponse","CreateChatCompletionRequestSchema","CreateResponseRequestSchema","CreateMessageRequestSchema","CreateGenerateContentRequestSchema","log","withTag","createChatHandler","options","app","config","resolveModelConfig","modelName","models","length","modelConfig","name","pattern","includes","regex","RegExp","replace","test","makeUpstreamRequest","url","body","headers","_stream","response","fetch","method","JSON","stringify","ok","errorText","text","error","status","Error","normalizeBaseUrl","buildUpstreamHeaders","adapter","apiKey","Authorization","Object","assign","adapters","normalizeOpenAIRequest","request","normalized","max_completion_tokens","max_tokens","enable_thinking","undefined","thinking","type","post","c","auditCtx","req","json","parseResult","safeParse","success","message","param","code","details","issues","data","model","baseUrl","outputProtocol","ANTHROPIC","GEMINI","OPENAI","endpoint","inputProtocol","streaming","stream","clientIp","userAgent","header","requestMeta","temperature","top_p","info","messages","upstreamUrl","upstreamBody","upstreamHeaders","setProvider","provider","handleStreamingRequest","responseData","result","usage","setTokenUsage","prompt_tokens","completion_tokens","setResponseMeta","finish_reason","choices","complete","total_tokens","firstTokenRecorded","totalOutputTokens","reader","getReader","writeSSE","decoder","TextDecoder","buffer","done","value","read","decode","lines","split","pop","line","trim","startsWith","slice","parsed","parse","converted","convertStreamEvent","recordFirstToken","err","releaseLock","event","convertAnthropicStreamEvent","convertGeminiStreamEvent","delta","id","Date","now","object","created","Math","floor","index","content","finishReason","stop_reason","output_tokens","candidates","parts","textParts","filter","p","map","join","input_tokens","gemini","contents","usageMetadata","totalTokenCount","promptTokenCount","candidatesTokenCount","previousContext","previous_response_id","isDbInitialized","getEntityManager","ResponseEntity","em","fork","prevResponse","findOne","responseId","input","output","warn","e","max_output_tokens","inputType","Array","isArray","chatRequest","responsesToChatCompletions","handleResponsesStreamingRequest","chatResponse","chatCompletionsToResponses","responseEntity","instructions","previousResponseId","tools","toolChoice","tool_choice","metadata","durationMs","getDuration","persist","flush","debug","output_items","push","role","prevInput","item","textContent","find","parallel_tool_calls","store","user","choice","tool_calls","toolCall","function","arguments","created_at","outputItemId","output_index","content_index","get","fetchUpstream","query","allModels","m","owned_by","context_window","contextWindow","max_input_tokens","maxInputTokens","maxOutputTokens","fetchUpstreamModels","normalizedUrl","res","some","existing"],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { serve } from "@hono/node-server";
2
+ import consola from "consola";
3
+ import { createServer } from "./server/server.js";
4
+ const log = consola.withTag("mcps");
5
+ let serverHandle;
6
+ function shutdown() {
7
+ log.info("Shutting down...");
8
+ if (serverHandle) {
9
+ serverHandle.close(() => process.exit(0));
10
+ setTimeout(() => process.exit(1), 3000);
11
+ }
12
+ else {
13
+ process.exit(0);
14
+ }
15
+ }
16
+ process.on("SIGINT", shutdown);
17
+ process.on("SIGTERM", shutdown);
18
+ export async function startServer(options) {
19
+ const port = Number.parseInt(options.port, 10);
20
+ const { app, printEndpoints, finalize } = createServer({
21
+ cwd: options.cwd,
22
+ port,
23
+ discoveryConfig: options.discoveryConfig,
24
+ setup: options.setup
25
+ });
26
+ await finalize();
27
+ log.info(`Starting MCPS server on port ${port}`);
28
+ serverHandle = serve({
29
+ fetch: app.fetch,
30
+ port,
31
+ hostname: "0.0.0.0"
32
+ });
33
+ log.success(`MCPS server running at http://localhost:${port}`);
34
+ printEndpoints();
35
+ }
36
+ //# sourceMappingURL=cli-start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli-start.ts"],"sourcesContent":["import { serve } from '@hono/node-server';\nimport consola from 'consola';\nimport { createServer, type CreateServerOptions } from './server/server';\n\nconst log = consola.withTag('mcps');\n\nlet serverHandle: ReturnType<typeof serve> | undefined;\n\nfunction shutdown() {\n\tlog.info('Shutting down...');\n\tif (serverHandle) {\n\t\tserverHandle.close(() => process.exit(0));\n\t\tsetTimeout(() => process.exit(1), 3000);\n\t} else {\n\t\tprocess.exit(0);\n\t}\n}\n\nprocess.on('SIGINT', shutdown);\nprocess.on('SIGTERM', shutdown);\n\nexport async function startServer(options: { port: string; cwd: string; discoveryConfig: boolean; setup?: CreateServerOptions['setup'] }) {\n\tconst port = Number.parseInt(options.port, 10);\n\tconst { app, printEndpoints, finalize } = createServer({\n\t\tcwd: options.cwd,\n\t\tport,\n\t\tdiscoveryConfig: options.discoveryConfig,\n\t\tsetup: options.setup,\n\t});\n\n\tawait finalize();\n\n\tlog.info(`Starting MCPS server on port ${port}`);\n\n\tserverHandle = serve({\n\t\tfetch: app.fetch,\n\t\tport,\n\t\thostname: '0.0.0.0',\n\t});\n\n\tlog.success(`MCPS server running at http://localhost:${port}`);\n\tprintEndpoints();\n}\n"],"names":["serve","consola","createServer","log","withTag","serverHandle","shutdown","info","close","process","exit","setTimeout","on","startServer","options","port","Number","parseInt","app","printEndpoints","finalize","cwd","discoveryConfig","setup","fetch","hostname","success"],"mappings":"AAAA,SAASA,KAAK,QAAQ,oBAAoB;AAC1C,OAAOC,aAAa,UAAU;AAC9B,SAASC,YAAY,QAAkC,kBAAkB;AAEzE,MAAMC,MAAMF,QAAQG,OAAO,CAAC;AAE5B,IAAIC;AAEJ,SAASC;IACRH,IAAII,IAAI,CAAC;IACT,IAAIF,cAAc;QACjBA,aAAaG,KAAK,CAAC,IAAMC,QAAQC,IAAI,CAAC;QACtCC,WAAW,IAAMF,QAAQC,IAAI,CAAC,IAAI;IACnC,OAAO;QACND,QAAQC,IAAI,CAAC;IACd;AACD;AAEAD,QAAQG,EAAE,CAAC,UAAUN;AACrBG,QAAQG,EAAE,CAAC,WAAWN;AAEtB,OAAO,eAAeO,YAAYC,OAAsG;IACvI,MAAMC,OAAOC,OAAOC,QAAQ,CAACH,QAAQC,IAAI,EAAE;IAC3C,MAAM,EAAEG,GAAG,EAAEC,cAAc,EAAEC,QAAQ,EAAE,GAAGlB,aAAa;QACtDmB,KAAKP,QAAQO,GAAG;QAChBN;QACAO,iBAAiBR,QAAQQ,eAAe;QACxCC,OAAOT,QAAQS,KAAK;IACrB;IAEA,MAAMH;IAENjB,IAAII,IAAI,CAAC,CAAC,6BAA6B,EAAEQ,MAAM;IAE/CV,eAAeL,MAAM;QACpBwB,OAAON,IAAIM,KAAK;QAChBT;QACAU,UAAU;IACX;IAEAtB,IAAIuB,OAAO,CAAC,CAAC,wCAAwC,EAAEX,MAAM;IAC7DI;AACD"}
package/lib/cli.js ADDED
@@ -0,0 +1,19 @@
1
+ import { Command } from 'commander';
2
+ /**
3
+ * Create a reusable Commander program for MCPS server.
4
+ * Consumers can register providers before calling `program.parseAsync()`.
5
+ */ export function createProgram(options = {}) {
6
+ const { name = 'mcps', description = 'MCP Proxy Server - Unified MCP service with relay, SQL, CLS, and Prometheus support', version = '0.1.0', defaultPort = '8036', beforeStart, setup } = options;
7
+ const program = new Command();
8
+ program.name(name).description(description).version(version).option('-p, --port <port>', 'Port to listen on', defaultPort).option('-c, --cwd <path>', 'Working directory for config files', process.cwd()).option('--discovery-config', 'Enable server config discovery endpoints', false).action(async (opts)=>{
9
+ await beforeStart?.();
10
+ const { startServer } = await import('./cli-start.js');
11
+ await startServer({
12
+ ...opts,
13
+ setup
14
+ });
15
+ });
16
+ return program;
17
+ }
18
+
19
+ //# sourceMappingURL=cli.js.map
package/lib/cli.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander';\nimport type { CreateServerOptions } from './server/server';\n\nexport interface CreateProgramOptions {\n\tname?: string;\n\tdescription?: string;\n\tversion?: string;\n\tdefaultPort?: string;\n\t/** Called before the server starts, allows registering additional providers via side-effect imports */\n\tbeforeStart?: () => void | Promise<void>;\n\t/** Server setup callback, passed to createServer. Use to register plugins like audit. */\n\tsetup?: CreateServerOptions['setup'];\n}\n\n/**\n * Create a reusable Commander program for MCPS server.\n * Consumers can register providers before calling `program.parseAsync()`.\n */\nexport function createProgram(options: CreateProgramOptions = {}): Command {\n\tconst {\n\t\tname = 'mcps',\n\t\tdescription = 'MCP Proxy Server - Unified MCP service with relay, SQL, CLS, and Prometheus support',\n\t\tversion = '0.1.0',\n\t\tdefaultPort = '8036',\n\t\tbeforeStart,\n\t\tsetup,\n\t} = options;\n\n\tconst program = new Command();\n\n\tprogram\n\t\t.name(name)\n\t\t.description(description)\n\t\t.version(version)\n\t\t.option('-p, --port <port>', 'Port to listen on', defaultPort)\n\t\t.option('-c, --cwd <path>', 'Working directory for config files', process.cwd())\n\t\t.option('--discovery-config', 'Enable server config discovery endpoints', false)\n\t\t.action(async (opts) => {\n\t\t\tawait beforeStart?.();\n\t\t\tconst { startServer } = await import('./cli-start.js');\n\t\t\tawait startServer({ ...opts, setup });\n\t\t});\n\n\treturn program;\n}\n"],"names":["Command","createProgram","options","name","description","version","defaultPort","beforeStart","setup","program","option","process","cwd","action","opts","startServer"],"mappings":"AAAA,SAASA,OAAO,QAAQ,YAAY;AAcpC;;;CAGC,GACD,OAAO,SAASC,cAAcC,UAAgC,CAAC,CAAC;IAC/D,MAAM,EACLC,OAAO,MAAM,EACbC,cAAc,qFAAqF,EACnGC,UAAU,OAAO,EACjBC,cAAc,MAAM,EACpBC,WAAW,EACXC,KAAK,EACL,GAAGN;IAEJ,MAAMO,UAAU,IAAIT;IAEpBS,QACEN,IAAI,CAACA,MACLC,WAAW,CAACA,aACZC,OAAO,CAACA,SACRK,MAAM,CAAC,qBAAqB,qBAAqBJ,aACjDI,MAAM,CAAC,oBAAoB,sCAAsCC,QAAQC,GAAG,IAC5EF,MAAM,CAAC,sBAAsB,4CAA4C,OACzEG,MAAM,CAAC,OAAOC;QACd,MAAMP;QACN,MAAM,EAAEQ,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC;QACrC,MAAMA,YAAY;YAAE,GAAGD,IAAI;YAAEN;QAAM;IACpC;IAED,OAAOC;AACR"}
package/lib/dev.server.js CHANGED
@@ -1,5 +1,11 @@
1
+ import { setupAudit } from '#/server/audit-plugin';
1
2
  import { createServer } from '#/server/server';
2
- const { app } = createServer({});
3
+ const { app, finalize } = createServer({
4
+ setup: (ctx)=>{
5
+ setupAudit(ctx);
6
+ }
7
+ });
8
+ await finalize();
3
9
  export default {
4
10
  fetch: app.fetch
5
11
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dev.server.ts"],"sourcesContent":["import { createServer } from '#/server/server';\n\nconst { app } = createServer({});\n\nexport default {\n\tfetch: app.fetch,\n};\n"],"names":["createServer","app","fetch"],"mappings":"AAAA,SAASA,YAAY,QAAQ,kBAAkB;AAE/C,MAAM,EAAEC,GAAG,EAAE,GAAGD,aAAa,CAAC;AAE9B,eAAe;IACdE,OAAOD,IAAIC,KAAK;AACjB,EAAE"}
1
+ {"version":3,"sources":["../src/dev.server.ts"],"sourcesContent":["import { setupAudit } from '#/server/audit-plugin';\nimport { createServer } from '#/server/server';\n\nconst { app, finalize } = createServer({\n\tsetup: (ctx) => {\n\t\tsetupAudit(ctx);\n\t},\n});\n\nawait finalize();\n\nexport default {\n\tfetch: app.fetch,\n};\n"],"names":["setupAudit","createServer","app","finalize","setup","ctx","fetch"],"mappings":"AAAA,SAASA,UAAU,QAAQ,wBAAwB;AACnD,SAASC,YAAY,QAAQ,kBAAkB;AAE/C,MAAM,EAAEC,GAAG,EAAEC,QAAQ,EAAE,GAAGF,aAAa;IACtCG,OAAO,CAACC;QACPL,WAAWK;IACZ;AACD;AAEA,MAAMF;AAEN,eAAe;IACdG,OAAOJ,IAAII,KAAK;AACjB,EAAE"}
package/lib/index.js CHANGED
@@ -1,3 +1,21 @@
1
- export { };
2
-
3
- //# sourceMappingURL=index.js.map
1
+ // Core server
2
+ export { createServer } from "./server/server.js";
3
+ // Events (emittery-based decoupling)
4
+ export { McpsEventType, createMcpsEmitter } from "./server/events.js";
5
+ // Configuration
6
+ export { loadConfig, substituteEnvVars, loadEnvFiles } from "./server/config.js";
7
+ export { McpsConfigSchema, ServerConfigSchema, ModelConfigSchema, AuditConfigSchema, DbConfigSchema, HeaderNames } from "./server/schema.js";
8
+ // MCP routes and handler
9
+ export { registerMcpRoutes } from "./server/mcp-routes.js";
10
+ export { registerChatRoutes } from "./server/chat-routes.js";
11
+ export { registerApiRoutes } from "./server/api-routes.js";
12
+ export { createMcpLoggingHandler } from "./server/mcp-handler.js";
13
+ export { createMcpsRouter } from "./server/mcps-router.js";
14
+ // Providers
15
+ export { defineMcpServerHandler, registerMcpServerHandler, getAllMcpServerHandlerDefs, getMcpServerHandlerDef } from "./providers/McpServerHandlerDef.js";
16
+ export { findMcpServerDef, resolveMcpServerDef, getMcpServerDefCount } from "./providers/findMcpServerDef.js";
17
+ // Contracts
18
+ export * from "./contracts/index.js";
19
+ // Chat
20
+ export { createChatHandler } from "./chat/index.js";
21
+ //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export {};\n"],"names":[],"mappings":"AAAA,WAAU"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Core server\nexport { createServer, type CreateServerOptions, type McpsServerContext, type StatsProvider } from './server/server';\n\n// Events (emittery-based decoupling)\nexport { McpsEventType, createMcpsEmitter, type McpsEmitter, type McpsEventData, type McpsRequestEvent } from './server/events';\n\n// Configuration\nexport { loadConfig, substituteEnvVars, loadEnvFiles } from './server/config';\nexport {\n\ttype McpsConfig,\n\ttype ServerConfig,\n\ttype ModelConfig,\n\ttype AuditConfig,\n\ttype DbConfig,\n\tMcpsConfigSchema,\n\tServerConfigSchema,\n\tModelConfigSchema,\n\tAuditConfigSchema,\n\tDbConfigSchema,\n\tHeaderNames,\n} from './server/schema';\n\n// MCP routes and handler\nexport { registerMcpRoutes } from './server/mcp-routes';\nexport { registerChatRoutes } from './server/chat-routes';\nexport { registerApiRoutes } from './server/api-routes';\nexport { createMcpLoggingHandler } from './server/mcp-handler';\nexport { createMcpsRouter } from './server/mcps-router';\n\n// Providers\nexport {\n\ttype McpServerHandlerDef,\n\ttype McpServerHandlerDef as McpServerDef,\n\ttype HeaderMapping,\n\ttype DefineMcpServerHandlerOptions,\n\tdefineMcpServerHandler,\n\tregisterMcpServerHandler,\n\tgetAllMcpServerHandlerDefs,\n\tgetMcpServerHandlerDef,\n} from './providers/McpServerHandlerDef';\nexport { findMcpServerDef, resolveMcpServerDef, getMcpServerDefCount } from './providers/findMcpServerDef';\n\n// Contracts\nexport * from './contracts';\n\n// Chat\nexport { createChatHandler, type ChatHandlerOptions } from './chat';\n"],"names":["createServer","McpsEventType","createMcpsEmitter","loadConfig","substituteEnvVars","loadEnvFiles","McpsConfigSchema","ServerConfigSchema","ModelConfigSchema","AuditConfigSchema","DbConfigSchema","HeaderNames","registerMcpRoutes","registerChatRoutes","registerApiRoutes","createMcpLoggingHandler","createMcpsRouter","defineMcpServerHandler","registerMcpServerHandler","getAllMcpServerHandlerDefs","getMcpServerHandlerDef","findMcpServerDef","resolveMcpServerDef","getMcpServerDefCount","createChatHandler"],"mappings":"AAAA,cAAc;AACd,SAASA,YAAY,QAA8E,kBAAkB;AAErH,qCAAqC;AACrC,SAASC,aAAa,EAAEC,iBAAiB,QAAqE,kBAAkB;AAEhI,gBAAgB;AAChB,SAASC,UAAU,EAAEC,iBAAiB,EAAEC,YAAY,QAAQ,kBAAkB;AAC9E,SAMCC,gBAAgB,EAChBC,kBAAkB,EAClBC,iBAAiB,EACjBC,iBAAiB,EACjBC,cAAc,EACdC,WAAW,QACL,kBAAkB;AAEzB,yBAAyB;AACzB,SAASC,iBAAiB,QAAQ,sBAAsB;AACxD,SAASC,kBAAkB,QAAQ,uBAAuB;AAC1D,SAASC,iBAAiB,QAAQ,sBAAsB;AACxD,SAASC,uBAAuB,QAAQ,uBAAuB;AAC/D,SAASC,gBAAgB,QAAQ,uBAAuB;AAExD,YAAY;AACZ,SAKCC,sBAAsB,EACtBC,wBAAwB,EACxBC,0BAA0B,EAC1BC,sBAAsB,QAChB,kCAAkC;AACzC,SAASC,gBAAgB,EAAEC,mBAAmB,EAAEC,oBAAoB,QAAQ,+BAA+B;AAE3G,YAAY;AACZ,cAAc,cAAc;AAE5B,OAAO;AACP,SAASC,iBAAiB,QAAiC,SAAS"}
package/lib/mcps-cli.js CHANGED
@@ -1,41 +1,12 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * MCPS - MCP Proxy Server CLI
4
- *
5
- * A unified MCP server that supports:
6
- * - Tencent CLS (Cloud Log Service)
7
- * - SQL (MySQL, PostgreSQL, SQLite)
8
- * - Prometheus
9
- * - Relay (proxy to other MCP servers)
10
- */ import { serve } from "@hono/node-server";
11
- import { Command } from "commander";
12
2
  import consola from "consola";
13
- import { createServer } from "./server/server.js";
3
+ import { createProgram } from "./cli.js";
14
4
  const log = consola.withTag("mcps");
15
- const program = new Command();
16
- program.name("mcps").description("MCP Proxy Server - Unified MCP service with relay, SQL, CLS, and Prometheus support").version("0.1.0").option("-p, --port <port>", "Port to listen on", "8036").option("-c, --cwd <path>", "Working directory for config files", process.cwd()).option("--discovery-config", "Enable server config discovery endpoints", false).action(async (options) => {
17
- const port = Number.parseInt(options.port, 10);
18
- const { app } = createServer({
19
- cwd: options.cwd,
20
- port,
21
- discoveryConfig: options.discoveryConfig
22
- });
23
- log.info(`Starting MCPS server on port ${port}`);
24
- serve({
25
- fetch: app.fetch,
26
- port,
27
- hostname: "0.0.0.0"
28
- });
29
- log.success(`MCPS server running at http://localhost:${port}`);
30
- });
31
- // Handle graceful shutdown
32
- process.on("SIGINT", () => {
33
- log.info("Shutting down...");
34
- process.exit(130);
35
- });
36
- process.on("SIGTERM", () => {
37
- log.info("Shutting down...");
38
- process.exit(143);
5
+ const program = createProgram({
6
+ setup: async (ctx) => {
7
+ const { setupAudit } = await import("./server/audit-plugin.js");
8
+ setupAudit(ctx);
9
+ }
39
10
  });
40
11
  program.parseAsync(process.argv).catch((error) => {
41
12
  log.error(error.message);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mcps-cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * MCPS - MCP Proxy Server CLI\n *\n * A unified MCP server that supports:\n * - Tencent CLS (Cloud Log Service)\n * - SQL (MySQL, PostgreSQL, SQLite)\n * - Prometheus\n * - Relay (proxy to other MCP servers)\n */\nimport { serve } from '@hono/node-server';\nimport { Command } from 'commander';\nimport consola from 'consola';\nimport { createServer } from './server/server';\n\nconst log = consola.withTag('mcps');\n\nconst program = new Command();\n\nprogram\n\t.name('mcps')\n\t.description('MCP Proxy Server - Unified MCP service with relay, SQL, CLS, and Prometheus support')\n\t.version('0.1.0')\n\t.option('-p, --port <port>', 'Port to listen on', '8036')\n\t.option('-c, --cwd <path>', 'Working directory for config files', process.cwd())\n\t.option('--discovery-config', 'Enable server config discovery endpoints', false)\n\t.action(async (options) => {\n\t\tconst port = Number.parseInt(options.port, 10);\n\t\tconst { app } = createServer({\n\t\t\tcwd: options.cwd,\n\t\t\tport,\n\t\t\tdiscoveryConfig: options.discoveryConfig,\n\t\t});\n\n\t\tlog.info(`Starting MCPS server on port ${port}`);\n\n\t\tserve({\n\t\t\tfetch: app.fetch,\n\t\t\tport,\n\t\t\thostname: '0.0.0.0',\n\t\t});\n\n\t\tlog.success(`MCPS server running at http://localhost:${port}`);\n\t});\n\n// Handle graceful shutdown\nprocess.on('SIGINT', () => {\n\tlog.info('Shutting down...');\n\tprocess.exit(130);\n});\nprocess.on('SIGTERM', () => {\n\tlog.info('Shutting down...');\n\tprocess.exit(143);\n});\n\nprogram.parseAsync(process.argv).catch((error) => {\n\tlog.error(error.message);\n\tprocess.exit(1);\n});\n"],"names":["serve","Command","consola","createServer","log","withTag","program","name","description","version","option","process","cwd","action","options","port","Number","parseInt","app","discoveryConfig","info","fetch","hostname","success","on","exit","parseAsync","argv","catch","error","message"],"mappings":";AACA;;;;;;;;CAQC,GACD,SAASA,KAAK,QAAQ,oBAAoB;AAC1C,SAASC,OAAO,QAAQ,YAAY;AACpC,OAAOC,aAAa,UAAU;AAC9B,SAASC,YAAY,QAAQ,kBAAkB;AAE/C,MAAMC,MAAMF,QAAQG,OAAO,CAAC;AAE5B,MAAMC,UAAU,IAAIL;AAEpBK,QACEC,IAAI,CAAC,QACLC,WAAW,CAAC,uFACZC,OAAO,CAAC,SACRC,MAAM,CAAC,qBAAqB,qBAAqB,QACjDA,MAAM,CAAC,oBAAoB,sCAAsCC,QAAQC,GAAG,IAC5EF,MAAM,CAAC,sBAAsB,4CAA4C,OACzEG,MAAM,CAAC,OAAOC;IACd,MAAMC,OAAOC,OAAOC,QAAQ,CAACH,QAAQC,IAAI,EAAE;IAC3C,MAAM,EAAEG,GAAG,EAAE,GAAGf,aAAa;QAC5BS,KAAKE,QAAQF,GAAG;QAChBG;QACAI,iBAAiBL,QAAQK,eAAe;IACzC;IAEAf,IAAIgB,IAAI,CAAC,CAAC,6BAA6B,EAAEL,MAAM;IAE/Cf,MAAM;QACLqB,OAAOH,IAAIG,KAAK;QAChBN;QACAO,UAAU;IACX;IAEAlB,IAAImB,OAAO,CAAC,CAAC,wCAAwC,EAAER,MAAM;AAC9D;AAED,2BAA2B;AAC3BJ,QAAQa,EAAE,CAAC,UAAU;IACpBpB,IAAIgB,IAAI,CAAC;IACTT,QAAQc,IAAI,CAAC;AACd;AACAd,QAAQa,EAAE,CAAC,WAAW;IACrBpB,IAAIgB,IAAI,CAAC;IACTT,QAAQc,IAAI,CAAC;AACd;AAEAnB,QAAQoB,UAAU,CAACf,QAAQgB,IAAI,EAAEC,KAAK,CAAC,CAACC;IACvCzB,IAAIyB,KAAK,CAACA,MAAMC,OAAO;IACvBnB,QAAQc,IAAI,CAAC;AACd"}
1
+ {"version":3,"sources":["../src/mcps-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport consola from 'consola';\nimport { createProgram } from './cli';\n\nconst log = consola.withTag('mcps');\n\nconst program = createProgram({\n\tsetup: async (ctx) => {\n\t\tconst { setupAudit } = await import('./server/audit-plugin.js');\n\t\tsetupAudit(ctx);\n\t},\n});\n\nprogram.parseAsync(process.argv).catch((error) => {\n\tlog.error(error.message);\n\tprocess.exit(1);\n});\n"],"names":["consola","createProgram","log","withTag","program","setup","ctx","setupAudit","parseAsync","process","argv","catch","error","message","exit"],"mappings":";AACA,OAAOA,aAAa,UAAU;AAC9B,SAASC,aAAa,QAAQ,QAAQ;AAEtC,MAAMC,MAAMF,QAAQG,OAAO,CAAC;AAE5B,MAAMC,UAAUH,cAAc;IAC7BI,OAAO,OAAOC;QACb,MAAM,EAAEC,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC;QACpCA,WAAWD;IACZ;AACD;AAEAF,QAAQI,UAAU,CAACC,QAAQC,IAAI,EAAEC,KAAK,CAAC,CAACC;IACvCV,IAAIU,KAAK,CAACA,MAAMC,OAAO;IACvBJ,QAAQK,IAAI,CAAC;AACd"}
@@ -0,0 +1,35 @@
1
+ import { FeishuMcpServerDef } from "@wener/ai/mcp/feishu";
2
+ import { HeaderNames } from "../../server/schema.js";
3
+ import { defineMcpServerHandler, registerMcpServerHandler } from "../McpServerHandlerDef.js";
4
+ export const FeishuMcpServerHandlerDef = defineMcpServerHandler(FeishuMcpServerDef, {
5
+ headerMappings: [
6
+ {
7
+ header: HeaderNames.FEISHU_APP_ID,
8
+ property: "appId",
9
+ required: true
10
+ },
11
+ {
12
+ header: HeaderNames.FEISHU_APP_SECRET,
13
+ property: "appSecret",
14
+ required: true
15
+ },
16
+ {
17
+ header: HeaderNames.FEISHU_DOMAIN,
18
+ property: "domain"
19
+ }
20
+ ],
21
+ resolveConfig(config, headers) {
22
+ const appId = config.appId || headers?.get(HeaderNames.FEISHU_APP_ID) || config.headers?.[HeaderNames.FEISHU_APP_ID];
23
+ const appSecret = config.appSecret || headers?.get(HeaderNames.FEISHU_APP_SECRET) || config.headers?.[HeaderNames.FEISHU_APP_SECRET];
24
+ if (!appId || !appSecret)
25
+ return null;
26
+ const domain = config.domain || headers?.get(HeaderNames.FEISHU_DOMAIN) || config.headers?.[HeaderNames.FEISHU_DOMAIN] || "feishu";
27
+ return {
28
+ appId,
29
+ appSecret,
30
+ domain
31
+ };
32
+ }
33
+ });
34
+ registerMcpServerHandler(FeishuMcpServerHandlerDef);
35
+ //# sourceMappingURL=def.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/providers/feishu/def.ts"],"sourcesContent":["import { FeishuMcpServerDef, type CreateFeishuMcpServerOptions } from '@wener/ai/mcp/feishu';\nimport { HeaderNames, type FeishuConfig } from '../../server/schema';\nimport { defineMcpServerHandler, registerMcpServerHandler } from '../McpServerHandlerDef';\n\nexport const FeishuMcpServerHandlerDef = defineMcpServerHandler<CreateFeishuMcpServerOptions, FeishuConfig>(\n\tFeishuMcpServerDef,\n\t{\n\t\theaderMappings: [\n\t\t\t{ header: HeaderNames.FEISHU_APP_ID, property: 'appId', required: true },\n\t\t\t{ header: HeaderNames.FEISHU_APP_SECRET, property: 'appSecret', required: true },\n\t\t\t{ header: HeaderNames.FEISHU_DOMAIN, property: 'domain' },\n\t\t],\n\n\t\tresolveConfig(config, headers) {\n\t\t\tconst appId =\n\t\t\t\tconfig.appId ||\n\t\t\t\theaders?.get(HeaderNames.FEISHU_APP_ID) ||\n\t\t\t\tconfig.headers?.[HeaderNames.FEISHU_APP_ID];\n\t\t\tconst appSecret =\n\t\t\t\tconfig.appSecret ||\n\t\t\t\theaders?.get(HeaderNames.FEISHU_APP_SECRET) ||\n\t\t\t\tconfig.headers?.[HeaderNames.FEISHU_APP_SECRET];\n\n\t\t\tif (!appId || !appSecret) return null;\n\n\t\t\tconst domain =\n\t\t\t\tconfig.domain ||\n\t\t\t\theaders?.get(HeaderNames.FEISHU_DOMAIN) ||\n\t\t\t\tconfig.headers?.[HeaderNames.FEISHU_DOMAIN] ||\n\t\t\t\t'feishu';\n\n\t\t\treturn { appId, appSecret, domain };\n\t\t},\n\t},\n);\n\nregisterMcpServerHandler(FeishuMcpServerHandlerDef);\n"],"names":["FeishuMcpServerDef","HeaderNames","defineMcpServerHandler","registerMcpServerHandler","FeishuMcpServerHandlerDef","headerMappings","header","FEISHU_APP_ID","property","required","FEISHU_APP_SECRET","FEISHU_DOMAIN","resolveConfig","config","headers","appId","get","appSecret","domain"],"mappings":"AAAA,SAASA,kBAAkB,QAA2C,uBAAuB;AAC7F,SAASC,WAAW,QAA2B,sBAAsB;AACrE,SAASC,sBAAsB,EAAEC,wBAAwB,QAAQ,yBAAyB;AAE1F,OAAO,MAAMC,4BAA4BF,uBACxCF,oBACA;IACCK,gBAAgB;QACf;YAAEC,QAAQL,YAAYM,aAAa;YAAEC,UAAU;YAASC,UAAU;QAAK;QACvE;YAAEH,QAAQL,YAAYS,iBAAiB;YAAEF,UAAU;YAAaC,UAAU;QAAK;QAC/E;YAAEH,QAAQL,YAAYU,aAAa;YAAEH,UAAU;QAAS;KACxD;IAEDI,eAAcC,MAAM,EAAEC,OAAO;QAC5B,MAAMC,QACLF,OAAOE,KAAK,IACZD,SAASE,IAAIf,YAAYM,aAAa,KACtCM,OAAOC,OAAO,EAAE,CAACb,YAAYM,aAAa,CAAC;QAC5C,MAAMU,YACLJ,OAAOI,SAAS,IAChBH,SAASE,IAAIf,YAAYS,iBAAiB,KAC1CG,OAAOC,OAAO,EAAE,CAACb,YAAYS,iBAAiB,CAAC;QAEhD,IAAI,CAACK,SAAS,CAACE,WAAW,OAAO;QAEjC,MAAMC,SACLL,OAAOK,MAAM,IACbJ,SAASE,IAAIf,YAAYU,aAAa,KACtCE,OAAOC,OAAO,EAAE,CAACb,YAAYU,aAAa,CAAC,IAC3C;QAED,OAAO;YAAEI;YAAOE;YAAWC;QAAO;IACnC;AACD,GACC;AAEFf,yBAAyBC"}