§
    éƒtjkw  ã                  óò  — U d Z ddlmZ ddlZddlZddlZddlmZmZ ddlm	Z	 ddl
mZmZ i Zded<   i Zd	ed
<   dZdmd„Zdndod„Zdpdqd„Zdrd„Zdsd„Zdtd„Zdud „Zdd!œdvd#„Zd$d%d&d'd(œdwd*„Zdxd+„Zdyd,„Zdzd-„Zd{d/„Zd|d1„Zdd2œd}d6„Zd~d8„Z dndd9„Z!ddddddddddd:œ
d€dF„Z"d�dG„Z#dnd‚dI„Z$dddJdddKdLœdƒdT„Z%dnd„dU„Z&d…dV„Z'd†dW„Z(d…dX„Z)d‡dZ„Z*d[d\œdˆd_„Z+d‰d`„Z,ddddddaœdŠdb„Z-d‹dc„Z.dŒdf„Z/d…dg„Z0d�di„Z1dŽdk„Z2d�dl„Z3dS )�zKSaaS multi-tenant schema and helpers (Postgres or SQLite via app.database).é    )ÚannotationsN)ÚdatetimeÚtimezone)ÚAny)Úget_connectionÚtable_columnsz'dict[str, tuple[float, dict[str, Any]]]Ú_AGENT_CACHEz-dict[str, tuple[float, list[dict[str, Any]]]]Ú_DOCS_CACHEg      >@ÚreturnÚstrc                 ób   — t          j        t          j        ¦  «                             ¦   «         S ©N)r   Únowr   ÚutcÚ	isoformat© ó    ú'/var/www/html/CA-Chatbot/app/saas/db.pyÚ_nowr      s    € ÝŒ<�œÑ%Ô%×/Ò/Ñ1Ô1Ð1r   Úagent_idú
str | NoneÚNonec                óv   — | rt                                | d ¦  «         d S t                                ¦   «          d S r   )r	   ÚpopÚclear©r   s    r   Úinvalidate_agent_cacher      s>   € Øð Ý×Ò˜ 4Ñ(Ô(Ð(Ð(Ð(å×ÒÑÔÐÐÐr   Úorg_idc                ó  — | rA|r?t                                | › d|› �d ¦  «         t                                | › d�d ¦  «         nh| rM| › d�}t          t           ¦  «        D ]2}|                     |¦  «        rt                                |d ¦  «         Œ3nt                                ¦   «          	 ddlm} ddlm} | r|r|                     | › d|› �d ¦  «         n| s|                     ¦   «           || |¦  «         d S # t          $ r Y d S w xY w)Nú:r   )Ú_JOBS_LIST_CACHE)Úinvalidate_knowledge_cache)
r
   r   ÚlistÚ
startswithr   Úapp.saas.kb_answerr!   Úapp.saas.knowledge_stater"   Ú	Exception)r   r   ÚprefixÚkeyr!   r"   s         r   Úinvalidate_docs_cacher*      sp  € Øð 	�(ð 	Ý�Š˜6Ð.Ð. HÐ.Ð.°Ñ5Ô5Ð5Ý�Š˜6˜˜˜ dÑ+Ô+Ð+Ð+Ø	ð Ø���ˆÝ�Ñ$Ô$ð 	+ð 	+ˆCØ�~Š~˜fÑ%Ô%ð +Ý—’  TÑ*Ô*Ð*øð	+õ 	×ÒÑÔÐð
Ø7Ð7Ð7Ð7Ð7Ð7ØGÐGÐGÐGÐGÐGàð 	%�hð 	%Ø× Ò  FÐ!7Ð!7¨XÐ!7Ð!7¸Ñ>Ô>Ð>Ð>Øð 	%Ø×"Ò"Ñ$Ô$Ð$Ø"Ð" 6¨8Ñ4Ô4Ð4Ð4Ð4øÝð ð ð Øˆˆðøøøs   Â-AC= Ã=
DÄ
DÚrowr   c                óf   — t          t          | t          ¦  «        r| d         n| d         ¦  «        S )NÚidr   )r   Ú
isinstanceÚdict)r+   s    r   Ú_row_idr0   7   s+   € Ý�J s­DÑ1Ô1Ð=ˆs�4Œyˆy°s¸1´vÑ>Ô>Ð>r   c                 ó  — t          ¦   «         5 } |                      d¦  «         	 t          | d¦  «        }d|v rd|v r|                      d¦  «         n# t          $ r Y nw xY wt          | d¦  «        }d|vr|                      d¦  «         |                      d	¦  «         d
D ]4\  }}||vr+|                      d|› d|› �¦  «         t          | d¦  «        }Œ5t          | d¦  «        }d|vr|                      d¦  «         d„ |                      d¦  «                             ¦   «         D ¦   «         }|D ]¨}|                      d|f¦  «                             ¦   «         }|rŒ.|                      d|f¦  «                             ¦   «         }	|	p(|                      d|f¦  «                             ¦   «         }
|
r$|                      dt          |
¦  «        f¦  «         Œ©	 d d d ¦  «         n# 1 swxY w Y   ddlm	}  |¦   «          d S )NuŽ  
            -- saas_users (not "users") â€” avoids collision with chat-companion on shared Postgres
            CREATE TABLE IF NOT EXISTS saas_users (
                id            TEXT PRIMARY KEY,
                email         TEXT NOT NULL UNIQUE,
                password_hash TEXT NOT NULL,
                full_name     TEXT,
                created_at    TEXT NOT NULL
            );

            CREATE TABLE IF NOT EXISTS orgs (
                id            TEXT PRIMARY KEY,
                name          TEXT NOT NULL,
                slug          TEXT NOT NULL UNIQUE,
                plan          TEXT NOT NULL DEFAULT 'free',
                kb_mode       TEXT NOT NULL DEFAULT 'tenant',
                created_at    TEXT NOT NULL
            );

            CREATE TABLE IF NOT EXISTS memberships (
                id         TEXT PRIMARY KEY,
                user_id    TEXT NOT NULL REFERENCES saas_users(id),
                org_id     TEXT NOT NULL REFERENCES orgs(id),
                role       TEXT NOT NULL DEFAULT 'owner',
                created_at TEXT NOT NULL,
                UNIQUE(user_id, org_id)
            );

            CREATE TABLE IF NOT EXISTS kb_documents (
                id            TEXT PRIMARY KEY,
                org_id        TEXT NOT NULL REFERENCES orgs(id),
                filename      TEXT NOT NULL,
                content_type  TEXT,
                status        TEXT NOT NULL DEFAULT 'pending',
                chunk_count   INTEGER DEFAULT 0,
                error         TEXT,
                uploaded_by   TEXT REFERENCES saas_users(id),
                created_at    TEXT NOT NULL,
                updated_at    TEXT NOT NULL
            );

            CREATE TABLE IF NOT EXISTS api_keys (
                id          TEXT PRIMARY KEY,
                org_id      TEXT NOT NULL REFERENCES orgs(id),
                name        TEXT NOT NULL,
                key_prefix  TEXT NOT NULL,
                key_hash    TEXT NOT NULL,
                created_by  TEXT REFERENCES saas_users(id),
                created_at  TEXT NOT NULL,
                last_used   TEXT,
                revoked     INTEGER DEFAULT 0
            );

            CREATE TABLE IF NOT EXISTS agents (
                id            TEXT PRIMARY KEY,
                org_id        TEXT NOT NULL REFERENCES orgs(id),
                name          TEXT NOT NULL,
                description   TEXT,
                avatar_path   TEXT,
                kb_mode       TEXT NOT NULL DEFAULT 'tenant',
                welcome_message TEXT,
                is_main       INTEGER NOT NULL DEFAULT 0,
                created_by    TEXT REFERENCES saas_users(id),
                created_at    TEXT NOT NULL,
                updated_at    TEXT NOT NULL
            );

            CREATE INDEX IF NOT EXISTS idx_memberships_user ON memberships(user_id);
            CREATE INDEX IF NOT EXISTS idx_memberships_org ON memberships(org_id);
            CREATE INDEX IF NOT EXISTS idx_kb_docs_org ON kb_documents(org_id);
            CREATE INDEX IF NOT EXISTS idx_api_keys_org ON api_keys(org_id);
            CREATE INDEX IF NOT EXISTS idx_agents_org ON agents(org_id);
            ÚusersÚ	full_nameÚemaila  
                    INSERT INTO saas_users(id, email, password_hash, full_name, created_at)
                    SELECT id, email, password_hash, full_name, created_at FROM users
                    WHERE id NOT IN (SELECT id FROM saas_users)
                    Úkb_documentsr   z1ALTER TABLE kb_documents ADD COLUMN agent_id TEXTzFCREATE INDEX IF NOT EXISTS idx_kb_docs_agent ON kb_documents(agent_id)))Úprogress_pctúINTEGER DEFAULT 0)Úprogress_stageÚTEXT)Ú
