@itz4blitz/agentful 0.2.1 → 0.3.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.
@@ -7,60 +7,26 @@ tools: Read, Write, Edit, Glob, Grep
7
7
 
8
8
  # Conversation Skill
9
9
 
10
- This skill provides natural language processing capabilities for understanding user intent, managing conversation context, resolving references, and maintaining conversation history.
11
-
12
- ## When to Use
13
-
14
- This skill is invoked when:
15
- - User runs `/agentful <text>` with natural language input
16
- - Any command receives ambiguous or unclear input
17
- - Need to resolve pronouns or references from conversation history
18
- - Need to classify user intent before routing to handlers
19
-
20
- **Entry Point**: The `/agentful` command delegates to this skill for all natural language processing.
10
+ Provides natural language processing for understanding user intent, managing conversation context, resolving references, and maintaining conversation history.
21
11
 
22
12
  ## Responsibilities
23
13
 
24
- 1. **Intent Classification** - Determine what the user wants (feature, bug fix, status, etc.)
14
+ 1. **Intent Classification** - Determine what the user wants
25
15
  2. **Reference Resolution** - Resolve "it", "that", "this" to actual feature names
26
16
  3. **Entity Extraction** - Extract features, domains, subtasks mentioned
27
17
  4. **Ambiguity Detection** - Identify unclear requests and ask clarifying questions
28
18
  5. **Context Management** - Track conversation state, detect context loss
29
- 6. **Routing** - Route to appropriate handler (orchestrator, status, validate, etc.)
19
+ 6. **Routing** - Route to appropriate handler
30
20
  7. **History Tracking** - Maintain conversation history for context
31
21
 
32
- ## Core Functions
33
-
34
- ### 1. Intent Classification
22
+ ## Intent Classification
35
23
 
36
24
  ```typescript
37
- /**
38
- * Classify user intent with confidence score
39
- * @param message - User's current message
40
- * @param conversation_history - Recent conversation context
41
- * @param product_spec - Product features and requirements
42
- * @returns Intent classification with confidence
43
- */
44
25
  function classify_intent(
45
26
  message: string,
46
27
  conversation_history: ConversationMessage[],
47
28
  product_spec: ProductSpec
48
29
  ): IntentClassification {
49
- const intents = [
50
- 'feature_request',
51
- 'bug_report',
52
- 'question',
53
- 'clarification',
54
- 'status_update',
55
- 'mind_change',
56
- 'context_switch',
57
- 'approval',
58
- 'rejection',
59
- 'pause',
60
- 'continue'
61
- ];
62
-
63
- // Analyze message patterns
64
30
  const patterns = {
65
31
  feature_request: /(?:add|create|implement|build|new|feature|support|enable)/i,
66
32
  bug_report: /(?:bug|broken|error|issue|problem|wrong|doesn't work|fix)/i,
@@ -75,31 +41,13 @@ function classify_intent(
75
41
  continue: /(?:continue|resume|let's continue|back)/i
76
42
  };
77
43
 
78
- // Score each intent
79
44
  const scores = {};
80
45
  for (const [intent, pattern] of Object.entries(patterns)) {
81
46
  const matches = message.match(pattern);
82
- const baseScore = matches ? matches.length * 0.3 : 0;
83
-
84
- // Context-aware scoring
85
- let contextBonus = 0;
86
- if (conversation_history.length > 0) {
87
- const lastMessage = conversation_history[conversation_history.length - 1];
88
- if (lastMessage.role === 'assistant' && intent === 'clarification') {
89
- contextBonus += 0.2; // User asking for clarification after assistant response
90
- }
91
- if (lastMessage.intent === 'question' && intent === 'clarification') {
92
- contextBonus += 0.15; // Follow-up clarification
93
- }
94
- }
95
-
96
- scores[intent] = Math.min(0.95, baseScore + contextBonus);
47
+ scores[intent] = matches ? matches.length * 0.3 : 0;
97
48
  }
98
49
 
99
- // Find highest scoring intent
100
- const topIntent = Object.entries(scores).reduce((a, b) =>
101
- a[1] > b[1] ? a : b
102
- );
50
+ const topIntent = Object.entries(scores).reduce((a, b) => a[1] > b[1] ? a : b);
103
51
 
104
52
  return {
105
53
  intent: topIntent[0],
@@ -111,23 +59,11 @@ function classify_intent(
111
59
  .map(([intent, score]) => ({ intent, confidence: score }))
112
60
  };
113
61
  }
114
-
115
- interface IntentClassification {
116
- intent: string;
117
- confidence: number;
118
- alternative_intents: Array<{ intent: string; confidence: number }>;
119
- }
120
62
  ```
121
63
 
122
- ### 2. Feature Extraction
64
+ ## Entity Extraction
123
65
 
124
66
  ```typescript
125
- /**
126
- * Extract which feature/user is talking about
127
- * @param message - User's current message
128
- * @param product_spec - Product features and requirements
129
- * @returns Extracted feature reference
130
- */
131
67
  function extract_feature_mention(
132
68
  message: string,
133
69
  product_spec: ProductSpec
@@ -149,10 +85,9 @@ function extract_feature_mention(
149
85
  }
150
86
  }
151
87
 
152
- // Hierarchical structure
88
+ // Domain and nested feature matches
153
89
  if (product_spec.domains) {
154
90
  for (const [domainId, domain] of Object.entries(product_spec.domains)) {
155
- // Check domain mention
156
91
  if (message.toLowerCase().includes(domain.name.toLowerCase())) {
157
92
  mentioned.push({
158
93
  type: 'domain',
@@ -162,7 +97,6 @@ function extract_feature_mention(
162
97
  });
163
98
  }
164
99
 
165
- // Check feature mentions within domain
166
100
  if (domain.features) {
167
101
  for (const [featureId, feature] of Object.entries(domain.features)) {
168
102
  const featureName = feature.name || featureId;
@@ -180,9 +114,8 @@ function extract_feature_mention(
180
114
  }
181
115
  }
182
116
 
183
- // Subtask mentions
184
- const subtaskPattern = /(?:subtask|task|item)\s+(\d+)/i;
185
- const subtaskMatch = message.match(subtaskPattern);
117
+ // Subtask references
118
+ const subtaskMatch = message.match(/(?:subtask|task|item)\s+(\d+)/i);
186
119
  if (subtaskMatch) {
187
120
  mentioned.push({
188
121
  type: 'subtask_reference',
@@ -191,137 +124,32 @@ function extract_feature_mention(
191
124
  });
192
125
  }
193
126
 
194
- // Return highest confidence mention or null
195
- if (mentioned.length === 0) {
196
- return { type: 'none', confidence: 0 };
197
- }
198
-
127
+ if (mentioned.length === 0) return { type: 'none', confidence: 0 };
199
128
  return mentioned.sort((a, b) => b.confidence - a.confidence)[0];
200
129
  }
201
-
202
- interface FeatureMention {
203
- type: 'direct' | 'domain' | 'feature' | 'subtask_reference' | 'none';
204
- domain_id?: string;
205
- domain_name?: string;
206
- feature_id?: string;
207
- feature_name?: string;
208
- reference?: string;
209
- confidence: number;
210
- }
211
130
  ```
