Commit Graph

12 Commits

Author SHA1 Message Date
fcca6509cc wip(microsteps): B3.3 + B3.10 part 1 — prompts + microstep_patterns schema
Storage-side scaffolding for B3.3 (granularity prompt variants) and
B3.10 (mastery fade). The user-facing wiring (decompose_and_store
granularity threading, complete_subtask_cmd count bump, MicroSteps
inline prompt + skip-check, Settings UI) is part 2 of this batch.

B3.3 (prompts.rs): three new system-prompt constants
DECOMPOSE_LIGHT_SYSTEM (3 atomic verb-first steps),
DECOMPOSE_DEFAULT_SYSTEM (4-5 balanced steps), DECOMPOSE_DETAILED_SYSTEM
(6-7 with brief context) all preserve the cue-anchored "When [cue],
[action]" framing from PR 1.1. DECOMPOSE_TASK_SYSTEM remains as an
alias of Default for back-compat with existing callers and tests.
4 snapshot tests assert the framing survives across variants and the
alias matches.

B3.10 (storage): migration v18 adds microstep_patterns
(normalized_title PK, sample_title, completed_count, skip_breakdown,
prompted_at) plus an index on completed_count. New storage functions:
normalize_microstep_title (lowercase + whitespace-collapse + trim),
get_microstep_pattern, upsert_microstep_pattern_increment,
set_microstep_pattern_decision. 5 storage tests cover normalisation,
upsert/bump semantics, decision persistence, and the threshold query.

74 storage tests pass (was 69), 9 prompts tests pass (was 5).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 19:58:02 +01:00
0a8cb55447 feat(copy): PR 1.1 — research-grounded copy + prompt corrections
Add cue-anchored "When [cue], [action]" framing to the task-decomposition
prompt where natural cues are present (Gollwitzer-style implementation
intentions, d=0.65 effect size). Soften Bionic Reading and accessibility-
font copy to honest preference framing per the v3 audit (Strukelj 2024;
Doyon n=2,074). Update timer nudge from "Still on that timer?" (which
read as judgmental) to "Timer's still running." Replace stale Tasks
page header copy promising automatic extraction.

Audio envelopes (focusTimer 20ms ramp, sounds.ts 10ms attack) verified
correct per memo §B; no code change needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 18:12:58 +01:00
3410d3c586 feat(auto-title): kon-llm prompt + generate_title engine method
Recorder-style auto-titling for transcripts. Mirrors the Phase 9
content-tags pipeline so the same prompt-injection-hardened pattern,
spawn_blocking discipline, and sanitisation-after-generation shape get
reused; the user-facing surface (auto on save + on-demand button) lands
in a follow-up commit.

- crates/llm/src/prompts.rs: new TRANSCRIPT_TITLE_SYSTEM constant. Same
  injection guard wording as ai-formatting's CLEANUP_PROMPT — dictated
  speech is data, not instructions. Rules constrain output shape: 4-8
  words, Title Case, no quotes, no terminal punctuation, "Untitled"
  fallback for empty input.

- crates/llm/src/lib.rs: LlmEngine::generate_title returns
  Result<String, EngineError>. Mirrors extract_content_tags shape:
  trailing-2000-char UTF-8-boundary truncation, temperature 0,
  max_tokens 24, free-form output (no GBNF — titles are prose, not a
  closed set). Sanitisation runs server-side via the new private
  sanitize_title helper, which handles the real Qwen3 failure modes:
  surrounding curly + ASCII quotes, leading "Title:" prefix, multi-line
  output, trailing "." / "!" / "?", whitespace runs, 100-char cap,
  literal "Untitled" → None. Three unit tests cover composite real-world
  outputs end-to-end. kon-llm test suite goes 15 → 18 passing.

The Tauri wrapper, invoke_handler registration, and frontend wiring
follow in subsequent commits.
2026-04-25 19:47:56 +01:00
Claude
bd16c118cc build(android): split GPU acceleration into optional features
Both `kon-transcription` and `kon-llm` previously hardcoded their native
acceleration features in Cargo.toml — `whisper-rs` with `vulkan`,
`llama-cpp-2` with `openmp` + `vulkan`. That worked everywhere desktop
ships (Linux/macOS/Windows all have Vulkan via MoltenVK on Mac), but it
made an Android build structurally impossible: NDK builds against drivers
that vary wildly across SoCs (Adreno OK, Mali patchy, PowerVR worse), and
some older devices have no Vulkan at all.

Roadmap step 0 from the Android plan: make the GPU acceleration
opt-in so a CPU-only target compiles. Reuses the existing pattern that
README's "future Windows non-AVX2 build" comment hinted at.

- kon-transcription: new `whisper-vulkan` feature gates `whisper-rs/vulkan`
  via the optional-syntax `whisper-rs?/vulkan`. Default features stay as
  `["whisper", "whisper-vulkan"]` so desktop is unchanged.
