Commit Graph
3788 Commits
Author SHA1 Message Date
David ZandGitHub 39de577a5d fix(i18n): translate French design system flow copy (#7906) 2026-09-15 08:21:51 +00:00
maoxin1234andGitHub 55b3762afe feat(daemon): capture per-request request_id + token usage for claude_code runs (#4620)
* feat(daemon): capture per-request request_id + token usage for claude_code runs

The claude-stream-json parser read every assistant message's `message.id`
only to dedup streamed text/thinking and then dropped it, and never read
`message.usage` at all — so a run with N model requests collapsed into a
single run-level `result.usage` record with no request id. That left
request-level cost/percentile analysis stuck at run-level (~0.9% coverage).

Surface the per-request granularity the wire already carries:

- claude-stream.ts emits a new `request_usage` event per assistant message,
  keyed by `message.id` (the provider `msg_…` request id), carrying the
  per-message input/output/cache tokens via a `perRequestUsageFrom` helper.
- packages/contracts adds `request_usage` to both the live SSE
  `DaemonAgentPayload` and the `PersistedAgentEvent` union; server.ts maps
  the live event to its persisted form.
- mocks/lib/format-claude.mjs now emits per-message `usage` summing to the
  run-level `result.usage`, so the capture path is verifiable by local
  replay without burning provider budget.

The per-request token sum reconciles against the run-level `result.usage`
aggregate — the correctness anchor. New daemon test plus regenerated claude
golden cover both the synthetic stream and the mock-replay path. No change
to run execution; only telemetry/contract surface is added. claude-stream-
json only for now; other runtime families ship per-request shapes in
follow-ups.

Closes #4610

* feat(daemon): thread per-request usage through Langfuse + PostHog run telemetry

Addresses review on #4620: the parser emitted the per-request records but they
stopped at SSE/message persistence and never reached the telemetry sinks named
in #4610's acceptance criteria, so PostHog/Langfuse still had no per-request
request_id + token coverage.

Wire the records through the existing run telemetry choke point:

- run-analytics-observability.ts adds `scanRunEventsForPerRequestUsageAnalytics`,
  a pure scanner that collects the per-request records keyed by request_id and
  checks the reconciliation invariant (per-request token sum == run-level
  `result.usage`). Both sinks read this one source.
- langfuse-bridge.ts `collectAgentEvents` exports one `agent-request-usage`
  Langfuse event per model request, keyed by the provider request id.
- routes/runs.ts adds `run_finished` coverage properties
  (`request_usage_count`, per-request token sums, and
  `request_usage_reconciles_aggregate`) so the PostHog request-level surface
  lifts off the ~0.9% floor; contract fields added to RunFinishedProps.

Test extended: a multi-request claude run produces telemetry records keyed by
request_id whose token sum reconciles with `result.usage`, plus a
non-reconciling guard. langfuse-bridge + run-analytics suites stay green.

* fix(daemon): fold cache tokens into per-request usage reconciliation

Addresses review on #4620: request_usage_reconciles_aggregate compared only
input/output tokens, so a run whose prompt/completion tokens matched but whose
cache creation/read tokens drifted still reported `true` — letting the new
PostHog/Langfuse telemetry certify the #4610 invariant when part of
`result.usage` had not reconciled.

scanRunEventsForPerRequestUsageAnalytics now reads the aggregate
`cache_creation_input_tokens` / `cache_read_input_tokens` and folds every field
`result.usage` reported into the boolean (each compared only when the aggregate
carries it, mirroring the input/output leniency). Added a fixture where cache
tokens mismatch while input/output still match, so the flag stays false and
this cannot regress.

* feat(daemon): map request_usage to durable PersistedAgentEvent

* feat(daemon): wire per-request usage rollup into run_finished analytics lifecycle

* ci: trigger fresh validation run for approved changes

* feat(daemon): preserve per-request usage in truncation-proof run side ledger
2026-09-15 08:21:32 +00:00
lorenzozaneandGitHub 127ec0f027 fix(daemon): defer invalid-payload until launcher state is eligible (#7520)
On a fresh Windows install the launcher has no versions/0.16.1 tree yet,
so resolvePayloadExecutable returns null and
prepareLegacyPayloadDesktopHandoff immediately returned invalid-payload.
That ran before the eligibility check (active == lastSuccessful,
generation 0), masking the real state as a payload error. The daemon
then logged [packaged desktop handoff] skipped { reason:
'invalid-payload' } and left trustedWebOriginPort null, so /api fell
through to the Next.js HTML shell (already fixed web-side by #7399 for
the no-daemon-origin path).

Reorder the check: report launcher-state-not-eligible first and only
return invalid-payload when the launcher state is actually eligible for
a handoff but the payload file is missing. Payload resolution stays
manifest-driven, so a missing or mismatched manifest keeps failing
closed instead of accepting a guessed executable that the updater never
promoted.

The regression now covers both halves of #6074: the fresh-install
classification, and the packaged startup that actually delivers the web
port the daemon trusts for /api.

Fixes #6074
2026-09-15 06:08:57 +00:00
Tony BoxandGitHub 8031b5e217 fix(daemon): prefer direct Copilot CLI (#7974)
Avoid VS Code's interactive Copilot bootstrapper when a direct CLI install is available, while retaining the bootstrapper as a fallback.
2026-09-15 06:08:34 +00:00
dc61db8e03 fix(daemon): show Codex and OpenCode tools before arguments finish (#8117)
* fix(daemon): stream early Codex and OpenCode tool previews

* fix(daemon): retry missing runtime versions for tool previews

* test(amr): verify early tool previews through real Vela runs

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-09-15 04:21:09 +00:00
David ZandGitHub 7dc55872bb fix(i18n): translate French Library and Memory copy (#7756) 2026-09-15 03:39:29 +00:00
6b0692f868 Expand the Novita AI model catalog (#6327)
* add Novita AI provider preset

Adds Novita AI to KNOWN_PROVIDERS so it appears in the BYOK provider
picker alongside the other OpenAI-compatible presets.

Follows the PPIO entry directly above it: same openai protocol, a
/v3/openai base URL, and a preferredModels list. The apiKeyConsoleLink
follows the Atlas Cloud entry so Settings can deep-link to the key page.

Model ids were taken from the live /v3/openai/models catalogue.
No new dependencies, no changes to any shared type or function.

* fix(providers): correct Novita base URL to current documented endpoint

The KNOWN_PROVIDERS Novita AI entry used https://api.novita.ai/v3/openai,
copied from this loop's own evidence store (browser-use's own
examples/models/novita.py, an older third-party example). Novita's
current documented OpenAI-compatible endpoint (novita.ai/docs/guides/llm-api)
is https://api.novita.ai/openai. Both paths return identical, working
results today (verified live against /models and /chat/completions), so
this is a stale citation, not a functional break. The separate PPIO entry
(a different vendor, api.ppinfra.com) is untouched.

* fix(providers): update Novita preferred models per QA catalog check

Replace superseded deepseek/deepseek-v3.2 and qwen/qwen3.5-397b-a17b
with current live-catalog flagships minimax/minimax-m3 and
qwen/qwen3.8-max.

* feat(providers): add Novita BYOK preset

---------

Co-authored-by: jax-novita <jax-novita@users.noreply.github.com>
Co-authored-by: jax-novita <jax@novita.ai>
Co-authored-by: Ray Xi <2667192167@qq.com>
2026-09-15 03:34:20 +00:00
netteeandGitHub d465086b2c fix(amr): align client links with Cloud dashboard routes (#8126)
* fix(amr): use canonical cloud dashboard URLs

* test(e2e): align AMR recharge link assertion

Generated-By: looper 0.13.1 (runner=fixer, agent=codex)

* fix(amr): honor selected dashboard profile

Generated-By: looper 0.13.1 (runner=fixer, agent=codex)
2026-09-14 11:23:17 +00:00
e3400d2d00 fix(chat): fall back when artifact cover image fails (#8045)
* test(chat): expose blank artifact card when cover image fails

* fix(chat): fall back when artifact cover fails

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 09:56:14 +00:00
39d9eb593b fix(web): restore terminal artifacts without overriding user preview (#8050)
* test(web): expose reattach artifact focus regression

* fix(web): refresh recovered artifacts without overriding user preview

* fix(web): preserve host ownership of automatic initial selection

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 08:40:28 +00:00
PerishFireandGitHub 1ff25e5b2b fix(packaged): preserve MCP runtime integrity and sidecar delivery (#8027)
* fix(daemon): keep packaged MCP discovery out of package managers

* fix(packaged): preserve MCP payload identity and require sidecar supervisor

* fix(pack): finalize runtime manifests and report entry recovery

* ci: allow isolated full Windows smoke on dispatched revisions

* test(packaged): derive recovery versions from the release channel

* test(win): read portable installer logs and retain rollback diagnostics

* test(win): distinguish portable startup reconciliation from installer sync
2026-09-14 08:13:45 +00:00
Ray XiandGitHub 1af682238d fix(acp): send session cancellation as a notification (#7959) 2026-09-14 08:05:45 +00:00
7abe49c858 fix(desktop): preserve the running launcher payload during cleanup (#7963)
Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 06:03:42 +00:00
810cbe058f fix(daemon): preserve buffered ACP text before empty-output checks (#8015)
Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 04:36:56 +00:00
8921ccac20 fix(daemon): exclude URLs from ACP title file inference (#8063)
Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 03:53:01 +00:00
bf60362dbc fix(web): expose requested read ranges in execution record titles (#8062)
Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 03:52:51 +00:00
dcfd44eed9 fix(chat): honor the selected artifact card order (OPEND-2774) (#8060)
Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 03:52:37 +00:00
13d3676f83 fix(chat): use physical run starts for execution clocks (#8059)
Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 03:52:29 +00:00
954f304dd1 fix(chat): restore next steps for successful image deliveries (#8057)
Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 03:52:16 +00:00
5a3f0c8923 fix(daemon): archive owned Codex threads after terminal completion (#8051)
* fix(daemon): archive owned Codex threads after terminal completion

* fix(daemon): archive owned Codex threads after interrupted close

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 03:52:01 +00:00
1424be9727 fix(chat): refresh live artifact cards after same-path updates (#8047)
* fix(chat): bust live artifact iframe cache on file updates

* fix(chat): scope artifact cache refresh to live HTML previews

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 03:51:45 +00:00
668c094362 fix(daemon): preserve failed ACP tool results (#8046)
* fix(daemon): preserve failed ACP tool results

* fix(daemon): retain ACP failures across partial tool updates

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 03:51:37 +00:00
lefarcenandGitHub a62d5e08cf fix(chat): remove native tooltips from question options (#8033)
* test(chat): reject native option description tooltips

* fix(chat): remove native tooltips from question options

* test(chat): cover checkbox descriptions without native tooltips
2026-09-14 03:51:14 +00:00
393ecfe9e3 fix(web): keep Continue on the owning conversation turn (#8014)
Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 03:51:06 +00:00
e10b5b487b fix(chat): keep question form controls in the UI language (#8010)
* fix(chat): keep question form controls in the UI language

* test(web): locate questionnaire controls by visible semantics

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 03:50:59 +00:00
50e9c0fcce fix(chat): keep workspace writes out of Agent deliverables (#7997)
* fix(chat): preserve manual file ownership across run recovery (OPEND-2928)

Record successful workspace document writes and exclude their unchanged
receipts from assistant produced/trace files while retaining proven Agent
writes and existing unknown-runtime output handling.

Carry receipts through reconnects of the same scoped physical run, including
transport failure ordering and manual reconnect after a missing status.
Keep cleanup on real terminal exits, failed run creation and scope changes.

* fix(chat): preserve file ownership during inline artifact recovery

Use the resolved project authority for artifact writes and carry scoped
manual-write receipts through terminal error handling into artifact recovery.
Read the transport text when deciding whether artifact recovery is pending,
and filter existing produced/trace projections without dropping Agent output.

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 03:50:51 +00:00
6086bbfd97 fix(chat): preserve earlier question forms before explicit done (#7996)
* fix(chat): preserve the earliest visible done boundary

* fix(chat): validate implicit boundaries before authenticated done

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 03:50:44 +00:00
lorenzozaneandGitHub 01726d9fc6 fix(daemon): keep OD Next clarifications resumable after a restart drops the source Run snapshot (#7575)
durableRunState never serialized appliedPluginSnapshotId, so a daemon restart
restored the source Run without the field while the strategy task kept its
locked snapshot; the clarification continuation guard then rejected the task
with STRATEGY_TASK_SOURCE_RUN_INVALID. Persist the field on the durable run
state, and recover a missing id from the applied_plugin_snapshots run_id link,
which survives restarts. Runs whose snapshot id is set but differs, or whose
snapshot row is not linked to the source Run, keep failing the guard.
2026-09-14 03:50:37 +00:00
Ray XiandGitHub 75840861f3 fix(daemon): allow BYOK image input without capability metadata (#8035)
* fix(daemon): allow BYOK image input without capability metadata

* test(daemon): expect image modalities in BYOK chat config
2026-09-14 03:35:18 +00:00
e2944dabac fix(daemon): accept a clarification turn whose Runtime State names the wrong stage (#7980)
After the user answers the one clarification round, the agent's next turn
carries a complete Full Plan plus a Runtime State. On 0.22.1-prerelease.9
(OPEND-2954) that state said `inputStage: "request"` — the value every
Runtime State example in the protocol reference shows, and the one field the
clarification continuation never named — and the coordinator refused the turn
on that field alone. The task settled terminal-`blocked`, a plan that passed
every other gate never reached production, and no repair path could anchor on
it because the block was schema-valid and the mismatch is not a parser issue.

The stage is host-owned truth: the daemon issued it, wrote it into the
continuation wrapper, and holds it on the task, so a disagreeing declaration
carries no authority — the same footing as the execution mode a clarification
turn predicts, which the parser already discards. `adoptHostInputStage` now
gives the state the host's stage before validation whenever the corrected
state is a valid declaration for that stage, and records the decision as a
normalization rather than a reason code so an agent-declared `blocked` keeps
its own attribution. Where the field does carry meaning — a second
`clarification_required`, a `plan_ready` at production — the corrected state
fails the contract, the agent's value stands, and the turn is refused exactly
as before. The serialization-repair anchor gets the same treatment so a fenced
plan on a clarification turn can still enter its one repair.

The clarification continuation now also says which stage it runs at, mirroring
the production continuation's `inputStage production`, so the agent has one
sentence to follow instead of three examples that all say `request`.

Specs: a clarification turn declaring `request` / `plan_ready` with a valid
plan reaches `plan_ready` (red on main: blocked with
`od_next_protocol_stage_mismatch`); an agent-declared block with the wrong
stage keeps `od_next_agent_declared_block`; a second question round is still
refused; a fenced plan with the wrong stage still anchors a repair; the
continuation text names `inputStage clarification`.

Co-authored-by: Cheems <216108319+hihicheems@users.noreply.github.com>
2026-09-14 03:22:04 +00:00
Austin WandGitHub 6d1d91a302 fix(daemon): keep proxy Basic credentials off the media wait tool-token lane (#8006)
* fix(daemon): keep proxy Basic credentials off the media wait tool-token lane

The media task wait route selected the run-scoped tool-token lane on the
mere presence of an Authorization header. Tool tokens are only ever
parsed out of a Bearer header (bearerTokenFromRequest), so a reverse
proxy that authenticates browsers itself and forwards its own
`Authorization: Basic ...` could never satisfy that lane: every proxied
poll of POST /api/media/tasks/:id/wait failed 401 TOOL_TOKEN_MISSING,
so image and video generation never reported completion.

Gate the lane on the Bearer scheme. The existing intent is preserved —
once a Bearer caller does choose the lane, invalid, expired or
under-scoped credentials still must not downgrade to project
authorization; this only changes what counts as choosing it.

The other two authorizeToolRequest callers in this file,
/api/tools/media/scaffold and /api/tools/media/generate, are agent-only
endpoints that unconditionally require a tool token and are unchanged.

Same root cause as #7819, which covers the export and archive routes in
apps/daemon/src/import-export-routes.ts.

* fix(daemon): fail closed on a malformed Bearer credential

Review catch: `authorizationHeader.trim()` reduces `Authorization: Bearer `
to `Bearer`, which the `/^Bearer\s+/i` predicate rejected. That sent a
malformed Bearer credential to `authorizeProjectRequest` instead of
`authorizeToolRequest`, so a caller reaching for the tool-token lane could
reach the browser project-authority lane — before this branch, any
Authorization header produced TOOL_TOKEN_MISSING.

Classify the scheme independently of whether a token follows it, so both
`Bearer` and `Bearer <invalid>` stay on the tool-token lane and fail closed,
while Basic credentials still reach project authorization.

Regression coverage added for `Bearer ` and a bare `Bearer`; both return a
full task snapshot (HTTP 200) with the previous predicate and 401 with this
one.
2026-09-14 03:20:42 +00:00
0af03070ee fix(web): allow horizontal scrolling of chat image rows (#8013)
* fix(web): allow horizontal scrolling of chat image rows

* fix(chat): keep thumbnail scrollbars clear of previews and clicks

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 02:59:39 +00:00
9f76c3a9cf fix(daemon): keep proxy Basic credentials off the export tool-token lane (#7999)
* fix(daemon): keep proxy Basic credentials off the export tool-token lane

authorizeExportRead treated any Authorization header that was not the
daemon API token as a run-scoped agent tool-token call. Tool tokens are
only ever parsed out of a Bearer header (bearerTokenFromRequest), so a
reverse proxy that authenticates browsers itself and forwards its own
`Authorization: Basic ...` (Coolify native basic auth, Traefik basicAuth
without header stripping) could never satisfy that lane: every browser
export and archive request failed 401 TOOL_TOKEN_MISSING.

Gate the tool lane on the Bearer scheme so foreign Basic credentials fall
through to project authorization like a header-free browser request.
Foreign Bearer tokens still fail closed in the registry.

Covers export/{html,pptx,pdf-image,image}, the generic export route,
archive, archive/batch and the inline-HTML route, which all share the
helper.

Root-cause analysis and the Bearer-gate approach are @airano-ir's, from
the #7819 report.

Fixes #7819

Co-Authored-By: airano <244096521+airano-ir@users.noreply.github.com>

* fix(daemon): fail closed on a malformed Bearer credential

Carries the review finding from #8006 across to the export lane, which had
the same predicate. `authorizationHeader.trim()` reduces `Authorization:
Bearer ` to `Bearer`, which `/^Bearer\s+/i` rejected, downgrading a
malformed Bearer credential to browser project authority instead of failing
closed with TOOL_TOKEN_MISSING.

Classify the scheme independently of whether a token follows it. Regression
coverage added for `Bearer ` and a bare `Bearer`.

---------

Co-authored-by: airano <244096521+airano-ir@users.noreply.github.com>
2026-09-14 02:41:54 +00:00
0c500ef3eb fix(chat): keep preparing action during send admission (#8069)
Co-authored-by: lefarcen <935902669@qq.com>
2026-09-14 02:40:37 +00:00
lefarcenandGitHub e21f6bf297 fix(web): stabilize long question form titles (#8031)
* test(web): reproduce question title wrapping

* fix(web): keep question titles on one line

* fix(chat): stabilize question metadata and verify the rendered header
2026-09-14 01:52:54 +00:00
lefarcenandGitHub b4783cfc85 fix(chat): preserve uploaded attachment sizes (#8030)
* fix(chat): preserve uploaded attachment sizes

* test(daemon): cover uploaded attachment size across UI save ordering
2026-09-14 01:52:52 +00:00
Ray XiandGitHub d06eb1efeb fix(daemon): fail blocked OD Next runs before finalization (#7942)
* fix(daemon): fail blocked OD Next runs before finalization

* test: align run fixtures with OD Next terminal status

Keep generic session and smoke fixtures on ordinary runs, and assert the blocked verdict in the strategy timing fixture.

Generated-By: looper 0.13.0 (runner=fixer, agent=codex)

* test(daemon): isolate Codex resume and retry fixtures from OD Next

Select ordinary-run mode for plain-reply session and recovery fixtures, restoring the rollout override after each test.

Generated-By: looper 0.13.0 (runner=fixer, agent=codex)
2026-09-14 01:37:47 +00:00
ad9078b87c fix(chat): keep footer actions and time visible in narrow panes (#8001)
Co-authored-by: lefarcen <935902669@qq.com>
2026-09-11 17:38:59 +00:00
933dc96038 fix(daemon,web): stop a delivered OD Next turn reporting as failed, and name the real gate (#7931)
* fix(daemon,web): stop a refused turn reporting a delivered deck as failed

One predicate answered two different questions, and the strict answer is the
wrong answer to the loose one.

`validateRunDeliverable` asks "did THIS run write the canonical entry". That is
the right gate for accepting an Agent's completion claim — a turn must not pass
by pointing at a file an earlier turn wrote. It is also `false` for the most
ordinary shape of an OD Next refusal: the user types 「继续」, the agent
re-checks work an earlier turn already finished, correctly rewrites nothing,
and the turn is refused over its machine block.

Both safety nets read that one answer, so both went down together. The
coordinator's completion inference declined, and `deliveredDespiteBlock` in the
web provider — the carve-out that exists to keep a delivered turn out of the
failure branch — could never fire. A field report shows the result: a red
「回复已收到,但没能记录下来」card under a finished 16-page deck the user could
see rendered in the preview pane beside it. The physical run had exited 0 and
the 2.27 MB file was on disk.

`validateProjectDeliverable` is the second question: does the user have it,
right now. Same entry resolution, same kind contract, same readability check,
minus the run-scoped gates. `GET /api/runs/:id` resolves it only for a terminal
run whose strategy task settled blocked — the one case a client has to
distinguish — and logs the answer, because withholding a failure the user
cannot act on is right and withholding it invisibly is not.

The verdict does not move: the task still blocks, the strategy contract still
refuses to complete on an unproven claim, and a turn that delivered nothing
still fails with its card. What changes is that a bookkeeping failure no longer
tells a user they lost work that is sitting in their project.

This is also what `docs/design/run-errors/error-ux-design.md` §3 already ruled
for the case: 「文件生成了但进程报错:算成功」, with the stated reason that doing
otherwise "把一堆无害报错变成失败潮".

Red spec: apps/web/tests/providers/strategy-blocked-verdict.test.ts
「does not become a failure when the project holds the deliverable」 — red on
main, green here.

* fix(daemon,web): name the gate that refused a turn, not the parser that noticed

The protocol parser raises `od_next_protocol_runtime_state_missing` before
`validateAcceptedTurn` — the function that owns the real gates — is ever
reached. So every block-less turn was filed under the parser's own code, and
`reasonCodes[0]` is what the failure card, the diagnostics export and the
analytics bucket all read.

The effect on a user who got nothing this round: they were told a marker was
missing. True of the reply, useless to them, and not the reason the turn could
not succeed — the identical failure with a DECLARED block reported
`od_next_canonical_deliverable_invalid`, the host fact they can act on. Two
names for one failure, and the less useful one was the one that shipped.

`reattributeUndeclaredTurn` already existed for exactly this, scoped to one
cell (a clarification turn that asked again). Extend it: when a block-less turn
was SHAPED like a completion the host may infer and the inference still
declined, the evidence is what refused — both helpers gate on the shape, which
just held, and the evidence. Lead with it. The parser's code stays behind it,
because `blocked_reason_codes_json` is the durable record of what the turn
actually wrote, and a triage that cannot tell "declared badly" from "declared
nothing" has lost the one distinction that decides whether a serialization
repair was ever possible.

ATTRIBUTION ONLY — no verdict moves. The two existing specs that pinned the old
name still assert the verdict they own and now assert the new attribution; the
turns they describe block exactly as before.

`od_next_canonical_deliverable_invalid` gets the card it now needs. It is
deliberately not the Runtime State copy: those say "your reply went missing",
this says "nothing came out this round", and only the second is true when the
project is empty. Retry earns its place here — the deliverable is missing
because this turn wrote nothing, and a re-run is the thing that can write it.

⚠️ The copy is engineering's, like the rows around it. `error-ux-design.md` has
no cell for it; S23 (跑完没生成文件) is the nearest and is listed there as
invisible in telemetry. Product should rewrite the wording, not the routing.

Red spec: apps/daemon/tests/strategies/od-next/coordinator.test.ts
「names the evidence that refused an undeclared completion, not the parser」 and
「gives the undeclared and declared shapes of one failure the same name」 — both
red on main, green here.

* feat(daemon): make an OD Next block countable instead of invisible

`run_finished.result` is derived from the physical run status
(`runResultFromStatus`: `succeeded → success`), and a refused OD Next turn
normally exits 0 with a complete reply on screen. So this entire class of
failure reported `result: 'success'` while the user was looking at a red card,
and nothing queryable disagreed — the reason codes lived only in the task
store's `blocked_reason_codes_json` and in a client-side error object.

`error-ux-design.md` §《线上频次与优先级》 already flags the shape of this
problem for S23/S24: 「被算成了成功 —— 看不到是坏事:线上到底有多少,我们不知
道」. OD Next made it worse than invisible by pairing the silent metric with a
visible failure card.

Carrying `reasonCodes[0]` — the same value the card keys on — makes the class
countable without changing what `result` means. Read off the run's own terminal
projection, the object the SSE `end` payload and the failure card were both
built from, so the three cannot drift. Omitted for every run whose strategy
task did not block, which is the common case.

This is the half that makes the suppression in the preceding commits safe to
ship: a failure the user is no longer shown is one we can still count.

* fix(web): do not go silent on a turn that produced no reply either

The preceding fix credits a deliverable an EARLIER turn wrote, which is right
for the case it was written for — the agent re-checks finished work and
correctly rewrites nothing — and wrong for the mirror case in #7564: a blank OD
Next response into a project that already holds a prototype. There the file is
real and the user still got nothing, so withholding the card swaps one wrong
answer for the other.

Require the turn to have actually said something before the looser field can
suppress a failure. The accumulated assistant text is already on hand in the
stream consumer, so this costs nothing and needs no new daemon field.

The stricter field keeps its existing behaviour untouched: an artifact THIS run
produced is delivery whether or not the agent narrated it.

Red spec: apps/web/tests/providers/strategy-blocked-verdict.test.ts
「still fails when the turn produced no reply at all」 — verified red with the
guard removed, green with it.

* refactor(contracts): make the OD Next block dimension a tested pure mapper

Observability that nothing exercises is observability that rots. The derivation
was inline in the run lifecycle, where the only way to reach it is to boot the
whole analytics flow — so it would have failed silently to "field absent",
which is indistinguishable from "no run ever blocked".

Move it next to `harnessAnalyticsFromRolloutDecision`, which answers the
neighbouring question about the same run and already has a suite. The edges
that matter are the ones a wrong answer would quietly mislabel: a task that has
not settled, one that settled on something other than `blocked`, and a blocked
one an older daemon projected without a reason.

---------

Co-authored-by: Cheems <216108319+hihicheems@users.noreply.github.com>
Co-authored-by: lefarcen <935902669@qq.com>
2026-09-11 04:29:23 +00:00
lefarcenandGitHub ab009b1a30 fix(chat): preserve ranges for repeated file reads (#8019)
* test(chat): expose ranges for repeated file reads

* fix(chat): preserve read ranges in file ops
2026-09-11 03:42:36 +00:00
Ray XiandGitHub c333324da0 test(amr): verify prerelease runtime identity and Vela contracts (#7957)
* test(amr): verify prerelease runtime identity and Vela contracts

* docs(amr): bind continuation evidence to final upstream commit

* docs(amr): track host cancellation integration dependency

* docs(amr): record final Write test-only dependency head
2026-09-11 03:08:47 +00:00
Ray XiandGitHub 6801f25c06 fix(daemon): recognize linked prototype page delivery (#7949)
* fix(daemon): recognize linked prototype page delivery

* fix(daemon): omit absent delivery test inputs

Preserve the missing-baseline and unreliable-diff assertions while satisfying exactOptionalPropertyTypes.

Generated-By: looper 0.13.0 (runner=fixer, agent=codex)

* fix(daemon): preserve pre-run entry before index inference

Prefer the verified prototype baseline over post-run inference while preserving explicit entry authority. Cover linked index creation, retained homepage metadata, and subsequent delivery validation.

Generated-By: looper 0.13.0 (runner=fixer, agent=codex)
2026-09-11 03:08:42 +00:00
07170f8d22 fix(release): track in-place re-runs in the prerelease card (#7950)
The watcher treated "I once saw this run completed" as permanent and stopped
polling the lane. GitHub re-runs a workflow IN PLACE — run_attempt increments,
status returns to in_progress, conclusion is rewritten, all under the same run
id — so the card froze on the first attempt's verdict for the rest of the watch.

Both dispatched lanes had it. Each now re-reads its run every cycle and refreshes
the paginated job list only when the run's own status/conclusion/run_attempt/
updated_at say it moved, so watching for a re-run costs no call the lane was not
already making.


Claude-Session: https://claude.ai/code/session_01PbTMU3bKHcu6cmJYy42eF3

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 12:18:51 +00:00
lefarcenandGitHub 712b0db974 fix(prompts): write next-step suggestions in the run's UI locale (#7920)
The three follow-up suggestions under a completed turn are written by the
model, not picked from i18n files, so the only thing that decides their
language is the prompt. That prompt carried one soft rule — "write them in
the language the user is speaking" — printed directly under three English
examples, and nothing about the run's actual locale.

The locale rule lived only in `# UI locale override`, a section of the
cache-stable prompt head that `server.ts` deliberately drops on resume turns
to protect the upstream prompt cache. The keyed follow-up block is re-sent
every turn. So the rule was absent exactly on the turns that carry the
marker, and a zh-CN run closed with English suggestions — one of them a
near-copy of the prompt's own example.

Thread the run locale into `renderChatTurnHostProtocolInstructions` so the
per-turn block states its own language requirement, including the existing
brand/code/technical-identifier exception so `localStorage` and `CTA` still
survive. An English or absent locale renders byte-for-byte what it did
before. Also collapses the third copy of the zh-CN/zh-TW name mapping into
`prompts/ui-locale.ts`.

Fixes OPEND-2765
2026-09-10 11:04:15 +00:00
98f2fd1a46 fix(chat): hide undesigned cards and auxiliary message panels (#7956)
* fix(chat): render cards inside execution records

Render supported od-card payloads inside execution records with the existing
card components, instance scopes, and browser-assistance callback. Preserve
Markdown code examples and isolate card payloads from later Markdown parsing.

* test(web): await writable scope before deleting a conversation

* fix(web): buffer streamed card opener prefixes

* fix(web): remove undesigned ChatPanel cards (OPEND-2971)

Remove task-brief and rule-proposal presentation and their exclusive UI,
styles, and translations following the explicit product decision.
Preserve quoted card examples, neighboring prose, and the three retained
card kinds, including browser-assist callbacks.

* fix(chat): stop generating undesigned brief and rule cards

* test(web): use supported role query options for removed cards

* fix(chat): hide retired brand browser assistance cards

* fix(web): hide undesigned assistant message panels

* test(web): specify the brand project kind in hidden UI fixture

* style(web): remove trailing blank line after panel styles

* fix(web): hide verification scorecards in ChatPanel

* test(chat): align retired UI expectations with approved hiding

* fix(chat): keep card payloads opaque to question form parsing

* fix(web): preserve card parsing across replay metadata

Keep marker masking aligned with physical run boundaries, and replace repeated
Markdown tail scans with a forward indexed walk. Preserve actual forms and raw
code examples with replay and paragraph-boundary regression coverage.

* fix(web): keep form field syntax inside its payload

Recognize complete forms through the existing parser before scanning their
fields for card or code markers. Preserve sibling form actions and keep outer
card/code ownership with callback-based parsing that avoids an import cycle.

* fix(chat): share question form protocol context with host detection

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-09-10 10:24:07 +00:00
875d0b95a4 test(daemon): check W102 grammar leaks in SSE content (#7990)
Co-authored-by: lefarcen <935902669@qq.com>
2026-09-10 10:12:28 +00:00
5f814a5cd0 fix(chat): wait for pending clarification before continuing todos (#7989)
* fix(chat): wait for pending clarification before continuing todos

* fix(chat): preserve recovery for truncated clarification forms

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-09-10 09:58:31 +00:00
Ray XiandGitHub eb7fbd8175 fix daemon AMR media model chat guard (#7695) 2026-09-10 09:24:15 +00:00
e02d0adbd0 docs: follow the Settings panel rename in the Rescan instructions (#7907)
Co-authored-by: QiuQiuNB666 <318713393+QiuQiuNB666@users.noreply.github.com>
2026-09-10 09:09:34 +00:00
4de36a0f79 fix(chat): retain readable history during workspace scope confirmation (#7955)
* fix(chat): retain readable history during workspace scope confirmation

* fix(chat): gate queue dispatch on the current transcript authority

* test(chat): account for transcript read cancellation signals

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-09-10 08:50:13 +00:00