212
131
 
213
- ### 3. Bug Description Extraction
132
+ ## Ambiguity Detection
214
133
 
215
134
  ```typescript
216
- /**
217
- * Extract bug details from conversation context
218
- * @param message - User's current message
219
- * @param conversation_history - Recent conversation context
220
- * @returns Bug description with context
221
- */
222
- function extract_bug_description(
223
- message: string,
224
- conversation_history: ConversationMessage[]
225
- ): BugDescription {
226
- const bugInfo = {
227
- description: message,
228
- steps_to_reproduce: [],
229
- expected_behavior: null,
230
- actual_behavior: null,
231
- related_feature: null,
232
- severity: 'unknown',
233
- context_messages: []
234
- };
235
-
236
- // Look for "expected" vs "actual" patterns
237
- const expectedPattern = /(?:expected|should|supposed to):\s*(.+?)(?:\.|$)/i;
238
- const actualPattern = /(?:actually|but it|instead):\s*(.+?)(?:\.|$)/i;
239
-
240
- const expectedMatch = message.match(expectedPattern);
241
- const actualMatch = message.match(actualPattern);
242
-
243
- if (expectedMatch) {
244
- bugInfo.expected_behavior = expectedMatch[1].trim();
245
- }
246
- if (actualMatch) {
247
- bugInfo.actual_behavior = actualMatch[1].trim();
248
- }
249
-
250
- // Look for numbered steps
251
- const stepPattern = /^\d+\.\s*(.+)$/gm;
252
- const steps = message.match(stepPattern);
253
- if (steps) {
254
- bugInfo.steps_to_reproduce = steps.map(step => step.replace(/^\d+\.\s*/, ''));
255
- }
256
-
257
- // Infer severity from keywords
258
- const severeKeywords = ['crash', 'broken', 'fail', 'critical', 'blocking'];
259
- const minorKeywords = ['typo', 'cosmetic', 'minor', 'polish'];
260
-
261
- if (severeKeywords.some(kw => message.toLowerCase().includes(kw))) {
262
- bugInfo.severity = 'high';
263
- } else if (minorKeywords.some(kw => message.toLowerCase().includes(kw))) {
264
- bugInfo.severity = 'low';
265
- }
266
-
267
- // Gather relevant context from conversation history
268
- const relevantContext = conversation_history
269
- .filter(msg => {
270
- const msgTime = new Date(msg.timestamp);
271
- const now = new Date();
272
- const hoursDiff = (now.getTime() - msgTime.getTime()) / (1000 * 60 * 60);
273
- return hoursDiff < 2; // Last 2 hours
274
- })
275
- .slice(-5); // Last 5 messages
276
-
277
- bugInfo.context_messages = relevantContext;
278
-
279
- return bugInfo;
280
- }
281
-
282
- interface BugDescription {
283
- description: string;
284
- steps_to_reproduce: string[];
285
- expected_behavior: string | null;
286
- actual_behavior: string | null;
287
- related_feature: string | null;
288
- severity: 'high' | 'medium' | 'low' | 'unknown';
289
- context_messages: ConversationMessage[];
290
- }
291
- ```
292
-
293
- ### 4. Ambiguity Detection
294
-
295
- ```typescript
296
- /**
297
- * Detect unclear or ambiguous requests
298
- * @param message - User's current message
299
- * @returns Ambiguity analysis
300
- */
301
135
  function detect_ambiguity(message: string): AmbiguityAnalysis {
302
136
  const ambiguities = [];
303
137
  let confidence = 0;
304
138
 
305
- // Check for pronouns without context
306
- const pronounPattern = /\b(it|that|this|they|them|those)\b/gi;
307
- const pronouns = message.match(pronounPattern);
308
- if (pronouns && pronouns.length > 0) {
309
- // If message starts with pronoun, highly likely needs context
310
- if (/^(it|that|this|they|them)/i.test(message.trim())) {
311
- ambiguities.push({
312
- type: 'pronoun_without_antecedent',
313
- severity: 'high',
314
- text: pronouns[0],
315
- message: 'Pronoun at start of message without clear referent'
316
- });
317
- confidence = Math.max(confidence, 0.8);
318
- }
139
+ // Pronouns without context
140
+ const pronouns = message.match(/\b(it|that|this|they|them|those)\b/gi);
141
+ if (pronouns && /^(it|that|this|they|them)/i.test(message.trim())) {
142
+ ambiguities.push({
143
+ type: 'pronoun_without_antecedent',
144
+ severity: 'high',
145
+ text: pronouns[0],
146
+ message: 'Pronoun at start of message without clear referent'
147
+ });
148
+ confidence = 0.8;
319
149
  }
320
150
 
321
- // Check for vague verbs
322
- const vagueVerbs = ['fix', 'update', 'change', 'improve', 'handle'];
323
- const vagueVerbPattern = new RegExp(`\\b(${vagueVerbs.join('|')})\\b\\s+(?:it|that|this)`, 'i');
324
- const vagueMatch = message.match(vagueVerbPattern);
151
+ // Vague actions
152
+ const vagueMatch = message.match(/\b(fix|update|change|improve|handle)\b\s+(?:it|that|this)/i);
325
153
  if (vagueMatch) {
326
154
  ambiguities.push({
327
155
  type: 'vague_action',
@@ -332,19 +160,7 @@ function detect_ambiguity(message: string): AmbiguityAnalysis {
332
160
  confidence = Math.max(confidence, 0.6);
333
161
  }
334
162
 
335
- // Check for short messages (< 10 words)
336
- const wordCount = message.split(/\s+/).length;
337
- if (wordCount < 10 && wordCount > 1) {
338
- ambiguities.push({
339
- type: 'insufficient_detail',
340
- severity: 'low',
341
- text: message,
342
- message: 'Message is very short, may lack detail'
343
- });
344
- confidence = Math.max(confidence, 0.4);
345
- }
346
-
347
- // Check for multiple possible intents
163
+ // Multiple actions
348
164
  const actionWords = message.split(/\s+/).filter(word =>
349
165
  /^(add|create|fix|update|delete|remove|test|check|verify|deploy|build|run)/i.test(word)
350
166
  );
@@ -362,180 +178,14 @@ function detect_ambiguity(message: string): AmbiguityAnalysis {
362
178
  is_ambiguous: ambiguities.length > 0,
363
179
  confidence,
364
180
  ambiguities,
365
- suggestion: ambiguities.length > 0 ? generate_clarification_suggestion(ambiguities) : null
366
- };
367
- }
368
-
369
- interface AmbiguityAnalysis {
370
- is_ambiguous: boolean;
371
- confidence: number;
372
- ambiguities: Array<{
373
- type: string;
374
- severity: 'high' | 'medium' | 'low';
375
- text: string;
376
- message: string;
377
- }>;
378
- suggestion: string | null;
379
- }
380
-
381
- function generate_clarification_suggestion(ambiguities: any[]): string {
382
- const highSeverity = ambiguities.find(a => a.severity === 'high');
383
- if (highSeverity) {
384
- return 'Could you please provide more specific details? What specifically are you referring to?';
385
- }
386
- return 'I want to make sure I understand correctly. Could you provide a bit more detail?';
387
- }
388
- ```
389
-
390
- ### 5. Clarification Suggestions
391
-
392
- ```typescript
393
- /**
394
- * Generate helpful clarifying questions
395
- * @param ambiguous_message - The ambiguous user message
396
- * @param product_spec - Product features and requirements
397
- * @returns Suggested clarifying questions
398
- */
399
- function suggest_clarification(
400
- ambiguous_message: string,
401
- product_spec: ProductSpec
402
- ): ClarificationSuggestion {
403
- const questions = [];
404
-
405
- // Feature-specific clarification
406
- const featureMention = extract_feature_mention(ambiguous_message, product_spec);
407
- if (featureMention.type === 'none') {
408
- // No feature mentioned, ask which one
409
- if (product_spec.features) {
410
- const featureNames = Object.values(product_spec.features)
411
- .map(f => f.name || f.id)
412
- .slice(0, 5);
413
- questions.push({
414
- type: 'feature_selection',
415
- question: `Which feature are you referring to? For example: ${featureNames.join(', ')}`,
416
- options: featureNames
417
- });
418
- } else if (product_spec.domains) {
419
- const domainNames = Object.values(product_spec.domains)
420
- .map(d => d.name)
421
- .slice(0, 5);
422
- questions.push({
423
- type: 'domain_selection',
424
- question: `Which domain would you like to work on? For example: ${domainNames.join(', ')}`,
425
- options: domainNames
426
- });
427
- }
428
- }
429
-
430
- // Action-specific clarification
431
- const actions = ambiguous_message.match(/(?:add|create|fix|update|delete|remove|test|check)/gi);
432
- if (actions && actions.length > 1) {
433
- questions.push({
434
- type: 'action_priority',
435
- question: `I see multiple actions: ${actions.join(', ')}. Which would you like me to focus on first?`,
436
- options: actions
437
- });
438
- }
439
-
440
- // Bug report clarification
441
- if (/bug|broken|error|issue/i.test(ambiguous_message)) {
442
- questions.push({
443
- type: 'bug_details',
444
- question: 'Could you provide more details about the bug? What should happen vs. what actually happens?',
445
- options: null
446
- });
447
- }
448
-
449
- // Generic clarification if no specific ones
450
- if (questions.length === 0) {
451
- questions.push({
452
- type: 'generic',
453
- question: 'Could you please provide more details about what you\'d like me to do?',
454
- options: null
455
- });
456
- }
457
-
458
- return {
459
- primary_question: questions[0].question,
460
- follow_up_questions: questions.slice(1),
461
- suggested_responses: questions[0].options || []
462
- };
463
- }
464
-
465
- interface ClarificationSuggestion {
466
- primary_question: string;
467
- follow_up_questions: Array<{ type: string; question: string; options: string[] | null }>;
468
- suggested_responses: string[];
469
- }
470
- ```
471
-
472
- ## Conversation State Management
473
-
474
- ### State Structure
475
-
476
- ```typescript
477
- /**
478
- * Conversation state schema
479
- * Stored in: .agentful/conversation-state.json
480
- */
481
- interface ConversationState {
482
- // Current context
483
- current_feature: {
484
- domain_id?: string;
485
- feature_id?: string;
486
- feature_name?: string;
487
- subtask_id?: string;
488
- } | null;
489
-
490
- current_phase: 'idle' | 'planning' | 'implementing' | 'testing' | 'reviewing' | 'deploying';
491
-
492
- last_action: {
493
- type: string;
494
- description: string;
495
- timestamp: string;
496
- result?: any;
497
- } | null;
498
-
499
- // Related features context
500
- related_features: Array<{
501
- feature_id: string;
502
- feature_name: string;
503
- relationship: 'dependency' | 'similar' | 'related';
504
- }>;
505
-
506
- // User preferences
507
- user_preferences: {
508
- communication_style: 'concise' | 'detailed' | 'balanced';
509
- update_frequency: 'immediate' | 'summary' | 'on_completion';
510
- ask_before_deleting: boolean;
511
- test_automatically: boolean;
512
- };
513
-
514
- // Session tracking
515
- session_start: string;
516
- last_message_time: string;
517
- message_count: number;
518
-
519
- // Context health
520
- context_health: {
521
- is_stale: boolean;
522
- last_confirmed_intent: string;
523
- ambiguity_count: number;
524
- clarification_count: number;
181
+ suggestion: ambiguities.length > 0 ? 'Could you please provide more specific details?' : null
525
182
  };
526
183
  }
527
184
  ```
