@letta-ai/letta-code 0.32.1 → 0.32.3

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.
Files changed (74) hide show
  1. package/README.md +6 -0
  2. package/dist/agent-presets.js +25 -1
  3. package/dist/agent-presets.js.map +2 -2
  4. package/dist/channels-public.js +32 -2
  5. package/dist/channels-public.js.map +3 -3
  6. package/dist/channels-slack.js +100 -4
  7. package/dist/channels-slack.js.map +7 -6
  8. package/dist/gateway-core.js +125 -32
  9. package/dist/gateway-core.js.map +8 -7
  10. package/dist/mcp-client.js +2 -2
  11. package/dist/mcp-client.js.map +1 -1
  12. package/dist/memory-constraints.js +77 -1
  13. package/dist/memory-constraints.js.map +5 -4
  14. package/dist/types/agent/memory-git-hooks.d.ts +1 -1
  15. package/dist/types/agent/memory-git-hooks.d.ts.map +1 -1
  16. package/dist/types/agent/skills.d.ts.map +1 -1
  17. package/dist/types/agent/subagents/manager.d.ts.map +1 -1
  18. package/dist/types/backend/backend.d.ts +0 -1
  19. package/dist/types/backend/backend.d.ts.map +1 -1
  20. package/dist/types/backend/dev/fake-headless-backend.d.ts.map +1 -1
  21. package/dist/types/channels/gateway-core.d.ts +2 -0
  22. package/dist/types/channels/gateway-core.d.ts.map +1 -1
  23. package/dist/types/channels/gateway-sources.d.ts +6 -0
  24. package/dist/types/channels/gateway-sources.d.ts.map +1 -0
  25. package/dist/types/channels/message-channel-bindings.d.ts +39 -0
  26. package/dist/types/channels/message-channel-bindings.d.ts.map +1 -0
  27. package/dist/types/channels/message-channel-executor.d.ts +4 -0
  28. package/dist/types/channels/message-channel-executor.d.ts.map +1 -1
  29. package/dist/types/channels/message-channel-tool-definition.d.ts.map +1 -1
  30. package/dist/types/channels/message-channel-types.d.ts +3 -1
  31. package/dist/types/channels/message-channel-types.d.ts.map +1 -1
  32. package/dist/types/channels/plugin-types.d.ts +9 -1
  33. package/dist/types/channels/plugin-types.d.ts.map +1 -1
  34. package/dist/types/channels/progress-builder.d.ts +1 -1
  35. package/dist/types/channels/progress-builder.d.ts.map +1 -1
  36. package/dist/types/channels/progress-types.d.ts +28 -0
  37. package/dist/types/channels/progress-types.d.ts.map +1 -0
  38. package/dist/types/channels/slack/message-action-contract.d.ts +2 -0
  39. package/dist/types/channels/slack/message-action-contract.d.ts.map +1 -1
  40. package/dist/types/channels/slack/progress.d.ts.map +1 -1
  41. package/dist/types/channels/slack/status-controller.d.ts +2 -1
  42. package/dist/types/channels/slack/status-controller.d.ts.map +1 -1
  43. package/dist/types/channels/types.d.ts +6 -23
  44. package/dist/types/channels/types.d.ts.map +1 -1
  45. package/dist/types/cli/helpers/app-urls.d.ts +0 -4
  46. package/dist/types/cli/helpers/app-urls.d.ts.map +1 -1
  47. package/dist/types/cli/helpers/error-formatter.d.ts.map +1 -1
  48. package/dist/types/gateway-core.d.ts +1 -0
  49. package/dist/types/gateway-core.d.ts.map +1 -1
  50. package/dist/types/memory-constraints.d.ts +1 -0
  51. package/dist/types/memory-constraints.d.ts.map +1 -1
  52. package/dist/types/memory-frontmatter.d.ts +18 -0
  53. package/dist/types/memory-frontmatter.d.ts.map +1 -0
  54. package/dist/types/tools/letta-toolset.d.ts +10 -0
  55. package/dist/types/tools/letta-toolset.d.ts.map +1 -0
  56. package/dist/types/tools/toolset-options.d.ts +4 -0
  57. package/dist/types/tools/toolset-options.d.ts.map +1 -0
  58. package/dist/types/tools/toolset-types.d.ts +1 -2
  59. package/dist/types/tools/toolset-types.d.ts.map +1 -1
  60. package/dist/types/tools/toolset.d.ts.map +1 -1
  61. package/dist/types/types/protocol_v2.d.ts +3 -2
  62. package/dist/types/types/protocol_v2.d.ts.map +1 -1
  63. package/dist/types/types/toolset-protocol.d.ts +10 -0
  64. package/dist/types/types/toolset-protocol.d.ts.map +1 -0
  65. package/dist/types/websocket/listener/device-toolset-status.d.ts +6 -0
  66. package/dist/types/websocket/listener/device-toolset-status.d.ts.map +1 -0
  67. package/dist/types/websocket/listener/protocol-outbound.d.ts.map +1 -1
  68. package/letta.js +968 -1482
  69. package/package.json +2 -1
  70. package/scripts/source-file-size-baseline.json +6 -6
  71. package/skills/image-generation/SKILL.md +5 -4
  72. package/skills/self-configuration/SKILL.md +1 -1
  73. package/skills/working-across-computers/SKILL.md +88 -0
  74. package/skills/teleporting-between-environments/SKILL.md +0 -114
package/letta.js CHANGED
@@ -66,6 +66,50 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
66
66
  var __promiseAll = (args) => Promise.all(args);
67
67
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
68
68
 
69
+ // src/utils/startup-log-boundary.ts
70
+ import { writeSync } from "node:fs";
71
+ function sealStartupLogs() {
72
+ if (failure)
73
+ throw failure;
74
+ if (marker === undefined)
75
+ return;
76
+ try {
77
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(marker)) {
78
+ throw new Error("LETTA_STARTUP_LOG_MARKER must be a UUID");
79
+ }
80
+ const bytes = Buffer.from(`
81
+ [letta-startup-end:${marker}]
82
+ `);
83
+ let offset = 0;
84
+ while (offset < bytes.length) {
85
+ const written = writeSync(1, bytes, offset, bytes.length - offset);
86
+ if (written === 0)
87
+ throw new Error("Startup marker write made no progress");
88
+ offset += written;
89
+ }
90
+ marker = undefined;
91
+ } catch (cause) {
92
+ failure = new Error("Failed to seal startup logs", { cause });
93
+ throw failure;
94
+ }
95
+ }
96
+ var marker, ownerPid, failure;
97
+ var init_startup_log_boundary = __esm(() => {
98
+ marker = process.env.LETTA_STARTUP_LOG_MARKER;
99
+ ownerPid = process.env.LETTA_STARTUP_LOG_OWNER_PID;
100
+ delete process.env.LETTA_STARTUP_LOG_MARKER;
101
+ delete process.env.LETTA_STARTUP_LOG_OWNER_PID;
102
+ if (ownerPid !== undefined) {
103
+ if (!/^[1-9][0-9]*$/.test(ownerPid) || !Number.isSafeInteger(Number(ownerPid))) {
104
+ failure = new Error("Failed to seal startup logs", {
105
+ cause: new Error("LETTA_STARTUP_LOG_OWNER_PID must be a positive integer")
106
+ });
107
+ } else if (Number(ownerPid) !== process.pid) {
108
+ marker = undefined;
109
+ }
110
+ }
111
+ });
112
+
69
113
  // node_modules/@earendil-works/pi-ai/dist/utils/provider-env.js
