BUG/PERF: read/control API endpoints create ghost AgentContexts for unknown IDs #182

Open
opened 2026-09-09 15:05:27 +00:00 by nsaspy · 0 comments
Owner

Finding

ApiHandler.use_context() defaults create_if_not_exists=True, and many endpoints that are semantically read/control operations on an existing context call it without overriding that default.

Examples:

  • api/chat_export.py: exporting an unknown ctxid constructs a brand-new context and serializes that instead of returning not-found.
  • api/history_get.py: history lookup for an unknown ID creates an empty context and returns its history/token count.
  • api/chat_reset.py: resetting an unknown ID creates a context, resets it, persists it and removes its message-files path.
  • the same helper appears throughout pause/nudge/context-window/path/subagent and plugin API handlers and needs an endpoint-by-endpoint audit.

Each accidental creation runs initialize_agent(), profile reconciliation and AgentContext registration. The ghost context then participates in global roster/state work and may later be persisted. Bad/stale browser IDs or API clients can therefore inflate memory/chat lists simply by reading or controlling nonexistent contexts.

This also makes endpoint semantics surprising: a typo is transformed into a successful new resource rather than a 404/conflict.

Direction

Split context access into explicit APIs:

  • require_context(id) / lookup-only: never creates; returns typed not-found
  • create_context(...): creation-only with collision checks (#44) and validated IDs (#43)
  • optional get_or_create_context only for the narrow flows that intentionally need it

Do not keep a default-to-create helper on generic read/control endpoints.

Acceptance

  • chat_export, history_get, chat_reset, pause/nudge and other existing-resource operations return not-found for unknown IDs and never register a new context.
  • Audit every self.use_context(...) / shared context helper call and classify creation intent explicitly.
  • Only endpoints whose documented contract creates a context may call a creation primitive.
  • Repeated invalid/stale IDs cannot increase AgentContext.all() or the chat roster.
  • Not-found errors are typed/safe 404s rather than generic tracebacks.
  • Tests assert registry size and persisted-chat count remain unchanged after invalid lookup/control requests.
  • WebSocket handlers follow the same lookup-vs-create contract.

Mirrored from lost-rob0t/a0-symbolics#45 via tracker sync.

## Finding `ApiHandler.use_context()` defaults `create_if_not_exists=True`, and many endpoints that are semantically **read/control operations on an existing context** call it without overriding that default. Examples: - `api/chat_export.py`: exporting an unknown `ctxid` constructs a brand-new context and serializes that instead of returning not-found. - `api/history_get.py`: history lookup for an unknown ID creates an empty context and returns its history/token count. - `api/chat_reset.py`: resetting an unknown ID creates a context, resets it, persists it and removes its message-files path. - the same helper appears throughout pause/nudge/context-window/path/subagent and plugin API handlers and needs an endpoint-by-endpoint audit. Each accidental creation runs `initialize_agent()`, profile reconciliation and `AgentContext` registration. The ghost context then participates in global roster/state work and may later be persisted. Bad/stale browser IDs or API clients can therefore inflate memory/chat lists simply by reading or controlling nonexistent contexts. This also makes endpoint semantics surprising: a typo is transformed into a successful new resource rather than a 404/conflict. ## Direction Split context access into explicit APIs: - `require_context(id)` / lookup-only: never creates; returns typed not-found - `create_context(...)`: creation-only with collision checks (#44) and validated IDs (#43) - optional `get_or_create_context` only for the narrow flows that intentionally need it Do not keep a default-to-create helper on generic read/control endpoints. ## Acceptance - [ ] `chat_export`, `history_get`, `chat_reset`, pause/nudge and other existing-resource operations return not-found for unknown IDs and never register a new context. - [ ] Audit every `self.use_context(...)` / shared context helper call and classify creation intent explicitly. - [ ] Only endpoints whose documented contract creates a context may call a creation primitive. - [ ] Repeated invalid/stale IDs cannot increase `AgentContext.all()` or the chat roster. - [ ] Not-found errors are typed/safe 404s rather than generic tracebacks. - [ ] Tests assert registry size and persisted-chat count remain unchanged after invalid lookup/control requests. - [ ] WebSocket handlers follow the same lookup-vs-create contract. --- *Mirrored from [`lost-rob0t/a0-symbolics#45`](https://github.com/lost-rob0t/a0-symbolics/issues/45)* via tracker sync.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nsaspy/a0-symbolics#182
No description provided.