page_countr7   )Úpages_processedr7   )Úchunks_createdr7   )Úembeddings_doner7   )Úvectors_storedr7   z$ALTER TABLE kb_documents ADD COLUMN Ú ÚagentsÚis_mainz@ALTER TABLE agents ADD COLUMN is_main INTEGER NOT NULL DEFAULT 0c                ó,   — g | ]}t          |¦  «        ‘ŒS r   )r0   ©Ú.0Úrs     r   ú
<listcomp>z$init_saas_tables.<locals>.<listcomp>­   s   € ÐVÐVÐV !•7˜1‘:”:ÐVÐVÐVr   zSELECT id FROM orgsz>SELECT id FROM agents WHERE org_id = ? AND is_main = 1 LIMIT 1z_SELECT id FROM agents WHERE org_id = ? AND lower(name) = 'alex' ORDER BY created_at ASC LIMIT 1zFSELECT id FROM agents WHERE org_id = ? ORDER BY created_at ASC LIMIT 1ú9UPDATE agents SET is_main = 1, name = 'Alex' WHERE id = ?r   )Úinit_fdi_tables)
r   Úexecutescriptr   Úexecuter'   ÚfetchallÚfetchoner0   Úapp.fdi.schemarH   )ÚconnÚlegacyÚcolsÚcolÚdeclÚ
agent_colsÚorg_idsÚoidÚmainÚalexÚpickrH   s               r   Úinit_saas_tablesrY   ;   sì  € Ý	Ñ	Ô	ð E˜TØ×ÒðHñJ	
ô J	
ð J	
ðX	Ý" 4¨Ñ1Ô1ˆFØ˜fÐ$Ð$¨°FÐ):Ð):Ø—’ðñô ð øøõ ð 	ð 	ð 	ØˆDð	øøøõ ˜T >Ñ2Ô2ˆØ˜TÐ!Ð!Ø�LŠLÐLÑMÔMÐMØ�ŠØTñ	
ô 	
ð 	
ð
ð 	;ð 	;‰IˆC�ð ˜$ˆˆØ—’ÐPÀCÐPÐPÈ$ÐPÐPÑQÔQÐQÝ$ T¨>Ñ:Ô:�øÝ" 4¨Ñ2Ô2ˆ
Ø˜JÐ&Ð&Ø�LŠLÐ[Ñ\Ô\Ð\àVÐV t§|¢|Ð4IÑ'JÔ'J×'SÒ'SÑ'UÔ'UÐVÑVÔVˆØð 	ð 	ˆCØ—<’<ØPØ�ñô ÷ Šh‰jŒjð ð ð ØØ—<’<ØqØ�ñô ÷ Šh‰jŒjð ð ð ˜4Ÿ<š<ØXØ�ñô ÷ Šh‰jŒjð ð ð Ø—’ØOÝ˜T‘]”]Ð$ñô ð øð!	ðeEð Eð Eñ Eô Eð Eð Eð Eð Eð Eð Eøøøð Eð Eð Eð EðP /Ð.Ð.Ð.Ð.Ð.à€OÑÔÐÐÐs5   �G+¦-AÁG+Á
A!ÁG+Á A!Á!E=G+Ç+G/Ç2G/r4   Úpassword_hashr3   Úorg_nameúdict[str, Any]c           
     óÜ  — t          t          j        ¦   «         ¦  «        }t          t          j        ¦   «         ¦  «        }t          t          j        ¦   «         ¦  «        }t          ¦   «         }d                     d„ |D ¦   «         ¦  «                             d¦  «        pd}|d d…         › dt          j        d¦  «        › �}	t          ¦   «         5 }
|
 	                    d||  
                    ¦   «                              ¦   «         ||                     ¦   «         |f¦  «         |
 	                    d||                     ¦   «         |	d	d
|f¦  «         |
 	                    d|||d|f¦  «         d d d ¦  «         n# 1 swxY w Y   t          |dd|d
dd¬¦  «         ||  
                    ¦   «                              ¦   «         |                     ¦   «         ||                     ¦   «         |	dd
