@letta-ai/letta-code 0.11.2-next.2 → 0.11.2-next.4
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/letta.js +7059 -6390
- package/package.json +1 -1
- package/skills/acquiring-skills/SKILL.md +126 -0
- package/skills/creating-skills/SKILL.md +3 -3
- package/skills/finding-agents/SKILL.md +9 -9
- package/skills/migrating-memory/SKILL.md +34 -11
- package/skills/migrating-memory/scripts/attach-block.ts +91 -22
- package/skills/migrating-memory/scripts/copy-block.ts +107 -19
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
* It reads agent ID from LETTA_AGENT_ID env var or --agent-id arg.
|
|
8
8
|
*
|
|
9
9
|
* Usage:
|
|
10
|
-
* npx tsx copy-block.ts --block-id <block-id> [--label <new-label>] [--agent-id <agent-id>]
|
|
10
|
+
* npx tsx copy-block.ts --block-id <block-id> [--label <new-label>] [--agent-id <agent-id>] [--override]
|
|
11
11
|
*
|
|
12
12
|
* Options:
|
|
13
|
-
* --label Override the block label (
|
|
13
|
+
* --label Override the block label (useful to avoid duplicate label errors)
|
|
14
14
|
* --agent-id Target agent ID (overrides LETTA_AGENT_ID env var)
|
|
15
|
+
* --override If you already have a block with the same label, detach it first
|
|
16
|
+
* (on error, the original block is reattached)
|
|
15
17
|
*
|
|
16
18
|
* This creates a new block with the same content as the source block,
|
|
17
19
|
* then attaches it to the current agent. Changes to the new block
|
|
@@ -37,6 +39,7 @@ interface CopyBlockResult {
|
|
|
37
39
|
sourceBlock: Awaited<ReturnType<LettaClient["blocks"]["retrieve"]>>;
|
|
38
40
|
newBlock: Awaited<ReturnType<LettaClient["blocks"]["create"]>>;
|
|
39
41
|
attachResult: Awaited<ReturnType<LettaClient["agents"]["blocks"]["attach"]>>;
|
|
42
|
+
detachedBlock?: Awaited<ReturnType<LettaClient["blocks"]["retrieve"]>>;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
/**
|
|
@@ -86,44 +89,125 @@ function createClient(): LettaClient {
|
|
|
86
89
|
* Copy a block's content to a new block and attach to the current agent
|
|
87
90
|
* @param client - Letta client instance
|
|
88
91
|
* @param blockId - The source block ID to copy from
|
|
89
|
-
* @param options - Optional settings: labelOverride, targetAgentId
|
|
92
|
+
* @param options - Optional settings: labelOverride, targetAgentId, override
|
|
90
93
|
* @returns Object containing source block, new block, and attach result
|
|
91
94
|
*/
|
|
92
95
|
export async function copyBlock(
|
|
93
96
|
client: LettaClient,
|
|
94
97
|
blockId: string,
|
|
95
|
-
options?: {
|
|
98
|
+
options?: {
|
|
99
|
+
labelOverride?: string;
|
|
100
|
+
targetAgentId?: string;
|
|
101
|
+
override?: boolean;
|
|
102
|
+
},
|
|
96
103
|
): Promise<CopyBlockResult> {
|
|
97
|
-
// Get current agent ID (the agent calling this script) or use provided ID
|
|
98
104
|
const currentAgentId = getAgentId(options?.targetAgentId);
|
|
105
|
+
let detachedBlock:
|
|
106
|
+
| Awaited<ReturnType<LettaClient["blocks"]["retrieve"]>>
|
|
107
|
+
| undefined;
|
|
99
108
|
|
|
100
109
|
// 1. Get source block details
|
|
101
110
|
const sourceBlock = await client.blocks.retrieve(blockId);
|
|
111
|
+
const targetLabel =
|
|
112
|
+
options?.labelOverride || sourceBlock.label || "migrated-block";
|
|
102
113
|
|
|
103
|
-
// 2.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
114
|
+
// 2. If override is requested, check for existing block with same label and detach it
|
|
115
|
+
if (options?.override) {
|
|
116
|
+
const currentBlocksResponse =
|
|
117
|
+
await client.agents.blocks.list(currentAgentId);
|
|
118
|
+
// The response may be paginated or an array depending on SDK version
|
|
119
|
+
const currentBlocks = Array.isArray(currentBlocksResponse)
|
|
120
|
+
? currentBlocksResponse
|
|
121
|
+
: (currentBlocksResponse as { items?: unknown[] }).items || [];
|
|
122
|
+
const conflictingBlock = currentBlocks.find(
|
|
123
|
+
(b: { label?: string }) => b.label === targetLabel,
|
|
124
|
+
);
|
|
110
125
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
126
|
+
if (conflictingBlock) {
|
|
127
|
+
console.error(
|
|
128
|
+
`Detaching existing block with label "${targetLabel}" (${conflictingBlock.id})...`,
|
|
129
|
+
);
|
|
130
|
+
detachedBlock = conflictingBlock;
|
|
131
|
+
try {
|
|
132
|
+
await client.agents.blocks.detach(conflictingBlock.id, {
|
|
133
|
+
agent_id: currentAgentId,
|
|
134
|
+
});
|
|
135
|
+
} catch (detachError) {
|
|
136
|
+
throw new Error(
|
|
137
|
+
`Failed to detach existing block "${targetLabel}": ${detachError instanceof Error ? detachError.message : String(detachError)}`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
115
142
|
|
|
116
|
-
|
|
143
|
+
// 3. Create new block with same content
|
|
144
|
+
let newBlock: Awaited<ReturnType<LettaClient["blocks"]["create"]>>;
|
|
145
|
+
try {
|
|
146
|
+
newBlock = await client.blocks.create({
|
|
147
|
+
label: targetLabel,
|
|
148
|
+
value: sourceBlock.value,
|
|
149
|
+
description: sourceBlock.description || undefined,
|
|
150
|
+
limit: sourceBlock.limit,
|
|
151
|
+
});
|
|
152
|
+
} catch (createError) {
|
|
153
|
+
// If create failed and we detached a block, try to reattach it
|
|
154
|
+
if (detachedBlock) {
|
|
155
|
+
console.error(
|
|
156
|
+
`Create failed, reattaching original block "${detachedBlock.label}"...`,
|
|
157
|
+
);
|
|
158
|
+
try {
|
|
159
|
+
await client.agents.blocks.attach(detachedBlock.id, {
|
|
160
|
+
agent_id: currentAgentId,
|
|
161
|
+
});
|
|
162
|
+
console.error("Original block reattached successfully.");
|
|
163
|
+
} catch {
|
|
164
|
+
console.error(
|
|
165
|
+
`WARNING: Failed to reattach original block! Block ID: ${detachedBlock.id}`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
throw createError;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 4. Attach new block to current agent
|
|
173
|
+
let attachResult: Awaited<ReturnType<typeof client.agents.blocks.attach>>;
|
|
174
|
+
try {
|
|
175
|
+
attachResult = await client.agents.blocks.attach(newBlock.id, {
|
|
176
|
+
agent_id: currentAgentId,
|
|
177
|
+
});
|
|
178
|
+
} catch (attachError) {
|
|
179
|
+
// If attach failed and we detached a block, try to reattach it
|
|
180
|
+
if (detachedBlock) {
|
|
181
|
+
console.error(
|
|
182
|
+
`Attach failed, reattaching original block "${detachedBlock.label}"...`,
|
|
183
|
+
);
|
|
184
|
+
try {
|
|
185
|
+
await client.agents.blocks.attach(detachedBlock.id, {
|
|
186
|
+
agent_id: currentAgentId,
|
|
187
|
+
});
|
|
188
|
+
console.error("Original block reattached successfully.");
|
|
189
|
+
} catch {
|
|
190
|
+
console.error(
|
|
191
|
+
`WARNING: Failed to reattach original block! Block ID: ${detachedBlock.id}`,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
throw attachError;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return { sourceBlock, newBlock, attachResult, detachedBlock };
|
|
117
199
|
}
|
|
118
200
|
|
|
119
201
|
function parseArgs(args: string[]): {
|
|
120
202
|
blockId: string;
|
|
121
203
|
label?: string;
|
|
122
204
|
agentId?: string;
|
|
205
|
+
override: boolean;
|
|
123
206
|
} {
|
|
124
207
|
const blockIdIndex = args.indexOf("--block-id");
|
|
125
208
|
const labelIndex = args.indexOf("--label");
|
|
126
209
|
const agentIdIndex = args.indexOf("--agent-id");
|
|
210
|
+
const override = args.includes("--override");
|
|
127
211
|
|
|
128
212
|
if (blockIdIndex === -1 || blockIdIndex + 1 >= args.length) {
|
|
129
213
|
throw new Error("Missing required argument: --block-id <block-id>");
|
|
@@ -139,6 +223,7 @@ function parseArgs(args: string[]): {
|
|
|
139
223
|
agentIdIndex !== -1 && agentIdIndex + 1 < args.length
|
|
140
224
|
? (args[agentIdIndex + 1] as string)
|
|
141
225
|
: undefined,
|
|
226
|
+
override,
|
|
142
227
|
};
|
|
143
228
|
}
|
|
144
229
|
|
|
@@ -147,11 +232,14 @@ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
|
147
232
|
if (isMainModule) {
|
|
148
233
|
(async () => {
|
|
149
234
|
try {
|
|
150
|
-
const { blockId, label, agentId } = parseArgs(
|
|
235
|
+
const { blockId, label, agentId, override } = parseArgs(
|
|
236
|
+
process.argv.slice(2),
|
|
237
|
+
);
|
|
151
238
|
const client = createClient();
|
|
152
239
|
const result = await copyBlock(client, blockId, {
|
|
153
240
|
labelOverride: label,
|
|
154
241
|
targetAgentId: agentId,
|
|
242
|
+
override,
|
|
155
243
|
});
|
|
156
244
|
console.log(JSON.stringify(result, null, 2));
|
|
157
245
|
} catch (error) {
|
|
@@ -164,7 +252,7 @@ if (isMainModule) {
|
|
|
164
252
|
error.message.includes("Missing required argument")
|
|
165
253
|
) {
|
|
166
254
|
console.error(
|
|
167
|
-
"\nUsage: npx tsx copy-block.ts --block-id <block-id> [--label <new-label>] [--agent-id <agent-id>]",
|
|
255
|
+
"\nUsage: npx tsx copy-block.ts --block-id <block-id> [--label <new-label>] [--agent-id <agent-id>] [--override]",
|
|
168
256
|
);
|
|
169
257
|
}
|
|
170
258
|
process.exit(1);
|