Skip to main content
DevOps9 min read

Streaming-First CI “AI Steps” with WebSockets: Lower Latency, Fewer Timeouts, Better Logs, and Predictable Cost

AI steps inside CI/CD often fail for the same reasons as flaky integration tests: slow feedback, brittle timeouts, and poor observability. With OpenAI introducing a WebSocket-based execution mode aimed at reducing latency in agentic workflows, teams can redesign “AI steps” to be streaming-first—improving responsiveness, failure handling, and cost control without sacrificing reproducibility.

CI pipelines were built for deterministic tasks: compile, test, package, deploy. But as more teams embed “AI steps” into build/test/release and operations (triaging failures, proposing upgrades, generating migration diffs, writing release notes, or reviewing risky changes), the pipeline shape starts to look less like batch processing and more like an interactive session.

That mismatch is where most “flaky AI step” incidents come from: a long-running request hits a timeout, retries silently multiply cost, logs arrive too late to debug, and the whole job fails with little context. The good news is that the underlying execution model is catching up. OpenAI has introduced a WebSocket-based execution mode designed to reduce latency in agentic workflows—specifically targeting agent-style interactions where responsiveness and incremental progress matter (as reported by InfoQ).

This post breaks down what “streaming-first” means for CI, why WebSockets change the design constraints, and how to implement timeouts, retries, logs, and cost controls that make AI automation supportable in production—especially for software maintenance and modernization work.

Context: why CI “AI steps” feel flaky

Streaming-First CI “AI Steps” with WebSockets: Lower Latency, Fewer Timeouts, Better Logs, and Predictable Cost
Streaming-First CI “AI Steps” with WebSockets: Lower Latency, Fewer Timeouts, Better Logs, and Predictable Cost

Many AI-in-CI integrations are built like this:

  1. Gather a big bundle of context (logs, diffs, test results, repo files).
  2. Send one large request.
  3. Wait.
  4. Parse one large response.

That pattern is natural when you’re calling an API over HTTP request/response. But it’s a poor fit for agentic workflows where the system may:

  • ask for additional context (“show me the failing test output,” “open this file,” “what is the dependency tree?”)
  • produce partial progress (a plan, then an action, then a patch)
  • stream logs and intermediate reasoning that operators need to see

In practice, you get familiar failure modes:

  • Timeouts and premature aborts: a single long request exceeds CI job limits or reverse proxy timeouts.
  • Retries that amplify cost: CI retries re-run the same expensive step, often without deduplication.
  • Opaque logs: engineers see nothing until the end, which makes it hard to debug or to trust outcomes.
  • Non-reproducibility: re-running the same job yields different outputs because the interaction wasn’t captured as a sequence of events.

InfoQ’s coverage of OpenAI’s WebSocket-based execution mode points at the core issue: agent-style interactions need responsiveness and incremental progress, not just an eventual response. Lower latency isn’t only about speed—it’s about control.

What changes with WebSocket execution mode

With WebSockets, the integration becomes a live, bidirectional channel:

  • The model can start emitting output immediately.
  • Your system can stream additional context or tool results as they’re produced.
  • You can enforce backpressure: if your CI runner or log collector can’t keep up, you can slow down ingestion rather than crash.

From a pipeline perspective, this is less like “call an API” and more like “run a subprocess with structured stdout/stderr.” That mental model unlocks better operational patterns.

Why lower latency matters in agentic workflows

Agentic steps are often gated by a tight feedback loop:

  • propose a change → run tests → react to failures → adjust patch

If each iteration blocks on a long response, the whole loop becomes expensive and brittle. WebSocket streaming helps in three ways:

  1. Faster first token / first event: operators see immediate progress.
  2. Incremental results: you can decide to stop early if the step is going off-track.
  3. More resilient execution: you can recover from partial failure without restarting the entire step.

This aligns with broader “engineering at AI speed” conversations (also covered by InfoQ) where teams learn to shorten feedback cycles and keep automation observable.

Redesigning CI “AI steps” to be streaming-first

Treat your AI step like a long-running job with a stream of structured events. The objective is not merely to display a transcript—it’s to make the step operationally legible.

1) Streaming logs: separate “operator logs” from “artifact logs”