d	dœ	S )NÚ c              3  ój   K  — | ].}|                      ¦   «         r|                     ¦   «         nd V — Œ/dS )Ú-N)ÚisalnumÚlower)rD   Úcs     r   ú	<genexpr>z'create_user_with_org.<locals>.<genexpr>Ô   s;   è è € ÐLÐL¸a Q§Y¢Y¡[¤[Ð9˜Ÿš™	œ	˜	°cÐLÐLÐLÐLÐLÐLr   r`   Úorgé(   é   zZINSERT INTO saas_users(id, email, password_hash, full_name, created_at) VALUES (?,?,?,?,?)zPINSERT INTO orgs(id, name, slug, plan, kb_mode, created_at) VALUES (?,?,?,?,?,?)ÚfreeÚtenantzQINSERT INTO memberships(id, user_id, org_id, role, created_at) VALUES (?,?,?,?,?)ÚownerÚAlexú*Your main accounting and finance assistantõl   Hello! I'm Alex â€” your accounting assistant. Ask about spend, merchants, or upload documents in Knowledge.T©r   ÚnameÚdescriptionÚ
created_byÚkb_modeÚwelcome_messagerA   )	Úuser_idr4   r3   r   r[   Úorg_slugÚrolerr   Úplan)r   ÚuuidÚuuid4r   ÚjoinÚstripÚsecretsÚ	token_hexr   rJ   rb   Úcreate_agent)r4   rZ   r3   r[   rt   r   Úmembership_idr   Ú	slug_baseÚslugrN   s              r   Úcreate_user_with_orgr‚   É   s'  € õ •$”*‘,”,ÑÔ€GÝ•”‘”ÑÔ€FÝ�œ
™œÑ%Ô%€MÝ
‰&Œ&€CØ—’ÐLÐLÀ8ÐLÑLÔLÑLÔL×RÒRÐSVÑWÔWÐ`Ð[`€IØ˜˜˜ŒnÐ5Ð5�wÔ0°Ñ3Ô3Ð5Ð5€Då	Ñ	Ô	ð 
˜TØ�ŠØhØ�e—k’k‘m”m×)Ò)Ñ+Ô+¨]¸I¿OºOÑ<MÔ<MÈsÐSñ	
ô 	
ð 	
ð 	�ŠØ^Ø�X—^’^Ñ%Ô% t¨V°X¸sÐCñ	
ô 	
ð 	
ð 	�ŠØ_Ø˜G V¨W°cÐ:ñ	
ô 	
ð 	
ð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
õ ØØØ@ØØð GØðñ ô ð ð Ø—’‘”×$Ò$Ñ&Ô&Ø—_’_Ñ&Ô&ØØ—N’NÑ$Ô$ØØØØð
ð 
ð 
s   ÃBE9Å9E=Æ E=údict[str, Any] | Nonec                ó  — t          ¦   «         5 }|                     d|                      ¦   «                              ¦   «         f¦  «                             ¦   «         }|rt          |¦  «        nd cd d d ¦  «         S # 1 swxY w Y   d S )Nz(SELECT * FROM saas_users WHERE email = ?)r   rJ   rb   r{   rL   r/   )r4   rN   r+   s      r   Úget_user_by_emailr…   ý   sÁ   € Ý	Ñ	Ô	ð *˜TØ�lŠlØ6Ø�[Š[‰]Œ]× Ò Ñ"Ô"Ð$ñ
ô 
÷ Š(‰*Œ*ð 	ð  Ð)�t�C‰yŒyˆy Tð*ð *ð *ð *ñ *ô *ð *ð *ð *ð *ð *ð *øøøð *ð *ð *ð *ð *ð *s   �A A<Á<B ÂB ©r3   rt   c               óà   — t          ¦   «         5 }|�,|                     d||                     ¦   «         | f¦  «         n|                     d|| f¦  «         d d d ¦  «         d S # 1 swxY w Y   d S )NzCUPDATE saas_users SET password_hash = ?, full_name = ? WHERE id = ?z4UPDATE saas_users SET password_hash = ? WHERE id = ?)r   rJ   r{   )rt   rZ   r3   rN   s       r   Úupdate_user_passwordrˆ     sÊ   € Ý	Ñ	Ô	ð 
˜TØÐ Ø�LŠLØUØ 	§¢Ñ 1Ô 1°7Ð;ñô ð ð ð
 �LŠLØFØ Ð(ñô ð ð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
ð 
ð 
s   �AA#Á#A'Á*A'zadmin@gmail.comzThetitan@1234ÚAdminzAdmin Workspace)r4   Úpasswordr3   r[   rŠ   c                ó€  — ddl m} t          | ¦  «        } ||¦  «        }|r‚t          |d         ||¬¦  «         t	          |d         ¦  «        }|r#t          |d         d         |d         ¬¦  «         |d         |                      ¦   «                              ¦   «         ddœS t          | |||¬¦  «        }i |¥d	d
i¥S )z:Create or refresh the demo admin login used by the studio.r   )Úhash_passwordr-   r†   )rq   F)rt   r4   Úcreated)r4   rZ   r3   r[   r�   T)	Úapp.saas.securityrŒ   r…   rˆ   Úlist_user_orgsÚensure_main_agentrb   r{   r‚   )	r4   rŠ   r3   r[   rŒ   ÚexistingÚpwd_hashÚorgsr�   s	            r   Úensure_admin_accountr”     sí   € ð 0Ð/Ð/Ð/Ð/Ð/å  Ñ'Ô'€HØˆ}˜XÑ&Ô&€HØð ]Ý˜X dœ^¨XÀÐKÑKÔKÐKÝ˜h tœnÑ-Ô-ˆØð 	HÝ˜d 1œg dœm¸À¼ÐGÑGÔGÐGØ# Dœ>°E·K²K±M´M×4GÒ4GÑ4IÔ4IÐV[Ð\Ð\Ð\Ý"ØØØØð	ñ ô €Gð (ˆgÐ'�y $Ð'Ð'Ð'r   c                óÊ   — t          ¦   «         5 }|                     d| f¦  «                             ¦   «         }|rt          |¦  «        nd cd d d ¦  «         S # 1 swxY w Y   d S )Nz%SELECT * FROM saas_users WHERE id = ?©r   rJ   rL   r/   )rt   rN   r+   s      r   Úget_user_by_idr—   /  s£   € Ý	Ñ	Ô	ð *˜TØ�lŠlÐBÀWÀJÑOÔO×XÒXÑZÔZˆØÐ)�t�C‰yŒyˆy Tð*ð *ð *ð *ñ *ô *ð *ð *ð *ð *ð *ð *øøøð *ð *ð *ð *ð *ð *ó   �<AÁAÁAc                óÊ   — t          ¦   «         5 }|                     d| f¦  «                             ¦   «         }|rt          |¦  «        nd cd d d ¦  «         S # 1 swxY w Y   d S )NzSELECT * FROM orgs WHERE id = ?r–   )r   rN   r+   s      r   Úget_orgrš   5  s£   € Ý	Ñ	Ô	ð *˜TØ�lŠlÐ<¸v¸iÑHÔH×QÒQÑSÔSˆØÐ)�t�C‰yŒyˆy Tð*ð *ð *ð *ñ *ô *ð *ð *ð *ð *ð *ð *øøøð *ð *ð *ð *ð *ð *r˜   c                óÌ   — t          ¦   «         5 }|                     d| |f¦  «                             ¦   «         }|rt          |¦  «        nd cd d d ¦  «         S # 1 swxY w Y   d S )Nz:SELECT * FROM memberships WHERE user_id = ? AND org_id = ?r–   )rt   r   rN   r+   s       r   Úget_membershiprœ   ;  s¯   € Ý	Ñ	Ô	ð *˜TØ�lŠlØHØ�fÐñ
ô 
÷ Š(‰*Œ*ð 	ð  Ð)�t�C‰yŒyˆy Tð*ð *ð *ð *ñ *ô *ð *ð *ð *ð *ð *ð *øøøð *ð *ð *ð *ð *ð *s   �=AÁAÁ Aúlist[dict[str, Any]]c                ó¼   — t          ¦   «         5 }|                     d| f¦  «                             ¦   «         }d„ |D ¦   «         cd d d ¦  «         S # 1 swxY w Y   d S )Nz¼
            SELECT o.*, m.role
            FROM orgs o
            JOIN memberships m ON m.org_id = o.id
            WHERE m.user_id = ?
            ORDER BY o.created_at ASC
            c                ó,   — g | ]}t          |¦  «        ‘ŒS r   ©r/   rC   s     r   rF   z"list_user_orgs.<locals>.<listcomp>P  ó   € Ð&Ð&Ð&˜A•�Q‘”Ð&Ð&Ð&r   ©r   rJ   rK   )rt   rN   Úrowss      r   r�   r�   D  s¯   € Ý	Ñ	Ô	ð '˜TØ�|Š|ðð ˆJñ	
ô 	
÷ Š(‰*Œ*ð 	ð 'Ð& Ð&Ñ&Ô&ð'ð 'ð 'ð 'ñ 'ô 'ð 'ð 'ð 'ð 'ð 'ð 'øøøð 'ð 'ð 'ð 'ð 'ð 'ó   �5AÁAÁArr   c                óª   — |dvrt          d¦  «        ‚t          ¦   «         5 }|                     d|| f¦  «         d d d ¦  «         d S # 1 swxY w Y   d S )N>   ri   ÚcombinedÚplatformz-kb_mode must be platform, tenant, or combinedz(UPDATE orgs SET kb_mode = ? WHERE id = ?)Ú
ValueErrorr   rJ   )r   rr   rN   s      r   Úset_org_kb_moder©   S  s·   € ØÐ8Ð8Ð8ÝÐHÑIÔIÐIÝ	Ñ	Ô	ð T˜TØ�ŠÐ?À'È6ÐARÑSÔSÐSðTð Tð Tñ Tô Tð Tð Tð Tð Tð Tð Tð Tøøøð Tð Tð Tð Tð Tð Ts   ¢AÁAÁAr   ÚfilenameÚcontent_typeÚuploaded_byc                ó$  — t          t          j        ¦   «         ¦  «        }t          ¦   «         }t	          ¦   «         5 }|                     d|| ||||||f¦  «         d d d ¦  «         n# 1 swxY w Y   t          | |¦  «         t          |¦  «        S )NzÐ
            INSERT INTO kb_documents(id, org_id, agent_id, filename, content_type, status, chunk_count, uploaded_by, created_at, updated_at)
            VALUES (?,?,?,?,?, 'pending', 0, ?, ?, ?)
            )r   rx   ry   r   r   rJ   r*   Úget_kb_document)r   rª   r«   r¬   r   Údoc_idr   rN   s           r   Úcreate_kb_documentr°   Z  sÐ   € õ •”‘”ÑÔ€FÝ
