docs(timeline): describe immutable submitted prompt identity

Provider echoes now enrich daemon-internal identity only; wire rows keep their acceptance-time identity and rewind performs the provider translation.
This commit is contained in:
Mohamed Boudra
2026-08-01 11:56:25 +02:00
parent 7493eb5fac
commit fdda65531c
2 changed files with 12 additions and 18 deletions
+3 -3
View File
@@ -42,11 +42,11 @@ OpenCode MCP injection is dynamic and session-scoped. Call OpenCode's `mcp.add`
OpenCode owns user message IDs. Do not pass Paseo-generated IDs to OpenCode prompt APIs; let OpenCode create `msg*` IDs and record the user timeline item from the `message.updated` event.
`AgentManager` owns the one canonical timeline row for a foreground prompt carrying a Paseo `clientMessageId`. It records that row when `startTurn` accepts. Provider adapters still emit their native user-message echo with the same `clientMessageId` when available; the manager uses it to enrich the existing row with the provider `messageId` without allocating another sequence. If an adapter emits the echo before `startTurn` resolves, the manager carries its provider identity into the row it records at acceptance. Provider adapters continue to own externally initiated user rows that have no Paseo client identity. Do not perform global transcript text dedupe.
`AgentManager` owns the one canonical timeline row for a foreground prompt carrying a Paseo `clientMessageId`. It records that row when `startTurn` accepts, with the wire `messageId` set to the same value. Provider adapters still emit their native user-message echo with the same `clientMessageId` when available; the manager records its provider identity on the internal row without changing or redispatching the wire item. If an adapter emits the echo before `startTurn` resolves, the manager records the provider identity with the row at acceptance. Provider adapters continue to own externally initiated user rows that have no Paseo client identity. Do not perform global transcript text dedupe.
When the provider echo arrives after acceptance, the manager publishes the enriched canonical row again at its original sequence. This is an in-place row revision, not another timeline append; consumers may apply it only to the already-covered row with the matching `clientMessageId`.
Rewind accepts the canonical wire `messageId` and resolves it to the provider identity before calling the adapter. A submitted prompt cannot be rewound until its provider echo supplies that identity.
Submitted user-message rows preserve both identities: `messageId` is the provider-visible ID and the optional `clientMessageId` is the Paseo ID from `AgentRunOptions`. Attach `clientMessageId` only to the canonical row for that foreground submission; provider history and externally initiated user rows do not have a Paseo client ID.
Submitted user-message wire items carry the same Paseo ID in `messageId` and `clientMessageId`. Provider adapters attach `clientMessageId` only to the echo for that foreground submission; provider history and externally initiated user rows do not have a Paseo client ID.
Draft metadata lookups should avoid creating provider sessions when the upstream provider has top-level APIs for that metadata. Prefer `AgentClient.fetchCatalog`, `listCommands`, or `listFeatures` over creating a scratch `AgentSession`; scratch sessions can show up as empty native sessions in provider import/history UIs. `fetchCatalog` is the single discovery API for models and modes — provider implementations may use one process, separate upstream calls, or static data internally, but callers outside the provider do not get separate runtime model/mode probes. Draft feature and command listing must use the explicit draft model only; if no model is selected yet, return no metadata instead of resolving a default model through catalog discovery.
+9 -15
View File
@@ -98,10 +98,10 @@ reconciled with the authoritative tail and subsequent catch-up.
Every daemon-derived live item carries its timeline epoch and sequence position. Bootstrap
replacement keeps only positioned rows newer than the page it installs, while unresolved local
user presentations identify themselves by having client identity without provider identity or a
timeline position. This prevents a page from duplicating rows it already covers without coupling
display continuity to the shorter-lived submission registry. Unreconciled local presentations are
not persisted in the durable replica cache.
user presentations identify themselves by having client identity without a timeline position. This
prevents a page from duplicating rows it already covers without coupling display continuity to the
shorter-lived submission registry. Unreconciled local presentations are not persisted in the durable
replica cache.
## Selective and legacy delivery
@@ -173,18 +173,12 @@ second running state. Disconnect and replica removal remain destructive close bo
comes only from turn liveness, never from submission records or whichever timeline rows happen to be
mounted.
The daemon records one canonical submitted user row with Paseo's `clientMessageId` as soon as the
provider accepts the turn. A correlated provider echo enriches that same sequence with its provider
`messageId`; it never appends a second source row. The row's identity and pagination position are
therefore independent of provider notification timing. A late echo is streamed as a revision at the
original sequence; clients apply it only to the already-covered row with the same client identity.
The daemon records one canonical submitted user row at acceptance. Its wire `messageId` is the
submission's `clientMessageId`, so the row is born with its final identity and remains immutable on
the wire. A correlated provider echo records the provider's native identity internally without
dispatching another timeline event. Rewind resolves the wire identity to that provider identity at
the provider boundary. Daemon-handled prompts follow the same identity rule.
Clients that understand these same-sequence updates advertise the
`canonical_submitted_prompt_revisions` client capability. For older destinations, the daemon keeps
the canonical row globally but withholds an identity-awaiting foreground prompt until provider identity
arrives or the turn produces later output or a terminal. Finalization optionally adds provider
identity, removes the internal delivery marker, and redispatches the same stored sequence. Timeline
fetches hide only that trailing marked row; daemon-handled prompts are never marked.
Content matching is limited to the dated compatibility path for daemon timelines created before
that field existed. Canonical ingestion may match only an explicit unreconciled local candidate;
the draft-create handoff is the one boundary that also permits the legacy canonical twin to have