
    (<iS                    v   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m	Z	 ddl
mZmZmZ ddlmZ ddlmZ ddlmZ ddlmZmZ dd	lmZ dd
lmZmZmZ ddlmZ ddlm Z m!Z!m"Z"m#Z# ddl$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z* ddl+m,Z, ddl-m.Z.m/Z/m0Z0  ejb                  e2      Z3 ejh                         Z5 e       Z6 ed      Z7i Z8de9d<   d#dZ:d$dZ;d#dZ<	 	 	 	 	 	 	 	 	 	 d%dZ=d&dZ>d&dZ?d'd(dZ@d&dZAd&dZBd&dZCd&dZDd)dZEd*dZFe2d k(  r6 ej                  d!ej                  "        ej                   eF              yy)+u   멀티모델 봇 통합 프로세스.

3개 봇(잼민이/코덱스/클로디)을 하나의 프로세스에서 실행하며,
공유 DiscussionManager를 통해 봇 간 토론을 지원합니다.
    )annotationsN)AnyCallable	Coroutine)replace_thinking_messagesend_thinking_messagesplit_message)CODE_ANALYSIS_PROMPT_PREFIX)handle_message)BOT_PERSONASConversationMemory)DiscussionManager)call_claude
call_codexcall_gemini)InlineKeyboardButtonInlineKeyboardMarkupMessageUpdate)ApplicationCallbackQueryHandlerCommandHandlerContextTypesMessageHandlerfilters)HTTPXRequest)CLAUDE_BOT_TOKENCODEX_BOT_TOKENGEMINI_BOT_TOKENz$/home/jay/workspace/memory/groupchat)storage_basezHdict[str, tuple[Application, Callable[[str], Coroutine[Any, Any, str]]]]bot_appsc                   K   	 t         j                  |        d{    y7 # t        $ r }t        j	                  d|       Y d}~yd}~ww xY ww)u(   롤링 서머리 생성 (에러 안전).Nu1   롤링 서머리 생성 실패 (비치명적): %s)memorygenerate_rolling_summary	Exceptionloggerwarning)chat_idexcs     Q/home/jay/workspace/.worktrees/task-2057-dev2/services/multimodel-bot/main_bot.py_generate_rolling_summary_safer+   )   sC     Q--g666 QJCPPQs6   A$ "$ A$ 	AAAAAc                h  K   t         j                  | d      }|sydj                  d |D              }t         j                  j	                  | d      }|rd| nd}d| d	| d
}	 t        |d       d{   }|S 7 # t        $ r%}t        j                  d|       d| cY d}~S d}~ww xY ww)u6   전체 대화 내용을 분석하여 합의문 생성.2   limitu   토론 내용이 없습니다.
c              3  R   K   | ]  }|j                    d |j                    ! yw): N)sendertext).0ms     r*   	<genexpr>z,generate_consensus_report.<locals>.<genexpr>7   s#     !LaQXXJb"9!Ls   %' u   

[이전 요약]
u>  아래 토론 대화를 분석하여 합의문을 작성해줘.
반드시 아래 형식을 따라줘:

📋 토론 합의문

[주제]: (토론 주제 한 줄 요약)
[참여]: 잼민이(Gemini), 코덱스(GPT), 클로디(Claude)

✅ 합의사항:
1. ...
2. ...

⚠️ 미합의:
1. ...

📌 다음 단계:
1. ...

z

<user_content>
z
</user_content><   )timeoutNu   합의문 생성 실패: %su   합의문 생성 실패: )	r#   get_contextjoin_rolling_summariesgetr   r%   r&   r'   )r(   messagesconversation_textrollingrolling_sectionpromptreportr)   s           r*   generate_consensus_reportrE   1   s     !!'!4H/		!L8!LL ''++GR8G;B-gY7O	 
 
 	 &1"6266 7 14c:*3%001sH   A%B2(B 8A?9B >B2?B 	B/
