@letta-ai/letta-code 0.20.0 → 0.21.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letta-ai/letta-code",
3
- "version": "0.20.0",
3
+ "version": "0.21.1",
4
4
  "description": "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,8 +32,9 @@ Prompts that are compiled as part of the system prompt (contained in `system/`)
32
32
 
33
33
  Use the following script to evaluate the token usage of the system prompt:
34
34
  ```bash
35
- bun scripts/estimate_system_tokens.ts --memory-dir "$MEMORY_DIR"
35
+ npx tsx <SKILL_DIR>/scripts/estimate_system_tokens.ts --memory-dir "$MEMORY_DIR"
36
36
  ```
37
+ Where `<SKILL_DIR>` is the Skill Directory shown when the skill was loaded (visible in the injection header).
37
38
 
38
39
  **Questions to ask**:
39
40
  - Do all these tokens need to be passed to the LLM on every turn, or can they be retrieved when needed through being part of external memory of my conversation history?
@@ -1,10 +1,23 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * Estimate token usage of system prompt memory files.
4
+ *
5
+ * Self-contained — no imports from the letta-code source tree.
6
+ *
7
+ * Usage:
8
+ * npx tsx estimate_system_tokens.ts --memory-dir "$MEMORY_DIR"
9
+ * npx tsx estimate_system_tokens.ts --memory-dir ~/.letta/agents/<id>/memory
10
+ */
2
11
 
3
12
  import { existsSync, readdirSync, readFileSync } from "node:fs";
4
13
  import { join } from "node:path";
5
- import { getClient } from "../../../../agent/client";
6
- import { estimateTokens } from "../../../../cli/helpers/format";
7
- import { settingsManager } from "../../../../settings-manager";
14
+
15
+ // Codex heuristic: ~4 bytes per token (codex-rs/core/src/truncate.rs APPROX_BYTES_PER_TOKEN = 4)
16
+ const BYTES_PER_TOKEN = 4;
17
+
18
+ function estimateTokens(text: string): number {
19
+ return Math.ceil(Buffer.byteLength(text, "utf8") / BYTES_PER_TOKEN);
20
+ }
8
21
 
