
    Xi_W              
       n   d dl Z d dlZd dlZd dlZd dlZd dlZd dlmZmZm	Z	m
Z
mZ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 d dlmZ d dlmZmZ d dlmZ d dlmZ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, d dl-m.Z.m/Z/m0Z0m1Z1m2Z2  e&e$dde)dd        ejf                  e4      Z5d dl6m7Z7 d dl8m9Z9 d dl:m;Z; d dl<m=Z= d dl>m?Z?m@Z@ dZA G d d      ZB eB       ZC e       ZD e9eC      ZEdZFeDj                  d      dedeeHef   fd       ZId ZJd!eHd"ej                  fd#ZLeDj                  d$      defd%       ZMeDj                  d&      d!eHdefd'       ZNeDj                  d()      d*eHdefd+       ZOeDj                  d,      defd-       ZPeDj                  d.      d/        ZReDj                  d0)      defd1       ZSd2 ZTd3eHdeeHef   fd4ZUd5 ZVe4d6k(  rR eT       ZWeWj                  d7k(  r eVeWj                         yeWj                  d8k(  rS eUeWj                        Z[ ej                  eCj                  e[            a] e^ ej                  t        d9d:;             yeWj                  d<k(  rjeWj                  r^ eUeWj                        Z[ ej                  eCj                  eWj                  e[            a] e^ ej                  t        d9d:;             yeWj                  d=k(  r> ed=>      ZbeCj                  d?d@dAd?dBdCdCdDidEgiidFdGdHd@iiebI      D ]
  Zd e^ed        yyy)J    N)AnyDictIterableAsyncIterableAsyncGeneratorOptional)FastAPIHTTPExceptionRequest)StreamingResponseJSONResponse)RunnableConfig)
StateGraphEND)CompiledStateGraph)new_contextContext)graph_helper)LOG_FILE)setup_loggingrequest_context)	LOG_LEVEL)ErrorClassifierclassify_error)AgentStreamRunnerWorkflowStreamRunneragent_stream_handlerworkflow_stream_handlerRunOpti  @   T)log_file	max_bytesbackup_count	log_leveluse_json_formatconsole_output)to_stream_input)OpenAIChatHandler)LangGraphParser)extract_core_stack)init_run_configinit_agent_configi  c                   J   e Zd Zd ZefdZeddededefd       Z	d Z
efd	eeef   d
edee   fdZdd	eeef   deeef   fdZdd	eeef   dee   deedf   fdZddedee   deeef   fdZdded	eeef   defdZdefdZedfd	eeef   ded
edee   dee   f
dZy)GraphServicec                     i | _         t               | _        t               | _        t               | _        d | _        t        j                         | _
        y N)running_tasksr   error_classifierr   _agent_stream_runnerr   _workflow_stream_runner_graph	threadingLock_graph_lockselfs    /app/project/src/main.py__init__zGraphService.__init__-   sA    68 / 1$5$7!';'=$$>>+    c                 X   t        j                         rt        j                  d|      S | j                  | j                  S | j                  5  | j                  | j                  cd d d        S t        j
                  d      | _        | j                  cd d d        S # 1 sw Y   y xY w)Nzagents.agentzgraphs.graph)r   is_agent_projget_agent_instancer5   r8   get_graph_instance)r:   ctxs     r;   
_get_graphzGraphService._get_graph8   s~    %%'22>3GG;;";;{{&{{  '99.IDK;;	 s   B 1%B  B)Ndataevent_idreturnc                 Z    |rd| dnd}| dt        j                  | dt               dS )Nzid: 
 zevent: message
