-
Notifications
You must be signed in to change notification settings - Fork 765
Expand file tree
/
Copy patherrors.test.ts
More file actions
128 lines (109 loc) · 5.37 KB
/
Copy patherrors.test.ts
File metadata and controls
128 lines (109 loc) · 5.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import { CodesignError } from '@open-codesign/shared';
import { describe, expect, it } from 'vitest';
import { remapProviderError, rewriteUpstreamMessage } from './errors';
const LEAKED =
'Incorrect API key provided: sk-AAA. You can find your API key at https://platform.openai.com/account/api-keys.';
function httpError(status: number, message: string): Error & { status: number } {
const err = new Error(message) as Error & { status: number };
err.status = status;
return err;
}
describe('rewriteUpstreamMessage', () => {
it('keeps openai URL when active provider is openai', () => {
const result = rewriteUpstreamMessage(LEAKED, 'openai', 401);
expect(result.rewritten).toBe(false);
expect(result.message).toContain('platform.openai.com/account/api-keys');
});
it('rewrites leaked openai URL to anthropic billing URL', () => {
const result = rewriteUpstreamMessage(LEAKED, 'anthropic', 401);
expect(result.rewritten).toBe(true);
expect(result.message).not.toContain('openai.com');
expect(result.message).toContain('console.anthropic.com/settings/keys');
});
it('rewrites leaked openai URL to openrouter URL', () => {
const result = rewriteUpstreamMessage(LEAKED, 'openrouter', 401);
expect(result.message).toContain('openrouter.ai/settings/keys');
});
it('rewrites to deepseek URL even though it is not in the typed enum', () => {
const result = rewriteUpstreamMessage(LEAKED, 'deepseek', 401);
expect(result.message).toContain('platform.deepseek.com/api_keys');
});
it('strips URL and adds generic hint for unknown providers', () => {
const result = rewriteUpstreamMessage(LEAKED, 'mystery-llm', 401);
expect(result.rewritten).toBe(true);
expect(result.message).not.toContain('openai.com');
expect(result.message).toContain("Check your provider's API key settings");
});
it('does not rewrite 5xx errors', () => {
const result = rewriteUpstreamMessage(LEAKED, 'anthropic', 503);
expect(result.rewritten).toBe(false);
});
it('does not rewrite when no openai URL is present', () => {
const result = rewriteUpstreamMessage('Bad request: model not found', 'anthropic', 400);
expect(result.rewritten).toBe(false);
});
});
describe('remapProviderError', () => {
it('passes openai 401 through verbatim', () => {
const err = httpError(401, LEAKED);
const out = remapProviderError(err, 'openai');
expect(out).toBe(err);
});
it('rewrites anthropic 401 with leaked openai URL into a CodesignError', () => {
const err = httpError(401, LEAKED);
const out = remapProviderError(err, 'anthropic');
expect(out).toBeInstanceOf(CodesignError);
expect((out as CodesignError).message).toContain('console.anthropic.com/settings/keys');
expect((out as CodesignError).message).not.toContain('openai.com');
expect((out as CodesignError).code).toBe('PROVIDER_HTTP_4XX');
});
it('strips the URL when provider is unknown', () => {
const err = httpError(401, LEAKED);
const out = remapProviderError(err, 'mystery-llm');
expect(out).toBeInstanceOf(CodesignError);
expect((out as CodesignError).message).not.toContain('openai.com');
expect((out as CodesignError).message).toContain("Check your provider's API key settings");
});
it('passes 5xx errors through unchanged', () => {
const err = httpError(503, 'upstream unavailable');
const out = remapProviderError(err, 'anthropic');
expect(out).toBe(err);
});
it('tags 5xx "not implemented" bodies as PROVIDER_GATEWAY_INCOMPATIBLE on anthropic wire', () => {
const err = httpError(500, 'not implemented');
const out = remapProviderError(err, 'anthropic', 'anthropic');
expect(out).toBeInstanceOf(CodesignError);
expect((out as CodesignError).code).toBe('PROVIDER_GATEWAY_INCOMPATIBLE');
expect((out as CodesignError).message).toContain('not implemented');
});
it('tags status-less errors whose message mentions 501 as PROVIDER_GATEWAY_INCOMPATIBLE on anthropic wire', () => {
const out = remapProviderError(new Error('HTTP 501 from gateway'), 'anthropic', 'anthropic');
expect(out).toBeInstanceOf(CodesignError);
expect((out as CodesignError).code).toBe('PROVIDER_GATEWAY_INCOMPATIBLE');
});
it('does NOT remap 5xx "not implemented" to gateway-incompatible on openai-chat wire', () => {
const err = httpError(501, 'not implemented');
const out = remapProviderError(err, 'openai', 'openai-chat');
// Non-anthropic wire: 501 is just a generic upstream error, pass through.
expect(out).toBe(err);
});
it('does NOT remap 501 on openai-responses wire even when body matches gateway pattern', () => {
const err = httpError(501, 'messages api not supported');
const out = remapProviderError(err, 'openai', 'openai-responses');
expect(out).toBe(err);
});
it('does NOT remap when wire is undefined (safer default: pass through)', () => {
const err = httpError(500, 'not implemented');
const out = remapProviderError(err, 'anthropic');
expect(out).toBe(err);
});
it('extracts status code from CodesignError messages that embed it', () => {
const err = new CodesignError(
'HTTP 401 — see https://platform.openai.com/account/api-keys',
'PROVIDER_ERROR',
);
const out = remapProviderError(err, 'anthropic');
expect(out).toBeInstanceOf(CodesignError);
expect((out as CodesignError).message).toContain('console.anthropic.com/settings/keys');
});
});