fix(acpx): preserve commentary across steering intervals

Project incremental assistant output as progress while keeping final snapshots authoritative. Verify frozen native steering intervals preserve their earlier commentary and record the failed native browser attempt and current validation scope.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-09 06:19:09 -05:00
1 parent f0d8417801
commit 370d3b8ddb
4 files changed
+73 -4

No files matched your search

@@ -1965,3 +1965,36 @@ The earlier cloud cold-start and ZIP timeouts remain failed. A separate
foundation signoff-policy cancellation/reconciliation failure still needs
qualification; the other current stack heads pass that shard. Full CI, review,
browser controls, paid credentials and actual Daytona remain required.
### 2026-10-09 interrupted charges and steering commentary
An authenticated OpenRouter usage frame can report a charge before the HTTP
stream fails. The receipt now retains that verified charge in the known
subtotal while keeping request completeness and token totals unavailable.
The pinned SDK regression reproduces the original lost charge, then passes
after the fix, including a subsequent successful request. Conflicting receipts
remain unpriced. All 13 billing tests pass; the combined pinned Python suite
passes 53 tests and skips one real-Linux bubblewrap test on Mac. The runtime
manifests change only the reviewed `billing.py` entry. The derived Mac and Linux
closure pins still require fresh cloud provisioning before accepting them as
clean consumer or remote proof.
The Mac native browser attempt using source `78c57ca` and the verified cloud
daemon shows reasoning and text before completion, then delivers the actual
Steer control to the same native turn. Native tools write the corrected file
and its authorized download matches. The attempt fails when earlier commentary
disappears after steering. Stored events retain that message; the TypeScript
ACPX driver incorrectly projects its channel as unknown. Deltas now project as
progress, matching the Rust normalizer, while the settled snapshot remains
final. All 64 driver and 174 transcript assertions pass. Fresh native browser
acceptance is still required; the failed attempt is not relabeled.
The announcement can appear after the dashboard URL settles. The company
navigation test now retries the ordinary sidebar click with a bounded deadline,
dismissing the actual card through its normal control if it blocks navigation.
All 29 cases in the chat messaging browser file pass. UI and Runner TypeScript,
the TypeScript-only build, and UI token gates pass. No local Docker, local Rust
build, provider credential or paid model call is used. Current cloud signoff
shards pass; an isolated server Git-streaming fixture times out on one stack
head and remains failed. Fresh full CI, review, paid connection and actual
Daytona qualification remain open.
@@ -361,7 +361,7 @@ describe("Codex ACPX harness driver", () => {
`${turnId}:assistant-message`,
]);
expect(assistantEvents.map((event) => event.payload.channel)).toEqual([
"unknown",
"progress",
"final",
]);
await expect(session.snapshot()).resolves.toMatchObject({
@@ -471,7 +471,7 @@ describe("Codex ACPX harness driver", () => {
`${turnId}:assistant-message`,
]);
expect(assistant.map((event) => event.payload.channel)).toEqual([
"unknown",
"progress",
"final",
]);
await session.close({ reason: "channel identity verified" });
@@ -1683,7 +1683,9 @@ class CodexAcpxSession implements HarnessSession {
"item.delta",
{
kind: isReasoning ? "reasoning" : "agentMessage",
channel: isReasoning ? "summary" : "unknown",
// Output chunks are progress; the settled snapshot owns final text.
// Frozen pre-steering intervals must retain their commentary.
channel: isReasoning ? "summary" : "progress",
text: output,
},
{
@@ -2,7 +2,12 @@ import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
import type { HeartbeatRunEvent } from "@paperclipai/shared";
import { nativeRunEventsToTranscript } from "./native-run-events";
import { transcriptToTaskChatItems } from "../task-chat/transcript-adapter";
import {
paperclipRunnerTimelineItems,
settledRunChildren,
splitTranscriptAtAnchors,
transcriptToTaskChatItems,
} from "../task-chat/transcript-adapter";
const RUN_ID = "10000000-0000-4000-8000-000000000001";
@@ -74,6 +79,35 @@ function runResult(summary: string): Record<string, unknown> {
}
describe("provider notice presentation", () => {
it("keeps native ACPX commentary when steering freezes its earlier interval", () => {
const entries = nativeRunEventsToTranscript([
itemEvent(1, "item.delta", "reasoning-1", {
kind: "reasoning", channel: "summary", text: "Inspecting the current task.",
}),
itemEvent(2, "item.delta", "message-before-steer", {
kind: "agentMessage", channel: "progress", text: "I am starting the requested work.",
}),
itemEvent(3, "item.completed", "steering-ack", {
kind: "steering_acknowledgement", status: "acknowledged", text: "Steering acknowledged for the active turn.",
}),
itemEvent(4, "item.delta", "message-after-steer", {
kind: "agentMessage", channel: "progress", text: "The correction is now applied.",
}),
]);
const [before, after] = splitTranscriptAtAnchors(
entries, Date.parse("2026-08-25T18:00:00.000Z"), [Date.parse("2026-08-25T18:00:03.000Z")],
);
const frozen = settledRunChildren(paperclipRunnerTimelineItems(transcriptToTaskChatItems(before.entries, {
runId: RUN_ID, running: false,
})));
expect(frozen.filter(item => item.kind === "activity_phase").map(item => item.interstitial?.text))
.toContain("I am starting the requested work.");
const continued = transcriptToTaskChatItems(after.entries, { runId: RUN_ID, running: true });
expect(continued.find(item => item.kind === "message")).toMatchObject({
text: "The correction is now applied.", channel: "progress",
});
});
it("omits unrelated information from saved chat without removing warnings or responses", () => {
const legacyNotice = {
schema: "paperclip.provider.notice.v1",