- kon-llm: new `gpu-vulkan` and `openmp` features each gate the matching
  `llama-cpp-2` feature. Default stays `["gpu-vulkan", "openmp"]`. They are
  independent so an Android Vulkan build can opt into vulkan without
  openmp (NDK OpenMP linking has known cross-version fragility).

CPU-only build invocations:
  cargo build -p kon-transcription --no-default-features --features whisper
  cargo build -p kon-llm --no-default-features

Verified: all 91 tests in the buildable-in-sandbox crates still pass.
The two crates whose Cargo.toml changed (kon-transcription, kon-llm)
can't be compiled in this sandbox (ort-sys CDN + cmake-built llama.cpp);
CI's Linux/macOS/Windows builders will exercise the default-feature path
exactly as before.

https://claude.ai/code/session_0189xUb6ie6t9qHkzatGZ9Rb
2026-04-25 12:42:44 +00:00
7567bede52 feat(phase9): LlmEngine::extract_content_tags + smoke test
Added as a method on LlmEngine alongside cleanup_text and
extract_tasks; same render_chat_prompt -> generate -> parse pattern.
Truncates the transcript to its trailing 2000 chars on a UTF-8 char
boundary, runs at temperature 0.0 with the CONTENT_TAGS_GRAMMAR GBNF,
and re-validates intent against INTENT_CLOSED_SET to catch the
unlikely grammar bypass case. max_tokens 96 is enough for the JSON
envelope. Smoke test gated on KON_LLM_TEST_MODEL like the existing
smoke.rs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 00:02:12 +01:00
1b6ad88ead feat(phase9): ContentTags schema, system prompt, and GBNF grammar
ContentTags serde-serialisable. CONTENT_TAGS_SYSTEM is the system
message rendered at extraction time; INTENT_CLOSED_SET is the single
source of truth for the enum values the grammar restricts. Grammar is
strict: lowercase hyphen-joined topic 3+ chars (max enforced by
max_tokens at call site), intent from the closed set, JSON-only
output. Recursive topic-rest matches the existing GBNF style in this
file.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:58:36 +01:00
b333c6229e chore(hardening): tighten security and footprint defaults 2026-04-24 19:03:57 +01:00
46be0a5aca feat(feedback): Phase 2 — HITL thumbs + correction capture with prompt-conditioning loop
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
Closes the human-in-the-loop gap from docs/brief/feature-set.md and
Phase 2 of the 2026-04-23 feature-complete roadmap.

Storage (kon-storage):
- Migration v10 adds the `feedback` table: (target_type, target_id,
  rating, original_text, corrected_text, context_json, profile_id,
  created_at) with CHECK constraints on target_type and rating, plus
  indexes on (target_type, rating, created_at DESC) for prompt-time
  retrieval and (profile_id, target_type, created_at DESC) for
  per-profile scoping.
- New public API: `FeedbackTargetType`, `RecordFeedbackParams`,
  `FeedbackRow`, `record_feedback`, `list_feedback_examples`.
- Tests updated — the RB-02 rollback regression now discovers the
  real max version at runtime instead of hard-coding v10 for its
  poison migration.

LLM (kon-llm):
- `prompts::FeedbackExample` — local shape for few-shot exemplars so
  kon-llm stays independent of kon-storage.
- `prompts::build_conditioned_system_prompt` — appends a "here is
  the style this user prefers" block to the base system prompt
  when examples are available; returns the base prompt unchanged
  when empty, so new users and early sessions see generic output.
- `LlmEngine::decompose_task_with_feedback` and
  `LlmEngine::extract_tasks_with_feedback` thread examples through
  to the builder. The old one-arg variants are preserved and now
  call through with an empty slice.
- 4 unit tests covering empty, empty-input-skip, correction-wins,
  and thumbs-up-only fallback.

Tauri (src-tauri):
- New commands::feedback module: `record_feedback`,
  `list_feedback_examples_cmd`.
- `decompose_and_store` and `extract_tasks_from_transcript_cmd`
  now fetch the last 5 positive/neutral feedback rows for their
  target type and pass them through to the LLM, wiring the
  learning loop end-to-end.
- Shared `to_llm_examples` helper parses the `context_json.input`
  field (where the recorder stashes the parent task text / transcript
  chunk) back into the exemplar shape.

Frontend (MicroSteps.svelte):
- Thumbs-up and thumbs-down buttons on every micro-step row.
  Hover-revealed; the vote recolours the icon; clicking again
  clears the local highlight (the row itself stays in the audit
  trail).
- Pencil icon + double-click to edit step text. Save flows through
  update_task_cmd for persistence and records a correction feedback
  row with (original_text, corrected_text) — the highest-value
  training signal.
- Parent task text is captured in context_json.input at record time
  so the prompt builder can reconstruct the (input, preferred-output)
  pair on subsequent decompositions.
- Feedback capture is best-effort — a record_feedback failure never
  interrupts the primary action.

What's deferred to a later phase:
- Thumbs + corrections on extracted tasks (same pipeline, different
  surface — probably TasksPage after the AI-extraction path)
