@letta-ai/letta-code 0.11.2-next.1 → 0.11.2-next.2
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 +18 -2
- package/package.json +1 -1
- package/skills/finding-agents/scripts/find-agents.ts +54 -11
- package/skills/migrating-memory/scripts/attach-block.ts +77 -16
- package/skills/migrating-memory/scripts/copy-block.ts +87 -22
- package/skills/migrating-memory/scripts/get-agent-blocks.ts +52 -11
- package/skills/searching-messages/scripts/get-messages.ts +10 -3
- package/skills/searching-messages/scripts/search-messages.ts +10 -3
package/letta.js
CHANGED
|
@@ -3237,7 +3237,7 @@ var package_default;
|
|
|
3237
3237
|
var init_package = __esm(() => {
|
|
3238
3238
|
package_default = {
|
|
3239
3239
|
name: "@letta-ai/letta-code",
|
|
3240
|
-
version: "0.11.2-next.
|
|
3240
|
+
version: "0.11.2-next.2",
|
|
3241
3241
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
3242
3242
|
type: "module",
|
|
3243
3243
|
bin: {
|
|
@@ -33383,6 +33383,17 @@ function getRipgrepBinDir() {
|
|
|
33383
33383
|
return;
|
|
33384
33384
|
}
|
|
33385
33385
|
}
|
|
33386
|
+
function getPackageNodeModulesDir() {
|
|
33387
|
+
try {
|
|
33388
|
+
const __filename2 = fileURLToPath(import.meta.url);
|
|
33389
|
+
const require2 = createRequire2(__filename2);
|
|
33390
|
+
const clientPath = require2.resolve("@letta-ai/letta-client");
|
|
33391
|
+
const match = clientPath.match(/^(.+[/\\]node_modules)[/\\]/);
|
|
33392
|
+
return match ? match[1] : undefined;
|
|
33393
|
+
} catch {
|
|
33394
|
+
return;
|
|
33395
|
+
}
|
|
33396
|
+
}
|
|
33386
33397
|
function getShellEnv() {
|
|
33387
33398
|
const env3 = { ...process.env };
|
|
33388
33399
|
const rgBinDir = getRipgrepBinDir();
|
|
@@ -33401,6 +33412,11 @@ function getShellEnv() {
|
|
|
33401
33412
|
}
|
|
33402
33413
|
} catch {}
|
|
33403
33414
|
}
|
|
33415
|
+
const nodeModulesDir = getPackageNodeModulesDir();
|
|
33416
|
+
if (nodeModulesDir) {
|
|
33417
|
+
const currentNodePath = env3.NODE_PATH || "";
|
|
33418
|
+
env3.NODE_PATH = currentNodePath ? `${nodeModulesDir}${path3.delimiter}${currentNodePath}` : nodeModulesDir;
|
|
33419
|
+
}
|
|
33404
33420
|
return env3;
|
|
33405
33421
|
}
|
|
33406
33422
|
var init_shellEnv = __esm(async () => {
|
|
@@ -77085,4 +77101,4 @@ Error during initialization: ${message}`);
|
|
|
77085
77101
|
}
|
|
77086
77102
|
main();
|
|
77087
77103
|
|
|
77088
|
-
//# debugId=
|
|
77104
|
+
//# debugId=638326A0AF7C44CC64756E2164756E21
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
#!/usr/bin/env npx
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
2
|
/**
|
|
3
3
|
* Find Agents - Search for agents with various filters
|
|
4
4
|
*
|
|
5
|
+
* This script is standalone and can be run outside the CLI process.
|
|
6
|
+
* It reads auth from LETTA_API_KEY env var or ~/.letta/settings.json.
|
|
7
|
+
*
|
|
5
8
|
* Usage:
|
|
6
|
-
* npx
|
|
9
|
+
* npx tsx find-agents.ts [options]
|
|
7
10
|
*
|
|
8
11
|
* Options:
|
|
9
12
|
* --name <name> Exact name match
|
|
@@ -17,9 +20,17 @@
|
|
|
17
20
|
* Raw API response from GET /v1/agents
|
|
18
21
|
*/
|
|
19
22
|
|
|
20
|
-
import
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
+
import { readFileSync } from "node:fs";
|
|
24
|
+
import { createRequire } from "node:module";
|
|
25
|
+
import { homedir } from "node:os";
|
|
26
|
+
import { join } from "node:path";
|
|
27
|
+
|
|
28
|
+
// Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
|
|
29
|
+
// (ES module imports don't respect NODE_PATH, but require does)
|
|
30
|
+
const require = createRequire(import.meta.url);
|
|
31
|
+
const Letta = require("@letta-ai/letta-client")
|
|
32
|
+
.default as typeof import("@letta-ai/letta-client").default;
|
|
33
|
+
type LettaClient = InstanceType<typeof Letta>;
|
|
23
34
|
|
|
24
35
|
interface FindAgentsOptions {
|
|
25
36
|
name?: string;
|
|
@@ -30,6 +41,38 @@ interface FindAgentsOptions {
|
|
|
30
41
|
limit?: number;
|
|
31
42
|
}
|
|
32
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Get API key from env var or settings file
|
|
46
|
+
*/
|
|
47
|
+
function getApiKey(): string {
|
|
48
|
+
// First check env var (set by CLI's getShellEnv)
|
|
49
|
+
if (process.env.LETTA_API_KEY) {
|
|
50
|
+
return process.env.LETTA_API_KEY;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Fall back to settings file
|
|
54
|
+
const settingsPath = join(homedir(), ".letta", "settings.json");
|
|
55
|
+
try {
|
|
56
|
+
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
57
|
+
if (settings.env?.LETTA_API_KEY) {
|
|
58
|
+
return settings.env.LETTA_API_KEY;
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
// Settings file doesn't exist or is invalid
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
throw new Error(
|
|
65
|
+
"No LETTA_API_KEY found. Set the env var or run the Letta CLI to authenticate.",
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Create a Letta client with auth from env/settings
|
|
71
|
+
*/
|
|
72
|
+
function createClient(): LettaClient {
|
|
73
|
+
return new Letta({ apiKey: getApiKey() });
|
|
74
|
+
}
|
|
75
|
+
|
|
33
76
|
/**
|
|
34
77
|
* Find agents matching the given criteria
|
|
35
78
|
* @param client - Letta client instance
|
|
@@ -37,7 +80,7 @@ interface FindAgentsOptions {
|
|
|
37
80
|
* @returns Array of agent objects from the API
|
|
38
81
|
*/
|
|
39
82
|
export async function findAgents(
|
|
40
|
-
client:
|
|
83
|
+
client: LettaClient,
|
|
41
84
|
options: FindAgentsOptions = {},
|
|
42
85
|
): Promise<Awaited<ReturnType<typeof client.agents.list>>> {
|
|
43
86
|
const params: Parameters<typeof client.agents.list>[0] = {
|
|
@@ -103,13 +146,13 @@ function parseArgs(args: string[]): FindAgentsOptions {
|
|
|
103
146
|
return options;
|
|
104
147
|
}
|
|
105
148
|
|
|
106
|
-
// CLI entry point
|
|
107
|
-
|
|
149
|
+
// CLI entry point - check if this file is being run directly
|
|
150
|
+
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
151
|
+
if (isMainModule) {
|
|
108
152
|
(async () => {
|
|
109
153
|
try {
|
|
110
154
|
const options = parseArgs(process.argv.slice(2));
|
|
111
|
-
|
|
112
|
-
const client = await getClient();
|
|
155
|
+
const client = createClient();
|
|
113
156
|
const result = await findAgents(client, options);
|
|
114
157
|
console.log(JSON.stringify(result, null, 2));
|
|
115
158
|
} catch (error) {
|
|
@@ -118,7 +161,7 @@ if (require.main === module) {
|
|
|
118
161
|
error instanceof Error ? error.message : String(error),
|
|
119
162
|
);
|
|
120
163
|
console.error(`
|
|
121
|
-
Usage: npx
|
|
164
|
+
Usage: npx tsx find-agents.ts [options]
|
|
122
165
|
|
|
123
166
|
Options:
|
|
124
167
|
--name <name> Exact name match
|
|
@@ -1,24 +1,79 @@
|
|
|
1
|
-
#!/usr/bin/env npx
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
2
|
/**
|
|
3
3
|
* Attach Block - Attaches an existing memory block to an agent (sharing)
|
|
4
4
|
*
|
|
5
|
+
* This script is standalone and can be run outside the CLI process.
|
|
6
|
+
* It reads auth from LETTA_API_KEY env var or ~/.letta/settings.json.
|
|
7
|
+
* It reads agent ID from LETTA_AGENT_ID env var or --agent-id arg.
|
|
8
|
+
*
|
|
5
9
|
* Usage:
|
|
6
|
-
* npx
|
|
10
|
+
* npx tsx attach-block.ts --block-id <block-id> [--agent-id <agent-id>] [--read-only]
|
|
7
11
|
*
|
|
8
12
|
* This attaches an existing block to another agent, making it shared.
|
|
9
13
|
* Changes to the block will be visible to all agents that have it attached.
|
|
10
14
|
*
|
|
11
15
|
* Options:
|
|
12
|
-
* --
|
|
16
|
+
* --agent-id Target agent ID (overrides LETTA_AGENT_ID env var)
|
|
17
|
+
* --read-only Target agent can read but not modify the block
|
|
13
18
|
*
|
|
14
19
|
* Output:
|
|
15
20
|
* Raw API response from the attach operation
|
|
16
21
|
*/
|
|
17
22
|
|
|
18
|
-
import
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
23
|
+
import { readFileSync } from "node:fs";
|
|
24
|
+
import { createRequire } from "node:module";
|
|
25
|
+
import { homedir } from "node:os";
|
|
26
|
+
import { join } from "node:path";
|
|
27
|
+
|
|
28
|
+
// Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
|
|
29
|
+
// (ES module imports don't respect NODE_PATH, but require does)
|
|
30
|
+
const require = createRequire(import.meta.url);
|
|
31
|
+
const Letta = require("@letta-ai/letta-client")
|
|
32
|
+
.default as typeof import("@letta-ai/letta-client").default;
|
|
33
|
+
type LettaClient = InstanceType<typeof Letta>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get API key from env var or settings file
|
|
37
|
+
*/
|
|
38
|
+
function getApiKey(): string {
|
|
39
|
+
if (process.env.LETTA_API_KEY) {
|
|
40
|
+
return process.env.LETTA_API_KEY;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const settingsPath = join(homedir(), ".letta", "settings.json");
|
|
44
|
+
try {
|
|
45
|
+
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
46
|
+
if (settings.env?.LETTA_API_KEY) {
|
|
47
|
+
return settings.env.LETTA_API_KEY;
|
|
48
|
+
}
|
|
49
|
+
} catch {
|
|
50
|
+
// Settings file doesn't exist or is invalid
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
throw new Error(
|
|
54
|
+
"No LETTA_API_KEY found. Set the env var or run the Letta CLI to authenticate.",
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Get agent ID from CLI arg, env var, or throw
|
|
60
|
+
*/
|
|
61
|
+
function getAgentId(cliArg?: string): string {
|
|
62
|
+
if (cliArg) return cliArg;
|
|
63
|
+
if (process.env.LETTA_AGENT_ID) {
|
|
64
|
+
return process.env.LETTA_AGENT_ID;
|
|
65
|
+
}
|
|
66
|
+
throw new Error(
|
|
67
|
+
"No agent ID provided. Use --agent-id or ensure LETTA_AGENT_ID env var is set.",
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Create a Letta client with auth from env/settings
|
|
73
|
+
*/
|
|
74
|
+
function createClient(): LettaClient {
|
|
75
|
+
return new Letta({ apiKey: getApiKey() });
|
|
76
|
+
}
|
|
22
77
|
|
|
23
78
|
/**
|
|
24
79
|
* Attach an existing block to the current agent (sharing it)
|
|
@@ -29,13 +84,13 @@ import { settingsManager } from "../../../../settings-manager";
|
|
|
29
84
|
* @returns API response from the attach operation
|
|
30
85
|
*/
|
|
31
86
|
export async function attachBlock(
|
|
32
|
-
client:
|
|
87
|
+
client: LettaClient,
|
|
33
88
|
blockId: string,
|
|
34
89
|
readOnly = false,
|
|
35
90
|
targetAgentId?: string,
|
|
36
91
|
): Promise<Awaited<ReturnType<typeof client.agents.blocks.attach>>> {
|
|
37
92
|
// Get current agent ID (the agent calling this script) or use provided ID
|
|
38
|
-
const currentAgentId = targetAgentId
|
|
93
|
+
const currentAgentId = getAgentId(targetAgentId);
|
|
39
94
|
|
|
40
95
|
const result = await client.agents.blocks.attach(blockId, {
|
|
41
96
|
agent_id: currentAgentId,
|
|
@@ -58,8 +113,10 @@ export async function attachBlock(
|
|
|
58
113
|
function parseArgs(args: string[]): {
|
|
59
114
|
blockId: string;
|
|
60
115
|
readOnly: boolean;
|
|
116
|
+
agentId?: string;
|
|
61
117
|
} {
|
|
62
118
|
const blockIdIndex = args.indexOf("--block-id");
|
|
119
|
+
const agentIdIndex = args.indexOf("--agent-id");
|
|
63
120
|
const readOnly = args.includes("--read-only");
|
|
64
121
|
|
|
65
122
|
if (blockIdIndex === -1 || blockIdIndex + 1 >= args.length) {
|
|
@@ -69,17 +126,21 @@ function parseArgs(args: string[]): {
|
|
|
69
126
|
return {
|
|
70
127
|
blockId: args[blockIdIndex + 1] as string,
|
|
71
128
|
readOnly,
|
|
129
|
+
agentId:
|
|
130
|
+
agentIdIndex !== -1 && agentIdIndex + 1 < args.length
|
|
131
|
+
? (args[agentIdIndex + 1] as string)
|
|
132
|
+
: undefined,
|
|
72
133
|
};
|
|
73
134
|
}
|
|
74
135
|
|
|
75
|
-
// CLI entry point
|
|
76
|
-
|
|
136
|
+
// CLI entry point - check if this file is being run directly
|
|
137
|
+
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
138
|
+
if (isMainModule) {
|
|
77
139
|
(async () => {
|
|
78
140
|
try {
|
|
79
|
-
const { blockId, readOnly } = parseArgs(process.argv.slice(2));
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
const result = await attachBlock(client, blockId, readOnly);
|
|
141
|
+
const { blockId, readOnly, agentId } = parseArgs(process.argv.slice(2));
|
|
142
|
+
const client = createClient();
|
|
143
|
+
const result = await attachBlock(client, blockId, readOnly, agentId);
|
|
83
144
|
console.log(JSON.stringify(result, null, 2));
|
|
84
145
|
} catch (error) {
|
|
85
146
|
console.error(
|
|
@@ -91,7 +152,7 @@ if (require.main === module) {
|
|
|
91
152
|
error.message.includes("Missing required argument")
|
|
92
153
|
) {
|
|
93
154
|
console.error(
|
|
94
|
-
"\nUsage: npx
|
|
155
|
+
"\nUsage: npx tsx attach-block.ts --block-id <block-id> [--agent-id <agent-id>] [--read-only]",
|
|
95
156
|
);
|
|
96
157
|
}
|
|
97
158
|
process.exit(1);
|
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
#!/usr/bin/env npx
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
2
|
/**
|
|
3
3
|
* Copy Block - Copies a memory block to create a new independent block for the current agent
|
|
4
4
|
*
|
|
5
|
+
* This script is standalone and can be run outside the CLI process.
|
|
6
|
+
* It reads auth from LETTA_API_KEY env var or ~/.letta/settings.json.
|
|
7
|
+
* It reads agent ID from LETTA_AGENT_ID env var or --agent-id arg.
|
|
8
|
+
*
|
|
5
9
|
* Usage:
|
|
6
|
-
* npx
|
|
10
|
+
* npx tsx copy-block.ts --block-id <block-id> [--label <new-label>] [--agent-id <agent-id>]
|
|
7
11
|
*
|
|
8
12
|
* Options:
|
|
9
|
-
* --label
|
|
13
|
+
* --label Override the block label (required if you already have a block with that label)
|
|
14
|
+
* --agent-id Target agent ID (overrides LETTA_AGENT_ID env var)
|
|
10
15
|
*
|
|
11
16
|
* This creates a new block with the same content as the source block,
|
|
12
17
|
* then attaches it to the current agent. Changes to the new block
|
|
@@ -16,17 +21,65 @@
|
|
|
16
21
|
* Raw API response from each step (retrieve, create, attach)
|
|
17
22
|
*/
|
|
18
23
|
|
|
19
|
-
import
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
24
|
+
import { readFileSync } from "node:fs";
|
|
25
|
+
import { createRequire } from "node:module";
|
|
26
|
+
import { homedir } from "node:os";
|
|
27
|
+
import { join } from "node:path";
|
|
28
|
+
|
|
29
|
+
// Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
|
|
30
|
+
// (ES module imports don't respect NODE_PATH, but require does)
|
|
31
|
+
const require = createRequire(import.meta.url);
|
|
32
|
+
const Letta = require("@letta-ai/letta-client")
|
|
33
|
+
.default as typeof import("@letta-ai/letta-client").default;
|
|
34
|
+
type LettaClient = InstanceType<typeof Letta>;
|
|
23
35
|
|
|
24
36
|
interface CopyBlockResult {
|
|
25
|
-
sourceBlock: Awaited<ReturnType<
|
|
26
|
-
newBlock: Awaited<ReturnType<
|
|
27
|
-
attachResult: Awaited<
|
|
28
|
-
|
|
29
|
-
|
|
37
|
+
sourceBlock: Awaited<ReturnType<LettaClient["blocks"]["retrieve"]>>;
|
|
38
|
+
newBlock: Awaited<ReturnType<LettaClient["blocks"]["create"]>>;
|
|
39
|
+
attachResult: Awaited<ReturnType<LettaClient["agents"]["blocks"]["attach"]>>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get API key from env var or settings file
|
|
44
|
+
*/
|
|
45
|
+
function getApiKey(): string {
|
|
46
|
+
if (process.env.LETTA_API_KEY) {
|
|
47
|
+
return process.env.LETTA_API_KEY;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const settingsPath = join(homedir(), ".letta", "settings.json");
|
|
51
|
+
try {
|
|
52
|
+
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
53
|
+
if (settings.env?.LETTA_API_KEY) {
|
|
54
|
+
return settings.env.LETTA_API_KEY;
|
|
55
|
+
}
|
|
56
|
+
} catch {
|
|
57
|
+
// Settings file doesn't exist or is invalid
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
throw new Error(
|
|
61
|
+
"No LETTA_API_KEY found. Set the env var or run the Letta CLI to authenticate.",
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get agent ID from CLI arg, env var, or throw
|
|
67
|
+
*/
|
|
68
|
+
function getAgentId(cliArg?: string): string {
|
|
69
|
+
if (cliArg) return cliArg;
|
|
70
|
+
if (process.env.LETTA_AGENT_ID) {
|
|
71
|
+
return process.env.LETTA_AGENT_ID;
|
|
72
|
+
}
|
|
73
|
+
throw new Error(
|
|
74
|
+
"No agent ID provided. Use --agent-id or ensure LETTA_AGENT_ID env var is set.",
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Create a Letta client with auth from env/settings
|
|
80
|
+
*/
|
|
81
|
+
function createClient(): LettaClient {
|
|
82
|
+
return new Letta({ apiKey: getApiKey() });
|
|
30
83
|
}
|
|
31
84
|
|
|
32
85
|
/**
|
|
@@ -37,12 +90,12 @@ interface CopyBlockResult {
|
|
|
37
90
|
* @returns Object containing source block, new block, and attach result
|
|
38
91
|
*/
|
|
39
92
|
export async function copyBlock(
|
|
40
|
-
client:
|
|
93
|
+
client: LettaClient,
|
|
41
94
|
blockId: string,
|
|
42
95
|
options?: { labelOverride?: string; targetAgentId?: string },
|
|
43
96
|
): Promise<CopyBlockResult> {
|
|
44
97
|
// Get current agent ID (the agent calling this script) or use provided ID
|
|
45
|
-
const currentAgentId = options?.targetAgentId
|
|
98
|
+
const currentAgentId = getAgentId(options?.targetAgentId);
|
|
46
99
|
|
|
47
100
|
// 1. Get source block details
|
|
48
101
|
const sourceBlock = await client.blocks.retrieve(blockId);
|
|
@@ -63,9 +116,14 @@ export async function copyBlock(
|
|
|
63
116
|
return { sourceBlock, newBlock, attachResult };
|
|
64
117
|
}
|
|
65
118
|
|
|
66
|
-
function parseArgs(args: string[]): {
|
|
119
|
+
function parseArgs(args: string[]): {
|
|
120
|
+
blockId: string;
|
|
121
|
+
label?: string;
|
|
122
|
+
agentId?: string;
|
|
123
|
+
} {
|
|
67
124
|
const blockIdIndex = args.indexOf("--block-id");
|
|
68
125
|
const labelIndex = args.indexOf("--label");
|
|
126
|
+
const agentIdIndex = args.indexOf("--agent-id");
|
|
69
127
|
|
|
70
128
|
if (blockIdIndex === -1 || blockIdIndex + 1 >= args.length) {
|
|
71
129
|
throw new Error("Missing required argument: --block-id <block-id>");
|
|
@@ -77,17 +135,24 @@ function parseArgs(args: string[]): { blockId: string; label?: string } {
|
|
|
77
135
|
labelIndex !== -1 && labelIndex + 1 < args.length
|
|
78
136
|
? (args[labelIndex + 1] as string)
|
|
79
137
|
: undefined,
|
|
138
|
+
agentId:
|
|
139
|
+
agentIdIndex !== -1 && agentIdIndex + 1 < args.length
|
|
140
|
+
? (args[agentIdIndex + 1] as string)
|
|
141
|
+
: undefined,
|
|
80
142
|
};
|
|
81
143
|
}
|
|
82
144
|
|
|
83
|
-
// CLI entry point
|
|
84
|
-
|
|
145
|
+
// CLI entry point - check if this file is being run directly
|
|
146
|
+
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
147
|
+
if (isMainModule) {
|
|
85
148
|
(async () => {
|
|
86
149
|
try {
|
|
87
|
-
const { blockId, label } = parseArgs(process.argv.slice(2));
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
150
|
+
const { blockId, label, agentId } = parseArgs(process.argv.slice(2));
|
|
151
|
+
const client = createClient();
|
|
152
|
+
const result = await copyBlock(client, blockId, {
|
|
153
|
+
labelOverride: label,
|
|
154
|
+
targetAgentId: agentId,
|
|
155
|
+
});
|
|
91
156
|
console.log(JSON.stringify(result, null, 2));
|
|
92
157
|
} catch (error) {
|
|
93
158
|
console.error(
|
|
@@ -99,7 +164,7 @@ if (require.main === module) {
|
|
|
99
164
|
error.message.includes("Missing required argument")
|
|
100
165
|
) {
|
|
101
166
|
console.error(
|
|
102
|
-
"\nUsage: npx
|
|
167
|
+
"\nUsage: npx tsx copy-block.ts --block-id <block-id> [--label <new-label>] [--agent-id <agent-id>]",
|
|
103
168
|
);
|
|
104
169
|
}
|
|
105
170
|
process.exit(1);
|
|
@@ -1,17 +1,58 @@
|
|
|
1
|
-
#!/usr/bin/env npx
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
2
|
/**
|
|
3
3
|
* Get Agent Blocks - Retrieves memory blocks from a specific agent
|
|
4
4
|
*
|
|
5
|
+
* This script is standalone and can be run outside the CLI process.
|
|
6
|
+
* It reads auth from LETTA_API_KEY env var or ~/.letta/settings.json.
|
|
7
|
+
*
|
|
5
8
|
* Usage:
|
|
6
|
-
* npx
|
|
9
|
+
* npx tsx get-agent-blocks.ts --agent-id <agent-id>
|
|
7
10
|
*
|
|
8
11
|
* Output:
|
|
9
12
|
* Raw API response from GET /v1/agents/{id}/core-memory/blocks
|
|
10
13
|
*/
|
|
11
14
|
|
|
12
|
-
import
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
+
import { readFileSync } from "node:fs";
|
|
16
|
+
import { createRequire } from "node:module";
|
|
17
|
+
import { homedir } from "node:os";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
|
|
20
|
+
// Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
|
|
21
|
+
// (ES module imports don't respect NODE_PATH, but require does)
|
|
22
|
+
const require = createRequire(import.meta.url);
|
|
23
|
+
const Letta = require("@letta-ai/letta-client")
|
|
24
|
+
.default as typeof import("@letta-ai/letta-client").default;
|
|
25
|
+
type LettaClient = InstanceType<typeof Letta>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get API key from env var or settings file
|
|
29
|
+
*/
|
|
30
|
+
function getApiKey(): string {
|
|
31
|
+
if (process.env.LETTA_API_KEY) {
|
|
32
|
+
return process.env.LETTA_API_KEY;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const settingsPath = join(homedir(), ".letta", "settings.json");
|
|
36
|
+
try {
|
|
37
|
+
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
38
|
+
if (settings.env?.LETTA_API_KEY) {
|
|
39
|
+
return settings.env.LETTA_API_KEY;
|
|
40
|
+
}
|
|
41
|
+
} catch {
|
|
42
|
+
// Settings file doesn't exist or is invalid
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
throw new Error(
|
|
46
|
+
"No LETTA_API_KEY found. Set the env var or run the Letta CLI to authenticate.",
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Create a Letta client with auth from env/settings
|
|
52
|
+
*/
|
|
53
|
+
function createClient(): LettaClient {
|
|
54
|
+
return new Letta({ apiKey: getApiKey() });
|
|
55
|
+
}
|
|
15
56
|
|
|
16
57
|
/**
|
|
17
58
|
* Get memory blocks for a specific agent
|
|
@@ -20,7 +61,7 @@ import { settingsManager } from "../../../../settings-manager";
|
|
|
20
61
|
* @returns Array of block objects from the API
|
|
21
62
|
*/
|
|
22
63
|
export async function getAgentBlocks(
|
|
23
|
-
client:
|
|
64
|
+
client: LettaClient,
|
|
24
65
|
agentId: string,
|
|
25
66
|
): Promise<Awaited<ReturnType<typeof client.agents.blocks.list>>> {
|
|
26
67
|
return await client.agents.blocks.list(agentId);
|
|
@@ -34,13 +75,13 @@ function parseArgs(args: string[]): { agentId: string } {
|
|
|
34
75
|
return { agentId: args[agentIdIndex + 1] as string };
|
|
35
76
|
}
|
|
36
77
|
|
|
37
|
-
// CLI entry point
|
|
38
|
-
|
|
78
|
+
// CLI entry point - check if this file is being run directly
|
|
79
|
+
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
80
|
+
if (isMainModule) {
|
|
39
81
|
(async () => {
|
|
40
82
|
try {
|
|
41
83
|
const { agentId } = parseArgs(process.argv.slice(2));
|
|
42
|
-
|
|
43
|
-
const client = await getClient();
|
|
84
|
+
const client = createClient();
|
|
44
85
|
const result = await getAgentBlocks(client, agentId);
|
|
45
86
|
console.log(JSON.stringify(result, null, 2));
|
|
46
87
|
} catch (error) {
|
|
@@ -53,7 +94,7 @@ if (require.main === module) {
|
|
|
53
94
|
error.message.includes("Missing required argument")
|
|
54
95
|
) {
|
|
55
96
|
console.error(
|
|
56
|
-
"\nUsage: npx
|
|
97
|
+
"\nUsage: npx tsx get-agent-blocks.ts --agent-id <agent-id>",
|
|
57
98
|
);
|
|
58
99
|
}
|
|
59
100
|
process.exit(1);
|
|
@@ -26,9 +26,16 @@
|
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
import { readFileSync } from "node:fs";
|
|
29
|
+
import { createRequire } from "node:module";
|
|
29
30
|
import { homedir } from "node:os";
|
|
30
31
|
import { join } from "node:path";
|
|
31
|
-
|
|
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>;
|
|
32
39
|
|
|
33
40
|
interface GetMessagesOptions {
|
|
34
41
|
startDate?: string;
|
|
@@ -85,7 +92,7 @@ function getAgentId(cliArg?: string): string {
|
|
|
85
92
|
/**
|
|
86
93
|
* Create a Letta client with auth from env/settings
|
|
87
94
|
*/
|
|
88
|
-
function createClient():
|
|
95
|
+
function createClient(): LettaClient {
|
|
89
96
|
return new Letta({ apiKey: getApiKey() });
|
|
90
97
|
}
|
|
91
98
|
|
|
@@ -96,7 +103,7 @@ function createClient(): Letta {
|
|
|
96
103
|
* @returns Array of messages in chronological order
|
|
97
104
|
*/
|
|
98
105
|
export async function getMessages(
|
|
99
|
-
client:
|
|
106
|
+
client: LettaClient,
|
|
100
107
|
options: GetMessagesOptions = {},
|
|
101
108
|
): Promise<unknown[]> {
|
|
102
109
|
const agentId = getAgentId(options.agentId);
|
|
@@ -24,9 +24,16 @@
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
import { readFileSync } from "node:fs";
|
|
27
|
+
import { createRequire } from "node:module";
|
|
27
28
|
import { homedir } from "node:os";
|
|
28
29
|
import { join } from "node:path";
|
|
29
|
-
|
|
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>;
|
|
30
37
|
|
|
31
38
|
interface SearchMessagesOptions {
|
|
32
39
|
query: string;
|
|
@@ -83,7 +90,7 @@ function getAgentId(cliArg?: string): string {
|
|
|
83
90
|
/**
|
|
84
91
|
* Create a Letta client with auth from env/settings
|
|
85
92
|
*/
|
|
86
|
-
function createClient():
|
|
93
|
+
function createClient(): LettaClient {
|
|
87
94
|
return new Letta({ apiKey: getApiKey() });
|
|
88
95
|
}
|
|
89
96
|
|
|
@@ -94,7 +101,7 @@ function createClient(): Letta {
|
|
|
94
101
|
* @returns Array of search results with scores
|
|
95
102
|
*/
|
|
96
103
|
export async function searchMessages(
|
|
97
|
-
client:
|
|
104
|
+
client: LettaClient,
|
|
98
105
|
options: SearchMessagesOptions,
|
|
99
106
|
): Promise<Awaited<ReturnType<typeof client.messages.search>>> {
|
|
100
107
|
// Default to current agent unless --all-agents is specified
|