@letta-ai/letta-code 0.21.9 → 0.21.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/letta.js +725 -189
- package/package.json +1 -1
- package/skills/context_doctor/SKILL.md +11 -11
- package/skills/dispatching-coding-agents/SKILL.md +1 -1
- package/skills/initializing-memory/SKILL.md +563 -98
- package/skills/syncing-memory-filesystem/SKILL.md +1 -2
- package/skills/migrating-from-codex-and-claude-code/SKILL.md +0 -162
- package/skills/migrating-from-codex-and-claude-code/references/claude-format.md +0 -212
- package/skills/migrating-from-codex-and-claude-code/references/codex-format.md +0 -229
- /package/skills/{migrating-from-codex-and-claude-code/scripts/detect.sh → initializing-memory/scripts/detect-history.sh} +0 -0
- /package/skills/{migrating-from-codex-and-claude-code → initializing-memory}/scripts/list-sessions.sh +0 -0
- /package/skills/{migrating-from-codex-and-claude-code/scripts/search.sh → initializing-memory/scripts/search-history.sh} +0 -0
- /package/skills/{migrating-from-codex-and-claude-code → initializing-memory}/scripts/view-session.sh +0 -0
package/letta.js
CHANGED
|
@@ -3269,7 +3269,7 @@ var package_default;
|
|
|
3269
3269
|
var init_package = __esm(() => {
|
|
3270
3270
|
package_default = {
|
|
3271
3271
|
name: "@letta-ai/letta-code",
|
|
3272
|
-
version: "0.21.
|
|
3272
|
+
version: "0.21.11",
|
|
3273
3273
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
3274
3274
|
type: "module",
|
|
3275
3275
|
bin: {
|
|
@@ -3535,6 +3535,7 @@ var init_secrets = __esm(async () => {
|
|
|
3535
3535
|
// src/settings-manager.ts
|
|
3536
3536
|
var exports_settings_manager = {};
|
|
3537
3537
|
__export(exports_settings_manager, {
|
|
3538
|
+
shouldPersistSessionState: () => shouldPersistSessionState,
|
|
3538
3539
|
settingsManager: () => settingsManager
|
|
3539
3540
|
});
|
|
3540
3541
|
import { randomUUID } from "node:crypto";
|
|
@@ -3543,6 +3544,9 @@ import { join as join2, resolve } from "node:path";
|
|
|
3543
3544
|
function isSubagentProcess() {
|
|
3544
3545
|
return process.env.LETTA_CODE_AGENT_ROLE === "subagent";
|
|
3545
3546
|
}
|
|
3547
|
+
function shouldPersistSessionState() {
|
|
3548
|
+
return process.env.LETTA_CODE_AGENT_ROLE !== "subagent" && process.env.LETTA_DISABLE_SESSION_PERSIST !== "1";
|
|
3549
|
+
}
|
|
3546
3550
|
function normalizeBaseUrl(baseUrl) {
|
|
3547
3551
|
let normalized = baseUrl.replace(/^https?:\/\//, "");
|
|
3548
3552
|
normalized = normalized.replace(/\/$/, "");
|
|
@@ -5484,7 +5488,6 @@ var init_memory_check_reminder = () => {};
|
|
|
5484
5488
|
var memory_filesystem_default = `---
|
|
5485
5489
|
label: memory_filesystem
|
|
5486
5490
|
description: Filesystem view of memory blocks (system + user)
|
|
5487
|
-
limit: 8000
|
|
5488
5491
|
---
|
|
5489
5492
|
|
|
5490
5493
|
/memory/
|
|
@@ -6577,7 +6580,7 @@ When applying memory in responses, integrate it naturally — like a colleague w
|
|
|
6577
6580
|
var init_system_prompt_blocks = () => {};
|
|
6578
6581
|
|
|
6579
6582
|
// src/agent/prompts/system_prompt_memfs.md
|
|
6580
|
-
var system_prompt_memfs_default = "# Memory\n\nYour memory is
|
|
6583
|
+
var system_prompt_memfs_default = "# Memory\n\nYour memory is projected onto the local memory filesystem (MemFS) at `$MEMORY_DIR` (usually `~/.letta/agents/$AGENT_ID/memory/`), including your memory blocks (in-context in the system prompt) and external memory. This projection makes it easy for you to modify your own context with filesystem operations which also include git tracking. Local changes are only propagated to your actual state on a successful push to remote, and the system prompt is only recompiled on compactions or new conversations (so may be stale). \n\n## Memory structure\nYou are responsible to maintaining a clear memory structure. All memory files are markdown with YAML frontmatter (`description`, optional `metadata`).\n\n**In-context memory** (`system/`): Memory files in `system/` correspond to memory blocks, which are pinned directly into your system prompt — visible at all times. This is your most valuable real estate: reserve it for durable knowledge that helps across sessions (user identity, persona, project architecture, conventions, gotchas). Do NOT store transient items here like specific commits, current work items, or session-specific notes — those dilute the signal.\n\n**External memory**: Files outside `system/` follow progressive disclosure — an index of files and descriptions is kept in the system prompt, but full contents must be retrieved on demand (e.g. by reading the file). Skills are a special type of external memory stored in the `skills/` folder. Use `[[path]]` to index files from memory blocks, or create discovery paths between related context (e.g. `[[reference/project/architecture.md]]` or `[[skills/using-slack/SKILL.md]]`).\n\n**Recall** (conversation history): Your full message history is searchable even after messages leave your context window. Use the recall subagent to retrieve past discussions, decisions, and context from earlier sessions.\n\n## Syncing\n\nChanges you commit and push sync to the Letta server within seconds, and server-side changes sync back automatically.\n\n```bash\ncd \"$MEMORY_DIR\"\n\n# See what changed\ngit status\n\n# Commit and push your changes\ngit add .\ngit commit --author=\"$AGENT_NAME <$AGENT_ID@letta.com>\" -m \"<type>: <what changed>\" # e.g. \"fix: update user prefs\", \"refactor: reorganize persona blocks\"\ngit push\n\n# Get latest from server\ngit pull\n```\nThe system will remind you when your memory has uncommitted changes. Sync when convenient.\n\n## History\n```bash\ngit -C \"$MEMORY_DIR\" log --oneline\n```\n";
|
|
6581
6584
|
var init_system_prompt_memfs = () => {};
|
|
6582
6585
|
|
|
6583
6586
|
// src/utils/error.ts
|
|
@@ -6708,12 +6711,6 @@ async function loadMemoryBlocksFromMdx() {
|
|
|
6708
6711
|
if (frontmatter.description) {
|
|
6709
6712
|
block.description = frontmatter.description;
|
|
6710
6713
|
}
|
|
6711
|
-
if (frontmatter.limit) {
|
|
6712
|
-
const limit2 = parseInt(frontmatter.limit, 10);
|
|
6713
|
-
if (!Number.isNaN(limit2) && limit2 > 0) {
|
|
6714
|
-
block.limit = limit2;
|
|
6715
|
-
}
|
|
6716
|
-
}
|
|
6717
6714
|
if (READ_ONLY_BLOCK_LABELS.includes(label)) {
|
|
6718
6715
|
block.read_only = true;
|
|
6719
6716
|
}
|
|
@@ -6840,7 +6837,7 @@ var history_analyzer_default = `---
|
|
|
6840
6837
|
name: history-analyzer
|
|
6841
6838
|
description: Analyze Claude Code or Codex conversation history and directly update agent memory files with insights
|
|
6842
6839
|
tools: Read, Write, Bash, Glob, Grep
|
|
6843
|
-
skills:
|
|
6840
|
+
skills:
|
|
6844
6841
|
model: auto
|
|
6845
6842
|
memoryBlocks: none
|
|
6846
6843
|
mode: stateless
|
|
@@ -6858,19 +6855,64 @@ Your memory files form the parent agent's identity and knowledge. Follow these p
|
|
|
6858
6855
|
- **Generalize, don't memorize**: Distill patterns from repeated observations. "Always use uv, never pip (corrected 10+ times)" is valuable; a single offhand mention is not. Look for signal through repetition.
|
|
6859
6856
|
- **System/ is the core program**: Only durable, generalizable knowledge belongs in \`system/\`. Distilled preferences, behavioral rules, project gotchas, conventions enforced through corrections. Evidence trails, raw session summaries, and verbose context go outside \`system/\`.
|
|
6860
6857
|
- **Progressive disclosure**: Frontmatter descriptions should let the agent decide whether to load a file without reading it. Summaries and principles in \`system/\`; detail and evidence outside it, linked with \`[[path]]\`.
|
|
6861
|
-
- **Identity continuity**:
|
|
6858
|
+
- **Identity continuity**: This history IS the agent's past. These are memories of working with this user — you're reconstructing lived experience, not analyzing external data. Write findings as learned knowledge ("I've seen Sarah correct this 10+ times"), not research summaries ("The user appears to prefer...").
|
|
6862
6859
|
- **Preserve and connect**: If a memory file already has good content, extend it — don't replace it. Use \`[[path]]\` links to connect new findings to existing memory.
|
|
6860
|
+
- **Promote findings into canonical memory**: Don't leave durable insights trapped in generic ingestion files if they can be promoted into focused memory like \`system/human/identity.md\`, \`system/human/prefs/workflow.md\`, or \`system/<project>/gotchas.md\`.
|
|
6863
6861
|
|
|
6864
6862
|
## Goal
|
|
6865
6863
|
|
|
6866
|
-
Distill actionable knowledge from conversation history into well-organized memory.
|
|
6864
|
+
Distill actionable knowledge from conversation history into well-organized memory. You MUST produce findings in all three categories below — missing any category is a failure.
|
|
6865
|
+
|
|
6866
|
+
This is not a request for a thin recap. Your output should be detailed enough that the parent agent can use it in future sessions without rereading the history chunk.
|
|
6867
|
+
|
|
6868
|
+
### Required Output Categories
|
|
6869
|
+
|
|
6870
|
+
You MUST extract and document all three:
|
|
6871
|
+
|
|
6872
|
+
**1. User Personality & Identity** (REQUIRED)
|
|
6873
|
+
- How would you describe them as a person? (e.g., "pragmatic builder who values shipping over perfection")
|
|
6874
|
+
- What drives them? What are their goals? (e.g., "building tools that reduce friction for developers")
|
|
6875
|
+
- Communication style beyond just "direct" — do they joke? Use sarcasm? Have catchphrases?
|
|
6876
|
+
- Quirks, linguistic patterns, unique attributes
|
|
6877
|
+
- Pattern-match to common personas if applicable (e.g., "scrappy startup engineer", "meticulous architect")
|
|
6878
|
+
|
|
6879
|
+
**2. Hard Rules & Preferences** (REQUIRED)
|
|
6880
|
+
- Coding preferences with enforcement evidence (e.g., "Use uv — corrected 10+ times")
|
|
6881
|
+
- Workflow patterns (testing habits, commit style, tool choices)
|
|
6882
|
+
- What frustrates them and why
|
|
6883
|
+
- Explicit "always/never" statements
|
|
6884
|
+
|
|
6885
|
+
**3. Project Context** (REQUIRED)
|
|
6886
|
+
- Codebase structures, conventions, patterns
|
|
6887
|
+
- Gotchas discovered through debugging
|
|
6888
|
+
- Which files are safe to edit vs deprecated
|
|
6889
|
+
- Environment quirks
|
|
6890
|
+
|
|
6891
|
+
If you cannot extract meaningful findings for ANY category, explicitly state why (e.g., "Insufficient data for personality analysis — only 5 prompts, all about a single bug fix").
|
|
6892
|
+
|
|
6893
|
+
### Quality Bar
|
|
6894
|
+
|
|
6895
|
+
When sufficient data exists, aim to extract at least:
|
|
6896
|
+
- **5+ durable findings** for user personality / identity
|
|
6897
|
+
- **8+ durable findings** for hard rules / preferences
|
|
6898
|
+
- **8+ durable findings** for project context
|
|
6899
|
+
|
|
6900
|
+
If you produce materially fewer findings in a category, explain why the chunk truly lacked signal.
|
|
6901
|
+
|
|
6902
|
+
Avoid low-value summaries like:
|
|
6903
|
+
- "User is direct"
|
|
6904
|
+
- "Project uses TypeScript"
|
|
6905
|
+
- "Uses conventional commits"
|
|
6906
|
+
|
|
6907
|
+
These are insufficient unless paired with concrete operational detail, enforcement patterns, or repo-specific implications.
|
|
6908
|
+
|
|
6909
|
+
### What NOT to Store
|
|
6910
|
+
One-off events, session-by-session summaries, anything that can be retrieved from conversation history on demand.
|
|
6867
6911
|
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
- **Working patterns**: How the user works — debugging style, testing habits, tools they reach for, communication style.
|
|
6871
|
-
- **Conventions actually used**: Not just what's in a README, but what's enforced through practice.
|
|
6912
|
+
### What TO Preserve
|
|
6913
|
+
Focus on understanding **why** the user reacted the way they did — what mistake or behavior triggered the correction? The pattern matters more than the quote. For example, don't just record "user said stop adding stuff" — record that the agent was over-engineering by adding abstractions when a simple flag change was needed. Quotes can serve as supporting evidence, but the real value is the behavioral pattern and what to do differently.
|
|
6872
6914
|
|
|
6873
|
-
|
|
6915
|
+
Keep specific correction counts ("corrected 10+ times"), specific file paths, and specific gotchas with context. Specificity is identity; vague summaries are forgettable.
|
|
6874
6916
|
|
|
6875
6917
|
## Workflow
|
|
6876
6918
|
|
|
@@ -6888,12 +6930,29 @@ git worktree add "$WORKTREE_DIR/$BRANCH_NAME" -b "$BRANCH_NAME"
|
|
|
6888
6930
|
If worktree creation fails (locked index), retry up to 3 times with backoff (sleep 2, 5, 10). Never delete \`.git/index.lock\` manually. All edits go in \`$WORKTREE_DIR/$BRANCH_NAME/\`.
|
|
6889
6931
|
|
|
6890
6932
|
### 2. Read existing memory
|
|
6891
|
-
|
|
6892
|
-
Read all files in your worktree's \`system/\` directory. Understand what's already there so you can extend it, not duplicate it.
|
|
6933
|
+
Read the memory files in your worktree, to understand what already exists in the memory filesystem.
|
|
6893
6934
|
|
|
6894
6935
|
### 3. Read and analyze history
|
|
6895
6936
|
|
|
6896
|
-
|
|
6937
|
+
Your prompt will specify a pre-split JSONL chunk file and its source format. Use these patterns to read it:
|
|
6938
|
+
|
|
6939
|
+
**Claude Code** (\`~/.claude/\`):
|
|
6940
|
+
- \`history.jsonl\` — each line: \`.display\` (prompt text), \`.timestamp\` (unix ms), \`.project\` (working dir), \`.sessionId\`
|
|
6941
|
+
- Session files at \`~/.claude/projects/<encoded-path>/<session-uuid>.jsonl\` (path encoding: \`/\` → \`-\`)
|
|
6942
|
+
- User messages: \`jq 'select(.type == "user") | .message.content'\`
|
|
6943
|
+
- Assistant text: \`jq 'select(.type == "assistant") | .message.content[] | select(.type == "text") | .text'\`
|
|
6944
|
+
- Tool calls: \`jq 'select(.type == "assistant") | .message.content[] | select(.type == "tool_use") | {name, input}'\`
|
|
6945
|
+
- Summaries: \`jq 'select(.type == "summary") | .summary'\`
|
|
6946
|
+
|
|
6947
|
+
**OpenAI Codex** (\`~/.codex/\`):
|
|
6948
|
+
- \`history.jsonl\` — each line: \`.text\` (prompt text), \`.ts\` (unix seconds) — no project path
|
|
6949
|
+
- Session files at \`~/.codex/sessions/<year>/<month>/<day>/rollout-*.jsonl\`
|
|
6950
|
+
- Session metadata (first line): \`jq 'select(.type == "session_meta") | .payload.cwd'\` (to get project dir)
|
|
6951
|
+
- User messages: \`jq 'select(.type == "event_msg" and .payload.type == "user_message") | .payload.message'\`
|
|
6952
|
+
- Assistant text: \`jq 'select(.type == "response_item" and .payload.type == "message") | .payload.content[] | select(.type == "output_text") | .text'\`
|
|
6953
|
+
- Tool calls: \`jq 'select(.type == "response_item" and .payload.type == "function_call") | {name: .payload.name, args: .payload.arguments}'\`
|
|
6954
|
+
|
|
6955
|
+
**Key format difference**: Claude uses \`.timestamp\` (milliseconds) and \`.display\`; Codex uses \`.ts\` (seconds) and \`.text\`.
|
|
6897
6956
|
|
|
6898
6957
|
Look for **repeated patterns**, not isolated events:
|
|
6899
6958
|
- Count correction frequency — 10 corrections on the same topic >> 1 mention
|
|
@@ -6901,38 +6960,70 @@ Look for **repeated patterns**, not isolated events:
|
|
|
6901
6960
|
- Implicit preferences revealed by what commands they run, what patterns they follow
|
|
6902
6961
|
- Frustration signals — "no", "undo", rapid corrections, /clear, model switches
|
|
6903
6962
|
|
|
6963
|
+
**For personality analysis**, look beyond the reaction to what caused it:
|
|
6964
|
+
- What agent behaviors triggered corrections? (over-engineering, wrong tool, verbose explanations, etc.)
|
|
6965
|
+
- What agent behaviors got positive responses? (fast fixes, running tests unprompted, etc.)
|
|
6966
|
+
- How do they phrase requests? (imperative, collaborative, questioning?)
|
|
6967
|
+
- What topics excite them vs bore them?
|
|
6968
|
+
- What's their tolerance for explanation vs "just fix it"?
|
|
6969
|
+
- How do they handle mistakes — their own and the agent's?
|
|
6970
|
+
|
|
6904
6971
|
### 4. Update memory files
|
|
6905
6972
|
|
|
6906
6973
|
**Content placement:**
|
|
6907
6974
|
- \`system/\`: Generalized rules, distilled preferences, project gotchas, identity. Keep files lean — bullets, short lines, scannable.
|
|
6908
6975
|
- Outside \`system/\`: Evidence, detailed history, verbose context. Link from system/ with \`[[path]]\`.
|
|
6909
6976
|
|
|
6977
|
+
**Preferred canonical paths:**
|
|
6978
|
+
- \`system/human/identity.md\`
|
|
6979
|
+
- \`system/human/prefs/communication.md\`
|
|
6980
|
+
- \`system/human/prefs/workflow.md\`
|
|
6981
|
+
- \`system/human/prefs/coding.md\`
|
|
6982
|
+
- \`system/<project>/conventions.md\`
|
|
6983
|
+
- \`system/<project>/gotchas.md\`
|
|
6984
|
+
|
|
6985
|
+
If the current memory uses a more compressed layout, extend it carefully, but prefer splitting into these focused files when there is enough material to justify the move.
|
|
6986
|
+
|
|
6910
6987
|
**File structure:**
|
|
6911
6988
|
- Use the project's **real name** as directory prefix (e.g. \`my-app/conventions.md\`), not generic \`project/\`
|
|
6912
6989
|
- One concept per file, nested with \`/\` paths
|
|
6913
6990
|
- Every file needs a meaningful \`description\` in frontmatter
|
|
6914
6991
|
- Write for the agent's future self — clean, actionable, no clutter
|
|
6915
6992
|
|
|
6993
|
+
Each durable finding should include at least one of:
|
|
6994
|
+
- correction frequency or intensity
|
|
6995
|
+
- concrete commands that worked or failed
|
|
6996
|
+
- concrete file or directory paths
|
|
6997
|
+
- date range or source reference for future lookup
|
|
6998
|
+
- why the rule matters in practice
|
|
6999
|
+
|
|
6916
7000
|
You can also cite the files if you want to note where something came from (e.g. \`(from: ~/.claude/history.jsonl)\`).
|
|
6917
7001
|
|
|
6918
7002
|
### 5. Commit
|
|
6919
7003
|
|
|
7004
|
+
Before writing the commit, resolve the actual ID values:
|
|
7005
|
+
\`\`\`bash
|
|
7006
|
+
echo "AGENT_ID=$LETTA_AGENT_ID"
|
|
7007
|
+
echo "PARENT_AGENT_ID=$LETTA_PARENT_AGENT_ID"
|
|
7008
|
+
\`\`\`
|
|
7009
|
+
|
|
7010
|
+
Use the printed values (e.g., \`agent-abc123...\`) in the trailers. If a variable is empty or unset, omit that trailer. Never write a literal variable name like \`$LETTA_AGENT_ID\` or \`$AGENT_ID\` in the commit message.
|
|
7011
|
+
|
|
6920
7012
|
\`\`\`bash
|
|
6921
7013
|
cd $WORKTREE_DIR/$BRANCH_NAME
|
|
6922
7014
|
git add -A
|
|
6923
|
-
git commit -m "<type>(history-analyzer):
|
|
7015
|
+
git commit --author="History Analyzer <<ACTUAL_AGENT_ID>@letta.com>" -m "<type>(history-analyzer): <summary> ⏳
|
|
6924
7016
|
|
|
6925
7017
|
Source: [file path] ([N] prompts, [DATE RANGE])
|
|
6926
|
-
|
|
6927
|
-
|
|
7018
|
+
|
|
7019
|
+
Updates:
|
|
7020
|
+
- <what changed and why>
|
|
6928
7021
|
|
|
6929
7022
|
Generated-By: Letta Code
|
|
6930
7023
|
Agent-ID: <ACTUAL_AGENT_ID>
|
|
6931
7024
|
Parent-Agent-ID: <ACTUAL_PARENT_AGENT_ID>"
|
|
6932
7025
|
\`\`\`
|
|
6933
7026
|
|
|
6934
|
-
Resolve \`ACTUAL_AGENT_ID\` and \`ACTUAL_PARENT_AGENT_ID\` by running \`echo $LETTA_AGENT_ID\` and \`echo $LETTA_PARENT_AGENT_ID\` first. Never write literal variable names in the commit message. Omit trailers if the variable is empty.
|
|
6935
|
-
|
|
6936
7027
|
**Commit types**: \`chore\` (routine ingestion), \`feat\` (new memory topics), \`refactor\` (reorganizing by domain).
|
|
6937
7028
|
|
|
6938
7029
|
## Rules
|
|
@@ -6940,7 +7031,8 @@ Resolve \`ACTUAL_AGENT_ID\` and \`ACTUAL_PARENT_AGENT_ID\` by running \`echo $LE
|
|
|
6940
7031
|
- Work in your worktree — do NOT edit the memory dir directly
|
|
6941
7032
|
- Do NOT merge into main — the parent agent handles merging
|
|
6942
7033
|
- Preserve existing content — extend or refine, don't replace
|
|
6943
|
-
-
|
|
7034
|
+
- Preserve specificity — specific quotes, correction counts, and file paths are more valuable than vague summaries. Don't compress away the details that give the parent agent its character and grounding.
|
|
7035
|
+
- **REQUIRED**: You MUST produce findings for all three output categories (Personality, Rules, Project). If any category lacks data, explicitly state why.
|
|
6944
7036
|
`;
|
|
6945
7037
|
var init_history_analyzer = () => {};
|
|
6946
7038
|
|
|
@@ -53756,7 +53848,7 @@ If a directory has more than 1,000 entries, only the first 1,000 will be shown.`
|
|
|
53756
53848
|
var init_LS = () => {};
|
|
53757
53849
|
|
|
53758
53850
|
// src/tools/descriptions/Memory.md
|
|
53759
|
-
var Memory_default =
|
|
53851
|
+
var Memory_default = "# Memory\nA convinience tool for memories stored in the memory directory (`$MEMORY_DIR`) that automatically commits and pushes changes. \n\nFiles stored inside of `system/` eventually become part of the agent's system prompt, so are always in the context window and do not need to be re-read. Other files only have metadata in the system prompt, so may need to be explicitly read to be updated. \n\nSupported operations on memory files: \n- `str_replace`\n- `insert`\n- `delete` (files, or directories recursively)\n- `rename` (path rename only)\n- `update_description`\n- `create`\nMore general operations can be performanced through directory modifying the files. \n\nPath formats accepted:\n- relative memory file paths (e.g. `system/contacts.md`, `reference/project/team.md`)\n- absolute paths only when they are inside `$MEMORY_DIR`\n\nNote: absolute paths outside `$MEMORY_DIR` are rejected.\n\nWhen creating or deleting files, check for `[[path]]` references in other memory files that may need to be added or updated. Keeping references consistent ensures future discoverability.\n\nExamples:\n\n```python\n# Replace text in a memory file \nmemory(command=\"str_replace\", reason=\"Update theme preference\", path=\"system/human/preferences.md\", old_string=\"theme: dark\", new_string=\"theme: light\")\n\n# Insert text at line 5\nmemory(command=\"insert\", reason=\"Add note about meeting\", path=\"reference/history/meeting-notes.md\", insert_line=5, insert_text=\"New note here\")\n\n# Delete a memory file \nmemory(command=\"delete\", reason=\"Remove stale notes\", path=\"reference/history/old_notes.md\")\n\n# Rename a memory file \nmemory(command=\"rename\", reason=\"Promote temp notes\", old_path=\"reference/history/temp.md\", new_path=\"reference/history/permanent.md\")\n\n# Update a block description\nmemory(command=\"update_description\", reason=\"Clarify coding prefs block\", path=\"system/human/prefs/coding.md\", description=\"Dr. Wooders' coding preferences.\")\n\n# Create a block with starting text\nmemory(command=\"create\", reason=\"Track coding preferences\", path=\"system/human/prefs/coding.md\", description=\"The user's coding preferences.\", file_text=\"The user seems to add type hints to all of their Python code.\")\n\n# Create an empty block\nmemory(command=\"create\", reason=\"Create coding preferences block\", path=\"reference/history/coding_preferences.md\", description=\"The user's coding preferences.\")\n```\n";
|
|
53760
53852
|
var init_Memory = () => {};
|
|
53761
53853
|
|
|
53762
53854
|
// src/tools/descriptions/MemoryApplyPatch.md
|
|
@@ -65799,6 +65891,9 @@ function parseResultFromStdout(stdout, agentId) {
|
|
|
65799
65891
|
};
|
|
65800
65892
|
}
|
|
65801
65893
|
}
|
|
65894
|
+
function resolveSubagentWorkingDirectory(env3 = process.env, fallbackCwd = process.cwd()) {
|
|
65895
|
+
return env3.USER_CWD || fallbackCwd;
|
|
65896
|
+
}
|
|
65802
65897
|
function resolveSubagentLauncher(cliArgs, options = {}) {
|
|
65803
65898
|
const env3 = options.env ?? process.env;
|
|
65804
65899
|
const argv = options.argv ?? process.argv;
|
|
@@ -65913,8 +66008,9 @@ async function executeSubagent(type, config, model, userPrompt, baseURL, subagen
|
|
|
65913
66008
|
const settings = await settingsManager.getSettingsWithSecureTokens();
|
|
65914
66009
|
const inheritedApiKey = process.env.LETTA_API_KEY || settings.env?.LETTA_API_KEY;
|
|
65915
66010
|
const inheritedBaseUrl = process.env.LETTA_BASE_URL || settings.env?.LETTA_BASE_URL;
|
|
66011
|
+
const subagentWorkingDirectory = resolveSubagentWorkingDirectory();
|
|
65916
66012
|
const proc2 = spawn4(launcher.command, launcher.args, {
|
|
65917
|
-
cwd:
|
|
66013
|
+
cwd: subagentWorkingDirectory,
|
|
65918
66014
|
env: {
|
|
65919
66015
|
...process.env,
|
|
65920
66016
|
...inheritedApiKey && { LETTA_API_KEY: inheritedApiKey },
|
|
@@ -73306,18 +73402,29 @@ var init_turn_recovery_policy = __esm(() => {
|
|
|
73306
73402
|
});
|
|
73307
73403
|
|
|
73308
73404
|
// src/agent/approval-recovery.ts
|
|
73309
|
-
async function
|
|
73405
|
+
async function fetchRunErrorInfo(runId) {
|
|
73310
73406
|
if (!runId)
|
|
73311
73407
|
return null;
|
|
73312
73408
|
try {
|
|
73313
73409
|
const client = await getClient();
|
|
73314
73410
|
const run = await client.runs.retrieve(runId);
|
|
73315
73411
|
const metaError = run.metadata?.error;
|
|
73316
|
-
|
|
73412
|
+
const nestedError = metaError?.error;
|
|
73413
|
+
const errorInfo = {
|
|
73414
|
+
error_type: metaError?.error_type ?? metaError?.type ?? nestedError?.error_type ?? nestedError?.type,
|
|
73415
|
+
message: metaError?.message ?? nestedError?.message,
|
|
73416
|
+
detail: metaError?.detail ?? nestedError?.detail,
|
|
73417
|
+
run_id: metaError?.run_id ?? nestedError?.run_id ?? runId
|
|
73418
|
+
};
|
|
73419
|
+
return errorInfo.error_type || errorInfo.message || errorInfo.detail ? errorInfo : null;
|
|
73317
73420
|
} catch {
|
|
73318
73421
|
return null;
|
|
73319
73422
|
}
|
|
73320
73423
|
}
|
|
73424
|
+
async function fetchRunErrorDetail(runId) {
|
|
73425
|
+
const errorInfo = await fetchRunErrorInfo(runId);
|
|
73426
|
+
return errorInfo?.detail ?? errorInfo?.message ?? null;
|
|
73427
|
+
}
|
|
73321
73428
|
var init_approval_recovery = __esm(async () => {
|
|
73322
73429
|
init_turn_recovery_policy();
|
|
73323
73430
|
await init_client2();
|
|
@@ -75761,6 +75868,7 @@ class StreamProcessor {
|
|
|
75761
75868
|
const errorDetail = chunkWithError.error.detail || "";
|
|
75762
75869
|
errorInfo = {
|
|
75763
75870
|
message: errorDetail ? `${errorText}: ${errorDetail}` : errorText,
|
|
75871
|
+
detail: errorDetail || undefined,
|
|
75764
75872
|
run_id: this.lastRunId || undefined
|
|
75765
75873
|
};
|
|
75766
75874
|
}
|
|
@@ -77090,13 +77198,53 @@ function requestApprovalOverWS(runtime, socket, requestId, controlRequest) {
|
|
|
77090
77198
|
if (socket.readyState !== WebSocket.OPEN) {
|
|
77091
77199
|
return Promise.reject(new Error("WebSocket not open"));
|
|
77092
77200
|
}
|
|
77201
|
+
const abortSignal = runtime.activeAbortController?.signal ?? null;
|
|
77202
|
+
const isInterrupted = () => runtime.cancelRequested || abortSignal?.aborted === true;
|
|
77203
|
+
if (isInterrupted()) {
|
|
77204
|
+
return Promise.reject(new Error("Cancelled by user"));
|
|
77205
|
+
}
|
|
77093
77206
|
return new Promise((resolve23, reject) => {
|
|
77207
|
+
let settled = false;
|
|
77208
|
+
const cleanupAbortListener = () => {
|
|
77209
|
+
abortSignal?.removeEventListener("abort", handleAbort);
|
|
77210
|
+
};
|
|
77211
|
+
const wrappedResolve = (response) => {
|
|
77212
|
+
if (settled) {
|
|
77213
|
+
return;
|
|
77214
|
+
}
|
|
77215
|
+
settled = true;
|
|
77216
|
+
cleanupAbortListener();
|
|
77217
|
+
resolve23(response);
|
|
77218
|
+
};
|
|
77219
|
+
const wrappedReject = (error) => {
|
|
77220
|
+
if (settled) {
|
|
77221
|
+
return;
|
|
77222
|
+
}
|
|
77223
|
+
settled = true;
|
|
77224
|
+
cleanupAbortListener();
|
|
77225
|
+
reject(error);
|
|
77226
|
+
};
|
|
77227
|
+
const handleAbort = () => {
|
|
77228
|
+
runtime.pendingApprovalResolvers.delete(requestId);
|
|
77229
|
+
runtime.listener.approvalRuntimeKeyByRequestId.delete(requestId);
|
|
77230
|
+
wrappedReject(new Error("Cancelled by user"));
|
|
77231
|
+
};
|
|
77232
|
+
abortSignal?.addEventListener("abort", handleAbort, { once: true });
|
|
77233
|
+
if (isInterrupted()) {
|
|
77234
|
+
handleAbort();
|
|
77235
|
+
return;
|
|
77236
|
+
}
|
|
77094
77237
|
runtime.pendingApprovalResolvers.set(requestId, {
|
|
77095
|
-
resolve:
|
|
77096
|
-
reject,
|
|
77238
|
+
resolve: wrappedResolve,
|
|
77239
|
+
reject: wrappedReject,
|
|
77097
77240
|
controlRequest
|
|
77098
77241
|
});
|
|
77099
77242
|
runtime.listener.approvalRuntimeKeyByRequestId.set(requestId, runtime.key);
|
|
77243
|
+
if (isInterrupted()) {
|
|
77244
|
+
handleAbort();
|
|
77245
|
+
return;
|
|
77246
|
+
}
|
|
77247
|
+
runtime.lastStopReason = "requires_approval";
|
|
77100
77248
|
setLoopStatus(runtime, "WAITING_ON_APPROVAL");
|
|
77101
77249
|
emitLoopStatusIfOpen(runtime.listener, {
|
|
77102
77250
|
agent_id: runtime.agentId,
|
|
@@ -77392,12 +77540,18 @@ function populateInterruptQueue(runtime, input) {
|
|
|
77392
77540
|
return false;
|
|
77393
77541
|
}
|
|
77394
77542
|
function consumeInterruptQueue(runtime, agentId, conversationId) {
|
|
77543
|
+
const ctx = runtime.pendingInterruptedContext;
|
|
77544
|
+
const matchingContext = !!ctx && ctx.agentId === agentId && ctx.conversationId === conversationId && ctx.continuationEpoch === runtime.continuationEpoch;
|
|
77395
77545
|
if (!runtime.pendingInterruptedResults || runtime.pendingInterruptedResults.length === 0) {
|
|
77546
|
+
if (matchingContext) {
|
|
77547
|
+
runtime.pendingInterruptedResults = null;
|
|
77548
|
+
runtime.pendingInterruptedContext = null;
|
|
77549
|
+
runtime.pendingInterruptedToolCallIds = null;
|
|
77550
|
+
}
|
|
77396
77551
|
return null;
|
|
77397
77552
|
}
|
|
77398
|
-
const ctx = runtime.pendingInterruptedContext;
|
|
77399
77553
|
let result = null;
|
|
77400
|
-
if (
|
|
77554
|
+
if (matchingContext) {
|
|
77401
77555
|
result = {
|
|
77402
77556
|
approvalMessage: {
|
|
77403
77557
|
type: "approval",
|
|
@@ -77565,6 +77719,175 @@ var init_permissionMode = __esm(() => {
|
|
|
77565
77719
|
init_remote_settings();
|
|
77566
77720
|
});
|
|
77567
77721
|
|
|
77722
|
+
// src/websocket/listener/recoverable-notices.ts
|
|
77723
|
+
function getRecoverableStatusNoticeVisibility(kind) {
|
|
77724
|
+
switch (kind) {
|
|
77725
|
+
case "stale_approval_conflict_recovery":
|
|
77726
|
+
return "debug_only";
|
|
77727
|
+
default:
|
|
77728
|
+
return "transcript";
|
|
77729
|
+
}
|
|
77730
|
+
}
|
|
77731
|
+
function getRecoverableRetryNoticeVisibility(kind, attempt) {
|
|
77732
|
+
switch (kind) {
|
|
77733
|
+
case "transient_provider_retry":
|
|
77734
|
+
return attempt === 1 ? "debug_only" : "transcript";
|
|
77735
|
+
default:
|
|
77736
|
+
return "transcript";
|
|
77737
|
+
}
|
|
77738
|
+
}
|
|
77739
|
+
function isDesktopDebugPanelMirrorEnabled() {
|
|
77740
|
+
return process.env.LETTA_DESKTOP_DEBUG_PANEL === "1";
|
|
77741
|
+
}
|
|
77742
|
+
function mirrorRecoverableNoticeToDesktopDebugPanel(message) {
|
|
77743
|
+
if (!isDesktopDebugPanelMirrorEnabled()) {
|
|
77744
|
+
return;
|
|
77745
|
+
}
|
|
77746
|
+
try {
|
|
77747
|
+
process.stderr.write(`${DESKTOP_DEBUG_PANEL_INFO_PREFIX} ${message}
|
|
77748
|
+
`);
|
|
77749
|
+
} catch {}
|
|
77750
|
+
}
|
|
77751
|
+
function toStructuredApiError(errorInfo) {
|
|
77752
|
+
if (!errorInfo?.error_type || !errorInfo.run_id) {
|
|
77753
|
+
return;
|
|
77754
|
+
}
|
|
77755
|
+
return {
|
|
77756
|
+
message_type: "error_message",
|
|
77757
|
+
message: errorInfo.message || errorInfo.detail || "An error occurred",
|
|
77758
|
+
error_type: errorInfo.error_type,
|
|
77759
|
+
run_id: errorInfo.run_id,
|
|
77760
|
+
...errorInfo.detail ? { detail: errorInfo.detail } : {}
|
|
77761
|
+
};
|
|
77762
|
+
}
|
|
77763
|
+
function getStructuredApiErrorFromError(error) {
|
|
77764
|
+
if (!(error instanceof Error)) {
|
|
77765
|
+
return;
|
|
77766
|
+
}
|
|
77767
|
+
const errorWithStructuredInfo = error;
|
|
77768
|
+
return errorWithStructuredInfo.apiError ?? toStructuredApiError(errorWithStructuredInfo.runErrorInfo);
|
|
77769
|
+
}
|
|
77770
|
+
function buildStructuredFormatInput(apiError) {
|
|
77771
|
+
return {
|
|
77772
|
+
error: {
|
|
77773
|
+
error: {
|
|
77774
|
+
type: apiError.error_type,
|
|
77775
|
+
message: apiError.message,
|
|
77776
|
+
...apiError.detail ? { detail: apiError.detail } : {}
|
|
77777
|
+
},
|
|
77778
|
+
run_id: apiError.run_id
|
|
77779
|
+
}
|
|
77780
|
+
};
|
|
77781
|
+
}
|
|
77782
|
+
function isAbortLikeError(error) {
|
|
77783
|
+
if (error instanceof APIUserAbortError) {
|
|
77784
|
+
return true;
|
|
77785
|
+
}
|
|
77786
|
+
if (!(error instanceof Error)) {
|
|
77787
|
+
return false;
|
|
77788
|
+
}
|
|
77789
|
+
const errorWithCode = error;
|
|
77790
|
+
return error.name === "AbortError" || error.message === "The operation was aborted" || errorWithCode.code === "ABORT_ERR";
|
|
77791
|
+
}
|
|
77792
|
+
function isTerminatedProcessNoise(message) {
|
|
77793
|
+
return message.trim().toLowerCase() === "terminated";
|
|
77794
|
+
}
|
|
77795
|
+
function isProxyTransportError(detail, error, message) {
|
|
77796
|
+
if (error instanceof APIError2 && error.status >= 500 && detail.toLowerCase().includes("trying to proxy")) {
|
|
77797
|
+
return true;
|
|
77798
|
+
}
|
|
77799
|
+
return detail.toLowerCase().includes("error occurred while trying to proxy") || message.toLowerCase().includes("error occurred while trying to proxy");
|
|
77800
|
+
}
|
|
77801
|
+
function getLoopErrorNoticeDecision(params) {
|
|
77802
|
+
const apiError = params.apiError ?? toStructuredApiError(params.errorInfo) ?? toStructuredApiError(params.runErrorInfo) ?? getStructuredApiErrorFromError(params.error);
|
|
77803
|
+
const detail = apiError?.detail ?? params.errorInfo?.detail ?? params.runErrorInfo?.detail ?? extractConflictDetail(params.error) ?? "";
|
|
77804
|
+
if (params.cancelRequested || params.abortSignal?.aborted || isAbortLikeError(params.error) || isTerminatedProcessNoise(params.message)) {
|
|
77805
|
+
return {
|
|
77806
|
+
visibility: "debug_only",
|
|
77807
|
+
message: params.message
|
|
77808
|
+
};
|
|
77809
|
+
}
|
|
77810
|
+
const cloudflareMessage = checkCloudflareEdgeError2(detail) ?? checkCloudflareEdgeError2(params.message);
|
|
77811
|
+
if (cloudflareMessage) {
|
|
77812
|
+
return {
|
|
77813
|
+
visibility: "transcript",
|
|
77814
|
+
message: cloudflareMessage,
|
|
77815
|
+
apiError
|
|
77816
|
+
};
|
|
77817
|
+
}
|
|
77818
|
+
if (isProxyTransportError(detail, params.error, params.message)) {
|
|
77819
|
+
return {
|
|
77820
|
+
visibility: "transcript",
|
|
77821
|
+
message: "Connection to Letta service failed. Please retry.",
|
|
77822
|
+
apiError
|
|
77823
|
+
};
|
|
77824
|
+
}
|
|
77825
|
+
const formattedMessage = formatErrorDetails2(apiError ? buildStructuredFormatInput(apiError) : params.error ?? params.message, params.agentId ?? undefined, params.conversationId ?? undefined);
|
|
77826
|
+
return {
|
|
77827
|
+
visibility: "transcript",
|
|
77828
|
+
message: formattedMessage,
|
|
77829
|
+
apiError
|
|
77830
|
+
};
|
|
77831
|
+
}
|
|
77832
|
+
function emitLoopErrorNotice(socket, runtime, params) {
|
|
77833
|
+
const decision = getLoopErrorNoticeDecision(params);
|
|
77834
|
+
if (decision.visibility === "debug_only") {
|
|
77835
|
+
debugLog("recovery", `Debug-only loop error (${params.stopReason}): ${params.message}`);
|
|
77836
|
+
mirrorRecoverableNoticeToDesktopDebugPanel(params.message);
|
|
77837
|
+
return;
|
|
77838
|
+
}
|
|
77839
|
+
emitLoopErrorDelta(socket, runtime, {
|
|
77840
|
+
message: decision.message,
|
|
77841
|
+
stopReason: params.stopReason,
|
|
77842
|
+
isTerminal: params.isTerminal,
|
|
77843
|
+
runId: params.runId,
|
|
77844
|
+
agentId: params.agentId,
|
|
77845
|
+
conversationId: params.conversationId,
|
|
77846
|
+
apiError: decision.apiError
|
|
77847
|
+
});
|
|
77848
|
+
}
|
|
77849
|
+
function emitRecoverableStatusNotice(socket, runtime, params) {
|
|
77850
|
+
const visibility = getRecoverableStatusNoticeVisibility(params.kind);
|
|
77851
|
+
if (visibility === "debug_only") {
|
|
77852
|
+
debugLog("recovery", `Debug-only lifecycle notice (${params.kind}): ${params.message}`);
|
|
77853
|
+
mirrorRecoverableNoticeToDesktopDebugPanel(params.message);
|
|
77854
|
+
return;
|
|
77855
|
+
}
|
|
77856
|
+
emitStatusDelta(socket, runtime, {
|
|
77857
|
+
message: params.message,
|
|
77858
|
+
level: params.level,
|
|
77859
|
+
runId: params.runId,
|
|
77860
|
+
agentId: params.agentId,
|
|
77861
|
+
conversationId: params.conversationId
|
|
77862
|
+
});
|
|
77863
|
+
}
|
|
77864
|
+
function emitRecoverableRetryNotice(socket, runtime, params) {
|
|
77865
|
+
const visibility = getRecoverableRetryNoticeVisibility(params.kind, params.attempt);
|
|
77866
|
+
if (visibility === "debug_only") {
|
|
77867
|
+
debugLog("recovery", `Debug-only retry notice (${params.kind}, attempt ${params.attempt}/${params.maxAttempts}): ${params.message}`);
|
|
77868
|
+
mirrorRecoverableNoticeToDesktopDebugPanel(params.message);
|
|
77869
|
+
return;
|
|
77870
|
+
}
|
|
77871
|
+
emitRetryDelta(socket, runtime, {
|
|
77872
|
+
message: params.message,
|
|
77873
|
+
reason: params.reason,
|
|
77874
|
+
attempt: params.attempt,
|
|
77875
|
+
maxAttempts: params.maxAttempts,
|
|
77876
|
+
delayMs: params.delayMs,
|
|
77877
|
+
runId: params.runId,
|
|
77878
|
+
agentId: params.agentId,
|
|
77879
|
+
conversationId: params.conversationId
|
|
77880
|
+
});
|
|
77881
|
+
}
|
|
77882
|
+
var DESKTOP_DEBUG_PANEL_INFO_PREFIX = "[LETTA_DESKTOP_DEBUG_PANEL_INFO]";
|
|
77883
|
+
var init_recoverable_notices = __esm(async () => {
|
|
77884
|
+
init_error();
|
|
77885
|
+
init_turn_recovery_policy();
|
|
77886
|
+
init_errorFormatter();
|
|
77887
|
+
init_debug();
|
|
77888
|
+
await init_protocol_outbound();
|
|
77889
|
+
});
|
|
77890
|
+
|
|
77568
77891
|
// node_modules/diff/libesm/diff/base.js
|
|
77569
77892
|
class Diff {
|
|
77570
77893
|
diff(oldStr, newStr, options = {}) {
|
|
@@ -79144,13 +79467,15 @@ async function drainRecoveryStreamWithEmission(recoveryStream, socket, runtime,
|
|
|
79144
79467
|
}
|
|
79145
79468
|
}
|
|
79146
79469
|
if (errorInfo) {
|
|
79147
|
-
|
|
79470
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
79148
79471
|
message: errorInfo.message || "Stream error",
|
|
79149
79472
|
stopReason: errorInfo.error_type || "error",
|
|
79150
79473
|
isTerminal: false,
|
|
79151
79474
|
runId: runtime.activeRunId || errorInfo.run_id,
|
|
79152
79475
|
agentId: params.agentId ?? undefined,
|
|
79153
|
-
conversationId: params.conversationId
|
|
79476
|
+
conversationId: params.conversationId,
|
|
79477
|
+
errorInfo,
|
|
79478
|
+
abortSignal: params.abortSignal
|
|
79154
79479
|
});
|
|
79155
79480
|
}
|
|
79156
79481
|
if (shouldOutput) {
|
|
@@ -79201,7 +79526,7 @@ function finalizeHandledRecoveryTurn(runtime, socket, params) {
|
|
|
79201
79526
|
const runId = runtime.activeRunId;
|
|
79202
79527
|
clearActiveRunState(runtime);
|
|
79203
79528
|
emitRuntimeStateUpdates(runtime, scope);
|
|
79204
|
-
|
|
79529
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
79205
79530
|
message: `Recovery continuation ended unexpectedly: ${terminalStopReason}`,
|
|
79206
79531
|
stopReason: terminalStopReason,
|
|
79207
79532
|
isTerminal: true,
|
|
@@ -79538,7 +79863,8 @@ var init_recovery = __esm(async () => {
|
|
|
79538
79863
|
init_approval_suggestions(),
|
|
79539
79864
|
init_interrupts(),
|
|
79540
79865
|
init_protocol_outbound(),
|
|
79541
|
-
init_queue()
|
|
79866
|
+
init_queue(),
|
|
79867
|
+
init_recoverable_notices()
|
|
79542
79868
|
]);
|
|
79543
79869
|
});
|
|
79544
79870
|
|
|
@@ -79646,9 +79972,6 @@ async function resolveStaleApprovals(runtime, socket, abortSignal, deps = {}) {
|
|
|
79646
79972
|
];
|
|
79647
79973
|
let pendingNeedsUserInput = [...needsUserInput];
|
|
79648
79974
|
if (pendingNeedsUserInput.length > 0) {
|
|
79649
|
-
runtime.lastStopReason = "requires_approval";
|
|
79650
|
-
setLoopStatus(runtime, "WAITING_ON_APPROVAL", scope);
|
|
79651
|
-
emitRuntimeStateUpdates(runtime, scope);
|
|
79652
79975
|
while (pendingNeedsUserInput.length > 0) {
|
|
79653
79976
|
const ac = pendingNeedsUserInput.shift();
|
|
79654
79977
|
if (!ac) {
|
|
@@ -79842,8 +80165,8 @@ async function sendMessageStreamWithRetry(conversationId, messages, opts, socket
|
|
|
79842
80165
|
throw new Error("Cancelled by user");
|
|
79843
80166
|
}
|
|
79844
80167
|
}
|
|
79845
|
-
const
|
|
79846
|
-
throw new Error(detail || `Pre-stream approval conflict after ${preStreamRecoveryAttempts} recovery attempts`);
|
|
80168
|
+
const runErrorInfo = await fetchRunErrorInfo(runtime.activeRunId);
|
|
80169
|
+
throw Object.assign(new Error(runErrorInfo?.detail || runErrorInfo?.message || `Pre-stream approval conflict after ${preStreamRecoveryAttempts} recovery attempts`), { runErrorInfo });
|
|
79847
80170
|
}
|
|
79848
80171
|
if (action === "retry_transient") {
|
|
79849
80172
|
runtime.isRecoveringApprovals = true;
|
|
@@ -79976,8 +80299,8 @@ async function sendApprovalContinuationWithRetry(conversationId, messages, opts,
|
|
|
79976
80299
|
}
|
|
79977
80300
|
continue;
|
|
79978
80301
|
}
|
|
79979
|
-
const
|
|
79980
|
-
throw new Error(detail || `Approval continuation conflict after ${preStreamRecoveryAttempts} recovery attempts`);
|
|
80302
|
+
const runErrorInfo = await fetchRunErrorInfo(runtime.activeRunId);
|
|
80303
|
+
throw Object.assign(new Error(runErrorInfo?.detail || runErrorInfo?.message || `Approval continuation conflict after ${preStreamRecoveryAttempts} recovery attempts`), { runErrorInfo });
|
|
79981
80304
|
}
|
|
79982
80305
|
if (action === "retry_transient") {
|
|
79983
80306
|
runtime.isRecoveringApprovals = true;
|
|
@@ -80103,7 +80426,7 @@ async function handleApprovalStop(params) {
|
|
|
80103
80426
|
agent_id: agentId,
|
|
80104
80427
|
conversation_id: conversationId
|
|
80105
80428
|
});
|
|
80106
|
-
|
|
80429
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
80107
80430
|
message: "requires_approval stop returned no approvals",
|
|
80108
80431
|
stopReason: "error",
|
|
80109
80432
|
isTerminal: true,
|
|
@@ -80177,11 +80500,6 @@ async function handleApprovalStop(params) {
|
|
|
80177
80500
|
if (shouldInterrupt()) {
|
|
80178
80501
|
return interruptTermination();
|
|
80179
80502
|
}
|
|
80180
|
-
runtime.lastStopReason = "requires_approval";
|
|
80181
|
-
setLoopStatus(runtime, "WAITING_ON_APPROVAL", {
|
|
80182
|
-
agent_id: agentId,
|
|
80183
|
-
conversation_id: conversationId
|
|
80184
|
-
});
|
|
80185
80503
|
while (pendingNeedsUserInput.length > 0) {
|
|
80186
80504
|
const ac = pendingNeedsUserInput.shift();
|
|
80187
80505
|
if (!ac) {
|
|
@@ -80411,6 +80729,7 @@ var init_turn_approval = __esm(async () => {
|
|
|
80411
80729
|
init_interrupts(),
|
|
80412
80730
|
init_protocol_outbound(),
|
|
80413
80731
|
init_queue(),
|
|
80732
|
+
init_recoverable_notices(),
|
|
80414
80733
|
init_recovery(),
|
|
80415
80734
|
init_send()
|
|
80416
80735
|
]);
|
|
@@ -80742,13 +81061,16 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
80742
81061
|
}
|
|
80743
81062
|
if (errorInfo) {
|
|
80744
81063
|
latestErrorText = errorInfo.message || latestErrorText;
|
|
80745
|
-
|
|
81064
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
80746
81065
|
message: errorInfo.message || "Stream error",
|
|
80747
81066
|
stopReason: errorInfo.error_type || "error",
|
|
80748
81067
|
isTerminal: false,
|
|
80749
81068
|
runId: runId || errorInfo.run_id,
|
|
80750
81069
|
agentId,
|
|
80751
|
-
conversationId
|
|
81070
|
+
conversationId,
|
|
81071
|
+
errorInfo,
|
|
81072
|
+
cancelRequested: runtime.cancelRequested,
|
|
81073
|
+
abortSignal: turnAbortSignal
|
|
80752
81074
|
});
|
|
80753
81075
|
}
|
|
80754
81076
|
if (shouldOutput) {
|
|
@@ -80808,7 +81130,8 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
80808
81130
|
}
|
|
80809
81131
|
if (stopReason !== "requires_approval") {
|
|
80810
81132
|
const lastRunId = runId || msgRunIds[msgRunIds.length - 1] || null;
|
|
80811
|
-
const
|
|
81133
|
+
const runErrorInfo = lastRunId ? await fetchRunErrorInfo(lastRunId) : null;
|
|
81134
|
+
const errorDetail = latestErrorText || runErrorInfo?.detail || runErrorInfo?.message || null;
|
|
80812
81135
|
if (shouldAttemptPostStopApprovalRecovery({
|
|
80813
81136
|
stopReason,
|
|
80814
81137
|
runIdsSeen: msgRunIds.length,
|
|
@@ -80817,7 +81140,8 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
80817
81140
|
latestErrorText
|
|
80818
81141
|
})) {
|
|
80819
81142
|
postStopApprovalRecoveryRetries += 1;
|
|
80820
|
-
|
|
81143
|
+
emitRecoverableStatusNotice(socket, runtime, {
|
|
81144
|
+
kind: "stale_approval_conflict_recovery",
|
|
80821
81145
|
message: "Recovering from stale approval conflict after interrupted/reconnected turn",
|
|
80822
81146
|
level: "warning",
|
|
80823
81147
|
runId: lastRunId || undefined,
|
|
@@ -80913,7 +81237,8 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
80913
81237
|
detail: errorDetail
|
|
80914
81238
|
});
|
|
80915
81239
|
const retryMessage = getRetryStatusMessage(errorDetail) || `LLM API error encountered, retrying (attempt ${attempt}/${LLM_API_ERROR_MAX_RETRIES})...`;
|
|
80916
|
-
|
|
81240
|
+
emitRecoverableRetryNotice(socket, runtime, {
|
|
81241
|
+
kind: "transient_provider_retry",
|
|
80917
81242
|
message: retryMessage,
|
|
80918
81243
|
reason: "llm_api_error",
|
|
80919
81244
|
attempt,
|
|
@@ -80968,13 +81293,16 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
80968
81293
|
conversation_id: conversationId
|
|
80969
81294
|
});
|
|
80970
81295
|
const errorMessage = errorDetail || `Unexpected stop reason: ${stopReason}`;
|
|
80971
|
-
|
|
81296
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
80972
81297
|
message: errorMessage,
|
|
80973
81298
|
stopReason: effectiveStopReason,
|
|
80974
81299
|
isTerminal: true,
|
|
80975
81300
|
runId,
|
|
80976
81301
|
agentId,
|
|
80977
|
-
conversationId
|
|
81302
|
+
conversationId,
|
|
81303
|
+
runErrorInfo: runErrorInfo ?? undefined,
|
|
81304
|
+
cancelRequested: runtime.cancelRequested,
|
|
81305
|
+
abortSignal: turnAbortSignal
|
|
80978
81306
|
});
|
|
80979
81307
|
break;
|
|
80980
81308
|
}
|
|
@@ -81058,12 +81386,15 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
81058
81386
|
conversation_id: conversationId
|
|
81059
81387
|
});
|
|
81060
81388
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
81061
|
-
|
|
81389
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
81062
81390
|
message: errorMessage,
|
|
81063
81391
|
stopReason: "error",
|
|
81064
81392
|
isTerminal: true,
|
|
81065
81393
|
agentId: agentId || undefined,
|
|
81066
|
-
conversationId
|
|
81394
|
+
conversationId,
|
|
81395
|
+
error,
|
|
81396
|
+
cancelRequested: runtime.cancelRequested,
|
|
81397
|
+
abortSignal: turnAbortSignal
|
|
81067
81398
|
});
|
|
81068
81399
|
if (isDebugEnabled()) {
|
|
81069
81400
|
console.error("[Listen] Error handling message:", error);
|
|
@@ -81113,6 +81444,7 @@ var init_turn = __esm(async () => {
|
|
|
81113
81444
|
init_toolset(),
|
|
81114
81445
|
init_interrupts(),
|
|
81115
81446
|
init_protocol_outbound(),
|
|
81447
|
+
init_recoverable_notices(),
|
|
81116
81448
|
init_recovery(),
|
|
81117
81449
|
init_send(),
|
|
81118
81450
|
init_turn_approval()
|
|
@@ -81436,7 +81768,7 @@ function buildLoopStatus(runtime, params) {
|
|
|
81436
81768
|
const conversationRuntime = getConversationRuntime(listener, scopedAgentId, scopedConversationId);
|
|
81437
81769
|
const interruptedCacheActive = hasInterruptedCacheForScope(listener, scope);
|
|
81438
81770
|
const recovered = getRecoveredApprovalStateForScope(listener, scope);
|
|
81439
|
-
const status = interruptedCacheActive ? !conversationRuntime?.isProcessing ? "WAITING_ON_INPUT" : conversationRuntime?.loopStatus ?? "WAITING_ON_INPUT" : recovered && recovered.pendingRequestIds.size > 0 && conversationRuntime?.loopStatus === "WAITING_ON_INPUT" ? "WAITING_ON_APPROVAL" : conversationRuntime?.loopStatus ?? "WAITING_ON_INPUT";
|
|
81771
|
+
const status = interruptedCacheActive ? !conversationRuntime?.isProcessing ? "WAITING_ON_INPUT" : conversationRuntime?.loopStatus === "WAITING_ON_APPROVAL" ? "WAITING_ON_INPUT" : conversationRuntime?.loopStatus ?? "WAITING_ON_INPUT" : recovered && recovered.pendingRequestIds.size > 0 && conversationRuntime?.loopStatus === "WAITING_ON_INPUT" ? "WAITING_ON_APPROVAL" : conversationRuntime?.loopStatus ?? "WAITING_ON_INPUT";
|
|
81440
81772
|
return {
|
|
81441
81773
|
status,
|
|
81442
81774
|
active_run_ids: interruptedCacheActive && !conversationRuntime?.isProcessing ? [] : conversationRuntime?.activeRunId ? [conversationRuntime.activeRunId] : []
|
|
@@ -81598,9 +81930,6 @@ function resolveSubagentScopeForSnapshot(runtime, scope) {
|
|
|
81598
81930
|
function buildSubagentSnapshot(runtime, scope) {
|
|
81599
81931
|
const runtimeScope = resolveSubagentScopeForSnapshot(runtime, scope);
|
|
81600
81932
|
return getSubagents().filter((a) => {
|
|
81601
|
-
if (a.status !== "pending" && a.status !== "running") {
|
|
81602
|
-
return false;
|
|
81603
|
-
}
|
|
81604
81933
|
if (a.silent && a.isBackground !== true) {
|
|
81605
81934
|
return false;
|
|
81606
81935
|
}
|
|
@@ -81672,7 +82001,8 @@ function emitLoopErrorDelta(socket, runtime, params) {
|
|
|
81672
82001
|
...createLifecycleMessageBase("loop_error", params.runId),
|
|
81673
82002
|
message: params.message,
|
|
81674
82003
|
stop_reason: params.stopReason,
|
|
81675
|
-
is_terminal: params.isTerminal
|
|
82004
|
+
is_terminal: params.isTerminal,
|
|
82005
|
+
...params.apiError ? { api_error: params.apiError } : {}
|
|
81676
82006
|
}, {
|
|
81677
82007
|
agent_id: params.agentId,
|
|
81678
82008
|
conversation_id: params.conversationId
|
|
@@ -82915,12 +83245,13 @@ function handleModeChange(msg, socket, runtime, scope) {
|
|
|
82915
83245
|
}
|
|
82916
83246
|
} catch (error) {
|
|
82917
83247
|
trackListenerError("listener_mode_change_failed", error, "listener_mode_change");
|
|
82918
|
-
|
|
83248
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
82919
83249
|
message: error instanceof Error ? error.message : "Mode change failed",
|
|
82920
83250
|
stopReason: "error",
|
|
82921
83251
|
isTerminal: false,
|
|
82922
83252
|
agentId: scope?.agent_id,
|
|
82923
|
-
conversationId: scope?.conversation_id
|
|
83253
|
+
conversationId: scope?.conversation_id,
|
|
83254
|
+
error
|
|
82924
83255
|
});
|
|
82925
83256
|
if (isDebugEnabled()) {
|
|
82926
83257
|
console.error("[Listen] Mode change failed:", error);
|
|
@@ -83670,6 +84001,7 @@ async function handleAbortMessageInput(listener, params, deps = {}) {
|
|
|
83670
84001
|
}
|
|
83671
84002
|
const interruptedRunId = scopedRuntime.activeRunId;
|
|
83672
84003
|
scopedRuntime.cancelRequested = true;
|
|
84004
|
+
const pendingRequestsSnapshot = hasPendingApprovals ? resolvedDeps.getPendingControlRequests(listener, scope) : [];
|
|
83673
84005
|
if (scopedRuntime.activeExecutingToolCallIds.length > 0 && (!scopedRuntime.pendingInterruptedResults || scopedRuntime.pendingInterruptedResults.length === 0)) {
|
|
83674
84006
|
scopedRuntime.pendingInterruptedResults = scopedRuntime.activeExecutingToolCallIds.map((toolCallId) => ({
|
|
83675
84007
|
type: "tool",
|
|
@@ -83715,9 +84047,8 @@ async function handleAbortMessageInput(listener, params, deps = {}) {
|
|
|
83715
84047
|
agentId: scope.agent_id,
|
|
83716
84048
|
conversationId: scope.conversation_id
|
|
83717
84049
|
});
|
|
83718
|
-
} else if (hasPendingApprovals) {
|
|
83719
|
-
|
|
83720
|
-
scopedRuntime.pendingInterruptedResults = pendingRequests.map((req) => ({
|
|
84050
|
+
} else if (hasPendingApprovals && (!scopedRuntime.pendingInterruptedResults || scopedRuntime.pendingInterruptedResults.length === 0) && pendingRequestsSnapshot.length > 0) {
|
|
84051
|
+
scopedRuntime.pendingInterruptedResults = pendingRequestsSnapshot.map((req) => ({
|
|
83721
84052
|
type: "approval",
|
|
83722
84053
|
tool_call_id: req.request.tool_call_id,
|
|
83723
84054
|
approve: false,
|
|
@@ -83728,6 +84059,7 @@ async function handleAbortMessageInput(listener, params, deps = {}) {
|
|
|
83728
84059
|
conversationId: scope.conversation_id,
|
|
83729
84060
|
continuationEpoch: scopedRuntime.continuationEpoch
|
|
83730
84061
|
};
|
|
84062
|
+
scopedRuntime.pendingInterruptedToolCallIds = null;
|
|
83731
84063
|
resolvedDeps.emitInterruptedStatusDelta(params.socket, scopedRuntime, {
|
|
83732
84064
|
runId: interruptedRunId,
|
|
83733
84065
|
agentId: scope.agent_id,
|
|
@@ -83772,12 +84104,13 @@ async function handleCwdChange(msg, socket, runtime) {
|
|
|
83772
84104
|
conversation_id: conversationId
|
|
83773
84105
|
});
|
|
83774
84106
|
} catch (error) {
|
|
83775
|
-
|
|
84107
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
83776
84108
|
message: error instanceof Error ? error.message : "Working directory change failed",
|
|
83777
84109
|
stopReason: "error",
|
|
83778
84110
|
isTerminal: false,
|
|
83779
84111
|
agentId,
|
|
83780
|
-
conversationId
|
|
84112
|
+
conversationId,
|
|
84113
|
+
error
|
|
83781
84114
|
});
|
|
83782
84115
|
}
|
|
83783
84116
|
}
|
|
@@ -83996,7 +84329,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
83996
84329
|
return;
|
|
83997
84330
|
}
|
|
83998
84331
|
if (parsed.type === "__invalid_input") {
|
|
83999
|
-
|
|
84332
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
84000
84333
|
message: parsed.reason,
|
|
84001
84334
|
stopReason: "error",
|
|
84002
84335
|
isTerminal: false,
|
|
@@ -84039,7 +84372,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
84039
84372
|
}
|
|
84040
84373
|
const inputPayload = parsed.payload;
|
|
84041
84374
|
if (inputPayload.kind !== "create_message") {
|
|
84042
|
-
|
|
84375
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
84043
84376
|
message: `Unsupported input payload kind: ${String(inputPayload.kind)}`,
|
|
84044
84377
|
stopReason: "error",
|
|
84045
84378
|
isTerminal: false,
|
|
@@ -84056,7 +84389,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
84056
84389
|
};
|
|
84057
84390
|
const hasApprovalPayload = incoming.messages.some((payload) => ("type" in payload) && payload.type === "approval");
|
|
84058
84391
|
if (hasApprovalPayload) {
|
|
84059
|
-
|
|
84392
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
84060
84393
|
message: "Protocol violation: approval payloads are not allowed in input.kind=create_message. Use input.kind=approval_response.",
|
|
84061
84394
|
stopReason: "error",
|
|
84062
84395
|
isTerminal: false,
|
|
@@ -84613,12 +84946,13 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
84613
84946
|
if (!parsedScope) {
|
|
84614
84947
|
return;
|
|
84615
84948
|
}
|
|
84616
|
-
|
|
84949
|
+
emitLoopErrorNotice(socket, runtime, {
|
|
84617
84950
|
message: error instanceof Error ? error.message : "Failed to process listener message",
|
|
84618
84951
|
stopReason: "error",
|
|
84619
84952
|
isTerminal: false,
|
|
84620
84953
|
agentId: parsedScope.agent_id,
|
|
84621
|
-
conversationId: parsedScope.conversation_id
|
|
84954
|
+
conversationId: parsedScope.conversation_id,
|
|
84955
|
+
error
|
|
84622
84956
|
});
|
|
84623
84957
|
}
|
|
84624
84958
|
});
|
|
@@ -84916,6 +85250,7 @@ var init_client4 = __esm(async () => {
|
|
|
84916
85250
|
init_protocol_inbound(),
|
|
84917
85251
|
init_protocol_outbound(),
|
|
84918
85252
|
init_queue(),
|
|
85253
|
+
init_recoverable_notices(),
|
|
84919
85254
|
init_recovery(),
|
|
84920
85255
|
init_send(),
|
|
84921
85256
|
init_turn(),
|
|
@@ -85336,7 +85671,7 @@ var init_skills2 = __esm(() => {
|
|
|
85336
85671
|
var exports_fs = {};
|
|
85337
85672
|
__export(exports_fs, {
|
|
85338
85673
|
writeJsonFile: () => writeJsonFile,
|
|
85339
|
-
writeFile: () =>
|
|
85674
|
+
writeFile: () => writeFile7,
|
|
85340
85675
|
readJsonFile: () => readJsonFile,
|
|
85341
85676
|
readFile: () => readFile9,
|
|
85342
85677
|
mkdir: () => mkdir6,
|
|
@@ -85352,7 +85687,7 @@ import { dirname as dirname13 } from "node:path";
|
|
|
85352
85687
|
async function readFile9(path23) {
|
|
85353
85688
|
return fsReadFileSync2(path23, { encoding: "utf-8" });
|
|
85354
85689
|
}
|
|
85355
|
-
async function
|
|
85690
|
+
async function writeFile7(path23, content) {
|
|
85356
85691
|
const dir = dirname13(path23);
|
|
85357
85692
|
if (!existsSync25(dir)) {
|
|
85358
85693
|
mkdirSync17(dir, { recursive: true });
|
|
@@ -85373,7 +85708,7 @@ async function writeJsonFile(path23, data, options) {
|
|
|
85373
85708
|
const indent = options?.indent ?? 2;
|
|
85374
85709
|
const content = `${JSON.stringify(data, null, indent)}
|
|
85375
85710
|
`;
|
|
85376
|
-
await
|
|
85711
|
+
await writeFile7(path23, content);
|
|
85377
85712
|
}
|
|
85378
85713
|
var init_fs2 = () => {};
|
|
85379
85714
|
|
|
@@ -85398,7 +85733,7 @@ async function queryTerminalBackground(timeoutMs = 100) {
|
|
|
85398
85733
|
}
|
|
85399
85734
|
const wasRaw = process.stdin.isRaw;
|
|
85400
85735
|
const wasFlowing = process.stdin.readableFlowing;
|
|
85401
|
-
return new Promise((
|
|
85736
|
+
return new Promise((resolve26) => {
|
|
85402
85737
|
let response = "";
|
|
85403
85738
|
let resolved = false;
|
|
85404
85739
|
const cleanup = () => {
|
|
@@ -85415,7 +85750,7 @@ async function queryTerminalBackground(timeoutMs = 100) {
|
|
|
85415
85750
|
};
|
|
85416
85751
|
const timeout = setTimeout(() => {
|
|
85417
85752
|
cleanup();
|
|
85418
|
-
|
|
85753
|
+
resolve26(null);
|
|
85419
85754
|
}, timeoutMs);
|
|
85420
85755
|
const onData = (data) => {
|
|
85421
85756
|
response += data.toString();
|
|
@@ -85425,7 +85760,7 @@ async function queryTerminalBackground(timeoutMs = 100) {
|
|
|
85425
85760
|
if (match3) {
|
|
85426
85761
|
clearTimeout(timeout);
|
|
85427
85762
|
cleanup();
|
|
85428
|
-
|
|
85763
|
+
resolve26({
|
|
85429
85764
|
r: parseHexComponent(match3[1] ?? "0"),
|
|
85430
85765
|
g: parseHexComponent(match3[2] ?? "0"),
|
|
85431
85766
|
b: parseHexComponent(match3[3] ?? "0")
|
|
@@ -85440,7 +85775,7 @@ async function queryTerminalBackground(timeoutMs = 100) {
|
|
|
85440
85775
|
} catch {
|
|
85441
85776
|
clearTimeout(timeout);
|
|
85442
85777
|
cleanup();
|
|
85443
|
-
|
|
85778
|
+
resolve26(null);
|
|
85444
85779
|
}
|
|
85445
85780
|
});
|
|
85446
85781
|
}
|
|
@@ -86649,10 +86984,10 @@ __export(exports_setup, {
|
|
|
86649
86984
|
runSetup: () => runSetup
|
|
86650
86985
|
});
|
|
86651
86986
|
async function runSetup() {
|
|
86652
|
-
return new Promise((
|
|
86987
|
+
return new Promise((resolve27) => {
|
|
86653
86988
|
const { waitUntilExit } = render_default(import_react32.default.createElement(SetupUI, {
|
|
86654
86989
|
onComplete: () => {
|
|
86655
|
-
|
|
86990
|
+
resolve27();
|
|
86656
86991
|
}
|
|
86657
86992
|
}));
|
|
86658
86993
|
waitUntilExit().catch((error) => {
|
|
@@ -87127,6 +87462,20 @@ function validateRegistryHandleOrThrow2(handle) {
|
|
|
87127
87462
|
}
|
|
87128
87463
|
}
|
|
87129
87464
|
|
|
87465
|
+
// src/runtime-context.ts
|
|
87466
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
87467
|
+
function getCurrentWorkingDirectory() {
|
|
87468
|
+
const workingDirectory = runtimeContextStorage.getStore()?.workingDirectory;
|
|
87469
|
+
if (typeof workingDirectory === "string" && workingDirectory.length > 0) {
|
|
87470
|
+
return workingDirectory;
|
|
87471
|
+
}
|
|
87472
|
+
return process.env.USER_CWD || process.cwd();
|
|
87473
|
+
}
|
|
87474
|
+
var runtimeContextStorage;
|
|
87475
|
+
var init_runtime_context = __esm(() => {
|
|
87476
|
+
runtimeContextStorage = new AsyncLocalStorage;
|
|
87477
|
+
});
|
|
87478
|
+
|
|
87130
87479
|
// src/agent/github-utils.ts
|
|
87131
87480
|
var exports_github_utils = {};
|
|
87132
87481
|
__export(exports_github_utils, {
|
|
@@ -87167,11 +87516,11 @@ __export(exports_import, {
|
|
|
87167
87516
|
extractSkillsFromAf: () => extractSkillsFromAf
|
|
87168
87517
|
});
|
|
87169
87518
|
import { createReadStream } from "node:fs";
|
|
87170
|
-
import { chmod, mkdir as mkdir7, readFile as readFile10, writeFile as
|
|
87171
|
-
import { dirname as dirname14, resolve as
|
|
87519
|
+
import { chmod, mkdir as mkdir7, readFile as readFile10, writeFile as writeFile8 } from "node:fs/promises";
|
|
87520
|
+
import { dirname as dirname14, resolve as resolve27 } from "node:path";
|
|
87172
87521
|
async function importAgentFromFile(options) {
|
|
87173
87522
|
const client = await getClient();
|
|
87174
|
-
const resolvedPath =
|
|
87523
|
+
const resolvedPath = resolve27(options.filePath);
|
|
87175
87524
|
const file = createReadStream(resolvedPath);
|
|
87176
87525
|
const importResponse = await client.agents.importFile({
|
|
87177
87526
|
file,
|
|
@@ -87206,7 +87555,7 @@ async function extractSkillsFromAf(afPath, destDir) {
|
|
|
87206
87555
|
return [];
|
|
87207
87556
|
}
|
|
87208
87557
|
for (const skill2 of afData.skills) {
|
|
87209
|
-
const skillDir =
|
|
87558
|
+
const skillDir = resolve27(destDir, skill2.name);
|
|
87210
87559
|
await mkdir7(skillDir, { recursive: true });
|
|
87211
87560
|
if (skill2.files) {
|
|
87212
87561
|
await writeSkillFiles(skillDir, skill2.files);
|
|
@@ -87226,9 +87575,9 @@ async function writeSkillFiles(skillDir, files) {
|
|
|
87226
87575
|
}
|
|
87227
87576
|
}
|
|
87228
87577
|
async function writeSkillFile(skillDir, filePath, content) {
|
|
87229
|
-
const fullPath =
|
|
87578
|
+
const fullPath = resolve27(skillDir, filePath);
|
|
87230
87579
|
await mkdir7(dirname14(fullPath), { recursive: true });
|
|
87231
|
-
await
|
|
87580
|
+
await writeFile8(fullPath, content, "utf-8");
|
|
87232
87581
|
const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
|
|
87233
87582
|
if (isScript) {
|
|
87234
87583
|
try {
|
|
@@ -87281,7 +87630,7 @@ function parseRegistryHandle(handle) {
|
|
|
87281
87630
|
async function importAgentFromRegistry(options) {
|
|
87282
87631
|
const { tmpdir: tmpdir4 } = await import("node:os");
|
|
87283
87632
|
const { join: join35 } = await import("node:path");
|
|
87284
|
-
const { writeFile:
|
|
87633
|
+
const { writeFile: writeFile9, unlink: unlink3 } = await import("node:fs/promises");
|
|
87285
87634
|
const { author, name } = parseRegistryHandle(options.handle);
|
|
87286
87635
|
const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER}/${AGENT_REGISTRY_REPO}/refs/heads/${AGENT_REGISTRY_BRANCH}/agents/@${author}/${name}/${name}.af`;
|
|
87287
87636
|
const response = await fetch(rawUrl);
|
|
@@ -87293,7 +87642,7 @@ async function importAgentFromRegistry(options) {
|
|
|
87293
87642
|
}
|
|
87294
87643
|
const afContent = await response.text();
|
|
87295
87644
|
const tempPath = join35(tmpdir4(), `letta-import-${author}-${name}-${Date.now()}.af`);
|
|
87296
|
-
await
|
|
87645
|
+
await writeFile9(tempPath, afContent, "utf-8");
|
|
87297
87646
|
try {
|
|
87298
87647
|
const result = await importAgentFromFile({
|
|
87299
87648
|
filePath: tempPath,
|
|
@@ -87524,7 +87873,7 @@ async function prepareHeadlessToolExecutionContext(params) {
|
|
|
87524
87873
|
agentId: params.agentId,
|
|
87525
87874
|
conversationId: params.conversationId,
|
|
87526
87875
|
overrideModel: params.overrideModel,
|
|
87527
|
-
workingDirectory:
|
|
87876
|
+
workingDirectory: getCurrentWorkingDirectory(),
|
|
87528
87877
|
exclude: ["AskUserQuestion"]
|
|
87529
87878
|
});
|
|
87530
87879
|
return {
|
|
@@ -87532,6 +87881,20 @@ async function prepareHeadlessToolExecutionContext(params) {
|
|
|
87532
87881
|
availableTools: preparedToolContext.preparedToolContext.clientTools.map((tool) => tool.name)
|
|
87533
87882
|
};
|
|
87534
87883
|
}
|
|
87884
|
+
async function flushAndExit(code) {
|
|
87885
|
+
const flushWritable = (stream2) => new Promise((resolve28) => {
|
|
87886
|
+
if (stream2.destroyed || stream2.writableEnded) {
|
|
87887
|
+
resolve28();
|
|
87888
|
+
return;
|
|
87889
|
+
}
|
|
87890
|
+
stream2.write("", () => resolve28());
|
|
87891
|
+
});
|
|
87892
|
+
await Promise.allSettled([
|
|
87893
|
+
flushWritable(process.stdout),
|
|
87894
|
+
flushWritable(process.stderr)
|
|
87895
|
+
]);
|
|
87896
|
+
process.exit(code);
|
|
87897
|
+
}
|
|
87535
87898
|
async function handleHeadlessCommand(parsedArgs, model, skillsDirectoryOverride, skillSourcesOverride, systemInfoReminderEnabledOverride) {
|
|
87536
87899
|
const { values, positionals } = parsedArgs;
|
|
87537
87900
|
telemetry.setSurface("headless");
|
|
@@ -87602,6 +87965,7 @@ In headless mode, use:
|
|
|
87602
87965
|
let forceNewConversation = values.new ?? false;
|
|
87603
87966
|
const fromAgentId = values["from-agent"];
|
|
87604
87967
|
let agent = null;
|
|
87968
|
+
let autoEnableMemfsForFreshAgent = false;
|
|
87605
87969
|
let specifiedAgentId = values.agent;
|
|
87606
87970
|
const specifiedAgentName = values.name;
|
|
87607
87971
|
let specifiedConversationId = values.conversation;
|
|
@@ -87884,7 +88248,7 @@ In headless mode, use:
|
|
|
87884
88248
|
}
|
|
87885
88249
|
if (!agent && forceNew) {
|
|
87886
88250
|
const updateArgs = getModelUpdateArgs2(model);
|
|
87887
|
-
const { isLettaCloud: isLettaCloud2
|
|
88251
|
+
const { isLettaCloud: isLettaCloud2 } = await Promise.resolve().then(() => (init_memoryFilesystem(), exports_memoryFilesystem));
|
|
87888
88252
|
const willAutoEnableMemfs = shouldAutoEnableMemfsForNewAgent && await isLettaCloud2();
|
|
87889
88253
|
const effectiveMemoryMode = requestedMemoryPromptMode ?? (willAutoEnableMemfs ? "memfs" : undefined);
|
|
87890
88254
|
const createOptions = {
|
|
@@ -87904,13 +88268,11 @@ In headless mode, use:
|
|
|
87904
88268
|
};
|
|
87905
88269
|
const result = await createAgent(createOptions);
|
|
87906
88270
|
agent = result.agent;
|
|
87907
|
-
|
|
87908
|
-
await enableMemfsIfCloud2(agent.id);
|
|
87909
|
-
}
|
|
88271
|
+
autoEnableMemfsForFreshAgent = willAutoEnableMemfs;
|
|
87910
88272
|
}
|
|
87911
88273
|
if (!agent) {
|
|
87912
88274
|
await settingsManager.loadLocalProjectSettings();
|
|
87913
|
-
const localAgentId = settingsManager.getLocalLastAgentId(
|
|
88275
|
+
const localAgentId = settingsManager.getLocalLastAgentId(getCurrentWorkingDirectory());
|
|
87914
88276
|
if (localAgentId) {
|
|
87915
88277
|
try {
|
|
87916
88278
|
agent = await client.agents.retrieve(localAgentId);
|
|
@@ -87965,13 +88327,14 @@ In headless mode, use:
|
|
|
87965
88327
|
let conversationId;
|
|
87966
88328
|
let effectiveReflectionSettings;
|
|
87967
88329
|
const isSubagent = process.env.LETTA_CODE_AGENT_ROLE === "subagent";
|
|
88330
|
+
const startupMemfsFlag = autoEnableMemfsForFreshAgent ? true : memfsFlag;
|
|
87968
88331
|
let memfsBgPromise;
|
|
87969
88332
|
const secretsAgentId = agent?.id;
|
|
87970
88333
|
const secretsInitPromise = secretsAgentId ? init_secretsStore().then(() => exports_secretsStore).then(({ initSecretsFromServer: initSecretsFromServer2 }) => initSecretsFromServer2(secretsAgentId)) : Promise.resolve();
|
|
87971
88334
|
if (memfsStartupPolicy === "skip") {
|
|
87972
88335
|
try {
|
|
87973
88336
|
const { applyMemfsFlags: applyMemfsFlags2 } = await Promise.resolve().then(() => (init_memoryFilesystem(), exports_memoryFilesystem));
|
|
87974
|
-
await applyMemfsFlags2(agent.id,
|
|
88337
|
+
await applyMemfsFlags2(agent.id, startupMemfsFlag, noMemfsFlag, {
|
|
87975
88338
|
pullOnExistingRepo: false,
|
|
87976
88339
|
agentTags: agent.tags,
|
|
87977
88340
|
skipPromptUpdate: forceNew
|
|
@@ -87983,7 +88346,7 @@ In headless mode, use:
|
|
|
87983
88346
|
}
|
|
87984
88347
|
} else if (memfsStartupPolicy === "background") {
|
|
87985
88348
|
const { applyMemfsFlags: applyMemfsFlags2 } = await Promise.resolve().then(() => (init_memoryFilesystem(), exports_memoryFilesystem));
|
|
87986
|
-
memfsBgPromise = applyMemfsFlags2(agent.id,
|
|
88349
|
+
memfsBgPromise = applyMemfsFlags2(agent.id, startupMemfsFlag, noMemfsFlag, {
|
|
87987
88350
|
pullOnExistingRepo: true,
|
|
87988
88351
|
agentTags: agent.tags,
|
|
87989
88352
|
skipPromptUpdate: forceNew
|
|
@@ -87994,7 +88357,7 @@ In headless mode, use:
|
|
|
87994
88357
|
} else {
|
|
87995
88358
|
try {
|
|
87996
88359
|
const { applyMemfsFlags: applyMemfsFlags2 } = await Promise.resolve().then(() => (init_memoryFilesystem(), exports_memoryFilesystem));
|
|
87997
|
-
const memfsResult = await applyMemfsFlags2(agent.id,
|
|
88360
|
+
const memfsResult = await applyMemfsFlags2(agent.id, startupMemfsFlag, noMemfsFlag, {
|
|
87998
88361
|
pullOnExistingRepo: true,
|
|
87999
88362
|
agentTags: agent.tags,
|
|
88000
88363
|
skipPromptUpdate: forceNew
|
|
@@ -88097,7 +88460,7 @@ In headless mode, use:
|
|
|
88097
88460
|
}
|
|
88098
88461
|
markMilestone("HEADLESS_CONVERSATION_READY");
|
|
88099
88462
|
setConversationId2(conversationId);
|
|
88100
|
-
if (
|
|
88463
|
+
if (shouldPersistSessionState()) {
|
|
88101
88464
|
await settingsManager.loadLocalProjectSettings();
|
|
88102
88465
|
settingsManager.persistSession(agent.id, conversationId);
|
|
88103
88466
|
}
|
|
@@ -88136,7 +88499,7 @@ In headless mode, use:
|
|
|
88136
88499
|
conversation_id: conversationId,
|
|
88137
88500
|
model: agent.llm_config?.model ?? "",
|
|
88138
88501
|
tools: availableTools,
|
|
88139
|
-
cwd:
|
|
88502
|
+
cwd: getCurrentWorkingDirectory(),
|
|
88140
88503
|
mcp_servers: [],
|
|
88141
88504
|
permission_mode: "",
|
|
88142
88505
|
slash_commands: [],
|
|
@@ -88297,6 +88660,7 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
88297
88660
|
},
|
|
88298
88661
|
state: sharedReminderState,
|
|
88299
88662
|
sessionContextReminderEnabled: systemInfoReminderEnabled,
|
|
88663
|
+
workingDirectory: getCurrentWorkingDirectory(),
|
|
88300
88664
|
reflectionSettings: effectiveReflectionSettings,
|
|
88301
88665
|
skillSources: resolvedSkillSources,
|
|
88302
88666
|
resolvePlanModeReminder: async () => {
|
|
@@ -88470,7 +88834,7 @@ ${loadedContents.join(`
|
|
|
88470
88834
|
} else {
|
|
88471
88835
|
console.error(`Conversation is busy, waiting ${Math.round(retryDelayMs / 1000)}s and retrying...`);
|
|
88472
88836
|
}
|
|
88473
|
-
await new Promise((
|
|
88837
|
+
await new Promise((resolve28) => setTimeout(resolve28, retryDelayMs));
|
|
88474
88838
|
continue;
|
|
88475
88839
|
}
|
|
88476
88840
|
}
|
|
@@ -88519,7 +88883,7 @@ ${loadedContents.join(`
|
|
|
88519
88883
|
const delaySeconds = Math.round(delayMs / 1000);
|
|
88520
88884
|
console.error(`Transient API error before streaming (attempt ${attempt} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
|
|
88521
88885
|
}
|
|
88522
|
-
await new Promise((
|
|
88886
|
+
await new Promise((resolve28) => setTimeout(resolve28, delayMs));
|
|
88523
88887
|
conversationBusyRetries = 0;
|
|
88524
88888
|
continue;
|
|
88525
88889
|
}
|
|
@@ -88758,7 +89122,7 @@ ${loadedContents.join(`
|
|
|
88758
89122
|
const delaySeconds = Math.round(delayMs / 1000);
|
|
88759
89123
|
console.error(`LLM API error encountered (attempt ${attempt} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
|
|
88760
89124
|
}
|
|
88761
|
-
await new Promise((
|
|
89125
|
+
await new Promise((resolve28) => setTimeout(resolve28, delayMs));
|
|
88762
89126
|
refreshCurrentInputOtids();
|
|
88763
89127
|
continue;
|
|
88764
89128
|
}
|
|
@@ -88844,7 +89208,7 @@ ${loadedContents.join(`
|
|
|
88844
89208
|
} else {
|
|
88845
89209
|
console.error(`Empty LLM response, retrying (attempt ${attempt} of ${EMPTY_RESPONSE_MAX_RETRIES2})...`);
|
|
88846
89210
|
}
|
|
88847
|
-
await new Promise((
|
|
89211
|
+
await new Promise((resolve28) => setTimeout(resolve28, delayMs));
|
|
88848
89212
|
refreshCurrentInputOtids();
|
|
88849
89213
|
continue;
|
|
88850
89214
|
}
|
|
@@ -88872,7 +89236,7 @@ ${loadedContents.join(`
|
|
|
88872
89236
|
const delaySeconds = Math.round(delayMs / 1000);
|
|
88873
89237
|
console.error(`LLM API error encountered (attempt ${attempt} of ${LLM_API_ERROR_MAX_RETRIES2}), retrying in ${delaySeconds}s...`);
|
|
88874
89238
|
}
|
|
88875
|
-
await new Promise((
|
|
89239
|
+
await new Promise((resolve28) => setTimeout(resolve28, delayMs));
|
|
88876
89240
|
refreshCurrentInputOtids();
|
|
88877
89241
|
continue;
|
|
88878
89242
|
}
|
|
@@ -89001,6 +89365,7 @@ ${loadedContents.join(`
|
|
|
89001
89365
|
}
|
|
89002
89366
|
markMilestone("HEADLESS_COMPLETE");
|
|
89003
89367
|
reportAllMilestones();
|
|
89368
|
+
await flushAndExit(0);
|
|
89004
89369
|
}
|
|
89005
89370
|
async function runBidirectionalMode(agent, conversationId, client, _outputFormat, includePartialMessages, availableTools, skillSources, systemInfoReminderEnabled, reflectionSettings) {
|
|
89006
89371
|
const sessionId = agent.id;
|
|
@@ -89013,7 +89378,7 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
|
|
|
89013
89378
|
conversation_id: conversationId,
|
|
89014
89379
|
model: agent.llm_config?.model,
|
|
89015
89380
|
tools: availableTools,
|
|
89016
|
-
cwd:
|
|
89381
|
+
cwd: getCurrentWorkingDirectory(),
|
|
89017
89382
|
memfs_enabled: settingsManager.isMemfsEnabled(agent.id),
|
|
89018
89383
|
skill_sources: skillSources,
|
|
89019
89384
|
system_info_reminder_enabled: systemInfoReminderEnabled,
|
|
@@ -89205,9 +89570,9 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
|
|
|
89205
89570
|
const syntheticUserLine = serializeQueuedMessageAsUserLine(queuedMessage);
|
|
89206
89571
|
maybeNotifyBlocked(syntheticUserLine);
|
|
89207
89572
|
if (lineResolver) {
|
|
89208
|
-
const
|
|
89573
|
+
const resolve28 = lineResolver;
|
|
89209
89574
|
lineResolver = null;
|
|
89210
|
-
|
|
89575
|
+
resolve28(syntheticUserLine);
|
|
89211
89576
|
return;
|
|
89212
89577
|
}
|
|
89213
89578
|
lineQueue.push(syntheticUserLine);
|
|
@@ -89215,9 +89580,9 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
|
|
|
89215
89580
|
rl.on("line", (line) => {
|
|
89216
89581
|
maybeNotifyBlocked(line);
|
|
89217
89582
|
if (lineResolver) {
|
|
89218
|
-
const
|
|
89583
|
+
const resolve28 = lineResolver;
|
|
89219
89584
|
lineResolver = null;
|
|
89220
|
-
|
|
89585
|
+
resolve28(line);
|
|
89221
89586
|
} else {
|
|
89222
89587
|
lineQueue.push(line);
|
|
89223
89588
|
}
|
|
@@ -89226,17 +89591,17 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
|
|
|
89226
89591
|
setMessageQueueAdder(null);
|
|
89227
89592
|
msgQueueRuntime.clear("shutdown");
|
|
89228
89593
|
if (lineResolver) {
|
|
89229
|
-
const
|
|
89594
|
+
const resolve28 = lineResolver;
|
|
89230
89595
|
lineResolver = null;
|
|
89231
|
-
|
|
89596
|
+
resolve28(null);
|
|
89232
89597
|
}
|
|
89233
89598
|
});
|
|
89234
89599
|
async function getNextLine() {
|
|
89235
89600
|
if (lineQueue.length > 0) {
|
|
89236
89601
|
return lineQueue.shift() ?? null;
|
|
89237
89602
|
}
|
|
89238
|
-
return new Promise((
|
|
89239
|
-
lineResolver =
|
|
89603
|
+
return new Promise((resolve28) => {
|
|
89604
|
+
lineResolver = resolve28;
|
|
89240
89605
|
});
|
|
89241
89606
|
}
|
|
89242
89607
|
async function requestPermission(toolCallId, toolName, toolInput) {
|
|
@@ -89655,6 +90020,7 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
|
|
|
89655
90020
|
},
|
|
89656
90021
|
state: sharedReminderState,
|
|
89657
90022
|
sessionContextReminderEnabled: systemInfoReminderEnabled,
|
|
90023
|
+
workingDirectory: getCurrentWorkingDirectory(),
|
|
89658
90024
|
reflectionSettings,
|
|
89659
90025
|
skillSources,
|
|
89660
90026
|
resolvePlanModeReminder: async () => {
|
|
@@ -89739,7 +90105,7 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
|
|
|
89739
90105
|
uuid: `retry-bidir-${randomUUID8()}`
|
|
89740
90106
|
};
|
|
89741
90107
|
console.log(JSON.stringify(retryMsg));
|
|
89742
|
-
await new Promise((
|
|
90108
|
+
await new Promise((resolve28) => setTimeout(resolve28, delayMs));
|
|
89743
90109
|
continue;
|
|
89744
90110
|
}
|
|
89745
90111
|
throw preStreamError;
|
|
@@ -89980,6 +90346,7 @@ var init_headless = __esm(async () => {
|
|
|
89980
90346
|
init_constants();
|
|
89981
90347
|
init_diffPreview();
|
|
89982
90348
|
init_queueRuntime();
|
|
90349
|
+
init_runtime_context();
|
|
89983
90350
|
init_interactivePolicy();
|
|
89984
90351
|
init_debug();
|
|
89985
90352
|
init_timing();
|
|
@@ -90034,10 +90401,10 @@ async function detectAndEnableKittyProtocol() {
|
|
|
90034
90401
|
detectionComplete = true;
|
|
90035
90402
|
return;
|
|
90036
90403
|
}
|
|
90037
|
-
return new Promise((
|
|
90404
|
+
return new Promise((resolve28) => {
|
|
90038
90405
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
90039
90406
|
detectionComplete = true;
|
|
90040
|
-
|
|
90407
|
+
resolve28();
|
|
90041
90408
|
return;
|
|
90042
90409
|
}
|
|
90043
90410
|
const originalRawMode = process.stdin.isRaw;
|
|
@@ -90070,7 +90437,7 @@ async function detectAndEnableKittyProtocol() {
|
|
|
90070
90437
|
console.error("[kitty] protocol query unsupported; enabled anyway (best-effort)");
|
|
90071
90438
|
}
|
|
90072
90439
|
detectionComplete = true;
|
|
90073
|
-
|
|
90440
|
+
resolve28();
|
|
90074
90441
|
};
|
|
90075
90442
|
const handleData = (data) => {
|
|
90076
90443
|
if (timeoutId === undefined) {
|
|
@@ -112256,7 +112623,7 @@ var init_pasteRegistry = __esm(() => {
|
|
|
112256
112623
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
112257
112624
|
import { existsSync as existsSync29, readFileSync as readFileSync16, statSync as statSync10, unlinkSync as unlinkSync10 } from "node:fs";
|
|
112258
112625
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
112259
|
-
import { basename as basename4, extname as extname5, isAbsolute as isAbsolute18, join as join38, resolve as
|
|
112626
|
+
import { basename as basename4, extname as extname5, isAbsolute as isAbsolute18, join as join38, resolve as resolve28 } from "node:path";
|
|
112260
112627
|
function countLines2(text) {
|
|
112261
112628
|
return (text.match(/\r\n|\r|\n/g) || []).length + 1;
|
|
112262
112629
|
}
|
|
@@ -112304,7 +112671,7 @@ function translatePasteForImages(paste) {
|
|
|
112304
112671
|
} catch {}
|
|
112305
112672
|
}
|
|
112306
112673
|
if (!isAbsolute18(filePath))
|
|
112307
|
-
filePath =
|
|
112674
|
+
filePath = resolve28(process.cwd(), filePath);
|
|
112308
112675
|
const ext3 = extname5(filePath || "").toLowerCase();
|
|
112309
112676
|
if (IMAGE_EXTS.has(ext3) && existsSync29(filePath) && statSync10(filePath).isFile()) {
|
|
112310
112677
|
const buf = readFileSync16(filePath);
|
|
@@ -113450,9 +113817,16 @@ var init_registry = __esm(async () => {
|
|
|
113450
113817
|
}
|
|
113451
113818
|
},
|
|
113452
113819
|
"/reflect": {
|
|
113453
|
-
desc: "Launch
|
|
113820
|
+
desc: "Launch reflection (/reflect [transcript_file])",
|
|
113821
|
+
args: "[transcript_file]",
|
|
113454
113822
|
order: 50,
|
|
113455
|
-
|
|
113823
|
+
handler: () => {
|
|
113824
|
+
return "Launching reflection agent...";
|
|
113825
|
+
}
|
|
113826
|
+
},
|
|
113827
|
+
"/reflection": {
|
|
113828
|
+
desc: "Alias for /reflect",
|
|
113829
|
+
args: "[transcript_file]",
|
|
113456
113830
|
handler: () => {
|
|
113457
113831
|
return "Launching reflection agent...";
|
|
113458
113832
|
}
|
|
@@ -113812,14 +114186,6 @@ Location: ${keybindingsPath}`;
|
|
|
113812
114186
|
return "Clearing credentials...";
|
|
113813
114187
|
}
|
|
113814
114188
|
},
|
|
113815
|
-
"/empanada": {
|
|
113816
|
-
desc: "Order empanadas from Empanada Empire",
|
|
113817
|
-
order: 44.5,
|
|
113818
|
-
args: "[address]",
|
|
113819
|
-
handler: () => {
|
|
113820
|
-
return "Checking Empanada Empire...";
|
|
113821
|
-
}
|
|
113822
|
-
},
|
|
113823
114189
|
"/ralph": {
|
|
113824
114190
|
desc: 'Start Ralph Wiggum loop (/ralph [prompt] [--completion-promise "X"] [--max-iterations N])',
|
|
113825
114191
|
order: 45,
|
|
@@ -114324,11 +114690,11 @@ var init_HelpDialog = __esm(async () => {
|
|
|
114324
114690
|
|
|
114325
114691
|
// src/hooks/writer.ts
|
|
114326
114692
|
import { homedir as homedir31 } from "node:os";
|
|
114327
|
-
import { resolve as
|
|
114693
|
+
import { resolve as resolve29 } from "node:path";
|
|
114328
114694
|
function isProjectSettingsPathCollidingWithGlobal2(workingDirectory) {
|
|
114329
114695
|
const home = process.env.HOME || homedir31();
|
|
114330
|
-
const globalSettingsPath =
|
|
114331
|
-
const projectSettingsPath =
|
|
114696
|
+
const globalSettingsPath = resolve29(home, ".letta", "settings.json");
|
|
114697
|
+
const projectSettingsPath = resolve29(workingDirectory, ".letta", "settings.json");
|
|
114332
114698
|
return globalSettingsPath === projectSettingsPath;
|
|
114333
114699
|
}
|
|
114334
114700
|
function loadHooksFromLocation(location, workingDirectory = process.cwd()) {
|
|
@@ -116966,7 +117332,7 @@ var init_AgentInfoBar = __esm(async () => {
|
|
|
116966
117332
|
|
|
116967
117333
|
// src/cli/helpers/fileSearch.ts
|
|
116968
117334
|
import { readdirSync as readdirSync13, statSync as statSync11 } from "node:fs";
|
|
116969
|
-
import { join as join41, relative as relative15, resolve as
|
|
117335
|
+
import { join as join41, relative as relative15, resolve as resolve30 } from "node:path";
|
|
116970
117336
|
function searchDirectoryRecursive(dir, pattern, maxResults = 200, results = [], depth = 0, maxDepth = 10, lowerPattern = pattern.toLowerCase()) {
|
|
116971
117337
|
if (results.length >= maxResults || depth >= maxDepth) {
|
|
116972
117338
|
return results;
|
|
@@ -117009,7 +117375,7 @@ async function searchFiles(query, deep = false) {
|
|
|
117009
117375
|
const dirPart = query.slice(0, lastSlashIndex);
|
|
117010
117376
|
const pattern = query.slice(lastSlashIndex + 1);
|
|
117011
117377
|
try {
|
|
117012
|
-
const resolvedDir =
|
|
117378
|
+
const resolvedDir = resolve30(getIndexRoot(), dirPart);
|
|
117013
117379
|
try {
|
|
117014
117380
|
statSync11(resolvedDir);
|
|
117015
117381
|
searchDir = resolvedDir;
|
|
@@ -131808,7 +132174,7 @@ async function executeStatusLineCommand(command, payload, options) {
|
|
|
131808
132174
|
};
|
|
131809
132175
|
}
|
|
131810
132176
|
function runWithLauncher(launcher, inputJson, timeout, signal, workingDirectory, startTime) {
|
|
131811
|
-
return new Promise((
|
|
132177
|
+
return new Promise((resolve31, reject) => {
|
|
131812
132178
|
const [executable, ...args] = launcher;
|
|
131813
132179
|
if (!executable) {
|
|
131814
132180
|
reject(new Error("Empty launcher"));
|
|
@@ -131821,7 +132187,7 @@ function runWithLauncher(launcher, inputJson, timeout, signal, workingDirectory,
|
|
|
131821
132187
|
const safeResolve = (result) => {
|
|
131822
132188
|
if (!resolved) {
|
|
131823
132189
|
resolved = true;
|
|
131824
|
-
|
|
132190
|
+
resolve31(result);
|
|
131825
132191
|
}
|
|
131826
132192
|
};
|
|
131827
132193
|
let child;
|
|
@@ -132998,14 +133364,14 @@ __export(exports_export, {
|
|
|
132998
133364
|
packageSkills: () => packageSkills
|
|
132999
133365
|
});
|
|
133000
133366
|
import { readdir as readdir10, readFile as readFile13 } from "node:fs/promises";
|
|
133001
|
-
import { relative as relative16, resolve as
|
|
133367
|
+
import { relative as relative16, resolve as resolve31 } from "node:path";
|
|
133002
133368
|
async function packageSkills(agentId, skillsDir) {
|
|
133003
133369
|
const skills = [];
|
|
133004
133370
|
const skillNames = new Set;
|
|
133005
133371
|
const dirsToCheck = skillsDir ? [skillsDir] : [
|
|
133006
133372
|
agentId && getAgentSkillsDir(agentId),
|
|
133007
|
-
|
|
133008
|
-
|
|
133373
|
+
resolve31(process.cwd(), ".skills"),
|
|
133374
|
+
resolve31(process.env.HOME || "~", ".letta", "skills")
|
|
133009
133375
|
].filter((dir) => Boolean(dir));
|
|
133010
133376
|
for (const baseDir of dirsToCheck) {
|
|
133011
133377
|
try {
|
|
@@ -133015,8 +133381,8 @@ async function packageSkills(agentId, skillsDir) {
|
|
|
133015
133381
|
continue;
|
|
133016
133382
|
if (skillNames.has(entry.name))
|
|
133017
133383
|
continue;
|
|
133018
|
-
const skillDir =
|
|
133019
|
-
const skillMdPath =
|
|
133384
|
+
const skillDir = resolve31(baseDir, entry.name);
|
|
133385
|
+
const skillMdPath = resolve31(skillDir, "SKILL.md");
|
|
133020
133386
|
try {
|
|
133021
133387
|
await readFile13(skillMdPath, "utf-8");
|
|
133022
133388
|
} catch {
|
|
@@ -133046,7 +133412,7 @@ async function readSkillFiles(skillDir) {
|
|
|
133046
133412
|
async function walk(dir) {
|
|
133047
133413
|
const entries = await readdir10(dir, { withFileTypes: true });
|
|
133048
133414
|
for (const entry of entries) {
|
|
133049
|
-
const fullPath =
|
|
133415
|
+
const fullPath = resolve31(dir, entry.name);
|
|
133050
133416
|
if (entry.isDirectory()) {
|
|
133051
133417
|
await walk(fullPath);
|
|
133052
133418
|
} else {
|
|
@@ -135530,7 +135896,7 @@ ${newState.originalPrompt}`,
|
|
|
135530
135896
|
cancelled = true;
|
|
135531
135897
|
break;
|
|
135532
135898
|
}
|
|
135533
|
-
await new Promise((
|
|
135899
|
+
await new Promise((resolve32) => setTimeout(resolve32, 100));
|
|
135534
135900
|
}
|
|
135535
135901
|
buffersRef.current.byId.delete(statusId);
|
|
135536
135902
|
buffersRef.current.order = buffersRef.current.order.filter((id) => id !== statusId);
|
|
@@ -135594,7 +135960,7 @@ ${newState.originalPrompt}`,
|
|
|
135594
135960
|
cancelled = true;
|
|
135595
135961
|
break;
|
|
135596
135962
|
}
|
|
135597
|
-
await new Promise((
|
|
135963
|
+
await new Promise((resolve32) => setTimeout(resolve32, 100));
|
|
135598
135964
|
}
|
|
135599
135965
|
if (retryStatusId) {
|
|
135600
135966
|
buffersRef.current.byId.delete(retryStatusId);
|
|
@@ -136352,7 +136718,7 @@ ${feedback}
|
|
|
136352
136718
|
});
|
|
136353
136719
|
buffersRef.current.order.push(statusId);
|
|
136354
136720
|
refreshDerived();
|
|
136355
|
-
await new Promise((
|
|
136721
|
+
await new Promise((resolve32) => setTimeout(resolve32, delayMs));
|
|
136356
136722
|
buffersRef.current.byId.delete(statusId);
|
|
136357
136723
|
buffersRef.current.order = buffersRef.current.order.filter((id) => id !== statusId);
|
|
136358
136724
|
refreshDerived();
|
|
@@ -136412,7 +136778,7 @@ ${feedback}
|
|
|
136412
136778
|
cancelled = true;
|
|
136413
136779
|
break;
|
|
136414
136780
|
}
|
|
136415
|
-
await new Promise((
|
|
136781
|
+
await new Promise((resolve32) => setTimeout(resolve32, 100));
|
|
136416
136782
|
}
|
|
136417
136783
|
if (retryStatusId) {
|
|
136418
136784
|
buffersRef.current.byId.delete(retryStatusId);
|
|
@@ -143626,11 +143992,11 @@ __export(exports_import2, {
|
|
|
143626
143992
|
extractSkillsFromAf: () => extractSkillsFromAf2
|
|
143627
143993
|
});
|
|
143628
143994
|
import { createReadStream as createReadStream2 } from "node:fs";
|
|
143629
|
-
import { chmod as chmod2, mkdir as mkdir8, readFile as readFile14, writeFile as
|
|
143630
|
-
import { dirname as dirname19, resolve as
|
|
143995
|
+
import { chmod as chmod2, mkdir as mkdir8, readFile as readFile14, writeFile as writeFile9 } from "node:fs/promises";
|
|
143996
|
+
import { dirname as dirname19, resolve as resolve32 } from "node:path";
|
|
143631
143997
|
async function importAgentFromFile2(options) {
|
|
143632
143998
|
const client = await getClient();
|
|
143633
|
-
const resolvedPath =
|
|
143999
|
+
const resolvedPath = resolve32(options.filePath);
|
|
143634
144000
|
const file = createReadStream2(resolvedPath);
|
|
143635
144001
|
const importResponse = await client.agents.importFile({
|
|
143636
144002
|
file,
|
|
@@ -143665,7 +144031,7 @@ async function extractSkillsFromAf2(afPath, destDir) {
|
|
|
143665
144031
|
return [];
|
|
143666
144032
|
}
|
|
143667
144033
|
for (const skill2 of afData.skills) {
|
|
143668
|
-
const skillDir =
|
|
144034
|
+
const skillDir = resolve32(destDir, skill2.name);
|
|
143669
144035
|
await mkdir8(skillDir, { recursive: true });
|
|
143670
144036
|
if (skill2.files) {
|
|
143671
144037
|
await writeSkillFiles2(skillDir, skill2.files);
|
|
@@ -143685,9 +144051,9 @@ async function writeSkillFiles2(skillDir, files) {
|
|
|
143685
144051
|
}
|
|
143686
144052
|
}
|
|
143687
144053
|
async function writeSkillFile2(skillDir, filePath, content) {
|
|
143688
|
-
const fullPath =
|
|
144054
|
+
const fullPath = resolve32(skillDir, filePath);
|
|
143689
144055
|
await mkdir8(dirname19(fullPath), { recursive: true });
|
|
143690
|
-
await
|
|
144056
|
+
await writeFile9(fullPath, content, "utf-8");
|
|
143691
144057
|
const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
|
|
143692
144058
|
if (isScript) {
|
|
143693
144059
|
try {
|
|
@@ -143740,7 +144106,7 @@ function parseRegistryHandle2(handle) {
|
|
|
143740
144106
|
async function importAgentFromRegistry2(options) {
|
|
143741
144107
|
const { tmpdir: tmpdir7 } = await import("node:os");
|
|
143742
144108
|
const { join: join50 } = await import("node:path");
|
|
143743
|
-
const { writeFile:
|
|
144109
|
+
const { writeFile: writeFile10, unlink: unlink3 } = await import("node:fs/promises");
|
|
143744
144110
|
const { author, name } = parseRegistryHandle2(options.handle);
|
|
143745
144111
|
const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER2}/${AGENT_REGISTRY_REPO2}/refs/heads/${AGENT_REGISTRY_BRANCH2}/agents/@${author}/${name}/${name}.af`;
|
|
143746
144112
|
const response = await fetch(rawUrl);
|
|
@@ -143752,7 +144118,7 @@ async function importAgentFromRegistry2(options) {
|
|
|
143752
144118
|
}
|
|
143753
144119
|
const afContent = await response.text();
|
|
143754
144120
|
const tempPath = join50(tmpdir7(), `letta-import-${author}-${name}-${Date.now()}.af`);
|
|
143755
|
-
await
|
|
144121
|
+
await writeFile10(tempPath, afContent, "utf-8");
|
|
143756
144122
|
try {
|
|
143757
144123
|
const result = await importAgentFromFile2({
|
|
143758
144124
|
filePath: tempPath,
|
|
@@ -148687,12 +149053,15 @@ async function runMemfsSubcommand(argv) {
|
|
|
148687
149053
|
|
|
148688
149054
|
// src/cli/subcommands/messages.ts
|
|
148689
149055
|
await init_client2();
|
|
149056
|
+
import { writeFile as writeFile6 } from "node:fs/promises";
|
|
149057
|
+
import { resolve as resolve23 } from "node:path";
|
|
148690
149058
|
import { parseArgs as parseArgs8 } from "node:util";
|
|
148691
149059
|
function printUsage5() {
|
|
148692
149060
|
console.log(`
|
|
148693
149061
|
Usage:
|
|
148694
149062
|
letta messages search --query <text> [options]
|
|
148695
149063
|
letta messages list [options]
|
|
149064
|
+
letta messages transcript --conversation <id> [options]
|
|
148696
149065
|
|
|
148697
149066
|
Search options:
|
|
148698
149067
|
--query <text> Search query (required)
|
|
@@ -148714,6 +149083,16 @@ List options:
|
|
|
148714
149083
|
--start-date <date> Client-side filter: after this date (ISO format)
|
|
148715
149084
|
--end-date <date> Client-side filter: before this date (ISO format)
|
|
148716
149085
|
|
|
149086
|
+
Transcript options:
|
|
149087
|
+
--conversation <id> Conversation ID to export (required)
|
|
149088
|
+
--conversation-id <id> Alias for --conversation
|
|
149089
|
+
--agent <id> Required when conversation is "default"
|
|
149090
|
+
--agent-id <id> Alias for --agent
|
|
149091
|
+
--limit <n> Page size while fetching (default: 100)
|
|
149092
|
+
--max-pages <n> Max pagination pages to fetch (default: 200)
|
|
149093
|
+
--out <path> Write transcript text to file
|
|
149094
|
+
--output <path> Alias for --out
|
|
149095
|
+
|
|
148717
149096
|
Notes:
|
|
148718
149097
|
- Output is JSON only.
|
|
148719
149098
|
- Uses CLI auth; override with LETTA_API_KEY/LETTA_BASE_URL if needed.
|
|
@@ -148755,7 +149134,12 @@ var MESSAGES_OPTIONS = {
|
|
|
148755
149134
|
"agent-id": { type: "string" },
|
|
148756
149135
|
after: { type: "string" },
|
|
148757
149136
|
before: { type: "string" },
|
|
148758
|
-
order: { type: "string" }
|
|
149137
|
+
order: { type: "string" },
|
|
149138
|
+
conversation: { type: "string" },
|
|
149139
|
+
"conversation-id": { type: "string" },
|
|
149140
|
+
"max-pages": { type: "string" },
|
|
149141
|
+
out: { type: "string" },
|
|
149142
|
+
output: { type: "string" }
|
|
148759
149143
|
};
|
|
148760
149144
|
function parseMessagesArgs(argv) {
|
|
148761
149145
|
return parseArgs8({
|
|
@@ -148782,6 +149166,115 @@ async function runMessagesSubcommand(argv) {
|
|
|
148782
149166
|
}
|
|
148783
149167
|
try {
|
|
148784
149168
|
const client = await getClient();
|
|
149169
|
+
const renderText = (value) => {
|
|
149170
|
+
if (typeof value === "string")
|
|
149171
|
+
return value;
|
|
149172
|
+
if (!Array.isArray(value))
|
|
149173
|
+
return "";
|
|
149174
|
+
return value.map((part) => {
|
|
149175
|
+
if (part && typeof part === "object" && "type" in part && part.type === "text" && "text" in part) {
|
|
149176
|
+
return typeof part.text === "string" ? part.text : "";
|
|
149177
|
+
}
|
|
149178
|
+
return "";
|
|
149179
|
+
}).filter((text) => text.length > 0).join(`
|
|
149180
|
+
`);
|
|
149181
|
+
};
|
|
149182
|
+
const renderUnknown = (value) => {
|
|
149183
|
+
if (typeof value === "string")
|
|
149184
|
+
return value;
|
|
149185
|
+
if (value === null || value === undefined)
|
|
149186
|
+
return "";
|
|
149187
|
+
try {
|
|
149188
|
+
return JSON.stringify(value);
|
|
149189
|
+
} catch {
|
|
149190
|
+
return String(value);
|
|
149191
|
+
}
|
|
149192
|
+
};
|
|
149193
|
+
const safeTypeLabel = (msg) => msg.message_type || "unknown_message";
|
|
149194
|
+
const formatEntry = (msg) => {
|
|
149195
|
+
const timestamp = msg.date || "unknown-time";
|
|
149196
|
+
const type = safeTypeLabel(msg);
|
|
149197
|
+
if (type === "user_message") {
|
|
149198
|
+
const text = renderText(msg.content);
|
|
149199
|
+
return [`[${timestamp}] user`, text || "(empty)"];
|
|
149200
|
+
}
|
|
149201
|
+
if (type === "assistant_message") {
|
|
149202
|
+
const text = renderText(msg.content);
|
|
149203
|
+
return [`[${timestamp}] assistant`, text || "(empty)"];
|
|
149204
|
+
}
|
|
149205
|
+
if (type === "reasoning_message") {
|
|
149206
|
+
return [
|
|
149207
|
+
`[${timestamp}] reasoning`,
|
|
149208
|
+
msg.reasoning && msg.reasoning.length > 0 ? msg.reasoning : "(empty)"
|
|
149209
|
+
];
|
|
149210
|
+
}
|
|
149211
|
+
if (type === "tool_call_message" || type === "approval_request_message") {
|
|
149212
|
+
const calls = Array.isArray(msg.tool_calls) ? msg.tool_calls : msg.tool_call ? [msg.tool_call] : [];
|
|
149213
|
+
if (calls.length === 0) {
|
|
149214
|
+
return [`[${timestamp}] ${type}`, "(no tool call payload)"];
|
|
149215
|
+
}
|
|
149216
|
+
return calls.flatMap((call) => {
|
|
149217
|
+
const header = `[${timestamp}] tool_call ${call.name || "unknown"} (${call.tool_call_id || "no-id"})`;
|
|
149218
|
+
const args = call.arguments ? call.arguments : "{}";
|
|
149219
|
+
return [header, args];
|
|
149220
|
+
});
|
|
149221
|
+
}
|
|
149222
|
+
if (type === "tool_return_message") {
|
|
149223
|
+
const returns = Array.isArray(msg.tool_returns) ? msg.tool_returns : [
|
|
149224
|
+
{
|
|
149225
|
+
tool_call_id: msg.tool_call_id,
|
|
149226
|
+
status: msg.status,
|
|
149227
|
+
tool_return: msg.tool_return,
|
|
149228
|
+
func_response: msg.func_response
|
|
149229
|
+
}
|
|
149230
|
+
];
|
|
149231
|
+
return returns.flatMap((ret) => {
|
|
149232
|
+
const header = `[${timestamp}] tool_return (${ret.tool_call_id || "no-id"}) status=${ret.status || "unknown"}`;
|
|
149233
|
+
const body = renderUnknown(ret.tool_return ?? ret.func_response);
|
|
149234
|
+
return [header, body || "(empty)"];
|
|
149235
|
+
});
|
|
149236
|
+
}
|
|
149237
|
+
const fallbackText = renderText(msg.content) || renderUnknown(msg.content) || "(no content)";
|
|
149238
|
+
return [`[${timestamp}] ${type}`, fallbackText];
|
|
149239
|
+
};
|
|
149240
|
+
const sortChronological3 = (messages) => {
|
|
149241
|
+
return [...messages].sort((a, b) => {
|
|
149242
|
+
const ta = a.date ? new Date(a.date).getTime() : 0;
|
|
149243
|
+
const tb = b.date ? new Date(b.date).getTime() : 0;
|
|
149244
|
+
return ta - tb;
|
|
149245
|
+
});
|
|
149246
|
+
};
|
|
149247
|
+
const fetchConversationMessages = async (conversationId, agentIdForDefault, pageLimit, maxPages) => {
|
|
149248
|
+
const collected = [];
|
|
149249
|
+
const seenIds = new Set;
|
|
149250
|
+
let cursorBefore;
|
|
149251
|
+
for (let pageIndex = 0;pageIndex < maxPages; pageIndex += 1) {
|
|
149252
|
+
const page = await client.conversations.messages.list(conversationId, {
|
|
149253
|
+
limit: pageLimit,
|
|
149254
|
+
order: "desc",
|
|
149255
|
+
...conversationId === "default" && agentIdForDefault ? { agent_id: agentIdForDefault } : {},
|
|
149256
|
+
...cursorBefore ? { before: cursorBefore } : {}
|
|
149257
|
+
});
|
|
149258
|
+
const items = page.getPaginatedItems();
|
|
149259
|
+
if (items.length === 0) {
|
|
149260
|
+
break;
|
|
149261
|
+
}
|
|
149262
|
+
let newItems = 0;
|
|
149263
|
+
for (const item of items) {
|
|
149264
|
+
const id = item.id;
|
|
149265
|
+
if (id && !seenIds.has(id)) {
|
|
149266
|
+
seenIds.add(id);
|
|
149267
|
+
collected.push(item);
|
|
149268
|
+
newItems += 1;
|
|
149269
|
+
}
|
|
149270
|
+
}
|
|
149271
|
+
cursorBefore = items[items.length - 1]?.id;
|
|
149272
|
+
if (newItems === 0 || items.length < pageLimit) {
|
|
149273
|
+
break;
|
|
149274
|
+
}
|
|
149275
|
+
}
|
|
149276
|
+
return sortChronological3(collected);
|
|
149277
|
+
};
|
|
148785
149278
|
if (action === "search") {
|
|
148786
149279
|
const query = parsed.values.query;
|
|
148787
149280
|
if (!query || typeof query !== "string") {
|
|
@@ -148846,6 +149339,44 @@ async function runMessagesSubcommand(argv) {
|
|
|
148846
149339
|
console.log(JSON.stringify(sorted, null, 2));
|
|
148847
149340
|
return 0;
|
|
148848
149341
|
}
|
|
149342
|
+
if (action === "transcript") {
|
|
149343
|
+
const conversationId = parsed.values.conversation || parsed.values["conversation-id"];
|
|
149344
|
+
if (!conversationId || typeof conversationId !== "string") {
|
|
149345
|
+
console.error("Missing conversation id. Pass --conversation <id> or --conversation-id <id>.");
|
|
149346
|
+
return 1;
|
|
149347
|
+
}
|
|
149348
|
+
const agentId = getAgentId5(parsed.values.agent, parsed.values["agent-id"]);
|
|
149349
|
+
if (conversationId === "default" && !agentId) {
|
|
149350
|
+
console.error('Conversation "default" requires an agent id. Set LETTA_AGENT_ID or pass --agent/--agent-id.');
|
|
149351
|
+
return 1;
|
|
149352
|
+
}
|
|
149353
|
+
const pageLimit = Math.max(1, parseLimit3(parsed.values.limit, 100));
|
|
149354
|
+
const maxPages = Math.max(1, parseLimit3(parsed.values["max-pages"], 200));
|
|
149355
|
+
const outputPathRaw = parsed.values.out || parsed.values.output;
|
|
149356
|
+
const messages = await fetchConversationMessages(conversationId, agentId || undefined, pageLimit, maxPages);
|
|
149357
|
+
const transcript = messages.flatMap((msg) => formatEntry(msg)).join(`
|
|
149358
|
+
|
|
149359
|
+
`).trim();
|
|
149360
|
+
if (outputPathRaw && typeof outputPathRaw === "string") {
|
|
149361
|
+
const outputPath = resolve23(process.cwd(), outputPathRaw);
|
|
149362
|
+
await writeFile6(outputPath, `${transcript}
|
|
149363
|
+
`, "utf-8");
|
|
149364
|
+
console.log(JSON.stringify({
|
|
149365
|
+
conversation_id: conversationId,
|
|
149366
|
+
agent_id: agentId || null,
|
|
149367
|
+
message_count: messages.length,
|
|
149368
|
+
output_path: outputPath
|
|
149369
|
+
}, null, 2));
|
|
149370
|
+
return 0;
|
|
149371
|
+
}
|
|
149372
|
+
console.log(JSON.stringify({
|
|
149373
|
+
conversation_id: conversationId,
|
|
149374
|
+
agent_id: agentId || null,
|
|
149375
|
+
message_count: messages.length,
|
|
149376
|
+
transcript
|
|
149377
|
+
}, null, 2));
|
|
149378
|
+
return 0;
|
|
149379
|
+
}
|
|
148849
149380
|
} catch (error) {
|
|
148850
149381
|
console.error(error instanceof Error ? error.message : String(error));
|
|
148851
149382
|
return 1;
|
|
@@ -148886,7 +149417,7 @@ async function runSubcommand(argv) {
|
|
|
148886
149417
|
init_readOnlyShell();
|
|
148887
149418
|
init_shell_command_normalization();
|
|
148888
149419
|
import { homedir as homedir23 } from "node:os";
|
|
148889
|
-
import { isAbsolute as isAbsolute16, join as join29, relative as relative12, resolve as
|
|
149420
|
+
import { isAbsolute as isAbsolute16, join as join29, relative as relative12, resolve as resolve24 } from "node:path";
|
|
148890
149421
|
var MODE_KEY2 = Symbol.for("@letta/permissionMode");
|
|
148891
149422
|
var PLAN_FILE_KEY2 = Symbol.for("@letta/planFilePath");
|
|
148892
149423
|
var MODE_BEFORE_PLAN_KEY2 = Symbol.for("@letta/permissionModeBeforePlan");
|
|
@@ -148922,12 +149453,12 @@ function resolvePlanTargetPath2(targetPath, workingDirectory) {
|
|
|
148922
149453
|
if (!trimmedPath)
|
|
148923
149454
|
return null;
|
|
148924
149455
|
if (trimmedPath.startsWith("~/")) {
|
|
148925
|
-
return
|
|
149456
|
+
return resolve24(homedir23(), trimmedPath.slice(2));
|
|
148926
149457
|
}
|
|
148927
149458
|
if (isAbsolute16(trimmedPath)) {
|
|
148928
|
-
return
|
|
149459
|
+
return resolve24(trimmedPath);
|
|
148929
149460
|
}
|
|
148930
|
-
return
|
|
149461
|
+
return resolve24(workingDirectory, trimmedPath);
|
|
148931
149462
|
}
|
|
148932
149463
|
function isPathInPlansDir2(path23, plansDir) {
|
|
148933
149464
|
if (!path23.endsWith(".md"))
|
|
@@ -149203,7 +149734,7 @@ await __promiseAll([
|
|
|
149203
149734
|
]);
|
|
149204
149735
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
149205
149736
|
import { homedir as homedir24 } from "node:os";
|
|
149206
|
-
import { join as join30, resolve as
|
|
149737
|
+
import { join as join30, resolve as resolve25 } from "node:path";
|
|
149207
149738
|
var DEFAULT_SETTINGS3 = {
|
|
149208
149739
|
lastAgent: null,
|
|
149209
149740
|
tokenStreaming: false,
|
|
@@ -149228,6 +149759,9 @@ var DEFAULT_LETTA_API_URL2 = "https://api.letta.com";
|
|
|
149228
149759
|
function isSubagentProcess2() {
|
|
149229
149760
|
return process.env.LETTA_CODE_AGENT_ROLE === "subagent";
|
|
149230
149761
|
}
|
|
149762
|
+
function shouldPersistSessionState2() {
|
|
149763
|
+
return process.env.LETTA_CODE_AGENT_ROLE !== "subagent" && process.env.LETTA_DISABLE_SESSION_PERSIST !== "1";
|
|
149764
|
+
}
|
|
149231
149765
|
function normalizeBaseUrl2(baseUrl) {
|
|
149232
149766
|
let normalized = baseUrl.replace(/^https?:\/\//, "");
|
|
149233
149767
|
normalized = normalized.replace(/\/$/, "");
|
|
@@ -149654,7 +150188,7 @@ class SettingsManager2 {
|
|
|
149654
150188
|
return join30(workingDirectory, ".letta", "settings.json");
|
|
149655
150189
|
}
|
|
149656
150190
|
isProjectSettingsPathCollidingWithGlobal(workingDirectory) {
|
|
149657
|
-
return
|
|
150191
|
+
return resolve25(this.getProjectSettingsPath(workingDirectory)) === resolve25(this.getSettingsPath());
|
|
149658
150192
|
}
|
|
149659
150193
|
getLocalProjectSettingsPath(workingDirectory) {
|
|
149660
150194
|
return join30(workingDirectory, ".letta", "settings.local.json");
|
|
@@ -150616,8 +151150,8 @@ function acquireSwitchLock2() {
|
|
|
150616
151150
|
const lock = getSwitchLock2();
|
|
150617
151151
|
lock.refCount++;
|
|
150618
151152
|
if (lock.refCount === 1) {
|
|
150619
|
-
lock.promise = new Promise((
|
|
150620
|
-
lock.resolve =
|
|
151153
|
+
lock.promise = new Promise((resolve26) => {
|
|
151154
|
+
lock.resolve = resolve26;
|
|
150621
151155
|
});
|
|
150622
151156
|
}
|
|
150623
151157
|
}
|
|
@@ -150888,6 +151422,7 @@ SUBCOMMANDS (JSON-only)
|
|
|
150888
151422
|
letta agents list [--query <text> | --name <name> | --tags <tags>]
|
|
150889
151423
|
letta messages search --query <text> [--all-agents]
|
|
150890
151424
|
letta messages list [--agent <id>]
|
|
151425
|
+
letta messages transcript --conversation <id> [--out <path>]
|
|
150891
151426
|
letta blocks list --agent <id>
|
|
150892
151427
|
letta blocks copy --block-id <id> [--label <label>] [--agent <id>] [--override]
|
|
150893
151428
|
letta blocks attach --block-id <id> [--agent <id>] [--read-only] [--override]
|
|
@@ -151076,14 +151611,6 @@ async function main() {
|
|
|
151076
151611
|
}
|
|
151077
151612
|
const { checkAndAutoUpdate: checkAndAutoUpdate2 } = await init_auto_update().then(() => exports_auto_update);
|
|
151078
151613
|
const autoUpdatePromise = startStartupAutoUpdateCheck(checkAndAutoUpdate2);
|
|
151079
|
-
const { startDockerVersionCheck: startDockerVersionCheck2 } = await init_startup_docker_check().then(() => exports_startup_docker_check);
|
|
151080
|
-
startDockerVersionCheck2().catch(() => {});
|
|
151081
|
-
const { cleanupOldOverflowFiles: cleanupOldOverflowFiles2 } = await Promise.resolve().then(() => (init_overflow2(), exports_overflow));
|
|
151082
|
-
Promise.resolve().then(() => {
|
|
151083
|
-
try {
|
|
151084
|
-
cleanupOldOverflowFiles2(process.cwd());
|
|
151085
|
-
} catch {}
|
|
151086
|
-
});
|
|
151087
151614
|
const processedArgs = preprocessCliArgs(process.argv);
|
|
151088
151615
|
let values;
|
|
151089
151616
|
let positionals;
|
|
@@ -151109,7 +151636,7 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
151109
151636
|
printHelp();
|
|
151110
151637
|
const helpDelayMs = Number.parseInt(process.env.LETTA_TEST_HELP_EXIT_DELAY_MS ?? "", 10);
|
|
151111
151638
|
if (Number.isFinite(helpDelayMs) && helpDelayMs > 0) {
|
|
151112
|
-
await new Promise((
|
|
151639
|
+
await new Promise((resolve33) => setTimeout(resolve33, helpDelayMs));
|
|
151113
151640
|
}
|
|
151114
151641
|
process.exit(0);
|
|
151115
151642
|
}
|
|
@@ -151194,6 +151721,16 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
151194
151721
|
const isHeadless = values.prompt || values.run || !process.stdin.isTTY;
|
|
151195
151722
|
telemetry2.setSurface(isHeadless ? "headless" : "tui");
|
|
151196
151723
|
telemetry2.init();
|
|
151724
|
+
if (!isHeadless) {
|
|
151725
|
+
const { startDockerVersionCheck: startDockerVersionCheck2 } = await init_startup_docker_check().then(() => exports_startup_docker_check);
|
|
151726
|
+
startDockerVersionCheck2().catch(() => {});
|
|
151727
|
+
const { cleanupOldOverflowFiles: cleanupOldOverflowFiles2 } = await Promise.resolve().then(() => (init_overflow2(), exports_overflow));
|
|
151728
|
+
Promise.resolve().then(() => {
|
|
151729
|
+
try {
|
|
151730
|
+
cleanupOldOverflowFiles2(process.cwd());
|
|
151731
|
+
} catch {}
|
|
151732
|
+
});
|
|
151733
|
+
}
|
|
151197
151734
|
if (command && !isHeadless) {
|
|
151198
151735
|
console.error(`Error: Unknown command or argument "${command}"`);
|
|
151199
151736
|
console.error("Run 'letta --help' for usage information.");
|
|
@@ -151321,9 +151858,9 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
151321
151858
|
process.exit(1);
|
|
151322
151859
|
}
|
|
151323
151860
|
} else {
|
|
151324
|
-
const { resolve:
|
|
151861
|
+
const { resolve: resolve33 } = await import("path");
|
|
151325
151862
|
const { existsSync: existsSync40 } = await import("fs");
|
|
151326
|
-
const resolvedPath =
|
|
151863
|
+
const resolvedPath = resolve33(fromAfFile);
|
|
151327
151864
|
if (!existsSync40(resolvedPath)) {
|
|
151328
151865
|
console.error(`Error: AgentFile not found: ${resolvedPath}`);
|
|
151329
151866
|
process.exit(1);
|
|
@@ -151798,6 +152335,7 @@ Error: ${message}`);
|
|
|
151798
152335
|
setLoadingState("initializing");
|
|
151799
152336
|
const { createAgent: createAgent3 } = await init_create3().then(() => exports_create2);
|
|
151800
152337
|
let agent = null;
|
|
152338
|
+
let autoEnableMemfsForFreshAgent = false;
|
|
151801
152339
|
if (fromAfFile2) {
|
|
151802
152340
|
setLoadingState("importing");
|
|
151803
152341
|
let result;
|
|
@@ -151882,10 +152420,7 @@ Error: ${message}`);
|
|
|
151882
152420
|
});
|
|
151883
152421
|
agent = result.agent;
|
|
151884
152422
|
setAgentProvenance(result.provenance);
|
|
151885
|
-
|
|
151886
|
-
const { enableMemfsIfCloud: enableMemfsIfCloud3 } = await Promise.resolve().then(() => (init_memoryFilesystem2(), exports_memoryFilesystem2));
|
|
151887
|
-
await enableMemfsIfCloud3(agent.id);
|
|
151888
|
-
}
|
|
152423
|
+
autoEnableMemfsForFreshAgent = willAutoEnableMemfs;
|
|
151889
152424
|
}
|
|
151890
152425
|
if (!agent && resumingAgentId) {
|
|
151891
152426
|
try {
|
|
@@ -151908,11 +152443,12 @@ Error: ${message}`);
|
|
|
151908
152443
|
settingsManager2.updateLocalProjectSettings({ lastAgent: agent.id });
|
|
151909
152444
|
settingsManager2.updateSettings({ lastAgent: agent.id });
|
|
151910
152445
|
setAgentContext(agent.id, skillsDirectory2, resolvedSkillSources);
|
|
151911
|
-
const isSubagent = process.env.LETTA_CODE_AGENT_ROLE === "subagent";
|
|
151912
152446
|
const agentId2 = agent.id;
|
|
151913
152447
|
const agentTags = agent.tags ?? undefined;
|
|
151914
|
-
const
|
|
151915
|
-
|
|
152448
|
+
const startupMemfsFlag = autoEnableMemfsForFreshAgent ? true : memfsFlag;
|
|
152449
|
+
const memfsSyncPromise = Promise.resolve().then(() => (init_memoryFilesystem2(), exports_memoryFilesystem2)).then(({ applyMemfsFlags: applyMemfsFlags3 }) => applyMemfsFlags3(agentId2, startupMemfsFlag, noMemfsFlag, {
|
|
152450
|
+
agentTags,
|
|
152451
|
+
skipPromptUpdate: shouldCreateNew
|
|
151916
152452
|
}));
|
|
151917
152453
|
const secretsInitPromise = init_secretsStore2().then(() => exports_secretsStore2).then(({ initSecretsFromServer: initSecretsFromServer3 }) => initSecretsFromServer3(agentId2));
|
|
151918
152454
|
const isResumingProject = !shouldCreateNew && !!resumingAgentId;
|
|
@@ -152053,7 +152589,7 @@ Error: ${message}`);
|
|
|
152053
152589
|
}
|
|
152054
152590
|
}
|
|
152055
152591
|
}
|
|
152056
|
-
if (
|
|
152592
|
+
if (shouldPersistSessionState2()) {
|
|
152057
152593
|
settingsManager2.persistSession(agent.id, conversationIdToUse);
|
|
152058
152594
|
}
|
|
152059
152595
|
setAgentId(agent.id);
|
|
@@ -152199,4 +152735,4 @@ Error during initialization: ${message}`);
|
|
|
152199
152735
|
}
|
|
152200
152736
|
main();
|
|
152201
152737
|
|
|
152202
|
-
//# debugId=
|
|
152738
|
+
//# debugId=AA1793542E1A081B64756E2164756E21
|