import test from "node:test"; import assert from "node:assert/strict"; const { toJsonErrorPayload } = await import("../../src/shared/utils/upstreamError.ts"); const { createErrorResponse, createErrorResponseFromUnknown } = await import("../../src/lib/api/errorResponse.ts"); const { getAccountDisplayName, getProviderDisplayName } = await import("../../src/lib/display/names.ts"); const { resolveProviderName } = await import("../../src/lib/display/useProviderNodeMap.ts"); test("toJsonErrorPayload: preserves upstream error objects that already have error payloads", () => { const payload = { error: { message: "provider exploded", code: "quota_exceeded", }, }; assert.deepEqual(toJsonErrorPayload(payload), payload); }); test("toJsonErrorPayload: normalizes object payloads with string error", () => { assert.deepEqual(toJsonErrorPayload({ error: "plain provider error" }), { error: { message: "plain provider error", type: "upstream_error", code: "upstream_error", }, }); }); test("toJsonErrorPayload: wraps plain objects under error key", () => { assert.deepEqual(toJsonErrorPayload({ status: 503, message: "backend down" }), { error: { status: 503, message: "backend down", }, }); }); test("toJsonErrorPayload: extracts provider errors arrays into message strings", () => { assert.deepEqual( toJsonErrorPayload({ errors: ["content-type must be multipart/form-data"], name: "bad request", }), { error: { message: "content-type must be multipart/form-data", type: "upstream_error", code: "upstream_error", details: { errors: ["content-type must be multipart/form-data"], name: "bad request", }, }, } ); }); test("toJsonErrorPayload: normalizes object entries in provider errors arrays", () => { assert.deepEqual( toJsonErrorPayload({ errors: [ { message: "first provider error" }, { detail: "second provider error" }, { code: "invalid_request", field: "prompt" }, ], name: "bad request", }), { error: { message: 'first provider error, second provider error, {"code":"invalid_request","field":"prompt"}', type: "upstream_error", code: "upstream_error", details: { errors: [ { message: "first provider error" }, { detail: "second provider error" }, { code: "invalid_request", field: "prompt" }, ], name: "bad request", }, }, } ); }); test("toJsonErrorPayload: parses JSON strings recursively", () => { const raw = JSON.stringify({ error: { message: "nested json", code: "bad_request" } }); assert.deepEqual(toJsonErrorPayload(raw), { error: { message: "nested json", code: "bad_request", }, }); }); test("toJsonErrorPayload: falls back for blank strings and unsupported values", () => { const fallback = { error: { message: "custom fallback", type: "upstream_error", code: "upstream_error", }, }; assert.deepEqual(toJsonErrorPayload(" ", "custom fallback"), fallback); assert.deepEqual(toJsonErrorPayload(null, "custom fallback"), fallback); }); test("toJsonErrorPayload: converts non-JSON strings into normalized error payloads", () => { assert.deepEqual(toJsonErrorPayload("gateway timeout"), { error: { message: "gateway timeout", type: "upstream_error", code: "upstream_error", }, }); }); test("createErrorResponse: infers error types from status and preserves details", async () => { const response = createErrorResponse({ status: 409, message: "Conflict detected", details: { field: "name" }, }); const body = (await response.json()) as any; assert.equal(response.status, 409); assert.equal(body.error.message, "Conflict detected"); assert.equal(body.error.type, "conflict"); assert.deepEqual(body.error.details, { field: "name" }); assert.match(body.requestId, /^[0-9a-f-]{36}$/i); }); test("createErrorResponse: uses explicit type when provided", async () => { const response = createErrorResponse({ status: 418, message: "teapot", type: "not_found", }); const body = (await response.json()) as any; assert.equal(body.error.type, "not_found"); }); test("createErrorResponseFromUnknown: normalizes typed errors", async () => { const response = createErrorResponseFromUnknown({ message: "db exploded", status: 503, type: "server_error", details: { retryable: true }, }); const body = (await response.json()) as any; assert.equal(response.status, 503); assert.equal(body.error.message, "db exploded"); assert.equal(body.error.type, "server_error"); assert.deepEqual(body.error.details, { retryable: true }); }); test("createErrorResponseFromUnknown: falls back for non-object errors", async () => { const response = createErrorResponseFromUnknown("boom", "fallback message"); const body = (await response.json()) as any; assert.equal(response.status, 500); assert.equal(body.error.message, "fallback message"); assert.equal(body.error.type, "server_error"); }); test("getAccountDisplayName: respects priority order and fallback", () => { assert.equal( getAccountDisplayName({ id: "abcdef123456", name: "Primary Name", displayName: "Display Name", email: "account@example.com", }), "Primary Name" ); assert.equal( getAccountDisplayName({ id: "abcdef123456", name: " ", displayName: "Display Name", email: "account@example.com", }), "Display Name" ); assert.equal( getAccountDisplayName({ id: "abcdef123456", name: null, displayName: " ", email: "account@example.com", }), "account@example.com" ); assert.equal(getAccountDisplayName({ id: "abcdef123456" }), "Account #abcdef"); assert.equal(getAccountDisplayName(null), "Unknown Account"); }); test("resolveProviderName: returns user-given name from nodeMap for custom provider", () => { const nodeMap = new Map([ ["openai-compatible-chat-abc123", { name: "My LLM", prefix: "my-llm" }], ]); assert.equal( resolveProviderName("openai-compatible-chat-abc123", nodeMap), "My LLM", "should return the user-given name when present in the map" ); // Falls back to prefix when name is blank const mapNoName = new Map([ ["openai-compatible-chat-abc123", { name: null, prefix: "my-prefix" }], ]); assert.equal(resolveProviderName("openai-compatible-chat-abc123", mapNoName), "my-prefix"); // Falls back to de-UUIDed label when no node entry exists assert.equal( resolveProviderName("openai-compatible-chat-02669115-2545-4896-b003-cb4dac09d441", new Map()), "Compatible (openai)" ); // Falls back gracefully for unknown ids not in the map assert.equal(resolveProviderName("plain-provider", nodeMap), "plain-provider"); // Handles null/undefined id assert.equal(resolveProviderName(null, nodeMap), "Unknown Provider"); assert.equal(resolveProviderName(undefined, null), "Unknown Provider"); }); test("getProviderDisplayName: prefers node metadata and simplifies compatible IDs", () => { assert.equal( getProviderDisplayName("openai-compatible-chat-02669115-2545-4896-b003-cb4dac09d441", { name: "Friendly Node", prefix: "ignored-prefix", }), "Friendly Node" ); assert.equal( getProviderDisplayName("anthropic-compatible-responses-02669115-2545-4896-b003-cb4dac09d441", { name: " ", prefix: "Anthropic Prefix", }), "Anthropic Prefix" ); assert.equal( getProviderDisplayName("openai-compatible-chat-02669115-2545-4896-b003-cb4dac09d441"), "Compatible (openai)" ); assert.equal( getProviderDisplayName("anthropic-compatible-responses-02669115-2545-4896-b003-cb4dac09d441"), "Compatible (anthropic)" ); assert.equal(getProviderDisplayName(undefined), "Unknown Provider"); assert.equal(getProviderDisplayName("plain-provider-id"), "plain-provider-id"); });