data: F)ensure_asciidefaultz

)jsondumpsstr)rD   rE   id_lines      r;   
_sse_eventzGraphService._sse_eventD   s8    )1D
"%r0Du^a1b0ccghhr=   c                 Z    t        j                         r| j                  S | j                  S r0   )r   r?   r3   r4   r9   s    r;   _get_stream_runnerzGraphService._get_stream_runnerI   s&    %%',,,///r=   payload
run_configc              #      K   | j                  |      }| j                         }|j                  ||||      D ]  }|  y wr0   )rC   rR   stream)r:   rS   rT   rB   graphstream_runnerchunks          r;   rV   zGraphService.streamP   sC     $//1"))'5*cJEK Ks   A Ac                 "  K   |t        d      }|j                  }t        j                  d|        	 | j	                  |      }t        ||      }d|j                  i|d<   |j                  |||       d {   | j                  j                  |d        S 7  # t        j                  $ r> t        j                  d| d       d|d	d
cY | j                  j                  |d        S t        $ rv}| j                  j                  |d|d      }t        j                  d|j                   d|j                    d|j"                  j$                   dt'                        d }~ww xY w# | j                  j                  |d        w xY ww)NrunzStarting run with run_id: 	thread_idconfigurable)configcontextzRun z was cancelled	cancelledExecution was cancelledstatusrun_idmessage	node_namerd   zError in GraphService.run: [] z
Category: z
Traceback:
)r   rd   loggerinforC   r+   ainvoker1   popasyncioCancelledError	Exceptionr2   classifyerrorcodere   categorynamer*   )r:   rS   rB   rd   rW   rT   eerrs           r;   r[   zGraphService.runW   sz    ;e$C09:	1OOC(E(4J*5szz)BJ~& wz3OO$ ""640% P%% 	cKK$vhn56)VHabb ""640  
	''00%SY4Z[CLL.sxxj3;;- H \\../ 01346 
	 ""640sZ   2FAB :B;B >FB 2E+E. F-E+5A1E&&E++E. .FFrun_optc                  K   |t        d      }|
t               }|j                  }t        j	                  d|        | j                  |      }t        j                         rt        ||      }nt        ||      }t        j                          }	 | j                  |||||      2 3 d {   }|r+t        |t              r|\  }	}
| j                  |
|	       6| j                  |       K7 F6 	 | j                  j                  |d        t!        j"                          y # | j                  j                  |d        t!        j"                          w xY ww)N
stream_ssemethodzStarting stream with run_id: )rT   rB   rw   )r   r   rd   ri   rj   rC   r   r?   r,   r+   astream
isinstancetuplerP   r1   rl   cozeloopflush)r:   rS   rB   rw   rd   rW   rT   is_workflowrY   rE   rD   s              r;   ry   zGraphService.stream_sse{   s(    ;\2C?hG3F8<=$%%'*5#6J(4J&4466
	#||GUzWZdk|l 1e:eU#;%*NHd//$99//%001l ""640NN ""640NNsC   BE D+ +C8/C60C83AD+ 6C88D+ :1E +2EE rd   rB   c                 `   t         j                  d|        || j                  v rk| j                  |   }|j                         s.|j	                          t         j                  d|        d|ddS t         j                  d|        d|ddS t         j                  d	|        d
|ddS )u   
        取消指定run_id的执行

        使用asyncio.Task.cancel()来取消任务,这是标准的Python异步取消机制。
        LangGraph会在节点之间检查CancelledError,实现优雅的取消。
        zAttempting to cancel run_id: z#Cancellation requested for run_id: successzDCancellation signal sent, task will be cancelled at next await pointrb   z#Task already completed for run_id: already_completedzTask has already completedz!No active task found for run_id: 	not_foundz\No active task found with this run_id. Task may have already completed or run_id is invalid.)ri   rj   r1   donecancelwarning)r:   rd   rB   tasks       r;   
cancel_runzGraphService.cancel_run   s     	3F8<= T'''%%f-D99; A&JK'$e  A&JK1$;  NN>vhGH% y r=   node_idc                 &  K   |t         j                  dk(  rt        d      }| j                         }t	        j
                  |j                         |      \  }}}||t        d| d      t        |      }|j                  |      xs i }	t        |||      }
|
j                  d||	       |
j                  d       |
j                  dt               |
j                         }t!        ||      }|j#                  ||	       d {   S 7 w)
NrI   node_runrz   	node_id 'z' not foundinput_schemaoutput_schemasn)metadata)r^   )r   rd   r   rC   r   get_graph_node_func_with_inout	get_graphKeyErrorr)   get_node_metadatar   add_nodeset_entry_pointadd_edger   compiler+   rk   )r:   r   rS   rB   r5   	node_func	input_cls
output_clsparserr   _grT   s               r;   run_nodezGraphService.run_node   s     ;'..B.Z0C"+7+V+VW]WgWgWikr+s(	9j	 1Ywi{;<< (++G4:		T
D)h7
4 
D#$VS1
^^GJ^????s   DD
DDc                    t        j                         ri i dS t        | j                         dd       }|St        |dd       xs | j                  j                         }t        |dd       xs | j                  j                         }nIt        j                  d       | j                  j                         }| j                  j                         }|j                         |j                         dddS )	Nr   builderr   r   zVNo builder input schema found for graph_inout_schema, using graph input schema insteadr   rI   )r   r   rr   msg)
r   r?   getattrrC   rW   get_input_schemaget_output_schemari   r   model_json_schema)r:   r   r   r   s       r;   graph_inout_schemazGraphService.graph_inout_schema   s    %%'$&<<$//+Y=>_$**B]B]B_I /4@bDJJD`D`DbJNNsu

335I557J &779'99;	
 	
r=   rW   c                z   K   | j                         }|j                  |||||      2 3 d {   }| 7 
6 y wr0   )rR   r|   )r:   rS   rW   rT   rB   rw   rX   rY   s           r;   r|   zGraphService.astream   s@     //1(00%SRYZ 	%K	Zs   &;979;9;r0   )NN)__name__
__module____qualname__r<   r   rC   staticmethodr   rN   rP   rR   r   r   r   rV   r[   r   r   r   ry   r   r   r   r   r   r|    r=   r;   r.   r.   ,   s   	, % 
 i i is i i0 OV d38n . ZbcfZg !1c3h !1d38n !1HS#X 8TZK[ guvy{v  hA :# #8G+< #SRUX #L@c @DcN @QT @*
C 
& qx  VZ T#s(^ <N \j   CK  LR  CS   _l  mp  _q r=   r.   zx-run-idz/runrequestrF   c           
        K   | j                          d {   }	 |j                  d      }t        d| j                        }| j                  j                  t              }|r||_        |j                  }t        j                  |       t        j                  d	| d
t!        | j"                         d|        	 | j%                          d {   }d|v r<t'        |d   t              r)|d   }dddd|idgii|d<   t        j                  d       t)        j*                  t,        j/                  ||            }	|	t,        j0                  |<   	 t)        j2                  |	t5        t6                     d {   at8        si at'        t8        t               r	|t8        d<   t8        tC        jD                          S 7 # t        $ r8}t        |      }t	        dd| dt        j                          d|       d }~ww xY w7 47 # t(        j:                  $ r} t        j=                  dt6         d|        |	j?                          	 |	 d {  7  an=# t(        j@                  $ r' d|dt6         ddcY cY tC        jD                          S w xY wY w xY w# t$        jF                  $ rJ}t        j=                  d| dt        j                                 t	        ddtI                      d }~wt(        j@                  $ r; t        j                  d|        d|ddat8        cY tC        jD                          S t        $ r}t,        jJ                  jM                  |d|d       }
t        j=                  d!|
d"    d#|
d$    dt        j                          d%&       t	        d'|
d"   |
d$   tI               d(      d }~ww xY w# tC        jD                          w xY ww))Nutf-8  Invalid JSON format: , traceback: 	, error: status_codedetailr[   r{   headersz"Received request for /run: run_id=, query=, body=contentqueryprompttexttyper   ;Normalized payload: converted string content to dict format)timeoutzRun execution timeout after zs for run_id: r   zExecution timeout: exceeded z secondsrb   rd   zJSON decode error in http_run: zInvalid JSON format, zRequest cancelled for run_id: r`   ra   http_runrf   zUnexpected error in http_run: [
error_coderh   error_messageTexc_info  r   r   stack_trace)'bodydecodero   rN   r
   	traceback
format_excr   r   getHEADER_X_RUN_IDrd   r   setri   rj   dictquery_paramsrL   r}   rm   create_taskservicer[   r1   wait_forfloatTIMEOUT_SECONDSresultTimeoutErrorrq   r   rn   r   r   JSONDecodeErrorr*   r2   get_error_response)r   raw_body	body_textru   rB   upstream_run_idrd   rS   text_contentr   error_responses              r;   r   r      s     \\^#HyOOG,	 UGOO
<Coo))/:O$
ZZF
KK g**+, -{	A& Jwy/A3$G"9-L!'V\4JK"GI KKUW ""7;;w#<=(,f%	"++D%:PQQF Ffd#%F86 	q $  yM	%:9+]S\SgSgSiRjjstusv#wy 	yy* '( R## 
	LL77HW]V^_`KKM#)) '$!=o=NhW J 	M 	
	$  d6qcyG[G[G]F^_`6KL^L`Ka4bcc!! 4VH=>'6F_`$ 	!  
 11DDQV`lrHst-n\.J-K2n]lNmMn o#..013=A 	 	
 ,\:!/!@13
 	

  	s  O)F?O)G BO)?J HB J 'H ;H	<H  *J *O)	H3G>>HO)J 	H AJIIIJ!J;J=J >O)JJJ JJ O1AK66:O0O 1O)OA:OOO O&&O)zx-workflow-stream-moderd   r   c                 *    |t         j                  | <   y r0   )r   r1   )rd   r   s     r;   _register_taskr   U  s    $(G&!r=   z/stream_runc                 @  K   t        d| j                        }| j                  j                  t              }|r||_        | j                  j                  t
        d      j                         }|dk(  }t        j                  |       | j                          d {   }	 |j                  d      }|j                  }t        j                          }	t"        j%                  d| d|	 dt'        | j(                         d|        	 | j+                          d {   }
d|
v r<t5        |
d   t              r)|
d   }dddd|idgii|
d<   t"        j%                  d       |	rAt7        |
||t8        j:                  t8        j<                  t8        j>                  t@              }nKtC        |
||t8        j:                  t8        j<                  t8        j>                  t@        tE        |            }tG        |d      }|S 7 a# t        $ r.}t        |      }t        dd| dt                d	| 
      d }~ww xY w7 # t*        j,                  $ rJ}t"        j/                  d| dt1        j2                                 t        ddt                
      d }~ww xY ww)N
stream_runr   rI   debugr   r   r   r   r   r   z)Received request for /stream_run: run_id=z, is_agent_project=r   r   z&JSON decode error in http_stream_run: Invalid JSON format:r   r   r   r   r   r   )rS   rB   rd   stream_sse_funcsse_event_funcr2   register_task_func)workflow_debug)rS   rB   rd   r   r   r2   r   rw   ztext/event-stream)
media_type)$r   r   r   r   rd   HEADER_X_WORKFLOW_STREAM_MODElowerr   r   r   r   ro   rN   r
   r*   r   r?   ri   rj   r   r   rL   r   rq   r   r   r}   r   r   ry   rP   r2   r   r   r   r   )r   rB   r   workflow_stream_moder   r   r   ru   rd   is_agentrS   r   stream_generatorresponses                 r;   http_stream_runr   Y  s    
\7??
CCoo))/:O$
"??../LbQWWY)W4N\\^#HwOOG,	
 ZZF))+H
KK $: &g**+, -{		c& G
79+=s Cy)#0FG
	 	QS/#.."--$55-
 3#.."--$55-.9	
 !!1>QRHOu $  wM	%:9+]SeSgRhhqrsqt#uw 	ww ' c=aSiNbNbNdMefg6JK]K_J`4abbcso   BJG>J#H 4AJ	H> H;H> !CJ	H8
)H33H88J;H> >JAJJJz/cancel/{run_id}c                    K   t        d|j                        }t        j                  |       t        j                  d|         t        j                  | |      }|S w)u   
    取消指定run_id的执行

    使用asyncio.Task.cancel()实现取消,这是Python标准的异步任务取消机制。
    LangGraph会在节点之间的await点检查CancelledError,实现优雅取消。
    r   r   z$Received cancel request for run_id: )r   r   r   r   ri   rj   r   r   )rd   r   rB   r   s       r;   http_cancelr     sQ      Xw
?C
KK6vh?@,FMs   AAz/node_run/{node_id})pathr   c           
      Z  K   |j                          d {   }	 |j                  d      }t        d|j                        }t        j                  |       t        j                  d|  dt        |j                         d	|        	 |j                          d {   }	 t&        j)                  | ||       d {   t+        j,                          S 7 # t        $ r t        |      }t	        dd|       w xY w7 b# t        j                  $ rJ}t        j                  d
| dt!        j"                                 t	        ddt%                      d }~ww xY w7 # t.        $ r t	        dd|  dt%                      t0        $ r~}t&        j2                  j5                  |d| i      }t        j                  d|d    d|d    dt!        j"                          d       t	        d|d   |d   t%               d      d }~ww xY w# t+        j,                          w xY ww)Nr   r   r   r   r   r   zReceived request for /node_run/z: query=r   z$JSON decode error in http_node_run: r   r   i  r   z6' not found or input miss required fields, traceback: rg   z$Unexpected error in http_node_run: [r   rh   r   Tr   r   r   )r   r   UnicodeDecodeErrorrN   r
   r   r   r   r   ri   rj   r   r   rL   r   rq   r   r   r*   r   r   r   r   r   ro   r2   r   )r   r   r   r   rB   rS   ru   r   s           r;   http_node_runr     sA    \\^#HYOOG,	 Z
AC
KK
)' 3g**+, -{	c&%%gw<<( 	Q $  YM	6KI;4WXXY ' c;A3mIL`L`LbKcde6JK]K_J`4abbc = F%.wi7m  oA  oC  nD  $EF 	F 
 11DDQV]H^_2>,3O2PPRSabqSrRs t#..013=A 	 	
 ,\:!/!@13
 	

  	s   H+CH+C AH+D DD $E% >E#?E% H+%C>>H+D E AEE  H+#E% %,HA9H

HH H((H+z/v1/chat/completionsc                   K   t        d| j                        }t        j                  |       t        j                  d|j                          	 | j                          d{   }t        j                  ||       d{   t        j                          S 7 67 # t        j                  $ r*}t        j                  d|        t        dd      d}~ww xY w# t        j                          w xY ww)	u(   OpenAI Chat Completions API 兼容接口openai_chatr   z2Received request for /v1/chat/completions: run_id=Nz.JSON decode error in openai_chat_completions: r   zInvalid JSON formatr   )r   r   r   r   ri   rj   rd   rL   openai_handlerhandler   r   r   rq   r
   )r   rB   rS   ru   s       r;   openai_chat_completionsr    s      ]GOO
DC
KKDSZZLQR&#**7C88
 	 '8 KEaSIJ4IJJK 	sZ   AC9B  %B&B  BB  C9B  B   C3%CCC   C66C9z/healthc                  d   K   	 dddS # t         $ r} t        dt        |             d } ~ ww xY ww)NokzService is running)rc   re   i  r   )ro   r
   rN   )ru   s    r;   health_checkr    s?     < +
 	
  <CF;;<s   0	 0	-(-0z/graph_parameterc                 2   K   t         j                         S wr0   )r   r   )r   s    r;   http_graph_inout_parameterr    s     %%''s   c                     t        j                  d      } | j                  dt        dd       | j                  dt        dd	       | j                  d
t        dd       | j                  dt        dd       | j                         S )NzStart FastAPI server)descriptionz-mhttpz Run mode, support http,flow,node)r   rK   helpz-nrI   zNode ID for single node runz-pi  zHTTP server portz-iz$Input JSON string for flow/node mode)argparseArgumentParseradd_argumentrN   int
parse_args)r   s    r;   r  r    s    $$1GHF
3=_`
39VW
3;MN
39_`r=   	input_strc                 t    | sddiS 	 t        j                  |       S # t         j                  $ r d| icY S w xY w)z;Parse input string, support both JSON string and plain textr      你好)rL   loadsr   )r  s    r;   parse_inputr    sD    !!#zz)$$ #	""#s    77c                     d}d}t        j                         rd}t        j                  d|  d|        t	        j
                  dd| ||       y )	N   FTzStart HTTP Server, Port: z, Workers: zmain:appz0.0.0.0)hostportreloadworkers)r   
is_dev_envri   rj   uvicornr[   )r  r  r  s      r;   start_http_serverr    sK    GF 
KK+D6WIFGKK
fgVr=   __main__r	  flowF   )rJ   indentnodeagentrz   r   1r  r   r   u3   现在几点了？请调用工具获取当前时间r   )r   
session_idre   r   r]   r%  )rT   rB   )er  rm   rL   r6   r   loggingtypingr   r   r   r   r   r   r   r  timefastapir	   r
   r   fastapi.responsesr   r   langchain_core.runnablesr   langgraph.graphr   r   langgraph.graph.stater   %coze_coding_utils.runtime_ctx.contextr   r   coze_coding_utils.helperr   coze_coding_utils.log.node_logr   coze_coding_utils.log.write_logr   r   coze_coding_utils.log.configr   "coze_coding_utils.error.classifierr   r   &coze_coding_utils.helper.stream_runnerr   r   r   r   r   	getLoggerr   ri   %coze_coding_utils.helper.agent_helperr'    coze_coding_utils.openai.handlerr(   coze_coding_utils.log.parserr)   coze_coding_utils.log.err_tracer*    coze_coding_utils.log.loop_tracer+   r,   r   r.   r   appr   r   postrN   r   r   Taskr   r   r   r   r  r   r  r  r  r  r  argsmpirS   r[   r   printrM   nr   	agent_ctxrV   rY   r   r=   r;   <module>rE     s         O O    3 3 = 3 + 4 F 1 3 J 2 N P  P  
		8	$ A > 8 > O } }@ .i #7+ &ZG ZS#X Z Zz !9 )3 )gll ) -C7 C CJ 
c G   $%) )w ) &)X 
 !7  "" < <  !(g ( "(
#3 
#4S> 
#W z<Dvv$&&!	6	dff%W[[12jdjjeA>?	6	dffdff%W--dffg>?jdjjeA>?	7	w/	^^#"%'$,2068m/n!"'"	 	 +\3,?@# $ 
E& %L'
 
 r=   