Conversation
Every lesson of a unit was generated from the same grammar points and vocabulary sets, with no knowledge of its siblings and with lesson_type used only as a label. The model had no differentiation signal, so consecutive lessons of a unit repeated the same explanation, the same example sentences and the same common mistakes. Lesson generation now receives two additional signals: - The lessons already generated for the same unit are condensed into a capped summary (titles, types, explanation excerpts, example sentences, vocabulary, common traps) and injected as delimited data the new lesson must not reuse. The router builds the list from the lessons it already loaded for the plan, so no extra query is needed, and keeps it current when several lessons of a unit are generated in one request. - The declared lesson_type selects an instruction block describing what the explanation, the exercise mix and the vocabulary of a grammar, vocabulary, reading, writing, listening or review lesson must emphasise. Unknown types fall back to a generic block, and review lessons keep recycling the unit material but with new sentences and contexts. The output JSON schema is unchanged.
The VAD closed an utterance after 0.9-1.3 s of silence, derived from the CEFR level and hardcoded in ConversationMode. A learner reaching for a word routinely pauses longer than that, so the turn was submitted while they were still speaking and the tutor answered half a sentence. Nothing in Settings could change it, and a level assigned too high made the window shorter still. The automatic values now leave more room — 1800 ms for A1/A2, 1500 ms for B1/B2, 1200 ms for C1/C2, 1500 ms without a level — and learners who need more can choose 1, 2 or 3 seconds in Settings under Conversation. The resolution rule lives in lib/conversation-vad.ts: the stored conversation_speech_pause wins when set, 0 means automatic. The value is persisted on the user, validated against the offered set, and read when the VAD is created, so a change applies to the next session. The setting is a comfort preference, not a quota, so a subscription downgrade leaves it untouched.
The placement quiz offered four options and no way out, so a learner who did not know an item had to guess. With four options a guess is right about a quarter of the time, the scoring cannot tell it from knowledge, and the resulting level is too high — which then feeds the study plan, lesson difficulty and the conversation end-of-speech window. Each question now offers an explicit "I don't know" next to the options, kept visually apart so it does not read as a fifth answer. It is submitted as its own signal, `dont_know: true`, so the evaluator can separate a declared gap from a wrong answer: - A declared gap never counts as correct, whatever else the client sends. - A skill is a weakness when the learner declared a gap on at least half of its questions, even if the remaining answers keep its score above the usual threshold. - The legacy LLM evaluation prompt is told that a declared gap is reliable evidence the item is above the learner, while a wrong answer can still show partial knowledge. For the adaptive question selection a declared gap behaves exactly like a wrong answer. Removing the guess is the fix; penalising the honest answer on top of it would only trade one misplacement for another.
- Add `ANTHROPIC_MAX_TOKENS` to dev and example env files with an 8192 default - Use the configurable Anthropic output budget in the LLM adapter - Raise `LLMResponseError` when Anthropic responses stop due to `max_tokens` - Update tests to cover the new output limit and truncation handling - Bump version references, changelog, and architecture docs to 1.8.45
feature: fix issue 297
The "I don't know" action was 11px text-fl-muted-4 with no vertical padding: 2.7:1 against the light-theme card and a touch target only as tall as the glyphs. It is now 12px text-fl-muted-1 with vertical padding, 5.5:1 light and 6.6:1 dark. It stays borderless and uppercase, so it still reads as secondary to the four answer options.
The four options sat in one non-wrapping flex row, so the longer German, Spanish and Russian labels overflowed their buttons below about 375 px. They now use a two-column grid that becomes four columns from the sm breakpoint up.
Collect the unit vocabulary from every previous lesson instead of only the six that get a detailed summary. Scope the minimum share of grammar-targeting exercises to the lesson type, so a vocabulary lesson can ask for lexical exercises without contradicting the strict constraints. Stop claiming the student worked through the listed lessons, since a sibling can still be pending. Skip explanation blocks that are not lists, which the lesson schema still allows.
Differentiate lessons within a curriculum unit
…indow Make the voice end-of-turn pause longer and configurable
- Add `speaking` to the lesson type union and prompt guidance - Define speaking-specific lesson instructions and grammar ratio - Extend tests to cover speaking prompts and curriculum policy alignment - Update curriculum, architecture, testing, and changelog docs with new lesson and test counts - Refresh frontend layout formatting changes from the staged diff
feature: fix issue 305
Let learners decline a placement question instead of guessing
- Require an explicit study_plan_id for STT uploads and validate ownership server-side - Derive STT language from the persisted study plan and make STT service language mandatory - Route flashcard generation and review to the owning study plan instead of active client language - Update voice recording UIs to submit study-plan context and serialize pending reviews - Forward request cancellation through the STT proxy and warmup calls - Refresh documentation, changelog, and test counts to reflect the new behavior
feature: fix issue 304
- Gate admin overview subscription metrics and past-due alerts on the Stripe config flag - Hide admin user detail subscription status, subscription tab, and override controls when Stripe is disabled - Ignore subscription filters in the admin user list when Stripe is disabled and adjust table layout accordingly - Add tests for Stripe-enabled and Stripe-disabled admin visibility and stale query handling - Update architecture, testing, and changelog documentation for the new admin subscription behavior
feature: hidden settings when stripe is disabled
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.