Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 17 additions & 16 deletions open-sse/handlers/chatCore.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { injectMemoryAndSkills } from "./chatCore/memorySkillsInjection.ts";
import { resolveChatCoreRequestSetup } from "./chatCore/requestSetup.ts";
import { buildFailureUsageRecord } from "./chatCore/failureUsage.ts";
import { checkIdempotencyCache } from "./chatCore/idempotency.ts";
import { checkSemanticCache } from "./chatCore/semanticCache.ts";
import { sanitizeChatRequestBody } from "./chatCore/sanitization.ts";
Expand Down Expand Up @@ -708,23 +709,23 @@ export async function handleChatCore({
payload?: unknown,
maxDepth = 3
): EffectiveServiceTier | null => resolveReportedServiceTierFor(provider, payload, maxDepth);
// Failure usage record building extracted to chatCore/failureUsage.ts (#3501); the handler keeps
// the fire-and-forget save + computes latencyMs, so the call sites stay byte-identical.
const persistFailureUsage = (statusCode: number, errorCode?: string | null) => {
saveRequestUsage({
provider: provider || "unknown",
model: model || "unknown",
tokens: { input: 0, output: 0, cacheRead: 0, cacheCreation: 0, reasoning: 0 },
status: String(statusCode),
success: false,
latencyMs: Date.now() - startTime,
timeToFirstTokenMs: 0,
errorCode: errorCode || String(statusCode),
timestamp: new Date().toISOString(),
connectionId: connectionId || undefined,
apiKeyId: apiKeyInfo?.id || undefined,
apiKeyName: apiKeyInfo?.name || undefined,
serviceTier: effectiveServiceTier,
comboStrategy: isCombo ? comboStrategy || undefined : undefined,
}).catch(() => {});
saveRequestUsage(
buildFailureUsageRecord({
provider,
model,
connectionId,
apiKeyInfo,
effectiveServiceTier,
isCombo,
comboStrategy,
statusCode,
errorCode,
latencyMs: Date.now() - startTime,
})
).catch(() => {});
};

// Key-health updater extracted to chatCore/keyHealth.ts (#3501); bind the per-request log once
Expand Down
39 changes: 39 additions & 0 deletions open-sse/handlers/chatCore/failureUsage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* chatCore failed-request usage record builder (Quality Gate v2 / Fase 9 — chatCore god-file
* decomposition, #3501).
*
* Pure core of handleChatCore's persistFailureUsage closure: builds the usage-history entry for a
* failed request (zeroed tokens/timing, success:false, the unknown/undefined fallbacks, and the
* combo-strategy gate). The handler keeps the impure parts byte-identically: it computes
* `latencyMs` (Date.now() - startTime) and fires the fire-and-forget saveRequestUsage(...).catch().
*/

export function buildFailureUsageRecord(opts: {
provider: string | null | undefined;
model: string | null | undefined;
connectionId: string | null | undefined;
apiKeyInfo: { id?: string; name?: string } | null | undefined;
effectiveServiceTier: string;
isCombo: boolean;
comboStrategy: string | null | undefined;
statusCode: number;
errorCode: string | null | undefined;
latencyMs: number;
}) {
return {
provider: opts.provider || "unknown",
model: opts.model || "unknown",
tokens: { input: 0, output: 0, cacheRead: 0, cacheCreation: 0, reasoning: 0 },
status: String(opts.statusCode),
success: false,
latencyMs: opts.latencyMs,
timeToFirstTokenMs: 0,
errorCode: opts.errorCode || String(opts.statusCode),
timestamp: new Date().toISOString(),
connectionId: opts.connectionId || undefined,
apiKeyId: opts.apiKeyInfo?.id || undefined,
apiKeyName: opts.apiKeyInfo?.name || undefined,
serviceTier: opts.effectiveServiceTier,
comboStrategy: opts.isCombo ? opts.comboStrategy || undefined : undefined,
};
}
79 changes: 79 additions & 0 deletions tests/unit/chatcore-failure-usage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// tests/unit/chatcore-failure-usage.test.ts
// Characterization of buildFailureUsageRecord — the failed-request usage payload builder extracted
// from handleChatCore's persistFailureUsage closure (chatCore god-file decomposition, #3501). Pure:
// the handler keeps the fire-and-forget saveRequestUsage(...).catch() call and computes latencyMs;
// this builds the record. Locks the unknown/undefined fallbacks, the zeroed token/timing fields,
// the combo-strategy gate, and the ISO timestamp.
import { test } from "node:test";
import assert from "node:assert/strict";
import { buildFailureUsageRecord } from "../../open-sse/handlers/chatCore/failureUsage.ts";

const ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;

test("maps a fully-populated failure into the usage record", () => {
const r = buildFailureUsageRecord({
provider: "openai",
model: "gpt-4o",
connectionId: "conn-1",
apiKeyInfo: { id: "key-1", name: "My Key" },
effectiveServiceTier: "priority",
isCombo: true,
comboStrategy: "weighted",
statusCode: 429,
errorCode: "rate_limited",
latencyMs: 1234,
});
assert.equal(r.provider, "openai");
assert.equal(r.model, "gpt-4o");
assert.deepEqual(r.tokens, { input: 0, output: 0, cacheRead: 0, cacheCreation: 0, reasoning: 0 });
assert.equal(r.status, "429");
assert.equal(r.success, false);
assert.equal(r.latencyMs, 1234);
assert.equal(r.timeToFirstTokenMs, 0);
assert.equal(r.errorCode, "rate_limited");
assert.match(String(r.timestamp), ISO);
assert.equal(r.connectionId, "conn-1");
assert.equal(r.apiKeyId, "key-1");
assert.equal(r.apiKeyName, "My Key");
assert.equal(r.serviceTier, "priority");
assert.equal(r.comboStrategy, "weighted");
});

test("applies the unknown/undefined fallbacks", () => {
const r = buildFailureUsageRecord({
provider: null,
model: undefined,
connectionId: null,
apiKeyInfo: null,
effectiveServiceTier: "standard",
isCombo: false,
comboStrategy: "priority",
statusCode: 502,
errorCode: null,
latencyMs: 7,
});
assert.equal(r.provider, "unknown");
assert.equal(r.model, "unknown");
assert.equal(r.errorCode, "502"); // falls back to String(statusCode)
assert.equal(r.connectionId, undefined);
assert.equal(r.apiKeyId, undefined);
assert.equal(r.apiKeyName, undefined);
// isCombo false → comboStrategy is dropped even when supplied
assert.equal(r.comboStrategy, undefined);
});

test("combo strategy is included only for combo requests", () => {
const combo = buildFailureUsageRecord({
provider: "x", model: "y", connectionId: null, apiKeyInfo: null,
effectiveServiceTier: "standard", isCombo: true, comboStrategy: "round-robin",
statusCode: 500, errorCode: "boom", latencyMs: 1,
});
assert.equal(combo.comboStrategy, "round-robin");

const comboNoStrategy = buildFailureUsageRecord({
provider: "x", model: "y", connectionId: null, apiKeyInfo: null,
effectiveServiceTier: "standard", isCombo: true, comboStrategy: null,
statusCode: 500, errorCode: "boom", latencyMs: 1,
});
assert.equal(comboNoStrategy.comboStrategy, undefined);
});
Loading