Skip to content

release: v1.0.0-alpha.6 - #244

Merged
Atom112 merged 10 commits into
masterfrom
release-1.0.0-alpha.6
Oct 29, 2026
Merged

Atom112 merged 10 commits into
masterfrom
release-1.0.0-alpha.6

Conversation

@Atom112

@Atom112 Atom112 commented Oct 29, 2026

Copy link
Copy Markdown
Owner

Summary

Release branch for v1.0.0-alpha.6 — the "field-report-driven root fixes" release.

Four real-usage reports, each traced to its root cause with measured evidence:

  1. Subagent step-card animation twitch (fix(chat): stop subagent step-card animation restart per streamed token batch #239): the store produce rebuilt the step slot object per 80 ms stream batch, so StepCard's props.step identity changed and every render effect (including the animation shorthand) re-ran — replayed pulse/spin per token. Fixed with in-place property assignment; the orphan is-spinning class replaced by the theme's real animate-agent-process-spin utility.
  2. pwsh object-output P0s (fix(harness): pwsh object-output P0s - formatter loss on exit, rc-0 masking, CLIXML stderr #241): exit skipped PowerShell's lazy format flush (table output lost whenever a native command had run — 3 false conclusions in the reporting session); $LASTEXITCODE=0 masked later cmdlet errors as success; redirected stderr arrived as CLIXML. Fixed with the Out-Default scriptblock tail, non-zero-only exit propagation, -OutputFormat Text + a mechanical CLIXML decoder — verified by a live pwsh behavioural matrix in the production spawn shape.
  3. DeepSeek thinking/action imbalance (fix(provider): DeepSeek thinking/action imbalance - reasoning round-trip + real effort ladder #242): reasoning_content was never round-tripped (violating DeepSeek's documented tool-call contract — the model's cross-round working memory), forcing every round to re-think and re-read files; and the reasoning slider was a no-op because thinking defaults ON at high effort. New deepseek provider plugin: round-trip both paths + a real effort ladder (off → thinking: disabled, medium → low).
  4. Long-process topic switch/expand jank (perf(chat): long-process topic switch/expand jank - lazy mount + paged step reveal + O(1) lookup #243): measured the reporter's DB — one topic with 18 messages carries 16.53 MB of agent_steps_json / ~1674 step cards (worst message: 588 steps / 381 tool calls / 8.01 MB). Collapsed historical rounds were mounting up to 100 cards each (max-height: 0 hides but does not unmount), "show earlier" mounted all 588 in one frame, and the step lookup was O(n²). Now: lazy mount gate (collapsed rounds mount 0 cards), paged reveal (100 per click), memoized O(1) lookup, content-visibility on cards, and paged-in history pre-marked as animated.

Changes in this PR

  • Version bumps: package.json / tauri.conf.json / Cargo.toml / Cargo.lock → 1.0.0-alpha.6
  • CHANGELOG: the four post-alpha.5 sections promoted into the v1.0.0-alpha.6 block (chronological order), and the duplicate ## Unreleased heading that the self-iteration commit introduced at the file top merged back into the single bracketed section

Verification

  • Docs link check + prettier clean after the promotion; every underlying PR ran npm run verify green (#239: 87 FE tests; #241: 460 Rust + gates; #242: 469 Rust + full verify; #243: 93 FE tests + full verify)
  • Honest scope note carried from perf(chat): long-process topic switch/expand jank - lazy mount + paged step reveal + O(1) lookup #243: that fix's frame-timing claim needs the reporter's installed build to confirm; the mount arithmetic (469 → 0 on switch, 588 → 100 per reveal click) is what was verified here

Atom112 and others added 10 commits October 24, 2026 18:46
…en batch

mutateSubagentSteps rebuilt the steps[subIdx] slot object inside produce
({...subStep} spread) on every 80ms subagent delta flush. AgentProcessBlock's
stepById returns objects by identity, so StepCard's props.step changed
reference per batch, re-running every style/classList render effect and
cancelling+replaying the running animations (stepCardPulse, icon spin) —
the visible per-token "twitch" on subagent cards.

Solid-store produce mutates in place: assigning the property directly
(subStep.subagentSteps = mutate(...)) keeps the slot object's reference
stable across the whole stream. Only readers of subagentSteps itself
(live progress line, subagent conversation view) still update — fine-grained
semantics preserved.

Also: StepCard's icon classList referenced 'is-spinning', which has no CSS
definition anywhere (orphan class) — the running step icon never animated.
Switch to the already-defined-but-unused theme utility
'animate-agent-process-spin' (--animate-agent-process-spin +
agentProcessIconSpin keyframes, 2.4s linear infinite).

check:frontend green (87 tests, tsc, eslint 0 warnings, prettier, gates).
…asking, CLIXML stderr

AIO self-iteration round 2 left an 8-item report (.temp/harness-
report-round2.md, preserved in the tracking issue); the three P0s are
all 'pwsh object output x pipe capture' pits. All claims re-verified
by independent probe before implementation, and the fixes by a live
pwsh behavioral matrix in the exact production spawn shape
(CREATE_NO_WINDOW + pipes).

- P0-1: PowerShell's default formatter commits LAZILY at runspace
  close; a script-level exit skips the flush, so 'run git once, then
  print a table' dropped the table 100% of the time (2-byte stdout,
  three false conclusions in the report's session). The body now runs
  in a scriptblock piped through Out-Default (eager render), with
  \True captured INSIDE the block (the pipe resets it outside).
- P0-2: the old tail (\ -ne \0) exits 0 the moment
  any native command succeeded, masking every later cmdlet error from
  tool_ok and the failure-signature detectors. The new tail only
  propagates a NONZERO native exit code, falling through to the
  captured \True otherwise.
- P0-3: redirected stderr made pwsh serialize error records as CLIXML
  (unreadable _x001B_ escapes, signature detection dead). Adds
  -OutputFormat Text (honored by pwsh 7, silently ignored by 5.1) plus
  a mechanical CLIXML decoder in decode_console_output (record
  boundaries to lines, tag strip, _xHHHH_ unescape, ANSI strip) for
  the 5.1 residual.
- P1-1 (\/backtick blanket block): relaxation DECLINED - \ is a
  command-substitution vector regardless of intent and the scan runs
  before any trust decision; the rejection messages now teach the
  equivalent rewrites (-ExpandProperty, '+' concat, temp .ps1 via
  pwsh -File) instead.
- P2-3: the finish_reason=length continuation instruction now carries
  the truncated reply's last ~200 chars as an anchor (multi-section
  output no longer loses the thread on resume).
- P2-5: the report itself is filed as an issue (the sanctioned home
  for one-off artifacts per docs-style.md).
- P1-2 / P2-1 / P2-2 / P2-4: declined with rationale in the PR
  description (environment facts and design tradeoffs).

Tests: shell_tools 33 (+3: CLIXML decode, tail structure, live pwsh
matrix - all three cases fail under the old tail); round_artifacts +1
(anchor, four branches); full suite 464 green; clippy -D warnings
clean.
fix(chat): stop subagent step-card animation restart per streamed token batch
Harness round 2's additions (CLIXML decoder + behavioral tests) pushed
shell_tools.rs to 2951 lines, over the 2770 file-size ratchet (the gate
failure CI caught on this PR; the ratchet itself is untouched).

Mechanical move, zero behavior change: the self-contained encode/decode
pair around agent shell commands now lives in utils/shell_codec.rs -
- decode: decode_console_output (+ ANSI code page + CLIXML unwrap)
- encode: START_PROCESS_HIDDEN_SHIM, pwsh_script, rewrite_cmd_start_hidden,
  cmd_utf8_prelude, pwsh_encoded

shell_tools re-exports the historical names (rewrite_cmd_start_hidden
test-only, hence cfg(all(windows, test))); all tests stay in
shell_tools untouched. Full verify green: clippy -D warnings, 464 Rust
tests, check:frontend (incl. the file-size gate) 87 FE tests.
fix(harness): pwsh object-output P0s - formatter loss on exit, rc-0 masking, CLIXML stderr
…rip + real effort ladder

Real-world report: DeepSeek V4.1 Flash spends tens of minutes thinking,
re-reads dozens of files, never acts - the thinking:action ratio explodes.
Diagnosis: model trait (thinking ON at HIGH effort by default, documented)
AMPLIFIED by two genuine harness defects, both fixed here.

Defect 1 (the amplifier): reasoning_content was never round-tripped -
violating DeepSeek's documented tool-call contract. In tool-carrying
conversations the field is the model's CROSS-ROUND WORKING MEMORY
('let the model continue its previous thinking'); AIO dropped it on both
paths (in-turn append_assistant_message built role/content/tool_calls
only; history finish_message_for_api never inserted it though the DB
stores it). Every round started thinking from scratch and re-read files
to re-establish understanding - the re-read loop behind the report.

- New deepseek provider plugin (claims api.deepseek.com; URL/auth/models
  delegate to the fallback), with trait additions:
  - roundtrip_reasoning_content (default false - OpenAI's strict schema
    rejects the unknown field, so the contract must stay provider-scoped)
  - adjust_chat_body (default no-op), applied unconditionally in
    stream_one_round after generic body assembly
- In-turn: append_assistant_message attaches the round's reasoning as
  reasoning_content when flagged (empty stays absent); main loop computes
  the flag once per turn, subagent loops wired identically
- History: finish_message_for_api inserts it (assistant role, non-empty,
  gated by the same flag); the FE now passes message.reasoning through
  buildApiMessages; chat-mode (no tools) stays unflagged per the contract
  (server ignores the field without tools)

Defect 2: the reasoning slider was a no-op for DeepSeek. Thinking is ON
at HIGH effort by default and the only documented off-switch is
{'thinking':{'type':'disabled'}} - which AIO never sent. The deepseek
adjust_chat_body override now: Off -> thinking disabled (the slider's
'off' is finally real; BEHAVIOR CHANGE: DeepSeek users at Off no longer
get chain-of-thought output - move the slider to Low+ when thinking is
wanted); Medium -> Low (DeepSeek's real ladder is low/high/max and
upstream collapses medium to high - Low keeps three settings
distinguishable); Low/High pass through. Subagent rounds (which never
inherit the slider) default to thinking disabled - executor role.

Tests: provider +4 (host claim/guards, effort ladder mapping, URL
delegation), round_artifacts +1 (round-trip three branches), messages +1
(history round-trip role/flag/empty gating); full suite 469 green;
npm run verify fully green (87 FE tests, gates rgba=173 any=77 held).
…trip

fix(provider): DeepSeek thinking/action imbalance - reasoning round-trip + real effort ladder
…d step reveal + O(1) step lookup

Report: switching to the topic where AIO worked on AIO itself (9 rounds /
18 messages) loads visibly slower than other topics, and expanding its
hundreds of intermediate steps collapses the frame rate. Measured the real
DB: that topic carries 16.53MB of agent_steps_json / ~1674 step cards (the
worst single message: 588 steps, 381 tool calls, 8.01MB). Three stacked
costs, all fixed:

1. Collapsed historical rounds still mounted their cards (the main switch
   cost). max-height:0 hides without unmounting, so a topic switch built up
   to 100 cards per past round (~469 cards across this topic's five big
   rounds), each with its own effects, signals and 920ms entrance timer,
   plus one linear stepById scan per card. Now the body is gated by
   <Show when={isExpanded()}>: a collapsed round mounts ZERO cards (Solid's
   false branch builds no DOM/components/effects) and the id-sync effect
   short-circuits while collapsed, resolving lazily on expand.

2. 'Show earlier' mounted every remaining card in one frame. Replaced the
   showAllSteps boolean with paged reveal: each click adds another
   STEP_WINDOW (100) page and the button label counts down the remainder.

3. stepById ran timelineSteps().find(...) per card, and timelineSteps()
   sliced the whole array on every call - ~345k element copies for a full
   reveal. Now a memoized timeline + id->step Map make it O(n) once and
   O(1) per card.

Supporting: content-visibility:auto + contain-intrinsic-size on the step
card (offscreen cards skip layout/paint, the MessageBubble pattern);
paged-in historical steps are pre-marked as animated (same contract as
ChatInterface's load-earlier) so expanding does not fire a hundred
simultaneous entrance animations.

Window arithmetic extracted to utils/stepWindow.ts with 6 unit tests
(active pass-through, tail-window bounds, page increments, short/empty
lists, negative reveal, countdown). Untouched: the active round's streaming
queue/auto-follow, DiffView (measured: 1 changed file - not a bottleneck),
and the legacy no-agentSteps ToolCallBubble fallback.

Verified: npm run verify green (93 FE tests incl. 6 new, gates, lint, tsc,
build; Rust suite green). Real-device frame timing still needs the installed
build - the mount arithmetic here is 469 -> 0 cards on switch and 588 -> 100
per reveal click.
perf(chat): long-process topic switch/expand jank - lazy mount + paged step reveal + O(1) lookup
Promotes the four post-alpha.5 sections into the v1.0.0-alpha.6 release
block (chronological: subagent step-card twitch #239, pwsh object-output
P0s #241, DeepSeek reasoning round-trip #242, long-process step-window
jank #243) and merges the duplicate '## Unreleased' heading the
self-iteration commit introduced at the file top into the single
bracketed section that carries the historical round content.

Verification: docs link check + prettier clean; version bumped in
package.json / tauri.conf.json / Cargo.toml / Cargo.lock.
@Atom112
Atom112 merged commit e0e1a57 into master Oct 29, 2026
8 checks passed
@Atom112
Atom112 deleted the release-1.0.0-alpha.6 branch October 29, 2026 13:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant