|
|
@@ -28,7 +28,7 @@ The system prompt lives on the surface. It is an ordinary surface event, `system
|
|
|
| A `system/message` survives and the rendered prompt differs from its text (including a prompt that becomes empty) | replace exactly that node: `surfaceOp: { op: 'replace', start: <seq of the node>, end: <same> }`, `sourceEventSeqs: [<seq of the node>]`; an empty prompt produces an empty-content node that projects to no message |
|
|
|
| The rendered prompt equals the surviving node's text | no operation |
|
|
|
|
|
|
-The loop reserves an empty system head before the initial admitted user messages so a prompt that first becomes non-empty later still replaces node 0. Omitting that empty node would append the later prompt behind user history, where pi-ai converts it to a user message rather than its `systemPrompt`. Replacing node 0 is a head rewrite expressed on the surface: the provider prefix changes from the first token, the log records the shadowed node through `sourceEventSeqs`, and `replaceGeneration` advances as it does for a compaction replacement. The loop's `startsSeries` detection (`requestSurfaceGeneration !== surfaceGeneration`) therefore covers the prompt change without a `system` comparison in `headerEquals`. `request/header` keeps reasons `initial`, `resume`, `change`, and `series`; `change` means config or tools changed, and the unchanged header that follows a prompt replacement logs as `series`.
|
|
|
+When the initial rendered prompt is empty, the loop reserves an empty system head before the initial admitted user messages so a prompt that first becomes non-empty later still replaces node 0. Omitting that empty node would append the later prompt behind user history, where pi-ai converts it to a user message rather than its `systemPrompt`. Replacing node 0 is a head rewrite expressed on the surface: the provider prefix changes from the first token, the log records the shadowed node through `sourceEventSeqs`, and `replaceGeneration` advances as it does for a compaction replacement. The loop's `startsSeries` detection (`requestSurfaceGeneration !== surfaceGeneration`) therefore covers the prompt change without a `system` comparison in `headerEquals`. `request/header` keeps reasons `initial`, `resume`, `change`, and `series`; `change` means config or tools changed, and the unchanged header that follows a prompt replacement logs as `series`.
|
|
|
|
|
|
`packages/core/session/src/surface.ts` enforces the head invariant in `assertSystemHeadRewrite`: a replacement whose range covers surface node 0 while node 0 is a `system/message` is rejected unless the replacing event is itself a `system/message` covering exactly that node. System nodes at later positions carry no such protection; a compaction range may shadow them.
|
|
|
|
|
|
@@ -56,6 +56,18 @@ In `packages/core/agent-loop/src/agent.ts`, `preStep` renders the prompt with `r
|
|
|
|
|
|
`RuntimeContextProjection` and `SystemPromptProjection` are symmetric: both watch owned surface nodes and their shadowing through `sourceEventSeqs`, and both hand the loop an uncommitted message that `turn()` commits. The difference is the role and the operation set — runtime context appends user-role snapshots only, the system prompt appends once and then replaces.
|
|
|
|
|
|
+### V2-to-V3 structural conversion
|
|
|
+
|
|
|
+The [V2-to-V3 migration](../../../../packages/session/session-format-v2-to-v3/README.md) converts each V2 `request/header.system` into the protected `system/message` head and removes the retired header field. It inserts an empty head immediately after the first `step/start`, then replaces that head immediately before a header whose prompt differs. Inserted messages have deterministic IDs. The transform preserves source event order, reconstructed request meaning, and the exact IDs and content of every other message. A native V3 writer emits its normal prompt head; the migrated event layout is semantically equivalent, not byte-identical to a native recording.
|
|
|
+
|
|
|
+Inserted events shift local sequence positions. The transform remaps local sequence references, replacement ranges, and the inherited cut; historical delivery/version facts and captured references to other sessions retain their source values. These historical coordinates must not be relabeled as acknowledgements of the transformed V3 log.
|
|
|
+
|
|
|
+Strict migration refuses unknown events whose payloads cannot be safely transformed, unsupported surface history before the first step, and a prompt transition outside an open step. Such a V2 source can be valid while having no order-preserving conversion under the current core step invariant. Refusal leaves the original files unchanged; it does not reorder source events or relax the invariant to force a conversion. The V3 reader rejects the retired `header.system` field and validates system-message payloads and protected-head rewrites rather than relying on TypeScript field omission.
|
|
|
+
|
|
|
+The [released-format policy](2026-08-31-released-session-format-migrations.md) keeps V0, V1, and V2 generations byte-frozen and publishes only V3 successors. V3 is one unreleased target, not a new version per feature; it can evolve before release, so integration requires disposable homes. An existing V3 generation does not rerun V2-to-V3. Projection-cache version 4 is independent of the Session format and does not imply Session V4.
|
|
|
+
|
|
|
+[Canonical-envelope work](https://github.com/deepseek-ai/deepseek-harness/pull/3636) is separate and not integrated here. Its composition order is after this structural transform within the same V2-to-V3 edge, so it canonicalizes the transformed events rather than replacing the conversion.
|
|
|
+
|
|
|
## Alternatives considered
|
|
|
|
|
|
**Keep `header.system` and add `system/message` only for updates.** Two homes for one fact: every consumer above would read the header for message 0 and the surface for later messages, and the loop would need a special case that ignores `system` in `headerEquals` while a surface system node exists. Rejected because the point of the change is one representation.
|