mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-17 13:13:35 +08:00
fix: capture direct provider trace headers
Trace direct provider calls from the effective Request metadata so headers carried by Request input are sanitized and persisted instead of being dropped when init.headers is empty. Tested: bun test src/server/__tests__/trace-capture.test.ts src/server/__tests__/proxy-network-settings.test.ts Tested: bun run check:server Confidence: high Scope-risk: narrow
This commit is contained in:
parent
be64e16621
commit
6e9c13f032
@ -565,6 +565,52 @@ describe('trace capture service', () => {
|
||||
}
|
||||
})
|
||||
|
||||
test('captures direct provider headers when fetch input is a Request', async () => {
|
||||
const originalFetch = globalThis.fetch
|
||||
const originalTraceEnv = process.env.CC_HAHA_TRACE_API_CALLS
|
||||
process.env.CC_HAHA_TRACE_API_CALLS = '1'
|
||||
try {
|
||||
globalThis.fetch = (async () => new Response(
|
||||
JSON.stringify({ id: 'msg-request-input', content: [{ type: 'text', text: 'ok' }] }),
|
||||
{
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
},
|
||||
)) as typeof fetch
|
||||
|
||||
const traceFetch = createDumpPromptsFetch('agent-direct-request-input', {
|
||||
traceSessionId: 'session-direct-request-input',
|
||||
querySource: 'test_query',
|
||||
})
|
||||
const requestInput = new Request('https://sub2api.example.test/v1/messages', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer sk-direct-header-secret',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
await traceFetch(requestInput, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ model: 'gpt-5.5', messages: [{ role: 'user', content: 'request input' }] }),
|
||||
})
|
||||
|
||||
const trace = await waitForTrace(
|
||||
'session-direct-request-input',
|
||||
(snapshot) => Boolean(snapshot.calls[0]?.response) && snapshot.events.length >= 2,
|
||||
)
|
||||
expect(trace.summary.apiCalls).toBe(1)
|
||||
expect(trace.calls[0].request.headers.authorization).toBe('[redacted]')
|
||||
expect(trace.calls[0].request.headers['content-type']).toBe('application/json')
|
||||
expect(trace.calls[0].request.body.preview).toContain('request input')
|
||||
expect(trace.calls[0].response.body.preview).toContain('msg-request-input')
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch
|
||||
if (originalTraceEnv === undefined) delete process.env.CC_HAHA_TRACE_API_CALLS
|
||||
else process.env.CC_HAHA_TRACE_API_CALLS = originalTraceEnv
|
||||
}
|
||||
})
|
||||
|
||||
test('captures direct provider fetch failures without changing thrown behavior', async () => {
|
||||
const originalFetch = globalThis.fetch
|
||||
const originalTraceEnv = process.env.CC_HAHA_TRACE_API_CALLS
|
||||
|
||||
@ -266,6 +266,15 @@ export function createDumpPromptsFetch(
|
||||
})(),
|
||||
}
|
||||
: init
|
||||
const traceRequest = timestamp
|
||||
? new Request(input, requestInit)
|
||||
: undefined
|
||||
const traceRequestUrl = traceRequest?.url ?? requestUrl
|
||||
const traceRequestMethod = traceRequest?.method ?? init?.method ?? 'POST'
|
||||
const traceRequestHeaders = (traceRequest?.headers ?? requestInit?.headers) as
|
||||
| Headers
|
||||
| Record<string, string>
|
||||
| undefined
|
||||
|
||||
const traceModel = extractModelFromRequestBody(traceRequestBody)
|
||||
const traceCallId = timestamp && traceEnabled && !isProviderProxyTrace
|
||||
@ -283,9 +292,9 @@ export function createDumpPromptsFetch(
|
||||
status: 'pending',
|
||||
startedAt: timestamp,
|
||||
request: {
|
||||
method: init?.method ?? 'POST',
|
||||
url: requestUrl,
|
||||
headers: requestInit?.headers as Headers | Record<string, string> | undefined,
|
||||
method: traceRequestMethod,
|
||||
url: traceRequestUrl,
|
||||
headers: traceRequestHeaders,
|
||||
bodySnapshot: createRequestPendingSnapshot(traceRequestBody),
|
||||
},
|
||||
metadata: {
|
||||
@ -303,7 +312,7 @@ export function createDumpPromptsFetch(
|
||||
severity: 'info',
|
||||
title: 'API call started',
|
||||
metadata: {
|
||||
url: requestUrl,
|
||||
url: traceRequestUrl,
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -328,9 +337,9 @@ export function createDumpPromptsFetch(
|
||||
completedAt,
|
||||
durationMs: Date.now() - traceStartedAtMs,
|
||||
request: {
|
||||
method: init?.method ?? 'POST',
|
||||
url: requestUrl,
|
||||
headers: requestInit?.headers as Headers | Record<string, string> | undefined,
|
||||
method: traceRequestMethod,
|
||||
url: traceRequestUrl,
|
||||
headers: traceRequestHeaders,
|
||||
bodySnapshot: createRequestPendingSnapshot(traceRequestBody),
|
||||
},
|
||||
error: err,
|
||||
@ -351,7 +360,7 @@ export function createDumpPromptsFetch(
|
||||
title: 'API call failed',
|
||||
message: err instanceof Error ? err.message : String(err),
|
||||
metadata: {
|
||||
url: requestUrl,
|
||||
url: traceRequestUrl,
|
||||
...(aborted ? { aborted: true } : {}),
|
||||
},
|
||||
})
|
||||
@ -372,9 +381,9 @@ export function createDumpPromptsFetch(
|
||||
model: traceModel,
|
||||
startedAt: timestamp,
|
||||
request: {
|
||||
method: init?.method ?? 'POST',
|
||||
url: requestUrl,
|
||||
headers: requestInit?.headers as Headers | Record<string, string> | undefined,
|
||||
method: traceRequestMethod,
|
||||
url: traceRequestUrl,
|
||||
headers: traceRequestHeaders,
|
||||
body: traceRequestBody,
|
||||
},
|
||||
}
|
||||
@ -420,7 +429,7 @@ export function createDumpPromptsFetch(
|
||||
title: 'API call completed',
|
||||
metadata: {
|
||||
status: response.status,
|
||||
url: requestUrl,
|
||||
url: traceRequestUrl,
|
||||
},
|
||||
})
|
||||
return
|
||||
@ -455,7 +464,7 @@ export function createDumpPromptsFetch(
|
||||
message: abortError.message,
|
||||
metadata: {
|
||||
status: response.status,
|
||||
url: requestUrl,
|
||||
url: traceRequestUrl,
|
||||
durationMs,
|
||||
aborted: true,
|
||||
},
|
||||
@ -472,7 +481,7 @@ export function createDumpPromptsFetch(
|
||||
message: captureFailure instanceof Error ? captureFailure.message : String(captureFailure),
|
||||
metadata: {
|
||||
status: response.status,
|
||||
url: requestUrl,
|
||||
url: traceRequestUrl,
|
||||
},
|
||||
})
|
||||
// The clone shares the upstream source with the SDK's branch, so a
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user