@hashgraphonline/conversational-agent 0.1.207 → 0.1.209

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 (70) hide show
  1. package/dist/cjs/conversational-agent.d.ts +67 -8
  2. package/dist/cjs/index.cjs +1 -1
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/cjs/index.d.ts +1 -0
  5. package/dist/cjs/langchain/ContentAwareAgentExecutor.d.ts +4 -6
  6. package/dist/cjs/langchain-agent.d.ts +8 -0
  7. package/dist/cjs/memory/SmartMemoryManager.d.ts +58 -21
  8. package/dist/cjs/memory/index.d.ts +1 -1
  9. package/dist/esm/index.js +8 -0
  10. package/dist/esm/index.js.map +1 -1
  11. package/dist/esm/index12.js +124 -46
  12. package/dist/esm/index12.js.map +1 -1
  13. package/dist/esm/index13.js +178 -13
  14. package/dist/esm/index13.js.map +1 -1
  15. package/dist/esm/index14.js +604 -100
  16. package/dist/esm/index14.js.map +1 -1
  17. package/dist/esm/index15.js +453 -59
  18. package/dist/esm/index15.js.map +1 -1
  19. package/dist/esm/index16.js +44 -172
  20. package/dist/esm/index16.js.map +1 -1
  21. package/dist/esm/index17.js +11 -156
  22. package/dist/esm/index17.js.map +1 -1
  23. package/dist/esm/index18.js +106 -191
  24. package/dist/esm/index18.js.map +1 -1
  25. package/dist/esm/index19.js +7 -90
  26. package/dist/esm/index19.js.map +1 -1
  27. package/dist/esm/index2.js +22 -13
  28. package/dist/esm/index2.js.map +1 -1
  29. package/dist/esm/index20.js +130 -616
  30. package/dist/esm/index20.js.map +1 -1
  31. package/dist/esm/index21.js +138 -215
  32. package/dist/esm/index21.js.map +1 -1
  33. package/dist/esm/index22.js +45 -159
  34. package/dist/esm/index22.js.map +1 -1
  35. package/dist/esm/index23.js +25 -121
  36. package/dist/esm/index23.js.map +1 -1
  37. package/dist/esm/index24.js +83 -56
  38. package/dist/esm/index24.js.map +1 -1
  39. package/dist/esm/index25.js +236 -32
  40. package/dist/esm/index25.js.map +1 -1
  41. package/dist/esm/index5.js +1 -1
  42. package/dist/esm/index6.js +295 -17
  43. package/dist/esm/index6.js.map +1 -1
  44. package/dist/esm/index8.js +82 -8
  45. package/dist/esm/index8.js.map +1 -1
  46. package/dist/types/conversational-agent.d.ts +67 -8
  47. package/dist/types/index.d.ts +1 -0
  48. package/dist/types/langchain/ContentAwareAgentExecutor.d.ts +4 -6
  49. package/dist/types/langchain-agent.d.ts +8 -0
  50. package/dist/types/memory/SmartMemoryManager.d.ts +58 -21
  51. package/dist/types/memory/index.d.ts +1 -1
  52. package/package.json +3 -3
  53. package/src/context/ReferenceContextManager.ts +9 -4
  54. package/src/context/ReferenceResponseProcessor.ts +3 -4
  55. package/src/conversational-agent.ts +379 -31
  56. package/src/index.ts +2 -0
  57. package/src/langchain/ContentAwareAgentExecutor.ts +4 -97
  58. package/src/langchain-agent.ts +94 -11
  59. package/src/mcp/ContentProcessor.ts +13 -3
  60. package/src/mcp/adapters/langchain.ts +1 -9
  61. package/src/memory/ContentStorage.ts +3 -51
  62. package/src/memory/MemoryWindow.ts +4 -16
  63. package/src/memory/ReferenceIdGenerator.ts +0 -4
  64. package/src/memory/SmartMemoryManager.ts +400 -33
  65. package/src/memory/TokenCounter.ts +12 -16
  66. package/src/memory/index.ts +1 -1
  67. package/src/plugins/hcs-10/HCS10Plugin.ts +44 -14
  68. package/src/services/ContentStoreManager.ts +0 -3
  69. package/src/types/content-reference.ts +8 -8
  70. package/src/types/index.ts +0 -1
