@hashgraphonline/conversational-agent 0.1.204 → 0.1.206

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 (87) hide show
  1. package/dist/cjs/base-agent.d.ts +6 -0
  2. package/dist/cjs/context/ReferenceContextManager.d.ts +84 -0
  3. package/dist/cjs/context/ReferenceResponseProcessor.d.ts +76 -0
  4. package/dist/cjs/conversational-agent.d.ts +34 -0
  5. package/dist/cjs/index.cjs +1 -1
  6. package/dist/cjs/index.cjs.map +1 -1
  7. package/dist/cjs/langchain-agent.d.ts +1 -0
  8. package/dist/cjs/mcp/ContentProcessor.d.ts +37 -0
  9. package/dist/cjs/mcp/MCPClientManager.d.ts +19 -1
  10. package/dist/cjs/memory/ContentStorage.d.ts +205 -0
  11. package/dist/cjs/memory/MemoryWindow.d.ts +114 -0
  12. package/dist/cjs/memory/ReferenceIdGenerator.d.ts +45 -0
  13. package/dist/cjs/memory/SmartMemoryManager.d.ts +201 -0
  14. package/dist/cjs/memory/TokenCounter.d.ts +61 -0
  15. package/dist/cjs/memory/index.d.ts +7 -0
  16. package/dist/cjs/plugins/hbar-transfer/TransferHbarTool.d.ts +18 -0
  17. package/dist/cjs/services/ContentStoreManager.d.ts +54 -0
  18. package/dist/cjs/types/content-reference.d.ts +213 -0
  19. package/dist/cjs/types/index.d.ts +4 -0
  20. package/dist/esm/index12.js +15 -2
  21. package/dist/esm/index12.js.map +1 -1
  22. package/dist/esm/index14.js +119 -95
  23. package/dist/esm/index14.js.map +1 -1
  24. package/dist/esm/index15.js +159 -114
  25. package/dist/esm/index15.js.map +1 -1
  26. package/dist/esm/index16.js +122 -81
  27. package/dist/esm/index16.js.map +1 -1
  28. package/dist/esm/index17.js +236 -0
  29. package/dist/esm/index17.js.map +1 -0
  30. package/dist/esm/index18.js +95 -0
  31. package/dist/esm/index18.js.map +1 -0
  32. package/dist/esm/index19.js +663 -0
  33. package/dist/esm/index19.js.map +1 -0
  34. package/dist/esm/index2.js +3 -1
  35. package/dist/esm/index2.js.map +1 -1
  36. package/dist/esm/index20.js +233 -0
  37. package/dist/esm/index20.js.map +1 -0
  38. package/dist/esm/index21.js +182 -0
  39. package/dist/esm/index21.js.map +1 -0
  40. package/dist/esm/index22.js +126 -0
  41. package/dist/esm/index22.js.map +1 -0
  42. package/dist/esm/index23.js +68 -0
  43. package/dist/esm/index23.js.map +1 -0
  44. package/dist/esm/index24.js +38 -0
  45. package/dist/esm/index24.js.map +1 -0
  46. package/dist/esm/index6.js +143 -84
  47. package/dist/esm/index6.js.map +1 -1
  48. package/dist/esm/index7.js.map +1 -1
  49. package/dist/esm/index8.js +69 -5
  50. package/dist/esm/index8.js.map +1 -1
  51. package/dist/types/base-agent.d.ts +6 -0
  52. package/dist/types/context/ReferenceContextManager.d.ts +84 -0
  53. package/dist/types/context/ReferenceResponseProcessor.d.ts +76 -0
  54. package/dist/types/conversational-agent.d.ts +34 -0
  55. package/dist/types/langchain-agent.d.ts +1 -0
  56. package/dist/types/mcp/ContentProcessor.d.ts +37 -0
  57. package/dist/types/mcp/MCPClientManager.d.ts +19 -1
  58. package/dist/types/memory/ContentStorage.d.ts +205 -0
  59. package/dist/types/memory/MemoryWindow.d.ts +114 -0
  60. package/dist/types/memory/ReferenceIdGenerator.d.ts +45 -0
  61. package/dist/types/memory/SmartMemoryManager.d.ts +201 -0
  62. package/dist/types/memory/TokenCounter.d.ts +61 -0
  63. package/dist/types/memory/index.d.ts +7 -0
  64. package/dist/types/plugins/hbar-transfer/TransferHbarTool.d.ts +18 -0
  65. package/dist/types/services/ContentStoreManager.d.ts +54 -0
  66. package/dist/types/types/content-reference.d.ts +213 -0
  67. package/dist/types/types/index.d.ts +4 -0
  68. package/package.json +30 -26
  69. package/src/base-agent.ts +6 -0
  70. package/src/context/ReferenceContextManager.ts +345 -0
  71. package/src/context/ReferenceResponseProcessor.ts +296 -0
  72. package/src/conversational-agent.ts +166 -92
  73. package/src/langchain-agent.ts +89 -2
  74. package/src/mcp/ContentProcessor.ts +317 -0
  75. package/src/mcp/MCPClientManager.ts +61 -1
  76. package/src/mcp/adapters/langchain.ts +9 -4
  77. package/src/memory/ContentStorage.ts +954 -0
  78. package/src/memory/MemoryWindow.ts +247 -0
  79. package/src/memory/ReferenceIdGenerator.ts +84 -0
  80. package/src/memory/SmartMemoryManager.ts +323 -0
  81. package/src/memory/TokenCounter.ts +152 -0
  82. package/src/memory/index.ts +8 -0
  83. package/src/plugins/hbar-transfer/TransferHbarTool.ts +19 -1
  84. package/src/plugins/hcs-10/HCS10Plugin.ts +5 -4
  85. package/src/services/ContentStoreManager.ts +199 -0
  86. package/src/types/content-reference.ts +281 -0
  87. package/src/types/index.ts +6 -0
