Skip to content

feat(server): M3.2 PR-B - omp-server FastAPI HTTP server#4

Merged
Ketankhunti merged 2 commits into
mainfrom
005-async-fastapi-pr-b
May 2, 2026
Merged

feat(server): M3.2 PR-B - omp-server FastAPI HTTP server#4
Ketankhunti merged 2 commits into
mainfrom
005-async-fastapi-pr-b

Conversation

@Ketankhunti

Copy link
Copy Markdown
Owner

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.

ketan7506 added 2 commits May 2, 2026 21:50
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.
@Ketankhunti
Ketankhunti merged commit 053313d into main May 2, 2026
3 checks passed
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.

2 participants