Skip to content

Commit 445a34b

Browse files
committed
return usage stats from providers
1 parent d1a6fe9 commit 445a34b

File tree

4 files changed

+55
-4
lines changed

4 files changed

+55
-4
lines changed

node/providers/anthropic.ts

+18-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
type StopReason,
77
type Provider,
88
type ProviderMessage,
9+
type Usage,
910
} from "./provider.ts";
1011
import type { ToolRequestId } from "../tools/toolManager.ts";
1112
import { assertUnreachable } from "../utils/assertUnreachable.ts";
@@ -49,6 +50,7 @@ export class AnthropicProvider implements Provider {
4950
): Promise<{
5051
toolRequests: Result<ToolManager.ToolRequest, { rawRequest: unknown }>[];
5152
stopReason: StopReason;
53+
usage: Usage;
5254
}> {
5355
const buf: string[] = [];
5456
let flushInProgress: boolean = false;
@@ -225,9 +227,22 @@ export class AnthropicProvider implements Provider {
225227
return extendError(result, { rawRequest: req });
226228
});
227229

228-
this.nvim.logger?.debug("toolRequests: " + JSON.stringify(toolRequests));
229-
this.nvim.logger?.debug("stopReason: " + response.stop_reason);
230-
return { toolRequests, stopReason: response.stop_reason || "end_turn" };
230+
const usage: Usage = {
231+
inputTokens: response.usage.input_tokens,
232+
outputTokens: response.usage.output_tokens,
233+
};
234+
if (response.usage.cache_read_input_tokens) {
235+
usage.cacheHits = response.usage.cache_read_input_tokens;
236+
}
237+
if (response.usage.cache_creation_input_tokens) {
238+
usage.cacheMisses = response.usage.cache_creation_input_tokens;
239+
}
240+
241+
return {
242+
toolRequests,
243+
stopReason: response.stop_reason || "end_turn",
244+
usage,
245+
};
231246
} finally {
232247
this.request = undefined;
233248
}

node/providers/mock.ts

+11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
type Provider,
77
type ProviderMessage,
88
type StopReason,
9+
type Usage,
910
} from "./provider.ts";
1011

1112
type MockRequest = {
@@ -15,6 +16,7 @@ type MockRequest = {
1516
defer: Defer<{
1617
toolRequests: Result<ToolRequest, { rawRequest: unknown }>[];
1718
stopReason: StopReason;
19+
usage: Usage;
1820
}>;
1921
};
2022

@@ -28,6 +30,10 @@ export class MockProvider implements Provider {
2830
lastRequest.defer.resolve({
2931
toolRequests: [],
3032
stopReason: "end_turn",
33+
usage: {
34+
inputTokens: 0,
35+
outputTokens: 0,
36+
},
3137
});
3238
}
3339
}
@@ -40,6 +46,7 @@ export class MockProvider implements Provider {
4046
): Promise<{
4147
toolRequests: Result<ToolRequest, { rawRequest: unknown }>[];
4248
stopReason: StopReason;
49+
usage: Usage;
4350
}> {
4451
const request: MockRequest = {
4552
messages,
@@ -79,6 +86,10 @@ export class MockProvider implements Provider {
7986
lastRequest.defer.resolve({
8087
toolRequests,
8188
stopReason,
89+
usage: {
90+
inputTokens: 0,
91+
outputTokens: 0,
92+
},
8293
});
8394
}
8495
}

node/providers/openai.ts

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import OpenAI from "openai";
22
import * as ToolManager from "../tools/toolManager.ts";
33
import { extendError, type Result } from "../utils/result.ts";
4-
import type { StopReason, Provider, ProviderMessage } from "./provider.ts";
4+
import type {
5+
StopReason,
6+
Provider,
7+
ProviderMessage,
8+
Usage,
9+
} from "./provider.ts";
510
import { assertUnreachable } from "../utils/assertUnreachable.ts";
611
import type { ToolName, ToolRequestId } from "../tools/toolManager.ts";
712
import type { Nvim } from "nvim-node";
@@ -46,6 +51,7 @@ export class OpenAIProvider implements Provider {
4651
): Promise<{
4752
toolRequests: Result<ToolManager.ToolRequest, { rawRequest: unknown }>[];
4853
stopReason: StopReason;
54+
usage: Usage;
4955
}> {
5056
const openaiMessages: OpenAI.ChatCompletionMessageParam[] = [
5157
{
@@ -148,7 +154,9 @@ export class OpenAIProvider implements Provider {
148154

149155
const toolRequests = [];
150156
let stopReason: StopReason | undefined;
157+
let lastChunk: OpenAI.ChatCompletionChunk | undefined;
151158
for await (const chunk of stream) {
159+
lastChunk = chunk;
152160
const choice = chunk.choices[0];
153161
if (choice.delta.content) {
154162
onText(choice.delta.content);
@@ -229,6 +237,15 @@ export class OpenAIProvider implements Provider {
229237
return extendError(result, { rawRequest: req });
230238
}),
231239
stopReason: stopReason || "end_turn",
240+
usage: lastChunk?.usage
241+
? {
242+
inputTokens: lastChunk.usage.prompt_tokens,
243+
outputTokens: lastChunk.usage.completion_tokens,
244+
}
245+
: {
246+
inputTokens: 0,
247+
outputTokens: 0,
248+
},
232249
};
233250
} finally {
234251
this.request = undefined;

node/providers/provider.ts

+8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ export type StopReason =
1717
| "content"
1818
| "stop_sequence";
1919

20+
export type Usage = {
21+
inputTokens: number;
22+
outputTokens: number;
23+
cacheHits?: number;
24+
cacheMisses?: number;
25+
};
26+
2027
export type ProviderMessage = {
2128
role: "user" | "assistant";
2229
content: string | Array<ProviderMessageContent>;
@@ -57,6 +64,7 @@ export interface Provider {
5764
): Promise<{
5865
toolRequests: Result<ToolManager.ToolRequest, { rawRequest: unknown }>[];
5966
stopReason: StopReason;
67+
usage: Usage;
6068
}>;
6169

6270
abort(): void;

0 commit comments

Comments
 (0)