@gonzih/debate-coach 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +250 -0
- package/SKILL.md +91 -0
- package/dist/claude.d.ts +26 -0
- package/dist/claude.d.ts.map +1 -0
- package/dist/claude.js +285 -0
- package/dist/claude.js.map +1 -0
- package/dist/database.d.ts +19 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +157 -0
- package/dist/database.js.map +1 -0
- package/dist/fallacies.d.ts +11 -0
- package/dist/fallacies.d.ts.map +1 -0
- package/dist/fallacies.js +207 -0
- package/dist/fallacies.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +571 -0
- package/dist/index.js.map +1 -0
- package/dist/session.d.ts +22 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +104 -0
- package/dist/session.js.map +1 -0
- package/dist/topics.d.ts +8 -0
- package/dist/topics.d.ts.map +1 -0
- package/dist/topics.js +463 -0
- package/dist/topics.js.map +1 -0
- package/dist/types.d.ts +83 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/llms.txt +104 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Maksim Soltan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# debate-coach
|
|
2
|
+
|
|
3
|
+
> An MCP server that trains critical thinking by making students argue both sides of any topic, catching logical fallacies in real time, scoring argument quality, and teaching the difference between an opinion and a reasoned position.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@gonzih/debate-coach)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## The Dream
|
|
11
|
+
|
|
12
|
+
A 16-year-old says *"I think social media should be banned for under 18s."*
|
|
13
|
+
|
|
14
|
+
Instead of agreeing or disagreeing, the AI says: *"Interesting. Make your case — give me your 3 strongest arguments."*
|
|
15
|
+
|
|
16
|
+
The student argues. The AI rates each argument:
|
|
17
|
+
- *"Argument 1: solid (evidence-based)."*
|
|
18
|
+
- *"Argument 2: weak (anecdotal, logical fallacy: hasty generalization)."*
|
|
19
|
+
- *"Argument 3: strong."*
|
|
20
|
+
|
|
21
|
+
Then: *"Now flip sides. Argue against your own position as convincingly as you can."*
|
|
22
|
+
|
|
23
|
+
This is how lawyers are trained. This is how scientists think. This is how good citizens reason.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## What It Does
|
|
28
|
+
|
|
29
|
+
### 1. Argument Quality Scoring (0–10 per argument)
|
|
30
|
+
Each argument is scored on four dimensions:
|
|
31
|
+
- **Evidence (0–3):** Factual backing — studies, data, expert consensus
|
|
32
|
+
- **Logic (0–3):** Soundness — no fallacies, valid reasoning
|
|
33
|
+
- **Relevance (0–2):** Does it actually support the proposition?
|
|
34
|
+
- **Originality (0–2):** Nuanced insight vs. generic platitude
|
|
35
|
+
|
|
36
|
+
### 2. Real-Time Logical Fallacy Detection
|
|
37
|
+
Detects 20 logical fallacies including:
|
|
38
|
+
- Ad hominem, straw man, false dichotomy
|
|
39
|
+
- Slippery slope, hasty generalization, appeal to authority
|
|
40
|
+
- Post hoc (correlation ≠ causation), cherry picking, and 12 more
|
|
41
|
+
|
|
42
|
+
### 3. Steel-Manning
|
|
43
|
+
After you argue your side, the AI presents the *strongest possible opposing argument* — not a strawman. This prepares you for the flip challenge and teaches genuine intellectual honesty.
|
|
44
|
+
|
|
45
|
+
### 4. Mandatory Flip-Sides Exercise
|
|
46
|
+
You must argue the *opposite* of your original position. This is the hardest and most valuable part. It teaches:
|
|
47
|
+
- Epistemic humility
|
|
48
|
+
- Understanding of opposing views
|
|
49
|
+
- How to construct genuinely compelling arguments you disagree with
|
|
50
|
+
|
|
51
|
+
### 5. 50+ Curated Debate Topics
|
|
52
|
+
Categories: Social/Ethical, Science/Environment, Politics/Policy, Philosophy/Values, Technology, Historical, Economics, Health
|
|
53
|
+
|
|
54
|
+
### 6. Progress Tracking
|
|
55
|
+
- Fallacy rate over time: *"You used hasty generalization 8 times 3 weeks ago, 2 times this week"*
|
|
56
|
+
- Average argument score trend
|
|
57
|
+
- Topics breadth
|
|
58
|
+
- Flip success rate
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Installation
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm install -g @gonzih/debate-coach
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Or use with `npx`:
|
|
69
|
+
```bash
|
|
70
|
+
npx @gonzih/debate-coach
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## MCP Configuration
|
|
76
|
+
|
|
77
|
+
Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"mcpServers": {
|
|
82
|
+
"debate-coach": {
|
|
83
|
+
"command": "npx",
|
|
84
|
+
"args": ["@gonzih/debate-coach"]
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Or if installed globally:
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"mcpServers": {
|
|
94
|
+
"debate-coach": {
|
|
95
|
+
"command": "debate-coach"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## MCP Tools
|
|
104
|
+
|
|
105
|
+
### `start_debate`
|
|
106
|
+
```
|
|
107
|
+
start_debate({ profileId, topic?, position? })
|
|
108
|
+
→ { proposition, sessionId, instructions }
|
|
109
|
+
```
|
|
110
|
+
Start a new debate session. The AI frames your topic as a proper debate proposition.
|
|
111
|
+
|
|
112
|
+
### `submit_argument`
|
|
113
|
+
```
|
|
114
|
+
submit_argument({ sessionId, argument })
|
|
115
|
+
→ { score, fallacies[], feedback, strengtheningSuggestion }
|
|
116
|
+
```
|
|
117
|
+
Submit an argument. Get scored on evidence/logic/relevance/originality and fallacy-checked.
|
|
118
|
+
|
|
119
|
+
### `get_steelman`
|
|
120
|
+
```
|
|
121
|
+
get_steelman({ sessionId })
|
|
122
|
+
→ { steelman, keyCounterArguments[] }
|
|
123
|
+
```
|
|
124
|
+
After 3+ PRO arguments: see the strongest possible case against your position.
|
|
125
|
+
|
|
126
|
+
### `flip_sides`
|
|
127
|
+
```
|
|
128
|
+
flip_sides({ sessionId })
|
|
129
|
+
→ { prompt, newPosition }
|
|
130
|
+
```
|
|
131
|
+
Switch to arguing the opposite side.
|
|
132
|
+
|
|
133
|
+
### `complete_debate`
|
|
134
|
+
```
|
|
135
|
+
complete_debate({ sessionId })
|
|
136
|
+
→ { synthesis, scores, fallaciesDetected }
|
|
137
|
+
```
|
|
138
|
+
Finalize the debate and receive a synthesis of both sides.
|
|
139
|
+
|
|
140
|
+
### `build_argument`
|
|
141
|
+
```
|
|
142
|
+
build_argument({ sessionId, thought })
|
|
143
|
+
→ { questions[], hint }
|
|
144
|
+
```
|
|
145
|
+
Argument Builder Mode: Socratic scaffolding for students who don't know where to start.
|
|
146
|
+
|
|
147
|
+
### `get_topic_list`
|
|
148
|
+
```
|
|
149
|
+
get_topic_list({ category?, ageGroup?, difficulty? })
|
|
150
|
+
→ Topic[]
|
|
151
|
+
```
|
|
152
|
+
Browse 50+ curated debate topics.
|
|
153
|
+
|
|
154
|
+
### `get_progress`
|
|
155
|
+
```
|
|
156
|
+
get_progress({ profileId })
|
|
157
|
+
→ { debatesCompleted, avgScore, fallacyTrend, improvementAreas, ... }
|
|
158
|
+
```
|
|
159
|
+
View progress over time.
|
|
160
|
+
|
|
161
|
+
### `get_fallacy_guide`
|
|
162
|
+
```
|
|
163
|
+
get_fallacy_guide({ fallacyType? })
|
|
164
|
+
→ Fallacy guide or specific fallacy detail
|
|
165
|
+
```
|
|
166
|
+
Learn about the 20 logical fallacies the system detects.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Debate Flow
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
start_debate
|
|
174
|
+
↓
|
|
175
|
+
submit_argument ×3-5 (PRO phase)
|
|
176
|
+
↓
|
|
177
|
+
get_steelman (see opposing case)
|
|
178
|
+
↓
|
|
179
|
+
flip_sides (switch positions)
|
|
180
|
+
↓
|
|
181
|
+
submit_argument ×3-5 (CON phase)
|
|
182
|
+
↓
|
|
183
|
+
complete_debate (synthesis + scoring)
|
|
184
|
+
↓
|
|
185
|
+
get_progress (track improvement)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## The Socratic Method Connection
|
|
191
|
+
|
|
192
|
+
Socrates never stated opinions — he asked questions until his interlocutors discovered contradictions in their own positions. The *elenchus* (cross-examination) was designed not to teach facts but to develop the capacity for rigorous thinking.
|
|
193
|
+
|
|
194
|
+
debate-coach uses the same approach: it doesn't tell you what to think, it forces you to *defend* what you think — and then defend the opposite.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Debate Formats Supported Conceptually
|
|
199
|
+
|
|
200
|
+
### Lincoln-Douglas (LD) Debate
|
|
201
|
+
One-on-one. Values-focused. Emphasizes philosophical and ethical clash. Perfect for the philosophical and policy topics in the topic list.
|
|
202
|
+
|
|
203
|
+
**Structure adapted here:** PRO arguments → Steel-man → CON arguments → Synthesis
|
|
204
|
+
|
|
205
|
+
### Oxford-Style Debate
|
|
206
|
+
Motion-based. Audience votes before and after. The Oxford format's key insight: you must be able to articulate *why* the other side is reasonable before you can effectively argue against it. This is exactly what the steel-man step provides.
|
|
207
|
+
|
|
208
|
+
### Karl Popper Format
|
|
209
|
+
Teams of three argue competing positions. Focus on cross-examination. The Karl Popper format explicitly teaches students to attack *the strongest version* of the opposition — which is the steel-manning principle.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Classroom Integration Guide
|
|
214
|
+
|
|
215
|
+
### Individual Practice
|
|
216
|
+
Students use debate-coach independently to prepare for class discussions. The progress tracking helps teachers see who is improving.
|
|
217
|
+
|
|
218
|
+
### Paired Debate Prep
|
|
219
|
+
Two students start debates on the same topic but opposite sides. They compare their steel-mans — seeing how well each predicted the other's actual arguments.
|
|
220
|
+
|
|
221
|
+
### Flipped Classroom
|
|
222
|
+
Assign debate-coach sessions as homework. Class time is spent discussing: *"What surprised you when you had to argue the other side?"*
|
|
223
|
+
|
|
224
|
+
### Formative Assessment
|
|
225
|
+
Use `get_progress` to track:
|
|
226
|
+
- Which fallacies students commit most
|
|
227
|
+
- Score improvement over the term
|
|
228
|
+
- Whether students attempt the flip challenge
|
|
229
|
+
|
|
230
|
+
### Discussion Starter
|
|
231
|
+
After completing a debate session, share the synthesis in class. Use it as a jumping-off point: *"The AI says the core tension here is X vs. Y — do you agree?"*
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Progress Data Storage
|
|
236
|
+
|
|
237
|
+
Debate history is stored locally in `~/.debate-coach/debates.db` (SQLite). No data is sent to any server. API calls are made only to Anthropic's Claude API for AI-powered scoring and analysis.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Requirements
|
|
242
|
+
|
|
243
|
+
- Node.js 18+
|
|
244
|
+
- `ANTHROPIC_API_KEY` environment variable
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## License
|
|
249
|
+
|
|
250
|
+
MIT © Gonzih
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# debate-coach Skill Guide
|
|
2
|
+
|
|
3
|
+
## What Is This?
|
|
4
|
+
debate-coach is an MCP server that trains critical thinking through structured debate. It implements the Socratic method digitally: instead of telling you what to think, it forces you to defend what you think — and then defend the opposite.
|
|
5
|
+
|
|
6
|
+
## Quick Start
|
|
7
|
+
|
|
8
|
+
### 1. Start a Debate
|
|
9
|
+
```
|
|
10
|
+
Use the start_debate tool with:
|
|
11
|
+
- profileId: "student_alice"
|
|
12
|
+
- topic: "Social media should be banned for users under 18"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### 2. Submit Arguments (PRO side first)
|
|
16
|
+
```
|
|
17
|
+
Use submit_argument with your sessionId and each argument.
|
|
18
|
+
Example: "Multiple peer-reviewed studies, including the Haidt/Twenge research,
|
|
19
|
+
show strong correlations between heavy social media use and increased rates of
|
|
20
|
+
anxiety and depression in adolescent girls."
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 3. Get the Steel-Man
|
|
24
|
+
```
|
|
25
|
+
After 3+ arguments, call get_steelman to see the strongest opposing case.
|
|
26
|
+
This is essential preparation for the flip challenge.
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 4. Flip Sides
|
|
30
|
+
```
|
|
31
|
+
Call flip_sides to switch to arguing AGAINST your original position.
|
|
32
|
+
This is the hardest and most valuable part.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 5. Submit CON Arguments
|
|
36
|
+
```
|
|
37
|
+
Submit 3-5 arguments against the proposition using submit_argument.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 6. Complete & Synthesize
|
|
41
|
+
```
|
|
42
|
+
Call complete_debate to receive your final synthesis and save progress.
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Argument Builder Mode (For Beginners)
|
|
46
|
+
If you don't know where to start:
|
|
47
|
+
```
|
|
48
|
+
Call build_argument with:
|
|
49
|
+
- sessionId: your session ID
|
|
50
|
+
- thought: "I think social media is bad but I don't know why exactly"
|
|
51
|
+
```
|
|
52
|
+
You'll receive Socratic questions to develop your rough thought into a strong argument.
|
|
53
|
+
|
|
54
|
+
## Browse Topics
|
|
55
|
+
```
|
|
56
|
+
Call get_topic_list to browse 50+ curated topics.
|
|
57
|
+
Filter by category: social, science, policy, philosophy, technology, historical, economics, health
|
|
58
|
+
Filter by difficulty: easy, medium, hard
|
|
59
|
+
Filter by ageGroup: teens, general
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Track Progress
|
|
63
|
+
```
|
|
64
|
+
Call get_progress with your profileId to see:
|
|
65
|
+
- Score improvement over time
|
|
66
|
+
- Which logical fallacies you commit most
|
|
67
|
+
- Flip success rate
|
|
68
|
+
- Topics debated
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## What Makes a Good Argument?
|
|
72
|
+
A strong argument (7+/10) has:
|
|
73
|
+
- **Specific evidence**: Not just "studies show" but "the 2019 Twenge et al. meta-analysis of..."
|
|
74
|
+
- **Logical structure**: Premise → Reasoning → Conclusion with no gaps
|
|
75
|
+
- **Relevance**: Directly addresses the proposition, not a tangent
|
|
76
|
+
- **Nuance**: Goes beyond the obvious — acknowledge complexity
|
|
77
|
+
|
|
78
|
+
## Common Mistakes to Avoid
|
|
79
|
+
1. **Anecdotal evidence**: "My cousin tried X and it worked" — use systematic data
|
|
80
|
+
2. **Hasty generalization**: "Three examples prove all cases" — be careful with scale
|
|
81
|
+
3. **False dichotomy**: "Either we do X or catastrophe" — more options usually exist
|
|
82
|
+
4. **Post hoc**: "A happened, then B happened, so A caused B" — correlation ≠ causation
|
|
83
|
+
5. **Appeal to emotion**: Emotional language without supporting logic
|
|
84
|
+
|
|
85
|
+
## Learning Outcomes
|
|
86
|
+
After regular use of debate-coach, students develop:
|
|
87
|
+
- Ability to construct evidence-based arguments
|
|
88
|
+
- Recognition of logical fallacies in real-world discourse (news, politics, advertising)
|
|
89
|
+
- Intellectual empathy — understanding why reasonable people disagree
|
|
90
|
+
- Comfort arguing positions they personally disagree with
|
|
91
|
+
- Awareness of their own cognitive biases
|
package/dist/claude.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ScoredArgument, DebateSession } from "./types.js";
|
|
2
|
+
export declare function refineProposition(rawTopic: string): Promise<{
|
|
3
|
+
proposition: string;
|
|
4
|
+
explanation: string;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function scoreArgument(params: {
|
|
7
|
+
proposition: string;
|
|
8
|
+
position: string;
|
|
9
|
+
argument: string;
|
|
10
|
+
previousArguments: string[];
|
|
11
|
+
}): Promise<ScoredArgument>;
|
|
12
|
+
export declare function generateSteelman(session: DebateSession): Promise<{
|
|
13
|
+
steelman: string;
|
|
14
|
+
keyCounterArguments: string[];
|
|
15
|
+
}>;
|
|
16
|
+
export declare function generateSynthesis(session: DebateSession): Promise<string>;
|
|
17
|
+
export declare function scaffoldArgument(params: {
|
|
18
|
+
proposition: string;
|
|
19
|
+
position: string;
|
|
20
|
+
userThought: string;
|
|
21
|
+
}): Promise<{
|
|
22
|
+
questions: string[];
|
|
23
|
+
hint: string;
|
|
24
|
+
}>;
|
|
25
|
+
export declare function formatScoredArgument(arg: ScoredArgument): string;
|
|
26
|
+
//# sourceMappingURL=claude.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,cAAc,EACd,aAAa,EACd,MAAM,YAAY,CAAC;AAOpB,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACjE,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC,CA+BD;AAID,wBAAsB,aAAa,CAAC,MAAM,EAAE;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B,GAAG,OAAO,CAAC,cAAc,CAAC,CAyF1B;AAID,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,EAAE,CAAC;CAC/B,CAAC,CAoDD;AAID,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA8D/E;AAID,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC;IACV,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC,CAkCD;AAID,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAkChE"}
|
package/dist/claude.js
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
+
import { FALLACY_NAMES_FOR_PROMPT } from "./fallacies.js";
|
|
3
|
+
const client = new Anthropic();
|
|
4
|
+
const MODEL = "claude-opus-4-6";
|
|
5
|
+
// ─── Proposition Refinement ────────────────────────────────────────────────
|
|
6
|
+
export async function refineProposition(rawTopic) {
|
|
7
|
+
const response = await client.messages.create({
|
|
8
|
+
model: MODEL,
|
|
9
|
+
max_tokens: 1024,
|
|
10
|
+
messages: [
|
|
11
|
+
{
|
|
12
|
+
role: "user",
|
|
13
|
+
content: `You are a debate coach helping a student frame a debate topic as a proper proposition.
|
|
14
|
+
|
|
15
|
+
The student's topic: "${rawTopic}"
|
|
16
|
+
|
|
17
|
+
A good debate proposition:
|
|
18
|
+
- Is a clear, specific statement (not a question)
|
|
19
|
+
- Can be argued FOR or AGAINST
|
|
20
|
+
- Is falsifiable and not purely subjective
|
|
21
|
+
- Is stated in present tense: "X should/is/does..."
|
|
22
|
+
|
|
23
|
+
Respond with a JSON object only:
|
|
24
|
+
{
|
|
25
|
+
"proposition": "The refined, properly-stated proposition",
|
|
26
|
+
"explanation": "Brief explanation of why this framing works well for debate (1-2 sentences)"
|
|
27
|
+
}`,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
});
|
|
31
|
+
const text = response.content.find(b => b.type === "text")?.text ?? "{}";
|
|
32
|
+
const jsonMatch = text.match(/\{[\s\S]*\}/);
|
|
33
|
+
if (!jsonMatch)
|
|
34
|
+
throw new Error("Failed to parse proposition from Claude");
|
|
35
|
+
return JSON.parse(jsonMatch[0]);
|
|
36
|
+
}
|
|
37
|
+
// ─── Argument Scoring ──────────────────────────────────────────────────────
|
|
38
|
+
export async function scoreArgument(params) {
|
|
39
|
+
const previousContext = params.previousArguments.length > 0
|
|
40
|
+
? `\nPrevious arguments made:\n${params.previousArguments.map((a, i) => `${i + 1}. ${a}`).join("\n")}`
|
|
41
|
+
: "";
|
|
42
|
+
const response = await client.messages.create({
|
|
43
|
+
model: MODEL,
|
|
44
|
+
max_tokens: 2048,
|
|
45
|
+
messages: [
|
|
46
|
+
{
|
|
47
|
+
role: "user",
|
|
48
|
+
content: `You are an expert debate coach and logician. Analyze this argument rigorously.
|
|
49
|
+
|
|
50
|
+
PROPOSITION: "${params.proposition}"
|
|
51
|
+
POSITION BEING ARGUED: ${params.position}
|
|
52
|
+
${previousContext}
|
|
53
|
+
|
|
54
|
+
NEW ARGUMENT TO ANALYZE:
|
|
55
|
+
"${params.argument}"
|
|
56
|
+
|
|
57
|
+
Score the argument on these criteria:
|
|
58
|
+
- Evidence (0-3): Does it include factual backing? Studies, data, specific examples, expert consensus?
|
|
59
|
+
0 = pure opinion, 1 = vague reference, 2 = reasonable claim with some support, 3 = strong empirical backing
|
|
60
|
+
- Logic (0-3): Is the reasoning sound? No fallacies? Does the conclusion follow from premises?
|
|
61
|
+
0 = deeply flawed, 1 = some logical problems, 2 = mostly sound, 3 = rigorous and valid
|
|
62
|
+
- Relevance (0-2): Does it actually address and support the specific proposition?
|
|
63
|
+
0 = tangential, 1 = partially relevant, 2 = directly on-point
|
|
64
|
+
- Originality (0-2): Is this a nuanced/specific point or a generic/obvious one?
|
|
65
|
+
0 = very common/generic, 1 = somewhat specific, 2 = genuinely nuanced insight
|
|
66
|
+
|
|
67
|
+
Detect ALL logical fallacies present (from this list):
|
|
68
|
+
${FALLACY_NAMES_FOR_PROMPT}
|
|
69
|
+
|
|
70
|
+
Respond with a JSON object ONLY (no other text):
|
|
71
|
+
{
|
|
72
|
+
"scores": {
|
|
73
|
+
"evidence": <0-3>,
|
|
74
|
+
"logic": <0-3>,
|
|
75
|
+
"relevance": <0-2>,
|
|
76
|
+
"originality": <0-2>
|
|
77
|
+
},
|
|
78
|
+
"fallacies": [
|
|
79
|
+
{
|
|
80
|
+
"type": "<fallacy_type_key>",
|
|
81
|
+
"name": "<Human readable name>",
|
|
82
|
+
"description": "<what this fallacy is>",
|
|
83
|
+
"explanation": "<exactly how it appears in this specific argument>",
|
|
84
|
+
"quote": "<the specific phrase in the argument that contains the fallacy>"
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
"feedback": "<2-3 sentence evaluation: what's strong, what's weak, how it relates to the proposition>",
|
|
88
|
+
"strengtheningSuggestion": "<specific, actionable suggestion to make this argument stronger>"
|
|
89
|
+
}`,
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
});
|
|
93
|
+
const text = response.content.find(b => b.type === "text")?.text ?? "{}";
|
|
94
|
+
const jsonMatch = text.match(/\{[\s\S]*\}/);
|
|
95
|
+
if (!jsonMatch)
|
|
96
|
+
throw new Error("Failed to parse argument score from Claude");
|
|
97
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
98
|
+
const score = {
|
|
99
|
+
evidence: Math.min(3, Math.max(0, parsed.scores.evidence)),
|
|
100
|
+
logic: Math.min(3, Math.max(0, parsed.scores.logic)),
|
|
101
|
+
relevance: Math.min(2, Math.max(0, parsed.scores.relevance)),
|
|
102
|
+
originality: Math.min(2, Math.max(0, parsed.scores.originality)),
|
|
103
|
+
total: Math.min(3, Math.max(0, parsed.scores.evidence)) +
|
|
104
|
+
Math.min(3, Math.max(0, parsed.scores.logic)) +
|
|
105
|
+
Math.min(2, Math.max(0, parsed.scores.relevance)) +
|
|
106
|
+
Math.min(2, Math.max(0, parsed.scores.originality)),
|
|
107
|
+
};
|
|
108
|
+
return {
|
|
109
|
+
text: params.argument,
|
|
110
|
+
score,
|
|
111
|
+
fallacies: parsed.fallacies || [],
|
|
112
|
+
feedback: parsed.feedback || "",
|
|
113
|
+
strengtheningSuggestion: parsed.strengtheningSuggestion || "",
|
|
114
|
+
timestamp: new Date().toISOString(),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// ─── Steel-Man Generation ──────────────────────────────────────────────────
|
|
118
|
+
export async function generateSteelman(session) {
|
|
119
|
+
const proArgsSummary = session.proArguments
|
|
120
|
+
.map((a, i) => `${i + 1}. "${a.text}" (Score: ${a.score.total}/10)`)
|
|
121
|
+
.join("\n");
|
|
122
|
+
const response = await client.messages.create({
|
|
123
|
+
model: MODEL,
|
|
124
|
+
max_tokens: 3000,
|
|
125
|
+
messages: [
|
|
126
|
+
{
|
|
127
|
+
role: "user",
|
|
128
|
+
content: `You are a master debater and philosopher. A student has just argued FOR the following proposition.
|
|
129
|
+
|
|
130
|
+
PROPOSITION: "${session.proposition}"
|
|
131
|
+
|
|
132
|
+
THE STUDENT'S ARGUMENTS (arguing FOR):
|
|
133
|
+
${proArgsSummary}
|
|
134
|
+
|
|
135
|
+
Your task: Present the STRONGEST POSSIBLE CASE AGAINST this proposition.
|
|
136
|
+
This is steel-manning — you must construct the best version of the opposing argument,
|
|
137
|
+
not a straw man. Think like the best lawyer for the opposing side.
|
|
138
|
+
|
|
139
|
+
Rules:
|
|
140
|
+
- Engage with the actual strongest version of the opposing position
|
|
141
|
+
- Use real evidence, studies, and expert perspectives where possible
|
|
142
|
+
- Acknowledge any valid points in the student's arguments while showing their limits
|
|
143
|
+
- Be intellectually honest — this should be a genuinely challenging counter-case
|
|
144
|
+
- This will help the student understand what they're really up against
|
|
145
|
+
|
|
146
|
+
Respond with a JSON object ONLY:
|
|
147
|
+
{
|
|
148
|
+
"steelman": "<A compelling, well-reasoned paragraph (150-250 words) presenting the strongest case AGAINST the proposition. Write in first person as if you are arguing this side.>",
|
|
149
|
+
"keyCounterArguments": [
|
|
150
|
+
"<Counter-argument 1: specific, evidence-backed, most powerful>",
|
|
151
|
+
"<Counter-argument 2: addresses a weakness in the student's arguments>",
|
|
152
|
+
"<Counter-argument 3: presents a genuine trade-off or unintended consequence>",
|
|
153
|
+
"<Counter-argument 4: philosophical or values-based counter>",
|
|
154
|
+
"<Counter-argument 5: empirical/practical counter>"
|
|
155
|
+
]
|
|
156
|
+
}`,
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
});
|
|
160
|
+
const text = response.content.find(b => b.type === "text")?.text ?? "{}";
|
|
161
|
+
const jsonMatch = text.match(/\{[\s\S]*\}/);
|
|
162
|
+
if (!jsonMatch)
|
|
163
|
+
throw new Error("Failed to parse steelman from Claude");
|
|
164
|
+
return JSON.parse(jsonMatch[0]);
|
|
165
|
+
}
|
|
166
|
+
// ─── Debate Synthesis ──────────────────────────────────────────────────────
|
|
167
|
+
export async function generateSynthesis(session) {
|
|
168
|
+
const proArgsSummary = session.proArguments
|
|
169
|
+
.map((a, i) => ` ${i + 1}. "${a.text.substring(0, 100)}..." — Score: ${a.score.total}/10, Fallacies: ${a.fallacies.length}`)
|
|
170
|
+
.join("\n");
|
|
171
|
+
const conArgsSummary = session.conArguments
|
|
172
|
+
.map((a, i) => ` ${i + 1}. "${a.text.substring(0, 100)}..." — Score: ${a.score.total}/10, Fallacies: ${a.fallacies.length}`)
|
|
173
|
+
.join("\n");
|
|
174
|
+
const proAvg = session.proArguments.length > 0
|
|
175
|
+
? (session.proArguments.reduce((s, a) => s + a.score.total, 0) /
|
|
176
|
+
session.proArguments.length).toFixed(1)
|
|
177
|
+
: "N/A";
|
|
178
|
+
const conAvg = session.conArguments.length > 0
|
|
179
|
+
? (session.conArguments.reduce((s, a) => s + a.score.total, 0) /
|
|
180
|
+
session.conArguments.length).toFixed(1)
|
|
181
|
+
: "N/A";
|
|
182
|
+
const response = await client.messages.create({
|
|
183
|
+
model: MODEL,
|
|
184
|
+
max_tokens: 2000,
|
|
185
|
+
messages: [
|
|
186
|
+
{
|
|
187
|
+
role: "user",
|
|
188
|
+
content: `You are a master debate coach providing a final synthesis after a student has argued BOTH sides of a proposition.
|
|
189
|
+
|
|
190
|
+
PROPOSITION: "${session.proposition}"
|
|
191
|
+
|
|
192
|
+
ARGUMENTS FOR (avg score: ${proAvg}/10):
|
|
193
|
+
${proArgsSummary}
|
|
194
|
+
|
|
195
|
+
ARGUMENTS AGAINST (avg score: ${conAvg}/10):
|
|
196
|
+
${conArgsSummary}
|
|
197
|
+
|
|
198
|
+
Write a final synthesis (200-300 words) that:
|
|
199
|
+
1. Acknowledges what the student did well on BOTH sides
|
|
200
|
+
2. Identifies the strongest arguments that emerged from the full debate
|
|
201
|
+
3. Explains what "the strongest version of this debate" looks like — what would a professional debater argue on each side?
|
|
202
|
+
4. Names the key tension or core value clash at the heart of this debate
|
|
203
|
+
5. Leaves the student with a philosophical insight about why these debates matter
|
|
204
|
+
|
|
205
|
+
Be encouraging but honest. This synthesis should make the student feel they've grown intellectually.
|
|
206
|
+
|
|
207
|
+
Write as flowing prose, no bullet points, no JSON — just a thoughtful paragraph.`,
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
});
|
|
211
|
+
return response.content.find(b => b.type === "text")?.text ?? "Debate completed.";
|
|
212
|
+
}
|
|
213
|
+
// ─── Argument Builder Scaffold ─────────────────────────────────────────────
|
|
214
|
+
export async function scaffoldArgument(params) {
|
|
215
|
+
const response = await client.messages.create({
|
|
216
|
+
model: MODEL,
|
|
217
|
+
max_tokens: 1024,
|
|
218
|
+
messages: [
|
|
219
|
+
{
|
|
220
|
+
role: "user",
|
|
221
|
+
content: `You are a Socratic debate coach. A student wants to argue ${params.position} on this proposition:
|
|
222
|
+
|
|
223
|
+
"${params.proposition}"
|
|
224
|
+
|
|
225
|
+
The student says: "${params.userThought}"
|
|
226
|
+
|
|
227
|
+
Guide them to build a stronger argument using the Socratic method.
|
|
228
|
+
|
|
229
|
+
Respond with JSON ONLY:
|
|
230
|
+
{
|
|
231
|
+
"questions": [
|
|
232
|
+
"<Question 1: ask them to clarify or deepen their belief>",
|
|
233
|
+
"<Question 2: ask for evidence or examples>",
|
|
234
|
+
"<Question 3: ask how they'd respond to the strongest counter-argument>",
|
|
235
|
+
"<Question 4: ask about trade-offs or unintended consequences>"
|
|
236
|
+
],
|
|
237
|
+
"hint": "<1-sentence suggestion for how to turn their thought into a strong argument>"
|
|
238
|
+
}`,
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
});
|
|
242
|
+
const text = response.content.find(b => b.type === "text")?.text ?? "{}";
|
|
243
|
+
const jsonMatch = text.match(/\{[\s\S]*\}/);
|
|
244
|
+
if (!jsonMatch)
|
|
245
|
+
throw new Error("Failed to parse scaffold from Claude");
|
|
246
|
+
return JSON.parse(jsonMatch[0]);
|
|
247
|
+
}
|
|
248
|
+
// ─── Format Scoring Output ─────────────────────────────────────────────────
|
|
249
|
+
export function formatScoredArgument(arg) {
|
|
250
|
+
const scoreEmoji = (score, max) => {
|
|
251
|
+
const pct = score / max;
|
|
252
|
+
if (pct >= 0.8)
|
|
253
|
+
return "✅";
|
|
254
|
+
if (pct >= 0.5)
|
|
255
|
+
return "⚠️";
|
|
256
|
+
return "❌";
|
|
257
|
+
};
|
|
258
|
+
const lines = [
|
|
259
|
+
`**Score: ${arg.score.total}/10**`,
|
|
260
|
+
"",
|
|
261
|
+
`${scoreEmoji(arg.score.evidence, 3)} **Evidence (${arg.score.evidence}/3):** ${arg.score.evidence === 3 ? "Strong factual backing" : arg.score.evidence === 2 ? "Reasonable support" : arg.score.evidence === 1 ? "Vague, needs specifics" : "No evidence — pure opinion"}`,
|
|
262
|
+
`${scoreEmoji(arg.score.logic, 3)} **Logic (${arg.score.logic}/3):** ${arg.score.logic === 3 ? "Sound and valid reasoning" : arg.score.logic === 2 ? "Mostly sound reasoning" : arg.score.logic === 1 ? "Some logical problems" : "Flawed reasoning"}`,
|
|
263
|
+
`${scoreEmoji(arg.score.relevance, 2)} **Relevance (${arg.score.relevance}/2):** ${arg.score.relevance === 2 ? "Directly supports the proposition" : arg.score.relevance === 1 ? "Partially relevant" : "Off-topic"}`,
|
|
264
|
+
`${scoreEmoji(arg.score.originality, 2)} **Originality (${arg.score.originality}/2):** ${arg.score.originality === 2 ? "Nuanced insight" : arg.score.originality === 1 ? "Somewhat specific" : "Common/generic point"}`,
|
|
265
|
+
"",
|
|
266
|
+
`**Feedback:** ${arg.feedback}`,
|
|
267
|
+
"",
|
|
268
|
+
`💡 **Could strengthen:** ${arg.strengtheningSuggestion}`,
|
|
269
|
+
];
|
|
270
|
+
if (arg.fallacies.length > 0) {
|
|
271
|
+
lines.push("");
|
|
272
|
+
lines.push(`**⚠️ Logical fallacies detected (${arg.fallacies.length}):**`);
|
|
273
|
+
for (const fallacy of arg.fallacies) {
|
|
274
|
+
lines.push(`- **${fallacy.name}**: ${fallacy.explanation}`);
|
|
275
|
+
if (fallacy.quote)
|
|
276
|
+
lines.push(` *"${fallacy.quote}"*`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
lines.push("");
|
|
281
|
+
lines.push("**✅ No logical fallacies detected**");
|
|
282
|
+
}
|
|
283
|
+
return lines.join("\n");
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=claude.js.map
|