‰&Œ&€CÝ	Ñ	Ô	ð 
˜TØ�Šðð �V˜X x°¸{ÈCÐQTÐUñ	
ô 	
ð 	
ð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
õ ˜& (Ñ+Ô+Ð+Ý˜6Ñ"Ô"Ð"s   ½A(Á(A,Á/A,r¯   c                óÊ   — t          ¦   «         5 }|                     d| f¦  «                             ¦   «         }|rt          |¦  «        nd cd d d ¦  «         S # 1 swxY w Y   d S )Nz'SELECT * FROM kb_documents WHERE id = ?r–   )r¯   rN   r+   s      r   r®   r®   p  s£   € Ý	Ñ	Ô	ð *˜TØ�lŠlÐDÀvÀiÑPÔP×YÒYÑ[Ô[ˆØÐ)�t�C‰yŒyˆy Tð*ð *ð *ð *ñ *ô *ð *ð *ð *ð *ð *ð *øøøð *ð *ð *ð *ð *ð *r˜   c                óÖ  — | › d|pd› �}t                                |¦  «        }t          j        ¦   «         }|r||d         z
  t          k     r|d         S t          ¦   «         5 }|r+|                     d| |f¦  «                             ¦   «         }n)|                     d| f¦  «                             ¦   «         }d„ |D ¦   «         }d d d ¦  «         n# 1 swxY w Y   ||ft           |<   |S )Nr    r^   r   é   z—
                SELECT * FROM kb_documents
                WHERE org_id = ? AND agent_id = ?
                ORDER BY created_at DESC
                z†
                SELECT * FROM kb_documents
                WHERE org_id = ?
                ORDER BY created_at DESC
                c                ó,   — g | ]}t          |¦  «        ‘ŒS r   r    rC   s     r   rF   z%list_kb_documents.<locals>.<listcomp>�  r¡   r   )r
   ÚgetÚtimeÚ	monotonicÚ_CACHE_TTL_Sr   rJ   rK   )r   r   Ú	cache_keyÚhitr   rN   r£   Údocss           r   Úlist_kb_documentsr¼   v  sK  € ØÐ,Ð,˜H˜N¨Ð,Ð,€IÝ
�/Š/˜)Ñ
$Ô
$€CÝ
Œ.Ñ
Ô
€CØ
ð ��c˜!”f‘¥Ò,Ð,Ø�1Œvˆå	Ñ	Ô	ð '˜TØð 	Ø—<’<ðð
 ˜Ð"ñô ÷ Šh‰jŒjð ˆDð —<’<ðð
 �	ñô ÷ Šh‰jŒjð ð 'Ð& Ð&Ñ&Ô&ˆð''ð 'ð 'ñ 'ô 'ð 'ð 'ð 'ð 'ð 'ð 'øøøð 'ð 'ð 'ð 'ð( " 4˜[…K�	ÑØ€Ks   Á#A#CÃCÃC©
ÚstatusÚchunk_countÚerrorr6   r8   r:   r;   r<   r=   r>   r¾   r¿   ú
int | NonerÀ   r6   r8   r:   r;   r<   r=   r>   c       
        óØ  — dg}t          ¦   «         g}|||||||||	|
dœ
}|                     ¦   «         D ]4\  }}|�-|                     |› d�¦  «         |                     |¦  «         Œ5|                     | ¦  «         t          ¦   «         5 }|                     dd                     |¦  «        › d�|¦  «         d d d ¦  «         n# 1 swxY w Y   t                               ¦   «          d S )Núupdated_at = ?r½   z = ?zUPDATE kb_documents SET ú, ú WHERE id = ?)r   ÚitemsÚappendr   rJ   rz   r
   r   )r¯   r¾   r¿   rÀ   r6   r8   r:   r;   r<   r=   r>   ÚfieldsÚparamsÚmappingrQ   ÚvalrN   s                    r   Úupdate_kb_documentrÌ   •  sU  € ð *Ð*€FÝ™œ˜€FàØ"ØØ$Ø(Ø Ø*Ø(Ø*Ø(ðð €Gð —M’M‘O”Oð ð ‰ˆˆSØˆ?Ø�MŠM˜S˜,˜,˜,Ñ'Ô'Ð'Ø�MŠM˜#ÑÔÐøØ
‡M‚M�&ÑÔÐÝ	Ñ	Ô	ð Z˜TØ�ŠÐP°·	²	¸&Ñ0AÔ0AÐPÐPÐPÐRXÑYÔYÐYðZð Zð Zñ Zô Zð Zð Zð Zð Zð Zð Zøøøð Zð Zð Zð Zõ ×ÒÑÔÐÐÐs   Â.CÃC
ÃC
c                ó²   — t          ¦   «         5 }|                     d| f¦  «         d d d ¦  «         n# 1 swxY w Y   t                               ¦   «          d S )Nz%DELETE FROM kb_documents WHERE id = ?)r   rJ   r
   r   )r¯   rN   s     r   Údelete_kb_documentrÎ   ¼  sŸ   € Ý	Ñ	Ô	ð I˜TØ�ŠÐ<¸v¸iÑHÔHÐHðIð Ið Iñ Iô Ið Ið Ið Ið Ið Ið Iøøøð Ið Ið Ið Iå×ÒÑÔÐÐÐs   �3³7º7Úintc                ó0  — t          ¦   «         5 }|r+|                     d| |f¦  «                             ¦   «         }n)|                     d| f¦  «                             ¦   «         }t          |r|d         nd¦  «        cd d d ¦  «         S # 1 swxY w Y   d S )Nz´
                SELECT COALESCE(SUM(chunk_count), 0) AS c
                FROM kb_documents
                WHERE org_id = ? AND agent_id = ? AND status = 'ready'
                z£
                SELECT COALESCE(SUM(chunk_count), 0) AS c
                FROM kb_documents
                WHERE org_id = ? AND status = 'ready'
                rc   r   )r   rJ   rL   rÏ   )r   r   rN   r+   s       r   Úcount_ready_kb_chunksrÑ   Â  sò   € Ý	Ñ	Ô	ð +˜TØð 	Ø—,’,ðð
 ˜Ð"ñô ÷ Šh‰jŒjð ˆCð —,’,ðð
 �	ñô ÷ Šh‰jŒjð õ ˜sÐ)�3�s”8�8¨Ñ*Ô*ð'+ð +ð +ð +ñ +ô +ð +ð +ð +ð +ð +ð +øøøð +ð +ð +ð +ð +ð +s   �A/BÂBÂBri   F)rp   rq   rr   rs   Úavatar_pathrA   ro   rp   rq   rs   rÒ   rA   Úboolc                óÐ  — t          t          j        ¦   «         ¦  «        }t          ¦   «         }	|dvrd}t	          ¦   «         5 }
|r|
                     d| f¦  «         |
                     d|| |                     ¦   «         |pd                     ¦   «         pd |||pd|                     ¦   «         › d�|rdnd	||	|	f¦  «         d d d ¦  «         n# 1 swxY w Y   t          |¦  «        S )
N>   ri   r¦   r§   ri   ú.UPDATE agents SET is_main = 0 WHERE org_id = ?zÊ
            INSERT INTO agents(id, org_id, name, description, avatar_path, kb_mode, welcome_message, is_main, created_by, created_at, updated_at)
            VALUES (?,?,?,?,?,?,?,?,?,?,?)
            r^   zHi, I'm z5. Ask me anything or feed me documents to learn from.r³   r   )r   rx   ry   r   r   rJ   r{   Ú	get_agent)r   ro   rp   rq   rr   rs   rÒ   rA   r   r   rN   s              r   r~   r~   Û  sE  € õ •4”:‘<”<Ñ Ô €HÝ
