[Feature] Add optional PowerContext pluggable long-term memory backend - #7080
[Feature] Add optional PowerContext pluggable long-term memory backend#7080kic635 wants to merge 9 commits into
Conversation
|
Hi @kic635, thank you for your first Pull Request! 🎉 📋 About PR TemplateTo help maintainers review your PR faster, please make sure to include:
Complete PR information helps speed up the review process. You can edit the PR description to add these details. 🙌 Join Developer CommunityThanks so much for your contribution! We'd love to invite you to join the official QwenPaw developer group! You can find the Discord and DingTalk group links under the "Developer Community" section on our docs page: We truly appreciate your enthusiasm—and look forward to your future contributions! 😊 We'll review your PR soon. |
jinliyl
left a comment
There was a problem hiding this comment.
Thank you for the thorough implementation and for including focused tests and UI configuration. I checked the integration against the current PowerContext HTTP schema and ran the targeted QwenPaw tests locally. The endpoint names and the main request/response fields match the upstream contract, and the selected tests pass. I did, however, find three runtime boundary issues that I think should be addressed before merging:
-
Automatic writes are bounded by characters, while PowerContext enforces an UTF-8 byte limit.
In
PowerContextMemoryManager.auto_memory(), the payload is truncated withtext[:8000]. The upstreamRememberMemoryRequest.textcontract allows at most 8192 UTF-8 bytes after normalization, not 8192 characters. An 8000-character Chinese payload can be roughly 24 KB, so a normal long Chinese turn can produce HTTP 422 on every automatic write. Because_schedule_remember()only logs the background exception, users would see no visible indication that long-term memory is not being saved.Please truncate on a UTF-8 boundary (for example, encode, cap to 8192 bytes, and decode safely), ideally leaving room for any normalization behavior, and add a multibyte test. It would also be useful to validate or bound explicit
memory_remember()text consistently.Upstream schema reference: https://github.com/oceanbase/powercontext/blob/9750e8751ae5c4d455ea7338a543e805130934c8/src/powercontext/http/_generated/models.py#L569-L576
-
max_resultscan exceed the server contract and disable both automatic and explicit search.PowerContext requires
SearchMemoryRequest.limitto be between 1 and 50. The QwenPaw model only enforces a lower bound, the Console input has no maximum, andmemory_search()forwards the value unchanged. Therefore, a saved value such as 100 makes every automatic lookup fail with HTTP 422; an agent can trigger the same failure through the explicit tool.Please enforce
le=50in configuration/UI and validate or clamp the tool/client argument to1..50, with boundary tests.Upstream schema reference: https://github.com/oceanbase/powercontext/blob/9750e8751ae5c4d455ea7338a543e805130934c8/src/powercontext/http/_generated/models.py#L1384-L1391
-
Automatic persistence should remove synthetic auto-search blocks before collecting assistant text.
The existing ReMeLight and ADBPG managers both call
_messages_without_auto_memory_search()before persisting a turn. The new manager collects every assistant message directly. If the syntheticmemory_searchmessage is present in the batch, retrieved memory is written back as a newtask_state; over repeated turns this can duplicate and amplify recalled content, reduce search quality, and waste storage. Please sanitizeall_messagesfirst and add a regression test proving that synthetic search results are not included in the remember payload.
As a smaller UX/documentation follow-up, the existing memoryManagerBackendTooltip translations still list only ReMeLight/ADBPG/none, and this PR does not explain how to install/start PowerContext or that selecting this backend automatically sends turn content to the configured service. Updating those strings and adding a short configuration note would make the feature much safer to adopt.
Local verification performed on commit 32bfebc7:
- 75 targeted Python tests passed (
powercontext_client,powercontext_memory_manager, memory config, and governance registration). - Console TypeScript and Prettier checks passed.
- The current PowerContext endpoint and payload shapes were compared with the upstream generated HTTP models.
Thanks again for the substantial contribution. The overall abstraction fit is good; the items above are mostly contract and lifecycle edge cases that mocked happy-path tests do not currently expose.
|
Thank you for the thorough review and for validating the upstream HTTP contract. Your feedback on byte-length limits, search bounds, and lifecycle handling was especially helpful. I addressed the points in commit
The focused Python suite now passes with Thanks again for the precise review. |
1db1523 to
6235896
Compare
|
Rebased this branch onto the latest The conflicts were caused by an upstream rewrite of Post-rebase verification:
GitHub now reports the PR as mergeable. |
|
Thanks for the thorough implementation and the follow-up fixes. I checked the current branch at I found two additional runtime-boundary issues that I think should be addressed before merging:
The overall abstraction fit and error handling look good. The default scope isolation issue is the main merge blocker from my review. |
|
Thank you for the careful follow-up review. I addressed both runtime-boundary issues in commit Per-agent default scope isolation
Remaining request-field contract limits
Verification:
Thank you again — the scope isolation point was an important safety boundary to make explicit. |
|
Thank you for the latest follow-up fixes. I reviewed the current branch at I found two additional runtime boundary issues:
I also have one question about the intended definition and isolation guarantees of PowerContext
Clarifying this would help ensure that the documentation phrase “isolated/private scope” matches the actual boundary guaranteed by PowerContext. Local verification on
Thank you again for the careful iteration on this integration. |
|
Thank you for the careful follow-up review. I addressed the retrieval-budget, timeout-boundary, and default-scope isolation points in commit 9f88929. 1. Bounded automatic retrieval injectionI added a PowerContext-specific
The Console exposes this as Maximum injected context (bytes) in the expanded automatic-memory-search section, with matching 1,024–32,768 validation. I rebuilt and browser-verified the current Console bundle: the field is present, 1,024 and 32,768 save successfully, and 32,768 persists after restart. 2. Finite timeout boundary
The Console follows the existing QwenPaw 3. Default scope isolation across installationsA PowerContext scope is an exact namespace within one service; PowerContext does not infer client identity. Relying only on When
This gives independently created QwenPaw installations separate default scopes while keeping a stable scope across restarts. Explicit workspace/project/team scopes remain unchanged as the intentional opt-in sharing mechanism. The documentation now states this boundary explicitly, including that copying an entire working directory also copies its persisted installation identity; cloned deployments that require isolation should configure a new explicit scope. 4. Coverage and verificationAdded coverage for:
Local verification completed:
Thank you again for identifying these runtime-boundary cases. They materially improved the safety of the optional backend without changing the default ReMeLight behavior. |
|
Thank you again for the careful follow-up work. I reviewed the current head at I found a few additional boundary issues that I think are worth addressing before approval:
As a smaller localization follow-up, the newly added scope placeholder, context-budget label, and tooltip remain in English in several non-English locale files ( Thank you again for the substantial iteration on this integration. The earlier fixes look good; the first two items above are the main remaining approval concerns from my review. |
|
Thanks for the careful boundary review. I addressed all four items in commit 1. Malformed successful search responses and token safety
Malformed responses now produce fixed protocol-error messages that do not echo server-provided values. Manager-side exception paths use the same bounded bearer-token redaction helper for logs and tool results. I added regression coverage for malformed hit shapes and a score containing the configured token. 2. Untrusted historical evidenceAutomatically recalled content is now prefixed with:
The notice also states that current system/developer/user/repository instructions and live validation take precedence. The same notice is included in explicit search output, and a regression test verifies that recalled instruction-like text remains data. 3. Explicit truncation semantics
4. LocalizationThe newly added PowerContext scope placeholder, injected-context budget label, and tooltip are now translated in Verification
The browser could not deterministically force a model-generated |

Summary
Add an optional PowerContext-backed long-term memory backend to QwenPaw.
PowerContextMemoryManagerimplements QwenPaw's existingBaseMemoryManagerabstraction and is registered through@memory_registry.register("powercontext"). It is a selectable peer ofReMeLightMemoryManager; existing agents remain unchanged unlessmemory_manager_backendis explicitly set topowercontextandpowercontext_memory_configis configured.The integration uses PowerContext's public HTTP memory APIs for scoped persistence and retrieval. It supports automatic context injection before a turn, non-blocking post-turn persistence, explicit agent-facing memory tools, citation-aware results, governance registration, and safe error diagnostics.

Components affected
agents/memory, configuration, governanceWhat Problem This Solves
The default local memory backend is suitable for single-machine usage, but deployments may need a shared, persistent, and explicitly scoped memory boundary.
PowerContext provides:
Proposed implementation
1. PowerContextMemoryManager
The manager is registered as a standard QwenPaw memory backend:
Implemented behavior:
start()powercontext_memory_config, creates the HTTP client, and disables safely when URL configuration is absent or initialization fails.close()get_memory_config()get_memory_prompt()list_memory_tools()memory_searchandmemory_remember.get_auto_memory_interval()auto_memory_search()auto_memory()/summarize()task_statememory.memory_search()memory_remember()Automatic retrieval is controlled by
auto_memory_search_config.enabled, and its result count is controlled bymax_results. Automatic writes are fire-and-forget from the conversation's perspective, while pending tasks are retained and drained during shutdown.Missing configuration, failed requests, and unavailable services return bounded tool errors and do not crash the normal conversation flow.
2. PowerContextMemoryClient
The integration adds a small standalone async client using
httpx.AsyncClient:POST /v1/memory/rememberscope_id,kind,textPOST /v1/memory/searchscope_id,query,limitThe client supports configurable base URL and timeout, plus an optional
Authorization: Bearer <token>header.Non-success responses are represented by an operation-specific
PowerContextHTTPError. Diagnostics include the operation, HTTP status code, and a short server-provided message/error/detail/code summary. Summaries are length-bounded, never include response headers, and redact the configured bearer token if it appears in a returned payload.3. Automatic memory lifecycle
Before a turn:
After a turn:
task_statepayload.This provides proactive recall and persistent task-state capture without delaying normal responses.
4. Explicit memory tools
When PowerContext is selected, the manager exposes:
memory_searchinternalmemory_remembernetworkStable governance identities are:
memory_remembervalidates that bothkindandtextare present. Under strict governance it can require approval before data is sent to the external memory service.5. Citation-aware search
Search hits preserve:
memory_ref.familymemory_ref.artifact_idmemory_ref.revisionentry_identry_version_idResults are rendered with score and citation metadata, for example:
Incomplete citations remain usable but are explicitly labelled unavailable rather than silently fabricated.
6. Console configuration
The Agent Config page adds
powercontextto the memory backend mapping and renders a dedicated configuration card with:The configuration is persisted through
AgentsRunningConfig.powercontext_memory_config, including form merge behavior for existing agent configuration. Supported locale files contain the PowerContext labels and configuration strings; the UI no longer displays raw i18n keys.7. Configuration shape
{ "running": { "memory_manager_backend": "powercontext", "powercontext_memory_config": { "base_url": "http://127.0.0.1:8000", "token": "", "scope_id": "workspace:qwenpaw", "timeout": 10.0, "auto_memory_search_config": { "enabled": true, "max_results": 3 } } } }Defaults:
base_urltokenscope_idworkspace:qwenpawtimeout10.0seconds3Benefits
Non-breaking behavior and non-goals
remelight.fallback_backendfield continue to load because extra fields are ignored.Evidence
Unit coverage includes:
task_statewrites.Validation:
Manual local browser E2E validation covered backend selection, configuration persistence, restart retention, tool registration, explicit write/search, citation rendering, cross-chat recall, scope isolation, empty results, unavailable-service diagnostics, token masking, and switching back to ReMeLight. These are manual validation scenarios, not automated browser tests committed in this PR.