fix: 修复 anthropic 煞笔的四个 bug (#352)
* fix: 移除文件编辑前必须先读取的限制 移除 FileEditTool 和 FileWriteTool 中的 "read before edit" 校验, 允许直接编辑未读取过的文件。保留文件修改过期检测。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: 更新 teach-me 自动写 note 笔记的功能 * fix: 修复 DeepSeek V4 reasoning_content 回传导致的 400 错误 - 扩大模型名称检测范围,匹配所有 deepseek 模型(V4、R1 等) - 始终保留 thinking blocks 为 reasoning_content 回传给 API - 移除有 bug 的 turn boundary 剥离逻辑 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: Opus 4.6/4.7 默认推理 effort 从 medium 改为 high Pro 和 Max/Team 订阅者的 Opus 默认 effort 之前被降级为 medium, 导致用户感知模型「变笨」。恢复为 high。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: 移除 thinkingClearLatched sticky-on 机制 空闲超过 1 小时后 thinkingClearLatched 会被触发且永不重置, 导致每轮 API 调用都清除 thinking 历史。完整移除该 latch 机制, clearAllThinking 硬编码为 false。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: 移除 numeric_length_anchors 系统指令 删除「工具调用间文字 ≤25 词、最终回复 ≤100 词」的硬性限制。 ablation 测试显示该约束使整体智能下降 3%。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: 修复测试中 reasoning_content 类型断言 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
fe9da6e5b9
commit
995d3a473c
|
|
@ -1,325 +0,0 @@
|
|||
---
|
||||
name: teach-me
|
||||
description: "Personalized 1-on-1 AI tutor. Diagnoses level, builds learning path, teaches via guided questions, tracks misconceptions. Use when user wants to learn/study/understand a topic, says 'teach me', 'help me understand', or invokes /teach-me."
|
||||
---
|
||||
|
||||
# Teach Me
|
||||
|
||||
Personalized mastery tutor. Diagnose, question, advance on understanding.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
/teach-me Python decorators
|
||||
/teach-me 量子力学 --level beginner
|
||||
/teach-me React hooks --resume
|
||||
```
|
||||
|
||||
## Arguments
|
||||
|
||||
| Argument | Description |
|
||||
|----------|-------------|
|
||||
| `<topic>` | Subject to learn (required, or prompted) |
|
||||
| `--level <level>` | Starting level: beginner, intermediate, advanced (default: diagnose) |
|
||||
| `--resume` | Resume previous session from `.claude/skills/teach-me/records/{topic-slug}/` |
|
||||
|
||||
## Core Rules
|
||||
|
||||
1. **Minimize lecturing, but don't be dogmatic.** Prefer questions that lead to discovery. For complete beginners with zero context, a brief 1-2 sentence framing is acceptable before asking.
|
||||
2. **Diagnose first.** Always probe current understanding before teaching.
|
||||
3. **Mastery gate.** Advance to next concept only when the learner can explain it clearly and apply it.
|
||||
4. **1-2 questions per round.** No more.
|
||||
5. **Patience + rigor.** Encouraging tone, but never hand-wave past gaps.
|
||||
6. **Language follows user.** Match the user's language. Technical terms can stay in English.
|
||||
7. **Always use AskUserQuestion.** Every question to the learner MUST use AskUserQuestion with predefined options. Never ask open-ended plain-text questions — users need options to anchor their thinking. Even conceptual/deep questions should offer 3-4 options plus let the user pick "Other" for free-form input. Options serve as scaffolding, not just convenience.
|
||||
|
||||
## Output Directory
|
||||
|
||||
All teach-me data is stored under `.claude/skills/teach-me/records/`:
|
||||
|
||||
```
|
||||
.claude/skills/teach-me/records/
|
||||
├── learner-profile.md # Cross-topic notes (created on first session)
|
||||
└── {topic-slug}/
|
||||
└── session.md # Learning state: concepts, status, notes
|
||||
```
|
||||
|
||||
**Slug**: Topic in kebab-case, 2-5 words. Example: "Python decorators" → `python-decorators`
|
||||
|
||||
## Workflow
|
||||
|
||||
```
|
||||
Input → [Load Profile] → [Diagnose] → [Build Concept List] → [Tutor Loop] → [Session End]
|
||||
```
|
||||
|
||||
### Step 0: Parse Input
|
||||
|
||||
1. Extract topic. If none, use AskUserQuestion to ask what they want to learn (provide common categories as options).
|
||||
2. Detect language from user input.
|
||||
3. Load learner profile if `.claude/skills/teach-me/records/learner-profile.md` exists.
|
||||
4. Check for existing session:
|
||||
- If `--resume`: read `session.md`, restore state, continue.
|
||||
- If exists without `--resume`: use AskUserQuestion to ask whether to resume or start fresh.
|
||||
5. Create output directory: `.claude/skills/teach-me/records/{topic-slug}/`
|
||||
|
||||
### Step 1: Diagnose Level
|
||||
|
||||
Ask 2-3 questions to calibrate understanding, all via AskUserQuestion with predefined options.
|
||||
|
||||
If learner profile exists, use it to skip known strengths and probe known weak areas.
|
||||
|
||||
If `--level` provided, use as hint but still ask 1-2 probing questions.
|
||||
|
||||
**Example for "Python decorators"**:
|
||||
|
||||
Round 1 (AskUserQuestion):
|
||||
```
|
||||
header: "Level check"
|
||||
question: "Which of these Python concepts are you comfortable with?"
|
||||
multiSelect: true
|
||||
options:
|
||||
- label: "Functions as values"
|
||||
- label: "Closures"
|
||||
- label: "The @ syntax"
|
||||
- label: "Writing custom decorators"
|
||||
```
|
||||
|
||||
Round 2 (AskUserQuestion — conceptual question with options as scaffolding):
|
||||
```
|
||||
header: "Understanding"
|
||||
question: "When Python sees @my_decorator above a function, what do you think happens?"
|
||||
multiSelect: false
|
||||
options:
|
||||
- label: "It replaces the function with a new one"
|
||||
description: "The decorator wraps or replaces the original function"
|
||||
- label: "It's just syntax sugar for calling the decorator"
|
||||
description: "@decorator is equivalent to func = decorator(func)"
|
||||
- label: "It modifies the function in-place"
|
||||
description: "The original function object is changed directly"
|
||||
- label: "I'm not sure"
|
||||
description: "No worries, we'll figure it out together"
|
||||
```
|
||||
|
||||
### Step 2: Build Concept List
|
||||
|
||||
Decompose topic into 5-15 atomic concepts, ordered by dependency. Save to `session.md`:
|
||||
|
||||
```markdown
|
||||
# Session: {topic}
|
||||
- Level: {diagnosed}
|
||||
- Started: {timestamp}
|
||||
|
||||
## Concepts
|
||||
1. ✅ Functions as first-class objects (mastered)
|
||||
2. 🔵 Higher-order functions (in progress)
|
||||
3. ⬜ Closures
|
||||
4. ⬜ Decorator basics
|
||||
...
|
||||
|
||||
## Misconceptions
|
||||
- [concept]: "{what learner said}" → likely root cause: {analysis}
|
||||
|
||||
## Log
|
||||
- [timestamp] Diagnosed: intermediate
|
||||
- [timestamp] Concept 1: pre-existing knowledge, skipped
|
||||
- [timestamp] Concept 2: started
|
||||
```
|
||||
|
||||
Use simple status: ✅ mastered | 🔵 in progress | ⬜ not started | ❌ needs review
|
||||
|
||||
Present the concept list to the learner as a brief text outline so they see the path ahead.
|
||||
|
||||
### Step 3: Tutor Loop
|
||||
|
||||
For each concept:
|
||||
|
||||
#### 3a. Introduce (Brief)
|
||||
|
||||
Set context with 1-2 sentences max, then ask an opening question via AskUserQuestion. Options serve as thinking scaffolds:
|
||||
|
||||
Example for "closures":
|
||||
```
|
||||
header: "Closures"
|
||||
question: "A closure is a function that remembers variables from where it was created. Why might that be useful?"
|
||||
multiSelect: false
|
||||
options:
|
||||
- label: "To create private state"
|
||||
description: "Keep variables hidden from outside code"
|
||||
- label: "To pass data between functions"
|
||||
description: "Share information without global variables"
|
||||
- label: "To cache expensive computations"
|
||||
description: "Remember results for reuse"
|
||||
- label: "I'm not sure yet"
|
||||
description: "We'll explore this together"
|
||||
```
|
||||
|
||||
#### 3b. Question Cycle
|
||||
|
||||
ALL questions use AskUserQuestion. Design options that probe understanding — include a mix of correct, partially correct, and common-wrong-answer distractors. The user can always use "Other" for free-form input when they have a specific idea.
|
||||
|
||||
**Option design tips**:
|
||||
- Include 1-2 correct answers (split nuance into separate options)
|
||||
- Include 1 distractor based on a common misconception
|
||||
- Include "I'm not sure" or "Let me think about it" as a safe option
|
||||
- Use descriptions to add hints or context to each option
|
||||
|
||||
**Interleaving** (every 3-4 questions): Mix a previously mastered concept into the current question's options naturally. Don't announce it as review.
|
||||
|
||||
Example (learning closures, already mastered higher-order functions):
|
||||
```
|
||||
header: "Prediction"
|
||||
question: "Here's a function that takes a callback and returns a new function. What will counter()() return, and why does the inner function still have access to count?"
|
||||
multiSelect: false
|
||||
options:
|
||||
- label: "0, because count starts at 0"
|
||||
description: "The inner function reads the initial value"
|
||||
- label: "1, because count was incremented before returning"
|
||||
description: "Closure captures the live variable, not a copy"
|
||||
- label: "Error, because count is out of scope"
|
||||
description: "The outer function already returned, so count is gone"
|
||||
- label: "Undefined behavior"
|
||||
description: "Depends on how the function was defined"
|
||||
```
|
||||
|
||||
#### 3c. Respond to Answers
|
||||
|
||||
| Answer Quality | Response |
|
||||
|----------------|----------|
|
||||
| Correct + good explanation | Brief acknowledgment, harder follow-up via AskUserQuestion |
|
||||
| Correct but shallow | "Good. Can you explain *why*?" — as AskUserQuestion with why-options |
|
||||
| Partially correct | "On the right track with [part]." — follow up with a more targeted AskUserQuestion |
|
||||
| Incorrect | "Interesting. Let's step back." — simpler AskUserQuestion to re-anchor |
|
||||
| "I don't know" / "Not sure" | "That's fine." — give a concrete example, then ask via AskUserQuestion with simpler options |
|
||||
|
||||
**Hint escalation**: rephrase → simpler question → concrete example → point to principle → walk through minimal example together.
|
||||
|
||||
#### 3d. Misconception Tracking
|
||||
|
||||
On incorrect or partially correct answers, diagnose the underlying wrong mental model:
|
||||
|
||||
1. Present a counter-example via AskUserQuestion — ask the learner to predict what happens, where the wrong mental model leads to a clearly wrong answer:
|
||||
```
|
||||
header: "Check this"
|
||||
question: "Given [counter-example], what do you think the output will be?"
|
||||
multiSelect: false
|
||||
options:
|
||||
- label: "[wrong prediction from their mental model]"
|
||||
description: "Based on what we discussed earlier"
|
||||
- label: "[correct prediction]"
|
||||
description: "A different perspective"
|
||||
- label: "[another wrong prediction]"
|
||||
description: "Yet another possibility"
|
||||
- label: "I need to think more"
|
||||
description: "Take your time"
|
||||
```
|
||||
2. Record in session.md under `## Misconceptions`
|
||||
3. When the learner sees the contradiction (their model predicts the wrong thing), guide them to articulate why.
|
||||
4. A misconception is resolved when the learner articulates why their old thinking was wrong AND handles a new scenario correctly.
|
||||
|
||||
Never say "that's a misconception." Let them discover it.
|
||||
|
||||
#### 3e. Mastery Check
|
||||
|
||||
After 3-5 question rounds, assess qualitatively. The learner demonstrates mastery when they can:
|
||||
|
||||
- Explain the concept in their own words
|
||||
- Apply it to a new scenario
|
||||
- Distinguish it from similar concepts
|
||||
- Find errors in incorrect usage
|
||||
|
||||
If not ready: identify the specific gap and cycle back with targeted questions.
|
||||
|
||||
#### 3f. Practice Phase
|
||||
|
||||
Before marking mastered, give a small hands-on task via AskUserQuestion. Present the task as a code/output prediction or scenario choice:
|
||||
|
||||
- **Programming**: Show a small code snippet and ask what it outputs or which fix is correct:
|
||||
```
|
||||
header: "Practice"
|
||||
question: "Here's a buggy decorator. What's wrong with it?"
|
||||
multiSelect: false
|
||||
options:
|
||||
- label: "Missing return wrapper"
|
||||
description: "The decorator doesn't return the inner function"
|
||||
- label: "Wrong function signature"
|
||||
description: "The wrapper doesn't accept *args, **kwargs"
|
||||
- label: "Missing @functools.wraps"
|
||||
description: "Metadata from the original function is lost"
|
||||
- label: "I'd like to try writing one from scratch"
|
||||
description: "Use 'Other' to write your own code"
|
||||
```
|
||||
- **Non-programming**: Ask to identify which scenario best applies the concept:
|
||||
```
|
||||
header: "Apply it"
|
||||
question: "Which real-world scenario best demonstrates [concept]?"
|
||||
multiSelect: false
|
||||
options:
|
||||
- label: "[scenario A]"
|
||||
- label: "[scenario B]"
|
||||
- label: "[scenario C]"
|
||||
- label: "I have my own example"
|
||||
description: "Use 'Other' to share your own"
|
||||
```
|
||||
|
||||
Keep it 2-5 minutes. Pass = mastered. Fail = diagnose gap, cycle back.
|
||||
|
||||
#### 3g. Sync Progress (Every Round)
|
||||
|
||||
Update `session.md` after each round:
|
||||
- Change concept status if applicable
|
||||
- Add new misconceptions or resolve existing ones
|
||||
- Append to log
|
||||
|
||||
### Step 4: Session End
|
||||
|
||||
When all concepts mastered or user ends session:
|
||||
|
||||
1. Update `session.md` with final state.
|
||||
2. Update `.claude/skills/teach-me/records/learner-profile.md` (keep under 30 lines):
|
||||
|
||||
```markdown
|
||||
# Learner Profile
|
||||
Updated: {timestamp}
|
||||
|
||||
## Style
|
||||
- Learns best with: {concrete examples / abstract principles / visual ...}
|
||||
- Pace: {fast / moderate / needs-time}
|
||||
|
||||
## Patterns
|
||||
- Tends to confuse X with Y
|
||||
- Recurring difficulty with: {area}
|
||||
|
||||
## Topics
|
||||
- Python decorators (8/10 concepts, 2025-01-15)
|
||||
```
|
||||
|
||||
3. Give a brief text summary of what was covered, key insights, and areas for further study.
|
||||
|
||||
## Resuming Sessions
|
||||
|
||||
On `--resume`:
|
||||
|
||||
1. Read `session.md` and `learner-profile.md`
|
||||
2. Quick check on 1-2 previously mastered concepts via AskUserQuestion:
|
||||
```
|
||||
header: "Quick review"
|
||||
question: "Last time you mastered [concept X]. Can you recall which of these is true about it?"
|
||||
multiSelect: false
|
||||
options:
|
||||
- label: "[correct statement]"
|
||||
- label: "[plausible distractor]"
|
||||
- label: "[plausible distractor]"
|
||||
- label: "I forgot this one"
|
||||
description: "No worries, we'll revisit it"
|
||||
```
|
||||
3. If forgotten, mark as ❌ needs review and revisit before continuing
|
||||
4. Recap: "Last time you mastered [X]. You were working on [Y]."
|
||||
5. Continue from first in-progress or not-started concept
|
||||
|
||||
## Notes
|
||||
|
||||
- Keep it conversational, not mechanical
|
||||
- Vary question types: predict, compare, debug, extend, teach-back, connect
|
||||
- Slow down when struggling, speed up when flying
|
||||
- Interleaving should feel natural, not like a pop quiz
|
||||
- Wrong answers are more informative than right ones — never rush past them
|
||||
|
|
@ -1,235 +0,0 @@
|
|||
# Pedagogy Guide
|
||||
|
||||
## Bloom's 2-Sigma Effect
|
||||
|
||||
Benjamin Bloom (1984) found that students tutored 1-on-1 with mastery learning performed 2 standard deviations above conventional classroom students. The two key ingredients:
|
||||
|
||||
1. **Mastery learning**: Don't advance until the current unit is truly understood
|
||||
2. **1-on-1 tutoring**: Adapt pace, style, and content to the individual learner
|
||||
|
||||
## Socratic Method Integration
|
||||
|
||||
Never lecture. Instead:
|
||||
- Ask questions that lead the learner to discover the answer
|
||||
- When they're stuck, don't explain — ask a simpler question
|
||||
- When they answer correctly, don't just confirm — ask them to explain why
|
||||
|
||||
## Question Design Patterns
|
||||
|
||||
### Diagnostic Questions (Step 1)
|
||||
|
||||
Purpose: Quickly map what the learner knows and doesn't know.
|
||||
|
||||
| Type | Example | Probes |
|
||||
|------|---------|--------|
|
||||
| Vocabulary check | "What does [term] mean to you?" | Do they know the words? |
|
||||
| Concept sorting | "Which of these are examples of X?" (AskUserQuestion) | Can they categorize? |
|
||||
| Prediction | "What do you think happens when...?" | Intuition level |
|
||||
| Explain-back | "Explain [concept] as if to a 10-year-old" | Depth of understanding |
|
||||
|
||||
### Teaching Questions (Step 3)
|
||||
|
||||
| Pattern | When | Example |
|
||||
|---------|------|---------|
|
||||
| **Predict** | Introducing new behavior | "What will this code print?" |
|
||||
| **Compare** | Distinguishing similar concepts | "How is X different from Y?" |
|
||||
| **Debug** | Testing careful reading | "This code has a bug. Can you find it?" |
|
||||
| **Extend** | Testing transfer | "Now how would you modify this to also handle...?" |
|
||||
| **Teach-back** | Confirming mastery | "Explain to me how [concept] works" |
|
||||
| **Connect** | Building knowledge graph | "How does [new concept] relate to [previous concept]?" |
|
||||
|
||||
### Mastery Check Questions (Step 3g)
|
||||
|
||||
These should be synthesis-level:
|
||||
- Combine the current concept with 1-2 previous concepts
|
||||
- Require application, not just recall
|
||||
- Include at least one novel scenario not seen during teaching
|
||||
|
||||
### Interleaving Questions (Step 3b)
|
||||
|
||||
Interleaving means mixing questions about old concepts into the current learning flow. Research (Rohrer & Taylor 2007, Dunlosky et al. 2013) shows interleaved practice improves long-term retention by ~43% compared to blocked practice.
|
||||
|
||||
**Why it works**: Interleaving forces the learner to discriminate between concepts ("which tool applies here?"), which is a higher cognitive demand than applying a known concept. This discrimination practice is what builds durable, flexible knowledge.
|
||||
|
||||
**How to design interleaving questions**:
|
||||
- The question must require BOTH the old concept and the current concept
|
||||
- Don't announce it as review — embed it naturally
|
||||
- Prioritize concepts that are easily confused with the current one
|
||||
- If the learner fails the old-concept part, it's a signal the old concept is decaying — note it for spaced repetition
|
||||
|
||||
| Interleaving Pattern | Example |
|
||||
|---------------------|---------|
|
||||
| **Combine** | "Use both [old concept] and [new concept] to solve this" |
|
||||
| **Discriminate** | "Would you use [old concept] or [new concept] here? Why?" |
|
||||
| **Contrast** | "This looks similar to [old concept]. What's different?" |
|
||||
| **Layer** | "We used [old concept] to do X. Now add [new concept] on top." |
|
||||
|
||||
## Mastery Scoring (Calibrated)
|
||||
|
||||
### Rubric-Based Assessment
|
||||
|
||||
Do NOT score based on vague impression. Use these 4 criteria for each mastery check question:
|
||||
|
||||
| Criterion | Weight | What to look for |
|
||||
|-----------|--------|------------------|
|
||||
| **Accurate** | 1 point | Factually/logically correct answer |
|
||||
| **Explained** | 1 point | Learner articulates the WHY, not just the WHAT |
|
||||
| **Novel application** | 1 point | Can apply to a scenario not seen during teaching |
|
||||
| **Discrimination** | 1 point | Can distinguish from similar/related concepts |
|
||||
|
||||
Score per question = criteria met / 4. Concept mastery requires >= 3/4 on each mastery check question AND >= 80% overall concept score.
|
||||
|
||||
### Self-Assessment Calibration
|
||||
|
||||
Ask the learner to self-assess BEFORE revealing your evaluation. Compare:
|
||||
|
||||
| Self vs Rubric | What it means | Action |
|
||||
|----------------|---------------|--------|
|
||||
| Both high | Good metacognition, true mastery | Proceed to practice phase |
|
||||
| Self HIGH, rubric LOW | **Fluency illusion** — most dangerous | Flag explicitly, show evidence of gaps |
|
||||
| Self LOW, rubric HIGH | Under-confidence | Reassure with specific evidence |
|
||||
| Both low | Honest awareness of gaps | Cycle back, adjust approach |
|
||||
|
||||
**Fluency illusion** (Bjork, 1994): The feeling of understanding that comes from familiarity rather than actual comprehension. Common triggers: seeing a worked example and thinking "I could do that", recognizing terminology without being able to apply it, confusing passive exposure with active mastery.
|
||||
|
||||
### Qualitative Signals
|
||||
|
||||
Beyond the rubric, these signals indicate genuine mastery:
|
||||
- Learner can explain concept in their own words
|
||||
- Learner can give novel examples
|
||||
- Learner can identify errors in incorrect examples
|
||||
- Learner can connect concept to broader context
|
||||
|
||||
## Misconception Handling
|
||||
|
||||
### Why Misconceptions Matter More Than Gaps
|
||||
|
||||
A gap in knowledge ("I don't know X") is easy to fill — just teach X. A misconception ("I know X, but my version of X is wrong") is far harder because the wrong model must be dismantled before the correct one can take hold. Research (Vosniadou 2013, Chi 2005) shows that misconceptions are the #1 barrier to learning in most domains.
|
||||
|
||||
### Types of Misconceptions
|
||||
|
||||
| Type | Example | Why it's sticky |
|
||||
|------|---------|----------------|
|
||||
| **Overgeneralization** | "All functions return values" | Correct in many cases, fails in edge cases |
|
||||
| **False analogy** | "Electricity flows like water" | Useful at first, breaks down at depth |
|
||||
| **Vocabulary confusion** | "Parameter and argument are the same" | Language reinforces the error daily |
|
||||
| **Causal reversal** | "Practice makes talent" (vs talent enables practice) | Correlation mistaken for causation |
|
||||
| **Incomplete model** | "Closures copy variables" (actually capture references) | Partially correct, fails under mutation |
|
||||
|
||||
### The Counter-Example Method
|
||||
|
||||
The most effective way to dislodge a misconception is NOT to say "that's wrong." It's to construct a scenario where the wrong model makes a clear, testable prediction — and then show reality contradicts it.
|
||||
|
||||
Steps:
|
||||
1. **Identify** the wrong model from the learner's answer
|
||||
2. **Construct** a scenario where the wrong model predicts outcome A
|
||||
3. **Ask** the learner to predict the outcome (they'll predict A)
|
||||
4. **Reveal** that the actual outcome is B
|
||||
5. **Ask** the learner to explain the discrepancy
|
||||
6. **Wait** — let the learner wrestle with the contradiction. Do NOT explain immediately.
|
||||
7. **Guide** toward the correct model only after they've engaged with the contradiction
|
||||
|
||||
### Misconception Resolution Criteria
|
||||
|
||||
A misconception is resolved ONLY when BOTH conditions are met:
|
||||
1. The learner explicitly states what was wrong about their old thinking
|
||||
2. The learner correctly handles a new scenario that would have triggered the old misconception
|
||||
|
||||
Getting the right answer once is NOT enough — they must also articulate why the old answer was wrong.
|
||||
|
||||
## Spaced Repetition
|
||||
|
||||
### The Forgetting Curve
|
||||
|
||||
Ebbinghaus (1885) demonstrated that without review, memory decays exponentially:
|
||||
- After 1 hour: ~50% forgotten
|
||||
- After 1 day: ~70% forgotten
|
||||
- After 1 week: ~90% forgotten
|
||||
|
||||
The only way to counteract this is **spaced review** — re-testing at increasing intervals.
|
||||
|
||||
### Interval Schedule
|
||||
|
||||
Sigma uses a simplified SM-2 inspired schedule:
|
||||
|
||||
| Event | Next Review Interval |
|
||||
|-------|---------------------|
|
||||
| Concept first mastered | 1 day |
|
||||
| Review: correct | Double the interval (1d → 2d → 4d → 8d → 16d → 32d) |
|
||||
| Review: incorrect | Reset to 1 day |
|
||||
| Maximum interval | 32 days |
|
||||
|
||||
### Review Question Design
|
||||
|
||||
Review questions should be:
|
||||
- **Brief**: 1 question per concept, not a full mastery check
|
||||
- **Application-level**: Not "what is X?" but "use X to solve this small problem"
|
||||
- **Connected**: Where possible, connect the review concept to the current concept being learned (this also serves as interleaving)
|
||||
|
||||
### Session Review Protocol
|
||||
|
||||
On `--resume`, before continuing new content:
|
||||
1. Identify all mastered concepts where `days_since_review >= review_interval`
|
||||
2. Sort by most overdue first
|
||||
3. Review max 5 concepts per session (don't turn the session into all review)
|
||||
4. Adjust intervals based on results
|
||||
5. If a concept drops back to `in-progress`, address it before continuing forward
|
||||
|
||||
## Deliberate Practice
|
||||
|
||||
### Understanding ≠ Ability
|
||||
|
||||
Ericsson's research on expert performance (1993) established that knowing how something works is fundamentally different from being able to do it. The gap between declarative knowledge ("I can explain decorators") and procedural knowledge ("I can write a decorator") requires practice to bridge.
|
||||
|
||||
### Practice Task Design
|
||||
|
||||
Good practice tasks for Sigma:
|
||||
|
||||
| Property | Good | Bad |
|
||||
|----------|------|-----|
|
||||
| **Size** | 2-5 minutes | 30-minute project |
|
||||
| **Scope** | Tests one concept | Tests everything at once |
|
||||
| **Novelty** | New scenario, same concept | Repeat of a teaching example |
|
||||
| **Output** | Learner produces something | Learner answers more questions |
|
||||
| **Feedback** | Clear right/wrong signal | Ambiguous quality |
|
||||
|
||||
### Practice vs More Questions
|
||||
|
||||
Practice is NOT more Q&A. The key differences:
|
||||
|
||||
| Dimension | Questions (3b) | Practice (3h) |
|
||||
|-----------|----------------|---------------|
|
||||
| Mode | Reactive (answer what's asked) | Generative (produce something new) |
|
||||
| Cognitive load | Recognition + recall | Planning + execution + self-monitoring |
|
||||
| Output | Words | Artifact (code, design, example, explanation) |
|
||||
| Feedback | Immediate from tutor | Self-discovered through doing |
|
||||
|
||||
### The Generation Effect
|
||||
|
||||
Slamecka & Graf (1978) showed that information the learner generates themselves is remembered 2-3x better than information they read. Practice tasks leverage this effect — the learner constructs knowledge through the act of doing.
|
||||
|
||||
## Adaptive Pacing
|
||||
|
||||
| Signal | Action |
|
||||
|--------|--------|
|
||||
| Answers quickly and correctly | Skip to harder questions, consider merging concepts |
|
||||
| Answers correctly but slowly | Proceed normally, give time |
|
||||
| Partially correct | Ask follow-up probing questions before moving on |
|
||||
| Consistently wrong | Break down into sub-concepts, use more concrete examples |
|
||||
| Frustrated | Switch to a visual aid, use analogy, acknowledge difficulty |
|
||||
| Bored | Increase difficulty, introduce real-world application |
|
||||
|
||||
## Visual Aid Selection
|
||||
|
||||
Use the right format for the right purpose:
|
||||
|
||||
| Need | Format | When |
|
||||
|------|--------|------|
|
||||
| Show relationships | Excalidraw concept map | Concepts have dependencies or hierarchy |
|
||||
| Walk through process | HTML step-by-step | Code execution, algorithm steps |
|
||||
| Abstract idea | Generated image (nano-banana-pro) | Metaphors, mental models |
|
||||
| Compare options | HTML table/grid | Feature comparison, trade-offs |
|
||||
| Show flow/logic | Excalidraw flowchart | Decision trees, control flow |
|
||||
| Summarize progress | HTML dashboard | Milestones, session end |
|
||||
|
||||
Don't generate visuals for every round — use them when they genuinely help understanding or when the learner seems stuck.
|
||||
|
|
@ -273,18 +273,6 @@ export const FileEditTool = buildTool({
|
|||
}
|
||||
|
||||
const readTimestamp = toolUseContext.readFileState.get(fullFilePath)
|
||||
if (!readTimestamp || readTimestamp.isPartialView) {
|
||||
return {
|
||||
result: false,
|
||||
behavior: 'ask',
|
||||
message:
|
||||
'File has not been read yet. Read it first before writing to it.',
|
||||
meta: {
|
||||
isFilePathAbsolute: String(isAbsolute(file_path)),
|
||||
},
|
||||
errorCode: 6,
|
||||
}
|
||||
}
|
||||
|
||||
// Check if file exists and get its last modified time
|
||||
if (readTimestamp) {
|
||||
|
|
|
|||
|
|
@ -186,14 +186,6 @@ export function renderToolUseErrorMessage(
|
|||
extractTag(result, 'tool_use_error')
|
||||
) {
|
||||
const errorMessage = extractTag(result, 'tool_use_error')
|
||||
// Show a less scary message for intended behavior
|
||||
if (errorMessage?.includes('File has not been read yet')) {
|
||||
return (
|
||||
<MessageResponse>
|
||||
<Text dimColor>File must be read first</Text>
|
||||
</MessageResponse>
|
||||
)
|
||||
}
|
||||
if (errorMessage?.includes(FILE_NOT_FOUND_CWD_NOTE)) {
|
||||
return (
|
||||
<MessageResponse>
|
||||
|
|
|
|||
|
|
@ -196,25 +196,18 @@ export const FileWriteTool = buildTool({
|
|||
}
|
||||
|
||||
const readTimestamp = toolUseContext.readFileState.get(fullFilePath)
|
||||
if (!readTimestamp || readTimestamp.isPartialView) {
|
||||
return {
|
||||
result: false,
|
||||
message:
|
||||
'File has not been read yet. Read it first before writing to it.',
|
||||
errorCode: 2,
|
||||
}
|
||||
}
|
||||
|
||||
// Reuse mtime from the stat above — avoids a redundant statSync via
|
||||
// getFileModificationTime. The readTimestamp guard above ensures this
|
||||
// block is always reached when the file exists.
|
||||
const lastWriteTime = Math.floor(fileMtimeMs)
|
||||
if (lastWriteTime > readTimestamp.timestamp) {
|
||||
return {
|
||||
result: false,
|
||||
message:
|
||||
'File has been modified since read, either by the user or by a linter. Read it again before attempting to write it.',
|
||||
errorCode: 3,
|
||||
// getFileModificationTime.
|
||||
if (readTimestamp) {
|
||||
const lastWriteTime = Math.floor(fileMtimeMs)
|
||||
if (lastWriteTime > readTimestamp.timestamp) {
|
||||
return {
|
||||
result: false,
|
||||
message:
|
||||
'File has been modified since read, either by the user or by a linter. Read it again before attempting to write it.',
|
||||
errorCode: 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -235,11 +235,6 @@ type State = {
|
|||
// microcompact is first enabled, keep sending the header so mid-session
|
||||
// GrowthBook/settings toggles don't bust the prompt cache.
|
||||
cacheEditingHeaderLatched: boolean | null
|
||||
// Sticky-on latch for clearing thinking from prior tool loops. Triggered
|
||||
// when >1h since last API call (confirmed cache miss — no cache-hit
|
||||
// benefit to keeping thinking). Once latched, stays on so the newly-warmed
|
||||
// thinking-cleared cache isn't busted by flipping back to keep:'all'.
|
||||
thinkingClearLatched: boolean | null
|
||||
// Current prompt ID (UUID) correlating a user prompt with subsequent OTel events
|
||||
promptId: string | null
|
||||
// Last API requestId for the main conversation chain (not subagents).
|
||||
|
|
@ -414,7 +409,6 @@ function getInitialState(): State {
|
|||
afkModeHeaderLatched: null,
|
||||
fastModeHeaderLatched: null,
|
||||
cacheEditingHeaderLatched: null,
|
||||
thinkingClearLatched: null,
|
||||
// Current prompt ID
|
||||
promptId: null,
|
||||
lastMainRequestId: undefined,
|
||||
|
|
@ -1729,14 +1723,6 @@ export function setCacheEditingHeaderLatched(v: boolean): void {
|
|||
STATE.cacheEditingHeaderLatched = v
|
||||
}
|
||||
|
||||
export function getThinkingClearLatched(): boolean | null {
|
||||
return STATE.thinkingClearLatched
|
||||
}
|
||||
|
||||
export function setThinkingClearLatched(v: boolean): void {
|
||||
STATE.thinkingClearLatched = v
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset beta header latches to null. Called on /clear and /compact so a
|
||||
* fresh conversation gets fresh header evaluation.
|
||||
|
|
@ -1745,7 +1731,6 @@ export function clearBetaHeaderLatches(): void {
|
|||
STATE.afkModeHeaderLatched = null
|
||||
STATE.fastModeHeaderLatched = null
|
||||
STATE.cacheEditingHeaderLatched = null
|
||||
STATE.thinkingClearLatched = null
|
||||
}
|
||||
|
||||
export function getPromptId(): string | null {
|
||||
|
|
@ -1755,4 +1740,6 @@ export function getPromptId(): string | null {
|
|||
export function setPromptId(id: string | null): void {
|
||||
STATE.promptId = id
|
||||
}
|
||||
export function isReplBridgeActive(): boolean { return false; }
|
||||
export function isReplBridgeActive(): boolean {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,14 +123,12 @@ import {
|
|||
getPromptCache1hAllowlist,
|
||||
getPromptCache1hEligible,
|
||||
getSessionId,
|
||||
getThinkingClearLatched,
|
||||
setAfkModeHeaderLatched,
|
||||
setCacheEditingHeaderLatched,
|
||||
setFastModeHeaderLatched,
|
||||
setLastMainRequestId,
|
||||
setPromptCache1hAllowlist,
|
||||
setPromptCache1hEligible,
|
||||
setThinkingClearLatched,
|
||||
} from 'src/bootstrap/state.js'
|
||||
import {
|
||||
AFK_MODE_BETA_HEADER,
|
||||
|
|
@ -1521,20 +1519,6 @@ async function* queryModel(
|
|||
}
|
||||
}
|
||||
|
||||
// Only latch from agentic queries so a classifier call doesn't flip the
|
||||
// main thread's context_management mid-turn.
|
||||
let thinkingClearLatched = getThinkingClearLatched() === true
|
||||
if (!thinkingClearLatched && isAgenticQuery) {
|
||||
const lastCompletion = getLastApiCompletionTimestamp()
|
||||
if (
|
||||
lastCompletion !== null &&
|
||||
Date.now() - lastCompletion > CACHE_TTL_1HOUR_MS
|
||||
) {
|
||||
thinkingClearLatched = true
|
||||
setThinkingClearLatched(true)
|
||||
}
|
||||
}
|
||||
|
||||
const effort = resolveAppliedEffort(options.model, options.effortValue)
|
||||
|
||||
if (feature('PROMPT_CACHE_BREAK_DETECTION')) {
|
||||
|
|
@ -1746,7 +1730,7 @@ async function* queryModel(
|
|||
const contextManagement = getAPIContextManagement({
|
||||
hasThinking,
|
||||
isRedactThinkingActive: betasParams.includes(REDACT_THINKING_BETA_HEADER),
|
||||
clearAllThinking: thinkingClearLatched,
|
||||
clearAllThinking: false,
|
||||
})
|
||||
|
||||
// Fast mode: header is latched session-stable (cache-safe), but
|
||||
|
|
|
|||
|
|
@ -81,7 +81,9 @@ describe('isOpenAIThinkingEnabled', () => {
|
|||
})
|
||||
|
||||
test('returns true when model name is namespaced for deepseek-reasoner', () => {
|
||||
expect(isOpenAIThinkingEnabled('TokenService/deepseek-reasoner')).toBe(true)
|
||||
expect(isOpenAIThinkingEnabled('TokenService/deepseek-reasoner')).toBe(
|
||||
true,
|
||||
)
|
||||
})
|
||||
|
||||
test('returns true when model name is "deepseek-v3.2"', () => {
|
||||
|
|
@ -100,16 +102,28 @@ describe('isOpenAIThinkingEnabled', () => {
|
|||
expect(isOpenAIThinkingEnabled('TokenService/deepseek-v3.2')).toBe(true)
|
||||
})
|
||||
|
||||
test('returns false when model name is "deepseek-chat"', () => {
|
||||
expect(isOpenAIThinkingEnabled('deepseek-chat')).toBe(false)
|
||||
test('returns true when model name is "deepseek-chat"', () => {
|
||||
expect(isOpenAIThinkingEnabled('deepseek-chat')).toBe(true)
|
||||
})
|
||||
|
||||
test('returns false when model name is "deepseek-v3"', () => {
|
||||
expect(isOpenAIThinkingEnabled('deepseek-v3')).toBe(false)
|
||||
test('returns true when model name is "deepseek-v3"', () => {
|
||||
expect(isOpenAIThinkingEnabled('deepseek-v3')).toBe(true)
|
||||
})
|
||||
|
||||
test('returns false when model name contains "deepseek" but not "reasoner" or "v3.2"', () => {
|
||||
expect(isOpenAIThinkingEnabled('deepseek-coder')).toBe(false)
|
||||
test('returns true when model name is "deepseek-v4"', () => {
|
||||
expect(isOpenAIThinkingEnabled('deepseek-v4')).toBe(true)
|
||||
})
|
||||
|
||||
test('returns true when model name is "deepseek-v4-pro"', () => {
|
||||
expect(isOpenAIThinkingEnabled('deepseek-v4-pro')).toBe(true)
|
||||
})
|
||||
|
||||
test('returns true when model name is "deepseek-r1"', () => {
|
||||
expect(isOpenAIThinkingEnabled('deepseek-r1')).toBe(true)
|
||||
})
|
||||
|
||||
test('returns true when model name contains "deepseek"', () => {
|
||||
expect(isOpenAIThinkingEnabled('deepseek-coder')).toBe(true)
|
||||
})
|
||||
|
||||
test('returns false when model name is "gpt-4o"', () => {
|
||||
|
|
@ -126,6 +140,7 @@ describe('isOpenAIThinkingEnabled', () => {
|
|||
process.env.OPENAI_ENABLE_THINKING = '1'
|
||||
expect(isOpenAIThinkingEnabled('gpt-4o')).toBe(true)
|
||||
expect(isOpenAIThinkingEnabled('deepseek-v3')).toBe(true)
|
||||
expect(isOpenAIThinkingEnabled('qwen-3')).toBe(true)
|
||||
})
|
||||
|
||||
test('OPENAI_ENABLE_THINKING=false disables thinking even for deepseek-reasoner', () => {
|
||||
|
|
@ -172,14 +187,20 @@ describe('buildOpenAIRequestBody — thinking params', () => {
|
|||
})
|
||||
|
||||
test('does NOT include thinking params when disabled', () => {
|
||||
const body = buildOpenAIRequestBody({ ...baseParams, enableThinking: false })
|
||||
const body = buildOpenAIRequestBody({
|
||||
...baseParams,
|
||||
enableThinking: false,
|
||||
})
|
||||
expect(body.thinking).toBeUndefined()
|
||||
expect(body.enable_thinking).toBeUndefined()
|
||||
expect(body.chat_template_kwargs).toBeUndefined()
|
||||
})
|
||||
|
||||
test('always includes stream and stream_options', () => {
|
||||
const body = buildOpenAIRequestBody({ ...baseParams, enableThinking: false })
|
||||
const body = buildOpenAIRequestBody({
|
||||
...baseParams,
|
||||
enableThinking: false,
|
||||
})
|
||||
expect(body.stream).toBe(true)
|
||||
expect(body.stream_options).toEqual({ include_usage: true })
|
||||
})
|
||||
|
|
@ -203,7 +224,10 @@ describe('buildOpenAIRequestBody — thinking params', () => {
|
|||
})
|
||||
|
||||
test('excludes temperature when thinking is off and no override', () => {
|
||||
const body = buildOpenAIRequestBody({ ...baseParams, enableThinking: false })
|
||||
const body = buildOpenAIRequestBody({
|
||||
...baseParams,
|
||||
enableThinking: false,
|
||||
})
|
||||
expect(body.temperature).toBeUndefined()
|
||||
})
|
||||
|
||||
|
|
@ -219,8 +243,11 @@ describe('buildOpenAIRequestBody — thinking params', () => {
|
|||
})
|
||||
|
||||
test('excludes tools when empty', () => {
|
||||
const body = buildOpenAIRequestBody({ ...baseParams, enableThinking: false })
|
||||
const body = buildOpenAIRequestBody({
|
||||
...baseParams,
|
||||
enableThinking: false,
|
||||
})
|
||||
expect(body.tools).toBeUndefined()
|
||||
expect(body.tool_choice).toBeUndefined()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,22 +1,20 @@
|
|||
// Auto-generated type stub — replace with real implementation
|
||||
export type getSessionId = any;
|
||||
export type getAfkModeHeaderLatched = any;
|
||||
export type getCacheEditingHeaderLatched = any;
|
||||
export type getFastModeHeaderLatched = any;
|
||||
export type getLastApiCompletionTimestamp = any;
|
||||
export type getPromptCache1hAllowlist = any;
|
||||
export type getPromptCache1hEligible = any;
|
||||
export type getThinkingClearLatched = any;
|
||||
export type setAfkModeHeaderLatched = any;
|
||||
export type setCacheEditingHeaderLatched = any;
|
||||
export type setFastModeHeaderLatched = any;
|
||||
export type setLastMainRequestId = any;
|
||||
export type setPromptCache1hAllowlist = any;
|
||||
export type setPromptCache1hEligible = any;
|
||||
export type setThinkingClearLatched = any;
|
||||
export type addToTotalDurationState = any;
|
||||
export type consumePostCompaction = any;
|
||||
export type getIsNonInteractiveSession = any;
|
||||
export type getTeleportedSessionInfo = any;
|
||||
export type markFirstTeleportMessageLogged = any;
|
||||
export type setLastApiCompletionTimestamp = any;
|
||||
export type getSessionId = any
|
||||
export type getAfkModeHeaderLatched = any
|
||||
export type getCacheEditingHeaderLatched = any
|
||||
export type getFastModeHeaderLatched = any
|
||||
export type getLastApiCompletionTimestamp = any
|
||||
export type getPromptCache1hAllowlist = any
|
||||
export type getPromptCache1hEligible = any
|
||||
export type setAfkModeHeaderLatched = any
|
||||
export type setCacheEditingHeaderLatched = any
|
||||
export type setFastModeHeaderLatched = any
|
||||
export type setLastMainRequestId = any
|
||||
export type setPromptCache1hAllowlist = any
|
||||
export type setPromptCache1hEligible = any
|
||||
export type addToTotalDurationState = any
|
||||
export type consumePostCompaction = any
|
||||
export type getIsNonInteractiveSession = any
|
||||
export type getTeleportedSessionInfo = any
|
||||
export type markFirstTeleportMessageLogged = any
|
||||
export type setLastApiCompletionTimestamp = any
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user