feat(billing): bill Cursor executor usage via stream-json token parsing
Memind CI / Test, build, and release guards (push) Failing after 14m36s
Memind CI / Test, build, and release guards (push) Failing after 14m36s
Parse Cursor CLI usage from stream-json output and charge through billSessionUsage so subscription quota is consumed first and wallet overage applies when needed. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
buildCursorBillingTokenState,
|
||||
extractCursorAgentDisplayText,
|
||||
normalizeCursorAgentUsage,
|
||||
parseCursorAgentUsage,
|
||||
} from './cursor-agent-usage.mjs';
|
||||
|
||||
const SAMPLE_STREAM_JSON = [
|
||||
'{"type":"system","subtype":"init","cwd":"/tmp","session_id":"abc","model":"Auto"}',
|
||||
'{"type":"user","message":{"role":"user","content":[{"type":"text","text":"reply with exactly: ok"}]}}',
|
||||
'{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"ok"}]}}',
|
||||
'{"type":"result","subtype":"success","duration_ms":13064,"result":"ok","usage":{"inputTokens":7765,"outputTokens":64,"cacheReadTokens":5427,"cacheWriteTokens":0}}',
|
||||
].join('\n');
|
||||
|
||||
test('parseCursorAgentUsage reads result usage from stream-json stdout', () => {
|
||||
const usage = parseCursorAgentUsage(SAMPLE_STREAM_JSON);
|
||||
assert.deepEqual(usage, {
|
||||
inputTokens: 7765,
|
||||
outputTokens: 64,
|
||||
cacheReadTokens: 5427,
|
||||
cacheWriteTokens: 0,
|
||||
});
|
||||
});
|
||||
|
||||
test('normalizeCursorAgentUsage includes cache write tokens in billable input', () => {
|
||||
const usage = normalizeCursorAgentUsage({
|
||||
inputTokens: 1000,
|
||||
outputTokens: 200,
|
||||
cacheWriteTokens: 300,
|
||||
});
|
||||
assert.deepEqual(usage, {
|
||||
inputTokens: 1300,
|
||||
outputTokens: 200,
|
||||
cacheReadTokens: 0,
|
||||
cacheWriteTokens: 300,
|
||||
});
|
||||
});
|
||||
|
||||
test('extractCursorAgentDisplayText prefers result text', () => {
|
||||
assert.equal(extractCursorAgentDisplayText(SAMPLE_STREAM_JSON), 'ok');
|
||||
});
|
||||
|
||||
test('buildCursorBillingTokenState accumulates on prior session billing', () => {
|
||||
const tokenState = buildCursorBillingTokenState(
|
||||
{ inputTokens: 1000, outputTokens: 200 },
|
||||
{ lastInputTokens: 5000, lastOutputTokens: 800 },
|
||||
);
|
||||
assert.deepEqual(tokenState, {
|
||||
accumulatedInputTokens: 6000,
|
||||
accumulatedOutputTokens: 1000,
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user