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.
- package/dist/commands/apply-template.d.ts +12 -0
- package/dist/commands/apply-template.d.ts.map +1 -0
- package/dist/commands/apply-template.js +118 -0
- package/dist/commands/apply-template.js.map +1 -0
- package/dist/commands/apply.d.ts.map +1 -1
- package/dist/commands/apply.js +42 -358
- package/dist/commands/apply.js.map +1 -1
- package/dist/lib/agent-manager.d.ts +0 -8
- package/dist/lib/agent-manager.d.ts.map +1 -1
- package/dist/lib/agent-manager.js +10 -58
- package/dist/lib/agent-manager.js.map +1 -1
- package/dist/lib/apply-helpers.d.ts +29 -0
- package/dist/lib/apply-helpers.d.ts.map +1 -0
- package/dist/lib/apply-helpers.js +224 -0
- package/dist/lib/apply-helpers.js.map +1 -0
- package/dist/lib/block-manager.d.ts +6 -29
- package/dist/lib/block-manager.d.ts.map +1 -1
- package/dist/lib/block-manager.js +76 -218
- package/dist/lib/block-manager.js.map +1 -1
- package/dist/lib/diff-analyzers.d.ts +17 -0
- package/dist/lib/diff-analyzers.d.ts.map +1 -0
- package/dist/lib/diff-analyzers.js +172 -0
- package/dist/lib/diff-analyzers.js.map +1 -0
- package/dist/lib/diff-applier.d.ts +27 -0
- package/dist/lib/diff-applier.d.ts.map +1 -0
- package/dist/lib/diff-applier.js +196 -0
- package/dist/lib/diff-applier.js.map +1 -0
- package/dist/lib/diff-engine.d.ts +0 -19
- package/dist/lib/diff-engine.d.ts.map +1 -1
- package/dist/lib/diff-engine.js +8 -359
- package/dist/lib/diff-engine.js.map +1 -1
- package/dist/lib/letta-client.d.ts +5 -0
- package/dist/lib/letta-client.d.ts.map +1 -1
- package/dist/lib/letta-client.js +3 -0
- package/dist/lib/letta-client.js.map +1 -1
- package/dist/utils/hash-utils.d.ts +9 -0
- package/dist/utils/hash-utils.d.ts.map +1 -0
- package/dist/utils/hash-utils.js +54 -0
- package/dist/utils/hash-utils.js.map +1 -0
- 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":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"diff-engine.d.ts","sourceRoot":"","sources":["../../src/lib/diff-engine.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/diff-engine.js
CHANGED
|
@@ -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
|
|
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
|
|
73
|
+
operations.blocks = await (0, diff_analyzers_1.analyzeBlockChanges)(currentBlocks, [
|
|
78
74
|
...(desiredConfig.memoryBlocks || []),
|
|
79
75
|
...(desiredConfig.sharedBlocks || []).map(name => ({ name, isShared: true }))
|
|
80
|
-
],
|
|
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
|
|
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
|
-
|
|
295
|
-
|
|
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;
|