lettactl 0.5.7 → 0.5.9

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 (40) hide show
  1. package/dist/commands/apply-template.d.ts +12 -0
  2. package/dist/commands/apply-template.d.ts.map +1 -0
  3. package/dist/commands/apply-template.js +118 -0
  4. package/dist/commands/apply-template.js.map +1 -0
  5. package/dist/commands/apply.d.ts.map +1 -1
  6. package/dist/commands/apply.js +42 -358
  7. package/dist/commands/apply.js.map +1 -1
  8. package/dist/lib/agent-manager.d.ts +0 -8
  9. package/dist/lib/agent-manager.d.ts.map +1 -1
  10. package/dist/lib/agent-manager.js +10 -58
  11. package/dist/lib/agent-manager.js.map +1 -1
  12. package/dist/lib/apply-helpers.d.ts +29 -0
  13. package/dist/lib/apply-helpers.d.ts.map +1 -0
  14. package/dist/lib/apply-helpers.js +224 -0
  15. package/dist/lib/apply-helpers.js.map +1 -0
  16. package/dist/lib/block-manager.d.ts +6 -29
  17. package/dist/lib/block-manager.d.ts.map +1 -1
  18. package/dist/lib/block-manager.js +76 -218
  19. package/dist/lib/block-manager.js.map +1 -1
  20. package/dist/lib/diff-analyzers.d.ts +17 -0
  21. package/dist/lib/diff-analyzers.d.ts.map +1 -0
  22. package/dist/lib/diff-analyzers.js +172 -0
  23. package/dist/lib/diff-analyzers.js.map +1 -0
  24. package/dist/lib/diff-applier.d.ts +27 -0
  25. package/dist/lib/diff-applier.d.ts.map +1 -0
  26. package/dist/lib/diff-applier.js +196 -0
  27. package/dist/lib/diff-applier.js.map +1 -0
  28. package/dist/lib/diff-engine.d.ts +0 -19
  29. package/dist/lib/diff-engine.d.ts.map +1 -1
  30. package/dist/lib/diff-engine.js +8 -359
  31. package/dist/lib/diff-engine.js.map +1 -1
  32. package/dist/lib/letta-client.d.ts +5 -0
  33. package/dist/lib/letta-client.d.ts.map +1 -1
  34. package/dist/lib/letta-client.js +3 -0
  35. package/dist/lib/letta-client.js.map +1 -1
  36. package/dist/utils/hash-utils.d.ts +9 -0
  37. package/dist/utils/hash-utils.d.ts.map +1 -0
  38. package/dist/utils/hash-utils.js +54 -0
  39. package/dist/utils/hash-utils.js.map +1 -0
  40. package/package.json +1 -1
