Skip to content

fix(ledger): prevent status card from getting stuck at running - #4

Closed
danvitv wants to merge 30 commits into
nightlyfrom
fix/ledger-status-stuck-running
Closed

fix(ledger): prevent status card from getting stuck at running#4
danvitv wants to merge 30 commits into
nightlyfrom
fix/ledger-status-stuck-running

Conversation

@danvitv

@danvitv danvitv commented Aug 11, 2026

Copy link
Copy Markdown
Owner

@z:\GlazeProject\glaze_flutter_tmp_pr_body.md

danvitv and others added 30 commits August 9, 2026 10:03
feat(ledger): add selective gap-filler projection
fix(chat): preserve line breaks around unmatched emphasis
All four chat transports (OpenAI, Anthropic, Gemini, OpenAI Responses)
trimmed the entire SSE line before extracting the data: payload, then
trimmed the payload again. This stripped leading/trailing whitespace
that is part of the JSON content — most notably newlines in streaming
text deltas — causing paragraph breaks to be lost during reception.

Replace the double-trim with a shared _sseData helper that:
- strips only a trailing \r (CRLF line ending)
- accepts both data: and data:  (single optional space is framing)
- does NOT trim the extracted JSON payload

Add a regression test that splits an SSE body across multiple network
chunks and verifies newlines in content survive intact.
fix(transport): preserve whitespace in SSE data field parsing
utf8.decode(chunk, allowMalformed: true) decodes each network chunk
independently, which corrupts multi-byte UTF-8 sequences (e.g. Cyrillic,
emoji) when they are split across chunk boundaries. Replace with
utf8.decoder.bind(responseStream) so the decoder maintains state across
chunks and only emits complete characters.

Added a regression test with Russian text 'Привет\n\nмир' split inside
the first 'П' byte to verify both UTF-8 integrity and newline preservation.
fix: preserve SSE UTF-8 and action styling
…istory

The global \s{2,} → ' ' replacement in _stripThinkDirective was
intended to clean up residual whitespace after removing <think> directive
patterns, but it ran on EVERY message — including chat history — and
collapsed all \n\n paragraph breaks into single spaces.

This caused the model to see history as one unbroken line, which it then
mirrored in its output. The effect was intermittent because the stripper
only runs when isFinalResponse && (!requestReasoning || omitReasoning).

The directive patterns already include their own \s* boundaries, so the
global whitespace collapse is unnecessary. Removing it preserves paragraph
structure while still stripping think directives and rewriting literal tags.

Regression tests verify newlines survive stripping for roleplay content,
lumiaooc blocks, and multi-paragraph text.
fix(reasoning-stripper): stop collapsing paragraph newlines in chat history
…ll#250)

- FilterTagsSection takes an optional fetchSuggestions autocomplete and an
  allowCustomTags flag, so a source with free-text tags can resolve a query to a
  name-based FilterTag that is not in the curated list
- _FilterTags debounces the query into that callback, guards against
  out-of-order responses, and lists suggested custom tags plus the raw query
- _FilterTags._selectedList includes selected names with no entry in tags, so a
  picked custom tag is visible and removable
- CatalogFilterSheet wires fetchJanitorTagSuggestions and allowCustomTags for
  the JanitorAI provider only; other providers keep the previous behaviour
- New catalog_add_custom_tag string (en/ru)
…rides (hydall#251)

- Render each slot as one MenuGroup of dropdown rows: API connection and model override as MenuSelectorItem, plus a "Parameter overrides" row linking into the slot settings sheet
- Always offer "Automatic" in the model picker so a slot on a stale model id can be reset back to the connection's own model
- Give every parameter in the slot settings sheet an "Override selected preset value" switch; off, a read-only row shows what the selected connection contributes
- Back the switches with <field>Override flags on StudioAgentSettings and CleanerSettings; an unset flag makes AgentConfigResolver pass null so the API preset's value survives. Flags default to true, preserving upgrade behaviour
- Honour the negative-temperature sentinel for the post-processing slot
- Resolve model lists with pickChatTransportFor(config) instead of a hardcoded OpenAI transport, so Gemini/Anthropic/OpenRouter slots are listed over their own protocol and auth, matching the LLM tab
- Mirror the LLM tab's endpoint/key precondition, and stop falling back to the active preset when a slot points at a deleted config
- Add an optional description to MenuSelectorItem; rewrite the tab hint and fix grammar in the slot hints (en + ru)
The Agents tab read and wrote the API slot bindings on the preset row with id
`default`, while a turn resolves them from the preset activeStudioPresetProvider
names. With any non-default Studio preset selected the two diverged: the tab
edited `default`, the turn read the active preset's empty slot and fell back to
the chat's own connection. The model override lives in global PipelineSettings
and was still applied, so a model picked from one provider's list was sent to
another provider's endpoint and came back "model not found" — only "Automatic"
worked, since it takes the model from whichever connection the turn ended up on.

- Resolve studioPresetProvider through activeStudioPresetProvider, falling back
  to the seeded `default` row, mirroring StudioTurnConfigResolver
- Move it next to that provider; db_provider cannot import it back without a cycle
- Write slot changes to the same active preset, seeding `default` only when the
  stored active id no longer resolves
- Cover all three resolutions with a regression test
…ion-scroll

fix(memory): regenerate drafts and stabilize chat scroll
…and-modes

fix(memory): restore prompt preset tools and clarify retrieval modes
…-timeouts

fix(prompt): isolate lorebook timeout failures
ownsRunningStatus() used identical() object identity to decide whether
the current run still owns the postGenStatusProvider state. Riverpod
internal state replacements and the auto-dismiss timer in
PostGenStatusCard can replace the state object between startStatus and
finishOwnedStatus, causing identical() to fail and leaving the status
card permanently stuck at 'Ledger running...'.

Replace the identical() check with a logical check: same session id,
same task, and phase == running. This still prevents older runs from
overwriting newer ones (different task or non-running phase fails the
check) while tolerating state-object replacement.

Also add a success toast ('Studio Ledger ok (ops=N)') when the ledger
run completes with ops > 0, mirroring the existing failure toast.
@danvitv

danvitv commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

Wrong base repo. Opening PR to upstream hydall/Glaze:nightly instead.

@danvitv danvitv closed this Aug 11, 2026
@danvitv
danvitv deleted the fix/ledger-status-stuck-running branch August 11, 2026 17:28
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.

2 participants