fix(hermes): fail closed on unknown GLM, namespaces, and ACP identity

Extra High review held #1039. Stop pricing every future glm-5.x as 5.2,
stop collapsing unknown provider/org/model trees onto a priced leaf, and
stop calling ACP Buzz — source=acp is a transport and the DB has no
client field. Strip trailing punctuation on PR URLs and bump the Hermes
parse version so old cache rows reparse.
This commit is contained in:
Aditya Vikram Singh 2026-08-19 19:42:42 +05:30
parent 66a776acfa
commit 10fdec6037
6 changed files with 35 additions and 22 deletions

View file

@ -630,8 +630,7 @@ function routedModelCandidates(model: string): string[] {
ids.push(value)
}
push(model)
let current = getCanonicalName(model)
push(current)
let current = model
let peeled = true
while (peeled) {
peeled = false
@ -644,13 +643,9 @@ function routedModelCandidates(model: string): string[] {
}
}
}
if (current.includes('/')) push(current.slice(current.lastIndexOf('/') + 1))
const leaf = current.includes('/') ? current.slice(current.lastIndexOf('/') + 1) : current
if (/^glm-5(?:\.\d+)?$/i.test(leaf)) {
push('glm-5p2')
push('glm-5p1')
push('glm-5')
}
// One house-style vendor strip (anthropic/foo → foo). Do not keep
// collapsing unknown provider/org/model trees onto a priced leaf.
push(getCanonicalName(current))
return ids
}

View file

@ -2493,7 +2493,7 @@ function providerCallToCachedCall(call: ParsedProviderCall): CachedCall {
webSearchRequests: call.webSearchRequests,
cacheCreationOneHourTokens: 0,
},
costUSD: (call.provider === 'mistral-vibe' || call.provider === 'antigravity' || call.provider === 'devin' || call.provider === 'vercel-gateway' || call.provider === 'hermes' || call.provider === 'buzz' || call.provider === 'kiro' || call.provider === 'codewhale' || call.provider === 'quickdesk' || call.provider === 'cline-cli') ? call.costUSD : undefined,
costUSD: (call.provider === 'mistral-vibe' || call.provider === 'antigravity' || call.provider === 'devin' || call.provider === 'vercel-gateway' || call.provider === 'hermes' || call.provider === 'kiro' || call.provider === 'codewhale' || call.provider === 'quickdesk' || call.provider === 'cline-cli') ? call.costUSD : undefined,
isEstimated: call.costIsEstimated || undefined,
speed: call.speed,
timestamp: call.timestamp,

View file

@ -99,7 +99,8 @@ function extractGithubPullUrls(...texts: Array<string | null | undefined>): stri
if (!text) continue
for (const match of text.matchAll(re)) {
try {
const url = new URL(match[0])
const raw = match[0].replace(/[).,\]]:;]+$/g, '')
const url = new URL(raw)
if (url.protocol !== 'https:') continue
if (!/^\/[^/]+\/[^/]+\/pull\/\d+$/.test(url.pathname)) continue
found.add(`${url.origin}${url.pathname}`)
@ -280,15 +281,11 @@ function isRealWorkspace(cwd: string | null | undefined): cwd is string {
return true
}
function hermesSurfaceProvider(source: string | null | undefined): 'hermes' | 'buzz' {
return source === 'acp' ? 'buzz' : 'hermes'
}
function resolveHermesWorkspace(
row: HermesSessionRow,
messages: HermesMessageRow[],
): { project: string; projectPath?: string; provider: 'hermes' | 'buzz' } {
const provider = hermesSurfaceProvider(row.source)
): { project: string; projectPath?: string; provider: 'hermes' } {
const provider = 'hermes' as const
const repo = row.git_repo_root?.trim()
if (isRealWorkspace(repo)) {
return { project: sanitizeProject(basename(repo)), projectPath: repo, provider }

View file

@ -292,7 +292,7 @@ export const PROVIDER_PARSE_VERSIONS: Record<string, string> = {
// replays (double-counted before), takes the model from the reporting
// assistant/message, and keeps agent-injected context out of the preview.
dsh: 'seed-aware-v1',
hermes: 'reasoning-output-accounting-v1-est-cost',
hermes: 'reasoning-output-accounting-v1-est-cost-routed-ids-workspace-pr-v2',
'lingtai-tui': 'token-ledger-registry-activity-v3',
'ibm-bob': 'worktree-project-grouping-v1',
// project-path-v1: the parser now records the session's full working

View file

@ -71,8 +71,9 @@ describe('getModelCosts', () => {
expect(upper!.outputCostPerToken).toBe(sibling!.outputCostPerToken)
expect(getModelCosts('cp/cline-pass/glm-5.3')!.inputCostPerToken).toBe(sibling!.inputCostPerToken)
expect(getModelCosts('omniroute:cp/cline-pass/glm-5.3')!.inputCostPerToken).toBe(sibling!.inputCostPerToken)
expect(getModelCosts('glm-5.4')!.inputCostPerToken).toBe(sibling!.inputCostPerToken)
expect(getModelCosts('cmd/deepseek/deepseek-v4-flash')).not.toBeNull()
expect(getModelCosts('glm-5.4')).toBeNull()
expect(getModelCosts('provider/org/glm-5.3')).toBeNull()
})
})

View file

@ -520,6 +520,26 @@ skipUnlessSqlite('hermes provider', () => {
expect(calls[0]?.project).toBe('hermes')
})
it('captures GitHub pull URLs that are wrapped in prose punctuation', async () => {
const dbPath = createHermesDb(tmpDir)
withTestDb(dbPath, (db) => {
insertSession(db, {
id: 'pr-punct',
inputTokens: 10,
outputTokens: 5,
cacheReadTokens: 0,
cacheWriteTokens: 0,
reasoningTokens: 0,
startedAt: 1779549200,
})
db.prepare('INSERT INTO messages (session_id, role, content, timestamp) VALUES (?, ?, ?, ?)')
.run('pr-punct', 'assistant', 'See (https://github.com/getagentseal/codeburn/pull/1037).', 1779549201)
})
const calls = await collectCalls(tmpDir, `${dbPath}#hermes-session=pr-punct`)
expect(calls[0]?.prLinks).toEqual(['https://github.com/getagentseal/codeburn/pull/1037'])
})
it('ignores GitHub pull URLs that only appear in tool dumps', async () => {
const dbPath = createHermesDb(tmpDir)
withTestDb(dbPath, (db) => {
@ -542,7 +562,7 @@ skipUnlessSqlite('hermes provider', () => {
expect(calls[0]?.prLinks).toBeUndefined()
})
it('treats ACP sessions as the Buzz app, not a Hermes folder', async () => {
it('keeps ACP sessions on Hermes because source=acp is a transport, not Buzz', async () => {
const dbPath = createHermesDb(tmpDir)
withTestDb(dbPath, (db) => {
insertSession(db, {
@ -561,8 +581,8 @@ skipUnlessSqlite('hermes provider', () => {
const calls = await collectCalls(tmpDir, `${dbPath}#hermes-session=acp-session`)
expect(calls[0]).toMatchObject({
provider: 'buzz',
project: 'buzz',
provider: 'hermes',
project: 'hermes',
})
})