@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.
Files changed (59) hide show
  1. package/.kodrdriv-test-cache.json +6 -0
  2. package/BUG-ANALYSIS.md +523 -0
  3. package/CODE-REVIEW-SUMMARY.md +330 -0
  4. package/FIXES-APPLIED.md +437 -0
  5. package/README.md +2 -2
  6. package/dist/builder.js +3 -0
  7. package/dist/builder.js.map +1 -1
  8. package/dist/chat.d.ts +1 -1
  9. package/dist/chat.js +2 -5
  10. package/dist/chat.js.map +1 -1
  11. package/dist/constants.js +1 -2
  12. package/dist/constants.js.map +1 -1
  13. package/dist/context-manager.d.ts +136 -0
  14. package/dist/context-manager.js +243 -0
  15. package/dist/context-manager.js.map +1 -0
  16. package/dist/conversation-logger.d.ts +285 -0
  17. package/dist/conversation-logger.js +491 -0
  18. package/dist/conversation-logger.js.map +1 -0
  19. package/dist/conversation.d.ts +277 -0
  20. package/dist/conversation.js +649 -0
  21. package/dist/conversation.js.map +1 -0
  22. package/dist/formatter.js.map +1 -1
  23. package/dist/items/section.js +3 -3
  24. package/dist/items/section.js.map +1 -1
  25. package/dist/iteration-strategy.d.ts +233 -0
  26. package/dist/iteration-strategy.js +520 -0
  27. package/dist/iteration-strategy.js.map +1 -0
  28. package/dist/loader.js +21 -3
  29. package/dist/loader.js.map +1 -1
  30. package/dist/message-builder.d.ts +156 -0
  31. package/dist/message-builder.js +256 -0
  32. package/dist/message-builder.js.map +1 -0
  33. package/dist/model-config.d.ts +115 -0
  34. package/dist/model-config.js +205 -0
  35. package/dist/model-config.js.map +1 -0
  36. package/dist/override.js +8 -1
  37. package/dist/override.js.map +1 -1
  38. package/dist/parser.js +3 -3
  39. package/dist/parser.js.map +1 -1
  40. package/dist/recipes.d.ts +42 -0
  41. package/dist/recipes.js +189 -4
  42. package/dist/recipes.js.map +1 -1
  43. package/dist/reflection.d.ts +250 -0
  44. package/dist/reflection.js +419 -0
  45. package/dist/reflection.js.map +1 -0
  46. package/dist/riotprompt.cjs +3854 -178
  47. package/dist/riotprompt.cjs.map +1 -1
  48. package/dist/riotprompt.d.ts +20 -2
  49. package/dist/riotprompt.js +10 -1
  50. package/dist/riotprompt.js.map +1 -1
  51. package/dist/token-budget.d.ts +177 -0
  52. package/dist/token-budget.js +401 -0
  53. package/dist/token-budget.js.map +1 -0
  54. package/dist/tools.d.ts +239 -0
  55. package/dist/tools.js +324 -0
  56. package/dist/tools.js.map +1 -0
  57. package/dist/util/general.js +1 -1
  58. package/dist/util/general.js.map +1 -1
  59. package/package.json +23 -20
