fix(mem0): api_key optional in schema; harden composition test env isolation - #64
Conversation
…olation Two follow-up fixes from Greptile review of merged PR #43. - plugins/memory/mem0/__init__.py: api_key was marked required:True even though is_available() bypasses it when host is set (self-hosted gates on admin_api_key). The required flag forced any setup/validation UI to demand a cloud key for a self-hosted server that never uses one. Mark it optional and document the conditional requirement; is_available() remains the real gate. - tests/test_request_composition.py: test_fixed_divisor_default_and_out_of_range_fallback mutated os.environ directly without try/finally, so a mid-loop assertion failure would leak HERMES_COMPOSITION_CHARS_PER_TOKEN_FIXED into later tests. Switch to monkeypatch + try/finally, matching the adjacent override tests. Adds behavior-contract tests: api_key not required in schema, self-hosted is_available without an api_key, and cloud mode still requires one.
🔎 Lint report:
|
| Rule | Count |
|---|---|
invalid-assignment |
1 |
First entries
tests/run_agent/test_credits_notices_toggle.py:76: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to attribute `_credits_session_start_micros` of type `int`
✅ Fixed issues (2):
| Rule | Count |
|---|---|
unresolved-attribute |
2 |
First entries
tests/run_agent/test_credits_notices_toggle.py:76: [unresolved-attribute] unresolved-attribute: Unresolved attribute `_credits_session_start_micros` on type `AIAgent`
run_agent.py:2931: [unresolved-attribute] unresolved-attribute: Object of type `Self@get_credits_spent_micros` has no attribute `_credits_session_start_micros`
Unchanged: 5855 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
|
CI note (not a blocker): the
All deterministic floor checks are green: |
|
| Filename | Overview |
|---|---|
| plugins/memory/mem0/init.py | Single-line schema fix: api_key changed from required: True to required: False with an updated description. The runtime gate in is_available() is unchanged. Module-level docstring still annotates MEM0_API_KEY as (required), which is now stale. |
| tests/plugins/memory/test_mem0_selfhost.py | Three new behavior-contract tests added: schema required assertion, self-hosted availability without api_key, and cloud mode still requiring api_key. All use monkeypatch + tmp_path isolation correctly. |
| tests/test_request_composition.py | Converted test_fixed_divisor_default_and_out_of_range_fallback from raw os.environ mutation to monkeypatch + try/finally, eliminating the env-leak risk on mid-loop assertion failure. The cleanup logic is sound. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[is_available called] --> B{host set?}
B -- Yes: self-hosted --> C{admin_api_key set?}
C -- Yes --> D[✅ available]
C -- No --> E[❌ not available]
B -- No: cloud --> F{api_key set?}
F -- Yes --> G[✅ available]
F -- No --> H[❌ not available]
subgraph Schema["get_config_schema() — after this PR"]
S1["api_key: required=False ← changed"]
S2["admin_api_key: required=False"]
S3["host: optional"]
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[is_available called] --> B{host set?}
B -- Yes: self-hosted --> C{admin_api_key set?}
C -- Yes --> D[✅ available]
C -- No --> E[❌ not available]
B -- No: cloud --> F{api_key set?}
F -- Yes --> G[✅ available]
F -- No --> H[❌ not available]
subgraph Schema["get_config_schema() — after this PR"]
S1["api_key: required=False ← changed"]
S2["admin_api_key: required=False"]
S3["host: optional"]
end
Comments Outside Diff (1)
-
plugins/memory/mem0/__init__.py, line 9 (link)The module-level docstring still annotates
MEM0_API_KEYas(required), but the PR changes it torequired: False. A reader configuring self-hosted mode from the module header alone would still be misled into thinking the cloud key is mandatory.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Reviews (1): Last reviewed commit: "fix(mem0): api_key optional in schema; h..." | Re-trigger Greptile
Summary
Two follow-up fixes for the real issues Greptile flagged on merged PR #43
(
fix(blackbox): two-tier char→token divisor). Both were valid; neither wasaddressed before that PR merged.
1.
plugins/memory/mem0/__init__.py—api_keywronglyrequired: Trueis_available()bypassesapi_keyentirely whenhostis set — self-hostedmode is gated on
admin_api_key, not the cloud key:But
get_config_schema()markedapi_keyrequired: True, so anyschema-driven setup/validation UI would block a self-hosted configuration
unless a cloud key it never uses was also supplied. Marked optional, with the
conditional requirement documented in the field description.
is_available()remains the real runtime gate, so cloud mode still effectively requires the key.
2.
tests/test_request_composition.py— env leak on assertion failuretest_fixed_divisor_default_and_out_of_range_fallbackmutatedos.environdirectly without
try/finally(unlike the adjacent monkeypatch tests). Amid-loop assertion failure would leak
HERMES_COMPOSITION_CHARS_PER_TOKEN_FIXEDinto later tests, causing order-dependent failures. Switched to
monkeypatch+try/finally.Tests
Behavior-contract tests added (not value snapshots):
api_keyis notrequiredin the schema.is_available()is true withhost+admin_api_key, no api_key.api_key.Run in the repo venv with the worktree code on the path.