fix: scope tool token cache keys by tenantId

Tool definitions can differ per tenant in multi-tenant deployments.
Prefix per-tool cache keys with tenantId when present on the user
object, so tenants don't share stale token counts across different
tool configurations.

Cache key format: "{tenantId}:{toolName}" or "{toolName}" when no
tenant context exists.
This commit is contained in:
Danny Avila 2026-04-03 12:53:13 -04:00
parent df99e33543
commit 8db4f21f97
2 changed files with 8 additions and 2 deletions

View file

@ -390,6 +390,7 @@ export async function createRun({
provider,
clientOptions: llmConfig,
tokenCounter,
tenantId: user?.tenantId,
});
}

View file

@ -126,18 +126,22 @@ export async function getOrComputeToolTokens({
provider,
clientOptions,
tokenCounter,
tenantId,
}: {
tools?: GenericTool[];
toolDefinitions?: LCTool[];
provider: Providers;
clientOptions?: ClientOptions;
tokenCounter: TokenCounter;
tenantId?: string;
}): Promise<number> {
const schemas = collectToolSchemas(tools, toolDefinitions);
if (schemas.size === 0) {
return 0;
}
const keyPrefix = tenantId ? `${tenantId}:` : '';
let cache: Keyv | undefined;
try {
cache = getCache();
@ -149,11 +153,12 @@ export async function getOrComputeToolTokens({
const toWrite: Array<{ key: string; value: number }> = [];
for (const [name, json] of schemas) {
const cacheKey = `${keyPrefix}${name}`;
let rawCount: number | undefined;
if (cache) {
try {
rawCount = (await cache.get(name)) as number | undefined;
rawCount = (await cache.get(cacheKey)) as number | undefined;
} catch {
// Cache read failed for this tool — will compute fresh
}
@ -162,7 +167,7 @@ export async function getOrComputeToolTokens({
if (rawCount == null || rawCount <= 0) {
rawCount = tokenCounter(new SystemMessage(json));
if (rawCount > 0 && cache) {
toWrite.push({ key: name, value: rawCount });
toWrite.push({ key: cacheKey, value: rawCount });
}
}