A streaming-first AI step should produce two log channels:

  • Operator logs (live): short, continuous updates suitable for CI consoles (e.g., GitHub Actions, GitLab, Jenkins). Examples: “analyzing dependency graph…”, “proposed 3-file patch…”, “running unit tests…”.
  • Artifact logs (persisted): a full event trace stored as an artifact (JSONL works well), including inputs, tool calls, partial outputs, and final results.

Why two channels?

  • CI consoles have limits (line truncation, retention, redaction constraints).
  • Post-incident analysis needs a stable artifact for reproducibility.

Actionable pattern: log structured events, not just text. For example:

  • phase_started: analyze
  • tool_call: read_file(path)
  • tool_result: read_file(success, bytes)
  • partial_output: patch_diff
  • decision: abort(reason=budget_exceeded)

This design also supports modernization workflows: when the AI proposes an upgrade patch, the patch diff and the decision trail become part of the maintenance record.

2) Backpressure: don’t let streaming become a failure amplifier

Streaming can overwhelm downstream systems:

  • CI log collectors
  • internal event buses
  • your own WebSocket client

Backpressure is your friend. Your “AI step runner” should be able to:

  • pause consumption when buffers fill
  • drop or compress low-value log events (e.g., repeated status updates)
  • enforce an upper bound on in-flight tool results

Actionable pattern: implement a bounded queue for events and a “log sampling” policy:

  • always keep errors
  • sample verbose progress messages
  • summarize long outputs (e.g., cap stack traces, store full content as artifact)

This turns WebSockets into a controlled stream instead of an uncontrolled firehose.

3) Timeouts: replace one big timeout with phase budgets

Batch HTTP calls encourage a single timeout like “120 seconds.” Streaming-first steps should use phase-based budgets:

  • connect budget (e.g., 5s)
  • first-event budget (e.g., 10s to see any progress)
  • analysis budget (e.g., 60–180s depending on repo size)
  • patch budget (e.g., 60s)
  • test/run budget (e.g., bounded by CI job limits)

If a phase exceeds budget, you can:

  • request a summary of progress so far
  • gracefully abort with a clear reason
  • emit partial artifacts (e.g., “here’s the proposed patch but tests weren’t run”)

This is a major reducer of “flaky AI step” incidents: instead of “step timed out,” you get “analysis phase exceeded 120s; returning partial plan and stopping.”

4) Retries: make them idempotent, resumable, and cost-aware

Retries are necessary—networks fail, CI runners restart. But naive retries double (or triple) spend.

A streaming-first AI step should define resume semantics:

  • checkpoint at phase boundaries
  • persist the event trace (inputs + tool results)
  • on retry, replay the trace rather than re-fetching everything

Actionable pattern: design your step as a state machine:

  • INIT → CONTEXT_READY → ANALYZED → PATCH_PROPOSED → TESTED → DONE

On retry:

  • resume from the last completed state
  • re-run only the missing phases
  • if inputs changed (new commit SHA, different lockfile), invalidate and restart cleanly

This approach is especially valuable for maintenance automation where changes are frequent and failures are common: dependency upgrades, security patching, and refactoring tasks should be resumable and auditable.

5) Cost controls: token budgets, early exits, and “stop-the-bleed” mechanisms

Lower latency is great, but streaming can also make it easier to spend continuously unless you set hard limits.

Implement cost controls at three levels:

a) Per-step budgets

Define a maximum spend (or token budget) per CI job, per repo, or per PR. If the step crosses the limit, stop and emit:

  • a partial summary
  • the point of failure
  • next recommended action

b) Incremental “value checks”

Don’t wait until the end to decide if the step was worth it. Examples:

  • If the model can’t identify the failing test within N seconds, abort and ask for human input.
  • If the upgrade touches more than N files, require manual approval.

c) Deduplicate repeated work

Cache expensive context building:

  • dependency graphs
  • SBOMs
  • lint/test summaries

In a modernization platform like Vibgrate, this caching is a force multiplier: maintenance automation becomes predictable when you reuse computed context across runs.

Practical implications for engineering teams

Moving to WebSockets isn’t just an SDK change; it’s a pipeline design change.

Observability: treat AI steps like production services

If an AI step can change code, it deserves production-grade telemetry:

  • event traces as artifacts
  • metrics: time-to-first-event, phase durations, retry counts, abort reasons
  • spend metrics correlated to repo, branch, and workflow type

