@letta-ai/letta-code 0.31.11 → 0.31.13
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/README.md +16 -14
- package/dist/agent-presets.js +3 -3
- package/dist/agent-presets.js.map +1 -1
- package/dist/channels-slack.js +20 -1
- package/dist/channels-slack.js.map +3 -3
- package/dist/gateway-core.js +2 -1
- package/dist/gateway-core.js.map +3 -3
- package/dist/mcp-client.js +4 -4
- package/dist/mcp-client.js.map +2 -2
- package/dist/types/agent/subagents/manager.d.ts +1 -1
- package/dist/types/agent/subagents/manager.d.ts.map +1 -1
- package/dist/types/backend/api/client.d.ts.map +1 -1
- package/dist/types/backend/backend.d.ts +1 -0
- package/dist/types/backend/backend.d.ts.map +1 -1
- package/dist/types/channels/message-channel-tool-definition.d.ts.map +1 -1
- package/dist/types/channels/plugin-types.d.ts +1 -1
- package/dist/types/channels/plugin-types.d.ts.map +1 -1
- package/dist/types/channels/slack/internal-types.d.ts +5 -0
- package/dist/types/channels/slack/internal-types.d.ts.map +1 -1
- package/dist/types/channels/slack/message-action-contract.d.ts +2 -0
- package/dist/types/channels/slack/message-action-contract.d.ts.map +1 -1
- package/dist/types/channels/types.d.ts +1 -0
- package/dist/types/channels/types.d.ts.map +1 -1
- package/dist/types/cli/helpers/git-context.d.ts +1 -1
- package/dist/types/cli/helpers/git-context.d.ts.map +1 -1
- package/dist/types/tools/impl/bash.d.ts +2 -0
- package/dist/types/tools/impl/bash.d.ts.map +1 -1
- package/dist/types/tools/impl/exec-command.d.ts +8 -0
- package/dist/types/tools/impl/exec-command.d.ts.map +1 -1
- package/dist/types/tools/impl/task.d.ts +2 -2
- package/dist/types/websocket/listener/cwd-change.d.ts.map +1 -1
- package/dist/types/websocket/listener/device-git-context.d.ts +17 -0
- package/dist/types/websocket/listener/device-git-context.d.ts.map +1 -0
- package/dist/types/websocket/listener/listener-constants.d.ts.map +1 -1
- package/dist/types/websocket/listener/protocol-outbound.d.ts +1 -0
- package/dist/types/websocket/listener/protocol-outbound.d.ts.map +1 -1
- package/dist/types/websocket/listener/stream-observers.d.ts.map +1 -1
- package/dist/types/websocket/listener/worktree-watcher.d.ts.map +1 -1
- package/letta.js +1008 -888
- package/package.json +3 -2
- package/scripts/codex-watch/release-analysis.test.ts +87 -0
- package/scripts/codex-watch/release-analysis.ts +57 -7
- package/scripts/postinstall-patches.js +37 -14
- package/scripts/source-file-size-baseline.json +3 -3
- package/skills/browser-use/SKILL.md +22 -61
- package/skills/dispatching-coding-agents/SKILL.md +6 -6
- package/skills/messaging-agents/SKILL.md +34 -21
- package/skills/scheduling-tasks/SKILL.md +1 -1
- package/skills/submitting-feedback/SKILL.md +4 -2
- package/skills/teleporting-between-environments/SKILL.md +12 -12
- package/dist/types/tools/impl/foreground-sleep.d.ts +0 -13
- package/dist/types/tools/impl/foreground-sleep.d.ts.map +0 -1
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@letta-ai/letta-code",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.13",
|
|
4
4
|
"description": "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"packageManager": "bun@1.3.
|
|
6
|
+
"packageManager": "bun@1.3.14",
|
|
7
7
|
"bin": {
|
|
8
8
|
"letta": "letta.js"
|
|
9
9
|
},
|
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
},
|
|
123
123
|
"license": "Apache-2.0",
|
|
124
124
|
"engines": {
|
|
125
|
+
"bun": ">=1.3.2",
|
|
125
126
|
"node": ">=22.19.0"
|
|
126
127
|
},
|
|
127
128
|
"publishConfig": {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
findLatestStableReleaseAfter,
|
|
3
|
+
listStableReleases,
|
|
3
4
|
type Release,
|
|
4
5
|
releaseNotesForRange,
|
|
5
6
|
} from "./release-analysis.ts";
|
|
@@ -49,3 +50,89 @@ describe("Codex stable release range", () => {
|
|
|
49
50
|
);
|
|
50
51
|
});
|
|
51
52
|
});
|
|
53
|
+
|
|
54
|
+
describe("Codex GitHub release fetch", () => {
|
|
55
|
+
test("retries a server error before succeeding", async () => {
|
|
56
|
+
const sleeps: number[] = [];
|
|
57
|
+
let requests = 0;
|
|
58
|
+
|
|
59
|
+
const releases = await listStableReleases({
|
|
60
|
+
fetchImpl: (async () => {
|
|
61
|
+
requests++;
|
|
62
|
+
if (requests === 1) {
|
|
63
|
+
return new Response("Gateway Timeout", { status: 504 });
|
|
64
|
+
}
|
|
65
|
+
return new Response(JSON.stringify(STABLES), { status: 200 });
|
|
66
|
+
}) as typeof fetch,
|
|
67
|
+
sleep: async (delayMs) => {
|
|
68
|
+
sleeps.push(delayMs);
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(requests).toBe(2);
|
|
73
|
+
expect(sleeps).toEqual([1000]);
|
|
74
|
+
expect(releases).toEqual(STABLES);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("retries a network error before succeeding", async () => {
|
|
78
|
+
const sleeps: number[] = [];
|
|
79
|
+
let requests = 0;
|
|
80
|
+
|
|
81
|
+
const releases = await listStableReleases({
|
|
82
|
+
fetchImpl: (async () => {
|
|
83
|
+
requests++;
|
|
84
|
+
if (requests === 1) throw new TypeError("fetch failed: ECONNRESET");
|
|
85
|
+
return new Response(JSON.stringify(STABLES), { status: 200 });
|
|
86
|
+
}) as typeof fetch,
|
|
87
|
+
sleep: async (delayMs) => {
|
|
88
|
+
sleeps.push(delayMs);
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
expect(requests).toBe(2);
|
|
93
|
+
expect(sleeps).toEqual([1000]);
|
|
94
|
+
expect(releases).toEqual(STABLES);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("stops after the bounded retry budget", async () => {
|
|
98
|
+
const sleeps: number[] = [];
|
|
99
|
+
let requests = 0;
|
|
100
|
+
|
|
101
|
+
const result = listStableReleases({
|
|
102
|
+
fetchImpl: (async () => {
|
|
103
|
+
requests++;
|
|
104
|
+
return new Response("Gateway Timeout", { status: 504 });
|
|
105
|
+
}) as typeof fetch,
|
|
106
|
+
sleep: async (delayMs) => {
|
|
107
|
+
sleeps.push(delayMs);
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
await expect(result).rejects.toThrow(
|
|
112
|
+
"GitHub releases API failed (504): Gateway Timeout",
|
|
113
|
+
);
|
|
114
|
+
expect(requests).toBe(3);
|
|
115
|
+
expect(sleeps).toEqual([1000, 2000]);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("fails immediately on a client error", async () => {
|
|
119
|
+
const sleeps: number[] = [];
|
|
120
|
+
let requests = 0;
|
|
121
|
+
|
|
122
|
+
const result = listStableReleases({
|
|
123
|
+
fetchImpl: (async () => {
|
|
124
|
+
requests++;
|
|
125
|
+
return new Response("Not Found", { status: 404 });
|
|
126
|
+
}) as typeof fetch,
|
|
127
|
+
sleep: async (delayMs) => {
|
|
128
|
+
sleeps.push(delayMs);
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
await expect(result).rejects.toThrow(
|
|
133
|
+
"GitHub releases API failed (404): Not Found",
|
|
134
|
+
);
|
|
135
|
+
expect(requests).toBe(1);
|
|
136
|
+
expect(sleeps).toEqual([]);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
@@ -21,6 +21,8 @@ export const WATCHED_PATHS = [
|
|
|
21
21
|
];
|
|
22
22
|
|
|
23
23
|
const MAX_COMMITS_PER_PATH = 8;
|
|
24
|
+
const GITHUB_RELEASES_FETCH_ATTEMPTS = 3;
|
|
25
|
+
const GITHUB_RELEASES_RETRY_DELAY_MS = 1_000;
|
|
24
26
|
|
|
25
27
|
export interface Release {
|
|
26
28
|
tag_name: string;
|
|
@@ -167,7 +169,12 @@ export async function analyzeCodexRelease(
|
|
|
167
169
|
}
|
|
168
170
|
}
|
|
169
171
|
|
|
170
|
-
export async function listStableReleases(
|
|
172
|
+
export async function listStableReleases(
|
|
173
|
+
options: {
|
|
174
|
+
fetchImpl?: typeof fetch;
|
|
175
|
+
sleep?: (delayMs: number) => Promise<void>;
|
|
176
|
+
} = {},
|
|
177
|
+
): Promise<Release[]> {
|
|
171
178
|
const releases: Release[] = [];
|
|
172
179
|
const headers: Record<string, string> = {
|
|
173
180
|
Accept: "application/vnd.github+json",
|
|
@@ -175,15 +182,15 @@ export async function listStableReleases(): Promise<Release[]> {
|
|
|
175
182
|
};
|
|
176
183
|
const token = process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
|
|
177
184
|
if (token) headers.Authorization = `Bearer ${token}`;
|
|
185
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
186
|
+
const sleep =
|
|
187
|
+
options.sleep ??
|
|
188
|
+
((delayMs: number) =>
|
|
189
|
+
new Promise<void>((resolve) => setTimeout(resolve, delayMs)));
|
|
178
190
|
|
|
179
191
|
for (let page = 1; page <= 10; page++) {
|
|
180
192
|
const url = `https://api.github.com/repos/${CODEX_REPO}/releases?per_page=100&page=${page}`;
|
|
181
|
-
const res = await
|
|
182
|
-
if (!res.ok) {
|
|
183
|
-
throw new Error(
|
|
184
|
-
`GitHub releases API failed (${res.status}): ${await res.text()}`,
|
|
185
|
-
);
|
|
186
|
-
}
|
|
193
|
+
const res = await fetchGitHubReleasesPage(url, headers, fetchImpl, sleep);
|
|
187
194
|
const batch = (await res.json()) as Release[];
|
|
188
195
|
releases.push(...batch);
|
|
189
196
|
if (batch.length < 100) break;
|
|
@@ -193,6 +200,49 @@ export async function listStableReleases(): Promise<Release[]> {
|
|
|
193
200
|
.sort((a, b) => (a.published_at ?? "").localeCompare(b.published_at ?? ""));
|
|
194
201
|
}
|
|
195
202
|
|
|
203
|
+
async function fetchGitHubReleasesPage(
|
|
204
|
+
url: string,
|
|
205
|
+
headers: Record<string, string>,
|
|
206
|
+
fetchImpl: typeof fetch,
|
|
207
|
+
sleep: (delayMs: number) => Promise<void>,
|
|
208
|
+
): Promise<Response> {
|
|
209
|
+
for (let attempt = 1; ; attempt++) {
|
|
210
|
+
let response: Response;
|
|
211
|
+
try {
|
|
212
|
+
response = await fetchImpl(url, { headers });
|
|
213
|
+
} catch (error) {
|
|
214
|
+
if (attempt === GITHUB_RELEASES_FETCH_ATTEMPTS) {
|
|
215
|
+
throw new Error(
|
|
216
|
+
`GitHub releases API request failed after ${attempt} attempts: ${String(error)}`,
|
|
217
|
+
{ cause: error },
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
await retryGitHubReleasesFetch(attempt, String(error), sleep);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (response.ok) return response;
|
|
225
|
+
|
|
226
|
+
const message = `GitHub releases API failed (${response.status}): ${await response.text()}`;
|
|
227
|
+
if (response.status < 500 || attempt === GITHUB_RELEASES_FETCH_ATTEMPTS) {
|
|
228
|
+
throw new Error(message);
|
|
229
|
+
}
|
|
230
|
+
await retryGitHubReleasesFetch(attempt, message, sleep);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function retryGitHubReleasesFetch(
|
|
235
|
+
attempt: number,
|
|
236
|
+
error: string,
|
|
237
|
+
sleep: (delayMs: number) => Promise<void>,
|
|
238
|
+
): Promise<void> {
|
|
239
|
+
const delayMs = GITHUB_RELEASES_RETRY_DELAY_MS * 2 ** (attempt - 1);
|
|
240
|
+
console.warn(
|
|
241
|
+
`${error}; retrying GitHub releases request in ${delayMs}ms (${attempt}/${GITHUB_RELEASES_FETCH_ATTEMPTS})`,
|
|
242
|
+
);
|
|
243
|
+
await sleep(delayMs);
|
|
244
|
+
}
|
|
245
|
+
|
|
196
246
|
function isStableRelease(release: Release): boolean {
|
|
197
247
|
if (release.draft || release.prerelease) return false;
|
|
198
248
|
return /^(rust-v|v)?\d+\.\d+\.\d+$/.test(release.tag_name);
|
|
@@ -16,6 +16,20 @@ import { fileURLToPath } from "node:url";
|
|
|
16
16
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
17
|
const pkgRoot = dirname(__dirname);
|
|
18
18
|
const require = createRequire(import.meta.url);
|
|
19
|
+
const packageJson = JSON.parse(
|
|
20
|
+
readFileSync(join(pkgRoot, "package.json"), "utf-8"),
|
|
21
|
+
);
|
|
22
|
+
const minimumBunVersion = packageJson.engines.bun.replace(/^>=/, "");
|
|
23
|
+
|
|
24
|
+
function isBunVersionSupported(version) {
|
|
25
|
+
const current = version.split(".").map(Number);
|
|
26
|
+
const minimum = minimumBunVersion.split(".").map(Number);
|
|
27
|
+
for (let index = 0; index < minimum.length; index++) {
|
|
28
|
+
if ((current[index] ?? 0) > (minimum[index] ?? 0)) return true;
|
|
29
|
+
if ((current[index] ?? 0) < (minimum[index] ?? 0)) return false;
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
19
33
|
|
|
20
34
|
async function copyToResolved(srcRel, targetSpecifier) {
|
|
21
35
|
const src = join(pkgRoot, srcRel);
|
|
@@ -100,7 +114,10 @@ await copyToResolved(
|
|
|
100
114
|
"ink/build/hooks/use-input.js",
|
|
101
115
|
);
|
|
102
116
|
await copyToResolved("vendor/ink/build/devtools.js", "ink/build/devtools.js");
|
|
103
|
-
await copyToResolved(
|
|
117
|
+
await copyToResolved(
|
|
118
|
+
"vendor/ink/build/log-update.js",
|
|
119
|
+
"ink/build/log-update.js",
|
|
120
|
+
);
|
|
104
121
|
await copyToResolved("vendor/ink/build/wrap-text.js", "ink/build/wrap-text.js");
|
|
105
122
|
|
|
106
123
|
// ink-text-input (optional vendor with externalCursorOffset support)
|
|
@@ -111,24 +128,30 @@ await copyToResolved(
|
|
|
111
128
|
|
|
112
129
|
console.log("[patch] Ink runtime patched");
|
|
113
130
|
|
|
114
|
-
// On Unix with Bun available, use polyglot shebang to prefer
|
|
131
|
+
// On Unix with a supported Bun available, use a polyglot shebang to prefer it.
|
|
115
132
|
// This enables Bun.secrets for secure keychain storage instead of fallback.
|
|
116
|
-
// Windows
|
|
133
|
+
// Windows and installs with an older Bun keep the Node shebang.
|
|
117
134
|
if (process.platform !== "win32") {
|
|
118
135
|
try {
|
|
119
|
-
execSync("bun --version", {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
136
|
+
const bunVersion = execSync("bun --version", { encoding: "utf-8" }).trim();
|
|
137
|
+
if (isBunVersionSupported(bunVersion)) {
|
|
138
|
+
const lettaPath = join(pkgRoot, "letta.js");
|
|
139
|
+
if (existsSync(lettaPath)) {
|
|
140
|
+
let content = readFileSync(lettaPath, "utf-8");
|
|
141
|
+
if (content.startsWith("#!/usr/bin/env node")) {
|
|
142
|
+
content = content.replace(
|
|
143
|
+
"#!/usr/bin/env node",
|
|
144
|
+
`#!/bin/sh
|
|
127
145
|
":" //#; exec /usr/bin/env sh -c 'command -v bun >/dev/null && exec bun "$0" "$@" || exec node "$0" "$@"' "$0" "$@"`,
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
146
|
+
);
|
|
147
|
+
writeFileSync(lettaPath, content);
|
|
148
|
+
console.log("[patch] Configured letta to prefer Bun runtime");
|
|
149
|
+
}
|
|
131
150
|
}
|
|
151
|
+
} else {
|
|
152
|
+
console.log(
|
|
153
|
+
`[patch] Bun ${bunVersion} is below ${minimumBunVersion}; keeping Node runtime`,
|
|
154
|
+
);
|
|
132
155
|
}
|
|
133
156
|
} catch {
|
|
134
157
|
// Bun not available, keep node shebang
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"src/cli/app/use-approval-flow.ts": 1163,
|
|
11
11
|
"src/cli/app/use-configuration-handlers.ts": 1421,
|
|
12
12
|
"src/cli/app/use-conversation-loop.ts": 2912,
|
|
13
|
-
"src/cli/app/use-submit-handler.ts":
|
|
13
|
+
"src/cli/app/use-submit-handler.ts": 4074,
|
|
14
14
|
"src/cli/components/AgentSelector.tsx": 1104,
|
|
15
15
|
"src/cli/components/InputRich.tsx": 2225,
|
|
16
16
|
"src/cli/components/ModelSelector.tsx": 1259,
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"src/cli/mods/local-mod-loader.test.ts": 1043,
|
|
22
22
|
"src/cli/reflection-transcript.test.ts": 1084,
|
|
23
23
|
"src/cli/subcommands/skills.ts": 1264,
|
|
24
|
-
"src/headless.ts":
|
|
24
|
+
"src/headless.ts": 4986,
|
|
25
25
|
"src/hooks/integration.test.ts": 1147,
|
|
26
26
|
"src/index.ts": 2773,
|
|
27
27
|
"src/mods/learning-harness.ts": 2434,
|
|
@@ -44,6 +44,6 @@
|
|
|
44
44
|
"src/websocket/listener/file-commands.ts": 1053,
|
|
45
45
|
"src/websocket/listener/lifecycle.ts": 1048,
|
|
46
46
|
"src/websocket/listener/protocol-inbound.ts": 2207,
|
|
47
|
-
"src/websocket/listener/protocol-outbound.ts":
|
|
47
|
+
"src/websocket/listener/protocol-outbound.ts": 1042,
|
|
48
48
|
"src/websocket/listener/turn.ts": 1058
|
|
49
49
|
}
|
|
@@ -19,66 +19,30 @@ Protocol reference: https://chromedevtools.github.io/devtools-protocol/.
|
|
|
19
19
|
The running browser's exact schema is at `http://127.0.0.1:<port>/json/protocol`;
|
|
20
20
|
tip-of-tree docs can differ from the installed version.
|
|
21
21
|
|
|
22
|
-
##
|
|
23
|
-
|
|
24
|
-
When
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
It starts the managed desktop and launches Chrome through the persistent Cua
|
|
39
|
-
Driver with its required root flag. Then load `computer-use` for visible
|
|
40
|
-
interaction. If protocol-level control is necessary, use Cua Driver's explicit
|
|
41
|
-
`browser_prepare` flow after binding the exact visible window; do not pass
|
|
42
|
-
remote-debugging flags through `launch_app`. The launcher exits zero only
|
|
43
|
-
after Cua Driver reports an on-screen browser window. If it exits nonzero, stop
|
|
44
|
-
and report the launch failure instead of claiming the browser opened.
|
|
22
|
+
## Visible by default when a display exists
|
|
23
|
+
|
|
24
|
+
When the computer has a display, prefer a visible (headful) browser for any
|
|
25
|
+
task the user might watch or take over: clicking or typing, forms, sign-in,
|
|
26
|
+
checkout/payment, CAPTCHAs or bot protection, and user handoff. Most browser
|
|
27
|
+
tasks exist because plain HTTP is not enough; a headless browser is more
|
|
28
|
+
likely to trigger bot protection and gives the user no way to observe or step
|
|
29
|
+
in. Visible does not mean pixel-driven: keep operating the page over CDP, and
|
|
30
|
+
the user sees every action in the window.
|
|
31
|
+
|
|
32
|
+
Use headless mode only for work the user explicitly wants in the background
|
|
33
|
+
and that cannot require interaction or handoff, such as read-only scraping,
|
|
34
|
+
CI, or screenshot/PDF generation, or when no display exists. A headless page
|
|
35
|
+
does not satisfy a request to open or reopen a site in a browser the user can
|
|
36
|
+
see.
|
|
45
37
|
|
|
46
38
|
When the user asks to review, watch, or take over, leave that browser window
|
|
47
39
|
open after the task. Do not kill or close it before replying.
|
|
48
40
|
|
|
49
|
-
1. Run `start-letta-desktop` and use its exit status as the result. Warnings
|
|
50
|
-
from optional services do not mean startup failed when the command exits 0.
|
|
51
|
-
If it exits nonzero, stop and report that the managed desktop is
|
|
52
|
-
unavailable. Never create another Xvfb, VNC server, or private display: the
|
|
53
|
-
Computer viewer only shows the managed desktop.
|
|
54
|
-
2. Load `computer-use`, inspect the managed desktop, and use Cua Driver to
|
|
55
|
-
operate an existing Chrome window or launch Chrome there. When launching,
|
|
56
|
-
round-trip Chrome's `launch_path` from `cua-driver call list_apps '{}'
|
|
57
|
-
instead of rebuilding it; the managed launch path carries required flags.
|
|
58
|
-
For forms, sign-in, checkout, CAPTCHA, and bot-protected pages, keep using
|
|
59
|
-
Cua Driver so the interaction remains visible and available for user
|
|
60
|
-
takeover.
|
|
61
|
-
3. Use CDP only when protocol-level inspection or deterministic automation is
|
|
62
|
-
needed. Bind the exact visible browser window with Cua Driver, then use its
|
|
63
|
-
explicit `browser_prepare` flow. Do not pass remote-debugging flags
|
|
64
|
-
through `launch_app`. Include `--no-sandbox` when running Chrome as
|
|
65
|
-
root. Do not add `--headless` or override `DISPLAY`.
|
|
66
|
-
4. Use headless mode only for work the user explicitly wants in the background
|
|
67
|
-
and that cannot require interaction or handoff, such as read-only scraping,
|
|
68
|
-
CI, or screenshot/PDF generation.
|
|
69
|
-
5. Verify the result through the managed desktop window (Cua Driver window
|
|
70
|
-
state or screenshot), not only through DOM output or a screenshot from a
|
|
71
|
-
separate process.
|
|
72
|
-
|
|
73
|
-
A headless page does not satisfy a request to open or reopen a site in the
|
|
74
|
-
user-visible browser.
|
|
75
|
-
|
|
76
41
|
## Workflow
|
|
77
42
|
|
|
78
43
|
1. Find a Chromium-based browser (below). If none exists, see "No Chrome installed".
|
|
79
|
-
2.
|
|
80
|
-
|
|
81
|
-
attach to the user's normal profile unless explicitly asked.
|
|
44
|
+
2. Launch with a dedicated profile and remote debugging. Never attach to the
|
|
45
|
+
user's normal profile unless explicitly asked.
|
|
82
46
|
3. Discover targets via `/json/list`; pick the `"page"` target by URL or title.
|
|
83
47
|
4. Connect to its `webSocketDebuggerUrl` and enable only the domains you need
|
|
84
48
|
(usually `Page`, `Runtime`, `DOM`, `Input`; add `Network`, `Log` when debugging).
|
|
@@ -124,7 +88,7 @@ Tell the user that browser use requires Chrome or another Chromium-based
|
|
|
124
88
|
browser and recommend either:
|
|
125
89
|
|
|
126
90
|
1. Install Chrome on the current computer, then retry the browser task.
|
|
127
|
-
2. Teleport the conversation back to its Cloud sandbox, where
|
|
91
|
+
2. Teleport the conversation back to its Cloud sandbox, where a
|
|
128
92
|
browser is already installed.
|
|
129
93
|
|
|
130
94
|
Wait for the user to choose. Do not silently replace the browser task with
|
|
@@ -132,9 +96,8 @@ plain HTTP or claim browser automation succeeded.
|
|
|
132
96
|
|
|
133
97
|
## Launching
|
|
134
98
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
`id -u` is 0:
|
|
99
|
+
Use a disposable profile and a fixed port. Chrome refuses to run as root
|
|
100
|
+
without `--no-sandbox`, so add that flag when `id -u` is 0:
|
|
138
101
|
|
|
139
102
|
```bash
|
|
140
103
|
chrome_args=( \
|
|
@@ -149,10 +112,8 @@ chrome_args=( \
|
|
|
149
112
|
"$CHROME" "${chrome_args[@]}" https://example.com
|
|
150
113
|
```
|
|
151
114
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
the visible-browser rule above and never replace its managed display with a
|
|
155
|
-
private one.
|
|
115
|
+
Add `--headless=new` only for explicitly invisible work or when no display
|
|
116
|
+
exists (see "Visible by default" above).
|
|
156
117
|
With `--remote-debugging-port=0`, read the chosen port from
|
|
157
118
|
`<user-data-dir>/DevToolsActivePort`. Launch in the background and poll
|
|
158
119
|
`http://127.0.0.1:9222/json/version` until it responds.
|
|
@@ -66,7 +66,7 @@ Different agents have different strengths. Track what works in your memory over
|
|
|
66
66
|
- Use `--max-budget-usd N` (Claude Code) to cap spend on exploratory tasks
|
|
67
67
|
|
|
68
68
|
### Known quirks
|
|
69
|
-
- **Claude Code can hang on large repos** with unrestricted tools — consider `--
|
|
69
|
+
- **Claude Code can hang on large repos** with unrestricted tools — consider `--tools "Read Grep Glob"` (no Bash) and shorter timeouts for research tasks
|
|
70
70
|
- **Codex compactions can destroy long trajectories** — for very long tasks, prefer multiple shorter sessions over one marathon
|
|
71
71
|
- **Opus tends to over-generate** — produces more code than necessary. Good for exploration, verify before applying.
|
|
72
72
|
|
|
@@ -135,7 +135,7 @@ cd /path/to/repo && claude -p "Read /tmp/my-plan.md and critique it. What am I m
|
|
|
135
135
|
|
|
136
136
|
## Handling Failures
|
|
137
137
|
|
|
138
|
-
- **Timeout**: If an agent times out (especially Claude Code on large repos), try: (1) a shorter, more focused prompt, (2) restricting tools with `--
|
|
138
|
+
- **Timeout**: If an agent times out (especially Claude Code on large repos), try: (1) a shorter, more focused prompt, (2) restricting tools with `--tools`, (3) switching to Codex which handles large repos better
|
|
139
139
|
- **Garbage output**: If results are incoherent, the prompt was probably too vague. Rewrite with more specific file paths and clearer instructions.
|
|
140
140
|
- **Session errors**: Claude Code can hit "stale approval from interrupted session" — `--dangerously-skip-permissions` prevents this. If Codex errors, start a fresh `exec` session.
|
|
141
141
|
- **Compaction mid-task**: If a Codex session runs long enough to compact, it may lose earlier context. Break long tasks into smaller sequential sessions.
|
|
@@ -153,12 +153,13 @@ claude -p "YOUR PROMPT" --model MODEL --dangerously-skip-permissions
|
|
|
153
153
|
| `-p` / `--print` | Non-interactive mode, prints response and exits |
|
|
154
154
|
| `--dangerously-skip-permissions` | Skip approval prompts (prevents stale approval errors on timeout) |
|
|
155
155
|
| `--model MODEL` | Alias or model name accepted by the installed CLI; omit to use the configured default |
|
|
156
|
-
| `--effort LEVEL` | `low`, `medium`, `high` — controls reasoning depth |
|
|
156
|
+
| `--effort LEVEL` | `low`, `medium`, `high`, `xhigh`, `max` — controls reasoning depth |
|
|
157
157
|
| `--append-system-prompt "..."` | Inject additional system instructions |
|
|
158
|
-
| `--allowedTools "Bash Edit Read"` |
|
|
158
|
+
| `--allowedTools "Bash Edit Read"` | Tools that execute without prompting for permission |
|
|
159
|
+
| `--tools "Read Grep Glob"` | Restrict which built-in tools are available |
|
|
159
160
|
| `--max-budget-usd N` | Cap spend for the invocation |
|
|
160
161
|
| `--add-dir DIR` | Allow access to an additional directory; does not change the working directory |
|
|
161
|
-
| `--output-format json` | Structured output with `session_id`, `
|
|
162
|
+
| `--output-format json` | Structured output with `session_id`, `total_cost_usd`, `duration_ms` |
|
|
162
163
|
|
|
163
164
|
Set Claude Code's working directory with `cd /path/to/repo && claude ...` in the Bash command, not with a Claude flag.
|
|
164
165
|
|
|
@@ -174,7 +175,6 @@ codex exec "YOUR PROMPT" --sandbox workspace-write
|
|
|
174
175
|
| `-m MODEL` | Model accepted by the installed CLI; omit to use the configured default |
|
|
175
176
|
| `--sandbox MODE` | Select a read-only or writable sandbox |
|
|
176
177
|
| `-C DIR` | Set working directory |
|
|
177
|
-
| `--search` | Enable web search tool |
|
|
178
178
|
| `review` | Native code review — `codex review --uncommitted` or `codex exec review "prompt"` |
|
|
179
179
|
|
|
180
180
|
## Session Management
|
|
@@ -66,15 +66,24 @@ Results include `agent_id` for each matching message.
|
|
|
66
66
|
letta -p --from-agent $LETTA_AGENT_ID --agent <id> "message text"
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
When no `--
|
|
70
|
-
|
|
69
|
+
When no `--computer` is specified, the target agent will run on the same
|
|
70
|
+
computer as the caller agent.
|
|
71
71
|
|
|
72
|
-
To route the target agent turn through a specific remote/local
|
|
72
|
+
To route the target agent turn through a specific remote/local computer:
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
75
|
letta -p --from-agent $LETTA_AGENT_ID \
|
|
76
76
|
--agent <id> \
|
|
77
|
-
--
|
|
77
|
+
--computer <name-or-device-id-or-connection-id> \
|
|
78
|
+
"message text"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Use `--computer cloud` to route through the target agent's cloud sandbox:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
letta -p --from-agent $LETTA_AGENT_ID \
|
|
85
|
+
--agent <id> \
|
|
86
|
+
--computer cloud \
|
|
78
87
|
"message text"
|
|
79
88
|
```
|
|
80
89
|
|
|
@@ -83,7 +92,7 @@ letta -p --from-agent $LETTA_AGENT_ID \
|
|
|
83
92
|
|-----|----------|-------------|
|
|
84
93
|
| `--agent <id>` | Yes | Target agent ID to message |
|
|
85
94
|
| `--from-agent <id>` | Yes | Sender agent ID (injects agent-to-agent system reminder) |
|
|
86
|
-
| `--
|
|
95
|
+
| `--computer <selector>` | No | Route through `cloud` (target agent's cloud sandbox) or an online computer by connection name, device ID, or connection ID |
|
|
87
96
|
| `"message text"` | Yes | Message body (positional after flags) |
|
|
88
97
|
|
|
89
98
|
**Example:**
|
|
@@ -93,13 +102,17 @@ letta -p --from-agent $LETTA_AGENT_ID \
|
|
|
93
102
|
"What do you know about the authentication system?"
|
|
94
103
|
```
|
|
95
104
|
|
|
96
|
-
**Response:**
|
|
105
|
+
**Response (JSON format with `--output json`):**
|
|
97
106
|
```json
|
|
98
107
|
{
|
|
99
|
-
"
|
|
100
|
-
"
|
|
108
|
+
"type": "result",
|
|
109
|
+
"subtype": "success",
|
|
110
|
+
"is_error": false,
|
|
111
|
+
"result": "The authentication system uses JWT tokens...",
|
|
101
112
|
"agent_id": "agent-abc123",
|
|
102
|
-
"
|
|
113
|
+
"conversation_id": "conversation-xyz789",
|
|
114
|
+
"environment": { "source": "same-environment" },
|
|
115
|
+
"usage": { "prompt_tokens": 120, "completion_tokens": 80, "total_tokens": 200, "step_count": 1 }
|
|
103
116
|
}
|
|
104
117
|
```
|
|
105
118
|
|
|
@@ -109,34 +122,34 @@ letta -p --from-agent $LETTA_AGENT_ID \
|
|
|
109
122
|
letta -p --from-agent $LETTA_AGENT_ID --conversation <id> "message text"
|
|
110
123
|
```
|
|
111
124
|
|
|
112
|
-
Add `--
|
|
125
|
+
Add `--computer <selector>` to continue the conversation on a specific computer.
|
|
113
126
|
|
|
114
|
-
### Discovering
|
|
127
|
+
### Discovering Computers
|
|
115
128
|
|
|
116
129
|
```bash
|
|
117
|
-
letta
|
|
130
|
+
letta computers list --online-only
|
|
118
131
|
# alias:
|
|
119
132
|
letta envs list --online-only
|
|
120
133
|
```
|
|
121
134
|
|
|
122
135
|
Use `connectionName`, `deviceId`, or `connectionId` from the JSON output as the
|
|
123
|
-
`--
|
|
124
|
-
`connectionId`. In `
|
|
136
|
+
`--computer` selector. If a name is ambiguous, prefer `deviceId` or
|
|
137
|
+
`connectionId`. In `computers list`, the current local runtime is marked with
|
|
125
138
|
`"isCurrent": true`.
|
|
126
139
|
|
|
127
|
-
To force the target agent onto the current registered Letta Code
|
|
128
|
-
resolve the current
|
|
140
|
+
To force the target agent onto the current registered Letta Code computer,
|
|
141
|
+
resolve the current computer and pass its `connectionId`:
|
|
129
142
|
|
|
130
143
|
```bash
|
|
131
|
-
|
|
144
|
+
CURRENT_COMPUTER=$(letta computers current | jq -r .connectionId)
|
|
132
145
|
letta -p --from-agent $LETTA_AGENT_ID \
|
|
133
146
|
--agent agent-abc123 \
|
|
134
|
-
--
|
|
135
|
-
"Run on my same
|
|
147
|
+
--computer "$CURRENT_COMPUTER" \
|
|
148
|
+
"Run on my same computer."
|
|
136
149
|
```
|
|
137
150
|
|
|
138
|
-
Omit `--
|
|
139
|
-
|
|
151
|
+
Omit `--computer` when you want the target agent to run on the same computer as
|
|
152
|
+
the caller agent.
|
|
140
153
|
|
|
141
154
|
**Arguments:**
|
|
142
155
|
| Arg | Required | Description |
|
|
@@ -21,7 +21,7 @@ This skill lets you create, list, and manage scheduled tasks using the `letta cr
|
|
|
21
21
|
Pass a flag only when you have a requirement the default can't infer:
|
|
22
22
|
|
|
23
23
|
- **`--runner cloud`** — the schedule must fire no matter which computers are online; execute in the agent's cloud sandbox.
|
|
24
|
-
- **`--computer <deviceId>`** — the work needs a specific connected computer (its filesystem, services, or credentials). Get the deviceId from `letta
|
|
24
|
+
- **`--computer <deviceId>`** — the work needs a specific connected computer (its filesystem, services, or credentials). Get the deviceId from `letta computers list`. If that computer is offline at fire time, execution falls back to the cloud sandbox.
|
|
25
25
|
- **`--runner local`** — the work must only ever run on the current computer, even if that means missing fires while no session is running here.
|
|
26
26
|
|
|
27
27
|
The CLI reports its placement in the command output. If it warns that the schedule is local (this happens when the cloud scheduler cannot reach the current computer), the schedule only fires while a Letta session is running here — read the warning and decide whether that's acceptable.
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: submitting-feedback
|
|
3
|
-
description: Submits user-approved feedback about Letta Code
|
|
3
|
+
description: Submits user-approved product feedback and bug reports about Letta Code to the Letta team. Load when the user reports a Letta Code bug, requests a product or developer change, or explicitly asks to send feedback. Do not load for corrections to the current agent's behavior or preferences; those are memory edits. Works with cloud-hosted and local agents. Ask before submitting unless the user already explicitly requested submission.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Submitting Feedback
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Use this skill for product and developer feedback about Letta Code: reproducible bugs, broken features, confusing product behavior, and requested changes to the software or its developer-facing behavior.
|
|
9
|
+
|
|
10
|
+
Do **not** use this skill when the user corrects how the current agent should behave, communicate, remember, or work with them. Treat that as learning: make the appropriate memory edit so the correction changes the agent's future behavior. A user's frustration with the agent is not by itself product feedback and is not a reason to offer feedback submission.
|
|
9
11
|
|
|
10
12
|
If the user says yes, or directly asks you to submit feedback:
|
|
11
13
|
|