@@ -0,0 +1,152 @@
1
+ import { encoding_for_model } from 'tiktoken';
2
+ import type { TiktokenModel } from 'tiktoken';
3
+ import type { BaseMessage } from '@langchain/core/messages';
4
+
5
+ /**
6
+ * Token counter utility for OpenAI models using tiktoken encoding
7
+ * Provides accurate token counting for text content and chat messages
8
+ */
9
+ export class TokenCounter {
10
+ private encoding: ReturnType<typeof encoding_for_model>;
11
+ private modelName: TiktokenModel;
12
+
13
+ // Token overhead per message for chat completion format
14
+ private static readonly MESSAGE_OVERHEAD = 3; // <|start|>role<|end|>content<|end|>
15
+ private static readonly ROLE_OVERHEAD = 1; // Additional token for role specification
16
+
17
+ constructor(modelName: TiktokenModel = 'gpt-4o') {
18
+ this.modelName = modelName;
19
+ try {
20
+ this.encoding = encoding_for_model(modelName);
21
+ } catch (error) {
22
+ // Fallback to gpt-4o if specific model encoding is not available
23
+ console.warn(`Model ${modelName} not found, falling back to gpt-4o encoding`);
24
+ this.encoding = encoding_for_model('gpt-4o');
25
+ this.modelName = 'gpt-4o';
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Count tokens in raw text content
31
+ * @param text - The text to count tokens for
32
+ * @returns Number of tokens
33
+ */
34
+ countTokens(text: string): number {
35
+ if (!text || text.trim() === '') {
36
+ return 0;
37
+ }
38
+
39
+ try {
40
+ const tokens = this.encoding.encode(text);
41
+ return tokens.length;
42
+ } catch (error) {
43
+ console.warn('Error counting tokens, falling back to word-based estimation:', error);
44
+ // Fallback: rough estimation based on words (typically 1.3 tokens per word)
45
+ return Math.ceil(text.split(/\s+/).length * 1.3);
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Count tokens for a single chat message including role overhead
51
+ * @param message - The message to count tokens for
52
+ * @returns Number of tokens including message formatting overhead
53
+ */
54
+ countMessageTokens(message: BaseMessage): number {
55
+ const contentTokens = this.countTokens(message.content as string);
56
+ const roleTokens = this.countTokens(this.getMessageRole(message));
57
+
58
+ // Add overhead for message structure and role
59
+ return contentTokens + roleTokens + TokenCounter.MESSAGE_OVERHEAD + TokenCounter.ROLE_OVERHEAD;
60
+ }
61
+
62
+ /**
63
+ * Count tokens for multiple messages
64
+ * @param messages - Array of messages to count
65
+ * @returns Total token count for all messages
66
+ */
67
+ countMessagesTokens(messages: BaseMessage[]): number {
68
+ if (!messages || messages.length === 0) {
69
+ return 0;
70
+ }
71
+
72
+ return messages.reduce((total, message) => {
73
+ return total + this.countMessageTokens(message);
74
+ }, 0);
75
+ }
76
+
77
+ /**
78
+ * Estimate tokens for system prompt
79
+ * System prompts have slightly different overhead in chat completions
80
+ * @param systemPrompt - The system prompt text
81
+ * @returns Estimated token count
82
+ */
83
+ estimateSystemPromptTokens(systemPrompt: string): number {
84
+ if (!systemPrompt || systemPrompt.trim() === '') {
85
+ return 0;
86
+ }
87
+
88
+ const contentTokens = this.countTokens(systemPrompt);
89
+ const roleTokens = this.countTokens('system');
90
+
91
+ // System messages have similar overhead to regular messages
92
+ return contentTokens + roleTokens + TokenCounter.MESSAGE_OVERHEAD + TokenCounter.ROLE_OVERHEAD;
93
+ }
94
+
95
+ /**
96
+ * Get total context size estimate including system prompt and messages
97
+ * @param systemPrompt - System prompt text
98
+ * @param messages - Conversation messages
99
+ * @returns Total estimated token count
100
+ */
101
+ estimateContextSize(systemPrompt: string, messages: BaseMessage[]): number {
102
+ const systemTokens = this.estimateSystemPromptTokens(systemPrompt);
103
+ const messageTokens = this.countMessagesTokens(messages);
104
+
105
+ // Add a small buffer for chat completion overhead
106
+ const completionOverhead = 10;
107
+
108
+ return systemTokens + messageTokens + completionOverhead;
109
+ }
110
+
111
+ /**
112
+ * Get the role string for a message
113
+ * @param message - The message to get the role for
114
+ * @returns Role string ('user', 'assistant', 'system', etc.)
115
+ */
116
+ private getMessageRole(message: BaseMessage): string {
117
+ const messageType = message._getType();
118
+ switch (messageType) {
119
+ case 'human':
120
+ return 'user';
121
+ case 'ai':
122
+ return 'assistant';
123
+ case 'system':
124
+ return 'system';
125
+ case 'function':
126
+ return 'function';
127
+ case 'tool':
128
+ return 'tool';
129
+ default:
130
+ return 'user'; // Default fallback
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Get the model name being used for token counting
136
+ * @returns The tiktoken model name
137
+ */
138
+ getModelName(): string {
139
+ return this.modelName;
140
+ }
141
+
142
+ /**
143
+ * Clean up encoding resources
144
+ */
145
+ dispose(): void {
146
+ try {
147
+ this.encoding.free();
148
+ } catch (error) {
149
+ console.warn('Error disposing encoding:', error);
150
+ }
151
+ }
152
+ }
@@ -0,0 +1,8 @@
1
+ export { TokenCounter } from './TokenCounter';
2
+ export { MemoryWindow } from './MemoryWindow';
3
+ export { ContentStorage } from './ContentStorage';
4
+ export { SmartMemoryManager } from './SmartMemoryManager';
5
+
6
+ export type { SmartMemoryConfig, SearchOptions, MemoryStats } from './SmartMemoryManager';
7
+ export type { AddMessageResult } from './MemoryWindow';
8
+ export type { StorageStats } from './ContentStorage';
@@ -10,7 +10,7 @@ const HbarTransferInputSchema = z.object({
10
10
  amount: z
11
11
  .union([z.number(), z.string()])
12
12
  .describe(
13
- 'HBAR amount. Positive for credit, negative for debit. Builder handles Hbar unit & sum validation.'
13
+ 'HBAR amount in decimal format (e.g., 1 for 1 HBAR, 0.5 for 0.5 HBAR). Positive for credit, negative for debit. DO NOT multiply by 10^8 for tinybars - just use the HBAR amount directly.'
14
14
  ),
15
15
  });
16
16
 
@@ -24,6 +24,11 @@ const TransferHbarZodSchemaCore = z.object({
24
24
  memo: z.string().optional().describe('Optional. Memo for the transaction.'),
25
25
  });
26
26
 
27
+ /**
28
+ * A Hedera transaction tool for transferring HBAR between accounts.
29
+ * Supports single and multi-party transfers with automatic balance validation.
30
+ * Extends BaseHederaTransactionTool to handle HBAR transfer transactions on the Hedera network.
31
+ */
27
32
  export class TransferHbarTool extends BaseHederaTransactionTool<
28
33
  typeof TransferHbarZodSchemaCore
29
34
  > {
@@ -34,10 +39,23 @@ export class TransferHbarTool extends BaseHederaTransactionTool<
34
39
  namespace = 'account';
35
40
 
36
41
 
42
+ /**
43
+ * Creates and returns the service builder for account operations.
44
+ *
45
+ * @returns BaseServiceBuilder instance configured for account operations
46
+ */
37
47
  protected getServiceBuilder(): BaseServiceBuilder {
38
48
  return new AccountBuilder(this.hederaKit) as BaseServiceBuilder;
39
49
  }
40
50
 
51
+ /**
52
+ * Executes the HBAR transfer using the provided builder and arguments.
53
+ * Validates that all transfers sum to zero before execution.
54
+ *
55
+ * @param builder - The service builder instance for executing transactions
56
+ * @param specificArgs - The validated transfer parameters including transfers array and optional memo
57
+ * @returns Promise that resolves when the transfer is complete
58
+ */
41
59
  protected async callBuilderMethod(
42
60
  builder: BaseServiceBuilder,
43
61
  specificArgs: z.infer<typeof TransferHbarZodSchemaCore>
@@ -91,7 +91,6 @@ export class HCS10Plugin extends BasePlugin {
91
91
  `Set current agent: ${accountId} with topics ${inboundTopicId}/${outboundTopicId}`
92
92
  );
93
93
 
94
- // Initialize ConnectionsManager on the state manager if needed
95
94
  if (this.stateManager && !this.stateManager.getConnectionsManager()) {
96
95
  const privateKey = hederaKit.signer.getOperatorPrivateKey().toString();
97
96
  const hcs10Client = new HCS10Client({
@@ -100,9 +99,11 @@ export class HCS10Plugin extends BasePlugin {
100
99
  operatorPrivateKey: privateKey,
101
100
  logLevel: 'error',
102
101
  });
103
-
104
- this.stateManager.initializeConnectionsManager(hcs10Client);
105
- this.context.logger.info('ConnectionsManager initialized in HCS10Plugin');
102
+
103
+ this.stateManager.initializeConnectionsManager(hcs10Client as any);
104
+ this.context.logger.info(
105
+ 'ConnectionsManager initialized in HCS10Plugin'
106
+ );
106
107
  }
107
108
 
108
109
  this.initializeTools();
@@ -0,0 +1,199 @@
1
+ import { ContentStorage } from '../memory/ContentStorage';
2
+ import {
3
+ ContentStoreService,
4
+ extractReferenceId,
5
+ shouldUseReference,
6
+ ContentResolverRegistry,
7
+ type ContentStoreInterface,
8
+ type ContentResolverInterface,
9
+ type ReferenceResolutionResult
10
+ } from '@hashgraphonline/standards-sdk';
11
+ import type { ContentReferenceConfig } from '../types/content-reference';
12
+ import { Logger } from '@hashgraphonline/standards-sdk';
13
+
14
+ /**
15
+ * Adapter to make ContentStorage compatible with ContentStoreInterface
16
+ */
17
+ class ContentStorageAdapter implements ContentStoreInterface {
18
+ constructor(private storage: ContentStorage) {}
19
+
20
+ async storeContent(content: Buffer, metadata: any) {
21
+ const contentRef = await this.storage.storeContent(content, metadata);
22
+ return contentRef.referenceId;
23
+ }
24
+
25
+ async resolveReference(referenceId: string): Promise<ReferenceResolutionResult> {
26
+ const result = await this.storage.resolveReference(referenceId);
27
+ // Convert to match the interface from standards-sdk
28
+ if (result.success && result.content) {
29
+ const response: ReferenceResolutionResult = {
30
+ content: result.content
31
+ };
32
+ if (result.metadata) {
33
+ response.metadata = {
34
+ ...(result.metadata.mimeType !== undefined && { mimeType: result.metadata.mimeType }),
35
+ ...(result.metadata.fileName !== undefined && { fileName: result.metadata.fileName }),
36
+ originalSize: result.metadata.sizeBytes
37
+ };
38
+ }
39
+ return response;
40
+ } else {
41
+ // If resolution fails, throw an error as the interface expects content to be present
42
+ throw new Error(result.error || 'Reference not found');
43
+ }
44
+ }
45
+
46
+ async hasReference(referenceId: string) {
47
+ return await this.storage.hasReference(referenceId);
48
+ }
49
+
50
+ async cleanupReference(referenceId: string) {
51
+ await this.storage.cleanupReference(referenceId);
52
+ }
53
+
54
+ async getStats() {
55
+ return await this.storage.getStats();
56
+ }
57
+
58
+ async updateConfig(config: any) {
59
+ return await this.storage.updateConfig(config);
60
+ }
61
+
62
+ async performCleanup() {
63
+ await this.storage.performCleanup();
64
+ }
65
+
66
+ async dispose() {
67
+ return Promise.resolve(this.storage.dispose());
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Content resolver implementation for dependency injection
73
+ */
74
+ class ContentResolver implements ContentResolverInterface {
75
+ constructor(private adapter: ContentStorageAdapter) {}
76
+
77
+ async resolveReference(referenceId: string): Promise<ReferenceResolutionResult> {
78
+ // The adapter already handles the conversion
79
+ return await this.adapter.resolveReference(referenceId);
80
+ }
81
+
82
+ shouldUseReference(content: string | Buffer): boolean {
83
+ return shouldUseReference(content);
84
+ }
85
+
86
+ extractReferenceId(input: string): string | null {
87
+ return extractReferenceId(input);
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Manages content store lifecycle and cross-package registration
93
+ */
94
+ export class ContentStoreManager {
95
+ private contentStorage: ContentStorage;
96
+ private adapter: ContentStorageAdapter;
97
+ private resolver: ContentResolver;
98
+ private logger: Logger;
99
+ private isRegistered = false;
100
+
101
+ constructor(
102
+ maxMessageStorage: number = 1000,
103
+ referenceConfig?: Partial<ContentReferenceConfig>,
104
+ logger?: Logger
105
+ ) {
106
+ this.logger = logger || {
107
+ info: console.log,
108
+ debug: console.log,
109
+ warn: console.warn,
110
+ error: console.error
111
+ } as Logger;
112
+
113
+ this.contentStorage = new ContentStorage(maxMessageStorage, referenceConfig);
114
+ this.adapter = new ContentStorageAdapter(this.contentStorage);
115
+ this.resolver = new ContentResolver(this.adapter);
116
+ }
117
+
118
+ /**
119
+ * Initialize and register content storage for cross-package access
120
+ */
121
+ async initialize(): Promise<void> {
122
+ if (this.isRegistered) {
123
+ this.logger.warn('ContentStoreManager is already initialized');
124
+ return;
125
+ }
126
+
127
+ try {
128
+ await ContentStoreService.setInstance(this.adapter);
129
+ ContentResolverRegistry.register(this.resolver);
130
+ this.isRegistered = true;
131
+ this.logger.info('ContentStoreManager initialized and registered for cross-package access');
132
+ } catch (error) {
133
+ this.logger.error('Failed to initialize ContentStoreManager:', error);
134
+ throw error;
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Get the underlying ContentStorage instance
140
+ */
141
+ getContentStorage(): ContentStorage {
142
+ return this.contentStorage;
143
+ }
144
+
145
+ /**
146
+ * Get storage statistics
147
+ */
148
+ async getStats() {
149
+ return await this.contentStorage.getStats();
150
+ }
151
+
152
+ /**
153
+ * Update configuration
154
+ */
155
+ async updateConfig(config: Partial<ContentReferenceConfig>) {
156
+ return await this.contentStorage.updateConfig(config);
157
+ }
158
+
159
+ /**
160
+ * Perform manual cleanup
161
+ */
162
+ async performCleanup() {
163
+ return await this.contentStorage.performCleanup();
164
+ }
165
+
166
+ /**
167
+ * Check if content should be stored as reference
168
+ */
169
+ shouldUseReference(content: Buffer | string): boolean {
170
+ return this.contentStorage.shouldUseReference(content);
171
+ }
172
+
173
+ /**
174
+ * Store content if it's large enough
175
+ */
176
+ async storeContentIfLarge(content: Buffer | string, metadata: any) {
177
+ return await this.contentStorage.storeContentIfLarge(content, metadata);
178
+ }
179
+
180
+ /**
181
+ * Cleanup and unregister
182
+ */
183
+ async dispose(): Promise<void> {
184
+ if (this.isRegistered) {
185
+ this.contentStorage.dispose();
186
+ ContentStoreService.dispose();
187
+ ContentResolverRegistry.unregister();
188
+ this.isRegistered = false;
189
+ this.logger.info('ContentStoreManager disposed and unregistered');
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Check if the manager is initialized
195
+ */
196
+ isInitialized(): boolean {
197
+ return this.isRegistered;
198
+ }
199
+ }
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Content Reference System Types
3
+ *
4
+ * Shared interfaces for the Reference-Based Content System that handles
5
+ * large content storage with unique reference IDs to optimize context window usage.
6
+ */
7
+
8
+ /**
9
+ * Unique identifier for stored content references
10
+ * Format: Cryptographically secure 32-byte identifier with base64url encoding
11
+ */
12
+ export type ReferenceId = string;
13
+
14
+ /**
15
+ * Lifecycle state of a content reference
16
+ */
17
+ export type ReferenceLifecycleState = 'active' | 'expired' | 'cleanup_pending' | 'invalid';
18
+
19
+ /**
20
+ * Content types supported by the reference system
21
+ */
22
+ export type ContentType = 'text' | 'json' | 'html' | 'markdown' | 'binary' | 'unknown';
23
+
24
+ /**
25
+ * Sources that created the content reference
26
+ */
27
+ export type ContentSource = 'mcp_tool' | 'user_upload' | 'agent_generated' | 'system';
28
+
29
+ /**
30
+ * Metadata associated with stored content
31
+ */
32
+ export interface ContentMetadata {
33
+ /** Content type classification */
34
+ contentType: ContentType;
35
+
36
+ /** MIME type of the original content */
37
+ mimeType?: string;
38
+
39
+ /** Size in bytes of the stored content */
40
+ sizeBytes: number;
41
+
42
+ /** When the content was originally stored */
43
+ createdAt: Date;
44
+
45
+ /** Last time the content was accessed via reference resolution */
46
+ lastAccessedAt: Date;
47
+
48
+ /** Source that created this content reference */
49
+ source: ContentSource;
50
+
51
+ /** Name of the MCP tool that generated the content (if applicable) */
52
+ mcpToolName?: string;
53
+
54
+ /** Original filename or suggested name for the content */
55
+ fileName?: string;
56
+
57
+ /** Number of times this reference has been resolved */
58
+ accessCount: number;
59
+
60
+ /** Tags for categorization and cleanup policies */
61
+ tags?: string[];
62
+
63
+ /** Custom metadata from the source */
64
+ customMetadata?: Record<string, unknown>;
65
+ }
66
+
67
+ /**
68
+ * Core content reference object passed through agent context
69
+ * Designed to be lightweight (<100 tokens) while providing enough
70
+ * information for agent decision-making
71
+ */
72
+ export interface ContentReference {
73
+ /** Unique identifier for resolving the content */
74
+ referenceId: ReferenceId;
75
+
76
+ /** Current lifecycle state */
77
+ state: ReferenceLifecycleState;
78
+
79
+ /** Brief description or preview of the content (max 200 chars) */
80
+ preview: string;
81
+
82
+ /** Essential metadata for agent decision-making */
83
+ metadata: Pick<ContentMetadata, 'contentType' | 'sizeBytes' | 'source' | 'fileName' | 'mimeType'>;
84
+
85
+ /** When this reference was created */
86
+ createdAt: Date;
87
+
88
+ /** Special format indicator for reference IDs in content */
89
+ readonly format: 'ref://{id}';
90
+ }
91
+
92
+ /**
93
+ * Result of attempting to resolve a content reference
94
+ */
95
+ export interface ReferenceResolutionResult {
96
+ /** Whether the resolution was successful */
97
+ success: boolean;
98
+
99
+ /** The resolved content if successful */
100
+ content?: Buffer;
101
+
102
+ /** Complete metadata if successful */
103
+ metadata?: ContentMetadata;
104
+
105
+ /** Error message if resolution failed */
106
+ error?: string;
107
+
108
+ /** Specific error type for targeted error handling */
109
+ errorType?: 'not_found' | 'expired' | 'corrupted' | 'access_denied' | 'system_error';
110
+
111
+ /** Suggested actions for recovery */
112
+ suggestedActions?: string[];
113
+ }
114
+
115
+ /**
116
+ * Configuration for content reference storage and lifecycle
117
+ */
118
+ export interface ContentReferenceConfig {
119
+ /** Size threshold above which content should be stored as references (default: 10KB) */
120
+ sizeThresholdBytes: number;
121
+
122
+ /** Maximum age for unused references before cleanup (default: 1 hour) */
123
+ maxAgeMs: number;
124
+
125
+ /** Maximum number of references to store simultaneously */
126
+ maxReferences: number;
127
+
128
+ /** Maximum total storage size for all references */
129
+ maxTotalStorageBytes: number;
130
+
131
+ /** Whether to enable automatic cleanup */
132
+ enableAutoCleanup: boolean;
133
+
134
+ /** Interval for cleanup checks in milliseconds */
135
+ cleanupIntervalMs: number;
136
+
137
+ /** Whether to persist references across restarts */
138
+ enablePersistence: boolean;
139
+
140
+ /** Storage backend configuration */
141
+ storageBackend: 'memory' | 'filesystem' | 'hybrid';
142
+
143
+ /** Cleanup policies for different content types */
144
+ cleanupPolicies: {
145
+ /** Policy for content marked as "recent" from MCP tools */
146
+ recent: { maxAgeMs: number; priority: number };
147
+
148
+ /** Policy for user-uploaded content */
149
+ userContent: { maxAgeMs: number; priority: number };
150
+
151
+ /** Policy for agent-generated content */
152
+ agentGenerated: { maxAgeMs: number; priority: number };
153
+
154
+ /** Default policy for other content */
155
+ default: { maxAgeMs: number; priority: number };
156
+ };
157
+ }
158
+
159
+ /**
160
+ * Default configuration values
161
+ */
162
+ export const DEFAULT_CONTENT_REFERENCE_CONFIG: ContentReferenceConfig = {
163
+ sizeThresholdBytes: 10 * 1024, // 10KB
164
+ maxAgeMs: 60 * 60 * 1000, // 1 hour
165
+ maxReferences: 100,
166
+ maxTotalStorageBytes: 100 * 1024 * 1024, // 100MB
167
+ enableAutoCleanup: true,
168
+ cleanupIntervalMs: 5 * 60 * 1000, // 5 minutes
169
+ enablePersistence: false,
170
+ storageBackend: 'memory',
171
+ cleanupPolicies: {
172
+ recent: { maxAgeMs: 30 * 60 * 1000, priority: 1 }, // 30 minutes, highest priority
173
+ userContent: { maxAgeMs: 2 * 60 * 60 * 1000, priority: 2 }, // 2 hours
174
+ agentGenerated: { maxAgeMs: 60 * 60 * 1000, priority: 3 }, // 1 hour
175
+ default: { maxAgeMs: 60 * 60 * 1000, priority: 4 } // 1 hour, lowest priority
176
+ }
177
+ };
178
+
179
+ /**
180
+ * Statistics about content reference usage and storage
181
+ */
182
+ export interface ContentReferenceStats {
183
+ /** Total number of active references */
184
+ activeReferences: number;
185
+
186
+ /** Total storage used by all references in bytes */
187
+ totalStorageBytes: number;
188
+
189
+ /** Number of references cleaned up in last cleanup cycle */
190
+ recentlyCleanedUp: number;
191
+
192
+ /** Number of successful reference resolutions since startup */
193
+ totalResolutions: number;
194
+
195
+ /** Number of failed resolution attempts */
196
+ failedResolutions: number;
197
+
198
+ /** Average content size in bytes */
199
+ averageContentSize: number;
200
+
201
+ /** Most frequently accessed reference ID */
202
+ mostAccessedReferenceId?: ReferenceId;
203
+
204
+ /** Storage utilization percentage */
205
+ storageUtilization: number;
206
+
207
+ /** Performance metrics */
208
+ performanceMetrics: {
209
+ /** Average time to create a reference in milliseconds */
210
+ averageCreationTimeMs: number;
211
+
212
+ /** Average time to resolve a reference in milliseconds */
213
+ averageResolutionTimeMs: number;
214
+
215
+ /** Average cleanup time in milliseconds */
216
+ averageCleanupTimeMs: number;
217
+ };
218
+ }
219
+
220
+ /**
221
+ * Error types for content reference operations
222
+ */
223
+ export class ContentReferenceError extends Error {
224
+ constructor(
225
+ message: string,
226
+ public readonly type: ReferenceResolutionResult['errorType'],
227
+ public readonly referenceId?: ReferenceId,
228
+ public readonly suggestedActions?: string[]
229
+ ) {
230
+ super(message);
231
+ this.name = 'ContentReferenceError';
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Interface for content reference storage implementations
237
+ */
238
+ export interface ContentReferenceStore {
239
+ /**
240
+ * Store content and return a reference
241
+ */
242
+ storeContent(
243
+ content: Buffer,
244
+ metadata: Omit<ContentMetadata, 'createdAt' | 'lastAccessedAt' | 'accessCount'>
245
+ ): Promise<ContentReference>;
246
+
247
+ /**
248
+ * Resolve a reference to its content
249
+ */
250
+ resolveReference(referenceId: ReferenceId): Promise<ReferenceResolutionResult>;
251
+
252
+ /**
253
+ * Check if a reference exists and is valid
254
+ */
255
+ hasReference(referenceId: ReferenceId): Promise<boolean>;
256
+
257
+ /**
258
+ * Mark a reference for cleanup
259
+ */
260
+ cleanupReference(referenceId: ReferenceId): Promise<boolean>;
261
+
262
+ /**
263
+ * Get current storage statistics
264
+ */
265
+ getStats(): Promise<ContentReferenceStats>;
266
+
267
+ /**
268
+ * Update configuration
269
+ */
270
+ updateConfig(config: Partial<ContentReferenceConfig>): Promise<void>;
271
+
272
+ /**
273
+ * Perform cleanup based on current policies
274
+ */
275
+ performCleanup(): Promise<{ cleanedUp: number; errors: string[] }>;
276
+
277
+ /**
278
+ * Dispose of resources
279
+ */
280
+ dispose(): Promise<void>;
281
+ }