@@ -0,0 +1,649 @@
1
+ import { z } from 'zod';
2
+ import { ContextManager } from './context-manager.js';
3
+ import { ConversationLogger } from './conversation-logger.js';
4
+ import { wrapLogger, DEFAULT_LOGGER } from './logger.js';
5
+ import { MessageBuilder } from './message-builder.js';
6
+ import { create } from './formatter.js';
7
+ import { TokenBudgetManager } from './token-budget.js';
8
+
9
+ function _define_property(obj, key, value) {
10
+ if (key in obj) {
11
+ Object.defineProperty(obj, key, {
12
+ value: value,
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true
16
+ });
17
+ } else {
18
+ obj[key] = value;
19
+ }
20
+ return obj;
21
+ }
22
+ // ===== SCHEMAS =====
23
+ const ConversationBuilderConfigSchema = z.object({
24
+ model: z.string(),
25
+ formatter: z.any().optional(),
26
+ trackContext: z.boolean().optional().default(true),
27
+ deduplicateContext: z.boolean().optional().default(true)
28
+ });
29
+ // ===== CONVERSATION BUILDER =====
30
+ /**
31
+ * ConversationBuilder manages multi-turn conversations with full lifecycle support.
32
+ *
33
+ * Features:
34
+ * - Initialize from RiotPrompt prompts
35
+ * - Add messages of any type (system, user, assistant, tool)
36
+ * - Handle tool calls and results
37
+ * - Inject dynamic context
38
+ * - Clone for parallel exploration
39
+ * - Serialize/deserialize for persistence
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * // Create from prompt
44
+ * const conversation = ConversationBuilder.create()
45
+ * .fromPrompt(prompt, 'gpt-4o')
46
+ * .build();
47
+ *
48
+ * // Add messages
49
+ * conversation.addUserMessage('Analyze this code');
50
+ *
51
+ * // Handle tool calls
52
+ * conversation.addAssistantWithToolCalls(null, toolCalls);
53
+ * conversation.addToolResult(toolCallId, result);
54
+ *
55
+ * // Export
56
+ * const messages = conversation.toMessages();
57
+ * ```
58
+ */ class ConversationBuilder {
59
+ /**
60
+ * Create a new ConversationBuilder instance
61
+ */ static create(config, logger) {
62
+ const defaultConfig = {
63
+ model: 'gpt-4o',
64
+ trackContext: true,
65
+ deduplicateContext: true,
66
+ ...config
67
+ };
68
+ return new ConversationBuilder(defaultConfig, logger);
69
+ }
70
+ /**
71
+ * Initialize conversation from a RiotPrompt prompt
72
+ */ fromPrompt(prompt, model) {
73
+ const targetModel = model || this.config.model;
74
+ this.logger.debug('Initializing from prompt', {
75
+ model: targetModel
76
+ });
77
+ // Use formatter (provided or create new one)
78
+ const formatter$1 = this.config.formatter || create();
79
+ const request = formatter$1.formatPrompt(targetModel, prompt);
80
+ // Add all messages from formatted request
81
+ request.messages.forEach((msg)=>{
82
+ this.state.messages.push(msg);
83
+ });
84
+ this.updateMetadata();
85
+ this.logger.debug('Initialized from prompt', {
86
+ messageCount: this.state.messages.length
87
+ });
88
+ return this;
89
+ }
90
+ /**
91
+ * Add a system message
92
+ */ addSystemMessage(content) {
93
+ this.logger.debug('Adding system message');
94
+ let messageContent;
95
+ if (typeof content === 'string') {
96
+ messageContent = content;
97
+ } else {
98
+ // Format section using formatter
99
+ const formatter$1 = this.config.formatter || create();
100
+ messageContent = formatter$1.format(content);
101
+ }
102
+ this.state.messages.push({
103
+ role: 'system',
104
+ content: messageContent
105
+ });
106
+ this.updateMetadata();
107
+ return this;
108
+ }
109
+ /**
110
+ * Add a user message (with automatic budget management)
111
+ */ addUserMessage(content) {
112
+ this.logger.debug('Adding user message');
113
+ let messageContent;
114
+ if (typeof content === 'string') {
115
+ messageContent = content;
116
+ } else {
117
+ // Format section using formatter
118
+ const formatter$1 = this.config.formatter || create();
119
+ messageContent = formatter$1.format(content);
120
+ }
121
+ const message = {
122
+ role: 'user',
123
+ content: messageContent
124
+ };
125
+ // Check budget if enabled
126
+ if (this.budgetManager) {
127
+ if (!this.budgetManager.canAddMessage(message, this.state.messages)) {
128
+ this.logger.warn('Budget exceeded, compressing conversation');
129
+ this.state.messages = this.budgetManager.compress(this.state.messages);
130
+ // Re-check after compression and warn if still over budget
131
+ if (!this.budgetManager.canAddMessage(message, this.state.messages)) {
132
+ this.logger.warn('Token budget still exceeded after compression, adding message anyway');
133
+ // Note: We add the message anyway to maintain backward compatibility
134
+ // Consider setting onBudgetExceeded: 'error' in config if strict enforcement is needed
135
+ }
136
+ }
137
+ }
138
+ this.state.messages.push(message);
139
+ this.updateMetadata();
140
+ return this;
141
+ }
142
+ /**
143
+ * Add an assistant message
144
+ */ addAssistantMessage(content) {
145
+ this.logger.debug('Adding assistant message');
146
+ this.state.messages.push({
147
+ role: 'assistant',
148
+ content: content || ''
149
+ });
150
+ this.updateMetadata();
151
+ return this;
152
+ }
153
+ /**
154
+ * Add an assistant message with tool calls
155
+ */ addAssistantWithToolCalls(content, toolCalls) {
156
+ this.logger.debug('Adding assistant message with tool calls', {
157
+ toolCount: toolCalls.length
158
+ });
159
+ this.state.messages.push({
160
+ role: 'assistant',
161
+ content: content,
162
+ tool_calls: toolCalls
163
+ });
164
+ this.state.metadata.toolCallCount += toolCalls.length;
165
+ this.updateMetadata();
166
+ return this;
167
+ }
168
+ /**
169
+ * Add a tool result message
170
+ */ addToolResult(toolCallId, content, toolName) {
171
+ this.logger.debug('Adding tool result', {
172
+ toolCallId,
173
+ toolName
174
+ });
175
+ const message = {
176
+ role: 'tool',
177
+ tool_call_id: toolCallId,
178
+ content: content
179
+ };
180
+ if (toolName) {
181
+ message.name = toolName;
182
+ }
183
+ this.state.messages.push(message);
184
+ this.updateMetadata();
185
+ return this;
186
+ }
187
+ /**
188
+ * Alias for addToolResult (more intuitive naming)
189
+ */ addToolMessage(toolCallId, content, toolName) {
190
+ return this.addToolResult(toolCallId, content, toolName);
191
+ }
192
+ /**
193
+ * Inject context into the conversation with advanced options
194
+ *
195
+ * @param context - Array of content items to inject
196
+ * @param options - Injection options (position, format, deduplication, etc.)
197
+ */ injectContext(context, options) {
198
+ var _this_config_deduplicateContext;
199
+ const opts = {
200
+ position: 'end',
201
+ format: 'structured',
202
+ deduplicate: (_this_config_deduplicateContext = this.config.deduplicateContext) !== null && _this_config_deduplicateContext !== void 0 ? _this_config_deduplicateContext : true,
203
+ deduplicateBy: 'id',
204
+ priority: 'medium',
205
+ weight: 1.0,
206
+ category: undefined,
207
+ source: undefined,
208
+ ...options
209
+ };
210
+ this.logger.debug('Injecting context', {
211
+ itemCount: context.length,
212
+ options: opts
213
+ });
214
+ // Filter out duplicates if enabled
215
+ const itemsToAdd = [];
216
+ for (const item of context){
217
+ const enrichedItem = {
218
+ ...item,
219
+ priority: item.priority || opts.priority,
220
+ weight: item.weight || opts.weight,
221
+ category: item.category || opts.category,
222
+ source: item.source || opts.source,
223
+ timestamp: item.timestamp || new Date()
224
+ };
225
+ // Check deduplication
226
+ if (opts.deduplicate) {
227
+ let skip = false;
228
+ switch(opts.deduplicateBy){
229
+ case 'id':
230
+ if (enrichedItem.id && this.state.contextManager.hasContext(enrichedItem.id)) {
231
+ this.logger.debug('Skipping duplicate context by ID', {
232
+ id: enrichedItem.id
233
+ });
234
+ skip = true;
235
+ }
236
+ break;
237
+ case 'hash':
238
+ if (this.state.contextManager.hasContentHash(enrichedItem.content)) {
239
+ this.logger.debug('Skipping duplicate context by hash');
240
+ skip = true;
241
+ }
242
+ break;
243
+ case 'content':
244
+ if (this.state.contextManager.hasSimilarContent(enrichedItem.content)) {
245
+ this.logger.debug('Skipping duplicate context by content');
246
+ skip = true;
247
+ }
248
+ break;
249
+ }
250
+ if (skip) {
251
+ continue;
252
+ }
253
+ }
254
+ itemsToAdd.push(enrichedItem);
255
+ }
256
+ // Only proceed if we have items to add
257
+ if (itemsToAdd.length === 0) {
258
+ return this;
259
+ }
260
+ // Calculate position
261
+ const position = this.calculatePosition(opts.position);
262
+ // Format and inject
263
+ for(let i = 0; i < itemsToAdd.length; i++){
264
+ const item = itemsToAdd[i];
265
+ const formatted = this.formatContextItem(item, opts.format);
266
+ const contextMessage = {
267
+ role: 'user',
268
+ content: formatted
269
+ };
270
+ // Each item is inserted at position + index to maintain order
271
+ const actualPosition = position + i;
272
+ this.state.messages.splice(actualPosition, 0, contextMessage);
273
+ // Track in context manager with correct position
274
+ this.state.contextManager.track(item, actualPosition);
275
+ }
276
+ this.updateMetadata();
277
+ return this;
278
+ }
279
+ /**
280
+ * Inject system-level context
281
+ */ injectSystemContext(context) {
282
+ this.logger.debug('Injecting system context');
283
+ let messageContent;
284
+ if (typeof context === 'string') {
285
+ messageContent = context;
286
+ } else {
287
+ const formatter$1 = this.config.formatter || create();
288
+ messageContent = formatter$1.format(context);
289
+ }
290
+ this.state.messages.push({
291
+ role: 'system',
292
+ content: messageContent
293
+ });
294
+ this.updateMetadata();
295
+ return this;
296
+ }
297
+ /**
298
+ * Get the number of messages in the conversation
299
+ */ getMessageCount() {
300
+ return this.state.messages.length;
301
+ }
302
+ /**
303
+ * Get the last message in the conversation
304
+ */ getLastMessage() {
305
+ return this.state.messages[this.state.messages.length - 1];
306
+ }
307
+ /**
308
+ * Get all messages
309
+ */ getMessages() {
310
+ return [
311
+ ...this.state.messages
312
+ ];
313
+ }
314
+ /**
315
+ * Check if conversation has any tool calls
316
+ */ hasToolCalls() {
317
+ return this.state.metadata.toolCallCount > 0;
318
+ }
319
+ /**
320
+ * Get conversation metadata
321
+ */ getMetadata() {
322
+ return {
323
+ ...this.state.metadata
324
+ };
325
+ }
326
+ /**
327
+ * Export messages in OpenAI format (deep copy to prevent shared state)
328
+ */ toMessages() {
329
+ return this.state.messages.map((msg)=>({
330
+ ...msg,
331
+ tool_calls: msg.tool_calls ? msg.tool_calls.map((tc)=>({
332
+ ...tc,
333
+ function: {
334
+ ...tc.function
335
+ }
336
+ })) : undefined
337
+ }));
338
+ }
339
+ /**
340
+ * Serialize conversation to JSON
341
+ */ toJSON() {
342
+ const serialized = {
343
+ messages: this.state.messages,
344
+ metadata: {
345
+ ...this.state.metadata,
346
+ created: this.state.metadata.created.toISOString(),
347
+ lastModified: this.state.metadata.lastModified.toISOString()
348
+ },
349
+ contextProvided: Array.from(this.state.contextProvided)
350
+ };
351
+ return JSON.stringify(serialized, null, 2);
352
+ }
353
+ /**
354
+ * Restore conversation from JSON
355
+ */ static fromJSON(json, config, logger) {
356
+ const parsed = JSON.parse(json);
357
+ const builder = ConversationBuilder.create({
358
+ model: parsed.metadata.model,
359
+ ...config
360
+ }, logger);
361
+ // Restore state
362
+ builder.state.messages = parsed.messages;
363
+ builder.state.metadata = {
364
+ ...parsed.metadata,
365
+ created: new Date(parsed.metadata.created),
366
+ lastModified: new Date(parsed.metadata.lastModified)
367
+ };
368
+ builder.state.contextProvided = new Set(parsed.contextProvided);
369
+ return builder;
370
+ }
371
+ /**
372
+ * Clone the conversation for parallel exploration (deep copy to prevent shared state)
373
+ */ clone() {
374
+ this.logger.debug('Cloning conversation');
375
+ const cloned = ConversationBuilder.create({
376
+ ...this.config
377
+ }, this.logger);
378
+ // Deep copy state (note: contextManager is already created in constructor)
379
+ cloned.state.messages = this.state.messages.map((msg)=>({
380
+ ...msg,
381
+ tool_calls: msg.tool_calls ? msg.tool_calls.map((tc)=>({
382
+ ...tc,
383
+ function: {
384
+ ...tc.function
385
+ }
386
+ })) : undefined
387
+ }));
388
+ cloned.state.metadata = {
389
+ ...this.state.metadata
390
+ };
391
+ cloned.state.contextProvided = new Set(this.state.contextProvided);
392
+ // Copy context manager state
393
+ const allContext = this.state.contextManager.getAll();
394
+ allContext.forEach((item)=>{
395
+ cloned.state.contextManager.track(item, item.position);
396
+ });
397
+ return cloned;
398
+ }
399
+ /**
400
+ * Truncate conversation to last N messages
401
+ */ truncate(maxMessages) {
402
+ this.logger.debug('Truncating conversation', {
403
+ maxMessages,
404
+ current: this.state.messages.length
405
+ });
406
+ if (this.state.messages.length > maxMessages) {
407
+ this.state.messages = this.state.messages.slice(-maxMessages);
408
+ this.updateMetadata();
409
+ }
410
+ return this;
411
+ }
412
+ /**
413
+ * Remove all messages of a specific type
414
+ */ removeMessagesOfType(role) {
415
+ this.logger.debug('Removing messages of type', {
416
+ role
417
+ });
418
+ this.state.messages = this.state.messages.filter((msg)=>msg.role !== role);
419
+ this.updateMetadata();
420
+ return this;
421
+ }
422
+ /**
423
+ * Get the context manager
424
+ */ getContextManager() {
425
+ return this.state.contextManager;
426
+ }
427
+ /**
428
+ * Get conversation state (for conditional injection)
429
+ */ getState() {
430
+ return {
431
+ messages: [
432
+ ...this.state.messages
433
+ ],
434
+ metadata: {
435
+ ...this.state.metadata
436
+ },
437
+ contextProvided: new Set(this.state.contextProvided),
438
+ contextManager: this.state.contextManager
439
+ };
440
+ }
441
+ // ===== SEMANTIC MESSAGE METHODS (Feature 5) =====
442
+ /**
443
+ * Add a system message using semantic builder
444
+ */ asSystem(content) {
445
+ const message = MessageBuilder.system(this.logger).withContent(content).withFormatter(this.config.formatter || create()).buildForModel(this.config.model);
446
+ this.state.messages.push(message);
447
+ this.updateMetadata();
448
+ return this;
449
+ }
450
+ /**
451
+ * Add a user message using semantic builder
452
+ */ asUser(content) {
453
+ const message = MessageBuilder.user(this.logger).withContent(content).withFormatter(this.config.formatter || create()).buildForModel(this.config.model);
454
+ // Check budget if enabled
455
+ if (this.budgetManager) {
456
+ if (!this.budgetManager.canAddMessage(message, this.state.messages)) {
457
+ this.logger.warn('Budget exceeded, compressing conversation');
458
+ this.state.messages = this.budgetManager.compress(this.state.messages);
459
+ }
460
+ }
461
+ this.state.messages.push(message);
462
+ this.updateMetadata();
463
+ return this;
464
+ }
465
+ /**
466
+ * Add an assistant message using semantic builder
467
+ */ asAssistant(content, toolCalls) {
468
+ const builder = MessageBuilder.assistant(this.logger).withFormatter(this.config.formatter || create());
469
+ if (content) {
470
+ builder.withContent(content);
471
+ }
472
+ if (toolCalls) {
473
+ builder.withToolCalls(toolCalls);
474
+ }
475
+ const message = builder.buildForModel(this.config.model);
476
+ if (toolCalls) {
477
+ this.state.metadata.toolCallCount += toolCalls.length;
478
+ }
479
+ this.state.messages.push(message);
480
+ this.updateMetadata();
481
+ return this;
482
+ }
483
+ /**
484
+ * Add a tool result message using semantic builder
485
+ */ asTool(callId, result, metadata) {
486
+ const builder = MessageBuilder.tool(callId, this.logger).withResult(result);
487
+ if (metadata) {
488
+ builder.withMetadata(metadata);
489
+ }
490
+ const message = builder.buildForModel(this.config.model);
491
+ this.state.messages.push(message);
492
+ this.updateMetadata();
493
+ return this;
494
+ }
495
+ /**
496
+ * Configure token budget
497
+ */ withTokenBudget(config) {
498
+ this.logger.debug('Configuring token budget', {
499
+ max: config.max
500
+ });
501
+ this.budgetManager = new TokenBudgetManager(config, this.config.model, this.logger);
502
+ return this;
503
+ }
504
+ /**
505
+ * Configure conversation logging
506
+ */ withLogging(config) {
507
+ this.logger.debug('Configuring conversation logging');
508
+ this.conversationLogger = new ConversationLogger(config, this.logger);
509
+ this.conversationLogger.onConversationStart({
510
+ model: this.config.model,
511
+ startTime: new Date()
512
+ });
513
+ return this;
514
+ }
515
+ /**
516
+ * Save conversation log
517
+ */ async saveLog() {
518
+ if (!this.conversationLogger) {
519
+ throw new Error('Logging not enabled. Call withLogging() first.');
520
+ }
521
+ this.conversationLogger.onConversationEnd({
522
+ totalMessages: this.state.messages.length,
523
+ toolCallsExecuted: this.state.metadata.toolCallCount,
524
+ iterations: 0,
525
+ success: true
526
+ });
527
+ return await this.conversationLogger.save();
528
+ }
529
+ /**
530
+ * Get current token usage
531
+ */ getTokenUsage() {
532
+ if (!this.budgetManager) {
533
+ return {
534
+ used: 0,
535
+ max: Infinity,
536
+ remaining: Infinity,
537
+ percentage: 0
538
+ };
539
+ }
540
+ return this.budgetManager.getCurrentUsage(this.state.messages);
541
+ }
542
+ /**
543
+ * Manually compress conversation
544
+ */ compress(_strategy) {
545
+ if (this.budgetManager) {
546
+ this.state.messages = this.budgetManager.compress(this.state.messages);
547
+ }
548
+ return this;
549
+ }
550
+ /**
551
+ * Build and return the builder (for fluent API compatibility)
552
+ */ build() {
553
+ return this;
554
+ }
555
+ /**
556
+ * Calculate position for context injection
557
+ *
558
+ * Positions:
559
+ * - 'end': After all messages
560
+ * - 'before-last': Before the last message
561
+ * - 'after-system': After the LAST system message (useful for models with multiple system messages)
562
+ * - number: Specific index (clamped to valid range)
563
+ */ calculatePosition(position) {
564
+ if (typeof position === 'number') {
565
+ return Math.max(0, Math.min(position, this.state.messages.length));
566
+ }
567
+ switch(position){
568
+ case 'end':
569
+ return this.state.messages.length;
570
+ case 'before-last':
571
+ return Math.max(0, this.state.messages.length - 1);
572
+ case 'after-system':
573
+ {
574
+ // Find last system message (uses reverse search to find most recent system message)
575
+ let lastSystemIdx = -1;
576
+ for(let i = this.state.messages.length - 1; i >= 0; i--){
577
+ if (this.state.messages[i].role === 'system') {
578
+ lastSystemIdx = i;
579
+ break;
580
+ }
581
+ }
582
+ return lastSystemIdx >= 0 ? lastSystemIdx + 1 : 0;
583
+ }
584
+ default:
585
+ return this.state.messages.length;
586
+ }
587
+ }
588
+ /**
589
+ * Format context item based on format option
590
+ */ formatContextItem(item, format) {
591
+ switch(format){
592
+ case 'structured':
593
+ {
594
+ let result = `## ${item.title || 'Context'}\n\n${item.content}`;
595
+ // Add metadata if available
596
+ const metadata = [];
597
+ if (item.source) {
598
+ metadata.push(`Source: ${item.source}`);
599
+ }
600
+ if (item.timestamp) {
601
+ metadata.push(`Timestamp: ${item.timestamp.toISOString()}`);
602
+ }
603
+ if (metadata.length > 0) {
604
+ result += `\n\n_${metadata.join(' | ')}_`;
605
+ }
606
+ return result;
607
+ }
608
+ case 'inline':
609
+ return `Note: ${item.title ? `${item.title}: ` : ''}${item.content}`;
610
+ case 'reference':
611
+ return `[Context Reference: ${item.id || 'unknown'}]\nSee attached context${item.title ? ` for ${item.title}` : ''}`;
612
+ default:
613
+ return item.content;
614
+ }
615
+ }
616
+ /**
617
+ * Update metadata after state changes
618
+ */ updateMetadata() {
619
+ this.state.metadata.messageCount = this.state.messages.length;
620
+ this.state.metadata.lastModified = new Date();
621
+ }
622
+ constructor(config, logger){
623
+ _define_property(this, "state", void 0);
624
+ _define_property(this, "config", void 0);
625
+ _define_property(this, "logger", void 0);
626
+ _define_property(this, "budgetManager", void 0);
627
+ _define_property(this, "conversationLogger", void 0);
628
+ this.config = ConversationBuilderConfigSchema.parse(config);
629
+ this.logger = wrapLogger(logger || DEFAULT_LOGGER, 'ConversationBuilder');
630
+ this.state = {
631
+ messages: [],
632
+ metadata: {
633
+ model: this.config.model,
634
+ created: new Date(),
635
+ lastModified: new Date(),
636
+ messageCount: 0,
637
+ toolCallCount: 0
638
+ },
639
+ contextProvided: new Set(),
640
+ contextManager: new ContextManager(logger)
641
+ };
642
+ this.logger.debug('Created ConversationBuilder', {
643
+ model: this.config.model
644
+ });
645
+ }
646
+ }
647
+
648
+ export { ConversationBuilder, ConversationBuilder as default };
649
+ //# sourceMappingURL=conversation.js.map