@letta-ai/letta-code 0.14.3 → 0.14.5
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 +10772 -9218
- package/package.json +2 -2
- package/skills/defragmenting-memory/SKILL.md +4 -5
- package/skills/finding-agents/SKILL.md +12 -12
- package/skills/messaging-agents/SKILL.md +19 -19
- package/skills/migrating-memory/SKILL.md +47 -81
- package/skills/searching-messages/SKILL.md +14 -16
- package/skills/syncing-memory-filesystem/SKILL.md +27 -46
- package/skills/finding-agents/scripts/find-agents.ts +0 -177
- package/skills/messaging-agents/scripts/continue-conversation.ts +0 -226
- package/skills/messaging-agents/scripts/start-conversation.ts +0 -229
- package/skills/migrating-memory/scripts/attach-block.ts +0 -230
- package/skills/migrating-memory/scripts/copy-block.ts +0 -261
- package/skills/migrating-memory/scripts/get-agent-blocks.ts +0 -103
- package/skills/searching-messages/scripts/get-messages.ts +0 -230
- package/skills/searching-messages/scripts/search-messages.ts +0 -200
- package/skills/syncing-memory-filesystem/scripts/memfs-diff.ts +0 -361
- package/skills/syncing-memory-filesystem/scripts/memfs-resolve.ts +0 -412
- package/skills/syncing-memory-filesystem/scripts/memfs-status.ts +0 -354
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env npx tsx
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Get Messages - Retrieve messages from an agent in chronological order
|
|
5
|
-
*
|
|
6
|
-
* This script is standalone and can be run outside the CLI process.
|
|
7
|
-
* It reads auth from LETTA_API_KEY env var or ~/.letta/settings.json.
|
|
8
|
-
* It reads agent ID from LETTA_AGENT_ID env var or --agent-id arg.
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* npx tsx get-messages.ts [options]
|
|
12
|
-
*
|
|
13
|
-
* Options:
|
|
14
|
-
* --start-date <date> Filter messages after this date (ISO format)
|
|
15
|
-
* --end-date <date> Filter messages before this date (ISO format)
|
|
16
|
-
* --limit <n> Max results (default: 20)
|
|
17
|
-
* --agent-id <id> Explicit agent ID (overrides LETTA_AGENT_ID env var)
|
|
18
|
-
* --after <message-id> Cursor: get messages after this ID
|
|
19
|
-
* --before <message-id> Cursor: get messages before this ID
|
|
20
|
-
* --order <asc|desc> Sort order (default: desc = newest first)
|
|
21
|
-
*
|
|
22
|
-
* Use this after search-messages.ts to expand around a found needle.
|
|
23
|
-
*
|
|
24
|
-
* Output:
|
|
25
|
-
* Messages in chronological order (filtered by date if specified)
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
import { readFileSync } from "node:fs";
|
|
29
|
-
import { createRequire } from "node:module";
|
|
30
|
-
import { homedir } from "node:os";
|
|
31
|
-
import { join } from "node:path";
|
|
32
|
-
|
|
33
|
-
// Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
|
|
34
|
-
// (ES module imports don't respect NODE_PATH, but require does)
|
|
35
|
-
const require = createRequire(import.meta.url);
|
|
36
|
-
const Letta = require("@letta-ai/letta-client")
|
|
37
|
-
.default as typeof import("@letta-ai/letta-client").default;
|
|
38
|
-
type LettaClient = InstanceType<typeof Letta>;
|
|
39
|
-
|
|
40
|
-
interface GetMessagesOptions {
|
|
41
|
-
startDate?: string;
|
|
42
|
-
endDate?: string;
|
|
43
|
-
limit?: number;
|
|
44
|
-
agentId?: string;
|
|
45
|
-
after?: string;
|
|
46
|
-
before?: string;
|
|
47
|
-
order?: "asc" | "desc";
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Get API key from env var or settings file
|
|
52
|
-
*/
|
|
53
|
-
function getApiKey(): string {
|
|
54
|
-
// First check env var (set by CLI's getShellEnv)
|
|
55
|
-
if (process.env.LETTA_API_KEY) {
|
|
56
|
-
return process.env.LETTA_API_KEY;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Fall back to settings file
|
|
60
|
-
const settingsPath = join(homedir(), ".letta", "settings.json");
|
|
61
|
-
try {
|
|
62
|
-
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
63
|
-
if (settings.env?.LETTA_API_KEY) {
|
|
64
|
-
return settings.env.LETTA_API_KEY;
|
|
65
|
-
}
|
|
66
|
-
} catch {
|
|
67
|
-
// Settings file doesn't exist or is invalid
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
throw new Error(
|
|
71
|
-
"No LETTA_API_KEY found. Set the env var or run the Letta CLI to authenticate.",
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Get agent ID from CLI arg, env var, or throw
|
|
77
|
-
*/
|
|
78
|
-
function getAgentId(cliArg?: string): string {
|
|
79
|
-
// CLI arg takes precedence
|
|
80
|
-
if (cliArg) return cliArg;
|
|
81
|
-
|
|
82
|
-
// Then env var (set by CLI's getShellEnv)
|
|
83
|
-
if (process.env.LETTA_AGENT_ID) {
|
|
84
|
-
return process.env.LETTA_AGENT_ID;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
throw new Error(
|
|
88
|
-
"No agent ID provided. Use --agent-id or ensure LETTA_AGENT_ID env var is set.",
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Create a Letta client with auth from env/settings
|
|
94
|
-
*/
|
|
95
|
-
function createClient(): LettaClient {
|
|
96
|
-
return new Letta({ apiKey: getApiKey() });
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Get messages from an agent, optionally filtered by date range
|
|
101
|
-
* @param client - Letta client instance
|
|
102
|
-
* @param options - Options for filtering
|
|
103
|
-
* @returns Array of messages in chronological order
|
|
104
|
-
*/
|
|
105
|
-
export async function getMessages(
|
|
106
|
-
client: LettaClient,
|
|
107
|
-
options: GetMessagesOptions = {},
|
|
108
|
-
): Promise<unknown[]> {
|
|
109
|
-
const agentId = getAgentId(options.agentId);
|
|
110
|
-
const limit = options.limit ?? 20;
|
|
111
|
-
|
|
112
|
-
// Fetch messages from the agent
|
|
113
|
-
const response = await client.agents.messages.list(agentId, {
|
|
114
|
-
limit,
|
|
115
|
-
after: options.after,
|
|
116
|
-
before: options.before,
|
|
117
|
-
order: options.order,
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
const messages = response.items ?? [];
|
|
121
|
-
|
|
122
|
-
// Client-side date filtering if specified
|
|
123
|
-
if (options.startDate || options.endDate) {
|
|
124
|
-
const startTime = options.startDate
|
|
125
|
-
? new Date(options.startDate).getTime()
|
|
126
|
-
: 0;
|
|
127
|
-
const endTime = options.endDate
|
|
128
|
-
? new Date(options.endDate).getTime()
|
|
129
|
-
: Number.POSITIVE_INFINITY;
|
|
130
|
-
|
|
131
|
-
const filtered = messages.filter((msg) => {
|
|
132
|
-
// Messages use 'date' field, not 'created_at'
|
|
133
|
-
if (!("date" in msg) || !msg.date) return true;
|
|
134
|
-
const msgTime = new Date(msg.date).getTime();
|
|
135
|
-
return msgTime >= startTime && msgTime <= endTime;
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// Sort chronologically (oldest first)
|
|
139
|
-
return filtered.sort((a, b) => {
|
|
140
|
-
const aDate = "date" in a && a.date ? new Date(a.date).getTime() : 0;
|
|
141
|
-
const bDate = "date" in b && b.date ? new Date(b.date).getTime() : 0;
|
|
142
|
-
return aDate - bDate;
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Sort chronologically (oldest first)
|
|
147
|
-
return [...messages].sort((a, b) => {
|
|
148
|
-
const aDate = "date" in a && a.date ? new Date(a.date).getTime() : 0;
|
|
149
|
-
const bDate = "date" in b && b.date ? new Date(b.date).getTime() : 0;
|
|
150
|
-
return aDate - bDate;
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function parseArgs(args: string[]): GetMessagesOptions {
|
|
155
|
-
const options: GetMessagesOptions = {};
|
|
156
|
-
|
|
157
|
-
const startDateIndex = args.indexOf("--start-date");
|
|
158
|
-
if (startDateIndex !== -1 && startDateIndex + 1 < args.length) {
|
|
159
|
-
options.startDate = args[startDateIndex + 1];
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const endDateIndex = args.indexOf("--end-date");
|
|
163
|
-
if (endDateIndex !== -1 && endDateIndex + 1 < args.length) {
|
|
164
|
-
options.endDate = args[endDateIndex + 1];
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const limitIndex = args.indexOf("--limit");
|
|
168
|
-
if (limitIndex !== -1 && limitIndex + 1 < args.length) {
|
|
169
|
-
const limit = Number.parseInt(args[limitIndex + 1] as string, 10);
|
|
170
|
-
if (!Number.isNaN(limit)) {
|
|
171
|
-
options.limit = limit;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const agentIdIndex = args.indexOf("--agent-id");
|
|
176
|
-
if (agentIdIndex !== -1 && agentIdIndex + 1 < args.length) {
|
|
177
|
-
options.agentId = args[agentIdIndex + 1];
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const afterIndex = args.indexOf("--after");
|
|
181
|
-
if (afterIndex !== -1 && afterIndex + 1 < args.length) {
|
|
182
|
-
options.after = args[afterIndex + 1];
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const beforeIndex = args.indexOf("--before");
|
|
186
|
-
if (beforeIndex !== -1 && beforeIndex + 1 < args.length) {
|
|
187
|
-
options.before = args[beforeIndex + 1];
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const orderIndex = args.indexOf("--order");
|
|
191
|
-
if (orderIndex !== -1 && orderIndex + 1 < args.length) {
|
|
192
|
-
const order = args[orderIndex + 1] as string;
|
|
193
|
-
if (order === "asc" || order === "desc") {
|
|
194
|
-
options.order = order;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return options;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// CLI entry point - check if this file is being run directly
|
|
202
|
-
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
203
|
-
if (isMainModule) {
|
|
204
|
-
(async () => {
|
|
205
|
-
try {
|
|
206
|
-
const options = parseArgs(process.argv.slice(2));
|
|
207
|
-
const client = createClient();
|
|
208
|
-
const result = await getMessages(client, options);
|
|
209
|
-
console.log(JSON.stringify(result, null, 2));
|
|
210
|
-
} catch (error) {
|
|
211
|
-
console.error(
|
|
212
|
-
"Error:",
|
|
213
|
-
error instanceof Error ? error.message : String(error),
|
|
214
|
-
);
|
|
215
|
-
console.error(`
|
|
216
|
-
Usage: npx tsx get-messages.ts [options]
|
|
217
|
-
|
|
218
|
-
Options:
|
|
219
|
-
--after <message-id> Cursor: get messages after this ID
|
|
220
|
-
--before <message-id> Cursor: get messages before this ID
|
|
221
|
-
--order <asc|desc> Sort order (default: desc = newest first)
|
|
222
|
-
--limit <n> Max results (default: 20)
|
|
223
|
-
--agent-id <id> Explicit agent ID (overrides LETTA_AGENT_ID env var)
|
|
224
|
-
--start-date <date> Client-side filter: after this date (ISO format)
|
|
225
|
-
--end-date <date> Client-side filter: before this date (ISO format)
|
|
226
|
-
`);
|
|
227
|
-
process.exit(1);
|
|
228
|
-
}
|
|
229
|
-
})();
|
|
230
|
-
}
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env npx tsx
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Search Messages - Search past conversations with vector/FTS search
|
|
5
|
-
*
|
|
6
|
-
* This script is standalone and can be run outside the CLI process.
|
|
7
|
-
* It reads auth from LETTA_API_KEY env var or ~/.letta/settings.json.
|
|
8
|
-
* It reads agent ID from LETTA_AGENT_ID env var or --agent-id arg.
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* npx tsx search-messages.ts --query <text> [options]
|
|
12
|
-
*
|
|
13
|
-
* Options:
|
|
14
|
-
* --query <text> Search query (required)
|
|
15
|
-
* --mode <mode> Search mode: vector, fts, hybrid (default: hybrid)
|
|
16
|
-
* --start-date <date> Filter messages after this date (ISO format)
|
|
17
|
-
* --end-date <date> Filter messages before this date (ISO format)
|
|
18
|
-
* --limit <n> Max results (default: 10)
|
|
19
|
-
* --all-agents Search all agents, not just current agent
|
|
20
|
-
* --agent-id <id> Explicit agent ID (overrides LETTA_AGENT_ID env var)
|
|
21
|
-
*
|
|
22
|
-
* Output:
|
|
23
|
-
* Raw API response with search results
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
import { readFileSync } from "node:fs";
|
|
27
|
-
import { createRequire } from "node:module";
|
|
28
|
-
import { homedir } from "node:os";
|
|
29
|
-
import { join } from "node:path";
|
|
30
|
-
|
|
31
|
-
// Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
|
|
32
|
-
// (ES module imports don't respect NODE_PATH, but require does)
|
|
33
|
-
const require = createRequire(import.meta.url);
|
|
34
|
-
const Letta = require("@letta-ai/letta-client")
|
|
35
|
-
.default as typeof import("@letta-ai/letta-client").default;
|
|
36
|
-
type LettaClient = InstanceType<typeof Letta>;
|
|
37
|
-
|
|
38
|
-
interface SearchMessagesOptions {
|
|
39
|
-
query: string;
|
|
40
|
-
mode?: "vector" | "fts" | "hybrid";
|
|
41
|
-
startDate?: string;
|
|
42
|
-
endDate?: string;
|
|
43
|
-
limit?: number;
|
|
44
|
-
allAgents?: boolean;
|
|
45
|
-
agentId?: string;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Get API key from env var or settings file
|
|
50
|
-
*/
|
|
51
|
-
function getApiKey(): string {
|
|
52
|
-
// First check env var (set by CLI's getShellEnv)
|
|
53
|
-
if (process.env.LETTA_API_KEY) {
|
|
54
|
-
return process.env.LETTA_API_KEY;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Fall back to settings file
|
|
58
|
-
const settingsPath = join(homedir(), ".letta", "settings.json");
|
|
59
|
-
try {
|
|
60
|
-
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
61
|
-
if (settings.env?.LETTA_API_KEY) {
|
|
62
|
-
return settings.env.LETTA_API_KEY;
|
|
63
|
-
}
|
|
64
|
-
} catch {
|
|
65
|
-
// Settings file doesn't exist or is invalid
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
throw new Error(
|
|
69
|
-
"No LETTA_API_KEY found. Set the env var or run the Letta CLI to authenticate.",
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Get agent ID from CLI arg, env var, or throw
|
|
75
|
-
*/
|
|
76
|
-
function getAgentId(cliArg?: string): string {
|
|
77
|
-
// CLI arg takes precedence
|
|
78
|
-
if (cliArg) return cliArg;
|
|
79
|
-
|
|
80
|
-
// Then env var (set by CLI's getShellEnv)
|
|
81
|
-
if (process.env.LETTA_AGENT_ID) {
|
|
82
|
-
return process.env.LETTA_AGENT_ID;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
throw new Error(
|
|
86
|
-
"No agent ID provided. Use --agent-id or ensure LETTA_AGENT_ID env var is set.",
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Create a Letta client with auth from env/settings
|
|
92
|
-
*/
|
|
93
|
-
function createClient(): LettaClient {
|
|
94
|
-
return new Letta({ apiKey: getApiKey() });
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Search messages in past conversations
|
|
99
|
-
* @param client - Letta client instance
|
|
100
|
-
* @param options - Search options
|
|
101
|
-
* @returns Array of search results with scores
|
|
102
|
-
*/
|
|
103
|
-
export async function searchMessages(
|
|
104
|
-
client: LettaClient,
|
|
105
|
-
options: SearchMessagesOptions,
|
|
106
|
-
): Promise<Awaited<ReturnType<typeof client.messages.search>>> {
|
|
107
|
-
// Default to current agent unless --all-agents is specified
|
|
108
|
-
let agentId: string | undefined;
|
|
109
|
-
if (!options.allAgents) {
|
|
110
|
-
agentId = getAgentId(options.agentId);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return await client.messages.search({
|
|
114
|
-
query: options.query,
|
|
115
|
-
agent_id: agentId,
|
|
116
|
-
search_mode: options.mode ?? "hybrid",
|
|
117
|
-
start_date: options.startDate,
|
|
118
|
-
end_date: options.endDate,
|
|
119
|
-
limit: options.limit ?? 10,
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function parseArgs(args: string[]): SearchMessagesOptions {
|
|
124
|
-
const queryIndex = args.indexOf("--query");
|
|
125
|
-
if (queryIndex === -1 || queryIndex + 1 >= args.length) {
|
|
126
|
-
throw new Error("Missing required argument: --query <text>");
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const options: SearchMessagesOptions = {
|
|
130
|
-
query: args[queryIndex + 1] as string,
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
const modeIndex = args.indexOf("--mode");
|
|
134
|
-
if (modeIndex !== -1 && modeIndex + 1 < args.length) {
|
|
135
|
-
const mode = args[modeIndex + 1] as string;
|
|
136
|
-
if (mode === "vector" || mode === "fts" || mode === "hybrid") {
|
|
137
|
-
options.mode = mode;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const startDateIndex = args.indexOf("--start-date");
|
|
142
|
-
if (startDateIndex !== -1 && startDateIndex + 1 < args.length) {
|
|
143
|
-
options.startDate = args[startDateIndex + 1];
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const endDateIndex = args.indexOf("--end-date");
|
|
147
|
-
if (endDateIndex !== -1 && endDateIndex + 1 < args.length) {
|
|
148
|
-
options.endDate = args[endDateIndex + 1];
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const limitIndex = args.indexOf("--limit");
|
|
152
|
-
if (limitIndex !== -1 && limitIndex + 1 < args.length) {
|
|
153
|
-
const limit = Number.parseInt(args[limitIndex + 1] as string, 10);
|
|
154
|
-
if (!Number.isNaN(limit)) {
|
|
155
|
-
options.limit = limit;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (args.includes("--all-agents")) {
|
|
160
|
-
options.allAgents = true;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const agentIdIndex = args.indexOf("--agent-id");
|
|
164
|
-
if (agentIdIndex !== -1 && agentIdIndex + 1 < args.length) {
|
|
165
|
-
options.agentId = args[agentIdIndex + 1];
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return options;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// CLI entry point - check if this file is being run directly
|
|
172
|
-
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
173
|
-
if (isMainModule) {
|
|
174
|
-
(async () => {
|
|
175
|
-
try {
|
|
176
|
-
const options = parseArgs(process.argv.slice(2));
|
|
177
|
-
const client = createClient();
|
|
178
|
-
const result = await searchMessages(client, options);
|
|
179
|
-
console.log(JSON.stringify(result, null, 2));
|
|
180
|
-
} catch (error) {
|
|
181
|
-
console.error(
|
|
182
|
-
"Error:",
|
|
183
|
-
error instanceof Error ? error.message : String(error),
|
|
184
|
-
);
|
|
185
|
-
console.error(`
|
|
186
|
-
Usage: npx tsx search-messages.ts --query <text> [options]
|
|
187
|
-
|
|
188
|
-
Options:
|
|
189
|
-
--query <text> Search query (required)
|
|
190
|
-
--mode <mode> Search mode: vector, fts, hybrid (default: hybrid)
|
|
191
|
-
--start-date <date> Filter messages after this date (ISO format)
|
|
192
|
-
--end-date <date> Filter messages before this date (ISO format)
|
|
193
|
-
--limit <n> Max results (default: 10)
|
|
194
|
-
--all-agents Search all agents, not just current agent
|
|
195
|
-
--agent-id <id> Explicit agent ID (overrides LETTA_AGENT_ID env var)
|
|
196
|
-
`);
|
|
197
|
-
process.exit(1);
|
|
198
|
-
}
|
|
199
|
-
})();
|
|
200
|
-
}
|