33
44import asyncpg
55
6- from api .config import settings
7- from api .services .security import api_key_hashes_match , generate_api_key , hash_api_key
6+ from api .config import settings
7+ from api .services .provider_keys import normalize_provider_name
8+ from api .services .security import api_key_hashes_match , encrypt_provider_key , generate_api_key , hash_api_key
89
9- from api .services .provider_keys import (
10- ProviderConfigError ,
11- normalize_provider_name ,
12- )
13- from api .services .security import encrypt_provider_key
1410
11+ _USER_COLUMNS : str = (
12+ "id, external_id, api_key_hash, created_at, max_memories_injected, "
13+ "retrieval_threshold, dedup_threshold, extraction_provider, "
14+ "extraction_model, openai_api_key_encrypted, gemini_api_key_encrypted, anthropic_api_key_encrypted"
15+ )
1516
16- _USER_COLUMNS : str = (
17- "id, external_id, api_key_hash, created_at, max_memories_injected, "
18- "retrieval_threshold, dedup_threshold, extraction_provider, "
19- "openai_api_key_encrypted, gemini_api_key_encrypted, anthropic_api_key_encrypted"
20- )
2117
22-
23- _PROVIDER_KEY_ENCRYPTED_COLUMNS : dict [str , str ] = {
24- "openai" : "openai_api_key_encrypted" ,
25- "gemini" : "gemini_api_key_encrypted" ,
26- "anthropic" : "anthropic_api_key_encrypted" ,
27- }
28-
29-
30- class CachedUser (TypedDict ):
18+ class CachedUser (TypedDict ):
3119 id : object
3220 external_id : str
3321 api_key_hash : str
3422 created_at : object
3523 max_memories_injected : int
3624 retrieval_threshold : float
37- dedup_threshold : float
38- extraction_provider : str
39- cached_at : float
25+ dedup_threshold : float
26+ extraction_provider : str
27+ extraction_model : str
28+ cached_at : float
4029
4130
4231_user_auth_cache : dict [str , CachedUser ] = {}
@@ -111,9 +100,9 @@ async def get_user_by_api_key(api_key: str, db: asyncpg.Connection) -> asyncpg.R
111100 row = await db .fetchrow (
112101 f"""
113102 SELECT users.id, users.external_id, user_api_keys.api_key_hash, users.created_at,
114- users.max_memories_injected, users.retrieval_threshold, users.dedup_threshold,
115- users.extraction_provider,
116- users.openai_api_key_encrypted, users.gemini_api_key_encrypted, users.anthropic_api_key_encrypted
103+ users.max_memories_injected, users.retrieval_threshold, users.dedup_threshold,
104+ users.extraction_provider, users.extraction_model,
105+ users.openai_api_key_encrypted, users.gemini_api_key_encrypted, users.anthropic_api_key_encrypted
117106 FROM user_api_keys
118107 JOIN users ON users.id = user_api_keys.user_id
119108 WHERE user_api_keys.api_key_hash = $1
@@ -248,19 +237,25 @@ async def get_user_provider_config(user_id: object, db: asyncpg.Connection) -> d
248237
249238
250239async def update_user_provider_config (
251- user_id : object ,
252- extraction_provider : str | None ,
253- openai_api_key : str | None ,
240+ user_id : object ,
241+ extraction_provider : str | None ,
242+ extraction_model : str | None ,
243+ openai_api_key : str | None ,
254244 gemini_api_key : str | None ,
255245 anthropic_api_key : str | None ,
256246 clear_openai_key : bool ,
257247 clear_gemini_key : bool ,
258248 clear_anthropic_key : bool ,
259249 db : asyncpg .Connection ,
260250) -> dict [str , object ]:
261- chosen_provider : str | None = None
262- if extraction_provider is not None :
263- chosen_provider = normalize_provider_name (extraction_provider )
251+ chosen_provider : str | None = None
252+ if extraction_provider is not None :
253+ chosen_provider = normalize_provider_name (extraction_provider )
254+ clean_extraction_model : str | None = None
255+ if extraction_model is not None :
256+ clean_extraction_model = extraction_model .strip ()
257+ if not clean_extraction_model :
258+ raise ValueError ("Extraction model is required" )
264259
265260 openai_blob : object = _SENTINEL_NO_UPDATE
266261 gemini_blob : object = _SENTINEL_NO_UPDATE
@@ -280,11 +275,14 @@ async def update_user_provider_config(
280275
281276 assignments : list [str ] = []
282277 params : list [object ] = []
283- if chosen_provider is not None :
284- assignments .append ("extraction_provider = $" + str (len (params ) + 2 ))
285- params .append (chosen_provider )
286- if openai_blob is not _SENTINEL_NO_UPDATE :
287- assignments .append ("openai_api_key_encrypted = $" + str (len (params ) + 2 ))
278+ if chosen_provider is not None :
279+ assignments .append ("extraction_provider = $" + str (len (params ) + 2 ))
280+ params .append (chosen_provider )
281+ if clean_extraction_model is not None :
282+ assignments .append ("extraction_model = $" + str (len (params ) + 2 ))
283+ params .append (clean_extraction_model )
284+ if openai_blob is not _SENTINEL_NO_UPDATE :
285+ assignments .append ("openai_api_key_encrypted = $" + str (len (params ) + 2 ))
288286 params .append (openai_blob )
289287 if gemini_blob is not _SENTINEL_NO_UPDATE :
290288 assignments .append ("gemini_api_key_encrypted = $" + str (len (params ) + 2 ))
@@ -318,19 +316,21 @@ def cache_user_auth(api_key_hash: str, row: asyncpg.Record | dict[str, object])
318316 prune_user_auth_cache ()
319317 max_memories_injected = get_row_value (row , "max_memories_injected" , settings .max_memories_injected )
320318 retrieval_threshold = get_row_value (row , "retrieval_threshold" , settings .retrieval_threshold )
321- dedup_threshold = get_row_value (row , "dedup_threshold" , settings .dedup_threshold )
322- extraction_provider = get_row_value (row , "extraction_provider" , settings .extraction_provider )
323- _user_auth_cache [api_key_hash ] = {
319+ dedup_threshold = get_row_value (row , "dedup_threshold" , settings .dedup_threshold )
320+ extraction_provider = get_row_value (row , "extraction_provider" , settings .extraction_provider )
321+ extraction_model = get_row_value (row , "extraction_model" , settings .extraction_model )
322+ _user_auth_cache [api_key_hash ] = {
324323 "id" : row ["id" ],
325324 "external_id" : row ["external_id" ],
326325 "api_key_hash" : api_key_hash ,
327326 "created_at" : row ["created_at" ],
328327 "max_memories_injected" : int (max_memories_injected ),
329328 "retrieval_threshold" : float (retrieval_threshold ),
330- "dedup_threshold" : float (dedup_threshold ),
331- "extraction_provider" : str (extraction_provider ),
332- "cached_at" : monotonic (),
333- }
329+ "dedup_threshold" : float (dedup_threshold ),
330+ "extraction_provider" : str (extraction_provider ),
331+ "extraction_model" : str (extraction_model ),
332+ "cached_at" : monotonic (),
333+ }
334334 trim_user_auth_cache ()
335335
336336
0 commit comments