B*$B/%B2*B//B2c                D  K   	 t        |        d{   }t        j                         D ]A  \  }\  }}	 t        |      }|D ]'  }|j                  j                  | |       d{    )  n t        j                         D ])  \  }\  }}	 t        |j                  | |       d{     n t        j                  j                  | d       y7 7 l# t        $ r Y w xY w7 ;# t        $ r Y mw xY w# t        $ r }t        j                  d|       Y d}~yd}~ww xY ww)uG   토론 종료 시 합의문 생성 후 그룹챗에 전송 + 아누 DM.Nr(   r4   u1   합의문 생성/전송 실패 (비치명적): %s)rE   r!   itemsr	   botsend_messager%   _send_insight_to_ownerr#   r=   popr&   r'   )r(   rD   bot_usernameapp_partspartr)   s           r*   _generate_consensus_report_saferR   X   s)    Q099&.nn&6 	"L(3%f-! KD''..wT.JJJK	 '/nn&6 	"L(3,SWWgvFFF	 	!!%%gt4) : K  G   QJCPPQs   D C4 C!C4 0C%C&C, C4 C%'C#(C%,#C4 D C4 C	C C4 C  C4 #C%%	C1.C4 0C11C4 4	D=DD DD c           	     Z  K   t         4 d{    t        j                  t        j                         d{    t        j                  |      s(t        j                  |d       	 ddd      d{    y| t        vr>t        j                  d|        t        j                  |d       	 ddd      d{    yt        |    \  }}	 t        |j                  |       d{   }t        j                  || t        j                  |      j                        }| dk(  r+t        j!                  |      }t#        ||       d{   }	nI| dk(  r4t        j%                  |      rt&        |z   }t)        |d	       d{   }	n ||       d{   }	t+        |j                  |||	       d{    t-        j.                  | i       j/                  d
|       }
t        j1                  ||
|	d       t        j3                  |       }|rt        j4                  j/                  |      }|rN|j6                  dkD  r?|j6                  dz  dk(  r-|j8                  dk(  rt        j:                  t=        |             t        j:                  t?        |||	|              n4t        j                  |d       t        j:                  tA        |             ddd      d{    y7 7 7 w7 47 7 7 t7 f7 I# tB        $ r}t        j                  d| ||d       t        j                  |d       t        jE                          	 |j                  jG                  |d|        d{  7   n# tB        $ r Y nw xY wY d}~d}~ww xY w7 # 1 d{  7  sw Y   yxY ww)uS   다음 턴 봇이 맥락 기반 프롬프트로 응답하도록 트리거합니다.NFu   알 수 없는 봇 username: %s)phasecodex_view_bot)modelclaude_view_botT)code_analysisname)is_botr      u6   trigger_next_bot_response 오류 (bot=%s, chat=%d): %sexc_infou-   ❌ 응답 중 오류가 발생했습니다: rG   )$
_turn_lockasynciosleepdm
TURN_DELAYis_discussion_activeset_chain_runningr!   r&   errorr   rI   r#   format_contextget_current_phasevalueget_codex_modelr   is_code_analysis_moder
   r   r   r   r>   add_messageon_bot_response_statesround_countbot_response_countcreate_taskr+   trigger_next_bot_responserR   r%   stop_discussionrJ   )next_bot_usernamer(   previous_messageprevious_bot_namerN   call_fnthinking_msg_idcontext_promptcodex_modelresultbot_name	next_nextstatees                 r*   rq   rq   u   sa      N NmmBMM*** &&w/  %0N N N H,LL:<MN  %0N N N   12W?	$9#''7$KKO $22*"2F2Fw2O2U2U 3 N
 !$44 009).LL"&77B<T<TU\<]!<~!M*>NN&~66 +377G_fUUU $''(92>BB6K\]Hw&F **+<=I

w/U..2u7H7H17LPQ7QV[VnVnrsVs''(Fw(OP##-!)	 $$We4##$CG$LMyN N N*N N" L M O6 V6  	LLH!     %0 gg**#HL +     	}N N N NsA  N+K%N+'NK(0N)N+4K+5N+:5N/N+:K.;N+ NL &K1'A#L 
K48L K7L K:L 4K=5DL N+N N+(N+N+.N+1L 4L 7L :L =L  	N	AN#M81M42M87N8	NNNNNNNN+N(NN($N+c                  K   | j                   | j                  y| j                   j                  }	 t        j	                  |       d{   }| j                  j                  |       d{    t        |j                  ||       d{    y7 G7 &7 	# t        $ r`}t        j                  d||d       	 | j                  j                  d|        d{  7   n# t        $ r Y nw xY wY d}~yY d}~yd}~ww xY ww)uk   /정리 커맨드 핸들러. 대화 요약(insight)을 생성하여 그룹챗에 전송 + 아누 DM 전송.Nu+   handle_cleanup_command 오류 (chat=%d): %sTr\   u-   ❌ 정리 중 오류가 발생했습니다: )effective_chateffective_messageidr#   generate_insight
reply_textrK   rI   r%   r&   re   )updatecontextr(   insight_textr~   s        r*   handle_cleanup_commandr      s     $(@(@(H##&&G#44W==&&11,??? %W[['<HHH >? 	I BGQY]^	**558efgeh6ijjj 		 ks   0DB B"B .B/B BB DB B B 	D"C=<!C$C C$#C=$	C0-C=/C00C=3
D=DDc                J  K   | j                   | j                  y	 t        j                  d      }|s$| j                  j                  d       d{    yt        | j                  |d       d{    y# t        $ r t        j                  d      }Y hw xY w7 K7 ,w)uG   /메모리 커맨드 핸들러. InlineKeyboard로 요약 목록 표시.Nr-   r.      u0   📚 저장된 대화 메모리가 없습니다.r   )page)r   r   r#   get_all_summary_filesAttributeErrorget_recent_summariesr   _send_memory_page)r   r   all_summariess      r*   handle_memory_commandr      s     $(@(@(H=4424> &&112deee F44m!
LLL  =33!3<= 	f MsE   B#A:  B#B B#4B!5B#:BB#BB#!B#c                  K   d}||z  }||z   }||| }t        |      |z   dz
  |z  }g }	|D ]x  }
|
j                  dd      }|
j                  dd      }|
j                  dd      dd	 }|
j                  d
d      }d| d| d| }|	j                  t        |d|       g       z g }|dkD  r"|j                  t        dd|dz
                ||dz
  k  r"|j                  t        dd|dz                 |r|	j                  |       t	        |	      }d|dz    d| d}|r(t        | d      r| j                  ||       d{    y| j                  ||       d{    y7 !7 w)u)   InlineKeyboard 페이지를 표시한다.r      dater8   	topic_taggeneralsummaryN   filenameunknown[]     — mem:callback_datar   u
   ◀ 이전mempage:u
   다음 ▶u   📚 대화 메모리 (/u    페이지)	edit_textreply_markup)lenr>   appendr   r   hasattrr   r   )message	summariesr   edit	page_sizestartend