528
185
 
529
- ### Reference Resolution
186
+ ## Reference Resolution
530
187
 
531
188
  ```typescript
532
- /**
533
- * Resolve pronouns and references to previous messages
534
- * @param message - Current message with potential references
535
- * @param conversation_history - Message history
536
- * @param state - Current conversation state
537
- * @returns Resolved message with references expanded
538
- */
539
189
  function resolve_references(
540
190
  message: string,
541
191
  conversation_history: ConversationMessage[],
@@ -544,7 +194,7 @@ function resolve_references(
544
194
  let resolved = message;
545
195
  const references = [];
546
196
 
547
- // Replace "it", "that", "this" with actual referents
197
+ // Replace pronouns with actual referents
548
198
  const pronounMap = {
549
199
  'it': state.current_feature?.feature_name,
550
200
  'that': state.last_action?.description,
@@ -556,16 +206,12 @@ function resolve_references(
556
206
  const pattern = new RegExp(`\\b${pronoun}\\b`, 'gi');
557
207
  if (pattern.test(message)) {
558
208
  resolved = resolved.replace(pattern, referent);
559
- references.push({
560
- original: pronoun,
561
- resolved: referent,
562
- type: 'pronoun'
563
- });
209
+ references.push({ original: pronoun, resolved: referent, type: 'pronoun' });
564
210
  }
565
211
  }
566
212
  }
567
213
 
568
- // Resolve "the feature", "the bug", etc.
214
+ // Replace definite references
569
215
  const definiteReferences = {
570
216
  'the feature': state.current_feature?.feature_name,
571
217
  'the bug': state.last_action?.type === 'bug_fix' ? state.last_action.description : null,
@@ -575,11 +221,7 @@ function resolve_references(
575
221
  for (const [phrase, referent] of Object.entries(definiteReferences)) {
576
222
  if (referent) {
577
223
  resolved = resolved.replace(new RegExp(phrase, 'gi'), referent);
578
- references.push({
579
- original: phrase,
580
- resolved: referent,
581
- type: 'definite_reference'
582
- });
224
+ references.push({ original: phrase, resolved: referent, type: 'definite_reference' });
583
225
  }
584
226
  }
585
227
 
@@ -590,28 +232,35 @@ function resolve_references(
590
232
  confidence: references.length > 0 ? 0.85 : 1.0
591
233
  };
592
234
  }
235
+ ```
236
+
237
+ ## Context Management
593
238
 
