@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
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 <
|
|
28
|
+
npx tsx <SKILL_DIR>/scripts/mcp-http.ts <url> list-tools
|
|
29
29
|
|
|
30
30
|
# With auth header
|
|
31
|
-
npx tsx <
|
|
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 <
|
|
38
|
+
cd <SKILL_DIR>/scripts && npm install
|
|
38
39
|
|
|
39
40
|
# Then connect
|
|
40
|
-
npx tsx <
|
|
41
|
+
npx tsx <SKILL_DIR>/scripts/mcp-stdio.ts "<command>" list-tools
|
|
41
42
|
|
|
42
43
|
# Examples
|
|
43
|
-
npx tsx <
|
|
44
|
-
npx tsx <
|
|
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 <
|
|
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 <
|
|
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:**
|