page_itemstotal_pagesbuttonssr   topicr   r   btn_textnav_buttonsr   r4   s                      r*   r   r      s    I9E
)
C5%Jy>I-1i?K02G ZuuVR k9-%%	2&s+55Y/tfBugU7)4,XtH:EVWXYZ /1Kax/hW[^_W_V`LabckAo/hW[^_W_V`Labc{#'0L$TAXJa}KHD-<@@@  L AAA 	AAs$   EE.E*	E.$E,%E.,E.c                  K   | j                   }|y|j                          d{    |j                  xs d}t        |j                  t
              sy|j                  }|j                  d      rLt        |j                  d      d         }	 t        j                  d      }t        |||d	
       d{    y|j                  d      r|j                  dd      d   }t        j                         }||j                  d       d{    yddlm}	  |	|      | dz  }
|
j%                         s|j                  d|        d{    y	 t'        j(                  |
j+                  d            }d|j-                  dd       d|j-                  dd       d|j-                  dd      dddj/                  |j-                  dg              ddj/                  |j-                  dg              ddj/                  |j-                  dg              d|j-                  d d       g}t1        t3        d!d"#      gg      }|j                  d$j/                  |      |%       d{    yy7 T# t        $ r t        j                  d      }Y w xY w7 7 7 X7 8# t4        $ r'}|j                  d&|        d{  7   Y d}~yd}~ww xY ww)'u   InlineKeyboard 콜백 처리.Nr8   r   :r   r-   r.   r   T)r   r   r   u/   요약 디렉토리를 찾을 수 없습니다.r   )Pathz.jsonu#   파일을 찾을 수 없습니다: utf-8encodingu   📄 r   r   r   r   u   🏷 주제: z, 
key_topicsu   ✅ 결정: key_decisionsu   📋 액션: action_itemsu   🤝 합의: consensus_levelu   ◀ 목록으로z	mempage:0r   r0   r   u   파일 읽기 오류: )callback_queryanswerdata
isinstancer   r   
startswithintsplitr#   r   r   r   r   _summaries_dirr   pathlibr   existsjsonloads	read_textr>   r<   r   r   r%   )r   r   queryr   msgr   r   r   summaries_dirr   	file_pathsummary_datalinesback_buttonr)   s                  r*   handle_memory_callbackr     s    !!E}
,,.::D emmW-==Cz"4::c?1%&	A"88r8BM  ]DIII		 ::c1%a(--/ -- QRRR 'XJe*<<	!--"EhZ PQQQ	@::i&9&97&9&KLL((45U<;K;KKY[;\:]^  B/		,*:*:<*L MNOtyy)9)9/2)NOPQ		,*:*:>2*N OPQ 0 01BB GHI	E /1EFXhs1t0u/vwK--		% 0{-KKK; 
!%   	A"77a7@M	AI S R" L 	@--"8 >???	@s   #K I9A)K I< &K 8J"9AK J%A K J(K DJ- 2J+3J- 7K <JK JK %K (K +J- -	K6KKKK KK c                  K   | j                   | j                  y|j                  rdj                  |j                        nd}|s$| j                  j	                  d       d{    yt
        j                         }||j                         s$| j                  j	                  d       d{    yg }t        |j                  d            D ]  }	 t        j                  |j                  d            }dj                  |j                  d	d      dj                  |j                  d