9
22
  type FileEstimate = {
10
23
  path: string;
@@ -13,7 +26,6 @@ type FileEstimate = {
13
26
 
14
27
  type ParsedArgs = {
15
28
  memoryDir?: string;
16
- agentId?: string;
17
29
  top: number;
18
30
  };
19
31
 
@@ -27,11 +39,6 @@ function parseArgs(argv: string[]): ParsedArgs {
27
39
  i++;
28
40
  continue;
29
41
  }
30
- if (arg === "--agent-id") {
31
- parsed.agentId = argv[i + 1];
32
- i++;
33
- continue;
34
- }
35
42
  if (arg === "--top") {
36
43
  const raw = argv[i + 1];
37
44
  const value = Number.parseInt(raw ?? "", 10);
@@ -63,9 +70,6 @@ function walkMarkdownFiles(dir: string): string[] {
63
70
  }
64
71
  const full = join(dir, entry.name);
65
72
  if (entry.isDirectory()) {
66
- if (entry.name === ".git") {
67
- continue;
68
- }
69
73
  out.push(...walkMarkdownFiles(full));
70
74
  continue;
71
75
  }
@@ -77,70 +81,25 @@ function walkMarkdownFiles(dir: string): string[] {
77
81
  return out;
78
82
  }
79
83
 
80
- function inferAgentIdFromMemoryDir(memoryDir: string): string | null {
81
- const parts = normalizePath(memoryDir).split("/");
82
- for (let i = 0; i < parts.length - 1; i++) {
83
- if (parts[i] === "agents" && parts[i + 1]?.startsWith("agent-")) {
84
- return parts[i + 1];
85
- }
86
- }
87
-
88
- const maybe = parts.at(-2);
89
- return maybe?.startsWith("agent-") ? maybe : null;
90
- }
91
-
92
- async function resolveAgentId(
93
- memoryDir: string,
94
- cliAgentId?: string,
95
- ): Promise<string> {
96
- if (cliAgentId) {
97
- return cliAgentId;
98
- }
99
-
100
- if (process.env.AGENT_ID) {
101
- return process.env.AGENT_ID;
102
- }
103
-
104
- const inferred = inferAgentIdFromMemoryDir(memoryDir);
105
- if (inferred) {
106
- return inferred;
107
- }
108
-
109
- const fromSession = settingsManager.getEffectiveLastAgentId(process.cwd());
110
- if (fromSession) {
111
- return fromSession;
112
- }
113
-
114
- throw new Error(
115
- "Unable to resolve agent ID. Pass --agent-id or set AGENT_ID.",
116
- );
117
- }
118
-
119
84
  function formatNumber(value: number): string {
120
85
  return value.toLocaleString("en-US");
121
86
  }
122
87
 
123
- async function main(): Promise<number> {
124
- await settingsManager.initialize();
125
-
88
+ function main(): number {
126
89
  const args = parseArgs(process.argv.slice(2));
127
90
  const memoryDir = args.memoryDir || process.env.MEMORY_DIR;
128
91
 
129
92
  if (!memoryDir) {
130
- throw new Error("Missing memory dir. Pass --memory-dir or set MEMORY_DIR.");
93
+ console.error("Missing memory dir. Pass --memory-dir or set MEMORY_DIR.");
94
+ return 1;
131
95
  }
132
96
 
133
97
  const systemDir = join(memoryDir, "system");
134
98
  if (!existsSync(systemDir)) {
135
- throw new Error(`Missing system directory: ${systemDir}`);
99
+ console.error(`Missing system directory: ${systemDir}`);
100
+ return 1;
136
101
  }
137
102
 
138
- const agentId = await resolveAgentId(memoryDir, args.agentId);
139
-
140
- // Use the SDK auth path used by letta-code (OAuth + API key handling via getClient).
141
- const client = await getClient();
142
- await client.agents.retrieve(agentId);
143
-
144
103
  const files = walkMarkdownFiles(systemDir).sort();
145
104
  const rows: FileEstimate[] = [];
146
105
 
@@ -166,11 +125,4 @@ async function main(): Promise<number> {
166
125
  return 0;
167
126
  }
168
127
 
169
- main()
170
- .then((code) => {
171
- process.exit(code);
172
- })
173
- .catch((error: unknown) => {
174
- console.error(error instanceof Error ? error.message : String(error));
175
- process.exit(1);
176
- });
128
+ process.exit(main());
@@ -25,23 +25,24 @@ Ask the user:
25
25
 
26
26
  **For HTTP servers:**
27
27
  ```bash
28
- npx tsx <skill-path>/scripts/mcp-http.ts <url> list-tools
28
+ npx tsx <SKILL_DIR>/scripts/mcp-http.ts <url> list-tools
29
29
 
30
30
  # With auth header
31
- npx tsx <skill-path>/scripts/mcp-http.ts <url> --header "Authorization: Bearer KEY" list-tools
31
+ npx tsx <SKILL_DIR>/scripts/mcp-http.ts <url> --header "Authorization: Bearer KEY" list-tools
32
32
  ```
33
+ Where `<SKILL_DIR>` is the Skill Directory shown when the skill was loaded (visible in the injection header).
33
34
 
34
35
  **For stdio servers:**
35
36
  ```bash
36
37
  # First, install dependencies (one time)
37
- cd <skill-path>/scripts && npm install
38
+ cd <SKILL_DIR>/scripts && npm install
38
39
 
39
40
  # Then connect
40
- npx tsx <skill-path>/scripts/mcp-stdio.ts "<command>" list-tools
41
+ npx tsx <SKILL_DIR>/scripts/mcp-stdio.ts "<command>" list-tools
41
42
 
42
43
  # Examples
43
- npx tsx <skill-path>/scripts/mcp-stdio.ts "npx -y @modelcontextprotocol/server-filesystem ." list-tools
44
- npx tsx <skill-path>/scripts/mcp-stdio.ts "python server.py" list-tools
44
+ npx tsx <SKILL_DIR>/scripts/mcp-stdio.ts "npx -y @modelcontextprotocol/server-filesystem ." list-tools
45
+ npx tsx <SKILL_DIR>/scripts/mcp-stdio.ts "python server.py" list-tools
45
46
  ```
46
47
 
47
48
  ### Step 3: Explore available tools
@@ -113,7 +114,7 @@ Connects to MCP servers that run as subprocesses. Requires npm install first.
113
114
 
114
115
  ```bash
115
116
  # One-time setup
116
- cd <skill-path>/scripts && npm install
117
+ cd <SKILL_DIR>/scripts && npm install
117
118
 
118
119
  npx tsx mcp-stdio.ts "<command>" [options] <action> [args]
119
120
 
@@ -163,7 +164,7 @@ Here are some well-known MCP servers:
163
164
  - Or `--env "API_KEY=xxx"` for stdio servers that need env vars
164
165
 
165
166
  **stdio "npm install" error:**
166
- - Run `cd <skill-path>/scripts && npm install` first
167
+ - Run `cd <SKILL_DIR>/scripts && npm install` first
167
168
  - The stdio client requires the MCP SDK
168
169
 
169
170
  **Tool call fails:**
@@ -265,6 +265,7 @@ Usage:
265
265
  ```bash
266
266
  npx tsx <SKILL_DIR>/scripts/init-skill.ts <skill-name> --path <output-directory>
267
267
  ```
268
+ Where `<SKILL_DIR>` is the Skill Directory shown when the skill was loaded (visible in the injection header).
268
269
 
269
270
  The script:
270
271