kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: WIP kittens
rodzic
4223db8a9a
commit
2e458b226f
|
@ -171,29 +171,108 @@ export async function resolveOriginRequest(
|
|||
})
|
||||
}
|
||||
|
||||
// TODO: what do we want the API gateway's interface to be?
|
||||
// - support both MCP and OpenAPI / raw?
|
||||
|
||||
const { originAdapter } = deployment
|
||||
let originRequest: Request | undefined
|
||||
|
||||
if (originAdapter.type === 'openapi' || originAdapter.type === 'raw') {
|
||||
const originRequestUrl = `${deployment.originUrl}${toolPath}${search}`
|
||||
console.log('originRequestUrl', originRequestUrl)
|
||||
|
||||
originRequest = new Request(originRequestUrl, req)
|
||||
|
||||
// TODO: For OpenAPI, we need to convert from POST to the correct operation?
|
||||
// Or, do we only support a single public MCP interface?
|
||||
if (originAdapter.type === 'openapi') {
|
||||
const operation = originAdapter.toolToOperationMap[tool.name]
|
||||
assert(operation, 404, `Tool "${tool.name}" not found in OpenAPI spec`)
|
||||
|
||||
// req.method = operation.method
|
||||
const tempInitialRequest = ctx.req.clone()
|
||||
const tempInitialRequestBody: any = await tempInitialRequest.json()
|
||||
|
||||
const params = Object.entries(operation.parameterSources)
|
||||
const bodyParams = params.filter(([_key, source]) => source === 'body')
|
||||
const formDataParams = params.filter(
|
||||
([_key, source]) => source === 'formData'
|
||||
)
|
||||
const headerParams = params.filter(
|
||||
([_key, source]) => source === 'header'
|
||||
)
|
||||
const pathParams = params.filter(([_key, source]) => source === 'path')
|
||||
const queryParams = params.filter(([_key, source]) => source === 'query')
|
||||
const cookieParams = params.filter(
|
||||
([_key, source]) => source === 'cookie'
|
||||
)
|
||||
|
||||
const headers: Record<string, string> = {}
|
||||
if (headerParams.length > 0) {
|
||||
for (const [key] of headerParams) {
|
||||
headers[key] = tempInitialRequest.headers.get(key) as string
|
||||
}
|
||||
}
|
||||
|
||||
let body: string | undefined
|
||||
if (bodyParams.length > 0) {
|
||||
body = JSON.stringify(
|
||||
Object.fromEntries(
|
||||
bodyParams.map(([key]) => [key, tempInitialRequestBody[key] as any])
|
||||
)
|
||||
)
|
||||
|
||||
headers['content-type'] ??= 'application/json'
|
||||
} else if (formDataParams.length > 0) {
|
||||
body = JSON.stringify(
|
||||
Object.fromEntries(
|
||||
formDataParams.map(([key]) => [
|
||||
key,
|
||||
tempInitialRequestBody[key] as any
|
||||
])
|
||||
)
|
||||
)
|
||||
|
||||
headers['content-type'] ??= 'application/x-www-form-urlencoded'
|
||||
}
|
||||
|
||||
let path = operation.path
|
||||
if (pathParams.length > 0) {
|
||||
for (const [key] of pathParams) {
|
||||
const value: string = tempInitialRequestBody[key]
|
||||
assert(value, 400, `Missing required parameter "${key}"`)
|
||||
|
||||
const pathParamPlaceholder = `{${key}}`
|
||||
assert(
|
||||
path.includes(pathParamPlaceholder),
|
||||
500,
|
||||
`Misconfigured OpenAPI deployment "${deployment.id}": invalid path "${operation.path}" missing required path parameter "${key}"`
|
||||
)
|
||||
|
||||
path = path.replaceAll(pathParamPlaceholder, value)
|
||||
}
|
||||
}
|
||||
assert(
|
||||
!/\{\w+\}/.test(path),
|
||||
500,
|
||||
`Misconfigured OpenAPI deployment "${deployment.id}": invalid path "${operation.path}"`
|
||||
)
|
||||
|
||||
const query = new URLSearchParams()
|
||||
for (const [key] of queryParams) {
|
||||
query.set(key, tempInitialRequestBody[key] as string)
|
||||
}
|
||||
|
||||
for (const [key] of cookieParams) {
|
||||
headers[key] = tempInitialRequestBody[key] as string
|
||||
}
|
||||
|
||||
const queryString = query.toString()
|
||||
const originRequestUrl = `${deployment.originUrl}${path}${
|
||||
queryString ? `?${queryString}` : ''
|
||||
}`
|
||||
originRequest = new Request(originRequestUrl, {
|
||||
method: operation.method,
|
||||
body,
|
||||
headers
|
||||
})
|
||||
} else {
|
||||
const originRequestUrl = `${deployment.originUrl}${toolPath}${search}`
|
||||
originRequest = new Request(originRequestUrl, req)
|
||||
}
|
||||
|
||||
console.log('originRequestUrl', originRequest.url)
|
||||
updateOriginRequest(originRequest, { consumer, deployment })
|
||||
}
|
||||
|
||||
|
|
|
@ -40,14 +40,14 @@
|
|||
- share hono middleware and utils across apps/api and apps/gateway
|
||||
- or combine these together? ehhhh
|
||||
- MCP server vs REST gateway on public and internal sides
|
||||
- RAW: `METHOD gateway.agentic.so/deploymentIdentifier/<pathname>`
|
||||
- => Raw HTTP: `METHOD originUrl/<pathname>` simple HTTP proxy request
|
||||
- REST: `POST gateway.agentic.so/deploymentIdentifier/toolName`
|
||||
- **REST**: `POST gateway.agentic.so/deploymentIdentifier/toolName`
|
||||
- => MCP: `MCPClient.callTool` with JSON body parameters
|
||||
- => OpenAPI: `GET/POST/ETC originUrl/toolName` operation with transformed JSON body params
|
||||
- MCP: `mcp.agentic.so/deploymentIdentifier/sse` MCP server?
|
||||
- **MCP**: `mcp.agentic.so/deploymentIdentifier/sse` MCP server?
|
||||
- => MCP: `MCPClient.callTool` just proxying tool call
|
||||
- => OpenAPI: `GET/POST/ETC originUrl/toolName` operation with transformed tool params
|
||||
- RAW: `METHOD gateway.agentic.so/deploymentIdentifier/<pathname>`
|
||||
- => Raw HTTP: `METHOD originUrl/<pathname>` simple HTTP proxy request
|
||||
- add support for caching
|
||||
- add support for custom headers on responses
|
||||
- signed requests
|
||||
|
|
Ładowanie…
Reference in New Issue