
    ϴ\i^                         S r SSKJrJrJrJrJrJr  SSKrSSK	r	SSK
r
SSKrSSKJr  SSKJr  \	R                   " \5      r\" S\5      r0 rS\S\4S	 jrS\S\4S
 jrS\S\4S jrS\S\S\4S jrS\S\S\S\4S jrS\S\4S jrS\S\4S jrS$S\S\S\4S jjr S\4S jr!S\4S jr"S r#\RI                  SS/S9\S\4S j5       5       r%\RI                  SS /S9\S\4S! j5       5       r&\RI                  S"S/S9\S\4S# j5       5       r'g)%ut   
AI 助手路由 - 题目详情页面的 AI 对话功能

支持工具调用，可以读写文件、执行命令等
    )	BlueprintResponsejsonifyrequestgstream_with_contextNPath)login_requiredgenerate_assistantchallenge_idreturnc                 2   SSK Jn  U" U 5      nU(       d  gUR                  SS5      nU(       d  gUR                  S5      (       dD  [	        [
        5      R                  R                  R                  R                  n[        XC-  5      n[	        U5      S-  $ )u<   获取对话历史文件路径（存储在题目目录下）r   get_challenge_recordN
output_dir /zchat_history.json)app.models.database.operationsr   get
startswithr
   __file__parentstr)r   r   	challenger   project_roots        =/Users/yu22x/Desktop/ge/ctf/app/routes/generator/assistant.py_get_history_file_pathr      s    C$\2I|R0J   %%H~,,33::AA23
 
