@@ -29,6 +29,7 @@ const REQUESTER_RUNTIME_SCHEMA_VERSION = "2026-06-04"
2929const REQUESTER_RUNTIME_SOURCE = "openclaw-taas-affinity"
3030const GIT_PROBE_TIMEOUT_MS = 250
3131const LAST_ROUTE_LIMIT = 256
32+ const PLUGIN_VERSION = "0.5.2"
3233
3334// OpenClaw stores active registry state (including workspaceDir) on globalThis
3435// under this well-known symbol key.
@@ -40,6 +41,10 @@ type RequesterRuntime = Record<string, unknown>
4041type AutorouterCapture = {
4142 sessionId : string
4243 capturedAt : number
44+ taasRequestId : string | null
45+ taasTraceId : string | null
46+ openclawTurnId : string | null
47+ openclawAttempt : string | null
4348 autorouterModel : string | null
4449 autorouterAlgo : string | null
4550 autorouterAlgoSource : string | null
@@ -162,6 +167,49 @@ function deriveAgentIdForCapture(ctx: { agentDir?: string; workspaceDir?: string
162167 return seg
163168}
164169
170+ function buildCorrelationMetadata (
171+ sessionId : string ,
172+ source : string ,
173+ ctx : ProviderWrapStreamFnContext ,
174+ agentId : string | null
175+ ) : Record < string , unknown > {
176+ const ctxRecord = ctx as unknown as Record < string , unknown >
177+ const modelRecord = asRecord ( ctxRecord . model )
178+ const modelId = safeString ( ctxRecord . modelId ) ?? safeString ( modelRecord ?. id )
179+ const provider = safeString ( ctxRecord . provider )
180+ return {
181+ schema_version : "2026-06-05" ,
182+ source : REQUESTER_RUNTIME_SOURCE ,
183+ plugin_version : PLUGIN_VERSION ,
184+ session_id : sessionId ,
185+ sticky_key : sessionId ,
186+ session_source_hint : stableHash ( source , "source" ) ,
187+ ...( agentId && { agent_id : agentId } ) ,
188+ ...( provider && { provider } ) ,
189+ ...( modelId && { model_id : modelId } ) ,
190+ }
191+ }
192+
193+ function buildCorrelationHeaders ( args : {
194+ sessionId : string
195+ turnId ?: unknown
196+ attempt ?: unknown
197+ agentId ?: string | null
198+ } ) : Record < string , string > {
199+ const headers : Record < string , string > = {
200+ "X-Session-Id" : args . sessionId ,
201+ "X-OpenClaw-Session-Id" : args . sessionId ,
202+ "X-OpenClaw-Plugin-Version" : PLUGIN_VERSION ,
203+ }
204+ const turnId = safeString ( args . turnId )
205+ const attempt = args . attempt === undefined || args . attempt === null ? undefined : String ( args . attempt )
206+ const agentId = safeString ( args . agentId )
207+ if ( turnId ) headers [ "X-OpenClaw-Turn-Id" ] = turnId
208+ if ( attempt ) headers [ "X-OpenClaw-Attempt" ] = attempt
209+ if ( agentId ) headers [ "X-OpenClaw-Agent-Id" ] = agentId
210+ return headers
211+ }
212+
165213function buildRequesterRuntime (
166214 ctx : ProviderWrapStreamFnContext ,
167215 sessionId : string ,
@@ -199,20 +247,23 @@ function buildRequesterRuntime(
199247function patchPayloadMetadata (
200248 payload : Record < string , unknown > ,
201249 sessionId : string ,
202- requesterRuntime ?: RequesterRuntime
250+ requesterRuntime ?: RequesterRuntime ,
251+ correlation ?: Record < string , unknown >
203252) : Record < string , unknown > {
204253 const existingMeta = asRecord ( payload . metadata ) ?? { }
205254 const needsSessionId = ! existingMeta . session_id
206255 const needsStickyKey = ! existingMeta . sticky_key
207256 const needsRequesterRuntime = requesterRuntime && ! existingMeta . requester_runtime
208- if ( ! needsSessionId && ! needsStickyKey && ! needsRequesterRuntime ) return payload
257+ const needsCorrelation = correlation && ! existingMeta . openclaw_correlation
258+ if ( ! needsSessionId && ! needsStickyKey && ! needsRequesterRuntime && ! needsCorrelation ) return payload
209259 return {
210260 ...payload ,
211261 metadata : {
212262 ...existingMeta ,
213263 ...( needsSessionId && { session_id : sessionId } ) ,
214264 ...( needsStickyKey && { sticky_key : sessionId } ) ,
215265 ...( needsRequesterRuntime && { requester_runtime : requesterRuntime } ) ,
266+ ...( needsCorrelation && { openclaw_correlation : correlation } ) ,
216267 } ,
217268 }
218269}
@@ -258,6 +309,10 @@ function captureAutorouterFromHeaders(
258309 autorouterModel : lowered [ "x-taas-autorouter-model" ] ?? null ,
259310 autorouterAlgo : lowered [ "x-taas-autorouter-mode" ] ?? null ,
260311 autorouterAlgoSource : lowered [ "x-taas-autorouter-algorithm-source" ] ?? null ,
312+ taasRequestId : lowered [ "x-request-id" ] ?? lowered [ "x-taas-request-id" ] ?? null ,
313+ taasTraceId : lowered [ "x-trace-id" ] ?? lowered [ "x-taas-trace-id" ] ?? null ,
314+ openclawTurnId : lowered [ "x-openclaw-turn-id" ] ?? null ,
315+ openclawAttempt : lowered [ "x-openclaw-attempt" ] ?? null ,
261316 thinkingApplied : lowered [ "x-taas-thinking-applied" ] ?? null ,
262317 routedContextWindow :
263318 parsedContextWindow && Number . isFinite ( parsedContextWindow ) && parsedContextWindow > 0
@@ -294,6 +349,7 @@ function buildWrapper(ctx: ProviderWrapStreamFnContext) {
294349 const { sessionId, source } = resolveSessionId ( ctx . workspaceDir )
295350 const agentIdForCapture = deriveAgentIdForCapture ( ctx as { agentDir ?: string ; workspaceDir ?: string } )
296351 const requesterRuntime = buildRequesterRuntime ( ctx , sessionId , source )
352+ const correlation = buildCorrelationMetadata ( sessionId , source , ctx , agentIdForCapture )
297353
298354 if ( isDev ) console . debug ( `[taas-affinity] wrapStreamFn sessionId=${ sessionId } source=${ source } ` )
299355
@@ -304,7 +360,7 @@ function buildWrapper(ctx: ProviderWrapStreamFnContext) {
304360 const onPayload : NonNullable < typeof options > [ "onPayload" ] = async ( payload , payloadModel ) => {
305361 const payloadRecord = asRecord ( payload )
306362 if ( ! payloadRecord ) return prevOnPayload ? prevOnPayload ( payload , payloadModel ) : payload
307- const patched = patchPayloadMetadata ( payloadRecord , sessionId , requesterRuntime )
363+ const patched = patchPayloadMetadata ( payloadRecord , sessionId , requesterRuntime , correlation )
308364 return prevOnPayload ? prevOnPayload ( patched , payloadModel ) : patched
309365 }
310366 const prevOnResponse = options ?. onResponse
@@ -323,13 +379,14 @@ function buildWrapper(ctx: ProviderWrapStreamFnContext) {
323379function buildTransportTurnState ( ctx : ProviderResolveTransportTurnStateContext ) : ProviderTransportTurnState | null {
324380 const activeSource = getActiveSessionSource ( ) ?? fallbackSessionSource ( )
325381 const sessionId = deriveSessionId ( activeSource )
382+ const agentId = deriveAgentIdForCapture ( ctx as unknown as { agentDir ?: string ; workspaceDir ?: string } )
326383 if ( isDev ) {
327384 console . debug (
328385 `[taas-affinity] resolveTransportTurnState sessionId=${ sessionId } ` +
329386 `source=${ activeSource } turnId=${ ctx . turnId } attempt=${ ctx . attempt } `
330387 )
331388 }
332- return { headers : { "X-Session-Id" : sessionId } }
389+ return { headers : buildCorrelationHeaders ( { sessionId , turnId : ctx . turnId , attempt : ctx . attempt , agentId } ) }
333390}
334391
335392export default {
@@ -382,6 +439,8 @@ export default {
382439 patchPayloadMetadata,
383440 resolveSessionId,
384441 captureAutorouterFromHeaders,
442+ buildCorrelationHeaders,
443+ buildCorrelationMetadata,
385444 getLastRouteForAgent,
386445 getLastRouteForSession,
387446 } ,
0 commit comments