Commit Graph

5 Commits

Author SHA1 Message Date
Peter Steinberger
d628e35574 fix(apple): prevent stale thinking after model switches and reconnects (#103767)
* fix(apple): prevent stale model thinking state

* test(apple): complete attachment transport fixture

* fix(apple): scope model patch ordering by route identity

* chore(apple): sync native CI metadata
2026-07-10 16:48:11 +01:00
Peter Steinberger
91d4e8ed8e feat(apple): session search, archived browsing, and sheet management actions (#101053)
The shared chat session sheet (iOS chat + macOS webchat) gains server-backed
search (sessions.list search param, 250ms debounce, cancellation-safe local
fallback when offline), an Active/Archived scope, swipe/context actions for
pin/rename/archive with optimistic updates and rollback, pin indicators, and
restore-on-open for archived rows. Archiving the open session switches back
to the main session so the composer never points at a send-rejecting session.

OpenClawChatTransport consolidates the two list requirements into canonical
listSessions(limit:search:archived:) with forwarding sugars (unreleased
internal API; all in-repo conformers updated: iOS gateway transport, demo and
fixture transports, previews, macOS webchat, test fakes). macOS webchat also
implements patchSession, giving the sheet's controls a live transport there.

OpenClawChatSessionEntry becomes var-based and gains pinnedAt/archivedAt;
the two full-init rebuild blocks in ChatViewModel collapse to copy-mutation
(the pattern that silently dropped newly added fields), preserving main's
model-identity/thinking-metadata semantics. A shared session list organizer
mirrors gateway ordering (pinnedAt desc, updatedAt desc, key) for cached and
offline lists, and pinned sessions survive the 24h recency cutoff in the
session picker.

Refs #100712
2026-07-07 00:28:38 +01:00
Peter Steinberger
06789ca4c2 fix(ios): keep offline chat sends on their original route (#100942) 2026-07-06 17:53:05 +01:00
Peter Steinberger
538d4eeb77 feat(ios): hide thinking-level control for models without reasoning support (#100875) 2026-07-06 15:59:03 +01:00
Peter Steinberger
4b7661e9a0 feat(ios): durable offline command outbox for chat sends (#100331)
* feat(ios): durable offline command outbox for chat sends

Text messages sent while the gateway is unreachable queue in a durable
per-gateway outbox (new outbox_commands table in the per-gateway chat
cache SQLite store, schema v2) instead of failing. Queued bubbles render
with visible Queued/Sending/Not sent states and flush strictly in
createdAt order once transport health recovers; each command's client
UUID rides as the send idempotency key, so at-least-once delivery plus
gateway dedupe keeps the transcript exact.

Contract summary:
- Bounds: 50 queued commands per gateway; refused enqueues keep the
  draft. Queued rows older than 48h expire to failed("expired") rather
  than silently sending stale commands; tap-to-retry refreshes
  createdAt so an expired row can resend as new intent.
- Failure taxonomy: transport-level failures keep rows queued without
  burning retry attempts (backoff ladder, then health drops so the
  reconnect machinery owns pacing); gateway rejections burn attempts
  and fail terminally after 3, with context-menu retry/delete.
- Deletes are tombstoned synchronously and rechecked after the claim
  await so an active flush can never send a removed command; Delete is
  hidden while a bubble is already in flight; offline enqueue is
  guarded against double submit during the health probe.
- Post-reconnect live sends route behind draining outbox rows (FIFO),
  and a cold open assumes a backlog until restore adopts durable rows.
- Crash safety: 'sending' rows revert to 'queued' at startup; flushed
  turns are spliced into the session's cached transcript before their
  outbox row is deleted, and stale history snapshots cannot evict a
  just-flushed turn until a snapshot confirms it.
- Per-gateway scoping and purge ride the transcript cache: one SQLite
  file per gateway; reset/forget drops the queue with the cache.
  Fixture/unpaired transports get no outbox.

Part of #46664

* chore(ios): sync native i18n inventory

* style(chat-ui): satisfy strict SwiftFormat lint (doc comment, scope blank line)
2026-07-06 05:23:46 +01:00