Files
9router/tests/unit/request-details-redaction.test.js
luulam 59f17b3725 feat(usage): raw request detail modal + raw stream capture
* Add /api/usage/request-details/raw endpoint serving a single
  stored request detail verbatim (raw payloads), with /raw doc
  clarifying it stays gated by the dashboard auth layer.
* Add RawDetailModal opened from a new 'Raw' button in
  RequestDetailsTab. Modal loads /raw, exposes per-section copy
  buttons and a 'Copy all (JSON)' that bundles every section.
* Capture the raw provider SSE text inside the streaming
  transform (cap 64KB) and forward it through
  onStreamComplete.rawProviderText so handler stores it as the
  providerResponse. response.content stays the extracted user
  text. Tool-call-only turns remain so the marker.
* Accumulate from translated client-facing chunks instead of
  raw provider shapes so Responses, Claude delta types, and
  Gemini/Antigravity parts all contribute.
* Drop redaction from the list endpoint; raw access is now via
  the dedicated /raw endpoint. Tests cover the new behavior.
2026-09-07 14:23:48 +07:00

39 lines
1.7 KiB
JavaScript

import { describe, it, expect } from "vitest";
// Mirrors src/app/api/usage/request-details/route.js after redaction removal.
// The endpoint now returns stored detail rows verbatim so operators can see
// the full request / providerRequest / providerResponse / response payloads.
function listResponse(details) {
return { details: details || [], pagination: { page: 1, pageSize: 20, totalItems: (details || []).length, totalPages: 1 } };
}
describe("request-details list endpoint", () => {
it("returns full conversation payloads for operator debugging", () => {
const details = [{
id: "abc",
provider: "opencode",
model: "deepseek-v4-flash-free",
timestamp: "2026-08-05T00:00:00Z",
status: "success",
tokens: { prompt_tokens: 10, completion_tokens: 5 },
request: { messages: [{ role: "user", content: "secret prompt" }] },
providerRequest: { messages: [{ role: "user", content: "secret prompt" }] },
providerResponse: { choices: [{ message: { content: "secret answer" } }] },
response: { content: "secret answer" },
}];
const out = listResponse(details).details[0];
expect(out.id).toBe("abc");
expect(out.tokens).toEqual({ prompt_tokens: 10, completion_tokens: 5 });
expect(out.request).toEqual({ messages: [{ role: "user", content: "secret prompt" }] });
expect(out.providerRequest).toEqual({ messages: [{ role: "user", content: "secret prompt" }] });
expect(out.providerResponse).toEqual({ choices: [{ message: { content: "secret answer" } }] });
expect(out.response).toEqual({ content: "secret answer" });
});
it("handles empty details", () => {
const out = listResponse([]);
expect(out.details).toEqual([]);
expect(out.pagination.totalItems).toBe(0);
});
});