feat(server): M3.2 PR-B - omp-server FastAPI HTTP server#4
Merged
Conversation
Implements Phase 6 + Phase 7-PR-B of specs/005-async-fastapi (T034-T051, T057-T061).
Public surface (openmem.server, [server] extra):
- OmpServerConfig frozen dataclass with CFG-INV-1..4 invariants
- create_app(config) -> FastAPI; lazy __getattr__ for openmem.server.app
- omp-server CLI (argparse): CLI > env > defaults; --version exits 0;
--help contains 'trusted-network deployment only' + 'auth deferred';
missing config exits 2 with 'omp-server: missing config:' on stderr;
successful boot prints 'omp-server: serving <provider> at http://...' once
9 routes mirroring spec/omp-0.1.openapi.yaml exactly:
- GET /capabilities, POST/GET/PATCH/DELETE /memories[/{id}],
GET /memories/search, POST /context, GET /audit, GET /healthz
- Each handler is async def + Depends(get_memory) for cancellation propagation
Cross-cutting middleware:
- MaxRequestSizeMiddleware (FR-021): 413 BEFORE Pydantic; honors Content-Length,
bounded chunked read fallback; range 1KiB..100MiB
- LoggingMiddleware (FR-020): one INFO line per request; redacts user_id,
Authorization, password|secret|token|key|api_key; X-Request-Id echoed
- CORSMiddleware default-deny; only mounted when cors_origins non-empty;
allow_credentials=False; methods restricted to GET/POST/PATCH/DELETE
11-row error envelope mapping (FR-016/017): NotFoundError->404,
InvalidRequestError->400, UnauthorizedError->401, ScopeDeniedError->403,
RateLimitedError->429, UnsupportedCapabilityError->405,
ProviderError(ingestion_timeout)->504, ProviderError(other)->502,
Exception->500, PayloadTooLarge->413, ProviderUnavailable->503;
RequestValidationError normalized to 400 invalid_request
Provider-aware /healthz (FR-019): postgres acquire within 1s; passthrough
HEAD within 2s; mem0/supermemory/letta unconditional 200 (paid endpoints)
Test suite (sdk-python/tests/server, 72 tests):
- test_server_config (23): all 4 invariants + frozen + adapter_kwargs
- test_server_routes (16): happy-path + user_id rejection + CORS default-deny
- test_server_errors: parametrized 11-row mapping
- test_server_openapi_conformance: spec-driven jsonschema validation
- test_server_health: postgres mock 200/503; managed providers unconditional 200
- test_server_logging: caplog redaction proof for user_id + secret tokens
- test_server_cli: --help/--version/missing-config + boot-time ?2s
- test_server_size_limit: 413 with and without Content-Length
- test_server_disconnect: pool baseline restored within 1s post-cancel
Suite totals: 476 passed, 26 skipped, 85.92% coverage (gate >=85%).
Files: 8 server modules (~520 LOC) + 10 test files; pyproject bumped to 0.5.0;
omp-server console script registered; READMEs + CHANGELOG updated.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements Phase 6 + Phase 7-PR-B of specs/005-async-fastapi (T034-T051, T057-T061).
Public surface (openmem.server, [server] extra):
OmpServerConfig frozen dataclass with CFG-INV-1..4 invariants
create_app(config) -> FastAPI; lazy getattr for openmem.server.app
omp-server CLI (argparse): CLI > env > defaults; --version exits 0;
--help contains 'trusted-network deployment only' + 'auth deferred';
missing config exits 2 with 'omp-server: missing config:' on stderr;
successful boot prints 'omp-server: serving at http://...' once
9 routes mirroring spec/omp-0.1.openapi.yaml exactly:
GET /capabilities, POST/GET/PATCH/DELETE /memories[/{id}],
GET /memories/search, POST /context, GET /audit, GET /healthz
Each handler is async def + Depends(get_memory) for cancellation propagation
Cross-cutting middleware:
MaxRequestSizeMiddleware (FR-021): 413 BEFORE Pydantic; honors Content-Length,
bounded chunked read fallback; range 1KiB..100MiB
LoggingMiddleware (FR-020): one INFO line per request; redacts user_id,
Authorization, password|secret|token|key|api_key; X-Request-Id echoed
CORSMiddleware default-deny; only mounted when cors_origins non-empty;
allow_credentials=False; methods restricted to GET/POST/PATCH/DELETE
11-row error envelope mapping (FR-016/017): NotFoundError->404,
InvalidRequestError->400, UnauthorizedError->401, ScopeDeniedError->403,
RateLimitedError->429, UnsupportedCapabilityError->405,
ProviderError(ingestion_timeout)->504, ProviderError(other)->502,
Exception->500, PayloadTooLarge->413, ProviderUnavailable->503;
RequestValidationError normalized to 400 invalid_request
Provider-aware /healthz (FR-019): postgres acquire within 1s; passthrough
HEAD within 2s; mem0/supermemory/letta unconditional 200 (paid endpoints)
Test suite (sdk-python/tests/server, 72 tests):
test_server_config (23): all 4 invariants + frozen + adapter_kwargs
test_server_routes (16): happy-path + user_id rejection + CORS default-deny
test_server_errors: parametrized 11-row mapping
test_server_openapi_conformance: spec-driven jsonschema validation
test_server_health: postgres mock 200/503; managed providers unconditional 200
test_server_logging: caplog redaction proof for user_id + secret tokens
test_server_cli: --help/--version/missing-config + boot-time ?2s
test_server_size_limit: 413 with and without Content-Length
test_server_disconnect: pool baseline restored within 1s post-cancel
Suite totals: 476 passed, 26 skipped, 85.92% coverage (gate >=85%).
Files: 8 server modules (~520 LOC) + 10 test files; pyproject bumped to 0.5.0;
omp-server console script registered; READMEs + CHANGELOG updated.