@riotprompt/riotprompt 0.0.9 → 0.0.10

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.
Files changed (49) hide show
  1. package/BUG-ANALYSIS.md +523 -0
  2. package/CODE-REVIEW-SUMMARY.md +330 -0
  3. package/FIXES-APPLIED.md +437 -0
  4. package/dist/chat.d.ts +1 -1
  5. package/dist/chat.js +2 -5
  6. package/dist/chat.js.map +1 -1
  7. package/dist/constants.js +1 -2
  8. package/dist/constants.js.map +1 -1
  9. package/dist/context-manager.d.ts +3 -2
  10. package/dist/context-manager.js +29 -6
  11. package/dist/context-manager.js.map +1 -1
  12. package/dist/conversation-logger.d.ts +3 -1
  13. package/dist/conversation-logger.js +41 -4
  14. package/dist/conversation-logger.js.map +1 -1
  15. package/dist/conversation.d.ts +8 -2
  16. package/dist/conversation.js +36 -9
  17. package/dist/conversation.js.map +1 -1
  18. package/dist/items/section.js +3 -3
  19. package/dist/items/section.js.map +1 -1
  20. package/dist/iteration-strategy.d.ts +2 -0
  21. package/dist/iteration-strategy.js +40 -6
  22. package/dist/iteration-strategy.js.map +1 -1
  23. package/dist/loader.js +18 -3
  24. package/dist/loader.js.map +1 -1
  25. package/dist/message-builder.js +4 -2
  26. package/dist/message-builder.js.map +1 -1
  27. package/dist/model-config.d.ts +115 -0
  28. package/dist/model-config.js +205 -0
  29. package/dist/model-config.js.map +1 -0
  30. package/dist/override.js +5 -1
  31. package/dist/override.js.map +1 -1
  32. package/dist/parser.js +3 -3
  33. package/dist/parser.js.map +1 -1
  34. package/dist/recipes.d.ts +1 -1
  35. package/dist/recipes.js +4 -4
  36. package/dist/recipes.js.map +1 -1
  37. package/dist/reflection.js +5 -2
  38. package/dist/reflection.js.map +1 -1
  39. package/dist/riotprompt.cjs +439 -94
  40. package/dist/riotprompt.cjs.map +1 -1
  41. package/dist/riotprompt.d.ts +2 -0
  42. package/dist/riotprompt.js +1 -0
  43. package/dist/riotprompt.js.map +1 -1
  44. package/dist/token-budget.d.ts +2 -2
  45. package/dist/token-budget.js +23 -26
  46. package/dist/token-budget.js.map +1 -1
  47. package/dist/util/general.js +1 -1
  48. package/dist/util/general.js.map +1 -1
  49. package/package.json +1 -1