g             dj                  |j                  dg             g      }|j                         |j                         v r|j                  |        |s(| j                  j	                  d| d       d{    yd| dt#        |       dg}|dd D ]U  }	|	j                  dd      }
|	j                  dd      }|	j                  d	d      dd }|j                  d|
 d| d|        W | j                  j	                  dj                  |             d{    y7 7 # t         $ r Y w xY w7 7 w)uG   /기억 <키워드> 커맨드 핸들러. 요약에서 키워드 검색.N r8   u   사용법: /기억 <키워드>u#   🔍 검색 결과가 없습니다.*.jsonr   r   r   r   r   u   🔍 'u*   '에 대한 검색 결과가 없습니다.u   ' 검색 결과 (u   건):r   r   r   r9   u   • [r   r2   r0   )r   r   argsr<   r   r#   r   r   sortedglobr   r   r   r>   lowerr   r%   r   )r   r   keywordr   resultsfpr   
searchabler   rr   r   r   s                r*   handle_search_memory_commandr   S  sX    $(@(@(H(/chhw||$"G&&112RSSS ))+MM$8$8$:&&112WXXXG]''12 	::bllGl<=DHHY+HHTXXlB78HHTXXor:;J }}*"2"2"44t$  &&11F7)Cm2nooogY/G~UCDERS\ 9uuVR k9-%%	2&s+uTF"UG2gY78	9 
"
"
-
-dii.>
???K 	T 	Y"  		 	p @si   A#I6%I&A	I6/I0$I6B8I"&I63I24B"I6I4I6I6"	I/+I6.I//I64I6c                p  K   | j                   | j                  y|j                  rdj                  |j                        nd}|s$| j                  j	                  d       d{    y| j                   j
                  }	 t        j                  ||       d{   }| j                  j	                  |       d{    y7 ^7 *7 	# t        $ r`}t        j                  d||d       	 | j                  j	                  d|        d{  7   n# t        $ r Y nw xY wY d}~yY d}~yd}~ww xY ww)	u.   /스마트검색 <질문> 커맨드 핸들러.Nr   r8   u$   사용법: /스마트검색 <질문>u0   handle_smart_search_command 오류 (chat=%d): %sTr\   u2   스마트검색 중 오류가 발생했습니다: )r   r   r   r<   r   r   r#   smart_searchr%   r&   re   )r   r   r   r(   rz   r~   s         r*   handle_smart_search_commandr     s    $(@(@(H&-llCHHW\\"E&&112XYYY##&&G**5'::&&11&999 	Z ;9 GRS^bc	**558jkljm6nooo 		 ps   A#D6%C&D6C
 C"C
 >C?C
 D6C
 C
 
	D3D.-!DDDD.	D!D. D!!D.$
D6.D33D6c           
     X  K   | j                   | j                  yt        j                         }||j	                         s$| j                  j                  d       d{    yddlm}  |t              }t        |j                  d            D ]  }	 t        j                  |j                  d            }|j                  d|j                  dd	       }|j                  d