This supports the “verification over trust” mindset increasingly emphasized in software supply chains: don’t trust an AI patch because it sounds right—verify with tests, policy checks, and auditable traces.

Reproducibility: capture interactions, not just outputs

For maintenance and modernization, reproducibility is everything. A patch that can’t be explained or replayed becomes a long-term liability.

Streaming-first design helps by capturing:

  • every tool call and result
  • the exact diff proposed
  • the gating checks performed

You can then answer: “Why did this change happen?” and “Can we recreate it on a new version?”

Failure handling: graceful degradation beats hard failure

A mature AI step does not have only two outcomes (success/fail). It can degrade:

  • return a diagnosis without a patch
  • return a patch without tests
  • return a plan and required human inputs

This keeps CI moving while preserving safety.

A streaming-first blueprint for CI “AI steps”

If you’re implementing this now, aim for these building blocks:

  1. WebSocket session manager with reconnect + resume support
  2. Event schema (JSON) for logs, tool calls, and results
  3. Phase state machine with checkpoints
  4. Budget enforcer (time + cost)
  5. Artifact exporter (event trace + patch diff + summaries)
  6. Policy gates (file touch limits, approval thresholds, test requirements)

Even if you don’t adopt every component immediately, designing toward them prevents the common trap: a brittle “AI step” that becomes an always-red pipeline liability.

Conclusion: WebSockets push CI automation from batch to interactive

InfoQ’s report on OpenAI’s WebSocket-based execution mode highlights a shift toward lower-latency agentic workflows—exactly the kind of interaction pattern CI “AI steps” have been faking with long-running HTTP calls. For engineering leaders, the opportunity isn’t just faster outputs; it’s a more controllable, observable, and supportable automation layer.

Teams that redesign pipelines to be streaming-first—phase budgets, resumable retries, structured logs, backpressure, and cost guardrails—will see fewer flaky incidents and more trustworthy maintenance automation. As modernization work accelerates (dependency upgrades, platform migrations, security patches), these patterns turn AI from a demo into durable infrastructure.

Source: InfoQ, “OpenAI Introduces Websocket-Based Execution Mode to Reduce Latency in Agentic Workflows” (May 2026): https://www.infoq.com/news/2026/05/openai-websocket-responses-api/

Vibgrate CLI

See a real scan run

A replay of the actual CLI running against our test repositories — live progress, real findings, a genuine DriftScore. Nothing executes in your browser.

Replay
demo@vibgrate — bash
npx @vibgrate/cli scan
 
╭──────────────────────────────────────────╮
Vibgrate Drift Report
╰──────────────────────────────────────────╯
 
── node-turborepo (node) .
Runtime: >=18.0.0 (6 majors behind)
Frameworks:
Turbo: 1.13.4 → 2.10.11 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
1 current 1 1-behind 3 2+ behind 1 unknown
 
── @repo/admin (node) apps/admin
Frameworks:
TanStack Query: 5.101.4 → 5.101.4 (current)
React: 18.3.1 → 19.2.8 (1 behind)
React DOM: 18.3.1 → 19.2.8 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Vite: 5.4.21 → 8.2.1 (3 behind)
Dependencies:
3 current 9 1-behind 3 2+ behind 4 unknown
 
── @repo/api (node) apps/api
Frameworks:
Express: 4.22.2 → 5.2.1 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Vitest: 1.6.1 → 4.1.11 (3 behind)
Dependencies:
7 current 5 1-behind 3 2+ behind 4 unknown
 
── @repo/web (node) apps/web
Frameworks:
Next.js: 14.2.35 → 16.3.1 (2 behind)
React: 18.3.1 → 19.2.8 (1 behind)
React DOM: 18.3.1 → 19.2.8 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
2 current 6 1-behind 3 2+ behind 5 unknown
 
── @repo/config (node) packages/config
Frameworks:
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
2 current 2 1-behind 5 2+ behind 0 unknown
 