111    c                 
    [        U 5      n[        R                  SU 35        U(       ag  UR                  5       (       aR  [	        USSS9 n[
        R                  " U5      n[        R                  S[        U5       SU  S35        UsSSS5        $ [        R                  S	U 35         / $ ! , (       d  f       / $ = f! [         a8  n[        R                  S
U 35        SSKnUR                  " 5          SnA/ $ SnAff = f)u   从文件加载对话历史u   加载对话历史文件: rutf-8encodingu   成功加载 u    条对话历史 (challenge_id=)Nu   对话历史文件不存在: u   加载对话历史失败: r   )r   loggerdebugexistsopenjsonloadinfolen	Exceptionerror	traceback	print_exc)r   	file_pathfhistoryer0   s         r   _load_history_from_filer6   -   s    *<8	1)=>))++iw71))A,mCL>9XYeXffghi 87
 LL8DE
 I 87 I	  1!56I	s<   A
C  =B.		C  C  .
B=8C  =C   
D
-C==Dr4   c                     [        U 5      nU(       ai  UR                  R                  SSS9  [        USSS9 n[        R
                  " XSSS9  S	S	S	5        [        R                  S
[        U5       SU 35        g	g	! , (       d  f       N4= f! [         a7  n[        R                  SU 35        SS	KnUR                  " 5          S	nAg	S	nAff = f)u   保存对话历史到文件T)parentsexist_okwr"   r#   F   )ensure_asciiindentNu   保存 u    条对话历史到 u   保存对话历史失败: r   )r   r   mkdirr)   r*   dumpr&   r,   r-   r.   r/   r0   r1   )r   r4   r2   r3   r5   r0   s         r   _save_history_to_filer@   @   s    
*<8	""4$"?iw71		'5C 8KK'#g,/CI;OP	 77  1!56s.   7B A>,B >
BB 
C-CCuser_idc                     U [         ;  a	  0 [         U '   U[         U    ;  a  [        U5      [         U    U'   [         U    U   $ )u?   获取对话历史（优先从缓存，否则从文件加载）)_conversation_cacher6   rA   r   s     r   _get_historyrE   O   sK     ))')G$.w775L\5ZG$\2w'55r   rolecontentc                     [        X5      nUR                  X#S.5        [        U5      S:  a  USS nU[        U    U'   [	        X5        g)u6   添加消息到历史（同时更新缓存和文件）rF   rG   2   iN)rE   appendr-   rC   r@   )rA   r   rF   rG   r4   s        r   _add_messagerL   \   sN    71GNND56 7|b#$-5<G$\2 ,0r   c                 b    U [         ;   a  U[         U    ;   a  / [         U    U'   [        U/ 5        g)u3   清空对话历史（同时清除缓存和文件）N)rC   r@   rD   s     r   _clear_historyrN   j   s6     %%,:Mg:V*V57G$\2 ,+r   c                 $    SSK Jn  SSKJn  U" U 5      nU(       d  gUR	                  SS5      nU(       a{  UR                  S5      (       de  [        R                  R                  U5      (       dA  U" [        5      R                  R                  R                  R                  n[        XT-  5      nUR	                  SS	5      UR	                  S
S5      US/ S.nU(       a  U" U5      S-  nUR                  5       (       a+   [        USSS9 nUR                  5       SS US'   SSS5        U" U5      n	U	R                  5       (       a  U	R                  S5       Hk  nUR!                  5       (       d  M  [#        S UR$                   5       5      (       a  M=  [        UR'                  U	5      5      n
US   R)                  U
5        Mm     U$ ! , (       d  f       N= f!    N= f! [*         a"  n[,        R/                  SU 35         SnAgSnAff = f)u   获取题目上下文信息r   r   r	   Nr   r   r   nameu   未命名题目description)rP   rQ   r   writeupfilesz
writeup.mdr!   r"   r#   i  rR   *c              3   B   #    U  H  oR                  S 5      v   M     g7f).N)r   ).0parts     r   	<genexpr>)_get_challenge_context.<locals>.<genexpr>   s     .XPWs/C/CPWs   rS   u   获取题目上下文失败: )r   r   pathlibr
   r   r   ospathisabsr   r   r   r(   r)   readrglobis_fileanypartsrelative_torK   r.   r&   r/   )r   r   r
   r   r   r   contextwriteup_pathr3   output_pathrel_pathr5   s               r   _get_challenge_contextri   t   s   /G (6	 ]]<4
((--bggmmJ6O6O#H~44;;BBII !:;
 MM&*;<$==;$
 
+l:L""$$lC'Ba-.VVXet_	* C z*K!!##$**3/Ayy{{3.XPQPWPW.X+X+X#&q}}['A#B(//9 0
  CB  4QC89sf   G# C#G# G G$G ,AG# 4G# 3G# 
GG G# G G G# #
H-H

Hchallenge_contextabs_output_dirc                    SR                  S U R                  S/ 5      SS  5       5      nU=(       d    U R                  SS5      nU(       a  U S3OSnS	U R                  S
S5       SU R                  SS5       SU SU SU S3$ )ut   构建系统提示词

Args:
    challenge_context: 题目上下文
    abs_output_dir: 绝对路径的输出目录

c              3   ,   #    U  H
  nS U 3v   M     g7f)z- N )rW   r3   s     r   rY   '_build_system_prompt.<locals>.<genexpr>   s     T,SqBqc(,Ss   rS   N   r   r   /dockeru}   你是一个 CTF 题目助手，帮助用户优化和改进已生成的 CTF 题目。

## 当前题目信息
- 题目名称: rP   u   未知u   
- 题目描述: rQ   u   无u   
- 题目目录: u   

## 题目文件
uY  

## 重要：你必须使用工具来完成任务
你有以下工具可用，当用户请求涉及文件操作或命令执行时，你**必须**调用相应的工具：

1. **read_file** - 读取文件内容。参数: path (文件绝对路径)
2. **write_file** - 写入文件。参数: path (文件绝对路径), content (文件内容)
3. **run_command** - 执行命令。参数: command (命令字符串), cwd (工作目录，可选)
4. **list_directory** - 列出目录。参数: path (目录绝对路径)

## 工作流程
- 当用户要求查看文件时，调用 read_file 工具
- 当用户要求修改文件时，先调用 read_file 读取，然后调用 write_file 写入
- 当用户要求执行命令时，调用 run_command 工具
- 不要假装执行工具，必须真正调用工具函数

## 题目目录
所有文件操作的基础路径是: )joinr   )rj   rk   	files_strr   
docker_dirs        r   _build_system_promptrv      s     		T,=,A,A'2,NsPR,STTIJ#4#8#8r#JJ+5J<w'2J #&&vx89 :"&&}e<= >   '" (2l 33 r   c                      SSK Jn  UR                  U 5      nU(       a  U$ g! [         a"  n[        R                  SU 35         SnAgSnAff = f)u   创建 AI 服务实例r   )AIProviderFactoryNu   创建 AI 服务失败: )app.services.ai.providersrx   create_for_userr.   r&   r/   )rA   rx   providerr5   s       r   _create_ai_servicer|      sL    	?$44W=O /s34s   # 
AA

Ar   c                 l    SSK JnJn  U (       a  [        [	        U 5      S-  5      OSnU (       a  X/O/ nU Vs/ s H  oU(       d  M  UPM     nnU" USS9n[        SU SU 3S	S
9  U" XcS9$ s  snf ! [         a7  n[        R                  SU 35        SSK	nUR                  " 5          SnAgSnAff = f)u   创建工具执行器r   )ToolExecutorSandboxConfigdockerNi'  )allowed_directoriesmax_output_sizeu.   [AI助手] 创建工具执行器: working_dir=z, allowed_dirs=Tflush)sandboxworking_diru   创建工具执行器失败: )app.services.ai.toolsr~   r   r   r
   printr.   r&   r/   r0   r1   )	r   r~   r   ru   allowed_dirsdr   r5   r0   s	            r   _create_tool_executorr      s    E :DSj)H45
 4>
/2#/5<a1<5 ,!

 	>zl/ZfYghptuGDD 6  4QC89	s.   8A2 
A-A-A2 -A2 2
B3<-B..B3c                      SSK Jn   U R                  5       U R                  5       U R	                  5       U R                  5       /$ )u   获取 AI 助手可用的工具r   ToolDefinition)app.services.ai.providers.baser   	read_file
write_filerun_commandlist_directoryr   s    r   _get_assistant_toolsr      s?    =  "!!#""$%%'	 r   z-/challenge/<int:challenge_id>/continue/streamPOST)methodsc                 P  ^ ^
^^^^^  [         R                  R                  m[        R                  " 5       =(       d    0 nUR                  SS5      R                  5       nU(       d  [        SSS.5      S4$ [        T 5      m
T
(       d  [        SSS.5      S4$ S	S
K	J
n  U" T 5      nU(       aC  UR                  S5      T:w  a.  [         R                  R                  S:w  a  [        SSS.5      S4$ [        T5      mT(       d  [        SSS.5      S4$ [        TT SU5        T
R                  SS5      mT(       a_  TR                  S5      (       dI  S	SKn[!        ["        5      R$                  R$                  R$                  R$                  n['        UT-  5      m[)        ST 3SS9  [+        T5      mT(       a
  [-        5       OSm[)        STSL 3SS9  [)        ST(       a  [/        T5      OS	 3SS9  T(       a#  [)        ST Vs/ s H
  owS   S   PM     sn 3SS9  U
U UUUUU4S jn[1        [3        U" 5       5      SSSS S!.S"9$ s  snf ! [4         aP  n	[6        R9                  S#U	 35        [:        R<                  " 5         [        S['        U	5      S.5      S$4s Sn	A	$ Sn	A	ff = f)%u   流式对话接口instructionr   Fu   请输入指令successmessagei  u   题目不存在i  r   r   rA   admin   无权访问此题目  uD   未配置 AI 服务，请先在个人中心或 AI 配置页面设置userr   r   Nu&   [AI助手] output_dir (绝对路径): Tr   u'   [AI助手] tool_executor 创建结果: u   [AI助手] tools 数量: u   [AI助手] 工具列表: functionrP   c            
   3   H  >#     / n [        TT5      nU R                  SUS.5        [        SS 3SS9  [        SSS9  [        ST 3SS9  [        S	T"(       a  [        T"5      OS
 3SS9  [        ST! 3SS9  [        S[	        T 5      R
                   3SS9  [        S SS9  TR                  S5      (       a3  TS   SS nU R                  SSU 3S.5        U R                  SSS.5        [        T#T5      nUSS  H  nU R                  U5        M     SnS
nSn[        T S5      =(       d    [        T S5      nT(       a  T S3OSn	[        SU 3SS9  [        SU	 3SS9  Xe:  Gay  US-  n[        SU S3SS9  [        S[        U 5       3SS9  [        S U S!   S"    S#U S!   R                  S$S5      SS  S%3SS9  U(       a&  U	(       a  [        S&U	 3SS9  T R                  U T"U	S'9n
O<[        S(T"(       a  T" Vs/ s H
  oS)   S*   PM     snO/  3SS9  T R                  U T"S+9n
[        S,SS9  [        S-U
R                  S.5       3SS9  [        S/[        U
R                  S$S5      5       3SS9  [        S0U
R                  S$S5      SS1  S%3SS9  U(       a  U
R                  S$S5      nUnSn[        S
[        U5      U5       H'  nXX-    nS2[        R                  " S3US4.S5S69 S73v   M)     [        T#TSU5        S2[        R                  " S8S90S5S69 S73v   [        S:SS9  GOU
R                  S.5      n[        S;U S<T!SL 3SS9  U(       Ga  T!(       Ga  [        S=[        U5       S>3SS9  [        U5       Hi  u  nn[        S?US-    S@UR                  S)0 5      R                  S*SA5       3SS9  [        SBUR                  S)0 5      R                  SCSD5      SS1  3SS9  Mk     U
R                  S$S5      nU(       a*  X|S-   -  nSnS2[        R                  " S3UU-   S4.S5S69 S73v   SUUSE.nU R                  U5        U H  nUS)   S*   nUR                  S)0 5      R                  SCSD5      n[        SFU 3SS9  [        SGUSSH  3SS9  SIU S3nS2[        R                  " S3US4.S5S69 S73v   UU-  nT!R                  U5      n[        SJUSSH  S%3SS9  [        U5      S1:  a  USS1 S%-   OUnSKU S3nS2[        R                  " S3US4.S5S69 S73v   UU-  nU R                  SLUSM   UUSN.5        M     [        SOSS9  GM  [        SPSS9  U
R                  S$S5      nX|-  nSn[        S
[        U5      U5       H'  nXX-    nS2[        R                  " S3US4.S5S69 S73v   M)     [        T#TSU5        S2[        R                  " S8S90S5S69 S73v   [        SQSS9   Xe:  aL  SRnS2[        R                  " S3US4.S5S69 S73v   [        T#TSU5        S2[        R                  " S8S90S5S69 S73v   ggs  snf ! [          a^  n["        R%                  SSU 35        [&        R(                  " 5         S2[        R                  " ST[+        U5      SU.S5S69 S73v    SnAgSnAff = f7f)Vu3   生成器函数，流式输出，支持工具调用systemrI   rm   z<============================================================Tr   u   [AI助手] 开始对话u   [AI助手] 题目目录: u   [AI助手] 工具数量: r   u   [AI助手] 工具执行器: u   [AI助手] Provider类型: rR   Ni  r   u   题目 Writeup 摘要：
	assistantu$   好的，我已了解题目信息。id   r   router_type_call_claude_chatrr   u   [AI助手] CLI模式: u   [AI助手] Docker目录:    u   
[AI助手] === 轮次 z ===u   [AI助手] 消息数量: u   [AI助手] 最后一条消息: rF   z - rG   z...u3   [AI助手] 使用 CLI 模式调用，工作目录: )toolsworkspace_diru-   [AI助手] 使用 API 模式调用，工具: r   rP   )r   u   [AI助手] AI 响应:z  - tool_calls: 
tool_callsu     - content长度: u     - content预览:    zdata: chunk)typerG   F)r<   z

r   doneu   [AI助手] CLI模式完成u*   [AI助手] 检查工具调用: tool_calls=z, tool_executor=u"   [AI助手] 检测到工具调用: u    个u   [AI助手]   工具 z: unknownu   [AI助手]   参数: 	argumentsz{})rF   rG   r   u   [AI助手] 执行工具: u   [AI助手] 参数: i,  u   
🔧 执行工具: u   [AI助手] 工具结果: u   📋 结果: toolid)rF   tool_call_idrP   rG   u/   [AI助手] 工具执行完成，继续下一轮u2   [AI助手] 没有工具调用，返回最终响应u   [AI助手] 对话完成u,   
⚠️ 达到最大工具调用次数限制u   AI 对话失败: r/   )r   r   )rv   rK   r   r-   r   __name__r   rE   hasattrchatranger*   dumpsrL   	enumerateexecute_tool_callr.   r&   r/   r0   r1   r   )$messagessystem_promptwriteup_summaryr4   msgmax_iterations	iterationfull_contentis_cli_moderu   responsetrG   
chunk_sizeir   r   tcnewlineassistant_msg	tool_call	tool_name	tool_argstool_msgtool_resultresult_preview
result_msgwarning_msgr5   rj   r   r   r{   tool_executorr   rA   s$                                r   generatechat_stream.<locals>.generate9  s    nj !55F
 Sm LM6(m40/=1*>dK1#e*11MNVZ[4]ODDQ3DN4K4K3LMUYZ. %((33&7	&B5D&IOOO &%??P#Q%  OO +#I%  'w="34=COOC( ) "%	! &h>h'(TgBh7A
|73t
.{m<DI1*>dK0NI4YKtDDQ5c(m_ETR;HRL<P;QQTU]^`UaUeUefoqsUtuyvyUzT{{~  HL  M #z ST^S_`hlm#+==V`=#a  Mx}nsNtnsijQ[}]cOdnsNt  DF  NG  H  PT  U#+===#G1$?,X\\,-G,HIQUV/HLLB4O0P/QRZ^_/Y0KDS0Q/RRUV^bc #"*,,y""='. &)
!&q#g,
!CA$+al$;E$*4::wSX6Yhm+n*oos"tt "D
 %WlKV &tzz662BQV'W&XX\]] :4H "*l!;JFzlRbcpx|c|b}~  GK  L!m B3z?BSSWX`de%.z%:EAr!$81RzSU@V@Z@Z[acl@m?n"ow{|!$9"&&R:P:T:TU`bf:ghlil:m9n"ow{| &; #+,,y""= #(dN:L&*G$*4::wSZ]dSd6ety+z*{{  #A  A %0'.*4)
 !6 *4I(1*(=f(EI(1j"(E(I(I+W[(\I!$=i["IQUV!$7	$37H"IQUV *?yk'LH$*4::wS[6\kp+q*rrv"ww(H4L +8*I*I)*TK!$=k$3>O=PPS"T\`a KNkJZ]`J`[#->-FfqN+88H)KJ$*4::wS]6^mr+s*ttx"yy(J6L %OO(.09$(1+6	- 1 *4@  OX\]   R[_`"*,,y""=$/ &)
!&q#g,
!CA$+al$;E$*4::wSX6Yhm+n*oos"tt "D
 %WlKV &tzz662BQV'W&XX\]] 7E ."QK"4::w;.Wfk#l"mmqrr ,\R"4::vv.>U#S"TTXYY	 /S Ou^  j045##%tzz7s1v*N]bcddhiijsC   Z"G6X7 ;X2
P$X7 0Z"2X7 7
ZAZZ"ZZ"ztext/event-streamzno-cachenoz
keep-alive)zCache-ControlzX-Accel-Buffering
Connection)mimetypeheadersu   处理对话请求失败:   )r   r   r   r   get_jsonr   stripr   ri   r   r   rF   r|   rL   r   r\   r
   r   r   r   r   r   r   r-   r   r   r.   r&   r/   r0   r1   )r   datar   r   r   r\   r   r   r   r5   rj   r   r{   r   r   rA   s   `         @@@@@@r   chat_streamr     s   nC&&))!'Rhh}b1779u9JKLcQQ 3<@ u9JKLcQQ 	H(6	y1W<PWAWu9PQRTWWW &g.u9  A  B  DG  G  G 	WlFK@ '**<<
 j33C88>0077>>EEL\J67J6zlC4P-j9*7$&T7T8Q7RS[_`)#e*1)EFdS-e.Te}V/De.T-UV^bcp	j p	jd 
+(!+%)*
 	
i /U|  C1!565SV<=sBBCsK   A.I 8!I AI 2!I C0I I
0I I 
J%AJ J% J%z./challenge/<int:challenge_id>/continue/historyGETc                     [         R                  R                  nSSKJn  U" U 5      nU(       aC  UR                  S5      U:w  a.  [         R                  R                  S:w  a  [        SSS.5      S4$ [        X5      n[        S	US
.5      $ ! [         a;  n[        R                  SU 35        [        S[        U5      S.5      S4s SnA$ SnAff = f)u   获取对话历史r   r   rA   r   Fr   r   r   T)r   r4   u   获取对话历史失败: r   N)r   r   r   r   r   r   rF   r   rE   r.   r&   r/   r   )r   rA   r   r   r4   r5   s         r   get_historyr     s    C&&)) 	H(6	y1W<PWAWu9PQRTWWWw5
  	
  C1!565SV<=sBBC$   A1B 4B 
C0CCCz,/challenge/<int:challenge_id>/continue/clearc                     [         R                  R                  nSSKJn  U" U 5      nU(       aC  UR                  S5      U:w  a.  [         R                  R                  S:w  a  [        SSS.5      S4$ [        X5        [        S	S
S.5      $ ! [         a;  n[        R                  SU 35        [        S[        U5      S.5      S4s SnA$ SnAff = f)u   清空对话历史r   r   rA   r   Fr   r   r   Tu   对话历史已清空u   清空对话历史失败: r   N)r   r   r   r   r   r   rF   r   rN   r.   r&   r/   r   )r   rA   r   r   r5   s        r   clear_historyr     s    C&&)) 	H(6	y1W<PWAWu9PQRTWWWw-.
  	
  C1!565SV<=sBBCr   )N)(__doc__flaskr   r   r   r   r   r   r*   loggingr\   r0   r[   r
   app.services.auth.decoratorsr   	getLoggerr   r&   bp_assistantrC   intr   listr6   r@   rE   r   rL   rN   dictri   rv   r|   r   r   router   r   r   ro   r   r   <module>r      s   P O   	   7			8	$-x8  2 2 2*# $ & d 
6# 
6S 
6T 
61# 1S 1 1c 1,C ,s ,1 1 1h&D &# &QT &R c 8 CfXVpCc pC  WpCf DugVCc C  WC. BVHUC C  VCr   