d      }|j                  dd      dd }	|j                  dd      }
d|j                  v r|j                  j!                  dd      d   n|j                  }||   j#                  d| d|	 d|
 d        |s$| j                  j                  d       d{    ydg}t        |j'                         d      dd D ]*  }|j#                  | d       |j)                  ||          , | j                  j                  dj+                  |             d{    y7 # t$        $ r Y w xY w7 7 w)u<   /목차 커맨드 핸들러. 날짜별 요약 목록 표시.Nu&   📋 저장된 목차가 없습니다.r   )defaultdictr   r   r   r   
   r   r   r   r8   (   r   exploratoryrO   r   z  - r2   z ()u   📋 대화 목차T)reverse   r   r0   )r   r   r#   r   r   r   collectionsr   listr   r   r   r   r   r>   stemr   r   r%   keysextendr<   )r   r   r   r   entriesr   r   r   r   r   	consensus
entry_namer   s                r*   handle_index_commandr     s    $(@(@(H))+MM$8$8$:&&112Z[[['$/$5G]''12 
		::bllGl<=D88FBGGCRL1DHH[)4Ehhy"-cr2G!2MBI58BGG^sA.q1JDM  4
|2gYb1!MN
 &&112Z[[[!"Ew||~t4Ra8 $vQZ WT]#$ 
"
"
-
-dii.>
???9 	\   		 	\ @sV   AH* H!4H*CH*"H*H&B H*H(H*	H#H*"H##H*(H*c                  K   	 ddl m} d| d}dt        |      z
  }|t        |      |kD  r|d| n|z   }| j                  ||       d{    y7 # t        $ r }t
        j                  d|       Y d}~yd}~ww xY ww)	u<   insight 결과를 OWNER_USER_ID에게 DM으로 전송한다.r   )OWNER_USER_IDu'   📋 그룹챗 정리 완료 (chat_id: z)

i   NrG   u*   아누 DM 전송 실패 (비치명적): %s)configr   r   rJ   r%   r&   r'   )rI   r(   r   r   headermax_lenr4   r)   s           r*   rK   rK     s     	J(:7)5IV$3|3Dw3Nhw/T`a}4@@@ JCSIIJsA   B AA AA B A 	A=A83B 8A==B c            	     <  K   t        dddd      } t        j                         j                  t              j                  |       j                         }t        j                         j                  t              j                  |       j                         }t        j                         j                  t              j                  |       j                         }|t        ft        d<   |t        ft        d<   |t        ft        d<   |||fD ]  }t        |j                  d<    d }d	 }d
 }dt        fdt         fdt"        fdt$        fdt&        fg}|||fD ]:  }|D ]3  \  }	}