70
114
  function getBunSandboxEnvValue(name) {
71
115
  if (typeof process === "undefined" || !process.versions?.bun || Object.keys(process.env).length > 0) {
@@ -5471,7 +5515,8 @@ var package_default;
5471
5515
  var init_package = __esm(() => {
5472
5516
  package_default = {
5473
5517
  name: "@letta-ai/letta-code",
5474
- version: "0.32.1",
5518
+ version: "0.32.3",
5519
+ lettaStartupLogProtocol: 1,
5475
5520
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5476
5521
  type: "module",
5477
5522
  packageManager: "bun@1.3.14",
@@ -24251,15 +24296,15 @@ var init_memories = __esm(() => {
24251
24296
  return path3.join(__classPrivateFieldGet3(this, _SessionMemoryStores_workdir, "f"), "memory", resource.name || resource.memory_store_id);
24252
24297
  }, _SessionMemoryStores_scanMarker = async function _SessionMemoryStores_scanMarker2(store) {
24253
24298
  const local = await store.files.hashtree();
24254
- const marker = local[MARKER_PATH];
24299
+ const marker2 = local[MARKER_PATH];
24255
24300
  delete local[MARKER_PATH];
24256
- if (marker === markerSha(store.memoryStoreId)) {
24301
+ if (marker2 === markerSha(store.memoryStoreId)) {
24257
24302
  return { files: local, markerOk: true, distrustReason: null };
24258
24303
  }
24259
24304
  return {
24260
24305
  files: local,
24261
24306
  markerOk: false,
24262
- distrustReason: marker !== undefined ? "the marker file does not match this store" : "the marker file is gone"
24307
+ distrustReason: marker2 !== undefined ? "the marker file does not match this store" : "the marker file is gone"
24263
24308
  };
24264
24309
  }, _SessionMemoryStores_syncStore = async function _SessionMemoryStores_syncStore2(store, final) {
24265
24310
  try {
@@ -85829,6 +85874,81 @@ var init_context = __esm(() => {
85829
85874
  context2 = getContext();
85830
85875
  });
85831
85876
 
85877
+ // src/memory-frontmatter.ts
85878
+ function validateMemoryFileFrontmatter({
85879
+ path: path7,
85880
+ content,
85881
+ previousContent,
85882
+ format: format5
85883
+ }) {
85884
+ const errors4 = [];
85885
+ const v2 = format5 === "memfs-v2";
85886
+ const lines = content.split(`
85887
+ `);
85888
+ if (v2 && path7.split("/").at(-1) === "MEMORY.md") {
85889
+ return lines[0] === "---" ? [`${path7}: MEMORY.md must not have frontmatter`] : [];
85890
+ }
85891
+ if (lines[0] !== "---") {
85892
+ return [`${path7}: missing frontmatter (must start with ---)`];
85893
+ }
85894
+ const closing = lines.indexOf("---", 1);
85895
+ if (closing < 0) {
85896
+ return [
85897
+ `${path7}: frontmatter opened but never closed (missing closing ---)`
85898
+ ];
85899
+ }
85900
+ function legacyValue(text, key) {
85901
+ const previousLines = text?.split(`
85902
+ `) ?? [];
85903
+ const end = previousLines.indexOf("---", 1);
85904
+ if (end < 0)
85905
+ return "";
85906
+ return previousLines.slice(1, end).filter((line) => line.startsWith(`${key}:`)).map((line) => line.slice(key.length + 1).replace(/^ +| +$/g, "")).join(`
85907
+ `);
85908
+ }
85909
+ if (!v2 && previousContent && legacyValue(previousContent, "read_only") === "true") {
85910
+ return [`${path7}: file is read_only and cannot be modified`];
85911
+ }
85912
+ const seen = new Set;
85913
+ const allowed = v2 ? ["name", "description"] : ["description", "read_only", "limit"];
85914
+ for (const line of lines.slice(1, closing)) {
85915
+ if (!line)
85916
+ continue;
85917
+ if (!v2 && /^[ \t]/.test(line))
85918
+ continue;
85919
+ const separator = line.indexOf(":");
85920
+ const rawKey = separator < 0 ? line : line.slice(0, separator);
85921
+ const key = v2 ? rawKey.replace(/^ +| +$/g, "") : rawKey.replaceAll(" ", "");
85922
+ const value = (separator < 0 ? line : line.slice(separator + 1)).replace(/^ +| +$/g, "");
85923
+ if (!allowed.includes(key)) {
85924
+ errors4.push(`${path7}: unknown frontmatter key '${key}' (allowed: ${allowed.join(" ")})`);
85925
+ continue;
85926
+ }
85927
+ if (v2 && seen.has(key)) {
85928
+ errors4.push(`${path7}: duplicate frontmatter key '${key}'`);
85929
+ }
85930
+ seen.add(key);
85931
+ if (key === "read_only") {
85932
+ if (!previousContent) {
85933
+ errors4.push(`${path7}: 'read_only' is a protected field and cannot be set by the agent`);
85934
+ } else if (value !== legacyValue(previousContent, key)) {
85935
+ errors4.push(`${path7}: 'read_only' is a protected field and cannot be changed by the agent`);
85936
+ }
85937
+ }
85938
+ if ((v2 || key === "description") && (!value || v2 && (value === '""' || value === "''"))) {
85939
+ errors4.push(`${path7}: '${key}' must not be empty`);
85940
+ }
85941
+ }
85942
+ for (const key of v2 ? ["name", "description"] : ["description"]) {
85943
+ if (!seen.has(key))
85944
+ errors4.push(`${path7}: missing required field '${key}'`);
85945
+ }
85946
+ if (!v2 && legacyValue(previousContent, "read_only") && !legacyValue(content, "read_only")) {
85947
+ errors4.push(`${path7}: 'read_only' is a protected field and cannot be removed by the agent`);
85948
+ }
85949
+ return errors4;
85950
+ }
85951
+
85832
85952
  // src/memory-constraints.ts
85833
85953
  async function validateMemoryTreeConstraints(reader, options) {
85834
85954
  const errors4 = [];
@@ -86242,10 +86362,8 @@ var init_memory_git_hooks = __esm(() => {
86242
86362
  # Validate frontmatter in staged memory .md files
86243
86363
  # Installed by Letta Code CLI
86244
86364
 
86245
- AGENT_EDITABLE_KEYS="description"
86246
- PROTECTED_KEYS="read_only"
86247
- ALL_KNOWN_KEYS="description read_only limit"
86248
86365
  errors=""
86366
+ memory_files=()
86249
86367
 
86250
86368
  memory_layout_policy_file="$(git rev-parse --git-common-dir 2>/dev/null)/${MEMORY_LAYOUT_POLICY}"
86251
86369
  memory_layout_policy=$(cat "$memory_layout_policy_file" 2>/dev/null || true)
@@ -86256,63 +86374,33 @@ validate_memory_constraints() {
86256
86374
  fi
86257
86375
  }
86258
86376
 
86259
- validate_v2_file() {
86260
- local file="$1" staged first_line closing_line frontmatter line key value
86261
- local has_name=false has_description=false
86262
- staged=$(git show ":$file")
86263
-
86264
- if [ "\${file##*/}" = "MEMORY.md" ]; then
86265
- first_line=$(echo "$staged" | head -1)
86266
- if [ "$first_line" = "---" ]; then
86267
- errors="$errors\\n $file: MEMORY.md must not have frontmatter"
86268
- fi
86269
- return
86270
- fi
86271
-
86272
- first_line=$(echo "$staged" | head -1)
86273
- if [ "$first_line" != "---" ]; then
86274
- errors="$errors\\n $file: missing frontmatter (must start with ---)"
86275
- return
86276
- fi
86277
- closing_line=$(echo "$staged" | tail -n +2 | grep -n '^---$' | head -1 | cut -d: -f1)
86278
- if [ -z "$closing_line" ]; then
86279
- errors="$errors\\n $file: frontmatter opened but never closed (missing closing ---)"
86280
- return
86281
- fi
86282
- frontmatter=$(echo "$staged" | tail -n +2 | head -n $((closing_line - 1)))
86283
-
86284
- while IFS= read -r line; do
86285
- [ -z "$line" ] && continue
86286
- key=$(echo "$line" | cut -d: -f1 | sed 's/^ *//;s/ *$//')
86287
- value=$(echo "$line" | cut -d: -f2- | sed 's/^ *//;s/ *$//')
86288
- case "$key" in
86289
- name)
86290
- if [ "$has_name" = "true" ]; then
86291
- errors="$errors\\n $file: duplicate frontmatter key 'name'"
86292
- fi
86293
- has_name=true
86294
- ;;
86295
- description)
86296
- if [ "$has_description" = "true" ]; then
86297
- errors="$errors\\n $file: duplicate frontmatter key 'description'"
86298
- fi
86299
- has_description=true
86300
- ;;
86301
- *)
86302
- errors="$errors\\n $file: unknown frontmatter key '$key' (allowed: name description)"
86303
- continue
86304
- ;;
86305
- esac
86306
- if [ -z "$value" ] || [ "$value" = '""' ] || [ "$value" = "''" ]; then
86307
- errors="$errors\\n $file: '$key' must not be empty"
86308
- fi
86309
- done <<< "$frontmatter"
86310
-
86311
- if [ "$has_name" = "false" ]; then
86312
- errors="$errors\\n $file: missing required field 'name'"
86313
- fi
86314
- if [ "$has_description" = "false" ]; then
86315
- errors="$errors\\n $file: missing required field 'description'"
86377
+ validate_memory_files() {
86378
+ [ "\${#memory_files[@]}" -eq 0 ] && return
86379
+ local result
86380
+ result=$(node - "$1" "\${memory_files[@]}" <<'LETTA_MEMORY_FRONTMATTER'
86381
+ const { execFileSync, spawnSync } = require("node:child_process");
86382
+ const validateMemoryFileFrontmatter = ${validateMemoryFileFrontmatter.toString()};
86383
+ const [format, ...paths] = process.argv.slice(2);
86384
+ try {
86385
+ for (const path of paths) {
86386
+ const content = execFileSync("git", ["show", ":" + path], { encoding: "utf8", maxBuffer: Infinity, stdio: ["ignore", "pipe", "pipe"] });
86387
+ let previousContent = null;
86388
+ if (format === "legacy") {
86389
+ const previous = spawnSync("git", ["show", "HEAD:" + path], { encoding: "utf8", maxBuffer: Infinity, stdio: ["ignore", "pipe", "pipe"] });
86390
+ if (previous.error) throw previous.error;
86391
+ if (previous.status === 0) previousContent = previous.stdout;
86392
+ }
86393
+ const errors = validateMemoryFileFrontmatter({ path, content, previousContent, format });
86394
+ for (const error of errors) console.log(" " + error);
86395
+ }
86396
+ } catch {
86397
+ console.error("Memory validation could not read Git contents. No files were committed.");
86398
+ process.exit(1);
86399
+ }
86400
+ LETTA_MEMORY_FRONTMATTER
86401
+ ) || exit $?
86402
+ if [ -n "$result" ]; then
86403
+ errors="$errors\\n$result"
86316
86404
  fi
86317
86405
  }
86318
86406
 
@@ -86354,8 +86442,9 @@ if [ "$use_v2_validation" = "true" ]; then
86354
86442
  ;;
86355
86443
  esac
86356
86444
  fi
86357
- [ "$projected" = "true" ] && validate_v2_file "$file"
86445
+ [ "$projected" = "true" ] && memory_files+=("$file")
86358
86446
  done < <(git ls-files '*.md')
86447
+ validate_memory_files "memfs-v2"
86359
86448
 
86360
86449
  if [ -n "$errors" ]; then
86361
86450
  echo "Memory validation failed:"
@@ -86372,122 +86461,12 @@ for file in $(git diff --cached --name-only --diff-filter=ACMR | grep -E '^(memo
86372
86461
  errors="$errors\\n $file: invalid skill path (skills must be folders). Use skills/<name>/SKILL.md"
86373
86462
  done
86374
86463
 
86375
- # Helper: extract a frontmatter value from content
86376
- get_fm_value() {
86377
- local content="$1" key="$2"
86378
- local closing_line
86379
- closing_line=$(echo "$content" | tail -n +2 | grep -n '^---$' | head -1 | cut -d: -f1)
86380
- [ -z "$closing_line" ] && return
86381
- echo "$content" | tail -n +2 | head -n $((closing_line - 1)) | grep "^$key:" | cut -d: -f2- | sed 's/^ *//;s/ *$//'
86382
- }
86383
-
86384
86464
  # Match .md files under system/ or reference/ (with optional memory/ prefix).
86385
86465
  # Skip skill SKILL.md files — they use a different frontmatter format.
86386
86466
  for file in $(git diff --cached --name-only --diff-filter=ACM | grep -E '^(memory/)?(system|reference)/.*\\.md$'); do
86387
- staged=$(git show ":$file")
86388
-
86389
- # Frontmatter is required
86390
- first_line=$(echo "$staged" | head -1)
86391
- if [ "$first_line" != "---" ]; then
86392
- errors="$errors\\n $file: missing frontmatter (must start with ---)"
86393
- continue
86394
- fi
86395
-
86396
- # Check frontmatter is properly closed
86397
- closing_line=$(echo "$staged" | tail -n +2 | grep -n '^---$' | head -1 | cut -d: -f1)
86398
- if [ -z "$closing_line" ]; then
86399
- errors="$errors\\n $file: frontmatter opened but never closed (missing closing ---)"
86400
- continue
86401
- fi
86402
-
86403
- # Check read_only protection against HEAD version
86404
- head_content=$(git show "HEAD:$file" 2>/dev/null || true)
86405
- if [ -n "$head_content" ]; then
86406
- head_ro=$(get_fm_value "$head_content" "read_only")
86407
- if [ "$head_ro" = "true" ]; then
86408
- errors="$errors\\n $file: file is read_only and cannot be modified"
86409
- continue
86410
- fi
86411
- fi
86412
-
86413
- # Extract frontmatter lines
86414
- frontmatter=$(echo "$staged" | tail -n +2 | head -n $((closing_line - 1)))
86415
-
86416
- # Track required fields
86417
- has_description=false
86418
-
86419
- # Validate each line
86420
- while IFS= read -r line; do
86421
- [ -z "$line" ] && continue
86422
- # Skip YAML multiline continuation lines (indented lines that continue a previous value)
86423
- case "$line" in
86424
- " "*|$' '*) continue ;;
86425
- esac
86426
-
86427
- key=$(echo "$line" | cut -d: -f1 | tr -d ' ')
86428
- value=$(echo "$line" | cut -d: -f2- | sed 's/^ *//;s/ *$//')
86429
-
86430
- # Check key is known
86431
- known=false
86432
- for k in $ALL_KNOWN_KEYS; do
86433
- if [ "$key" = "$k" ]; then
86434
- known=true
86435
- break
86436
- fi
86437
- done
86438
- if [ "$known" = "false" ]; then
86439
- errors="$errors\\n $file: unknown frontmatter key '$key' (allowed: $ALL_KNOWN_KEYS)"
86440
- continue
86441
- fi
86442
-
86443
- # Check if agent is trying to modify a protected key
86444
- for k in $PROTECTED_KEYS; do
86445
- if [ "$key" = "$k" ]; then
86446
- # Compare against HEAD — if value changed (or key was added), reject
86447
- if [ -n "$head_content" ]; then
86448
- head_val=$(get_fm_value "$head_content" "$key")
86449
- if [ "$value" != "$head_val" ]; then
86450
- errors="$errors\\n $file: '$key' is a protected field and cannot be changed by the agent"
86451
- fi
86452
- else
86453
- # New file with read_only — agent shouldn't set this
86454
- errors="$errors\\n $file: '$key' is a protected field and cannot be set by the agent"
86455
- fi
86456
- fi
86457
- done
86458
-
86459
- # Validate value types
86460
- case "$key" in
86461
- limit)
86462
- # Legacy field accepted for backward compatibility.
86463
- ;;
86464
- description)
86465
- has_description=true
86466
- if [ -z "$value" ]; then
86467
- errors="$errors\\n $file: 'description' must not be empty"
86468
- fi
86469
- ;;
86470
- esac
86471
- done <<< "$frontmatter"
86472
-
86473
- # Check required fields
86474
- if [ "$has_description" = "false" ]; then
86475
- errors="$errors\\n $file: missing required field 'description'"
86476
- fi
86477
-
86478
- # Check if protected keys were removed (existed in HEAD but not in staged)
86479
- if [ -n "$head_content" ]; then
86480
- for k in $PROTECTED_KEYS; do
86481
- head_val=$(get_fm_value "$head_content" "$k")
86482
- if [ -n "$head_val" ]; then
86483
- staged_val=$(get_fm_value "$staged" "$k")
86484
- if [ -z "$staged_val" ]; then
86485
- errors="$errors\\n $file: '$k' is a protected field and cannot be removed by the agent"
86486
- fi
86487
- fi
86488
- done
86489
- fi
86467
+ memory_files+=("$file")
86490
86468
  done
86469
+ validate_memory_files "legacy"
86491
86470
 
86492
86471
  if [ -n "$errors" ]; then
86493
86472
  echo "Frontmatter validation failed:"
@@ -86787,6 +86766,12 @@ If the user wants help or to give feedback on Letta Code, point them to discord.
86787
86766
 
86788
86767
  Tool results and user messages may include \`<system-reminder>\` tags. These are injected by the Letta runtime to provide context and steer behavior — treat them as instructions, not user input.
86789
86768
 
86769
+ ## Following user requests
86770
+
86771
+ Users may send additional messages while you are working. Treat non-conflicting requests as cumulative, not replacements. If a later message cancels, replaces, or conflicts with earlier work, follow the new instruction while preserving unaffected requests.
86772
+
86773
+ Carry unfinished requests across tool calls, queued-message delivery, and context transitions. Before sending a final response, make sure every outstanding request is answered or completed, or explain what is blocked or explicitly deferred by the user. A successful tool call does not replace an answer the user requested.
86774
+
86790
86775
  ## Subagents
86791
86776
 
86792
86777
  Delegate to specialized subagents via the Agent tool. Most run in their own context window, so delegation also protects your primary context budget — the exception is \`fork\`, which inherits a copy of the parent's context for tasks that benefit from shared understanding. Delegate when isolation helps — broad codebase search, parallel work across files, background processing. Do work directly when it's contained.
@@ -86989,6 +86974,12 @@ If the user wants help or to give feedback on Letta Code, point them to discord.
86989
86974
 
86990
86975
  Tool results and user messages may include \`<system-reminder>\` tags. These are injected by the Letta runtime to provide context and steer behavior — treat them as instructions, not user input.
86991
86976
 
86977
+ ## Following user requests
86978
+
86979
+ Users may send additional messages while you are working. Treat non-conflicting requests as cumulative, not replacements. If a later message cancels, replaces, or conflicts with earlier work, follow the new instruction while preserving unaffected requests.
86980
+
86981
+ Carry unfinished requests across tool calls, queued-message delivery, and context transitions. Before sending a final response, make sure every outstanding request is answered or completed, or explain what is blocked or explicitly deferred by the user. A successful tool call does not replace an answer the user requested.
86982
+
86992
86983
  ## Subagents
86993
86984
 
86994
86985
  Delegate to specialized subagents via the Agent tool. Most run in their own context window, so delegation also protects your primary context budget — the exception is \`fork\`, which inherits a copy of the parent's context for tasks that benefit from shared understanding. Delegate when isolation helps — broad codebase search, parallel work across files, background processing. Do work directly when it's contained.
@@ -87125,6 +87116,12 @@ Your full memory (other than recall) is represented through memory blocks and ex
87125
87116
 
87126
87117
  **References as synapses.** Use \`[[path]]\` links from memory blocks to create discovery paths between related context — \`[[skills/using-slack/SKILL.md]]\`, \`[[reference/api.md]]\`, \`[[projects/letta-code]]\`. These references are the synapses of your memory: they should strengthen with use, and the paths you build today should make tomorrow's retrieval faster.
87127
87118
 
87119
+ # Following user requests
87120
+
87121
+ Users may send additional messages while you are working. Treat non-conflicting requests as cumulative, not replacements. If a later message cancels, replaces, or conflicts with earlier work, follow the new instruction while preserving unaffected requests.
87122
+
87123
+ Carry unfinished requests across tool calls, queued-message delivery, and context transitions. Before sending a final response, make sure every outstanding request is answered or completed, or explain what is blocked or explicitly deferred by the user. A successful tool call does not replace an answer the user requested.
87124
+
87128
87125
  # Subagents
87129
87126
 
87130
87127
  Delegate to specialized subagents via the Agent tool. Each gets its own context window, so delegation also protects your primary context budget. Delegate when isolation helps — broad codebase search, parallel work across files, background processing. Do work directly when it's contained.
@@ -87335,6 +87332,12 @@ If the user wants help or to give feedback on Letta Code, point them to discord.
87335
87332
 
87336
87333
  Tool results and user messages may include \`<system-reminder>\` tags. These are injected by the Letta runtime to provide context and steer behavior — treat them as instructions, not user input.
87337
87334
 
87335
+ ## Following user requests
87336
+
87337
+ Users may send additional messages while you are working. Treat non-conflicting requests as cumulative, not replacements. If a later message cancels, replaces, or conflicts with earlier work, follow the new instruction while preserving unaffected requests.
87338
+
87339
+ Carry unfinished requests across tool calls, queued-message delivery, and context transitions. Before sending a final response, make sure every outstanding request is answered or completed, or explain what is blocked or explicitly deferred by the user. A successful tool call does not replace an answer the user requested.
87340
+
87338
87341
  ## Subagents
87339
87342
 
87340
87343
  Delegate to specialized subagents via the Agent tool. Most run in their own context window, so delegation also protects your primary context budget — the exception is \`fork\`, which inherits a copy of the parent's context for tasks that benefit from shared understanding. Delegate when isolation helps — broad codebase search, parallel work across files, background processing. Do work directly when it's contained.
@@ -93097,7 +93100,7 @@ function isProjectedMemoryPath(relativePath, allPaths, format5) {
93097
93100
  }
93098
93101
  return true;
93099
93102
  }
93100
- function assertMemfsV2MemoryPathIndexed(memoryDir, relativePath, markerExists = (marker) => existsSync7(join10(memoryDir, marker))) {
93103
+ function assertMemfsV2MemoryPathIndexed(memoryDir, relativePath, markerExists = (marker2) => existsSync7(join10(memoryDir, marker2))) {
93101
93104
  const normalized = relativePath.replace(/\\/g, "/");
93102
93105
  if (normalized === "MEMORY.md")
93103
93106
  return;
@@ -93108,9 +93111,9 @@ function assertMemfsV2MemoryPathIndexed(memoryDir, relativePath, markerExists =
93108
93111
  let current = "";
93109
93112
  for (const directory of directories) {
93110
93113
  current = current ? `${current}/${directory}` : directory;
93111
- const marker = `${current}/MEMORY.md`;
93112
- if (marker !== normalized && !markerExists(marker)) {
93113
- throw new Error(`Memory requires ${marker} before writing ${normalized}`);
93114
+ const marker2 = `${current}/MEMORY.md`;
93115
+ if (marker2 !== normalized && !markerExists(marker2)) {
93116
+ throw new Error(`Memory requires ${marker2} before writing ${normalized}`);
93114
93117
  }
93115
93118
  }
93116
93119
  }
@@ -98013,7 +98016,7 @@ Note: \`fork\` cannot be combined with \`agent_id\` or \`conversation_id\`.
98013
98016
 
98014
98017
  ## Running on Another Computer
98015
98018
 
98016
- Pass \`computer\` to run the subagent's turn on another connected computer instead of this machine. Works with any subagent type. The call fails fast if the named device is offline, ambiguous, or too old to support routing.
98019
+ Pass \`computer\` to run the subagent's turn on another connected computer instead of this machine. Prefer a stable device ID or computer name; these select the freshest online listener for that device. Ephemeral connection IDs are still supported to pin a specific listener. Works with any subagent type. The call fails fast if the named device is offline, the name matches multiple online devices, or the listener is too old to support routing.
98017
98020
 
98018
98021
  \`computer: "cloud"\` provisions a Cloud sandbox for the subagent's conversation and runs the turn there. Sandboxes are per-conversation: this is a separate machine from wherever you are running now, even if you are already in a Cloud sandbox.
98019
98022
 
@@ -99750,11 +99753,11 @@ function lockHandlesEqual(left, right) {
99750
99753
  }
99751
99754
  function isLockOwnerProcessAlive(ownerToken) {
99752
99755
  const separatorIndex = ownerToken.indexOf("-");
99753
- const ownerPid = Number(separatorIndex === -1 ? ownerToken : ownerToken.slice(0, separatorIndex));
99754
- if (!Number.isSafeInteger(ownerPid) || ownerPid <= 0)
99756
+ const ownerPid2 = Number(separatorIndex === -1 ? ownerToken : ownerToken.slice(0, separatorIndex));
99757
+ if (!Number.isSafeInteger(ownerPid2) || ownerPid2 <= 0)
99755
99758
  return false;
99756
99759
  try {
99757
- process.kill(ownerPid, 0);
99760
+ process.kill(ownerPid2, 0);
99758
99761
  return true;
99759
99762
  } catch (error4) {
99760
99763
  return !hasErrorCode(error4, "ESRCH");
@@ -101986,14 +101989,14 @@ function runExtractionCommand(command, args) {
101986
101989
  return `${command}: ${formatSpawnFailure(result)}`;
101987
101990
  }
101988
101991
  function extractTarGzArchive(archivePath, extractDir, assetName) {
101989
- const failure = runExtractionCommand("tar", [
101992
+ const failure2 = runExtractionCommand("tar", [
101990
101993
  "xzf",
101991
101994
  archivePath,
101992
101995
  "-C",
101993
101996
  extractDir
101994
101997
  ]);
101995
- if (failure) {
101996
- throw new Error(`Failed to extract ${assetName}: ${failure}`);
101998
+ if (failure2) {
101999
+ throw new Error(`Failed to extract ${assetName}: ${failure2}`);
101997
102000
  }
101998
102001
  }
101999
102002
  function getWindowsTarCommand() {
@@ -103120,10 +103123,10 @@ function startShellProcess(launcher, options) {
103120
103123
  } catch (error4) {
103121
103124
  completed = true;
103122
103125
  cleanup();
103123
- const failure = error4 instanceof Error ? error4 : new Error(String(error4));
103124
- rejectCompletion(failure);
103126
+ const failure2 = error4 instanceof Error ? error4 : new Error(String(error4));
103127
+ rejectCompletion(failure2);
103125
103128
  completion.catch(() => {});
103126
- throw failure;
103129
+ throw failure2;
103127
103130
  }
103128
103131
  if (options.timeoutMs) {
103129
103132
  timeoutTimer = setTimeout(() => {
@@ -106318,6 +106321,88 @@ var init_device_status_cache = __esm(() => {
106318
106321
  lastDeviceStatusByTransport = new WeakMap;
106319
106322
  });
106320
106323
 
106324
+ // src/tools/toolset-options.ts
106325
+ var TOOLSET_OPTIONS;
106326
+ var init_toolset_options = __esm(() => {
106327
+ TOOLSET_OPTIONS = [
106328
+ {
106329
+ id: "auto",
106330
+ display_name: "Auto",
106331
+ label: "Auto",
106332
+ description: "Auto-select based on the model",
106333
+ is_featured: true
106334
+ },
106335
+ {
106336
+ id: "letta",
106337
+ display_name: "Letta",
106338
+ label: "Letta toolset",
106339
+ description: "Experimental unified toolset for every model",
106340
+ is_featured: true
106341
+ },
106342
+ {
106343
+ id: "none",
106344
+ display_name: "None",
106345
+ label: "None",
106346
+ description: "Remove all Letta Code tools from your agent",
106347
+ is_featured: true
106348
+ },
106349
+ {
106350
+ id: "default",
106351
+ display_name: "Claude",
106352
+ label: "Claude toolset",
106353
+ description: "Optimized for Anthropic models",
106354
+ is_featured: true
106355
+ },
106356
+ {
106357
+ id: "codex",
106358
+ display_name: "Codex",
106359
+ label: "Codex toolset",
106360
+ description: "Optimized for GPT/Codex models",
106361
+ is_featured: true
106362
+ },
106363
+ {
106364
+ id: "gemini",
106365
+ display_name: "Gemini",
106366
+ label: "Gemini toolset",
106367
+ description: "Optimized for Google Gemini models",
106368
+ is_featured: true
106369
+ },
106370
+ {
106371
+ id: "codex_snake",
106372
+ display_name: "Codex (snake_case)",
106373
+ label: "Codex toolset (snake_case)",
106374
+ description: "Optimized for GPT/Codex models (snake_case)",
106375
+ is_featured: false
106376
+ },
106377
+ {
106378
+ id: "gemini_snake",
106379
+ display_name: "Gemini (snake_case)",
106380
+ label: "Gemini toolset (snake_case)",
106381
+ description: "Optimized for Google Gemini models (snake_case)",
106382
+ is_featured: false
106383
+ }
106384
+ ];
106385
+ });
106386
+
106387
+ // src/websocket/listener/device-toolset-status.ts
106388
+ function buildDeviceToolsetStatus(agentId, conversationId, conversationRuntime) {
106389
+ let preference = "auto";
106390
+ if (agentId) {
106391
+ try {
106392
+ preference = settingsManager.getToolsetPreference(agentId, conversationId ?? "default");
106393
+ } catch {}
106394
+ }
106395
+ return {
106396
+ current_toolset: conversationRuntime?.currentToolset ?? (preference === "auto" ? null : preference),
106397
+ current_toolset_preference: conversationRuntime?.currentToolset === null ? preference : conversationRuntime?.currentToolsetPreference ?? preference,
106398
+ available_toolsets: [...TOOLSET_OPTIONS]
106399
+ };
106400
+ }
106401
+ var init_device_toolset_status = __esm(() => {
106402
+ init_settings_manager();
106403
+ init_toolset_options();
106404
+ });
106405
+
106321
106406
  // src/websocket/listener/listener-constants.ts
106322
106407
  var SUPPORTED_REMOTE_COMMANDS;
106323
106408
  var init_listener_constants = __esm(() => {
@@ -106978,8 +107063,7 @@ function buildDeviceStatus(runtime, params) {
106978
107063
  current_working_directory: fallbackCwd,
106979
107064
  git_context: deviceGitContextCache.read(fallbackCwd),
106980
107065
  letta_code_version: process.env.npm_package_version || null,
106981
- current_toolset: null,
106982
- current_toolset_preference: "auto",
107066
+ ...buildDeviceToolsetStatus(null, null),
106983
107067
  current_loaded_tools: [],
106984
107068
  current_available_skills: [],
106985
107069
  background_processes: buildBackgroundProcessSnapshot(),
@@ -106997,16 +107081,6 @@ function buildDeviceStatus(runtime, params) {
106997
107081
  const agentId = resolveScopedAgentId(listener, scope);
106998
107082
  const conversationId = resolveScopedConversationId(listener, scope);
106999
107083
  const conversationRuntime = getConversationRuntime(listener, agentId, conversationId);
107000
- const toolsetPreference = (() => {
107001
- if (!agentId) {
107002
- return "auto";
107003
- }
107004
- try {
107005
- return settingsManager.getToolsetPreference(agentId, conversationId);
107006
- } catch {
107007
- return "auto";
107008
- }
107009
- })();
107010
107084
  const conversationPermissionModeState = getConversationPermissionModeState(listener, agentId, conversationId);
107011
107085
  const interruptedCacheActive = hasInterruptedCacheForScope(listener, scope);
107012
107086
  const resolvedCwd = conversationRuntime?.activeWorkingDirectory ?? getConversationWorkingDirectory(listener, agentId, conversationId);
@@ -107031,8 +107105,7 @@ function buildDeviceStatus(runtime, params) {
107031
107105
  current_working_directory: resolvedCwd,
107032
107106
  git_context: deviceGitContextCache.read(resolvedCwd),
107033
107107
  letta_code_version: process.env.npm_package_version || null,
107034
- current_toolset: conversationRuntime?.currentToolset ?? (toolsetPreference === "auto" ? null : toolsetPreference),
107035
- current_toolset_preference: conversationRuntime?.currentToolset === null ? toolsetPreference : conversationRuntime?.currentToolsetPreference ?? toolsetPreference,
107108
+ ...buildDeviceToolsetStatus(agentId, conversationId, conversationRuntime),
107036
107109
  current_loaded_tools: conversationRuntime?.currentLoadedTools ?? [],
107037
107110
  current_available_skills: conversationRuntime?.currentAvailableSkills ?? [],
107038
107111
  background_processes: buildBackgroundProcessSnapshot(agentId, conversationId),
@@ -107468,7 +107541,6 @@ var init_protocol_outbound = __esm(() => {
107468
107541
  init_constants2();
107469
107542
  init_manager();
107470
107543
  init_mode();
107471
- init_settings_manager();
107472
107544
  init_error_reporting();
107473
107545
  init_debug();
107474
107546
  init_background_process_snapshot();
@@ -107477,6 +107549,7 @@ var init_protocol_outbound = __esm(() => {
107477
107549
  init_cwd();
107478
107550
  init_device_git_context();
107479
107551
  init_device_status_cache();
107552
+ init_device_toolset_status();
107480
107553
  init_listener_constants();
107481
107554
  init_outbound_wire();
107482
107555
  init_permission_mode();
@@ -107760,11 +107833,11 @@ async function runGit2(args, cwd, options = {}) {
107760
107833
  timeoutMs
107761
107834
  });
107762
107835
  } catch (error4) {
107763
- const failure = error4;
107764
- throw new GitCommandError(failure.killed ? `Timed out running git ${args.join(" ")}` : `Failed to run git ${args.join(" ")}: ${failure.message}`, args, {
107765
- stdout: failure.stdout ?? "",
107766
- stderr: failure.stderr ?? "",
107767
- exitCode: typeof failure.code === "number" ? failure.code : null
107836
+ const failure2 = error4;
107837
+ throw new GitCommandError(failure2.killed ? `Timed out running git ${args.join(" ")}` : `Failed to run git ${args.join(" ")}: ${failure2.message}`, args, {
107838
+ stdout: failure2.stdout ?? "",
107839
+ stderr: failure2.stderr ?? "",
107840
+ exitCode: typeof failure2.code === "number" ? failure2.code : null
107768
107841
  });
107769
107842
  }
107770
107843
  if (result.exitCode !== 0 && !options.allowFailure) {
@@ -112550,12 +112623,12 @@ class MonitorOutputWriter {
112550
112623
  this.bytesWritten += chunk.length;
112551
112624
  return true;
112552
112625
  }
112553
- const marker = Buffer.from(`
112626
+ const marker2 = Buffer.from(`
112554
112627
  [output truncated at ${MONITOR_OUTPUT_FILE_BYTES} bytes]
112555
112628
  `, "utf8");
112556
112629
  try {
112557
- const content = validUtf8Prefix(Buffer.concat([readFileSync10(this.path), chunk]), MONITOR_OUTPUT_FILE_BYTES - marker.length);
112558
- const truncatedOutput = Buffer.concat([content, marker]);
112630
+ const content = validUtf8Prefix(Buffer.concat([readFileSync10(this.path), chunk]), MONITOR_OUTPUT_FILE_BYTES - marker2.length);
112631
+ const truncatedOutput = Buffer.concat([content, marker2]);
112559
112632
  writeFileSync9(this.path, truncatedOutput);
112560
112633
  this.bytesWritten = truncatedOutput.length;
112561
112634
  this.truncated = true;
@@ -122404,7 +122477,8 @@ var init_skills5 = __esm(() => {
122404
122477
  init_skill_sources();
122405
122478
  LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS = new Set([
122406
122479
  "image-generation",
122407
- "managing-shared-memory"
122480
+ "managing-shared-memory",
122481
+ "working-across-computers"
122408
122482
  ]);
122409
122483
  PROJECT_SKILLS_DIR = join26(".agents", "skills");
122410
122484
  GLOBAL_SKILLS_DIR = join26(process.env.HOME || process.env.USERPROFILE || "~", ".letta/skills");
@@ -123129,23 +123203,20 @@ function buildAgentTerminalLink(agentId, options, label = agentId) {
123129
123203
  function buildChatWebUrl(path30) {
123130
123204
  return `${CHAT_BASE}${path30}`;
123131
123205
  }
123132
- function buildPlatformUrl(path30) {
123133
- return `${PLATFORM_BASE}${path30}`;
123134
- }
123135
- var CHAT_BASE = "https://chat.letta.com", PLATFORM_BASE = "https://platform.letta.com", LETTA_CHAT_API_KEYS_URL;
123206
+ var CHAT_BASE = "https://chat.letta.com", LETTA_CHAT_API_KEYS_URL;
123136
123207
  var init_app_urls = __esm(() => {
123137
123208
  LETTA_CHAT_API_KEYS_URL = `${CHAT_BASE}/preferences/api-keys`;
123138
123209
  });
123139
123210
 
123140
123211
  // src/utils/subagent-stdout-failure.ts
123141
- import { writeSync } from "node:fs";
123212
+ import { writeSync as writeSync2 } from "node:fs";
123142
123213
  function isSubagentStdoutLostError(stderr) {
123143
123214
  return stderr.includes(SUBAGENT_STDOUT_LOST_MARKER);
123144
123215
  }
123145
123216
  function reportSubagentStdoutLoss(detail) {
123146
123217
  const suffix = detail === undefined ? "" : ` (${getErrorMessage2(detail)})`;
123147
123218
  try {
123148
- writeSync(2, `${SUBAGENT_STDOUT_LOST_MARKER}${suffix}
123219
+ writeSync2(2, `${SUBAGENT_STDOUT_LOST_MARKER}${suffix}
123149
123220
  `);
123150
123221
  } catch {}
123151
123222
  }
@@ -123986,7 +124057,7 @@ async function executeSubagent(type3, config, model, userPrompt, subagentId, isR
123986
124057
  agentId: parentAgentIdOverride
123987
124058
  });
123988
124059
  if (primaryModel) {
123989
- return executeSubagent(type3, config, primaryModel, userPrompt, subagentId, true, signal, undefined, undefined, maxTurns, parentAgentIdOverride, transcriptPath, undefined, undefined, environment2, actingUserIdOverride);
124060
+ return executeSubagent(type3, config, primaryModel, userPrompt, subagentId, true, signal, undefined, undefined, maxTurns, parentAgentIdOverride, transcriptPath, memoryScope, systemPromptOverride, environment2, actingUserIdOverride);
123990
124061
  }
123991
124062
  }
123992
124063
  if (!isRetry && isSubagentStdoutLostError(stderr)) {
@@ -126262,7 +126333,7 @@ var init_Task2 = __esm(() => {
126262
126333
  },
126263
126334
  computer: {
126264
126335
  type: "string",
126265
- description: `Run the subagent on another connected computer instead of this machine. Pass a computer name/connection ID, or "cloud" to provision a Cloud sandbox for the subagent's conversation. Fails fast if the device is offline or does not support routing. Omit this field to run on the current machine (the default) — only set it when the task specifically needs to run elsewhere.`
126336
+ description: `Run the subagent on another connected computer instead of this machine. Prefer a stable device ID or computer name; ephemeral connection IDs are also supported to pin a specific listener. Pass "cloud" to provision a Cloud sandbox for the subagent's conversation. Fails fast if the device is offline or does not support routing. Omit this field to run on the current machine (the default) — only set it when the task specifically needs to run elsewhere.`
126266
126337
  }
126267
126338
  },
126268
126339
  required: ["description", "prompt", "subagent_type"],
@@ -131714,7 +131785,7 @@ var init_error_formatter = __esm(() => {
131714
131785
  init_error_context();
131715
131786
  init_zai_errors();
131716
131787
  LETTA_USAGE_URL = buildChatWebUrl("/preferences/usage");
131717
- LETTA_AGENTS_URL = buildPlatformUrl("/projects/default-project/agents");
131788
+ LETTA_AGENTS_URL = buildChatWebUrl("/agents");
131718
131789
  CLOUDFLARE_EDGE_5XX_MARKER_PATTERN = /(^|\s)(502|52[0-6])\s*<!doctype html|error code\s*(502|52[0-6])/i;
131719
131790
  CLOUDFLARE_EDGE_5XX_TITLE_PATTERN = /\|\s*(502|52[0-6])\s*:/i;
131720
131791
  CLOUDFLARE_EDGE_5XX_FORMATTED_PATTERN = /\bCloudflare\s+(502|52[0-6])\b/i;
@@ -134115,6 +134186,40 @@ var init_manager4 = __esm(async () => {
134115
134186
  MOD_SECRET_NAME_PATTERN = /^[A-Z_][A-Z0-9_]*$/;
134116
134187
  });
134117
134188
 
134189
+ // src/tools/letta-toolset.ts
134190
+ async function loadStartupTools(params) {
134191
+ const { modelIdentifier, toolset, exclude: exclude3 = [] } = params;
134192
+ if (toolset === "letta") {
134193
+ await loadSpecificTools(LETTA_TOOLS.filter((toolName2) => !exclude3.includes(toolName2)));
134194
+ return;
134195
+ }
134196
+ const modelForTools = toolset === "codex" ? "openai/gpt-4" : toolset === "gemini" ? "google_ai/gemini-3.1-pro-preview" : toolset === "default" ? "anthropic/claude-sonnet-4" : modelIdentifier;
134197
+ await loadTools(modelForTools, { exclude: exclude3 });
134198
+ }
134199
+ var LETTA_TOOLS;
134200
+ var init_letta_toolset = __esm(async () => {
134201
+ await init_manager4();
134202
+ LETTA_TOOLS = [
134203
+ "AskUserQuestion",
134204
+ "EnterWorktree",
134205
+ "ExitWorktree",
134206
+ "SetWorkingDirectory",
134207
+ "memory",
134208
+ "Task",
134209
+ "Monitor",
134210
+ "TaskOutput",
134211
+ "TaskStop",
134212
+ "Skill",
134213
+ "exec_command",
134214
+ "write_stdin",
134215
+ "Read",
134216
+ "Edit",
134217
+ "Write",
134218
+ "ViewImage",
134219
+ "UpdatePlan"
134220
+ ];
134221
+ });
134222
+
134118
134223
  // src/tools/toolset.ts
134119
134224
  var exports_toolset = {};
134120
134225
  __export(exports_toolset, {
@@ -134239,6 +134344,9 @@ function getToolNamesForToolset(toolsetName) {
134239
134344
  case "gemini_snake":
134240
134345
  tools = [...GEMINI_DEFAULT_TOOLS];
134241
134346
  break;
134347
+ case "letta":
134348
+ tools = [...LETTA_TOOLS];
134349
+ break;
134242
134350
  case "none":
134243
134351
  tools = [];
134244
134352
  break;
@@ -134521,11 +134629,14 @@ async function forceToolsetSwitch(toolsetName, agentId) {
134521
134629
  } else if (toolsetName === "gemini_snake") {
134522
134630
  await loadTools("google_ai/gemini-3-pro-preview");
134523
134631
  modelForLoading = "google_ai/gemini-3-pro-preview";
134632
+ } else if (toolsetName === "letta") {
134633
+ await loadSpecificTools([...LETTA_TOOLS]);
134634
+ modelForLoading = "anthropic/claude-sonnet-4";
134524
134635
  } else {
134525
134636
  await loadTools("anthropic/claude-sonnet-4");
134526
134637
  modelForLoading = "anthropic/claude-sonnet-4";
134527
134638
  }
134528
- const useMemoryPatch = toolsetName === "codex" || toolsetName === "codex_snake";
134639
+ const useMemoryPatch = toolsetName === "codex" || toolsetName === "codex_snake" || toolsetName === "letta";
134529
134640
  await ensureCorrectMemoryTool(agentId, modelForLoading, useMemoryPatch);
134530
134641
  }
134531
134642
  async function switchToolsetForModel(modelIdentifier, agentId, providerType) {
@@ -134559,6 +134670,7 @@ var init_toolset = __esm(async () => {
134559
134670
  init_settings_manager();
134560
134671
  init_filter();
134561
134672
  await __promiseAll([
134673
+ init_letta_toolset(),
134562
134674
  init_manager4(),
134563
134675
  init_tool_definitions()
134564
134676
  ]);
@@ -136745,18 +136857,18 @@ function truncateLocalToolResultTextForRepair(text, maxChars) {
136745
136857
  [Tool result truncated during local transcript repair: omitted `;
136746
136858
  const markerSuffix = ` chars]
136747
136859
  `;
136748
- let marker = `${markerPrefix}${text.length - maxChars}${markerSuffix}`;
136749
- let keepChars = Math.max(0, maxChars - marker.length);
136860
+ let marker2 = `${markerPrefix}${text.length - maxChars}${markerSuffix}`;
136861
+ let keepChars = Math.max(0, maxChars - marker2.length);
136750
136862
  let headChars = Math.ceil(keepChars / 2);
136751
136863
  let tailChars = keepChars - headChars;
136752
136864
  let omittedChars = text.length - headChars - tailChars;
136753
- marker = `${markerPrefix}${omittedChars}${markerSuffix}`;
136754
- keepChars = Math.max(0, maxChars - marker.length);
136865
+ marker2 = `${markerPrefix}${omittedChars}${markerSuffix}`;
136866
+ keepChars = Math.max(0, maxChars - marker2.length);
136755
136867
  headChars = Math.ceil(keepChars / 2);
136756
136868
  tailChars = keepChars - headChars;
136757
136869
  omittedChars = text.length - headChars - tailChars;
136758
- marker = `${markerPrefix}${omittedChars}${markerSuffix}`;
136759
- return `${text.slice(0, headChars)}${marker}${tailChars > 0 ? text.slice(-tailChars) : ""}`;
136870
+ marker2 = `${markerPrefix}${omittedChars}${markerSuffix}`;
136871
+ return `${text.slice(0, headChars)}${marker2}${tailChars > 0 ? text.slice(-tailChars) : ""}`;
136760
136872
  }
136761
136873
  function clipOversizedLocalToolResults(messages, options = {}) {
136762
136874
  const maxToolResultTextChars = options.maxToolResultTextChars ?? LOCAL_REPAIRED_TOOL_RESULT_TEXT_MAX_CHARS;
@@ -139229,7 +139341,7 @@ function isContextWindowOverflowError(error4) {
139229
139341
  "request too large",
139230
139342
  "request_too_large",
139231
139343
  "model_context_window_exceeded"
139232
- ].some((marker) => haystack.includes(marker));
139344
+ ].some((marker2) => haystack.includes(marker2));
139233
139345
  }
139234
139346
  var init_context_window_overflow = () => {};
139235
139347
 
@@ -139914,7 +140026,6 @@ var init_fake_headless_backend = __esm(() => {
139914
140026
  remoteMemfs: false,
139915
140027
  serverSideToolManagement: false,
139916
140028
  serverSecrets: false,
139917
- agentFileImportExport: false,
139918
140029
  promptRecompile: false,
139919
140030
  byokProviderRefresh: false,
139920
140031
  localModelCatalog: true,
@@ -141756,10 +141867,10 @@ function middleTruncateText(text, budgetChars, headFrac = 0.3, tailFrac = 0.3) {
141756
141867
  const head = text.slice(0, headLength);
141757
141868
  const tail = tailLength > 0 ? text.slice(-tailLength) : "";
141758
141869
  const dropped = Math.max(0, text.length - (head.length + tail.length));
141759
- const marker = `
141870
+ const marker2 = `
141760
141871
  [TRUNCATED: dropped ${dropped} middle chars due to context budget]
141761
141872
  `;
141762
- return `${head}${marker}${tail}`;
141873
+ return `${head}${marker2}${tail}`;
141763
141874
  }
141764
141875
  function textFromUserContent(content) {
141765
141876
  const value = content.content;
@@ -144029,7 +144140,6 @@ class APIBackend {
144029
144140
  remoteMemfs: true,
144030
144141
  serverSideToolManagement: true,
144031
144142
  serverSecrets: true,
144032
- agentFileImportExport: true,
144033
144143
  promptRecompile: true,
144034
144144
  byokProviderRefresh: true,
144035
144145
  localModelCatalog: false,
@@ -145366,7 +145476,7 @@ var init_args = __esm(() => {
145366
145476
  mode: "both",
145367
145477
  help: {
145368
145478
  argLabel: "<name>",
145369
- description: 'Toolset mode: "auto", "codex", "default", or "gemini" (manual values override model-based auto-selection)'
145479
+ description: 'Toolset mode: "auto", "letta", "codex", "default", or "gemini" (manual values override model-based auto-selection)'
145370
145480
  }
145371
145481
  },
145372
145482
  prompt: {
@@ -145462,16 +145572,6 @@ var init_args = __esm(() => {
145462
145572
  }
145463
145573
  },
145464
145574
  "pre-load-skills": { parser: { type: "string" }, mode: "headless" },
145465
- "from-af": { parser: { type: "string" }, mode: "both" },
145466
- import: {
145467
- parser: { type: "string" },
145468
- mode: "both",
145469
- help: {
145470
- argLabel: "<path>",
145471
- description: "Create agent from an AgentFile (.af) template",
145472
- continuationLines: ["Use @author/name to import from the agent registry"]
145473
- }
145474
- },
145475
145575
  tags: { parser: { type: "string" }, mode: "headless" },
145476
145576
  memfs: {
145477
145577
  parser: { type: "boolean" },
@@ -181498,16 +181598,16 @@ function highlightCommand(command) {
181498
181598
  const firstLine = allLines[0] ?? "";
181499
181599
  const heredocMatch = HEREDOC_RE.exec(firstLine);
181500
181600
  if (heredocMatch && allLines.length > 2) {
181501
- const marker = heredocMatch[1] ?? "EOF";
181601
+ const marker2 = heredocMatch[1] ?? "EOF";
181502
181602
  let endIdx = allLines.length - 1;
181503
181603
  for (let i4 = allLines.length - 1;i4 > 0; i4--) {
181504
- if (allLines[i4]?.trim() === marker) {
181604
+ if (allLines[i4]?.trim() === marker2) {
181505
181605
  endIdx = i4;
181506
181606
  break;
181507
181607
  }
181508
181608
  }
181509
181609
  const bodyLines = allLines.slice(1, endIdx);
181510
- const terminatorLine = allLines[endIdx] ?? marker;
181610
+ const terminatorLine = allLines[endIdx] ?? marker2;
181511
181611
  const bashSpans = highlightSingleLineBash(firstLine);
181512
181612
  const fileMatch = REDIRECT_FILE_RE.exec(firstLine.slice(0, heredocMatch.index));
181513
181613
  const targetFile = fileMatch?.[1];
@@ -181835,9 +181935,9 @@ var jsx_dev_runtime5, headerRegex, codeBlockOpenRegex, codeBlockCloseRegex, list
181835
181935
  const listMatch = line.match(listItemRegex);
181836
181936
  if (listMatch && listMatch[1] !== undefined && listMatch[2] && listMatch[3] !== undefined) {
181837
181937
  const indent = listMatch[1].length;
181838
- const marker = listMatch[2];
181938
+ const marker2 = listMatch[2];
181839
181939
  const content = listMatch[3];
181840
- const bullet = `${marker} `;
181940
+ const bullet = `${marker2} `;
181841
181941
  const bulletWidth = bullet.length;
181842
181942
  contentBlocks.push(/* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Box_default, {
181843
181943
  paddingLeft: indent,
@@ -183645,9 +183745,6 @@ function normalizeConversationShorthandFlags(options) {
183645
183745
  }
183646
183746
  return { specifiedConversationId, specifiedAgentId };
183647
183747
  }
183648
- function resolveImportFlagAlias(options) {
183649
- return options.importFlagValue ?? options.fromAfFlagValue;
183650
- }
183651
183748
  function parsePositiveIntFlag(options) {
183652
183749
  const { rawValue, flagName } = options;
183653
183750
  if (rawValue === undefined) {
@@ -183928,14 +184025,14 @@ function runExtractionCommand2(command, args) {
183928
184025
  return `${command}: ${formatSpawnFailure2(result2)}`;
183929
184026
  }
183930
184027
  function extractTarGzArchive2(archivePath, extractDir) {
183931
- const failure = runExtractionCommand2("tar", [
184028
+ const failure2 = runExtractionCommand2("tar", [
183932
184029
  "xzf",
183933
184030
  archivePath,
183934
184031
  "-C",
183935
184032
  extractDir
183936
184033
  ]);
183937
- if (failure) {
183938
- throw new Error(`Failed to extract fd: ${failure}`);
184034
+ if (failure2) {
184035
+ throw new Error(`Failed to extract fd: ${failure2}`);
183939
184036
  }
183940
184037
  }
183941
184038
  function getWindowsTarCommand2() {
@@ -185112,8 +185209,6 @@ function getLoadingMessage(loadingState, continueSession) {
185112
185209
  return continueSession ? "Resuming agent..." : "Creating agent...";
185113
185210
  case "assembling":
185114
185211
  return "Assembling tools...";
185115
- case "importing":
185116
- return "Importing agent...";
185117
185212
  case "checking":
185118
185213
  return "Checking for pending approvals...";
185119
185214
  default:
@@ -185727,8 +185822,8 @@ function validatePrimaryStartupFlagConflicts(options) {
185727
185822
  message: "--ephemeral cannot be used with --stateless, --memfs, or --memfs-startup"
185728
185823
  },
185729
185824
  {
185730
- when: options.importFile || options.shouldResume,
185731
- message: "--ephemeral cannot be used with --import or --resume"
185825
+ when: options.shouldResume,
185826
+ message: "--ephemeral cannot be used with --resume"
185732
185827
  }
185733
185828
  ]
185734
185829
  });
@@ -185755,10 +185850,6 @@ function validatePrimaryStartupFlagConflicts(options) {
185755
185850
  when: options.forceNewAgent,
185756
185851
  message: "--conversation cannot be used with --new-agent"
185757
185852
  },
185758
- {
185759
- when: options.importFile,
185760
- message: "--conversation cannot be used with --import"
185761
- },
185762
185853
  {
185763
185854
  when: options.shouldResume,
185764
185855
  message: "--conversation cannot be used with --resume"
@@ -185779,13 +185870,6 @@ function validatePrimaryStartupFlagConflicts(options) {
185779
185870
  ]
185780
185871
  });
185781
185872
  }
185782
- function validateRegistryHandleOrThrow(handle2) {
185783
- const normalized = handle2.startsWith("@") ? handle2.slice(1) : handle2;
185784
- const parts = normalized.split("/");
185785
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
185786
- throw new Error(`Invalid registry handle "${handle2}"`);
185787
- }
185788
- }
185789
185873
 
185790
185874
  // src/cli/startup-mode.ts
185791
185875
  function isHeadlessStartup(flags, stdinIsTTY, firstPositional) {
@@ -187816,12 +187900,12 @@ function getResolvedEntrypoint() {
187816
187900
  }
187817
187901
  }
187818
187902
  function findInstalledPackagePath(resolvedPath) {
187819
- const marker = `${join42("node_modules", "@letta-ai", "letta-code")}`;
187820
- const index = resolvedPath.lastIndexOf(marker);
187903
+ const marker2 = `${join42("node_modules", "@letta-ai", "letta-code")}`;
187904
+ const index = resolvedPath.lastIndexOf(marker2);
187821
187905
  if (index === -1) {
187822
187906
  return null;
187823
187907
  }
187824
- return resolvedPath.slice(0, index + marker.length);
187908
+ return resolvedPath.slice(0, index + marker2.length);
187825
187909
  }
187826
187910
  function canWritePath(path33) {
187827
187911
  try {
@@ -191907,14 +191991,14 @@ function firstNonEmptyString2(...values4) {
191907
191991
  }
191908
191992
  return;
191909
191993
  }
191910
- function truncateChannelProgressText(value, maxLength3, marker = "...") {
191994
+ function truncateChannelProgressText(value, maxLength3, marker2 = "...") {
191911
191995
  if (value.length <= maxLength3) {
191912
191996
  return value;
191913
191997
  }
191914
- if (maxLength3 <= marker.length) {
191915
- return marker.slice(0, Math.max(0, maxLength3));
191998
+ if (maxLength3 <= marker2.length) {
191999
+ return marker2.slice(0, Math.max(0, maxLength3));
191916
192000
  }
191917
- return `${value.slice(0, maxLength3 - marker.length).trimEnd()}${marker}`;
192001
+ return `${value.slice(0, maxLength3 - marker2.length).trimEnd()}${marker2}`;
191918
192002
  }
191919
192003
  function replaceControlCharacters(value) {
191920
192004
  let result2 = "";
@@ -192313,7 +192397,8 @@ function resolveSlackConcreteActivity(event) {
192313
192397
  if (event.kind !== "tool" || !isNonEmptyString5(event.toolName) || event.toolName.toLowerCase() === "messagechannel") {
192314
192398
  return null;
192315
192399
  }
192316
- for (const description of [event.toolTitle, event.toolDetails]) {
192400
+ const descriptions = event.toolBatchTitle !== undefined ? [event.toolBatchTitle] : [event.toolTitle, event.toolDetails];
192401
+ for (const description of descriptions) {
192317
192402
  if (!isNonEmptyString5(description)) {
192318
192403
  continue;
192319
192404
  }
@@ -195184,6 +195269,12 @@ ${loadingText}`;
195184
195269
  signatureByConversation.set(stateKey, signature);
195185
195270
  const previous = writePromiseByConversation.get(stateKey) ?? Promise.resolve();
195186
195271
  const operation = previous.then(async () => {
195272
+ if (footerText && !stateByConversation.get(stateKey)?.isThinkingActive) {
195273
+ if (signatureByConversation.get(stateKey) === signature) {
195274
+ signatureByConversation.delete(stateKey);
195275
+ }
195276
+ return false;
195277
+ }
195187
195278
  try {
195188
195279
  await setStatus.call(slackClient.assistant?.threads, {
195189
195280
  channel_id: source.chatId,
@@ -195191,6 +195282,16 @@ ${loadingText}`;
195191
195282
  status: footerText,
195192
195283
  ...footerText ? { loading_messages: [loadingText] } : {}
195193
195284
  });
195285
+ const state = stateByConversation.get(stateKey);
195286
+ if (footerText && state && !state.isThinkingActive) {
195287
+ await setStatus.call(slackClient.assistant?.threads, {
195288
+ channel_id: source.chatId,
195289
+ thread_ts: threadTs,
195290
+ status: ""
195291
+ });
195292
+ clearedStaleReplyKeys.add(replyKey);
195293
+ return true;
195294
+ }
195194
195295
  if (footerText)
195195
195296
  clearedStaleReplyKeys.delete(replyKey);
195196
195297
  else
@@ -195289,7 +195390,40 @@ ${loadingText}`;
195289
195390
  await writeStatus(source, "", "", { force: true });
195290
195391
  signatureByConversation.delete(key2);
195291
195392
  }
195393
+ async function refresh(source) {
195394
+ const key2 = getConversationKey(source);
195395
+ const state = key2 ? stateByConversation.get(key2) : undefined;
195396
+ if (!key2 || !state?.isThinkingActive)
195397
+ return false;
195398
+ await writeStatus(source, state.typingFooterText, state.thinkingText, {
195399
+ force: true
195400
+ });
195401
+ if (stateByConversation.get(key2) === state && state.isThinkingActive) {
195402
+ scheduleKeepalive(key2);
195403
+ }
195404
+ return true;
195405
+ }
195406
+ async function handleLifecycle(event) {
195407
+ if (event.type === "queued") {
195408
+ if (await refresh(event.source))
195409
+ return;
195410
+ if (event.source.showStartupStatus) {
195411
+ await activate(event.source, SLACK_ASSISTANT_STARTUP_STATUS, SLACK_ASSISTANT_STARTUP_STATUS);
195412
+ }
195413
+ return;
195414
+ }
195415
+ for (const source of getUniqueSources(event.sources)) {
195416
+ if (event.type === "processing") {
195417
+ await clearStale(source);
195418
+ } else if (event.stopReason !== "requires_approval") {
195419
+ const remaining = event.remainingSources?.some((other) => other.accountId === source.accountId && getConversationKey(other) === getConversationKey(source) && getLifecycleReplyKey(other) === getLifecycleReplyKey(source));
195420
+ if (!remaining)
195421
+ await deactivate(source);
195422
+ }
195423
+ }
195424
+ }
195292
195425
  return {
195426
+ handleLifecycle,
195293
195427
  getUniqueSources,
195294
195428
  getLifecycleErrorReplyKey,
195295
195429
  activate,
@@ -195329,7 +195463,9 @@ ${loadingText}`;
195329
195463
  };
195330
195464
  }
195331
195465
  var SLACK_ASSISTANT_STATUS_KEEPALIVE_MS = 90000;
195332
- var init_status_controller = () => {};
195466
+ var init_status_controller = __esm(() => {
195467
+ init_progress();
195468
+ });
195333
195469
 
195334
195470
  // src/channels/slack/thread-context.ts
195335
195471
  function shouldHydrateCurrentSlackMessageAttachments(msg) {
@@ -195612,19 +195748,19 @@ function createSlackAdapter(config) {
195612
195748
  if (!running)
195613
195749
  return;
195614
195750
  if (event.type === "queued") {
195615
- if (isSlackFlatChannelThreadOpener(event.source) && isNonEmptyString4(event.source.messageId) && !agentThreadTracker.has(event.source.chatId, event.source.messageId)) {
195616
- await status.activate(event.source, SLACK_ASSISTANT_STARTUP_STATUS, SLACK_ASSISTANT_STARTUP_STATUS);
195617
- }
195751
+ const showStartupStatus = event.source.showStartupStatus || isSlackFlatChannelThreadOpener(event.source) && isNonEmptyString4(event.source.messageId) && !agentThreadTracker.has(event.source.chatId, event.source.messageId);
195752
+ await status.handleLifecycle({
195753
+ ...event,
195754
+ source: { ...event.source, showStartupStatus }
195755
+ });
195618
195756
  return;
195619
195757
  }
195620
195758
  const sources = status.getUniqueSources(event.sources);
195621
- if (event.type === "processing") {
195622
- await Promise.all(sources.map(status.clearStale));
195759
+ await status.handleLifecycle(event);
195760
+ if (event.type === "processing")
195623
195761
  return;
195624
- }
195625
195762
  if (event.stopReason === "requires_approval")
195626
195763
  return;
195627
- await Promise.all(sources.map(status.deactivate));
195628
195764
  if (!shouldPostSlackTerminalError(event.stopReason))
195629
195765
  return;
195630
195766
  const errorText = event.error?.trim() ?? "";
@@ -195899,6 +196035,36 @@ var init_attachment_task = __esm(() => {
195899
196035
  init_process_manager();
195900
196036
  });
195901
196037
 
196038
+ // src/channels/message-channel-bindings.ts
196039
+ function formatSlackBindingNotice(info, conversationId) {
196040
+ if (!info)
196041
+ return "";
196042
+ if ("unavailable" in info) {
196043
+ return `
196044
+ The message was delivered, but its thread binding could not be checked.`;
196045
+ }
196046
+ if (!info.binding)
196047
+ return `
196048
+ This thread has no incoming-message binding.`;
196049
+ const binding = info.binding;
196050
+ const state = binding.detached ? `This thread is detached (binding: ${binding.conversationId}).` : !binding.enabled ? `Incoming replies are paused for this thread (binding: ${binding.conversationId}).` : binding.conversationId === conversationId ? `Replies in this thread go to this conversation (${conversationId}).` : `Replies in this thread currently go to ${binding.conversationId}; this conversation is ${conversationId}.`;
196051
+ if (binding.conversationId === conversationId)
196052
+ return `
196053
+ ${state}`;
196054
+ const action3 = {
196055
+ action: "update-binding",
196056
+ channel: info.channel,
196057
+ accountId: info.accountId,
196058
+ chat_id: info.chatId,
196059
+ threadId: info.threadId,
196060
+ conversationId,
196061
+ expectedConversationId: binding.conversationId
196062
+ };
196063
+ return `
196064
+ ${state}
196065
+ To change this thread's destination to this conversation, call MessageChannel with ${JSON.stringify(action3)}. Existing pause/detach settings are preserved.`;
196066
+ }
196067
+
195902
196068
  // src/channels/slack/message-action-contract.ts
195903
196069
  async function sendSlackMessage(context3) {
195904
196070
  const { request, route, adapter, formatText } = context3;
@@ -195922,7 +196088,8 @@ async function sendSlackMessage(context3) {
195922
196088
  agentId: route.agentId,
195923
196089
  conversationId: route.conversationId
195924
196090
  });
195925
- return request.mediaPath ? `Attachment sent to slack (message_id: ${result2.messageId})` : `Message sent to slack (message_id: ${result2.messageId})`;
196091
+ const confirmation = request.mediaPath ? `Attachment sent to slack (message_id: ${result2.messageId})` : `Message sent to slack (message_id: ${result2.messageId})`;
196092
+ return confirmation + formatSlackBindingNotice(result2.bindingInfo, route.conversationId);
195926
196093
  }
195927
196094
  async function reactInSlack(context3) {
195928
196095
  const { request, route, adapter } = context3;
@@ -195965,11 +196132,26 @@ function createSlackMessageActionAdapter(options = {}) {
195965
196132
  ...options.react ? ["react"] : [],
195966
196133
  ...options.listCustomEmojis ? ["list-custom-emojis"] : [],
195967
196134
  ...options.uploadFile ? ["upload-file"] : [],
195968
- ...options.downloadFile ? ["download-file"] : []
196135
+ ...options.downloadFile ? ["download-file"] : [],
196136
+ ...options.bindings ? ["get-binding", "update-binding"] : []
195969
196137
  ];
195970
196138
  return {
195971
196139
  describeMessageTool() {
195972
196140
  const properties4 = {};
196141
+ if (options.bindings) {
196142
+ properties4.threadId = {
196143
+ type: ["string", "null"],
196144
+ description: "Thread identifier. Binding actions require an exact Slack thread timestamp, or explicit null for an unthreaded DM."
196145
+ };
196146
+ properties4.conversationId = {
196147
+ type: "string",
196148
+ description: "Destination conversation for update-binding. Must belong to this agent; default selects this agent's default conversation."
196149
+ };
196150
+ properties4.expectedConversationId = {
196151
+ type: "string",
196152
+ description: "Expected current destination for update-binding, from get-binding. A different current binding returns a conflict; an already-matching destination is a no-op."
196153
+ };
196154
+ }
195973
196155
  if (options.downloadFile) {
195974
196156
  properties4.attachmentId = {
195975
196157
  type: "string",
@@ -196012,6 +196194,7 @@ function createSlackMessageActionAdapter(options = {}) {
196012
196194
  }
196013
196195
  };
196014
196196
  }
196197
+ var init_message_action_contract = () => {};
196015
196198
 
196016
196199
  // src/channels/targets.ts
196017
196200
  import { existsSync as existsSync37, mkdirSync as mkdirSync21, readFileSync as readFileSync23, writeFileSync as writeFileSync16 } from "node:fs";
@@ -196391,6 +196574,7 @@ async function downloadSlackFile(context3) {
196391
196574
  var slackMessageActions;
196392
196575
  var init_message_actions2 = __esm(() => {
196393
196576
  init_attachment_task();
196577
+ init_message_action_contract();
196394
196578
  init_target_resolution();
196395
196579
  slackMessageActions = createSlackMessageActionAdapter({
196396
196580
  react: true,
@@ -204807,10 +204991,10 @@ function formatChannelStartupError(error4) {
204807
204991
  return String(error4);
204808
204992
  }
204809
204993
  function formatChannelStartupFailures(failures) {
204810
- const failedChannels = Array.from(new Set(failures.map((failure) => failure.channelId)));
204811
- const lines = failures.map((failure) => {
204812
- const label = failure.accountId ? `${failure.channelId}/${failure.accountId}` : failure.channelId;
204813
- return `- ${label}: ${failure.error}`;
204994
+ const failedChannels = Array.from(new Set(failures.map((failure2) => failure2.channelId)));
204995
+ const lines = failures.map((failure2) => {
204996
+ const label = failure2.accountId ? `${failure2.channelId}/${failure2.accountId}` : failure2.channelId;
204997
+ return `- ${label}: ${failure2.error}`;
204814
204998
  });
204815
204999
  return [
204816
205000
  "Failed to start requested channel listeners.",
@@ -217168,7 +217352,7 @@ function shouldProcessInboundMessageDirectly(runtime, parsed) {
217168
217352
  });
217169
217353
  return getListenerBlockedReason(runtime.turnLifecycle.snapshot(), activeScope ? getPendingControlRequestCount(runtime.listener, activeScope) : 0) === null;
217170
217354
  }
217171
- function consumeQueuedTurn(runtime) {
217355
+ function consumeQueuedTurn(runtime, continuation) {
217172
217356
  const queuedItems = runtime.queueRuntime.peekReady();
217173
217357
  const firstQueuedItem = queuedItems[0];
217174
217358
  if (!firstQueuedItem || !isCoalescable(firstQueuedItem.kind)) {
@@ -217180,15 +217364,22 @@ function consumeQueuedTurn(runtime) {
217180
217364
  let hasCronPrompt = false;
217181
217365
  let hasModContinue = false;
217182
217366
  let batchConnectionId;
217367
+ let batchActingUserId = firstQueuedItem.actingUserId;
217183
217368
  let batchImageFailureMode = null;
217184
217369
  const isNoCoalesce = (candidate) => candidate.kind === "message" && candidate.noCoalesce === true;
217185
217370
  for (const item of queuedItems) {
217371
+ if (continuation && item.actingUserId !== continuation.actingUserId) {
217372
+ break;
217373
+ }
217186
217374
  if (!isCoalescable(item.kind) || !hasSameQueueScope(firstQueuedItem, item)) {
217187
217375
  break;
217188
217376
  }
217189
217377
  if (queueLen > 0 && (isNoCoalesce(item) || isNoCoalesce(firstQueuedItem))) {
217190
217378
  break;
217191
217379
  }
217380
+ if (batchActingUserId && item.actingUserId && batchActingUserId !== item.actingUserId) {
217381
+ break;
217382
+ }
217192
217383
  if (item.kind === "message") {
217193
217384
  const itemConnectionId = runtime.queuedMessagesByItemId.get(item.id)?.connectionId;
217194
217385
  if (batchConnectionId !== undefined && itemConnectionId !== undefined && itemConnectionId !== batchConnectionId) {
@@ -217201,6 +217392,7 @@ function consumeQueuedTurn(runtime) {
217201
217392
  }
217202
217393
  batchImageFailureMode = itemImageFailureMode;
217203
217394
  }
217395
+ batchActingUserId ??= item.actingUserId;
217204
217396
  queueLen += 1;
217205
217397
  if (item.kind === "message") {
217206
217398
  hasMessage = true;
@@ -218066,12 +218258,12 @@ async function resolveDesktopEnvironmentConnectionId(list = listEnvironments) {
218066
218258
  }
218067
218259
  return { connectionId: environment2.connectionId, environment: environment2 };
218068
218260
  }
218069
- async function resolveEnvironmentConnectionId(selector) {
218261
+ async function resolveEnvironmentConnectionId(selector, list = listEnvironments) {
218070
218262
  const trimmed = selector.trim();
218071
218263
  if (!trimmed) {
218072
218264
  throw new Error("Computer selector must not be empty");
218073
218265
  }
218074
- const response = await listEnvironments({ limit: 100 });
218266
+ const response = await list({ limit: 100 });
218075
218267
  const matches3 = response.connections.filter((environment3) => {
218076
218268
  return environment3.connectionId === trimmed || environment3.id === trimmed || environment3.deviceId === trimmed || environment3.connectionName === trimmed;
218077
218269
  });
@@ -218082,9 +218274,10 @@ async function resolveEnvironmentConnectionId(selector) {
218082
218274
  if (onlineMatches.length === 0) {
218083
218275
  throw new Error(`Computer "${trimmed}" is offline. Matched: ${matches3.map(describeEnvironment).join(", ")}`);
218084
218276
  }
218085
- if (onlineMatches.length > 1) {
218277
+ if (new Set(onlineMatches.map((environment3) => environment3.deviceId)).size > 1) {
218086
218278
  throw new Error(`Computer "${trimmed}" is ambiguous. Matched: ${onlineMatches.map(describeEnvironment).join(", ")}`);
218087
218279
  }
218280
+ onlineMatches.sort((a2, b3) => Math.max(b3.lastHeartbeat ?? 0, b3.lastSeenAt) - Math.max(a2.lastHeartbeat ?? 0, a2.lastSeenAt));
218088
218281
  const environment2 = onlineMatches[0];
218089
218282
  if (!environment2) {
218090
218283
  throw new Error(`Computer "${trimmed}" is offline`);
@@ -219014,7 +219207,9 @@ List options:
219014
219207
  Notes:
219015
219208
  - Output is JSON only.
219016
219209
  - Uses CLI auth; override with LETTA_API_KEY/LETTA_BASE_URL if needed.
219017
- - Use letta computers current to get this computer's connectionId.
219210
+ - Use letta computers current to get this computer's stable deviceId.
219211
+ - Prefer deviceId or connectionName for --computer and Agent(computer=...).
219212
+ connectionId is ephemeral; use it only to pin a specific listener.
219018
219213
  - Use --computer cloud to route through the target agent's cloud sandbox.
219019
219214
  - Use --computer <name|device-id|connection-id> with headless messaging
219020
219215
  to route a message through a specific registered computer.
@@ -223003,6 +223198,7 @@ var init_protocol_inbound = __esm(() => {
223003
223198
  "default",
223004
223199
  "gemini",
223005
223200
  "gemini_snake",
223201
+ "letta",
223006
223202
  "none"
223007
223203
  ]);
223008
223204
  });
@@ -224792,15 +224988,8 @@ function formatToolsetName(id2) {
224792
224988
  }
224793
224989
  var TOOLSET_DISPLAY_NAMES;
224794
224990
  var init_toolset_labels = __esm(() => {
224795
- TOOLSET_DISPLAY_NAMES = {
224796
- default: "Claude",
224797
- codex: "Codex",
224798
- codex_snake: "Codex (snake_case)",
224799
- gemini: "Gemini",
224800
- gemini_snake: "Gemini (snake_case)",
224801
- none: "None",
224802
- auto: "Auto"
224803
- };
224991
+ init_toolset_options();
224992
+ TOOLSET_DISPLAY_NAMES = Object.fromEntries(TOOLSET_OPTIONS.map((option2) => [option2.id, option2.display_name]));
224804
224993
  });
224805
224994
 
224806
224995
  // src/mods/disabled-mod-adapter.ts
@@ -396850,7 +397039,7 @@ function handleModelToolsetCommand(parsed, context3) {
396850
397039
  });
396851
397040
  safeSocketSend(socket, response, "listener_update_model_send_failed", "listener_update_model");
396852
397041
  } catch (error4) {
396853
- const failure = {
397042
+ const failure2 = {
396854
397043
  type: "update_model_response",
396855
397044
  request_id: parsed.request_id,
396856
397045
  success: false,
@@ -396862,7 +397051,7 @@ function handleModelToolsetCommand(parsed, context3) {
396862
397051
  model_handle: resolvedModel?.handle ?? parsed.payload.model_handle,
396863
397052
  error: error4 instanceof Error ? error4.message : "Failed to update model"
396864
397053
  };
396865
- safeSocketSend(socket, failure, "listener_update_model_send_failed", "listener_update_model");
397054
+ safeSocketSend(socket, failure2, "listener_update_model_send_failed", "listener_update_model");
396866
397055
  }
396867
397056
  });
396868
397057
  return true;
@@ -396880,7 +397069,7 @@ function handleModelToolsetCommand(parsed, context3) {
396880
397069
  });
396881
397070
  safeSocketSend(socket, response, "listener_update_toolset_send_failed", "listener_update_toolset");
396882
397071
  } catch (error4) {
396883
- const failure = {
397072
+ const failure2 = {
396884
397073
  type: "update_toolset_response",
396885
397074
  request_id: parsed.request_id,
396886
397075
  success: false,
@@ -396890,7 +397079,7 @@ function handleModelToolsetCommand(parsed, context3) {
396890
397079
  },
396891
397080
  error: error4 instanceof Error ? error4.message : "Failed to update toolset"
396892
397081
  };
396893
- safeSocketSend(socket, failure, "listener_update_toolset_send_failed", "listener_update_toolset");
397082
+ safeSocketSend(socket, failure2, "listener_update_toolset_send_failed", "listener_update_toolset");
396894
397083
  }
396895
397084
  });
396896
397085
  return true;
@@ -405223,13 +405412,14 @@ async function handleApprovalStop(params) {
405223
405412
  }
405224
405413
  ]);
405225
405414
  let continuationBatchId = dequeuedBatchId;
405226
- let continuationActingUserId;
405227
- const consumedQueuedTurn = consumeQueuedTurn(runtime);
405415
+ const sendOptions = buildSendOptions() ?? {};
405416
+ const consumedQueuedTurn = consumeQueuedTurn(runtime, {
405417
+ actingUserId: sendOptions.actingUserId
405418
+ });
405228
405419
  if (consumedQueuedTurn) {
405229
405420
  const { dequeuedBatch, queuedTurn } = consumedQueuedTurn;
405230
405421
  turnCorrelation?.appendDequeuedBatch(dequeuedBatch.batchId);
405231
405422
  continuationBatchId = dequeuedBatch.batchId;
405232
- continuationActingUserId = queuedTurn.actingUserId;
405233
405423
  nextTurnInput = appendQueuedTurnToInput(nextTurnInput, queuedTurn);
405234
405424
  emitDequeuedUserMessage(socket, runtime, queuedTurn, dequeuedBatch);
405235
405425
  }
@@ -405244,11 +405434,9 @@ async function handleApprovalStop(params) {
405244
405434
  });
405245
405435
  let sendResult;
405246
405436
  try {
405247
- const sendOptions = buildSendOptions() ?? {};
405248
405437
  const imageFailureModesByMessageOtid = mergeImageFailureModesByMessageOtid(sendOptions.imageFailureModesByMessageOtid, nextTurnInput.imageFailureModesByMessageOtid);
405249
405438
  sendResult = await sendApprovalContinuation(conversationId, nextInputWithSkillContent, {
405250
405439
  ...sendOptions,
405251
- ...continuationActingUserId ? { actingUserId: continuationActingUserId } : {},
405252
405440
  ...imageFailureModesByMessageOtid ? { imageFailureModesByMessageOtid } : {},
405253
405441
  ...continuationWasFullyAutoHandled ? { allowResponseStateReuse: true } : {}
405254
405442
  }, socket, runtime, turnLease);
@@ -406427,12 +406615,12 @@ function rowToolCalls(row, index, diagnostics2) {
406427
406615
  }
406428
406616
  return calls;
406429
406617
  }
406430
- function contentText2(content) {
406618
+ function contentText(content) {
406431
406619
  if (typeof content === "string") {
406432
406620
  if (content.startsWith(CONTENT_JSON_PREFIX)) {
406433
406621
  const encoded = content.slice(CONTENT_JSON_PREFIX.length);
406434
406622
  try {
406435
- return contentText2(JSON.parse(encoded));
406623
+ return contentText(JSON.parse(encoded));
406436
406624
  } catch {
406437
406625
  return encoded;
406438
406626
  }
@@ -406518,7 +406706,7 @@ var init_hermes = __esm(() => {
406518
406706
  });
406519
406707
  };
406520
406708
  if (row.role === "user") {
406521
- const content = contentText2(row.content);
406709
+ const content = contentText(row.content);
406522
406710
  if (content) {
406523
406711
  emit({
406524
406712
  type: "message",
@@ -406538,7 +406726,7 @@ var init_hermes = __esm(() => {
406538
406726
  ...timestamp ? { timestamp } : {}
406539
406727
  });
406540
406728
  }
406541
- const content = contentText2(row.content);
406729
+ const content = contentText(row.content);
406542
406730
  if (content) {
406543
406731
  emit({
406544
406732
  type: "message",
@@ -406561,7 +406749,7 @@ var init_hermes = __esm(() => {
406561
406749
  if (row.role === "tool") {
406562
406750
  emit({
406563
406751
  type: "tool_result",
406564
- content: contentText2(row.content),
406752
+ content: contentText(row.content),
406565
406753
  ...typeof row.tool_call_id === "string" && row.tool_call_id ? { callId: row.tool_call_id } : {},
406566
406754
  ...timestamp ? { timestamp } : {}
406567
406755
  });
@@ -407763,28 +407951,28 @@ function truncateText(text2, limit4, strategy) {
407763
407951
  let low = 0;
407764
407952
  let high = Math.min(textLength2 - 1, limit4);
407765
407953
  let keep = -1;
407766
- let marker = "";
407954
+ let marker2 = "";
407767
407955
  while (low <= high) {
407768
407956
  const candidateKeep = Math.floor((low + high) / 2);
407769
407957
  const candidateMarker = truncationMarker(textLength2 - candidateKeep);
407770
407958
  if (candidateKeep + codePointLength(candidateMarker) <= limit4) {
407771
407959
  keep = candidateKeep;
407772
- marker = candidateMarker;
407960
+ marker2 = candidateMarker;
407773
407961
  low = candidateKeep + 1;
407774
407962
  } else {
407775
407963
  high = candidateKeep - 1;
407776
407964
  }
407777
407965
  }
407778
407966
  if (keep < 0) {
407779
- marker = sliceCodePoints("…", 0, limit4);
407780
- keep = limit4 - codePointLength(marker);
407967
+ marker2 = sliceCodePoints("…", 0, limit4);
407968
+ keep = limit4 - codePointLength(marker2);
407781
407969
  }
407782
407970
  if (strategy === "head") {
407783
- return sliceCodePoints(text2, 0, keep) + marker;
407971
+ return sliceCodePoints(text2, 0, keep) + marker2;
407784
407972
  }
407785
407973
  const headLength = Math.ceil(keep / 2);
407786
407974
  const tailLength = keep - headLength;
407787
- return sliceCodePoints(text2, 0, headLength) + marker + (tailLength > 0 ? sliceCodePoints(text2, textLength2 - tailLength, textLength2) : "");
407975
+ return sliceCodePoints(text2, 0, headLength) + marker2 + (tailLength > 0 ? sliceCodePoints(text2, textLength2 - tailLength, textLength2) : "");
407788
407976
  }
407789
407977
  function truncationMarker(remaining) {
407790
407978
  return `
@@ -409095,7 +409283,7 @@ function normalizeReflectionTranscript(entries) {
409095
409283
  transcript,
409096
409284
  sourceContext: { partial: true },
409097
409285
  bounds: {
409098
- toolArguments: { maxCharacters: TOOL_ARGS_TRUNCATE_LIMIT }
409286
+ toolArguments: { maxCharacters: null }
409099
409287
  },
409100
409288
  filters: { toolResults: "include" }
409101
409289
  });
@@ -409843,7 +410031,7 @@ async function finalizeMultiReflectionPayload(agentId, manifest, success) {
409843
410031
  await finalizeAutoReflectionPayload(agentId, slice2.conversation_id, slice2.payload_path, slice2.end_snapshot_line, true);
409844
410032
  }
409845
410033
  }
409846
- var LEGACY_MESSAGE_ID_STATE_SCHEMA_VERSION = "v2_message_id", REFLECTION_STATE_SCHEMA_VERSION = "v3_assistant_steps", stateMutexes, TOOL_ARGS_TRUNCATE_LIMIT = 300, REFLECTION_AUTO_QUERIES, REFLECTION_AUTO_RECENT_LIMIT = 20, REFLECTION_AUTO_UNREFLECTED_LIMIT = 20, REFLECTION_AUTO_SEARCH_LIMIT_PER_QUERY = 10, REFLECTION_AUTO_MAX_CATALOG_CANDIDATES = 30, REFLECTION_AUTO_MAX_SELECTED_TRANSCRIPTS = 5;
410034
+ var LEGACY_MESSAGE_ID_STATE_SCHEMA_VERSION = "v2_message_id", REFLECTION_STATE_SCHEMA_VERSION = "v3_assistant_steps", stateMutexes, REFLECTION_AUTO_QUERIES, REFLECTION_AUTO_RECENT_LIMIT = 20, REFLECTION_AUTO_UNREFLECTED_LIMIT = 20, REFLECTION_AUTO_SEARCH_LIMIT_PER_QUERY = 10, REFLECTION_AUTO_MAX_CATALOG_CANDIDATES = 30, REFLECTION_AUTO_MAX_SELECTED_TRANSCRIPTS = 5;
409847
410035
  var init_reflection_transcript = __esm(() => {
409848
410036
  init_dist11();
409849
410037
  init_memory_filesystem2();
@@ -410510,7 +410698,7 @@ function isRetryableReflectionArenaModelError(error4) {
410510
410698
  "insufficient credits",
410511
410699
  "exceeded-quota",
410512
410700
  "llm_insufficient_credits"
410513
- ].some((marker) => normalized.includes(marker));
410701
+ ].some((marker2) => normalized.includes(marker2));
410514
410702
  }
410515
410703
  var init_reflection_configuration_error = __esm(() => {
410516
410704
  init_strip_ansi();
@@ -410568,9 +410756,9 @@ function recordReflectionIntegrationRetry(agentId, integration, success, trigger
410568
410756
  const previous = retries.get(agentId);
410569
410757
  const delayMs = previous ? Math.min(previous.delayMs * 2, MAX_RETRY_DELAY_MS2) : INITIAL_RETRY_DELAY_MS3;
410570
410758
  const notifiedFailures = previous?.notifiedFailures ?? new Set;
410571
- const failure = `${integration.status}:${integration.failurePhase ?? ""}`;
410572
- const shouldNotify = triggerSource === "manual" || !notifiedFailures.has(failure);
410573
- notifiedFailures.add(failure);
410759
+ const failure2 = `${integration.status}:${integration.failurePhase ?? ""}`;
410760
+ const shouldNotify = triggerSource === "manual" || !notifiedFailures.has(failure2);
410761
+ notifiedFailures.add(failure2);
410574
410762
  retries.set(agentId, { delayMs, retryAt: now2 + delayMs, notifiedFailures });
410575
410763
  return shouldNotify;
410576
410764
  }
@@ -416668,12 +416856,12 @@ async function resolveDirectory(requestedPath, currentBootWorkingDirectory) {
416668
416856
  return normalizedPath;
416669
416857
  }
416670
416858
  function getCwdScopeKeyFromRuntimeKey(runtimeKey) {
416671
- const marker = "::conversation:";
416672
- const markerIndex = runtimeKey.lastIndexOf(marker);
416859
+ const marker2 = "::conversation:";
416860
+ const markerIndex = runtimeKey.lastIndexOf(marker2);
416673
416861
  if (!runtimeKey.startsWith("agent:") || markerIndex === -1) {
416674
416862
  return null;
416675
416863
  }
416676
- const conversationId = runtimeKey.slice(markerIndex + marker.length);
416864
+ const conversationId = runtimeKey.slice(markerIndex + marker2.length);
416677
416865
  return conversationId === "default" ? runtimeKey : `conversation:${conversationId}`;
416678
416866
  }
416679
416867
  async function applyScopeUpdates(socket, runtime) {
@@ -417897,10 +418085,12 @@ function createListenerMessageHandler(params) {
417897
418085
  } = params;
417898
418086
  const connectionId = explicitConnectionId ?? opts.connectionId;
417899
418087
  return async (data) => {
418088
+ const lifecycleMessage = parseListenerReadyMessage(data) ?? parseServerLifecycleMessage(data);
418089
+ if (lifecycleMessage?.type !== "pong")
418090
+ sealStartupLogs();
417900
418091
  const raw2 = data.toString();
417901
418092
  let parsedScope = null;
417902
418093
  try {
417903
- const lifecycleMessage = parseListenerReadyMessage(data) ?? parseServerLifecycleMessage(data);
417904
418094
  if (lifecycleMessage) {
417905
418095
  if (lifecycleMessage.type === "pong") {
417906
418096
  runtime.lastPongAt = Date.now();
@@ -418445,6 +418635,7 @@ var init_message_router = __esm(async () => {
418445
418635
  init_system_prompt_warning();
418446
418636
  init_settings_manager();
418447
418637
  init_debug();
418638
+ init_startup_log_boundary();
418448
418639
  init_terminal_handler();
418449
418640
  init_agents_conversations();
418450
418641
  init_app_server_info();
@@ -418892,6 +419083,7 @@ function stopRuntime(runtime, suppressCallbacks) {
418892
419083
  async function startConnectedListenerRuntime(runtime, transport, opts, processQueuedTurn, options = {}) {
418893
419084
  if (runtime !== getActiveRuntime() || runtime.intentionallyClosed)
418894
419085
  return;
419086
+ sealStartupLogs();
418895
419087
  installExternalToolBridge(runtime);
418896
419088
  const shouldStartCronScheduler = options.startCronScheduler !== false && process.env.LETTA_DISABLE_CRON_SCHEDULER !== "1";
418897
419089
  markListenerConnectionInitialized(runtime, opts.connectionId);
@@ -419346,6 +419538,7 @@ var init_lifecycle = __esm(async () => {
419346
419538
  init_telemetry();
419347
419539
  init_error_reporting();
419348
419540
  init_debug();
419541
+ init_startup_log_boundary();
419349
419542
  init_terminal_handler();
419350
419543
  init_approval();
419351
419544
  init_auth();
@@ -422827,13 +423020,13 @@ function legacyImageFromPart(part) {
422827
423020
  const mediaType = typeof part.mediaType === "string" ? part.mediaType : typeof part.mime === "string" ? part.mime : undefined;
422828
423021
  const url = typeof part.url === "string" ? part.url : undefined;
422829
423022
  if (mediaType?.startsWith("image/") && url?.startsWith("data:")) {
422830
- const marker = ";base64,";
422831
- const markerIndex = url.indexOf(marker);
423023
+ const marker2 = ";base64,";
423024
+ const markerIndex = url.indexOf(marker2);
422832
423025
  if (markerIndex >= 0) {
422833
423026
  return {
422834
423027
  type: "image",
422835
423028
  mimeType: mediaType,
422836
- data: url.slice(markerIndex + marker.length)
423029
+ data: url.slice(markerIndex + marker2.length)
422837
423030
  };
422838
423031
  }
422839
423032
  }
@@ -440056,7 +440249,7 @@ var init_mcp_client = __esm(() => {
440056
440249
  init_streamableHttp();
440057
440250
  DEFAULT_CLIENT_INFO = {
440058
440251
  name: "letta-code",
440059
- version: "0.32.1"
440252
+ version: "0.32.3"
440060
440253
  };
440061
440254
  });
440062
440255
 
@@ -443945,7 +444138,7 @@ async function request(path50, init, deps) {
443945
444138
  async function ensureConversationSandbox(agentId, conversationId, deps = defaultDeps) {
443946
444139
  const response = await request(`/v1/agents/${encodeURIComponent(agentId)}/sandboxes`, {
443947
444140
  method: "POST",
443948
- body: JSON.stringify({ conversationId })
444141
+ body: JSON.stringify(conversationId === "default" ? {} : { conversationId })
443949
444142
  }, deps);
443950
444143
  return await response.json();
443951
444144
  }
@@ -443983,8 +444176,17 @@ Usage:
443983
444176
  letta sandbox upload <local-path>
443984
444177
  letta sandbox download <sandbox-path> [--to <local-path>]
443985
444178
 
444179
+ Target another conversation (upload or download):
444180
+ letta sandbox upload <local-path> --conversation <conv-id>
444181
+ letta sandbox upload <local-path> --agent <agent-id>
444182
+
443986
444183
  Notes:
443987
- - Requires an active conversation for a Letta Cloud agent.
444184
+ - Without target flags, uses the active Letta Cloud conversation.
444185
+ - --conversation resolves the owning agent; --agent, if given, must match.
444186
+ - --agent alone selects that agent's main/default sandbox.
444187
+ - --conversation default is also supported and requires explicit --agent.
444188
+ - Target flags override shell/session context without changing it.
444189
+ - Run upload on the computer containing the local file, including a remote subagent.
443988
444190
  - Uploads are stored under /root/downloads in the conversation sandbox.
443989
444191
  - Downloads are limited to files under /root/downloads.
443990
444192
  - Output is JSON only.
@@ -444021,6 +444223,35 @@ function resolveSandboxSession(env5, fallback) {
444021
444223
  }
444022
444224
  return session2;
444023
444225
  }
444226
+ async function resolveSandboxTarget(target2, getCurrentSession, retrieveConversation) {
444227
+ if (target2.agent === undefined && target2.conversation === undefined) {
444228
+ return getCurrentSession();
444229
+ }
444230
+ const agentId = target2.agent?.trim();
444231
+ const conversationId = target2.conversation === undefined && agentId ? "default" : target2.conversation?.trim();
444232
+ if (target2.agent !== undefined && !agentId) {
444233
+ throw new Error("--agent must not be empty");
444234
+ }
444235
+ if (!conversationId || conversationId === "new") {
444236
+ throw new Error("Specify --conversation <conv-id> or --conversation default");
444237
+ }
444238
+ if (agentId && isLocalAgentId(agentId)) {
444239
+ throw new Error("Sandbox file transfer requires a Letta Cloud agent");
444240
+ }
444241
+ if (conversationId === "default") {
444242
+ if (!agentId)
444243
+ throw new Error("--conversation default requires --agent");
444244
+ return { agentId, conversationId };
444245
+ }
444246
+ const conversation = await retrieveConversation(conversationId);
444247
+ if (!conversation.agent_id || isLocalAgentId(conversation.agent_id)) {
444248
+ throw new Error("The target conversation must belong to a Letta Cloud agent");
444249
+ }
444250
+ if (agentId && agentId !== conversation.agent_id) {
444251
+ throw new Error(`Conversation ${conversationId} does not belong to ${agentId}`);
444252
+ }
444253
+ return { agentId: conversation.agent_id, conversationId };
444254
+ }
444024
444255
  async function initializeSandboxSettings() {
444025
444256
  await settingsManager.initialize();
444026
444257
  await settingsManager.loadLocalProjectSettings();
@@ -444049,24 +444280,37 @@ async function runSandboxSubcommand(argv, deps = {}) {
444049
444280
  if (!await (deps.isCloud ?? isLettaCloud)()) {
444050
444281
  throw new Error("Sandbox file transfer is only available on Letta Cloud");
444051
444282
  }
444052
- const session2 = resolveSandboxSession(process.env, (deps.getLastSession ?? (() => settingsManager.getEffectiveLastSession()))());
444053
- const ensureSandbox = deps.ensureSandbox ?? ensureConversationSandbox;
444283
+ const session2 = await resolveSandboxTarget(parsed.values, () => resolveSandboxSession(process.env, (deps.getLastSession ?? (() => settingsManager.getEffectiveLastSession()))()), deps.retrieveConversation ?? (async (id2) => (await getClient()).conversations.retrieve(id2)));
444284
+ const explicitTarget = parsed.values.conversation !== undefined || parsed.values.agent !== undefined;
444285
+ const ensureSandbox = async () => {
444286
+ const sandbox2 = await (deps.ensureSandbox ?? ensureConversationSandbox)(session2.agentId, session2.conversationId);
444287
+ if (explicitTarget && (sandbox2.conversationId ?? "default") !== session2.conversationId) {
444288
+ throw new Error("The server returned a sandbox for a different conversation; no files transferred");
444289
+ }
444290
+ return sandbox2;
444291
+ };
444292
+ const targetOutput = explicitTarget ? session2 : {};
444054
444293
  if (action3 === "upload") {
444055
444294
  const localPath2 = resolve37(path50);
444056
444295
  const fileStat = await (deps.statLocalPath ?? stat17)(localPath2);
444057
444296
  if (!fileStat.isFile())
444058
444297
  throw new Error(`${localPath2} is not a file`);
444059
444298
  const data2 = await (deps.readLocalFile ?? readFile25)(localPath2);
444060
- const sandbox2 = await ensureSandbox(session2.agentId, session2.conversationId);
444299
+ const sandbox2 = await ensureSandbox();
444061
444300
  const result2 = await (deps.uploadFile ?? uploadFileToSandbox)(sandbox2.sandboxId, { blob: new Blob([data2]), name: basename26(localPath2) });
444062
- console.log(JSON.stringify(result2, null, 2));
444301
+ console.log(JSON.stringify({ ...result2, ...targetOutput }, null, 2));
444063
444302
  return 0;
444064
444303
  }
444065
- const sandbox = await ensureSandbox(session2.agentId, session2.conversationId);
444304
+ const sandbox = await ensureSandbox();
444066
444305
  const data = await (deps.downloadFile ?? downloadFileFromSandbox)(sandbox.sandboxId, path50);
444067
444306
  const localPath = resolve37(parsed.values.to ?? basename26(path50));
444068
444307
  await (deps.writeLocalFile ?? writeFile17)(localPath, data);
444069
- console.log(JSON.stringify({ path: localPath, sandboxPath: path50, size: data.byteLength }, null, 2));
444308
+ console.log(JSON.stringify({
444309
+ path: localPath,
444310
+ sandboxPath: path50,
444311
+ size: data.byteLength,
444312
+ ...targetOutput
444313
+ }, null, 2));
444070
444314
  return 0;
444071
444315
  } catch (error5) {
444072
444316
  console.error(`Error: ${error5 instanceof Error ? error5.message : error5}`);
@@ -444076,11 +444320,14 @@ async function runSandboxSubcommand(argv, deps = {}) {
444076
444320
  var SANDBOX_OPTIONS;
444077
444321
  var init_sandbox2 = __esm(() => {
444078
444322
  init_memory_filesystem2();
444323
+ init_client4();
444079
444324
  init_sandbox_files();
444080
444325
  init_settings_manager();
444081
444326
  SANDBOX_OPTIONS = {
444082
444327
  help: { type: "boolean", short: "h" },
444083
- to: { type: "string" }
444328
+ to: { type: "string" },
444329
+ conversation: { type: "string" },
444330
+ agent: { type: "string" }
444084
444331
  };
444085
444332
  });
444086
444333
 
@@ -446835,13 +447082,13 @@ function parseGitHubSpecifier(input) {
446835
447082
  if (!owner || !repo)
446836
447083
  return null;
446837
447084
  const repoUrl = `https://github.com/${owner}/${repo}.git`;
446838
- const marker = parts[2];
446839
- if ((marker === "tree" || marker === "blob") && parts.length >= 4) {
447085
+ const marker2 = parts[2];
447086
+ if ((marker2 === "tree" || marker2 === "blob") && parts.length >= 4) {
446840
447087
  const treePath = parts.slice(3).join("/");
446841
447088
  return {
446842
447089
  repoUrl,
446843
447090
  branch: null,
446844
- subdir: marker === "blob" ? dirname34(treePath) : treePath
447091
+ subdir: marker2 === "blob" ? dirname34(treePath) : treePath
446845
447092
  };
446846
447093
  }
446847
447094
  return { repoUrl, branch: null, subdir: null };
@@ -449056,43 +449303,43 @@ function addSignalStyle(state, start, style) {
449056
449303
  }
449057
449304
  state.ranges.push({ start, length, style });
449058
449305
  }
449059
- function canOpenSignalMarker(text2, index, marker) {
449060
- const next = text2[index + marker.delimiter.length];
449306
+ function canOpenSignalMarker(text2, index, marker2) {
449307
+ const next = text2[index + marker2.delimiter.length];
449061
449308
  if (!next || /\s/.test(next)) {
449062
449309
  return false;
449063
449310
  }
449064
- if (!marker.requireWordBoundary) {
449311
+ if (!marker2.requireWordBoundary) {
449065
449312
  return true;
449066
449313
  }
449067
449314
  const previous = text2[index - 1];
449068
449315
  return !isWordLike(previous);
449069
449316
  }
449070
- function isValidSignalMarkerContent(text2, closeIndex, content, marker) {
449317
+ function isValidSignalMarkerContent(text2, closeIndex, content, marker2) {
449071
449318
  if (content.length === 0 || /^\s|\s$/.test(content)) {
449072
449319
  return false;
449073
449320
  }
449074
- if (!marker.requireWordBoundary) {
449321
+ if (!marker2.requireWordBoundary) {
449075
449322
  return true;
449076
449323
  }
449077
- const next = text2[closeIndex + marker.delimiter.length];
449324
+ const next = text2[closeIndex + marker2.delimiter.length];
449078
449325
  return !isWordLike(next);
449079
449326
  }
449080
- function findSignalClosingMarker(text2, contentStart, marker) {
449327
+ function findSignalClosingMarker(text2, contentStart, marker2) {
449081
449328
  let searchIndex = contentStart;
449082
449329
  while (searchIndex < text2.length) {
449083
- const closeIndex = text2.indexOf(marker.delimiter, searchIndex);
449330
+ const closeIndex = text2.indexOf(marker2.delimiter, searchIndex);
449084
449331
  if (closeIndex < 0) {
449085
449332
  return -1;
449086
449333
  }
449087
449334
  if (isEscaped(text2, closeIndex)) {
449088
- searchIndex = closeIndex + marker.delimiter.length;
449335
+ searchIndex = closeIndex + marker2.delimiter.length;
449089
449336
  continue;
449090
449337
  }
449091
449338
  const content = text2.slice(contentStart, closeIndex);
449092
- if (isValidSignalMarkerContent(text2, closeIndex, content, marker)) {
449339
+ if (isValidSignalMarkerContent(text2, closeIndex, content, marker2)) {
449093
449340
  return closeIndex;
449094
449341
  }
449095
- searchIndex = closeIndex + marker.delimiter.length;
449342
+ searchIndex = closeIndex + marker2.delimiter.length;
449096
449343
  }
449097
449344
  return -1;
449098
449345
  }
@@ -449124,17 +449371,17 @@ function parseSignalInline(text2, state) {
449124
449371
  continue;
449125
449372
  }
449126
449373
  }
449127
- const marker = SIGNAL_INLINE_MARKERS.find((candidate) => text2.startsWith(candidate.delimiter, index) && !isEscaped(text2, index) && canOpenSignalMarker(text2, index, candidate));
449128
- if (marker) {
449129
- const contentStart = index + marker.delimiter.length;
449130
- const closeIndex = findSignalClosingMarker(text2, contentStart, marker);
449374
+ const marker2 = SIGNAL_INLINE_MARKERS.find((candidate) => text2.startsWith(candidate.delimiter, index) && !isEscaped(text2, index) && canOpenSignalMarker(text2, index, candidate));
449375
+ if (marker2) {
449376
+ const contentStart = index + marker2.delimiter.length;
449377
+ const closeIndex = findSignalClosingMarker(text2, contentStart, marker2);
449131
449378
  if (closeIndex >= 0) {
449132
449379
  const start = state.text.length;
449133
449380
  parseSignalInline(text2.slice(contentStart, closeIndex), state);
449134
- for (const style of marker.styles) {
449381
+ for (const style of marker2.styles) {
449135
449382
  addSignalStyle(state, start, style);
449136
449383
  }
449137
- index = closeIndex + marker.delimiter.length;
449384
+ index = closeIndex + marker2.delimiter.length;
449138
449385
  continue;
449139
449386
  }
449140
449387
  }
@@ -449524,6 +449771,38 @@ async function executeMessageChannel(input, options) {
449524
449771
  const normalized = normalizeMessageChannelInput(input, options.resolver);
449525
449772
  if (typeof normalized === "string")
449526
449773
  return normalized;
449774
+ if (normalized.action === "get-binding" || normalized.action === "update-binding") {
449775
+ if (normalized.channel !== "slack" || !options.bindings) {
449776
+ return "Error: Binding operations are not supported by this channel host.";
449777
+ }
449778
+ if (!normalized.chatId || normalized.target) {
449779
+ return "Error: Binding operations require chat_id; target is for outbound sends.";
449780
+ }
449781
+ if (input.threadId !== null && (typeof input.threadId !== "string" || !/^\d+\.\d+$/.test(input.threadId))) {
449782
+ return "Error: Binding operations require an exact threadId timestamp, or explicit null for an unthreaded DM.";
449783
+ }
449784
+ const selection = {
449785
+ channel: normalized.channel,
449786
+ accountId: normalized.accountId,
449787
+ chatId: normalized.chatId,
449788
+ threadId: input.threadId
449789
+ };
449790
+ try {
449791
+ if (normalized.action === "get-binding") {
449792
+ return JSON.stringify(await options.bindings.get(selection, options.scope));
449793
+ }
449794
+ const conversationId = firstNonEmptyString4(input.conversationId);
449795
+ const expectedConversationId = firstNonEmptyString4(input.expectedConversationId);
449796
+ if (!conversationId || !expectedConversationId) {
449797
+ return "Error: update-binding requires conversationId and expectedConversationId.";
449798
+ }
449799
+ const result2 = await options.bindings.update({ ...selection, conversationId, expectedConversationId }, options.scope);
449800
+ const prefix = result2.status === "conflict" || result2.status === "not-found" ? "Error: " : "";
449801
+ return `${prefix}${JSON.stringify(result2)}`;
449802
+ } catch (error5) {
449803
+ return `Error: Binding operation failed: ${error5 instanceof Error ? error5.message : "unknown error"}`;
449804
+ }
449805
+ }
449527
449806
  if (normalized.channel === "slack" && normalized.action === "download-file" && normalized.target) {
449528
449807
  return "Error: Slack download-file requires chat_id from a routed channel context; target is not supported.";
449529
449808
  }
@@ -449538,6 +449817,7 @@ async function executeMessageChannel(input, options) {
449538
449817
  channel: normalized.channel,
449539
449818
  chatId: normalized.chatId,
449540
449819
  accountId,
449820
+ ...normalized.threadId !== null ? { threadId: normalized.threadId } : {},
449541
449821
  scope: options.scope
449542
449822
  });
449543
449823
  if (typeof context4 === "string")
@@ -450299,6 +450579,36 @@ var init_channel_rich_draft_streamer = __esm(() => {
450299
450579
  ]);
450300
450580
  });
450301
450581
 
450582
+ // src/channels/gateway-sources.ts
450583
+ function sourceRouteKey(source) {
450584
+ return [
450585
+ source.channel,
450586
+ source.accountId ?? "",
450587
+ source.chatId,
450588
+ source.threadId ?? ""
450589
+ ].join(":");
450590
+ }
450591
+ function sourceLifecycleKey(source) {
450592
+ return [
450593
+ sourceRouteKey(source),
450594
+ source.messageId ?? "",
450595
+ source.agentId,
450596
+ source.conversationId
450597
+ ].join(":");
450598
+ }
450599
+ function uniqueSourcesBy(sources, getKey) {
450600
+ const byKey = new Map;
450601
+ for (const source of sources)
450602
+ byKey.set(getKey(source), source);
450603
+ return [...byKey.values()];
450604
+ }
450605
+ function uniqueRoutedSources(sources) {
450606
+ return uniqueSourcesBy(sources, sourceRouteKey);
450607
+ }
450608
+ function uniqueLifecycleSources(sources) {
450609
+ return uniqueSourcesBy(sources, sourceLifecycleKey);
450610
+ }
450611
+
450302
450612
  // src/channels/progress-builder.ts
450303
450613
  function getMessageType(delta2) {
450304
450614
  return firstNonEmptyString2(delta2.message_type, delta2.messageType) ?? null;
@@ -450351,6 +450661,34 @@ function toolNameForMessage(summary) {
450351
450661
  function createChannelTurnProgressBuilder(options = {}) {
450352
450662
  const argumentsByToolCallId = new Map;
450353
450663
  const namesByToolCallId = new Map;
450664
+ const batchesByStep = new Map;
450665
+ const batchesByToolCallId = new Map;
450666
+ function addToolBatchTitles(delta2, updates) {
450667
+ const record5 = asRecord4(delta2);
450668
+ if (!record5)
450669
+ return updates;
450670
+ const messageType = getMessageType(record5);
450671
+ const isToolRequest = messageType === "tool_call_message" || messageType === "approval_request_message";
450672
+ const stepKey = isToolRequest ? firstNonEmptyString2(record5.step_id, record5.id) : undefined;
450673
+ let requestBatch = stepKey ? batchesByStep.get(stepKey) : undefined;
450674
+ if (stepKey && !requestBatch) {
450675
+ requestBatch = { title: null };
450676
+ batchesByStep.set(stepKey, requestBatch);
450677
+ }
450678
+ return updates.map((update3) => {
450679
+ if (update3.kind !== "tool")
450680
+ return update3;
450681
+ const batch = (update3.toolCallId ? batchesByToolCallId.get(update3.toolCallId) : undefined) ?? requestBatch;
450682
+ if (!batch)
450683
+ return update3;
450684
+ if (update3.toolCallId)
450685
+ batchesByToolCallId.set(update3.toolCallId, batch);
450686
+ if (batch.title === null && update3.state === "started") {
450687
+ batch.title = firstNonEmptyString2(update3.toolTitle, update3.toolDetails) ?? null;
450688
+ }
450689
+ return { ...update3, toolBatchTitle: batch.title };
450690
+ });
450691
+ }
450354
450692
  function extractToolCallSummary(value) {
450355
450693
  const record5 = asRecord4(value);
450356
450694
  if (!record5) {
@@ -450667,7 +451005,9 @@ function createChannelTurnProgressBuilder(options = {}) {
450667
451005
  return [];
450668
451006
  }
450669
451007
  }
450670
- return { buildUpdates };
451008
+ return {
451009
+ buildUpdates: (delta2) => addToolBatchTitles(delta2, buildUpdates(delta2))
451010
+ };
450671
451011
  }
450672
451012
  var init_progress_builder = __esm(() => {
450673
451013
  init_progress_formatting();
@@ -450680,34 +451020,6 @@ function runtimeKey(runtime) {
450680
451020
  function hasAgentRuntime(value) {
450681
451021
  return !!value.runtime?.agent_id;
450682
451022
  }
450683
- function sourceRouteKey(source) {
450684
- return [
450685
- source.channel,
450686
- source.accountId ?? "",
450687
- source.chatId,
450688
- source.threadId ?? ""
450689
- ].join(":");
450690
- }
450691
- function sourceLifecycleKey(source) {
450692
- return [
450693
- sourceRouteKey(source),
450694
- source.messageId ?? "",
450695
- source.agentId,
450696
- source.conversationId
450697
- ].join(":");
450698
- }
450699
- function uniqueSourcesBy(sources, getKey) {
450700
- const byKey = new Map;
450701
- for (const source of sources)
450702
- byKey.set(getKey(source), source);
450703
- return [...byKey.values()];
450704
- }
450705
- function uniqueRoutedSources(sources) {
450706
- return uniqueSourcesBy(sources, sourceRouteKey);
450707
- }
450708
- function uniqueLifecycleSources(sources) {
450709
- return uniqueSourcesBy(sources, sourceLifecycleKey);
450710
- }
450711
451023
  function channelTagsForSources(sources) {
450712
451024
  return [...new Set(sources.map((source) => `channel:${source.channel}`))];
450713
451025
  }
@@ -450766,6 +451078,7 @@ class ChannelGateway {
450766
451078
  state.acceptedClientMessageIds.add(delivery.clientMessageId);
450767
451079
  return true;
450768
451080
  }
451081
+ const workAtSubmit = state.active || state.pendingSourcesByClientMessageId.size > 0;
450769
451082
  state.pendingSourcesByClientMessageId.set(delivery.clientMessageId, {
450770
451083
  sources: uniqueLifecycleSources(delivery.sources),
450771
451084
  disposition: "submitting"
@@ -450794,6 +451107,8 @@ class ChannelGateway {
450794
451107
  });
450795
451108
  if (!response.accepted) {
450796
451109
  state.pendingSourcesByClientMessageId.delete(delivery.clientMessageId);
451110
+ if (workAtSubmit && !state.active)
451111
+ this.finishRejectedDelivery(state, delivery);
450797
451112
  return false;
450798
451113
  }
450799
451114
  this.rememberAcceptedClientMessageId(state, delivery.clientMessageId);
@@ -450813,9 +451128,28 @@ class ChannelGateway {
450813
451128
  return true;
450814
451129
  } catch (error5) {
450815
451130
  state.pendingSourcesByClientMessageId.delete(delivery.clientMessageId);
451131
+ if (workAtSubmit && !state.active)
451132
+ this.finishRejectedDelivery(state, delivery);
450816
451133
  throw error5;
450817
451134
  }
450818
451135
  }
451136
+ remainingSources(state) {
451137
+ return uniqueLifecycleSources([
451138
+ ...state.active?.lifecycleSources ?? [],
451139
+ ...Array.from(state.pendingSourcesByClientMessageId.values()).flatMap((pending) => pending.sources)
451140
+ ]);
451141
+ }
451142
+ finishRejectedDelivery(state, delivery) {
451143
+ const remainingSources = this.remainingSources(state);
451144
+ this.enqueueHook(state, () => this.hooks.onLifecycle({
451145
+ type: "finished",
451146
+ batchId: `channel-${delivery.clientMessageId}`,
451147
+ sources: delivery.sources,
451148
+ stopReason: "cancelled",
451149
+ outcome: "cancelled",
451150
+ remainingSources
451151
+ }));
451152
+ }
450819
451153
  adoptQueuedDelivery(delivery) {
450820
451154
  const state = this.getState(delivery.runtime);
450821
451155
  const sources = uniqueLifecycleSources(delivery.sources);
@@ -451198,12 +451532,14 @@ class ChannelGateway {
451198
451532
  this.activateSources(state, firstDequeued.clientMessageId, dequeued.flatMap((entry) => entry.sources));
451199
451533
  }
451200
451534
  for (const entry of cancelled) {
451535
+ const remainingSources = this.remainingSources(state);
451201
451536
  this.enqueueHook(state, () => this.hooks.onLifecycle({
451202
451537
  type: "finished",
451203
451538
  batchId: `channel-${entry.clientMessageId}`,
451204
451539
  sources: entry.sources,
451205
451540
  outcome: "cancelled",
451206
- stopReason: "cancelled"
451541
+ stopReason: "cancelled",
451542
+ ...remainingSources.length ? { remainingSources } : {}
451207
451543
  }));
451208
451544
  }
451209
451545
  }
@@ -451280,12 +451616,14 @@ class ChannelGateway {
451280
451616
  return;
451281
451617
  state.active = null;
451282
451618
  active.richDraft?.dispose();
451619
+ const remainingSources = lifecycleOutcome(terminal.stopReason) === "completed" ? this.remainingSources(state) : [];
451283
451620
  this.enqueueHook(state, () => this.hooks.onLifecycle({
451284
451621
  type: "finished",
451285
451622
  batchId: active.batchId,
451286
451623
  sources: active.lifecycleSources,
451287
451624
  outcome: lifecycleOutcome(terminal.stopReason),
451288
451625
  stopReason: terminal.stopReason,
451626
+ ...remainingSources.length ? { remainingSources } : {},
451289
451627
  ...terminal.runId ?? active.runId ? { runId: terminal.runId ?? active.runId } : {},
451290
451628
  ...terminal.error ? { error: terminal.error } : {}
451291
451629
  }));
@@ -451523,7 +451861,9 @@ Replies to routed Telegram topics stay in the current topic automatically.` : ""
451523
451861
  hasAction("react") ? 'action="react" with emoji + messageId' : "",
451524
451862
  hasAction("list-custom-emojis") ? 'action="list-custom-emojis" to discover the workspace custom emoji names available for reactions' : "",
451525
451863
  hasAction("upload-file") ? 'action="upload-file" with media' : "",
451526
- hasAction("download-file") ? 'action="download-file" with attachmentId + messageId' : ""
451864
+ hasAction("download-file") ? 'action="download-file" with attachmentId + messageId' : "",
451865
+ hasAction("get-binding") ? 'action="get-binding" with chat_id and an explicit threadId (null for an unthreaded DM) to inspect the persisted incoming-message destination without sending' : "",
451866
+ hasAction("update-binding") ? 'action="update-binding" with the same exact thread, conversationId, and expectedConversationId to reassign an existing binding within this agent. It does not send a message, copy history, move queued inputs, change computers, or alter pause/detach settings. Outbound sends never take over an existing binding' : ""
451527
451867
  ].filter(Boolean) : [];
451528
451868
  const slackCapabilityGuidance = slackCapabilities.length > 0 ? `
451529
451869
 
@@ -454682,493 +455022,6 @@ var init_headless_tool_events = __esm(async () => {
454682
455022
  await init_approval_execution();
454683
455023
  });
454684
455024
 
454685
- // src/skills/builtin/creating-skills/scripts/validate-skill.ts
454686
- import { existsSync as existsSync65, readFileSync as readFileSync41 } from "node:fs";
454687
- import { basename as basename29, join as join83, resolve as resolve39 } from "node:path";
454688
- import { fileURLToPath as fileURLToPath11 } from "node:url";
454689
- function parseQuotedScalar(value) {
454690
- if (value.startsWith('"')) {
454691
- if (!value.endsWith('"') || value.length === 1) {
454692
- throw new Error("Unterminated double-quoted scalar");
454693
- }
454694
- return JSON.parse(value);
454695
- }
454696
- if (value.startsWith("'")) {
454697
- if (!value.endsWith("'") || value.length === 1) {
454698
- throw new Error("Unterminated single-quoted scalar");
454699
- }
454700
- return value.slice(1, -1).replace(/''/g, "'");
454701
- }
454702
- return value;
454703
- }
454704
- function parseScalar(value) {
454705
- const trimmed = value.trim();
454706
- if (!trimmed)
454707
- return "";
454708
- if (trimmed === "true")
454709
- return true;
454710
- if (trimmed === "false")
454711
- return false;
454712
- if (trimmed === "null" || trimmed === "~")
454713
- return null;
454714
- if (trimmed.startsWith('"') || trimmed.startsWith("'")) {
454715
- return parseQuotedScalar(trimmed);
454716
- }
454717
- if (trimmed.includes(": ")) {
454718
- throw new Error(`Unexpected ':' in unquoted scalar: ${trimmed}`);
454719
- }
454720
- if (/^-?\d+(?:\.\d+)?$/.test(trimmed)) {
454721
- return Number(trimmed);
454722
- }
454723
- return trimmed;
454724
- }
454725
- function parseFrontmatterFallback(source) {
454726
- const result2 = {};
454727
- const lines = source.split(/\r?\n/);
454728
- for (let i4 = 0;i4 < lines.length; i4++) {
454729
- const line = lines[i4];
454730
- if (line === undefined)
454731
- continue;
454732
- const trimmed = line.trim();
454733
- if (!trimmed || trimmed.startsWith("#")) {
454734
- continue;
454735
- }
454736
- if (/^\s/.test(line)) {
454737
- continue;
454738
- }
454739
- const colonIndex = line.indexOf(":");
454740
- if (colonIndex <= 0) {
454741
- throw new Error(`Invalid frontmatter line: ${line}`);
454742
- }
454743
- const key2 = line.slice(0, colonIndex).trim();
454744
- const rawValue = line.slice(colonIndex + 1).trim();
454745
- if (!key2) {
454746
- throw new Error(`Invalid frontmatter line: ${line}`);
454747
- }
454748
- if (!rawValue) {
454749
- result2[key2] = {};
454750
- continue;
454751
- }
454752
- if (rawValue === "|" || rawValue === ">") {
454753
- const blockLines = [];
454754
- for (let j2 = i4 + 1;j2 < lines.length; j2++) {
454755
- const nextLine = lines[j2];
454756
- if (nextLine === undefined)
454757
- continue;
454758
- if (nextLine.trim() && !/^\s/.test(nextLine)) {
454759
- break;
454760
- }
454761
- blockLines.push(nextLine.replace(/^\s{2}/, ""));
454762
- i4 = j2;
454763
- }
454764
- result2[key2] = rawValue === ">" ? blockLines.join(" ").trim() : blockLines.join(`
454765
- `);
454766
- continue;
454767
- }
454768
- result2[key2] = parseScalar(rawValue);
454769
- }
454770
- return result2;
454771
- }
454772
- function parseFrontmatter2(source) {
454773
- const bunParse = globalThis.Bun?.YAML?.parse;
454774
- if (bunParse) {
454775
- const parsed = bunParse(source);
454776
- if (typeof parsed !== "object" || parsed === null) {
454777
- throw new Error("Frontmatter must be a YAML dictionary");
454778
- }
454779
- return parsed;
454780
- }
454781
- return parseFrontmatterFallback(source);
454782
- }
454783
- function validateSkill(skillPath) {
454784
- const skillMdPath = join83(skillPath, "SKILL.md");
454785
- if (!existsSync65(skillMdPath)) {
454786
- return { valid: false, message: "SKILL.md not found" };
454787
- }
454788
- const content = readFileSync41(skillMdPath, "utf-8");
454789
- if (!content.startsWith("---")) {
454790
- return { valid: false, message: "No YAML frontmatter found" };
454791
- }
454792
- const match3 = content.match(/^---\n([\s\S]*?)\n---/);
454793
- if (!match3) {
454794
- return { valid: false, message: "Invalid frontmatter format" };
454795
- }
454796
- const frontmatterText = match3[1];
454797
- let frontmatter;
454798
- try {
454799
- frontmatter = parseFrontmatter2(frontmatterText);
454800
- if (typeof frontmatter !== "object" || frontmatter === null) {
454801
- return { valid: false, message: "Frontmatter must be a YAML dictionary" };
454802
- }
454803
- } catch (e2) {
454804
- return {
454805
- valid: false,
454806
- message: `Invalid YAML in frontmatter: ${e2 instanceof Error ? e2.message : String(e2)}`
454807
- };
454808
- }
454809
- const warnings = [];
454810
- const unexpectedKeys = Object.keys(frontmatter).filter((key2) => !ALLOWED_PROPERTIES.has(key2));
454811
- if (unexpectedKeys.length > 0) {
454812
- warnings.push(`Unknown frontmatter key(s): ${unexpectedKeys.sort().join(", ")}. Known properties are: ${[...ALLOWED_PROPERTIES].sort().join(", ")}`);
454813
- }
454814
- if (!("name" in frontmatter)) {
454815
- return { valid: false, message: "Missing 'name' in frontmatter" };
454816
- }
454817
- if (!("description" in frontmatter)) {
454818
- return { valid: false, message: "Missing 'description' in frontmatter" };
454819
- }
454820
- const name = frontmatter.name;
454821
- if (typeof name !== "string") {
454822
- return {
454823
- valid: false,
454824
- message: `Name must be a string, got ${typeof name}`
454825
- };
454826
- }
454827
- const trimmedName = name.trim();
454828
- if (trimmedName) {
454829
- if (!/^[a-z0-9-]+$/.test(trimmedName)) {
454830
- return {
454831
- valid: false,
454832
- message: `Name '${trimmedName}' should be hyphen-case (lowercase letters, digits, and hyphens only)`
454833
- };
454834
- }
454835
- if (trimmedName.startsWith("-") || trimmedName.endsWith("-") || trimmedName.includes("--")) {
454836
- return {
454837
- valid: false,
454838
- message: `Name '${trimmedName}' cannot start/end with hyphen or contain consecutive hyphens`
454839
- };
454840
- }
454841
- if (trimmedName.length > MAX_SKILL_NAME_LENGTH) {
454842
- return {
454843
- valid: false,
454844
- message: `Name is too long (${trimmedName.length} characters). Maximum is ${MAX_SKILL_NAME_LENGTH} characters.`
454845
- };
454846
- }
454847
- const dirName = basename29(skillPath);
454848
- if (trimmedName !== dirName) {
454849
- warnings.push(`Name '${trimmedName}' doesn't match directory name '${dirName}'. For portability, these should match.`);
454850
- }
454851
- }
454852
- const description = frontmatter.description;
454853
- if (typeof description !== "string") {
454854
- return {
454855
- valid: false,
454856
- message: `Description must be a string, got ${typeof description}`
454857
- };
454858
- }
454859
- const trimmedDescription = description.trim();
454860
- if (trimmedDescription) {
454861
- if (trimmedDescription.includes("<") || trimmedDescription.includes(">")) {
454862
- return {
454863
- valid: false,
454864
- message: "Description cannot contain angle brackets (< or >)"
454865
- };
454866
- }
454867
- if (trimmedDescription.length > 1024) {
454868
- return {
454869
- valid: false,
454870
- message: `Description is too long (${trimmedDescription.length} characters). Maximum is 1024 characters.`
454871
- };
454872
- }
454873
- }
454874
- return {
454875
- valid: true,
454876
- message: "Skill is valid!",
454877
- warnings: warnings.length > 0 ? warnings : undefined
454878
- };
454879
- }
454880
- function isMainModule() {
454881
- const entrypoint = process.argv[1];
454882
- return entrypoint ? resolve39(entrypoint) === fileURLToPath11(import.meta.url) : false;
454883
- }
454884
- var ALLOWED_PROPERTIES, MAX_SKILL_NAME_LENGTH = 64;
454885
- var init_validate_skill = __esm(() => {
454886
- ALLOWED_PROPERTIES = new Set([
454887
- "name",
454888
- "description",
454889
- "license",
454890
- "compatibility",
454891
- "metadata",
454892
- "allowed-tools"
454893
- ]);
454894
- if (isMainModule()) {
454895
- const args = process.argv.slice(2);
454896
- if (args.length !== 1) {
454897
- console.log("Usage: npx tsx validate-skill.ts <skill-directory>");
454898
- process.exit(1);
454899
- }
454900
- const { valid: valid2, message, warnings } = validateSkill(args[0]);
454901
- console.log(message);
454902
- if (warnings && warnings.length > 0) {
454903
- for (const warning of warnings) {
454904
- console.warn(`Warning: ${warning}`);
454905
- }
454906
- }
454907
- process.exit(valid2 ? 0 : 1);
454908
- }
454909
- });
454910
-
454911
- // src/agent/github-utils.ts
454912
- var exports_github_utils = {};
454913
- __export(exports_github_utils, {
454914
- parseDirNames: () => parseDirNames,
454915
- fetchGitHubContents: () => fetchGitHubContents
454916
- });
454917
- async function fetchGitHubContents(owner, repo, branch, path50) {
454918
- const apiPath = path50 ? `repos/${owner}/${repo}/contents/${path50}?ref=${branch}` : `repos/${owner}/${repo}/contents?ref=${branch}`;
454919
- try {
454920
- const { execFileSync: execFileSync7 } = await import("node:child_process");
454921
- const result2 = execFileSync7("gh", ["api", apiPath], {
454922
- encoding: "utf-8",
454923
- stdio: ["pipe", "pipe", "ignore"]
454924
- });
454925
- return JSON.parse(result2);
454926
- } catch {}
454927
- const url2 = `https://api.github.com/repos/${owner}/${repo}/contents/${path50}?ref=${branch}`;
454928
- const response = await fetch(url2, {
454929
- headers: {
454930
- Accept: "application/vnd.github.v3+json",
454931
- "User-Agent": "letta-code"
454932
- }
454933
- });
454934
- if (!response.ok) {
454935
- throw new Error(`Failed to fetch from ${owner}/${repo}/${branch}/${path50}: ${response.statusText}`);
454936
- }
454937
- return await response.json();
454938
- }
454939
- function parseDirNames(entries) {
454940
- return new Set(entries.filter((e2) => e2.type === "dir").map((e2) => e2.name));
454941
- }
454942
-
454943
- // src/agent/import.ts
454944
- var exports_import = {};
454945
- __export(exports_import, {
454946
- importAgentFromRegistry: () => importAgentFromRegistry,
454947
- importAgentFromFile: () => importAgentFromFile,
454948
- extractSkillsFromAf: () => extractSkillsFromAf
454949
- });
454950
- import { createReadStream as createReadStream3 } from "node:fs";
454951
- import { access as access3, chmod, mkdir as mkdir17, readFile as readFile30, writeFile as writeFile19 } from "node:fs/promises";
454952
- import { dirname as dirname35, isAbsolute as isAbsolute31, relative as relative14, resolve as resolve40, sep as sep9, win32 as win325 } from "node:path";
454953
- function validateImportedSkillName(name) {
454954
- const trimmedName = name.trim();
454955
- if (trimmedName !== name || trimmedName.length === 0 || trimmedName.length > MAX_SKILL_NAME_LENGTH || trimmedName === "." || trimmedName === ".." || !IMPORTED_SKILL_NAME_PATTERN.test(trimmedName)) {
454956
- throw new Error(`Invalid imported skill name "${String(name)}". Skill names may only contain letters, numbers, dots, underscores, and hyphens.`);
454957
- }
454958
- return trimmedName;
454959
- }
454960
- function assertPathInside(parent, child) {
454961
- const parentPath = resolve40(parent);
454962
- const childPath = resolve40(child);
454963
- const relativePath = relative14(parentPath, childPath);
454964
- if (relativePath === "" || relativePath === ".." || relativePath.startsWith(`..${sep9}`) || isAbsolute31(relativePath)) {
454965
- throw new Error(`Imported skill file path escapes skill directory: ${child}`);
454966
- }
454967
- }
454968
- function validateImportedSkillFilePath(filePath) {
454969
- if (filePath.length === 0 || filePath === "." || filePath.includes("\x00") || filePath.includes("\\") || isAbsolute31(filePath) || win325.isAbsolute(filePath)) {
454970
- throw new Error(`Invalid imported skill file path "${filePath}".`);
454971
- }
454972
- const segments = filePath.split("/");
454973
- if (segments.some((segment) => !segment || segment === "." || segment === "..")) {
454974
- throw new Error(`Invalid imported skill file path "${filePath}".`);
454975
- }
454976
- return filePath;
454977
- }
454978
- function resolveImportedSkillFilePath(skillDir, filePath) {
454979
- const safeFilePath = validateImportedSkillFilePath(filePath);
454980
- const fullPath = resolve40(skillDir, safeFilePath);
454981
- assertPathInside(skillDir, fullPath);
454982
- return fullPath;
454983
- }
454984
- function tagsEqual(left, right) {
454985
- return left.length === right.length && left.every((tag, i4) => tag === right[i4]);
454986
- }
454987
- async function resolveImportedAgentMemfsEnabled() {
454988
- const backend3 = getBackend();
454989
- const isLettaCloud2 = backend3.capabilities.remoteMemfs && !backend3.capabilities.localMemfs ? await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem)).then((module3) => module3.isLettaCloud()) : false;
454990
- return resolveCreatedAgentMemfsConfig({
454991
- capabilities: backend3.capabilities,
454992
- isLettaCloud: isLettaCloud2
454993
- }).enableMemfs;
454994
- }
454995
- async function ensureImportedAgentCreationTags(agent, enableMemfs) {
454996
- const tags = buildCreatedAgentTags({
454997
- tags: agent.tags,
454998
- enableMemfs
454999
- });
455000
- if (tagsEqual(agent.tags ?? [], tags)) {
455001
- return agent;
455002
- }
455003
- const updatedAgent = await getBackend().updateAgent(agent.id, { tags });
455004
- return {
455005
- ...agent,
455006
- ...updatedAgent,
455007
- tags: updatedAgent.tags ?? tags
455008
- };
455009
- }
455010
- async function importAgentFromFile(options) {
455011
- if (!getBackend().capabilities.agentFileImportExport) {
455012
- throw new Error("Agent file import is not supported by this backend yet");
455013
- }
455014
- const resolvedPath = resolve40(options.filePath);
455015
- try {
455016
- await access3(resolvedPath);
455017
- } catch {
455018
- throw new Error(`AgentFile not found: ${resolvedPath}`);
455019
- }
455020
- const client = await getClient();
455021
- const file = createReadStream3(resolvedPath);
455022
- const importResponse = await client.agents.importFile({
455023
- file,
455024
- strip_messages: options.stripMessages ?? true,
455025
- override_existing_tools: false
455026
- });
455027
- if (!importResponse.agent_ids || importResponse.agent_ids.length === 0) {
455028
- throw new Error("Import failed: no agent IDs returned");
455029
- }
455030
- const agentId = importResponse.agent_ids[0];
455031
- let agent = await client.agents.retrieve(agentId, {
455032
- include: ["agent.tags"]
455033
- });
455034
- if (options.modelOverride) {
455035
- const updateArgs = getModelUpdateArgs(options.modelOverride);
455036
- await updateAgentLLMConfig(agentId, options.modelOverride, updateArgs);
455037
- const { ensureCorrectMemoryTool: ensureCorrectMemoryTool2 } = await init_toolset().then(() => exports_toolset);
455038
- await ensureCorrectMemoryTool2(agentId, options.modelOverride);
455039
- agent = await client.agents.retrieve(agentId, { include: ["agent.tags"] });
455040
- }
455041
- agent = await ensureImportedAgentCreationTags(agent, await resolveImportedAgentMemfsEnabled());
455042
- let skills;
455043
- if (!options.stripSkills) {
455044
- const { getAgentSkillsDir: getAgentSkillsDir2 } = await Promise.resolve().then(() => (init_skills5(), exports_skills2));
455045
- const skillsDir = getAgentSkillsDir2(agentId);
455046
- skills = await extractSkillsFromAf(resolvedPath, skillsDir);
455047
- }
455048
- return { agent, skills };
455049
- }
455050
- async function extractSkillsFromAf(afPath, destDir) {
455051
- const extracted = [];
455052
- const content = await readFile30(afPath, "utf-8");
455053
- const afData = JSON.parse(content);
455054
- if (!afData.skills || !Array.isArray(afData.skills)) {
455055
- return [];
455056
- }
455057
- for (const skill2 of afData.skills) {
455058
- const skillName = validateImportedSkillName(skill2.name);
455059
- const skillDir = resolve40(destDir, skillName);
455060
- await mkdir17(skillDir, { recursive: true });
455061
- if (skill2.files) {
455062
- await writeSkillFiles(skillDir, skill2.files);
455063
- extracted.push(skillName);
455064
- } else if (skill2.source_url) {
455065
- await fetchSkillFromUrl(skillDir, skill2.source_url);
455066
- extracted.push(skillName);
455067
- } else {
455068
- console.warn(`Skipping skill ${skillName}: no files or source_url`);
455069
- }
455070
- }
455071
- return extracted;
455072
- }
455073
- async function writeSkillFiles(skillDir, files) {
455074
- for (const [filePath, fileContent] of Object.entries(files)) {
455075
- await writeSkillFile(skillDir, filePath, fileContent);
455076
- }
455077
- }
455078
- async function writeSkillFile(skillDir, filePath, content) {
455079
- const fullPath = resolveImportedSkillFilePath(skillDir, filePath);
455080
- await mkdir17(dirname35(fullPath), { recursive: true });
455081
- await writeFile19(fullPath, content, "utf-8");
455082
- const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
455083
- if (isScript) {
455084
- try {
455085
- await chmod(fullPath, 493);
455086
- } catch {}
455087
- }
455088
- }
455089
- async function fetchSkillFromUrl(skillDir, sourceUrl) {
455090
- const githubPath = sourceUrl.replace(/^github\.com\//, "").replace(/\/tree\//, "/");
455091
- const parts = githubPath.split("/");
455092
- if (parts.length < 4 || !parts[0] || !parts[1] || !parts[2]) {
455093
- throw new Error(`Invalid GitHub path: ${githubPath}`);
455094
- }
455095
- const owner = parts[0];
455096
- const repo = parts[1];
455097
- const branch = parts[2];
455098
- const path50 = parts.slice(3).join("/");
455099
- const { fetchGitHubContents: fetchGitHubContents2 } = await Promise.resolve().then(() => exports_github_utils);
455100
- const entries = await fetchGitHubContents2(owner, repo, branch, path50);
455101
- if (!Array.isArray(entries)) {
455102
- throw new Error(`Expected directory at ${sourceUrl}, got file`);
455103
- }
455104
- await downloadGitHubDirectory(entries, skillDir, owner, repo, branch, path50);
455105
- }
455106
- async function downloadGitHubDirectory(entries, destDir, owner, repo, branch, basePath) {
455107
- const { fetchGitHubContents: fetchGitHubContents2 } = await Promise.resolve().then(() => exports_github_utils);
455108
- for (const entry of entries) {
455109
- if (entry.type === "file") {
455110
- if (!entry.download_url) {
455111
- throw new Error(`Missing download_url for file: ${entry.path}`);
455112
- }
455113
- const fileResponse = await fetch(entry.download_url);
455114
- const fileContent = await fileResponse.text();
455115
- const relativePath = entry.path.replace(`${basePath}/`, "");
455116
- await writeSkillFile(destDir, relativePath, fileContent);
455117
- } else if (entry.type === "dir") {
455118
- const subEntries = await fetchGitHubContents2(owner, repo, branch, entry.path);
455119
- await downloadGitHubDirectory(subEntries, destDir, owner, repo, branch, basePath);
455120
- }
455121
- }
455122
- }
455123
- function parseRegistryHandle(handle2) {
455124
- const normalized = handle2.startsWith("@") ? handle2.slice(1) : handle2;
455125
- const parts = normalized.split("/");
455126
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
455127
- throw new Error(`Invalid import handle "${handle2}". Use format: @author/agentname`);
455128
- }
455129
- return { author: parts[0], name: parts[1] };
455130
- }
455131
- async function importAgentFromRegistry(options) {
455132
- const { tmpdir: tmpdir12 } = await import("node:os");
455133
- const { join: join84 } = await import("node:path");
455134
- const { writeFile: writeFile20, unlink: unlink6 } = await import("node:fs/promises");
455135
- const { author, name } = parseRegistryHandle(options.handle);
455136
- const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER}/${AGENT_REGISTRY_REPO}/refs/heads/${AGENT_REGISTRY_BRANCH}/agents/@${author}/${name}/${name}.af`;
455137
- const response = await fetch(rawUrl);
455138
- if (!response.ok) {
455139
- if (response.status === 404) {
455140
- throw new Error(`Agent @${author}/${name} not found in registry. Check that the agent exists at https://github.com/${AGENT_REGISTRY_OWNER}/${AGENT_REGISTRY_REPO}/tree/${AGENT_REGISTRY_BRANCH}/agents/@${author}/${name}`);
455141
- }
455142
- throw new Error(`Failed to download agent @${author}/${name}: ${response.statusText}`);
455143
- }
455144
- const afContent = await response.text();
455145
- const tempPath = join84(tmpdir12(), `letta-import-${author}-${name}-${Date.now()}.af`);
455146
- await writeFile20(tempPath, afContent, "utf-8");
455147
- try {
455148
- const result2 = await importAgentFromFile({
455149
- filePath: tempPath,
455150
- modelOverride: options.modelOverride,
455151
- stripMessages: options.stripMessages ?? true,
455152
- stripSkills: options.stripSkills ?? false
455153
- });
455154
- return result2;
455155
- } finally {
455156
- try {
455157
- await unlink6(tempPath);
455158
- } catch {}
455159
- }
455160
- }
455161
- var IMPORTED_SKILL_NAME_PATTERN, AGENT_REGISTRY_OWNER = "letta-ai", AGENT_REGISTRY_REPO = "agent-file", AGENT_REGISTRY_BRANCH = "main";
455162
- var init_import = __esm(() => {
455163
- init_backend2();
455164
- init_client4();
455165
- init_validate_skill();
455166
- init_create5();
455167
- init_model();
455168
- init_modify();
455169
- IMPORTED_SKILL_NAME_PATTERN = /^[A-Za-z0-9._-]+$/;
455170
- });
455171
-
455172
455025
  // src/agent/defaults.ts
455173
455026
  var exports_defaults = {};
455174
455027
  __export(exports_defaults, {
@@ -455533,10 +455386,10 @@ async function sendScopedApprovalMessages(params) {
455533
455386
  });
455534
455387
  }
455535
455388
  async function flushAndExit(code2) {
455536
- const flushWritable = (stream12) => new Promise((resolve41) => {
455389
+ const flushWritable = (stream12) => new Promise((resolve39) => {
455537
455390
  if (stream12.destroyed || stream12.writableEnded)
455538
- return resolve41();
455539
- stream12.write("", () => resolve41());
455391
+ return resolve39();
455392
+ stream12.write("", () => resolve39());
455540
455393
  });
455541
455394
  await closeClientMcpServers();
455542
455395
  await Promise.allSettled([
@@ -455546,12 +455399,12 @@ async function flushAndExit(code2) {
455546
455399
  process.exit(code2);
455547
455400
  }
455548
455401
  async function writeFinalHeadlessStdout(text2) {
455549
- await new Promise((resolve41) => {
455402
+ await new Promise((resolve39) => {
455550
455403
  if (process.stdout.destroyed || process.stdout.writableEnded) {
455551
- resolve41();
455404
+ resolve39();
455552
455405
  return;
455553
455406
  }
455554
- process.stdout.write(text2, () => resolve41());
455407
+ process.stdout.write(text2, () => resolve39());
455555
455408
  });
455556
455409
  }
455557
455410
  function buildEnvironmentResponseMetadata(params) {
@@ -455698,10 +455551,6 @@ In headless mode, use:
455698
455551
  process.exit(1);
455699
455552
  }
455700
455553
  const shouldAutoEnableMemfsForNewAgent = !memfsFlag && !isStatelessSession;
455701
- const fromAfFile = resolveImportFlagAlias({
455702
- importFlagValue: values4.import,
455703
- fromAfFlagValue: values4["from-af"]
455704
- });
455705
455554
  const preLoadSkillsRaw = values4["pre-load-skills"];
455706
455555
  const systemInfoReminderEnabled = systemInfoReminderEnabledOverride ?? !values4["no-system-info-reminder"];
455707
455556
  const reflectionOverrides = (() => {
@@ -455754,7 +455603,7 @@ In headless mode, use:
455754
455603
  return reportAndExitHeadless("headless_conversation_shorthand_failed", error5, "headless_startup_conversation_shorthand");
455755
455604
  }
455756
455605
  const ambientAgentId = (process.env.LETTA_AGENT_ID || process.env.AGENT_ID || "").trim();
455757
- if ((startupOptions.requestedBackendMode || usesRemoteEnvironment) && ambientAgentId && !specifiedAgentId && !specifiedAgentName && !specifiedConversationId && !forceNew && !fromAfFile && !fromAgentId) {
455606
+ if ((startupOptions.requestedBackendMode || usesRemoteEnvironment) && ambientAgentId && !specifiedAgentId && !specifiedAgentName && !specifiedConversationId && !forceNew && !fromAgentId) {
455758
455607
  specifiedAgentId = ambientAgentId;
455759
455608
  specifiedAgentIdFromAmbient = true;
455760
455609
  }
@@ -455791,7 +455640,6 @@ In headless mode, use:
455791
455640
  specifiedAgentName,
455792
455641
  forceNewAgent: forceNew,
455793
455642
  forceNewConversation,
455794
- importFile: fromAfFile,
455795
455643
  stateless: statelessFlag,
455796
455644
  ephemeral: ephemeralFlag,
455797
455645
  isHeadless: true,
@@ -455804,39 +455652,6 @@ In headless mode, use:
455804
455652
  if (ephemeralFlag && (isBidirectionalMode || usesRemoteEnvironment)) {
455805
455653
  return reportAndExitHeadless("headless_ephemeral_transport_unsupported", "--ephemeral supports direct one-shot headless prompts only", "headless_startup_flag_conflicts");
455806
455654
  }
455807
- let isRegistryImport = false;
455808
- if (fromAfFile) {
455809
- try {
455810
- validateFlagConflicts({
455811
- guard: fromAfFile,
455812
- checks: [
455813
- {
455814
- when: specifiedAgentId,
455815
- message: "--import cannot be used with --agent"
455816
- },
455817
- {
455818
- when: specifiedAgentName,
455819
- message: "--import cannot be used with --name"
455820
- },
455821
- {
455822
- when: forceNew,
455823
- message: "--import cannot be used with --new-agent"
455824
- }
455825
- ]
455826
- });
455827
- } catch (error5) {
455828
- return reportAndExitHeadless("headless_import_flag_validation_failed", error5, "headless_startup_import_flag_validation");
455829
- }
455830
- if (fromAfFile.startsWith("@")) {
455831
- isRegistryImport = true;
455832
- try {
455833
- validateRegistryHandleOrThrow(fromAfFile);
455834
- } catch {
455835
- console.error(`Error: Invalid registry handle "${fromAfFile}". Use format: letta --import @author/agentname`);
455836
- process.exit(1);
455837
- }
455838
- }
455839
- }
455840
455655
  if (specifiedAgentName) {
455841
455656
  if (specifiedAgentId) {
455842
455657
  console.error("Error: --name cannot be used with --agent");
@@ -455878,35 +455693,6 @@ In headless mode, use:
455878
455693
  process.exit(1);
455879
455694
  }
455880
455695
  }
455881
- if (!agent && fromAfFile) {
455882
- let result2;
455883
- if (isRegistryImport) {
455884
- const { importAgentFromRegistry: importAgentFromRegistry2 } = await Promise.resolve().then(() => (init_import(), exports_import));
455885
- result2 = await importAgentFromRegistry2({
455886
- handle: fromAfFile,
455887
- modelOverride: model,
455888
- stripMessages: true,
455889
- stripSkills: false
455890
- });
455891
- } else {
455892
- const { importAgentFromFile: importAgentFromFile2 } = await Promise.resolve().then(() => (init_import(), exports_import));
455893
- result2 = await importAgentFromFile2({
455894
- filePath: fromAfFile,
455895
- modelOverride: model,
455896
- stripMessages: true,
455897
- stripSkills: false
455898
- });
455899
- }
455900
- agent = result2.agent;
455901
- if (settingsManager.isReady) {
455902
- settingsManager.setSystemPromptCustom(agent.id);
455903
- }
455904
- if (result2.skills && result2.skills.length > 0) {
455905
- const { getAgentSkillsDir: getAgentSkillsDir2 } = await Promise.resolve().then(() => (init_skills5(), exports_skills2));
455906
- const skillsDir = getAgentSkillsDir2(agent.id);
455907
- console.log(`\uD83D\uDCE6 Extracted ${result2.skills.length} skill${result2.skills.length === 1 ? "" : "s"} to ${skillsDir}: ${result2.skills.join(", ")}`);
455908
- }
455909
- }
455910
455696
  if (!agent && specifiedAgentId) {
455911
455697
  try {
455912
455698
  agent = await backend3.retrieveAgent(specifiedAgentId, {
@@ -456023,7 +455809,7 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
456023
455809
  markMilestone("HEADLESS_AGENT_RESOLVED");
456024
455810
  const publicAgentId = ephemeralFlag ? null : agent.id;
456025
455811
  telemetry.setCurrentAgent(publicAgentId, agent.tags);
456026
- const isResumingAgent = !ephemeralFlag && !!(specifiedAgentId || !forceNew && !fromAfFile);
455812
+ const isResumingAgent = !ephemeralFlag && !!(specifiedAgentId || !forceNew);
456027
455813
  if (isResumingAgent) {
456028
455814
  if (model) {
456029
455815
  const modelHandle = resolveModel(model);
@@ -456789,7 +456575,7 @@ ${loadedContents.join(`
456789
456575
  } else {
456790
456576
  console.error(`Conversation is busy, waiting ${Math.round(retryDelayMs / 1000)}s and retrying...`);
456791
456577
  }
456792
- await new Promise((resolve41) => setTimeout(resolve41, retryDelayMs));
456578
+ await new Promise((resolve39) => setTimeout(resolve39, retryDelayMs));
456793
456579
  continue;
456794
456580
  }
456795
456581
  }
@@ -456818,7 +456604,7 @@ ${loadedContents.join(`
456818
456604
  const delaySeconds = Math.round(delayMs / 1000);
456819
456605
  console.error(`Transient API error before streaming (attempt ${attempt2} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
456820
456606
  }
456821
- await new Promise((resolve41) => setTimeout(resolve41, delayMs));
456607
+ await new Promise((resolve39) => setTimeout(resolve39, delayMs));
456822
456608
  conversationBusyRetries = 0;
456823
456609
  continue;
456824
456610
  }
@@ -457073,7 +456859,7 @@ ${loadedContents.join(`
457073
456859
  const delaySeconds = Math.round(delayMs / 1000);
457074
456860
  console.error(`LLM API error encountered (attempt ${attempt2} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
457075
456861
  }
457076
- await new Promise((resolve41) => setTimeout(resolve41, delayMs));
456862
+ await new Promise((resolve39) => setTimeout(resolve39, delayMs));
457077
456863
  currentInput = refreshInputOtidsForNewRequest(currentInput);
457078
456864
  continue;
457079
456865
  }
@@ -457165,7 +456951,7 @@ ${loadedContents.join(`
457165
456951
  } else {
457166
456952
  console.error(`Empty LLM response, retrying (attempt ${attempt2} of ${EMPTY_RESPONSE_MAX_RETRIES2})...`);
457167
456953
  }
457168
- await new Promise((resolve41) => setTimeout(resolve41, delayMs));
456954
+ await new Promise((resolve39) => setTimeout(resolve39, delayMs));
457169
456955
  currentInput = refreshInputOtidsForNewRequest(currentInput);
457170
456956
  continue;
457171
456957
  }
@@ -457193,7 +456979,7 @@ ${loadedContents.join(`
457193
456979
  const delaySeconds = Math.round(delayMs / 1000);
457194
456980
  console.error(`LLM API error encountered (attempt ${attempt2} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
457195
456981
  }
457196
- await new Promise((resolve41) => setTimeout(resolve41, delayMs));
456982
+ await new Promise((resolve39) => setTimeout(resolve39, delayMs));
457197
456983
  currentInput = refreshInputOtidsForNewRequest(currentInput);
457198
456984
  continue;
457199
456985
  }
@@ -457223,7 +457009,7 @@ ${loadedContents.join(`
457223
457009
  const delaySeconds = Math.round(delayMs / 1000);
457224
457010
  console.error(`LLM API error encountered (attempt ${attempt2} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
457225
457011
  }
457226
- await new Promise((resolve41) => setTimeout(resolve41, delayMs));
457012
+ await new Promise((resolve39) => setTimeout(resolve39, delayMs));
457227
457013
  currentInput = refreshInputOtidsForNewRequest(currentInput);
457228
457014
  continue;
457229
457015
  }
@@ -457618,9 +457404,9 @@ async function runBidirectionalMode(agent, conversationId, _outputFormat, includ
457618
457404
  const syntheticUserLine = serializeQueuedMessageAsUserLine(queuedMessage);
457619
457405
  maybeNotifyBlocked(syntheticUserLine);
457620
457406
  if (lineResolver) {
457621
- const resolve41 = lineResolver;
457407
+ const resolve39 = lineResolver;
457622
457408
  lineResolver = null;
457623
- resolve41(syntheticUserLine);
457409
+ resolve39(syntheticUserLine);
457624
457410
  return;
457625
457411
  }
457626
457412
  lineQueue.push(syntheticUserLine);
@@ -457640,9 +457426,9 @@ async function runBidirectionalMode(agent, conversationId, _outputFormat, includ
457640
457426
  if (action3 === "abort-active") {
457641
457427
  currentAbortController.abort();
457642
457428
  if (lineResolver) {
457643
- const resolve41 = lineResolver;
457429
+ const resolve39 = lineResolver;
457644
457430
  lineResolver = null;
457645
- resolve41(null);
457431
+ resolve39(null);
457646
457432
  }
457647
457433
  } else if (action3 === "latch") {
457648
457434
  pendingInterrupt = true;
@@ -457662,9 +457448,9 @@ async function runBidirectionalMode(agent, conversationId, _outputFormat, includ
457662
457448
  if (lineResolver) {
457663
457449
  if (parsedLine?.type === "user")
457664
457450
  turnStarting = true;
457665
- const resolve41 = lineResolver;
457451
+ const resolve39 = lineResolver;
457666
457452
  lineResolver = null;
457667
- resolve41(line);
457453
+ resolve39(line);
457668
457454
  } else {
457669
457455
  lineQueue.push(line);
457670
457456
  }
@@ -457673,17 +457459,17 @@ async function runBidirectionalMode(agent, conversationId, _outputFormat, includ
457673
457459
  setMessageQueueAdder(null);
457674
457460
  msgQueueRuntime.clear("shutdown");
457675
457461
  if (lineResolver) {
457676
- const resolve41 = lineResolver;
457462
+ const resolve39 = lineResolver;
457677
457463
  lineResolver = null;
457678
- resolve41(null);
457464
+ resolve39(null);
457679
457465
  }
457680
457466
  });
457681
457467
  async function getNextLine() {
457682
457468
  if (lineQueue.length > 0) {
457683
457469
  return lineQueue.shift() ?? null;
457684
457470
  }
457685
- return new Promise((resolve41) => {
457686
- lineResolver = resolve41;
457471
+ return new Promise((resolve39) => {
457472
+ lineResolver = resolve39;
457687
457473
  });
457688
457474
  }
457689
457475
  async function requestPermission(toolCallId, toolName2, toolInput) {
@@ -458171,7 +457957,7 @@ async function runBidirectionalMode(agent, conversationId, _outputFormat, includ
458171
457957
  uuid: `retry-bidir-${randomUUID37()}`
458172
457958
  };
458173
457959
  writeWireMessage(retryMsg);
458174
- await new Promise((resolve41) => setTimeout(resolve41, delayMs));
457960
+ await new Promise((resolve39) => setTimeout(resolve39, delayMs));
458175
457961
  continue;
458176
457962
  }
458177
457963
  throw preStreamError;
@@ -458885,7 +458671,7 @@ var BYTES_PER_TOKEN = 4;
458885
458671
 
458886
458672
  // src/cli/helpers/window-title-config.ts
458887
458673
  import { homedir as homedir45 } from "node:os";
458888
- import { basename as basename30, resolve as resolve41 } from "node:path";
458674
+ import { basename as basename29, resolve as resolve39 } from "node:path";
458889
458675
  function isWindowTitleField(value) {
458890
458676
  return WINDOW_TITLE_FIELDS.includes(value);
458891
458677
  }
@@ -459043,8 +458829,8 @@ function terminalTitleProjectName(data) {
459043
458829
  const directory = titleDirectory(data);
459044
458830
  if (!directory)
459045
458831
  return null;
459046
- const resolved = resolve41(directory);
459047
- const name = basename30(resolved) || formatDirectoryDisplay(resolved) || resolved;
458832
+ const resolved = resolve39(directory);
458833
+ const name = basename29(resolved) || formatDirectoryDisplay(resolved) || resolved;
459048
458834
  return truncateTerminalTitlePart(name, 24);
459049
458835
  }
459050
458836
  function titleDirectory(data) {
@@ -459053,7 +458839,7 @@ function titleDirectory(data) {
459053
458839
  function formatDirectoryDisplay(directory) {
459054
458840
  if (!directory)
459055
458841
  return null;
459056
- const resolved = resolve41(directory);
458842
+ const resolved = resolve39(directory);
459057
458843
  const home = homedir45();
459058
458844
  if (resolved === home)
459059
458845
  return "~";
@@ -459776,10 +459562,10 @@ var init_queued_message_parts = __esm(() => {
459776
459562
 
459777
459563
  // src/cli/helpers/reflection-arena-hf-upload.ts
459778
459564
  import { execFile as execFileCb5 } from "node:child_process";
459779
- import { existsSync as existsSync67 } from "node:fs";
459780
- import { appendFile as appendFile2, chmod as chmod2, mkdir as mkdir18, writeFile as writeFile20 } from "node:fs/promises";
459565
+ import { existsSync as existsSync66 } from "node:fs";
459566
+ import { appendFile as appendFile2, chmod, mkdir as mkdir17, writeFile as writeFile19 } from "node:fs/promises";
459781
459567
  import { homedir as homedir46 } from "node:os";
459782
- import { join as join85 } from "node:path";
459568
+ import { join as join84 } from "node:path";
459783
459569
  import { promisify as promisify16 } from "node:util";
459784
459570
  function buildGitEnv(token2, askpassPath) {
459785
459571
  return {
@@ -459815,8 +459601,8 @@ async function runGit6(cwd2, args, env5) {
459815
459601
  }
459816
459602
  }
459817
459603
  async function writeGitAskpass(repoRoot) {
459818
- const askpassPath = join85(repoRoot, "hf-askpass.sh");
459819
- await writeFile20(askpassPath, [
459604
+ const askpassPath = join84(repoRoot, "hf-askpass.sh");
459605
+ await writeFile19(askpassPath, [
459820
459606
  "#!/bin/sh",
459821
459607
  'case "$1" in',
459822
459608
  " *Username*) printf '%s\\n' 'hf_user' ;;",
@@ -459825,12 +459611,12 @@ async function writeGitAskpass(repoRoot) {
459825
459611
  ""
459826
459612
  ].join(`
459827
459613
  `), { encoding: "utf-8", mode: 448 });
459828
- await chmod2(askpassPath, 448);
459614
+ await chmod(askpassPath, 448);
459829
459615
  return askpassPath;
459830
459616
  }
459831
459617
  async function prepareHfRepo(env5) {
459832
- await mkdir18(HF_CACHE_ROOT, { recursive: true });
459833
- if (!existsSync67(join85(HF_REPO_DIR, ".git"))) {
459618
+ await mkdir17(HF_CACHE_ROOT, { recursive: true });
459619
+ if (!existsSync66(join84(HF_REPO_DIR, ".git"))) {
459834
459620
  await runGit6(HF_CACHE_ROOT, ["clone", "--depth", "1", HF_REPO_URL, HF_REPO_DIR], env5);
459835
459621
  return HF_REPO_DIR;
459836
459622
  }
@@ -459860,13 +459646,13 @@ async function maybeUploadReflectionArenaChoiceToHf(row) {
459860
459646
  if (!token2) {
459861
459647
  return { uploaded: false, reason: "missing_token" };
459862
459648
  }
459863
- await mkdir18(HF_CACHE_ROOT, { recursive: true });
459649
+ await mkdir17(HF_CACHE_ROOT, { recursive: true });
459864
459650
  const askpassPath = await writeGitAskpass(HF_CACHE_ROOT);
459865
459651
  const env5 = buildGitEnv(token2, askpassPath);
459866
459652
  try {
459867
459653
  const repoDir = await prepareHfRepo(env5);
459868
- await mkdir18(join85(repoDir, "data"), { recursive: true });
459869
- await appendFile2(join85(repoDir, HF_DATASET_PATH), `${JSON.stringify(row)}
459654
+ await mkdir17(join84(repoDir, "data"), { recursive: true });
459655
+ await appendFile2(join84(repoDir, HF_DATASET_PATH), `${JSON.stringify(row)}
459870
459656
  `, {
459871
459657
  encoding: "utf-8"
459872
459658
  });
@@ -459894,16 +459680,16 @@ var init_reflection_arena_hf_upload = __esm(() => {
459894
459680
  init_version();
459895
459681
  execFile18 = promisify16(execFileCb5);
459896
459682
  HF_REPO_URL = `https://huggingface.co/datasets/${HF_REPO_ID}`;
459897
- HF_CACHE_ROOT = join85(homedir46(), ".letta", "reflection-arena", "hf-upload");
459898
- HF_REPO_DIR = join85(HF_CACHE_ROOT, "repo");
459683
+ HF_CACHE_ROOT = join84(homedir46(), ".letta", "reflection-arena", "hf-upload");
459684
+ HF_REPO_DIR = join84(HF_CACHE_ROOT, "repo");
459899
459685
  });
459900
459686
 
459901
459687
  // src/cli/helpers/reflection-arena.ts
459902
459688
  import { execFile as execFileCb6 } from "node:child_process";
459903
459689
  import { randomInt as randomInt2, randomUUID as randomUUID38 } from "node:crypto";
459904
- import { appendFile as appendFile3, mkdir as mkdir19, readFile as readFile31, writeFile as writeFile21 } from "node:fs/promises";
459690
+ import { appendFile as appendFile3, mkdir as mkdir18, readFile as readFile30, writeFile as writeFile20 } from "node:fs/promises";
459905
459691
  import { homedir as homedir47 } from "node:os";
459906
- import { join as join86 } from "node:path";
459692
+ import { join as join85 } from "node:path";
459907
459693
  import { promisify as promisify17 } from "node:util";
459908
459694
  function sampleReflectionArenaComparisonModel(excludedModels = []) {
459909
459695
  const excluded = new Set(excludedModels);
@@ -459952,24 +459738,24 @@ function candidateIsConfirmedNoOp(candidate) {
459952
459738
  return candidate.result?.success === true && candidate.result.memoryNoChanges === true && candidate.result.memoryHead === candidate.worktree.baseHead;
459953
459739
  }
459954
459740
  function getReflectionArenaRoot() {
459955
- return join86(homedir47(), ".letta", "reflection-arena");
459741
+ return join85(homedir47(), ".letta", "reflection-arena");
459956
459742
  }
459957
459743
  function getReflectionArenaRunsDir() {
459958
- return join86(getReflectionArenaRoot(), "runs");
459744
+ return join85(getReflectionArenaRoot(), "runs");
459959
459745
  }
459960
459746
  function getReflectionArenaChoiceLogPath() {
459961
- return join86(getReflectionArenaRoot(), "choices.jsonl");
459747
+ return join85(getReflectionArenaRoot(), "choices.jsonl");
459962
459748
  }
459963
459749
  function getReflectionArenaRunPath(runId) {
459964
- return join86(getReflectionArenaRunsDir(), `${runId}.json`);
459750
+ return join85(getReflectionArenaRunsDir(), `${runId}.json`);
459965
459751
  }
459966
459752
  async function saveReflectionArenaRun(run) {
459967
- await mkdir19(getReflectionArenaRunsDir(), { recursive: true });
459968
- await writeFile21(getReflectionArenaRunPath(run.runId), `${JSON.stringify(run, null, 2)}
459753
+ await mkdir18(getReflectionArenaRunsDir(), { recursive: true });
459754
+ await writeFile20(getReflectionArenaRunPath(run.runId), `${JSON.stringify(run, null, 2)}
459969
459755
  `, "utf-8");
459970
459756
  }
459971
459757
  async function loadReflectionArenaRun(runId) {
459972
- const raw2 = await readFile31(getReflectionArenaRunPath(runId), "utf-8");
459758
+ const raw2 = await readFile30(getReflectionArenaRunPath(runId), "utf-8");
459973
459759
  return JSON.parse(raw2);
459974
459760
  }
459975
459761
  async function updateReflectionArenaRun(runId, update3) {
@@ -460135,7 +459921,7 @@ function formatReflectionArenaChoiceResult(params) {
460135
459921
  `);
460136
459922
  }
460137
459923
  async function appendChoiceRecord(run) {
460138
- await mkdir19(getReflectionArenaRoot(), { recursive: true });
459924
+ await mkdir18(getReflectionArenaRoot(), { recursive: true });
460139
459925
  await appendFile3(getReflectionArenaChoiceLogPath(), `${JSON.stringify({
460140
459926
  run_id: run.runId,
460141
459927
  agent_id: run.agentId,
@@ -460161,7 +459947,7 @@ async function appendChoiceRecord(run) {
460161
459947
  }
460162
459948
  async function readTranscriptPayloadForTelemetry(payloadPath) {
460163
459949
  try {
460164
- const transcript = await readFile31(payloadPath, "utf-8");
459950
+ const transcript = await readFile30(payloadPath, "utf-8");
460165
459951
  return {
460166
459952
  transcriptPayload: transcript.slice(0, REFLECTION_ARENA_TELEMETRY_TRANSCRIPT_MAX_CHARS),
460167
459953
  transcriptPayloadChars: transcript.length,
@@ -460852,8 +460638,8 @@ async function pushToMemoryRepositoryWithTimeout(agentId) {
460852
460638
  try {
460853
460639
  return await Promise.race([
460854
460640
  pushToMemoryRepository(agentId),
460855
- new Promise((resolve42) => {
460856
- timeout = setTimeout(() => resolve42("timeout"), INITIAL_PUSH_TIMEOUT_MS);
460641
+ new Promise((resolve40) => {
460642
+ timeout = setTimeout(() => resolve40("timeout"), INITIAL_PUSH_TIMEOUT_MS);
460857
460643
  })
460858
460644
  ]);
460859
460645
  } finally {
@@ -461117,13 +460903,13 @@ __export(exports_terminal_keybinding_installer, {
461117
460903
  });
461118
460904
  import {
461119
460905
  copyFileSync as copyFileSync6,
461120
- existsSync as existsSync68,
460906
+ existsSync as existsSync67,
461121
460907
  mkdirSync as mkdirSync45,
461122
- readFileSync as readFileSync43,
460908
+ readFileSync as readFileSync42,
461123
460909
  writeFileSync as writeFileSync35
461124
460910
  } from "node:fs";
461125
460911
  import { homedir as homedir48, platform as platform10 } from "node:os";
461126
- import { dirname as dirname36, join as join87 } from "node:path";
460912
+ import { dirname as dirname35, join as join86 } from "node:path";
461127
460913
  function detectTerminalType() {
461128
460914
  if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
461129
460915
  return "cursor";
@@ -461155,16 +460941,16 @@ function getKeybindingsPath(terminal) {
461155
460941
  }[terminal];
461156
460942
  const os9 = platform10();
461157
460943
  if (os9 === "darwin") {
461158
- return join87(homedir48(), "Library", "Application Support", appName, "User", "keybindings.json");
460944
+ return join86(homedir48(), "Library", "Application Support", appName, "User", "keybindings.json");
461159
460945
  }
461160
460946
  if (os9 === "win32") {
461161
460947
  const appData = process.env.APPDATA;
461162
460948
  if (!appData)
461163
460949
  return null;
461164
- return join87(appData, appName, "User", "keybindings.json");
460950
+ return join86(appData, appName, "User", "keybindings.json");
461165
460951
  }
461166
460952
  if (os9 === "linux") {
461167
- return join87(homedir48(), ".config", appName, "User", "keybindings.json");
460953
+ return join86(homedir48(), ".config", appName, "User", "keybindings.json");
461168
460954
  }
461169
460955
  return null;
461170
460956
  }
@@ -461186,10 +460972,10 @@ function parseKeybindings(content) {
461186
460972
  }
461187
460973
  }
461188
460974
  function keybindingExists(keybindingsPath) {
461189
- if (!existsSync68(keybindingsPath))
460975
+ if (!existsSync67(keybindingsPath))
461190
460976
  return false;
461191
460977
  try {
461192
- const content = readFileSync43(keybindingsPath, { encoding: "utf-8" });
460978
+ const content = readFileSync42(keybindingsPath, { encoding: "utf-8" });
461193
460979
  const keybindings = parseKeybindings(content);
461194
460980
  if (!keybindings)
461195
460981
  return false;
@@ -461199,7 +460985,7 @@ function keybindingExists(keybindingsPath) {
461199
460985
  }
461200
460986
  }
461201
460987
  function createBackup(keybindingsPath) {
461202
- if (!existsSync68(keybindingsPath))
460988
+ if (!existsSync67(keybindingsPath))
461203
460989
  return null;
461204
460990
  const backupPath = `${keybindingsPath}.letta-backup`;
461205
460991
  try {
@@ -461214,15 +461000,15 @@ function installKeybinding(keybindingsPath) {
461214
461000
  if (keybindingExists(keybindingsPath)) {
461215
461001
  return { success: true, alreadyExists: true };
461216
461002
  }
461217
- const parentDir = dirname36(keybindingsPath);
461218
- if (!existsSync68(parentDir)) {
461003
+ const parentDir = dirname35(keybindingsPath);
461004
+ if (!existsSync67(parentDir)) {
461219
461005
  mkdirSync45(parentDir, { recursive: true });
461220
461006
  }
461221
461007
  let keybindings = [];
461222
461008
  let backupPath = null;
461223
- if (existsSync68(keybindingsPath)) {
461009
+ if (existsSync67(keybindingsPath)) {
461224
461010
  backupPath = createBackup(keybindingsPath);
461225
- const content = readFileSync43(keybindingsPath, { encoding: "utf-8" });
461011
+ const content = readFileSync42(keybindingsPath, { encoding: "utf-8" });
461226
461012
  const parsed = parseKeybindings(content);
461227
461013
  if (parsed === null) {
461228
461014
  return {
@@ -461250,10 +461036,10 @@ function installKeybinding(keybindingsPath) {
461250
461036
  }
461251
461037
  function removeKeybinding(keybindingsPath) {
461252
461038
  try {
461253
- if (!existsSync68(keybindingsPath)) {
461039
+ if (!existsSync67(keybindingsPath)) {
461254
461040
  return { success: true };
461255
461041
  }
461256
- const content = readFileSync43(keybindingsPath, { encoding: "utf-8" });
461042
+ const content = readFileSync42(keybindingsPath, { encoding: "utf-8" });
461257
461043
  const keybindings = parseKeybindings(content);
461258
461044
  if (!keybindings) {
461259
461045
  return {
@@ -461317,14 +461103,14 @@ function getWezTermConfigPath() {
461317
461103
  }
461318
461104
  const xdgConfig = process.env.XDG_CONFIG_HOME;
461319
461105
  if (xdgConfig) {
461320
- const xdgPath = join87(xdgConfig, "wezterm", "wezterm.lua");
461321
- if (existsSync68(xdgPath))
461106
+ const xdgPath = join86(xdgConfig, "wezterm", "wezterm.lua");
461107
+ if (existsSync67(xdgPath))
461322
461108
  return xdgPath;
461323
461109
  }
461324
- const configPath = join87(homedir48(), ".config", "wezterm", "wezterm.lua");
461325
- if (existsSync68(configPath))
461110
+ const configPath = join86(homedir48(), ".config", "wezterm", "wezterm.lua");
461111
+ if (existsSync67(configPath))
461326
461112
  return configPath;
461327
- return join87(homedir48(), ".wezterm.lua");
461113
+ return join86(homedir48(), ".wezterm.lua");
461328
461114
  }
461329
461115
  function stripLuaCommentsFromLine(line, blockCommentEnd) {
461330
461116
  let code2 = "";
@@ -461427,10 +461213,10 @@ ${WEZTERM_DELETE_FIX}
461427
461213
  `;
461428
461214
  }
461429
461215
  function wezTermDeleteFixExists(configPath) {
461430
- if (!existsSync68(configPath))
461216
+ if (!existsSync67(configPath))
461431
461217
  return false;
461432
461218
  try {
461433
- const content = readFileSync43(configPath, { encoding: "utf-8" });
461219
+ const content = readFileSync42(configPath, { encoding: "utf-8" });
461434
461220
  return content.includes("Letta Code: Fix Delete key") || content.includes("key = 'Delete'") && content.includes("SendString") && content.includes("\\x1b[3~");
461435
461221
  } catch {
461436
461222
  return false;
@@ -461444,14 +461230,14 @@ function installWezTermDeleteFix() {
461444
461230
  }
461445
461231
  let content = "";
461446
461232
  let backupPath = null;
461447
- if (existsSync68(configPath)) {
461233
+ if (existsSync67(configPath)) {
461448
461234
  backupPath = `${configPath}.letta-backup`;
461449
461235
  copyFileSync6(configPath, backupPath);
461450
- content = readFileSync43(configPath, { encoding: "utf-8" });
461236
+ content = readFileSync42(configPath, { encoding: "utf-8" });
461451
461237
  }
461452
461238
  content = injectWezTermDeleteFix(content);
461453
- const parentDir = dirname36(configPath);
461454
- if (!existsSync68(parentDir)) {
461239
+ const parentDir = dirname35(configPath);
461240
+ if (!existsSync67(parentDir)) {
461455
461241
  mkdirSync45(parentDir, { recursive: true });
461456
461242
  }
461457
461243
  writeFileSync35(configPath, content, { encoding: "utf-8" });
@@ -461503,9 +461289,9 @@ __export(exports_settings2, {
461503
461289
  getSetting: () => getSetting
461504
461290
  });
461505
461291
  import { homedir as homedir49 } from "node:os";
461506
- import { join as join88 } from "node:path";
461292
+ import { join as join87 } from "node:path";
461507
461293
  function getSettingsPath() {
461508
- return join88(homedir49(), ".letta", "settings.json");
461294
+ return join87(homedir49(), ".letta", "settings.json");
461509
461295
  }
461510
461296
  async function loadSettings() {
461511
461297
  const settingsPath = getSettingsPath();
@@ -461542,7 +461328,7 @@ async function getSetting(key2) {
461542
461328
  return settings3[key2];
461543
461329
  }
461544
461330
  function getProjectSettingsPath() {
461545
- return join88(process.cwd(), ".letta", "settings.local.json");
461331
+ return join87(process.cwd(), ".letta", "settings.local.json");
461546
461332
  }
461547
461333
  async function loadProjectSettings() {
461548
461334
  const settingsPath = getProjectSettingsPath();
@@ -461560,7 +461346,7 @@ async function loadProjectSettings() {
461560
461346
  }
461561
461347
  async function saveProjectSettings(settings3) {
461562
461348
  const settingsPath = getProjectSettingsPath();
461563
- const dirPath = join88(process.cwd(), ".letta");
461349
+ const dirPath = join87(process.cwd(), ".letta");
461564
461350
  try {
461565
461351
  if (!exists(dirPath)) {
461566
461352
  await mkdir(dirPath, { recursive: true });
@@ -461860,14 +461646,6 @@ var init_registry2 = __esm(() => {
461860
461646
  return "Updating description...";
461861
461647
  }
461862
461648
  },
461863
- "/export": {
461864
- desc: "Export AgentFile (.af)",
461865
- order: 26,
461866
- noArgs: true,
461867
- handler: () => {
461868
- return "Exporting agent file...";
461869
- }
461870
- },
461871
461649
  "/toolset": {
461872
461650
  desc: "Switch toolset (replaces /link and /unlink)",
461873
461651
  order: 27,
@@ -462185,14 +461963,6 @@ Location: ${keybindingsPath}`;
462185
461963
  handler: () => {
462186
461964
  return "Opening agent browser...";
462187
461965
  }
462188
- },
462189
- "/download": {
462190
- desc: "Export AgentFile (.af)",
462191
- hidden: true,
462192
- noArgs: true,
462193
- handler: () => {
462194
- return "Exporting agent file...";
462195
- }
462196
461966
  }
462197
461967
  };
462198
461968
  });
@@ -462608,10 +462378,10 @@ var init_InlineBashApproval = __esm(async () => {
462608
462378
  });
462609
462379
 
462610
462380
  // src/cli/components/DiffRenderer.tsx
462611
- import { relative as relative15 } from "node:path";
462381
+ import { relative as relative14 } from "node:path";
462612
462382
  function formatDisplayPath4(filePath) {
462613
462383
  const cwd2 = process.cwd();
462614
- const relativePath = relative15(cwd2, filePath);
462384
+ const relativePath = relative14(cwd2, filePath);
462615
462385
  if (relativePath.startsWith("..")) {
462616
462386
  return filePath;
462617
462387
  }
@@ -462970,10 +462740,10 @@ var init_DiffRenderer = __esm(async () => {
462970
462740
  });
462971
462741
 
462972
462742
  // src/cli/components/AdvancedDiffRenderer.tsx
462973
- import { relative as relative16 } from "node:path";
462743
+ import { relative as relative15 } from "node:path";
462974
462744
  function formatRelativePath(filePath) {
462975
462745
  const cwd2 = process.cwd();
462976
- const relativePath = relative16(cwd2, filePath);
462746
+ const relativePath = relative15(cwd2, filePath);
462977
462747
  return relativePath.startsWith("..") ? relativePath : `./${relativePath}`;
462978
462748
  }
462979
462749
  function padLeft(n, width) {
@@ -463255,7 +463025,7 @@ function AdvancedDiffRenderer(props) {
463255
463025
  }
463256
463026
  const { hunks } = result2;
463257
463027
  const filePath = props.filePath;
463258
- const relative17 = formatRelativePath(filePath);
463028
+ const relative16 = formatRelativePath(filePath);
463259
463029
  const lang41 = languageFromPath(filePath);
463260
463030
  const shouldHighlight = lang41 && !exceedsAdvancedDiffHighlightLimits(hunks);
463261
463031
  const hunkSyntaxLines = [];
@@ -463278,7 +463048,7 @@ function AdvancedDiffRenderer(props) {
463278
463048
  const rows = buildAdvancedDiffRows(hunks, hunkSyntaxLines);
463279
463049
  const maxDisplayNo = rows.reduce((m4, r5) => Math.max(m4, r5.displayNo), 1);
463280
463050
  const gutterWidth = String(maxDisplayNo).length;
463281
- const header = props.kind === "write" ? `Wrote changes to ${relative17}` : `Updated ${relative17}`;
463051
+ const header = props.kind === "write" ? `Wrote changes to ${relative16}` : `Updated ${relative16}`;
463282
463052
  if (rows.length === 0) {
463283
463053
  const noChangesGutter = 4;
463284
463054
  return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Box_default, {
@@ -463329,7 +463099,7 @@ function AdvancedDiffRenderer(props) {
463329
463099
  "No changes to ",
463330
463100
  /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(Text2, {
463331
463101
  bold: true,
463332
- children: relative17
463102
+ children: relative16
463333
463103
  }, undefined, false, undefined, this),
463334
463104
  " (file content identical)"
463335
463105
  ]
@@ -463435,9 +463205,9 @@ function getHeaderText(fileEdit) {
463435
463205
  } else if (operations.length === 1) {
463436
463206
  const op = operations[0];
463437
463207
  if (op) {
463438
- const { relative: relative18 } = __require("node:path");
463208
+ const { relative: relative17 } = __require("node:path");
463439
463209
  const cwd3 = process.cwd();
463440
- const relPath2 = relative18(cwd3, op.path);
463210
+ const relPath2 = relative17(cwd3, op.path);
463441
463211
  const displayPath2 = relPath2.startsWith("..") ? op.path : relPath2;
463442
463212
  if (op.kind === "add") {
463443
463213
  return `Write to ${displayPath2}?`;
@@ -463451,14 +463221,14 @@ function getHeaderText(fileEdit) {
463451
463221
  }
463452
463222
  return "Apply patch?";
463453
463223
  }
463454
- const { relative: relative17 } = __require("node:path");
463224
+ const { relative: relative16 } = __require("node:path");
463455
463225
  const cwd2 = process.cwd();
463456
- const relPath = relative17(cwd2, fileEdit.filePath);
463226
+ const relPath = relative16(cwd2, fileEdit.filePath);
463457
463227
  const displayPath = relPath.startsWith("..") ? fileEdit.filePath : relPath;
463458
463228
  if (t2 === "write" || t2 === "write_file" || t2 === "writefile" || t2 === "write_file_gemini" || t2 === "writefilegemini") {
463459
- const { existsSync: existsSync69 } = __require("node:fs");
463229
+ const { existsSync: existsSync68 } = __require("node:fs");
463460
463230
  try {
463461
- if (existsSync69(fileEdit.filePath)) {
463231
+ if (existsSync68(fileEdit.filePath)) {
463462
463232
  return `Overwrite ${displayPath}?`;
463463
463233
  }
463464
463234
  } catch {}
@@ -463636,9 +463406,9 @@ var init_InlineFileEditApproval = __esm(async () => {
463636
463406
  children: fileEdit.patchInput ? /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Box_default, {
463637
463407
  flexDirection: "column",
463638
463408
  children: parsePatchOperations2(fileEdit.patchInput).map((op, idx) => {
463639
- const { relative: relative17 } = __require("node:path");
463409
+ const { relative: relative16 } = __require("node:path");
463640
463410
  const cwd2 = process.cwd();
463641
- const relPath = relative17(cwd2, op.path);
463411
+ const relPath = relative16(cwd2, op.path);
463642
463412
  const displayPath = relPath.startsWith("..") ? op.path : relPath;
463643
463413
  const diffKey = fileEdit.toolCallId ? `${fileEdit.toolCallId}:${op.path}` : undefined;
463644
463414
  const opDiff = diffKey && allDiffs ? allDiffs.get(diffKey) : undefined;
@@ -467175,11 +466945,11 @@ var init_HelpDialog = __esm(async () => {
467175
466945
 
467176
466946
  // src/hooks/writer.ts
467177
466947
  import { homedir as homedir50 } from "node:os";
467178
- import { resolve as resolve42 } from "node:path";
466948
+ import { resolve as resolve40 } from "node:path";
467179
466949
  function isProjectSettingsPathCollidingWithGlobal2(workingDirectory) {
467180
466950
  const home = process.env.HOME || homedir50();
467181
- const globalSettingsPath = resolve42(home, ".letta", "settings.json");
467182
- const projectSettingsPath = resolve42(workingDirectory, ".letta", "settings.json");
466951
+ const globalSettingsPath = resolve40(home, ".letta", "settings.json");
466952
+ const projectSettingsPath = resolve40(workingDirectory, ".letta", "settings.json");
467183
466953
  return globalSettingsPath === projectSettingsPath;
467184
466954
  }
467185
466955
  function loadHooksFromLocation(location, workingDirectory = process.cwd()) {
@@ -472969,15 +472739,15 @@ var init_InputRich = __esm(async () => {
472969
472739
  // src/cli/commands/install-github-app.ts
472970
472740
  import { execFileSync as execFileSync7 } from "node:child_process";
472971
472741
  import {
472972
- existsSync as existsSync69,
472742
+ existsSync as existsSync68,
472973
472743
  mkdirSync as mkdirSync46,
472974
472744
  mkdtempSync as mkdtempSync6,
472975
- readFileSync as readFileSync44,
472745
+ readFileSync as readFileSync43,
472976
472746
  rmSync as rmSync18,
472977
472747
  writeFileSync as writeFileSync36
472978
472748
  } from "node:fs";
472979
472749
  import { tmpdir as tmpdir12 } from "node:os";
472980
- import { dirname as dirname37, join as join89 } from "node:path";
472750
+ import { dirname as dirname36, join as join88 } from "node:path";
472981
472751
  function runCommand(command, args, cwd2, input) {
472982
472752
  try {
472983
472753
  return execFileSync7(command, args, {
@@ -473198,8 +472968,8 @@ async function createLettaAgent(apiKey, name) {
473198
472968
  return createMinimalAgent(apiKey, name);
473199
472969
  }
473200
472970
  function cloneRepoToTemp(repo) {
473201
- const tempDir = mkdtempSync6(join89(tmpdir12(), "letta-install-github-app-"));
473202
- const repoDir = join89(tempDir, "repo");
472971
+ const tempDir = mkdtempSync6(join88(tmpdir12(), "letta-install-github-app-"));
472972
+ const repoDir = join88(tempDir, "repo");
473203
472973
  runCommand("gh", ["repo", "clone", repo, repoDir, "--", "--depth=1"]);
473204
472974
  return { tempDir, repoDir };
473205
472975
  }
@@ -473210,14 +472980,14 @@ function runGit7(args, cwd2) {
473210
472980
  return runCommand("git", args, cwd2);
473211
472981
  }
473212
472982
  function writeWorkflow(repoDir, workflowPath, content) {
473213
- const absolutePath = join89(repoDir, workflowPath);
473214
- if (!existsSync69(dirname37(absolutePath))) {
473215
- mkdirSync46(dirname37(absolutePath), { recursive: true });
472983
+ const absolutePath = join88(repoDir, workflowPath);
472984
+ if (!existsSync68(dirname36(absolutePath))) {
472985
+ mkdirSync46(dirname36(absolutePath), { recursive: true });
473216
472986
  }
473217
472987
  const next = `${content.trimEnd()}
473218
472988
  `;
473219
- if (existsSync69(absolutePath)) {
473220
- const previous = readFileSync44(absolutePath, "utf8");
472989
+ if (existsSync68(absolutePath)) {
472990
+ const previous = readFileSync43(absolutePath, "utf8");
473221
472991
  if (previous === next) {
473222
472992
  return false;
473223
472993
  }
@@ -477106,9 +476876,9 @@ __export(exports_generate_memory_viewer, {
477106
476876
  generateAndOpenMemoryViewer: () => generateAndOpenMemoryViewer
477107
476877
  });
477108
476878
  import { execFile as execFileCb7 } from "node:child_process";
477109
- import { chmodSync as chmodSync7, existsSync as existsSync70, mkdirSync as mkdirSync47, writeFileSync as writeFileSync37 } from "node:fs";
476879
+ import { chmodSync as chmodSync7, existsSync as existsSync69, mkdirSync as mkdirSync47, writeFileSync as writeFileSync37 } from "node:fs";
477110
476880
  import { homedir as homedir51 } from "node:os";
477111
- import { join as join90 } from "node:path";
476881
+ import { join as join89 } from "node:path";
477112
476882
  import { promisify as promisify18 } from "node:util";
477113
476883
  function messagesFromOverview(overview) {
477114
476884
  return overview.messages?.map((message) => ({
@@ -477146,7 +476916,7 @@ async function runGitSafe(cwd2, args) {
477146
476916
  return "";
477147
476917
  }
477148
476918
  }
477149
- function parseFrontmatter3(raw2) {
476919
+ function parseFrontmatter2(raw2) {
477150
476920
  if (!raw2.startsWith("---")) {
477151
476921
  return { frontmatter: {}, body: raw2 };
477152
476922
  }
@@ -477175,7 +476945,7 @@ function collectFiles2(memoryRoot) {
477175
476945
  const fileNodes = getFileNodes(treeNodes);
477176
476946
  return fileNodes.filter((n) => n.name.endsWith(".md")).map((n) => {
477177
476947
  const raw2 = readFileContent(n.fullPath);
477178
- const { frontmatter, body: body3 } = parseFrontmatter3(raw2);
476948
+ const { frontmatter, body: body3 } = parseFrontmatter2(raw2);
477179
476949
  return {
477180
476950
  path: n.relativePath,
477181
476951
  isSystem: n.relativePath.startsWith("system/") || n.relativePath.startsWith("system\\"),
@@ -477417,7 +477187,7 @@ ${m4.body}` : m4.subject;
477417
477187
  async function generateAndOpenMemoryViewer(agentId, options) {
477418
477188
  const memoryRoot = getScopedMemoryFilesystemRoot(agentId);
477419
477189
  const repoDir = memoryRoot;
477420
- if (!existsSync70(join90(repoDir, ".git"))) {
477190
+ if (!existsSync69(join89(repoDir, ".git"))) {
477421
477191
  throw new Error("Memory viewer requires memfs. Run /memfs enable first.");
477422
477192
  }
477423
477193
  const data = await collectMemoryData(agentId, repoDir, memoryRoot, options?.conversationId);
@@ -477427,13 +477197,13 @@ async function generateAndOpenMemoryViewer(agentId, options) {
477427
477197
  data.context = applyContextUsageSnapshot(data.context, options?.contextUsage);
477428
477198
  const jsonPayload = JSON.stringify(data).replace(/</g, "\\u003c");
477429
477199
  const html5 = memory_viewer_template_default.replace("<!--LETTA_DATA_PLACEHOLDER-->", () => jsonPayload);
477430
- if (!existsSync70(VIEWERS_DIR)) {
477200
+ if (!existsSync69(VIEWERS_DIR)) {
477431
477201
  mkdirSync47(VIEWERS_DIR, { recursive: true, mode: 448 });
477432
477202
  }
477433
477203
  try {
477434
477204
  chmodSync7(VIEWERS_DIR, 448);
477435
477205
  } catch {}
477436
- const filePath = join90(VIEWERS_DIR, `memory-${encodeURIComponent(agentId)}.html`);
477206
+ const filePath = join89(VIEWERS_DIR, `memory-${encodeURIComponent(agentId)}.html`);
477437
477207
  writeFileSync37(filePath, html5);
477438
477208
  chmodSync7(filePath, 384);
477439
477209
  const skipOpen = Boolean(process.env.TMUX) || Boolean(process.env.SSH_CONNECTION) || Boolean(process.env.SSH_TTY);
@@ -477459,13 +477229,13 @@ var init_generate_memory_viewer = __esm(() => {
477459
477229
  init_local_memory_context();
477460
477230
  init_memory_viewer_template();
477461
477231
  execFile20 = promisify18(execFileCb7);
477462
- VIEWERS_DIR = join90(homedir51(), ".letta", "viewers");
477232
+ VIEWERS_DIR = join89(homedir51(), ".letta", "viewers");
477463
477233
  REFLECTION_PATTERN = /\(reflection\)|🔮|reflection:/i;
477464
477234
  });
477465
477235
 
477466
477236
  // src/cli/components/MemfsTreeViewer.tsx
477467
- import { existsSync as existsSync71 } from "node:fs";
477468
- import { join as join91 } from "node:path";
477237
+ import { existsSync as existsSync70 } from "node:fs";
477238
+ import { join as join90 } from "node:path";
477469
477239
  function renderTreePrefix(node) {
477470
477240
  let prefix = "";
477471
477241
  for (let i4 = 0;i4 < node.depth; i4++) {
@@ -477493,8 +477263,8 @@ function MemfsTreeViewer({
477493
477263
  const [status, setStatus] = import_react88.useState(null);
477494
477264
  const statusTimerRef = import_react88.useRef(null);
477495
477265
  const memoryRoot = getScopedMemoryFilesystemRoot(agentId);
477496
- const memoryExists = existsSync71(memoryRoot);
477497
- const hasGitRepo = import_react88.useMemo(() => existsSync71(join91(memoryRoot, ".git")), [memoryRoot]);
477266
+ const memoryExists = existsSync70(memoryRoot);
477267
+ const hasGitRepo = import_react88.useMemo(() => existsSync70(join90(memoryRoot, ".git")), [memoryRoot]);
477498
477268
  function showStatus(msg, durationMs) {
477499
477269
  if (statusTimerRef.current)
477500
477270
  clearTimeout(statusTimerRef.current);
@@ -479869,19 +479639,19 @@ var init_PersonalitySelector = __esm(async () => {
479869
479639
  });
479870
479640
 
479871
479641
  // src/utils/aws-credentials.ts
479872
- import { readFile as readFile32 } from "node:fs/promises";
479642
+ import { readFile as readFile31 } from "node:fs/promises";
479873
479643
  import { homedir as homedir52 } from "node:os";
479874
- import { join as join92 } from "node:path";
479644
+ import { join as join91 } from "node:path";
479875
479645
  async function parseAwsCredentials() {
479876
- const credentialsPath = join92(homedir52(), ".aws", "credentials");
479877
- const configPath = join92(homedir52(), ".aws", "config");
479646
+ const credentialsPath = join91(homedir52(), ".aws", "credentials");
479647
+ const configPath = join91(homedir52(), ".aws", "config");
479878
479648
  const profiles = new Map;
479879
479649
  try {
479880
- const content = await readFile32(credentialsPath, "utf-8");
479650
+ const content = await readFile31(credentialsPath, "utf-8");
479881
479651
  parseIniFile(content, profiles, false);
479882
479652
  } catch {}
479883
479653
  try {
479884
- const content = await readFile32(configPath, "utf-8");
479654
+ const content = await readFile31(configPath, "utf-8");
479885
479655
  parseIniFile(content, profiles, true);
479886
479656
  } catch {}
479887
479657
  return Array.from(profiles.values());
@@ -481453,8 +481223,8 @@ function SkillsDialog({ onClose, agentId }) {
481453
481223
  try {
481454
481224
  const { discoverSkills: discoverSkills2, SKILLS_DIR: SKILLS_DIR2 } = await Promise.resolve().then(() => (init_skills5(), exports_skills2));
481455
481225
  const { getSkillsDirectory: getSkillsDirectory2, getSkillSources: getSkillSources2 } = await Promise.resolve().then(() => (init_context(), exports_context));
481456
- const { join: join93 } = await import("node:path");
481457
- const skillsDir = getSkillsDirectory2() || join93(process.cwd(), SKILLS_DIR2);
481226
+ const { join: join92 } = await import("node:path");
481227
+ const skillsDir = getSkillsDirectory2() || join92(process.cwd(), SKILLS_DIR2);
481458
481228
  const result2 = await discoverSkills2(skillsDir, agentId, {
481459
481229
  sources: getSkillSources2()
481460
481230
  });
@@ -484852,15 +484622,15 @@ function ToolsetSelector({
484852
484622
  const solidLine = SOLID_LINE19.repeat(Math.max(terminalWidth, 10));
484853
484623
  const [showAll, setShowAll] = import_react103.useState(false);
484854
484624
  const [selectedIndex, setSelectedIndex] = import_react103.useState(0);
484855
- const featuredToolsets = import_react103.useMemo(() => toolsets.filter((toolset) => toolset.isFeatured), []);
484625
+ const featuredToolsets = import_react103.useMemo(() => TOOLSET_OPTIONS.filter((toolset) => toolset.is_featured), []);
484856
484626
  const visibleToolsets = import_react103.useMemo(() => {
484857
484627
  if (showAll)
484858
- return toolsets;
484628
+ return TOOLSET_OPTIONS;
484859
484629
  if (featuredToolsets.length > 0)
484860
484630
  return featuredToolsets;
484861
- return toolsets;
484631
+ return TOOLSET_OPTIONS;
484862
484632
  }, [featuredToolsets, showAll]);
484863
- const canToggleShowAll = featuredToolsets.length < toolsets.length;
484633
+ const canToggleShowAll = featuredToolsets.length < TOOLSET_OPTIONS.length;
484864
484634
  import_react103.useEffect(() => {
484865
484635
  if (selectedIndex >= visibleToolsets.length) {
484866
484636
  setSelectedIndex(Math.max(0, visibleToolsets.length - 1));
@@ -484944,10 +484714,11 @@ function ToolsetSelector({
484944
484714
  ]
484945
484715
  }, undefined, true, undefined, this);
484946
484716
  }
484947
- var import_react103, jsx_dev_runtime86, SOLID_LINE19 = "─", toolsets;
484717
+ var import_react103, jsx_dev_runtime86, SOLID_LINE19 = "─";
484948
484718
  var init_ToolsetSelector = __esm(async () => {
484949
484719
  init_use_terminal_width();
484950
484720
  init_toolset_labels();
484721
+ init_toolset_options();
484951
484722
  init_colors();
484952
484723
  await __promiseAll([
484953
484724
  init_build4(),
@@ -484955,48 +484726,6 @@ var init_ToolsetSelector = __esm(async () => {
484955
484726
  ]);
484956
484727
  import_react103 = __toESM(require_react(), 1);
484957
484728
  jsx_dev_runtime86 = __toESM(require_jsx_dev_runtime(), 1);
484958
- toolsets = [
484959
- {
484960
- id: "auto",
484961
- label: "Auto",
484962
- description: "Auto-select based on the model",
484963
- isFeatured: true
484964
- },
484965
- {
484966
- id: "none",
484967
- label: "None",
484968
- description: "Remove all Letta Code tools from your agent",
484969
- isFeatured: true
484970
- },
484971
- {
484972
- id: "default",
484973
- label: "Claude toolset",
484974
- description: "Optimized for Anthropic models",
484975
- isFeatured: true
484976
- },
484977
- {
484978
- id: "codex",
484979
- label: "Codex toolset",
484980
- description: "Optimized for GPT/Codex models",
484981
- isFeatured: true
484982
- },
484983
- {
484984
- id: "gemini",
484985
- label: "Gemini toolset",
484986
- description: "Optimized for Google Gemini models",
484987
- isFeatured: true
484988
- },
484989
- {
484990
- id: "codex_snake",
484991
- label: "Codex toolset (snake_case)",
484992
- description: "Optimized for GPT/Codex models (snake_case)"
484993
- },
484994
- {
484995
- id: "gemini_snake",
484996
- label: "Gemini toolset (snake_case)",
484997
- description: "Optimized for Google Gemini models (snake_case)"
484998
- }
484999
- ];
485000
484729
  });
485001
484730
 
485002
484731
  // src/cli/components/UserMessageRich.tsx
@@ -485616,9 +485345,9 @@ function getFileEditHeader(toolName2, toolArgs) {
485616
485345
  } else if (operations.length === 1) {
485617
485346
  const op = operations[0];
485618
485347
  if (op) {
485619
- const { relative: relative18 } = __require("node:path");
485348
+ const { relative: relative17 } = __require("node:path");
485620
485349
  const cwd3 = process.cwd();
485621
- const relPath2 = relative18(cwd3, op.path);
485350
+ const relPath2 = relative17(cwd3, op.path);
485622
485351
  const displayPath3 = relPath2.startsWith("..") ? op.path : relPath2;
485623
485352
  if (op.kind === "add")
485624
485353
  return `Write to ${displayPath3}?`;
@@ -485632,14 +485361,14 @@ function getFileEditHeader(toolName2, toolArgs) {
485632
485361
  return "Apply patch?";
485633
485362
  }
485634
485363
  const filePath = args.file_path || "";
485635
- const { relative: relative17 } = __require("node:path");
485364
+ const { relative: relative16 } = __require("node:path");
485636
485365
  const cwd2 = process.cwd();
485637
- const relPath = relative17(cwd2, filePath);
485366
+ const relPath = relative16(cwd2, filePath);
485638
485367
  const displayPath2 = relPath.startsWith("..") ? filePath : relPath;
485639
485368
  if (t2 === "write" || t2 === "write_file" || t2 === "writefile" || t2 === "write_file_gemini" || t2 === "writefilegemini") {
485640
- const { existsSync: existsSync72 } = __require("node:fs");
485369
+ const { existsSync: existsSync71 } = __require("node:fs");
485641
485370
  try {
485642
- if (existsSync72(filePath)) {
485371
+ if (existsSync71(filePath)) {
485643
485372
  return `Overwrite ${displayPath2}?`;
485644
485373
  }
485645
485374
  } catch {}
@@ -485722,9 +485451,9 @@ var init_ApprovalPreview = __esm(async () => {
485722
485451
  /* @__PURE__ */ jsx_dev_runtime92.jsxDEV(Box_default, {
485723
485452
  flexDirection: "column",
485724
485453
  children: operations.map((op, idx) => {
485725
- const { relative: relative17 } = __require("node:path");
485454
+ const { relative: relative16 } = __require("node:path");
485726
485455
  const cwd2 = process.cwd();
485727
- const relPath = relative17(cwd2, op.path);
485456
+ const relPath = relative16(cwd2, op.path);
485728
485457
  const displayPath2 = relPath.startsWith("..") ? op.path : relPath;
485729
485458
  const diffKey = toolCallId ? `${toolCallId}:${op.path}` : undefined;
485730
485459
  const opDiff = diffKey && allDiffs ? allDiffs.get(diffKey) : undefined;
@@ -500875,9 +500604,9 @@ __export(exports_generate_diff_viewer, {
500875
500604
  generateAndOpenDiffViewer: () => generateAndOpenDiffViewer
500876
500605
  });
500877
500606
  import { execFile as execFileCb8 } from "node:child_process";
500878
- import { chmodSync as chmodSync8, existsSync as existsSync72, mkdirSync as mkdirSync48, writeFileSync as writeFileSync38 } from "node:fs";
500607
+ import { chmodSync as chmodSync8, existsSync as existsSync71, mkdirSync as mkdirSync48, writeFileSync as writeFileSync38 } from "node:fs";
500879
500608
  import { homedir as homedir53 } from "node:os";
500880
- import { isAbsolute as isAbsolute32, join as join93, resolve as resolve43 } from "node:path";
500609
+ import { isAbsolute as isAbsolute31, join as join92, resolve as resolve41 } from "node:path";
500881
500610
  import { promisify as promisify19 } from "node:util";
500882
500611
  async function runGit8(cwd2, args) {
500883
500612
  try {
@@ -501075,7 +500804,7 @@ function escapeHtml3(value) {
501075
500804
  function resolveTargetPath(targetPath) {
501076
500805
  if (!targetPath?.trim())
501077
500806
  return process.cwd();
501078
- return isAbsolute32(targetPath) ? targetPath : resolve43(process.cwd(), targetPath);
500807
+ return isAbsolute31(targetPath) ? targetPath : resolve41(process.cwd(), targetPath);
501079
500808
  }
501080
500809
  function shouldSkipOpen() {
501081
500810
  return Boolean(process.env.TMUX) || Boolean(process.env.SSH_CONNECTION) || Boolean(process.env.SSH_TTY);
@@ -501096,13 +500825,13 @@ async function generateAndOpenDiffViewer(targetPath) {
501096
500825
  };
501097
500826
  const jsonPayload = JSON.stringify(payload).replace(/</g, "\\u003c");
501098
500827
  const html5 = diff_viewer_template_default.replace("<!--LETTA_DIFF_DATA_PLACEHOLDER-->", () => jsonPayload);
501099
- if (!existsSync72(VIEWERS_DIR2)) {
500828
+ if (!existsSync71(VIEWERS_DIR2)) {
501100
500829
  mkdirSync48(VIEWERS_DIR2, { recursive: true, mode: 448 });
501101
500830
  }
501102
500831
  try {
501103
500832
  chmodSync8(VIEWERS_DIR2, 448);
501104
500833
  } catch {}
501105
- const filePath = join93(VIEWERS_DIR2, `diff-${encodeURIComponent(worktreePath)}.html`);
500834
+ const filePath = join92(VIEWERS_DIR2, `diff-${encodeURIComponent(worktreePath)}.html`);
501106
500835
  writeFileSync38(filePath, html5);
501107
500836
  chmodSync8(filePath, 384);
501108
500837
  const skipOpen = shouldSkipOpen();
@@ -501173,7 +500902,7 @@ var init_generate_diff_viewer = __esm(() => {
501173
500902
  init_ssr();
501174
500903
  init_diff_viewer_template();
501175
500904
  execFile21 = promisify19(execFileCb8);
501176
- VIEWERS_DIR2 = join93(homedir53(), ".letta", "viewers");
500905
+ VIEWERS_DIR2 = join92(homedir53(), ".letta", "viewers");
501177
500906
  GIT_MAX_BUFFER = 50 * 1024 * 1024;
501178
500907
  });
501179
500908
 
@@ -503136,16 +502865,16 @@ __export(exports_shell_aliases, {
503136
502865
  expandAliases: () => expandAliases,
503137
502866
  clearAliasCache: () => clearAliasCache
503138
502867
  });
503139
- import { existsSync as existsSync73, readFileSync as readFileSync45 } from "node:fs";
502868
+ import { existsSync as existsSync72, readFileSync as readFileSync44 } from "node:fs";
503140
502869
  import { homedir as homedir54 } from "node:os";
503141
- import { join as join94 } from "node:path";
502870
+ import { join as join93 } from "node:path";
503142
502871
  function parseAliasesFromFile(filePath) {
503143
502872
  const aliases = new Map;
503144
- if (!existsSync73(filePath)) {
502873
+ if (!existsSync72(filePath)) {
503145
502874
  return aliases;
503146
502875
  }
503147
502876
  try {
503148
- const content = readFileSync45(filePath, "utf-8");
502877
+ const content = readFileSync44(filePath, "utf-8");
503149
502878
  const lines = content.split(`
503150
502879
  `);
503151
502880
  let inFunction = false;
@@ -503210,7 +502939,7 @@ function loadAliases(forceReload = false) {
503210
502939
  const home = homedir54();
503211
502940
  const allAliases = new Map;
503212
502941
  for (const file of ALIAS_FILES) {
503213
- const filePath = join94(home, file);
502942
+ const filePath = join93(home, file);
503214
502943
  const fileAliases = parseAliasesFromFile(filePath);
503215
502944
  for (const [name, value] of fileAliases) {
503216
502945
  allAliases.set(name, value);
@@ -504363,7 +504092,7 @@ var init_system_reminders = __esm(() => {
504363
504092
  // src/cli/app/use-conversation-loop.ts
504364
504093
  import { randomUUID as randomUUID41 } from "node:crypto";
504365
504094
  function sleep11(ms) {
504366
- return new Promise((resolve44) => setTimeout(resolve44, ms));
504095
+ return new Promise((resolve42) => setTimeout(resolve42, ms));
504367
504096
  }
504368
504097
  function makeExecutionPhaseHook(setExecutionPhase) {
504369
504098
  return ({ chunk: chunk2 }) => {
@@ -504819,7 +504548,7 @@ function useConversationLoop(ctx) {
504819
504548
  cancelled = true;
504820
504549
  break;
504821
504550
  }
504822
- await new Promise((resolve44) => setTimeout(resolve44, 100));
504551
+ await new Promise((resolve42) => setTimeout(resolve42, 100));
504823
504552
  }
504824
504553
  buffersRef.current.byId.delete(statusId);
504825
504554
  buffersRef.current.order = buffersRef.current.order.filter((id2) => id2 !== statusId);
@@ -504863,7 +504592,7 @@ function useConversationLoop(ctx) {
504863
504592
  cancelled = true;
504864
504593
  break;
504865
504594
  }
504866
- await new Promise((resolve44) => setTimeout(resolve44, 100));
504595
+ await new Promise((resolve42) => setTimeout(resolve42, 100));
504867
504596
  }
504868
504597
  if (retryStatusId) {
504869
504598
  buffersRef.current.byId.delete(retryStatusId);
@@ -505681,7 +505410,7 @@ ${feedback}
505681
505410
  });
505682
505411
  buffersRef.current.order.push(statusId);
505683
505412
  refreshDerived();
505684
- await new Promise((resolve44) => setTimeout(resolve44, delayMs));
505413
+ await new Promise((resolve42) => setTimeout(resolve42, delayMs));
505685
505414
  buffersRef.current.byId.delete(statusId);
505686
505415
  buffersRef.current.order = buffersRef.current.order.filter((id2) => id2 !== statusId);
505687
505416
  refreshDerived();
@@ -505721,7 +505450,7 @@ ${feedback}
505721
505450
  cancelled = true;
505722
505451
  break;
505723
505452
  }
505724
- await new Promise((resolve44) => setTimeout(resolve44, 100));
505453
+ await new Promise((resolve42) => setTimeout(resolve42, 100));
505725
505454
  }
505726
505455
  if (retryStatusId) {
505727
505456
  buffersRef.current.byId.delete(retryStatusId);
@@ -507467,7 +507196,7 @@ The deployment target for this project is CITATION-DOGFOOD-OK.
507467
507196
 
507468
507197
  // src/mods/learning-harness.ts
507469
507198
  import { spawn as spawn14 } from "node:child_process";
507470
- import { access as access4, copyFile as copyFile2, mkdir as mkdir20, readFile as readFile33, writeFile as writeFile22 } from "node:fs/promises";
507199
+ import { access as access3, copyFile as copyFile2, mkdir as mkdir19, readFile as readFile32, writeFile as writeFile21 } from "node:fs/promises";
507471
507200
  import path51 from "node:path";
507472
507201
  function slugify2(value) {
507473
507202
  const slug = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
@@ -507491,9 +507220,9 @@ function hasText(value) {
507491
507220
  return typeof value === "string" && value.trim().length > 0;
507492
507221
  }
507493
507222
  function markerChecks(markers, haystack) {
507494
- return (markers ?? []).map((marker) => ({
507495
- marker,
507496
- present: haystack.includes(marker)
507223
+ return (markers ?? []).map((marker2) => ({
507224
+ marker: marker2,
507225
+ present: haystack.includes(marker2)
507497
507226
  }));
507498
507227
  }
507499
507228
  function asStringArray(value) {
@@ -507705,7 +507434,7 @@ function safeJoin(root2, relativePath) {
507705
507434
  }
507706
507435
  async function fileExists(filePath) {
507707
507436
  try {
507708
- await access4(filePath);
507437
+ await access3(filePath);
507709
507438
  return true;
507710
507439
  } catch {
507711
507440
  return false;
@@ -507715,22 +507444,22 @@ async function existingPath(filePath) {
507715
507444
  return await fileExists(filePath) ? filePath : undefined;
507716
507445
  }
507717
507446
  async function writeJsonArtifact(filePath, value) {
507718
- await writeFile22(filePath, `${JSON.stringify(value, null, 2)}
507447
+ await writeFile21(filePath, `${JSON.stringify(value, null, 2)}
507719
507448
  `, "utf8");
507720
507449
  }
507721
507450
  async function writeCommandArtifacts(prefix, command, args, result2) {
507722
- await writeFile22(`${prefix}.command.txt`, `${renderCommand(command, args)}
507451
+ await writeFile21(`${prefix}.command.txt`, `${renderCommand(command, args)}
507723
507452
  `, "utf8");
507724
- await writeFile22(`${prefix}.stdout`, result2.stdout, "utf8");
507725
- await writeFile22(`${prefix}.stderr`, result2.stderr, "utf8");
507453
+ await writeFile21(`${prefix}.stdout`, result2.stdout, "utf8");
507454
+ await writeFile21(`${prefix}.stderr`, result2.stderr, "utf8");
507726
507455
  await writeJsonArtifact(`${prefix}.result.json`, result2);
507727
507456
  }
507728
507457
  async function prepareMemoryFiles(memoryDir, memoryFiles) {
507729
- await mkdir20(memoryDir, { recursive: true });
507458
+ await mkdir19(memoryDir, { recursive: true });
507730
507459
  for (const [relativePath, content] of Object.entries(memoryFiles ?? {})) {
507731
507460
  const filePath = safeJoin(memoryDir, relativePath);
507732
- await mkdir20(path51.dirname(filePath), { recursive: true });
507733
- await writeFile22(filePath, content, "utf8");
507461
+ await mkdir19(path51.dirname(filePath), { recursive: true });
507462
+ await writeFile21(filePath, content, "utf8");
507734
507463
  }
507735
507464
  }
507736
507465
  function renderEvaluationPrompt(prompt, memoryDir) {
@@ -508393,7 +508122,7 @@ function renderProposerGuide(params) {
508393
508122
  `;
508394
508123
  }
508395
508124
  async function writeHistoryArtifacts(params) {
508396
- await writeFile22(params.historyPath, renderHistoryIndex({
508125
+ await writeFile21(params.historyPath, renderHistoryIndex({
508397
508126
  attempts: params.attempts,
508398
508127
  historyManifestPath: params.historyManifestPath,
508399
508128
  proposerGuidePath: params.proposerGuidePath,
@@ -508401,11 +508130,11 @@ async function writeHistoryArtifacts(params) {
508401
508130
  spec: params.spec
508402
508131
  }), "utf8");
508403
508132
  await writeJsonArtifact(params.historyManifestPath, buildHistoryManifest(params));
508404
- await writeFile22(params.proposerGuidePath, renderProposerGuide(params), "utf8");
508133
+ await writeFile21(params.proposerGuidePath, renderProposerGuide(params), "utf8");
508405
508134
  }
508406
508135
  async function defaultCommandRunner(command, args, options) {
508407
508136
  const startedAt = Date.now();
508408
- return new Promise((resolve44) => {
508137
+ return new Promise((resolve42) => {
508409
508138
  const child = spawn14(command, args, {
508410
508139
  cwd: options.cwd,
508411
508140
  env: options.env,
@@ -508432,7 +508161,7 @@ async function defaultCommandRunner(command, args, options) {
508432
508161
  });
508433
508162
  child.on("close", (exitCode) => {
508434
508163
  clearTimeout(timeout);
508435
- resolve44({
508164
+ resolve42({
508436
508165
  args,
508437
508166
  command,
508438
508167
  cwd: options.cwd,
@@ -508492,7 +508221,7 @@ function createScenarioSuiteEvaluator(params) {
508492
508221
  outputFormat
508493
508222
  })
508494
508223
  ];
508495
- await writeFile22(hasConfiguredScenarios ? path51.join(scenarioDir, "prompt.md") : path51.join(context3.runDir, "eval-prompt.md"), evalPrompt, "utf8");
508224
+ await writeFile21(hasConfiguredScenarios ? path51.join(scenarioDir, "prompt.md") : path51.join(context3.runDir, "eval-prompt.md"), evalPrompt, "utf8");
508496
508225
  const scenarioEvalResult = await context3.runner(context3.cliCommand, evalArgs, {
508497
508226
  cwd: context3.repoRoot,
508498
508227
  env: {
@@ -508654,7 +508383,7 @@ async function runModLearningCandidate(params) {
508654
508383
  });
508655
508384
  };
508656
508385
  emitProgress("preparing", params.candidateCount > 1 ? `Preparing optimization iteration ${params.candidateIndex}/${params.candidateCount}` : "Preparing mod learning run");
508657
- await mkdir20(candidateDir, { recursive: true });
508386
+ await mkdir19(candidateDir, { recursive: true });
508658
508387
  await writeJsonArtifact(path51.join(runDir, "env.snapshot.json"), options.spec);
508659
508388
  let generationResult = null;
508660
508389
  if (options.candidateSourcePath) {
@@ -508684,7 +508413,7 @@ async function runModLearningCandidate(params) {
508684
508413
  outputFormat: "json"
508685
508414
  })
508686
508415
  ];
508687
- await writeFile22(path51.join(runDir, "generation-prompt.md"), generationPrompt, "utf8");
508416
+ await writeFile21(path51.join(runDir, "generation-prompt.md"), generationPrompt, "utf8");
508688
508417
  generationResult = await params.runner(params.cliCommand, generationArgs, {
508689
508418
  cwd: repoRoot,
508690
508419
  env: {
@@ -508741,7 +508470,7 @@ async function runModLearningCandidate(params) {
508741
508470
  if (passed && options.promoteToPath) {
508742
508471
  emitProgress("promoting", "Promoting passing candidate mod");
508743
508472
  promotedToPath = path51.resolve(repoRoot, options.promoteToPath);
508744
- await mkdir20(path51.dirname(promotedToPath), { recursive: true });
508473
+ await mkdir19(path51.dirname(promotedToPath), { recursive: true });
508745
508474
  await copyFile2(candidatePath, promotedToPath);
508746
508475
  }
508747
508476
  const reportPath = path51.join(runDir, "report.md");
@@ -508763,7 +508492,7 @@ async function runModLearningCandidate(params) {
508763
508492
  spec: options.spec
508764
508493
  };
508765
508494
  await writeJsonArtifact(path51.join(runDir, "report.json"), report);
508766
- await writeFile22(reportPath, renderMarkdownReport(report), "utf8");
508495
+ await writeFile21(reportPath, renderMarkdownReport(report), "utf8");
508767
508496
  await writeCandidateManifest(report);
508768
508497
  emitProgress("done", params.candidateCount > 1 ? `Optimization iteration ${params.candidateIndex}/${params.candidateCount} complete` : "mod optimization complete", {
508769
508498
  attempts: [...params.previousAttempts, summarizeAttempt(report)],
@@ -508792,7 +508521,7 @@ async function runModLearning(options) {
508792
508521
  const cliCommand = normalizedOptions.cliCommand ?? "bun";
508793
508522
  const cliArgsPrefix = normalizedOptions.cliArgsPrefix ?? ["run", "dev"];
508794
508523
  const baseEnv = normalizedOptions.env ?? process.env;
508795
- await mkdir20(runDir, { recursive: true });
508524
+ await mkdir19(runDir, { recursive: true });
508796
508525
  await writeJsonArtifact(path51.join(runDir, "env.snapshot.json"), normalizedOptions.spec);
508797
508526
  if (candidateCount === 1) {
508798
508527
  const report2 = await runModLearningCandidate({
@@ -508903,7 +508632,7 @@ async function runModLearning(options) {
508903
508632
  selectedCandidateIndex
508904
508633
  });
508905
508634
  promotedToPath = path51.resolve(repoRoot, normalizedOptions.promoteToPath);
508906
- await mkdir20(path51.dirname(promotedToPath), { recursive: true });
508635
+ await mkdir19(path51.dirname(promotedToPath), { recursive: true });
508907
508636
  await copyFile2(selectedReport.candidatePath, promotedToPath);
508908
508637
  }
508909
508638
  const reportPath = path51.join(runDir, "report.md");
@@ -508941,7 +508670,7 @@ async function runModLearning(options) {
508941
508670
  spec: normalizedOptions.spec
508942
508671
  });
508943
508672
  await writeJsonArtifact(path51.join(runDir, "report.json"), report);
508944
- await writeFile22(reportPath, renderMarkdownReport(report), "utf8");
508673
+ await writeFile21(reportPath, renderMarkdownReport(report), "utf8");
508945
508674
  normalizedOptions.onProgress?.({
508946
508675
  candidateCount,
508947
508676
  candidateIndex: selectedCandidateIndex,
@@ -508959,7 +508688,7 @@ async function runModLearning(options) {
508959
508688
  return report;
508960
508689
  }
508961
508690
  async function readModLearningEnv(envPath) {
508962
- return JSON.parse(await readFile33(envPath, "utf8"));
508691
+ return JSON.parse(await readFile32(envPath, "utf8"));
508963
508692
  }
508964
508693
  var init_learning_harness = __esm(async () => {
508965
508694
  await init_mod_engine();
@@ -509669,8 +509398,6 @@ var init_command_routing = __esm(() => {
509669
509398
  "/search",
509670
509399
  "/memory",
509671
509400
  "/feedback",
509672
- "/export",
509673
- "/download",
509674
509401
  "/mods",
509675
509402
  "/reasoning-tab",
509676
509403
  "/secret",
@@ -511199,7 +510926,7 @@ __export(exports_worktree_diff_list, {
511199
510926
  listWorktreeDiffOptions: () => listWorktreeDiffOptions
511200
510927
  });
511201
510928
  import { execFile as execFileCb9 } from "node:child_process";
511202
- import { basename as basename31 } from "node:path";
510929
+ import { basename as basename30 } from "node:path";
511203
510930
  import { promisify as promisify20 } from "node:util";
511204
510931
  async function runGit9(cwd2, args) {
511205
510932
  try {
@@ -511248,7 +510975,7 @@ function parseWorktreeList(output, currentPath) {
511248
510975
  if (current?.path) {
511249
510976
  worktrees.push({
511250
510977
  path: current.path,
511251
- name: basename31(current.path),
510978
+ name: basename30(current.path),
511252
510979
  branch: current.branch ?? "detached",
511253
510980
  head: current.head ?? "",
511254
510981
  isCurrent: current.path === currentPath,
@@ -511274,7 +511001,7 @@ function parseWorktreeList(output, currentPath) {
511274
511001
  if (current?.path) {
511275
511002
  worktrees.push({
511276
511003
  path: current.path,
511277
- name: basename31(current.path),
511004
+ name: basename30(current.path),
511278
511005
  branch: current.branch ?? "detached",
511279
511006
  head: current.head ?? "",
511280
511007
  isCurrent: current.path === currentPath,
@@ -511338,107 +511065,6 @@ var init_worktree_diff_list = __esm(() => {
511338
511065
  GIT_MAX_BUFFER2 = 10 * 1024 * 1024;
511339
511066
  });
511340
511067
 
511341
- // src/agent/export.ts
511342
- var exports_export = {};
511343
- __export(exports_export, {
511344
- packageSkills: () => packageSkills
511345
- });
511346
- import { readdir as readdir17, readFile as readFile34 } from "node:fs/promises";
511347
- import { relative as relative17, resolve as resolve44 } from "node:path";
511348
- async function packageSkills(agentId, skillsDir) {
511349
- const skills = [];
511350
- const skillNames = new Set;
511351
- const dirsToCheck = skillsDir ? [skillsDir] : [
511352
- agentId && getAgentSkillsDir(agentId),
511353
- resolve44(process.cwd(), ".skills"),
511354
- resolve44(process.env.HOME || "~", ".letta", "skills")
511355
- ].filter((dir) => Boolean(dir));
511356
- for (const baseDir of dirsToCheck) {
511357
- try {
511358
- const entries = await readdir17(baseDir, { withFileTypes: true });
511359
- for (const entry of entries) {
511360
- if (!entry.isDirectory())
511361
- continue;
511362
- if (skillNames.has(entry.name))
511363
- continue;
511364
- const skillDir = resolve44(baseDir, entry.name);
511365
- const skillMdPath = resolve44(skillDir, "SKILL.md");
511366
- try {
511367
- await readFile34(skillMdPath, "utf-8");
511368
- } catch {
511369
- console.warn(`Skipping invalid skill ${entry.name}: missing SKILL.md`);
511370
- continue;
511371
- }
511372
- const sourceUrl = skillsDir ? null : await findSkillSourceUrl(entry.name);
511373
- const skill2 = { name: entry.name };
511374
- if (sourceUrl) {
511375
- skill2.source_url = sourceUrl;
511376
- } else {
511377
- skill2.files = await readSkillFiles(skillDir);
511378
- }
511379
- skills.push(skill2);
511380
- skillNames.add(entry.name);
511381
- }
511382
- } catch (error5) {
511383
- if (error5.code !== "ENOENT") {
511384
- throw error5;
511385
- }
511386
- }
511387
- }
511388
- return skills;
511389
- }
511390
- async function readSkillFiles(skillDir) {
511391
- const files = {};
511392
- async function walk3(dir) {
511393
- const entries = await readdir17(dir, { withFileTypes: true });
511394
- for (const entry of entries) {
511395
- const fullPath = resolve44(dir, entry.name);
511396
- if (entry.isDirectory()) {
511397
- await walk3(fullPath);
511398
- } else {
511399
- const content = await readFile34(fullPath, "utf-8");
511400
- const relativePath = relative17(skillDir, fullPath).replace(/\\/g, "/");
511401
- files[relativePath] = content;
511402
- }
511403
- }
511404
- }
511405
- await walk3(skillDir);
511406
- return files;
511407
- }
511408
- async function findSkillSourceUrl(skillName) {
511409
- for (const repoPath of SKILL_REPOS) {
511410
- if (!dirCache.has(repoPath)) {
511411
- dirCache.set(repoPath, await fetchGitHubDirs(repoPath));
511412
- }
511413
- if (dirCache.get(repoPath)?.has(skillName)) {
511414
- return `${repoPath}/${skillName}`;
511415
- }
511416
- }
511417
- return null;
511418
- }
511419
- async function fetchGitHubDirs(path53) {
511420
- const [owner, repo, branch, ...pathParts] = path53.split("/");
511421
- if (!owner || !repo || !branch)
511422
- return new Set;
511423
- try {
511424
- const { fetchGitHubContents: fetchGitHubContents2, parseDirNames: parseDirNames2 } = await Promise.resolve().then(() => exports_github_utils);
511425
- const entries = await fetchGitHubContents2(owner, repo, branch, pathParts.join("/"));
511426
- return parseDirNames2(entries);
511427
- } catch {
511428
- return new Set;
511429
- }
511430
- }
511431
- var SKILL_REPOS, dirCache;
511432
- var init_export2 = __esm(() => {
511433
- init_skills5();
511434
- SKILL_REPOS = [
511435
- "letta-ai/skills/main/tools",
511436
- "letta-ai/skills/main/letta",
511437
- "anthropics/skills/main/skills"
511438
- ];
511439
- dirCache = new Map;
511440
- });
511441
-
511442
511068
  // src/cli/helpers/conversation-switch-alert.ts
511443
511069
  var exports_conversation_switch_alert = {};
511444
511070
  __export(exports_conversation_switch_alert, {
@@ -511532,9 +511158,9 @@ var init_conversation_switch_alert = __esm(() => {
511532
511158
 
511533
511159
  // src/cli/app/use-submit-handler.ts
511534
511160
  import { randomUUID as randomUUID43 } from "node:crypto";
511535
- import { existsSync as existsSync74, readFileSync as readFileSync46, renameSync as renameSync8, writeFileSync as writeFileSync39 } from "node:fs";
511161
+ import { existsSync as existsSync73, readFileSync as readFileSync45, renameSync as renameSync8 } from "node:fs";
511536
511162
  import { tmpdir as tmpdir13 } from "node:os";
511537
- import { join as join95 } from "node:path";
511163
+ import { join as join94 } from "node:path";
511538
511164
  async function findCustomCommandByName(commandName) {
511539
511165
  const { findCustomCommand: findCustomCommand2 } = await Promise.resolve().then(() => (init_custom(), exports_custom));
511540
511166
  return findCustomCommand2(commandName);
@@ -512234,12 +511860,12 @@ ${SYSTEM_REMINDER_CLOSE}`),
512234
511860
  try {
512235
511861
  const memoryRoot = getScopedMemoryFilesystemRoot(agentId);
512236
511862
  const personaCandidates = [
512237
- join95(memoryRoot, "system", "persona.md"),
512238
- join95(memoryRoot, "memory", "system", "persona.md")
511863
+ join94(memoryRoot, "system", "persona.md"),
511864
+ join94(memoryRoot, "memory", "system", "persona.md")
512239
511865
  ];
512240
- const personaPath = personaCandidates.find((candidate) => existsSync74(candidate));
511866
+ const personaPath = personaCandidates.find((candidate) => existsSync73(candidate));
512241
511867
  if (personaPath) {
512242
- const personaContent = readFileSync46(personaPath, "utf-8");
511868
+ const personaContent = readFileSync45(personaPath, "utf-8");
512243
511869
  setCurrentPersonalityId(detectPersonalityFromPersonaFile(personaContent));
512244
511870
  } else {
512245
511871
  setCurrentPersonalityId(null);
@@ -512991,42 +512617,6 @@ Tip: Use /clear instead to clear the current message buffer.`;
512991
512617
  cmd.finish(output, true);
512992
512618
  return { submitted: true };
512993
512619
  }
512994
- if (msg.trim() === "/export" || msg.trim() === "/download") {
512995
- const cmd = commandRunner.start(msg.trim(), "Exporting agent file...");
512996
- if (!getBackend().capabilities.agentFileImportExport) {
512997
- cmd.fail("AgentFile export is not supported by the local backend yet.");
512998
- return { submitted: true };
512999
- }
513000
- setCommandRunning(true);
513001
- try {
513002
- const client = await getClient();
513003
- const exportParams = {};
513004
- if (conversationId !== "default" && conversationId !== agentId) {
513005
- exportParams.conversation_id = conversationId;
513006
- }
513007
- const { packageSkills: packageSkills2 } = await Promise.resolve().then(() => (init_export2(), exports_export));
513008
- const skills = await packageSkills2(agentId);
513009
- const baseContent = await client.agents.exportFile(agentId, exportParams);
513010
- const fileContent = typeof baseContent === "string" ? JSON.parse(baseContent) : baseContent;
513011
- if (skills.length > 0) {
513012
- fileContent.skills = skills;
513013
- }
513014
- const fileName = exportParams.conversation_id ? `${exportParams.conversation_id}.af` : `${agentId}.af`;
513015
- writeFileSync39(fileName, JSON.stringify(fileContent, null, 2));
513016
- let summary = `AgentFile exported to ${fileName}`;
513017
- if (skills.length > 0) {
513018
- summary += `
513019
- \uD83D\uDCE6 Included ${skills.length} skill(s): ${skills.map((s3) => s3.name).join(", ")}`;
513020
- }
513021
- cmd.finish(summary, true);
513022
- } catch (error5) {
513023
- const errorDetails = formatErrorDetails2(error5, agentId);
513024
- cmd.fail(`Failed: ${errorDetails}`);
513025
- } finally {
513026
- setCommandRunning(false);
513027
- }
513028
- return { submitted: true };
513029
- }
513030
512620
  if (trimmed.startsWith("/memfs")) {
513031
512621
  const [, subcommand] = trimmed.split(/\s+/);
513032
512622
  const cmd = commandRunner.start(msg.trim(), "Processing memfs command...");
@@ -513119,11 +512709,11 @@ Path: ${memoryDir}`, true);
513119
512709
  setCommandRunning(true);
513120
512710
  try {
513121
512711
  const memoryDir = getScopedMemoryFilesystemRoot(agentId);
513122
- if (!existsSync74(memoryDir)) {
512712
+ if (!existsSync73(memoryDir)) {
513123
512713
  updateMemorySyncCommand(cmdId, "No local memory filesystem found to reset.", true, msg);
513124
512714
  return { submitted: true };
513125
512715
  }
513126
- const backupDir = join95(tmpdir13(), `letta-memfs-reset-${agentId}-${Date.now()}`);
512716
+ const backupDir = join94(tmpdir13(), `letta-memfs-reset-${agentId}-${Date.now()}`);
513127
512717
  renameSync8(memoryDir, backupDir);
513128
512718
  if (getBackend().capabilities.localMemfs) {
513129
512719
  const { initializeLocalMemoryRepo: initializeLocalMemoryRepo2 } = await Promise.resolve().then(() => (init_memory_git(), exports_memory_git));
@@ -514079,7 +513669,7 @@ var init_use_submit_handler = __esm(async () => {
514079
513669
  });
514080
513670
 
514081
513671
  // src/cli/app/AppCoordinator.tsx
514082
- import { join as join96 } from "node:path";
513672
+ import { join as join95 } from "node:path";
514083
513673
  function buildStartupCommandHints(options) {
514084
513674
  const {
514085
513675
  isResumingConversation,
@@ -515366,7 +514956,7 @@ function App2({
515366
514956
  agentId: a2.agentId ?? null
515367
514957
  }))
515368
514958
  });
515369
- const agentModsDirectory = modContext.memfs.enabled && modContext.memfs.memoryDir ? join96(modContext.memfs.memoryDir, "mods") : null;
514959
+ const agentModsDirectory = modContext.memfs.enabled && modContext.memfs.memoryDir ? join95(modContext.memfs.memoryDir, "mods") : null;
515370
514960
  const modAdapter = useLocalModAdapter(modContext, {
515371
514961
  agentModsDirectory,
515372
514962
  disabled: modsDisabled,
@@ -516137,9 +515727,9 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
516137
515727
  (async () => {
516138
515728
  try {
516139
515729
  const { watch: watch4 } = await import("node:fs");
516140
- const { existsSync: existsSync75 } = await import("node:fs");
515730
+ const { existsSync: existsSync74 } = await import("node:fs");
516141
515731
  const memRoot = getScopedMemoryFilesystemRoot(agentId);
516142
- if (!existsSync75(memRoot))
515732
+ if (!existsSync74(memRoot))
516143
515733
  return;
516144
515734
  watcher2 = watch4(memRoot, { recursive: true }, () => {});
516145
515735
  memfsWatcherRef.current = watcher2;
@@ -517714,12 +517304,12 @@ EXAMPLES
517714
517304
  console.log(usage);
517715
517305
  }
517716
517306
  async function printInfo() {
517717
- const { join: join97 } = await import("node:path");
517307
+ const { join: join96 } = await import("node:path");
517718
517308
  const { getVersion: getVersion2 } = await Promise.resolve().then(() => (init_version(), exports_version));
517719
517309
  const { SKILLS_DIR: SKILLS_DIR2 } = await Promise.resolve().then(() => (init_skills5(), exports_skills2));
517720
517310
  const { exists: exists2 } = await Promise.resolve().then(() => (init_fs(), exports_fs));
517721
517311
  const cwd2 = process.cwd();
517722
- const skillsDir = join97(cwd2, SKILLS_DIR2);
517312
+ const skillsDir = join96(cwd2, SKILLS_DIR2);
517723
517313
  const skillsExist = exists2(skillsDir);
517724
517314
  await settingsManager.loadLocalProjectSettings(cwd2);
517725
517315
  const pinned = settingsManager.getPinnedAgents();
@@ -517769,18 +517359,6 @@ async function printInfo() {
517769
517359
  console.log("Pinned agents: (none)");
517770
517360
  }
517771
517361
  }
517772
- function getModelForToolLoading(specifiedModel, specifiedToolset) {
517773
- if (specifiedToolset === "codex") {
517774
- return "openai/gpt-4";
517775
- }
517776
- if (specifiedToolset === "gemini") {
517777
- return "google_ai/gemini-3.1-pro-preview";
517778
- }
517779
- if (specifiedToolset === "default") {
517780
- return "anthropic/claude-sonnet-4";
517781
- }
517782
- return specifiedModel;
517783
- }
517784
517362
  function getStartupTargetLookupOrderForCredentials({
517785
517363
  baseURL,
517786
517364
  explicitBackendMode,
@@ -518066,10 +517644,6 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
518066
517644
  process.exit(1);
518067
517645
  }
518068
517646
  })();
518069
- const fromAfFile = resolveImportFlagAlias({
518070
- importFlagValue: values4.import,
518071
- fromAfFlagValue: values4["from-af"]
518072
- });
518073
517647
  const isHeadless = isHeadlessStartup(values4, process.stdin.isTTY, command);
518074
517648
  const terminalThemePromise = !isHeadless ? initTerminalTheme().catch(() => {
518075
517649
  return;
@@ -518151,8 +517725,8 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
518151
517725
  console.error("Error: --personality can only be used with --new-agent");
518152
517726
  process.exit(1);
518153
517727
  }
518154
- if (specifiedToolset && specifiedToolset !== "codex" && specifiedToolset !== "default" && specifiedToolset !== "gemini" && specifiedToolset !== "auto") {
518155
- console.error(`Error: Invalid toolset "${specifiedToolset}". Must be "auto", "codex", "default", or "gemini".`);
517728
+ if (specifiedToolset && specifiedToolset !== "codex" && specifiedToolset !== "default" && specifiedToolset !== "gemini" && specifiedToolset !== "letta" && specifiedToolset !== "auto") {
517729
+ console.error(`Error: Invalid toolset "${specifiedToolset}". Must be "auto", "letta", "codex", "default", or "gemini".`);
518156
517730
  process.exit(1);
518157
517731
  }
518158
517732
  if (systemPromptPreset && systemCustom) {
@@ -518179,7 +517753,6 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
518179
517753
  specifiedAgentName,
518180
517754
  forceNewAgent: forceNew,
518181
517755
  forceNewConversation,
518182
- importFile: fromAfFile,
518183
517756
  shouldResume,
518184
517757
  stateless: values4.stateless,
518185
517758
  isHeadless,
@@ -518190,52 +517763,6 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
518190
517763
  console.error(error5 instanceof Error ? `Error: ${error5.message}` : String(error5));
518191
517764
  process.exit(1);
518192
517765
  }
518193
- let isRegistryImport = false;
518194
- if (fromAfFile) {
518195
- try {
518196
- validateFlagConflicts({
518197
- guard: fromAfFile,
518198
- checks: [
518199
- {
518200
- when: specifiedAgentId,
518201
- message: "--import cannot be used with --agent"
518202
- },
518203
- {
518204
- when: specifiedAgentName,
518205
- message: "--import cannot be used with --name"
518206
- },
518207
- {
518208
- when: shouldResume,
518209
- message: "--import cannot be used with --resume"
518210
- },
518211
- {
518212
- when: forceNew,
518213
- message: "--import cannot be used with --new-agent"
518214
- }
518215
- ]
518216
- });
518217
- } catch (error5) {
518218
- console.error(error5 instanceof Error ? `Error: ${error5.message}` : String(error5));
518219
- process.exit(1);
518220
- }
518221
- if (fromAfFile.startsWith("@")) {
518222
- isRegistryImport = true;
518223
- try {
518224
- validateRegistryHandleOrThrow(fromAfFile);
518225
- } catch {
518226
- console.error(`Error: Invalid registry handle "${fromAfFile}". Use format: letta --import @author/agentname`);
518227
- process.exit(1);
518228
- }
518229
- } else {
518230
- const { resolve: resolve45 } = await import("node:path");
518231
- const { existsSync: existsSync75 } = await import("node:fs");
518232
- const resolvedPath = resolve45(fromAfFile);
518233
- if (!existsSync75(resolvedPath)) {
518234
- console.error(`Error: AgentFile not found: ${resolvedPath}`);
518235
- process.exit(1);
518236
- }
518237
- }
518238
- }
518239
517766
  let nameResolvedAgent = null;
518240
517767
  if (specifiedAgentName) {
518241
517768
  if (specifiedAgentId) {
@@ -518417,8 +517944,11 @@ Error: ${message}`);
518417
517944
  }
518418
517945
  if (isHeadless) {
518419
517946
  markMilestone("HEADLESS_MODE_START");
518420
- const modelForTools = getModelForToolLoading(specifiedModel, specifiedToolset);
518421
- await loadTools(modelForTools, { exclude: ["AskUserQuestion"] });
517947
+ await loadStartupTools({
517948
+ modelIdentifier: specifiedModel,
517949
+ toolset: specifiedToolset,
517950
+ exclude: ["AskUserQuestion"]
517951
+ });
518422
517952
  markMilestone("TOOLS_LOADED");
518423
517953
  const headlessValues = specifiedAgentId && values4.agent !== specifiedAgentId ? { ...values4, agent: specifiedAgentId } : values4;
518424
517954
  const { handleHeadlessCommand: handleHeadlessCommand2 } = await init_headless().then(() => exports_headless);
@@ -518445,9 +517975,7 @@ Error: ${message}`);
518445
517975
  model,
518446
517976
  systemPromptPreset: systemPromptPreset2,
518447
517977
  toolset,
518448
- skillsDirectory: skillsDirectory2,
518449
- fromAfFile: fromAfFile2,
518450
- isRegistryImport: isRegistryImport2
517978
+ skillsDirectory: skillsDirectory2
518451
517979
  }) {
518452
517980
  const [showKeybindingSetup, setShowKeybindingSetup] = useState56(null);
518453
517981
  const [loadingState, setLoadingState] = useState56("selecting");
@@ -518635,8 +518163,8 @@ Error: ${message}`);
518635
518163
  console.error("Run 'letta' to get started.");
518636
518164
  process.exit(1);
518637
518165
  }
518638
- if (forceNew2 || agentIdArg || fromAfFile2) {
518639
- if (agentIdArg && !forceNew2 && !fromAfFile2 && !forceNewConversation) {
518166
+ if (forceNew2 || agentIdArg) {
518167
+ if (agentIdArg && !forceNew2 && !forceNewConversation) {
518640
518168
  await settingsManager.loadLocalProjectSettings(process.cwd());
518641
518169
  const localSession2 = settingsManager.getLocalLastSession(process.cwd());
518642
518170
  if (localSession2?.agentId === agentIdArg && localSession2.conversationId && localSession2.conversationId !== "default") {
@@ -518743,13 +518271,7 @@ Error: ${message}`);
518743
518271
  setLoadingState("assembling");
518744
518272
  }
518745
518273
  checkAndStart();
518746
- }, [
518747
- forceNew2,
518748
- agentIdArg,
518749
- fromAfFile2,
518750
- shouldResume,
518751
- specifiedConversationId
518752
- ]);
518274
+ }, [forceNew2, agentIdArg, shouldResume, specifiedConversationId]);
518753
518275
  const initStartedRef = React14.useRef(false);
518754
518276
  useEffect50(() => {
518755
518277
  if (loadingState !== "assembling") {
@@ -518820,48 +518342,11 @@ Error: ${message}`);
518820
518342
  }
518821
518343
  }
518822
518344
  setIsResumingSession(!!resumingAgentId);
518823
- const modelForTools = getModelForToolLoading(model, toolset);
518824
- await loadTools(modelForTools);
518345
+ await loadStartupTools({ modelIdentifier: model, toolset });
518825
518346
  setLoadingState("initializing");
518826
518347
  const { createAgent: createAgent2 } = await Promise.resolve().then(() => (init_create5(), exports_create));
518827
518348
  let agent = null;
518828
518349
  let autoEnableMemfsForFreshAgent = false;
518829
- if (fromAfFile2) {
518830
- setLoadingState("importing");
518831
- let result2;
518832
- if (isRegistryImport2) {
518833
- const { importAgentFromRegistry: importAgentFromRegistry2 } = await Promise.resolve().then(() => (init_import(), exports_import));
518834
- result2 = await importAgentFromRegistry2({
518835
- handle: fromAfFile2,
518836
- modelOverride: model,
518837
- stripMessages: true,
518838
- stripSkills: false
518839
- });
518840
- } else {
518841
- const { importAgentFromFile: importAgentFromFile2 } = await Promise.resolve().then(() => (init_import(), exports_import));
518842
- result2 = await importAgentFromFile2({
518843
- filePath: fromAfFile2,
518844
- modelOverride: model,
518845
- stripMessages: true,
518846
- stripSkills: false
518847
- });
518848
- }
518849
- agent = result2.agent;
518850
- setAgentProvenance({
518851
- isNew: true,
518852
- blocks: []
518853
- });
518854
- if (settingsManager.isReady) {
518855
- settingsManager.setSystemPromptCustom(agent.id);
518856
- }
518857
- if (result2.skills && result2.skills.length > 0) {
518858
- const { getAgentSkillsDir: getAgentSkillsDir2 } = await Promise.resolve().then(() => (init_skills5(), exports_skills2));
518859
- const skillsDir = getAgentSkillsDir2(agent.id);
518860
- console.log(`
518861
- \uD83D\uDCE6 Extracted ${result2.skills.length} skill${result2.skills.length === 1 ? "" : "s"} to ${skillsDir}: ${result2.skills.join(", ")}
518862
- `);
518863
- }
518864
- }
518865
518350
  if (!agent && agentIdArg) {
518866
518351
  try {
518867
518352
  agent = await backend3.retrieveAgent(agentIdArg, {
@@ -518969,7 +518454,7 @@ Error: ${message}`);
518969
518454
  if (!shouldBlockOnMemfsStartup) {}
518970
518455
  const secretsInitPromise = Promise.resolve().then(() => (init_secrets_store(), exports_secrets_store)).then(({ initSecretsFromServer: initSecretsFromServer2 }) => initSecretsFromServer2(agentId2));
518971
518456
  const isResumingProject = !shouldCreateNew && !!resumingAgentId;
518972
- const isReusingExistingAgent = !shouldCreateNew && !fromAfFile2 && agent && agent.id;
518457
+ const isReusingExistingAgent = !shouldCreateNew && agent && agent.id;
518973
518458
  const resuming = !!(agentIdArg || isResumingProject || isReusingExistingAgent);
518974
518459
  setIsResumingSession(resuming);
518975
518460
  if (resuming) {
@@ -519129,7 +518614,6 @@ Error during initialization: ${message}`);
519129
518614
  agentIdArg,
519130
518615
  model,
519131
518616
  systemPromptPreset2,
519132
- fromAfFile2,
519133
518617
  loadingState,
519134
518618
  selectedGlobalAgentId,
519135
518619
  validatedAgent,
@@ -519253,15 +518737,14 @@ Error during initialization: ${message}`);
519253
518737
  model: specifiedModel,
519254
518738
  systemPromptPreset,
519255
518739
  toolset: specifiedToolset,
519256
- skillsDirectory,
519257
- fromAfFile,
519258
- isRegistryImport
518740
+ skillsDirectory
519259
518741
  }), {
519260
518742
  exitOnCtrlC: false
519261
518743
  });
519262
518744
  }
519263
518745
  var EMPTY_APPROVAL_ARRAY, EMPTY_MESSAGE_ARRAY;
519264
518746
  var init_src5 = __esm(async () => {
518747
+ init_startup_log_boundary();
519265
518748
  init_error();
519266
518749
  init_telemetry();
519267
518750
  init_error_reporting();
@@ -519293,7 +518776,7 @@ var init_src5 = __esm(async () => {
519293
518776
  init_ConversationSelector(),
519294
518777
  init_profile_selection(),
519295
518778
  init_router(),
519296
- init_manager4(),
518779
+ init_letta_toolset(),
519297
518780
  init_toolset()
519298
518781
  ]);
519299
518782
  EMPTY_APPROVAL_ARRAY = [];
@@ -519301,6 +518784,9 @@ var init_src5 = __esm(async () => {
519301
518784
  assertSupportedBunRuntime();
519302
518785
  main2();
519303
518786
  });
518787
+
518788
+ // src/standalone-entry.ts
518789
+ init_startup_log_boundary();
519304
518790
  // node_modules/@earendil-works/pi-ai/dist/auth/oauth/oauth-page.js
519305
518791
  var LOGO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800" aria-hidden="true"><path fill="#fff" fill-rule="evenodd" d="M165.29 165.29 H517.36 V400 H400 V517.36 H282.65 V634.72 H165.29 Z M282.65 282.65 V400 H400 V282.65 Z"/><path fill="#fff" d="M517.36 400 H634.72 V634.72 H517.36 Z"/></svg>`;
519306
518792
  function escapeHtml(value) {
@@ -521496,4 +520982,4 @@ function registerBunOAuthFlows() {
521496
520982
  registerBunOAuthFlows();
521497
520983
  await init_src5().then(() => exports_src2);
521498
520984
 
521499
- //# debugId=875FFD1EA43A424B64756E2164756E21
520985
+ //# debugId=95B2BCB7592A39B564756E2164756E21