Commit Graph
481 Commits
Author SHA1 Message Date
amosblomqvist 282f01e1f4 Merge accepted local main into PR #184 working branch 2026-10-27 18:12:09 +02:00
amosblomqvist 82c6999a63 fix: preserve failed responses when retrying model calls
Keep failed attempts in the saved transcript and omit only trailing failures from Retry's temporary agent history. Use the matching temporary prefix length when persisting genuinely new output.

Preserve the error notice across plan/compaction markers, refuse Retry after later compaction, and avoid synthesizing results for tool calls inside failed generations while retaining Pi's native filtering.

Verified: 173 focused Retry/session/compaction-projection/practice-record tests, typecheck, changed-file lint, and diff --check. No app launch or real provider calls.
2026-10-27 16:49:29 +02:00
amosblomqvist 06714e5998 Keep unresolved session identity separate from Strong fallback 2026-10-27 16:21:54 +02:00
amosblomqvist 419dcf1ba2 Restore exclusive provider-first setup recovery 2026-10-27 16:12:13 +02:00
amosblomqvist c1ef6d6822 Merge PR #211 dynamic dock sizing with reviewed viewport corrections 2026-10-27 15:47:15 +02:00
amosblomqvist d30acd4fdd fix: finish measured dock sizing and short-window scrolling 2026-10-27 15:27:08 +02:00
anikam13 42814ba6a6 fix: budget dock height for answer controls and toolbar 2026-10-26 23:03:09 -07:00
amosblomqvist 683eb93bcc Fix model labels and catalog-backed setup initialization 2026-10-26 19:43:09 +02:00
Evangelos Stavropoulos a572675900 fix: let the learner retry a turn whose model call failed 2026-10-26 14:31:51 +02:00
amosblomqvist 8c277f8320 Merge source-preserving math content presentation 2026-10-26 05:26:13 +02:00
amosblomqvist d3c8709bd2 fix: preserve source data and recover tool math at presentation 2026-10-26 04:49:47 +02:00
amosblomqvist c1d044f91b Merge server-owned web subscription connections 2026-10-26 03:18:19 +02:00
amosblomqvist c0c670b810 feat: enable subscription connections in web and dev 2026-10-26 03:00:40 +02:00
amosblomqvist 6370c9d618 Merge durable background job delivery and recovery 2026-10-26 02:39:59 +02:00
amosblomqvist e851432f4c fix: separate worker completion from durable session delivery 2026-10-26 01:55:52 +02:00
amosblomqvist 6701503801 fix: isolate generated SVG figures as images 2026-10-25 23:29:00 +02:00
amosblomqvist fc3673466d Merge bounded session answer and stream recovery 2026-10-25 20:46:25 +02:00
amosblomqvist 7d65fa8754 fix: recover session submissions and failed turn settlement 2026-10-25 19:45:17 +02:00
amosblomqvist 769fc85e17 fix: honor automatic updates preference and add Settings controls 2026-10-25 19:19:38 +02:00
amosblomqvist 7fb9a1505c Merge native Copilot and Grok subscription connections 2026-10-25 02:13:00 +03:00
amosblomqvist 3cc598ded5 fix: distinguish ChatGPT authorization recovery from storage failures 2026-10-25 01:52:52 +03:00
amosblomqvist 55a6501a09 fix: streamline subscription connection dialogs and actions 2026-10-25 01:34:46 +03:00
amosblomqvist d6e317c6fe feat: add app-owned Copilot and Grok subscription connections 2026-10-25 00:27:52 +03:00
amosblomqvist 5cf4e589be fix: keep current provider failures authoritative across reattach 2026-10-25 00:00:29 +03:00
amosblomqvist 671d2c8bb7 fix: restore final provider failure in chat error banner 2026-10-24 23:55:27 +03:00
amosblomqvist 04037e98d6 Merge compaction and native usage accounting fixes 2026-10-24 19:53:18 +03:00
amosblomqvist 8946209f98 fix: preserve unknown graph costs and cache detail 2026-10-24 19:11:39 +03:00
amosblomqvist 624c91a437 fix: align compaction cuts and native usage accounting 2026-10-24 19:05:02 +03:00
amosblomqvist 24d1dda07d fix(chatgpt): use private JSON credential storage without Keychain 2026-10-24 18:41:03 +03:00
amosblomqvist 6788a01add Add accounts from ChatGPT management dialog 2026-10-24 15:58:26 +03:00
amosblomqvist 102aa6f7ae Fence stale ChatGPT cancellation replies and steady toggle cursor 2026-10-24 15:45:54 +03:00
amosblomqvist 42abeb65ae Unify ChatGPT background use and account management 2026-10-24 15:28:26 +03:00
amosblomqvist 8691470d03 Fix pending ChatGPT login lifecycle and IPC error handling 2026-10-24 14:22:44 +03:00
amosblomqvist b8abad2b4f Refine ChatGPT setup and model provider settings 2026-10-24 14:02:54 +03:00
amosblomqvist 0fc6d4ab94 feat: add verified desktop ChatGPT subscription connection 2026-10-24 12:17:08 +03:00
amosblomqvist 4bd20be529 fix: keep research available without search keys 2026-10-24 06:52:36 +03:00
amosblomqvist c36c1c6b4d ui: simplify import feedback and shorten waiting status 2026-10-23 06:14:33 +03:00
amosblomqvist 2d67376b76 fix: always run explicit notes imports and surface failures 2026-10-23 04:43:56 +03:00
amosblomqvist 7f95753cf2 fix: share question math repair with practice displays 2026-10-21 00:00:20 +03:00
amosblomqvist 3d1ad38e46 ui: unify practice composer actions and node picker copy 2026-10-17 01:06:28 +03:00
amosblomqvist 487a63eaa5 ui: polish first-run setup copy and dialog dismissal 2026-10-17 00:38:57 +03:00
amosblomqvist 5601a98335 dialogs: delete dialogs drop the serif display title for the abort-turn look
Titles become text-sm font-semibold in destructive red — JetBrains Mono
via the UI default, matching the abort-turn/dismiss-question dialogs the
owner named as the ideal look. Node and session names below the title
drop the sized-up text-lg for normal text-sm, still white mono, no
code-block chrome. Settings and Setup keep their serif titles by owner
ruling; abort-turn already renders this way. 1610/1610 both configs;
verified live on the running dev server.
2026-10-13 09:54:43 +03:00
amosblomqvist 2a8f65de6e graph: session deep links reliably jump to the source message
The mount-time jump never fired on real graph-link arrivals: the
transcript scroller's ref is attached by a later sibling, and the queued
rAF was cancelled outright whenever use-stick-to-bottom re-created its
context while the initial scroll settled — every link landed at the
bottom (owner report 2026-10-13).