@@ -0,0 +1,196 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DiffApplier = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ /**
40
+ * DiffApplier applies update operations to agents
41
+ */
42
+ class DiffApplier {
43
+ constructor(client, basePath = '') {
44
+ this.client = client;
45
+ this.basePath = basePath;
46
+ }
47
+ /**
48
+ * Applies the update operations to the agent
49
+ */
50
+ async applyUpdateOperations(agentId, operations, verbose = false) {
51
+ if (operations.operationCount === 0) {
52
+ if (verbose)
53
+ console.log(' No changes needed');
54
+ return;
55
+ }
56
+ if (verbose)
57
+ console.log(` Applying ${operations.operationCount} updates (preserves conversation: ${operations.preservesConversation})`);
58
+ // Apply field updates
59
+ if (operations.updateFields) {
60
+ if (verbose)
61
+ console.log(' Updating agent fields...');
62
+ await this.client.updateAgent(agentId, operations.updateFields);
63
+ }
64
+ // Apply tool changes
65
+ if (operations.tools) {
66
+ for (const tool of operations.tools.toAdd) {
67
+ if (verbose)
68
+ console.log(` Attaching tool: ${tool.name}`);
69
+ await this.client.attachToolToAgent(agentId, tool.id);
70
+ }
71
+ for (const tool of operations.tools.toUpdate) {
72
+ if (verbose)
73
+ console.log(` Updating tool: ${tool.name} (${tool.reason})`);
74
+ // Detach old version and attach new version
75
+ await this.client.detachToolFromAgent(agentId, tool.currentId);
76
+ await this.client.attachToolToAgent(agentId, tool.newId);
77
+ }
78
+ for (const tool of operations.tools.toRemove) {
79
+ if (verbose)
80
+ console.log(` Detaching tool: ${tool.name}`);
81
+ await this.client.detachToolFromAgent(agentId, tool.id);
82
+ }
83
+ }
84
+ // Apply block changes
85
+ if (operations.blocks) {
86
+ for (const block of operations.blocks.toAdd) {
87
+ if (verbose)
88
+ console.log(` Attaching block: ${block.name}`);
89
+ await this.client.attachBlockToAgent(agentId, block.id);
90
+ }
91
+ for (const block of operations.blocks.toRemove) {
92
+ if (verbose)
93
+ console.log(` Detaching block: ${block.name}`);
94
+ await this.client.detachBlockFromAgent(agentId, block.id);
95
+ }
96
+ for (const block of operations.blocks.toUpdate) {
97
+ if (verbose)
98
+ console.log(` Updating block: ${block.name}`);
99
+ // First detach old, then attach new
100
+ await this.client.detachBlockFromAgent(agentId, block.currentId);
101
+ await this.client.attachBlockToAgent(agentId, block.newId);
102
+ }
103
+ }
104
+ // Apply folder changes
105
+ if (operations.folders) {
106
+ for (const folder of operations.folders.toAttach) {
107
+ if (verbose)
108
+ console.log(` Attaching folder: ${folder.name}`);
109
+ await this.client.attachFolderToAgent(agentId, folder.id);
110
+ }
111
+ for (const folder of operations.folders.toDetach) {
112
+ if (verbose)
113
+ console.log(` Detaching folder: ${folder.name}`);
114
+ await this.client.detachFolderFromAgent(agentId, folder.id);
115
+ }
116
+ for (const folder of operations.folders.toUpdate) {
117
+ if (verbose)
118
+ console.log(` Updating folder: ${folder.name}`);
119
+ // Add new files to the folder
120
+ for (const filePath of folder.filesToAdd) {
121
+ try {
122
+ if (verbose)
123
+ console.log(` Adding file: ${filePath}`);
124
+ await this.addFileToFolder(folder.id, filePath);
125
+ }
126
+ catch (error) {
127
+ console.error(` Failed to add file ${filePath}:`, error.message);
128
+ }
129
+ }
130
+ // Remove files from the folder
131
+ for (const fileName of folder.filesToRemove) {
132
+ try {
133
+ if (verbose)
134
+ console.log(` Removing file: ${fileName}`);
135
+ await this.removeFileFromFolder(folder.id, fileName);
136
+ }
137
+ catch (error) {
138
+ console.error(` Failed to remove file ${fileName}:`, error.message);
139
+ }
140
+ }
141
+ // Update existing files in the folder
142
+ for (const filePath of folder.filesToUpdate) {
143
+ try {
144
+ if (verbose)
145
+ console.log(` Updating file: ${filePath}`);
146
+ await this.updateFileInFolder(folder.id, filePath);
147
+ }
148
+ catch (error) {
149
+ console.error(` Failed to update file ${filePath}:`, error.message);
150
+ }
151
+ }
152
+ }
153
+ }
154
+ if (verbose)
155
+ console.log(' Updates completed successfully');
156
+ }
157
+ /**
158
+ * Helper method to add a file to an existing folder
159
+ */
160
+ async addFileToFolder(folderId, filePath) {
161
+ const fullPath = path.resolve(this.basePath, filePath);
162
+ const fileName = path.basename(filePath);
163
+ if (!fs.existsSync(fullPath)) {
164
+ throw new Error(`File not found: ${fullPath}`);
165
+ }
166
+ const fileStream = fs.createReadStream(fullPath);
167
+ await this.client.uploadFileToFolder(fileStream, folderId, fileName);
168
+ }
169
+ /**
170
+ * Helper method to remove a file from a folder
171
+ */
172
+ async removeFileFromFolder(folderId, fileName) {
173
+ // Get the file ID by name
174
+ const fileId = await this.client.getFileIdByName(folderId, fileName);
175
+ if (!fileId) {
176
+ throw new Error(`File not found in folder: ${fileName}`);
177
+ }
178
+ // Delete the file using the SDK
179
+ await this.client.deleteFileFromFolder(folderId, fileId);
180
+ }
181
+ /**
182
+ * Helper method to update an existing file in a folder
183
+ */
184
+ async updateFileInFolder(folderId, filePath) {
185
+ const fullPath = path.resolve(this.basePath, filePath);
186
+ const fileName = path.basename(filePath);
187
+ if (!fs.existsSync(fullPath)) {
188
+ throw new Error(`File not found: ${fullPath}`);
189
+ }
190
+ // For file updates, we re-upload the file
191
+ const fileStream = fs.createReadStream(fullPath);
192
+ await this.client.uploadFileToFolder(fileStream, folderId, fileName);
193
+ }
194
+ }
195
+ exports.DiffApplier = DiffApplier;
196
+ //# sourceMappingURL=diff-applier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-applier.js","sourceRoot":"","sources":["../../src/lib/diff-applier.ts"],"names":[],"mappings":"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"}
@@ -83,10 +83,6 @@ export declare class DiffEngine {
83
83
  private blockManager;
84
84
  private basePath;
85
85
  constructor(client: LettaClientWrapper, blockManager: BlockManager, basePath?: string);
86
- /**
87
- * Helper method to check if an item has file-based content that might have changed
88
- */
89
- private hasFileBasedContent;
90
86
  /**
91
87
  * Analyzes differences between existing and desired agent configuration
92
88
  * and generates specific update operations that preserve conversation history
@@ -111,24 +107,9 @@ export declare class DiffEngine {
111
107
  }>;
112
108
  sharedBlocks?: string[];
113
109
  }, toolRegistry: Map<string, string>, folderRegistry: Map<string, string>, verbose?: boolean, sharedBlockIds?: Map<string, string>): Promise<AgentUpdateOperations>;
114
- private analyzeToolChanges;
115
- private analyzeBlockChanges;
116
- private analyzeFolderChanges;
117
110
  /**
118
111
  * Applies the update operations to the agent
119
112
  */
120
113
  applyUpdateOperations(agentId: string, operations: AgentUpdateOperations, verbose?: boolean): Promise<void>;
121
- /**
122
- * Helper method to add a file to an existing folder
123
- */
124
- private addFileToFolder;
125
- /**
126
- * Helper method to remove a file from a folder
127
- */
128
- private removeFileFromFolder;
129
- /**
130
- * Helper method to update an existing file in a folder
131
- */
132
- private updateFileInFolder;
133
114
  }
