kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
pull/715/head
rodzic
add1a43cd7
commit
492396423c
|
@ -59,23 +59,25 @@ app.all(async (ctx) => {
|
|||
createAgenticClient({
|
||||
env: ctx.env,
|
||||
cache: caches.default,
|
||||
waitUntil,
|
||||
isCachingEnabled: isRequestPubliclyCacheable(ctx.req.raw)
|
||||
isCachingEnabled: isRequestPubliclyCacheable(ctx.req.raw),
|
||||
waitUntil
|
||||
})
|
||||
)
|
||||
|
||||
// TODO: Clean up the duplication between this block,
|
||||
// `resolveMcpEdgeRequest`, and `resolveHttpEdgeRequest`.
|
||||
const requestUrl = new URL(ctx.req.url)
|
||||
const { pathname } = requestUrl
|
||||
const requestedToolIdentifier = pathname.replace(/^\//, '').replace(/\/$/, '')
|
||||
const { toolName } = parseToolIdentifier(requestedToolIdentifier)
|
||||
|
||||
// Handle MCP requests
|
||||
if (toolName === 'mcp') {
|
||||
ctx.set('isJsonRpcRequest', true)
|
||||
const executionCtx = ctx.executionCtx as any
|
||||
const mcpInfo = await resolveMcpEdgeRequest(ctx)
|
||||
executionCtx.props = mcpInfo
|
||||
|
||||
// Handle MCP requests
|
||||
return DurableMcpServer.serve(pathname, {
|
||||
binding: 'DO_MCP_SERVER'
|
||||
}).fetch(ctx.req.raw, ctx.env, executionCtx)
|
||||
|
@ -86,41 +88,12 @@ app.all(async (ctx) => {
|
|||
let originResponse: Response | undefined
|
||||
let res: Response | undefined
|
||||
|
||||
function updateResponse(response: Response) {
|
||||
const res = new Response(response.body, response)
|
||||
|
||||
if (resolvedOriginToolCallResult) {
|
||||
if (resolvedOriginToolCallResult.rateLimitResult) {
|
||||
applyRateLimitHeaders({
|
||||
res,
|
||||
rateLimitResult: resolvedOriginToolCallResult.rateLimitResult
|
||||
})
|
||||
}
|
||||
|
||||
// Record the time it took for the origin to respond.
|
||||
res.headers.set(
|
||||
'x-origin-response-time',
|
||||
`${resolvedOriginToolCallResult.originTimespanMs}ms`
|
||||
)
|
||||
}
|
||||
|
||||
// Reset server to Agentic because Cloudflare likes to override things
|
||||
res.headers.set('server', 'agentic')
|
||||
|
||||
// Remove extra Cloudflare headers
|
||||
res.headers.delete('x-powered-by')
|
||||
res.headers.delete('via')
|
||||
res.headers.delete('nel')
|
||||
res.headers.delete('report-to')
|
||||
res.headers.delete('server-timing')
|
||||
res.headers.delete('reporting-endpoints')
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
try {
|
||||
// Resolve the http edge request to a specific deployment, consumer, and
|
||||
// tool call.
|
||||
resolvedHttpEdgeRequest = await resolveHttpEdgeRequest(ctx)
|
||||
|
||||
// Invoke the origin tool call.
|
||||
resolvedOriginToolCallResult = await resolveOriginToolCall({
|
||||
...resolvedHttpEdgeRequest,
|
||||
args: resolvedHttpEdgeRequest.toolCallArgs,
|
||||
|
@ -130,6 +103,7 @@ app.all(async (ctx) => {
|
|||
waitUntil
|
||||
})
|
||||
|
||||
// Transform the origin tool call response into an http response.
|
||||
if (resolvedOriginToolCallResult.originResponse) {
|
||||
originResponse = resolvedOriginToolCallResult.originResponse
|
||||
} else {
|
||||
|
@ -140,12 +114,17 @@ app.all(async (ctx) => {
|
|||
}
|
||||
|
||||
assert(originResponse, 500, 'Origin response is required')
|
||||
res = updateResponse(originResponse)
|
||||
|
||||
// Post-process the origin response.
|
||||
res = updateResponse(originResponse, resolvedOriginToolCallResult)
|
||||
return res
|
||||
} catch (err: any) {
|
||||
res = updateResponse(errorHandler(err, ctx))
|
||||
// Convert the error into an http response and post-process it.
|
||||
res = errorHandler(err, ctx)
|
||||
res = updateResponse(res, resolvedOriginToolCallResult)
|
||||
return res
|
||||
} finally {
|
||||
// Record the tool call usage.
|
||||
if (resolvedHttpEdgeRequest && res) {
|
||||
recordToolCallUsage({
|
||||
...resolvedHttpEdgeRequest,
|
||||
|
@ -161,3 +140,38 @@ app.all(async (ctx) => {
|
|||
}
|
||||
}
|
||||
})
|
||||
|
||||
function updateResponse(
|
||||
response: Response,
|
||||
resolvedOriginToolCallResult?: ResolvedOriginToolCallResult
|
||||
) {
|
||||
const res = new Response(response.body, response)
|
||||
|
||||
if (resolvedOriginToolCallResult) {
|
||||
if (resolvedOriginToolCallResult.rateLimitResult) {
|
||||
applyRateLimitHeaders({
|
||||
res,
|
||||
rateLimitResult: resolvedOriginToolCallResult.rateLimitResult
|
||||
})
|
||||
}
|
||||
|
||||
// Record the time it took for the origin to respond.
|
||||
res.headers.set(
|
||||
'x-origin-response-time',
|
||||
`${resolvedOriginToolCallResult.originTimespanMs}ms`
|
||||
)
|
||||
}
|
||||
|
||||
// Reset server to Agentic because Cloudflare likes to override things
|
||||
res.headers.set('server', 'agentic')
|
||||
|
||||
// Remove extra Cloudflare headers
|
||||
res.headers.delete('x-powered-by')
|
||||
res.headers.delete('via')
|
||||
res.headers.delete('nel')
|
||||
res.headers.delete('report-to')
|
||||
res.headers.delete('server-timing')
|
||||
res.headers.delete('reporting-endpoints')
|
||||
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -19,9 +19,8 @@ export function createAgenticClient({
|
|||
const client = new AgenticApiClient({
|
||||
apiBaseUrl: env.AGENTIC_API_BASE_URL,
|
||||
apiKey: env.AGENTIC_API_KEY,
|
||||
ky: !isCachingEnabled
|
||||
? defaultKy
|
||||
: defaultKy.extend({
|
||||
ky: isCachingEnabled
|
||||
? defaultKy.extend({
|
||||
hooks: {
|
||||
// NOTE: The order of the `beforeRequest` hook matters, and it only
|
||||
// works alongside the one in AgenticApiClient because that one's body
|
||||
|
@ -39,23 +38,26 @@ export function createAgenticClient({
|
|||
afterResponse: [
|
||||
async (request, _options, response) => {
|
||||
if (
|
||||
isCacheControlPubliclyCacheable(
|
||||
!isCacheControlPubliclyCacheable(
|
||||
response.headers.get('cache-control')
|
||||
)
|
||||
) {
|
||||
// Asynchronously update the cache with the response from
|
||||
// Agentic's backend API.
|
||||
waitUntil(
|
||||
cache.put(request, response.clone()).catch((err) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('cache put error', request, err)
|
||||
})
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Asynchronously update the cache with the response from
|
||||
// Agentic's backend API.
|
||||
waitUntil(
|
||||
cache.put(request, response.clone()).catch((err) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('cache put error', request, err)
|
||||
})
|
||||
)
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
: defaultKy
|
||||
})
|
||||
|
||||
return client
|
||||
|
|
|
@ -28,7 +28,7 @@ export default Sentry.withSentry(
|
|||
parsedEnv = parseEnv(env)
|
||||
} catch (err: any) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('error api gateway invalid env:', err.message)
|
||||
console.error('api gateway error invalid env:', err.message)
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'Invalid api gateway environment' }),
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
## TODO Post-MVP
|
||||
|
||||
- first-party deployment hosting
|
||||
- api gateway stress tests
|
||||
- auth
|
||||
- custom auth provider configs for projects/deployments
|
||||
- stripe
|
||||
|
|
Ładowanie…
Reference in New Issue