Rewrite the mount path as a synchronous 64ms retry watcher that keeps
running past its first success (hydration/adoption can replace the
jumped-to node), with a ~20s watchdog for cold-compile SSR streams
(observed 6.8s). jump() now reads the stick-to-bottom context through a
ref so effect identities stay stable, and the unmount cleanup no longer
strips a live flash. Verified live on real data: full load, SPA link
navigation, and in-session hashchange all land the anchor 16px from the
scroller top with the 2s highlight.

Also gives the node card's session/file rows matching horizontal and
vertical padding (px-2 py-1.5).
2026-10-13 09:28:09 +03:00
amosblomqvist cdd8ac047e sessions: source-message deep links from the graph + session Find (Cmd/Ctrl+F) 2026-10-13 08:26:31 +03:00
amosblomqvist bf29a2070f math: dollar delimiters end-to-end (exact answers, escaping examples, context rendering)
- switch the math authoring/rendering contract from \(...\)/\[...\] to the
  standard $...$ inline / $$...$$ display: prompts (20-question-tools,
  40-formatting), singleDollarTextMath on the renderer, legacy reader kept,
  and escape-debris recovery extended to dollar spans (mirroring micromark
  delimiter-run rules)
- exact answer membership now precedes debris cleanup in
  coerceCorrectAnswer (calculus incident: an exact sentence-final-period
  label was stripped as model debris, then rejected); option keys are
  passed at the boundary/grading seams, the dock no longer pre-coerces
- a complete, phase-correct JSON-escaping example rides the probe/quiz
  tool descriptions (serialized from one canonical body; quiz leads with
  type+nodeId), plus the one-sentence JSON-escaping rule in 40-formatting
- ask option descriptions render markdown/LaTeX in the pending dock;
  settled cards keep the details line and option descriptions
  retroactively, read from the persisted call arguments (chat passes
  part.input to AnsweredCard)

1566/1566 tests on both navigator configs; typecheck, lint, production
build, standalone packaging, and Electron-runtime smoke all green.
2026-10-13 06:24:33 +03:00
amosblomqvist e266c3c028 desktop: tri-platform window chrome, packaging and draft-release CI 2026-10-11 10:12:13 +03:00
amosblomqvist e8e00a5237 auto-update wiring: silent download, restart banner, local-feed drill seam
electron-updater in the shell (packaged builds only; dev never updates).
Checks at startup + every 24h, downloads silently, and the renderer shows
a Restart banner once the update is staged (it installs on quit either
way). Manual "Check for Updates..." under the app menu answers via dialog.
Every updater event routes through the shell log and is caught - the
updater can never take the app down (verified live: a feed failure logs
three lines and the app runs on).

LH_UPDATE_FEED overrides the baked GitHub feed with a generic local
server - the pre-release drill: serve latest-mac.yml + zip + blockmap
from localhost and a real installed copy updates itself, no release, no
public repo.