- Thumbs on transcript cleanup output
- Semantic retrieval over the feedback corpus (once there is enough
  data to justify embedding infrastructure; the storage shape is
  already ready for it)
2026-04-24 12:53:51 +01:00
9b0067b4c0 Land release blocker fixes and workspace cleanup
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
2026-04-23 00:16:09 +01:00
d1eb56fac9 feat(llm): wire Phase 3 local LLM runtime via llama-cpp-2
kon-llm now owns a real LlamaBackend + LlamaModel, with three Qwen3 tiers
(1.7B Q4, 4B-Instruct-2507 Q4, 14B Q5) selectable per hardware. Downloads
are resumable with SHA-256 verification and stored under ~/.kon/models/llm.

Engine exposes three high-level surfaces — all greedy/temp-0, GBNF-constrained
where output shape matters:
- cleanup_text (prompt-injection-hardened system prompt; profile terms
  appended as "preserve these spellings" suffix)
- decompose_task (3–7 micro-steps, constrained JSON array)
- extract_tasks (optional-array; empty when no explicit commitments)

post_process_segments now takes an Option<&LlmEngine> and, when loaded and
format_mode != Raw, joins segments → cleanup → replaces segments with the
cleaned text (first segment span). Rule-based path still runs first; LLM
errors log and keep rule-based output.

Tauri commands: recommend_llm_tier, check_llm_model, download_llm_model,
load_llm_model, unload_llm_model, delete_llm_model, get_llm_status,
cleanup_transcript_text_cmd, extract_tasks_from_transcript_cmd,
decompose_and_store (LLM-backed subtasks).

Settings: AI tier toggle (off / cleanup / tasks), model picker with
downloaded/loaded status, download progress events via
kon:llm-download-progress.

Dictation: ensureLlmModelLoaded on mount, cleanupTranscriptIfEnabled after
stop when tier != off and format_mode != Raw, LLM task extraction when
tier=tasks (regex fallback on failure).

Interim: both llama-cpp-sys-2 and whisper-rs-sys statically link their own
ggml, so src-tauri/build.rs emits -Wl,--allow-multiple-definition on Linux.
Replace with a system-ggml shared-lib setup as a follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 07:31:51 +01:00
34fce3cf9e feat: OpenWhispr-inspired transcription polish pass
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
Major quality pass on top of Phase 2. Five substantive changes plus
cross-cutting touches across audio, hotkey, transcription, and Tauri
command layers.

  Transcription quality

  - Long-audio chunking in commands/transcription.rs: Parakeet and large
    file transcription now chunk-and-recompose with overlap trimming, so
    the live-path chunking advantage extends to file-based workflows.
  - Stateful live speech gate in commands/live.rs on top of the earlier
    duplicate-boundary filtering — distinguishes start-of-speech from
    mid-speech and holds state across chunks.

  Auto-learning corrections

  - New crates/ai-formatting/src/correction_learning.rs: extracts user
    text corrections from viewer edits and proposes additions to the
    active profile's vocabulary.
  - src-tauri/src/commands/profiles.rs bridge for frontend-driven
    confirmation of learned terms.
  - src/routes/viewer/+page.svelte hooks the learning path into the
    segment-edit flow so corrections feed profile_terms without a
    separate 'train this profile' UX.

  Transcript profile provenance

  - Migration v8 (crates/storage/src/migrations.rs) adds profile_id to
    transcripts, defaulting to DEFAULT_PROFILE_ID so existing rows stay
    valid.
  - crates/storage/src/database.rs: TranscriptRow + CRUD carry profile_id.
  - src-tauri/src/commands/transcripts.rs: add_transcript accepts and
    persists profile_id.
  - DictationPage.svelte + FilesPage.svelte send activeProfileId on
    capture so learned corrections are attributed to the right profile.

  Cleanup prompt contract

  - crates/ai-formatting/src/llm_client.rs hardened: the CLEANUP_PROMPT
    now specifies concrete do/do-not rules, ready for a real model-backed
    cleanup pass. The llm_client is still a stub — kon-llm remains unwired
    — but the prompt shape is final.

  Cross-cutting polish

  - Minor touches in audio (capture/decode/resample), hotkey (lib/linux/stub),
    core, transcription (concurrency/model_manager/local_engine/whisper_rs),
    and the rest of src-tauri/src/commands/*: error-path tightening, log
    clarity, TS-migration follow-ups (@ts-nocheck additions for incremental
    typing).

Verified locally: npm run check, cargo test -p kon-ai-formatting,
cargo test -p kon-storage, cargo test -p kon --lib commands::live::tests,
cargo check — all green.

Scope boundary: kon-llm crate is still a stub; task extraction remains
rule-based. Bundled local-LLM runtime is the next clean step and is not
in this commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 22:39:08 +01:00
8640b255e9 feat(llm): add kon-llm stub crate with LlmEngine interface — Phase 3 will wire real model 2026-04-19 10:42:24 +01:00