managarten/packages
Till JS 3b5d58ecbe feat(shared-llm): Phase 4 — persistent LLM task queue
Until now, modules wanting to use the orchestrator had to await each
LLM call inline in their store code. That's fine for foreground tasks
("user clicked summarize") but a non-starter for background work
("auto-tag every new note", "generate a title for every voice memo
after STT finishes"). Background tasks need to:

  - Queue up while no LLM tier is ready, then drain when one becomes
    available (e.g. user just enabled the browser tier from settings)
  - Survive page reloads, browser restarts, and the user navigating
    away mid-execution
  - Run one at a time without blocking the foreground UI
  - Allow modules to subscribe to results reactively without polling
  - Retry transient failures (network, model loading) but not
    semantic ones (tier-too-low, content blocked)

Phase 4 ships exactly that.

Architecture:

  packages/shared-llm/src/queue.ts — LlmTaskQueue class
    + QueuedTask interface (the persistent row shape)
    + EnqueueOptions (refType/refId/priority/maxAttempts)
    + TaskRegistry type (name → LlmTask map)
    + LlmTaskQueueOptions (table + orchestrator + registry +
                           retryBackoffMs + idleWakeupMs)

  Public API:
    - enqueue(task, input, opts) → string  (returns the queued id)
    - get(id), list(filter)
    - retry(id), cancel(id), purge(olderThanMs)
    - start(), stop()  (idempotent processor lifecycle)

  apps/mana/apps/web/src/lib/llm-queue.ts — web app singleton
    - Dedicated `mana-llm-queue` Dexie database (separate from the
      main `mana` IDB; see comment for the rationale: ephemeral
      per-device state, no encryption needed, no sync needed, doesn't
      belong in the long-frozen `mana` schema)
    - Wires up the queue with llmOrchestrator + taskRegistry
    - Exposes startLlmQueue() / stopLlmQueue() for the layout hook

  apps/mana/apps/web/src/lib/llm-task-registry.ts
    - Maps task names → task objects so the queue processor can
      look up the implementation when pulling rows off the table.
      Closures can't be persisted, so we round-trip via name.
    - Currently registers extractDateTask + summarizeTextTask;
      module-side tasks land here as we add them.

  apps/mana/apps/web/src/routes/(app)/+layout.svelte
    - startLlmQueue() in handleAuthReady's Phase A (auth-independent)
      so guests + authenticated users both get the queue
    - stopLlmQueue() in onDestroy as a fire-and-forget cleanup

Processor loop semantics (the heart of the implementation):

  1. On start(), reclaim any 'running' rows from a crashed previous
     session — reset them to 'pending'. The orphan recovery is the
     reason a crash mid-task doesn't leave the queue stuck.
  2. findNextRunnable() picks the highest-priority pending task whose
     `notBefore` (retry-backoff timestamp) is in the past. Sort key:
     priority desc, then enqueuedAt asc (FIFO within priority).
  3. Mark the task running, increment attempts, look up the LlmTask
     in the registry, hand it to orchestrator.run().
  4. On success: mark done, store result + source + finishedAt.
  5. On error:
       - TierTooLowError or ProviderBlockedError → fail immediately,
         no retry. These are not transient — the user's settings or
         the content itself need to change.
       - Anything else → if attempts < maxAttempts, reset to pending
         with notBefore = now + retryBackoffMs (default 60s). Else
         mark failed.
  6. When no work is pending, sleep on a Promise that resolves when
     either (a) someone calls enqueue() (which fires notifyWakeup),
     or (b) idleWakeupMs elapses (default 30s, safety net for any
     missed wakeup signal).

Module-side reactive reads use Dexie liveQuery directly on the queue
table — no special subscription API on the queue itself. This is
consistent with how every other Mana module reads its data, so the
mental model stays uniform:

  const tags = useLiveQuery(
    () => llmQueueDb.tasks
      .where({ refType: 'note', refId, taskName: 'common.extractTags' })
      .reverse().first(),
    [refId]
  );

Smoke test: a new "Queue" tab in /llm-test lets you enqueue the
existing extractDate / summarize tasks and watch the live state of
the queue table via liveQuery. The display includes per-row state
badge (pending/running/done/failed), tier source, attempt count,
input/output, and a "Done/failed löschen" button that exercises
purge().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 01:51:20 +02:00
..
cards-database fix(cards-database): add .js extensions to relative imports for NodeNext 2026-04-07 14:01:44 +02:00
credits chore(matrix): scrub final matrix references after subsystem removal 2026-04-08 16:39:42 +02:00
eslint-config fix(timeblocks): type errors from recurrence migration 2026-04-07 13:22:59 +02:00
feedback feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
help feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
local-llm feat(local-llm): Phase 3 — move inference into a Web Worker 2026-04-09 01:27:10 +02:00
local-store fix(mana/web): sprint 2 — auth-aware data layer + guest migration 2026-04-07 13:07:12 +02:00
notify-client chore(matrix): final scrub of stale matrix references 2026-04-08 16:47:54 +02:00
qr-export chore(workspace): unify vitest to ^4.1.2 across all packages 2026-04-07 13:58:29 +02:00
shared-api-client feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
shared-auth feat(auth): structured error codes + conditional passkey UI 2026-04-08 12:40:51 +02:00
shared-auth-ui refactor(auth-ui): tighten LoginPage UX, a11y, and dead code 2026-04-08 12:41:19 +02:00
shared-branding fix(mana-auth) + chore: rewrite /api/v1/auth/login JWT mint, remove Matrix stack 2026-04-08 16:32:13 +02:00
shared-config chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
shared-drizzle-config feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
shared-error-tracking feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
shared-errors chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
shared-go chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
shared-hono refactor(shared-tailwind): rewrite themes.css to single-layer shadcn convention 2026-04-09 01:13:06 +02:00
shared-i18n chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
shared-icons chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
shared-landing-ui chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
shared-links feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
shared-llm feat(shared-llm): Phase 4 — persistent LLM task queue 2026-04-09 01:51:20 +02:00
shared-logger feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
shared-pwa feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
shared-python/manacore_auth feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
shared-splitscreen feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
shared-storage chore(workspace): unify vitest to ^4.1.2 across all packages 2026-04-07 13:58:29 +02:00
shared-stores fix: type errors from ManaCore→Mana rename and stale templates 2026-04-07 13:42:17 +02:00
shared-tags chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
shared-tailwind refactor(shared-tailwind): rewrite themes.css to single-layer shadcn convention 2026-04-09 01:13:06 +02:00
shared-theme chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
shared-theme-ui chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
shared-tsconfig feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
shared-types chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
shared-ui refactor(mana/web): consolidate ListView scaffolding into BaseListView 2026-04-08 18:40:47 +02:00
shared-uload feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
shared-utils fix(csp): move jsdelivr allowlist to mana-web hooks (Vite SSR cache workaround) 2026-04-08 23:03:38 +02:00
shared-vite-config chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
spiral-db chore(workspace): unify vitest to ^4.1.2 across all packages 2026-04-07 13:58:29 +02:00
subscriptions feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
test-config chore(workspace): unify vitest to ^4.1.2 across all packages 2026-04-07 13:58:29 +02:00
wallpaper-generator chore(workspace): unify vitest to ^4.1.2 across all packages 2026-04-07 13:58:29 +02:00