‰&Œ&€CØÐ8Ð8Ð8ØˆÝ	Ñ	Ô	ð 
˜TØð 	VØ�LŠLÐIÈFÈ9ÑUÔUÐUØ�Šðð
 ØØ—
’
‘”ØÐ" ×)Ò)Ñ+Ô+Ð3¨tØØØð bØa˜dŸjšj™lœlÐaÐaÐaØÐ#�� !ØØØðñ	
ô 	
ð 	
ð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
õ. �XÑÔÐs   ÁA?CÃCÃCc           	     óx  — t          | ¦  «        }t          d„ |D ¦   «         d¦  «        }|ro|                     d¦  «        pd                     ¦   «                              ¦   «         dk    r.t          |d         d¬¦  «         t          |d         ¦  «        p|}|S t          d	„ |D ¦   «         d¦  «        }|rot          ¦   «         5 }|                     d
| f¦  «         |                     d|d         f¦  «         ddd¦  «         n# 1 swxY w Y   t          |d         ¦  «        S t          | dd|ddd¬¦  «        S )z7Guarantee Alex exists as the main chatbot for this org.c              3  óD   K  — | ]}|                      d ¦  «        ¯|V — ŒdS )rA   N©rµ   ©rD   Úas     r   rd   z$ensure_main_agent.<locals>.<genexpr>  s3   è è € Ð7Ð7�q a§e¢e¨IÑ&6Ô&6Ð7�Ð7Ð7Ð7Ð7Ð7Ð7r   Nro   r^   rW   r-   rk   )ro   c              3  ót   K  — | ]3}|                      d ¦  «        pd                     ¦   «         dk    ¯/|V — Œ4dS )ro   r^   rW   N)rµ   rb   rÚ   s     r   rd   z$ensure_main_agent.<locals>.<genexpr>  sG   è è € ÐNÐN�q q§u¢u¨V¡}¤}Ð':¸×&AÒ&AÑ&CÔ&CÀvÒ&MÐ&M�Ð&MÐ&MÐ&MÐ&MÐNÐNr   rÕ   rG   rl   ri   rm   Trn   )
Úlist_agentsÚnextrµ   r{   rb   Úupdate_agentrÖ   r   rJ   r~   )r   rq   r@   rV   rW   rN   s         r   r�   r�     sœ  € å˜Ñ Ô €FÝÐ7Ð7˜FÐ7Ñ7Ô7¸Ñ>Ô>€DØð à�HŠH�VÑÔÐ" ×)Ò)Ñ+Ô+×1Ò1Ñ3Ô3°vÒ=Ð=Ý˜˜dœ¨&Ð1Ñ1Ô1Ð1Ý˜T $œZÑ(Ô(Ð0¨DˆDØˆÝÐNÐN˜FÐNÑNÔNÐPTÑUÔU€DØð %ÝÑÔð 	 Ø�LŠLÐIÈFÈ9ÑUÔUÐUØ�LŠLØKØ�d”�ñô ð ð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	õ ˜˜dœÑ$Ô$Ð$ÝØØØ@ØØð GØðñ ô ð s   Ã5DÄD
ÄD
c                ó4   — d„ t          | ¦  «        D ¦   «         S )z1Non-main chatbots (legacy multi-agent leftovers).c                ó<   — g | ]}|                      d ¦  «        °|‘ŒS )rA   rÙ   rÚ   s     r   rF   z%list_extra_agents.<locals>.<listcomp>$  s)   € ÐCÐCÐC�!°!·%²%¸	Ñ2BÔ2BÐCˆAÐCÐCÐCr   )rÝ   ©r   s    r   Úlist_extra_agentsrã   "  s   € àCÐC•{ 6Ñ*Ô*ÐCÑCÔCÐCr   c                ó|  — t                                | ¦  «        }t          j        ¦   «         }|r||d         z
  t          k     r|d         S t          ¦   «         5 }|                     d| f¦  «                             ¦   «         }|rt          |¦  «        nd }d d d ¦  «         n# 1 swxY w Y   |r||ft           | <   |S )Nr   r³   z!SELECT * FROM agents WHERE id = ?)	r	   rµ   r¶   r·   r¸   r   rJ   rL   r/   )r   rº   r   rN   r+   Úagents         r   rÖ   rÖ   '  sö   € Ý
×
Ò
˜8Ñ
$Ô
$€CÝ
Œ.Ñ
Ô
€CØ
ð ��c˜!”f‘¥Ò,Ð,Ø�1ŒvˆÝ	Ñ	Ô	ð +˜TØ�lŠlÐ>ÀÀÑLÔL×UÒUÑWÔWˆØ Ð*•�S‘	”	�	 dˆð+ð +ð +ñ +ô +ð +ð +ð +ð +ð +ð +øøøð +ð +ð +ð +ð ð .Ø"% u ��XÑØ€Ls   Á=B#Â#B'Â*B'c                ó¼   — t          ¦   «         5 }|                     d| f¦  «                             ¦   «         }d„ |D ¦   «         cd d d ¦  «         S # 1 swxY w Y   d S )Naž  
            SELECT a.*,
              (SELECT COUNT(DISTINCT d.filename) FROM kb_documents d WHERE d.agent_id = a.id AND d.status = 'ready') AS ready_docs,
              (SELECT COALESCE(SUM(chunk_count),0) FROM kb_documents d WHERE d.agent_id = a.id AND d.status = 'ready') AS chunk_count
            FROM agents a
            WHERE a.org_id = ?
            ORDER BY a.is_main DESC, a.created_at ASC
            c                ó,   — g | ]}t          |¦  «        ‘ŒS r   r    rC   s     r   rF   zlist_agents.<locals>.<listcomp>A  r¡   r   r¢   ©r   rN   r£   s      r   rÝ   rÝ   4  s¯   € Ý	Ñ	Ô	ð '˜TØ�|Š|ðð ˆIñ

ô 

÷ Š(‰*Œ*ð 	ð 'Ð& Ð&Ñ&Ô&ð'ð 'ð 'ð 'ñ 'ô 'ð 'ð 'ð 'ð 'ð 'ð 'øøøð 'ð 'ð 'ð 'ð 'ð 'r¤   údict[str, dict[str, int]]c                óæ  — t          ¦   «         5 }|                     d| f¦  «                             ¦   «         }ddd¦  «         n# 1 swxY w Y   i }|D �]}t          |¦  «        }t	          |                     d¦  «        pd¦  «        }|sŒ9|                     |dddddddœ¦  «        }t	          |                     d¦  «        pd¦  «        }t          |                     d	¦  «        pd¦  «        }	t          |                     d
¦  «        pd¦  «        }
||vrd||<   t          |                     |¦  «        pd¦  «        |	z   ||<   |dxx         |	z  cc<   |dk    r|d
xx         |
z  cc<   �Œ|S )zDMap agent_id -> {ready, failed, processing, pending, total, chunks}.a  
            SELECT
              agent_id,
              status,
              COUNT(*) AS n,
              COALESCE(SUM(chunk_count), 0) AS chunks
            FROM kb_documents
            WHERE org_id = ?
            GROUP BY agent_id, status
            Nr   r^   r   ©ÚreadyÚfailedÚ
