@@ -5,10 +5,13 @@ import (
55 "errors"
66 "fmt"
77 "strings"
8+ "time"
89
910 agentsession "neo-code/internal/session"
1011)
1112
13+ const prepareEventEmitTimeout = 200 * time .Millisecond
14+
1215// NewSessionInputPreparer 创建基于 session 子层实现的输入归一化适配器。
1316func NewSessionInputPreparer (store agentsession.Store , assetStore agentsession.AssetStore ) UserInputPreparer {
1417 return sessionInputPreparer {
@@ -51,7 +54,7 @@ func (s *Service) PrepareUserInput(ctx context.Context, input PrepareInput) (Use
5154 }
5255
5356 runID := strings .TrimSpace (input .RunID )
54- _ = s .emit (ctx , EventInputNormalized , runID , prepared .UserInput .SessionID , InputNormalizedPayload {
57+ _ = s .emitPrepareEvent (ctx , EventInputNormalized , runID , prepared .UserInput .SessionID , InputNormalizedPayload {
5558 TextLength : len ([]rune (strings .TrimSpace (input .Text ))),
5659 ImageCount : len (input .Images ),
5760 })
@@ -60,7 +63,7 @@ func (s *Service) PrepareUserInput(ctx context.Context, input PrepareInput) (Use
6063 if index >= 0 && index < len (input .Images ) {
6164 path = strings .TrimSpace (input .Images [index ].Path )
6265 }
63- _ = s .emit (ctx , EventAssetSaved , runID , prepared .UserInput .SessionID , AssetSavedPayload {
66+ _ = s .emitPrepareEvent (ctx , EventAssetSaved , runID , prepared .UserInput .SessionID , AssetSavedPayload {
6467 Index : index ,
6568 Path : path ,
6669 AssetID : asset .ID ,
@@ -86,13 +89,31 @@ func (s *Service) emitPrepareFailure(ctx context.Context, input PrepareInput, er
8689 if session := strings .TrimSpace (saveErr .SessionID ); session != "" {
8790 sessionID = session
8891 }
89- return s .emit (ctx , EventAssetSaveFailed , runID , sessionID , AssetSaveFailedPayload {
92+ return s .emitPrepareEvent (ctx , EventAssetSaveFailed , runID , sessionID , AssetSaveFailedPayload {
9093 Index : saveErr .Index ,
9194 Path : strings .TrimSpace (saveErr .Path ),
9295 Message : strings .TrimSpace (saveErr .Error ()),
9396 })
9497 }
95- return s .emit (ctx , EventError , runID , sessionID , strings .TrimSpace (err .Error ()))
98+ return s .emitPrepareEvent (ctx , EventError , runID , sessionID , strings .TrimSpace (err .Error ()))
99+ }
100+
101+ // emitPrepareEvent 在输入归一化阶段使用限时上下文发事件,避免通道拥塞导致提交链路卡死。
102+ func (s * Service ) emitPrepareEvent (ctx context.Context , kind EventType , runID string , sessionID string , payload any ) error {
103+ emitCtx := ctx
104+ cancel := func () {}
105+ if _ , hasDeadline := emitCtx .Deadline (); ! hasDeadline {
106+ emitCtx , cancel = context .WithTimeout (emitCtx , prepareEventEmitTimeout )
107+ }
108+ defer cancel ()
109+
110+ if err := s .emit (emitCtx , kind , runID , sessionID , payload ); err != nil {
111+ if errors .Is (err , context .DeadlineExceeded ) || errors .Is (err , context .Canceled ) {
112+ return nil
113+ }
114+ return err
115+ }
116+ return nil
96117}
97118
98119type sessionInputPreparer struct {
0 commit comments