594
- interface ResolvedMessage {
595
- original: string;
596
- resolved: string;
597
- references: Array<{
598
- original: string;
599
- resolved: string;
239
+ ```typescript
240
+ interface ConversationState {
241
+ current_feature: {
242
+ domain_id?: string;
243
+ feature_id?: string;
244
+ feature_name?: string;
245
+ subtask_id?: string;
246
+ } | null;
247
+ current_phase: 'idle' | 'planning' | 'implementing' | 'testing' | 'reviewing' | 'deploying';
248
+ last_action: {
600
249
  type: string;
250
+ description: string;
251
+ timestamp: string;
252
+ result?: any;
253
+ } | null;
254
+ related_features: Array<{
255
+ feature_id: string;
256
+ feature_name: string;
257
+ relationship: 'dependency' | 'similar' | 'related';
601
258
  }>;
602
- confidence: number;
259
+ session_start: string;
260
+ last_message_time: string;
261
+ message_count: number;
603
262
  }
604
- ```
605
-
606
- ### Context Loss Recovery
607
263
 
608
- ```typescript
609
- /**
610
- * Detect and handle context loss (>24h gaps)
611
- * @param conversation_history - Full conversation history
612
- * @param state - Current conversation state
613
- * @returns Context recovery recommendation
614
- */
615
264
  function detect_context_loss(
616
265
  conversation_history: ConversationMessage[],
617
266
  state: ConversationState
@@ -619,22 +268,15 @@ function detect_context_loss(
619
268
  const now = new Date();
620
269
  const lastMessage = conversation_history[conversation_history.length - 1];
621
270
  const lastMessageTime = new Date(lastMessage?.timestamp || state.session_start);
622
-
623
271
  const hoursDiff = (now.getTime() - lastMessageTime.getTime()) / (1000 * 60 * 60);
624
272
 
625
273
  if (hoursDiff > 24) {
626
- // Context is stale
627
274
  return {
628
275
  is_stale: true,
629
276
  hours_since_last_message: Math.round(hoursDiff),
630
277
  recommendation: 'summarize_and_confirm',
631
- message: `It's been ${Math.round(hoursDiff)} hours since our last conversation. Before I continue, let me confirm what we were working on.`,
632
- context_summary: {
633
- last_feature: state.current_feature?.feature_name,
634
- last_phase: state.current_phase,
635
- last_action: state.last_action?.description
636
- },
637
- suggested_confirmation: `We were working on ${state.current_feature?.feature_name || 'a feature'}. Would you like to continue with that, or would you prefer to start something new?`
278
+ message: `It's been ${Math.round(hoursDiff)} hours since our last conversation.`,
279
+ suggested_confirmation: `We were working on ${state.current_feature?.feature_name || 'a feature'}. Continue or start new?`
638
280
  };
639
281
  }
640
282
 
@@ -645,189 +287,11 @@ function detect_context_loss(
645
287
  message: null
646
288
  };
647
289
  }
