Internal documentation for developers. This page covers the Personal Assistant API internals: auth patterns, streaming SSE implementation, rate limiting, routine scheduling, and the runtime architecture. Not intended for end users.
Route Map
Plan Gating
Every PA route starts with plan validation:Auth Pattern
req.session.user.id.
Runtime Architecture
Language, intent, and verified knowledge pipeline
LanguageAndLocaleResolver resolves the response language separately from the
interface locale and persists durable conversation language metadata with a
compare-and-swap update. A short ambiguous message never overwrites the stored
language.
Human-language intent routing is model-classified into canonical intent IDs.
Only exact internal command IDs bypass that classifier. Invalid or
low-confidence classifier output fails closed to GENERAL_ANSWER.
The CANONICAL_CONTEXT_PIPELINE_V1 flow preserves the original route, query,
hash, active tabs, and safe transient states. It then resolves
VERIFIED_TEACHING_V1 or INTEGRATION_GUIDANCE_V1, adds provenance nodes to
the ContextGraph, and sends that verified context to the answer model.
Build-time coverage checks validate all 446 inventory surfaces; the generated
catalog is not imported into the request path.
Do not restore translated keyword arrays or substring matching for intents.
Do not expose an external navigation target unless its exact destination has a
verified source. Integration guidance is descriptive or links to verified
configuration only; it is never promoted to an executable action.
Streaming Implementation
The chat endpoint usesReadableStream with SSE format:
Routine Engine
/api/crons/personal-assistant-routines or similar) triggers them on schedule.
Rate Limiting
The chat endpoint enforces rate limits from@zappway/lib/rate-limit:
X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-Reset
i18n Context Injection
The chat route injects request context for i18n:Critical: Always callcleanupReqCtx()in thefinallyblock. Missing this causes locale context to leak between concurrent requests.
Privacy — Data Deletion
Known Issues / Gotchas
sourceIdentityis stripped from the input before passing toruntime.chat()— the dashboard always uses the authenticated user’s identity, never a client-supplied actor label.- Streaming abort handling: Both client abort (
client_disconnected) and timeout (personal_assistant_stream_timeout) triggerabortController.abort(). The error code is preserved in the SSEerrorevent for client-side differentiation. - State endpoint (
GET /state) usesPersonalAssistantStateQuerySchemavalidation + i18n injection — same pattern as chat. - Conversation isolation: PA conversations are scoped to
userId(not justorganizationId). Users cannot see each other’s PA conversations even within the same org.