134
115
  //# sourceMappingURL=diff-engine.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"diff-engine.d.ts","sourceRoot":"","sources":["../../src/lib/diff-engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"diff-engine.d.ts","sourceRoot":"","sources":["../../src/lib/diff-engine.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DiffEngine = void 0;
4
4
  const response_normalizer_1 = require("./response-normalizer");
5
+ const diff_applier_1 = require("./diff-applier");
6
+ const diff_analyzers_1 = require("./diff-analyzers");
5
7
  /**
6
8
  * DiffEngine determines what specific operations are needed to update an agent
7
9
  * while preserving conversation history whenever possible
@@ -12,12 +14,6 @@ class DiffEngine {
12
14
  this.blockManager = blockManager;
13
15
  this.basePath = basePath;
14
16
  }
15
- /**
16
- * Helper method to check if an item has file-based content that might have changed
17
- */
18
- hasFileBasedContent(itemName, fileHashes) {
19
- return !!fileHashes[itemName];
20
- }
21
17
  /**
22
18
  * Analyzes differences between existing and desired agent configuration
23
19
  * and generates specific update operations that preserve conversation history
@@ -71,373 +67,26 @@ class DiffEngine {
71
67
  operations.updateFields = fieldUpdates;
72
68
  }
73
69
  // Analyze tool changes
74
- operations.tools = await this.analyzeToolChanges(currentTools, desiredConfig.tools || [], toolRegistry, desiredConfig.toolSourceHashes || {});
70
+ operations.tools = await (0, diff_analyzers_1.analyzeToolChanges)(currentTools, desiredConfig.tools || [], toolRegistry, desiredConfig.toolSourceHashes || {});
75
71
  operations.operationCount += operations.tools.toAdd.length + operations.tools.toRemove.length + operations.tools.toUpdate.length;
76
72
  // Analyze memory block changes
77
- operations.blocks = await this.analyzeBlockChanges(currentBlocks, [
73
+ operations.blocks = await (0, diff_analyzers_1.analyzeBlockChanges)(currentBlocks, [
78
74
  ...(desiredConfig.memoryBlocks || []),
79
75
  ...(desiredConfig.sharedBlocks || []).map(name => ({ name, isShared: true }))
80
- ], desiredConfig.memoryBlockFileHashes || {}, existingAgent.name, sharedBlockIds);
76
+ ], this.blockManager, existingAgent.name);
81
77
  operations.operationCount += operations.blocks.toAdd.length + operations.blocks.toRemove.length + operations.blocks.toUpdate.length;
82
78
  // Analyze folder changes
83
- operations.folders = await this.analyzeFolderChanges(currentFolders, desiredConfig.folders || [], folderRegistry);
79
+ operations.folders = await (0, diff_analyzers_1.analyzeFolderChanges)(currentFolders, desiredConfig.folders || [], folderRegistry, this.client);
84
80
  operations.operationCount += operations.folders.toAttach.length + operations.folders.toDetach.length +
85
81
  operations.folders.toUpdate.reduce((sum, folder) => sum + folder.filesToAdd.length + folder.filesToRemove.length + folder.filesToUpdate.length, 0);
86
82
  return operations;
87
83
  }
88
- async analyzeToolChanges(currentTools, desiredToolNames, toolRegistry, toolSourceHashes = {}) {
89
- const currentToolNames = new Set(currentTools.map(t => t.name));
90
- const desiredToolSet = new Set(desiredToolNames);
91
- const toAdd = [];
92
- const toRemove = [];
93
- const toUpdate = [];
94
- const unchanged = [];
95
- // Find tools to add
96
- for (const toolName of desiredToolNames) {
97
- if (!currentToolNames.has(toolName)) {
98
- const toolId = toolRegistry.get(toolName);
99
- if (toolId) {
100
- toAdd.push({ name: toolName, id: toolId });
101
- }
102
- }
103
- }
104
- // Find tools to remove, update (source code changed), or leave unchanged
105
- for (const tool of currentTools) {
106
- if (desiredToolSet.has(tool.name)) {
107
- // Tool exists in both current and desired
108
- const toolName = tool.name;
109
- // Check if source code has changed for custom tools using the same pattern
110
- if (this.hasFileBasedContent(toolName, toolSourceHashes) && !['archival_memory_insert', 'archival_memory_search'].includes(toolName)) {
111
- // This tool has file-based source code, assume it might have changed and mark for update
112
- console.log(`Tool ${toolName} has file-based content, checking for updates...`);
113
- const currentToolId = tool.id;
114
- const newToolId = toolRegistry.get(toolName);
115
- if (newToolId && newToolId !== currentToolId) {
116
- // Tool was re-registered (source code actually changed)
117
- toUpdate.push({
118
- name: toolName,
119
- currentId: currentToolId,
120
- newId: newToolId,
121
- reason: 'source_code_changed'
122
- });
123
- }
124
- else {
125
- // Tool ID is same - fleet-parser already verified source hasn't changed
126
- unchanged.push({ name: toolName, id: currentToolId });
127
- }
128
- }
129
- else {
130
- unchanged.push({ name: tool.name, id: tool.id });
131
- }
132
- }
133
- else {
134
- // Tool exists in current but not desired - remove it
135
- toRemove.push({ name: tool.name, id: tool.id });
136
- }
137
- }
138
- return { toAdd, toRemove, toUpdate, unchanged };
139
- }
140
- async analyzeBlockChanges(currentBlocks, desiredBlocks, memoryBlockFileHashes = {}, agentName, sharedBlockIds) {
141
- // Extract base names from versioned labels (e.g., "brand_identity__v__20251210-550e4a42" -> "brand_identity")
142
- const extractBaseName = (label) => {
143
- const versionMatch = label.match(/^(.+?)(?:__v__.+)?$/);
144
- return versionMatch ? versionMatch[1] : label;
145
- };
146
- const currentBlockNames = new Set(currentBlocks.map(b => extractBaseName(b.label)));
147
- const desiredBlockNames = new Set(desiredBlocks.map(b => b.name));
148
- const toAdd = [];
149
- const toRemove = [];
150
- const toUpdate = [];
151
- const unchanged = [];
152
- // Find blocks to add
153
- for (const blockConfig of desiredBlocks) {
154
- if (!currentBlockNames.has(blockConfig.name)) {
155
- let blockId = blockConfig.isShared
156
- ? this.blockManager.getSharedBlockId(blockConfig.name)
157
- : this.blockManager.getAgentBlockId(blockConfig.name);
158
- // If block doesn't exist yet, create it
159
- if (!blockId && !blockConfig.isShared && blockConfig.description && agentName) {
160
- console.log(`Creating new memory block: ${blockConfig.name} for agent ${agentName}`);
161
- blockId = await this.blockManager.getOrCreateAgentBlock({
162
- name: blockConfig.name,
163
- description: blockConfig.description,
164
- limit: blockConfig.limit || 2000,
165
- value: blockConfig.value || ''
166
- }, agentName);
167
- }
168
- if (blockId) {
169
- toAdd.push({ name: blockConfig.name, id: blockId });
170
- }
171
- }
172
- }
173
- // Find blocks to remove, update (content changed), or unchanged
174
- for (const block of currentBlocks) {
175
- const baseName = extractBaseName(block.label);
176
- if (desiredBlockNames.has(baseName)) {
177
- // Block exists in both current and desired
178
- const blockName = baseName;
179
- // Check if this is a shared block with a new version
180
- const newSharedBlockId = sharedBlockIds?.get(blockName);
181
- if (newSharedBlockId && newSharedBlockId !== block.id) {
182
- console.log(`Shared block ${blockName} has new version, marking for update...`);
183
- toUpdate.push({ name: blockName, currentId: block.id, newId: newSharedBlockId });
184
- }
185
- // Check if content has changed by comparing with file hash (per-agent blocks)
186
- else if (this.hasFileBasedContent(blockName, memoryBlockFileHashes)) {
187
- // This block has file-based content, assume it might have changed and mark for update
188
- console.log(`Block ${blockName} has file-based content, checking for updates...`);
189
- // Create new block with updated content and mark for update
190
- const newBlockId = this.blockManager.getSharedBlockId(blockName); // Get updated block ID
191
- if (newBlockId && newBlockId !== block.id) {
192
- toUpdate.push({ name: blockName, currentId: block.id, newId: newBlockId });
193
- }
194
- else {
195
- // Content may have changed but block ID is same, still mark as update needed
196
- toUpdate.push({ name: blockName, currentId: block.id, newId: block.id });
197
- }
198
- }
199
- else {
200
- unchanged.push({ name: block.label, id: block.id });
201
- }
202
- }
203
- else {
204
- toRemove.push({ name: block.label, id: block.id });
205
- }
206
- }
207
- return { toAdd, toRemove, toUpdate, unchanged };
208
- }
209
- async analyzeFolderChanges(currentFolders, desiredFolders, folderRegistry) {
210
- const currentFolderNames = new Set(currentFolders.map(f => f.name));
211
- const desiredFolderNames = new Set(desiredFolders.map(f => f.name));
212
- const toAttach = [];
213
- const toDetach = [];
214
- const toUpdate = [];
215
- const unchanged = [];
216
- // Find folders to attach (new folders)
217
- for (const folderConfig of desiredFolders) {
218
- if (!currentFolderNames.has(folderConfig.name)) {
219
- const folderId = folderRegistry.get(folderConfig.name);
220
- if (folderId) {
221
- toAttach.push({ name: folderConfig.name, id: folderId });
222
- }
223
- }
224
- }
225
- // Find folders to detach, update, or leave unchanged
226
- for (const folder of currentFolders) {
227
- if (desiredFolderNames.has(folder.name)) {
228
- // Folder exists in both current and desired - check for file changes
229
- const desiredFolder = desiredFolders.find(f => f.name === folder.name);
230
- if (desiredFolder && desiredFolder.fileContentHashes) {
231
- // Get current files in this folder from server
232
- try {
233
- const currentFilesResponse = await this.client.listFolderFiles(folder.id);
234
- const currentFiles = (0, response_normalizer_1.normalizeResponse)(currentFilesResponse);
235
- const currentFileNames = new Set(currentFiles.map((f) => f.name || f.file_name || String(f)).filter(Boolean));
236
- const desiredFileNames = new Set(desiredFolder.files);
237
- const filesToAdd = [];
238
- const filesToRemove = [];
239
- const filesToUpdate = [];
240
- // Find files to add or update
241
- for (const filePath of desiredFolder.files) {
242
- const fileName = filePath.split('/').pop() || filePath; // Get just filename
243
- if (!currentFileNames.has(fileName)) {
244
- filesToAdd.push(filePath);
245
- }
246
- else {
247
- // File exists, check if content changed using the same pattern as memory blocks
248
- if (this.hasFileBasedContent(filePath, desiredFolder.fileContentHashes || {})) {
249
- console.log(`File ${filePath} has file-based content, checking for updates...`);
250
- filesToUpdate.push(filePath);
251
- }
252
- }
253
- }
254
- // Find files to remove
255
- for (const currentFile of currentFiles) {
256
- const fileName = currentFile.name || currentFile.file_name || String(currentFile);
257
- if (fileName && !desiredFileNames.has(fileName)) {
258
- filesToRemove.push(fileName);
259
- }
260
- }
261
- if (filesToAdd.length > 0 || filesToRemove.length > 0 || filesToUpdate.length > 0) {
262
- toUpdate.push({
263
- name: folder.name,
264
- id: folder.id,
265
- filesToAdd,
266
- filesToRemove,
267
- filesToUpdate
268
- });
269
- }
270
- else {
271
- unchanged.push({ name: folder.name, id: folder.id });
272
- }
273
- }
274
- catch (error) {
275
- console.warn(`Could not analyze files in folder ${folder.name}:`, error);
276
- unchanged.push({ name: folder.name, id: folder.id });
277
- }
278
- }
279
- else {
280
- unchanged.push({ name: folder.name, id: folder.id });
281
- }
282
- }
283
- else {
284
- // Folder exists in current but not desired - detach it
285
- toDetach.push({ name: folder.name, id: folder.id });
286
- }
287
- }
288
- return { toAttach, toDetach, toUpdate, unchanged };
289
- }
290
84
  /**
291
85
  * Applies the update operations to the agent
292
86
  */
