跪拜 Guibai
← All articles
Agent · Artificial Intelligence · Frontend

The Session Service Your Agent Can't Skip: Identity, Idempotency, and Real Cancel

By Sailing ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Without these mechanisms, agents duplicate work on retry, leak cross-tenant data via model-injected IDs, and burn money after users hit cancel. These are the failure modes that make production agents untrustworthy.

Summary

Production agent failures rarely come from the model itself. They come from identity passed as model parameters, sessions kept in memory instead of a database, double-clicks spawning two runs, and cancellation that only closes the SSE stream. The fix is a dedicated session service that owns conversation persistence, Run lifecycle, and a trusted RequestContext built from login state at the entry layer.

The article walks through the schema and flow: a RequestContext with tenant, user, roles, and scopes that every tool call must use; a runs table with a unique constraint on (tenant_id, idempotency_key) so one click creates one task; and a cancel path that writes cancel_requested, calls abort(), and distinguishes cancel_requested from cancelled. It also stresses that isolation must be enforced in queries, not filtered after fetch, and that keys never enter prompts or chat history.

Takeaways
— RequestContext must be built from server-side login state and passed to every layer; model params like userId are not trustworthy.
— The runs table should use a unique constraint on (tenant_id, idempotency_key) to prevent duplicate Run creation from retries or double clicks.
— Cancellation requires writing cancel_requested to the DB, calling abort() on the worker, and distinguishing that from the terminal cancelled state.
— Isolation should be applied in the query itself (matching conversationId + tenantId + userId), never by filtering after fetching all rows.
— Keys and access credentials belong only on the server; they must not appear in prompts, chat history, or logs.
— Every step in the background should check cancel_requested and an AbortSignal; closing SSE is not a cancel.
— Request idempotency doesn't imply tool execution idempotency; side-effectful tools need their own protection.
Conclusions

Agent frameworks like LangGraph track graph execution but not the operational concerns of identity, persistence, and cancellation, so a separate session service is necessary regardless of framework.

Isolate before query is a sharp principle: filtering after retrieval still exposes data to logs, cache, and model context, making it a leak vector even if the final response is safe.

Trusting model-provided userId is a classic prompt-injection hazard; the security boundary is an explicit server-side context, not the model's compliance.

Concepts & terms
Idempotency Key
A client-generated key that identifies a single business operation, so retries of the same operation return the same result instead of creating side effects again. Here it's used to ensure one send click creates one Run even if the network retries.
RequestContext
A server-side trusted data structure built after authentication, carrying tenant, user, roles, scopes, trace IDs, and a deadline. It is the only identity source for tool authorization, replacing untrusted model parameters.
Transactional Outbox
A pattern that writes an outbox record in the same DB transaction as the domain change, and a separate process publishes messages to the queue. It prevents the failure window where a DB commit succeeds but the queue publish doesn't.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