@riotprompt/riotprompt 0.0.8 → 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.
- package/.kodrdriv-test-cache.json +6 -0
- package/BUG-ANALYSIS.md +523 -0
- package/CODE-REVIEW-SUMMARY.md +330 -0
- package/FIXES-APPLIED.md +437 -0
- package/README.md +2 -2
- package/dist/builder.js +3 -0
- package/dist/builder.js.map +1 -1
- package/dist/chat.d.ts +1 -1
- package/dist/chat.js +2 -5
- package/dist/chat.js.map +1 -1
- package/dist/constants.js +1 -2
- package/dist/constants.js.map +1 -1
- package/dist/context-manager.d.ts +136 -0
- package/dist/context-manager.js +243 -0
- package/dist/context-manager.js.map +1 -0
- package/dist/conversation-logger.d.ts +285 -0
- package/dist/conversation-logger.js +491 -0
- package/dist/conversation-logger.js.map +1 -0
- package/dist/conversation.d.ts +277 -0
- package/dist/conversation.js +649 -0
- package/dist/conversation.js.map +1 -0
- package/dist/formatter.js.map +1 -1
- package/dist/items/section.js +3 -3
- package/dist/items/section.js.map +1 -1
- package/dist/iteration-strategy.d.ts +233 -0
- package/dist/iteration-strategy.js +520 -0
- package/dist/iteration-strategy.js.map +1 -0
- package/dist/loader.js +21 -3
- package/dist/loader.js.map +1 -1
- package/dist/message-builder.d.ts +156 -0
- package/dist/message-builder.js +256 -0
- package/dist/message-builder.js.map +1 -0
- package/dist/model-config.d.ts +115 -0
- package/dist/model-config.js +205 -0
- package/dist/model-config.js.map +1 -0
- package/dist/override.js +8 -1
- package/dist/override.js.map +1 -1
- package/dist/parser.js +3 -3
- package/dist/parser.js.map +1 -1
- package/dist/recipes.d.ts +42 -0
- package/dist/recipes.js +189 -4
- package/dist/recipes.js.map +1 -1
- package/dist/reflection.d.ts +250 -0
- package/dist/reflection.js +419 -0
- package/dist/reflection.js.map +1 -0
- package/dist/riotprompt.cjs +3854 -178
- package/dist/riotprompt.cjs.map +1 -1
- package/dist/riotprompt.d.ts +20 -2
- package/dist/riotprompt.js +10 -1
- package/dist/riotprompt.js.map +1 -1
- package/dist/token-budget.d.ts +177 -0
- package/dist/token-budget.js +401 -0
- package/dist/token-budget.js.map +1 -0
- package/dist/tools.d.ts +239 -0
- package/dist/tools.js +324 -0
- package/dist/tools.js.map +1 -0
- package/dist/util/general.js +1 -1
- package/dist/util/general.js.map +1 -1
- package/package.json +23 -20
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dynamic content item with enhanced tracking and lifecycle
|
|
3
|
+
*/
|
|
4
|
+
export interface DynamicContentItem {
|
|
5
|
+
content: string;
|
|
6
|
+
title?: string;
|
|
7
|
+
weight?: number;
|
|
8
|
+
id?: string;
|
|
9
|
+
category?: string;
|
|
10
|
+
source?: string;
|
|
11
|
+
priority?: 'high' | 'medium' | 'low';
|
|
12
|
+
timestamp?: Date;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Tracked context item with metadata
|
|
16
|
+
*/
|
|
17
|
+
export interface TrackedContextItem extends DynamicContentItem {
|
|
18
|
+
id: string;
|
|
19
|
+
hash: string;
|
|
20
|
+
position: number;
|
|
21
|
+
injectedAt: Date;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Context statistics
|
|
25
|
+
*/
|
|
26
|
+
export interface ContextStats {
|
|
27
|
+
totalItems: number;
|
|
28
|
+
byCategory: Map<string, number>;
|
|
29
|
+
byPriority: Map<string, number>;
|
|
30
|
+
bySource: Map<string, number>;
|
|
31
|
+
oldestTimestamp?: Date;
|
|
32
|
+
newestTimestamp?: Date;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* ContextManager tracks and manages dynamically injected context.
|
|
36
|
+
*
|
|
37
|
+
* Features:
|
|
38
|
+
* - Track all injected context with metadata
|
|
39
|
+
* - Deduplication by ID, hash, or content
|
|
40
|
+
* - Category-based organization
|
|
41
|
+
* - Query context state
|
|
42
|
+
* - Context statistics
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const manager = new ContextManager();
|
|
47
|
+
*
|
|
48
|
+
* // Track injected context
|
|
49
|
+
* manager.track({
|
|
50
|
+
* id: 'file:main.ts',
|
|
51
|
+
* content: fileContent,
|
|
52
|
+
* title: 'Main File',
|
|
53
|
+
* category: 'source-code'
|
|
54
|
+
* }, 5);
|
|
55
|
+
*
|
|
56
|
+
* // Check for duplicates
|
|
57
|
+
* if (manager.hasContext('file:main.ts')) {
|
|
58
|
+
* console.log('Already provided');
|
|
59
|
+
* }
|
|
60
|
+
*
|
|
61
|
+
* // Query by category
|
|
62
|
+
* const sourceFiles = manager.getByCategory('source-code');
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare class ContextManager {
|
|
66
|
+
private items;
|
|
67
|
+
private hashes;
|
|
68
|
+
private logger;
|
|
69
|
+
constructor(logger?: any);
|
|
70
|
+
/**
|
|
71
|
+
* Track a context item (with deduplication by content hash for items without ID)
|
|
72
|
+
*/
|
|
73
|
+
track(item: DynamicContentItem, position: number): void;
|
|
74
|
+
/**
|
|
75
|
+
* Check if context with given ID exists
|
|
76
|
+
*/
|
|
77
|
+
hasContext(id: string): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Check if content with given hash exists
|
|
80
|
+
*/
|
|
81
|
+
hasContentHash(content: string): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Check if similar content exists (fuzzy match)
|
|
84
|
+
* Uses similarity threshold to avoid overly aggressive deduplication
|
|
85
|
+
*/
|
|
86
|
+
hasSimilarContent(content: string, similarityThreshold?: number): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Get context item by ID
|
|
89
|
+
*/
|
|
90
|
+
get(id: string): TrackedContextItem | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Get all tracked context items
|
|
93
|
+
*/
|
|
94
|
+
getAll(): TrackedContextItem[];
|
|
95
|
+
/**
|
|
96
|
+
* Get context items by category
|
|
97
|
+
*/
|
|
98
|
+
getByCategory(category: string): TrackedContextItem[];
|
|
99
|
+
/**
|
|
100
|
+
* Get context items by priority
|
|
101
|
+
*/
|
|
102
|
+
getByPriority(priority: 'high' | 'medium' | 'low'): TrackedContextItem[];
|
|
103
|
+
/**
|
|
104
|
+
* Get context items by source
|
|
105
|
+
*/
|
|
106
|
+
getBySource(source: string): TrackedContextItem[];
|
|
107
|
+
/**
|
|
108
|
+
* Get all categories
|
|
109
|
+
*/
|
|
110
|
+
getCategories(): string[];
|
|
111
|
+
/**
|
|
112
|
+
* Get context statistics
|
|
113
|
+
*/
|
|
114
|
+
getStats(): ContextStats;
|
|
115
|
+
/**
|
|
116
|
+
* Remove context item by ID
|
|
117
|
+
*/
|
|
118
|
+
remove(id: string): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Clear all tracked context
|
|
121
|
+
*/
|
|
122
|
+
clear(): void;
|
|
123
|
+
/**
|
|
124
|
+
* Generate unique ID for context item
|
|
125
|
+
*/
|
|
126
|
+
private generateId;
|
|
127
|
+
/**
|
|
128
|
+
* Hash content for deduplication
|
|
129
|
+
*/
|
|
130
|
+
private hashContent;
|
|
131
|
+
/**
|
|
132
|
+
* Normalize content for comparison
|
|
133
|
+
*/
|
|
134
|
+
private normalizeContent;
|
|
135
|
+
}
|
|
136
|
+
export default ContextManager;
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import { wrapLogger, DEFAULT_LOGGER } from './logger.js';
|
|
3
|
+
|
|
4
|
+
function _define_property(obj, key, value) {
|
|
5
|
+
if (key in obj) {
|
|
6
|
+
Object.defineProperty(obj, key, {
|
|
7
|
+
value: value,
|
|
8
|
+
enumerable: true,
|
|
9
|
+
configurable: true,
|
|
10
|
+
writable: true
|
|
11
|
+
});
|
|
12
|
+
} else {
|
|
13
|
+
obj[key] = value;
|
|
14
|
+
}
|
|
15
|
+
return obj;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* ContextManager tracks and manages dynamically injected context.
|
|
19
|
+
*
|
|
20
|
+
* Features:
|
|
21
|
+
* - Track all injected context with metadata
|
|
22
|
+
* - Deduplication by ID, hash, or content
|
|
23
|
+
* - Category-based organization
|
|
24
|
+
* - Query context state
|
|
25
|
+
* - Context statistics
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const manager = new ContextManager();
|
|
30
|
+
*
|
|
31
|
+
* // Track injected context
|
|
32
|
+
* manager.track({
|
|
33
|
+
* id: 'file:main.ts',
|
|
34
|
+
* content: fileContent,
|
|
35
|
+
* title: 'Main File',
|
|
36
|
+
* category: 'source-code'
|
|
37
|
+
* }, 5);
|
|
38
|
+
*
|
|
39
|
+
* // Check for duplicates
|
|
40
|
+
* if (manager.hasContext('file:main.ts')) {
|
|
41
|
+
* console.log('Already provided');
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* // Query by category
|
|
45
|
+
* const sourceFiles = manager.getByCategory('source-code');
|
|
46
|
+
* ```
|
|
47
|
+
*/ class ContextManager {
|
|
48
|
+
/**
|
|
49
|
+
* Track a context item (with deduplication by content hash for items without ID)
|
|
50
|
+
*/ track(item, position) {
|
|
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();
|
|
60
|
+
const trackedItem = {
|
|
61
|
+
...item,
|
|
62
|
+
id,
|
|
63
|
+
hash,
|
|
64
|
+
position,
|
|
65
|
+
injectedAt: new Date(),
|
|
66
|
+
timestamp: item.timestamp || new Date(),
|
|
67
|
+
priority: item.priority || 'medium'
|
|
68
|
+
};
|
|
69
|
+
this.items.set(id, trackedItem);
|
|
70
|
+
this.hashes.add(hash);
|
|
71
|
+
this.logger.debug('Tracked context item', {
|
|
72
|
+
id,
|
|
73
|
+
category: item.category,
|
|
74
|
+
position
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Check if context with given ID exists
|
|
79
|
+
*/ hasContext(id) {
|
|
80
|
+
return this.items.has(id);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Check if content with given hash exists
|
|
84
|
+
*/ hasContentHash(content) {
|
|
85
|
+
const hash = this.hashContent(content);
|
|
86
|
+
return this.hashes.has(hash);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Check if similar content exists (fuzzy match)
|
|
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
|
+
}
|
|
100
|
+
const normalized = this.normalizeContent(content);
|
|
101
|
+
for (const item of this.items.values()){
|
|
102
|
+
const itemNormalized = this.normalizeContent(item.content || '');
|
|
103
|
+
// Exact match
|
|
104
|
+
if (normalized === itemNormalized) {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
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
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get context item by ID
|
|
123
|
+
*/ get(id) {
|
|
124
|
+
return this.items.get(id);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get all tracked context items
|
|
128
|
+
*/ getAll() {
|
|
129
|
+
return Array.from(this.items.values());
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get context items by category
|
|
133
|
+
*/ getByCategory(category) {
|
|
134
|
+
return this.getAll().filter((item)=>item.category === category);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get context items by priority
|
|
138
|
+
*/ getByPriority(priority) {
|
|
139
|
+
return this.getAll().filter((item)=>item.priority === priority);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get context items by source
|
|
143
|
+
*/ getBySource(source) {
|
|
144
|
+
return this.getAll().filter((item)=>item.source === source);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get all categories
|
|
148
|
+
*/ getCategories() {
|
|
149
|
+
const categories = new Set();
|
|
150
|
+
this.items.forEach((item)=>{
|
|
151
|
+
if (item.category) {
|
|
152
|
+
categories.add(item.category);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
return Array.from(categories).sort();
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get context statistics
|
|
159
|
+
*/ getStats() {
|
|
160
|
+
const byCategory = new Map();
|
|
161
|
+
const byPriority = new Map();
|
|
162
|
+
const bySource = new Map();
|
|
163
|
+
let oldestTimestamp;
|
|
164
|
+
let newestTimestamp;
|
|
165
|
+
this.items.forEach((item)=>{
|
|
166
|
+
// Category stats
|
|
167
|
+
if (item.category) {
|
|
168
|
+
byCategory.set(item.category, (byCategory.get(item.category) || 0) + 1);
|
|
169
|
+
}
|
|
170
|
+
// Priority stats
|
|
171
|
+
const priority = item.priority || 'medium';
|
|
172
|
+
byPriority.set(priority, (byPriority.get(priority) || 0) + 1);
|
|
173
|
+
// Source stats
|
|
174
|
+
if (item.source) {
|
|
175
|
+
bySource.set(item.source, (bySource.get(item.source) || 0) + 1);
|
|
176
|
+
}
|
|
177
|
+
// Timestamp stats
|
|
178
|
+
if (item.timestamp) {
|
|
179
|
+
if (!oldestTimestamp || item.timestamp < oldestTimestamp) {
|
|
180
|
+
oldestTimestamp = item.timestamp;
|
|
181
|
+
}
|
|
182
|
+
if (!newestTimestamp || item.timestamp > newestTimestamp) {
|
|
183
|
+
newestTimestamp = item.timestamp;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
return {
|
|
188
|
+
totalItems: this.items.size,
|
|
189
|
+
byCategory,
|
|
190
|
+
byPriority,
|
|
191
|
+
bySource,
|
|
192
|
+
oldestTimestamp,
|
|
193
|
+
newestTimestamp
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Remove context item by ID
|
|
198
|
+
*/ remove(id) {
|
|
199
|
+
const item = this.items.get(id);
|
|
200
|
+
if (item) {
|
|
201
|
+
this.items.delete(id);
|
|
202
|
+
this.hashes.delete(item.hash);
|
|
203
|
+
this.logger.debug('Removed context item', {
|
|
204
|
+
id
|
|
205
|
+
});
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Clear all tracked context
|
|
212
|
+
*/ clear() {
|
|
213
|
+
this.items.clear();
|
|
214
|
+
this.hashes.clear();
|
|
215
|
+
this.logger.debug('Cleared all context');
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Generate unique ID for context item
|
|
219
|
+
*/ generateId() {
|
|
220
|
+
return `ctx-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Hash content for deduplication
|
|
224
|
+
*/ hashContent(content) {
|
|
225
|
+
return crypto.createHash('sha256').update(content).digest('hex').substring(0, 16);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Normalize content for comparison
|
|
229
|
+
*/ normalizeContent(content) {
|
|
230
|
+
return content.replace(/\s+/g, ' ').trim().toLowerCase();
|
|
231
|
+
}
|
|
232
|
+
constructor(logger){
|
|
233
|
+
_define_property(this, "items", void 0);
|
|
234
|
+
_define_property(this, "hashes", void 0);
|
|
235
|
+
_define_property(this, "logger", void 0);
|
|
236
|
+
this.items = new Map();
|
|
237
|
+
this.hashes = new Set();
|
|
238
|
+
this.logger = wrapLogger(logger || DEFAULT_LOGGER, 'ContextManager');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export { ContextManager, ContextManager as default };
|
|
243
|
+
//# sourceMappingURL=context-manager.js.map
|
|
@@ -0,0 +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 (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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"}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { ConversationMessage, ToolCall } from './conversation';
|
|
2
|
+
/**
|
|
3
|
+
* Log format
|
|
4
|
+
*/
|
|
5
|
+
export type LogFormat = 'json' | 'markdown' | 'jsonl';
|
|
6
|
+
/**
|
|
7
|
+
* Log configuration
|
|
8
|
+
*/
|
|
9
|
+
export interface LogConfig {
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
outputPath?: string;
|
|
12
|
+
format?: LogFormat;
|
|
13
|
+
filenameTemplate?: string;
|
|
14
|
+
includeMetadata?: boolean;
|
|
15
|
+
includePrompt?: boolean;
|
|
16
|
+
redactSensitive?: boolean;
|
|
17
|
+
redactPatterns?: RegExp[];
|
|
18
|
+
onSaved?: (path: string) => void;
|
|
19
|
+
onError?: (error: Error) => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Logged conversation structure
|
|
23
|
+
*/
|
|
24
|
+
export interface LoggedConversation {
|
|
25
|
+
id: string;
|
|
26
|
+
metadata: ConversationLogMetadata;
|
|
27
|
+
prompt?: PromptSnapshot;
|
|
28
|
+
messages: LoggedMessage[];
|
|
29
|
+
summary: ConversationSummary;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Conversation metadata for logging
|
|
33
|
+
*/
|
|
34
|
+
export interface ConversationLogMetadata {
|
|
35
|
+
startTime: Date;
|
|
36
|
+
endTime?: Date;
|
|
37
|
+
duration?: number;
|
|
38
|
+
model: string;
|
|
39
|
+
template?: string;
|
|
40
|
+
userContext?: Record<string, any>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Snapshot of prompt configuration
|
|
44
|
+
*/
|
|
45
|
+
export interface PromptSnapshot {
|
|
46
|
+
persona?: string;
|
|
47
|
+
instructions?: string;
|
|
48
|
+
content?: string[];
|
|
49
|
+
context?: string[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Logged message with metadata
|
|
53
|
+
*/
|
|
54
|
+
export interface LoggedMessage {
|
|
55
|
+
index: number;
|
|
56
|
+
timestamp: string;
|
|
57
|
+
role: string;
|
|
58
|
+
content: string | null;
|
|
59
|
+
tool_calls?: ToolCall[];
|
|
60
|
+
tool_call_id?: string;
|
|
61
|
+
metadata?: MessageLogMetadata;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Message metadata for logging
|
|
65
|
+
*/
|
|
66
|
+
export interface MessageLogMetadata {
|
|
67
|
+
tokens?: number;
|
|
68
|
+
source?: string;
|
|
69
|
+
latency?: number;
|
|
70
|
+
tool?: string;
|
|
71
|
+
duration?: number;
|
|
72
|
+
success?: boolean;
|
|
73
|
+
[key: string]: any;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Conversation summary
|
|
77
|
+
*/
|
|
78
|
+
export interface ConversationSummary {
|
|
79
|
+
totalMessages: number;
|
|
80
|
+
totalTokens?: number;
|
|
81
|
+
toolCallsExecuted: number;
|
|
82
|
+
iterations: number;
|
|
83
|
+
finalOutput?: string;
|
|
84
|
+
success: boolean;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Tool call log entry
|
|
88
|
+
*/
|
|
89
|
+
export interface ToolCallLog {
|
|
90
|
+
callId: string;
|
|
91
|
+
toolName: string;
|
|
92
|
+
timestamp: string;
|
|
93
|
+
iteration: number;
|
|
94
|
+
arguments: any;
|
|
95
|
+
result: any;
|
|
96
|
+
duration: number;
|
|
97
|
+
success: boolean;
|
|
98
|
+
error?: string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* ConversationLogger logs conversations to various formats.
|
|
102
|
+
*
|
|
103
|
+
* Features:
|
|
104
|
+
* - Multiple formats (JSON, Markdown, JSONL)
|
|
105
|
+
* - Automatic timestamping
|
|
106
|
+
* - Metadata tracking
|
|
107
|
+
* - Sensitive data redaction
|
|
108
|
+
* - Streaming support (JSONL)
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* const logger = new ConversationLogger({
|
|
113
|
+
* enabled: true,
|
|
114
|
+
* outputPath: 'logs/conversations',
|
|
115
|
+
* format: 'json',
|
|
116
|
+
* includeMetadata: true
|
|
117
|
+
* });
|
|
118
|
+
*
|
|
119
|
+
* logger.onConversationStart({ model: 'gpt-4o', startTime: new Date() });
|
|
120
|
+
* logger.onMessageAdded(message);
|
|
121
|
+
* const path = await logger.save();
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
export declare class ConversationLogger {
|
|
125
|
+
private config;
|
|
126
|
+
private conversationId;
|
|
127
|
+
private metadata;
|
|
128
|
+
private messages;
|
|
129
|
+
private toolCalls;
|
|
130
|
+
private startTime;
|
|
131
|
+
private logger;
|
|
132
|
+
private messageIndex;
|
|
133
|
+
private cachedOutputPath?;
|
|
134
|
+
private writeQueue;
|
|
135
|
+
constructor(config: LogConfig, logger?: any);
|
|
136
|
+
/**
|
|
137
|
+
* Start conversation logging
|
|
138
|
+
*/
|
|
139
|
+
onConversationStart(metadata: Partial<ConversationLogMetadata>): void;
|
|
140
|
+
/**
|
|
141
|
+
* Log a message
|
|
142
|
+
*/
|
|
143
|
+
onMessageAdded(message: ConversationMessage, metadata?: MessageLogMetadata): void;
|
|
144
|
+
/**
|
|
145
|
+
* Log a tool call
|
|
146
|
+
*/
|
|
147
|
+
onToolCall(callId: string, toolName: string, iteration: number, args: any, result: any, duration: number, success: boolean, error?: string): void;
|
|
148
|
+
/**
|
|
149
|
+
* End conversation logging
|
|
150
|
+
*/
|
|
151
|
+
onConversationEnd(_summary: ConversationSummary): void;
|
|
152
|
+
/**
|
|
153
|
+
* Save conversation to disk
|
|
154
|
+
*/
|
|
155
|
+
save(): Promise<string>;
|
|
156
|
+
/**
|
|
157
|
+
* Get logged conversation object
|
|
158
|
+
*/
|
|
159
|
+
getConversation(): LoggedConversation;
|
|
160
|
+
/**
|
|
161
|
+
* Generate unique conversation ID
|
|
162
|
+
*/
|
|
163
|
+
private generateId;
|
|
164
|
+
/**
|
|
165
|
+
* Get output file path (cached for JSONL to avoid recalculation)
|
|
166
|
+
*/
|
|
167
|
+
private getOutputPath;
|
|
168
|
+
/**
|
|
169
|
+
* Save as JSON
|
|
170
|
+
*/
|
|
171
|
+
private saveAsJSON;
|
|
172
|
+
/**
|
|
173
|
+
* Save as Markdown
|
|
174
|
+
*/
|
|
175
|
+
private saveAsMarkdown;
|
|
176
|
+
/**
|
|
177
|
+
* Append to JSONL file (streaming)
|
|
178
|
+
*/
|
|
179
|
+
private appendToJSONL;
|
|
180
|
+
/**
|
|
181
|
+
* Redact sensitive content
|
|
182
|
+
*/
|
|
183
|
+
private redactContent;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Replay options
|
|
187
|
+
*/
|
|
188
|
+
export interface ReplayOptions {
|
|
189
|
+
model?: string;
|
|
190
|
+
maxIterations?: number;
|
|
191
|
+
retryFailedTools?: boolean;
|
|
192
|
+
toolTimeout?: number;
|
|
193
|
+
expectSimilarOutput?: boolean;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Replay result
|
|
197
|
+
*/
|
|
198
|
+
export interface ReplayResult {
|
|
199
|
+
success: boolean;
|
|
200
|
+
conversation: LoggedConversation;
|
|
201
|
+
errors?: Error[];
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Comparison result
|
|
205
|
+
*/
|
|
206
|
+
export interface ComparisonResult {
|
|
207
|
+
messageDiff: number;
|
|
208
|
+
toolCallDiff: number;
|
|
209
|
+
tokenDiff?: number;
|
|
210
|
+
outputSimilarity: number;
|
|
211
|
+
costSavings?: number;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* ConversationReplayer loads and replays logged conversations.
|
|
215
|
+
*
|
|
216
|
+
* Features:
|
|
217
|
+
* - Load from various formats
|
|
218
|
+
* - Replay conversations
|
|
219
|
+
* - Compare replays with originals
|
|
220
|
+
* - Export to different formats
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* const replayer = await ConversationReplayer.load('logs/conv.json');
|
|
225
|
+
*
|
|
226
|
+
* console.log('Messages:', replayer.messages.length);
|
|
227
|
+
* console.log('Tool calls:', replayer.getToolCalls().length);
|
|
228
|
+
*
|
|
229
|
+
* const timeline = replayer.getTimeline();
|
|
230
|
+
* console.log('Events:', timeline.length);
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
export declare class ConversationReplayer {
|
|
234
|
+
private conversation;
|
|
235
|
+
private logger;
|
|
236
|
+
private constructor();
|
|
237
|
+
/**
|
|
238
|
+
* Load conversation from file
|
|
239
|
+
*/
|
|
240
|
+
static load(filePath: string, logger?: any): Promise<ConversationReplayer>;
|
|
241
|
+
/**
|
|
242
|
+
* Load latest conversation from directory
|
|
243
|
+
*/
|
|
244
|
+
static loadLatest(directory: string, logger?: any): Promise<ConversationReplayer>;
|
|
245
|
+
/**
|
|
246
|
+
* Get all messages
|
|
247
|
+
*/
|
|
248
|
+
get messages(): LoggedMessage[];
|
|
249
|
+
/**
|
|
250
|
+
* Get conversation metadata
|
|
251
|
+
*/
|
|
252
|
+
getMetadata(): ConversationLogMetadata;
|
|
253
|
+
/**
|
|
254
|
+
* Get tool calls
|
|
255
|
+
*/
|
|
256
|
+
getToolCalls(): ToolCallLog[];
|
|
257
|
+
/**
|
|
258
|
+
* Get message at index
|
|
259
|
+
*/
|
|
260
|
+
getMessageAt(index: number): LoggedMessage | undefined;
|
|
261
|
+
/**
|
|
262
|
+
* Get timeline of events
|
|
263
|
+
*/
|
|
264
|
+
getTimeline(): TimelineEvent[];
|
|
265
|
+
/**
|
|
266
|
+
* Export to format
|
|
267
|
+
*/
|
|
268
|
+
exportToFormat(format: LogFormat, outputPath: string): Promise<string>;
|
|
269
|
+
/**
|
|
270
|
+
* Export as markdown
|
|
271
|
+
*/
|
|
272
|
+
private exportMarkdown;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Timeline event interface
|
|
276
|
+
*/
|
|
277
|
+
interface TimelineEvent {
|
|
278
|
+
timestamp: string;
|
|
279
|
+
iteration: number;
|
|
280
|
+
type: string;
|
|
281
|
+
description: string;
|
|
282
|
+
duration?: number;
|
|
283
|
+
success?: boolean;
|
|
284
|
+
}
|
|
285
|
+
export default ConversationLogger;
|