fix: SSE keepalive, request timeout, NoOp task store caching, and Docker tooling

- Add SSE keepalive middleware (15s comment heartbeat) to prevent Cloud Run
  LB from closing idle SSE connections during long tool executions
- Increase A2A server request timeout from 300s to 3600s (1 hour)
- Cache loaded tasks in NoOpTaskStore to prevent redundant GCS workspace
  restores on every SDK event cycle (was restoring 5+ times per request)
- Add undici dispatcher with 10-min timeouts for bridge SSE connections
- Install gh CLI and gcloud CLI in Docker image for agent GitHub/GCP access
This commit is contained in:
Adam Weidman
2026-02-20 10:02:13 -05:00
parent 305a47e5b5
commit bb379102d6
4 changed files with 67 additions and 5 deletions
+23
View File
@@ -206,6 +206,29 @@ export async function createApp() {
requestStorage.run({ req }, next);
});
// SSE keepalive — sends periodic comment lines to prevent Cloud Run's
// load balancer from closing idle SSE connections during long tool
// executions (npm install, tsc builds, etc.). SSE comments (`: ...`)
// are ignored by conformant parsers per the spec.
expressApp.use((req, res, next) => {
const origFlush = res.flushHeaders;
res.flushHeaders = function (this: express.Response) {
origFlush.call(this);
const ct = this.getHeader('content-type');
if (ct && String(ct).includes('text/event-stream')) {
const timer = setInterval(() => {
if (!res.writableEnded) {
res.write(': keepalive\n\n');
} else {
clearInterval(timer);
}
}, 15_000);
res.on('close', () => clearInterval(timer));
}
};
next();
});
// Google Chat bridge runs as a separate service (src/chat-bridge/server.ts).
// It connects to this A2A server over HTTP.
const appBuilder = new A2AExpressApp(requestHandler);