fest-gateway 0.5.0 → 0.5.2
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 +6 -5
- package/dist/cli/copilot.js +150 -28
- package/dist/cli/copilot.js.map +1 -1
- package/dist/server/bin/fest.js +12 -10
- package/dist/server/bin/fest.js.map +1 -1
- package/dist/server/config.js +9 -2
- package/dist/server/config.js.map +1 -1
- package/dist/server/http/body.js +42 -2
- package/dist/server/http/body.js.map +1 -1
- package/dist/server/http/client.js +7 -0
- package/dist/server/http/client.js.map +1 -1
- package/dist/server/http/server.js +30 -0
- package/dist/server/http/server.js.map +1 -1
- package/dist/server/pipeline/copilot.js +236 -0
- package/dist/server/pipeline/copilot.js.map +1 -0
- package/dist/server/pipeline/openai.js +2 -2
- package/dist/server/pipeline/openai.js.map +1 -1
- package/dist/server/pipeline/passthrough.js +12 -4
- package/dist/server/pipeline/passthrough.js.map +1 -1
- package/dist/server/pipeline/wire.js +56 -0
- package/dist/server/pipeline/wire.js.map +1 -1
- package/dist/server/secret/fingerprint.js +7 -1
- package/dist/server/secret/fingerprint.js.map +1 -1
- package/dist/server/usage/chat.js +95 -0
- package/dist/server/usage/chat.js.map +1 -0
- package/dist/web/dist/assets/{index-BClCav9v.js → index-DJb4NfM5.js} +2 -2
- package/dist/web/dist/assets/{index-BClCav9v.js.map → index-DJb4NfM5.js.map} +1 -1
- package/dist/web/dist/index.html +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Folds OpenAI Chat Completions SSE chunks into a single UsagePayload.
|
|
3
|
+
*
|
|
4
|
+
* Copilot's own API (`api.<plan>.githubcopilot.com`) serves three wires and
|
|
5
|
+
* picks one per model: Anthropic Messages for Claude, the Responses API for the
|
|
6
|
+
* GPT-5 family and later, and Chat Completions for the rest and for its own
|
|
7
|
+
* utility calls. This is the third. Chunks carry no `event:` field, so every
|
|
8
|
+
* one arrives as the SSE default type, `message`:
|
|
9
|
+
*
|
|
10
|
+
* data: {"choices":[{"delta":{"content":"po"}}],…}
|
|
11
|
+
* data: {"choices":[],"usage":{"prompt_tokens":812,"completion_tokens":5,
|
|
12
|
+
* "prompt_tokens_details":{"cached_tokens":768}},…}
|
|
13
|
+
* data: [DONE]
|
|
14
|
+
*
|
|
15
|
+
* Usage arrives once, on a late chunk, when the request asked for it
|
|
16
|
+
* (`stream_options.include_usage`); a client that did not ask gets none, and
|
|
17
|
+
* the row honestly records no tokens rather than a guess.
|
|
18
|
+
*
|
|
19
|
+
* ── Mapping onto Fest's disjoint buckets ─────────────────────────────────────
|
|
20
|
+
*
|
|
21
|
+
* Same rule as the Responses API: `prompt_tokens` INCLUDES the cached ones, so
|
|
22
|
+
*
|
|
23
|
+
* inputTokens = prompt_tokens − cached_tokens
|
|
24
|
+
* cacheReadTokens = cached_tokens
|
|
25
|
+
* outputTokens = completion_tokens
|
|
26
|
+
*
|
|
27
|
+
* Same contract as the other accumulators: last-wins per field, and `apply()`
|
|
28
|
+
* never throws.
|
|
29
|
+
*/
|
|
30
|
+
import { EMPTY_USAGE } from "../../shared/types.js";
|
|
31
|
+
import { asRecord, num, parse } from "./accumulator.js";
|
|
32
|
+
/** Every chunk is a `message`: Chat Completions never names its events. */
|
|
33
|
+
export const CHAT_USAGE_EVENT_TYPES = new Set(["message"]);
|
|
34
|
+
/** Read one Chat Completions `usage` object, or null when nothing in it is usable. */
|
|
35
|
+
function fromUsage(usage) {
|
|
36
|
+
const prompt = num(usage["prompt_tokens"]);
|
|
37
|
+
const completion = num(usage["completion_tokens"]);
|
|
38
|
+
if (prompt === undefined && completion === undefined)
|
|
39
|
+
return null;
|
|
40
|
+
const details = asRecord(usage["prompt_tokens_details"]);
|
|
41
|
+
const cached = (details ? num(details["cached_tokens"]) : undefined) ?? 0;
|
|
42
|
+
return {
|
|
43
|
+
...EMPTY_USAGE,
|
|
44
|
+
inputTokens: Math.max(0, (prompt ?? 0) - cached),
|
|
45
|
+
cacheReadTokens: cached,
|
|
46
|
+
outputTokens: completion ?? 0,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export function createChatAccumulator() {
|
|
50
|
+
let usage = EMPTY_USAGE;
|
|
51
|
+
let observed = false;
|
|
52
|
+
let error = null;
|
|
53
|
+
let terminal = false;
|
|
54
|
+
return {
|
|
55
|
+
apply(event) {
|
|
56
|
+
if (event.data === "[DONE]") {
|
|
57
|
+
terminal = true;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
// Every content delta is a `message` too, so this runs once per token.
|
|
61
|
+
// Parsing only the chunks that could hold usage or an error keeps the
|
|
62
|
+
// observer's cost proportional to the metadata, not to the answer.
|
|
63
|
+
if (!event.data.includes('"usage"') && !event.data.includes('"error"'))
|
|
64
|
+
return;
|
|
65
|
+
const root = asRecord(parse(event.data));
|
|
66
|
+
if (!root)
|
|
67
|
+
return;
|
|
68
|
+
const err = asRecord(root["error"]);
|
|
69
|
+
if (err) {
|
|
70
|
+
error = {
|
|
71
|
+
type: typeof err["type"] === "string" ? err["type"] : (typeof err["code"] === "string" ? err["code"] : "error"),
|
|
72
|
+
message: typeof err["message"] === "string" ? err["message"] : "",
|
|
73
|
+
};
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const u = asRecord(root["usage"]);
|
|
77
|
+
const parsed = u ? fromUsage(u) : null;
|
|
78
|
+
if (parsed !== null) {
|
|
79
|
+
usage = parsed;
|
|
80
|
+
observed = true;
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
snapshot: () => usage,
|
|
84
|
+
sawUsage: () => observed,
|
|
85
|
+
streamError: () => error,
|
|
86
|
+
sawTerminal: () => terminal,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/** Usage from a non-streaming `POST /chat/completions` body. */
|
|
90
|
+
export function chatUsageFromJson(body) {
|
|
91
|
+
const root = asRecord(body);
|
|
92
|
+
const u = root ? asRecord(root["usage"]) : undefined;
|
|
93
|
+
return u ? fromUsage(u) : null;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../server/usage/chat.ts"],"names":[],"mappings":"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"}
|