@@ -0,0 +1,437 @@
1
+ # Code Review Fixes Applied
2
+
3
+ All issues identified in the comprehensive code review have been fixed.
4
+
5
+ ## Summary
6
+
7
+ - **Total Issues Fixed:** 19
8
+ - **Critical Issues:** 4
9
+ - **High Priority Issues:** 6
10
+ - **Medium Priority Issues:** 9
11
+
12
+ ---
13
+
14
+ ## 🔴 Critical Issues Fixed
15
+
16
+ ### 1. **Memory Leak in TokenBudgetManager** ✅
17
+ **File:** `src/token-budget.ts`
18
+
19
+ **Problem:** Creating temporary `TokenBudgetManager` instances without disposing encoders.
20
+
21
+ **Fix:** Modified `compressAdaptive()` to temporarily modify config instead of creating new instance.
22
+
23
+ **Before:**
24
+ ```typescript
25
+ const tempManager = new TokenBudgetManager(modifiedConfig, 'gpt-4o', this.logger);
26
+ return tempManager.compressFIFO(messages, targetTokens);
27
+ ```
28
+
29
+ **After:**
30
+ ```typescript
31
+ const originalPreserveRecent = this.config.preserveRecent;
32
+ this.config.preserveRecent = 5;
33
+ const result = this.compressFIFO(messages, targetTokens);
34
+ this.config.preserveRecent = originalPreserveRecent;
35
+ return result;
36
+ ```
37
+
38
+ ---
39
+
40
+ ### 2. **Context Injection Position Tracking Bug** ✅
41
+ **File:** `src/conversation.ts`
42
+
43
+ **Problem:** Multiple items injected at same position had incorrect tracking.
44
+
45
+ **Fix:** Track each item at `position + index` to maintain correct positions.
46
+
47
+ **Before:**
48
+ ```typescript
49
+ this.state.messages.splice(position, 0, contextMessage);
50
+ this.state.contextManager.track(item, position);
51
+ ```
52
+
53
+ **After:**
54
+ ```typescript
55
+ const actualPosition = position + i;
56
+ this.state.messages.splice(actualPosition, 0, contextMessage);
57
+ this.state.contextManager.track(item, actualPosition);
58
+ ```
59
+
60
+ ---
61
+
62
+ ### 3. **Shallow Copy Causing Shared State** ✅
63
+ **File:** `src/conversation.ts`
64
+
65
+ **Problem:** Cloning conversations with shallow copy causes `tool_calls` arrays to be shared.
66
+
67
+ **Fix:** Deep copy messages including nested `tool_calls` arrays.
68
+
69
+ **Before:**
70
+ ```typescript
71
+ cloned.state.messages = this.state.messages.map(msg => ({ ...msg }));
72
+ ```
73
+
74
+ **After:**
75
+ ```typescript
76
+ cloned.state.messages = this.state.messages.map(msg => ({
77
+ ...msg,
78
+ tool_calls: msg.tool_calls ? msg.tool_calls.map(tc => ({
79
+ ...tc,
80
+ function: { ...tc.function }
81
+ })) : undefined
82
+ }));
83
+ ```
84
+
85
+ ---
86
+
87
+ ### 4. **Uncaught JSON Parse Error** ✅
88
+ **File:** `src/iteration-strategy.ts`
89
+
90
+ **Problem:** No error handling for `JSON.parse()` on tool arguments.
91
+
92
+ **Fix:** Wrapped JSON.parse in try-catch with descriptive error message.
93
+
94
+ **After:**
95
+ ```typescript
96
+ let toolArgs: any;
97
+ try {
98
+ toolArgs = JSON.parse(toolCall.function.arguments);
99
+ } catch (parseError) {
100
+ throw new Error(`Invalid JSON in tool arguments: ${parseError.message}`);
101
+ }
102
+ ```
103
+
104
+ ---
105
+
106
+ ## 🟡 High Priority Issues Fixed
107
+
108
+ ### 5. **Hardcoded Model in Recipe ExecuteWith** ✅
109
+ **File:** `src/recipes.ts`
110
+
111
+ **Problem:** `executeWith()` hardcoded `'gpt-4o'` model.
112
+
113
+ **Fix:** Added `model` parameter with default value.
114
+
115
+ **After:**
116
+ ```typescript
117
+ executeWith: async (
118
+ llm: LLMClient,
119
+ strategy: IterationStrategy,
120
+ model: Model = 'gpt-4o',
121
+ tokenBudget?: TokenBudgetConfig
122
+ )
123
+ ```
124
+
125
+ ---
126
+
127
+ ### 6. **Section Array Append Missing Options** ✅
128
+ **File:** `src/items/section.ts`
129
+
130
+ **Problem:** Options not propagated when appending arrays.
131
+
132
+ **Fix:** Pass `options` parameter in recursive calls.
133
+
134
+ **After:**
135
+ ```typescript
136
+ if (Array.isArray(item)) {
137
+ item.forEach((item) => {
138
+ append(item, options); // Now propagates options
139
+ });
140
+ }
141
+ ```
142
+
143
+ ---
144
+
145
+ ### 7. **JSONL File Race Condition** ✅
146
+ **File:** `src/conversation-logger.ts`
147
+
148
+ **Problem:** Fire-and-forget async writes could corrupt JSONL files.
149
+
150
+ **Fix:** Added write queue and cached output path.
151
+
152
+ **After:**
153
+ ```typescript
154
+ private cachedOutputPath?: string;
155
+ private writeQueue: Promise<void> = Promise.resolve();
156
+
157
+ // Queue writes
158
+ this.writeQueue = this.writeQueue
159
+ .then(() => this.appendToJSONL(loggedMessage))
160
+ .catch(this.config.onError);
161
+ ```
162
+
163
+ ---
164
+
165
+ ### 8. **Hardcoded Model Detection System** ✅
166
+ **Files:** New `src/model-config.ts`, `src/chat.ts`, `src/message-builder.ts`, `src/token-budget.ts`
167
+
168
+ **Problem:** Model names hardcoded throughout codebase, inflexible for new models.
169
+
170
+ **Fix:** Created flexible `ModelRegistry` system with pattern-based configuration.
171
+
172
+ **Key Features:**
173
+ - Pattern-based model matching (regex)
174
+ - Configurable role mapping (system vs developer)
175
+ - Tokenizer encoding configuration
176
+ - User-extensible via `configureModel()`
177
+
178
+ **Example Usage:**
179
+ ```typescript
180
+ import { configureModel } from 'riotprompt';
181
+
182
+ // Add support for new model family
183
+ configureModel({
184
+ pattern: /^gemini/i,
185
+ personaRole: 'system',
186
+ encoding: 'cl100k_base',
187
+ family: 'gemini'
188
+ });
189
+ ```
190
+
191
+ ---
192
+
193
+ ### 9. **Conversation Replayer JSON Parse Error** ✅
194
+ **File:** `src/conversation-logger.ts`
195
+
196
+ **Problem:** No error handling when parsing tool call arguments from logs.
197
+
198
+ **Fix:** Added try-catch with fallback object containing raw arguments.
199
+
200
+ ---
201
+
202
+ ### 10. **Iteration Counter Misplaced** ✅
203
+ **File:** `src/iteration-strategy.ts`
204
+
205
+ **Problem:** Counter incremented per phase instead of per iteration.
206
+
207
+ **Fix:** Moved `incrementIteration()` inside the iteration loop.
208
+
209
+ ---
210
+
211
+ ## 🟠 Medium Priority Issues Fixed
212
+
213
+ ### 11. **FIFO Compression O(n*m) Complexity** ✅
214
+ **File:** `src/token-budget.ts`
215
+
216
+ **Problem:** Using `includes()` on array is O(n*m) for large conversations.
217
+
218
+ **Fix:** Use `Set` for O(1) lookups, reducing to O(n).
219
+
220
+ ---
221
+
222
+ ### 12. **Overly Aggressive Similar Content Detection** ✅
223
+ **File:** `src/context-manager.ts`
224
+
225
+ **Problem:** "Hello" and "Hello world" considered duplicates.
226
+
227
+ **Fix:** Added similarity threshold (default 90%) for substring matching.
228
+
229
+ **After:**
230
+ ```typescript
231
+ hasSimilarContent(content: string, similarityThreshold: number = 0.9): boolean {
232
+ const lengthRatio = shorter.length / longer.length;
233
+ if (lengthRatio >= similarityThreshold) {
234
+ if (longer.includes(shorter)) {
235
+ return true;
236
+ }
237
+ }
238
+ }
239
+ ```
240
+
241
+ ---
242
+
243
+ ### 13. **Duplicate Context Without IDs** ✅
244
+ **File:** `src/context-manager.ts`
245
+
246
+ **Problem:** Same content tracked multiple times if no ID provided.
247
+
248
+ **Fix:** Check content hash before tracking items without IDs.
249
+
250
+ ---
251
+
252
+ ### 14. **Tool Category Filter Edge Case** ✅
253
+ **File:** `src/recipes.ts`
254
+
255
+ **Problem:** Tools without category could match empty string in filter array.
256
+
257
+ **Fix:** Added explicit check for truthy `tool.category`.
258
+
259
+ ---
260
+
261
+ ### 15. **Circuit Breaker for Failing Tools** ✅
262
+ **File:** `src/iteration-strategy.ts`
263
+
264
+ **Problem:** No protection against repeatedly calling broken tools.
265
+
266
+ **Fix:** Added circuit breaker with configurable threshold (default: 3 consecutive failures).
267
+
268
+ **Features:**
269
+ - Tracks consecutive failures per tool
270
+ - Configurable via `maxConsecutiveToolFailures` in phase config
271
+ - Resets counter on successful execution
272
+ - Logs circuit breaker triggers
273
+
274
+ ---
275
+
276
+ ### 16. **Generic Parser Error Message** ✅
277
+ **File:** `src/parser.ts`
278
+
279
+ **Problem:** Error said "instructions" but parser is used for all content types.
280
+
281
+ **Fix:** Changed to generic "content" in error message.
282
+
283
+ ---
284
+
285
+ ### 17. **Override Array Mutation** ✅
286
+ **File:** `src/override.ts`
287
+
288
+ **Problem:** Mutating `appends` array with `.reverse()`.
289
+
290
+ **Fix:** Create copy before reversing: `[...appends].reverse()`.
291
+
292
+ ---
293
+
294
+ ### 18. **Type Assertion Hack in Loader** ✅
295
+ **File:** `src/loader.ts`
296
+
297
+ **Problem:** Double cast `as unknown as T` circumventing type system.
298
+
299
+ **Fix:** Removed unnecessary cast - `Section.add()` correctly accepts `Section<T>`.
300
+
301
+ ---
302
+
303
+ ### 19. **Ignore Pattern Only Tests Filename** ✅
304
+ **File:** `src/loader.ts`
305
+
306
+ **Problem:** Regex patterns only tested against filename, not full path.
307
+
308
+ **Fix:** Test against both filename and full path for flexibility.
309
+
310
+ ---
311
+
312
+ ## New Features Added
313
+
314
+ ### Model Configuration System
315
+
316
+ Created a comprehensive, user-configurable model system:
317
+
318
+ **File:** `src/model-config.ts`
319
+
320
+ **Exports:**
321
+ - `ModelRegistry` - Main registry class
322
+ - `getModelRegistry()` - Get global instance
323
+ - `configureModel()` - Register custom models
324
+ - `getPersonaRole()` - Get role for model
325
+ - `getEncoding()` - Get tokenizer encoding
326
+ - `supportsToolCalls()` - Check tool support
327
+ - `getModelFamily()` - Get model family
328
+
329
+ **Default Configurations:**
330
+ - GPT-4 family (uses 'system' role)
331
+ - O-series models (uses 'developer' role)
332
+ - Claude family (uses 'system' role)
333
+ - Default fallback for unknown models
334
+
335
+ **Benefits:**
336
+ - No more hardcoded model names
337
+ - Easy to add new models without code changes
338
+ - Pattern-based matching (e.g., `/^o\d+/` matches o1, o2, o3, etc.)
339
+ - User-extensible at runtime
340
+
341
+ ---
342
+
343
+ ## Testing Recommendations
344
+
345
+ 1. **Memory Leak Test:** Run long conversation with many compressions, monitor memory
346
+ 2. **Context Injection Test:** Inject multiple items, verify position tracking
347
+ 3. **Clone Test:** Clone conversation, modify tool_calls, verify no cross-contamination
348
+ 4. **Invalid JSON Test:** Send malformed tool arguments, verify graceful error handling
349
+ 5. **Circuit Breaker Test:** Configure tool to fail repeatedly, verify circuit breaker triggers
350
+ 6. **Model Registry Test:** Register custom model, verify correct role/encoding selection
351
+ 7. **JSONL Race Test:** Add many messages rapidly, verify file integrity
352
+ 8. **Performance Test:** Compress large conversations (1000+ messages), verify Set optimization
353
+
354
+ ---
355
+
356
+ ## Breaking Changes
357
+
358
+ ⚠️ **Minor Breaking Change in Recipe API:**
359
+
360
+ ```typescript
361
+ // OLD
362
+ builder.executeWith(llm, strategy, tokenBudget)
363
+
364
+ // NEW
365
+ builder.executeWith(llm, strategy, model, tokenBudget)
366
+ // OR use default
367
+ builder.executeWith(llm, strategy) // defaults to 'gpt-4o'
368
+ ```
369
+
370
+ ---
371
+
372
+ ## Migration Guide
373
+
374
+ ### For Custom Model Support
375
+
376
+ **Before:** Had to modify source code to add new models
377
+
378
+ **After:** Configure at runtime:
379
+
380
+ ```typescript
381
+ import { configureModel } from 'riotprompt';
382
+
383
+ // Add new model family
384
+ configureModel({
385
+ pattern: /^my-model/i,
386
+ personaRole: 'system',
387
+ encoding: 'gpt-4o',
388
+ supportsToolCalls: true,
389
+ family: 'my-family'
390
+ });
391
+
392
+ // Add specific override
393
+ configureModel({
394
+ exactMatch: 'my-model-v2-special',
395
+ personaRole: 'developer',
396
+ encoding: 'cl100k_base'
397
+ });
398
+ ```
399
+
400
+ ---
401
+
402
+ ## Files Modified
403
+
404
+ 1. `src/model-config.ts` (NEW)
405
+ 2. `src/chat.ts`
406
+ 3. `src/conversation.ts`
407
+ 4. `src/token-budget.ts`
408
+ 5. `src/iteration-strategy.ts`
409
+ 6. `src/recipes.ts`
410
+ 7. `src/conversation-logger.ts`
411
+ 8. `src/context-manager.ts`
412
+ 9. `src/items/section.ts`
413
+ 10. `src/parser.ts`
414
+ 11. `src/loader.ts`
415
+ 12. `src/override.ts`
416
+ 13. `src/message-builder.ts`
417
+ 14. `src/riotprompt.ts`
418
+
419
+ ---
420
+
421
+ ## Next Steps
422
+
423
+ 1. ✅ All critical issues fixed
424
+ 2. ✅ All high priority issues fixed
425
+ 3. ✅ All medium priority issues fixed
426
+ 4. ✅ No linting errors
427
+ 5. ⏭️ Run test suite to verify fixes
428
+ 6. ⏭️ Update documentation for model configuration system
429
+ 7. ⏭️ Consider adding unit tests for circuit breaker
430
+ 8. ⏭️ Performance test compression optimization
431
+
432
+ ---
433
+
434
+ **Review completed:** December 27, 2025
435
+ **Total fixes applied:** 19
436
+ **Status:** ✅ All issues resolved
437
+
package/dist/chat.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export type Role = "user" | "assistant" | "system" | "developer";
2
- export type Model = "gpt-4o" | "gpt-4o-mini" | "o1-preview" | "o1-mini" | "o1" | "o3-mini" | "o1-pro";
2
+ export type Model = string;
3
3
  export interface Message {
4
4
  role: Role;
5
5
  content: string | string[];
package/dist/chat.js CHANGED
@@ -1,10 +1,7 @@
1
- import { DEFAULT_PERSONA_ROLE } from './constants.js';
1
+ import { getPersonaRole as getPersonaRole$1 } from './model-config.js';
2
2
 
3
3
  const getPersonaRole = (model)=>{
4
- if (model === "gpt-4o" || model === "gpt-4o-mini") {
5
- return "system";
6
- }
7
- return DEFAULT_PERSONA_ROLE;
4
+ return getPersonaRole$1(model);
8
5
  };
9
6
  const createRequest = (model)=>{
10
7
  const messages = [];
package/dist/chat.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"chat.js","sources":["../src/chat.ts"],"sourcesContent":["import { DEFAULT_PERSONA_ROLE } from \"./constants\";\n\nexport type Role = \"user\" | \"assistant\" | \"system\" | \"developer\";\n\nexport type Model = \"gpt-4o\" | \"gpt-4o-mini\" | \"o1-preview\" | \"o1-mini\" | \"o1\" | \"o3-mini\" | \"o1-pro\";\n\nexport interface Message {\n role: Role;\n content: string | string[];\n name?: string;\n}\n\nexport interface Request {\n messages: Message[];\n model: Model;\n\n addMessage(message: Message): void;\n}\n\nexport const getPersonaRole = (model: Model): Role => {\n if (model === \"gpt-4o\" || model === \"gpt-4o-mini\") {\n return \"system\";\n }\n return DEFAULT_PERSONA_ROLE;\n}\n\nexport const createRequest = (model: Model): Request => {\n const messages: Message[] = [];\n\n return {\n model,\n messages,\n addMessage: (message: Message) => {\n messages.push(message);\n }\n }\n}\n"],"names":["getPersonaRole","model","DEFAULT_PERSONA_ROLE","createRequest","messages","addMessage","message","push"],"mappings":";;AAmBO,MAAMA,iBAAiB,CAACC,KAAAA,GAAAA;IAC3B,IAAIA,KAAAA,KAAU,QAAA,IAAYA,KAAAA,KAAU,aAAA,EAAe;QAC/C,OAAO,QAAA;AACX,IAAA;IACA,OAAOC,oBAAAA;AACX;AAEO,MAAMC,gBAAgB,CAACF,KAAAA,GAAAA;AAC1B,IAAA,MAAMG,WAAsB,EAAE;IAE9B,OAAO;AACHH,QAAAA,KAAAA;AACAG,QAAAA,QAAAA;AACAC,QAAAA,UAAAA,EAAY,CAACC,OAAAA,GAAAA;AACTF,YAAAA,QAAAA,CAASG,IAAI,CAACD,OAAAA,CAAAA;AAClB,QAAA;AACJ,KAAA;AACJ;;;;"}
1
+ {"version":3,"file":"chat.js","sources":["../src/chat.ts"],"sourcesContent":["import { getPersonaRole as getPersonaRoleFromRegistry } from \"./model-config\";\n\nexport type Role = \"user\" | \"assistant\" | \"system\" | \"developer\";\n\n// Model is now a flexible string type\nexport type Model = string;\n\nexport interface Message {\n role: Role;\n content: string | string[];\n name?: string;\n}\n\nexport interface Request {\n messages: Message[];\n model: Model;\n\n addMessage(message: Message): void;\n}\n\nexport const getPersonaRole = (model: Model): Role => {\n return getPersonaRoleFromRegistry(model);\n}\n\nexport const createRequest = (model: Model): Request => {\n const messages: Message[] = [];\n\n return {\n model,\n messages,\n addMessage: (message: Message) => {\n messages.push(message);\n }\n }\n}\n"],"names":["getPersonaRole","model","getPersonaRoleFromRegistry","createRequest","messages","addMessage","message","push"],"mappings":";;AAoBO,MAAMA,iBAAiB,CAACC,KAAAA,GAAAA;AAC3B,IAAA,OAAOC,gBAAAA,CAA2BD,KAAAA,CAAAA;AACtC;AAEO,MAAME,gBAAgB,CAACF,KAAAA,GAAAA;AAC1B,IAAA,MAAMG,WAAsB,EAAE;IAE9B,OAAO;AACHH,QAAAA,KAAAA;AACAG,QAAAA,QAAAA;AACAC,QAAAA,UAAAA,EAAY,CAACC,OAAAA,GAAAA;AACTF,YAAAA,QAAAA,CAASG,IAAI,CAACD,OAAAA,CAAAA;AAClB,QAAA;AACJ,KAAA;AACJ;;;;"}
package/dist/constants.js CHANGED
@@ -1,6 +1,5 @@
1
1
  const DEFAULT_CHARACTER_ENCODING = "utf8";
2
2
  const LIBRARY_NAME = "riotprompt";
3
- const DEFAULT_PERSONA_ROLE = "developer";
4
3
  const DEFAULT_IGNORE_PATTERNS = [
5
4
  "^\\..*",
6
5
  "\\.(jpg|jpeg|png|gif|bmp|svg|webp|ico)$",
@@ -19,5 +18,5 @@ const DEFAULT_FORMAT_OPTIONS = {
19
18
  sectionDepth: 0
20
19
  };
21
20
 
22
- export { DEFAULT_CHARACTER_ENCODING, DEFAULT_FORMAT_OPTIONS, DEFAULT_IGNORE_PATTERNS, DEFAULT_PERSONA_ROLE, DEFAULT_SECTION_INDENTATION, DEFAULT_SECTION_SEPARATOR, DEFAULT_SECTION_TITLE_PROPERTY, LIBRARY_NAME };
21
+ export { DEFAULT_CHARACTER_ENCODING, DEFAULT_FORMAT_OPTIONS, DEFAULT_IGNORE_PATTERNS, DEFAULT_SECTION_INDENTATION, DEFAULT_SECTION_SEPARATOR, DEFAULT_SECTION_TITLE_PROPERTY, LIBRARY_NAME };
23
22
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sources":["../src/constants.ts"],"sourcesContent":["import { SectionSeparator } from \"formatter\";\n\nimport { FormatOptions } from \"formatter\";\n\nexport const DEFAULT_CHARACTER_ENCODING = \"utf8\";\nexport const LIBRARY_NAME = \"riotprompt\";\n\nexport const DEFAULT_PERSONA_ROLE = \"developer\";\n\nexport const DEFAULT_INSTRUCTIONS_AREA_TITLE = \"Instructions\";\nexport const DEFAULT_CONTENTS_AREA_TITLE = \"Contents\";\nexport const DEFAULT_CONTEXT_AREA_TITLE = \"Context\";\n\nexport const DEFAULT_IGNORE_PATTERNS: string[] = [\n \"^\\\\..*\", // Hidden files (e.g., .git, .DS_Store)\n \"\\\\.(jpg|jpeg|png|gif|bmp|svg|webp|ico)$\", // Image files\n \"\\\\.(mp3|wav|ogg|aac|flac)$\", // Audio files\n \"\\\\.(mp4|mov|avi|mkv|webm)$\", // Video files\n \"\\\\.(pdf|doc|docx|xls|xlsx|ppt|pptx)$\", // Document files\n \"\\\\.(zip|tar|gz|rar|7z)$\" // Compressed files\n];\n\nexport const DEFAULT_SECTION_SEPARATOR: SectionSeparator = \"tag\";\nexport const DEFAULT_SECTION_INDENTATION = true;\nexport const DEFAULT_SECTION_TAG = \"section\";\nexport const DEFAULT_SECTION_TITLE_PROPERTY = \"title\";\n\nexport const DEFAULT_FORMAT_OPTIONS: FormatOptions = {\n sectionSeparator: DEFAULT_SECTION_SEPARATOR,\n sectionIndentation: DEFAULT_SECTION_INDENTATION,\n sectionTitleProperty: DEFAULT_SECTION_TITLE_PROPERTY,\n sectionDepth: 0,\n}\n"],"names":["DEFAULT_CHARACTER_ENCODING","LIBRARY_NAME","DEFAULT_PERSONA_ROLE","DEFAULT_IGNORE_PATTERNS","DEFAULT_SECTION_SEPARATOR","DEFAULT_SECTION_INDENTATION","DEFAULT_SECTION_TITLE_PROPERTY","DEFAULT_FORMAT_OPTIONS","sectionSeparator","sectionIndentation","sectionTitleProperty","sectionDepth"],"mappings":"AAIO,MAAMA,6BAA6B;AACnC,MAAMC,eAAe;AAErB,MAAMC,uBAAuB;MAMvBC,uBAAAA,GAAoC;AAC7C,IAAA,QAAA;AACA,IAAA,yCAAA;AACA,IAAA,4BAAA;AACA,IAAA,4BAAA;AACA,IAAA,sCAAA;AACA,IAAA,yBAAA;;AAGG,MAAMC,4BAA8C;AACpD,MAAMC,8BAA8B;AAEpC,MAAMC,iCAAiC;MAEjCC,sBAAAA,GAAwC;IACjDC,gBAAAA,EAAkBJ,yBAAAA;IAClBK,kBAAAA,EAAoBJ,2BAAAA;IACpBK,oBAAAA,EAAsBJ,8BAAAA;IACtBK,YAAAA,EAAc;AAClB;;;;"}
1
+ {"version":3,"file":"constants.js","sources":["../src/constants.ts"],"sourcesContent":["import { SectionSeparator } from \"formatter\";\n\nimport { FormatOptions } from \"formatter\";\n\nexport const DEFAULT_CHARACTER_ENCODING = \"utf8\";\nexport const LIBRARY_NAME = \"riotprompt\";\n\nexport const DEFAULT_PERSONA_ROLE = \"developer\";\n\nexport const DEFAULT_INSTRUCTIONS_AREA_TITLE = \"Instructions\";\nexport const DEFAULT_CONTENTS_AREA_TITLE = \"Contents\";\nexport const DEFAULT_CONTEXT_AREA_TITLE = \"Context\";\n\nexport const DEFAULT_IGNORE_PATTERNS: string[] = [\n \"^\\\\..*\", // Hidden files (e.g., .git, .DS_Store)\n \"\\\\.(jpg|jpeg|png|gif|bmp|svg|webp|ico)$\", // Image files\n \"\\\\.(mp3|wav|ogg|aac|flac)$\", // Audio files\n \"\\\\.(mp4|mov|avi|mkv|webm)$\", // Video files\n \"\\\\.(pdf|doc|docx|xls|xlsx|ppt|pptx)$\", // Document files\n \"\\\\.(zip|tar|gz|rar|7z)$\" // Compressed files\n];\n\nexport const DEFAULT_SECTION_SEPARATOR: SectionSeparator = \"tag\";\nexport const DEFAULT_SECTION_INDENTATION = true;\nexport const DEFAULT_SECTION_TAG = \"section\";\nexport const DEFAULT_SECTION_TITLE_PROPERTY = \"title\";\n\nexport const DEFAULT_FORMAT_OPTIONS: FormatOptions = {\n sectionSeparator: DEFAULT_SECTION_SEPARATOR,\n sectionIndentation: DEFAULT_SECTION_INDENTATION,\n sectionTitleProperty: DEFAULT_SECTION_TITLE_PROPERTY,\n sectionDepth: 0,\n}\n"],"names":["DEFAULT_CHARACTER_ENCODING","LIBRARY_NAME","DEFAULT_IGNORE_PATTERNS","DEFAULT_SECTION_SEPARATOR","DEFAULT_SECTION_INDENTATION","DEFAULT_SECTION_TITLE_PROPERTY","DEFAULT_FORMAT_OPTIONS","sectionSeparator","sectionIndentation","sectionTitleProperty","sectionDepth"],"mappings":"AAIO,MAAMA,6BAA6B;AACnC,MAAMC,eAAe;MAQfC,uBAAAA,GAAoC;AAC7C,IAAA,QAAA;AACA,IAAA,yCAAA;AACA,IAAA,4BAAA;AACA,IAAA,4BAAA;AACA,IAAA,sCAAA;AACA,IAAA,yBAAA;;AAGG,MAAMC,4BAA8C;AACpD,MAAMC,8BAA8B;AAEpC,MAAMC,iCAAiC;MAEjCC,sBAAAA,GAAwC;IACjDC,gBAAAA,EAAkBJ,yBAAAA;IAClBK,kBAAAA,EAAoBJ,2BAAAA;IACpBK,oBAAAA,EAAsBJ,8BAAAA;IACtBK,YAAAA,EAAc;AAClB;;;;"}
@@ -68,7 +68,7 @@ export declare class ContextManager {
68
68
  private logger;
69
69
  constructor(logger?: any);
70
70
  /**
71
- * Track a context item
71
+ * Track a context item (with deduplication by content hash for items without ID)
72
72
  */
73
73
  track(item: DynamicContentItem, position: number): void;
74
74
  /**
@@ -81,8 +81,9 @@ export declare class ContextManager {
81
81
  hasContentHash(content: string): boolean;
82
82
  /**
83
83
  * Check if similar content exists (fuzzy match)
84
+ * Uses similarity threshold to avoid overly aggressive deduplication
84
85
  */
85
- hasSimilarContent(content: string): boolean;
86
+ hasSimilarContent(content: string, similarityThreshold?: number): boolean;
86
87
  /**
87
88
  * Get context item by ID
88
89
  */
@@ -46,10 +46,17 @@ function _define_property(obj, key, value) {
46
46
  * ```
47
47
  */ class ContextManager {
48
48
  /**
49
- * Track a context item
49
+ * Track a context item (with deduplication by content hash for items without ID)
50
50
  */ track(item, position) {
51
- const id = item.id || this.generateId();
52
51
  const hash = this.hashContent(item.content);
52
+ // If item has no ID and we already have this content hash, skip tracking
53
+ if (!item.id && this.hashes.has(hash)) {
54
+ this.logger.debug('Skipping duplicate context item by hash', {
55
+ hash
56
+ });
57
+ return;
58
+ }
59
+ const id = item.id || this.generateId();
53
60
  const trackedItem = {
54
61
  ...item,
55
62
  id,
@@ -80,7 +87,16 @@ function _define_property(obj, key, value) {
80
87
  }
81
88
  /**
82
89
  * Check if similar content exists (fuzzy match)
83
- */ hasSimilarContent(content) {
90
+ * Uses similarity threshold to avoid overly aggressive deduplication
91
+ */ hasSimilarContent(content, similarityThreshold = 0.9) {
92
+ // Warn if checking against a large number of items (performance consideration)
93
+ const MAX_ITEMS_WARNING = 1000;
94
+ if (this.items.size > MAX_ITEMS_WARNING) {
95
+ this.logger.warn('Large number of context items, similarity check may be slow', {
96
+ count: this.items.size,
97
+ threshold: MAX_ITEMS_WARNING
98
+ });
99
+ }
84
100
  const normalized = this.normalizeContent(content);
85
101
  for (const item of this.items.values()){
86
102
  const itemNormalized = this.normalizeContent(item.content || '');
@@ -88,9 +104,16 @@ function _define_property(obj, key, value) {
88
104
  if (normalized === itemNormalized) {
89
105
  return true;
90
106
  }
91
- // Substring match (one contains the other)
92
- if (normalized.includes(itemNormalized) || itemNormalized.includes(normalized)) {
93
- return true;
107
+ // Calculate similarity ratio (Jaccard-like)
108
+ const longer = normalized.length > itemNormalized.length ? normalized : itemNormalized;
109
+ const shorter = normalized.length <= itemNormalized.length ? normalized : itemNormalized;
110
+ // Only consider substring match if the shorter is at least 90% of longer
111
+ const lengthRatio = shorter.length / longer.length;
112
+ if (lengthRatio >= similarityThreshold) {
113
+ // Check if one is contained in the other
114
+ if (longer.includes(shorter)) {
115
+ return true;
116
+ }
94
117
  }
95
118
  }
96
119
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"context-manager.js","sources":["../src/context-manager.ts"],"sourcesContent":["import crypto from 'crypto';\nimport { DEFAULT_LOGGER, wrapLogger } from \"./logger\";\n\n// ===== TYPE DEFINITIONS =====\n\n/**\n * Dynamic content item with enhanced tracking and lifecycle\n */\nexport interface DynamicContentItem {\n content: string;\n title?: string;\n weight?: number;\n\n // Unique identifier for deduplication\n id?: string;\n\n // Category for grouping\n category?: string;\n\n // Source of context\n source?: string;\n\n // Priority level\n priority?: 'high' | 'medium' | 'low';\n\n // Timestamp\n timestamp?: Date;\n}\n\n/**\n * Tracked context item with metadata\n */\nexport interface TrackedContextItem extends DynamicContentItem {\n id: string;\n hash: string;\n position: number;\n injectedAt: Date;\n}\n\n/**\n * Context statistics\n */\nexport interface ContextStats {\n totalItems: number;\n byCategory: Map<string, number>;\n byPriority: Map<string, number>;\n bySource: Map<string, number>;\n oldestTimestamp?: Date;\n newestTimestamp?: Date;\n}\n\n/**\n * ContextManager tracks and manages dynamically injected context.\n *\n * Features:\n * - Track all injected context with metadata\n * - Deduplication by ID, hash, or content\n * - Category-based organization\n * - Query context state\n * - Context statistics\n *\n * @example\n * ```typescript\n * const manager = new ContextManager();\n *\n * // Track injected context\n * manager.track({\n * id: 'file:main.ts',\n * content: fileContent,\n * title: 'Main File',\n * category: 'source-code'\n * }, 5);\n *\n * // Check for duplicates\n * if (manager.hasContext('file:main.ts')) {\n * console.log('Already provided');\n * }\n *\n * // Query by category\n * const sourceFiles = manager.getByCategory('source-code');\n * ```\n */\nexport class ContextManager {\n private items: Map<string, TrackedContextItem>;\n private hashes: Set<string>;\n private logger: any;\n\n constructor(logger?: any) {\n this.items = new Map();\n this.hashes = new Set();\n this.logger = wrapLogger(logger || DEFAULT_LOGGER, 'ContextManager');\n }\n\n /**\n * Track a context item\n */\n track(item: DynamicContentItem, position: number): void {\n const id = item.id || this.generateId();\n const hash = this.hashContent(item.content);\n\n const trackedItem: TrackedContextItem = {\n ...item,\n id,\n hash,\n position,\n injectedAt: new Date(),\n timestamp: item.timestamp || new Date(),\n priority: item.priority || 'medium',\n };\n\n this.items.set(id, trackedItem);\n this.hashes.add(hash);\n\n this.logger.debug('Tracked context item', { id, category: item.category, position });\n }\n\n /**\n * Check if context with given ID exists\n */\n hasContext(id: string): boolean {\n return this.items.has(id);\n }\n\n /**\n * Check if content with given hash exists\n */\n hasContentHash(content: string): boolean {\n const hash = this.hashContent(content);\n return this.hashes.has(hash);\n }\n\n /**\n * Check if similar content exists (fuzzy match)\n */\n hasSimilarContent(content: string): boolean {\n const normalized = this.normalizeContent(content);\n\n for (const item of this.items.values()) {\n const itemNormalized = this.normalizeContent(item.content || '');\n\n // Exact match\n if (normalized === itemNormalized) {\n return true;\n }\n\n // Substring match (one contains the other)\n if (normalized.includes(itemNormalized) || itemNormalized.includes(normalized)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Get context item by ID\n */\n get(id: string): TrackedContextItem | undefined {\n return this.items.get(id);\n }\n\n /**\n * Get all tracked context items\n */\n getAll(): TrackedContextItem[] {\n return Array.from(this.items.values());\n }\n\n /**\n * Get context items by category\n */\n getByCategory(category: string): TrackedContextItem[] {\n return this.getAll().filter(item => item.category === category);\n }\n\n /**\n * Get context items by priority\n */\n getByPriority(priority: 'high' | 'medium' | 'low'): TrackedContextItem[] {\n return this.getAll().filter(item => item.priority === priority);\n }\n\n /**\n * Get context items by source\n */\n getBySource(source: string): TrackedContextItem[] {\n return this.getAll().filter(item => item.source === source);\n }\n\n /**\n * Get all categories\n */\n getCategories(): string[] {\n const categories = new Set<string>();\n this.items.forEach(item => {\n if (item.category) {\n categories.add(item.category);\n }\n });\n return Array.from(categories).sort();\n }\n\n /**\n * Get context statistics\n */\n getStats(): ContextStats {\n const byCategory = new Map<string, number>();\n const byPriority = new Map<string, number>();\n const bySource = new Map<string, number>();\n let oldestTimestamp: Date | undefined;\n let newestTimestamp: Date | undefined;\n\n this.items.forEach(item => {\n // Category stats\n if (item.category) {\n byCategory.set(item.category, (byCategory.get(item.category) || 0) + 1);\n }\n\n // Priority stats\n const priority = item.priority || 'medium';\n byPriority.set(priority, (byPriority.get(priority) || 0) + 1);\n\n // Source stats\n if (item.source) {\n bySource.set(item.source, (bySource.get(item.source) || 0) + 1);\n }\n\n // Timestamp stats\n if (item.timestamp) {\n if (!oldestTimestamp || item.timestamp < oldestTimestamp) {\n oldestTimestamp = item.timestamp;\n }\n if (!newestTimestamp || item.timestamp > newestTimestamp) {\n newestTimestamp = item.timestamp;\n }\n }\n });\n\n return {\n totalItems: this.items.size,\n byCategory,\n byPriority,\n bySource,\n oldestTimestamp,\n newestTimestamp,\n };\n }\n\n /**\n * Remove context item by ID\n */\n remove(id: string): boolean {\n const item = this.items.get(id);\n if (item) {\n this.items.delete(id);\n this.hashes.delete(item.hash);\n this.logger.debug('Removed context item', { id });\n return true;\n }\n return false;\n }\n\n /**\n * Clear all tracked context\n */\n clear(): void {\n this.items.clear();\n this.hashes.clear();\n this.logger.debug('Cleared all context');\n }\n\n /**\n * Generate unique ID for context item\n */\n private generateId(): string {\n return `ctx-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n }\n\n /**\n * Hash content for deduplication\n */\n private hashContent(content: string): string {\n return crypto\n .createHash('sha256')\n .update(content)\n .digest('hex')\n .substring(0, 16);\n }\n\n /**\n * Normalize content for comparison\n */\n private normalizeContent(content: string): string {\n return content.replace(/\\s+/g, ' ').trim().toLowerCase();\n }\n}\n\nexport default ContextManager;\n\n"],"names":["ContextManager","track","item","position","id","generateId","hash","hashContent","content","trackedItem","injectedAt","Date","timestamp","priority","items","set","hashes","add","logger","debug","category","hasContext","has","hasContentHash","hasSimilarContent","normalized","normalizeContent","values","itemNormalized","includes","get","getAll","Array","from","getByCategory","filter","getByPriority","getBySource","source","getCategories","categories","Set","forEach","sort","getStats","byCategory","Map","byPriority","bySource","oldestTimestamp","newestTimestamp","totalItems","size","remove","delete","clear","now","Math","random","toString","substring","crypto","createHash","update","digest","replace","trim","toLowerCase","wrapLogger","DEFAULT_LOGGER"],"mappings":"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"}
1
+ {"version":3,"file":"context-manager.js","sources":["../src/context-manager.ts"],"sourcesContent":["import crypto from 'crypto';\nimport { DEFAULT_LOGGER, wrapLogger } from \"./logger\";\n\n// ===== TYPE DEFINITIONS =====\n\n/**\n * Dynamic content item with enhanced tracking and lifecycle\n */\nexport interface DynamicContentItem {\n content: string;\n title?: string;\n weight?: number;\n\n // Unique identifier for deduplication\n id?: string;\n\n // Category for grouping\n category?: string;\n\n // Source of context\n source?: string;\n\n // Priority level\n priority?: 'high' | 'medium' | 'low';\n\n // Timestamp\n timestamp?: Date;\n}\n\n/**\n * Tracked context item with metadata\n */\nexport interface TrackedContextItem extends DynamicContentItem {\n id: string;\n hash: string;\n position: number;\n injectedAt: Date;\n}\n\n/**\n * Context statistics\n */\nexport interface ContextStats {\n totalItems: number;\n byCategory: Map<string, number>;\n byPriority: Map<string, number>;\n bySource: Map<string, number>;\n oldestTimestamp?: Date;\n newestTimestamp?: Date;\n}\n\n/**\n * ContextManager tracks and manages dynamically injected context.\n *\n * Features:\n * - Track all injected context with metadata\n * - Deduplication by ID, hash, or content\n * - Category-based organization\n * - Query context state\n * - Context statistics\n *\n * @example\n * ```typescript\n * const manager = new ContextManager();\n *\n * // Track injected context\n * manager.track({\n * id: 'file:main.ts',\n * content: fileContent,\n * title: 'Main File',\n * category: 'source-code'\n * }, 5);\n *\n * // Check for duplicates\n * if (manager.hasContext('file:main.ts')) {\n * console.log('Already provided');\n * }\n *\n * // Query by category\n * const sourceFiles = manager.getByCategory('source-code');\n * ```\n */\nexport class ContextManager {\n private items: Map<string, TrackedContextItem>;\n private hashes: Set<string>;\n private logger: any;\n\n constructor(logger?: any) {\n this.items = new Map();\n this.hashes = new Set();\n this.logger = wrapLogger(logger || DEFAULT_LOGGER, 'ContextManager');\n }\n\n /**\n * Track a context item (with deduplication by content hash for items without ID)\n */\n track(item: DynamicContentItem, position: number): void {\n const hash = this.hashContent(item.content);\n\n // If item has no ID and we already have this content hash, skip tracking\n if (!item.id && this.hashes.has(hash)) {\n this.logger.debug('Skipping duplicate context item by hash', { hash });\n return;\n }\n\n const id = item.id || this.generateId();\n\n const trackedItem: TrackedContextItem = {\n ...item,\n id,\n hash,\n position,\n injectedAt: new Date(),\n timestamp: item.timestamp || new Date(),\n priority: item.priority || 'medium',\n };\n\n this.items.set(id, trackedItem);\n this.hashes.add(hash);\n\n this.logger.debug('Tracked context item', { id, category: item.category, position });\n }\n\n /**\n * Check if context with given ID exists\n */\n hasContext(id: string): boolean {\n return this.items.has(id);\n }\n\n /**\n * Check if content with given hash exists\n */\n hasContentHash(content: string): boolean {\n const hash = this.hashContent(content);\n return this.hashes.has(hash);\n }\n\n /**\n * Check if similar content exists (fuzzy match)\n * Uses similarity threshold to avoid overly aggressive deduplication\n */\n hasSimilarContent(content: string, similarityThreshold: number = 0.9): boolean {\n // Warn if checking against a large number of items (performance consideration)\n const MAX_ITEMS_WARNING = 1000;\n if (this.items.size > MAX_ITEMS_WARNING) {\n this.logger.warn('Large number of context items, similarity check may be slow', {\n count: this.items.size,\n threshold: MAX_ITEMS_WARNING\n });\n }\n\n const normalized = this.normalizeContent(content);\n\n for (const item of this.items.values()) {\n const itemNormalized = this.normalizeContent(item.content || '');\n\n // Exact match\n if (normalized === itemNormalized) {\n return true;\n }\n\n // Calculate similarity ratio (Jaccard-like)\n const longer = normalized.length > itemNormalized.length ? normalized : itemNormalized;\n const shorter = normalized.length <= itemNormalized.length ? normalized : itemNormalized;\n\n // Only consider substring match if the shorter is at least 90% of longer\n const lengthRatio = shorter.length / longer.length;\n\n if (lengthRatio >= similarityThreshold) {\n // Check if one is contained in the other\n if (longer.includes(shorter)) {\n return true;\n }\n }\n }\n\n return false;\n }\n\n /**\n * Get context item by ID\n */\n get(id: string): TrackedContextItem | undefined {\n return this.items.get(id);\n }\n\n /**\n * Get all tracked context items\n */\n getAll(): TrackedContextItem[] {\n return Array.from(this.items.values());\n }\n\n /**\n * Get context items by category\n */\n getByCategory(category: string): TrackedContextItem[] {\n return this.getAll().filter(item => item.category === category);\n }\n\n /**\n * Get context items by priority\n */\n getByPriority(priority: 'high' | 'medium' | 'low'): TrackedContextItem[] {\n return this.getAll().filter(item => item.priority === priority);\n }\n\n /**\n * Get context items by source\n */\n getBySource(source: string): TrackedContextItem[] {\n return this.getAll().filter(item => item.source === source);\n }\n\n /**\n * Get all categories\n */\n getCategories(): string[] {\n const categories = new Set<string>();\n this.items.forEach(item => {\n if (item.category) {\n categories.add(item.category);\n }\n });\n return Array.from(categories).sort();\n }\n\n /**\n * Get context statistics\n */\n getStats(): ContextStats {\n const byCategory = new Map<string, number>();\n const byPriority = new Map<string, number>();\n const bySource = new Map<string, number>();\n let oldestTimestamp: Date | undefined;\n let newestTimestamp: Date | undefined;\n\n this.items.forEach(item => {\n // Category stats\n if (item.category) {\n byCategory.set(item.category, (byCategory.get(item.category) || 0) + 1);\n }\n\n // Priority stats\n const priority = item.priority || 'medium';\n byPriority.set(priority, (byPriority.get(priority) || 0) + 1);\n\n // Source stats\n if (item.source) {\n bySource.set(item.source, (bySource.get(item.source) || 0) + 1);\n }\n\n // Timestamp stats\n if (item.timestamp) {\n if (!oldestTimestamp || item.timestamp < oldestTimestamp) {\n oldestTimestamp = item.timestamp;\n }\n if (!newestTimestamp || item.timestamp > newestTimestamp) {\n newestTimestamp = item.timestamp;\n }\n }\n });\n\n return {\n totalItems: this.items.size,\n byCategory,\n byPriority,\n bySource,\n oldestTimestamp,\n newestTimestamp,\n };\n }\n\n /**\n * Remove context item by ID\n */\n remove(id: string): boolean {\n const item = this.items.get(id);\n if (item) {\n this.items.delete(id);\n this.hashes.delete(item.hash);\n this.logger.debug('Removed context item', { id });\n return true;\n }\n return false;\n }\n\n /**\n * Clear all tracked context\n */\n clear(): void {\n this.items.clear();\n this.hashes.clear();\n this.logger.debug('Cleared all context');\n }\n\n /**\n * Generate unique ID for context item\n */\n private generateId(): string {\n return `ctx-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n }\n\n /**\n * Hash content for deduplication\n */\n private hashContent(content: string): string {\n return crypto\n .createHash('sha256')\n .update(content)\n .digest('hex')\n .substring(0, 16);\n }\n\n /**\n * Normalize content for comparison\n */\n private normalizeContent(content: string): string {\n return content.replace(/\\s+/g, ' ').trim().toLowerCase();\n }\n}\n\nexport default ContextManager;\n\n"],"names":["ContextManager","track","item","position","hash","hashContent","content","id","hashes","has","logger","debug","generateId","trackedItem","injectedAt","Date","timestamp","priority","items","set","add","category","hasContext","hasContentHash","hasSimilarContent","similarityThreshold","MAX_ITEMS_WARNING","size","warn","count","threshold","normalized","normalizeContent","values","itemNormalized","longer","length","shorter","lengthRatio","includes","get","getAll","Array","from","getByCategory","filter","getByPriority","getBySource","source","getCategories","categories","Set","forEach","sort","getStats","byCategory","Map","byPriority","bySource","oldestTimestamp","newestTimestamp","totalItems","remove","delete","clear","now","Math","random","toString","substring","crypto","createHash","update","digest","replace","trim","toLowerCase","wrapLogger","DEFAULT_LOGGER"],"mappings":"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"}
@@ -130,6 +130,8 @@ export declare class ConversationLogger {
130
130
  private startTime;
131
131
  private logger;
132
132
  private messageIndex;
133
+ private cachedOutputPath?;
134
+ private writeQueue;
133
135
  constructor(config: LogConfig, logger?: any);
134
136
  /**
135
137
  * Start conversation logging
@@ -160,7 +162,7 @@ export declare class ConversationLogger {
160
162
  */
161
163
  private generateId;
162
164
  /**
163
- * Get output file path
165
+ * Get output file path (cached for JSONL to avoid recalculation)
164
166
  */
165
167
  private getOutputPath;
166
168
  /**