32fb2cdeaf
Add chat file/image upload UX, attachment proxying, vision thumbnails, and per-turn image scoping so agents only use the current upload. Extend MindSpace asset context, billing token state, OA/scenario verify scripts, and related runtime config. Co-authored-by: Cursor <cursoragent@cursor.com>
116 lines
3.9 KiB
JavaScript
116 lines
3.9 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {
|
|
enrichTokenStateForBilling,
|
|
estimateAccumulatedCostUsd,
|
|
loadCostEstimateConfig,
|
|
pickSessionAccumulatedCost,
|
|
resolveBillingTokenState,
|
|
} from './billing-token-state.mjs';
|
|
import { computeDeltaCostCents } from './billing.mjs';
|
|
|
|
test('pickSessionAccumulatedCost reads snake_case and camelCase', () => {
|
|
assert.equal(pickSessionAccumulatedCost({ accumulated_cost: 0.12 }), 0.12);
|
|
assert.equal(pickSessionAccumulatedCost({ accumulatedCost: 0.34 }), 0.34);
|
|
assert.equal(pickSessionAccumulatedCost({}), null);
|
|
});
|
|
|
|
test('estimateAccumulatedCostUsd uses DeepSeek-ish defaults', () => {
|
|
const estimate = estimateAccumulatedCostUsd(
|
|
{ accumulatedInputTokens: 1_000_000, accumulatedOutputTokens: 10_000 },
|
|
{ enabled: true, inputUsdPer1M: 0.27, outputUsdPer1M: 1.1 },
|
|
);
|
|
assert.equal(estimate, 0.281);
|
|
});
|
|
|
|
test('enrichTokenStateForBilling prefers upstream cost over estimate', () => {
|
|
const enriched = enrichTokenStateForBilling(
|
|
{ accumulatedInputTokens: 1000, accumulatedOutputTokens: 100, accumulatedCost: 0.05 },
|
|
{},
|
|
{ H5_USE_BACKEND_COST: '1' },
|
|
);
|
|
assert.equal(enriched.accumulatedCost, 0.05);
|
|
});
|
|
|
|
test('enrichTokenStateForBilling fills session cost when Finish omits it', () => {
|
|
const enriched = enrichTokenStateForBilling(
|
|
{ accumulatedInputTokens: 1000, accumulatedOutputTokens: 100 },
|
|
{ sessionCost: { accumulated_cost: 0.08 } },
|
|
{ H5_USE_BACKEND_COST: '1' },
|
|
);
|
|
assert.equal(enriched.accumulatedCost, 0.08);
|
|
});
|
|
|
|
test('enrichTokenStateForBilling estimates when cost mode enabled and upstream missing', () => {
|
|
const enriched = enrichTokenStateForBilling(
|
|
{ accumulatedInputTokens: 1_000_000, accumulatedOutputTokens: 0 },
|
|
{},
|
|
{
|
|
H5_USE_BACKEND_COST: '1',
|
|
H5_COST_ESTIMATE_FROM_TOKENS: '1',
|
|
H5_COST_ESTIMATE_INPUT_USD_PER_1M: '0.27',
|
|
H5_COST_ESTIMATE_OUTPUT_USD_PER_1M: '1.1',
|
|
},
|
|
);
|
|
assert.equal(enriched.accumulatedCost, 0.27);
|
|
});
|
|
|
|
test('loadCostEstimateConfig disables estimate when cost mode off', () => {
|
|
const cfg = loadCostEstimateConfig({ H5_USE_BACKEND_COST: '0' });
|
|
assert.equal(cfg.enabled, false);
|
|
});
|
|
|
|
test('resolveBillingTokenState fetches session before estimating', async () => {
|
|
let fetched = false;
|
|
const resolved = await resolveBillingTokenState(
|
|
{ accumulatedInputTokens: 1000, accumulatedOutputTokens: 100 },
|
|
{
|
|
sessionId: '20260710_11',
|
|
fetchSession: async (sessionId) => {
|
|
fetched = true;
|
|
assert.equal(sessionId, '20260710_11');
|
|
return { accumulated_cost: 0.42 };
|
|
},
|
|
},
|
|
{ H5_USE_BACKEND_COST: '1' },
|
|
);
|
|
assert.equal(fetched, true);
|
|
assert.equal(resolved.accumulatedCost, 0.42);
|
|
});
|
|
|
|
test('enriched cost drives 1.2x billing instead of flat fallback', () => {
|
|
const previous = { lastInputTokens: 224853, lastOutputTokens: 6685, lastAccumulatedCost: null };
|
|
const tokenState = enrichTokenStateForBilling(
|
|
{ accumulatedInputTokens: 2908661, accumulatedOutputTokens: 15349 },
|
|
{},
|
|
{
|
|
H5_USE_BACKEND_COST: '1',
|
|
H5_COST_ESTIMATE_FROM_TOKENS: '1',
|
|
H5_COST_ESTIMATE_INPUT_USD_PER_1M: '0.27',
|
|
H5_COST_ESTIMATE_OUTPUT_USD_PER_1M: '1.1',
|
|
},
|
|
);
|
|
const previousCost = estimateAccumulatedCostUsd(
|
|
{ accumulatedInputTokens: 224853, accumulatedOutputTokens: 6685 },
|
|
loadCostEstimateConfig({
|
|
H5_USE_BACKEND_COST: '1',
|
|
H5_COST_ESTIMATE_FROM_TOKENS: '1',
|
|
H5_COST_ESTIMATE_INPUT_USD_PER_1M: '0.27',
|
|
H5_COST_ESTIMATE_OUTPUT_USD_PER_1M: '1.1',
|
|
}),
|
|
);
|
|
const costCents = computeDeltaCostCents(
|
|
{ ...previous, lastAccumulatedCost: previousCost },
|
|
tokenState,
|
|
{
|
|
useBackendCost: true,
|
|
usdCnyRate: 7.2,
|
|
marginMultiplier: 1.2,
|
|
inputCentsPer1k: 2,
|
|
outputCentsPer1k: 6,
|
|
minBillCents: 1,
|
|
},
|
|
);
|
|
assert.ok(costCents < 1000, `expected cost-mode charge under ¥10, got ${costCents} cents`);
|
|
});
|