|j)                  t+        t-        j.                  |	      |
             5 < |j)                  t+        t,        j0                  t,        j2                   z  |             |j)                  t+        t,        j0                  t,        j2                   z  |             |j)                  t+        t,        j0                  t,        j2                   z  |             |||fD ]   }|j)                  t5        t6                     " |||fD ]g  }|j9                          d{    |j;                          d{    |j<                  J d       |j<                  j?                          d{    i t@        jC                  d       	 tE        jF                         jI                          d{    |||fD ]`  }|j<                  "|j<                  jO                          d{    |jO                          d{    |jQ                          d{    b y7 7 7 7 s# tJ        tL        f$ r Y w xY w7 T7 >7 (# |||fD ]c  }|j<                  #|j<                  jO                          d{  7   |jO                          d{  7   |jQ                          d{  7   e w xY ww)u'   3개 봇 통합 프로세스 진입점.r   r9   )connect_timeoutread_timeoutwrite_timeoutpool_timeoutgemini_view_botrU   rW   rq   c                N   K   t        | |t        t               d {    y 7 wN)ra   r#   )gemini_handlera   r#   r   r   s     r*   wrap_geminizmain.<locals>.wrap_gemini       FG6BBB   %#%c                N   K   t        | |t        t               d {    y 7 wr  )codex_handlera   r#   r  s     r*   
wrap_codexzmain.<locals>.wrap_codex  s     67r&AAAr  c                N   K   t        | |t        t               d {    y 7 wr  )claude_handlera   r#   r  s     r*   wrap_claudezmain.<locals>.wrap_claude  r  r  u   ^/정리u   ^/메모리u   ^/기억u   ^/목차u   ^/스마트검색Nu<   Application.updater가 None입니다 (polling 모드 필요)u&   3봇 통합 프로세스 시작 완료))r   r   buildertokenr   requestbuildr   r   r   r!   r   r   rq   bot_datar   r   r   r   r   add_handlerr   r   RegexTEXTCOMMANDr   r   
initializer   updaterstart_pollingr&   infor_   EventwaitKeyboardInterrupt
SystemExitstopshutdown)
tg_request
gemini_app	codex_app
claude_apprN   r  r  r  korean_commandspatternhandlers              r*   mainr)    s     brQSbdeJ$$&,,-=>FFzRXXZJ##%++O<DDZPVVXI$$&,,-=>FFzRXXZJ $.{";H"+Z!8H#-{";H Iz2 N4M01NCBC
 
,-	./	23	*+	:;O Iz2 M / 	MGWOON7==+A7KL	MM >',,'//9I*I;WX.8H)H*UV>',,'//9I*I;WX Iz2 F,-CDEF Iz2 *nniik{{&f(ff&kk'')))	* KK89
!mmo""$$$ 	:6 	!C{{&kk&&(((((*,,.  		! 	) 	%z* 
 ) 	 	:6 	!C{{&kk&&(((((*,,.  		!s   J
PN	P$N%4PNP6%N NN  1PN&P)N(*PN*PPPN N# N, "N##N, &P(P*P,2PO!
P7O:
8PP
PP__main__z4%(asctime)s - %(name)s - %(levelname)s - %(message)s)formatlevel)r(   r   returnNone)r(   r   r-  str)
rs   r/  r(   r   rt   r/  ru   r/  r-  r.  )r   r   r   zContextTypes.DEFAULT_TYPEr-  r.  )r   F)
r   r   r   r   r   r   r   boolr-  r.  )rI   r   r(   r   r   r/  r-  r.  )r-  r.  )J__doc__
__future__r   r_   r   loggingtypingr   r   r   	bot_utilsr   r   r	   
claude_botr
   r   r  	codex_botr
  conversation_memoryr   r   discussion_managerr   engine_v2.bot_apir   r   r   
gemini_botr  telegramr   r   r   r   telegram.extr   r   r   r   r   r   telegram.requestr   r   r   r   r   	getLogger__name__r&   Lockr^   ra   r#   r!   __annotations__r+   rE   rR   rq   r   r   r   r   r   r   r   rK   r)  basicConfigINFOrun     r*   <module>rH     sT   #    + + T T 2 6 4 @ 0 B B 6 P P q q ) F F			8	$W\\^
 	)O	P VX
R WQ$1NQ:UUU U 	U
 
Up.M& BF6@r,@^.#@LJB!J zGEll GKK rG  