Skip to content

feat(responses): Add optional compression in responses store - #1182

Open
s-akhtar-baig wants to merge 14 commits into
praxis-proxy:mainfrom
s-akhtar-baig:add_data_compression
Open

s-akhtar-baig wants to merge 14 commits into
praxis-proxy:mainfrom
s-akhtar-baig:add_data_compression

Conversation

@s-akhtar-baig

@s-akhtar-baig s-akhtar-baig commented Sep 15, 2026

Copy link
Copy Markdown

Summary

Adds optional zstd compression for the OpenAI responses store. Compression applies only to the three payload columns on the responses table — response_object, input, and messages. Conversation and conversation-item payloads are unaffected and remain plain TEXT.

Major Changes

  • Compression is opt-in and defaults to none, so existing deployments are unchanged unless they enable it.
  • encode compresses a JSON value to a raw zstd frame (or raw JSON bytes when none); decode auto-detects the zstd frame magic (28 B5 2F FD) and decompresses transparently.
  • Reads are independent of the configured algorithm, so uncompressed rows stay readable after compression is enabled and vice versa.
  • Schema bumped to version 3: the responses payload columns are now binary (BLOB on SQLite, BYTEA on PostgreSQL); conversations/items stay TEXT.
  • Migration docs live under docs/store/schema-migration.md.

Related issue

Closes #629

Validation

  • Unit tests
  • Integration or functional tests
  • make lint

Checklist

  • I reviewed every changed line and can explain the change.
  • New capabilities include an example config and functional example test.
  • User-facing behavior and generated documentation are updated.
  • Performance-sensitive changes include appropriate benchmark or load-test evidence.
  • Commits are signed and include a Signed-off-by trailer.

Breaking changes

Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
@s-akhtar-baig
s-akhtar-baig requested review from a team and yossiovadia September 15, 2026 15:26
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>

@praxis-bot praxis-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review

Summary: Clean, well-structured compression implementation with solid backward compatibility. Schema versioning, auto-detection on decode, and migration documentation are all sound. Two findings below.

Severity Count
Medium 2

Comment thread apis/src/store/compression.rs
Comment thread apis/src/store/tests.rs
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>

@leseb leseb left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Conversations deployments are incorrectly forced through the Responses v2 migration.
The shared SCHEMA_VERSION:38 now applies to the generated *_unused_responses:112 table used by openai_conversations. Existing v1 databases therefore fail initialization even though the Conversations schema did not change. The migration guide only covers the configured Responses table. Schema versions should be separated, or the generated table must be migrated and tested.

[P1] Required CI fails after changing payload columns to BLOB.
Two compact integration tests still read response_object and messages as String (line 691:691, line 993:993). Both the integration and coverage jobs fail with TEXT is not compatible with BLOB. Read bytes and deserialize with from_slice.

[P2] Compression can create records that cannot be read back.
encode:93 accepts arbitrarily large JSON, while decode:119 rejects decompressed values over 256 MiB. Enforce the same limit before a compressed write succeeds.

[P2] Public store constructors bypass compression validation.
SqliteResponseStore::new:69 and PostgresResponseStore::new:126 accept public StoreCompressionConfig values without validation. Invalid levels then fail only on first write, while algorithm: none silently ignores a level. Validate in both constructors.

Also missing: the required OpenAI SDK integration coverage for changes under apis/src/openai/.

And we need a benchmark this implementation, here we have done locally:

A directional M2 Pro microbenchmark of the exact zstd level-3 path showed:

Payload Extra write CPU Extra read CPU
10 KB 8–16 µs 3–12 µs
100 KB 23–77 µs 17–99 µs
1 MB 0.24–0.73 ms 0.12–0.95 ms

The range reflects highly compressible JSON versus low-redundancy content. Storage shrank to 2–75% of original size.

Important caveats:

  • The store compresses three JSON fields independently, so costs accumulate.
  • Compression runs synchronously on the async worker (compression.rs); large/concurrent writes may hurt p99 latency.
  • Database I/O was excluded. Against inference latency, the per-request cost is probably small, but throughput impact remains unmeasured.
  • With compression disabled—the default—there is effectively no zstd cost.

Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
@s-akhtar-baig

Copy link
Copy Markdown
Author

Thanks, @leseb, for reviewing this PR!

I have added fixes and a benchmark. PTAL when you get a chance.

Note that compression on the three columns still run synchronously. I'd have to look into the critical (write) section and investigate whether making asynchronous calls improve current performance. I'd like to do this exploratory work in a follow-up issue/PR pair as this PR is getting on the bigger side. But please let me know if you think it should be part of this PR. Thanks again!

@leseb leseb left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one last remaining P2: zstd decode and explicit-compaction encode still perform potentially large synchronous CPU work on async workers (compression.rs:110). Offload it or impose a much smaller inline size/level bound.

Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
@s-akhtar-baig

Copy link
Copy Markdown
Author

@leseb, I have updated the encode and decode functions to be asynchronous. Please let me know if I missed anything. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

response store: data compression

3 participants