648
-
649
- interface ContextRecovery {
650
- is_stale: boolean;
651
- hours_since_last_message: number;
652
- recommendation: 'summarize_and_confirm' | 'continue' | 'reset';
653
- message: string | null;
654
- context_summary?: {
655
- last_feature?: string;
656
- last_phase?: string;
657
- last_action?: string;
658
- };
659
- suggested_confirmation?: string;
660
- }
661
- ```
662
-
663
- ### User Preference Learning
664
-
665
- ```typescript
666
- /**
667
- * Learn and adapt to user preferences
668
- * @param conversation_history - Recent conversation history
669
- * @param state - Current conversation state
670
- * @returns Updated user preferences
671
- */
672
- function learn_user_preferences(
673
- conversation_history: ConversationMessage[],
674
- state: ConversationState
675
- ): UserPreferences {
676
- const preferences = { ...state.user_preferences };
677
-
678
- // Analyze user's communication style
679
- const userMessages = conversation_history.filter(m => m.role === 'user').slice(-20);
680
- const avgMessageLength = userMessages.reduce((sum, m) =>
681
- sum + m.content.split(/\s+/).length, 0
682
- ) / userMessages.length;
683
-
684
- if (avgMessageLength < 10) {
685
- preferences.communication_style = 'concise';
686
- } else if (avgMessageLength > 30) {
687
- preferences.communication_style = 'detailed';
688
- } else {
689
- preferences.communication_style = 'balanced';
690
- }
691
-
692
- // Detect preference for updates
693
- const statusRequests = userMessages.filter(m =>
694
- /status|progress|where are we|what's left/i.test(m.content)
695
- ).length;
696
-
697
- if (statusRequests > 3) {
698
- preferences.update_frequency = 'summary';
699
- } else if (statusRequests === 0 && userMessages.length > 10) {
700
- preferences.update_frequency = 'on_completion';
701
- }
702
-
703
- // Detect safety preference
704
- const confirmationRequests = userMessages.filter(m =>
705
- /are you sure|double check|verify|confirm/i.test(m.content)
706
- ).length;
707
-
708
- preferences.ask_before_deleting = confirmationRequests > 2;
709
-
710
- // Detect testing preference
711
- const testMentions = userMessages.filter(m =>
712
- /test|testing|tests|coverage/i.test(m.content)
713
- ).length;
714
-
715
- preferences.test_automatically = testMentions > 2;
716
-
717
- return preferences;
718
- }
719
-
720
- interface UserPreferences {
721
- communication_style: 'concise' | 'detailed' | 'balanced';
722
- update_frequency: 'immediate' | 'summary' | 'on_completion';
723
- ask_before_deleting: boolean;
724
- test_automatically: boolean;
725
- }
726
- ```
727
-
728
- ## Conversation History Management
729
-
730
- ### History File Structure
731
-
732
- ```bash
733
- # Stored in: .agentful/conversation-history.json
734
- {
735
- "version": "1.0",
736
- "session_id": "uuid",
737
- "started_at": "2026-01-18T00:00:00Z",
738
- "messages": [
739
- {
740
- "id": "msg-uuid",
741
- "role": "user|assistant|system",
742
- "content": "Message text",
743
- "timestamp": "2026-01-18T00:00:00Z",
744
- "intent": "feature_request",
745
- "entities": {
746
- "feature_id": "login",
747
- "domain_id": "authentication"
748
- },
749
- "references_resolved": ["it -> login feature"]
750
- }
751
- ],
752
- "context_snapshot": {
753
- "current_feature": "login",
754
- "current_phase": "implementing",
755
- "related_features": ["register", "logout"]
756
- }
757
- }
758
- ```
759
-
760
- ### History Operations
761
-
762
- ```typescript
763
- /**
764
- * Add message to conversation history
765
- */
766
- function add_message_to_history(
767
- message: ConversationMessage,
768
- history_path: string = '.agentful/conversation-history.json'
769
- ): void {
770
- let history = read_conversation_history(history_path);
771
-
772
- history.messages.push({
773
- ...message,
774
- id: message.id || generate_uuid(),
775
- timestamp: message.timestamp || new Date().toISOString()
776
- });
777
-
778
- // Keep only last 100 messages to prevent file bloat
779
- if (history.messages.length > 100) {
780
- history.messages = history.messages.slice(-100);
781
- }
782
-
783
- Write(history_path, JSON.stringify(history, null, 2));
784
- }
785
-
786
- /**
787
- * Read conversation history
788
- */
789
- function read_conversation_history(
790
- history_path: string = '.agentful/conversation-history.json'
791
- ): ConversationHistory {
792
- try {
793
- const content = Read(history_path);
794
- return JSON.parse(content);
795
- } catch (error) {
796
- // Initialize new history
797
- return {
798
- version: "1.0",
799
- session_id: generate_uuid(),
800
- started_at: new Date().toISOString(),
801
- messages: [],
802
- context_snapshot: null
803
- };
804
- }
805
- }
806
-
807
- /**
808
- * Get recent conversation context
809
- */
810
- function get_recent_context(
811
- history_path: string = '.agentful/conversation-history.json',
812
- message_count: number = 10
813
- ): ConversationMessage[] {
814
- const history = read_conversation_history(history_path);
815
- return history.messages.slice(-message_count);
816
- }
817
290
  ```
818
291
 
819
292
  ## Routing Logic
820
293
 
821
- ### Route to Handler
822
-
823
294
  ```typescript
