Phase 2: Streaming Stabilization & Observability - PRD & MCP
1. Product Requirements Document (PRD)
1.1 Objective
The goal of Phase 2 is to harden the "Zero-Buffer Streaming Proxy" architecture implemented in Phase 1. This phase focuses on reliability, observability, and error resilience. We aim to ensure the system can handle high concurrency, network instability, and malformed upstream responses without crashing or leaking resources, while providing deep visibility into the streaming pipeline.
1.2 Functional Requirements
1.2.1 Advanced Request Logging
- Streaming Support: The logger must support true streaming for both request and response bodies. The current
[]bytebuffer for request bodies must be replaced with a stream-aware interface (io.Reader). - Sanitization: Sensitive data (Thinking blocks, Tool arguments) must be redacted in real-time with zero-latency overhead.
- Format: Logs should optionally support NDJSON (Newline Delimited JSON) to facilitate machine parsing and ingestion into observability platforms.
1.2.2 AMP Response Rewriter Resilience
- Edge Case Handling: The rewriter must gracefully handle:
- Split JSON tokens across chunk boundaries (already implemented, needs verification).
- Invalid or malformed JSON from upstream.
- Mixed content types (e.g., error responses sent as plain text instead of SSE).
- Fallback Strategy: If rewriting fails (e.g., parsing error), the proxy must fallback to passing the raw chunk through to avoid disrupting the client, logging the error asynchronously.
1.2.3 Proxy Resilience & Timeouts
- Context Management: Request context must be propagated correctly. Client disconnection must immediately cancel the upstream request to save costs.
- Timeouts: The proxy must enforce explicit timeouts:
- Connect Timeout: Max 10s.
- Header Timeout: Max 30s (TTFB).
- Idle Timeout: Max 60s (for SSE streams).
1.3 Non-Functional Requirements
- Performance:
- Latency Overhead: < 5ms added by the proxy layer (decompression + rewriting + logging).
- Memory Usage: Constant memory usage per request (O(1)), independent of response size. Target: < 64KB overhead per active stream.
- Concurrency: Support 1000+ concurrent streaming connections on a standard instance without OOM.
- Observability: Expose Prometheus metrics for:
- Active streams.
- Log queue depth.
- Sanitization hit rate.
- Upstream latency histograms.
2. Master Control Plan (MCP)
2.1 Architecture Review
The Phase 1 refactor successfully removed full-body buffering from the Response path. However, the Request path still buffers the full body in memory (RequestLogger interface takes body []byte). Additionally, the current implementation lacks comprehensive error handling for network interruptions during streaming and doesn't expose internal metrics.
Refinement Areas:
- Logging Interface: Refactor
RequestLoggerto acceptio.Readerfor the request body. - Async Safety: Ensure the
eventLoopin the logger handles channel overflows gracefully (drop strategy vs. block strategy). - Transport Configuration: The
httputil.ReverseProxyneeds a customTransportwith tuned timeouts.
2.2 Implementation Roadmap
Step 1: Logging Interface Refactor (True Zero-Buffer)
- Task: Modify
RequestLogger.LogStreamingRequestsignature.- From:
LogStreamingRequest(..., body []byte, ...) - To:
LogStreamingRequest(..., body io.Reader, ...)
- From:
- Action: Update
internal/logging/request_logger.go. - Action: Update
internal/api/middleware/request_logging.goto pass the request body stream directly (usingio.TeeReaderif necessary to log and process, though usually we log what we read).
Step 2: Proxy Timeout & Transport Hardening
- Task: Configure
httputil.ReverseProxywith a customhttp.Transport. - Action: In
internal/api/modules/amp/proxy.go, define:Transport: &http.Transport{ DialContext: (&net.Dialer{ Timeout: 10 * time.Second, KeepAlive: 30 * time.Second, }).DialContext, ResponseHeaderTimeout: 30 * time.Second, IdleConnTimeout: 90 * time.Second, } - Task: Ensure
req.Context()cancellation propagates upstream.
Step 3: Observability Integration
- Task: Instrument the
FileStreamingLogWriterandResponseRewriter. - Action: Add counters for
log_events_dropped,chunks_processed,thinking_blocks_redacted.
Step 4: Testing & Validation
- Task: Add Unit/Integration Tests.
- Test
StreamingSanitizerwith random chunk splits (Fuzzing). - Test
ResponseRewriterwith invalid JSON. - Test Memory usage under load (using
pprof).
- Test
2.3 Technical Specifications
New Logger Interface
type RequestLogger interface {
// ... existing LogRequest ...
// LogStreamingRequest now accepts a reader for the request body
LogStreamingRequest(ctx context.Context, url, method string, headers map[string][]string, bodyStream io.Reader, requestID string) (StreamingLogWriter, error)
}
Struct Modifications
FileStreamingLogWriter:
- Add
dropCount atomic.Uint64to track buffer overflows. - Add
metrics MetricsCollectorinterface dependency.
ResponseRewriter:
- Add
FallbackMode boolflag. Iftrue, parser errors disable rewriting for the rest of the stream to ensure delivery.
2.4 Execution Strategy
- Refactor Logger Interface: High impact, touches middleware. Do this first.
- Harden Proxy: Low risk, high value for reliability.
- Add Tests: Critical for verifying the stability of the complex streaming logic.
- Add Metrics: Final polish for operations.