Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74a423567f | ||
|
|
b225fbdd69 | ||
|
|
244e8d2927 |
@@ -438,6 +438,16 @@ mod tests {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_session_update_tag_the_acp_dependency_does_not_know_fails_to_deserialize() {
|
||||
// `SessionUpdate` has no unknown-variant fallback, so this never reaches `Projection::apply`.
|
||||
let result: Result<SessionNotification, _> = serde_json::from_value(serde_json::json!({
|
||||
"sessionId": "acp-1",
|
||||
"update": {"sessionUpdate": "some_future_update_variant"},
|
||||
}));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn folds_content_tool_diff_plan_and_notice_rows() {
|
||||
let mut projection = Projection::default();
|
||||
|
||||
+23
-8
@@ -113,13 +113,25 @@ crate.
|
||||
| `ToolDiff` | The same tool-call machinery, when the tool's content includes a `Diff` block. | Same `tool:<tool_call_id>` identity as `ToolCall`; the *kind* flips between the two as the tool's own content changes, not the row. |
|
||||
| `Approval` | A daemon-originated permission request (`RequestPermissionRequest`), serialized without its nonce. | `approval:<uuid>` — minted fresh per request, unrelated to the ACP request's own id. |
|
||||
| `Plan` | A `plan` update — the agent's current step list. | The fixed id `"plan"`. Each new plan **replaces** the row wholesale; entries are not diffed against the previous plan. |
|
||||
| `Notice` | The raw JSON of any `session/update` variant the projection does not special-case. | `notice:<seq>`. |
|
||||
| `Notice` | The raw JSON of any `session/update` variant the ACP dependency already decodes but the projection does not special-case. | `notice:<seq>`. |
|
||||
|
||||
`Notice` is the projection's forward-compatibility seam: ACP adds
|
||||
notification variants over time, and an unrecognised one becomes a generic
|
||||
row instead of being silently dropped or making the daemon reject the whole
|
||||
stream. A client that does not know what to do with a `Notice` can render it
|
||||
as an opaque, collapsed line — that is a reasonable floor, not a client bug.
|
||||
`Notice` covers known-but-unspecialized `SessionUpdate` variants: ones the
|
||||
`agent-client-protocol` dependency's schema already deserializes (it
|
||||
currently folds `available_commands_update` and `session_info_update`
|
||||
there) but the projection's `match` doesn't fold into one of the other
|
||||
seven kinds. It is not a wire-level forward-compatibility seam:
|
||||
`SessionUpdate` is an internally-tagged enum with no unknown-variant
|
||||
fallback, so a `session/update` whose `sessionUpdate` tag this build's
|
||||
dependency has never heard of — including a variant gated behind an
|
||||
unstable ACP feature this build doesn't enable, which is compiled out of
|
||||
the enum entirely — fails to deserialize before the projection ever runs,
|
||||
rather than becoming a `Notice`. A genuinely new ACP variant needs the
|
||||
`agent-client-protocol` dependency upgraded (and, typically, the projection's
|
||||
`match` taught about it) before it can appear on this transcript at all — see
|
||||
`projection.rs`'s test asserting that an unrecognised `sessionUpdate` tag is a
|
||||
deserialization error, not a `Notice`. A client that does not know what to do
|
||||
with a `Notice` can still render it as an opaque, collapsed line — that
|
||||
remains a reasonable floor, not a client bug.
|
||||
|
||||
Rendering is entirely a client concern. The projection's job stops at
|
||||
folding ACP into these eight shapes; markdown formatting, diff rendering,
|
||||
@@ -139,8 +151,11 @@ choices, not daemon ones.
|
||||
- Approval nonce minting, secrecy, and the single-active-approval rule (see
|
||||
below) — a client never sees an ACP permission request before the daemon
|
||||
has already turned it into an `Approval` row and a nonce.
|
||||
- What happens to an ACP update variant nobody has taught the daemon about
|
||||
yet (falls back to `Notice` rather than erroring).
|
||||
- What happens to an ACP update variant the dependency decodes but nobody has
|
||||
taught the projection to special-case (falls back to `Notice` rather than
|
||||
erroring). A variant the dependency itself can't decode is a deserialization
|
||||
error, not a `Notice` — see [The eight transcript row
|
||||
kinds](#the-eight-transcript-row-kinds).
|
||||
- Persistence and replay: what is written to the event log, in what order,
|
||||
and how a restart resumes it.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user