@@ -1,182 +1,68 @@
1
- import { TokenCounter } from "./index23.js";
2
- const _MemoryWindow = class _MemoryWindow {
3
- // Remove messages in pairs to maintain conversation flow
4
- constructor(maxTokens = _MemoryWindow.DEFAULT_MAX_TOKENS, reserveTokens = _MemoryWindow.DEFAULT_RESERVE_TOKENS, tokenCounter) {
5
- this.messages = [];
6
- this.systemPrompt = "";
7
- this.systemPromptTokens = 0;
8
- if (reserveTokens >= maxTokens) {
9
- throw new Error("Reserve tokens must be less than max tokens");
10
- }
11
- this.maxTokens = maxTokens;
12
- this.reserveTokens = reserveTokens;
13
- this.tokenCounter = tokenCounter || new TokenCounter();
14
- }
1
+ import { createHash } from "crypto";
2
+ class ReferenceIdGenerator {
15
3
  /**
16
- * Add a message to the memory window, pruning old messages if necessary
17
- * @param message - The message to add
18
- * @returns Result of the add operation including any pruned messages
4
+ * Generate a content-based reference ID using SHA-256 hashing
5
+ *
6
+ * @param content The content to generate a reference ID for
7
+ * @returns Deterministic reference ID based on content hash
19
8
  */
20
- addMessage(message) {
21
- this.tokenCounter.countMessageTokens(message);
22
- this.messages.push(message);
23
- const currentTokens = this.getCurrentTokenCount();
24
- const availableTokens = this.maxTokens - this.reserveTokens;
25
- let prunedMessages = [];
26
- if (currentTokens > availableTokens) {
27
- this.messages.pop();
28
- prunedMessages = this.pruneToFit();
29
- this.messages.push(message);
30
- }
31
- return {
32
- added: true,
33
- prunedMessages,
34
- currentTokenCount: this.getCurrentTokenCount(),
35
- remainingCapacity: this.getRemainingTokenCapacity()
36
- };
9
+ static generateId(content) {
10
+ const hash = createHash("sha256");
11
+ hash.update(content);
12
+ return hash.digest("base64url");
37
13
  }
38
14
  /**
39
- * Prune old messages to fit within token limits
40
- * Removes messages in pairs to maintain conversational flow
41
- * @returns Array of pruned messages
15
+ * Validate that a string is a properly formatted reference ID
16
+ *
17
+ * @param id The ID to validate
18
+ * @returns true if the ID is valid format
42
19
  */
43
- pruneToFit() {
44
- const prunedMessages = [];
45
- const targetTokens = this.maxTokens - this.reserveTokens;
46
- while (this.getCurrentTokenCount() > targetTokens && this.messages.length > 0) {
47
- const batchSize = Math.min(_MemoryWindow.PRUNING_BATCH_SIZE, this.messages.length);
48
- for (let i = 0; i < batchSize; i++) {
49
- const prunedMessage = this.messages.shift();
50
- if (prunedMessage) {
51
- prunedMessages.push(prunedMessage);
52
- }
53
- }
54
- if (prunedMessages.length > 1e3) {
55
- console.warn("MemoryWindow: Excessive pruning detected, stopping to prevent infinite loop");
56
- break;
57
- }
20
+ static isValidReferenceId(id) {
21
+ if (!id || typeof id !== "string") {
22
+ return false;
58
23
  }
59
- return prunedMessages;
60
- }
61
- /**
62
- * Get current token count including system prompt and messages
63
- * @returns Current token count
64
- */
65
- getCurrentTokenCount() {
66
- const messageTokens = this.tokenCounter.countMessagesTokens(this.messages);
67
- return this.systemPromptTokens + messageTokens;
68
- }
69
- /**
70
- * Get remaining token capacity before hitting the reserve limit
71
- * @returns Remaining tokens that can be used
72
- */
73
- getRemainingTokenCapacity() {
74
- return Math.max(0, this.maxTokens - this.getCurrentTokenCount());
75
- }
76
- /**
77
- * Check if a message can be added without exceeding limits
78
- * @param message - The message to check
79
- * @returns True if message can be added within reserve limits
80
- */
81
- canAddMessage(message) {
82
- const messageTokens = this.tokenCounter.countMessageTokens(message);
83
- const currentTokens = this.getCurrentTokenCount();
84
- const wouldExceedReserve = currentTokens + messageTokens > this.maxTokens - this.reserveTokens;
85
- if (messageTokens > this.maxTokens) {
24
+ if (id.length !== 43) {
86
25
  return false;
87
26
  }
88
- return !wouldExceedReserve || this.messages.length > 0;
89
- }
90
- /**
91
- * Get all messages in the memory window
92
- * @returns Copy of current messages array
93
- */
94
- getMessages() {
95
- return [...this.messages];
96
- }
97
- /**
98
- * Clear all messages from the memory window
99
- */
100
- clear() {
101
- this.messages = [];
27
+ return /^[A-Za-z0-9_-]+$/.test(id);
102
28
  }
103
29
  /**
104
- * Set the system prompt and update token calculations
105
- * @param systemPrompt - The system prompt text
30
+ * Extract reference ID from ref:// format
31
+ *
32
+ * @param input Input string that may contain a reference ID
33
+ * @returns Extracted reference ID or null if not found
106
34
  */
107
- setSystemPrompt(systemPrompt) {
108
- this.systemPrompt = systemPrompt;
109
- this.systemPromptTokens = this.tokenCounter.estimateSystemPromptTokens(systemPrompt);
110
- }
111
- /**
112
- * Get the current system prompt
113
- * @returns Current system prompt
114
- */
115
- getSystemPrompt() {
116
- return this.systemPrompt;
117
- }
118
- /**
119
- * Get current configuration
120
- * @returns Memory window configuration
121
- */
122
- getConfig() {
123
- return {
124
- maxTokens: this.maxTokens,
125
- reserveTokens: this.reserveTokens,
126
- currentTokens: this.getCurrentTokenCount(),
127
- messageCount: this.messages.length,
128
- systemPromptTokens: this.systemPromptTokens
129
- };
130
- }
131
- /**
132
- * Update token limits
133
- * @param maxTokens - New maximum token limit
134
- * @param reserveTokens - New reserve token amount
135
- */
136
- updateLimits(maxTokens, reserveTokens) {
137
- if (reserveTokens !== void 0 && reserveTokens >= maxTokens) {
138
- throw new Error("Reserve tokens must be less than max tokens");
139
- }
140
- this.maxTokens = maxTokens;
141
- if (reserveTokens !== void 0) {
142
- this.reserveTokens = reserveTokens;
35
+ static extractReferenceId(input) {
36
+ if (!input || typeof input !== "string") {
37
+ return null;
143
38
  }
144
- if (this.getCurrentTokenCount() > this.maxTokens - this.reserveTokens) {
145
- this.pruneToFit();
39
+ const refFormatMatch = input.match(/^ref:\/\/([A-Za-z0-9_-]{43})$/);
40
+ if (refFormatMatch) {
41
+ return refFormatMatch[1];
146
42
  }
43
+ return this.isValidReferenceId(input) ? input : null;
147
44
  }
148
45
  /**
149
- * Get statistics about the memory window
150
- * @returns Memory usage statistics
46
+ * Format a reference ID in the standard ref:// format
47
+ *
48
+ * @param referenceId The reference ID to format
49
+ * @returns Formatted reference string
151
50
  */
152
- getStats() {
153
- const currentTokens = this.getCurrentTokenCount();
154
- const capacity = this.maxTokens;
155
- const usagePercentage = currentTokens / capacity * 100;
156
- return {
157
- totalMessages: this.messages.length,
158
- currentTokens,
159
- maxTokens: capacity,
160
- reserveTokens: this.reserveTokens,
161
- systemPromptTokens: this.systemPromptTokens,
162
- usagePercentage: Math.round(usagePercentage * 100) / 100,
163
- remainingCapacity: this.getRemainingTokenCapacity(),
164
- canAcceptMore: this.getRemainingTokenCapacity() > this.reserveTokens
165
- };
51
+ static formatReference(referenceId) {
52
+ return `ref://${referenceId}`;
166
53
  }
167
54
  /**
168
- * Clean up resources
55
+ * Generate a test reference ID (for testing purposes only)
56
+ *
57
+ * @param testSeed A test seed to generate a fake but valid ID format
58
+ * @returns A valid format reference ID for testing
169
59
  */
170
- dispose() {
171
- this.clear();
172
- this.tokenCounter.dispose();
60
+ static generateTestId(testSeed) {
61
+ const content = Buffer.from(`test-${testSeed}-${Date.now()}`);
62
+ return this.generateId(content);
173
63
  }
174
- };
175
- _MemoryWindow.DEFAULT_MAX_TOKENS = 8e3;
176
- _MemoryWindow.DEFAULT_RESERVE_TOKENS = 1e3;
177
- _MemoryWindow.PRUNING_BATCH_SIZE = 2;
178
- let MemoryWindow = _MemoryWindow;
64
+ }
179
65
  export {
180
- MemoryWindow
66
+ ReferenceIdGenerator
181
67
  };
182
68
  //# sourceMappingURL=index22.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index22.js","sources":["../../src/memory/MemoryWindow.ts"],"sourcesContent":["import type { BaseMessage } from '@langchain/core/messages';\nimport { TokenCounter } from './TokenCounter';\n\n/**\n * Result of adding a message to the memory window\n */\nexport interface AddMessageResult {\n /** Whether the message was successfully added */\n added: boolean;\n /** Messages that were pruned to make room */\n prunedMessages: BaseMessage[];\n /** Current token count after operation */\n currentTokenCount: number;\n /** Remaining token capacity */\n remainingCapacity: number;\n}\n\n/**\n * Memory window that manages conversation history with token-based size limits\n * Automatically prunes old messages to stay within token limits while preserving conversational context\n */\nexport class MemoryWindow {\n private messages: BaseMessage[] = [];\n private maxTokens: number;\n private reserveTokens: number;\n private tokenCounter: TokenCounter;\n private systemPrompt: string = '';\n private systemPromptTokens: number = 0;\n\n // Default token limits for different model contexts\n public static readonly DEFAULT_MAX_TOKENS = 8000; // Conservative limit for most models\n public static readonly DEFAULT_RESERVE_TOKENS = 1000; // Reserve for response generation\n public static readonly PRUNING_BATCH_SIZE = 2; // Remove messages in pairs to maintain conversation flow\n\n constructor(\n maxTokens: number = MemoryWindow.DEFAULT_MAX_TOKENS,\n reserveTokens: number = MemoryWindow.DEFAULT_RESERVE_TOKENS,\n tokenCounter?: TokenCounter\n ) {\n if (reserveTokens >= maxTokens) {\n throw new Error('Reserve tokens must be less than max tokens');\n }\n\n this.maxTokens = maxTokens;\n this.reserveTokens = reserveTokens;\n this.tokenCounter = tokenCounter || new TokenCounter();\n }\n\n /**\n * Add a message to the memory window, pruning old messages if necessary\n * @param message - The message to add\n * @returns Result of the add operation including any pruned messages\n */\n addMessage(message: BaseMessage): AddMessageResult {\n // Calculate tokens for the new message\n const messageTokens = this.tokenCounter.countMessageTokens(message);\n \n // Add the message first\n this.messages.push(message);\n \n // Check if we need to prune\n const currentTokens = this.getCurrentTokenCount();\n const availableTokens = this.maxTokens - this.reserveTokens;\n \n let prunedMessages: BaseMessage[] = [];\n \n if (currentTokens > availableTokens) {\n // Need to prune - remove the new message temporarily\n this.messages.pop();\n \n // Prune old messages to make room\n prunedMessages = this.pruneToFit();\n \n // Add the new message back\n this.messages.push(message);\n }\n\n return {\n added: true,\n prunedMessages,\n currentTokenCount: this.getCurrentTokenCount(),\n remainingCapacity: this.getRemainingTokenCapacity()\n };\n }\n\n /**\n * Prune old messages to fit within token limits\n * Removes messages in pairs to maintain conversational flow\n * @returns Array of pruned messages\n */\n pruneToFit(): BaseMessage[] {\n const prunedMessages: BaseMessage[] = [];\n const targetTokens = this.maxTokens - this.reserveTokens;\n \n while (this.getCurrentTokenCount() > targetTokens && this.messages.length > 0) {\n // Remove messages in batches to maintain conversation flow\n const batchSize = Math.min(MemoryWindow.PRUNING_BATCH_SIZE, this.messages.length);\n \n for (let i = 0; i < batchSize; i++) {\n const prunedMessage = this.messages.shift();\n if (prunedMessage) {\n prunedMessages.push(prunedMessage);\n }\n }\n \n // Safety check to prevent infinite loop\n if (prunedMessages.length > 1000) {\n console.warn('MemoryWindow: Excessive pruning detected, stopping to prevent infinite loop');\n break;\n }\n }\n\n return prunedMessages;\n }\n\n /**\n * Get current token count including system prompt and messages\n * @returns Current token count\n */\n getCurrentTokenCount(): number {\n const messageTokens = this.tokenCounter.countMessagesTokens(this.messages);\n return this.systemPromptTokens + messageTokens;\n }\n\n /**\n * Get remaining token capacity before hitting the reserve limit\n * @returns Remaining tokens that can be used\n */\n getRemainingTokenCapacity(): number {\n return Math.max(0, this.maxTokens - this.getCurrentTokenCount());\n }\n\n /**\n * Check if a message can be added without exceeding limits\n * @param message - The message to check\n * @returns True if message can be added within reserve limits\n */\n canAddMessage(message: BaseMessage): boolean {\n const messageTokens = this.tokenCounter.countMessageTokens(message);\n const currentTokens = this.getCurrentTokenCount();\n const wouldExceedReserve = (currentTokens + messageTokens) > (this.maxTokens - this.reserveTokens);\n \n // Always allow adding if we can prune to make room\n // Only return false if the message itself is larger than our total capacity\n if (messageTokens > this.maxTokens) {\n return false;\n }\n \n return !wouldExceedReserve || this.messages.length > 0;\n }\n\n /**\n * Get all messages in the memory window\n * @returns Copy of current messages array\n */\n getMessages(): BaseMessage[] {\n return [...this.messages];\n }\n\n /**\n * Clear all messages from the memory window\n */\n clear(): void {\n this.messages = [];\n }\n\n /**\n * Set the system prompt and update token calculations\n * @param systemPrompt - The system prompt text\n */\n setSystemPrompt(systemPrompt: string): void {\n this.systemPrompt = systemPrompt;\n this.systemPromptTokens = this.tokenCounter.estimateSystemPromptTokens(systemPrompt);\n }\n\n /**\n * Get the current system prompt\n * @returns Current system prompt\n */\n getSystemPrompt(): string {\n return this.systemPrompt;\n }\n\n /**\n * Get current configuration\n * @returns Memory window configuration\n */\n getConfig() {\n return {\n maxTokens: this.maxTokens,\n reserveTokens: this.reserveTokens,\n currentTokens: this.getCurrentTokenCount(),\n messageCount: this.messages.length,\n systemPromptTokens: this.systemPromptTokens\n };\n }\n\n /**\n * Update token limits\n * @param maxTokens - New maximum token limit\n * @param reserveTokens - New reserve token amount\n */\n updateLimits(maxTokens: number, reserveTokens?: number): void {\n if (reserveTokens !== undefined && reserveTokens >= maxTokens) {\n throw new Error('Reserve tokens must be less than max tokens');\n }\n\n this.maxTokens = maxTokens;\n if (reserveTokens !== undefined) {\n this.reserveTokens = reserveTokens;\n }\n\n // Prune if necessary after updating limits\n if (this.getCurrentTokenCount() > (this.maxTokens - this.reserveTokens)) {\n this.pruneToFit();\n }\n }\n\n /**\n * Get statistics about the memory window\n * @returns Memory usage statistics\n */\n getStats() {\n const currentTokens = this.getCurrentTokenCount();\n const capacity = this.maxTokens;\n const usagePercentage = (currentTokens / capacity) * 100;\n \n return {\n totalMessages: this.messages.length,\n currentTokens,\n maxTokens: capacity,\n reserveTokens: this.reserveTokens,\n systemPromptTokens: this.systemPromptTokens,\n usagePercentage: Math.round(usagePercentage * 100) / 100,\n remainingCapacity: this.getRemainingTokenCapacity(),\n canAcceptMore: this.getRemainingTokenCapacity() > this.reserveTokens\n };\n }\n\n /**\n * Clean up resources\n */\n dispose(): void {\n this.clear();\n this.tokenCounter.dispose();\n }\n}"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index22.js","sources":["../../src/memory/ReferenceIdGenerator.ts"],"sourcesContent":["import { createHash } from 'crypto';\nimport { ReferenceId } from '../types/content-reference';\n\n/**\n * Content-based reference ID generator using SHA-256 (HCS-1 style)\n * \n * Generates deterministic reference IDs based on content hashing.\n * Same content always produces the same reference ID.\n */\nexport class ReferenceIdGenerator {\n /**\n * Generate a content-based reference ID using SHA-256 hashing\n * \n * @param content The content to generate a reference ID for\n * @returns Deterministic reference ID based on content hash\n */\n static generateId(content: Buffer): ReferenceId {\n const hash = createHash('sha256');\n hash.update(content);\n return hash.digest('base64url');\n }\n \n /**\n * Validate that a string is a properly formatted reference ID\n * \n * @param id The ID to validate\n * @returns true if the ID is valid format\n */\n static isValidReferenceId(id: string): id is ReferenceId {\n if (!id || typeof id !== 'string') {\n return false;\n }\n \n if (id.length !== 43) {\n return false;\n }\n \n return /^[A-Za-z0-9_-]+$/.test(id);\n }\n \n /**\n * Extract reference ID from ref:// format\n * \n * @param input Input string that may contain a reference ID\n * @returns Extracted reference ID or null if not found\n */\n static extractReferenceId(input: string): ReferenceId | null {\n if (!input || typeof input !== 'string') {\n return null;\n }\n \n const refFormatMatch = input.match(/^ref:\\/\\/([A-Za-z0-9_-]{43})$/);\n if (refFormatMatch) {\n return refFormatMatch[1] as ReferenceId;\n }\n \n return this.isValidReferenceId(input) ? input : null;\n }\n \n /**\n * Format a reference ID in the standard ref:// format\n * \n * @param referenceId The reference ID to format\n * @returns Formatted reference string\n */\n static formatReference(referenceId: ReferenceId): string {\n return `ref://${referenceId}`;\n }\n \n /**\n * Generate a test reference ID (for testing purposes only)\n * \n * @param testSeed A test seed to generate a fake but valid ID format\n * @returns A valid format reference ID for testing\n */\n static generateTestId(testSeed: string): ReferenceId {\n const content = Buffer.from(`test-${testSeed}-${Date.now()}`);\n return this.generateId(content);\n }\n}"],"names":[],"mappings":";AASO,MAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhC,OAAO,WAAW,SAA8B;AAC9C,UAAM,OAAO,WAAW,QAAQ;AAChC,SAAK,OAAO,OAAO;AACnB,WAAO,KAAK,OAAO,WAAW;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,mBAAmB,IAA+B;AACvD,QAAI,CAAC,MAAM,OAAO,OAAO,UAAU;AACjC,aAAO;AAAA,IACT;AAEA,QAAI,GAAG,WAAW,IAAI;AACpB,aAAO;AAAA,IACT;AAEA,WAAO,mBAAmB,KAAK,EAAE;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,mBAAmB,OAAmC;AAC3D,QAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,aAAO;AAAA,IACT;AAEA,UAAM,iBAAiB,MAAM,MAAM,+BAA+B;AAClE,QAAI,gBAAgB;AAClB,aAAO,eAAe,CAAC;AAAA,IACzB;AAEA,WAAO,KAAK,mBAAmB,KAAK,IAAI,QAAQ;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,gBAAgB,aAAkC;AACvD,WAAO,SAAS,WAAW;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,eAAe,UAA+B;AACnD,UAAM,UAAU,OAAO,KAAK,QAAQ,QAAQ,IAAI,KAAK,IAAA,CAAK,EAAE;AAC5D,WAAO,KAAK,WAAW,OAAO;AAAA,EAChC;AACF;"}
@@ -1,126 +1,30 @@
1
- import { encoding_for_model } from "tiktoken";
2
- const _TokenCounter = class _TokenCounter {
3
- // Additional token for role specification
4
- constructor(modelName = "gpt-4o") {
5
- this.modelName = modelName;
6
- try {
7
- this.encoding = encoding_for_model(modelName);
8
- } catch (error) {
9
- console.warn(`Model ${modelName} not found, falling back to gpt-4o encoding`);
10
- this.encoding = encoding_for_model("gpt-4o");
11
- this.modelName = "gpt-4o";
12
- }
13
- }
14
- /**
15
- * Count tokens in raw text content
16
- * @param text - The text to count tokens for
17
- * @returns Number of tokens
18
- */
19
- countTokens(text) {
20
- if (!text || text.trim() === "") {
21
- return 0;
22
- }
23
- try {
24
- const tokens = this.encoding.encode(text);
25
- return tokens.length;
26
- } catch (error) {
27
- console.warn("Error counting tokens, falling back to word-based estimation:", error);
28
- return Math.ceil(text.split(/\s+/).length * 1.3);
29
- }
30
- }
31
- /**
32
- * Count tokens for a single chat message including role overhead
33
- * @param message - The message to count tokens for
34
- * @returns Number of tokens including message formatting overhead
35
- */
36
- countMessageTokens(message) {
37
- const contentTokens = this.countTokens(message.content);
38
- const roleTokens = this.countTokens(this.getMessageRole(message));
39
- return contentTokens + roleTokens + _TokenCounter.MESSAGE_OVERHEAD + _TokenCounter.ROLE_OVERHEAD;
40
- }
41
- /**
42
- * Count tokens for multiple messages
43
- * @param messages - Array of messages to count
44
- * @returns Total token count for all messages
45
- */
46
- countMessagesTokens(messages) {
47
- if (!messages || messages.length === 0) {
48
- return 0;
49
- }
50
- return messages.reduce((total, message) => {
51
- return total + this.countMessageTokens(message);
52
- }, 0);
53
- }
54
- /**
55
- * Estimate tokens for system prompt
56
- * System prompts have slightly different overhead in chat completions
57
- * @param systemPrompt - The system prompt text
58
- * @returns Estimated token count
59
- */
60
- estimateSystemPromptTokens(systemPrompt) {
61
- if (!systemPrompt || systemPrompt.trim() === "") {
62
- return 0;
63
- }
64
- const contentTokens = this.countTokens(systemPrompt);
65
- const roleTokens = this.countTokens("system");
66
- return contentTokens + roleTokens + _TokenCounter.MESSAGE_OVERHEAD + _TokenCounter.ROLE_OVERHEAD;
67
- }
68
- /**
69
- * Get total context size estimate including system prompt and messages
70
- * @param systemPrompt - System prompt text
71
- * @param messages - Conversation messages
72
- * @returns Total estimated token count
73
- */
74
- estimateContextSize(systemPrompt, messages) {
75
- const systemTokens = this.estimateSystemPromptTokens(systemPrompt);
76
- const messageTokens = this.countMessagesTokens(messages);
77
- const completionOverhead = 10;
78
- return systemTokens + messageTokens + completionOverhead;
79
- }
80
- /**
81
- * Get the role string for a message
82
- * @param message - The message to get the role for
83
- * @returns Role string ('user', 'assistant', 'system', etc.)
84
- */
85
- getMessageRole(message) {
86
- const messageType = message._getType();
87
- switch (messageType) {
88
- case "human":
89
- return "user";
90
- case "ai":
91
- return "assistant";
92
- case "system":
93
- return "system";
94
- case "function":
95
- return "function";
96
- case "tool":
97
- return "tool";
98
- default:
99
- return "user";
100
- }
101
- }
102
- /**
103
- * Get the model name being used for token counting
104
- * @returns The tiktoken model name
105
- */
106
- getModelName() {
107
- return this.modelName;
108
- }
109
- /**
110
- * Clean up encoding resources
111
- */
112
- dispose() {
113
- try {
114
- this.encoding.free();
115
- } catch (error) {
116
- console.warn("Error disposing encoding:", error);
117
- }
1
+ const DEFAULT_CONTENT_REFERENCE_CONFIG = {
2
+ sizeThresholdBytes: 10 * 1024,
3
+ maxAgeMs: 60 * 60 * 1e3,
4
+ maxReferences: 100,
5
+ maxTotalStorageBytes: 100 * 1024 * 1024,
6
+ enableAutoCleanup: true,
7
+ cleanupIntervalMs: 5 * 60 * 1e3,
8
+ enablePersistence: false,
9
+ storageBackend: "memory",
10
+ cleanupPolicies: {
11
+ recent: { maxAgeMs: 30 * 60 * 1e3, priority: 1 },
12
+ userContent: { maxAgeMs: 2 * 60 * 60 * 1e3, priority: 2 },
13
+ agentGenerated: { maxAgeMs: 60 * 60 * 1e3, priority: 3 },
14
+ default: { maxAgeMs: 60 * 60 * 1e3, priority: 4 }
118
15
  }
119
16
  };
120
- _TokenCounter.MESSAGE_OVERHEAD = 3;
121
- _TokenCounter.ROLE_OVERHEAD = 1;
122
- let TokenCounter = _TokenCounter;
17
+ class ContentReferenceError extends Error {
18
+ constructor(message, type, referenceId, suggestedActions) {
19
+ super(message);
20
+ this.type = type;
21
+ this.referenceId = referenceId;
22
+ this.suggestedActions = suggestedActions;
23
+ this.name = "ContentReferenceError";
24
+ }
25
+ }
123
26
  export {
124
- TokenCounter
27
+ ContentReferenceError,
28
+ DEFAULT_CONTENT_REFERENCE_CONFIG
125
29
  };
126
30
  //# sourceMappingURL=index23.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index23.js","sources":["../../src/memory/TokenCounter.ts"],"sourcesContent":["import { encoding_for_model } from 'tiktoken';\nimport type { TiktokenModel } from 'tiktoken';\nimport type { BaseMessage } from '@langchain/core/messages';\n\n/**\n * Token counter utility for OpenAI models using tiktoken encoding\n * Provides accurate token counting for text content and chat messages\n */\nexport class TokenCounter {\n private encoding: ReturnType<typeof encoding_for_model>;\n private modelName: TiktokenModel;\n\n // Token overhead per message for chat completion format\n private static readonly MESSAGE_OVERHEAD = 3; // <|start|>role<|end|>content<|end|>\n private static readonly ROLE_OVERHEAD = 1; // Additional token for role specification\n\n constructor(modelName: TiktokenModel = 'gpt-4o') {\n this.modelName = modelName;\n try {\n this.encoding = encoding_for_model(modelName);\n } catch (error) {\n // Fallback to gpt-4o if specific model encoding is not available\n console.warn(`Model ${modelName} not found, falling back to gpt-4o encoding`);\n this.encoding = encoding_for_model('gpt-4o');\n this.modelName = 'gpt-4o';\n }\n }\n\n /**\n * Count tokens in raw text content\n * @param text - The text to count tokens for\n * @returns Number of tokens\n */\n countTokens(text: string): number {\n if (!text || text.trim() === '') {\n return 0;\n }\n\n try {\n const tokens = this.encoding.encode(text);\n return tokens.length;\n } catch (error) {\n console.warn('Error counting tokens, falling back to word-based estimation:', error);\n // Fallback: rough estimation based on words (typically 1.3 tokens per word)\n return Math.ceil(text.split(/\\s+/).length * 1.3);\n }\n }\n\n /**\n * Count tokens for a single chat message including role overhead\n * @param message - The message to count tokens for\n * @returns Number of tokens including message formatting overhead\n */\n countMessageTokens(message: BaseMessage): number {\n const contentTokens = this.countTokens(message.content as string);\n const roleTokens = this.countTokens(this.getMessageRole(message));\n \n // Add overhead for message structure and role\n return contentTokens + roleTokens + TokenCounter.MESSAGE_OVERHEAD + TokenCounter.ROLE_OVERHEAD;\n }\n\n /**\n * Count tokens for multiple messages\n * @param messages - Array of messages to count\n * @returns Total token count for all messages\n */\n countMessagesTokens(messages: BaseMessage[]): number {\n if (!messages || messages.length === 0) {\n return 0;\n }\n\n return messages.reduce((total, message) => {\n return total + this.countMessageTokens(message);\n }, 0);\n }\n\n /**\n * Estimate tokens for system prompt\n * System prompts have slightly different overhead in chat completions\n * @param systemPrompt - The system prompt text\n * @returns Estimated token count\n */\n estimateSystemPromptTokens(systemPrompt: string): number {\n if (!systemPrompt || systemPrompt.trim() === '') {\n return 0;\n }\n\n const contentTokens = this.countTokens(systemPrompt);\n const roleTokens = this.countTokens('system');\n \n // System messages have similar overhead to regular messages\n return contentTokens + roleTokens + TokenCounter.MESSAGE_OVERHEAD + TokenCounter.ROLE_OVERHEAD;\n }\n\n /**\n * Get total context size estimate including system prompt and messages\n * @param systemPrompt - System prompt text\n * @param messages - Conversation messages\n * @returns Total estimated token count\n */\n estimateContextSize(systemPrompt: string, messages: BaseMessage[]): number {\n const systemTokens = this.estimateSystemPromptTokens(systemPrompt);\n const messageTokens = this.countMessagesTokens(messages);\n \n // Add a small buffer for chat completion overhead\n const completionOverhead = 10;\n \n return systemTokens + messageTokens + completionOverhead;\n }\n\n /**\n * Get the role string for a message\n * @param message - The message to get the role for\n * @returns Role string ('user', 'assistant', 'system', etc.)\n */\n private getMessageRole(message: BaseMessage): string {\n const messageType = message._getType();\n switch (messageType) {\n case 'human':\n return 'user';\n case 'ai':\n return 'assistant';\n case 'system':\n return 'system';\n case 'function':\n return 'function';\n case 'tool':\n return 'tool';\n default:\n return 'user'; // Default fallback\n }\n }\n\n /**\n * Get the model name being used for token counting\n * @returns The tiktoken model name\n */\n getModelName(): string {\n return this.modelName;\n }\n\n /**\n * Clean up encoding resources\n */\n dispose(): void {\n try {\n this.encoding.free();\n } catch (error) {\n console.warn('Error disposing encoding:', error);\n }\n }\n}"],"names":[],"mappings":";AAQO,MAAM,gBAAN,MAAM,cAAa;AAAA;AAAA,EAQxB,YAAY,YAA2B,UAAU;AAC/C,SAAK,YAAY;AACjB,QAAI;AACF,WAAK,WAAW,mBAAmB,SAAS;AAAA,IAC9C,SAAS,OAAO;AAEd,cAAQ,KAAK,SAAS,SAAS,6CAA6C;AAC5E,WAAK,WAAW,mBAAmB,QAAQ;AAC3C,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,MAAsB;AAChC,QAAI,CAAC,QAAQ,KAAK,KAAA,MAAW,IAAI;AAC/B,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,SAAS,KAAK,SAAS,OAAO,IAAI;AACxC,aAAO,OAAO;AAAA,IAChB,SAAS,OAAO;AACd,cAAQ,KAAK,iEAAiE,KAAK;AAEnF,aAAO,KAAK,KAAK,KAAK,MAAM,KAAK,EAAE,SAAS,GAAG;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBAAmB,SAA8B;AAC/C,UAAM,gBAAgB,KAAK,YAAY,QAAQ,OAAiB;AAChE,UAAM,aAAa,KAAK,YAAY,KAAK,eAAe,OAAO,CAAC;AAGhE,WAAO,gBAAgB,aAAa,cAAa,mBAAmB,cAAa;AAAA,EACnF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,oBAAoB,UAAiC;AACnD,QAAI,CAAC,YAAY,SAAS,WAAW,GAAG;AACtC,aAAO;AAAA,IACT;AAEA,WAAO,SAAS,OAAO,CAAC,OAAO,YAAY;AACzC,aAAO,QAAQ,KAAK,mBAAmB,OAAO;AAAA,IAChD,GAAG,CAAC;AAAA,EACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,2BAA2B,cAA8B;AACvD,QAAI,CAAC,gBAAgB,aAAa,KAAA,MAAW,IAAI;AAC/C,aAAO;AAAA,IACT;AAEA,UAAM,gBAAgB,KAAK,YAAY,YAAY;AACnD,UAAM,aAAa,KAAK,YAAY,QAAQ;AAG5C,WAAO,gBAAgB,aAAa,cAAa,mBAAmB,cAAa;AAAA,EACnF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,oBAAoB,cAAsB,UAAiC;AACzE,UAAM,eAAe,KAAK,2BAA2B,YAAY;AACjE,UAAM,gBAAgB,KAAK,oBAAoB,QAAQ;AAGvD,UAAM,qBAAqB;AAE3B,WAAO,eAAe,gBAAgB;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,eAAe,SAA8B;AACnD,UAAM,cAAc,QAAQ,SAAA;AAC5B,YAAQ,aAAA;AAAA,MACN,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IAAA;AAAA,EAEb;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACd,QAAI;AACF,WAAK,SAAS,KAAA;AAAA,IAChB,SAAS,OAAO;AACd,cAAQ,KAAK,6BAA6B,KAAK;AAAA,IACjD;AAAA,EACF;AACF;AA1IE,cAAwB,mBAAmB;AAC3C,cAAwB,gBAAgB;AANnC,IAAM,eAAN;"}
1
+ {"version":3,"file":"index23.js","sources":["../../src/types/content-reference.ts"],"sourcesContent":["/**\n * Content Reference System Types\n * \n * Shared interfaces for the Reference-Based Content System that handles\n * large content storage with unique reference IDs to optimize context window usage.\n */\n\n/**\n * Unique identifier for stored content references\n * Format: Cryptographically secure 32-byte identifier with base64url encoding\n */\nexport type ReferenceId = string;\n\n/**\n * Lifecycle state of a content reference\n */\nexport type ReferenceLifecycleState = 'active' | 'expired' | 'cleanup_pending' | 'invalid';\n\n/**\n * Content types supported by the reference system\n */\nexport type ContentType = 'text' | 'json' | 'html' | 'markdown' | 'binary' | 'unknown';\n\n/**\n * Sources that created the content reference\n */\nexport type ContentSource = 'mcp_tool' | 'user_upload' | 'agent_generated' | 'system';\n\n/**\n * Metadata associated with stored content\n */\nexport interface ContentMetadata {\n /** Content type classification */\n contentType: ContentType;\n \n /** MIME type of the original content */\n mimeType?: string;\n \n /** Size in bytes of the stored content */\n sizeBytes: number;\n \n /** When the content was originally stored */\n createdAt: Date;\n \n /** Last time the content was accessed via reference resolution */\n lastAccessedAt: Date;\n \n /** Source that created this content reference */\n source: ContentSource;\n \n /** Name of the MCP tool that generated the content (if applicable) */\n mcpToolName?: string;\n \n /** Original filename or suggested name for the content */\n fileName?: string;\n \n /** Number of times this reference has been resolved */\n accessCount: number;\n \n /** Tags for categorization and cleanup policies */\n tags?: string[];\n \n /** Custom metadata from the source */\n customMetadata?: Record<string, unknown>;\n}\n\n/**\n * Core content reference object passed through agent context\n * Designed to be lightweight (<100 tokens) while providing enough \n * information for agent decision-making\n */\nexport interface ContentReference {\n /** Unique identifier for resolving the content */\n referenceId: ReferenceId;\n \n /** Current lifecycle state */\n state: ReferenceLifecycleState;\n \n /** Brief description or preview of the content (max 200 chars) */\n preview: string;\n \n /** Essential metadata for agent decision-making */\n metadata: Pick<ContentMetadata, 'contentType' | 'sizeBytes' | 'source' | 'fileName' | 'mimeType'>;\n \n /** When this reference was created */\n createdAt: Date;\n \n /** Special format indicator for reference IDs in content */\n readonly format: 'ref://{id}';\n}\n\n/**\n * Result of attempting to resolve a content reference\n */\nexport interface ReferenceResolutionResult {\n /** Whether the resolution was successful */\n success: boolean;\n \n /** The resolved content if successful */\n content?: Buffer;\n \n /** Complete metadata if successful */\n metadata?: ContentMetadata;\n \n /** Error message if resolution failed */\n error?: string;\n \n /** Specific error type for targeted error handling */\n errorType?: 'not_found' | 'expired' | 'corrupted' | 'access_denied' | 'system_error';\n \n /** Suggested actions for recovery */\n suggestedActions?: string[];\n}\n\n/**\n * Configuration for content reference storage and lifecycle\n */\nexport interface ContentReferenceConfig {\n /** Size threshold above which content should be stored as references (default: 10KB) */\n sizeThresholdBytes: number;\n \n /** Maximum age for unused references before cleanup (default: 1 hour) */\n maxAgeMs: number;\n \n /** Maximum number of references to store simultaneously */\n maxReferences: number;\n \n /** Maximum total storage size for all references */\n maxTotalStorageBytes: number;\n \n /** Whether to enable automatic cleanup */\n enableAutoCleanup: boolean;\n \n /** Interval for cleanup checks in milliseconds */\n cleanupIntervalMs: number;\n \n /** Whether to persist references across restarts */\n enablePersistence: boolean;\n \n /** Storage backend configuration */\n storageBackend: 'memory' | 'filesystem' | 'hybrid';\n \n /** Cleanup policies for different content types */\n cleanupPolicies: {\n /** Policy for content marked as \"recent\" from MCP tools */\n recent: { maxAgeMs: number; priority: number };\n \n /** Policy for user-uploaded content */\n userContent: { maxAgeMs: number; priority: number };\n \n /** Policy for agent-generated content */\n agentGenerated: { maxAgeMs: number; priority: number };\n \n /** Default policy for other content */\n default: { maxAgeMs: number; priority: number };\n };\n}\n\n/**\n * Default configuration values\n */\nexport const DEFAULT_CONTENT_REFERENCE_CONFIG: ContentReferenceConfig = {\n sizeThresholdBytes: 10 * 1024,\n maxAgeMs: 60 * 60 * 1000,\n maxReferences: 100,\n maxTotalStorageBytes: 100 * 1024 * 1024,\n enableAutoCleanup: true,\n cleanupIntervalMs: 5 * 60 * 1000,\n enablePersistence: false,\n storageBackend: 'memory',\n cleanupPolicies: {\n recent: { maxAgeMs: 30 * 60 * 1000, priority: 1 },\n userContent: { maxAgeMs: 2 * 60 * 60 * 1000, priority: 2 },\n agentGenerated: { maxAgeMs: 60 * 60 * 1000, priority: 3 },\n default: { maxAgeMs: 60 * 60 * 1000, priority: 4 }\n }\n};\n\n/**\n * Statistics about content reference usage and storage\n */\nexport interface ContentReferenceStats {\n /** Total number of active references */\n activeReferences: number;\n \n /** Total storage used by all references in bytes */\n totalStorageBytes: number;\n \n /** Number of references cleaned up in last cleanup cycle */\n recentlyCleanedUp: number;\n \n /** Number of successful reference resolutions since startup */\n totalResolutions: number;\n \n /** Number of failed resolution attempts */\n failedResolutions: number;\n \n /** Average content size in bytes */\n averageContentSize: number;\n \n /** Most frequently accessed reference ID */\n mostAccessedReferenceId?: ReferenceId;\n \n /** Storage utilization percentage */\n storageUtilization: number;\n \n /** Performance metrics */\n performanceMetrics: {\n /** Average time to create a reference in milliseconds */\n averageCreationTimeMs: number;\n \n /** Average time to resolve a reference in milliseconds */\n averageResolutionTimeMs: number;\n \n /** Average cleanup time in milliseconds */\n averageCleanupTimeMs: number;\n };\n}\n\n/**\n * Error types for content reference operations\n */\nexport class ContentReferenceError extends Error {\n constructor(\n message: string,\n public readonly type: ReferenceResolutionResult['errorType'],\n public readonly referenceId?: ReferenceId,\n public readonly suggestedActions?: string[]\n ) {\n super(message);\n this.name = 'ContentReferenceError';\n }\n}\n\n/**\n * Interface for content reference storage implementations\n */\nexport interface ContentReferenceStore {\n /**\n * Store content and return a reference\n */\n storeContent(\n content: Buffer,\n metadata: Omit<ContentMetadata, 'createdAt' | 'lastAccessedAt' | 'accessCount'>\n ): Promise<ContentReference>;\n \n /**\n * Resolve a reference to its content\n */\n resolveReference(referenceId: ReferenceId): Promise<ReferenceResolutionResult>;\n \n /**\n * Check if a reference exists and is valid\n */\n hasReference(referenceId: ReferenceId): Promise<boolean>;\n \n /**\n * Mark a reference for cleanup\n */\n cleanupReference(referenceId: ReferenceId): Promise<boolean>;\n \n /**\n * Get current storage statistics\n */\n getStats(): Promise<ContentReferenceStats>;\n \n /**\n * Update configuration\n */\n updateConfig(config: Partial<ContentReferenceConfig>): Promise<void>;\n \n /**\n * Perform cleanup based on current policies\n */\n performCleanup(): Promise<{ cleanedUp: number; errors: string[] }>;\n \n /**\n * Dispose of resources\n */\n dispose(): Promise<void>;\n}"],"names":[],"mappings":"AAiKO,MAAM,mCAA2D;AAAA,EACtE,oBAAoB,KAAK;AAAA,EACzB,UAAU,KAAK,KAAK;AAAA,EACpB,eAAe;AAAA,EACf,sBAAsB,MAAM,OAAO;AAAA,EACnC,mBAAmB;AAAA,EACnB,mBAAmB,IAAI,KAAK;AAAA,EAC5B,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,IACf,QAAQ,EAAE,UAAU,KAAK,KAAK,KAAM,UAAU,EAAA;AAAA,IAC9C,aAAa,EAAE,UAAU,IAAI,KAAK,KAAK,KAAM,UAAU,EAAA;AAAA,IACvD,gBAAgB,EAAE,UAAU,KAAK,KAAK,KAAM,UAAU,EAAA;AAAA,IACtD,SAAS,EAAE,UAAU,KAAK,KAAK,KAAM,UAAU,EAAA;AAAA,EAAE;AAErD;AA8CO,MAAM,8BAA8B,MAAM;AAAA,EAC/C,YACE,SACgB,MACA,aACA,kBAChB;AACA,UAAM,OAAO;AAJG,SAAA,OAAA;AACA,SAAA,cAAA;AACA,SAAA,mBAAA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;"}
@@ -1,68 +1,95 @@
1
- import { createHash } from "crypto";
2
- class ReferenceIdGenerator {
3
- /**
4
- * Generate a content-based reference ID using SHA-256 hashing
5
- *
6
- * @param content The content to generate a reference ID for
7
- * @returns Deterministic reference ID based on content hash
8
- */
9
- static generateId(content) {
10
- const hash = createHash("sha256");
11
- hash.update(content);
12
- return hash.digest("base64url");
1
+ import { TransferTransaction, AccountId, Hbar } from "@hashgraph/sdk";
2
+ import BigNumber from "bignumber.js";
3
+ import { BaseServiceBuilder } from "hedera-agent-kit";
4
+ class AccountBuilder extends BaseServiceBuilder {
5
+ constructor(hederaKit) {
6
+ super(hederaKit);
13
7
  }
14
8
  /**
15
- * Validate that a string is a properly formatted reference ID
16
- *
17
- * @param id The ID to validate
18
- * @returns true if the ID is valid format
9
+ * Transfers HBAR between accounts with proper decimal handling
19
10
  */
20
- static isValidReferenceId(id) {
21
- if (!id || typeof id !== "string") {
22
- return false;
11
+ transferHbar(params, isUserInitiated = true) {
12
+ this.clearNotes();
13
+ const transaction = new TransferTransaction();
14
+ if (!params.transfers || params.transfers.length === 0) {
15
+ throw new Error("HbarTransferParams must include at least one transfer.");
23
16
  }
24
- if (id.length !== 43) {
25
- return false;
17
+ let netZeroInTinybars = new BigNumber(0);
18
+ let userTransferProcessedForScheduling = false;
19
+ if (isUserInitiated && this.kit.userAccountId && this.kit.operationalMode === "provideBytes" && params.transfers.length === 1) {
20
+ const receiverTransfer = params.transfers[0];
21
+ const amountValue = typeof receiverTransfer.amount === "string" || typeof receiverTransfer.amount === "number" ? receiverTransfer.amount : receiverTransfer.amount.toString();
22
+ const amountBigNum = new BigNumber(amountValue);
23
+ if (amountBigNum.isPositive()) {
24
+ const recipientAccountId = typeof receiverTransfer.accountId === "string" ? AccountId.fromString(receiverTransfer.accountId) : receiverTransfer.accountId;
25
+ const roundedAmount = amountBigNum.toFixed(8, BigNumber.ROUND_DOWN);
26
+ const sdkHbarAmount = Hbar.fromString(roundedAmount);
27
+ this.logger.info(
28
+ `[AccountBuilder.transferHbar] Configuring user-initiated scheduled transfer: ${sdkHbarAmount.toString()} from ${this.kit.userAccountId} to ${recipientAccountId.toString()}`
29
+ );
30
+ this.addNote(
31
+ `Configured HBAR transfer from your account (${this.kit.userAccountId}) to ${recipientAccountId.toString()} for ${sdkHbarAmount.toString()}.`
32
+ );
33
+ transaction.addHbarTransfer(recipientAccountId, sdkHbarAmount);
34
+ transaction.addHbarTransfer(
35
+ AccountId.fromString(this.kit.userAccountId),
36
+ sdkHbarAmount.negated()
37
+ );
38
+ userTransferProcessedForScheduling = true;
39
+ }
26
40
  }
27
- return /^[A-Za-z0-9_-]+$/.test(id);
28
- }
29
- /**
30
- * Extract reference ID from ref:// format
31
- *
32
- * @param input Input string that may contain a reference ID
33
- * @returns Extracted reference ID or null if not found
34
- */
35
- static extractReferenceId(input) {
36
- if (!input || typeof input !== "string") {
37
- return null;
41
+ if (!userTransferProcessedForScheduling) {
42
+ const processedTransfers = [];
43
+ for (const transferInput of params.transfers) {
44
+ const accountId = typeof transferInput.accountId === "string" ? AccountId.fromString(transferInput.accountId) : transferInput.accountId;
45
+ const amountValue = typeof transferInput.amount === "string" || typeof transferInput.amount === "number" ? transferInput.amount : transferInput.amount.toString();
46
+ const amountBigNum = new BigNumber(amountValue);
47
+ const roundedAmount = amountBigNum.toFixed(8, BigNumber.ROUND_DOWN);
48
+ this.logger.info(
49
+ `Processing transfer: ${amountValue} HBAR (rounded to ${roundedAmount}) for account ${accountId.toString()}`
50
+ );
51
+ const sdkHbarAmount = Hbar.fromString(roundedAmount);
52
+ processedTransfers.push({
53
+ accountId,
54
+ amount: amountBigNum,
55
+ hbar: sdkHbarAmount
56
+ });
57
+ const tinybarsContribution = sdkHbarAmount.toTinybars();
58
+ netZeroInTinybars = netZeroInTinybars.plus(
59
+ tinybarsContribution.toString()
60
+ );
61
+ }
62
+ if (!netZeroInTinybars.isZero()) {
63
+ this.logger.warn(
64
+ `Transfer sum not zero: ${netZeroInTinybars.toString()} tinybars off. Adjusting last transfer.`
65
+ );
66
+ if (processedTransfers.length > 0) {
67
+ const lastTransfer = processedTransfers[processedTransfers.length - 1];
68
+ const adjustment = netZeroInTinybars.dividedBy(-1e8);
69
+ const adjustedAmount = lastTransfer.amount.plus(adjustment);
70
+ const adjustedRounded = adjustedAmount.toFixed(8, BigNumber.ROUND_DOWN);
71
+ lastTransfer.hbar = Hbar.fromString(adjustedRounded);
72
+ this.logger.info(
73
+ `Adjusted last transfer for ${lastTransfer.accountId.toString()} to ${adjustedRounded} HBAR`
74
+ );
75
+ }
76
+ }
77
+ for (const transfer of processedTransfers) {
78
+ transaction.addHbarTransfer(transfer.accountId, transfer.hbar);
79
+ }
38
80
  }
39
- const refFormatMatch = input.match(/^ref:\/\/([A-Za-z0-9_-]{43})$/);
40
- if (refFormatMatch) {
41
- return refFormatMatch[1];
81
+ if (typeof params.memo !== "undefined") {
82
+ if (params.memo === null) {
83
+ this.logger.warn("Received null for memo in transferHbar.");
84
+ } else {
85
+ transaction.setTransactionMemo(params.memo);
86
+ }
42
87
  }
43
- return this.isValidReferenceId(input) ? input : null;
44
- }
45
- /**
46
- * Format a reference ID in the standard ref:// format
47
- *
48
- * @param referenceId The reference ID to format
49
- * @returns Formatted reference string
50
- */
51
- static formatReference(referenceId) {
52
- return `ref://${referenceId}`;
53
- }
54
- /**
55
- * Generate a test reference ID (for testing purposes only)
56
- *
57
- * @param testSeed A test seed to generate a fake but valid ID format
58
- * @returns A valid format reference ID for testing
59
- */
60
- static generateTestId(testSeed) {
61
- const content = Buffer.from(`test-${testSeed}-${Date.now()}`);
62
- return this.generateId(content);
88
+ this.setCurrentTransaction(transaction);
89
+ return this;
63
90
  }
64
91
  }
65
92
  export {
66
- ReferenceIdGenerator
93
+ AccountBuilder
67
94
  };
68
95
  //# sourceMappingURL=index24.js.map