@@ -89,6 +89,10 @@ type fakeRunner struct {
8989 err error
9090}
9191
92+ type ctxCapturingRunner struct {
93+ ctx context.Context
94+ }
95+
9296func (f * fakeRunner ) Run (ctx context.Context , userID string , sessionID string , message model.Message , runOpts ... agent.RunOption ) (<- chan * event.Event , error ) {
9397 if f .err != nil {
9498 return nil , f .err
@@ -105,6 +109,23 @@ func (f *fakeRunner) Run(ctx context.Context, userID string, sessionID string, m
105109
106110func (f * fakeRunner ) Close () error { return nil }
107111
112+ func (f * ctxCapturingRunner ) Run (
113+ ctx context.Context ,
114+ userID string ,
115+ sessionID string ,
116+ message model.Message ,
117+ runOpts ... agent.RunOption ,
118+ ) (<- chan * event.Event , error ) {
119+ f .ctx = ctx
120+ ch := make (chan * event.Event )
121+ close (ch )
122+ return ch , nil
123+ }
124+
125+ func (f * ctxCapturingRunner ) Close () error {
126+ return nil
127+ }
128+
108129type flushRecorder struct {
109130 * httptest.ResponseRecorder
110131}
@@ -1435,6 +1456,82 @@ func TestHandleRunSSE_NonStreaming(t *testing.T) {
14351456 assert .Contains (t , w .Body .String (), "data: " )
14361457}
14371458
1459+ func TestNewDetachedContextPreservesValues (t * testing.T ) {
1460+ type ctxKey struct {}
1461+ key := ctxKey {}
1462+ parent , cancel := context .WithCancel (
1463+ context .WithValue (context .Background (), key , "trace-id" ),
1464+ )
1465+ cancel ()
1466+
1467+ ctx := newDetachedContext (parent )
1468+
1469+ assert .Equal (t , "trace-id" , ctx .Value (key ))
1470+ _ , ok := ctx .Deadline ()
1471+ assert .False (t , ok )
1472+ assert .Nil (t , ctx .Done ())
1473+ assert .Nil (t , ctx .Err ())
1474+
1475+ err := agent .CheckContextCancelled (ctx )
1476+ assert .NoError (t , err )
1477+ }
1478+
1479+ func TestHandleRunSSE_UsesDetachedContext (t * testing.T ) {
1480+ type ctxKey struct {}
1481+ key := ctxKey {}
1482+
1483+ ctxRunner := & ctxCapturingRunner {}
1484+ server := & Server {
1485+ agents : map [string ]agent.Agent {},
1486+ router : mux .NewRouter (),
1487+ runners : map [string ]runner.Runner {"app" : ctxRunner },
1488+ sessionSvc : sessioninmemory .NewSessionService (),
1489+ traces : map [string ]attribute.Set {},
1490+
1491+ memoryExporter : newInMemoryExporter (),
1492+ }
1493+
1494+ reqBody := schema.AgentRunRequest {
1495+ AppName : "app" ,
1496+ UserID : "user" ,
1497+ SessionID : "sess" ,
1498+ NewMessage : schema.Content {
1499+ Role : "user" ,
1500+ Parts : []schema.Part {{Text : "hi" }},
1501+ },
1502+ Streaming : true ,
1503+ }
1504+ body , err := json .Marshal (reqBody )
1505+ require .NoError (t , err )
1506+
1507+ baseCtx , cancel := context .WithCancel (
1508+ context .WithValue (context .Background (), key , "trace-id" ),
1509+ )
1510+ cancel ()
1511+
1512+ req := httptest .NewRequest (
1513+ http .MethodPost ,
1514+ "/run_sse" ,
1515+ bytes .NewReader (body ),
1516+ ).WithContext (baseCtx )
1517+ req .Header .Set ("Content-Type" , "application/json" )
1518+ w := & flushRecorder {ResponseRecorder : httptest .NewRecorder ()}
1519+
1520+ server .handleRunSSE (w , req )
1521+
1522+ assert .Equal (t , http .StatusOK , w .Code )
1523+ if assert .NotNil (t , ctxRunner .ctx ) {
1524+ assert .Equal (t , "trace-id" , ctxRunner .ctx .Value (key ))
1525+ _ , ok := ctxRunner .ctx .Deadline ()
1526+ assert .False (t , ok )
1527+ assert .Nil (t , ctxRunner .ctx .Done ())
1528+ assert .Nil (t , ctxRunner .ctx .Err ())
1529+
1530+ err = agent .CheckContextCancelled (ctxRunner .ctx )
1531+ assert .NoError (t , err )
1532+ }
1533+ }
1534+
14381535func TestServerGetRunnerCache (t * testing.T ) {
14391536 server := New (map [string ]agent.Agent {
14401537 "app" : & mockAgent {name : "app" },
0 commit comments