processingÚpendingÚtotalÚchunksr¾   rï   Únrñ   rð   rì   )r   rJ   rK   r/   r   rµ   Ú
setdefaultrÏ   )r   rN   r£   Úoutr+   ÚdÚaidÚbucketr¾   rò   rñ   s              r   Údocument_status_countsrø   D  sÔ  € å	Ñ	Ô	ð ˜TØ�|Š|ð	ð ˆIñ
ô 
÷ Š(‰*Œ*ð 	ðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð &(€CØð 'ñ 'ˆÝ�‰IŒIˆÝ�!—%’%˜
Ñ#Ô#Ð) rÑ*Ô*ˆØð 	ØØ—’ØØ 1°AÀ!ÈaÐ[\Ð]Ð]ñ
ô 
ˆõ �Q—U’U˜8‘_”_Ð1¨	Ñ2Ô2ˆÝ�—’�c‘
”
�˜aÑ Ô ˆÝ�Q—U’U˜8‘_”_Ð)¨Ñ*Ô*ˆØ˜ÐÐØˆF�6‰NÝ˜VŸZšZ¨Ñ/Ô/Ð4°1Ñ5Ô5¸Ñ9ˆˆv‰ØˆwˆˆŒ˜1Ñˆˆ‰Ø�WÒÐØ�8ÐÐÔ Ñ&ÐÐÑùØ€Js   �*AÁA	ÁA	é   ©Údaysrû   úlist[dict[str, int | str]]c               óÐ  ‡‡‡— ddl m}mŠ t          dt	          t          |¦  «        d¦  «        ¦  «        }|                     ¦   «          ‰|dz
  ¬¦  «        z
  Š‰                     ¦   «         }t          ¦   «         5 }| 	                    d| |f¦  «         
                    ¦   «         }ddd¦  «         n# 1 swxY w Y   d„ |D ¦   «         Šˆˆˆfd	„t          |¦  «        D ¦   «         S )
z+Daily document uploads for the last N days.r   )ÚdateÚ	timedeltar³   é   rú   zú
            SELECT SUBSTR(created_at, 1, 10) AS day, COUNT(*) AS n
            FROM kb_documents
            WHERE org_id = ? AND SUBSTR(created_at, 1, 10) >= ?
            GROUP BY SUBSTR(created_at, 1, 10)
            ORDER BY day ASC
            Nc                óö   — i | ]v}t          |¦  «                             d ¦  «        ¯$t          t          |¦  «        d          ¦  «        t          t          |¦  «                             d¦  «        pd¦  «        “ŒwS )Údayrò   r   )r/   rµ   r   rÏ   rC   s     r   ú
