Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,6 @@ jest.mock('@/lib/constants', () => ({
APP_URL: 'https://app.kilo.ai',
}));

jest.mock('@/lib/redis', () => ({
redisClient: {
get: jest.fn(),
set: jest.fn(),
},
}));

import type { AdminSlackNotification } from '@/lib/slack/admin-notifications';
import {
alertIfSyncProvidersStale,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { captureException } from '@sentry/nextjs';
import { ai_gateway_sync_providers_state } from '@kilocode/db/schema';
import { APP_URL } from '@/lib/constants';
import { db } from '@/lib/drizzle';
import { redisClient } from '@/lib/redis';
import { SYNC_PROVIDERS_STALE_ALERT_LAST_POSTED_AT_REDIS_KEY } from '@/lib/redis-keys';
import {
sendAdminSlackNotification,
type AdminSlackNotification,
Expand Down Expand Up @@ -187,8 +185,8 @@ async function defaultGetLastAlertAt(): Promise<string | null> {
return row?.lastAlertAt ?? null;
}

async function defaultSetLastAlertAt(iso: string): Promise<unknown> {
return db.transaction(async tx => {
async function defaultSetLastAlertAt(iso: string): Promise<void> {
await db.transaction(async tx => {
await tx.insert(ai_gateway_sync_providers_state).values({ id: 1 }).onConflictDoNothing();
const [row] = await tx
.select({ lastAlertAt: ai_gateway_sync_providers_state.stale_alert_last_posted_at })
Expand All @@ -204,9 +202,6 @@ async function defaultSetLastAlertAt(iso: string): Promise<unknown> {
.update(ai_gateway_sync_providers_state)
.set({ stale_alert_last_posted_at: latestIso })
.where(eq(ai_gateway_sync_providers_state.id, 1));
return redisClient.set(SYNC_PROVIDERS_STALE_ALERT_LAST_POSTED_AT_REDIS_KEY, latestIso, {
ex: SYNC_PROVIDERS_STALE_ALERT_TTL_SECONDS,
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ import { logAutoModelChangesForAllOrgs } from '@/lib/organizations/auto-model-ch
import type { Provider } from '@/lib/ai-gateway/providers/types';
import type { StoredModel } from '@kilocode/db/schema-types';
import { EndpointsSchema, ModelsSchema } from '@kilocode/db/schema-types';
import { redisClient } from '@/lib/redis';
import {
AI_GATEWAY_STATE_REDIS_TTL_SECONDS,
SYNC_PROVIDERS_LAST_COMPLETED_AT_REDIS_KEY,
} from '@/lib/redis-keys';
import { syncDirectByokModels } from '@/lib/ai-gateway/providers/direct-byok/sync-direct-byok';
import { ATTRIBUTION_HEADERS } from '@/lib/ai-gateway/providers/openrouter/attribution-headers';
import {
Expand Down Expand Up @@ -411,9 +406,6 @@ export async function syncAndStoreProviders() {
.update(ai_gateway_sync_providers_state)
.set({ last_completed_at: completedAt })
.where(eq(ai_gateway_sync_providers_state.id, 1));
await redisClient.set(SYNC_PROVIDERS_LAST_COMPLETED_AT_REDIS_KEY, completedAt, {
ex: AI_GATEWAY_STATE_REDIS_TTL_SECONDS,
});
return completedAt;
});

Expand Down
13 changes: 0 additions & 13 deletions apps/web/src/lib/ai-gateway/request-logging-opt-ins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@ import * as z from 'zod';
import { ai_gateway_request_logging_opt_ins } from '@kilocode/db/schema';
import { createCachedFetch } from '@/lib/cached-fetch';
import { db } from '@/lib/drizzle';
import { redisClient } from '@/lib/redis';
import {
AI_GATEWAY_STATE_REDIS_TTL_SECONDS,
REQUEST_LOGGING_OPT_INS_REDIS_KEY,
} from '@/lib/redis-keys';
import { eq } from 'drizzle-orm';

export const RequestLoggingOptInSchema = z.object({
Expand Down Expand Up @@ -50,12 +45,6 @@ const getCachedRequestLoggingOptIns = createCachedFetch<RequestLoggingOptIn[]>(
[]
);

async function mirrorRequestLoggingOptInsToRedis(optIns: RequestLoggingOptIn[]): Promise<void> {
await redisClient.set(REQUEST_LOGGING_OPT_INS_REDIS_KEY, JSON.stringify(optIns), {
ex: AI_GATEWAY_STATE_REDIS_TTL_SECONDS,
});
}

export async function createRequestLoggingOptIn(
entry: RequestLoggingOptIn
): Promise<'created' | 'duplicate' | 'full'> {
Expand Down Expand Up @@ -88,7 +77,6 @@ export async function createRequestLoggingOptIn(
.update(ai_gateway_request_logging_opt_ins)
.set({ opt_ins: updatedOptIns })
.where(eq(ai_gateway_request_logging_opt_ins.id, 1));
await mirrorRequestLoggingOptInsToRedis(updatedOptIns);
return 'created' as const;
});
}
Expand All @@ -110,7 +98,6 @@ export async function deleteRequestLoggingOptIn(id: string): Promise<boolean> {
.update(ai_gateway_request_logging_opt_ins)
.set({ opt_ins: remaining })
.where(eq(ai_gateway_request_logging_opt_ins.id, 1));
await mirrorRequestLoggingOptInsToRedis(remaining);
return true;
});
}
Expand Down
16 changes: 1 addition & 15 deletions apps/web/src/lib/redis-keys.test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
import { describe, expect, test } from '@jest/globals';
import {
gitLabOAuthCredentialsRedisKey,
REQUEST_LOGGING_OPT_INS_REDIS_KEY,
SYNC_PROVIDERS_STALE_ALERT_LAST_POSTED_AT_REDIS_KEY,
} from './redis-keys';
import { gitLabOAuthCredentialsRedisKey } from './redis-keys';

describe('Redis key namespaces', () => {
test('groups GitLab OAuth credentials under auth credentials', () => {
expect(gitLabOAuthCredentialsRedisKey('ref-123')).toBe('auth-credentials:gitlab:ref-123');
});

test('uses one key for the request logging opt-in array', () => {
expect(REQUEST_LOGGING_OPT_INS_REDIS_KEY).toBe('ai-gateway:request-logging-opt-ins');
});

test('stores the stale sync-providers alert timestamp under ai-gateway', () => {
expect(SYNC_PROVIDERS_STALE_ALERT_LAST_POSTED_AT_REDIS_KEY).toBe(
'ai-gateway:sync-providers:stale-alert-last-posted-at'
);
});
});
14 changes: 0 additions & 14 deletions apps/web/src/lib/redis-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,6 @@ const redisKey = <const Key extends string>(key: Key): Key & RedisKey => key as

export const BLACKLIST_DOMAINS_REDIS_KEY = redisKey('admin:blacklisted-domains');

export const AI_GATEWAY_STATE_REDIS_TTL_SECONDS = 7 * 24 * 60 * 60;

export const VERCEL_ROUTING_REDIS_KEY = redisKey('ai-gateway:vercel-routing-percentage');

export const SYNC_PROVIDERS_LAST_COMPLETED_AT_REDIS_KEY = redisKey(
'ai-gateway:sync-providers:last-completed-at'
);

export const SYNC_PROVIDERS_STALE_ALERT_LAST_POSTED_AT_REDIS_KEY = redisKey(
'ai-gateway:sync-providers:stale-alert-last-posted-at'
);

export const posthogQueryRedisKey = (name: string) => redisKey(`posthog-query:${name}`);

export const codingPlanUsageRedisKey = (input: {
Expand All @@ -46,8 +34,6 @@ export const LEADERBOARD_MODEL_PROVIDER_USAGE_REDIS_KEY = redisKey(
export const LEADERBOARD_MODEL_USAGE_REDIS_KEY = redisKey('public-api:leaderboard-model-usage');
export const LEADERBOARD_PROVIDER_RACE_REDIS_KEY = redisKey('public-api:leaderboard-provider-race');

export const REQUEST_LOGGING_OPT_INS_REDIS_KEY = redisKey('ai-gateway:request-logging-opt-ins');

export const abuseRulesClassificationRedisKey = (identityKey: string) =>
redisKey(`ai-gateway.abuse-rules:last-classification:${identityKey}`);

Expand Down
20 changes: 3 additions & 17 deletions apps/web/src/routers/admin/gateway-config-router.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { adminProcedure, createTRPCRouter } from '@/lib/trpc/init';
import { redisClient } from '@/lib/redis';
import {
GatewayConfigSchema,
GatewayConfigInputSchema,
DEFAULT_GATEWAY_CONFIG,
} from '@/lib/ai-gateway/gateway-config';
import { AI_GATEWAY_STATE_REDIS_TTL_SECONDS, VERCEL_ROUTING_REDIS_KEY } from '@/lib/redis-keys';
import type { GatewayConfig } from '@/lib/ai-gateway/gateway-config';
import { TRPCError } from '@trpc/server';
import { ai_gateway_config } from '@kilocode/db/schema';
import { db } from '@/lib/drizzle';
import { eq } from 'drizzle-orm';
Expand Down Expand Up @@ -47,20 +44,9 @@ export const adminGatewayConfigRouter = createTRPCRouter({
updated_by_email: ctx.user.google_user_email,
note: input.note,
};
await db.transaction(async tx => {
await tx.insert(ai_gateway_config).values({ config }).onConflictDoUpdate({
target: ai_gateway_config.id,
set: { config },
});
const written = await redisClient.set(VERCEL_ROUTING_REDIS_KEY, JSON.stringify(config), {
ex: AI_GATEWAY_STATE_REDIS_TTL_SECONDS,
});
if (!written) {
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'Redis is not configured — cannot mirror routing override',
});
}
await db.insert(ai_gateway_config).values({ config }).onConflictDoUpdate({
target: ai_gateway_config.id,
set: { config },
});
return config;
}),
Expand Down