feat: pre-request token validation, mid-stream error handling, and usage stats improvements
- Qoder: handle mid-stream errors by returning proper error Response instead of embedding in stream - Qoder: add refreshCredentials() to validate token via quota endpoint before requests - chatCore: validate and refresh provider tokens before sending chat requests - chatCore: bail early with 401 on unrecoverable token refresh errors - Usage stats: track apiKey, comboName, fallbackHistory in request details - Dashboard: improve Combos, Endpoint, Provider, Usage, and RequestDetails pages - API keys route: upsert logic with provider_type support - DB repos: usageRepo query improvements, requestDetailsRepo pagination, apiKeysRepo updates
This commit is contained in:
@@ -49,7 +49,9 @@ export function createSSEStream(options = {}) {
|
||||
connectionId = null,
|
||||
body = null,
|
||||
onStreamComplete = null,
|
||||
apiKey = null
|
||||
apiKey = null,
|
||||
endpoint = null,
|
||||
comboName = null
|
||||
} = options;
|
||||
|
||||
let buffer = "";
|
||||
@@ -335,11 +337,11 @@ export function createSSEStream(options = {}) {
|
||||
}
|
||||
|
||||
if (hasValidUsage(usage)) {
|
||||
saveUsageStats({ provider, model, tokens: usage, connectionId, apiKey });
|
||||
saveUsageStats({ provider, model, tokens: usage, connectionId, apiKey, endpoint, comboName });
|
||||
} else {
|
||||
appendRequestLog({ model, provider, connectionId, tokens: null, status: "200 OK" }).catch(() => { });
|
||||
}
|
||||
|
||||
|
||||
// IMPORTANT: In passthrough mode we still must terminate the SSE stream.
|
||||
// Some clients (e.g. OpenClaw) expect the OpenAI-style sentinel:
|
||||
// data: [DONE]\n\n
|
||||
@@ -418,7 +420,7 @@ export function createSSEStream(options = {}) {
|
||||
}
|
||||
|
||||
if (hasValidUsage(state?.usage)) {
|
||||
saveUsageStats({ provider: state.provider || targetFormat, model, tokens: state.usage, connectionId, apiKey });
|
||||
saveUsageStats({ provider: state.provider || targetFormat, model, tokens: state.usage, connectionId, apiKey, endpoint, comboName });
|
||||
} else {
|
||||
appendRequestLog({ model, provider, connectionId, tokens: null, status: "200 OK" }).catch(() => { });
|
||||
}
|
||||
@@ -436,7 +438,7 @@ export function createSSEStream(options = {}) {
|
||||
});
|
||||
}
|
||||
|
||||
export function createSSETransformStreamWithLogger(targetFormat, sourceFormat, provider = null, reqLogger = null, toolNameMap = null, model = null, connectionId = null, body = null, onStreamComplete = null, apiKey = null) {
|
||||
export function createSSETransformStreamWithLogger(targetFormat, sourceFormat, provider = null, reqLogger = null, toolNameMap = null, model = null, connectionId = null, body = null, onStreamComplete = null, apiKey = null, endpoint = null, comboName = null) {
|
||||
return createSSEStream({
|
||||
mode: STREAM_MODE.TRANSLATE,
|
||||
targetFormat,
|
||||
@@ -448,11 +450,13 @@ export function createSSETransformStreamWithLogger(targetFormat, sourceFormat, p
|
||||
connectionId,
|
||||
body,
|
||||
onStreamComplete,
|
||||
apiKey
|
||||
apiKey,
|
||||
endpoint,
|
||||
comboName
|
||||
});
|
||||
}
|
||||
|
||||
export function createPassthroughStreamWithLogger(provider = null, reqLogger = null, model = null, connectionId = null, body = null, onStreamComplete = null, apiKey = null) {
|
||||
export function createPassthroughStreamWithLogger(provider = null, reqLogger = null, model = null, connectionId = null, body = null, onStreamComplete = null, apiKey = null, endpoint = null, comboName = null) {
|
||||
return createSSEStream({
|
||||
mode: STREAM_MODE.PASSTHROUGH,
|
||||
provider,
|
||||
@@ -461,6 +465,8 @@ export function createPassthroughStreamWithLogger(provider = null, reqLogger = n
|
||||
connectionId,
|
||||
body,
|
||||
onStreamComplete,
|
||||
apiKey
|
||||
apiKey,
|
||||
endpoint,
|
||||
comboName
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user