824
- /**
825
- * Determine which handler should process the classified intent
826
- * @param intent - Classified intent from user message
827
- * @param entities - Extracted entities (features, domains, etc.)
828
- * @param state - Current conversation state
829
- * @returns Routing decision with handler and context
830
- */
831
295
  function route_to_handler(
832
296
  intent: IntentClassification,
833
297
  entities: FeatureMention,
@@ -842,9 +306,6 @@ function route_to_handler(
842
306
  skill: null,
843
307
  context: {
844
308
  intent: intentName,
845
- message: entities.feature_name
846
- ? `User wants to ${intentName === 'feature_request' ? 'build' : 'fix'} ${entities.feature_name}`
847
- : 'User has a request that needs classification',
848
309
  feature_id: entities.feature_id,
849
310
  domain_id: entities.domain_id,
850
311
  work_type: intentName === 'feature_request' ? 'FEATURE_DEVELOPMENT' : 'BUGFIX'
@@ -852,7 +313,7 @@ function route_to_handler(
852
313
  };
853
314
  }
854
315
 
855
- // Status inquiries → product-tracking skill
316
+ // Status inquiries → product-tracking
856
317
  if (intentName === 'status_update') {
857
318
  return {
858
319
  handler: 'product-tracking',
@@ -865,7 +326,7 @@ function route_to_handler(
865
326
  };
866
327
  }
867
328
 
868
- // Validation requests → validation skill
329
+ // Validation → validation skill
869
330
  if (/test|validate|check/i.test(intentName)) {
870
331
  return {
871
332
  handler: 'validation',
@@ -877,42 +338,28 @@ function route_to_handler(
877
338
  };
878
339
  }
879
340
 
880
- // Decision handling → decision-handler
881
- if (intentName === 'decision' || /decide|choice|option/i.test(intentName)) {
882
- return {
883
- handler: 'decision-handler',
884
- skill: null,
885
- context: {
886
- intent: intentName
887
- }
888
- };
889
- }
890
-
891
341
  // Product planning → product-planning skill
892
342
  if (/plan|requirements|spec|analyze/i.test(intentName)) {
893
343
  return {
894
344
  handler: 'product-planning',
895
345
  skill: 'product-planning',
896
- context: {
897
- intent: intentName
898
- }
346
+ context: { intent: intentName }
899
347
  };
900
348
  }
901
349
 
902
- // Approval/continue → orchestrator (resume current work)
350
+ // Approval/continue → orchestrator (resume)
903
351
  if (intentName === 'approval' || intentName === 'continue') {
904
352
  return {
905
353
  handler: 'orchestrator',
906
354
  skill: null,
907
355
  context: {
908
356
  intent: 'continue',
909
- message: 'User approved or wants to continue current work',
910
357
  resume_feature: state.current_feature
911
358
  }
912
359
  };
913
360
  }
914
361
 
915
- // Rejection/stopupdate state, don't delegate
362
+ // Rejection/pauseinline
916
363
  if (intentName === 'rejection' || intentName === 'pause') {
917
364
  return {
918
365
  handler: 'inline',
@@ -924,7 +371,7 @@ function route_to_handler(
924
371
  };
925
372
  }
926
373
 
927
- // Questions/clarificationshandle inline
374
+ // Questions → inline
928
375
  if (intentName === 'question' || intentName === 'clarification') {
929
376
  return {
930
377
  handler: 'inline',
@@ -936,7 +383,7 @@ function route_to_handler(
936
383
  };
937
384
  }
938
385
 
939
- // Default: handle inline or ask for clarification
386
+ // Default: inline with clarification
940
387
  return {
941
388
  handler: 'inline',
942
389
  skill: null,
@@ -946,337 +393,68 @@ function route_to_handler(
946
393
  }
947
394
  };
948
395
  }
949
-
950
- interface RoutingDecision {
951
- handler: 'orchestrator' | 'product-tracking' | 'validation' | 'decision-handler' | 'product-planning' | 'inline';
952
- skill: string | null; // Skill name for Task delegation
953
- context: {
954
- intent: string;
955
- message?: string;
956
- feature_id?: string;
957
- domain_id?: string;
958
- work_type?: string;
959
- [key: string]: any;
960
- };
961
- }
962
- ```
963
-
964
- ### Execute Routing
965
-
966
- ```typescript
967
- /**
968
- * Execute the routing decision
969
- * @param routing - Routing decision from route_to_handler
970
- * @param userMessage - Original user message
971
- * @param resolved - Resolved message with references expanded
972
- */
973
- function execute_routing(
974
- routing: RoutingDecision,
975
- userMessage: string,
976
- resolved: ResolvedMessage
977
- ): void {
978
- switch (routing.handler) {
979
- case 'orchestrator':
980
- // Delegate to orchestrator agent
981
- Task('orchestrator',
982
- `${routing.context.message || userMessage}
983
-
984
- Work Type: ${routing.context.work_type || 'FEATURE_DEVELOPMENT'}
985
- ${routing.context.feature_id ? `Feature: ${routing.context.feature_id}` : ''}
986
- ${routing.context.domain_id ? `Domain: ${routing.context.domain_id}` : ''}
987
-
988
- Classify and execute appropriate workflow.`
989
- );
990
- break;
991
-
992
- case 'product-tracking':
993
- // Delegate to product-tracking skill
994
- Task('product-tracking',
995
- `Show status and progress.
996
- ${routing.context.feature_filter ? `Filter: feature ${routing.context.feature_filter}` : ''}
997
- ${routing.context.domain_filter ? `Filter: domain ${routing.context.domain_filter}` : ''}`
998
- );
999
- break;
1000
-
1001
- case 'validation':
1002
- // Delegate to validation skill
1003
- Task('validation',
1004
- `Run quality gates.
1005
- Scope: ${routing.context.scope || 'all'}`
1006
- );
1007
- break;
1008
-
1009
- case 'decision-handler':
1010
- // For now, show how to use /agentful-decide
1011
- return `You have pending decisions. Run \`/agentful-decide\` to review and resolve them.`;
1012
- break;
1013
-
1014
- case 'product-planning':
1015
- // Delegate to product-planning skill
1016
- Task('product-planning', userMessage);
1017
- break;
1018
-
1019
- case 'inline':
1020
- // Handle inline (no delegation needed)
1021
- if (routing.context.needs_clarification) {
1022
- return generate_clarification_response(userMessage, routing.context);
1023
- } else if (routing.context.action === 'pause_work') {
1024
- pause_current_work();
1025
- return 'Work paused. Run `/agentful` with your next request when ready to continue.';
1026
- } else if (routing.context.intent === 'question') {
1027
- return answer_question(userMessage, routing.context);
1028
- }
1029
- break;
1030
- }
1031
- }
1032
396
  ```
1033
397
 
1034
- ## Integration with Orchestrator
1035
-
1036
- ### Delegation Interface
398
+ ## History Management
1037
399
 
1038
400
  ```typescript
1039
- /**
1040
- * Determine if delegation to another skill is needed
1041
- * @param intent - Classified intent from user message
1042
- * @param entities - Extracted entities (features, domains, etc.)
1043
- * @returns Delegation decision
1044
- */
1045
- function determine_delegation(
1046
- intent: IntentClassification,
1047
- entities: FeatureMention
1048
- ): DelegationDecision {
1049
- // Feature-related intents -> delegate to appropriate agent
1050
- if (['feature_request', 'bug_report', 'status_update'].includes(intent.intent)) {
1051
- if (entities.type === 'feature' || entities.type === 'direct') {
1052
- return {
1053
- should_delegate: true,
1054
- target_skill: determine_skill_for_feature(entities),
1055
- context: {
1056
- intent: intent.intent,
1057
- feature_id: entities.feature_id,
1058
- domain_id: entities.domain_id
1059
- }
1060
- };
1061
- }
1062
- }
1063
-
1064
- // Validation request -> delegate to validation skill
1065
- if (/test|check|validate|verify/i.test(intent.intent)) {
1066
- return {
1067
- should_delegate: true,
1068
- target_skill: 'validation',
1069
- context: {
1070
- intent: intent.intent
1071
- }
1072
- };
1073
- }
1074
-
1075
- // Product tracking -> delegate to product-tracking skill
1076
- if (['status_update', 'progress'].includes(intent.intent)) {
1077
- return {
1078
- should_delegate: true,
1079
- target_skill: 'product-tracking',
1080
- context: {
1081
- intent: intent.intent
1082
- }
1083
- };
1084
- }
1085
-
1086
- return {
1087
- should_delegate: false,
1088
- target_skill: null,
1089
- context: null
1090
- };
1091
- }
1092
-
1093
- interface DelegationDecision {
1094
- should_delegate: boolean;
1095
- target_skill: string | null;
1096
- context: any;
1097
- }
1098
-
1099
- function determine_skill_for_feature(entities: FeatureMention): string {
1100
- // Map domains/features to appropriate skills
1101
- const domainSkillMap = {
1102
- 'authentication': 'backend',
1103
- 'user-management': 'backend',
1104
- 'database': 'backend',
1105
- 'frontend': 'frontend',
1106
- 'ui': 'frontend',
1107
- 'testing': 'tester'
1108
- };
1109
-
1110
- if (entities.domain_name) {
1111
- const domainKey = Object.keys(domainSkillMap).find(key =>
1112
- entities.domain_name.toLowerCase().includes(key)
1113
- );
1114
- if (domainKey) {
1115
- return domainSkillMap[domainKey];
1116
- }
1117
- }
1118
-
1119
- return 'backend'; // Default
401
+ // Stored in: .agentful/conversation-history.json
402
+ interface ConversationHistory {
403
+ version: "1.0";
404
+ session_id: string;
405
+ started_at: string;
406
+ messages: ConversationMessage[];
407
+ context_snapshot: any;
1120
408
  }
1121
- ```
1122
-
1123
- ### Completion Tracking Integration
1124
-
1125
- ```typescript
1126
- /**
1127
- * Update conversation state after action completion
1128
- * @param state - Current conversation state
1129
- * @param action_result - Result from delegated skill
1130
- * @returns Updated conversation state
1131
- */
1132
- function update_conversation_state(
1133
- state: ConversationState,
1134
- action_result: ActionResult
1135
- ): ConversationState {
1136
- const updated = { ...state };
1137
-
1138
- // Update last action
1139
- updated.last_action = {
1140
- type: action_result.type,
1141
- description: action_result.description,
1142
- timestamp: new Date().toISOString(),
1143
- result: action_result
1144
- };
1145
409
 
1146
- // Update phase based on action result
1147
- if (action_result.status === 'complete') {
1148
- if (state.current_phase === 'implementing') {
1149
- updated.current_phase = 'testing';
1150
- } else if (state.current_phase === 'testing') {
1151
- updated.current_phase = 'reviewing';
1152
- }
1153
- }
410
+ function add_message_to_history(
411
+ message: ConversationMessage,
412
+ history_path: string = '.agentful/conversation-history.json'
413
+ ): void {
414
+ let history = read_conversation_history(history_path);
1154
415
 
1155
- // Update message count and time
1156
- updated.message_count++;
1157
- updated.last_message_time = new Date().toISOString();
416
+ history.messages.push({
417
+ ...message,
418
+ id: message.id || generate_uuid(),
419
+ timestamp: message.timestamp || new Date().toISOString()
420
+ });
1158
421
 
1159
- // Clear ambiguity count on successful action
1160
- if (action_result.status === 'success') {
1161
- updated.context_health.ambiguity_count = 0;
1162
- updated.context_health.clarification_count = 0;
422
+ // Keep last 100 messages
423
+ if (history.messages.length > 100) {
424
+ history.messages = history.messages.slice(-100);
1163
425
  }
1164
426
 
1165
- return updated;
427
+ Write(history_path, JSON.stringify(history, null, 2));
1166
428
  }
1167
- ```
1168
429
 
1169
- ## Edge Case Handling
1170
-
1171
- ### Mind Changes
1172
-
1173
- ```typescript
1174
- /**
1175
- * Detect and handle user mind changes
1176
- * @param message - Current message
1177
- * @param state - Current conversation state
1178
- * @returns Mind change detection result
1179
- */
1180
- function detect_mind_change(
1181
- message: string,
1182
- state: ConversationState
1183
- ): MindChangeDetection {
1184
- const mindChangePatterns = [
1185
- /actually/i,
1186
- /wait/i,
1187
- /never mind/i,
1188
- /forget that/i,
1189
- /change\s+my\s+mind/i,
1190
- /instead/i,
1191
- /stop\s+(?:that|it)/i
1192
- ];
1193
-
1194
- const hasMindChange = mindChangePatterns.some(pattern => pattern.test(message));
1195
-
1196
- if (hasMindChange) {
430
+ function read_conversation_history(
431
+ history_path: string = '.agentful/conversation-history.json'
432
+ ): ConversationHistory {
433
+ try {
434
+ const content = Read(history_path);
435
+ return JSON.parse(content);
436
+ } catch (error) {
1197
437
  return {
1198
- detected: true,
1199
- confidence: 0.8,
1200
- previous_intent: state.last_action?.type,
1201
- suggestion: 'I understand you\'d like to change direction. What would you like to do instead?',
1202
- reset_context: /never mind|forget that|stop/i.test(message)
438
+ version: "1.0",
439
+ session_id: generate_uuid(),
440
+ started_at: new Date().toISOString(),
441
+ messages: [],
442
+ context_snapshot: null
1203
443
  };
1204
444
  }
1205
-
1206
- return {
1207
- detected: false,
1208
- confidence: 0,
1209
- previous_intent: null,
1210
- suggestion: null,
1211
- reset_context: false
1212
- };
1213
- }
1214
-
1215
- interface MindChangeDetection {
1216
- detected: boolean;
1217
- confidence: number;
1218
- previous_intent: string | null;
1219
- suggestion: string | null;
1220
- reset_context: boolean;
1221
- }
1222
- ```
1223
-
1224
- ### Stale Context Handling
1225
-
1226
- ```typescript
1227
- /**
1228
- * Handle stale context when references no longer make sense
1229
- * @param message - Current message
1230
- * @param state - Current conversation state
1231
- * @returns Stale context handling response
1232
- */
1233
- function handle_stale_context(
1234
- message: string,
1235
- state: ConversationState
1236
- ): StaleContextResponse {
1237
- // Check if current feature is referenced but stale
1238
- const featureReference = extract_feature_mention(message, null);
1239
-
1240
- if (featureReference.type === 'none' && state.current_feature) {
1241
- // User said "it" but current feature is old
1242
- const hoursSinceLastAction = state.last_action
1243
- ? (Date.now() - new Date(state.last_action.timestamp).getTime()) / (1000 * 60 * 60)
1244
- : Infinity;
1245
-
1246
- if (hoursSinceLastAction > 4) {
1247
- return {
1248
- is_stale: true,
1249
- suggestion: `I'm not sure what you're referring to. We last worked on ${state.current_feature.feature_name} ${Math.round(hoursSinceLastAction)} hours ago. Are you still referring to that?`,
1250
- confirm_needed: true
1251
- };
1252
- }
1253
- }
1254
-
1255
- return {
1256
- is_stale: false,
1257
- suggestion: null,
1258
- confirm_needed: false
1259
- };
1260
- }
1261
-
1262
- interface StaleContextResponse {
1263
- is_stale: boolean;
1264
- suggestion: string | null;
1265
- confirm_needed: boolean;
1266
445
  }
1267
446
  ```
1268
447
 
1269
- ## Usage Example
448
+ ## Complete Processing Flow
1270
449
 
1271
450
  ```typescript
1272
- // Complete conversation processing flow
1273
451
  async function process_conversation(userMessage: string): Promise<ConversationResponse> {
1274
- // 1. Load conversation state and history
452
+ // 1. Load state and history
1275
453
  const state = load_conversation_state('.agentful/conversation-state.json');
1276
454
  const history = read_conversation_history('.agentful/conversation-history.json');
1277
455
  const productSpec = load_product_spec('.claude/product/');
1278
456
 
1279
- // 2. Check for context loss
457
+ // 2. Check context loss
1280
458
  const contextRecovery = detect_context_loss(history.messages, state);
1281
459
  if (contextRecovery.is_stale) {
1282
460
  return {
@@ -1306,18 +484,17 @@ async function process_conversation(userMessage: string): Promise<ConversationRe
1306
484
  // 7. Detect ambiguity
1307
485
  const ambiguity = detect_ambiguity(resolved.resolved);
1308
486
  if (ambiguity.is_ambiguous && ambiguity.confidence > 0.6) {
1309
- const clarification = suggest_clarification(resolved.resolved, productSpec);
1310
487
  return {
1311
488
  type: 'clarification_needed',
1312
- message: clarification.primary_question,
1313
- suggestions: clarification.suggested_responses
489
+ message: ambiguity.suggestion,
490
+ suggestions: []
1314
491
  };
1315
492
  }
1316
493
 
1317
- // 8. Route to appropriate handler
494
+ // 8. Route to handler
1318
495
  const routing = route_to_handler(intent, entities, state);
1319
496
 
1320
- // 9. Add user message to history
497
+ // 9. Add to history
1321
498
  add_message_to_history({
1322
499
  role: 'user',
1323
500
  content: userMessage,
@@ -1329,7 +506,7 @@ async function process_conversation(userMessage: string): Promise<ConversationRe
1329
506
  // 10. Execute routing
1330
507
  execute_routing(routing, userMessage, resolved);
1331
508
 
1332
- // 11. Update conversation state
509
+ // 11. Update state
1333
510
  state.last_message_time = new Date().toISOString();
1334
511
  state.message_count++;
1335
512
  if (entities.feature_id) {
@@ -1347,41 +524,46 @@ async function process_conversation(userMessage: string): Promise<ConversationRe
1347
524
  context: routing.context
1348
525
  };
1349
526
  }
1350
- ```
1351
527
 
1352
- ### Complete Flow Diagram
528
+ function execute_routing(
529
+ routing: RoutingDecision,
530
+ userMessage: string,
531
+ resolved: ResolvedMessage
532
+ ): void {
533
+ switch (routing.handler) {
534
+ case 'orchestrator':
535
+ Task('orchestrator', `${routing.context.message || userMessage}
536
+ Work Type: ${routing.context.work_type || 'FEATURE_DEVELOPMENT'}
537
+ ${routing.context.feature_id ? `Feature: ${routing.context.feature_id}` : ''}
538
+ ${routing.context.domain_id ? `Domain: ${routing.context.domain_id}` : ''}`);
539
+ break;
1353
540
 
1354
- ```
1355
- User Input
1356
-
1357
- Load State & History
1358
-
1359
- Context Loss Check ──→ [STALE] ──→ Confirm & Resume
1360
- [FRESH]
1361
- Mind Change Detection ──→ [DETECTED] ──→ Reset Context
1362
- ↓ [CONTINUE]
1363
- Reference Resolution
1364
-
1365
- Intent Classification
1366
-
1367
- Entity Extraction
1368
-
1369
- Ambiguity Detection ──→ [AMBIGUOUS] ──→ Ask Clarifying Question
1370
- [CLEAR]
1371
- Route to Handler
1372
-
1373
- ├─→ [orchestrator] ──→ Task('orchestrator', context)
1374
- ├─→ [product-tracking] ──→ Task('product-tracking', context)
1375
- ├─→ [validation] ──→ Task('validation', context)
1376
- ├─→ [decision-handler] ──→ Show /agentful-decide
1377
- ├─→ [product-planning] ──→ Task('product-planning', context)
1378
- └─→ [inline] ──→ Generate Response Directly
1379
-
1380
- Add to History
1381
-
1382
- Update State
1383
-
1384
- Done
541
+ case 'product-tracking':
542
+ Task('product-tracking', `Show status and progress.
543
+ ${routing.context.feature_filter ? `Filter: feature ${routing.context.feature_filter}` : ''}
544
+ ${routing.context.domain_filter ? `Filter: domain ${routing.context.domain_filter}` : ''}`);
545
+ break;
546
+
547
+ case 'validation':
548
+ Task('validation', `Run quality gates. Scope: ${routing.context.scope || 'all'}`);
549
+ break;
550
+
551
+ case 'product-planning':
552
+ Task('product-planning', userMessage);
553
+ break;
554
+
555
+ case 'inline':
556
+ if (routing.context.needs_clarification) {
557
+ return 'Could you please provide more details about what you\'d like me to do?';
558
+ } else if (routing.context.action === 'pause_work') {
559
+ pause_current_work();
560
+ return 'Work paused. Run `/agentful` when ready to continue.';
561
+ } else if (routing.context.intent === 'question') {
562
+ return answer_question(userMessage, routing.context);
563
+ }
564
+ break;
565
+ }
566
+ }
1385
567
  ```
1386
568
 
1387
569
  ## File Locations
@@ -1390,18 +572,13 @@ Done
1390
572
  .agentful/
1391
573
  ├── conversation-state.json # Current conversation state
1392
574
  ├── conversation-history.json # Full message history
1393
- └── user-preferences.json # Learned user preferences (optional)
575
+ └── user-preferences.json # Learned user preferences
1394
576
  ```
1395
577
 
1396
- ## Best Practices
1397
-
1398
- 1. **Always resolve references** before processing intent
1399
- 2. **Check for context loss** after long gaps (>24h)
1400
- 3. **Detect ambiguity early** and ask clarifying questions
1401
- 4. **Learn user preferences** over time
1402
- 5. **Track related features** for better context
1403
- 6. **Handle mind changes gracefully** without losing all context
1404
- 7. **Delegate appropriately** based on intent and entities
1405
- 8. **Keep history manageable** (last 100 messages)
1406
- 9. **Update state after every action**
1407
- 10. **Provide summaries** after context recovery
578
+ ## Flow Diagram
579
+
580
+ ```
581
+ User Input Load State/History Context Loss Check → Mind Change Detection →
582
+ Reference Resolution Intent Classification Entity Extraction →
583
+ Ambiguity Detection Route to Handler → Add to History → Update State → Done
584
+ ```