mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-07-10 01:29:41 +00:00
fix(cursor): avoid duplicating aggregated agent tools
This commit is contained in:
parent
4d21fadd18
commit
b40c545a65
2 changed files with 15 additions and 5 deletions
|
|
@ -480,9 +480,7 @@ function loadComposerInputTokens(db: SqliteDatabase): Map<string, number> {
|
|||
try {
|
||||
const rows = db.query<{ composer_id: string; used: number | null; ctx: number | null }>(COMPOSER_TOKENS_QUERY)
|
||||
for (const r of rows) {
|
||||
// Distinguish null (field absent) from 0 (valid token count).
|
||||
// `used ?? ctx` would fall through on 0, suppressing a real zero.
|
||||
const tokens = r.used !== null ? r.used : (r.ctx ?? 0)
|
||||
const tokens = r.used ?? r.ctx ?? 0
|
||||
if (r.composer_id && tokens > 0) map.set(r.composer_id, tokens)
|
||||
}
|
||||
} catch {
|
||||
|
|
@ -641,6 +639,9 @@ function parseBubbles(
|
|||
|
||||
let inputTokens = row.input_tokens ?? 0
|
||||
let outputTokens = row.output_tokens ?? 0
|
||||
// The conversation's tools/bash attach to the single call that carries its
|
||||
// real input (its first turn), so they are counted exactly once.
|
||||
let creditedHere = false
|
||||
|
||||
// Current Cursor leaves tokenCount at {0,0}. Use the conversation's real
|
||||
// context size (promptTokenBreakdown) for input, credited once per
|
||||
|
|
@ -656,6 +657,7 @@ function parseBubbles(
|
|||
} else {
|
||||
inputTokens = real
|
||||
creditedComposers.add(conversationId)
|
||||
creditedHere = true
|
||||
}
|
||||
} else {
|
||||
inputTokens = Math.ceil(textLen / CHARS_PER_TOKEN)
|
||||
|
|
@ -692,7 +694,7 @@ function parseBubbles(
|
|||
const languages = extractLanguages(blobToText(row.code_blocks))
|
||||
const hasCode = languages.length > 0
|
||||
|
||||
const agentTurn = agentTools.get(conversationId)
|
||||
const agentTurn = creditedHere ? agentTools.get(conversationId) : undefined
|
||||
const cursorTools: string[] = [
|
||||
...(hasCode ? ['cursor:edit', ...languages.map(l => `lang:${l}`)] : []),
|
||||
...(agentTurn?.tools ?? []),
|
||||
|
|
|
|||
|
|
@ -198,13 +198,15 @@ describe.skipIf(skipReason !== null)('cursor real context tokens (#575)', () =>
|
|||
expect(credited).toBeDefined()
|
||||
})
|
||||
|
||||
it('attributes tools and bash commands from agentKv to the correct conversation', async () => {
|
||||
it('attributes aggregated agentKv tools once in a multi-bubble conversation', async () => {
|
||||
const composerId = 'eeee1111-2222-3333-4444-555566667777'
|
||||
const requestId = 'req-001'
|
||||
const dbPath = buildDb((db) => {
|
||||
insertComposerData(db, { composerId, totalUsedTokens: 10000 })
|
||||
insertBubble(db, { composerId, bubbleUuid: 'b1', type: 1, text: 'do stuff', requestId })
|
||||
insertBubble(db, { composerId, bubbleUuid: 'b2', type: 2, text: 'doing stuff', model: 'gpt-5' })
|
||||
insertBubble(db, { composerId, bubbleUuid: 'b3', type: 1, text: 'do more stuff', requestId: 'req-002' })
|
||||
insertBubble(db, { composerId, bubbleUuid: 'b4', type: 2, text: 'doing more stuff', model: 'gpt-5' })
|
||||
// agentKv with tool calls
|
||||
insertAgentKv(db, {
|
||||
blobId: 'akv-1', role: 'user',
|
||||
|
|
@ -228,6 +230,12 @@ describe.skipIf(skipReason !== null)('cursor real context tokens (#575)', () =>
|
|||
expect(callWithTools!.tools).toContain('Read')
|
||||
expect(callWithTools!.tools).toContain('Shell')
|
||||
expect(callWithTools!.bashCommands).toContain('npm test')
|
||||
|
||||
const allTools = calls.flatMap(c => c.tools)
|
||||
const allBashCommands = calls.flatMap(c => c.bashCommands)
|
||||
expect(allTools.filter(t => t === 'Read').length).toBe(1)
|
||||
expect(allTools.filter(t => t === 'Shell').length).toBe(1)
|
||||
expect(allBashCommands.filter(cmd => cmd === 'npm test').length).toBe(1)
|
||||
})
|
||||
|
||||
it('uses conversation model for pricing when input is on a user bubble', async () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue