claude-brain 0.14.2 → 0.14.4
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/README.md +191 -191
- package/VERSION +1 -1
- package/assets/CLAUDE-unified.md +11 -11
- package/assets/CLAUDE.md +11 -11
- package/bunfig.toml +8 -8
- package/package.json +80 -80
- package/packs/backend/node.json +173 -173
- package/packs/core/javascript.json +176 -176
- package/packs/core/typescript.json +222 -222
- package/packs/frontend/react.json +254 -254
- package/packs/meta/testing.json +172 -172
- package/src/automation/auto-context.ts +240 -240
- package/src/automation/decision-detector.ts +452 -452
- package/src/automation/index.ts +11 -11
- package/src/automation/phase12-manager.ts +456 -456
- package/src/automation/proactive-recall.ts +373 -373
- package/src/automation/project-detector.ts +310 -310
- package/src/automation/repo-scanner.ts +205 -205
- package/src/cli/auto-setup.ts +82 -82
- package/src/cli/bin.ts +202 -202
- package/src/cli/commands/chroma.ts +573 -573
- package/src/cli/commands/git-hook.ts +189 -189
- package/src/cli/commands/hooks.ts +213 -213
- package/src/cli/commands/init.ts +122 -122
- package/src/cli/commands/install-mcp.ts +92 -92
- package/src/cli/commands/pack.ts +197 -197
- package/src/cli/commands/serve.ts +167 -167
- package/src/cli/commands/start.ts +42 -42
- package/src/cli/commands/uninstall-mcp.ts +41 -41
- package/src/cli/commands/update.ts +121 -121
- package/src/cli/diagnose.ts +4 -4
- package/src/cli/health-check.ts +4 -4
- package/src/cli/migrate-chroma.ts +106 -106
- package/src/cli/setup.ts +4 -4
- package/src/cli/ui/animations.ts +80 -80
- package/src/cli/ui/components.ts +82 -82
- package/src/cli/ui/index.ts +4 -4
- package/src/cli/ui/logo.ts +36 -36
- package/src/cli/ui/theme.ts +55 -55
- package/src/config/defaults.ts +50 -50
- package/src/config/home.ts +55 -55
- package/src/config/index.ts +7 -7
- package/src/config/loader.ts +166 -166
- package/src/config/migration.ts +76 -76
- package/src/config/schema.ts +360 -360
- package/src/config/validator.ts +184 -184
- package/src/config/watcher.ts +86 -86
- package/src/context/assembler.ts +398 -398
- package/src/context/cache-manager.ts +101 -101
- package/src/context/formatter.ts +84 -84
- package/src/context/hierarchy.ts +85 -85
- package/src/context/index.ts +83 -83
- package/src/context/progress-tracker.ts +174 -174
- package/src/context/standards-manager.ts +287 -287
- package/src/context/types.ts +252 -252
- package/src/context/validator.ts +58 -58
- package/src/diagnostics/index.ts +123 -123
- package/src/health/index.ts +229 -229
- package/src/hooks/brain-hook.ts +112 -112
- package/src/hooks/capture.ts +168 -168
- package/src/hooks/deduplicator.ts +72 -72
- package/src/hooks/git-capture.ts +109 -109
- package/src/hooks/git-hook-installer.ts +207 -207
- package/src/hooks/index.ts +20 -20
- package/src/hooks/installer.ts +191 -194
- package/src/hooks/passive-classifier.ts +366 -366
- package/src/hooks/queue.ts +129 -129
- package/src/hooks/session-tracker.ts +275 -275
- package/src/hooks/types.ts +47 -47
- package/src/index.ts +7 -7
- package/src/intelligence/cross-project/affinity.ts +162 -162
- package/src/intelligence/cross-project/generalizer.ts +283 -283
- package/src/intelligence/cross-project/index.ts +13 -13
- package/src/intelligence/cross-project/transfer.ts +201 -201
- package/src/intelligence/index.ts +24 -24
- package/src/intelligence/optimization/index.ts +10 -10
- package/src/intelligence/optimization/precompute.ts +202 -202
- package/src/intelligence/optimization/semantic-cache.ts +207 -207
- package/src/intelligence/prediction/context-anticipator.ts +198 -198
- package/src/intelligence/prediction/decision-predictor.ts +184 -184
- package/src/intelligence/prediction/index.ts +13 -13
- package/src/intelligence/prediction/recommender.ts +268 -268
- package/src/intelligence/reasoning/chain-retrieval.ts +247 -247
- package/src/intelligence/reasoning/counterfactual.ts +248 -248
- package/src/intelligence/reasoning/index.ts +13 -13
- package/src/intelligence/reasoning/synthesizer.ts +169 -169
- package/src/intelligence/temporal/evolution.ts +197 -197
- package/src/intelligence/temporal/index.ts +16 -16
- package/src/intelligence/temporal/query-processor.ts +190 -190
- package/src/intelligence/temporal/timeline.ts +259 -259
- package/src/intelligence/temporal/trends.ts +263 -263
- package/src/knowledge/entity-extractor.ts +416 -416
- package/src/knowledge/graph/builder.ts +185 -185
- package/src/knowledge/graph/linker.ts +201 -201
- package/src/knowledge/graph/memory-graph.ts +359 -359
- package/src/knowledge/graph/schema.ts +99 -99
- package/src/knowledge/graph/search.ts +168 -168
- package/src/knowledge/relationship-extractor.ts +108 -108
- package/src/memory/chroma/client.ts +174 -174
- package/src/memory/chroma/collection-manager.ts +94 -94
- package/src/memory/chroma/config.ts +57 -57
- package/src/memory/chroma/embeddings.ts +153 -153
- package/src/memory/chroma/index.ts +82 -82
- package/src/memory/chroma/migration.ts +270 -270
- package/src/memory/chroma/schemas.ts +69 -69
- package/src/memory/chroma/search.ts +315 -315
- package/src/memory/chroma/store.ts +741 -741
- package/src/memory/consolidation/archiver.ts +164 -164
- package/src/memory/consolidation/merger.ts +186 -186
- package/src/memory/consolidation/scorer.ts +138 -138
- package/src/memory/context-builder.ts +236 -236
- package/src/memory/database.ts +169 -169
- package/src/memory/embedding-utils.ts +156 -156
- package/src/memory/embeddings.ts +226 -226
- package/src/memory/episodic/detector.ts +108 -108
- package/src/memory/episodic/manager.ts +351 -351
- package/src/memory/episodic/summarizer.ts +179 -179
- package/src/memory/episodic/types.ts +52 -52
- package/src/memory/index.ts +582 -582
- package/src/memory/knowledge-extractor.ts +455 -455
- package/src/memory/learning.ts +378 -378
- package/src/memory/patterns.ts +396 -396
- package/src/memory/schema.ts +88 -88
- package/src/memory/search.ts +309 -309
- package/src/memory/store.ts +787 -787
- package/src/memory/types.ts +121 -121
- package/src/orchestrator/coordinator.ts +272 -272
- package/src/orchestrator/decision-logger.ts +228 -228
- package/src/orchestrator/event-emitter.ts +198 -198
- package/src/orchestrator/event-queue.ts +184 -184
- package/src/orchestrator/handlers/base-handler.ts +70 -70
- package/src/orchestrator/handlers/context-handler.ts +73 -73
- package/src/orchestrator/handlers/decision-handler.ts +204 -204
- package/src/orchestrator/handlers/index.ts +10 -10
- package/src/orchestrator/handlers/status-handler.ts +131 -131
- package/src/orchestrator/handlers/task-handler.ts +171 -171
- package/src/orchestrator/index.ts +275 -275
- package/src/orchestrator/task-parser.ts +284 -284
- package/src/orchestrator/types.ts +98 -98
- package/src/packs/index.ts +9 -9
- package/src/packs/loader.ts +134 -134
- package/src/packs/manager.ts +204 -204
- package/src/packs/ranker.ts +78 -78
- package/src/packs/types.ts +81 -81
- package/src/phase12/index.ts +5 -5
- package/src/retrieval/bm25/index.ts +300 -300
- package/src/retrieval/bm25/tokenizer.ts +184 -184
- package/src/retrieval/feedback/adaptive.ts +223 -223
- package/src/retrieval/feedback/index.ts +16 -16
- package/src/retrieval/feedback/metrics.ts +223 -223
- package/src/retrieval/feedback/store.ts +283 -283
- package/src/retrieval/fusion/index.ts +194 -194
- package/src/retrieval/fusion/rrf.ts +163 -163
- package/src/retrieval/index.ts +12 -12
- package/src/retrieval/pipeline.ts +375 -375
- package/src/retrieval/query/expander.ts +198 -198
- package/src/retrieval/query/index.ts +27 -27
- package/src/retrieval/query/intent-classifier.ts +236 -236
- package/src/retrieval/query/temporal-parser.ts +295 -295
- package/src/retrieval/reranker/index.ts +188 -188
- package/src/retrieval/reranker/model.ts +95 -95
- package/src/retrieval/service.ts +125 -125
- package/src/retrieval/types.ts +162 -162
- package/src/routing/entity-extractor.ts +428 -428
- package/src/routing/intent-classifier.ts +436 -436
- package/src/routing/response-filter.ts +258 -254
- package/src/routing/router.ts +1322 -1314
- package/src/routing/search-engine.ts +475 -475
- package/src/routing/types.ts +94 -84
- package/src/scripts/health-check.ts +118 -118
- package/src/scripts/setup.ts +122 -122
- package/src/server/handlers/call-tool.ts +156 -156
- package/src/server/handlers/index.ts +9 -9
- package/src/server/handlers/list-tools.ts +35 -35
- package/src/server/handlers/tools/analyze-decision-evolution.ts +151 -151
- package/src/server/handlers/tools/auto-remember.ts +200 -200
- package/src/server/handlers/tools/brain.ts +85 -85
- package/src/server/handlers/tools/create-project.ts +135 -135
- package/src/server/handlers/tools/detect-trends.ts +144 -144
- package/src/server/handlers/tools/find-cross-project-patterns.ts +168 -168
- package/src/server/handlers/tools/get-activity-log.ts +194 -194
- package/src/server/handlers/tools/get-code-standards.ts +124 -124
- package/src/server/handlers/tools/get-corrections.ts +154 -154
- package/src/server/handlers/tools/get-decision-timeline.ts +172 -172
- package/src/server/handlers/tools/get-episode.ts +103 -103
- package/src/server/handlers/tools/get-patterns.ts +158 -158
- package/src/server/handlers/tools/get-phase12-status.ts +63 -63
- package/src/server/handlers/tools/get-project-context.ts +75 -75
- package/src/server/handlers/tools/get-recommendations.ts +145 -145
- package/src/server/handlers/tools/index.ts +31 -31
- package/src/server/handlers/tools/init-project.ts +757 -757
- package/src/server/handlers/tools/list-episodes.ts +90 -90
- package/src/server/handlers/tools/list-projects.ts +125 -125
- package/src/server/handlers/tools/rate-memory.ts +101 -101
- package/src/server/handlers/tools/recall-similar.ts +87 -87
- package/src/server/handlers/tools/recognize-pattern.ts +126 -126
- package/src/server/handlers/tools/record-correction.ts +125 -125
- package/src/server/handlers/tools/remember-decision.ts +153 -153
- package/src/server/handlers/tools/schemas.ts +253 -253
- package/src/server/handlers/tools/search-knowledge-graph.ts +102 -102
- package/src/server/handlers/tools/smart-context.ts +146 -146
- package/src/server/handlers/tools/update-progress.ts +131 -131
- package/src/server/handlers/tools/what-if-analysis.ts +135 -135
- package/src/server/http-api.ts +693 -693
- package/src/server/index.ts +40 -40
- package/src/server/mcp-server.ts +283 -283
- package/src/server/providers/index.ts +7 -7
- package/src/server/providers/prompts.ts +327 -327
- package/src/server/providers/resources.ts +622 -622
- package/src/server/services.ts +468 -468
- package/src/server/types.ts +39 -39
- package/src/server/utils/error-handler.ts +155 -155
- package/src/server/utils/index.ts +13 -13
- package/src/server/utils/memory-indicator.ts +83 -83
- package/src/server/utils/request-context.ts +122 -122
- package/src/server/utils/response-formatter.ts +129 -124
- package/src/server/utils/validators.ts +210 -210
- package/src/setup/index.ts +48 -48
- package/src/setup/wizard.ts +461 -461
- package/src/tools/index.ts +24 -24
- package/src/tools/registry.ts +115 -115
- package/src/tools/schemas.test.ts +30 -30
- package/src/tools/schemas.ts +617 -617
- package/src/tools/types.ts +412 -412
- package/src/utils/circuit-breaker.ts +130 -130
- package/src/utils/cleanup.ts +34 -34
- package/src/utils/error-handler.ts +132 -132
- package/src/utils/error-messages.ts +60 -60
- package/src/utils/fallback.ts +45 -45
- package/src/utils/index.ts +54 -54
- package/src/utils/logger-utils.ts +80 -80
- package/src/utils/logger.ts +88 -88
- package/src/utils/phase12-helper.ts +56 -56
- package/src/utils/retry.ts +94 -94
- package/src/utils/timing.ts +47 -47
- package/src/utils/transaction.ts +63 -63
- package/src/vault/frontmatter.ts +264 -264
- package/src/vault/index.ts +318 -318
- package/src/vault/paths.ts +106 -106
- package/src/vault/query.ts +422 -422
- package/src/vault/reader.ts +264 -264
- package/src/vault/templates.ts +186 -186
- package/src/vault/types.ts +73 -73
- package/src/vault/watcher.ts +277 -277
- package/src/vault/writer.ts +413 -413
- package/tsconfig.json +30 -30
|
@@ -1,436 +1,436 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Brain Intent Classifier
|
|
3
|
-
* Phase 16 + Phase 19: Rule-based intent classification for the unified brain() tool
|
|
4
|
-
*
|
|
5
|
-
* Priority-ordered — first confident match wins.
|
|
6
|
-
* No LLM calls, pure pattern matching.
|
|
7
|
-
*
|
|
8
|
-
* Phase 19 changes:
|
|
9
|
-
* - B1: Question confidence raised (? → 0.95, question word → 0.90)
|
|
10
|
-
* - B2: session_start narrowed (must be at start + no progress indicators)
|
|
11
|
-
* - B3: Temporal signal detection added to secondary intents
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export type Intent =
|
|
15
|
-
| 'session_start'
|
|
16
|
-
| 'context_needed'
|
|
17
|
-
| 'decision_made'
|
|
18
|
-
| 'store_this'
|
|
19
|
-
| 'pattern_found'
|
|
20
|
-
| 'mistake_learned'
|
|
21
|
-
| 'progress_update'
|
|
22
|
-
| 'question'
|
|
23
|
-
| 'comparison'
|
|
24
|
-
| 'exploration'
|
|
25
|
-
| 'list_all'
|
|
26
|
-
| 'update_memory'
|
|
27
|
-
| 'delete_memory'
|
|
28
|
-
| 'no_action'
|
|
29
|
-
|
|
30
|
-
export interface ClassificationResult {
|
|
31
|
-
primary: Intent
|
|
32
|
-
confidence: number
|
|
33
|
-
secondary: Intent[]
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Decision-indicating phrases
|
|
37
|
-
const DECISION_PHRASES = [
|
|
38
|
-
'i recommend', 'you should use', 'the best approach',
|
|
39
|
-
'i suggest', 'better to use', 'prefer using',
|
|
40
|
-
'go with', 'decided to', "let's use", 'we will use',
|
|
41
|
-
'the solution is', 'implement using', 'going with',
|
|
42
|
-
'switching to', 'adopting', 'we chose', 'the plan is to',
|
|
43
|
-
'i decided that', 'decided that', 'choosing', 'we picked',
|
|
44
|
-
'settled on', 'committing to', 'opting for', 'sticking with'
|
|
45
|
-
]
|
|
46
|
-
|
|
47
|
-
// Explicit "store this" phrases — the user wants to persist something
|
|
48
|
-
const STORE_PHRASES = [
|
|
49
|
-
'remember:', 'remember this:', 'remember that',
|
|
50
|
-
'note to self:', 'note to self', 'note:', 'save this:',
|
|
51
|
-
'save this', 'store this', 'keep this', 'record this',
|
|
52
|
-
'i prefer', 'my preference is', 'my convention is',
|
|
53
|
-
'i like to', 'i always', 'always use', 'never use this',
|
|
54
|
-
'from now on', 'going forward', 'the rule is',
|
|
55
|
-
'my approach is', 'my standard is', 'the standard is',
|
|
56
|
-
'we should always', 'we should never',
|
|
57
|
-
'i want to remember', 'don\'t forget',
|
|
58
|
-
'for future reference', 'for the record',
|
|
59
|
-
'important:', 'key decision:', 'takeaway:',
|
|
60
|
-
// Issue 3: Declarative patterns ("X should be Y")
|
|
61
|
-
'should be', 'must be', 'needs to be', 'has to be',
|
|
62
|
-
'is set to', 'will be set', 'is always', 'are always',
|
|
63
|
-
'is configured to', 'is configured as',
|
|
64
|
-
// Issue 6: "I learned that" is a store, not a mistake
|
|
65
|
-
'i learned that'
|
|
66
|
-
]
|
|
67
|
-
|
|
68
|
-
const REASONING_PHRASES = [
|
|
69
|
-
'because', 'since', 'due to', 'as it', 'which provides',
|
|
70
|
-
'this allows', 'this ensures', 'given that', 'considering',
|
|
71
|
-
'the reason is', 'this way'
|
|
72
|
-
]
|
|
73
|
-
|
|
74
|
-
// Mistake/correction indicators
|
|
75
|
-
const MISTAKE_PHRASES = [
|
|
76
|
-
'bug was', 'the issue was', 'the problem was', 'mistake was',
|
|
77
|
-
'should have', "shouldn't have", 'should not have',
|
|
78
|
-
'lesson learned', "don't use", 'avoid using',
|
|
79
|
-
'the fix is', 'the fix was', 'fixed by', 'solved by',
|
|
80
|
-
'was wrong', 'was broken', 'was incorrect',
|
|
81
|
-
'gotcha:', 'pitfall:', 'watch out for', 'be careful with',
|
|
82
|
-
'turns out that'
|
|
83
|
-
]
|
|
84
|
-
|
|
85
|
-
// Progress indicators
|
|
86
|
-
const PROGRESS_PHRASES = [
|
|
87
|
-
'finished', 'completed', 'done with', 'implemented',
|
|
88
|
-
'built', 'created', 'added', 'fixed', 'resolved',
|
|
89
|
-
'shipped', 'deployed', 'merged', 'released',
|
|
90
|
-
"i'm working on", 'currently working', 'making progress',
|
|
91
|
-
'just did', 'just finished',
|
|
92
|
-
// Phase 23b: present-tense statement patterns
|
|
93
|
-
"i'm implementing", "i'm building", "i'm adding",
|
|
94
|
-
"i'm fixing", "i'm refactoring", "i'm setting up",
|
|
95
|
-
"i'm migrating", "i'm updating", "i'm creating",
|
|
96
|
-
'started implementing', 'started building', 'started adding'
|
|
97
|
-
]
|
|
98
|
-
|
|
99
|
-
// Comparison indicators
|
|
100
|
-
const COMPARISON_PHRASES = [
|
|
101
|
-
' vs ', ' versus ', 'or should', 'compared to', 'comparing ',
|
|
102
|
-
'which is better', 'should i use', 'should we use',
|
|
103
|
-
'what if we switch', 'what if we change', 'what if we replace',
|
|
104
|
-
'pros and cons', 'tradeoffs', 'trade-offs'
|
|
105
|
-
]
|
|
106
|
-
|
|
107
|
-
// Pattern indicators
|
|
108
|
-
const PATTERN_PHRASES = [
|
|
109
|
-
'pattern:', 'best practice:', 'anti-pattern:', 'reusable solution',
|
|
110
|
-
'reusable approach', 'common issue:', 'this pattern',
|
|
111
|
-
'recognized pattern', 'document this pattern'
|
|
112
|
-
]
|
|
113
|
-
|
|
114
|
-
// Exploration indicators
|
|
115
|
-
const EXPLORATION_PHRASES = [
|
|
116
|
-
'show me', 'timeline', 'trends', 'evolution of',
|
|
117
|
-
'history of', 'graph', 'how has', 'what happened',
|
|
118
|
-
'decisions about', 'when did we', 'list episodes'
|
|
119
|
-
]
|
|
120
|
-
|
|
121
|
-
// Session start indicators — Phase 19: narrowed to require start-of-message
|
|
122
|
-
const SESSION_START_PHRASES = [
|
|
123
|
-
'starting work', 'beginning work', 'resuming',
|
|
124
|
-
'picking up', 'getting started', 'opening',
|
|
125
|
-
'starting on', 'working on', 'beginning on'
|
|
126
|
-
]
|
|
127
|
-
|
|
128
|
-
// Progress indicators that disqualify session_start
|
|
129
|
-
const PROGRESS_INDICATORS = [
|
|
130
|
-
'finished', 'completed', 'done', 'fixed', 'resolved',
|
|
131
|
-
'shipped', 'deployed', 'merged', 'released', 'just did',
|
|
132
|
-
'making progress', 'currently working'
|
|
133
|
-
]
|
|
134
|
-
|
|
135
|
-
// Question indicators
|
|
136
|
-
const QUESTION_WORDS = [
|
|
137
|
-
'what', 'how', 'when', 'why', 'where', 'which',
|
|
138
|
-
'who', 'can', 'does', 'is', 'are', 'should', 'could', 'would'
|
|
139
|
-
]
|
|
140
|
-
|
|
141
|
-
// No-action indicators
|
|
142
|
-
const NO_ACTION_PHRASES = [
|
|
143
|
-
'ok', 'okay', 'thanks', 'thank you', 'got it',
|
|
144
|
-
'sure', 'yes', 'no', 'cool', 'nice', 'great',
|
|
145
|
-
'understood', 'noted', 'alright', 'right'
|
|
146
|
-
]
|
|
147
|
-
|
|
148
|
-
// List/browse indicators
|
|
149
|
-
const LIST_PHRASES = [
|
|
150
|
-
'list all', 'show all', 'what decisions',
|
|
151
|
-
'what have i decided', 'all my decisions', 'all decisions',
|
|
152
|
-
'everything about', 'what do i know', 'what do we know',
|
|
153
|
-
'show me everything', 'list decisions', 'list memories',
|
|
154
|
-
'browse', 'dump all', 'show my',
|
|
155
|
-
// Issue 4: Additional list phrases
|
|
156
|
-
'list everything', "everything i've stored", "everything i know",
|
|
157
|
-
"what have i stored", "stored in my brain", "what's in my brain",
|
|
158
|
-
"what have i remembered", "what do i have stored"
|
|
159
|
-
]
|
|
160
|
-
|
|
161
|
-
// Update/correct existing memory
|
|
162
|
-
const UPDATE_PHRASES = [
|
|
163
|
-
'actually,', 'actually ', 'correction:', 'update that',
|
|
164
|
-
'i changed my mind', 'changed my mind', 'change that to', 'instead of what i said',
|
|
165
|
-
'supersedes', 'override', 'revise that', 'amend that',
|
|
166
|
-
'that should be', 'update the decision', 'modify that',
|
|
167
|
-
'replace that with', 'no wait', 'scratch that, use',
|
|
168
|
-
// Phase 23b: additional update triggers
|
|
169
|
-
'switch to', 'instead use', 'use instead', 'no longer using',
|
|
170
|
-
'moved to', 'migrated to', 'replaced with'
|
|
171
|
-
]
|
|
172
|
-
|
|
173
|
-
// Delete/forget memory
|
|
174
|
-
const DELETE_PHRASES = [
|
|
175
|
-
'forget that', 'forget about', 'delete that', 'delete the',
|
|
176
|
-
'remove that memory', 'remove that decision', 'that was wrong',
|
|
177
|
-
'discard that', 'erase that', 'undo that decision',
|
|
178
|
-
'remove the memory', 'clear that', 'drop that'
|
|
179
|
-
]
|
|
180
|
-
|
|
181
|
-
// Phase 19 B3: Temporal signal phrases
|
|
182
|
-
const TEMPORAL_PHRASES = [
|
|
183
|
-
'last week', 'last month', 'last year', 'yesterday', 'today',
|
|
184
|
-
'this week', 'this month', 'this year',
|
|
185
|
-
'since january', 'since february', 'since march', 'since april',
|
|
186
|
-
'since may', 'since june', 'since july', 'since august',
|
|
187
|
-
'since september', 'since october', 'since november', 'since december',
|
|
188
|
-
'in january', 'in february', 'in march', 'in april',
|
|
189
|
-
'in may', 'in june', 'in july', 'in august',
|
|
190
|
-
'in september', 'in october', 'in november', 'in december',
|
|
191
|
-
'ago', 'recently', 'before', 'after', 'during',
|
|
192
|
-
'last few days', 'past week', 'past month',
|
|
193
|
-
'earlier this', 'earlier today', 'over the past'
|
|
194
|
-
]
|
|
195
|
-
|
|
196
|
-
export class IntentClassifier {
|
|
197
|
-
/**
|
|
198
|
-
* Classify the intent of a message
|
|
199
|
-
*/
|
|
200
|
-
classify(message: string): ClassificationResult {
|
|
201
|
-
const lower = message.toLowerCase().trim()
|
|
202
|
-
const secondary: Intent[] = []
|
|
203
|
-
|
|
204
|
-
// Phase 19 B3: Detect temporal signals for secondary intent
|
|
205
|
-
const hasTemporal = this.hasTemporalSignal(lower)
|
|
206
|
-
|
|
207
|
-
// Check in priority order — first confident match wins
|
|
208
|
-
|
|
209
|
-
// 1. no_action: very short messages, greetings, acknowledgments
|
|
210
|
-
if (this.isNoAction(lower)) {
|
|
211
|
-
return { primary: 'no_action', confidence: 0.95, secondary: [] }
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// 2. delete_memory: "forget that", "delete", "remove"
|
|
215
|
-
if (this.isDeleteMemory(lower)) {
|
|
216
|
-
return { primary: 'delete_memory', confidence: 0.90, secondary }
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// 3. update_memory: "actually", "correction:", "change that to"
|
|
220
|
-
if (this.isUpdateMemory(lower)) {
|
|
221
|
-
return { primary: 'update_memory', confidence: 0.85, secondary }
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// 4. store_this: explicit "remember:", "save this:", "I prefer" (never for questions)
|
|
225
|
-
if (this.isStoreThis(lower, message)) {
|
|
226
|
-
if (this.hasDecisionSignal(lower)) secondary.push('decision_made')
|
|
227
|
-
return { primary: 'store_this', confidence: 0.90, secondary }
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// 5. decision_made: decision phrases + reasoning (never for questions)
|
|
231
|
-
if (this.isDecisionMade(lower, message)) {
|
|
232
|
-
if (this.hasComparisonSignal(lower)) secondary.push('comparison')
|
|
233
|
-
return { primary: 'decision_made', confidence: 0.85, secondary }
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// 6. mistake_learned: correction/bug/lesson indicators
|
|
237
|
-
if (this.isMistakeLearned(lower)) {
|
|
238
|
-
return { primary: 'mistake_learned', confidence: 0.85, secondary }
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// 7. list_all: "list all", "what decisions", "show all"
|
|
242
|
-
if (this.isListAll(lower, message)) {
|
|
243
|
-
return { primary: 'list_all', confidence: 0.85, secondary }
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// 8. progress_update: completed task indicators (NOT questions)
|
|
247
|
-
if (this.isProgressUpdate(lower, message)) {
|
|
248
|
-
if (this.hasSessionSignal(lower)) secondary.push('session_start')
|
|
249
|
-
return { primary: 'progress_update', confidence: 0.85, secondary }
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// 9. comparison: vs, which is better, etc.
|
|
253
|
-
if (this.isComparison(lower)) {
|
|
254
|
-
if (this.isQuestion(lower, message)) secondary.push('question')
|
|
255
|
-
if (hasTemporal) secondary.push('exploration')
|
|
256
|
-
return { primary: 'comparison', confidence: 0.85, secondary }
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// 10. pattern_found: explicit pattern documentation
|
|
260
|
-
if (this.isPatternFound(lower)) {
|
|
261
|
-
return { primary: 'pattern_found', confidence: 0.80, secondary }
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// 11. session_start: starting/resuming work (Phase 19: narrowed check)
|
|
265
|
-
if (this.isSessionStart(lower)) {
|
|
266
|
-
secondary.push('context_needed')
|
|
267
|
-
return { primary: 'session_start', confidence: 0.90, secondary }
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// 12. exploration: timeline, trends, graph, history
|
|
271
|
-
if (this.isExploration(lower)) {
|
|
272
|
-
if (this.isQuestion(lower, message)) secondary.push('question')
|
|
273
|
-
if (hasTemporal) secondary.push('exploration')
|
|
274
|
-
return { primary: 'exploration', confidence: 0.75, secondary }
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// 13. question: starts with question word or ends with ?
|
|
278
|
-
// Phase 19 B1: Higher confidence for questions
|
|
279
|
-
if (this.isQuestion(lower, message)) {
|
|
280
|
-
if (this.hasComparisonSignal(lower)) secondary.push('comparison')
|
|
281
|
-
if (this.hasExplorationSignal(lower)) secondary.push('exploration')
|
|
282
|
-
if (hasTemporal) secondary.push('exploration')
|
|
283
|
-
|
|
284
|
-
// Phase 19 B1: ? → 0.95, question word → 0.90
|
|
285
|
-
const confidence = message.trim().endsWith('?') ? 0.95 : 0.90
|
|
286
|
-
return { primary: 'question', confidence, secondary }
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// 14. Default: context_needed
|
|
290
|
-
if (hasTemporal) secondary.push('exploration')
|
|
291
|
-
return { primary: 'context_needed', confidence: 0.60, secondary }
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
private isNoAction(lower: string): boolean {
|
|
295
|
-
if (lower.length > 30) return false
|
|
296
|
-
const words = lower.split(/\s+/)
|
|
297
|
-
if (words.length > 5) return false
|
|
298
|
-
return NO_ACTION_PHRASES.some(p => lower === p || lower === p + '.' || lower === p + '!')
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
private isStoreThis(lower: string, original?: string): boolean {
|
|
302
|
-
// Questions are never storage requests — "Do I prefer X?" is a query, not "I prefer X"
|
|
303
|
-
if (original?.trim().endsWith('?')) return false
|
|
304
|
-
const firstWord = lower.split(/\s+/)[0] || ''
|
|
305
|
-
if (QUESTION_WORDS.includes(firstWord)) return false
|
|
306
|
-
// Phase 19 B4: Additional question guards
|
|
307
|
-
if (this.startsWithQuestionPattern(lower)) return false
|
|
308
|
-
return STORE_PHRASES.some(p => lower.includes(p))
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
private isDecisionMade(lower: string, original?: string): boolean {
|
|
312
|
-
// Questions are never decisions — "Did I decide to use X?" is a query
|
|
313
|
-
if (original?.trim().endsWith('?')) return false
|
|
314
|
-
const firstWord = lower.split(/\s+/)[0] || ''
|
|
315
|
-
if (QUESTION_WORDS.includes(firstWord)) return false
|
|
316
|
-
// Phase 19 B4: Additional question guards
|
|
317
|
-
if (this.startsWithQuestionPattern(lower)) return false
|
|
318
|
-
|
|
319
|
-
const hasDecision = DECISION_PHRASES.some(p => lower.includes(p))
|
|
320
|
-
if (!hasDecision) return false
|
|
321
|
-
// Higher confidence if reasoning is also present
|
|
322
|
-
const hasReasoning = REASONING_PHRASES.some(p => lower.includes(p))
|
|
323
|
-
return hasReasoning || lower.length > 30
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
private isMistakeLearned(lower: string): boolean {
|
|
327
|
-
return MISTAKE_PHRASES.some(p => lower.includes(p))
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
private isListAll(lower: string, _original: string): boolean {
|
|
331
|
-
return LIST_PHRASES.some(p => lower.includes(p))
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
private isProgressUpdate(lower: string, original: string): boolean {
|
|
335
|
-
// Must not be a question
|
|
336
|
-
if (original.trim().endsWith('?')) return false
|
|
337
|
-
const firstWord = lower.split(/\s+/)[0] || ''
|
|
338
|
-
if (QUESTION_WORDS.includes(firstWord)) return false
|
|
339
|
-
|
|
340
|
-
return PROGRESS_PHRASES.some(p => lower.includes(p))
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
private isComparison(lower: string): boolean {
|
|
344
|
-
return COMPARISON_PHRASES.some(p => lower.includes(p))
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
private isPatternFound(lower: string): boolean {
|
|
348
|
-
const hasPattern = PATTERN_PHRASES.some(p => lower.includes(p))
|
|
349
|
-
return hasPattern && lower.length > 50
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Phase 19 B2: Narrowed session_start detection.
|
|
354
|
-
* Must start at beginning of message AND have no progress indicators.
|
|
355
|
-
* "working on X" in the middle of a sentence is not a session start.
|
|
356
|
-
*/
|
|
357
|
-
private isSessionStart(lower: string): boolean {
|
|
358
|
-
// Must NOT have progress indicators (e.g. "finished working on X" is progress, not session start)
|
|
359
|
-
if (PROGRESS_INDICATORS.some(p => lower.includes(p))) return false
|
|
360
|
-
|
|
361
|
-
// Phase 19 B2: Session phrases must match near the start of the message
|
|
362
|
-
for (const phrase of SESSION_START_PHRASES) {
|
|
363
|
-
const idx = lower.indexOf(phrase)
|
|
364
|
-
if (idx !== -1 && idx <= 5) {
|
|
365
|
-
return true
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
return false
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
private isExploration(lower: string): boolean {
|
|
372
|
-
return EXPLORATION_PHRASES.some(p => lower.includes(p))
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
private isQuestion(lower: string, original: string): boolean {
|
|
376
|
-
if (original.trim().endsWith('?')) return true
|
|
377
|
-
const firstWord = lower.split(/\s+/)[0] || ''
|
|
378
|
-
if (QUESTION_WORDS.includes(firstWord)) return true
|
|
379
|
-
// Phase 19 B4: "do I", "did we", "have we", "can we" patterns
|
|
380
|
-
if (this.startsWithQuestionPattern(lower)) return true
|
|
381
|
-
return false
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
private isUpdateMemory(lower: string): boolean {
|
|
385
|
-
return UPDATE_PHRASES.some(p => lower.includes(p))
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
private isDeleteMemory(lower: string): boolean {
|
|
389
|
-
return DELETE_PHRASES.some(p => lower.includes(p))
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// Secondary signal checks
|
|
393
|
-
private hasDecisionSignal(lower: string): boolean {
|
|
394
|
-
return DECISION_PHRASES.some(p => lower.includes(p))
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
private hasComparisonSignal(lower: string): boolean {
|
|
398
|
-
return COMPARISON_PHRASES.some(p => lower.includes(p))
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
private hasExplorationSignal(lower: string): boolean {
|
|
402
|
-
return EXPLORATION_PHRASES.some(p => lower.includes(p))
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
private hasSessionSignal(lower: string): boolean {
|
|
406
|
-
return SESSION_START_PHRASES.some(p => lower.includes(p))
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Phase 19 B3: Detect temporal signals in the message.
|
|
411
|
-
* Used to add 'temporal' context to secondary intents.
|
|
412
|
-
*/
|
|
413
|
-
hasTemporalSignal(lower: string): boolean {
|
|
414
|
-
return TEMPORAL_PHRASES.some(p => lower.includes(p))
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
/**
|
|
418
|
-
* Phase 19 B4: Extended question guards.
|
|
419
|
-
* Catches "do I", "did we", "have we", "can we" etc. patterns
|
|
420
|
-
* that start with auxiliary verbs not in the QUESTION_WORDS list.
|
|
421
|
-
*/
|
|
422
|
-
private startsWithQuestionPattern(lower: string): boolean {
|
|
423
|
-
const questionStarters = [
|
|
424
|
-
'do i ', 'do we ', 'do you ',
|
|
425
|
-
'did i ', 'did we ', 'did you ',
|
|
426
|
-
'have i ', 'have we ', 'have you ',
|
|
427
|
-
'has it ', 'has the ',
|
|
428
|
-
'can i ', 'can we ', 'can you ',
|
|
429
|
-
'will i ', 'will we ', 'will you ',
|
|
430
|
-
'am i ', 'was i ', 'were we ',
|
|
431
|
-
'shall we ', 'shall i ',
|
|
432
|
-
'tell me '
|
|
433
|
-
]
|
|
434
|
-
return questionStarters.some(p => lower.startsWith(p))
|
|
435
|
-
}
|
|
436
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Brain Intent Classifier
|
|
3
|
+
* Phase 16 + Phase 19: Rule-based intent classification for the unified brain() tool
|
|
4
|
+
*
|
|
5
|
+
* Priority-ordered — first confident match wins.
|
|
6
|
+
* No LLM calls, pure pattern matching.
|
|
7
|
+
*
|
|
8
|
+
* Phase 19 changes:
|
|
9
|
+
* - B1: Question confidence raised (? → 0.95, question word → 0.90)
|
|
10
|
+
* - B2: session_start narrowed (must be at start + no progress indicators)
|
|
11
|
+
* - B3: Temporal signal detection added to secondary intents
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export type Intent =
|
|
15
|
+
| 'session_start'
|
|
16
|
+
| 'context_needed'
|
|
17
|
+
| 'decision_made'
|
|
18
|
+
| 'store_this'
|
|
19
|
+
| 'pattern_found'
|
|
20
|
+
| 'mistake_learned'
|
|
21
|
+
| 'progress_update'
|
|
22
|
+
| 'question'
|
|
23
|
+
| 'comparison'
|
|
24
|
+
| 'exploration'
|
|
25
|
+
| 'list_all'
|
|
26
|
+
| 'update_memory'
|
|
27
|
+
| 'delete_memory'
|
|
28
|
+
| 'no_action'
|
|
29
|
+
|
|
30
|
+
export interface ClassificationResult {
|
|
31
|
+
primary: Intent
|
|
32
|
+
confidence: number
|
|
33
|
+
secondary: Intent[]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Decision-indicating phrases
|
|
37
|
+
const DECISION_PHRASES = [
|
|
38
|
+
'i recommend', 'you should use', 'the best approach',
|
|
39
|
+
'i suggest', 'better to use', 'prefer using',
|
|
40
|
+
'go with', 'decided to', "let's use", 'we will use',
|
|
41
|
+
'the solution is', 'implement using', 'going with',
|
|
42
|
+
'switching to', 'adopting', 'we chose', 'the plan is to',
|
|
43
|
+
'i decided that', 'decided that', 'choosing', 'we picked',
|
|
44
|
+
'settled on', 'committing to', 'opting for', 'sticking with'
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
// Explicit "store this" phrases — the user wants to persist something
|
|
48
|
+
const STORE_PHRASES = [
|
|
49
|
+
'remember:', 'remember this:', 'remember that',
|
|
50
|
+
'note to self:', 'note to self', 'note:', 'save this:',
|
|
51
|
+
'save this', 'store this', 'keep this', 'record this',
|
|
52
|
+
'i prefer', 'my preference is', 'my convention is',
|
|
53
|
+
'i like to', 'i always', 'always use', 'never use this',
|
|
54
|
+
'from now on', 'going forward', 'the rule is',
|
|
55
|
+
'my approach is', 'my standard is', 'the standard is',
|
|
56
|
+
'we should always', 'we should never',
|
|
57
|
+
'i want to remember', 'don\'t forget',
|
|
58
|
+
'for future reference', 'for the record',
|
|
59
|
+
'important:', 'key decision:', 'takeaway:',
|
|
60
|
+
// Issue 3: Declarative patterns ("X should be Y")
|
|
61
|
+
'should be', 'must be', 'needs to be', 'has to be',
|
|
62
|
+
'is set to', 'will be set', 'is always', 'are always',
|
|
63
|
+
'is configured to', 'is configured as',
|
|
64
|
+
// Issue 6: "I learned that" is a store, not a mistake
|
|
65
|
+
'i learned that'
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
const REASONING_PHRASES = [
|
|
69
|
+
'because', 'since', 'due to', 'as it', 'which provides',
|
|
70
|
+
'this allows', 'this ensures', 'given that', 'considering',
|
|
71
|
+
'the reason is', 'this way'
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
// Mistake/correction indicators
|
|
75
|
+
const MISTAKE_PHRASES = [
|
|
76
|
+
'bug was', 'the issue was', 'the problem was', 'mistake was',
|
|
77
|
+
'should have', "shouldn't have", 'should not have',
|
|
78
|
+
'lesson learned', "don't use", 'avoid using',
|
|
79
|
+
'the fix is', 'the fix was', 'fixed by', 'solved by',
|
|
80
|
+
'was wrong', 'was broken', 'was incorrect',
|
|
81
|
+
'gotcha:', 'pitfall:', 'watch out for', 'be careful with',
|
|
82
|
+
'turns out that'
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
// Progress indicators
|
|
86
|
+
const PROGRESS_PHRASES = [
|
|
87
|
+
'finished', 'completed', 'done with', 'implemented',
|
|
88
|
+
'built', 'created', 'added', 'fixed', 'resolved',
|
|
89
|
+
'shipped', 'deployed', 'merged', 'released',
|
|
90
|
+
"i'm working on", 'currently working', 'making progress',
|
|
91
|
+
'just did', 'just finished',
|
|
92
|
+
// Phase 23b: present-tense statement patterns
|
|
93
|
+
"i'm implementing", "i'm building", "i'm adding",
|
|
94
|
+
"i'm fixing", "i'm refactoring", "i'm setting up",
|
|
95
|
+
"i'm migrating", "i'm updating", "i'm creating",
|
|
96
|
+
'started implementing', 'started building', 'started adding'
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
// Comparison indicators
|
|
100
|
+
const COMPARISON_PHRASES = [
|
|
101
|
+
' vs ', ' versus ', 'or should', 'compared to', 'comparing ',
|
|
102
|
+
'which is better', 'should i use', 'should we use',
|
|
103
|
+
'what if we switch', 'what if we change', 'what if we replace',
|
|
104
|
+
'pros and cons', 'tradeoffs', 'trade-offs'
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
// Pattern indicators
|
|
108
|
+
const PATTERN_PHRASES = [
|
|
109
|
+
'pattern:', 'best practice:', 'anti-pattern:', 'reusable solution',
|
|
110
|
+
'reusable approach', 'common issue:', 'this pattern',
|
|
111
|
+
'recognized pattern', 'document this pattern'
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
// Exploration indicators
|
|
115
|
+
const EXPLORATION_PHRASES = [
|
|
116
|
+
'show me', 'timeline', 'trends', 'evolution of',
|
|
117
|
+
'history of', 'graph', 'how has', 'what happened',
|
|
118
|
+
'decisions about', 'when did we', 'list episodes'
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
// Session start indicators — Phase 19: narrowed to require start-of-message
|
|
122
|
+
const SESSION_START_PHRASES = [
|
|
123
|
+
'starting work', 'beginning work', 'resuming',
|
|
124
|
+
'picking up', 'getting started', 'opening',
|
|
125
|
+
'starting on', 'working on', 'beginning on'
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
// Progress indicators that disqualify session_start
|
|
129
|
+
const PROGRESS_INDICATORS = [
|
|
130
|
+
'finished', 'completed', 'done', 'fixed', 'resolved',
|
|
131
|
+
'shipped', 'deployed', 'merged', 'released', 'just did',
|
|
132
|
+
'making progress', 'currently working'
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
// Question indicators
|
|
136
|
+
const QUESTION_WORDS = [
|
|
137
|
+
'what', 'how', 'when', 'why', 'where', 'which',
|
|
138
|
+
'who', 'can', 'does', 'is', 'are', 'should', 'could', 'would'
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
// No-action indicators
|
|
142
|
+
const NO_ACTION_PHRASES = [
|
|
143
|
+
'ok', 'okay', 'thanks', 'thank you', 'got it',
|
|
144
|
+
'sure', 'yes', 'no', 'cool', 'nice', 'great',
|
|
145
|
+
'understood', 'noted', 'alright', 'right'
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
// List/browse indicators
|
|
149
|
+
const LIST_PHRASES = [
|
|
150
|
+
'list all', 'show all', 'what decisions',
|
|
151
|
+
'what have i decided', 'all my decisions', 'all decisions',
|
|
152
|
+
'everything about', 'what do i know', 'what do we know',
|
|
153
|
+
'show me everything', 'list decisions', 'list memories',
|
|
154
|
+
'browse', 'dump all', 'show my',
|
|
155
|
+
// Issue 4: Additional list phrases
|
|
156
|
+
'list everything', "everything i've stored", "everything i know",
|
|
157
|
+
"what have i stored", "stored in my brain", "what's in my brain",
|
|
158
|
+
"what have i remembered", "what do i have stored"
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
// Update/correct existing memory
|
|
162
|
+
const UPDATE_PHRASES = [
|
|
163
|
+
'actually,', 'actually ', 'correction:', 'update that',
|
|
164
|
+
'i changed my mind', 'changed my mind', 'change that to', 'instead of what i said',
|
|
165
|
+
'supersedes', 'override', 'revise that', 'amend that',
|
|
166
|
+
'that should be', 'update the decision', 'modify that',
|
|
167
|
+
'replace that with', 'no wait', 'scratch that, use',
|
|
168
|
+
// Phase 23b: additional update triggers
|
|
169
|
+
'switch to', 'instead use', 'use instead', 'no longer using',
|
|
170
|
+
'moved to', 'migrated to', 'replaced with'
|
|
171
|
+
]
|
|
172
|
+
|
|
173
|
+
// Delete/forget memory
|
|
174
|
+
const DELETE_PHRASES = [
|
|
175
|
+
'forget that', 'forget about', 'delete that', 'delete the',
|
|
176
|
+
'remove that memory', 'remove that decision', 'that was wrong',
|
|
177
|
+
'discard that', 'erase that', 'undo that decision',
|
|
178
|
+
'remove the memory', 'clear that', 'drop that'
|
|
179
|
+
]
|
|
180
|
+
|
|
181
|
+
// Phase 19 B3: Temporal signal phrases
|
|
182
|
+
const TEMPORAL_PHRASES = [
|
|
183
|
+
'last week', 'last month', 'last year', 'yesterday', 'today',
|
|
184
|
+
'this week', 'this month', 'this year',
|
|
185
|
+
'since january', 'since february', 'since march', 'since april',
|
|
186
|
+
'since may', 'since june', 'since july', 'since august',
|
|
187
|
+
'since september', 'since october', 'since november', 'since december',
|
|
188
|
+
'in january', 'in february', 'in march', 'in april',
|
|
189
|
+
'in may', 'in june', 'in july', 'in august',
|
|
190
|
+
'in september', 'in october', 'in november', 'in december',
|
|
191
|
+
'ago', 'recently', 'before', 'after', 'during',
|
|
192
|
+
'last few days', 'past week', 'past month',
|
|
193
|
+
'earlier this', 'earlier today', 'over the past'
|
|
194
|
+
]
|
|
195
|
+
|
|
196
|
+
export class IntentClassifier {
|
|
197
|
+
/**
|
|
198
|
+
* Classify the intent of a message
|
|
199
|
+
*/
|
|
200
|
+
classify(message: string): ClassificationResult {
|
|
201
|
+
const lower = message.toLowerCase().trim()
|
|
202
|
+
const secondary: Intent[] = []
|
|
203
|
+
|
|
204
|
+
// Phase 19 B3: Detect temporal signals for secondary intent
|
|
205
|
+
const hasTemporal = this.hasTemporalSignal(lower)
|
|
206
|
+
|
|
207
|
+
// Check in priority order — first confident match wins
|
|
208
|
+
|
|
209
|
+
// 1. no_action: very short messages, greetings, acknowledgments
|
|
210
|
+
if (this.isNoAction(lower)) {
|
|
211
|
+
return { primary: 'no_action', confidence: 0.95, secondary: [] }
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// 2. delete_memory: "forget that", "delete", "remove"
|
|
215
|
+
if (this.isDeleteMemory(lower)) {
|
|
216
|
+
return { primary: 'delete_memory', confidence: 0.90, secondary }
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 3. update_memory: "actually", "correction:", "change that to"
|
|
220
|
+
if (this.isUpdateMemory(lower)) {
|
|
221
|
+
return { primary: 'update_memory', confidence: 0.85, secondary }
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// 4. store_this: explicit "remember:", "save this:", "I prefer" (never for questions)
|
|
225
|
+
if (this.isStoreThis(lower, message)) {
|
|
226
|
+
if (this.hasDecisionSignal(lower)) secondary.push('decision_made')
|
|
227
|
+
return { primary: 'store_this', confidence: 0.90, secondary }
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// 5. decision_made: decision phrases + reasoning (never for questions)
|
|
231
|
+
if (this.isDecisionMade(lower, message)) {
|
|
232
|
+
if (this.hasComparisonSignal(lower)) secondary.push('comparison')
|
|
233
|
+
return { primary: 'decision_made', confidence: 0.85, secondary }
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 6. mistake_learned: correction/bug/lesson indicators
|
|
237
|
+
if (this.isMistakeLearned(lower)) {
|
|
238
|
+
return { primary: 'mistake_learned', confidence: 0.85, secondary }
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// 7. list_all: "list all", "what decisions", "show all"
|
|
242
|
+
if (this.isListAll(lower, message)) {
|
|
243
|
+
return { primary: 'list_all', confidence: 0.85, secondary }
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// 8. progress_update: completed task indicators (NOT questions)
|
|
247
|
+
if (this.isProgressUpdate(lower, message)) {
|
|
248
|
+
if (this.hasSessionSignal(lower)) secondary.push('session_start')
|
|
249
|
+
return { primary: 'progress_update', confidence: 0.85, secondary }
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// 9. comparison: vs, which is better, etc.
|
|
253
|
+
if (this.isComparison(lower)) {
|
|
254
|
+
if (this.isQuestion(lower, message)) secondary.push('question')
|
|
255
|
+
if (hasTemporal) secondary.push('exploration')
|
|
256
|
+
return { primary: 'comparison', confidence: 0.85, secondary }
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// 10. pattern_found: explicit pattern documentation
|
|
260
|
+
if (this.isPatternFound(lower)) {
|
|
261
|
+
return { primary: 'pattern_found', confidence: 0.80, secondary }
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// 11. session_start: starting/resuming work (Phase 19: narrowed check)
|
|
265
|
+
if (this.isSessionStart(lower)) {
|
|
266
|
+
secondary.push('context_needed')
|
|
267
|
+
return { primary: 'session_start', confidence: 0.90, secondary }
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// 12. exploration: timeline, trends, graph, history
|
|
271
|
+
if (this.isExploration(lower)) {
|
|
272
|
+
if (this.isQuestion(lower, message)) secondary.push('question')
|
|
273
|
+
if (hasTemporal) secondary.push('exploration')
|
|
274
|
+
return { primary: 'exploration', confidence: 0.75, secondary }
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// 13. question: starts with question word or ends with ?
|
|
278
|
+
// Phase 19 B1: Higher confidence for questions
|
|
279
|
+
if (this.isQuestion(lower, message)) {
|
|
280
|
+
if (this.hasComparisonSignal(lower)) secondary.push('comparison')
|
|
281
|
+
if (this.hasExplorationSignal(lower)) secondary.push('exploration')
|
|
282
|
+
if (hasTemporal) secondary.push('exploration')
|
|
283
|
+
|
|
284
|
+
// Phase 19 B1: ? → 0.95, question word → 0.90
|
|
285
|
+
const confidence = message.trim().endsWith('?') ? 0.95 : 0.90
|
|
286
|
+
return { primary: 'question', confidence, secondary }
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// 14. Default: context_needed
|
|
290
|
+
if (hasTemporal) secondary.push('exploration')
|
|
291
|
+
return { primary: 'context_needed', confidence: 0.60, secondary }
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private isNoAction(lower: string): boolean {
|
|
295
|
+
if (lower.length > 30) return false
|
|
296
|
+
const words = lower.split(/\s+/)
|
|
297
|
+
if (words.length > 5) return false
|
|
298
|
+
return NO_ACTION_PHRASES.some(p => lower === p || lower === p + '.' || lower === p + '!')
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
private isStoreThis(lower: string, original?: string): boolean {
|
|
302
|
+
// Questions are never storage requests — "Do I prefer X?" is a query, not "I prefer X"
|
|
303
|
+
if (original?.trim().endsWith('?')) return false
|
|
304
|
+
const firstWord = lower.split(/\s+/)[0] || ''
|
|
305
|
+
if (QUESTION_WORDS.includes(firstWord)) return false
|
|
306
|
+
// Phase 19 B4: Additional question guards
|
|
307
|
+
if (this.startsWithQuestionPattern(lower)) return false
|
|
308
|
+
return STORE_PHRASES.some(p => lower.includes(p))
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
private isDecisionMade(lower: string, original?: string): boolean {
|
|
312
|
+
// Questions are never decisions — "Did I decide to use X?" is a query
|
|
313
|
+
if (original?.trim().endsWith('?')) return false
|
|
314
|
+
const firstWord = lower.split(/\s+/)[0] || ''
|
|
315
|
+
if (QUESTION_WORDS.includes(firstWord)) return false
|
|
316
|
+
// Phase 19 B4: Additional question guards
|
|
317
|
+
if (this.startsWithQuestionPattern(lower)) return false
|
|
318
|
+
|
|
319
|
+
const hasDecision = DECISION_PHRASES.some(p => lower.includes(p))
|
|
320
|
+
if (!hasDecision) return false
|
|
321
|
+
// Higher confidence if reasoning is also present
|
|
322
|
+
const hasReasoning = REASONING_PHRASES.some(p => lower.includes(p))
|
|
323
|
+
return hasReasoning || lower.length > 30
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
private isMistakeLearned(lower: string): boolean {
|
|
327
|
+
return MISTAKE_PHRASES.some(p => lower.includes(p))
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
private isListAll(lower: string, _original: string): boolean {
|
|
331
|
+
return LIST_PHRASES.some(p => lower.includes(p))
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
private isProgressUpdate(lower: string, original: string): boolean {
|
|
335
|
+
// Must not be a question
|
|
336
|
+
if (original.trim().endsWith('?')) return false
|
|
337
|
+
const firstWord = lower.split(/\s+/)[0] || ''
|
|
338
|
+
if (QUESTION_WORDS.includes(firstWord)) return false
|
|
339
|
+
|
|
340
|
+
return PROGRESS_PHRASES.some(p => lower.includes(p))
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
private isComparison(lower: string): boolean {
|
|
344
|
+
return COMPARISON_PHRASES.some(p => lower.includes(p))
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
private isPatternFound(lower: string): boolean {
|
|
348
|
+
const hasPattern = PATTERN_PHRASES.some(p => lower.includes(p))
|
|
349
|
+
return hasPattern && lower.length > 50
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Phase 19 B2: Narrowed session_start detection.
|
|
354
|
+
* Must start at beginning of message AND have no progress indicators.
|
|
355
|
+
* "working on X" in the middle of a sentence is not a session start.
|
|
356
|
+
*/
|
|
357
|
+
private isSessionStart(lower: string): boolean {
|
|
358
|
+
// Must NOT have progress indicators (e.g. "finished working on X" is progress, not session start)
|
|
359
|
+
if (PROGRESS_INDICATORS.some(p => lower.includes(p))) return false
|
|
360
|
+
|
|
361
|
+
// Phase 19 B2: Session phrases must match near the start of the message
|
|
362
|
+
for (const phrase of SESSION_START_PHRASES) {
|
|
363
|
+
const idx = lower.indexOf(phrase)
|
|
364
|
+
if (idx !== -1 && idx <= 5) {
|
|
365
|
+
return true
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return false
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
private isExploration(lower: string): boolean {
|
|
372
|
+
return EXPLORATION_PHRASES.some(p => lower.includes(p))
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
private isQuestion(lower: string, original: string): boolean {
|
|
376
|
+
if (original.trim().endsWith('?')) return true
|
|
377
|
+
const firstWord = lower.split(/\s+/)[0] || ''
|
|
378
|
+
if (QUESTION_WORDS.includes(firstWord)) return true
|
|
379
|
+
// Phase 19 B4: "do I", "did we", "have we", "can we" patterns
|
|
380
|
+
if (this.startsWithQuestionPattern(lower)) return true
|
|
381
|
+
return false
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
private isUpdateMemory(lower: string): boolean {
|
|
385
|
+
return UPDATE_PHRASES.some(p => lower.includes(p))
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
private isDeleteMemory(lower: string): boolean {
|
|
389
|
+
return DELETE_PHRASES.some(p => lower.includes(p))
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Secondary signal checks
|
|
393
|
+
private hasDecisionSignal(lower: string): boolean {
|
|
394
|
+
return DECISION_PHRASES.some(p => lower.includes(p))
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
private hasComparisonSignal(lower: string): boolean {
|
|
398
|
+
return COMPARISON_PHRASES.some(p => lower.includes(p))
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
private hasExplorationSignal(lower: string): boolean {
|
|
402
|
+
return EXPLORATION_PHRASES.some(p => lower.includes(p))
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
private hasSessionSignal(lower: string): boolean {
|
|
406
|
+
return SESSION_START_PHRASES.some(p => lower.includes(p))
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Phase 19 B3: Detect temporal signals in the message.
|
|
411
|
+
* Used to add 'temporal' context to secondary intents.
|
|
412
|
+
*/
|
|
413
|
+
hasTemporalSignal(lower: string): boolean {
|
|
414
|
+
return TEMPORAL_PHRASES.some(p => lower.includes(p))
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Phase 19 B4: Extended question guards.
|
|
419
|
+
* Catches "do I", "did we", "have we", "can we" etc. patterns
|
|
420
|
+
* that start with auxiliary verbs not in the QUESTION_WORDS list.
|
|
421
|
+
*/
|
|
422
|
+
private startsWithQuestionPattern(lower: string): boolean {
|
|
423
|
+
const questionStarters = [
|
|
424
|
+
'do i ', 'do we ', 'do you ',
|
|
425
|
+
'did i ', 'did we ', 'did you ',
|
|
426
|
+
'have i ', 'have we ', 'have you ',
|
|
427
|
+
'has it ', 'has the ',
|
|
428
|
+
'can i ', 'can we ', 'can you ',
|
|
429
|
+
'will i ', 'will we ', 'will you ',
|
|
430
|
+
'am i ', 'was i ', 'were we ',
|
|
431
|
+
'shall we ', 'shall i ',
|
|
432
|
+
'tell me '
|
|
433
|
+
]
|
|
434
|
+
return questionStarters.some(p => lower.startsWith(p))
|
|
435
|
+
}
|
|
436
|
+
}
|