feat(memory-gateway): merge memory mode with main
This commit is contained in:
@ -0,0 +1,351 @@
|
||||
# Hybrid Memory Gateway Integration Design
|
||||
|
||||
## Goal
|
||||
|
||||
Keep Beaver's existing curated memory as the permanent baseline and optionally
|
||||
add Memory Gateway as an independent second memory layer.
|
||||
|
||||
- Curated memory continues to load `MEMORY.md` and `USER.md` into a frozen
|
||||
per-run snapshot and continues to expose the existing `memory` tool.
|
||||
- Memory Gateway independently recalls conversation/resource memory through
|
||||
`POST /memories/search` and persists each completed conversation turn through
|
||||
one `POST /memories/add` followed by one `POST /memories/flush`.
|
||||
- The two layers do not synchronize, overwrite, merge, deduplicate, or resolve
|
||||
conflicts with each other.
|
||||
|
||||
Memory Gateway is best-effort. Gateway failures must be auditable without
|
||||
affecting curated memory or turning an otherwise successful chat run into a
|
||||
failure.
|
||||
|
||||
## Scope
|
||||
|
||||
This change includes:
|
||||
|
||||
- Runtime configuration for `curated` and `hybrid` modes.
|
||||
- Fixed Memory Gateway credentials and search scopes in instance config.
|
||||
- An asynchronous Memory Gateway HTTP client.
|
||||
- An optional `MemoryGatewayService` alongside the existing `MemoryService`.
|
||||
- Gateway recall before each provider run in hybrid mode.
|
||||
- Gateway add and flush after each normally completed run in hybrid mode.
|
||||
- Hidden session audit events for Gateway outcomes.
|
||||
- Unit and integration-style tests using fake transports and providers.
|
||||
|
||||
This change does not include:
|
||||
|
||||
- Replacing or disabling curated memory.
|
||||
- Synchronizing curated `memory` tool writes to Memory Gateway.
|
||||
- Writing Gateway conversation turns into `MEMORY.md` or `USER.md`.
|
||||
- Conflict resolution or automatic deduplication across the two layers.
|
||||
- Automatic `POST /users` calls or credential provisioning.
|
||||
- A memory settings UI or memory administration UI.
|
||||
- Resource upload support from Beaver.
|
||||
- Gateway override or deletion APIs.
|
||||
- Persisting tool calls, tool results, system events, reasoning, recalled
|
||||
memory, or skill activation messages to Gateway.
|
||||
|
||||
## Configuration
|
||||
|
||||
Beaver adds a top-level `memory` section:
|
||||
|
||||
```json
|
||||
{
|
||||
"memory": {
|
||||
"mode": "hybrid",
|
||||
"gateway": {
|
||||
"baseUrl": "http://127.0.0.1:8010",
|
||||
"userId": "gateway_test_user",
|
||||
"userKey": "uk_xxx",
|
||||
"appId": "default",
|
||||
"projectId": "default",
|
||||
"scope": ["current_chat", "resources"],
|
||||
"topK": 8,
|
||||
"timeoutSeconds": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Configuration rules:
|
||||
|
||||
- Valid modes are `curated` and `hybrid`.
|
||||
- Curated memory is initialized and enabled in both modes.
|
||||
- If the entire `memory` section is absent, the effective mode is implicitly
|
||||
`hybrid`. Missing Gateway credentials in this implicit-default case produce
|
||||
a startup warning and degrade only the Gateway layer; Beaver continues with
|
||||
curated memory.
|
||||
- If `mode: "hybrid"` is explicitly present, non-empty `baseUrl`, `userId`, and
|
||||
`userKey` are required. Missing required values fail runtime loading.
|
||||
- `mode: "curated"` disables Gateway initialization and ignores an optional
|
||||
Gateway block.
|
||||
- `appId` and `projectId` default to `default`.
|
||||
- `scope` must be a non-empty subset of `current_chat`, `resources`, and
|
||||
`all_user_memory`. The initial integration uses `current_chat` and
|
||||
`resources`.
|
||||
- `topK` defaults to 8 and must be between 1 and 100.
|
||||
- `timeoutSeconds` defaults to 10 and must be positive.
|
||||
- `userKey` must never appear in status payloads, warnings, logs produced by
|
||||
this integration, session events, or raised configuration/client errors.
|
||||
|
||||
The parsed configuration must retain whether hybrid mode was explicit or
|
||||
implicit so runtime loading can apply the different validation behavior.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Existing curated memory remains unchanged
|
||||
|
||||
`MemoryStore`, `MemorySnapshot`, `MemoryService`, and `MemoryTool` retain their
|
||||
current responsibilities:
|
||||
|
||||
- `EngineLoader` always initializes `MemoryService`.
|
||||
- `AgentLoop` always captures a per-run frozen curated snapshot.
|
||||
- `ContextBuilder` always receives that snapshot for system-prompt injection.
|
||||
- The original `memory` tool remains registered and always operates only on
|
||||
`MEMORY.md` and `USER.md`.
|
||||
- Gateway availability and Gateway failures do not change curated behavior.
|
||||
|
||||
### Optional Gateway service
|
||||
|
||||
Add a separate `MemoryGatewayService` rather than a mutually exclusive backend
|
||||
strategy. It is present only when hybrid mode has a valid Gateway configuration.
|
||||
|
||||
The service exposes two runtime operations:
|
||||
|
||||
1. `recall_before_run`: search Gateway using the current Beaver session and
|
||||
user prompt, then return sanitized reference messages plus audit metadata.
|
||||
2. `persist_after_run`: add the current user message and final assistant answer,
|
||||
then flush the Gateway chat session.
|
||||
|
||||
`EngineLoadResult` exposes `memory_gateway_service: MemoryGatewayService | None`.
|
||||
`AgentLoop` uses it conditionally while continuing its existing curated path
|
||||
unconditionally.
|
||||
|
||||
`session_search` remains independent and available in both modes.
|
||||
|
||||
### Memory Gateway HTTP client
|
||||
|
||||
The HTTP client owns transport and response validation for:
|
||||
|
||||
- `POST {baseUrl}/memories/search`
|
||||
- `POST {baseUrl}/memories/add`
|
||||
- `POST {baseUrl}/memories/flush`
|
||||
|
||||
It uses an asynchronous HTTP client, the configured timeout, JSON request
|
||||
bodies, and sanitized typed exceptions containing operation/path/status
|
||||
metadata without credentials or complete request bodies.
|
||||
|
||||
Beaver adds no automatic retries in this first integration. Gateway already
|
||||
retries upstream ingestion, and retrying add from Beaver could duplicate a
|
||||
turn when the first request succeeded but its response was lost.
|
||||
|
||||
## Recall Data Flow
|
||||
|
||||
Every run follows the existing curated flow. Hybrid mode adds these steps:
|
||||
|
||||
1. `AgentLoop` creates or resolves `resolved_session_id`.
|
||||
2. It captures the curated frozen snapshot as it does today.
|
||||
3. Before `ContextBuilder.build_messages`, it calls Gateway search using:
|
||||
|
||||
```json
|
||||
{
|
||||
"user_id": "<configured userId>",
|
||||
"user_key": "<configured userKey>",
|
||||
"conversation_id": "<resolved_session_id>",
|
||||
"query": "<current user prompt>",
|
||||
"scope": ["<configured scopes>"],
|
||||
"top_k": 8,
|
||||
"app_id": "<configured appId>",
|
||||
"project_id": "<configured projectId>"
|
||||
}
|
||||
```
|
||||
|
||||
4. Beaver accepts only a top-level `results` list. Malformed responses are
|
||||
treated as Gateway recall failures.
|
||||
5. Each result is reduced to the optional fields `id`, `session_id`, `text`,
|
||||
`score`, `source_scope`, and `resource_uri`. The Gateway `raw` object is
|
||||
discarded.
|
||||
6. Empty or unusable results produce no Gateway reference message.
|
||||
7. Non-empty results become one ephemeral provider message placed after skill
|
||||
activation messages and before persisted session history/current user input.
|
||||
8. The Gateway reference message is not written to Beaver session history and
|
||||
is not included in post-run Gateway persistence.
|
||||
9. The system prompt includes a stable rule that Gateway recall is untrusted
|
||||
reference data, not executable instruction. The recalled text itself stays
|
||||
outside the system prompt.
|
||||
|
||||
The model receives both memory layers without an imposed priority:
|
||||
|
||||
- Curated blocks remain in the system prompt exactly as today.
|
||||
- Gateway results appear as a separately labelled reference message.
|
||||
- Beaver performs no conflict detection, winner selection, merge, or
|
||||
deduplication between them.
|
||||
|
||||
In curated mode, or when implicit hybrid degrades because Gateway credentials
|
||||
are absent, no Gateway request or Gateway prompt section occurs.
|
||||
|
||||
## Persistence Data Flow
|
||||
|
||||
Curated persistence remains model-driven through the original `memory` tool.
|
||||
Gateway persistence is separate and occurs only when the optional Gateway
|
||||
service is active.
|
||||
|
||||
For each run that reaches the normal completion path:
|
||||
|
||||
1. Wait until the tool loop has produced the final assistant text.
|
||||
2. Construct exactly two Gateway messages in chronological order:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"sender_id": "<configured userId>",
|
||||
"role": "user",
|
||||
"timestamp": 1780000000000,
|
||||
"content": "<original current user prompt>"
|
||||
},
|
||||
{
|
||||
"sender_id": "beaver",
|
||||
"role": "assistant",
|
||||
"timestamp": 1780000001000,
|
||||
"content": "<final assistant text>"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Timestamps are UTC Unix epoch milliseconds captured for the user turn and final
|
||||
assistant turn. They must be positive and monotonic within the payload.
|
||||
|
||||
3. Call `/memories/add` exactly once with:
|
||||
|
||||
```json
|
||||
{
|
||||
"user_id": "<configured userId>",
|
||||
"user_key": "<configured userKey>",
|
||||
"session_id": "chat:<resolved_session_id>",
|
||||
"app_id": "<configured appId>",
|
||||
"project_id": "<configured projectId>",
|
||||
"messages": ["<the two messages above>"]
|
||||
}
|
||||
```
|
||||
|
||||
4. If add succeeds, call `/memories/flush` exactly once using the same Gateway
|
||||
identity, app/project scope, and `chat:<resolved_session_id>`.
|
||||
5. If add fails, do not call flush.
|
||||
6. Runs entering Beaver's exception/error completion path are not persisted.
|
||||
Normal completion outputs such as a tool-limit fallback are persisted because
|
||||
they are returned to the user.
|
||||
7. Tool calls, tool results, hidden events, system prompts, curated snapshot
|
||||
text, Gateway recalled text, reasoning, and activated skill text are never
|
||||
included in the Gateway add payload.
|
||||
8. Gateway persistence never modifies `MEMORY.md` or `USER.md`.
|
||||
9. Curated `memory` tool add/replace/remove operations never call Gateway.
|
||||
|
||||
## Session Audit Events
|
||||
|
||||
When the Gateway service is active, Beaver writes hidden
|
||||
(`context_visible=false`) session events without credentials or full response
|
||||
bodies:
|
||||
|
||||
- `memory_gateway_recall_succeeded`: configured scopes and result count.
|
||||
- `memory_gateway_recall_failed`: operation, sanitized error category, and
|
||||
optional HTTP status.
|
||||
- `memory_gateway_add_succeeded`: Gateway chat session and message count.
|
||||
- `memory_gateway_add_failed`: sanitized failure metadata.
|
||||
- `memory_gateway_flush_succeeded`: Gateway chat session.
|
||||
- `memory_gateway_flush_failed`: sanitized failure metadata and indication that
|
||||
add already succeeded.
|
||||
|
||||
For implicit hybrid degradation at runtime boot, use a normal application
|
||||
warning rather than a session event because no session exists yet. The warning
|
||||
must not contain credential values.
|
||||
|
||||
## Failure Semantics
|
||||
|
||||
- Curated initialization or writes retain their existing behavior and are not
|
||||
caught or changed by Gateway code.
|
||||
- Missing Gateway credentials in implicit-default hybrid mode: warn, leave the
|
||||
Gateway service unset, and continue with curated memory.
|
||||
- Missing/invalid Gateway configuration in explicit hybrid mode: fail runtime
|
||||
loading with a sanitized configuration error.
|
||||
- Search timeout, connection failure, 401, other HTTP error, or malformed JSON:
|
||||
record recall failure and continue with curated memory and normal context.
|
||||
- Add failure: record add failure, skip flush, and return the normal assistant
|
||||
result.
|
||||
- Flush failure: record flush failure and return the normal assistant result.
|
||||
- Gateway failures do not disable, roll back, or mutate curated memory.
|
||||
- Gateway failures are not surfaced as user-facing chat errors in this phase.
|
||||
|
||||
## Security and Privacy
|
||||
|
||||
- Fixed Gateway credentials come only from Beaver instance configuration.
|
||||
- `userKey` is passed only in Gateway request bodies and retained in memory by
|
||||
the typed config/client objects.
|
||||
- Client exceptions, startup warnings, and audit payloads never serialize
|
||||
request bodies or credentials.
|
||||
- Gateway conversation/resource text is treated as untrusted data.
|
||||
- Gateway `raw` fields are discarded before prompt construction.
|
||||
- Curated and Gateway stores remain isolated. No content is copied between
|
||||
them: curated receives only explicit `memory` tool mutations, while Gateway
|
||||
receives only the configured per-run conversation payload.
|
||||
|
||||
## Testing
|
||||
|
||||
### Configuration tests
|
||||
|
||||
- Missing memory configuration produces implicit hybrid mode.
|
||||
- Implicit hybrid without credentials leaves Gateway disabled and curated
|
||||
enabled, with one sanitized warning.
|
||||
- Explicit curated mode does not require or initialize Gateway.
|
||||
- Complete explicit hybrid config parses camelCase fields and initializes both
|
||||
memory layers.
|
||||
- Explicit hybrid with missing credentials fails loading.
|
||||
- Invalid mode, empty/unknown scope, invalid `topK`, and non-positive timeout
|
||||
fail with explicit sanitized errors.
|
||||
- No warning or exception text contains `userKey`.
|
||||
|
||||
### HTTP client tests
|
||||
|
||||
- Search, add, and flush use the exact paths and payload shapes above.
|
||||
- Configured timeout is applied.
|
||||
- Non-2xx, network, invalid JSON, and invalid response shapes produce sanitized
|
||||
client exceptions.
|
||||
- Exception strings never contain the configured key.
|
||||
|
||||
### Gateway service tests
|
||||
|
||||
- Search uses configured scopes and strips `raw` fields.
|
||||
- Empty search results produce no reference message.
|
||||
- Persistence sends exactly the original user prompt and final assistant
|
||||
response, then flushes once.
|
||||
- Add failure skips flush; flush failure preserves the successful add outcome.
|
||||
- Service methods never read or write curated files or call `MemoryStore`.
|
||||
|
||||
### Agent loop and loader tests
|
||||
|
||||
- Curated snapshot injection and `memory` tool availability remain present in
|
||||
both curated and hybrid modes.
|
||||
- Hybrid search occurs before the provider call while the curated snapshot is
|
||||
still present in the system prompt.
|
||||
- Gateway recall appears before the current user prompt and outside the system
|
||||
prompt body.
|
||||
- The system prompt contains the untrusted-reference rule only when Gateway is
|
||||
active.
|
||||
- Add and flush happen after the final assistant response and exactly once each.
|
||||
- Tool/system/reasoning/curated/Gateway-recall content is absent from the add
|
||||
payload.
|
||||
- Recall/add/flush failures do not change the returned `AgentRunResult` or the
|
||||
curated snapshot/tool behavior.
|
||||
- Hidden success/failure audit events contain no credentials.
|
||||
- Curated `memory` tool operations produce no Gateway calls.
|
||||
- Gateway persistence produces no changes to `MEMORY.md` or `USER.md`.
|
||||
- Curated mode and degraded implicit hybrid perform no Gateway HTTP calls.
|
||||
|
||||
## Documentation
|
||||
|
||||
Update the backend README/config example with:
|
||||
|
||||
- `hybrid` as the implicit default.
|
||||
- Explicit `curated` mode for disabling Gateway.
|
||||
- A complete explicit hybrid example.
|
||||
- The implicit-default degradation rule and explicit-hybrid validation rule.
|
||||
- A warning that `userKey` is a secret.
|
||||
- A note that changing memory mode/config requires runtime reload or restart
|
||||
because `EngineLoader` constructs the optional Gateway service during boot.
|
||||
@ -0,0 +1,282 @@
|
||||
# Memory Gateway Package and User Provisioning Design
|
||||
|
||||
## Goal
|
||||
|
||||
Reorganize Beaver's Memory Gateway code under the `beaver.memory` domain and
|
||||
replace the single fixed Gateway identity with per-Beaver-user credentials.
|
||||
|
||||
The final model has two independent configuration layers:
|
||||
|
||||
- One shared, non-secret Memory Gateway configuration used by every Beaver
|
||||
instance.
|
||||
- One per-instance credential file containing the Gateway identities created
|
||||
for Beaver frontend users.
|
||||
|
||||
Curated memory remains enabled and isolated. Gateway failures or missing user
|
||||
credentials must not modify `MEMORY.md`, `USER.md`, or the `memory` tool.
|
||||
|
||||
## Source Package
|
||||
|
||||
All Beaver-side Gateway source moves to:
|
||||
|
||||
```text
|
||||
app-instance/backend/beaver/memory/gateway/
|
||||
├── __init__.py
|
||||
├── config.py
|
||||
├── client.py
|
||||
├── credentials.py
|
||||
└── service.py
|
||||
```
|
||||
|
||||
- `config.py` owns the shared typed Gateway configuration.
|
||||
- `client.py` owns `MemoryGatewayClient` and sanitized client exceptions.
|
||||
- `credentials.py` owns typed user credentials and atomic credential-file
|
||||
persistence.
|
||||
- `service.py` owns search/add/flush orchestration and result types.
|
||||
- `__init__.py` exposes the supported public Gateway API.
|
||||
|
||||
Remove the old source locations:
|
||||
|
||||
- `beaver/integrations/memory_gateway/`
|
||||
- `beaver/services/memory_gateway_service.py`
|
||||
- Gateway configuration dataclasses in `beaver.foundation.config.schema`
|
||||
- The lazy `MemoryGatewayService` export from `beaver.services`
|
||||
|
||||
No compatibility forwarding modules are retained. After migration,
|
||||
`beaver.memory.gateway` is the only supported source entry point.
|
||||
|
||||
## Shared Configuration
|
||||
|
||||
All Beaver instances read the same public Gateway configuration from:
|
||||
|
||||
```text
|
||||
/home/tom/beaver_project/app-instance/backend/memory/config.json
|
||||
```
|
||||
|
||||
Inside the app-instance image this is available as:
|
||||
|
||||
```text
|
||||
/opt/app/backend/memory/config.json
|
||||
```
|
||||
|
||||
The file contains no user credentials:
|
||||
|
||||
```json
|
||||
{
|
||||
"memory": {
|
||||
"mode": "hybrid",
|
||||
"gateway": {
|
||||
"baseUrl": "http://172.19.207.37:8010",
|
||||
"appId": "default",
|
||||
"projectId": "default",
|
||||
"scope": ["current_chat", "resources", "all_user_memory"],
|
||||
"topK": 8,
|
||||
"timeoutSeconds": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- Valid modes remain `curated` and `hybrid`.
|
||||
- Curated memory is always initialized.
|
||||
- `hybrid` enables Gateway only for runs with a resolved user credential.
|
||||
- `baseUrl` is fixed to `http://172.19.207.37:8010` in the initial shared
|
||||
configuration.
|
||||
- Scope includes `current_chat`, `resources`, and `all_user_memory`.
|
||||
- The shared file is the authoritative Memory Gateway configuration. Instance
|
||||
`config.json` files continue to own providers, tools, channels, AuthZ, and
|
||||
backend identity, but no longer carry Gateway user credentials.
|
||||
- An optional `BEAVER_MEMORY_CONFIG_PATH` may override the shared file path for
|
||||
tests or non-image development runs.
|
||||
|
||||
## Per-Instance User Credentials
|
||||
|
||||
Each Beaver instance stores Gateway user credentials alongside its existing
|
||||
`config.json`, `runtime.env`, and `web_auth_users.json`:
|
||||
|
||||
```text
|
||||
app-instance/runtime/instances/<instance-slug>/beaver-home/
|
||||
├── config.json
|
||||
├── runtime.env
|
||||
├── web_auth_users.json
|
||||
└── memory_gateway_users.json
|
||||
```
|
||||
|
||||
The existing `beaver-home` mount exposes the file inside the container as:
|
||||
|
||||
```text
|
||||
/root/.beaver/memory_gateway_users.json
|
||||
```
|
||||
|
||||
The JSON format is:
|
||||
|
||||
```json
|
||||
{
|
||||
"users": {
|
||||
"tom": {
|
||||
"userId": "tom",
|
||||
"userKey": "uk_xxx"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- The map key is the authenticated Beaver login username.
|
||||
- Gateway `userId` is exactly the Beaver login username, with no prefix.
|
||||
- `userKey` is secret and must never appear in API responses, logs, audit
|
||||
events, exceptions, or tracked configuration.
|
||||
- Writes use a sibling temporary file followed by atomic replace.
|
||||
- The credential file is created with mode `0600`.
|
||||
- `BEAVER_MEMORY_GATEWAY_USERS_PATH` may override the default path for tests.
|
||||
|
||||
## Frontend User Provisioning
|
||||
|
||||
The frontend continues to call Beaver's existing `POST /api/auth/register`
|
||||
endpoint. The browser never calls Memory Gateway directly and never receives
|
||||
the Gateway `userKey`.
|
||||
|
||||
For a registration request with username `tom`, Beaver performs:
|
||||
|
||||
```http
|
||||
POST http://172.19.207.37:8010/users
|
||||
Content-Type: application/json
|
||||
|
||||
{"user_id":"tom"}
|
||||
```
|
||||
|
||||
Beaver validates that the response contains non-empty `user_id` and
|
||||
`user_key`, requires the returned `user_id` to equal `tom`, and stores the
|
||||
credential under the `tom` entry in `memory_gateway_users.json`.
|
||||
|
||||
The Gateway `/users` API is treated as idempotent. Registering an existing
|
||||
Beaver username may refresh the same credential entry without creating a
|
||||
second local identity.
|
||||
|
||||
For this first version:
|
||||
|
||||
- Gateway provisioning has no Beaver-side retries.
|
||||
- A Gateway provisioning failure does not roll back an otherwise valid Beaver
|
||||
registration.
|
||||
- A user without stored Gateway credentials continues with curated memory only.
|
||||
- No separate repair UI or background credential provisioning job is added.
|
||||
|
||||
## Authenticated Chat Identity
|
||||
|
||||
Gateway credential selection must use a trusted server-side principal.
|
||||
|
||||
- REST and WebSocket frontend chat paths resolve the Beaver username from the
|
||||
issued access token.
|
||||
- The resolved username is passed separately into the agent runtime as the
|
||||
Gateway identity key.
|
||||
- Client-provided `user_id` fields do not select Gateway credentials and cannot
|
||||
impersonate another Gateway user.
|
||||
- Runs without an authenticated frontend username, including channel or
|
||||
scheduled runs without a trusted mapped identity, continue with curated
|
||||
memory only.
|
||||
|
||||
This identity key is runtime-only. It is not included in provider prompts or
|
||||
Gateway persisted message content.
|
||||
|
||||
## Runtime Architecture
|
||||
|
||||
`EngineLoader` loads:
|
||||
|
||||
1. Curated `MemoryService`, unconditionally.
|
||||
2. Shared `MemoryGatewayConfig` from `memory/config.json`.
|
||||
3. A `MemoryGatewayCredentialStore` for the instance credential file.
|
||||
|
||||
It does not construct one fixed-user `MemoryGatewayService` at startup.
|
||||
|
||||
For each authenticated run in hybrid mode:
|
||||
|
||||
1. `AgentLoop` receives the trusted Beaver username.
|
||||
2. It reads that username's credential from the credential store.
|
||||
3. If a credential exists, it constructs a run-local Gateway service/client
|
||||
from the shared config and that credential.
|
||||
4. It performs Gateway recall before context construction.
|
||||
5. It performs Gateway add and flush after normal completion.
|
||||
|
||||
The run-local service has no shared mutable credential state, so concurrent
|
||||
runs for different users cannot exchange identities. No service cache is added
|
||||
in this version.
|
||||
|
||||
## Recall and Persistence
|
||||
|
||||
The existing hybrid behavior remains unchanged once a user credential has
|
||||
been resolved:
|
||||
|
||||
- Search uses the current Beaver session id, current prompt, configured top K,
|
||||
and all three configured scopes.
|
||||
- Sanitized Gateway results are injected as one ephemeral untrusted-reference
|
||||
message outside the system prompt.
|
||||
- Normal completion persists exactly the original current user prompt and final
|
||||
assistant text.
|
||||
- Add is called once, followed by flush once only after add succeeds.
|
||||
- Tool calls, tool results, system prompts, curated memory, recalled Gateway
|
||||
text, reasoning, and skills are not persisted to Gateway.
|
||||
- Gateway and curated memory remain isolated and do not synchronize, merge,
|
||||
overwrite, or deduplicate each other.
|
||||
|
||||
## Security
|
||||
|
||||
- The shared configuration is safe to track because it contains no `userKey`.
|
||||
- Per-user credentials live only under ignored instance runtime data.
|
||||
- Credential-file permissions are `0600`.
|
||||
- Credential objects suppress secrets from `repr`.
|
||||
- Gateway client exceptions contain only operation, category, path, and status
|
||||
metadata.
|
||||
- Registration responses expose Beaver authentication data only; Gateway
|
||||
credentials remain server-side.
|
||||
- Hidden Gateway audit events may include the Beaver/Gateway user id but never
|
||||
the user key or complete request/response body.
|
||||
|
||||
## Testing
|
||||
|
||||
### Package migration
|
||||
|
||||
- All imports use `beaver.memory.gateway`.
|
||||
- No references remain to the removed integration/service modules.
|
||||
- Gateway config, client, service, and credential-store tests remain isolated
|
||||
from curated memory.
|
||||
|
||||
### Shared configuration
|
||||
|
||||
- The shared file parses the fixed URL and three scopes.
|
||||
- Invalid mode, URL, scope, top K, or timeout fails with sanitized errors.
|
||||
- Instance config loading remains unchanged for non-memory settings.
|
||||
- Test overrides can select a temporary shared config file.
|
||||
|
||||
### Credential persistence
|
||||
|
||||
- Missing files produce an empty credential map.
|
||||
- Credentials round-trip by Beaver username.
|
||||
- Updating one user preserves all other users.
|
||||
- Files are atomically replaced and have mode `0600`.
|
||||
- No exception or representation contains `userKey`.
|
||||
|
||||
### Registration
|
||||
|
||||
- New frontend registration calls `/users` with the Beaver username.
|
||||
- Valid Gateway responses are stored without returning the key to the browser.
|
||||
- Existing usernames refresh the same credential entry.
|
||||
- Provisioning failure does not roll back Beaver registration and stores no
|
||||
partial credential.
|
||||
|
||||
### Agent runtime
|
||||
|
||||
- Authenticated username selects only its own Gateway credential.
|
||||
- Client-provided `user_id` cannot select another user's credential.
|
||||
- Concurrent users construct independent run-local Gateway services.
|
||||
- Missing credentials perform no Gateway calls and preserve curated behavior.
|
||||
- Existing recall/add/flush ordering, payload, audit, and failure tests remain
|
||||
valid.
|
||||
|
||||
### Verification
|
||||
|
||||
- Run targeted Gateway/config/auth/chat tests.
|
||||
- Run Python compile checks and the complete backend test suite.
|
||||
- Scan tracked files and diffs for real `userKey` values.
|
||||
Reference in New Issue
Block a user