@@ -108,6 +108,7 @@ interface TenantAccountOutput {
108108}
109109
110110type UpstreamProvider = "claude" | "codex"
111+ type WaitUntil = ( promise : Promise < unknown > ) => void
111112
112113const anthropicBootstrapModelQuotas : AccountModelQuotas = {
113114 opus : { remainingPercent : 100 } ,
@@ -2702,7 +2703,8 @@ const proxyUpstream = async (
27022703 env : Env ,
27032704 actor : DurableObjectStub < SubrouterDurableObject > ,
27042705 routeInput : RouteInput ,
2705- telemetry ?: MutableRequestTelemetryContext
2706+ telemetry ?: MutableRequestTelemetryContext ,
2707+ waitUntil ?: WaitUntil
27062708) : Promise < Response > => {
27072709 if ( ! routeInput . orgId ) {
27082710 return json ( { error : "tenant id required" } , { status : 401 } )
@@ -2722,9 +2724,10 @@ const proxyUpstream = async (
27222724 defaultUpstreamForAccount ( env , account )
27232725 )
27242726 const headers = setUpstreamAuthHeaders ( request . headers , account )
2725- await actor . recordTranscriptMeta ( {
2727+ const agentType = routeInput . agentType ?? "codex"
2728+ const transcriptMetaInput = {
27262729 orgId : routeInput . orgId ,
2727- agentType : routeInput . agentType ?? "codex" ,
2730+ agentType,
27282731 sessionId : routeInput . sessionId ,
27292732 type : "subrouter_meta" ,
27302733 payload : {
@@ -2736,36 +2739,56 @@ const proxyUpstream = async (
27362739 upstream : upstreamURL . toString ( ) ,
27372740 headers : redactedHeaders ( stripSubrouterHeaders ( request . headers ) ) ,
27382741 } ,
2739- } )
2742+ } satisfies TranscriptEventInput
27402743 const init : RequestInit = {
27412744 method : request . method ,
27422745 headers,
27432746 redirect : "manual" ,
27442747 }
2748+ let requestBody : Promise < ArrayBuffer > | undefined
27452749 if ( request . method !== "GET" && request . method !== "HEAD" ) {
2750+ requestBody = request . clone ( ) . arrayBuffer ( )
2751+ void requestBody . catch ( ( ) => { } )
2752+ init . body = request . body
2753+ }
2754+ const upstreamRequest = new Request ( upstreamURL , init )
2755+ const response = await fetch ( upstreamRequest )
2756+ if ( telemetry ) telemetry . upstreamStatus = response . status
2757+ const [ clientBody , transcriptBody ] = response . body
2758+ ? response . body . tee ( )
2759+ : [ null , null ]
2760+ const transcriptBodyBuffer = transcriptBody
2761+ ? new Response ( transcriptBody ) . arrayBuffer ( )
2762+ : Promise . resolve ( new ArrayBuffer ( 0 ) )
2763+ void transcriptBodyBuffer . catch ( ( ) => { } )
2764+ const recordTranscripts = async ( ) : Promise < void > => {
2765+ await actor . recordTranscriptMeta ( transcriptMetaInput )
2766+ if ( requestBody ) {
2767+ await recordTranscriptBodyFromArrayBuffer ( actor , {
2768+ orgId : routeInput . orgId ,
2769+ agentType,
2770+ sessionId : routeInput . sessionId ,
2771+ eventType : "http_body" ,
2772+ direction : "client_to_upstream" ,
2773+ body : await requestBody ,
2774+ } )
2775+ }
27462776 await recordTranscriptBodyFromArrayBuffer ( actor , {
27472777 orgId : routeInput . orgId ,
2748- agentType : routeInput . agentType ?? "codex" ,
2778+ agentType,
27492779 sessionId : routeInput . sessionId ,
27502780 eventType : "http_body" ,
2751- direction : "client_to_upstream" ,
2752- body : await request . clone ( ) . arrayBuffer ( ) ,
2781+ direction : "upstream_to_client" ,
2782+ body : await transcriptBodyBuffer ,
2783+ payload : { status : response . status } ,
27532784 } )
2754- init . body = request . body
27552785 }
2756- const upstreamRequest = new Request ( upstreamURL , init )
2757- const response = await fetch ( upstreamRequest )
2758- if ( telemetry ) telemetry . upstreamStatus = response . status
2759- await recordTranscriptBodyFromArrayBuffer ( actor , {
2760- orgId : routeInput . orgId ,
2761- agentType : routeInput . agentType ?? "codex" ,
2762- sessionId : routeInput . sessionId ,
2763- eventType : "http_body" ,
2764- direction : "upstream_to_client" ,
2765- body : await response . clone ( ) . arrayBuffer ( ) ,
2766- payload : { status : response . status } ,
2767- } )
2768- return new Response ( response . body , {
2786+ if ( waitUntil ) {
2787+ waitUntil ( recordTranscripts ( ) . catch ( ( ) => { } ) )
2788+ } else {
2789+ await recordTranscripts ( )
2790+ }
2791+ return new Response ( clientBody , {
27692792 status : response . status ,
27702793 statusText : response . statusText ,
27712794 headers : response . headers ,
@@ -3203,7 +3226,8 @@ const escapeHTML = (value: string): string =>
32033226const handleFetch = async (
32043227 request : Request ,
32053228 env : Env ,
3206- telemetry ?: MutableRequestTelemetryContext
3229+ telemetry ?: MutableRequestTelemetryContext ,
3230+ ctx ?: ExecutionContext
32073231) : Promise < Response > => {
32083232 const url = new URL ( request . url )
32093233
@@ -3561,28 +3585,37 @@ const handleFetch = async (
35613585 if ( isWebSocketUpgrade ( request ) ) {
35623586 return await proxyUpstreamWebSocket ( request , env , actor , tenantRouteInput , telemetry )
35633587 }
3564- return await proxyUpstream ( request , env , actor , tenantRouteInput , telemetry )
3588+ return await proxyUpstream (
3589+ request ,
3590+ env ,
3591+ actor ,
3592+ tenantRouteInput ,
3593+ telemetry ,
3594+ ctx ?. waitUntil . bind ( ctx )
3595+ )
35653596 } catch ( error ) {
35663597 if ( telemetry ) telemetry . errorType = errorTypeFor ( error )
35673598 return errorJson ( error , 503 )
35683599 }
35693600}
35703601
3602+ export const __test = { proxyUpstream }
3603+
35713604export default {
35723605 async fetch (
35733606 request : Request ,
35743607 env : Env ,
35753608 ctx ?: ExecutionContext
35763609 ) : Promise < Response > {
35773610 if ( ! isAxiomTelemetryConfigured ( env ) ) {
3578- return handleFetch ( request , env )
3611+ return handleFetch ( request , env , undefined , ctx )
35793612 }
35803613
35813614 const startTimeMs = Date . now ( )
35823615 const telemetry = createRequestTelemetryContext ( request )
35833616 let response : Response
35843617 try {
3585- response = await handleFetch ( request , env , telemetry )
3618+ response = await handleFetch ( request , env , telemetry , ctx )
35863619 } catch ( error ) {
35873620 telemetry . errorType = errorTypeFor ( error )
35883621 response = new Response ( "Internal Server Error" , { status : 500 } )
0 commit comments