── @repo/database (node) packages/database
Frameworks:
Prisma: 5.22.0 → 7.9.1 (2 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
1 current 0 1-behind 3 2+ behind 1 unknown
 
── @repo/types (node) packages/types
Frameworks:
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
0 current 0 1-behind 1 2+ behind 1 unknown
 
── @repo/ui (node) packages/ui
Frameworks:
React: 18.3.1 → 19.2.8 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
React: 18.3.1 → 19.2.8 (1 behind)
Dependencies:
1 current 4 1-behind 1 2+ behind 1 unknown
 
── @repo/utils (node) packages/utils
Frameworks:
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Vitest: 1.6.1 → 4.1.11 (3 behind)
Dependencies:
0 current 1 1-behind 2 2+ behind 1 unknown
 
Tech Stack
Frontend: React, React DOM
Meta-frameworks: Next.js
Bundlers: tsx, Turbo, Vite
CSS / UI: Autoprefixer, PostCSS, Tailwind CSS
Backend: Express
ORM / Database: Prisma, Prisma Client
Testing: Vitest
Lint & Format: ESLint, ESLint Prettier, ESLint React, Prettier, typescript-eslint
 
Services & Integrations
Auth: JWT 9.0.3
Databases: Prisma 5.22.0
 
TypeScript
v5.3.3 · strict ✔ · MIXED · target: ES2022
 
Build & Deploy
Package Managers: pnpm
Monorepo: npm-workspaces, pnpm-workspaces, turbo
 
Product Purpose Signals
Frameworks: react, nextjs
Evidence: 177
Top Signals:
- [heading] Dashboard (apps/admin/src/pages/Dashboard.tsx)
- [title] Revenue Overview (apps/admin/src/pages/Dashboard.tsx)
- [copy] workspace:* (packages/ui/package.json)
- [copy] ./dist (packages/ui/tsconfig.json)
- [copy] ./src/index.ts (packages/ui/package.json)
- [copy] @repo/config/tsconfig-base.json (packages/ui/tsconfig.json)
- [copy] @repo/ui (packages/ui/package.json)
- [copy] #3b82f6 (apps/admin/src/pages/Dashboard.tsx)
Unknowns:
- No pricing or billing evidence found.
- No integrations/connectors evidence found.
- No route structure evidence found.
 
Security Posture
Lockfile ✖ · .env ✔ · node_modules ✔
 
Platform
Native modules: turbo
 
Code Quality
Files: 36 · Functions: 183 · Avg complexity: 2.62 · Avg length: 21.13 lines
Max nesting: 2 · Circular deps: 0 · Dead code: 0%
God files: apps/admin/src/pages/Products (448 lines)
 
Database Schema
postgresql · 8 models · 1 enum
Models: Address, CartItem, Category, Order, OrderItem (+3 more)
 
Findings (16 errors, 11 warnings)
Node.js runtime ">=18.0.0" reached end-of-life on 2025-04-30 (latest: 24.0.0).
vibgrate/runtime-eol in .
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in .
60% of dependencies are 2+ major versions behind in node-turborepo.
vibgrate/dependency-rot in .
@types/node is 6 major versions behind (spec: ^20.11.0, latest: 26.2.0).
vibgrate/dependency-major-lag in .
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in apps/admin
Vite is 3 major versions behind (current: 5.4.21, latest: 8.2.1).
vibgrate/framework-major-lag in apps/admin
vite is 3 major versions behind (spec: ^5.0.12, latest: 8.2.1).
vibgrate/dependency-major-lag in apps/admin
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in apps/api
Vitest is 3 major versions behind (current: 1.6.1, latest: 4.1.11).
vibgrate/framework-major-lag in apps/api
@types/node is 6 major versions behind (spec: ^20.11.0, latest: 26.2.0).
vibgrate/dependency-major-lag in apps/api
vitest is 3 major versions behind (spec: ^1.2.1, latest: 4.1.11).
vibgrate/dependency-major-lag in apps/api
Next.js is 2 major versions behind (current: 14.2.35, latest: 16.3.1).
vibgrate/framework-major-lag in apps/web
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in apps/web
@types/node is 6 major versions behind (spec: ^20.11.0, latest: 26.2.0).
vibgrate/dependency-major-lag in apps/web
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/config
56% of dependencies are 2+ major versions behind in @repo/config.
vibgrate/dependency-rot in packages/config
eslint-plugin-react-hooks is 3 major versions behind (spec: ^4.6.0, latest: 7.1.1).
vibgrate/dependency-major-lag in packages/config
Prisma is 2 major versions behind (current: 5.22.0, latest: 7.9.1).
vibgrate/framework-major-lag in packages/database
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/database
75% of dependencies are 2+ major versions behind in @repo/database.
vibgrate/dependency-rot in packages/database
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/types
100% of dependencies are 2+ major versions behind in @repo/types.
vibgrate/dependency-rot in packages/types
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/ui
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/utils
Vitest is 3 major versions behind (current: 1.6.1, latest: 4.1.11).
vibgrate/framework-major-lag in packages/utils
67% of dependencies are 2+ major versions behind in @repo/utils.
vibgrate/dependency-rot in packages/utils
vitest is 3 major versions behind (spec: ^1.2.1, latest: 4.1.11).
vibgrate/dependency-major-lag in packages/utils
 
╭──────────────────────────────────────────╮
Top Priority Actions
╰──────────────────────────────────────────╯
 
1. Upgrade EOL runtime in node-turborepo
End-of-life runtimes no longer receive security patches and block ecosystem upgrades.
./.
>=18.0.0 → 24.0.0 (6 majors behind)
Impact: −10 drift points (runtime & EOL)
 
2. Fix security posture: no lockfile found
Without a lockfile, installs are non-deterministic. Run the install command to generate one and commit it.
./
Missing: package-lock.json, pnpm-lock.yaml, or yarn.lock
 
3. Upgrade Vite 5.4.21 → 8.2.1 in @repo/admin (+2 more)
3 major versions behind. Major framework drift increases breaking change risk and blocks access to security fixes and performance improvements.
./apps/admin
Vite: 5.4.21 → 8.2.1 (3 majors behind)
./apps/api
Vitest: 1.6.1 → 4.1.11 (3 majors behind)
./packages/utils
Vitest: 1.6.1 → 4.1.11 (3 majors behind)
Impact: −5–15 drift points
 
4. Reduce dependency rot in @repo/types (100% severely outdated)
1 of 1 dependencies are 2+ majors behind. Run `npm outdated` and prioritise packages with known CVEs or breaking API changes.
./packages/types
typescript: 5.9.3 → 7.0.2 (2 majors behind)
Impact: −5–10 drift points
 
5. Reduce dependency rot in @repo/database (75% severely outdated)
3 of 4 dependencies are 2+ majors behind. Run `npm outdated` and prioritise packages with known CVEs or breaking API changes.
./packages/database
@prisma/client: 5.22.0 → 7.9.1 (2 majors behind)
prisma: 5.22.0 → 7.9.1 (2 majors behind)
typescript: 5.9.3 → 7.0.2 (2 majors behind)
Impact: −5–10 drift points
 
╭──────────────────────────────────────────╮
Architecture Layers
╰──────────────────────────────────────────╯
 
Archetype: nextjs (80% confidence)
Files classified: 24 (11 unclassified)
Folders classified: 8
apps/admin/src presentation 100% 4 files
apps/admin/src/pages presentation 100% 2 files
apps/api/src/middleware middleware 100% 2 files
apps/api/src/routes routing 100% 2 files
apps/web/src/app presentation 100% 4 files
apps/web/src/app/products presentation 100% 2 files
apps/web/src/app/products/[id] presentation 100% 1 file
packages/ui/src presentation 100% 6 files
Unclassified source (sample): 11
 
presentation 15 files drift ████████████████████ 100 risk high
routing 4 files drift ████████████████████ 100 risk high
middleware 2 files drift ███████▍░░░░░░░░░░░░ 37 risk moderate
config 2 files drift ░░░░░░░░░░░░░░░░░░░░ 0 risk none
shared 1 file drift ████████████████████ 100 risk high
 
╭──────────────────────────────────────────╮
DriftScore Summary
╰──────────────────────────────────────────╯
 
DriftScore: 66/100
Risk Level: HIGH
Projects: 9
Classified: 8 nano · 1 micro · 0 small · 0 standard
Billable: 0.42 · 9 detected → 0.42 billable projects (micro-project pricing)
0.1 micro · 0.32 nano
These fractions add up across repositories, then round down to whole billable projects.
 
Score Breakdown
Runtime: ████████████████████ 100
Frameworks: █████████▏░░░░░░░░░░ 46
Dependencies: ██████▏░░░░░░░░░░░░░ 31
EOL Risk: ████████████████████ 100
 
Scanned at 2026-08-19T10:20:40.993Z · 5.9s · 286 files scanned · 56 workspace files · 27 dirs
Press Run to start.