工作原理
了解 Letta Code 的构建方式和自定义方法
本页面面向希望了解内部原理、为 Letta Code 做出贡献或使用 Letta SDK 构建自己的代理工具的开发者。
Letta Code 是一个围绕 Letta TypeScript SDK 构建的轻量级 CLI 工具。
它让 Letta 代理(运行在服务器上,本地或远程)能够与您的本地开发环境交互。
架构概述
┌─────────────────────────────────────────────────────────────┐
│ 您的终端 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Letta Code │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ │
│ │ │ CLI UI / │ │ 工具 │ │ 权限管理器 │ │ │
│ │ │ Headless │ │ 执行器 │ │ │ │ │
│ │ └────┬─────┘ └────┬─────┘ └────────┬─────────┘ │ │
│ │ │ │ │ │ │
│ │ └─────────────┴─────────────────┘ │ │
│ │ │ │ │
│ │ ┌──────┴──────┐ │ │
│ │ │ Letta TS SDK│ │ │
│ │ └──────┬──────┘ │ │
│ └──────────────────────┼──────────────────────────────┘ │
└─────────────────────────┼──────────────────────────────────┘
│
│ Letta API
│
┌─────┴─────┐
│ Letta │
│ 服务器 │
└───────────┘
Letta Code 的主要工作是:
- 管理消息生命周期 - 在用户和代理之间发送消息
- 本地执行工具 - 在您的机器上运行 Bash、Read、Write、Edit 等
- 处理权限 - 在工具执行前提示用户批准
- 提供终端 UI - 渲染代理状态、流式响应和工具调用
客户端工具执行
让 Letta Code 工作的核心机制是客户端工具执行。您的 Letta 代理运行在外部服务器上,但它调用的工具——如 Bash、Read 和 Write——在您的机器上本地执行。
这是通过 Letta API 的 客户端工具 功能实现的:
- 代理请求工具 - 代理决定调用
Bash(ls -la) - 服务器暂停代理执行等待批准 - 请求发送到您的终端
- Letta Code 本地执行 - 命令在您的机器上运行
- 结果返回 - 输出返回给代理继续
// 简化版:Letta Code 如何处理工具执行
const response = await client.agents.messages.create(agentId, {
messages: [{ role: "user", content: userInput }],
});
for (const msg of response.messages) {
if (msg.message_type === "approval_request_message") {
// 本地执行工具
const result = await executeToolLocally(msg.tool_call);
// 将结果发送回代理
await client.agents.messages.create(agentId, {
messages: [{
type: "approval",
approvals: [{
type: "tool",
tool_call_id: msg.tool_call.tool_call_id,
tool_return: result,
status: "success",
}],
}],
});
}
}
流式传输
Letta Code 使用 SDK 的 流式 API 实时显示推理、消息和工具调用。
const stream = await client.agents.messages.stream(agentId, {
messages: [{ role: "user", content: userInput }],
stream_tokens: true,
});
for await (const chunk of stream) {
if (chunk.message_type === "reasoning_message") {
process.stdout.write(chunk.reasoning);
} else if (chunk.message_type === "assistant_message") {
process.stdout.write(chunk.content);
}
}
后台模式流式传输
由于编程代理通常是长时间运行的,Letta Code 使用 后台模式流式传输。
这将代理执行与客户端连接解耦,允许:
- 可恢复的流 - 如果您的连接断开,您可以重新连接并从断开的地方继续
- 崩溃恢复 - 即使您的终端关闭,代理也会在服务器上继续处理
- 长时间操作 - 耗时 10+ 分钟的任务不会超时
// 后台模式在服务器端持久化流
const stream = await client.agents.messages.stream(agentId, {
messages: [{ role: "user", content: userInput }],
stream_tokens: true,
background: true, // 启用后台模式
});
// 每个块包含 run_id 和 seq_id 用于恢复
let runId, lastSeqId;
for await (const chunk of stream) {
if (chunk.run_id && chunk.seq_id) {
runId = chunk.run_id;
lastSeqId = chunk.seq_id;
}
// 处理块...
}
// 如果断开连接,从最后位置恢复
for await (const chunk of client.runs.stream(runId, {
starting_after: lastSeqId,
})) {
// 继续处理...
}
对话
Letta Code 将消息线程组织为对话。单个代理可以同时运行多个对话——所有对话共享相同的记忆块和可搜索的消息历史。
这让您可以同时运行多个编程会话(一个重构您的 API,另一个编写测试),具有独立的上下文窗口但共享知识。来自所有对话的消息汇集在一起并可搜索,因此您的代理可以回忆任何过去会话的上下文。
默认情况下,启动 letta 会恢复与您上次使用的代理的"默认"对话。使用 --new 为并行会话开始新对话,--continue 完全恢复您上次的会话,--resume 交互式浏览过去的对话,或在会话期间使用 /resume 在对话之间切换。
您的 Letta Code 代理是通用 Letta 代理
重要的一点:Letta Code 创建的代理是通用 Letta 代理。
这意味着它们可以通过以下方式完全访问:
- Letta API - 使用 Python 和 TypeScript SDK 或任何 REST 端点来修改/访问/消息它们
- ADE - 在 app.letta.com 查看和交互
- 其他客户端 - 在 Letta API 之上构建自己的界面(例如使用 Vercel AI SDK)
Letta Code 只是将一组专注于编程的工具和提示附加到您的代理,并提供终端界面与它们交互。
代理本身,包括它们的记忆和对话历史,存在于 Letta 服务器上。
这意味着您可以:
- 在 Letta Code 中开始会话,然后在 ADE 中继续
- 使用 API 以编程方式与您的编程代理交互
- 构建自定义 UI(例如仪表板)来查看您的 Letta Code 代理,即使您不在终端前