From 2db6261ad961ebaabe829385f0d5c793ecbff4fa Mon Sep 17 00:00:00 2001 From: Ross and Zober Date: Mon, 25 May 2026 18:02:04 +0700 Subject: [PATCH 1/2] feat: enhance grammar protocol block with detailed triggers and examples for better learner support --- frontend/src/features/agent/lib/prompt/sections.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/features/agent/lib/prompt/sections.ts b/frontend/src/features/agent/lib/prompt/sections.ts index 881fba36..ffd7296f 100644 --- a/frontend/src/features/agent/lib/prompt/sections.ts +++ b/frontend/src/features/agent/lib/prompt/sections.ts @@ -79,12 +79,13 @@ export function roleBlock(surface: PromptSurface): string { export function grammarProtocolBlock(): string { return tag('grammar_protocol', [ 'Grammar = the single source of truth is `search_document`, NEVER your own training knowledge.', - '- **SCOPE:** grammar means rules, particles, sentence patterns, word order. A bare single-word meaning ("what does 不 mean?") is vocabulary — answer it normally, no `search_document` needed. When a word\'s *behaviour* is the question (把, 了, 着, 过, 吗, 的/得/地), treat it as grammar and search.', - '- **TRIGGER:** any grammar question asked directly (a rule, particle, sentence pattern — e.g. 把 construction, 了/着/过, complements, word order) OR any sign the learner is struggling with grammar. In both cases call `search_document` FIRST with a concise natural-language query.', + '- **SCOPE:** grammar means rules, particles, sentence patterns, word order. A bare single-word meaning ("what does 不 mean?") is vocabulary — answer it normally, no `search_document` needed. When a word\'s *behaviour* is the question (把, 了, 着, 过, 吗, 的/得/地), OR when the learner is mixing up / cannot distinguish two similar words or particles (的 vs 得 vs 地, 了 placements, 在 vs 正在, 把 vs 被), treat it as grammar and search — distinguishing confusable items IS a grammar task.', + '- **TRIGGER — explicit OR implicit.** Explicit = a grammar question asked directly (a rule, particle, sentence pattern — e.g. 把 construction, 了/着/过, complements, word order). Implicit = ANY sign the learner is struggling, even with no question: frustration ("these two are so confusing", "I can never remember when to use this", "why is it 了 here but not there?"), repeated misuse of a pattern, or confusion between similar forms. In BOTH cases call `search_document` FIRST with a concise natural-language query, THEN address the struggle from the passages. Do not wait for a formal "explain X" request.', '- **GROUND:** answer ONLY from the returned passages. Do not answer grammar from training data, and do NOT use `get_skill_guide` for grammar.', '- **NO REDUNDANT CALLS:** if an earlier `search_document` result in this conversation already contains the passages needed to answer, reuse it — do NOT call again for the same point. Only re-query for a genuinely new grammar point or when prior passages are insufficient.', '- **ALWAYS SHOW THE SOURCE URL:** the passages include the YouTube link(s) the content was derived from. Every grammar answer MUST end with that link so the learner can watch the source. Use links found verbatim in the passages only — never invent or guess a URL; if a link is split across lines, rejoin into a single `https://youtu.be/` URL.', - '- **EXAMPLE — the rule holds even for "easy" questions.** Learner: "does 吗 make a sentence a question?" → call `search_document("吗 question particle")` FIRST, ground the answer in the passage, end with its URL. Do NOT shortcut to "yes" from memory: the most obvious questions are exactly where skipping the tool is most tempting.', + '- **EXAMPLE (explicit) — the rule holds even for "easy" questions.** Learner: "does 吗 make a sentence a question?" → call `search_document("吗 question particle")` FIRST, ground the answer in the passage, end with its URL. Do NOT shortcut to "yes" from memory: the most obvious questions are exactly where skipping the tool is most tempting.', + '- **EXAMPLE (implicit) — detect struggle with no question asked.** Learner: "ugh, 的 得 地 are so confusing, I can never tell them apart." This is not phrased as a question, but it is a clear grammar struggle → call `search_document("difference between 的 得 地 usage")` FIRST, then explain the distinction grounded in the passages and end with the URL. Treat venting/confusion as a trigger, not small talk.', ]) } From e7a60d08888a6186af0971e5f7ce4d46c0001125 Mon Sep 17 00:00:00 2001 From: Ross and Zober Date: Tue, 26 May 2026 00:49:09 +0700 Subject: [PATCH 2/2] feat: add ignoreDeprecations option to TypeScript configuration for improved compatibility --- README.md | 97 ++++++++++++++++++++++++++++++++++++++ frontend/tsconfig.app.json | 1 + 2 files changed, 98 insertions(+) diff --git a/README.md b/README.md index 21c3d9a2..e2b40827 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,103 @@ A Chinese language learning platform built around the **shadowing technique**. U --- +## AI Companion — Harness Architecture + +The AI companion is not a single LLM call — it's an engineered agent harness. A turn flows through five layers and loops back. + +### The Layers (one turn flows top → bottom → back) + +```mermaid +flowchart TD + U([User message]) + + subgraph PROMPT[" 1 · Prompt Assembly "] + direction TB + P1[Role + behaviour instructions] + P2[Grammar & learning protocols] + P3[Learner profile · memory · session state] + P4[Cache-stable prefix → cheap reuse] + end + + subgraph LOOP[" 2 · Agent Loop "] + direction TB + L1[Stream model response] + L2{Model wants
a tool?} + L3[Auto-resubmit with results
up to N rounds] + end + + subgraph TOOLS[" 3 · Tool Calling "] + direction TB + T1[Tool definitions
name · purpose · when-to-use] + T2[Executor
parallel-safe vs serialized] + T3[(Data tools
RAG · vocabulary · memory · study context)] + T4[(Render tools
study session · vocab card · charts)] + T5[(Guidance tools
teaching guidelines & manuals)] + end + + subgraph CTX[" 4 · Context Management "] + direction TB + C1[Track real token usage per turn] + C2{Over budget?} + C3[Compact: keep recent turns whole,
summarize older into structured recap] + C4[Strip stale tool output,
protect active RAG passages] + end + + subgraph BACK[" 5 · Backend & Knowledge "] + direction TB + B1[Streaming model gateway] + B2[RAG pipeline:
route → retrieve → ground] + B3[(Persisted chats
+ summaries)] + end + + U --> PROMPT --> LOOP + L1 --> L2 + L2 -- yes --> TOOLS + T1 --> T2 --> T3 & T4 & T5 + TOOLS -- results --> L3 --> L1 + L2 -- no --> CTX + C1 --> C2 + C2 -- yes --> C3 --> C4 --> BACK + C2 -- no --> BACK + B2 -.grounds.-> T3 + BACK --> A([Grounded answer + source link]) +``` + +### One Turn, End to End + +```mermaid +sequenceDiagram + participant U as Learner + participant H as Harness + participant M as Model + participant T as Tools / RAG + participant X as Context Mgr + + U->>H: "的 得 地 are so confusing…" + H->>H: Assemble prompt (protocols + profile,
cached prefix reused) + H->>M: Stream request + M-->>H: Intent: this is a grammar struggle → search + H->>T: search knowledge base + T-->>H: Verbatim passages + source URL + H->>M: Resubmit grounded with passages + M-->>H: Explanation grounded in source + H->>X: Record real token usage + alt Over budget + X->>X: Keep recent turns whole,
summarize older, protect active RAG + end + H-->>U: Answer + "watch the source" link +``` + +### Engineering Wins + +- **Infers intent** — fires retrieval on *implicit* struggle, not just explicit questions. +- **Grounded, not guessed** — grammar answers come from retrieved source passages, always cited. +- **Agentic loop** — multi-round tool use, not single-shot. +- **Never dead-ends** — compaction keeps long sessions alive instead of "start a new chat." +- **Cost-aware** — stable prompt prefix → cache hits → lower latency & spend. + +--- + ## Getting Started ### Prerequisites diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json index dd33526b..c4b12627 100644 --- a/frontend/tsconfig.app.json +++ b/frontend/tsconfig.app.json @@ -7,6 +7,7 @@ "moduleDetection": "force", "useDefineForClassFields": true, "baseUrl": ".", + "ignoreDeprecations": "6.0", "module": "ESNext", /* Bundler mode */