<dictcomp>z)document_daily_counts.<locals>.<dictcomp>|  sd   € ÐbÐbÐbÀ!ÍtÐTUÉwÌwÏ{Ê{Ð[`ÑOaÔOaÐb�c•$�q‘'”'˜%”.Ñ!Ô!¥3¥t¨A¡w¤w§{¢{°3Ñ'7Ô'7Ð'<¸1Ñ#=Ô#=ÐbÐbÐbr   c           	     ó¾   •— g | ]Y}‰ ‰|¬ ¦  «        z                         ¦   «         ‰                     ‰ ‰|¬ ¦  «        z                         ¦   «         d¦  «        dœ‘ŒZS )rú   r   )rþ   Úcount)r   rµ   )rD   ÚiÚby_dayÚstartrÿ   s     €€€r   rF   z)document_daily_counts.<locals>.<listcomp>}  s   ø€ ð ð ð àð ˜)˜)¨Ð+Ñ+Ô+Ñ+×6Ò6Ñ8Ô8À6Ç:Â:ÈuÐW`ÐW`ÐfgÐWhÑWhÔWhÑOh×NsÒNsÑNuÔNuÐwxÑCyÔCyÐzÐzðð ð r   )r   rþ   rÿ   ÚmaxÚminrÏ   Útodayr   r   rJ   rK   Úrange)	r   rû   rþ   ÚcutoffrN   r£   r  r  rÿ   s	         @@@r   Údocument_daily_countsr  j  sM  øøø€ à(Ð(Ð(Ð(Ð(Ð(Ð(Ð(åˆq•#•c˜$‘i”i Ñ$Ô$Ñ%Ô%€DØ�JŠJ‰LŒL˜9˜9¨$°©(Ð3Ñ3Ô3Ñ3€EØ�_Š_ÑÔ€FÝ	Ñ	Ô	ð 
˜TØ�|Š|ðð �VÐñ	
ô 	
÷ Š(‰*Œ*ð 	ð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
ð cÐbÀtÐbÑbÔb€Fðð ð ð ð ð å�t‘”ðñ ô ð s   Á=+B4Â4B8Â;B8c                óÞ  — ddl m} t          | ¦  «        }t          | ¦  «        }|                     | ¦  «        }|                     | ¬¦  «        }g }d}d}d}	d}
d}|D �]Ä}t          |d         ¦  «        }|                     |dddddddœ¦  «        }t          |                     d¦  «        pd¦  «        t          |                     d¦  «        pd¦  «        z   }t          |                     d¦  «        pd¦  «        }t          |                     d	¦  «        pd¦  «        }t          |                     d
¦  «        p|                     d¦  «        pd¦  «        }|                     |dddddœ¦  «        }t          |d         ¦  «        t          |d         ¦  «        z   }|rt          d|d         z  |z  d¦  «        nd}||z  }||z  }|	|z  }	|
t          |                     d¦  «        pd¦  «        z  }
||z  }| 
                    ||                     d¦  «        pdt          |                     d¦  «        ¦  «        |                     d¦  «        pd|                     d¦  «        |                     d¦  «        |                     d¦  «        rd|› d�nd|||t          |                     d¦  «        pd¦  «        |dœt          |d         ¦  «        t          |d         ¦  «        t          |d         ¦  «        t          |d         ¦  «        |dœd œ	¦  «         �ŒÆt          |d         ¦  «        t          |d         ¦  «        z   }|rt          d|d         z  |z  d¦  «        nd}|                     | d!¬"¦  «        }t          | d!¬#¦  «        }t          ¦   «         t          |¦  «        t!          d$„ |D ¦   «         ¦  «        |
|||	|t          |d         ¦  «        t          |d         ¦  «        t          |d         ¦  «        t          |d         ¦  «        |d%œ||	|d&œt          |d         ¦  «        t          |d         ¦  «        d'œ||d(„ |D ¦   «         d)„ |D ¦   «         d*œ|d+œS ),z/Aggregate workspace stats for the dashboard UI.r   )Údatabaserâ   r-   rë   rî   rï   rì   rí   rñ   r¿   )ÚupÚdownrð   Úwith_correctionr  r  g      Y@r³   Nrð   ro   Ú	AssistantrA   rr   ri   Ú
created_atÚ
updated_atrÒ   z/saas/agents/z/avatar)rì   rí   rî   rð   rñ   r  )r  r  rð   r  Úsatisfaction_pct)	r-   ro   rA   rr   r  r  Ú
avatar_urlr»   Úfeedbackrù   )r   rû   rú   c              3  óD   K  — | ]}|                      d ¦  «        °dV — ŒdS )rA   r³   NrÙ   rÚ   s     r   rd   z&build_org_dashboard.<locals>.<genexpr>Ë  s3   è è € Ð KÐ K q¸!¿%º%À	Ñ:JÔ:JÐ K Ð KÐ KÐ KÐ KÐ KÐ Kr   )r@   Úcustom_agentsÚ
docs_totalÚ
docs_readyÚdocs_failedÚdocs_processingrñ   Úfeedback_upÚfeedback_downÚfeedback_totalÚfeedback_correctionsr  )rì   rî   rí   )r  r  c                óV   — g | ]&}|d          |d         d         |d         d         dœ‘Œ'S )ro   r»   rñ   rì   )ro   rñ   rì   r   rC   s     r   rF   z'build_org_dashboard.<locals>.<listcomp>ã  sI   € ð !ð !ð !àð ˜6œ¨a°¬i¸Ô.AÈAÈfÌIÐV]ÔL^Ð_Ð_ð!ð !ð !r   c                óV   — g | ]&}|d          |d         d         |d         d         dœ‘Œ'S )ro   r  r  r  )ro   r  r  r   rC   s     r   rF   z'build_org_dashboard.<locals>.<listcomp>ç  sP   € ð #ð #ð #ð ð	 ˜fœIØ˜Jœ-¨Ô-Ø˜jœM¨&Ô1ðð ð#ð #ð #r   )Úknowledge_statusÚfeedback_splitÚfeedback_timelineÚdocs_timelineÚagents_by_chunksÚagents_by_feedback)r  ÚsummaryÚchartsr@   )Úappr  rÝ   rø   Úfeedback_counts_by_agentÚfeedback_rating_countsr   rµ   rÏ   ÚroundrÇ   rÓ   Úfeedback_daily_countsr  r   ÚlenÚsum)r   Úcore_dbr@   Ú
doc_countsÚfb_by_agentÚorg_fbÚ
agent_rowsÚtotal_readyÚtotal_failedÚtotal_processingÚ
total_docsÚtotal_chunksrÛ   rö   r»   rî   rì   rí   rñ   ÚfbÚratedÚsatisfactionÚ	org_ratedÚorg_satisfactionr(  r)  s                             r   Úbuild_org_dashboardrD  ƒ  sÝ  € à'Ð'Ð'Ð'Ð'Ð'å˜Ñ Ô €FÝ'¨Ñ/Ô/€JØ×2Ò2°6Ñ:Ô:€KØ×+Ò+°6Ð+Ñ:Ô:€Fà')€JØ€KØ€LØÐØ€JØ€Làð ,
ñ ,
ˆÝ�!�D”'‰lŒlˆØ�~Š~ØØ 1°AÀ!ÈaÐ[\Ð]Ð]ñ
ô 
ˆõ ˜Ÿš ,Ñ/Ô/Ð4°1Ñ5Ô5½¸D¿HºHÀYÑ<OÔ<OÐ<TÐSTÑ8UÔ8UÑUˆ
Ý�D—H’H˜WÑ%Ô%Ð*¨Ñ+Ô+ˆÝ�T—X’X˜hÑ'Ô'Ð,¨1Ñ-Ô-ˆÝ�T—X’X˜hÑ'Ô'ÐD¨1¯5ª5°Ñ+?Ô+?ÐDÀ1ÑEÔEˆØ�_Š_˜S¨°AÀÐVWÐ"XÐ"XÑYÔYˆÝ�B�t”H‘”¥ B v¤J¡¤Ñ/ˆØ?DÐN•u˜e b¨¤hÑ.°Ñ6¸Ñ;Ô;Ð;È$ˆà�uÑˆØ˜ÑˆØ˜JÑ&ÐØ•c˜$Ÿ(š( 7Ñ+Ô+Ð0¨qÑ1Ô1Ñ1ˆ
Ø˜Ñˆà×ÒàØŸš˜f™œÐ4¨Ý §¢ iÑ 0Ô 0Ñ1Ô1ØŸ5š5 Ñ+Ô+Ð7¨xØŸeše LÑ1Ô1ØŸeše LÑ1Ô1Ø>?¿eºeÀMÑ>RÔ>RÐ\Ð:¨cÐ:Ð:Ð:Ð:ÐX\à"Ø$Ø",Ý  §¢¨'Ñ!2Ô!2Ð!7°aÑ8Ô8Ø$ðð õ ˜b œh™-œ-Ý  6¤
™OœOÝ   G¤Ñ-Ô-Ý'*¨2Ð.?Ô+@Ñ'AÔ'AØ(4ðð ðð ñ	
ô 	
ð 	
ñ 	
õ4 �F˜4”LÑ!Ô!¥C¨¨v¬Ñ$7Ô$7Ñ7€IØGPÐZ•u˜e f¨T¤lÑ2°YÑ>ÀÑCÔCÐCÐVZÐà×5Ò5¸VÈ!Ð5ÑLÔLÐÝ)¨&°qÐ9Ñ9Ô9€Mõ ‘f”få˜&‘k”kÝ Ð KÐ K¨FÐ KÑ KÔ KÑKÔKØ$Ø%Ø'Ø/Ø"Ý˜v dœ|Ñ,Ô,Ý  ¨¤Ñ0Ô0Ý! &¨¤/Ñ2Ô2Ý$'¨Ð/@Ô(AÑ$BÔ$BØ 0ð
ð 
ð  %Ø.Ø&ð!ð !õ ˜& œ,Ñ'Ô'Ý˜F 6œNÑ+Ô+ðð ð "3Ø*ð!ð !à#ð!ñ !ô !ð#ð #ð $ð#ñ #ô #ð!
ð 
ð2 ðS*ð *ð *r   )ro   rp   rr   rs   rÒ   c               ó¢  — t          | ¦  «        }|sd S dg}t          ¦   «         g}|�<|                     d¦  «         |                     |                     ¦   «         ¦  «         |�<|                     d¦  «         |                     |                     ¦   «         ¦  «         |�=|dvrt	          d¦  «        ‚|                     d¦  «         |                     |¦  «         |�<|                     d¦  «         |                     |                     ¦   «         ¦  «         |�*|                     d¦  «         |                     |¦  «         |                     | ¦  «         t          ¦   «         5 }	|	                     d	d
                     |¦  «        › d�|¦  «         d d d ¦  «         n# 1 swxY w Y   t          | ¦  «         t          | ¦  «        S )NrÃ   zname = ?zdescription = ?>   ri   r¦   r§   zinvalid kb_modezkb_mode = ?zwelcome_message = ?zavatar_path = ?zUPDATE agents SET rÄ   rÅ   )	rÖ   r   rÇ   r{   r¨   r   rJ   rz   r   )
r   ro   rp   rr   rs   rÒ   rå   rÈ   rÉ   rN   s
             r   rß   rß   ô  s	  € õ �hÑÔ€EØð ØˆtØÐ€FÝ™œ˜€FØÐØ�Š�jÑ!Ô!Ð!Ø�Š�d—j’j‘l”lÑ#Ô#Ð#ØÐØ�ŠÐ'Ñ(Ô(Ð(Ø�Š�k×'Ò'Ñ)Ô)Ñ*Ô*Ð*ØÐØÐ<Ð<Ð<ÝÐ.Ñ/Ô/Ð/Ø�Š�mÑ$Ô$Ð$Ø�Š�gÑÔÐØÐ"Ø�ŠÐ+Ñ,Ô,Ð,Ø�Š�o×+Ò+Ñ-Ô-Ñ.Ô.Ð.ØÐØ�ŠÐ'Ñ(Ô(Ð(Ø�Š�kÑ"Ô"Ð"Ø
‡M‚M�(ÑÔÐÝ	Ñ	Ô	ð T˜TØ�ŠÐJ¨$¯)ª)°FÑ*;Ô*;ÐJÐJÐJÈFÑSÔSÐSðTð Tð Tñ Tô Tð Tð Tð Tð Tð Tð Tøøøð Tð Tð Tð Tå˜8Ñ$Ô$Ð$Ý�XÑÔÐs   Å..F(Æ(F,Æ/F,c                óþ   — t          ¦   «         5 }|                     d| f¦  «         |                     d| f¦  «         d d d ¦  «         n# 1 swxY w Y   t          | ¦  «         t                               ¦   «          d S )Nz+DELETE FROM kb_documents WHERE agent_id = ?zDELETE FROM agents WHERE id = ?)r   rJ   r   r
   r   )r   rN   s     r   Údelete_agentrG    sÆ   € Ý	Ñ	Ô	ð E˜TØ�ŠÐBÀXÀKÑPÔPÐPØ�ŠÐ6¸¸ÑDÔDÐDðEð Eð Eñ Eô Eð Eð Eð Eð Eð Eð Eøøøð Eð Eð Eð Eõ ˜8Ñ$Ô$Ð$Ý×ÒÑÔÐÐÐs   �/A
Á
AÁAÚ
key_prefixÚkey_hashc                óX  — t          t          j        ¦   «         ¦  «        }t          ¦   «         }t	          ¦   «         5 }|                     d|| |||||f¦  «         |                     d|f¦  «                             ¦   «         }t          |¦  «        cd d d ¦  «         S # 1 swxY w Y   d S )Nzœ
            INSERT INTO api_keys(id, org_id, name, key_prefix, key_hash, created_by, created_at, revoked)
            VALUES (?,?,?,?,?,?,?,0)
            z#SELECT * FROM api_keys WHERE id = ?)r   rx   ry   r   r   rJ   rL   r/   )	r   ro   rH  rI  rq   Úkey_idr   rN   r+   s	            r   Úcreate_api_keyrL  "  sé   € õ •”‘”ÑÔ€FÝ
‰&Œ&€CÝ	Ñ	Ô	ð 	˜TØ�Šðð �V˜T :¨x¸ÀSÐIñ	
ô 	
ð 	
ð �lŠlÐ@À6À)ÑLÔL×UÒUÑWÔWˆÝ�C‰yŒyð	ð 	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	s   ½ABÂB#Â&B#c                ó¼   — t          ¦   «         5 }|                     d| f¦  «                             ¦   «         }d„ |D ¦   «         cd d d ¦  «         S # 1 swxY w Y   d S )Nz¡
            SELECT id, org_id, name, key_prefix, created_at, last_used, revoked
            FROM api_keys WHERE org_id = ? ORDER BY created_at DESC
            c                ó,   — g | ]}t          |¦  «        ‘ŒS r   r    rC   s     r   rF   z!list_api_keys.<locals>.<listcomp>A  r¡   r   r¢   rè   s      r   Úlist_api_keysrO  8  s¯   € Ý	Ñ	Ô	ð '˜TØ�|Š|ðð ˆIñ
ô 
÷ Š(‰*Œ*ð 	ð 'Ð& Ð&Ñ&Ô&ð'ð 'ð 'ð 'ñ 'ô 'ð 'ð 'ð 'ð 'ð 'ð 'øøøð 'ð 'ð 'ð 'ð 'ð 'r¤   r(   c                óÊ   — t          ¦   «         5 }|                     d| f¦  «                             ¦   «         }|rt          |¦  «        nd cd d d ¦  «         S # 1 swxY w Y   d S )Nz;SELECT * FROM api_keys WHERE key_prefix = ? AND revoked = 0r–   )r(   rN   r+   s      r   Úget_api_key_by_prefixrQ  D  s¬   € Ý	Ñ	Ô	ð *˜TØ�lŠlØIØˆIñ
ô 
÷ Š(‰*Œ*ð 	ð  Ð)�t�C‰yŒyˆy Tð*ð *ð *ð *ñ *ô *ð *ð *ð *ð *ð *ð *øøøð *ð *ð *ð *ð *ð *r˜   rK  c                ó˜   — t          ¦   «         5 }|                     d| |f¦  «        }|j        dk    cd d d ¦  «         S # 1 swxY w Y   d S )Nz;UPDATE api_keys SET revoked = 1 WHERE id = ? AND org_id = ?r   )r   rJ   Úrowcount)rK  r   rN   Úcurs       r   Úrevoke_api_keyrU  M  s™   € Ý	Ñ	Ô	ð  ˜TØ�lŠlØIØ�VÐñ
ô 
ˆð Œ|˜aÒð ð  ð  ð  ñ  ô  ð  ð  ð  ð  ð  ð  øøøð  ð  ð  ð  ð  ð  s   �#?¿AÁAc                óœ   — t          ¦   «         5 }|                     dt          ¦   «         | f¦  «         d d d ¦  «         d S # 1 swxY w Y   d S )Nz.UPDATE api_keys SET last_used = ? WHERE id = ?)r   rJ   r   )rK  rN   s     r   Útouch_api_keyrW  V  s¡   € Ý	Ñ	Ô	ð Y˜TØ�ŠÐEÍÉÌÐPVÐGWÑXÔXÐXðYð Yð Yñ Yô Yð Yð Yð Yð Yð Yð Yð Yøøøð Yð Yð Yð Yð Yð Ys   �%AÁAÁA)r   r   r   )r   r   r   r   )NN)r   r   r   r   r   r   )r+   r   r   r   )r   r   )
r4   r   rZ   r   r3   r   r[   r   r   r\   )r4   r   r   rƒ   )rt   r   rZ   r   r3   r   r   r   )
r4   r   rŠ   r   r3   r   r[   r   r   r\   )rt   r   r   rƒ   )r   r   r   rƒ   )rt   r   r   r   r   rƒ   )rt   r   r   r�   )r   r   rr   r   r   r   )r   r   rª   r   r«   r   r¬   r   r   r   r   r\   )r¯   r   r   rƒ   )r   r   r   r   r   r�   )r¯   r   r¾   r   r¿   rÁ   rÀ   r   r6   rÁ   r8   r   r:   rÁ   r;   rÁ   r<   rÁ   r=   rÁ   r>   rÁ   r   r   )r¯   r   r   r   )r   r   r   r   r   rÏ   )r   r   ro   r   rp   r   rq   r   rr   r   rs   r   rÒ   r   rA   rÓ   r   r\   )r   r   rq   r   r   r\   )r   r   r   r�   )r   r   r   rƒ   )r   r   r   ré   )r   r   rû   rÏ   r   rü   )r   r   r   r\   )r   r   ro   r   rp   r   rr   r   rs   r   rÒ   r   r   rƒ   )r   r   r   r   )r   r   ro   r   rH  r   rI  r   rq   r   r   r\   )r(   r   r   rƒ   )rK  r   r   r   r   rÓ   )rK  r   r   r   )4Ú__doc__Ú
__future__r   r|   r¶   rx   r   r   Útypingr   Úapp.databaser   r   r	   Ú__annotations__r
   r¸   r   r   r*   r0   rY   r‚   r…   rˆ   r”   r—   rš   rœ   r�   r©   r°   r®   r¼   rÌ   rÎ   rÑ   r~   r�   rã   rÖ   rÝ   rø   r  rD  rß   rG  rL  rO  rQ  rU  rW  r   r   r   ú<module>r]     sM  ðØ QÐ QÐ Qà "Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø €€€Ø 'Ð 'Ð 'Ð 'Ð 'Ð 'Ð 'Ð 'Ø Ð Ð Ð Ð Ð à 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6ð 9;€Ð :Ð :Ð :Ñ :Ø=?€Ð ?Ð ?Ð ?Ñ ?Ø€ð2ð 2ð 2ð 2ðð ð ð ð ðð ð ð ð ð2?ð ?ð ?ð ?ðKð Kð Kð Kð\1ð 1ð 1ð 1ðh*ð *ð *ð *ð W[ð ð ð ð ð ð ð  #Ø#ØØ%ð(ð (ð (ð (ð (ð (ð6*ð *ð *ð *ð*ð *ð *ð *ð*ð *ð *ð *ð'ð 'ð 'ð 'ðTð Tð Tð Tð  ð#ð #ð #ð #ð #ð #ð,*ð *ð *ð *ðð ð ð ð ðD Ø"ØØ#Ø!%Ø!Ø"&Ø!%Ø"&Ø!%ð$ð $ð $ð $ð $ð $ðNð ð ð ð+ð +ð +ð +ð +ð: #Ø!ØØ"&Ø"Øð&ð &ð &ð &ð &ð &ðRð ð ð ð ð<Dð Dð Dð Dð

ð 
ð 
ð 
ð'ð 'ð 'ð 'ð #ð #ð #ð #ðL 78ð ð ð ð ð ð ð2nð nð nð nðh Ø"ØØ"&Ø"ð#ð #ð #ð #ð #ð #ðLð ð ð ðð ð ð ð,	'ð 	'ð 	'ð 	'ð*ð *ð *ð *ð ð  ð  ð  ðYð Yð Yð Yð Yð Yr   