293
87
  async applyUpdateOperations(agentId, operations, verbose = false) {
294
- if (operations.operationCount === 0) {
295
- if (verbose)
296
- console.log(' No changes needed');
297
- return;
298
- }
299
- if (verbose)
300
- console.log(` Applying ${operations.operationCount} updates (preserves conversation: ${operations.preservesConversation})`);
301
- // Apply field updates
302
- if (operations.updateFields) {
303
- if (verbose)
304
- console.log(' Updating agent fields...');
305
- await this.client.updateAgent(agentId, operations.updateFields);
306
- }
307
- // Apply tool changes
308
- if (operations.tools) {
309
- for (const tool of operations.tools.toAdd) {
310
- if (verbose)
311
- console.log(` Attaching tool: ${tool.name}`);
312
- await this.client.attachToolToAgent(agentId, tool.id);
313
- }
314
- for (const tool of operations.tools.toUpdate) {
315
- if (verbose)
316
- console.log(` Updating tool: ${tool.name} (${tool.reason})`);
317
- // Detach old version and attach new version
318
- await this.client.detachToolFromAgent(agentId, tool.currentId);
319
- await this.client.attachToolToAgent(agentId, tool.newId);
320
- }
321
- for (const tool of operations.tools.toRemove) {
322
- if (verbose)
323
- console.log(` Detaching tool: ${tool.name}`);
324
- await this.client.detachToolFromAgent(agentId, tool.id);
325
- }
326
- }
327
- // Apply block changes
328
- if (operations.blocks) {
329
- for (const block of operations.blocks.toAdd) {
330
- if (verbose)
331
- console.log(` Attaching block: ${block.name}`);
332
- await this.client.attachBlockToAgent(agentId, block.id);
333
- }
334
- for (const block of operations.blocks.toRemove) {
335
- if (verbose)
336
- console.log(` Detaching block: ${block.name}`);
337
- await this.client.detachBlockFromAgent(agentId, block.id);
338
- }
339
- for (const block of operations.blocks.toUpdate) {
340
- if (verbose)
341
- console.log(` Updating block: ${block.name}`);
342
- // First detach old, then attach new
343
- await this.client.detachBlockFromAgent(agentId, block.currentId);
344
- await this.client.attachBlockToAgent(agentId, block.newId);
345
- }
346
- }
347
- // Apply folder changes
348
- if (operations.folders) {
349
- for (const folder of operations.folders.toAttach) {
350
- if (verbose)
351
- console.log(` Attaching folder: ${folder.name}`);
352
- await this.client.attachFolderToAgent(agentId, folder.id);
353
- }
354
- for (const folder of operations.folders.toDetach) {
355
- if (verbose)
356
- console.log(` Detaching folder: ${folder.name}`);
357
- await this.client.detachFolderFromAgent(agentId, folder.id);
358
- }
359
- for (const folder of operations.folders.toUpdate) {
360
- if (verbose)
361
- console.log(` Updating folder: ${folder.name}`);
362
- // Add new files to the folder
363
- for (const filePath of folder.filesToAdd) {
364
- try {
365
- if (verbose)
366
- console.log(` Adding file: ${filePath}`);
367
- await this.addFileToFolder(folder.id, filePath);
368
- }
369
- catch (error) {
370
- console.error(` Failed to add file ${filePath}:`, error.message);
371
- }
372
- }
373
- // Remove files from the folder
374
- for (const fileName of folder.filesToRemove) {
375
- try {
376
- if (verbose)
377
- console.log(` Removing file: ${fileName}`);
378
- await this.removeFileFromFolder(folder.id, fileName);
379
- }
380
- catch (error) {
381
- console.error(` Failed to remove file ${fileName}:`, error.message);
382
- }
383
- }
384
- // Update existing files in the folder
385
- for (const filePath of folder.filesToUpdate) {
386
- try {
387
- if (verbose)
388
- console.log(` Updating file: ${filePath}`);
389
- await this.updateFileInFolder(folder.id, filePath);
390
- }
391
- catch (error) {
392
- console.error(` Failed to update file ${filePath}:`, error.message);
393
- }
394
- }
395
- }
396
- }
397
- if (verbose)
398
- console.log(' Updates completed successfully');
399
- }
400
- /**
401
- * Helper method to add a file to an existing folder
402
- */
403
- async addFileToFolder(folderId, filePath) {
404
- const fs = require('fs');
405
- const path = require('path');
406
- const fullPath = path.resolve(this.basePath, filePath);
407
- const fileName = path.basename(filePath);
408
- if (!fs.existsSync(fullPath)) {
409
- throw new Error(`File not found: ${fullPath}`);
410
- }
411
- const fileStream = fs.createReadStream(fullPath);
412
- await this.client.uploadFileToFolder(fileStream, folderId, fileName);
413
- }
414
- /**
415
- * Helper method to remove a file from a folder
416
- */
417
- async removeFileFromFolder(folderId, fileName) {
418
- // Get the file ID by name
419
- const fileId = await this.client.getFileIdByName(folderId, fileName);
420
- if (!fileId) {
421
- throw new Error(`File not found in folder: ${fileName}`);
422
- }
423
- // Delete the file using the SDK
424
- await this.client.deleteFileFromFolder(folderId, fileId);
425
- }
426
- /**
427
- * Helper method to update an existing file in a folder
428
- */
429
- async updateFileInFolder(folderId, filePath) {
430
- const fs = require('fs');
431
- const path = require('path');
432
- const fullPath = path.resolve(this.basePath, filePath);
433
- const fileName = path.basename(filePath);
434
- if (!fs.existsSync(fullPath)) {
435
- throw new Error(`File not found: ${fullPath}`);
436
- }
437
- // For file updates, we re-upload the file
438
- // This may overwrite the existing file or create a duplicate
439
- const fileStream = fs.createReadStream(fullPath);
440
- await this.client.uploadFileToFolder(fileStream, folderId, fileName);
88
+ const applier = new diff_applier_1.DiffApplier(this.client, this.basePath);
89
+ return applier.applyUpdateOperations(agentId, operations, verbose);
441
90
  }
442
91
  }
443
92
  exports.DiffEngine = DiffEngine;