Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/ai-bot/lib/responder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,12 @@ export class Responder {
let cachedTokens = (chunk.usage as any).prompt_tokens_details
?.cached_tokens;
let costUsd = (chunk.usage as any).cost;
// OpenRouter also stamps each chunk with the provider that served the
// request and the generation id. Recording them alongside the counts
// makes a cache miss attributable: a cachedTokens collapse with a
// provider change is a routing miss, not a prompt-shape bug.
let provider = (chunk as any).provider;
let generationId = chunk.id;
// Hand the counts to the publisher so they ride on the final room
// event. When the final edit has already gone out (the usage chunk
// trails the finish chunk), finalize() sends one more edit to carry
Expand All @@ -318,6 +324,8 @@ export class Responder {
completionTokens: chunk.usage.completion_tokens,
...(typeof cachedTokens === 'number' ? { cachedTokens } : {}),
...(typeof costUsd === 'number' ? { costUsd } : {}),
...(typeof provider === 'string' ? { provider } : {}),
...(typeof generationId === 'string' ? { generationId } : {}),
};
log.info(
`Request used ${chunk.usage.prompt_tokens} prompt tokens (${
Expand Down
11 changes: 11 additions & 0 deletions packages/ai-bot/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,17 @@ class Assistant {
// the cast.
(request as Record<string, unknown>).usage = { include: true };

// Prompt caches live per provider, and the router is otherwise free to
// spread a room's requests across providers — which turns a warm cache
// prefix into a full-price miss mid-conversation. Bias Anthropic-model
// requests to Anthropic itself, keeping fallbacks for availability.
if (this.getModel(prompt).startsWith('anthropic/')) {
(request as Record<string, unknown>).provider = {
order: ['anthropic'],
allow_fallbacks: true,
};
}

if (prompt.reasoningEffort !== undefined) {
request.reasoning_effort = prompt.reasoningEffort;
}
Expand Down
Loading
Loading