The asar allow-list re-includes electron-updater + its 16-package runtime
tree explicitly (gitignore last-match-wins; asar verified at 2.1 MB).
The banner rides the preload bridge (onUpdateStatus/installUpdate) and
renders nothing in the browser. window.lh typing centralized in
sidebar.tsx's declaration.
2026-10-10 14:11:19 +03:00
amosblomqvist 53112d2861 practice round: dead session starts, prompt laws, preamble, label unify
THE START BUG (owner report, reproduced live both kinds): new sessions
(?prompt flow — practice and teach alike) sat dead until a second
message, which then persisted WITHOUT the first. Root cause, proven
both directions: the submit POST rode the view's consumeAbort
controller; React StrictMode's simulated remount fires Diet A's
unmount cleanup (model.stop()) ~8ms in and killed the POST mid-flight;
the page's sentInitial guard had already flipped, so it never retried.
Teach was equally broken — only unnoticed, because every teach chat in
use predates the diet and practice starts are always fresh. Fix: the
submit law — POSTs are not abortable by view teardown (they are ~100ms
acks since Diet B and cannot starve the pool); after the ack, a
consumeAbort identity check guards the stream attach. Pinned with the
stop-mid-submit regression test. Live: StrictMode on, practice draft
POST 200/67ms, stream attached, message persisted, problem posed.

PRACTICE PROMPT (00-base): the opening rule — material arrives two
ways, both first-class (picked propositions primary; free-form —
topics, course material, files/PDFs — fully supported, never refused);
as soon as material exists the reply poses, at most one short line
before the problem call, no warm-up interview. Plus the hard law: no
problem is ever conversation — every problem through the tool (no
thinking field/no reveal/no verdict attaches to prose).

GRAPH-CONTEXT PREAMBLE: custom markers flatten to user-role on the
wire, so the old "Contextualization — the learner picked…" read like a
system broadcast in the learner's voice channel. Now the bracket
convention: "[Session context] — picked from the learner's knowledge
map…".

SIDEBAR: busy rows unify to "Working…" for both kinds (the spinner's
default label included); "Practicing…"/"Teacher is working…" retired.

Gates: 1490/1490, typecheck, lint. doctrine's stale doc pointer fixed.
2026-10-10 12:19:31 +03:00
amosblomqvist 26bc305d66 ui: plan canvas ink extent + the keyboard-first round
Plan canvas (owner report: arrows clipped at the viewBox edge in dist —
measured 14px/20px cuts in the owner's real plans): blockLayout now
unions node boxes with every edge path's control-point hull (a bezier
never leaves it; the layout calls edgePathD with the renderer's exact
inputs). Dagre's node extent stays the floor, so ordinary plans render
byte-identical; the viewBox origin shifts only when ink bulges past
zero. Verified on both real chats; pins use the owner's real
linear-algebra tree (golden-real-data).

Keyboard-first (owner's law: Enter always submits, arrows always cycle;
text fields the only exception):
- Enter guard split (enter-submits): a focused BUTTON keeps native
  Enter only when keyboard-walked (:focus-visible) or inside an open
  overlay (menus/dialogs); pointer-clicked transcript buttons submit,
  preventDefault suppressing the re-activation underneath.
- Focus hygiene (focus-hygiene): pointer clicks on transient controls
  (agent/user thinking toggles, copy, mermaid expand, plan chip) blur
  to body — the state clicking empty space produces.
- Session search owns the walk: Up/Down wrap-cycle the filtered rows,
  Enter opens the walked row or the first match (quick-open), then
  blurs and keeps the query. The Alt-arrow session cycle is RETIRED.
- Registry: model-menu walk/pick entries removed (obvious in-field
  navigation, not settings material); question-dock keys stay
  displayOnly per owner ruling.

Gates: 1489/1489, typecheck, lint. Verified live end-to-end.
2026-10-10 09:43:12 +03:00
amosblomqvist 643e7596f0 streaming: connection diet — the parallel-session freeze, fixed
Root cause (postmortem, verified live): Chromium caps 6 concurrent
HTTP/1.1 connections per origin. Every running turn pinned slots for
its whole life — the POST /api/chat response stream plus a reattach
GET stream per visit that never closed on navigate-away — so two
concurrent thinking sessions starved navigation RSC fetches in the
browser queue (147s measured) until the turns settled. Server was
exonerated (3ms curls during the freeze); main thread idle throughout.

- COMPACTION LAW + WIRE DIET (ui-stream): store the states, not the
  chunks — replace-in-place snapshot retention keyed by updateSlots,
  ~100ms coalesced latest-wins fan-out, slim wire drops pi's duplicate
  assistantMessageEvent payload.
- DIET B: POST /api/chat acks and closes ({ok:true}) — the turn wire
  is GET /stream for everyone, submitter included; send() reattaches
  via refetch-first resumeStream(true).
- DIET A: unmount cleanup calls model.stop() — navigating away aborts
  the view connection (turns are server-side background objects).
- Answer-flicker fix: resumeStream's eager tail clear moved off the
  refetch path (the refetch swaps base+tail atomically; clean-slate
  guard restored on refetch failure) — the optimistic answer card
  survives refetch latency (1.7s stalls measured on dev).
- Tests converted to the ack contract (drainTurn/drainRunning helpers,
  dietFetch mock) + a pin that the POST body reads while the turn runs.

Gates: 1489/1489, typecheck, lint. Live: dual streaming sessions,
navigations 335-648ms, in-page settings 19ms (was 147s).
2026-10-10 09:42:47 +03:00