@vacbo/opencode-anthropic-fix 0.0.44 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/dist/bun-proxy.mjs +282 -55
- package/dist/opencode-anthropic-auth-cli.mjs +194 -55
- package/dist/opencode-anthropic-auth-plugin.js +1816 -594
- package/package.json +1 -1
- package/src/__tests__/billing-edge-cases.test.ts +84 -0
- package/src/__tests__/bun-proxy.parallel.test.ts +460 -0
- package/src/__tests__/debug-gating.test.ts +76 -0
- package/src/__tests__/decomposition-smoke.test.ts +92 -0
- package/src/__tests__/fingerprint-regression.test.ts +1 -1
- package/src/__tests__/helpers/conversation-history.smoke.test.ts +338 -0
- package/src/__tests__/helpers/conversation-history.ts +376 -0
- package/src/__tests__/helpers/deferred.smoke.test.ts +161 -0
- package/src/__tests__/helpers/deferred.ts +122 -0
- package/src/__tests__/helpers/in-memory-storage.smoke.test.ts +166 -0
- package/src/__tests__/helpers/in-memory-storage.ts +152 -0
- package/src/__tests__/helpers/mock-bun-proxy.smoke.test.ts +92 -0
- package/src/__tests__/helpers/mock-bun-proxy.ts +229 -0
- package/src/__tests__/helpers/plugin-fetch-harness.smoke.test.ts +337 -0
- package/src/__tests__/helpers/plugin-fetch-harness.ts +401 -0
- package/src/__tests__/helpers/sse.smoke.test.ts +243 -0
- package/src/__tests__/helpers/sse.ts +288 -0
- package/src/__tests__/index.parallel.test.ts +711 -0
- package/src/__tests__/sanitization-regex.test.ts +65 -0
- package/src/__tests__/state-bounds.test.ts +110 -0
- package/src/account-identity.test.ts +213 -0
- package/src/account-identity.ts +108 -0
- package/src/accounts.dedup.test.ts +696 -0
- package/src/accounts.test.ts +2 -1
- package/src/accounts.ts +485 -191
- package/src/bun-fetch.test.ts +379 -0
- package/src/bun-fetch.ts +447 -174
- package/src/bun-proxy.ts +289 -57
- package/src/circuit-breaker.test.ts +274 -0
- package/src/circuit-breaker.ts +235 -0
- package/src/cli.test.ts +1 -0
- package/src/cli.ts +37 -18
- package/src/commands/router.ts +25 -5
- package/src/env.ts +1 -0
- package/src/headers/billing.ts +31 -13
- package/src/index.ts +224 -247
- package/src/oauth.ts +7 -1
- package/src/parent-pid-watcher.test.ts +219 -0
- package/src/parent-pid-watcher.ts +99 -0
- package/src/plugin-helpers.ts +112 -0
- package/src/refresh-helpers.ts +169 -0
- package/src/refresh-lock.test.ts +36 -9
- package/src/refresh-lock.ts +2 -2
- package/src/request/body.history.test.ts +398 -0
- package/src/request/body.ts +200 -13
- package/src/request/metadata.ts +6 -2
- package/src/response/index.ts +1 -1
- package/src/response/mcp.ts +60 -31
- package/src/response/streaming.test.ts +382 -0
- package/src/response/streaming.ts +403 -76
- package/src/storage.test.ts +127 -104
- package/src/storage.ts +152 -62
- package/src/system-prompt/builder.ts +33 -3
- package/src/system-prompt/sanitize.ts +12 -2
- package/src/token-refresh.test.ts +84 -1
- package/src/token-refresh.ts +14 -8
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
export interface SSEEvent {
|
|
2
|
+
event?: string;
|
|
3
|
+
data: string;
|
|
4
|
+
id?: string;
|
|
5
|
+
retry?: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface MessageStartEvent {
|
|
9
|
+
type: "message_start";
|
|
10
|
+
message: {
|
|
11
|
+
id: string;
|
|
12
|
+
type: "message";
|
|
13
|
+
role: "assistant";
|
|
14
|
+
content: unknown[];
|
|
15
|
+
model: string;
|
|
16
|
+
stop_reason: null;
|
|
17
|
+
stop_sequence: null;
|
|
18
|
+
usage: {
|
|
19
|
+
input_tokens: number;
|
|
20
|
+
output_tokens: number;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ContentBlockStartEvent {
|
|
26
|
+
type: "content_block_start";
|
|
27
|
+
index: number;
|
|
28
|
+
content_block: {
|
|
29
|
+
type: "text" | "tool_use";
|
|
30
|
+
text?: string;
|
|
31
|
+
id?: string;
|
|
32
|
+
name?: string;
|
|
33
|
+
input?: Record<string, unknown>;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ContentBlockDeltaEvent {
|
|
38
|
+
type: "content_block_delta";
|
|
39
|
+
index: number;
|
|
40
|
+
delta: {
|
|
41
|
+
type: "text_delta" | "input_json_delta";
|
|
42
|
+
text?: string;
|
|
43
|
+
partial_json?: string;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ContentBlockStopEvent {
|
|
48
|
+
type: "content_block_stop";
|
|
49
|
+
index: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface MessageDeltaEvent {
|
|
53
|
+
type: "message_delta";
|
|
54
|
+
delta: {
|
|
55
|
+
stop_reason: string | null;
|
|
56
|
+
stop_sequence: string | null;
|
|
57
|
+
};
|
|
58
|
+
usage: {
|
|
59
|
+
output_tokens: number;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface MessageStopEvent {
|
|
64
|
+
type: "message_stop";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface ErrorEvent {
|
|
68
|
+
type: "error";
|
|
69
|
+
error: {
|
|
70
|
+
type: string;
|
|
71
|
+
message: string;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function encodeSSEEvent(event: SSEEvent): string {
|
|
76
|
+
const lines: string[] = [];
|
|
77
|
+
|
|
78
|
+
if (event.event) {
|
|
79
|
+
lines.push(`event: ${event.event}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const dataLines = event.data.split("\n");
|
|
83
|
+
for (const line of dataLines) {
|
|
84
|
+
lines.push(`data: ${line}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (event.id !== undefined) {
|
|
88
|
+
lines.push(`id: ${event.id}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (event.retry !== undefined) {
|
|
92
|
+
lines.push(`retry: ${event.retry}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
lines.push("", "");
|
|
96
|
+
|
|
97
|
+
return lines.join("\n");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function encodeSSEStream(events: SSEEvent[]): string {
|
|
101
|
+
return events.map(encodeSSEEvent).join("");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function chunkUtf8AtOffsets(text: string, byteOffsets: number[]): Uint8Array[] {
|
|
105
|
+
const encoder = new TextEncoder();
|
|
106
|
+
const fullBytes = encoder.encode(text);
|
|
107
|
+
const chunks: Uint8Array[] = [];
|
|
108
|
+
|
|
109
|
+
const sortedOffsets = [...new Set(byteOffsets)].sort((a, b) => a - b);
|
|
110
|
+
|
|
111
|
+
let currentByte = 0;
|
|
112
|
+
|
|
113
|
+
for (const offset of sortedOffsets) {
|
|
114
|
+
if (offset <= currentByte || offset > fullBytes.length) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let endByte = offset;
|
|
119
|
+
while (endByte < fullBytes.length) {
|
|
120
|
+
const byte = fullBytes[endByte];
|
|
121
|
+
if ((byte & 0xc0) !== 0x80) {
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
endByte++;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const chunk = fullBytes.slice(currentByte, endByte);
|
|
128
|
+
chunks.push(chunk);
|
|
129
|
+
currentByte = endByte;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (currentByte < fullBytes.length) {
|
|
133
|
+
chunks.push(fullBytes.slice(currentByte));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return chunks;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function makeSSEResponse(body: ReadableStream<Uint8Array> | string, init?: ResponseInit): Response {
|
|
140
|
+
const headers = new Headers(init?.headers as unknown as string[][] | Record<string, string> | undefined);
|
|
141
|
+
headers.set("content-type", "text/event-stream");
|
|
142
|
+
|
|
143
|
+
return new Response(body, {
|
|
144
|
+
...init,
|
|
145
|
+
status: init?.status ?? 200,
|
|
146
|
+
headers,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function makeTruncatedSSEResponse(events: SSEEvent[], emitCount: number, init?: ResponseInit): Response {
|
|
151
|
+
const eventsToEmit = events.slice(0, emitCount);
|
|
152
|
+
const streamBody = encodeSSEStream(eventsToEmit);
|
|
153
|
+
|
|
154
|
+
const encoder = new TextEncoder();
|
|
155
|
+
const stream = new ReadableStream<Uint8Array>({
|
|
156
|
+
start(controller) {
|
|
157
|
+
const chunks = chunkUtf8AtOffsets(streamBody, [1024, 2048, 4096]);
|
|
158
|
+
for (const chunk of chunks) {
|
|
159
|
+
controller.enqueue(chunk);
|
|
160
|
+
}
|
|
161
|
+
controller.close();
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
return makeSSEResponse(stream, init);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function makeMalformedSSEResponse(malformedContent: string, init?: ResponseInit): Response {
|
|
169
|
+
const encoder = new TextEncoder();
|
|
170
|
+
|
|
171
|
+
const stream = new ReadableStream<Uint8Array>({
|
|
172
|
+
start(controller) {
|
|
173
|
+
controller.enqueue(encoder.encode(malformedContent));
|
|
174
|
+
controller.close();
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
return makeSSEResponse(stream, init);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function messageStartEvent(overrides: Partial<MessageStartEvent> = {}): SSEEvent {
|
|
182
|
+
const defaultEvent: MessageStartEvent = {
|
|
183
|
+
type: "message_start",
|
|
184
|
+
message: {
|
|
185
|
+
id: "msg_123",
|
|
186
|
+
type: "message",
|
|
187
|
+
role: "assistant",
|
|
188
|
+
content: [],
|
|
189
|
+
model: "claude-3-opus-20240229",
|
|
190
|
+
stop_reason: null,
|
|
191
|
+
stop_sequence: null,
|
|
192
|
+
usage: {
|
|
193
|
+
input_tokens: 10,
|
|
194
|
+
output_tokens: 0,
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
data: JSON.stringify({ ...defaultEvent, ...overrides }),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function contentBlockStartEvent(index: number, overrides: Partial<ContentBlockStartEvent> = {}): SSEEvent {
|
|
205
|
+
const defaultEvent: ContentBlockStartEvent = {
|
|
206
|
+
type: "content_block_start",
|
|
207
|
+
index,
|
|
208
|
+
content_block: {
|
|
209
|
+
type: "text",
|
|
210
|
+
text: "",
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
data: JSON.stringify({ ...defaultEvent, ...overrides }),
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function contentBlockDeltaEvent(
|
|
220
|
+
index: number,
|
|
221
|
+
text: string,
|
|
222
|
+
overrides: Partial<ContentBlockDeltaEvent> = {},
|
|
223
|
+
): SSEEvent {
|
|
224
|
+
const defaultEvent: ContentBlockDeltaEvent = {
|
|
225
|
+
type: "content_block_delta",
|
|
226
|
+
index,
|
|
227
|
+
delta: {
|
|
228
|
+
type: "text_delta",
|
|
229
|
+
text,
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
data: JSON.stringify({ ...defaultEvent, ...overrides }),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export function contentBlockStopEvent(index: number, overrides: Partial<ContentBlockStopEvent> = {}): SSEEvent {
|
|
239
|
+
const defaultEvent: ContentBlockStopEvent = {
|
|
240
|
+
type: "content_block_stop",
|
|
241
|
+
index,
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
data: JSON.stringify({ ...defaultEvent, ...overrides }),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function messageDeltaEvent(overrides: Partial<MessageDeltaEvent> = {}): SSEEvent {
|
|
250
|
+
const defaultEvent: MessageDeltaEvent = {
|
|
251
|
+
type: "message_delta",
|
|
252
|
+
delta: {
|
|
253
|
+
stop_reason: "end_turn",
|
|
254
|
+
stop_sequence: null,
|
|
255
|
+
},
|
|
256
|
+
usage: {
|
|
257
|
+
output_tokens: 100,
|
|
258
|
+
},
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
data: JSON.stringify({ ...defaultEvent, ...overrides }),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export function messageStopEvent(overrides: Partial<MessageStopEvent> = {}): SSEEvent {
|
|
267
|
+
const defaultEvent: MessageStopEvent = {
|
|
268
|
+
type: "message_stop",
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
data: JSON.stringify({ ...defaultEvent, ...overrides }),
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export function errorEvent(errorType: string, message: string, overrides: Partial<ErrorEvent> = {}): SSEEvent {
|
|
277
|
+
const defaultEvent: ErrorEvent = {
|
|
278
|
+
type: "error",
|
|
279
|
+
error: {
|
|
280
|
+
type: errorType,
|
|
281
|
+
message,
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
data: JSON.stringify({ ...defaultEvent, ...overrides }),
|
|
287
|
+
};
|
|
288
|
+
}
|