@letta-ai/letta-code 0.34.17 → 0.34.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/agent-presets.js +5 -1
- package/dist/agent-presets.js.map +2 -2
- package/dist/gateway-core.js +2 -2
- package/dist/gateway-core.js.map +3 -3
- package/dist/mcp-client.js +2 -2
- package/dist/mcp-client.js.map +1 -1
- package/dist/mcp-oauth.js +2 -2
- package/dist/mcp-oauth.js.map +1 -1
- package/dist/types/agent/approval-execution.d.ts +33 -1
- package/dist/types/agent/approval-execution.d.ts.map +1 -1
- package/dist/types/agent/client-skills.d.ts.map +1 -1
- package/dist/types/agent/parent-memory-note.d.ts +3 -0
- package/dist/types/agent/parent-memory-note.d.ts.map +1 -0
- package/dist/types/agent/preloaded-skills.d.ts +4 -0
- package/dist/types/agent/preloaded-skills.d.ts.map +1 -0
- package/dist/types/agent/skills.d.ts.map +1 -1
- package/dist/types/agent/subagent-state.d.ts +53 -2
- package/dist/types/agent/subagent-state.d.ts.map +1 -1
- package/dist/types/agent/subagents/child-send-tracking.d.ts.map +1 -1
- package/dist/types/agent/subagents/index.d.ts.map +1 -1
- package/dist/types/agent/subagents/remote-turn-wait.d.ts.map +1 -1
- package/dist/types/agent/subagents/subagent-stream.d.ts.map +1 -1
- package/dist/types/auth/oauth.d.ts +8 -1
- package/dist/types/auth/oauth.d.ts.map +1 -1
- package/dist/types/backend/api/conversation-enqueue.d.ts +4 -1
- package/dist/types/backend/api/conversation-enqueue.d.ts.map +1 -1
- package/dist/types/channels/message-channel-executor.d.ts.map +1 -1
- package/dist/types/cli/helpers/agent-info.d.ts +1 -0
- package/dist/types/cli/helpers/agent-info.d.ts.map +1 -1
- package/dist/types/cli/subcommands/mcp.d.ts +3 -1
- package/dist/types/cli/subcommands/mcp.d.ts.map +1 -1
- package/dist/types/headless-listener-launch.d.ts +5 -3
- package/dist/types/headless-listener-launch.d.ts.map +1 -1
- package/dist/types/headless-super-run-wait.d.ts +1 -1
- package/dist/types/headless-super-run-wait.d.ts.map +1 -1
- package/dist/types/reminders/engine.d.ts.map +1 -1
- package/dist/types/telemetry/channel.d.ts.map +1 -1
- package/dist/types/tools/external-tool-background-eligibility.d.ts +2 -1
- package/dist/types/tools/external-tool-background-eligibility.d.ts.map +1 -1
- package/dist/types/tools/external-tool-background.d.ts +14 -1
- package/dist/types/tools/external-tool-background.d.ts.map +1 -1
- package/dist/types/tools/external-tool-types.d.ts +1 -0
- package/dist/types/tools/external-tool-types.d.ts.map +1 -1
- package/dist/types/tools/impl/external-coding-agent.d.ts.map +1 -1
- package/dist/types/tools/impl/monitor.d.ts +2 -0
- package/dist/types/tools/impl/monitor.d.ts.map +1 -1
- package/dist/types/tools/impl/remote-external-coding-agent.d.ts +1 -0
- package/dist/types/tools/impl/remote-external-coding-agent.d.ts.map +1 -1
- package/dist/types/tools/impl/task-abort-hook.d.ts +2 -0
- package/dist/types/tools/impl/task-abort-hook.d.ts.map +1 -0
- package/dist/types/tools/impl/task-stop.d.ts.map +1 -1
- package/dist/types/tools/impl/task.d.ts.map +1 -1
- package/dist/types/tools/impl/watch-pr.d.ts +1 -1
- package/dist/types/tools/impl/watch-pr.d.ts.map +1 -1
- package/dist/types/tools/impl/workflow.d.ts +7 -0
- package/dist/types/tools/impl/workflow.d.ts.map +1 -1
- package/dist/types/tools/manager.d.ts +1 -1
- package/dist/types/tools/manager.d.ts.map +1 -1
- package/dist/types/tools/script-tool-scope.d.ts.map +1 -1
- package/dist/types/tools/workflow/sdk-spawner.d.ts.map +1 -1
- package/dist/types/tools/workflow/types.d.ts +2 -0
- package/dist/types/tools/workflow/types.d.ts.map +1 -1
- package/dist/types/utils/subagent-scope.d.ts +13 -0
- package/dist/types/utils/subagent-scope.d.ts.map +1 -0
- package/dist/types/utils/task-notifications.d.ts +43 -0
- package/dist/types/utils/task-notifications.d.ts.map +1 -1
- package/letta.js +1182 -692
- package/npm-shrinkwrap.json +98 -98
- package/package.json +2 -2
- package/scripts/claude-watch/docs-snapshot.test.ts +65 -0
- package/scripts/claude-watch/docs-snapshot.ts +10 -4
- package/scripts/isolated-unit-tests.json +5 -0
- package/scripts/source-file-size-baseline.json +9 -9
- package/skills/finding-agents/SKILL.md +0 -4
- package/skills/maintaining-core-memory/SKILL.md +101 -0
- package/skills/maintaining-deferred-memory/SKILL.md +84 -0
- package/skills/workflow-authoring/SKILL.md +3 -1
- package/skills/curating-memory-palace/SKILL.md +0 -147
- package/skills/migrating-memory/SKILL.md +0 -98
package/letta.js
CHANGED
|
@@ -3411,6 +3411,7 @@ __export(exports_oauth, {
|
|
|
3411
3411
|
validateCredentialsWithResult: () => validateCredentialsWithResult,
|
|
3412
3412
|
validateCredentials: () => validateCredentials,
|
|
3413
3413
|
revokeToken: () => revokeToken,
|
|
3414
|
+
resolveAuthBaseUrl: () => resolveAuthBaseUrl,
|
|
3414
3415
|
requestDeviceCode: () => requestDeviceCode2,
|
|
3415
3416
|
refreshAccessToken: () => refreshAccessToken3,
|
|
3416
3417
|
pollForToken: () => pollForToken2,
|
|
@@ -3418,6 +3419,28 @@ __export(exports_oauth, {
|
|
|
3418
3419
|
OAUTH_CONFIG: () => OAUTH_CONFIG,
|
|
3419
3420
|
LETTA_CLOUD_API_URL: () => LETTA_CLOUD_API_URL
|
|
3420
3421
|
});
|
|
3422
|
+
function resolveAuthBaseUrl() {
|
|
3423
|
+
const override = process.env.LETTA_AUTH_BASE_URL?.trim();
|
|
3424
|
+
if (!override) {
|
|
3425
|
+
return DEFAULT_AUTH_BASE_URL;
|
|
3426
|
+
}
|
|
3427
|
+
let warning = null;
|
|
3428
|
+
try {
|
|
3429
|
+
const url = new URL(override);
|
|
3430
|
+
const isLocalhost = url.hostname === "localhost" || url.hostname === "127.0.0.1";
|
|
3431
|
+
if (url.protocol === "https:" || url.protocol === "http:" && isLocalhost) {
|
|
3432
|
+
return url.origin;
|
|
3433
|
+
}
|
|
3434
|
+
warning = "must be an https origin (http is allowed for localhost)";
|
|
3435
|
+
} catch {
|
|
3436
|
+
warning = "is not a valid URL";
|
|
3437
|
+
}
|
|
3438
|
+
if (!hasWarnedAboutInvalidAuthBaseUrl) {
|
|
3439
|
+
hasWarnedAboutInvalidAuthBaseUrl = true;
|
|
3440
|
+
console.warn(`Ignoring invalid LETTA_AUTH_BASE_URL (${JSON.stringify(override)}): ${warning}. Falling back to ${DEFAULT_AUTH_BASE_URL}.`);
|
|
3441
|
+
}
|
|
3442
|
+
return DEFAULT_AUTH_BASE_URL;
|
|
3443
|
+
}
|
|
3421
3444
|
function getOAuthAuthHost() {
|
|
3422
3445
|
try {
|
|
3423
3446
|
return new URL(OAUTH_CONFIG.authBaseUrl).host;
|
|
@@ -3776,7 +3799,7 @@ function classifyCredentialValidationError(error) {
|
|
|
3776
3799
|
}
|
|
3777
3800
|
return { ok: false, reason: "unknown", message };
|
|
3778
3801
|
}
|
|
3779
|
-
var LETTA_CLOUD_API_URL = "https://api.letta.com", OAUTH_CONFIG, OAuthRefreshError, DEVICE_CODE_REQUEST_MAX_ATTEMPTS = 2, DEVICE_CODE_RETRY_DELAY_MS = 100, TOKEN_POLL_RESPONSE_FAILURE_LIMIT = 2, OAUTH_REQUEST_ID_HEADERS, OAuthTransientResponseError;
|
|
3802
|
+
var LETTA_CLOUD_API_URL = "https://api.letta.com", DEFAULT_AUTH_BASE_URL = "https://app.letta.com", hasWarnedAboutInvalidAuthBaseUrl = false, OAUTH_CONFIG, OAuthRefreshError, DEVICE_CODE_REQUEST_MAX_ATTEMPTS = 2, DEVICE_CODE_RETRY_DELAY_MS = 100, TOKEN_POLL_RESPONSE_FAILURE_LIMIT = 2, OAUTH_REQUEST_ID_HEADERS, OAuthTransientResponseError;
|
|
3780
3803
|
var init_oauth = __esm(() => {
|
|
3781
3804
|
init_letta_client();
|
|
3782
3805
|
init_error();
|
|
@@ -3784,7 +3807,9 @@ var init_oauth = __esm(() => {
|
|
|
3784
3807
|
OAUTH_CONFIG = {
|
|
3785
3808
|
clientId: "ci-let-724dea7e98f4af6f8f370f4b1466200c",
|
|
3786
3809
|
clientSecret: "",
|
|
3787
|
-
authBaseUrl
|
|
3810
|
+
get authBaseUrl() {
|
|
3811
|
+
return resolveAuthBaseUrl();
|
|
3812
|
+
},
|
|
3788
3813
|
apiBaseUrl: LETTA_CLOUD_API_URL
|
|
3789
3814
|
};
|
|
3790
3815
|
OAuthRefreshError = class OAuthRefreshError extends Error {
|
|
@@ -5916,7 +5941,7 @@ var package_default;
|
|
|
5916
5941
|
var init_package = __esm(() => {
|
|
5917
5942
|
package_default = {
|
|
5918
5943
|
name: "@letta-ai/letta-code",
|
|
5919
|
-
version: "0.34.
|
|
5944
|
+
version: "0.34.19",
|
|
5920
5945
|
lettaStartupLogProtocol: 1,
|
|
5921
5946
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
5922
5947
|
type: "module",
|
|
@@ -6191,7 +6216,7 @@ var init_package = __esm(() => {
|
|
|
6191
6216
|
},
|
|
6192
6217
|
lettaLifecycleProtocol: 1,
|
|
6193
6218
|
lettaRuntimeGraphProtocol: 1,
|
|
6194
|
-
lettaRuntimeGraphSha512: "sha512-
|
|
6219
|
+
lettaRuntimeGraphSha512: "sha512-RWgzMK/RLJluHmJEAXwWV7NZe1gpOgg3BYpp8+G8QfqsXUUmzZgQpQz5E9CHogeIwfcGzCaHAUIdboH6Ir7KyA=="
|
|
6195
6220
|
};
|
|
6196
6221
|
});
|
|
6197
6222
|
|
|
@@ -6463,6 +6488,7 @@ function telemetryChannel(value) {
|
|
|
6463
6488
|
return;
|
|
6464
6489
|
return [
|
|
6465
6490
|
"slack",
|
|
6491
|
+
"microsoftteams",
|
|
6466
6492
|
"microsoftTeams",
|
|
6467
6493
|
"telegram",
|
|
6468
6494
|
"discord",
|
|
@@ -99266,6 +99292,8 @@ You may also have access to shared memory: memory created independently of any s
|
|
|
99266
99292
|
|
|
99267
99293
|
Unlike the rest of your external memory, shared memory is not scoped to *you* specifically (since it may be attached to multiple agents at the same time), so each shared memory repository will have a different local projection root and remote git origin.
|
|
99268
99294
|
|
|
99295
|
+
Attached shared-memory mounts are shallow checkouts containing only the latest commit. If you need past history, run \`git fetch --deepen=<n>\` or \`git fetch --unshallow\` inside the mount only when needed, since some repositories have very long histories.
|
|
99296
|
+
|
|
99269
99297
|
Commit intended changes inside read/write attached shared-memory repositories. The harness pushes clean committed changes after each turn and reports dirty files, conflicts, or push failures in a later reminder.
|
|
99270
99298
|
|
|
99271
99299
|
### Syncing memory, state, and context
|
|
@@ -99823,6 +99851,8 @@ You may also have access to shared memory: memory created independently of any s
|
|
|
99823
99851
|
|
|
99824
99852
|
Unlike the rest of your external memory, shared memory is not scoped to *you* specifically (since it may be attached to multiple agents at the same time), so each shared memory repository will have a different local projection root and remote git origin.
|
|
99825
99853
|
|
|
99854
|
+
Attached shared-memory mounts are shallow checkouts containing only the latest commit. If you need past history, run \`git fetch --deepen=<n>\` or \`git fetch --unshallow\` inside the mount only when needed, since some repositories have very long histories.
|
|
99855
|
+
|
|
99826
99856
|
Commit intended changes inside read/write attached shared-memory repositories. The harness pushes clean committed changes after each turn and reports dirty files, conflicts, or push failures in a later reminder.
|
|
99827
99857
|
|
|
99828
99858
|
### Syncing memory, state, and context
|
|
@@ -103471,7 +103501,7 @@ async function syncRepoMount(args) {
|
|
|
103471
103501
|
await withRepositoryCheckout(args.directory, async (directory, fresh) => {
|
|
103472
103502
|
args = { ...args, publishedDirectory: args.directory, directory };
|
|
103473
103503
|
if (fresh) {
|
|
103474
|
-
await runGitWithRetry(directory, ["clone", args.remoteUrl, "."], args.token, {
|
|
103504
|
+
await runGitWithRetry(directory, ["clone", "--depth", "1", args.remoteUrl, "."], args.token, {
|
|
103475
103505
|
operation: `clone repository ${args.repositoryName}`,
|
|
103476
103506
|
timeoutMs: GIT_CLONE_TIMEOUT_MS
|
|
103477
103507
|
});
|
|
@@ -106605,34 +106635,29 @@ name: memory
|
|
|
106605
106635
|
description: Background memory upkeep during another task; when memory is the user's main request, edit it directly instead. Runs silently with no notification or result, so continue immediately. Make the assignment self-contained and quote the user's corrections and exceptions verbatim.
|
|
106606
106636
|
tools: Bash, Read, Edit, Write
|
|
106607
106637
|
model: inherit
|
|
106608
|
-
skills: creating-skills
|
|
106638
|
+
skills: creating-skills, maintaining-core-memory, maintaining-deferred-memory
|
|
106609
106639
|
fork: false
|
|
106610
106640
|
launchProfile: memory-subagent
|
|
106611
106641
|
---
|
|
106612
106642
|
|
|
106613
|
-
You are
|
|
106614
|
-
|
|
106615
|
-
Your tools are Bash, Read, Edit, and Write. Your working memory repository is \`$MEMORY_DIR\`; the assignment also gives the exact path. For a memory update it is a private worktree of the agent's memory: the harness merges your commits into the main checkout when you finish, and anything left uncommitted is discarded. For a Git repair it is the checkout itself. Read current files before editing; memory may have changed since the assignment. Keep all writes inside this repository. Do not modify git configuration or hook files.
|
|
106616
|
-
|
|
106617
|
-
## Updating memory
|
|
106618
|
-
|
|
106619
|
-
Capture the requested facts, preferences, corrections, or deletions. Use the assignment directly when it is sufficient. Consult the parent transcript only for a specific missing fact or ambiguity; do not read it for general orientation. Preserve the exact scope of facts and exceptions without adding inferred preferences. Keep quoted factual corrections and constraints verbatim rather than generalizing them. Update existing entries rather than duplicating them, and replace stale information at its source. Preserve unrelated content and established identity. Do not store secrets or ephemeral task logs. Update indexes when adding, moving, or deleting files.
|
|
106620
|
-
|
|
106621
|
-
Make focused edits. Reorganize or defragment memory only when explicitly requested. Do not perform transcript reflection or unrelated skill maintenance. For requested skill changes, apply the preloaded \`creating-skills\` guidance in \`$MEMORY_DIR/skills/\`; maintain skills in place rather than packaging them for distribution.
|
|
106643
|
+
You are a background memory subagent. Make the memory change in the assignment below, following the preloaded skills; consult the parent transcript only for a specific missing fact or ambiguity.
|
|
106622
106644
|
|
|
106623
106645
|
## Git
|
|
106624
106646
|
|
|
106625
|
-
|
|
106647
|
+
\`$MEMORY_DIR\` is a private worktree of the agent's memory. The harness merges your commits into the main checkout when you finish and handles sync, so commit but do not push; uncommitted edits are discarded. If a merge or rebase is already in progress, resolve it by reading both sides and preserving the intended memory, then finish the operation; do not abort, reset, stash, or amend.
|
|
106626
106648
|
|
|
106627
|
-
|
|
106649
|
+
Stage only the files you changed, by explicit path, and commit them in one call:
|
|
106628
106650
|
|
|
106629
|
-
|
|
106630
|
-
|
|
106631
|
-
|
|
106651
|
+
\`\`\`bash
|
|
106652
|
+
cd "$MEMORY_DIR"
|
|
106653
|
+
git add <file>...
|
|
106654
|
+
git commit -m "<type>(memory): <summary>
|
|
106632
106655
|
|
|
106633
|
-
|
|
106656
|
+
Updates:
|
|
106657
|
+
- <what changed and why>"
|
|
106658
|
+
\`\`\`
|
|
106634
106659
|
|
|
106635
|
-
|
|
106660
|
+
\`<type>\` is \`fix\` for correcting wrong or stale memory, \`feat\` for new memory, and \`chore\` for reorganization or minor edits. Do not change git configuration or bypass hooks; if the commit fails, report the failure rather than claiming success.
|
|
106636
106661
|
`;
|
|
106637
106662
|
var init_memory_v2 = () => {};
|
|
106638
106663
|
|
|
@@ -106862,121 +106887,28 @@ name: reflection
|
|
|
106862
106887
|
description: Background agent that reflects on recent conversations to update memory and maintain skills
|
|
106863
106888
|
tools: Bash, Edit
|
|
106864
106889
|
model: inherit
|
|
106865
|
-
skills: creating-skills
|
|
106890
|
+
skills: creating-skills, maintaining-core-memory, maintaining-deferred-memory
|
|
106866
106891
|
launchProfile: memory-subagent
|
|
106867
106892
|
---
|
|
106893
|
+
You are a reflection subagent tasked with improving a primary agent's capabilities and knowledge to perform better on future tasks.
|
|
106894
|
+
Using recent conversation transcripts, identify potential repeatable workflows (which can be converted into skills), behavior failures (which require updates to prompts), and general information and knowledge.
|
|
106895
|
+
The primary agent's context (prompts, skills, and deferred memory) is stored in $MEMORY_DIR, which contains the "Memory Filesystem" of the primary agent.
|
|
106896
|
+
Read through the transcript to identify and make updates to memory. You run autonomously and return a single final report when done. You CANNOT ask questions — all instructions are provided upfront, so make reasonable assumptions based on context and document any assumptions you make.
|
|
106868
106897
|
|
|
106869
|
-
You are
|
|
106870
|
-
|
|
106871
|
-
**You are NOT the primary agent.** You are reviewing conversations that already happened:
|
|
106872
|
-
- "system" messages are the primary agent's system prompt — use them only to understand the agent's identity and what's relevant to the user. They are not something you edit directly; memory edits flow through files in \`$MEMORY_DIR\`.
|
|
106873
|
-
- "assistant" messages are from the primary agent
|
|
106874
|
-
- "user" messages are from the primary agent's user
|
|
106875
|
-
|
|
106876
|
-
Your job is to turn lasting learnings from those conversations into changes to the primary agent's memory filesystem: memory edits for facts, preferences, and corrections, and — only when a reusable procedure appears — skill changes. Then commit them.
|
|
106877
|
-
|
|
106878
|
-
## The Memory Filesystem
|
|
106879
|
-
|
|
106880
|
-
The primary agent's context (its prompts, skills, and external memory files) is stored in a git-backed "memory filesystem" rooted at \`$MEMORY_DIR\`. Committed changes are reflected in the primary agent's context. Every piece of memory lives in one of three tiers, and the tier decides when the agent sees it and how it should be written:
|
|
106881
|
-
|
|
106882
|
-
| | **Root files** | **Deferred memory** | **Skills** |
|
|
106883
|
-
|---|---|---|---|
|
|
106884
|
-
| **Location** | Markdown files directly in \`$MEMORY_DIR\` | Directories under \`$MEMORY_DIR\` (other than \`skills/\`) | \`$MEMORY_DIR/skills/<name>/\` |
|
|
106885
|
-
| **When the agent sees it** | Every turn, in full — part of the system prompt | Only when the agent opens the directory with \`Memory(<dir>)\` or reads a file | Name and description every turn; the body only when the agent loads the skill |
|
|
106886
|
-
| **Cost** | Paid on every turn | Paid only when opened | Description on every turn; body only when loaded |
|
|
106887
|
-
| **What belongs here** | Identity, standing instructions, and facts that matter on every turn; the root \`MEMORY.md\` index of deferred memory | Knowledge about a subject (a person, project, repo, system, or incident) that the agent looks up when that subject comes up | Procedures with a clear "use when" trigger — usually a repeatable, multi-step workflow |
|
|
106888
|
-
| **Written as** | Instructions to the agent | Reference notes: instructions about the subject first, then facts | A procedure: steps, exact commands, pitfalls |
|
|
106889
|
-
| **Description says** | What belongs in the file | What the memory is *about* | What the skill does (third person) and when to use it |
|
|
106890
|
-
|
|
106891
|
-
### Choosing a tier
|
|
106892
|
-
|
|
106893
|
-
Decide placement for each learning in this order:
|
|
106894
|
-
|
|
106895
|
-
1. **Should it change how the agent behaves or what it knows on every turn?** Put it in a root file, written as an instruction. Root is expensive, so this bar is high.
|
|
106896
|
-
2. **Can you write a clear "Use when the user wants to …" trigger for it, and is it a procedure?** Make it a skill (see "Skills" below for when a skill is warranted).
|
|
106897
|
-
3. **Otherwise it is knowledge about a subject.** Put it in deferred memory, in the directory for that subject.
|
|
106898
|
-
|
|
106899
|
-
One-off task state belongs nowhere.
|
|
106900
|
-
|
|
106901
|
-
### Root files
|
|
106902
|
-
|
|
106903
|
-
Root Markdown files are part of the primary agent's system prompt: always in context and visible to the agent. Use them to define the core behavior of the agent: what it always knows, and the prompting that controls how it behaves.
|
|
106904
|
-
|
|
106905
|
-
Writing root files:
|
|
106906
|
-
* Write instructions, not explicit feedback. User or environment feedback tells you how the agent's behavior or knowledge should change. Write a prompt to affect this change, rather than simply recording the feedback.
|
|
106907
|
-
* Leave out the evidence or context for the edit. All context modifications are git-tracked with commit messages, so do not require an explanation for why an edit was made within the edit or details about the context under which the edit was made.
|
|
106908
|
-
* Minimize bloat. Too many tokens can distract agents and add cost to every turn. Instructions that are only needed sometimes belong in a skill (if a trigger can be defined) or in deferred memory.
|
|
106909
|
-
* Root files that define the agent's identity and behavior (such as \`persona.md\`) are load-bearing. Edit them surgically — append, modify specific entries, adjust wording. Never rewrite them wholesale or silently overwrite established identity.
|
|
106910
|
-
|
|
106911
|
-
**The root \`MEMORY.md\` is the only entry point to deferred memory.** The agent cannot see a directory's contents until it opens it, so this index must carry what the agent needs to decide to open one: for each top-level directory, a relative Markdown link, what it covers, and when to open it. For example:
|
|
106912
|
-
|
|
106913
|
-
\`\`\`
|
|
106914
|
-
- [letta-code/](letta-code/MEMORY.md) — repo conventions, CI, release process. Open before working in letta-code.
|
|
106915
|
-
\`\`\`
|
|
106916
|
-
|
|
106917
|
-
This is where "when to use" belongs for deferred memory — in the parent's link, not in the memory's own description.
|
|
106898
|
+
You are not the primary agent and do not reply to anyone. In the transcript, "assistant" messages are the primary agent, "user" messages are its user, and "system" messages are its system prompt, compiled from the memory files you edit.
|
|
106918
106899
|
|
|
106919
|
-
|
|
106920
|
-
|
|
106921
|
-
Directories contain *deferred memory*. Higher directory levels hold memory that is accessed more often; more deeply nested directories hold memory needed less often. Place related memory in the same directory so it can be loaded together. Each directory has a \`MEMORY.md\`, which is the directory's top level: when the primary agent calls \`Memory(<dir>)\`, it reads \`<dir>/MEMORY.md\` in full, plus a listing of the directory's other entries (each file's \`description\` and the first paragraph of each subdirectory's \`MEMORY.md\`). The listing shows at most 10 entries, most recently edited first. The agent can also read files directly with other tools.
|
|
106922
|
-
|
|
106923
|
-
Decide what goes in a \`MEMORY.md\` by what the agent should get from opening that directory:
|
|
106924
|
-
* **Small topic: put everything in \`MEMORY.md\`.** If the whole topic fits comfortably (well under 20,000 characters) and most of it is useful whenever the topic comes up, keep it in \`MEMORY.md\` with no other files. Splitting adds reads without saving context.
|
|
106925
|
-
* **Large topic, or one rarely needed in full: \`MEMORY.md\` holds what is needed every time, plus a map.** Keep only what the agent needs whenever it opens the directory, and defer the rest into files, or into subdirectories when a subtopic is itself large. \`MEMORY.md\` must then tell the agent where to go next, or that it can stop: say what each deferred file or subdirectory covers and when it is worth opening, using ordinary relative Markdown links. Do not rely on the listing, since it shows only the 10 most recently edited entries and stable files fall out of it.
|
|
106926
|
-
* **Either way, start \`MEMORY.md\` with a short plain-prose paragraph stating the directory's scope.** That paragraph is what the parent directory's listing shows, so do not open with a heading or a list.
|
|
106927
|
-
* Aim for fewer than 10 entries (files plus subdirectories) per directory so the listing stays complete; group related files into subdirectories only within the configured \`maxDepth\` (see below). At the depth limit, use clearly scoped sibling files and explicit links in \`MEMORY.md\`, or reorganize topics into shallower directories. The depth limit takes precedence over the fewer-than-10-entries guideline.
|
|
106928
|
-
|
|
106929
|
-
Writing deferred memory contents (in \`MEMORY.md\` and in other files):
|
|
106930
|
-
* **One subject per file**, named the way a future request would name it. If two files cover the same subject, merge them.
|
|
106931
|
-
* **Instructions first, then facts.** The agent opens deferred memory because it is about to act on that subject, so lead with what it should do differently — conventions, gotchas, things to avoid — written as instructions, like root files. Background facts follow.
|
|
106932
|
-
* **Make each statement stand alone.** Name the subject ("The letta-code release workflow …") rather than "it" or "the repo"; the agent may read only part of a file.
|
|
106933
|
-
* **Organize by topic under stable headings, not as a dated log.** Record the current state and fix contradictions in place. Use absolute dates only for facts that are genuinely time-bound.
|
|
106934
|
-
* **Leave out evidence and history**, as with root files. Git keeps it.
|
|
106935
|
-
|
|
106936
|
-
Writing memory descriptions (every deferred file other than \`MEMORY.md\`):
|
|
106937
|
-
* Describe what the memory is *about*, not when to use it. Lead with the subject (a person, project, repo, system, or incident) using the names a future request would mention, then the subtopics it covers.
|
|
106938
|
-
* If you can write a clear "use when the user wants to…" trigger, the content is procedural and belongs in a skill.
|
|
106939
|
-
* Make siblings distinguishable by subject; if two files cover the same subject, merge them.
|
|
106940
|
-
* Describe scope, not current contents: no entry lists, dates, status, or why the file was created.
|
|
106941
|
-
|
|
106942
|
-
### Skills
|
|
106943
|
-
|
|
106944
|
-
The \`skills/\` folder contains skills (folders which adhere to the skills specification). Skills are loaded by the primary agent with a \`Skill\` tool. Skill names and descriptions are automatically provided to the agent in context, so skills do not need to be indexed by \`MEMORY.md\` unless they relate to a specific memory.
|
|
106945
|
-
|
|
106946
|
-
Skills are not the default. A one-off task, a fact, or a preference belongs in memory, not a skill. Use a skill only when the conversation reveals a repeatable procedure that clearly generalizes beyond this session and has a trigger you can state.
|
|
106947
|
-
|
|
106948
|
-
Apply the preloaded \`creating-skills\` guidance to skills in \`$MEMORY_DIR/skills/\`; maintain them in place rather than packaging them for distribution.
|
|
106949
|
-
|
|
106950
|
-
### Frontmatter, size, and nesting limits
|
|
106951
|
-
|
|
106952
|
-
* \`MEMORY.md\` files (root and child) have no frontmatter.
|
|
106953
|
-
* Every other memory Markdown file has exactly \`name\` and \`description\` frontmatter; the memory repo's pre-commit check rejects missing or extra keys.
|
|
106954
|
-
* \`SKILL.md\` files are exempt from that check and follow the preloaded \`creating-skills\` guidance instead.
|
|
106955
|
-
* By default the memory repo's pre-commit check blocks any memory file over 20,000 characters and root Markdown totaling over 65,536 characters (\`.memfs.config.json\` may override these). Root files are paid for on every turn, so keep them well below the limits and move detail into child directories rather than growing root.
|
|
106956
|
-
* **Nesting is bounded by \`maxDepth\` in \`$MEMORY_DIR/.memfs.config.json\`.** The default configuration sets \`maxDepth: 2\`. Depth counts directories between the repo root and a memory file: \`persona.md\` is depth 0, \`topic/MEMORY.md\` is depth 1, and \`topic/subtopic/notes.md\` is depth 2. With that default, \`topic/subtopic/detail/notes.md\` is rejected at depth 3. Read the repo's configuration before adding or moving memory; an omitted \`maxDepth\` imposes no depth limit. This constraint excludes \`skills/\`. Fit memory to the configured limit rather than changing the configuration to permit deeper nesting.
|
|
106957
|
-
|
|
106958
|
-
You can create, delete, or modify files (contents, names, descriptions). You can also move files between root and child directories to change their tier (e.g., root → child directory removes it from in-context).
|
|
106959
|
-
|
|
106960
|
-
## Process
|
|
106900
|
+
## Trajectory Format
|
|
106961
106901
|
|
|
106962
106902
|
The payload is at \`$TRANSCRIPT_PATH\`. It may be either:
|
|
106963
106903
|
|
|
106964
106904
|
1. a JSON message array for one conversation, or
|
|
106965
106905
|
2. a \`multi_transcript_reflection_payload\` manifest. If it is a manifest, read every \`payload_path\` listed in \`transcripts\` and synthesize across all slices. Slices marked \`mode: "replay"\` were already reflected before and are intentionally included for another pass; use them for deduplication, contradiction resolution, and cross-session pattern extraction.
|
|
106966
106906
|
|
|
106967
|
-
When reviewing multiple transcripts, prefer patterns supported across sessions, resolve contradictions in favor of the latest evidence, and avoid recording one-off task state.
|
|
106968
|
-
|
|
106969
|
-
### Phase 1 — Investigate
|
|
106970
|
-
|
|
106971
|
-
Understand the current memory landscape before changing anything. Your user prompt already includes a \`<memory_filesystem>\` tree of memory file names (no descriptions; \`skills/\` is omitted) and the full content of every root file inlined in \`<memory>\` blocks — start there, since those are the parent agent's in-context prompts.
|
|
106907
|
+
When reviewing multiple transcripts, prefer patterns supported across sessions, resolve contradictions in favor of the latest evidence, and avoid recording one-off task state.
|
|
106972
106908
|
|
|
106973
|
-
Read
|
|
106909
|
+
Read transcripts in bounded chunks: check the size first, read files up to 15000 bytes in full, and use targeted reads on larger ones (\`head\`, \`tail\`, \`grep\`, \`sed -n\` on Unix; \`Get-Content\`, \`Select-String\` in PowerShell, which the Bash tool runs on Windows).
|
|
106974
106910
|
|
|
106975
|
-
|
|
106976
|
-
|
|
106977
|
-
For skills, list \`$MEMORY_DIR/skills/\` and read each \`SKILL.md\` frontmatter description to triage adjacency to the candidate procedure, then read the full \`SKILL.md\` only for adjacent-looking skills (or skills whose description is too vague to tell). If no description looks adjacent, you don't need to read any \`SKILL.md\`. When unsure about adjacency, err on the side of reading.
|
|
106978
|
-
|
|
106979
|
-
### Phase 2 — Extract
|
|
106911
|
+
## Trajectory review
|
|
106980
106912
|
|
|
106981
106913
|
Review the conversation and identify candidate learnings worth persisting. Prioritize in this order:
|
|
106982
106914
|
|
|
@@ -106986,132 +106918,59 @@ Review the conversation and identify candidate learnings worth persisting. Prior
|
|
|
106986
106918
|
4. **Contradictions** — anything that conflicts with what's currently stored in memory
|
|
106987
106919
|
5. **Reusable procedures** — repeatable, multi-step workflows that may belong in skills
|
|
106988
106920
|
|
|
106989
|
-
|
|
106990
|
-
|
|
106991
|
-
- **Lasting or ephemeral?** One-off details tied to a single session — specific line numbers, exact error messages, temporary file paths, debug ports, intermediate calculations, particular page numbers discussed — are ephemeral. Don't store them.
|
|
106992
|
-
- **Already captured?** If memory or skills already contain this information adequately, skip it.
|
|
106993
|
-
- **Generalizable?** Distill reusable patterns, not event transcripts. "Write short chapters that end on cliffhangers" is worth storing; "User edited chapter 3 paragraph 2 on Tuesday" is not. "Hedge FX exposure on quarterly positions" is worth storing; "Sold 500 shares of AAPL at $187.50" is not. "Write table-driven tests with testify" is worth storing; "User ran tests at 3pm on Tuesday" is not. The raw conversation is already searchable — don't re-record it.
|
|
106994
|
-
- **Temporal references?** Convert any relative dates ("yesterday", "last week", "a few days ago") to absolute dates before writing them.
|
|
106995
|
-
- **Which tier?** Apply "Choosing a tier" above.
|
|
106996
|
-
|
|
106997
|
-
If nothing survives filtering, make no changes and skip to Phase 5 with no commit.
|
|
106998
|
-
|
|
106999
|
-
### Phase 3 — Update
|
|
107000
|
-
|
|
107001
|
-
For each learning that survived Phase 2, make surgical, well-placed changes.
|
|
107002
|
-
|
|
107003
|
-
#### Memory edits
|
|
107004
|
-
|
|
107005
|
-
- **Placement**: Put the learning in the tier chosen in Phase 2, written the way that tier's section above describes.
|
|
107006
|
-
- **Integration**: If an existing file already covers this subject, update it. Only create a new file when the subject is genuinely distinct and has no natural home in existing files. Fragmentation makes memory harder to navigate.
|
|
107007
|
-
- **Contradiction resolution**: If new information contradicts existing memory, fix the stale entry at the source. Do not append the new version alongside the old.
|
|
107008
|
-
- **Discovery paths**: When adding or moving content, update the links in root \`MEMORY.md\` and any affected child \`MEMORY.md\` files so every deferred file stays reachable. Keep \`name\` and \`description\` frontmatter accurate.
|
|
107009
|
-
|
|
107010
|
-
#### Skills (only when a reusable procedure appears)
|
|
107011
|
-
|
|
107012
|
-
Only make a skill change when the conversation demonstrates a repeatable, multi-step workflow with enough concrete detail to be actionable. Pick **at most one** operation, listed in rough order of preference (prefer modifying an existing skill over creating a new one):
|
|
107013
|
-
|
|
107014
|
-
- \`update\` — an existing skill covers the workflow, but the conversation revealed a wrong, dangerous, or outdated step. Read the existing file, then fix that step in place with Edit; preserve the rest.
|
|
107015
|
-
- \`extend\` — an existing skill covers a similar workflow, and the conversation revealed a new variant or edge case. Add a new section with Edit rather than duplicating the skill or rewriting existing sections.
|
|
107016
|
-
- \`deprecate\` — an existing skill is obsolete, harmful, or replaced. Either \`rm -r skills/<name>/\` (delete mode), or add \`deprecated: "true"\` (and optionally \`replaced_by: <skill-name>\`) under the frontmatter \`metadata\` map, start the description with "Deprecated:" followed by the replacement skill's name, and add a short note at the top of the body explaining why (marker mode).
|
|
107017
|
-
- \`split\` — an existing skill has drifted to bundle two distinct procedures and the conversation makes that painful. Write both replacement \`SKILL.md\` files (plus relevant companion files for each) with Bash, then delete the source skill with Bash or trim it with Edit. Use sparingly.
|
|
107018
|
-
- \`create\` — a genuinely novel, repeatable procedure with concrete detail (commands, tool patterns, config values), and no existing skill covers it even partially.
|
|
107019
|
-
- \`none\` — one-off, trivial, informational, already covered, or better stored as ordinary memory. Make no skill changes.
|
|
107020
|
-
|
|
107021
|
-
As a heuristic, when unsure between \`create\` and \`none\`, choose \`none\`. When unsure between \`create\` and a modify op, choose the modify op.
|
|
107022
|
-
|
|
107023
|
-
For \`update\`/\`extend\`, preserve the existing frontmatter; change the description only if the skill's scope or triggers changed.
|
|
107024
|
-
|
|
107025
|
-
Do not report a \`create\`, \`update\`, \`extend\`, or \`split\` as merely "intended" if Bash can perform the write. The final report must describe actual filesystem changes.
|
|
107026
|
-
|
|
107027
|
-
### Phase 4 — Review
|
|
107028
|
-
|
|
107029
|
-
Quick sanity pass before committing.
|
|
107030
|
-
|
|
107031
|
-
- **No secrets or junk**: Do not persist sensitive values, raw logs, or ephemeral transcript details.
|
|
107032
|
-
|
|
107033
|
-
#### Memory
|
|
106921
|
+
Skip anything ephemeral (one-off task state, line numbers, exact errors, temporary paths) or already captured. Convert relative dates to absolute ones. If nothing survives, make no changes and do not commit.
|
|
107034
106922
|
|
|
107035
|
-
|
|
107036
|
-
- **Cross-reference integrity**: If you deleted or moved a file, check whether any ordinary relative Markdown links point to the old location and update them.
|
|
107037
|
-
- **Tier check**: Did you add anything to root that's really deferred material? Move it to a child directory. Did you leave something in a child directory that the agent needs on every turn? Promote it to root.
|
|
107038
|
-
- **Nesting check**: Confirm every added or moved memory file stays within the configured \`maxDepth\`, including each directory's \`MEMORY.md\`.
|
|
107039
|
-
- **Discoverability**: For each deferred file you added or moved, confirm the primary agent can reach it from root \`MEMORY.md\` through each intermediate directory's \`MEMORY.md\`, that each link says when the target is worth opening, and that its \`description\` says what it is about.
|
|
106923
|
+
## Making memory updates
|
|
107040
106924
|
|
|
107041
|
-
|
|
106925
|
+
Write each change the way the preloaded skills describe. Before editing, read the relevant existing files so you integrate rather than duplicate. For skills, prefer updating or extending an existing skill over creating one, make at most one skill change per run, and when unsure whether a procedure deserves a skill, make none.
|
|
107042
106926
|
|
|
107043
|
-
|
|
107044
|
-
- **Companion file completeness**: For \`create\`/\`split\`, if \`SKILL.md\` references files under \`scripts/\`, \`references/\`, or \`templates/\`, verify those paths actually exist.
|
|
107045
|
-
- **Stale skill references**: For \`deprecate\` (delete mode) or \`split\`, check whether any memory or skill file references the old skill path, and update those references.
|
|
106927
|
+
Use Edit for files that already exist. Create new files with a quoted heredoc on Unix, or on Windows a single-quoted here-string piped to \`Set-Content -Encoding utf8\`; memory files must stay UTF-8. Edit does not expand environment variables: resolve absolute paths first (\`printf "%s/persona.md\\n" "$MEMORY_DIR"\`, or \`Join-Path $env:MEMORY_DIR "persona.md"\` in PowerShell) and pass the printed path. Keep all writes inside \`$MEMORY_DIR\`.
|
|
107046
106928
|
|
|
107047
|
-
|
|
106929
|
+
## Commit
|
|
107048
106930
|
|
|
107049
106931
|
Before writing the commit, resolve the actual ID values:
|
|
107050
106932
|
\`\`\`bash
|
|
107051
106933
|
echo "CHILD_AGENT_ID=$LETTA_AGENT_ID"
|
|
107052
|
-
echo "PARENT_AGENT_ID=$LETTA_PARENT_AGENT_ID"
|
|
107053
106934
|
\`\`\`
|
|
107054
106935
|
|
|
107055
|
-
Use the printed
|
|
106936
|
+
Use the printed value (e.g., \`agent-abc123...\`) in the trailer. If it is empty or unset, omit the trailer. Never write a literal variable name like \`$LETTA_AGENT_ID\` in the commit message. Run git commands only from \`$MEMORY_DIR\`. Use plain \`-m "..."\` with an embedded multi-line string exactly as shown below:
|
|
107056
106937
|
|
|
107057
106938
|
\`\`\`bash
|
|
107058
106939
|
cd $MEMORY_DIR
|
|
107059
106940
|
git add -A
|
|
107060
106941
|
git commit --author="Reflection Subagent <<CHILD_AGENT_ID>@letta.com>" -m "<type>(reflection): <summary> 🔮
|
|
107061
106942
|
|
|
107062
|
-
Reviewed
|
|
106943
|
+
Reviewed transcripts:
|
|
106944
|
+
- <transcript_filepath>
|
|
106945
|
+
- ...
|
|
107063
106946
|
|
|
107064
106947
|
Updates:
|
|
107065
106948
|
- <what changed and why>
|
|
107066
106949
|
|
|
107067
|
-
Generated-By:
|
|
107068
|
-
Agent-ID: <CHILD_AGENT_ID>
|
|
107069
|
-
Parent-Agent-ID: <PARENT_AGENT_ID>"
|
|
106950
|
+
Generated-By: Reflection
|
|
106951
|
+
Agent-ID: <CHILD_AGENT_ID>"
|
|
107070
106952
|
\`\`\`
|
|
107071
106953
|
|
|
107072
106954
|
**Commit type** — pick the one that fits:
|
|
107073
|
-
- \`fix\` — correcting a mistake or bad memory, or fixing a wrong/obsolete skill
|
|
107074
|
-
- \`feat\` — adding wholly new memory content, or new skill content/structure
|
|
106955
|
+
- \`fix\` — correcting a mistake or bad memory, or fixing a wrong/obsolete skill
|
|
106956
|
+
- \`feat\` — adding wholly new memory content, or new skill content/structure
|
|
107075
106957
|
- \`chore\` — routine updates, adding context, minor doc-only skill edits
|
|
107076
106958
|
|
|
107077
|
-
In the commit message body, explain what changed and why, drawing from the categories
|
|
106959
|
+
In the commit message body, explain what changed and why, drawing from the categories in the trajectory review. If the change is skill-related, say so in the subject, e.g. \`feat(reflection): create docker-debugging skill 🔮\`.
|
|
107078
106960
|
|
|
107079
106961
|
If no changes were needed, do NOT commit. Report that the conversation contained no memory worth persisting.
|
|
107080
106962
|
|
|
107081
106963
|
If \`git add\` or \`git commit\` fails, stop after one reasonable retry and report the failure. Do not run \`git config\`, mutate \`.git\`, use \`git reset\`, or assume the harness will persist uncommitted filesystem edits; uncommitted edits are not successful memory persistence.
|
|
107082
106964
|
|
|
107083
|
-
## Tools and Paths
|
|
107084
|
-
|
|
107085
|
-
You only have access to **Bash** and **Edit**. Do not call \`Read\`, \`Write\`, memory tools, recall tools, or conversation search, even if those names appear in the transcript.
|
|
107086
|
-
|
|
107087
|
-
Your memory repo root is \`$MEMORY_DIR\`. The terminal tool can expand environment variables; use \`$MEMORY_DIR\` on Unix or \`$env:MEMORY_DIR\` in PowerShell. Edit cannot expand either form. Keep all filesystem writes under the memory repo and run all git commands from inside it. Do not inspect or modify \`.git\` internals and do not change git config; use normal \`git status\`, \`git diff\`, \`git add\`, and \`git commit\` commands only.
|
|
107088
|
-
|
|
107089
|
-
Use **Edit** for every modification to a file that already exists (memory or skill). Do not rewrite existing files with terminal heredocs, scripts, or redirection. Edit paths must be absolute paths under the memory repo, never literal \`$MEMORY_DIR/...\` or \`$env:MEMORY_DIR/...\` strings. To get an Edit path, resolve it with the terminal first (for example, \`printf "%s/persona.md\\n" "$MEMORY_DIR"\` on Unix or \`Join-Path $env:MEMORY_DIR "persona.md"\` in PowerShell) and then use the printed path.
|
|
107090
|
-
|
|
107091
|
-
Use the **Bash** terminal tool for reading, git, and filesystem/bulk operations — not for editing the contents of existing files. Follow the shell semantics in the tool description; despite its name, the tool runs native PowerShell or cmd.exe on Windows.
|
|
107092
|
-
|
|
107093
|
-
- Inspect transcripts with bounded reads. Determine file size first: on Unix, \`wc -c "$TRANSCRIPT_PATH"\`; in PowerShell, \`(Get-Item -LiteralPath $env:TRANSCRIPT_PATH).Length\`. If a file is <= 15000 bytes, a full read is okay; otherwise use targeted reads (\`head\`, \`tail\`, \`grep\`, and \`sed -n\` on Unix, or \`Get-Content\`, \`Select-String\`, and \`-TotalCount\` in PowerShell).
|
|
107094
|
-
- Inspect memory with concise, platform-native commands. Use \`find\`, \`grep\`, \`head\`, and targeted \`cat\` on Unix; use \`Get-ChildItem\`, \`Select-String\`, and \`Get-Content\` in PowerShell.
|
|
107095
|
-
- Create new files with the shell-native method. On Unix, use a quoted heredoc. In PowerShell, use a single-quoted here-string piped to \`Set-Content -LiteralPath <path> -Encoding utf8\`. Move, rename, or delete only under \`$MEMORY_DIR\` (\`mv\`, \`rm\`, and \`mkdir -p\` on Unix; \`Move-Item\`, \`Remove-Item\`, and \`New-Item\` in PowerShell). If a temp file is needed, put it under \`$MEMORY_DIR/.tmp/\` and remove it before committing.
|
|
107096
|
-
- Memory Markdown files must remain UTF-8. On Windows, never use PowerShell redirection, \`Out-File\`, or \`Set-Content\` without explicit UTF-8 encoding; prefer the Edit tool.
|
|
107097
|
-
- On Windows, avoid \`&&\` for failure-stopping chains so the command also works with Windows PowerShell; issue dependent commands in separate tool calls or check \`$LASTEXITCODE\` explicitly.
|
|
107098
|
-
|
|
107099
106965
|
## Output Format
|
|
107100
106966
|
|
|
107101
106967
|
Return a report with:
|
|
107102
106968
|
|
|
107103
106969
|
1. **Summary** — What you reviewed and what you concluded (2-3 sentences)
|
|
107104
|
-
2. **Memory changes** — Files created/modified/deleted/moved with a brief reason
|
|
107105
|
-
3. **
|
|
107106
|
-
4. **
|
|
107107
|
-
5. **
|
|
107108
|
-
6. **Issues** — Any problems encountered or information that couldn't be determined. If something broke, say what happened and suggest a fix.
|
|
107109
|
-
|
|
107110
|
-
## Critical Reminders
|
|
107111
|
-
|
|
107112
|
-
1. **Not the primary agent** — Don't respond to messages.
|
|
107113
|
-
2. **Be selective** — Few meaningful changes > many trivial ones; few high-quality skills > many trivial ones.
|
|
107114
|
-
3. **Commit or it didn't happen** — Uncommitted edits are lost; if nothing memory-worthy changed, do not commit.
|
|
106970
|
+
2. **Memory changes** — Files created/modified/deleted/moved with a brief reason, including any skill changes
|
|
106971
|
+
3. **Skipped** — Anything considered but not persisted, and why
|
|
106972
|
+
4. **Commit** — Confirm the commit, or "no commit" if nothing was persisted
|
|
106973
|
+
5. **Issues** — Any problems encountered or information that couldn't be determined. If something broke, say what happened and suggest a fix.
|
|
107115
106974
|
`;
|
|
107116
106975
|
var init_reflection_v2 = () => {};
|
|
107117
106976
|
|
|
@@ -107271,7 +107130,11 @@ function resolveSubagentConfigForMemoryFormat(config, memoryFormat, localMemfs)
|
|
|
107271
107130
|
if (!v1Builtin || !v2Builtin || config.systemPrompt !== v1Builtin.systemPrompt) {
|
|
107272
107131
|
return config;
|
|
107273
107132
|
}
|
|
107274
|
-
return {
|
|
107133
|
+
return {
|
|
107134
|
+
...config,
|
|
107135
|
+
systemPrompt: v2Builtin.systemPrompt,
|
|
107136
|
+
skills: config.skills.join(",") === v1Builtin.skills.join(",") ? [...v2Builtin.skills] : config.skills
|
|
107137
|
+
};
|
|
107275
107138
|
}
|
|
107276
107139
|
function getBuiltinSubagentNames() {
|
|
107277
107140
|
return new Set(Object.keys(getBuiltinSubagents()));
|
|
@@ -172772,6 +172635,16 @@ var init_message_queue_bridge = __esm(() => {
|
|
|
172772
172635
|
pendingMessages = [];
|
|
172773
172636
|
});
|
|
172774
172637
|
|
|
172638
|
+
// src/utils/subagent-scope.ts
|
|
172639
|
+
function subagentScopeMatches(parentAgentId, parentConversationId, scope) {
|
|
172640
|
+
if (scope.agentId !== undefined && parentAgentId !== scope.agentId) {
|
|
172641
|
+
return false;
|
|
172642
|
+
}
|
|
172643
|
+
if (scope.conversationId === undefined)
|
|
172644
|
+
return true;
|
|
172645
|
+
return parentConversationId === undefined || parentConversationId === scope.conversationId;
|
|
172646
|
+
}
|
|
172647
|
+
|
|
172775
172648
|
// src/utils/task-notifications.ts
|
|
172776
172649
|
function escapeXml(str) {
|
|
172777
172650
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
@@ -172880,6 +172753,47 @@ function appendTaskNotificationEventsToBuffer(summaries, buffer, generateId, flu
|
|
|
172880
172753
|
flush?.();
|
|
172881
172754
|
return true;
|
|
172882
172755
|
}
|
|
172756
|
+
function selectStopFailedNotifications(rows, seenIds, scope) {
|
|
172757
|
+
const failures = [];
|
|
172758
|
+
const stops = [];
|
|
172759
|
+
for (const row of rows) {
|
|
172760
|
+
if (!subagentScopeMatches(row.parentAgentId, row.parentConversationId, scope)) {
|
|
172761
|
+
continue;
|
|
172762
|
+
}
|
|
172763
|
+
if (row.stopFailed && (row.status === "pending" || row.status === "running")) {
|
|
172764
|
+
const key2 = `${row.id}:${row.stopOutcome?.attempt ?? 0}`;
|
|
172765
|
+
if (!seenIds.has(key2)) {
|
|
172766
|
+
seenIds.add(key2);
|
|
172767
|
+
failures.push(`Background task "${row.description}" could not be stopped — still running remotely. Press Esc to retry.`);
|
|
172768
|
+
}
|
|
172769
|
+
continue;
|
|
172770
|
+
}
|
|
172771
|
+
if (row.stopOutcome?.kind === "stopped" && row.status === "error") {
|
|
172772
|
+
const key2 = `${row.id}:${row.stopOutcome.attempt}`;
|
|
172773
|
+
if (!seenIds.has(key2)) {
|
|
172774
|
+
let surfacedEarlierFailure = false;
|
|
172775
|
+
for (let attempt2 = 0;attempt2 < row.stopOutcome.attempt; attempt2 += 1) {
|
|
172776
|
+
if (seenIds.has(`${row.id}:${attempt2}`)) {
|
|
172777
|
+
surfacedEarlierFailure = true;
|
|
172778
|
+
break;
|
|
172779
|
+
}
|
|
172780
|
+
}
|
|
172781
|
+
if (surfacedEarlierFailure) {
|
|
172782
|
+
seenIds.add(key2);
|
|
172783
|
+
stops.push(`Background task "${row.description}" stopped.`);
|
|
172784
|
+
}
|
|
172785
|
+
}
|
|
172786
|
+
}
|
|
172787
|
+
}
|
|
172788
|
+
const present = new Set(rows.map((row) => row.id));
|
|
172789
|
+
for (const key2 of seenIds) {
|
|
172790
|
+
const rowId = key2.slice(0, key2.lastIndexOf(":"));
|
|
172791
|
+
if (!present.has(rowId)) {
|
|
172792
|
+
seenIds.delete(key2);
|
|
172793
|
+
}
|
|
172794
|
+
}
|
|
172795
|
+
return { failures, stops };
|
|
172796
|
+
}
|
|
172883
172797
|
var init_task_notifications = __esm(() => {
|
|
172884
172798
|
init_context();
|
|
172885
172799
|
init_constants2();
|
|
@@ -210966,7 +210880,7 @@ var init_mcp_client = __esm(() => {
|
|
|
210966
210880
|
init_streamableHttp();
|
|
210967
210881
|
DEFAULT_CLIENT_INFO = {
|
|
210968
210882
|
name: "letta-code",
|
|
210969
|
-
version: "0.34.
|
|
210883
|
+
version: "0.34.19"
|
|
210970
210884
|
};
|
|
210971
210885
|
});
|
|
210972
210886
|
|
|
@@ -215101,7 +215015,7 @@ Do not use this tool for root memory files (already loaded) or skills/ (use Skil
|
|
|
215101
215015
|
var init_Memory = () => {};
|
|
215102
215016
|
|
|
215103
215017
|
// src/tools/descriptions/Monitor.md
|
|
215104
|
-
var Monitor_default = 'Start a background monitor that streams events from a long-running script. Each stdout line is an event — you keep working and notifications arrive in the chat. Events arrive on their own schedule and are not replies from the user, even if one lands while you\'re waiting for the user to answer a question.\n\nPick by how many notifications you need:\n- **One** ("tell me when the server is ready / the build finishes") → use **Bash with `run_in_background`** and a command that exits when the condition is true, e.g. `until grep -q "Ready in" dev.log; do sleep 0.5; done`. You get a single completion notification when it exits.\n- **One per occurrence, indefinitely** ("tell me every time an ERROR line appears") → Monitor with an unbounded command (`tail -f`, `inotifywait -m`, `while true`).\n- **One per occurrence, until a known end** ("emit each CI step result, stop when the run completes") → Monitor with a command that emits lines and then exits.\n\nYour script\'s stdout is the event stream. Each line becomes a notification. Exit ends the watch.\n # Each matching log line is an event\n tail -f /var/log/app.log | grep --line-buffered "ERROR"\n # Each file change is an event\n inotifywait -m --format \'%e %f\' /watched/dir\n # Node script that emits events as they arrive (e.g. WebSocket listener)\n node watch-for-events.js\n\nFor open github.com pull requests, use WatchPR instead. It covers the whole PR surface and keeps watching after CI finishes. Use Monitor only when WatchPR does not apply.\n\n**Don\'t use an unbounded command for a single notification.** `tail -f`, `inotifywait -m`, and `while true` never exit on their own, so the monitor stays armed until timeout even after the event has fired. For "tell me when X is ready," use Bash `run_in_background` with an `until` loop instead (one notification, ends in seconds). Note that `tail -f log | grep -m 1 ...` does *not* fix this: if the log goes quiet after the match, `tail` never receives SIGPIPE and the pipeline hangs anyway.\n\n- Every pipe stage must flush per line or matches sit in its buffer unseen: `grep` needs `--line-buffered`, `awk` needs `fflush()`. `head` cannot flush at all — `| head -N` delivers nothing until N matches accumulate, then ends the stream.\n- In poll loops, handle transient failures (`curl ... || true`) — one failed request shouldn\'t kill the monitor.\n- Poll intervals: 30s+ for remote APIs (rate limits), 0.5–1s for local checks.\n- Write a specific `description` — it appears in every notification ("errors in deploy.log" not "watching logs").\n- Only stdout is the event stream. Stderr goes to the output file (readable via Read) but does not trigger notifications — for a command you run directly (e.g. `python train.py 2>&1 | grep --line-buffered ...`), merge stderr with `2>&1` so its failures reach your filter. (No effect on `tail -f` of an existing log — that file only contains what its writer redirected.)\n\n**Coverage — silence is not success.** When watching a job or process for an outcome, your filter must match every terminal state, not just the happy path. A monitor that greps only for the success marker stays silent through a crashloop, a hung process, or an unexpected exit — and silence looks identical to "still running." Before arming, ask: *if this process crashed right now, would my filter emit anything?* If not, widen it.\n # Wrong — silent on crash, hang, or any non-success exit\n tail -f run.log | grep --line-buffered "elapsed_steps="\n # Right — one alternation covering progress + the failure signatures you\'d act on\n tail -f run.log | grep -E --line-buffered "elapsed_steps=|Traceback|Error|FAILED|assert|Killed|OOM"\n\nFor poll loops checking job state, emit on every terminal status (`succeeded|failed|cancelled|timeout`), not just success. If you cannot confidently enumerate the failure signatures, broaden the grep alternation rather than narrow it — some extra noise is better than missing a crashloop.\n\n**Output volume**: Every stdout line is a conversation message, so the filter should be selective — but selective means "the lines you\'d act on," not "only good news." Never pipe raw logs; filter to exactly the success and failure signals you care about. Monitors that produce too many events are automatically stopped; restart with a tighter filter if this happens.\n\nStdout lines within 200ms are batched into a single notification, so multiline output from a single event groups naturally.\n\nThe script runs in the same shell environment as Bash. Exit ends the watch (exit code is reported). Timeout → killed. Set `persistent: true` for session-length watches (log tails, long-lived event streams)
|
|
215018
|
+
var Monitor_default = 'Start a background monitor that streams events from a long-running script. Each stdout line is an event — you keep working and notifications arrive in the chat. Events arrive on their own schedule and are not replies from the user, even if one lands while you\'re waiting for the user to answer a question.\n\nPick by how many notifications you need:\n- **One** ("tell me when the server is ready / the build finishes") → use **Bash with `run_in_background`** and a command that exits when the condition is true, e.g. `until grep -q "Ready in" dev.log; do sleep 0.5; done`. You get a single completion notification when it exits.\n- **One per occurrence, indefinitely** ("tell me every time an ERROR line appears") → Monitor with an unbounded command (`tail -f`, `inotifywait -m`, `while true`).\n- **One per occurrence, until a known end** ("emit each CI step result, stop when the run completes") → Monitor with a command that emits lines and then exits.\n\nYour script\'s stdout is the event stream. Each line becomes a notification. Exit ends the watch.\n # Each matching log line is an event\n tail -f /var/log/app.log | grep --line-buffered "ERROR"\n # Each file change is an event\n inotifywait -m --format \'%e %f\' /watched/dir\n # Node script that emits events as they arrive (e.g. WebSocket listener)\n node watch-for-events.js\n\nFor open github.com pull requests, use WatchPR instead. It covers the whole PR surface and keeps watching after CI finishes. Use Monitor only when WatchPR does not apply.\n\n**Don\'t use an unbounded command for a single notification.** `tail -f`, `inotifywait -m`, and `while true` never exit on their own, so the monitor stays armed until timeout even after the event has fired. For "tell me when X is ready," use Bash `run_in_background` with an `until` loop instead (one notification, ends in seconds). Note that `tail -f log | grep -m 1 ...` does *not* fix this: if the log goes quiet after the match, `tail` never receives SIGPIPE and the pipeline hangs anyway.\n\n- Every pipe stage must flush per line or matches sit in its buffer unseen: `grep` needs `--line-buffered`, `awk` needs `fflush()`. `head` cannot flush at all — `| head -N` delivers nothing until N matches accumulate, then ends the stream.\n- In poll loops, handle transient failures (`curl ... || true`) — one failed request shouldn\'t kill the monitor.\n- Poll intervals: 30s+ for remote APIs (rate limits), 0.5–1s for local checks.\n- Write a specific `description` — it appears in every notification ("errors in deploy.log" not "watching logs").\n- Only stdout is the event stream. Stderr goes to the output file (readable via Read) but does not trigger notifications — for a command you run directly (e.g. `python train.py 2>&1 | grep --line-buffered ...`), merge stderr with `2>&1` so its failures reach your filter. (No effect on `tail -f` of an existing log — that file only contains what its writer redirected.)\n\n**Coverage — silence is not success.** When watching a job or process for an outcome, your filter must match every terminal state, not just the happy path. A monitor that greps only for the success marker stays silent through a crashloop, a hung process, or an unexpected exit — and silence looks identical to "still running." Before arming, ask: *if this process crashed right now, would my filter emit anything?* If not, widen it.\n # Wrong — silent on crash, hang, or any non-success exit\n tail -f run.log | grep --line-buffered "elapsed_steps="\n # Right — one alternation covering progress + the failure signatures you\'d act on\n tail -f run.log | grep -E --line-buffered "elapsed_steps=|Traceback|Error|FAILED|assert|Killed|OOM"\n\nFor poll loops checking job state, emit on every terminal status (`succeeded|failed|cancelled|timeout`), not just success. If you cannot confidently enumerate the failure signatures, broaden the grep alternation rather than narrow it — some extra noise is better than missing a crashloop.\n\n**Output volume**: Every stdout line is a conversation message, so the filter should be selective — but selective means "the lines you\'d act on," not "only good news." Never pipe raw logs; filter to exactly the success and failure signals you care about. Monitors that produce too many events are automatically stopped; restart with a tighter filter if this happens.\n\nStdout lines within 200ms are batched into a single notification, so multiline output from a single event groups naturally.\n\nThe script runs in the same shell environment as Bash. Exit ends the watch (exit code is reported). Timeout → killed. Set `persistent: true` for session-length watches (log tails, long-lived event streams). In managed Cloud sandboxes, every monitor stops after at most 1 hour, including persistent monitors; elsewhere persistent monitors run until TaskStop or session end. For longer Cloud waits, schedule a Wake or cron (which does not keep the sandbox running between turns) and combine it with shorter monitors. Use TaskStop to cancel early.\n\nWhen someone is waiting on the result, set `backup_after_seconds` (e.g. 900). If the monitor goes that long without an event, a durable Wake brings you back to check the real state, so a queued, hung, or dead watch can\'t leave them waiting in silence.\n\n**ws source** — open a WebSocket and stream each incoming text frame as an event. No shell, no polling: the server pushes, you get notified.\n ws: {url: \'wss://events.example.com/stream\', protocols: [\'v1\']},\n description: \'deploy events\',\n\nEach text frame becomes one notification (multiline frames stay as one event). Binary frames are reported as `[binary frame, N bytes]` rather than passed through. Socket close ends the watch with the close code surfaced; errors are surfaced before close. Same rate limiting as bash — a firehose will be suppressed and eventually stopped, so subscribe to a filtered feed where one exists.\n\nPrefer this over `command: \'websocat wss://…\'` — it avoids the extra process and line-buffering pitfalls. Use bash when you need to transform or filter frames with shell tools before they become events.\n';
|
|
215105
215019
|
var init_Monitor = () => {};
|
|
215106
215020
|
|
|
215107
215021
|
// src/tools/descriptions/Read.md
|
|
@@ -215624,6 +215538,8 @@ var init_Wake = () => {};
|
|
|
215624
215538
|
// src/tools/descriptions/WatchPR.md
|
|
215625
215539
|
var WatchPR_default = `Watch one open github.com pull request until it merges, closes, is stopped with TaskStop, or the session ends.
|
|
215626
215540
|
|
|
215541
|
+
In managed Cloud sandboxes, WatchPR also stops after a hard 1-hour limit and sends a timeout notification. For checks beyond that window, use Wake or cron (which does not keep the sandbox running between turns) and combine it with shorter watches. Local watches have no duration limit.
|
|
215542
|
+
|
|
215627
215543
|
Use WatchPR instead of writing a Monitor or shell polling loop when you need ongoing notifications about a PR. Start at most one watch per PR. It reports:
|
|
215628
215544
|
|
|
215629
215545
|
- current-head check failures, recoveries, retries, and completion;
|
|
@@ -221280,12 +221196,55 @@ var init_disk_space = __esm(() => {
|
|
|
221280
221196
|
var exports_approval_execution = {};
|
|
221281
221197
|
__export(exports_approval_execution, {
|
|
221282
221198
|
settleApprovalExecutionTasks: () => settleApprovalExecutionTasks,
|
|
221199
|
+
overlayPartialResults: () => overlayPartialResults,
|
|
221200
|
+
isUserAbortError: () => isUserAbortError,
|
|
221283
221201
|
getResourceKey: () => getResourceKey,
|
|
221284
221202
|
getDisplayableToolReturn: () => getDisplayableToolReturn,
|
|
221285
221203
|
executeAutoAllowedTools: () => executeAutoAllowedTools,
|
|
221286
|
-
executeApprovalBatch: () => executeApprovalBatch
|
|
221204
|
+
executeApprovalBatch: () => executeApprovalBatch,
|
|
221205
|
+
buildDeniedResults: () => buildDeniedResults,
|
|
221206
|
+
buildCompanionResults: () => buildCompanionResults,
|
|
221207
|
+
appendAbortPartials: () => appendAbortPartials,
|
|
221208
|
+
ABORT_GRACE_MS: () => ABORT_GRACE_MS
|
|
221287
221209
|
});
|
|
221288
221210
|
import * as path16 from "node:path";
|
|
221211
|
+
function isUserAbortError(error5) {
|
|
221212
|
+
return error5 instanceof APIUserAbortError || error5 instanceof Error && (error5.name === "AbortError" || error5.message === INTERRUPTED_BY_USER || error5.message === "The operation was aborted");
|
|
221213
|
+
}
|
|
221214
|
+
function overlayPartialResults(queued, partials) {
|
|
221215
|
+
const realById = new Map((partials ?? []).map((r5) => [r5.tool_call_id, r5]));
|
|
221216
|
+
const overlaid = (queued ?? []).map((r5) => realById.get(r5.tool_call_id) ?? r5);
|
|
221217
|
+
const queuedIds = new Set((queued ?? []).map((r5) => r5.tool_call_id));
|
|
221218
|
+
const extras = (partials ?? []).filter((r5) => !queuedIds.has(r5.tool_call_id));
|
|
221219
|
+
return [...overlaid, ...extras];
|
|
221220
|
+
}
|
|
221221
|
+
function buildDeniedResults(autoDenied) {
|
|
221222
|
+
return autoDenied.map((ad) => ({
|
|
221223
|
+
type: "approval",
|
|
221224
|
+
tool_call_id: ad.approval.toolCallId,
|
|
221225
|
+
approve: false,
|
|
221226
|
+
reason: ad.reason
|
|
221227
|
+
}));
|
|
221228
|
+
}
|
|
221229
|
+
function buildCompanionResults(autoHandled, autoDenied) {
|
|
221230
|
+
return [
|
|
221231
|
+
...autoHandled.map((ar) => ({
|
|
221232
|
+
type: "tool",
|
|
221233
|
+
tool_call_id: ar.toolCallId,
|
|
221234
|
+
tool_return: ar.result.toolReturn,
|
|
221235
|
+
status: ar.result.status,
|
|
221236
|
+
stdout: ar.result.stdout,
|
|
221237
|
+
stderr: ar.result.stderr
|
|
221238
|
+
})),
|
|
221239
|
+
...buildDeniedResults(autoDenied)
|
|
221240
|
+
];
|
|
221241
|
+
}
|
|
221242
|
+
function appendAbortPartials(error5, extras) {
|
|
221243
|
+
if (extras.length === 0 || !isUserAbortError(error5))
|
|
221244
|
+
return;
|
|
221245
|
+
const abortError = error5;
|
|
221246
|
+
abortError.partialResults = [...abortError.partialResults ?? [], ...extras];
|
|
221247
|
+
}
|
|
221289
221248
|
function getDisplayableToolReturn(content) {
|
|
221290
221249
|
if (typeof content === "string") {
|
|
221291
221250
|
return content;
|
|
@@ -221422,8 +221381,61 @@ async function executeSingleDecision(decision, onChunk, options) {
|
|
|
221422
221381
|
async function executeApprovalBatch(decisions, onChunk, options) {
|
|
221423
221382
|
return watchDiskSpaceDuring(options?.workingDirectory ?? getCurrentWorkingDirectory(), (text2) => deliverDiskSpaceReminder(text2, options?.parentScope), () => executeApprovalBatchUnwatched(decisions, onChunk, options));
|
|
221424
221383
|
}
|
|
221425
|
-
async function settleApprovalExecutionTasks(tasks, partialResults = () => []) {
|
|
221426
|
-
const
|
|
221384
|
+
async function settleApprovalExecutionTasks(tasks, partialResults = () => [], options) {
|
|
221385
|
+
const signal = options?.abortSignal;
|
|
221386
|
+
if (!signal || signal.aborted) {
|
|
221387
|
+
throwFirstSettledRejection(await Promise.allSettled(tasks), partialResults);
|
|
221388
|
+
return;
|
|
221389
|
+
}
|
|
221390
|
+
const settled = new Array(tasks.length);
|
|
221391
|
+
let remaining = tasks.length;
|
|
221392
|
+
const tracked = tasks.map((task, index) => task.then(() => {
|
|
221393
|
+
settled[index] = { status: "fulfilled", value: undefined };
|
|
221394
|
+
}, (reason) => {
|
|
221395
|
+
settled[index] = { status: "rejected", reason };
|
|
221396
|
+
}).finally(() => {
|
|
221397
|
+
remaining -= 1;
|
|
221398
|
+
}));
|
|
221399
|
+
let onAbort = () => {};
|
|
221400
|
+
const aborted2 = new Promise((resolve20) => {
|
|
221401
|
+
onAbort = resolve20;
|
|
221402
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
221403
|
+
});
|
|
221404
|
+
try {
|
|
221405
|
+
await Promise.race([Promise.all(tracked).then(() => {
|
|
221406
|
+
return;
|
|
221407
|
+
}), aborted2]);
|
|
221408
|
+
} finally {
|
|
221409
|
+
signal.removeEventListener("abort", onAbort);
|
|
221410
|
+
}
|
|
221411
|
+
if (remaining === 0) {
|
|
221412
|
+
throwFirstSettledRejection(settled, partialResults);
|
|
221413
|
+
return;
|
|
221414
|
+
}
|
|
221415
|
+
let graceTimer;
|
|
221416
|
+
const graceExpired = new Promise((resolve20) => {
|
|
221417
|
+
graceTimer = setTimeout(resolve20, ABORT_GRACE_MS);
|
|
221418
|
+
});
|
|
221419
|
+
try {
|
|
221420
|
+
await Promise.race([
|
|
221421
|
+
Promise.all(tracked).then(() => {
|
|
221422
|
+
return;
|
|
221423
|
+
}),
|
|
221424
|
+
graceExpired
|
|
221425
|
+
]);
|
|
221426
|
+
} finally {
|
|
221427
|
+
clearTimeout(graceTimer);
|
|
221428
|
+
}
|
|
221429
|
+
if (remaining === 0) {
|
|
221430
|
+
throwFirstSettledRejection(settled, partialResults);
|
|
221431
|
+
return;
|
|
221432
|
+
}
|
|
221433
|
+
throwFirstSettledRejection(settled.filter((result2) => result2 !== undefined), partialResults);
|
|
221434
|
+
const error5 = signal.reason instanceof Error ? signal.reason : new Error(INTERRUPTED_BY_USER);
|
|
221435
|
+
Object.assign(error5, { partialResults: partialResults() });
|
|
221436
|
+
throw error5;
|
|
221437
|
+
}
|
|
221438
|
+
function throwFirstSettledRejection(settled, partialResults) {
|
|
221427
221439
|
for (const result2 of settled) {
|
|
221428
221440
|
if (result2.status !== "rejected")
|
|
221429
221441
|
continue;
|
|
@@ -221437,6 +221449,19 @@ async function executeApprovalBatchUnwatched(decisions, onChunk, options) {
|
|
|
221437
221449
|
workingDirectory: options.workingDirectory
|
|
221438
221450
|
})).contextId : undefined);
|
|
221439
221451
|
const results = new Array(decisions.length).fill(null);
|
|
221452
|
+
let batchDiscarded = false;
|
|
221453
|
+
const guardedOnChunk = onChunk ? (chunk2) => {
|
|
221454
|
+
if (!batchDiscarded)
|
|
221455
|
+
onChunk(chunk2);
|
|
221456
|
+
} : undefined;
|
|
221457
|
+
const guardedOptions = options?.onStreamingOutput ? {
|
|
221458
|
+
...options,
|
|
221459
|
+
onStreamingOutput: (toolCallId, chunk2, isStderr) => {
|
|
221460
|
+
if (!batchDiscarded) {
|
|
221461
|
+
options.onStreamingOutput?.(toolCallId, chunk2, isStderr);
|
|
221462
|
+
}
|
|
221463
|
+
}
|
|
221464
|
+
} : options;
|
|
221440
221465
|
const parallelIndices = [];
|
|
221441
221466
|
const writeToolsByResource = new Map;
|
|
221442
221467
|
const denyIndices = [];
|
|
@@ -221472,11 +221497,11 @@ async function executeApprovalBatchUnwatched(decisions, onChunk, options) {
|
|
|
221472
221497
|
const decision = decisions[i4];
|
|
221473
221498
|
if (decision) {
|
|
221474
221499
|
let crossedEffectBoundary = false;
|
|
221475
|
-
const result2 = await executeSingleDecision(decision,
|
|
221476
|
-
...
|
|
221500
|
+
const result2 = await executeSingleDecision(decision, guardedOnChunk, {
|
|
221501
|
+
...guardedOptions,
|
|
221477
221502
|
toolContextId,
|
|
221478
221503
|
beforeToolExecution: async (toolCallId) => {
|
|
221479
|
-
await
|
|
221504
|
+
await guardedOptions?.beforeToolExecution?.(toolCallId);
|
|
221480
221505
|
crossedEffectBoundary = true;
|
|
221481
221506
|
}
|
|
221482
221507
|
});
|
|
@@ -221486,15 +221511,20 @@ async function executeApprovalBatchUnwatched(decisions, onChunk, options) {
|
|
|
221486
221511
|
}
|
|
221487
221512
|
}
|
|
221488
221513
|
};
|
|
221489
|
-
|
|
221490
|
-
|
|
221491
|
-
|
|
221492
|
-
|
|
221493
|
-
|
|
221494
|
-
|
|
221495
|
-
|
|
221496
|
-
|
|
221497
|
-
|
|
221514
|
+
try {
|
|
221515
|
+
await settleApprovalExecutionTasks([
|
|
221516
|
+
...parallelIndices.map(execute),
|
|
221517
|
+
...denyIndices.map(execute),
|
|
221518
|
+
...Array.from(writeToolsByResource.values()).map(async (indices) => {
|
|
221519
|
+
for (const i4 of indices) {
|
|
221520
|
+
await execute(i4);
|
|
221521
|
+
}
|
|
221522
|
+
})
|
|
221523
|
+
], () => results.filter((result2) => result2 !== null), { abortSignal: options?.abortSignal });
|
|
221524
|
+
} catch (error5) {
|
|
221525
|
+
batchDiscarded = true;
|
|
221526
|
+
throw error5;
|
|
221527
|
+
}
|
|
221498
221528
|
return results.filter((r5) => r5 !== null);
|
|
221499
221529
|
}
|
|
221500
221530
|
async function executeAutoAllowedTools(autoAllowed, onChunk, options) {
|
|
@@ -221513,8 +221543,9 @@ async function executeAutoAllowedTools(autoAllowed, onChunk, options) {
|
|
|
221513
221543
|
}
|
|
221514
221544
|
}));
|
|
221515
221545
|
}
|
|
221516
|
-
var PARALLEL_SAFE_TOOLS, FILE_PATH_TOOLS, GLOBAL_LOCK_TOOLS;
|
|
221546
|
+
var ABORT_GRACE_MS = 500, PARALLEL_SAFE_TOOLS, FILE_PATH_TOOLS, GLOBAL_LOCK_TOOLS;
|
|
221517
221547
|
var init_approval_execution = __esm(async () => {
|
|
221548
|
+
init_error();
|
|
221518
221549
|
init_constants2();
|
|
221519
221550
|
init_disk_space();
|
|
221520
221551
|
init_runtime_context();
|
|
@@ -222512,14 +222543,23 @@ function scheduleCompletedSubagentCleanup(id2) {
|
|
|
222512
222543
|
return;
|
|
222513
222544
|
}
|
|
222514
222545
|
clearCompletedSubagentCleanup(id2);
|
|
222546
|
+
armCompletedSubagentCleanup(id2);
|
|
222547
|
+
}
|
|
222548
|
+
function armCompletedSubagentCleanup(id2) {
|
|
222549
|
+
const agent = store2.agents.get(id2);
|
|
222550
|
+
if (!agent)
|
|
222551
|
+
return;
|
|
222515
222552
|
const timer = setTimeout(() => {
|
|
222553
|
+
completedSubagentCleanupTimers.delete(id2);
|
|
222516
222554
|
const current = store2.agents.get(id2);
|
|
222517
222555
|
if (!current || current.status !== "completed" && current.status !== "error") {
|
|
222518
|
-
|
|
222556
|
+
return;
|
|
222557
|
+
}
|
|
222558
|
+
if (current.cancelPending) {
|
|
222559
|
+
armCompletedSubagentCleanup(id2);
|
|
222519
222560
|
return;
|
|
222520
222561
|
}
|
|
222521
222562
|
store2.agents.delete(id2);
|
|
222522
|
-
completedSubagentCleanupTimers.delete(id2);
|
|
222523
222563
|
notifyListeners();
|
|
222524
222564
|
}, agent.result !== undefined ? publishedResultRetentionMs : completedSubagentRetentionMs);
|
|
222525
222565
|
unrefTimer2(timer);
|
|
@@ -222609,6 +222649,7 @@ function completeSubagent(id2, result2) {
|
|
|
222609
222649
|
...agent,
|
|
222610
222650
|
status: result2.success ? "completed" : "error",
|
|
222611
222651
|
error: result2.error,
|
|
222652
|
+
stopFailed: undefined,
|
|
222612
222653
|
...result2.result !== undefined ? { result: result2.result } : {},
|
|
222613
222654
|
durationMs: Date.now() - agent.startTime,
|
|
222614
222655
|
totalTokens: result2.totalTokens ?? agent.totalTokens,
|
|
@@ -222665,6 +222706,8 @@ function clearCompletedSubagents() {
|
|
|
222665
222706
|
for (const [id2, agent] of store2.agents.entries()) {
|
|
222666
222707
|
if (agent.result !== undefined)
|
|
222667
222708
|
continue;
|
|
222709
|
+
if (agent.cancelPending)
|
|
222710
|
+
continue;
|
|
222668
222711
|
if (agent.status === "completed" || agent.status === "error") {
|
|
222669
222712
|
clearCompletedSubagentCleanup(id2);
|
|
222670
222713
|
store2.agents.delete(id2);
|
|
@@ -222678,6 +222721,11 @@ function clearCompletedSubagents() {
|
|
|
222678
222721
|
function clearSubagentsByIds(ids) {
|
|
222679
222722
|
let removedAny = false;
|
|
222680
222723
|
for (const id2 of ids) {
|
|
222724
|
+
const agent = store2.agents.get(id2);
|
|
222725
|
+
if (agent?.cancelPending) {
|
|
222726
|
+
updateSubagent(id2, { silent: true });
|
|
222727
|
+
continue;
|
|
222728
|
+
}
|
|
222681
222729
|
clearCompletedSubagentCleanup(id2);
|
|
222682
222730
|
removedAny = store2.agents.delete(id2) || removedAny;
|
|
222683
222731
|
}
|
|
@@ -222693,15 +222741,28 @@ function hasActiveSubagents() {
|
|
|
222693
222741
|
}
|
|
222694
222742
|
return false;
|
|
222695
222743
|
}
|
|
222696
|
-
function
|
|
222744
|
+
function registerSubagentAbortHook(id2, hook) {
|
|
222745
|
+
subagentAbortHooks.set(id2, hook);
|
|
222746
|
+
}
|
|
222747
|
+
function clearSubagentAbortHook(id2) {
|
|
222748
|
+
subagentAbortHooks.delete(id2);
|
|
222749
|
+
}
|
|
222750
|
+
function interruptActiveSubagents(errorMessage, scope) {
|
|
222697
222751
|
let anyInterrupted = false;
|
|
222698
222752
|
for (const [id2, agent] of store2.agents.entries()) {
|
|
222699
222753
|
if (agent.status === "pending" || agent.status === "running") {
|
|
222754
|
+
if (scope && !subagentMatchesScope(agent, scope))
|
|
222755
|
+
continue;
|
|
222756
|
+
const hook = subagentAbortHooks.get(id2);
|
|
222757
|
+
hook?.();
|
|
222758
|
+
subagentAbortHooks.delete(id2);
|
|
222700
222759
|
const updatedAgent = {
|
|
222701
222760
|
...agent,
|
|
222702
222761
|
status: "error",
|
|
222703
222762
|
error: errorMessage,
|
|
222704
|
-
durationMs: Date.now() - agent.startTime
|
|
222763
|
+
durationMs: Date.now() - agent.startTime,
|
|
222764
|
+
...hook ? { cancelPending: true, stopAttempts: (agent.stopAttempts ?? 0) + 1 } : {},
|
|
222765
|
+
stopFailed: undefined
|
|
222705
222766
|
};
|
|
222706
222767
|
store2.agents.set(id2, updatedAgent);
|
|
222707
222768
|
scheduleCompletedSubagentCleanup(id2);
|
|
@@ -222712,6 +222773,50 @@ function interruptActiveSubagents(errorMessage) {
|
|
|
222712
222773
|
notifyListeners();
|
|
222713
222774
|
}
|
|
222714
222775
|
}
|
|
222776
|
+
function interruptStopFailedSubagents(errorMessage, scope) {
|
|
222777
|
+
const interrupted = [];
|
|
222778
|
+
for (const [id2, agent] of store2.agents.entries()) {
|
|
222779
|
+
if (!agent.stopFailed)
|
|
222780
|
+
continue;
|
|
222781
|
+
if (agent.status !== "pending" && agent.status !== "running")
|
|
222782
|
+
continue;
|
|
222783
|
+
if (scope && !subagentMatchesScope(agent, scope))
|
|
222784
|
+
continue;
|
|
222785
|
+
const hook = subagentAbortHooks.get(id2);
|
|
222786
|
+
hook?.();
|
|
222787
|
+
subagentAbortHooks.delete(id2);
|
|
222788
|
+
const updatedAgent = {
|
|
222789
|
+
...agent,
|
|
222790
|
+
status: "error",
|
|
222791
|
+
error: errorMessage,
|
|
222792
|
+
durationMs: Date.now() - agent.startTime,
|
|
222793
|
+
...hook ? { cancelPending: true, stopAttempts: (agent.stopAttempts ?? 0) + 1 } : {},
|
|
222794
|
+
stopFailed: undefined
|
|
222795
|
+
};
|
|
222796
|
+
store2.agents.set(id2, updatedAgent);
|
|
222797
|
+
scheduleCompletedSubagentCleanup(id2);
|
|
222798
|
+
interrupted.push(id2);
|
|
222799
|
+
}
|
|
222800
|
+
if (interrupted.length > 0) {
|
|
222801
|
+
notifyListeners();
|
|
222802
|
+
}
|
|
222803
|
+
return interrupted;
|
|
222804
|
+
}
|
|
222805
|
+
function subagentMatchesScope(agent, scope) {
|
|
222806
|
+
return subagentScopeMatches(agent.parentAgentId, agent.parentConversationId, scope);
|
|
222807
|
+
}
|
|
222808
|
+
function hasStopFailedSubagents(scope) {
|
|
222809
|
+
for (const agent of store2.agents.values()) {
|
|
222810
|
+
if (!agent.stopFailed)
|
|
222811
|
+
continue;
|
|
222812
|
+
if (agent.status !== "pending" && agent.status !== "running")
|
|
222813
|
+
continue;
|
|
222814
|
+
if (scope && !subagentMatchesScope(agent, scope))
|
|
222815
|
+
continue;
|
|
222816
|
+
return true;
|
|
222817
|
+
}
|
|
222818
|
+
return false;
|
|
222819
|
+
}
|
|
222715
222820
|
function subscribe2(listener) {
|
|
222716
222821
|
store2.listeners.add(listener);
|
|
222717
222822
|
return () => {
|
|
@@ -222732,7 +222837,7 @@ function emitStreamEvent(subagentId, event) {
|
|
|
222732
222837
|
listener(subagentId, event);
|
|
222733
222838
|
}
|
|
222734
222839
|
}
|
|
222735
|
-
var store2, cachedSnapshot, cachedLifecycleItems, DEFAULT_COMPLETED_SUBAGENT_RETENTION_MS = 30000, completedSubagentRetentionMs, DEFAULT_PUBLISHED_RESULT_RETENTION_MS, publishedResultRetentionMs, completedSubagentCleanupTimers, subagentCounter = 0, streamEventListeners;
|
|
222840
|
+
var store2, cachedSnapshot, cachedLifecycleItems, DEFAULT_COMPLETED_SUBAGENT_RETENTION_MS = 30000, completedSubagentRetentionMs, DEFAULT_PUBLISHED_RESULT_RETENTION_MS, publishedResultRetentionMs, completedSubagentCleanupTimers, subagentCounter = 0, subagentAbortHooks, streamEventListeners;
|
|
222736
222841
|
var init_subagent_state = __esm(() => {
|
|
222737
222842
|
store2 = {
|
|
222738
222843
|
agents: new Map,
|
|
@@ -222748,6 +222853,7 @@ var init_subagent_state = __esm(() => {
|
|
|
222748
222853
|
DEFAULT_PUBLISHED_RESULT_RETENTION_MS = 30 * 60000;
|
|
222749
222854
|
publishedResultRetentionMs = DEFAULT_PUBLISHED_RESULT_RETENTION_MS;
|
|
222750
222855
|
completedSubagentCleanupTimers = new Map;
|
|
222856
|
+
subagentAbortHooks = new Map;
|
|
222751
222857
|
streamEventListeners = new Set;
|
|
222752
222858
|
});
|
|
222753
222859
|
|
|
@@ -223266,10 +223372,37 @@ var init_tool_registry = __esm(() => {
|
|
|
223266
223372
|
});
|
|
223267
223373
|
|
|
223268
223374
|
// src/tools/external-tool-background.ts
|
|
223375
|
+
function interruptedExternalToolResult(toolName2) {
|
|
223376
|
+
return {
|
|
223377
|
+
status: "error",
|
|
223378
|
+
toolReturn: `External tool call interrupted by user: ${toolName2}. The remote tool may still finish; its outcome is unknown. Check the destination before retrying a write.`
|
|
223379
|
+
};
|
|
223380
|
+
}
|
|
223381
|
+
function raceExternalOperationAbort(operation, signal, toolName2) {
|
|
223382
|
+
if (signal.aborted) {
|
|
223383
|
+
return Promise.resolve(interruptedExternalToolResult(toolName2));
|
|
223384
|
+
}
|
|
223385
|
+
return new Promise((resolve21, reject2) => {
|
|
223386
|
+
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
223387
|
+
const onAbort = () => {
|
|
223388
|
+
cleanup();
|
|
223389
|
+
resolve21(interruptedExternalToolResult(toolName2));
|
|
223390
|
+
};
|
|
223391
|
+
signal.addEventListener("abort", onAbort);
|
|
223392
|
+
operation.then((result2) => {
|
|
223393
|
+
cleanup();
|
|
223394
|
+
resolve21(result2);
|
|
223395
|
+
}, (error5) => {
|
|
223396
|
+
cleanup();
|
|
223397
|
+
reject2(error5);
|
|
223398
|
+
});
|
|
223399
|
+
});
|
|
223400
|
+
}
|
|
223269
223401
|
function notificationText(toolReturn) {
|
|
223270
223402
|
return scrubAmbientSecrets(String(toolReturn));
|
|
223271
223403
|
}
|
|
223272
223404
|
async function autoBackgroundExternalTool(toolName2, tool, operation, options) {
|
|
223405
|
+
const signal = options?.signal;
|
|
223273
223406
|
const runtime = options?.runtimeScope;
|
|
223274
223407
|
const scope = options?.scope ?? (runtime?.agentId && runtime.conversationId ? {
|
|
223275
223408
|
agentId: runtime.agentId,
|
|
@@ -223278,24 +223411,36 @@ async function autoBackgroundExternalTool(toolName2, tool, operation, options) {
|
|
|
223278
223411
|
} : undefined);
|
|
223279
223412
|
const canBackground = () => typeof options?.canBackground === "function" ? options.canBackground() : options?.canBackground !== false;
|
|
223280
223413
|
if (tool?.autoBackground !== true || !canBackground() || !scope || !options?.enqueue && !isQueueBridgeConnected())
|
|
223281
|
-
return operation;
|
|
223414
|
+
return signal ? raceExternalOperationAbort(operation, signal, toolName2) : operation;
|
|
223282
223415
|
const startedAt = Date.now();
|
|
223283
223416
|
const settled = operation.then((result2) => ({ kind: "result", result: result2 }), (error5) => ({ kind: "error", error: error5 }));
|
|
223284
223417
|
let timer;
|
|
223418
|
+
let onAbort;
|
|
223419
|
+
const abortSettled = signal ? new Promise((resolve21) => {
|
|
223420
|
+
onAbort = () => resolve21({ kind: "aborted" });
|
|
223421
|
+
signal?.addEventListener("abort", onAbort);
|
|
223422
|
+
}) : undefined;
|
|
223285
223423
|
const first = await Promise.race([
|
|
223286
223424
|
settled,
|
|
223287
223425
|
new Promise((resolve21) => {
|
|
223288
223426
|
timer = setTimeout(() => resolve21({ kind: "yield" }), options?.yieldMs ?? DEFAULT_EXTERNAL_TOOL_YIELD_MS);
|
|
223289
|
-
})
|
|
223427
|
+
}),
|
|
223428
|
+
...abortSettled ? [abortSettled] : []
|
|
223290
223429
|
]);
|
|
223291
223430
|
if (timer !== undefined)
|
|
223292
223431
|
clearTimeout(timer);
|
|
223432
|
+
if (onAbort !== undefined && signal) {
|
|
223433
|
+
signal.removeEventListener("abort", onAbort);
|
|
223434
|
+
}
|
|
223435
|
+
if (first.kind === "aborted")
|
|
223436
|
+
return interruptedExternalToolResult(toolName2);
|
|
223293
223437
|
if (first.kind === "result")
|
|
223294
223438
|
return first.result;
|
|
223295
223439
|
if (first.kind === "error")
|
|
223296
223440
|
throw first.error;
|
|
223297
|
-
if (!canBackground())
|
|
223298
|
-
return operation;
|
|
223441
|
+
if (!canBackground()) {
|
|
223442
|
+
return signal ? raceExternalOperationAbort(operation, signal, toolName2) : operation;
|
|
223443
|
+
}
|
|
223299
223444
|
const taskId = `external_${crypto.randomUUID()}`;
|
|
223300
223445
|
const enqueue = options?.enqueue ?? addToMessageQueue;
|
|
223301
223446
|
settled.then(async (outcome) => {
|
|
@@ -223345,14 +223490,15 @@ function hasActiveToolEndHandlers(events) {
|
|
|
223345
223490
|
return false;
|
|
223346
223491
|
return events.hasHandlers?.("tool_end") ?? true;
|
|
223347
223492
|
}
|
|
223348
|
-
function listenerExternalToolBackgroundOptions(tool, events, runtimeScope) {
|
|
223493
|
+
function listenerExternalToolBackgroundOptions(tool, events, runtimeScope, signal) {
|
|
223349
223494
|
const registration = tool ? listenerRegistrations.get(tool) : undefined;
|
|
223350
223495
|
const notificationGuard = registration?.createNotificationGuard();
|
|
223351
223496
|
return {
|
|
223352
223497
|
canBackground: () => notificationGuard?.isCurrent() === true && !hasActiveToolEndHandlers(events),
|
|
223353
223498
|
...registration?.yieldMs !== undefined ? { yieldMs: registration.yieldMs } : {},
|
|
223354
223499
|
...notificationGuard ? { shouldEnqueue: notificationGuard.waitUntilCurrent } : {},
|
|
223355
|
-
runtimeScope
|
|
223500
|
+
runtimeScope,
|
|
223501
|
+
...signal ? { signal } : {}
|
|
223356
223502
|
};
|
|
223357
223503
|
}
|
|
223358
223504
|
var listenerRegistrations;
|
|
@@ -229130,7 +229276,6 @@ var LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS, PROJECT_SKILLS_DIR, SKILLS_DIR = ".skil
|
|
|
229130
229276
|
var init_skills5 = __esm(() => {
|
|
229131
229277
|
init_skill_sources();
|
|
229132
229278
|
LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS = new Set([
|
|
229133
|
-
"curating-memory-palace",
|
|
229134
229279
|
"image-generation",
|
|
229135
229280
|
"managing-agent-webhooks",
|
|
229136
229281
|
"managing-shared-memory",
|
|
@@ -229651,7 +229796,7 @@ async function buildClientSkillsPayload(options = {}) {
|
|
|
229651
229796
|
path: skill.path,
|
|
229652
229797
|
source: skill.source
|
|
229653
229798
|
})),
|
|
229654
|
-
skillPathById: Object.fromEntries(
|
|
229799
|
+
skillPathById: Object.fromEntries(discovery.skills.filter((skill) => typeof skill.path === "string" && skill.path.length > 0).map((skill) => [skill.id, skill.path])),
|
|
229655
229800
|
errors: errors6
|
|
229656
229801
|
};
|
|
229657
229802
|
if (useCache && generationBeforeDiscovery === getCacheGeneration() && checkoutGenerationBeforeDiscovery === getCheckoutGeneration()) {
|
|
@@ -230280,7 +230425,7 @@ function getExternalToolsAsClientTools() {
|
|
|
230280
230425
|
parameters: tool.parameters
|
|
230281
230426
|
}));
|
|
230282
230427
|
}
|
|
230283
|
-
async function executeExternalTool(toolCallId, toolName2, input, executorOverride, toolDefinition) {
|
|
230428
|
+
async function executeExternalTool(toolCallId, toolName2, input, executorOverride, toolDefinition, signal) {
|
|
230284
230429
|
const executor = executorOverride ?? getExternalToolExecutor();
|
|
230285
230430
|
if (!executor) {
|
|
230286
230431
|
return {
|
|
@@ -230292,7 +230437,7 @@ async function executeExternalTool(toolCallId, toolName2, input, executorOverrid
|
|
|
230292
230437
|
let success = false;
|
|
230293
230438
|
try {
|
|
230294
230439
|
const tool = toolDefinition ?? getExternalToolDefinition(toolName2);
|
|
230295
|
-
const result2 = await executor(toolCallId, toolName2, input, tool ? { tool } : undefined);
|
|
230440
|
+
const result2 = await executor(toolCallId, toolName2, input, tool ? { tool, signal } : undefined);
|
|
230296
230441
|
success = !result2.isError;
|
|
230297
230442
|
return {
|
|
230298
230443
|
toolReturn: clampToolReturnContent(normalizeExternalToolResultContent(result2.content), toolName2),
|
|
@@ -231059,7 +231204,7 @@ async function executeToolInner(name, args, options) {
|
|
|
231059
231204
|
if (permissionDecision2?.decision !== undefined && permissionDecision2.decision !== "allow") {
|
|
231060
231205
|
return createModPermissionToolResult(permissionDecision2);
|
|
231061
231206
|
}
|
|
231062
|
-
return runWithRuntimeContext(executionScope, () => autoBackgroundExternalTool(name, externalTool, executeExternalTool(options?.toolCallId ?? `ext-${Date.now()}`, name, eventArgs2, externalTool?.executor ?? activeExternalExecutor, externalTool), listenerExternalToolBackgroundOptions(externalTool, modEvents, executionScope)));
|
|
231207
|
+
return runWithRuntimeContext(executionScope, () => autoBackgroundExternalTool(name, externalTool, executeExternalTool(options?.toolCallId ?? `ext-${Date.now()}`, name, eventArgs2, externalTool?.executor ?? activeExternalExecutor, externalTool, options?.signal), listenerExternalToolBackgroundOptions(externalTool, modEvents, executionScope, options?.signal)));
|
|
231063
231208
|
}
|
|
231064
231209
|
const internalName = resolveInternalToolName(name, activeRegistry);
|
|
231065
231210
|
const tool = internalName ? activeRegistry.get(internalName) : undefined;
|
|
@@ -232521,12 +232666,12 @@ async function runCall(parsed, deps, agentId, stdout) {
|
|
|
232521
232666
|
await printJson(stdout, result2);
|
|
232522
232667
|
return result2.isError === true ? 2 : 0;
|
|
232523
232668
|
}
|
|
232524
|
-
async function callCatalogTool(catalog, deps, agentId, toolName2, args) {
|
|
232669
|
+
async function callCatalogTool(catalog, deps, agentId, toolName2, args, options) {
|
|
232525
232670
|
const tool = catalog.tools.find((candidate) => candidate.schema.name === toolName2);
|
|
232526
232671
|
if (!tool) {
|
|
232527
232672
|
throw new McpCliError("tool_not_found", `MCP tool '${toolName2}' is not available`);
|
|
232528
232673
|
}
|
|
232529
|
-
return tool.target.kind === "client" ? await tool.target.connection.callTool(tool.target.rawName, args) : mcpToolResultFromServer(await runUnifiedMcpTool({
|
|
232674
|
+
return tool.target.kind === "client" ? await tool.target.connection.callTool(tool.target.rawName, args, options) : mcpToolResultFromServer(await runUnifiedMcpTool({
|
|
232530
232675
|
client: await getServerClient(deps),
|
|
232531
232676
|
agentId,
|
|
232532
232677
|
mcpServerId: tool.target.serverId,
|
|
@@ -232555,7 +232700,7 @@ function createAgentMcpSession(agentId, deps = {}) {
|
|
|
232555
232700
|
return catalog;
|
|
232556
232701
|
};
|
|
232557
232702
|
return {
|
|
232558
|
-
callTool: async (toolName2, args) => callCatalogTool(await load(), deps, agentId, toolName2, args),
|
|
232703
|
+
callTool: async (toolName2, args, options) => callCatalogTool(await load(), deps, agentId, toolName2, args, options),
|
|
232559
232704
|
listTools: async () => (await load()).tools.map((tool) => tool.schema),
|
|
232560
232705
|
close: async () => {
|
|
232561
232706
|
closed = true;
|
|
@@ -232712,7 +232857,7 @@ async function createScriptToolScope(parentAgentId, signal) {
|
|
|
232712
232857
|
isError: result2.status === "error"
|
|
232713
232858
|
};
|
|
232714
232859
|
}
|
|
232715
|
-
return (await mcp()).callTool(toolName2, toolArgs);
|
|
232860
|
+
return (await mcp()).callTool(toolName2, toolArgs, signal ? { signal } : {});
|
|
232716
232861
|
},
|
|
232717
232862
|
cleanup: async () => {
|
|
232718
232863
|
await mcpSession?.then((session3) => session3.close()).catch(() => {
|
|
@@ -233255,6 +233400,9 @@ async function executeScript(spawner, options, meta2) {
|
|
|
233255
233400
|
if (opts.maxToolCalls !== undefined && (!Number.isSafeInteger(opts.maxToolCalls) || opts.maxToolCalls <= 0)) {
|
|
233256
233401
|
throw new Error("agent() maxToolCalls must be a positive safe integer.");
|
|
233257
233402
|
}
|
|
233403
|
+
if (opts.skills !== undefined && (!Array.isArray(opts.skills) || !opts.skills.every((id2) => typeof id2 === "string" && id2.trim()))) {
|
|
233404
|
+
throw new Error("agent() skills must be an array of skill names.");
|
|
233405
|
+
}
|
|
233258
233406
|
const callIndex = callCounter++;
|
|
233259
233407
|
const label = opts.label ?? defaultLabel(prompt);
|
|
233260
233408
|
const phase2 = opts.phase ?? currentPhase;
|
|
@@ -240001,6 +240149,9 @@ var init_monitor_event_stream = __esm(() => {
|
|
|
240001
240149
|
// src/tools/impl/monitor.ts
|
|
240002
240150
|
import { appendFileSync as appendFileSync7, readFileSync as readFileSync35, writeFileSync as writeFileSync27 } from "node:fs";
|
|
240003
240151
|
import { WebSocket as WebSocket4 } from "ws";
|
|
240152
|
+
function getMonitorTimeoutEvent(timeoutMs) {
|
|
240153
|
+
return isManagedCloudRuntime() && timeoutMs === MONITOR_MAX_TIMEOUT_MS ? "Monitor stopped at the 1-hour Cloud sandbox limit. Cloud monitors have a hard 1-hour limit to avoid keeping sandbox resources unnecessarily running. For later checks, schedule a Wake or cron, which does not keep the sandbox running between turns, and combine it with shorter monitors when needed." : "[Monitor timed out — re-arm if needed.]";
|
|
240154
|
+
}
|
|
240004
240155
|
function buildMonitorResult(taskId, timeoutMs, persistent, outputFile) {
|
|
240005
240156
|
const lifetime = persistent ? "persistent — runs until TaskStop or session end" : `timeout ${timeoutMs}ms`;
|
|
240006
240157
|
return {
|
|
@@ -240110,8 +240261,8 @@ function normalizeMonitorArgs(args) {
|
|
|
240110
240261
|
if (typeof normalized.description !== "string") {
|
|
240111
240262
|
throw new Error("Monitor description is required");
|
|
240112
240263
|
}
|
|
240113
|
-
if (typeof normalized.timeout_ms !== "number" || !Number.isFinite(normalized.timeout_ms) || normalized.timeout_ms < MIN_TIMEOUT_MS || !normalized.persistent && normalized.timeout_ms >
|
|
240114
|
-
throw new Error(`Monitor timeout_ms must be between ${MIN_TIMEOUT_MS} and ${
|
|
240264
|
+
if (typeof normalized.timeout_ms !== "number" || !Number.isFinite(normalized.timeout_ms) || normalized.timeout_ms < MIN_TIMEOUT_MS || !normalized.persistent && normalized.timeout_ms > MONITOR_MAX_TIMEOUT_MS) {
|
|
240265
|
+
throw new Error(`Monitor timeout_ms must be between ${MIN_TIMEOUT_MS} and ${MONITOR_MAX_TIMEOUT_MS}`);
|
|
240115
240266
|
}
|
|
240116
240267
|
if (typeof normalized.persistent !== "boolean") {
|
|
240117
240268
|
throw new Error("Monitor persistent must be a boolean");
|
|
@@ -240143,6 +240294,10 @@ function normalizeMonitorArgs(args) {
|
|
|
240143
240294
|
}
|
|
240144
240295
|
validateWebSocketSource(normalized.ws);
|
|
240145
240296
|
}
|
|
240297
|
+
if (isManagedCloudRuntime() && normalized.persistent) {
|
|
240298
|
+
normalized.persistent = false;
|
|
240299
|
+
normalized.timeout_ms = MONITOR_MAX_TIMEOUT_MS;
|
|
240300
|
+
}
|
|
240146
240301
|
return normalized;
|
|
240147
240302
|
}
|
|
240148
240303
|
function webSocketDisplayUrl(sourceUrl) {
|
|
@@ -240375,7 +240530,7 @@ function startCommandMonitor(args) {
|
|
|
240375
240530
|
`);
|
|
240376
240531
|
queueMonitorEvent({
|
|
240377
240532
|
taskId,
|
|
240378
|
-
event:
|
|
240533
|
+
event: getMonitorTimeoutEvent(args.timeout_ms),
|
|
240379
240534
|
scope,
|
|
240380
240535
|
actingUserId,
|
|
240381
240536
|
secrets: secrets2
|
|
@@ -240557,7 +240712,7 @@ function startWebSocketMonitor(args) {
|
|
|
240557
240712
|
return;
|
|
240558
240713
|
queueMonitorEvent({
|
|
240559
240714
|
taskId,
|
|
240560
|
-
event:
|
|
240715
|
+
event: getMonitorTimeoutEvent(args.timeout_ms),
|
|
240561
240716
|
scope,
|
|
240562
240717
|
actingUserId,
|
|
240563
240718
|
secrets: secrets2
|
|
@@ -240620,7 +240775,7 @@ function installMonitorProcessExitCleanup() {
|
|
|
240620
240775
|
monitorProcessExitCleanupInstalled = true;
|
|
240621
240776
|
process.once("exit", stopMonitorsForProcessExit);
|
|
240622
240777
|
}
|
|
240623
|
-
var MIN_TIMEOUT_MS = 1000,
|
|
240778
|
+
var MIN_TIMEOUT_MS = 1000, MONITOR_MAX_TIMEOUT_MS = 3600000, DEFAULT_TIMEOUT_MS4 = 300000, MONITOR_OUTPUT_FILE_BYTES, WEBSOCKET_MAX_PAYLOAD_BYTES, WEBSOCKET_PROTOCOL_PATTERN, monitorProcessExitCleanupInstalled = false;
|
|
240624
240779
|
var init_monitor = __esm(async () => {
|
|
240625
240780
|
init_strip_ansi();
|
|
240626
240781
|
init_runtime_context();
|
|
@@ -241429,6 +241584,12 @@ async function waitForShutdownRetry(delayMs, signal) {
|
|
|
241429
241584
|
onAbort();
|
|
241430
241585
|
});
|
|
241431
241586
|
}
|
|
241587
|
+
function getEnqueueAgentId(receipt) {
|
|
241588
|
+
const id2 = receipt.agent_id ?? receipt.parent_agent_id;
|
|
241589
|
+
if (!id2)
|
|
241590
|
+
throw new Error("Queued conversation has no agent or parent agent.");
|
|
241591
|
+
return id2;
|
|
241592
|
+
}
|
|
241432
241593
|
async function enqueueConversationMessage(input, signal, request = apiRequest) {
|
|
241433
241594
|
const body3 = {
|
|
241434
241595
|
agent_id: input.agentId,
|
|
@@ -241543,14 +241704,14 @@ function assistantText(messages) {
|
|
|
241543
241704
|
return text2.trim() ? text2 : null;
|
|
241544
241705
|
}
|
|
241545
241706
|
function noReplyMessage(receipt) {
|
|
241546
|
-
return `Remote task finished. Its reply was not collected. Read the conversation with: letta messages list --agent ${receipt
|
|
241707
|
+
return `Remote task finished. Its reply was not collected. Read the conversation with: letta messages list --agent ${getEnqueueAgentId(receipt)} --conversation ${receipt.conversation_id}. Do not launch the task again to retrieve its result.`;
|
|
241547
241708
|
}
|
|
241548
241709
|
async function waitForAcceptedSuperRun(receipt, signal, deps) {
|
|
241549
241710
|
const pollMs = deps.pollMs ?? 1000;
|
|
241550
241711
|
const sleep11 = deps.sleep ?? ((ms, waitSignal) => delay3(ms, undefined, { signal: waitSignal }));
|
|
241551
241712
|
while (true) {
|
|
241552
241713
|
signal.throwIfAborted();
|
|
241553
|
-
const exact = await retryRead(() => deps.exact(receipt
|
|
241714
|
+
const exact = await retryRead(() => deps.exact(getEnqueueAgentId(receipt), receipt.super_run_id, AbortSignal.any([signal, AbortSignal.timeout(30000)])), signal, sleep11, `Cloud status read for accepted Super Run ${receipt.super_run_id} failed`);
|
|
241554
241715
|
if (exact.id !== receipt.super_run_id) {
|
|
241555
241716
|
throw new RemoteExecutionFailed(`Exact Super Run read returned ${exact.id} for ${receipt.super_run_id}.`);
|
|
241556
241717
|
}
|
|
@@ -241588,6 +241749,7 @@ async function waitForAcceptedSuperRun(receipt, signal, deps) {
|
|
|
241588
241749
|
var RemoteExecutionFailed;
|
|
241589
241750
|
var init_headless_super_run_wait = __esm(() => {
|
|
241590
241751
|
init_letta_client();
|
|
241752
|
+
init_conversation_enqueue();
|
|
241591
241753
|
init_request();
|
|
241592
241754
|
RemoteExecutionFailed = class RemoteExecutionFailed extends Error {
|
|
241593
241755
|
};
|
|
@@ -241632,10 +241794,10 @@ function trackChildSend(input) {
|
|
|
241632
241794
|
const subagentId = generateSubagentId();
|
|
241633
241795
|
registerSubagent(subagentId, child.type, child.name, undefined, true, false, parentScope, input.prompt, false);
|
|
241634
241796
|
updateSubagent(subagentId, {
|
|
241635
|
-
agentId: receipt.agent_id,
|
|
241797
|
+
agentId: receipt.agent_id ?? undefined,
|
|
241636
241798
|
conversationId: receipt.conversation_id,
|
|
241637
241799
|
superRunId: receipt.super_run_id,
|
|
241638
|
-
agentURL: buildAgentReference(receipt
|
|
241800
|
+
agentURL: buildAgentReference(getEnqueueAgentId(receipt), {
|
|
241639
241801
|
conversationId: receipt.conversation_id
|
|
241640
241802
|
})
|
|
241641
241803
|
});
|
|
@@ -242398,7 +242560,7 @@ class CodexAppServerClient {
|
|
|
242398
242560
|
await this.request("initialize", {
|
|
242399
242561
|
clientInfo: {
|
|
242400
242562
|
name: "letta-code",
|
|
242401
|
-
version: "0.34.
|
|
242563
|
+
version: "0.34.19"
|
|
242402
242564
|
},
|
|
242403
242565
|
capabilities: null
|
|
242404
242566
|
});
|
|
@@ -242817,6 +242979,22 @@ var init_codex_app_server = __esm(() => {
|
|
|
242817
242979
|
DEFAULT_IDLE_TIMEOUT_MS = 5 * 60000;
|
|
242818
242980
|
});
|
|
242819
242981
|
|
|
242982
|
+
// src/agent/parent-memory-note.ts
|
|
242983
|
+
import { statSync as statSync18 } from "node:fs";
|
|
242984
|
+
function buildParentMemoryNote(parentAgentId) {
|
|
242985
|
+
const directory = getScopedMemoryFilesystemRoot(parentAgentId);
|
|
242986
|
+
try {
|
|
242987
|
+
if (!statSync18(directory).isDirectory())
|
|
242988
|
+
return;
|
|
242989
|
+
} catch {
|
|
242990
|
+
return;
|
|
242991
|
+
}
|
|
242992
|
+
return `Your parent agent (${parentAgentId}) keeps its memory as Markdown files at \`${directory}\`; attached shared-memory repos sit next to it. If the task depends on context about the user, project, people or conventions, check there first: start with \`MEMORY.md\` and the directory indexes, then open only the files that look relevant. Don't edit or commit there unless asked.`;
|
|
242993
|
+
}
|
|
242994
|
+
var init_parent_memory_note = __esm(() => {
|
|
242995
|
+
init_memory_filesystem2();
|
|
242996
|
+
});
|
|
242997
|
+
|
|
242820
242998
|
// src/cli/helpers/agent-info.ts
|
|
242821
242999
|
function getRelativeTime(dateStr) {
|
|
242822
243000
|
const date5 = new Date(dateStr);
|
|
@@ -242860,10 +243038,13 @@ function buildAgentInfo(options) {
|
|
|
242860
243038
|
})();
|
|
242861
243039
|
const memoryDirLine = showMemoryDir ? `
|
|
242862
243040
|
- **Memory directory (also stored in \`MEMORY_DIR\` env var)**: \`${getScopedMemoryFilesystemRoot(agentInfo.id)}\`` : "";
|
|
243041
|
+
const parentMemoryNote = options.parentAgentId && options.parentAgentId !== agentInfo.id ? buildParentMemoryNote(options.parentAgentId) : undefined;
|
|
243042
|
+
const parentMemoryLine = parentMemoryNote ? `
|
|
243043
|
+
- ${parentMemoryNote}` : "";
|
|
242863
243044
|
const convLine = conversationId ? `
|
|
242864
243045
|
- **Conversation ID (also stored in \`CONVERSATION_ID\` env var)**: ${conversationId}` : "";
|
|
242865
243046
|
return `${SYSTEM_REMINDER_OPEN} This is an automated message providing information about you.
|
|
242866
|
-
- **Agent ID (also stored in \`AGENT_ID\` env var)**: ${agentInfo.id}${convLine}${memoryDirLine}
|
|
243047
|
+
- **Agent ID (also stored in \`AGENT_ID\` env var)**: ${agentInfo.id}${convLine}${memoryDirLine}${parentMemoryLine}
|
|
242867
243048
|
- **Agent name**: ${agentInfo.name || "(unnamed)"} (the user can change this with /rename)
|
|
242868
243049
|
- **Agent description**: ${agentInfo.description || "(no description)"} (the user can change this with /description)
|
|
242869
243050
|
- **Last message**: ${lastRunInfo}
|
|
@@ -242874,6 +243055,7 @@ ${SYSTEM_REMINDER_CLOSE}`;
|
|
|
242874
243055
|
}
|
|
242875
243056
|
var init_agent_info = __esm(() => {
|
|
242876
243057
|
init_memory_filesystem2();
|
|
243058
|
+
init_parent_memory_note();
|
|
242877
243059
|
init_paths();
|
|
242878
243060
|
init_constants2();
|
|
242879
243061
|
init_settings_manager();
|
|
@@ -243343,7 +243525,14 @@ async function buildAgentInfoReminder(context3) {
|
|
|
243343
243525
|
if (!context3.systemInfoReminderEnabled || context3.state.hasSentAgentInfo) {
|
|
243344
243526
|
return null;
|
|
243345
243527
|
}
|
|
243528
|
+
let parentAgentId;
|
|
243529
|
+
try {
|
|
243530
|
+
const scopeAgentId = await getMcpScopeAgentId(context3.agent.id);
|
|
243531
|
+
if (scopeAgentId !== context3.agent.id)
|
|
243532
|
+
parentAgentId = scopeAgentId;
|
|
243533
|
+
} catch {}
|
|
243346
243534
|
const reminder = buildAgentInfo({
|
|
243535
|
+
parentAgentId,
|
|
243347
243536
|
agentInfo: {
|
|
243348
243537
|
id: context3.agent.id,
|
|
243349
243538
|
name: context3.agent.name,
|
|
@@ -244950,6 +245139,18 @@ async function resolveExternalCodingAgentSecretEnv(parentAgentId, lookupParent)
|
|
|
244950
245139
|
return { ...inherited, ...loadSecrets2(parentAgentId) };
|
|
244951
245140
|
}
|
|
244952
245141
|
async function runExternalCodingAgent(options, deps = {}) {
|
|
245142
|
+
const parentMemoryNote = buildParentMemoryNote(options.parentAgentId);
|
|
245143
|
+
options = {
|
|
245144
|
+
...options,
|
|
245145
|
+
mcpReminder: [
|
|
245146
|
+
parentMemoryNote ? `${SYSTEM_REMINDER_OPEN}
|
|
245147
|
+
${parentMemoryNote}
|
|
245148
|
+
${SYSTEM_REMINDER_CLOSE}` : undefined,
|
|
245149
|
+
options.mcpReminder
|
|
245150
|
+
].filter(Boolean).join(`
|
|
245151
|
+
|
|
245152
|
+
`) || undefined
|
|
245153
|
+
};
|
|
244953
245154
|
const startedAt = Date.now();
|
|
244954
245155
|
const secretEnv = await (deps.resolveSecretEnv ?? resolveExternalCodingAgentSecretEnv)(options.parentAgentId);
|
|
244955
245156
|
const env6 = {
|
|
@@ -245116,8 +245317,10 @@ async function runExternalCodingAgent(options, deps = {}) {
|
|
|
245116
245317
|
}
|
|
245117
245318
|
var EXTERNAL_CODING_AGENT_TYPES, EXTERNAL_AGENT_ID_PREFIXES, NATIVE_SESSION_ID_PATTERN, MISSING_EXECUTABLE_PREFIX = "Required executable '", CODEX_NOT_READY_PREFIX = "Codex executable is not ready", CLAUDE_NOT_SIGNED_IN_PREFIX = "claude-code authentication is not ready";
|
|
245118
245319
|
var init_external_coding_agent = __esm(() => {
|
|
245320
|
+
init_parent_memory_note();
|
|
245119
245321
|
init_subagent_depth();
|
|
245120
245322
|
init_subagent_process();
|
|
245323
|
+
init_constants2();
|
|
245121
245324
|
init_mcp_scope();
|
|
245122
245325
|
init_engine3();
|
|
245123
245326
|
init_runtime_context();
|
|
@@ -246327,8 +246530,11 @@ async function createListenerClient(connectionId, scope) {
|
|
|
246327
246530
|
});
|
|
246328
246531
|
}
|
|
246329
246532
|
async function cancelListenerInput(params) {
|
|
246533
|
+
const agentId = params.scope.agent_id ?? params.parentAgentId;
|
|
246534
|
+
if (!agentId)
|
|
246535
|
+
throw new Error("Listener cancellation requires an agent or parent agent.");
|
|
246330
246536
|
const removed = await (params.dequeue ?? dequeueConversationMessage)({
|
|
246331
|
-
agentId
|
|
246537
|
+
agentId,
|
|
246332
246538
|
conversationId: params.scope.conversation_id,
|
|
246333
246539
|
clientMessageId: params.clientMessageId,
|
|
246334
246540
|
actingUserId: params.scope.acting_user_id
|
|
@@ -246352,7 +246558,7 @@ async function cancelListenerInput(params) {
|
|
|
246352
246558
|
}
|
|
246353
246559
|
async function cancelAcceptedListenerInput(receipt) {
|
|
246354
246560
|
const removed = await dequeueConversationMessage({
|
|
246355
|
-
agentId: receipt
|
|
246561
|
+
agentId: getEnqueueAgentId(receipt),
|
|
246356
246562
|
conversationId: receipt.conversation_id,
|
|
246357
246563
|
clientMessageId: receipt.client_message_id,
|
|
246358
246564
|
actingUserId: receipt.acting_user_id
|
|
@@ -246376,6 +246582,7 @@ async function cancelAcceptedListenerInput(receipt) {
|
|
|
246376
246582
|
return await cancelListenerInput({
|
|
246377
246583
|
client,
|
|
246378
246584
|
scope,
|
|
246585
|
+
parentAgentId: receipt.parent_agent_id,
|
|
246379
246586
|
clientMessageId: receipt.client_message_id,
|
|
246380
246587
|
dequeue: async () => removed,
|
|
246381
246588
|
readState: () => ({ loop, cancelled: false })
|
|
@@ -246386,6 +246593,9 @@ async function cancelAcceptedListenerInput(receipt) {
|
|
|
246386
246593
|
}
|
|
246387
246594
|
}
|
|
246388
246595
|
async function launchListenerConversation(params, deps = {}) {
|
|
246596
|
+
const agentId = params.scope.agent_id ?? params.parentAgentId;
|
|
246597
|
+
if (!agentId)
|
|
246598
|
+
throw new Error("Listener delivery requires an agent or parent agent.");
|
|
246389
246599
|
const client = deps.client ?? await createListenerClient(params.connectionId, params.scope);
|
|
246390
246600
|
const clientMessageId = params.clientMessageId ?? randomUUID37();
|
|
246391
246601
|
const runIds = new Set;
|
|
@@ -246472,7 +246682,7 @@ async function launchListenerConversation(params, deps = {}) {
|
|
|
246472
246682
|
if (interrupted)
|
|
246473
246683
|
throw new Error("Launch cancelled before input was sent");
|
|
246474
246684
|
const accepted = await (deps.enqueue ?? enqueueConversationMessage)({
|
|
246475
|
-
agentId
|
|
246685
|
+
agentId,
|
|
246476
246686
|
conversationId: params.scope.conversation_id,
|
|
246477
246687
|
clientMessageId,
|
|
246478
246688
|
content: params.content,
|
|
@@ -246482,7 +246692,12 @@ async function launchListenerConversation(params, deps = {}) {
|
|
|
246482
246692
|
if (params.noWait)
|
|
246483
246693
|
return {
|
|
246484
246694
|
status: "queued",
|
|
246485
|
-
receipt: {
|
|
246695
|
+
receipt: {
|
|
246696
|
+
...accepted,
|
|
246697
|
+
connection_id: params.connectionId,
|
|
246698
|
+
agent_id: params.scope.agent_id,
|
|
246699
|
+
...params.scope.agent_id === null ? { parent_agent_id: agentId } : {}
|
|
246700
|
+
}
|
|
246486
246701
|
};
|
|
246487
246702
|
while (true) {
|
|
246488
246703
|
if (disconnected)
|
|
@@ -246496,6 +246711,7 @@ async function launchListenerConversation(params, deps = {}) {
|
|
|
246496
246711
|
if (await cancelListenerInput({
|
|
246497
246712
|
client,
|
|
246498
246713
|
scope: params.scope,
|
|
246714
|
+
parentAgentId: params.parentAgentId,
|
|
246499
246715
|
clientMessageId,
|
|
246500
246716
|
dequeue: deps.dequeue,
|
|
246501
246717
|
readState: () => ({ loop, cancelled })
|
|
@@ -246615,7 +246831,7 @@ function handleToolReturnEvent(event, state2) {
|
|
|
246615
246831
|
}
|
|
246616
246832
|
}
|
|
246617
246833
|
function isEnqueueReceipt(event) {
|
|
246618
|
-
return event.status === "queued" && typeof event.agent_id === "string" && typeof event.conversation_id === "string" && typeof event.client_message_id === "string" && typeof event.super_run_id === "string" && typeof event.workflow_id === "string" && (event.acting_user_id === undefined || event.acting_user_id === null || typeof event.acting_user_id === "string");
|
|
246834
|
+
return event.status === "queued" && (typeof event.agent_id === "string" || event.agent_id === null && typeof event.parent_agent_id === "string") && (event.parent_agent_id === undefined || typeof event.parent_agent_id === "string") && typeof event.conversation_id === "string" && typeof event.client_message_id === "string" && typeof event.super_run_id === "string" && typeof event.workflow_id === "string" && (event.acting_user_id === undefined || event.acting_user_id === null || typeof event.acting_user_id === "string");
|
|
246619
246835
|
}
|
|
246620
246836
|
function getResultEnvelopeError(event) {
|
|
246621
246837
|
return event.error || event.result || "Unknown error";
|
|
@@ -246626,6 +246842,7 @@ function handleResultEvent(event, state2, subagentId) {
|
|
|
246626
246842
|
state2.enqueueReceipt = {
|
|
246627
246843
|
status: "queued",
|
|
246628
246844
|
agent_id: event.agent_id,
|
|
246845
|
+
...event.parent_agent_id ? { parent_agent_id: event.parent_agent_id } : {},
|
|
246629
246846
|
conversation_id: event.conversation_id,
|
|
246630
246847
|
client_message_id: event.client_message_id,
|
|
246631
246848
|
super_run_id: event.super_run_id,
|
|
@@ -246757,9 +246974,9 @@ var init_subagent_stream = __esm(() => {
|
|
|
246757
246974
|
async function collectRemoteTurnResult(receipt, state2, subagentId, signal = new AbortController().signal) {
|
|
246758
246975
|
const startedAt = Date.now();
|
|
246759
246976
|
updateSubagent(subagentId, {
|
|
246760
|
-
agentId: receipt.agent_id,
|
|
246977
|
+
agentId: receipt.agent_id ?? undefined,
|
|
246761
246978
|
conversationId: receipt.conversation_id,
|
|
246762
|
-
agentURL: buildAgentReference(receipt
|
|
246979
|
+
agentURL: buildAgentReference(getEnqueueAgentId(receipt), {
|
|
246763
246980
|
conversationId: receipt.conversation_id
|
|
246764
246981
|
})
|
|
246765
246982
|
});
|
|
@@ -246779,7 +246996,7 @@ async function collectRemoteTurnResult(receipt, state2, subagentId, signal = new
|
|
|
246779
246996
|
}
|
|
246780
246997
|
});
|
|
246781
246998
|
return {
|
|
246782
|
-
agentId: receipt.agent_id,
|
|
246999
|
+
agentId: receipt.agent_id ?? "",
|
|
246783
247000
|
conversationId: receipt.conversation_id,
|
|
246784
247001
|
report: reply.text,
|
|
246785
247002
|
success: true,
|
|
@@ -246792,7 +247009,7 @@ async function collectRemoteTurnResult(receipt, state2, subagentId, signal = new
|
|
|
246792
247009
|
detail = cancelled ? INTERRUPTED_BY_USER : `${INTERRUPTED_BY_USER} (could not confirm cancellation of remote Super Run ${receipt.super_run_id})`;
|
|
246793
247010
|
}
|
|
246794
247011
|
return {
|
|
246795
|
-
agentId: receipt.agent_id,
|
|
247012
|
+
agentId: receipt.agent_id ?? "",
|
|
246796
247013
|
conversationId: receipt.conversation_id,
|
|
246797
247014
|
report: "",
|
|
246798
247015
|
success: false,
|
|
@@ -248730,12 +248947,13 @@ async function launchRemoteExternalCodingAgent(params, deps) {
|
|
|
248730
248947
|
durationMs: final.duration_ms || Date.now() - startedAt
|
|
248731
248948
|
};
|
|
248732
248949
|
} catch (error5) {
|
|
248950
|
+
const remoteWorkerStopped = signal?.reason === REMOTE_EXTERNAL_WORKER_STOPPED;
|
|
248733
248951
|
return {
|
|
248734
248952
|
agentId: parentScope.agentId,
|
|
248735
248953
|
model,
|
|
248736
248954
|
report: "",
|
|
248737
248955
|
success: false,
|
|
248738
|
-
error: error5 instanceof RemoteWorkerLostError && !signal?.aborted ? `The ${type3} worker on ${computer} is no longer listed: it may have finished while this session was disconnected (results are kept for 30 minutes), or the listener restarted. Check ${computer} or launch it again if the work is still needed.` : `${signal?.aborted ? "Stopped following this subagent" : errorMessage3(error5)}. The ${type3} worker may still be running on ${computer}.`,
|
|
248956
|
+
error: error5 instanceof RemoteWorkerLostError && !signal?.aborted ? `The ${type3} worker on ${computer} is no longer listed: it may have finished while this session was disconnected (results are kept for 30 minutes), or the listener restarted. Check ${computer} or launch it again if the work is still needed.` : remoteWorkerStopped ? `Stopped the ${type3} worker on ${computer}.` : `${signal?.aborted ? "Stopped following this subagent" : errorMessage3(error5)}. The ${type3} worker may still be running on ${computer}.`,
|
|
248739
248957
|
durationMs: Date.now() - startedAt
|
|
248740
248958
|
};
|
|
248741
248959
|
} finally {
|
|
@@ -248880,7 +249098,7 @@ async function sendRemoteExternalCodingAgentMessage(params, deps = {}) {
|
|
|
248880
249098
|
outputFile: tracked.outputFile
|
|
248881
249099
|
};
|
|
248882
249100
|
}
|
|
248883
|
-
var DISPLAY_NAMES, RemoteWorkerLostError;
|
|
249101
|
+
var REMOTE_EXTERNAL_WORKER_STOPPED, DISPLAY_NAMES, RemoteWorkerLostError;
|
|
248884
249102
|
var init_remote_external_coding_agent = __esm(() => {
|
|
248885
249103
|
init_subagent_state();
|
|
248886
249104
|
init_app_server_client();
|
|
@@ -248890,6 +249108,7 @@ var init_remote_external_coding_agent = __esm(() => {
|
|
|
248890
249108
|
init_headless_environment_response();
|
|
248891
249109
|
init_headless_listener_launch();
|
|
248892
249110
|
init_external_coding_agent();
|
|
249111
|
+
REMOTE_EXTERNAL_WORKER_STOPPED = Symbol("remote external worker stopped");
|
|
248893
249112
|
DISPLAY_NAMES = {
|
|
248894
249113
|
"claude-code": "Claude Code",
|
|
248895
249114
|
codex: "Codex",
|
|
@@ -248948,6 +249167,184 @@ var init_subagent_computer = __esm(() => {
|
|
|
248948
249167
|
LOCAL_COMPUTER_SELECTORS = new Set(["local", "self"]);
|
|
248949
249168
|
});
|
|
248950
249169
|
|
|
249170
|
+
// src/tools/impl/kill-bash.ts
|
|
249171
|
+
function killBackgroundProcess(shell_id) {
|
|
249172
|
+
const proc = backgroundProcesses.get(shell_id);
|
|
249173
|
+
const retainsEntry = proc?.kind === "monitor" || proc?.kind === "workflow";
|
|
249174
|
+
if (!proc || retainsEntry && proc.status !== "running") {
|
|
249175
|
+
return false;
|
|
249176
|
+
}
|
|
249177
|
+
const previousStatus = proc.status;
|
|
249178
|
+
const previousNotificationSuppression = proc.completionNotificationSuppressed;
|
|
249179
|
+
try {
|
|
249180
|
+
proc.completionNotificationSuppressed = true;
|
|
249181
|
+
if (retainsEntry) {
|
|
249182
|
+
proc.status = "failed";
|
|
249183
|
+
}
|
|
249184
|
+
proc.process.kill("SIGTERM");
|
|
249185
|
+
if (proc.kind === "monitor")
|
|
249186
|
+
cancelMonitorBackup(shell_id);
|
|
249187
|
+
clearBackgroundProcessCleanup(shell_id);
|
|
249188
|
+
if (retainsEntry) {
|
|
249189
|
+
scheduleBackgroundProcessCleanup(shell_id);
|
|
249190
|
+
notifyBackgroundProcessStateChanged(proc.runtimeScope);
|
|
249191
|
+
} else {
|
|
249192
|
+
backgroundProcesses.delete(shell_id);
|
|
249193
|
+
}
|
|
249194
|
+
return true;
|
|
249195
|
+
} catch {
|
|
249196
|
+
proc.status = previousStatus;
|
|
249197
|
+
proc.completionNotificationSuppressed = previousNotificationSuppression;
|
|
249198
|
+
return false;
|
|
249199
|
+
}
|
|
249200
|
+
}
|
|
249201
|
+
var init_kill_bash = __esm(async () => {
|
|
249202
|
+
init_process_manager();
|
|
249203
|
+
await init_monitor_backup();
|
|
249204
|
+
});
|
|
249205
|
+
|
|
249206
|
+
// src/tools/impl/task-stop.ts
|
|
249207
|
+
var exports_task_stop = {};
|
|
249208
|
+
__export(exports_task_stop, {
|
|
249209
|
+
task_stop: () => task_stop
|
|
249210
|
+
});
|
|
249211
|
+
async function cancelRemoteRun(subagentId) {
|
|
249212
|
+
const child = getSubagents().find((agent) => agent.id === subagentId);
|
|
249213
|
+
const target2 = child?.conversationId === "default" ? child.agentId : child?.conversationId;
|
|
249214
|
+
try {
|
|
249215
|
+
if (!target2)
|
|
249216
|
+
throw new Error("its conversation is not known yet");
|
|
249217
|
+
const results = await getBackend().cancelConversation(target2);
|
|
249218
|
+
const outcomes = Object.values(results);
|
|
249219
|
+
if (outcomes.length === 0 || outcomes.some((status) => status !== "cancelled")) {
|
|
249220
|
+
throw new Error("Cloud did not cancel every run");
|
|
249221
|
+
}
|
|
249222
|
+
return { killed: true, output: "Cancelled the remote run" };
|
|
249223
|
+
} catch (error5) {
|
|
249224
|
+
return {
|
|
249225
|
+
killed: false,
|
|
249226
|
+
output: `Couldn't cancel the remote run: ${getErrorMessage2(error5)}`
|
|
249227
|
+
};
|
|
249228
|
+
}
|
|
249229
|
+
}
|
|
249230
|
+
async function task_stop(args, deps = {}) {
|
|
249231
|
+
validateRequiredParams(args, ["task_id"], "TaskStop");
|
|
249232
|
+
const { task_id } = args;
|
|
249233
|
+
const task = backgroundTasks.get(task_id);
|
|
249234
|
+
if (task) {
|
|
249235
|
+
if (task.status === "running" && task.abortController) {
|
|
249236
|
+
const child = getSubagents().find((agent) => agent.id === task.subagentId);
|
|
249237
|
+
const external3 = parseExternalCodingAgentId(child?.agentId ?? undefined);
|
|
249238
|
+
let remote;
|
|
249239
|
+
let remoteExternalStopped = false;
|
|
249240
|
+
if (external3?.computer) {
|
|
249241
|
+
try {
|
|
249242
|
+
if (!task.runtimeScope)
|
|
249243
|
+
throw new Error("its parent conversation is not known");
|
|
249244
|
+
const result3 = await (deps.stopRemoteExternal ?? stopRemoteExternalCodingAgent)({
|
|
249245
|
+
agentId: child?.agentId,
|
|
249246
|
+
parentScope: {
|
|
249247
|
+
agentId: task.runtimeScope.agentId,
|
|
249248
|
+
conversationId: task.runtimeScope.conversationId,
|
|
249249
|
+
actingUserId: task.actingUserId
|
|
249250
|
+
}
|
|
249251
|
+
});
|
|
249252
|
+
remote = {
|
|
249253
|
+
killed: result3.stopped,
|
|
249254
|
+
output: result3.stopped ? "Stopped the remote external subagent" : "The remote external subagent was not running"
|
|
249255
|
+
};
|
|
249256
|
+
remoteExternalStopped = result3.stopped;
|
|
249257
|
+
} catch (error5) {
|
|
249258
|
+
remote = {
|
|
249259
|
+
killed: false,
|
|
249260
|
+
output: `Couldn't stop the remote external subagent: ${getErrorMessage2(error5)}`
|
|
249261
|
+
};
|
|
249262
|
+
}
|
|
249263
|
+
} else if (task.remote) {
|
|
249264
|
+
remote = await cancelRemoteRun(task.subagentId);
|
|
249265
|
+
}
|
|
249266
|
+
if (remote && !remote.killed)
|
|
249267
|
+
return remote;
|
|
249268
|
+
task.abortController.abort(remoteExternalStopped ? REMOTE_EXTERNAL_WORKER_STOPPED : undefined);
|
|
249269
|
+
task.error = "Aborted by user";
|
|
249270
|
+
await task.completion;
|
|
249271
|
+
task.status = "failed";
|
|
249272
|
+
scheduleBackgroundTaskCleanup(task_id);
|
|
249273
|
+
return remote ?? { killed: true };
|
|
249274
|
+
}
|
|
249275
|
+
return { killed: false };
|
|
249276
|
+
}
|
|
249277
|
+
return { killed: killBackgroundProcess(task_id) };
|
|
249278
|
+
}
|
|
249279
|
+
var init_task_stop = __esm(async () => {
|
|
249280
|
+
init_subagent_state();
|
|
249281
|
+
init_backend2();
|
|
249282
|
+
init_external_coding_agent();
|
|
249283
|
+
init_process_manager();
|
|
249284
|
+
init_remote_external_coding_agent();
|
|
249285
|
+
await init_kill_bash();
|
|
249286
|
+
});
|
|
249287
|
+
|
|
249288
|
+
// src/tools/impl/task-abort-hook.ts
|
|
249289
|
+
function buildBackgroundTaskAbortHook(taskId, abortController) {
|
|
249290
|
+
const bgTask = backgroundTasks.get(taskId);
|
|
249291
|
+
const remote = bgTask?.remote ?? false;
|
|
249292
|
+
const failSafeAbort = () => !remote && abortController.abort();
|
|
249293
|
+
const hook = () => {
|
|
249294
|
+
init_task_stop().then(() => exports_task_stop).then((m4) => m4.task_stop({ task_id: taskId })).then((result3) => {
|
|
249295
|
+
if (!result3.killed)
|
|
249296
|
+
failSafeAbort();
|
|
249297
|
+
settleInterruptedCancel(bgTask, remote, result3.killed, hook);
|
|
249298
|
+
}).catch(() => {
|
|
249299
|
+
failSafeAbort();
|
|
249300
|
+
settleInterruptedCancel(bgTask, remote, false, hook);
|
|
249301
|
+
});
|
|
249302
|
+
};
|
|
249303
|
+
return hook;
|
|
249304
|
+
}
|
|
249305
|
+
function settleInterruptedCancel(bgTask, remote, killed, hook) {
|
|
249306
|
+
if (!bgTask)
|
|
249307
|
+
return;
|
|
249308
|
+
const taskLive = bgTask.status === "running";
|
|
249309
|
+
if (remote && !killed && taskLive) {
|
|
249310
|
+
restoreInterruptedSubagentRow(bgTask.subagentId, hook);
|
|
249311
|
+
return;
|
|
249312
|
+
}
|
|
249313
|
+
const row = getSubagents().find((agent) => agent.id === bgTask.subagentId);
|
|
249314
|
+
updateSubagent(bgTask.subagentId, {
|
|
249315
|
+
cancelPending: undefined,
|
|
249316
|
+
stopFailed: undefined,
|
|
249317
|
+
stopOutcome: {
|
|
249318
|
+
attempt: row?.stopAttempts ?? 0,
|
|
249319
|
+
kind: killed ? "stopped" : "natural"
|
|
249320
|
+
}
|
|
249321
|
+
});
|
|
249322
|
+
}
|
|
249323
|
+
function restoreInterruptedSubagentRow(subagentId, hook) {
|
|
249324
|
+
const row = getSubagents().find((agent) => agent.id === subagentId);
|
|
249325
|
+
if (!row || row.status !== "error" || row.result !== undefined) {
|
|
249326
|
+
if (row) {
|
|
249327
|
+
updateSubagent(subagentId, {
|
|
249328
|
+
cancelPending: undefined,
|
|
249329
|
+
stopOutcome: { attempt: row.stopAttempts ?? 0, kind: "natural" }
|
|
249330
|
+
});
|
|
249331
|
+
}
|
|
249332
|
+
return;
|
|
249333
|
+
}
|
|
249334
|
+
updateSubagent(subagentId, {
|
|
249335
|
+
status: "running",
|
|
249336
|
+
error: undefined,
|
|
249337
|
+
cancelPending: undefined,
|
|
249338
|
+
stopFailed: true,
|
|
249339
|
+
stopOutcome: { attempt: row.stopAttempts ?? 0, kind: "failed" }
|
|
249340
|
+
});
|
|
249341
|
+
registerSubagentAbortHook(subagentId, hook);
|
|
249342
|
+
}
|
|
249343
|
+
var init_task_abort_hook = __esm(() => {
|
|
249344
|
+
init_subagent_state();
|
|
249345
|
+
init_process_manager();
|
|
249346
|
+
});
|
|
249347
|
+
|
|
248951
249348
|
// src/tools/impl/task-transcript.ts
|
|
248952
249349
|
function buildTaskResultHeader(subagentType, subagentId, result3, status) {
|
|
248953
249350
|
return [
|
|
@@ -249066,6 +249463,7 @@ function spawnBackgroundSubagentTask(args) {
|
|
|
249066
249463
|
actingUserId
|
|
249067
249464
|
};
|
|
249068
249465
|
backgroundTasks.set(taskId, bgTask);
|
|
249466
|
+
registerSubagentAbortHook(subagentId, buildBackgroundTaskAbortHook(taskId, abortController));
|
|
249069
249467
|
writeTaskTranscriptStart(outputFile, description, subagentType);
|
|
249070
249468
|
const parentAgentIdForSpawn = resolvedParentScope?.agentId;
|
|
249071
249469
|
const workerMemoryDir = subagentType === "memory" && resolvedParentScope ? memoryScope?.primaryRoot ?? getScopedMemoryFilesystemRoot(resolvedParentScope.agentId) : undefined;
|
|
@@ -249097,6 +249495,7 @@ function spawnBackgroundSubagentTask(args) {
|
|
|
249097
249495
|
const header = buildTaskResultHeader(subagentType, subagentId, result3, result3.success ? "success" : "error");
|
|
249098
249496
|
writeTaskTranscriptResult(outputFile, result3, header, !!memoryTask);
|
|
249099
249497
|
scheduleBackgroundTaskCleanup(taskId);
|
|
249498
|
+
clearSubagentAbortHook(subagentId);
|
|
249100
249499
|
completeSubagentFn(subagentId, {
|
|
249101
249500
|
success: result3.success,
|
|
249102
249501
|
error: result3.error,
|
|
@@ -249164,6 +249563,7 @@ Error: ${result3.error || "Subagent execution failed"}`;
|
|
|
249164
249563
|
[Task failed]
|
|
249165
249564
|
`);
|
|
249166
249565
|
scheduleBackgroundTaskCleanup(taskId);
|
|
249566
|
+
clearSubagentAbortHook(subagentId);
|
|
249167
249567
|
completeSubagentFn(subagentId, { success: false, error: errorMessage4 });
|
|
249168
249568
|
try {
|
|
249169
249569
|
await onComplete?.({
|
|
@@ -249522,6 +249922,7 @@ var init_task = __esm(async () => {
|
|
|
249522
249922
|
init_process_manager();
|
|
249523
249923
|
init_remote_external_coding_agent();
|
|
249524
249924
|
init_subagent_computer();
|
|
249925
|
+
init_task_abort_hook();
|
|
249525
249926
|
init_task_transcript();
|
|
249526
249927
|
init_truncation();
|
|
249527
249928
|
init_background_link();
|
|
@@ -250414,118 +250815,6 @@ var init_task_list = __esm(() => {
|
|
|
250414
250815
|
init_store();
|
|
250415
250816
|
});
|
|
250416
250817
|
|
|
250417
|
-
// src/tools/impl/kill-bash.ts
|
|
250418
|
-
function killBackgroundProcess(shell_id) {
|
|
250419
|
-
const proc = backgroundProcesses.get(shell_id);
|
|
250420
|
-
const retainsEntry = proc?.kind === "monitor" || proc?.kind === "workflow";
|
|
250421
|
-
if (!proc || retainsEntry && proc.status !== "running") {
|
|
250422
|
-
return false;
|
|
250423
|
-
}
|
|
250424
|
-
const previousStatus = proc.status;
|
|
250425
|
-
const previousNotificationSuppression = proc.completionNotificationSuppressed;
|
|
250426
|
-
try {
|
|
250427
|
-
proc.completionNotificationSuppressed = true;
|
|
250428
|
-
if (retainsEntry) {
|
|
250429
|
-
proc.status = "failed";
|
|
250430
|
-
}
|
|
250431
|
-
proc.process.kill("SIGTERM");
|
|
250432
|
-
if (proc.kind === "monitor")
|
|
250433
|
-
cancelMonitorBackup(shell_id);
|
|
250434
|
-
clearBackgroundProcessCleanup(shell_id);
|
|
250435
|
-
if (retainsEntry) {
|
|
250436
|
-
scheduleBackgroundProcessCleanup(shell_id);
|
|
250437
|
-
notifyBackgroundProcessStateChanged(proc.runtimeScope);
|
|
250438
|
-
} else {
|
|
250439
|
-
backgroundProcesses.delete(shell_id);
|
|
250440
|
-
}
|
|
250441
|
-
return true;
|
|
250442
|
-
} catch {
|
|
250443
|
-
proc.status = previousStatus;
|
|
250444
|
-
proc.completionNotificationSuppressed = previousNotificationSuppression;
|
|
250445
|
-
return false;
|
|
250446
|
-
}
|
|
250447
|
-
}
|
|
250448
|
-
var init_kill_bash = __esm(async () => {
|
|
250449
|
-
init_process_manager();
|
|
250450
|
-
await init_monitor_backup();
|
|
250451
|
-
});
|
|
250452
|
-
|
|
250453
|
-
// src/tools/impl/task-stop.ts
|
|
250454
|
-
async function cancelRemoteRun(subagentId) {
|
|
250455
|
-
const child = getSubagents().find((agent) => agent.id === subagentId);
|
|
250456
|
-
const target2 = child?.conversationId === "default" ? child.agentId : child?.conversationId;
|
|
250457
|
-
try {
|
|
250458
|
-
if (!target2)
|
|
250459
|
-
throw new Error("its conversation is not known yet");
|
|
250460
|
-
const results = await getBackend().cancelConversation(target2);
|
|
250461
|
-
const outcomes = Object.values(results);
|
|
250462
|
-
if (outcomes.length === 0 || outcomes.some((status) => status !== "cancelled")) {
|
|
250463
|
-
throw new Error("Cloud did not cancel every run");
|
|
250464
|
-
}
|
|
250465
|
-
return { killed: true, output: "Cancelled the remote run" };
|
|
250466
|
-
} catch (error5) {
|
|
250467
|
-
return {
|
|
250468
|
-
killed: false,
|
|
250469
|
-
output: `Couldn't cancel the remote run: ${getErrorMessage2(error5)}`
|
|
250470
|
-
};
|
|
250471
|
-
}
|
|
250472
|
-
}
|
|
250473
|
-
async function task_stop(args, deps = {}) {
|
|
250474
|
-
validateRequiredParams(args, ["task_id"], "TaskStop");
|
|
250475
|
-
const { task_id } = args;
|
|
250476
|
-
const task2 = backgroundTasks.get(task_id);
|
|
250477
|
-
if (task2) {
|
|
250478
|
-
if (task2.status === "running" && task2.abortController) {
|
|
250479
|
-
const child = getSubagents().find((agent) => agent.id === task2.subagentId);
|
|
250480
|
-
const external3 = parseExternalCodingAgentId(child?.agentId ?? undefined);
|
|
250481
|
-
let remote;
|
|
250482
|
-
if (external3?.computer) {
|
|
250483
|
-
try {
|
|
250484
|
-
if (!task2.runtimeScope)
|
|
250485
|
-
throw new Error("its parent conversation is not known");
|
|
250486
|
-
const result3 = await (deps.stopRemoteExternal ?? stopRemoteExternalCodingAgent)({
|
|
250487
|
-
agentId: child?.agentId,
|
|
250488
|
-
parentScope: {
|
|
250489
|
-
agentId: task2.runtimeScope.agentId,
|
|
250490
|
-
conversationId: task2.runtimeScope.conversationId,
|
|
250491
|
-
actingUserId: task2.actingUserId
|
|
250492
|
-
}
|
|
250493
|
-
});
|
|
250494
|
-
remote = {
|
|
250495
|
-
killed: result3.stopped,
|
|
250496
|
-
output: result3.stopped ? "Stopped the remote external subagent" : "The remote external subagent was not running"
|
|
250497
|
-
};
|
|
250498
|
-
} catch (error5) {
|
|
250499
|
-
remote = {
|
|
250500
|
-
killed: false,
|
|
250501
|
-
output: `Couldn't stop the remote external subagent: ${getErrorMessage2(error5)}`
|
|
250502
|
-
};
|
|
250503
|
-
}
|
|
250504
|
-
} else if (task2.remote) {
|
|
250505
|
-
remote = await cancelRemoteRun(task2.subagentId);
|
|
250506
|
-
}
|
|
250507
|
-
if (remote && !remote.killed)
|
|
250508
|
-
return remote;
|
|
250509
|
-
task2.abortController.abort();
|
|
250510
|
-
task2.error = "Aborted by user";
|
|
250511
|
-
await task2.completion;
|
|
250512
|
-
task2.status = "failed";
|
|
250513
|
-
scheduleBackgroundTaskCleanup(task_id);
|
|
250514
|
-
return remote ?? { killed: true };
|
|
250515
|
-
}
|
|
250516
|
-
return { killed: false };
|
|
250517
|
-
}
|
|
250518
|
-
return { killed: killBackgroundProcess(task_id) };
|
|
250519
|
-
}
|
|
250520
|
-
var init_task_stop = __esm(async () => {
|
|
250521
|
-
init_subagent_state();
|
|
250522
|
-
init_backend2();
|
|
250523
|
-
init_external_coding_agent();
|
|
250524
|
-
init_process_manager();
|
|
250525
|
-
init_remote_external_coding_agent();
|
|
250526
|
-
await init_kill_bash();
|
|
250527
|
-
});
|
|
250528
|
-
|
|
250529
250818
|
// src/tools/impl/task-update.ts
|
|
250530
250819
|
function validateStringArray(value, paramName) {
|
|
250531
250820
|
if (value === undefined)
|
|
@@ -251580,6 +251869,8 @@ ${describeGitHubPullRequestSnapshot(initial2)}
|
|
|
251580
251869
|
const controller = new AbortController;
|
|
251581
251870
|
const secrets2 = {};
|
|
251582
251871
|
let processState;
|
|
251872
|
+
const persistent = !isManagedCloudRuntime();
|
|
251873
|
+
let timeout;
|
|
251583
251874
|
const events = createMonitorEventStream({
|
|
251584
251875
|
emit(event) {
|
|
251585
251876
|
queueMonitorEvent({
|
|
@@ -251618,6 +251909,7 @@ ${describeGitHubPullRequestSnapshot(initial2)}
|
|
|
251618
251909
|
processState = {
|
|
251619
251910
|
process: {
|
|
251620
251911
|
kill() {
|
|
251912
|
+
clearTimeout(timeout);
|
|
251621
251913
|
events.cancel();
|
|
251622
251914
|
controller.abort();
|
|
251623
251915
|
}
|
|
@@ -251632,11 +251924,29 @@ ${describeGitHubPullRequestSnapshot(initial2)}
|
|
|
251632
251924
|
kind: "monitor",
|
|
251633
251925
|
description,
|
|
251634
251926
|
monitorSource: "github_pull_request",
|
|
251635
|
-
persistent
|
|
251927
|
+
persistent,
|
|
251636
251928
|
secrets: secrets2
|
|
251637
251929
|
};
|
|
251638
251930
|
backgroundProcesses.set(taskId, processState);
|
|
251639
251931
|
notifyBackgroundProcessStateChanged(scope);
|
|
251932
|
+
if (!persistent) {
|
|
251933
|
+
timeout = setTimeout(() => {
|
|
251934
|
+
if (processState.status !== "running")
|
|
251935
|
+
return;
|
|
251936
|
+
events.finish();
|
|
251937
|
+
if (processState.status !== "running")
|
|
251938
|
+
return;
|
|
251939
|
+
const event = getMonitorTimeoutEvent(MONITOR_MAX_TIMEOUT_MS);
|
|
251940
|
+
output.append(`
|
|
251941
|
+
${event}
|
|
251942
|
+
`);
|
|
251943
|
+
queueMonitorEvent({ taskId, event, scope, actingUserId, secrets: secrets2 });
|
|
251944
|
+
processState.completionNotificationSuppressed = true;
|
|
251945
|
+
markMonitorFinished(taskId, processState, "failed", null);
|
|
251946
|
+
processState.process.kill();
|
|
251947
|
+
}, MONITOR_MAX_TIMEOUT_MS);
|
|
251948
|
+
unrefTimer(timeout);
|
|
251949
|
+
}
|
|
251640
251950
|
const wait = deps.wait ?? defaultWait;
|
|
251641
251951
|
(async () => {
|
|
251642
251952
|
let previous = initial2;
|
|
@@ -251700,12 +252010,12 @@ ${describeGitHubPullRequestSnapshot(initial2)}
|
|
|
251700
252010
|
if (processState.status === "running") {
|
|
251701
252011
|
markMonitorFinished(taskId, processState, "failed", null);
|
|
251702
252012
|
}
|
|
251703
|
-
});
|
|
252013
|
+
}).finally(() => clearTimeout(timeout));
|
|
251704
252014
|
return {
|
|
251705
252015
|
content: [
|
|
251706
252016
|
{
|
|
251707
252017
|
type: "text",
|
|
251708
|
-
text: `WatchPR started (task ${taskId}). It will keep watching after CI finishes and report new failures, reviews, comments, conflicts, head changes, merge-state changes, and watcher errors. It stops when the PR merges/closes, on TaskStop, or when this session ends.
|
|
252018
|
+
text: `WatchPR started (task ${taskId}). It will keep watching after CI finishes and report new failures, reviews, comments, conflicts, head changes, merge-state changes, and watcher errors. It stops when the PR merges/closes, on TaskStop, or when this session ends.${persistent ? "" : " A hard 1-hour limit applies in this Cloud sandbox; use Wake or cron for later checks."}
|
|
251709
252019
|
|
|
251710
252020
|
Current state:
|
|
251711
252021
|
${describeGitHubPullRequestSnapshot(initial2)}
|
|
@@ -251716,7 +252026,7 @@ Output file: ${outputFile}`
|
|
|
251716
252026
|
taskId,
|
|
251717
252027
|
url: ref5.url,
|
|
251718
252028
|
headSha: initial2.headSha,
|
|
251719
|
-
persistent
|
|
252029
|
+
persistent
|
|
251720
252030
|
};
|
|
251721
252031
|
}
|
|
251722
252032
|
var WATCH_POLL_MS = 30000, WATCH_MAX_POLL_MS;
|
|
@@ -251874,6 +252184,36 @@ var init_sdk_loader = __esm(() => {
|
|
|
251874
252184
|
SDK_PACKAGE = ["@letta-ai", "letta-agent-sdk"].join("/");
|
|
251875
252185
|
});
|
|
251876
252186
|
|
|
252187
|
+
// src/agent/preloaded-skills.ts
|
|
252188
|
+
import { readFile as readFile18 } from "node:fs/promises";
|
|
252189
|
+
async function loadPreloadedSkills(ids, options = {}) {
|
|
252190
|
+
if (ids.length === 0)
|
|
252191
|
+
return "";
|
|
252192
|
+
const { skillPathById } = await buildClientSkillsPayload({
|
|
252193
|
+
...options,
|
|
252194
|
+
skillSources: options.skillSources?.length === 0 ? ["bundled"] : options.skillSources
|
|
252195
|
+
});
|
|
252196
|
+
const contents = [];
|
|
252197
|
+
for (const id2 of ids) {
|
|
252198
|
+
const path31 = skillPathById[id2];
|
|
252199
|
+
if (!path31)
|
|
252200
|
+
continue;
|
|
252201
|
+
try {
|
|
252202
|
+
contents.push(`<${id2}>
|
|
252203
|
+
${await readFile18(path31, "utf-8")}
|
|
252204
|
+
</${id2}>`);
|
|
252205
|
+
} catch {}
|
|
252206
|
+
}
|
|
252207
|
+
return contents.length ? `<loaded_skills>
|
|
252208
|
+
${contents.join(`
|
|
252209
|
+
|
|
252210
|
+
`)}
|
|
252211
|
+
</loaded_skills>` : "";
|
|
252212
|
+
}
|
|
252213
|
+
var init_preloaded_skills = __esm(() => {
|
|
252214
|
+
init_client_skills();
|
|
252215
|
+
});
|
|
252216
|
+
|
|
251877
252217
|
// src/tools/workflow/sdk-spawner.ts
|
|
251878
252218
|
async function latestWorkerRun(conversationId) {
|
|
251879
252219
|
const backend3 = getBackend();
|
|
@@ -252115,6 +252455,19 @@ function createSdkSpawner(client, config2) {
|
|
|
252115
252455
|
error: `Unknown model "${options.model}". Run \`letta model list\` for valid handles.`
|
|
252116
252456
|
};
|
|
252117
252457
|
}
|
|
252458
|
+
const loadedSkills = options.skills?.length ? await loadPreloadedSkills(options.skills, {
|
|
252459
|
+
agentId: config2.parentAgentId,
|
|
252460
|
+
...config2.cwd ? { workingDirectory: config2.cwd } : {}
|
|
252461
|
+
}) : "";
|
|
252462
|
+
const missingSkills = (options.skills ?? []).filter((id2) => !loadedSkills.includes(`<${id2}>
|
|
252463
|
+
`));
|
|
252464
|
+
if (missingSkills.length) {
|
|
252465
|
+
return {
|
|
252466
|
+
value: null,
|
|
252467
|
+
failed: true,
|
|
252468
|
+
error: `Unknown skill(s): ${missingSkills.join(", ")}.`
|
|
252469
|
+
};
|
|
252470
|
+
}
|
|
252118
252471
|
if (signal.aborted) {
|
|
252119
252472
|
return {
|
|
252120
252473
|
value: null,
|
|
@@ -252133,7 +252486,9 @@ function createSdkSpawner(client, config2) {
|
|
|
252133
252486
|
let query3;
|
|
252134
252487
|
try {
|
|
252135
252488
|
query3 = client.query({
|
|
252136
|
-
prompt
|
|
252489
|
+
prompt: loadedSkills ? `${loadedSkills}
|
|
252490
|
+
|
|
252491
|
+
${prompt}` : prompt,
|
|
252137
252492
|
options: {
|
|
252138
252493
|
...buildQueryOptions(options, model, config2, request2.callIndex),
|
|
252139
252494
|
...resumeId ? { conversationId: resumeId } : {}
|
|
@@ -252259,6 +252614,7 @@ function createSdkSpawner(client, config2) {
|
|
|
252259
252614
|
}
|
|
252260
252615
|
var DEFAULT_SUBAGENT_TIMEOUT_MS, DEFAULT_MAX_SUBAGENT_TOOL_CALLS = 1000, MAX_IDENTICAL_TOOL_CALLS = 3, SUBAGENT_PREAMBLE = `You are a subagent inside a deterministic workflow. You are not talking to a human: your final output is consumed by a script. Return raw data with no preamble, no markdown framing, and no questions.`, JSON_PREAMBLE = `Your final message must be a single JSON value and nothing else: no prose, no markdown code fence.`;
|
|
252261
252616
|
var init_sdk_spawner = __esm(async () => {
|
|
252617
|
+
init_preloaded_skills();
|
|
252262
252618
|
init_backend2();
|
|
252263
252619
|
init_tool_registry();
|
|
252264
252620
|
init_tool_name_mapping();
|
|
@@ -252336,10 +252692,12 @@ async function createSdkSpawnerHandle(args, setStage = () => {}) {
|
|
|
252336
252692
|
});
|
|
252337
252693
|
throw error5;
|
|
252338
252694
|
}
|
|
252339
|
-
const
|
|
252695
|
+
const backgroundStopController = args.wait ? undefined : new AbortController;
|
|
252696
|
+
const toolScope = await createScriptToolScope(parentAgentId, args.wait ? args.signal : backgroundStopController?.signal);
|
|
252340
252697
|
return {
|
|
252341
252698
|
spawner,
|
|
252342
252699
|
...toolScope,
|
|
252700
|
+
backgroundStopController,
|
|
252343
252701
|
cleanup: async () => {
|
|
252344
252702
|
await toolScope.cleanup();
|
|
252345
252703
|
await client[Symbol.asyncDispose]?.().catch(() => {
|
|
@@ -252399,6 +252757,14 @@ function jsonSafe(value) {
|
|
|
252399
252757
|
return String(value);
|
|
252400
252758
|
}
|
|
252401
252759
|
}
|
|
252760
|
+
function formatFailureResult(error5, agentsDone, journalPath) {
|
|
252761
|
+
const lines = [`Workflow failed: ${error5 ?? "unknown error"}`];
|
|
252762
|
+
if (agentsDone > 0) {
|
|
252763
|
+
lines.push(`${agentsDone} agent call${agentsDone === 1 ? "" : "s"} completed before the failure. Their full results are saved in ${journalPath} (one line per completed call; the return value is outcome.value).`);
|
|
252764
|
+
}
|
|
252765
|
+
return lines.join(`
|
|
252766
|
+
`);
|
|
252767
|
+
}
|
|
252402
252768
|
function formatCompletionResult(run, executionDir) {
|
|
252403
252769
|
const payload = JSON.stringify({
|
|
252404
252770
|
result: jsonSafe(run.result),
|
|
@@ -252544,7 +252910,7 @@ async function workflow(args) {
|
|
|
252544
252910
|
const taskId = getNextWorkflowId();
|
|
252545
252911
|
const outputFile = createBackgroundOutputFile(taskId);
|
|
252546
252912
|
const scope = resolveNotificationScope(args.parentScope);
|
|
252547
|
-
const abortController = new AbortController;
|
|
252913
|
+
const abortController = handle2.backgroundStopController ?? new AbortController;
|
|
252548
252914
|
const processState = {
|
|
252549
252915
|
process: {
|
|
252550
252916
|
kill() {
|
|
@@ -252590,7 +252956,7 @@ async function workflow(args) {
|
|
|
252590
252956
|
processState.status = outcome.run ? "completed" : "failed";
|
|
252591
252957
|
processState.exitCode = outcome.run ? 0 : 1;
|
|
252592
252958
|
}
|
|
252593
|
-
const result3 = outcome.run ? formatCompletionResult(outcome.run, executionDir) :
|
|
252959
|
+
const result3 = outcome.run ? formatCompletionResult(outcome.run, executionDir) : formatFailureResult(outcome.error, getWorkflowExecution(taskId)?.agentsDone ?? 0, journalPath);
|
|
252594
252960
|
appendToOutputFile(outputFile, outcome.run ? `
|
|
252595
252961
|
[result]
|
|
252596
252962
|
${result3}
|
|
@@ -253153,7 +253519,7 @@ var init_Monitor2 = __esm(() => {
|
|
|
253153
253519
|
persistent: {
|
|
253154
253520
|
type: "boolean",
|
|
253155
253521
|
default: false,
|
|
253156
|
-
description: "Run
|
|
253522
|
+
description: "Run until TaskStop or session end. In managed Cloud sandboxes, a hard 1-hour limit still applies; elsewhere there is no timeout. For longer waits in Cloud, use Wake/cron rather than keeping a monitor running."
|
|
253157
253523
|
},
|
|
253158
253524
|
backup_after_seconds: {
|
|
253159
253525
|
type: "integer",
|
|
@@ -254316,7 +254682,7 @@ import {
|
|
|
254316
254682
|
readFileSync as readFileSync38,
|
|
254317
254683
|
renameSync as renameSync10,
|
|
254318
254684
|
rmSync as rmSync18,
|
|
254319
|
-
statSync as
|
|
254685
|
+
statSync as statSync19,
|
|
254320
254686
|
writeFileSync as writeFileSync29
|
|
254321
254687
|
} from "node:fs";
|
|
254322
254688
|
import { join as join71 } from "node:path";
|
|
@@ -254635,11 +255001,11 @@ function createRecoveryLineageSidecarAccess(params) {
|
|
|
254635
255001
|
ownerIsAlive = error5.code !== "ESRCH";
|
|
254636
255002
|
}
|
|
254637
255003
|
}
|
|
254638
|
-
const ageMs = Date.now() -
|
|
255004
|
+
const ageMs = Date.now() - statSync19(join71(params.directory, file)).mtimeMs;
|
|
254639
255005
|
if (!ownerIsCurrentWriter && (!ownerIsAlive && ageMs >= staleTemporaryAgeMs || ageMs >= maximumTemporaryAgeMs)) {
|
|
254640
255006
|
const release = acquireDurableFileLock(join71(params.directory, mainFile), { waitMs: params.lockWaitMs });
|
|
254641
255007
|
try {
|
|
254642
|
-
const currentAgeMs = Date.now() -
|
|
255008
|
+
const currentAgeMs = Date.now() - statSync19(join71(params.directory, file)).mtimeMs;
|
|
254643
255009
|
if (!ownerIsCurrentWriter && (!ownerIsAlive && currentAgeMs >= staleTemporaryAgeMs || currentAgeMs >= maximumTemporaryAgeMs)) {
|
|
254644
255010
|
rmSync18(join71(params.directory, file), { force: true });
|
|
254645
255011
|
params.syncDirectory(params.directory);
|
|
@@ -257131,7 +257497,7 @@ import {
|
|
|
257131
257497
|
openSync as openSync7,
|
|
257132
257498
|
readFileSync as readFileSync40,
|
|
257133
257499
|
renameSync as renameSync11,
|
|
257134
|
-
statSync as
|
|
257500
|
+
statSync as statSync20,
|
|
257135
257501
|
unlinkSync as unlinkSync10,
|
|
257136
257502
|
writeFileSync as writeFileSync31
|
|
257137
257503
|
} from "node:fs";
|
|
@@ -257271,7 +257637,7 @@ function validateDurableStore(value) {
|
|
|
257271
257637
|
function readDurableStore(path32) {
|
|
257272
257638
|
if (!existsSync50(path32))
|
|
257273
257639
|
return emptyDurableStore();
|
|
257274
|
-
const size2 =
|
|
257640
|
+
const size2 = statSync20(path32).size;
|
|
257275
257641
|
if (size2 > MAX_INPUT_DISPOSITION_STORE_BYTES) {
|
|
257276
257642
|
throw new Error("Accepted-input disposition store exceeds its size limit");
|
|
257277
257643
|
}
|
|
@@ -261164,7 +261530,7 @@ var init_environments4 = __esm(() => {
|
|
|
261164
261530
|
});
|
|
261165
261531
|
|
|
261166
261532
|
// src/cli/subcommands/feedback.ts
|
|
261167
|
-
import { readFile as
|
|
261533
|
+
import { readFile as readFile19 } from "node:fs/promises";
|
|
261168
261534
|
import { parseArgs as parseArgs8 } from "node:util";
|
|
261169
261535
|
function printUsage6(stdout = console.log) {
|
|
261170
261536
|
stdout(`
|
|
@@ -261214,7 +261580,7 @@ async function runFeedbackSubcommand(argv, deps = {}) {
|
|
|
261214
261580
|
let rawMessage = typeof inlineMessage === "string" ? inlineMessage : "";
|
|
261215
261581
|
if (typeof messageFile === "string") {
|
|
261216
261582
|
try {
|
|
261217
|
-
rawMessage = await (deps.readMessageFile ?? ((path32) =>
|
|
261583
|
+
rawMessage = await (deps.readMessageFile ?? ((path32) => readFile19(path32, "utf8")))(messageFile);
|
|
261218
261584
|
} catch {
|
|
261219
261585
|
stderr(`Could not read feedback file: ${messageFile}`);
|
|
261220
261586
|
return 1;
|
|
@@ -263427,7 +263793,7 @@ var init_listen_log = __esm(() => {
|
|
|
263427
263793
|
|
|
263428
263794
|
// src/utils/machine-metadata.ts
|
|
263429
263795
|
import { execFile as execFile19 } from "node:child_process";
|
|
263430
|
-
import { readFile as
|
|
263796
|
+
import { readFile as readFile20 } from "node:fs/promises";
|
|
263431
263797
|
import { cpus, totalmem } from "node:os";
|
|
263432
263798
|
function getMachineMetadata() {
|
|
263433
263799
|
machineMetadata ??= collectMachineMetadata().catch(() => ({
|
|
@@ -263442,7 +263808,7 @@ function localSources() {
|
|
|
263442
263808
|
architecture: process.arch,
|
|
263443
263809
|
cpu: cpus()[0]?.model,
|
|
263444
263810
|
memoryBytes: Math.min(totalmem(), limit4 || Number.POSITIVE_INFINITY),
|
|
263445
|
-
read: (path32, signal) =>
|
|
263811
|
+
read: (path32, signal) => readFile20(path32, { encoding: "utf8", signal }),
|
|
263446
263812
|
run: (command, args, signal) => new Promise((resolve39, reject2) => {
|
|
263447
263813
|
execFile19(command, args, {
|
|
263448
263814
|
encoding: "utf8",
|
|
@@ -264021,7 +264387,7 @@ var init_auth3 = __esm(() => {
|
|
|
264021
264387
|
|
|
264022
264388
|
// src/websocket/listener/manual-instance-lock.ts
|
|
264023
264389
|
import { createHash as createHash14, randomUUID as randomUUID47 } from "node:crypto";
|
|
264024
|
-
import { link as link4, mkdir as mkdir13, readFile as
|
|
264390
|
+
import { link as link4, mkdir as mkdir13, readFile as readFile21, rm as rm11, unlink as unlink3, writeFile as writeFile15 } from "node:fs/promises";
|
|
264025
264391
|
import { homedir as homedir38 } from "node:os";
|
|
264026
264392
|
import path32 from "node:path";
|
|
264027
264393
|
function hasErrorCode3(error5, code2) {
|
|
@@ -264108,7 +264474,7 @@ async function recoverDeadOwner(lockPath, staleContents, recoveryOwnerContents,
|
|
|
264108
264474
|
}
|
|
264109
264475
|
let claimContents;
|
|
264110
264476
|
try {
|
|
264111
|
-
claimContents = await
|
|
264477
|
+
claimContents = await readFile21(claimPath, "utf-8");
|
|
264112
264478
|
} catch (error5) {
|
|
264113
264479
|
if (hasErrorCode3(error5, "ENOENT")) {
|
|
264114
264480
|
continue;
|
|
@@ -264128,7 +264494,7 @@ async function recoverDeadOwner(lockPath, staleContents, recoveryOwnerContents,
|
|
|
264128
264494
|
}
|
|
264129
264495
|
let currentContents;
|
|
264130
264496
|
try {
|
|
264131
|
-
currentContents = await
|
|
264497
|
+
currentContents = await readFile21(lockPath, "utf-8");
|
|
264132
264498
|
} catch (error5) {
|
|
264133
264499
|
return hasErrorCode3(error5, "ENOENT");
|
|
264134
264500
|
}
|
|
@@ -264178,7 +264544,7 @@ async function acquireManualListenerLock(scope, overrides = {}) {
|
|
|
264178
264544
|
return;
|
|
264179
264545
|
let currentContents;
|
|
264180
264546
|
try {
|
|
264181
|
-
currentContents = await
|
|
264547
|
+
currentContents = await readFile21(lockPath, "utf-8");
|
|
264182
264548
|
} catch (error5) {
|
|
264183
264549
|
if (hasErrorCode3(error5, "ENOENT")) {
|
|
264184
264550
|
released = true;
|
|
@@ -264198,7 +264564,7 @@ async function acquireManualListenerLock(scope, overrides = {}) {
|
|
|
264198
264564
|
}
|
|
264199
264565
|
let incumbentContents;
|
|
264200
264566
|
try {
|
|
264201
|
-
incumbentContents = await
|
|
264567
|
+
incumbentContents = await readFile21(lockPath, "utf-8");
|
|
264202
264568
|
} catch (error5) {
|
|
264203
264569
|
if (hasErrorCode3(error5, "ENOENT")) {
|
|
264204
264570
|
continue;
|
|
@@ -264867,7 +265233,7 @@ function isBrowserDeviceMcpOAuthProtocolCommand(value) {
|
|
|
264867
265233
|
return false;
|
|
264868
265234
|
const record6 = value;
|
|
264869
265235
|
if (record6.type === "browser_device_mcp_oauth") {
|
|
264870
|
-
return Object.keys(record6).length === 6 && typeof record6.request_id === "string" && REQUEST_ID_PATTERN.test(record6.request_id) && typeof record6.handoff_key === "string" && HANDOFF_KEY_PATTERN2.test(record6.handoff_key) && typeof record6.service === "string" && SERVICE_PATTERN.test(record6.service) && typeof record6.server_url === "string" && record6.server_url.length > 0 && record6.server_url.length <= MAX_SERVER_URL_LENGTH && !hasControlCharacters(record6.server_url) && typeof record6.timeout_ms === "number" && Number.isSafeInteger(record6.timeout_ms) && record6.timeout_ms > 0 && record6.timeout_ms <=
|
|
265236
|
+
return Object.keys(record6).length === 6 && typeof record6.request_id === "string" && REQUEST_ID_PATTERN.test(record6.request_id) && typeof record6.handoff_key === "string" && HANDOFF_KEY_PATTERN2.test(record6.handoff_key) && typeof record6.service === "string" && SERVICE_PATTERN.test(record6.service) && typeof record6.server_url === "string" && record6.server_url.length > 0 && record6.server_url.length <= MAX_SERVER_URL_LENGTH && !hasControlCharacters(record6.server_url) && typeof record6.timeout_ms === "number" && Number.isSafeInteger(record6.timeout_ms) && record6.timeout_ms > 0 && record6.timeout_ms <= MAX_TIMEOUT_MS;
|
|
264871
265237
|
}
|
|
264872
265238
|
return record6.type === "browser_device_mcp_oauth_cancel" && Object.keys(record6).length === 2 && typeof record6.operation_id === "string" && REQUEST_ID_PATTERN.test(record6.operation_id);
|
|
264873
265239
|
}
|
|
@@ -264879,7 +265245,7 @@ function hasControlCharacters(value) {
|
|
|
264879
265245
|
}
|
|
264880
265246
|
return false;
|
|
264881
265247
|
}
|
|
264882
|
-
var REQUEST_ID_PATTERN, HANDOFF_KEY_PATTERN2, SERVICE_PATTERN, MAX_SERVER_URL_LENGTH = 2048,
|
|
265248
|
+
var REQUEST_ID_PATTERN, HANDOFF_KEY_PATTERN2, SERVICE_PATTERN, MAX_SERVER_URL_LENGTH = 2048, MAX_TIMEOUT_MS = 285000;
|
|
264883
265249
|
var init_browser_device_mcp_oauth_protocol_inbound = __esm(() => {
|
|
264884
265250
|
REQUEST_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
264885
265251
|
HANDOFF_KEY_PATTERN2 = /^[A-Za-z0-9_-]{43,128}$/;
|
|
@@ -266294,7 +266660,7 @@ __export(exports_memory_scanner, {
|
|
|
266294
266660
|
readFileContent: () => readFileContent,
|
|
266295
266661
|
getFileNodes: () => getFileNodes
|
|
266296
266662
|
});
|
|
266297
|
-
import { readdirSync as readdirSync21, readFileSync as readFileSync42, statSync as
|
|
266663
|
+
import { readdirSync as readdirSync21, readFileSync as readFileSync42, statSync as statSync21 } from "node:fs";
|
|
266298
266664
|
import { join as join76, relative as relative7 } from "node:path";
|
|
266299
266665
|
function scanMemoryFilesystem(memoryRoot) {
|
|
266300
266666
|
const nodes = [];
|
|
@@ -266312,10 +266678,10 @@ function scanMemoryFilesystem(memoryRoot) {
|
|
|
266312
266678
|
let aIsDir = false;
|
|
266313
266679
|
let bIsDir = false;
|
|
266314
266680
|
try {
|
|
266315
|
-
aIsDir =
|
|
266681
|
+
aIsDir = statSync21(aPath).isDirectory();
|
|
266316
266682
|
} catch {}
|
|
266317
266683
|
try {
|
|
266318
|
-
bIsDir =
|
|
266684
|
+
bIsDir = statSync21(bPath).isDirectory();
|
|
266319
266685
|
} catch {}
|
|
266320
266686
|
if (aIsDir !== bIsDir)
|
|
266321
266687
|
return aIsDir ? -1 : 1;
|
|
@@ -266331,7 +266697,7 @@ function scanMemoryFilesystem(memoryRoot) {
|
|
|
266331
266697
|
const fullPath = join76(dir, name);
|
|
266332
266698
|
let isDir = false;
|
|
266333
266699
|
try {
|
|
266334
|
-
isDir =
|
|
266700
|
+
isDir = statSync21(fullPath).isDirectory();
|
|
266335
266701
|
} catch {
|
|
266336
266702
|
return;
|
|
266337
266703
|
}
|
|
@@ -266430,7 +266796,7 @@ async function handleListMemoryCommand(parsed, socket, safeSocketSend, overrides
|
|
|
266430
266796
|
const isMemfsEnabledOnServer2 = overrides.isMemfsEnabledOnServer ?? actualIsMemfsEnabledOnServer;
|
|
266431
266797
|
const { scanMemoryFilesystem: scanMemoryFilesystem2, getFileNodes: getFileNodes2, readFileContent: readFileContent2 } = await Promise.resolve().then(() => (init_memory_scanner(), exports_memory_scanner));
|
|
266432
266798
|
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => exports_frontmatter);
|
|
266433
|
-
const { existsSync: existsSync52, statSync:
|
|
266799
|
+
const { existsSync: existsSync52, statSync: statSync22 } = await import("node:fs");
|
|
266434
266800
|
const { join: join77, posix: posix3 } = await import("node:path");
|
|
266435
266801
|
const memoryRoot = getMemoryFilesystemRoot2(parsed.agent_id);
|
|
266436
266802
|
let memfsInitialized = existsSync52(join77(memoryRoot, ".git"));
|
|
@@ -266527,7 +266893,7 @@ async function handleListMemoryCommand(parsed, socket, safeSocketSend, overrides
|
|
|
266527
266893
|
if (imageMimeType) {
|
|
266528
266894
|
let size2 = 0;
|
|
266529
266895
|
try {
|
|
266530
|
-
size2 =
|
|
266896
|
+
size2 = statSync22(node.fullPath).size;
|
|
266531
266897
|
} catch {}
|
|
266532
266898
|
return {
|
|
266533
266899
|
relative_path: node.relativePath,
|
|
@@ -266750,7 +267116,7 @@ function handleMemoryProtocolCommand(parsed, context3) {
|
|
|
266750
267116
|
ensureLocalMemfsCheckout: ensureLocalMemfsCheckout2,
|
|
266751
267117
|
isMemfsEnabledOnServer: isMemfsEnabledOnServer2
|
|
266752
267118
|
} = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
|
|
266753
|
-
const { readFile:
|
|
267119
|
+
const { readFile: readFile22 } = await import("node:fs/promises");
|
|
266754
267120
|
const { existsSync: existsSync52 } = await import("node:fs");
|
|
266755
267121
|
const { isAbsolute: isAbsolute25, join: join77, normalize: normalize4, relative: relative8, sep: sep8 } = await import("node:path");
|
|
266756
267122
|
if (isAbsolute25(parsed.path) || parsed.path.length === 0) {
|
|
@@ -266776,7 +267142,7 @@ function handleMemoryProtocolCommand(parsed, context3) {
|
|
|
266776
267142
|
return;
|
|
266777
267143
|
}
|
|
266778
267144
|
}
|
|
266779
|
-
const buffer = await
|
|
267145
|
+
const buffer = await readFile22(absolutePath);
|
|
266780
267146
|
const content = encoding === "base64" ? buffer.toString("base64") : buffer.toString("utf-8");
|
|
266781
267147
|
const pathspec = rel.split(sep8).join("/");
|
|
266782
267148
|
safeSocketSend(socket, {
|
|
@@ -276035,7 +276401,7 @@ ${lanes.join(`
|
|
|
276035
276401
|
writeOutputIsTTY() {
|
|
276036
276402
|
return process.stdout.isTTY;
|
|
276037
276403
|
},
|
|
276038
|
-
readFile:
|
|
276404
|
+
readFile: readFile22,
|
|
276039
276405
|
writeFile: writeFile22,
|
|
276040
276406
|
watchFile: watchFile2,
|
|
276041
276407
|
watchDirectory,
|
|
@@ -276076,7 +276442,7 @@ ${lanes.join(`
|
|
|
276076
276442
|
return process.memoryUsage().heapUsed;
|
|
276077
276443
|
},
|
|
276078
276444
|
getFileSize(path35) {
|
|
276079
|
-
const stat12 =
|
|
276445
|
+
const stat12 = statSync22(path35);
|
|
276080
276446
|
if (stat12 == null ? undefined : stat12.isFile()) {
|
|
276081
276447
|
return stat12.size;
|
|
276082
276448
|
}
|
|
@@ -276119,7 +276485,7 @@ ${lanes.join(`
|
|
|
276119
276485
|
}
|
|
276120
276486
|
};
|
|
276121
276487
|
return nodeSystem;
|
|
276122
|
-
function
|
|
276488
|
+
function statSync22(path35) {
|
|
276123
276489
|
try {
|
|
276124
276490
|
return _fs.statSync(path35, statSyncOptions);
|
|
276125
276491
|
} catch {
|
|
@@ -276171,7 +276537,7 @@ ${lanes.join(`
|
|
|
276171
276537
|
activeSession.post("Profiler.stop", (err, { profile }) => {
|
|
276172
276538
|
var _a10;
|
|
276173
276539
|
if (!err) {
|
|
276174
|
-
if ((_a10 =
|
|
276540
|
+
if ((_a10 = statSync22(profilePath)) == null ? undefined : _a10.isDirectory()) {
|
|
276175
276541
|
profilePath = _path.join(profilePath, `${(/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-")}+P${process.pid}.cpuprofile`);
|
|
276176
276542
|
}
|
|
276177
276543
|
try {
|
|
@@ -276228,7 +276594,7 @@ ${lanes.join(`
|
|
|
276228
276594
|
function fsWatchWorker(fileOrDirectory, recursive, callback) {
|
|
276229
276595
|
return _fs.watch(fileOrDirectory, fsSupportsRecursiveFsWatch ? { persistent: true, recursive: !!recursive } : { persistent: true }, callback);
|
|
276230
276596
|
}
|
|
276231
|
-
function
|
|
276597
|
+
function readFile22(fileName, _encoding) {
|
|
276232
276598
|
let buffer;
|
|
276233
276599
|
try {
|
|
276234
276600
|
buffer = _fs.readFileSync(fileName);
|
|
@@ -276280,7 +276646,7 @@ ${lanes.join(`
|
|
|
276280
276646
|
let stat12;
|
|
276281
276647
|
if (typeof dirent === "string" || dirent.isSymbolicLink()) {
|
|
276282
276648
|
const name = combinePaths(path35, entry);
|
|
276283
|
-
stat12 =
|
|
276649
|
+
stat12 = statSync22(name);
|
|
276284
276650
|
if (!stat12) {
|
|
276285
276651
|
continue;
|
|
276286
276652
|
}
|
|
@@ -276304,7 +276670,7 @@ ${lanes.join(`
|
|
|
276304
276670
|
return matchFiles(path35, extensions, excludes, includes2, useCaseSensitiveFileNames2, process.cwd(), depth, getAccessibleFileSystemEntries, realpath6);
|
|
276305
276671
|
}
|
|
276306
276672
|
function fileSystemEntryExists(path35, entryKind) {
|
|
276307
|
-
const stat12 =
|
|
276673
|
+
const stat12 = statSync22(path35);
|
|
276308
276674
|
if (!stat12) {
|
|
276309
276675
|
return false;
|
|
276310
276676
|
}
|
|
@@ -276338,7 +276704,7 @@ ${lanes.join(`
|
|
|
276338
276704
|
}
|
|
276339
276705
|
function getModifiedTime3(path35) {
|
|
276340
276706
|
var _a10;
|
|
276341
|
-
return (_a10 =
|
|
276707
|
+
return (_a10 = statSync22(path35)) == null ? undefined : _a10.mtime;
|
|
276342
276708
|
}
|
|
276343
276709
|
function setModifiedTime(path35, time3) {
|
|
276344
276710
|
try {
|
|
@@ -307175,7 +307541,7 @@ ${lanes.join(`
|
|
|
307175
307541
|
const possibleOption = getSpellingSuggestion(unknownOption, diagnostics2.optionDeclarations, getOptionName);
|
|
307176
307542
|
return possibleOption ? createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, node, diagnostics2.unknownDidYouMeanDiagnostic, unknownOptionErrorText || unknownOption, possibleOption.name) : createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, node, diagnostics2.unknownOptionDiagnostic, unknownOptionErrorText || unknownOption);
|
|
307177
307543
|
}
|
|
307178
|
-
function parseCommandLineWorker(diagnostics2, commandLine,
|
|
307544
|
+
function parseCommandLineWorker(diagnostics2, commandLine, readFile22) {
|
|
307179
307545
|
const options = {};
|
|
307180
307546
|
let watchOptions;
|
|
307181
307547
|
const fileNames = [];
|
|
@@ -307213,7 +307579,7 @@ ${lanes.join(`
|
|
|
307213
307579
|
}
|
|
307214
307580
|
}
|
|
307215
307581
|
function parseResponseFile(fileName) {
|
|
307216
|
-
const text3 = tryReadFile(fileName,
|
|
307582
|
+
const text3 = tryReadFile(fileName, readFile22 || ((fileName2) => sys.readFile(fileName2)));
|
|
307217
307583
|
if (!isString7(text3)) {
|
|
307218
307584
|
errors6.push(text3);
|
|
307219
307585
|
return;
|
|
@@ -307316,8 +307682,8 @@ ${lanes.join(`
|
|
|
307316
307682
|
unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1,
|
|
307317
307683
|
optionTypeMismatchDiagnostic: Diagnostics.Compiler_option_0_expects_an_argument
|
|
307318
307684
|
};
|
|
307319
|
-
function parseCommandLine2(commandLine,
|
|
307320
|
-
return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine,
|
|
307685
|
+
function parseCommandLine2(commandLine, readFile22) {
|
|
307686
|
+
return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine, readFile22);
|
|
307321
307687
|
}
|
|
307322
307688
|
function getOptionFromName(optionName, allowShort) {
|
|
307323
307689
|
return getOptionDeclarationFromName(getOptionsNameMap, optionName, allowShort);
|
|
@@ -307385,8 +307751,8 @@ ${lanes.join(`
|
|
|
307385
307751
|
result3.originalFileName = result3.fileName;
|
|
307386
307752
|
return parseJsonSourceFileConfigFileContent(result3, host, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd2), optionsToExtend, getNormalizedAbsolutePath(configFileName, cwd2), undefined, extraFileExtensions, extendedConfigCache, watchOptionsToExtend);
|
|
307387
307753
|
}
|
|
307388
|
-
function readConfigFile(fileName,
|
|
307389
|
-
const textOrDiagnostic = tryReadFile(fileName,
|
|
307754
|
+
function readConfigFile(fileName, readFile22) {
|
|
307755
|
+
const textOrDiagnostic = tryReadFile(fileName, readFile22);
|
|
307390
307756
|
return isString7(textOrDiagnostic) ? parseConfigFileTextToJson(fileName, textOrDiagnostic) : { config: {}, error: textOrDiagnostic };
|
|
307391
307757
|
}
|
|
307392
307758
|
function parseConfigFileTextToJson(fileName, jsonText) {
|
|
@@ -307396,14 +307762,14 @@ ${lanes.join(`
|
|
|
307396
307762
|
error: jsonSourceFile.parseDiagnostics.length ? jsonSourceFile.parseDiagnostics[0] : undefined
|
|
307397
307763
|
};
|
|
307398
307764
|
}
|
|
307399
|
-
function readJsonConfigFile(fileName,
|
|
307400
|
-
const textOrDiagnostic = tryReadFile(fileName,
|
|
307765
|
+
function readJsonConfigFile(fileName, readFile22) {
|
|
307766
|
+
const textOrDiagnostic = tryReadFile(fileName, readFile22);
|
|
307401
307767
|
return isString7(textOrDiagnostic) ? parseJsonText(fileName, textOrDiagnostic) : { fileName, parseDiagnostics: [textOrDiagnostic] };
|
|
307402
307768
|
}
|
|
307403
|
-
function tryReadFile(fileName,
|
|
307769
|
+
function tryReadFile(fileName, readFile22) {
|
|
307404
307770
|
let text3;
|
|
307405
307771
|
try {
|
|
307406
|
-
text3 =
|
|
307772
|
+
text3 = readFile22(fileName);
|
|
307407
307773
|
} catch (e2) {
|
|
307408
307774
|
return createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, e2.message);
|
|
307409
307775
|
}
|
|
@@ -374833,12 +375199,12 @@ ${lanes.join(`
|
|
|
374833
375199
|
function createCompilerHost(options, setParentNodes) {
|
|
374834
375200
|
return createCompilerHostWorker(options, setParentNodes);
|
|
374835
375201
|
}
|
|
374836
|
-
function createGetSourceFile(
|
|
375202
|
+
function createGetSourceFile(readFile22, setParentNodes) {
|
|
374837
375203
|
return (fileName, languageVersionOrOptions, onError) => {
|
|
374838
375204
|
let text3;
|
|
374839
375205
|
try {
|
|
374840
375206
|
mark2("beforeIORead");
|
|
374841
|
-
text3 =
|
|
375207
|
+
text3 = readFile22(fileName);
|
|
374842
375208
|
mark2("afterIORead");
|
|
374843
375209
|
measure("I/O Read", "beforeIORead", "afterIORead");
|
|
374844
375210
|
} catch (e2) {
|
|
@@ -375629,7 +375995,7 @@ ${lanes.join(`
|
|
|
375629
375995
|
getRedirectFromOutput,
|
|
375630
375996
|
forEachResolvedProjectReference: forEachResolvedProjectReference2
|
|
375631
375997
|
});
|
|
375632
|
-
const
|
|
375998
|
+
const readFile22 = host.readFile.bind(host);
|
|
375633
375999
|
(_e = tracing) == null || _e.push(tracing.Phase.Program, "shouldProgramCreateNewSourceFiles", { hasOldProgram: !!oldProgram });
|
|
375634
376000
|
const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
|
|
375635
376001
|
(_f = tracing) == null || _f.pop();
|
|
@@ -375805,7 +376171,7 @@ ${lanes.join(`
|
|
|
375805
376171
|
shouldTransformImportCall,
|
|
375806
376172
|
emitBuildInfo,
|
|
375807
376173
|
fileExists,
|
|
375808
|
-
readFile:
|
|
376174
|
+
readFile: readFile22,
|
|
375809
376175
|
directoryExists: directoryExists2,
|
|
375810
376176
|
getSymlinkCache,
|
|
375811
376177
|
realpath: (_o = host.realpath) == null ? undefined : _o.bind(host),
|
|
@@ -437813,7 +438179,7 @@ import {
|
|
|
437813
438179
|
mkdirSync as mkdirSync42,
|
|
437814
438180
|
readdirSync as readdirSync23,
|
|
437815
438181
|
readFileSync as readFileSync46,
|
|
437816
|
-
statSync as
|
|
438182
|
+
statSync as statSync22,
|
|
437817
438183
|
unlinkSync as unlinkSync13,
|
|
437818
438184
|
writeFileSync as writeFileSync36
|
|
437819
438185
|
} from "node:fs";
|
|
@@ -438642,7 +439008,7 @@ async function loadLocalMods(options) {
|
|
|
438642
439008
|
recordLegacyExtensionLoadedDiagnostic(registry4, owner, source, options.onDiagnostic);
|
|
438643
439009
|
}
|
|
438644
439010
|
try {
|
|
438645
|
-
const mtimeMs =
|
|
439011
|
+
const mtimeMs = statSync22(modPath).mtimeMs;
|
|
438646
439012
|
const sourceText = readFileSync46(modPath, "utf8");
|
|
438647
439013
|
recordDeprecatedContextApiSourceDiagnostics(sourceText, (diagnostic) => {
|
|
438648
439014
|
recordModDiagnostic(registry4, {
|
|
@@ -443139,6 +443505,94 @@ var init_chatgpt_plan_rotation = __esm(() => {
|
|
|
443139
443505
|
init_backend2();
|
|
443140
443506
|
});
|
|
443141
443507
|
|
|
443508
|
+
// src/agent/ephemeral-conversation.ts
|
|
443509
|
+
async function buildEphemeralConversationCreateBody(options) {
|
|
443510
|
+
const system2 = options.systemPromptCustom ? options.systemPromptCustom : await resolveAndBuildSystemPrompt(options.systemPromptPreset, options.memoryPromptMode ?? "standard");
|
|
443511
|
+
const request2 = await buildCreateAgentRequest({
|
|
443512
|
+
model: options.model,
|
|
443513
|
+
system: system2,
|
|
443514
|
+
memoryPromptMode: "standard",
|
|
443515
|
+
enableMemfs: false,
|
|
443516
|
+
isSubagent: true,
|
|
443517
|
+
baseTools: []
|
|
443518
|
+
});
|
|
443519
|
+
const modelSettings = options.model ? getModelUpdateArgs(options.model) : undefined;
|
|
443520
|
+
const contextWindow = modelSettings?.context_window ?? await getModelContextWindow(request2.model);
|
|
443521
|
+
return {
|
|
443522
|
+
model: request2.model,
|
|
443523
|
+
system: request2.system ?? system2,
|
|
443524
|
+
...modelSettings ? { model_settings: modelSettings } : {},
|
|
443525
|
+
...contextWindow ? { context_window_limit: contextWindow } : {}
|
|
443526
|
+
};
|
|
443527
|
+
}
|
|
443528
|
+
function projectConversationState(conversation) {
|
|
443529
|
+
if (!conversation.model) {
|
|
443530
|
+
throw new Error("Cannot resume a conversation without a persisted model.");
|
|
443531
|
+
}
|
|
443532
|
+
return {
|
|
443533
|
+
id: conversation.id,
|
|
443534
|
+
name: "Ephemeral conversation",
|
|
443535
|
+
system: conversation.system ?? "",
|
|
443536
|
+
tools: [],
|
|
443537
|
+
memory: { blocks: [] },
|
|
443538
|
+
llm_config: {
|
|
443539
|
+
handle: conversation.model,
|
|
443540
|
+
model: conversation.model,
|
|
443541
|
+
context_window: conversation.context_window_limit ?? undefined,
|
|
443542
|
+
model_settings: conversation.model_settings ?? {}
|
|
443543
|
+
},
|
|
443544
|
+
model_settings: conversation.model_settings ?? {},
|
|
443545
|
+
message_buffer_autoclear: false
|
|
443546
|
+
};
|
|
443547
|
+
}
|
|
443548
|
+
async function createEphemeralConversation2(options) {
|
|
443549
|
+
const body3 = await buildEphemeralConversationCreateBody(options);
|
|
443550
|
+
const conversation = await createEphemeralConversation(body3);
|
|
443551
|
+
return {
|
|
443552
|
+
agent: projectConversationState({ ...body3, id: conversation.id }),
|
|
443553
|
+
conversationId: conversation.id
|
|
443554
|
+
};
|
|
443555
|
+
}
|
|
443556
|
+
async function retrieveResumeState(agentId, conversationId, backend3 = getBackend()) {
|
|
443557
|
+
return agentId ? backend3.retrieveAgent(agentId) : projectConversationState(await backend3.retrieveConversation(conversationId));
|
|
443558
|
+
}
|
|
443559
|
+
async function createLocalEphemeralConversation(options) {
|
|
443560
|
+
const body3 = await buildEphemeralConversationCreateBody(options);
|
|
443561
|
+
const backend3 = getBackend();
|
|
443562
|
+
const internalAgent = await backend3.createAgent({
|
|
443563
|
+
agent_type: "letta_v1_agent",
|
|
443564
|
+
name: "Ephemeral conversation",
|
|
443565
|
+
model: body3.model,
|
|
443566
|
+
system: body3.system,
|
|
443567
|
+
memory_blocks: [],
|
|
443568
|
+
tags: [],
|
|
443569
|
+
tools: [],
|
|
443570
|
+
include_base_tools: false,
|
|
443571
|
+
include_base_tool_rules: false,
|
|
443572
|
+
initial_message_sequence: [],
|
|
443573
|
+
parallel_tool_calls: true,
|
|
443574
|
+
hidden: true
|
|
443575
|
+
});
|
|
443576
|
+
const conversation = await backend3.createConversation({
|
|
443577
|
+
agent_id: internalAgent.id,
|
|
443578
|
+
model: body3.model,
|
|
443579
|
+
...body3.model_settings ? { model_settings: body3.model_settings } : {},
|
|
443580
|
+
...body3.context_window_limit ? { context_window_limit: body3.context_window_limit } : {}
|
|
443581
|
+
});
|
|
443582
|
+
return {
|
|
443583
|
+
agent: internalAgent,
|
|
443584
|
+
conversationId: conversation.id
|
|
443585
|
+
};
|
|
443586
|
+
}
|
|
443587
|
+
var init_ephemeral_conversation = __esm(() => {
|
|
443588
|
+
init_available_models();
|
|
443589
|
+
init_create_agent_request();
|
|
443590
|
+
init_model();
|
|
443591
|
+
init_system_prompt_resolution();
|
|
443592
|
+
init_backend2();
|
|
443593
|
+
init_ephemeral_conversations();
|
|
443594
|
+
});
|
|
443595
|
+
|
|
443142
443596
|
// src/cli/helpers/compaction-utils.ts
|
|
443143
443597
|
function extractCompactionSummary(text3) {
|
|
443144
443598
|
try {
|
|
@@ -447193,7 +447647,7 @@ async function tryResumeBusyConversationStream(params) {
|
|
|
447193
447647
|
}
|
|
447194
447648
|
}
|
|
447195
447649
|
async function resolveStaleApprovals(runtime, socket, turnLease, deps = {}) {
|
|
447196
|
-
if (!runtime.agentId)
|
|
447650
|
+
if (!runtime.agentId && runtime.conversationId === "default")
|
|
447197
447651
|
return null;
|
|
447198
447652
|
const getResumeDataImpl = deps.getResumeData ?? getResumeDataFromBackend;
|
|
447199
447653
|
const prepareToolExecutionContext = deps.prepareToolExecutionContext ?? prepareToolExecutionContextForScope;
|
|
@@ -447208,7 +447662,10 @@ async function resolveStaleApprovals(runtime, socket, turnLease, deps = {}) {
|
|
|
447208
447662
|
const backend3 = getBackend();
|
|
447209
447663
|
let agent;
|
|
447210
447664
|
try {
|
|
447211
|
-
agent = await (
|
|
447665
|
+
agent = await retrieveResumeState(runtime.agentId, runtime.conversationId, {
|
|
447666
|
+
retrieveAgent: deps.retrieveAgent ?? backend3.retrieveAgent.bind(backend3),
|
|
447667
|
+
retrieveConversation: deps.retrieveConversation ?? backend3.retrieveConversation.bind(backend3)
|
|
447668
|
+
});
|
|
447212
447669
|
} catch (err) {
|
|
447213
447670
|
assertCurrentTurnLease();
|
|
447214
447671
|
if (isBackendNotFoundError(err)) {
|
|
@@ -447241,14 +447698,14 @@ async function resolveStaleApprovals(runtime, socket, turnLease, deps = {}) {
|
|
|
447241
447698
|
agent_id: runtime.agentId,
|
|
447242
447699
|
conversation_id: recoveryConversationId
|
|
447243
447700
|
};
|
|
447244
|
-
const modAdapters = await ensureListenerModAdaptersForAgent(runtime.listener, runtime.agentId);
|
|
447701
|
+
const modAdapters = runtime.agentId ? await ensureListenerModAdaptersForAgent(runtime.listener, runtime.agentId) : [];
|
|
447245
447702
|
const preparedToolContext = await prepareToolExecutionContext({
|
|
447246
447703
|
connectionId: resolveTurnExecutionConnectionId(runtime.listener, scope, runtime.activeConnectionId ?? undefined),
|
|
447247
447704
|
agentId: runtime.agentId,
|
|
447248
447705
|
conversationId: recoveryConversationId,
|
|
447249
447706
|
workingDirectory: recoveryWorkingDirectory,
|
|
447250
447707
|
permissionModeState: getOrCreateConversationPermissionModeStateRef(runtime.listener, runtime.agentId, runtime.conversationId),
|
|
447251
|
-
modContext: createListenerAgentModContext(runtime.agentId),
|
|
447708
|
+
...runtime.agentId ? { modContext: createListenerAgentModContext(runtime.agentId) } : {},
|
|
447252
447709
|
modAdapters,
|
|
447253
447710
|
modEvents: createListenerModEvents(modAdapters)
|
|
447254
447711
|
});
|
|
@@ -447641,6 +448098,7 @@ var init_send = __esm(async () => {
|
|
|
447641
448098
|
init_error();
|
|
447642
448099
|
init_approval_recovery();
|
|
447643
448100
|
init_check_approval();
|
|
448101
|
+
init_ephemeral_conversation();
|
|
447644
448102
|
init_turn_recovery_policy();
|
|
447645
448103
|
init_backend2();
|
|
447646
448104
|
init_error_formatter();
|
|
@@ -451706,12 +452164,12 @@ function rowToolCalls(row, index, diagnostics2) {
|
|
|
451706
452164
|
}
|
|
451707
452165
|
return calls;
|
|
451708
452166
|
}
|
|
451709
|
-
function
|
|
452167
|
+
function contentText2(content) {
|
|
451710
452168
|
if (typeof content === "string") {
|
|
451711
452169
|
if (content.startsWith(CONTENT_JSON_PREFIX)) {
|
|
451712
452170
|
const encoded = content.slice(CONTENT_JSON_PREFIX.length);
|
|
451713
452171
|
try {
|
|
451714
|
-
return
|
|
452172
|
+
return contentText2(JSON.parse(encoded));
|
|
451715
452173
|
} catch {
|
|
451716
452174
|
return encoded;
|
|
451717
452175
|
}
|
|
@@ -451797,7 +452255,7 @@ var init_hermes = __esm(() => {
|
|
|
451797
452255
|
});
|
|
451798
452256
|
};
|
|
451799
452257
|
if (row.role === "user") {
|
|
451800
|
-
const content =
|
|
452258
|
+
const content = contentText2(row.content);
|
|
451801
452259
|
if (content) {
|
|
451802
452260
|
emit({
|
|
451803
452261
|
type: "message",
|
|
@@ -451817,7 +452275,7 @@ var init_hermes = __esm(() => {
|
|
|
451817
452275
|
...timestamp ? { timestamp } : {}
|
|
451818
452276
|
});
|
|
451819
452277
|
}
|
|
451820
|
-
const content =
|
|
452278
|
+
const content = contentText2(row.content);
|
|
451821
452279
|
if (content) {
|
|
451822
452280
|
emit({
|
|
451823
452281
|
type: "message",
|
|
@@ -451840,7 +452298,7 @@ var init_hermes = __esm(() => {
|
|
|
451840
452298
|
if (row.role === "tool") {
|
|
451841
452299
|
emit({
|
|
451842
452300
|
type: "tool_result",
|
|
451843
|
-
content:
|
|
452301
|
+
content: contentText2(row.content),
|
|
451844
452302
|
...typeof row.tool_call_id === "string" && row.tool_call_id ? { callId: row.tool_call_id } : {},
|
|
451845
452303
|
...timestamp ? { timestamp } : {}
|
|
451846
452304
|
});
|
|
@@ -453351,7 +453809,7 @@ var init_deepagents = __esm(() => {
|
|
|
453351
453809
|
});
|
|
453352
453810
|
|
|
453353
453811
|
// node_modules/@letta-ai/trajectory/dist/adapters/listing-shared.js
|
|
453354
|
-
import { readdirSync as readdirSync25, statSync as
|
|
453812
|
+
import { readdirSync as readdirSync25, statSync as statSync23 } from "node:fs";
|
|
453355
453813
|
import { join as join83 } from "node:path";
|
|
453356
453814
|
function sortListings(items3) {
|
|
453357
453815
|
return items3.sort((left, right) => {
|
|
@@ -453375,7 +453833,7 @@ function safeReadDir(path42) {
|
|
|
453375
453833
|
}
|
|
453376
453834
|
function safeStat(path42) {
|
|
453377
453835
|
try {
|
|
453378
|
-
const stats =
|
|
453836
|
+
const stats = statSync23(path42);
|
|
453379
453837
|
return { mtimeMs: stats.mtimeMs, sizeBytes: stats.size };
|
|
453380
453838
|
} catch {
|
|
453381
453839
|
return;
|
|
@@ -453832,7 +454290,7 @@ var exports_reflection_memory_v2 = {};
|
|
|
453832
454290
|
__export(exports_reflection_memory_v2, {
|
|
453833
454291
|
buildMemfsV2ParentMemorySnapshot: () => buildMemfsV2ParentMemorySnapshot
|
|
453834
454292
|
});
|
|
453835
|
-
import { readFile as
|
|
454293
|
+
import { readFile as readFile22 } from "node:fs/promises";
|
|
453836
454294
|
function renderProjectedTree(files) {
|
|
453837
454295
|
const root2 = { directories: new Map, files: [] };
|
|
453838
454296
|
for (const file of files) {
|
|
@@ -453885,7 +454343,7 @@ async function buildMemfsV2ParentMemorySnapshot(memoryDir, requestedMaxChars) {
|
|
|
453885
454343
|
`).length - prefix.length - suffix.length - 20;
|
|
453886
454344
|
if (remaining <= 0)
|
|
453887
454345
|
break;
|
|
453888
|
-
const content = (await
|
|
454346
|
+
const content = (await readFile22(file.fullPath, "utf-8")).slice(0, remaining);
|
|
453889
454347
|
lines.push(`${prefix}${content}${suffix}`);
|
|
453890
454348
|
}
|
|
453891
454349
|
lines.push("</parent_memory>");
|
|
@@ -453903,7 +454361,7 @@ import {
|
|
|
453903
454361
|
appendFile,
|
|
453904
454362
|
mkdir as mkdir14,
|
|
453905
454363
|
readdir as readdir9,
|
|
453906
|
-
readFile as
|
|
454364
|
+
readFile as readFile23,
|
|
453907
454365
|
stat as stat13,
|
|
453908
454366
|
writeFile as writeFile16
|
|
453909
454367
|
} from "node:fs/promises";
|
|
@@ -453951,7 +454409,7 @@ async function collectParentMemoryFiles(memoryDir) {
|
|
|
453951
454409
|
continue;
|
|
453952
454410
|
}
|
|
453953
454411
|
try {
|
|
453954
|
-
const content = await
|
|
454412
|
+
const content = await readFile23(entryPath, "utf-8");
|
|
453955
454413
|
const { frontmatter } = parseFrontmatter(content);
|
|
453956
454414
|
const description = typeof frontmatter.description === "string" ? frontmatter.description : undefined;
|
|
453957
454415
|
files.push({
|
|
@@ -454254,7 +454712,7 @@ async function ensurePaths(paths) {
|
|
|
454254
454712
|
}
|
|
454255
454713
|
async function readTranscriptLines(paths) {
|
|
454256
454714
|
try {
|
|
454257
|
-
const raw2 = await
|
|
454715
|
+
const raw2 = await readFile23(paths.transcriptPath, "utf-8");
|
|
454258
454716
|
return raw2.split(`
|
|
454259
454717
|
`).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
454260
454718
|
} catch {
|
|
@@ -454327,7 +454785,7 @@ function buildUnreflectedStateFromTranscript(lines) {
|
|
|
454327
454785
|
async function readState(paths) {
|
|
454328
454786
|
let raw2 = null;
|
|
454329
454787
|
try {
|
|
454330
|
-
raw2 = await
|
|
454788
|
+
raw2 = await readFile23(paths.statePath, "utf-8");
|
|
454331
454789
|
} catch {
|
|
454332
454790
|
raw2 = null;
|
|
454333
454791
|
}
|
|
@@ -454659,7 +455117,7 @@ function isReflectionAutoPriority(value) {
|
|
|
454659
455117
|
return value === "high" || value === "medium" || value === "low";
|
|
454660
455118
|
}
|
|
454661
455119
|
async function readReflectionAutoSelection(options) {
|
|
454662
|
-
const raw2 = options.selectionReport ?? (options.selectionOutputPath ? await
|
|
455120
|
+
const raw2 = options.selectionReport ?? (options.selectionOutputPath ? await readFile23(options.selectionOutputPath, "utf-8") : "");
|
|
454663
455121
|
const parsed = parseReflectionAutoSelectionJson(raw2);
|
|
454664
455122
|
if (!parsed || typeof parsed !== "object") {
|
|
454665
455123
|
throw new Error("Reflection selector did not return valid JSON.");
|
|
@@ -456368,36 +456826,6 @@ var init_turn_send = __esm(async () => {
|
|
|
456368
456826
|
]);
|
|
456369
456827
|
});
|
|
456370
456828
|
|
|
456371
|
-
// src/agent/preloaded-skills.ts
|
|
456372
|
-
import { readFile as readFile23 } from "node:fs/promises";
|
|
456373
|
-
async function loadPreloadedSkills(ids, options = {}) {
|
|
456374
|
-
if (ids.length === 0)
|
|
456375
|
-
return "";
|
|
456376
|
-
const { skillPathById } = await buildClientSkillsPayload({
|
|
456377
|
-
...options,
|
|
456378
|
-
skillSources: options.skillSources?.length === 0 ? ["bundled"] : options.skillSources
|
|
456379
|
-
});
|
|
456380
|
-
const contents = [];
|
|
456381
|
-
for (const id2 of ids) {
|
|
456382
|
-
const path42 = skillPathById[id2];
|
|
456383
|
-
if (!path42)
|
|
456384
|
-
continue;
|
|
456385
|
-
try {
|
|
456386
|
-
contents.push(`<${id2}>
|
|
456387
|
-
${await readFile23(path42, "utf-8")}
|
|
456388
|
-
</${id2}>`);
|
|
456389
|
-
} catch {}
|
|
456390
|
-
}
|
|
456391
|
-
return contents.length ? `<loaded_skills>
|
|
456392
|
-
${contents.join(`
|
|
456393
|
-
|
|
456394
|
-
`)}
|
|
456395
|
-
</loaded_skills>` : "";
|
|
456396
|
-
}
|
|
456397
|
-
var init_preloaded_skills = __esm(() => {
|
|
456398
|
-
init_client_skills();
|
|
456399
|
-
});
|
|
456400
|
-
|
|
456401
456829
|
// src/reminders/listen-context.ts
|
|
456402
456830
|
function buildListenReminderContext(params) {
|
|
456403
456831
|
return {
|
|
@@ -457222,7 +457650,7 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
457222
457650
|
conversationId
|
|
457223
457651
|
});
|
|
457224
457652
|
try {
|
|
457225
|
-
const agent = await
|
|
457653
|
+
const agent = await retrieveResumeState(agentId, conversationId);
|
|
457226
457654
|
const { pendingApprovals: existingApprovals } = await getResumeDataFromBackend(agent, requestedConversationId);
|
|
457227
457655
|
turnInput = rebuildTurnInputWithFreshDenials(turnInput, existingApprovals ?? [], STALE_APPROVAL_RECOVERY_DENIAL_REASON, isApprovalPendingError(errorDetail3));
|
|
457228
457656
|
} catch {
|
|
@@ -457635,8 +458063,8 @@ var init_turn = __esm(async () => {
|
|
|
457635
458063
|
init_approval_recovery();
|
|
457636
458064
|
init_chatgpt_plan_rotation();
|
|
457637
458065
|
init_check_approval();
|
|
458066
|
+
init_ephemeral_conversation();
|
|
457638
458067
|
init_turn_recovery_policy();
|
|
457639
|
-
init_backend2();
|
|
457640
458068
|
init_accumulator();
|
|
457641
458069
|
init_telemetry();
|
|
457642
458070
|
init_error_reporting();
|
|
@@ -468684,7 +469112,7 @@ var init_memory_tokens = __esm(() => {
|
|
|
468684
469112
|
});
|
|
468685
469113
|
|
|
468686
469114
|
// src/cli/subcommands/memory.ts
|
|
468687
|
-
import { cpSync, existsSync as existsSync64, mkdirSync as mkdirSync46, rmSync as rmSync22, statSync as
|
|
469115
|
+
import { cpSync, existsSync as existsSync64, mkdirSync as mkdirSync46, rmSync as rmSync22, statSync as statSync24 } from "node:fs";
|
|
468688
469116
|
import { readdir as readdir12 } from "node:fs/promises";
|
|
468689
469117
|
import { dirname as dirname35, join as join94 } from "node:path";
|
|
468690
469118
|
import { parseArgs as parseArgs11 } from "node:util";
|
|
@@ -468759,7 +469187,7 @@ async function listBackups(agentId) {
|
|
|
468759
469187
|
const path46 = join94(agentRoot, entry.name);
|
|
468760
469188
|
let createdAt = null;
|
|
468761
469189
|
try {
|
|
468762
|
-
const stat15 =
|
|
469190
|
+
const stat15 = statSync24(path46);
|
|
468763
469191
|
createdAt = stat15.mtime.toISOString();
|
|
468764
469192
|
} catch {
|
|
468765
469193
|
createdAt = null;
|
|
@@ -468886,7 +469314,7 @@ async function runMemorySubcommand(argv, deps = {}) {
|
|
|
468886
469314
|
console.error(`Backup not found: ${backupPath}`);
|
|
468887
469315
|
return 1;
|
|
468888
469316
|
}
|
|
468889
|
-
const stat15 =
|
|
469317
|
+
const stat15 = statSync24(backupPath);
|
|
468890
469318
|
if (!stat15.isDirectory()) {
|
|
468891
469319
|
console.error(`Backup path is not a directory: ${backupPath}`);
|
|
468892
469320
|
return 1;
|
|
@@ -468909,7 +469337,7 @@ async function runMemorySubcommand(argv, deps = {}) {
|
|
|
468909
469337
|
return 1;
|
|
468910
469338
|
}
|
|
468911
469339
|
if (existsSync64(out)) {
|
|
468912
|
-
const stat15 =
|
|
469340
|
+
const stat15 = statSync24(out);
|
|
468913
469341
|
if (stat15.isDirectory()) {
|
|
468914
469342
|
const contents = await readdir12(out);
|
|
468915
469343
|
if (contents.length > 0) {
|
|
@@ -468957,7 +469385,7 @@ var init_memory7 = __esm(() => {
|
|
|
468957
469385
|
});
|
|
468958
469386
|
|
|
468959
469387
|
// src/backend/local/transcript-search.ts
|
|
468960
|
-
import { existsSync as existsSync65, readdirSync as readdirSync27, readFileSync as readFileSync48, statSync as
|
|
469388
|
+
import { existsSync as existsSync65, readdirSync as readdirSync27, readFileSync as readFileSync48, statSync as statSync25 } from "node:fs";
|
|
468961
469389
|
import { join as join95 } from "node:path";
|
|
468962
469390
|
function readJsonFile3(path46) {
|
|
468963
469391
|
if (!existsSync65(path46))
|
|
@@ -469245,7 +469673,7 @@ function conversationDirectories(storageDir) {
|
|
|
469245
469673
|
if (!existsSync65(conversationsDir))
|
|
469246
469674
|
return [];
|
|
469247
469675
|
try {
|
|
469248
|
-
return readdirSync27(conversationsDir).map((entry) => join95(conversationsDir, entry)).filter((entryPath) =>
|
|
469676
|
+
return readdirSync27(conversationsDir).map((entry) => join95(conversationsDir, entry)).filter((entryPath) => statSync25(entryPath).isDirectory());
|
|
469249
469677
|
} catch {
|
|
469250
469678
|
return [];
|
|
469251
469679
|
}
|
|
@@ -474459,7 +474887,7 @@ import {
|
|
|
474459
474887
|
mkdtempSync as mkdtempSync6,
|
|
474460
474888
|
readFileSync as readFileSync50,
|
|
474461
474889
|
rmSync as rmSync25,
|
|
474462
|
-
statSync as
|
|
474890
|
+
statSync as statSync26,
|
|
474463
474891
|
writeFileSync as writeFileSync41
|
|
474464
474892
|
} from "node:fs";
|
|
474465
474893
|
import { mkdir as mkdir16, readdir as readdir13 } from "node:fs/promises";
|
|
@@ -474917,7 +475345,7 @@ async function installSkillDirectory(params) {
|
|
|
474917
475345
|
if (!existsSync69(skillMdPath)) {
|
|
474918
475346
|
throw new Error("No SKILL.md found in the skill directory.");
|
|
474919
475347
|
}
|
|
474920
|
-
if (!
|
|
475348
|
+
if (!statSync26(sourceDir).isDirectory()) {
|
|
474921
475349
|
throw new Error(`Skill source is not a directory: ${sourceDir}`);
|
|
474922
475350
|
}
|
|
474923
475351
|
const name = getSkillName(sourceDir);
|
|
@@ -474976,7 +475404,7 @@ async function deleteSkillDirectory(params) {
|
|
|
474976
475404
|
if (!existsSync69(targetPath)) {
|
|
474977
475405
|
throw new Error(`Skill "${name}" is not installed at ${targetPath}.`);
|
|
474978
475406
|
}
|
|
474979
|
-
if (!
|
|
475407
|
+
if (!statSync26(targetPath).isDirectory()) {
|
|
474980
475408
|
throw new Error(`Skill path is not a directory: ${targetPath}`);
|
|
474981
475409
|
}
|
|
474982
475410
|
rmSync25(targetPath, { recursive: true, force: true });
|
|
@@ -476874,7 +477302,7 @@ function firstDefinedBoolean(...values4) {
|
|
|
476874
477302
|
}
|
|
476875
477303
|
function normalizeChatTarget(channel, value) {
|
|
476876
477304
|
const trimmed = value.trim();
|
|
476877
|
-
if (channel === "signal")
|
|
477305
|
+
if (channel === "signal" || channel === "microsoftteams")
|
|
476878
477306
|
return trimmed;
|
|
476879
477307
|
const parts = trimmed.split(":").map((part) => part.trim()).filter(Boolean);
|
|
476880
477308
|
if (parts.length === 2 && /^[a-z_-]+$/i.test(parts[0] ?? "")) {
|
|
@@ -482031,88 +482459,6 @@ var init_headless_cloud_send = __esm(() => {
|
|
|
482031
482459
|
init_headless_environment_response();
|
|
482032
482460
|
});
|
|
482033
482461
|
|
|
482034
|
-
// src/agent/ephemeral-conversation.ts
|
|
482035
|
-
async function buildEphemeralConversationCreateBody(options) {
|
|
482036
|
-
const system2 = options.systemPromptCustom ? options.systemPromptCustom : await resolveAndBuildSystemPrompt(options.systemPromptPreset, options.memoryPromptMode ?? "standard");
|
|
482037
|
-
const request3 = await buildCreateAgentRequest({
|
|
482038
|
-
model: options.model,
|
|
482039
|
-
system: system2,
|
|
482040
|
-
memoryPromptMode: "standard",
|
|
482041
|
-
enableMemfs: false,
|
|
482042
|
-
isSubagent: true,
|
|
482043
|
-
baseTools: []
|
|
482044
|
-
});
|
|
482045
|
-
const modelSettings = options.model ? getModelUpdateArgs(options.model) : undefined;
|
|
482046
|
-
const contextWindow = modelSettings?.context_window ?? await getModelContextWindow(request3.model);
|
|
482047
|
-
return {
|
|
482048
|
-
model: request3.model,
|
|
482049
|
-
system: request3.system ?? system2,
|
|
482050
|
-
...modelSettings ? { model_settings: modelSettings } : {},
|
|
482051
|
-
...contextWindow ? { context_window_limit: contextWindow } : {}
|
|
482052
|
-
};
|
|
482053
|
-
}
|
|
482054
|
-
function projectEphemeralAgent(conversationId, body3) {
|
|
482055
|
-
return {
|
|
482056
|
-
id: conversationId,
|
|
482057
|
-
name: "Ephemeral conversation",
|
|
482058
|
-
system: body3.system,
|
|
482059
|
-
tools: [],
|
|
482060
|
-
memory: { blocks: [] },
|
|
482061
|
-
llm_config: {
|
|
482062
|
-
handle: body3.model,
|
|
482063
|
-
model: body3.model,
|
|
482064
|
-
context_window: body3.context_window_limit ?? undefined,
|
|
482065
|
-
model_settings: body3.model_settings ?? {}
|
|
482066
|
-
},
|
|
482067
|
-
model_settings: body3.model_settings ?? {},
|
|
482068
|
-
message_buffer_autoclear: false
|
|
482069
|
-
};
|
|
482070
|
-
}
|
|
482071
|
-
async function createEphemeralConversation2(options) {
|
|
482072
|
-
const body3 = await buildEphemeralConversationCreateBody(options);
|
|
482073
|
-
const conversation = await createEphemeralConversation(body3);
|
|
482074
|
-
return {
|
|
482075
|
-
agent: projectEphemeralAgent(conversation.id, body3),
|
|
482076
|
-
conversationId: conversation.id
|
|
482077
|
-
};
|
|
482078
|
-
}
|
|
482079
|
-
async function createLocalEphemeralConversation(options) {
|
|
482080
|
-
const body3 = await buildEphemeralConversationCreateBody(options);
|
|
482081
|
-
const backend3 = getBackend();
|
|
482082
|
-
const internalAgent = await backend3.createAgent({
|
|
482083
|
-
agent_type: "letta_v1_agent",
|
|
482084
|
-
name: "Ephemeral conversation",
|
|
482085
|
-
model: body3.model,
|
|
482086
|
-
system: body3.system,
|
|
482087
|
-
memory_blocks: [],
|
|
482088
|
-
tags: [],
|
|
482089
|
-
tools: [],
|
|
482090
|
-
include_base_tools: false,
|
|
482091
|
-
include_base_tool_rules: false,
|
|
482092
|
-
initial_message_sequence: [],
|
|
482093
|
-
parallel_tool_calls: true,
|
|
482094
|
-
hidden: true
|
|
482095
|
-
});
|
|
482096
|
-
const conversation = await backend3.createConversation({
|
|
482097
|
-
agent_id: internalAgent.id,
|
|
482098
|
-
model: body3.model,
|
|
482099
|
-
...body3.model_settings ? { model_settings: body3.model_settings } : {},
|
|
482100
|
-
...body3.context_window_limit ? { context_window_limit: body3.context_window_limit } : {}
|
|
482101
|
-
});
|
|
482102
|
-
return {
|
|
482103
|
-
agent: internalAgent,
|
|
482104
|
-
conversationId: conversation.id
|
|
482105
|
-
};
|
|
482106
|
-
}
|
|
482107
|
-
var init_ephemeral_conversation = __esm(() => {
|
|
482108
|
-
init_available_models();
|
|
482109
|
-
init_create_agent_request();
|
|
482110
|
-
init_model();
|
|
482111
|
-
init_system_prompt_resolution();
|
|
482112
|
-
init_backend2();
|
|
482113
|
-
init_ephemeral_conversations();
|
|
482114
|
-
});
|
|
482115
|
-
|
|
482116
482462
|
// src/headless-ephemeral-startup.ts
|
|
482117
482463
|
function prepareHeadlessEphemeralBackend(enabled) {
|
|
482118
482464
|
if (enabled && isLocalBackendEnabled()) {
|
|
@@ -482144,6 +482490,18 @@ function clearHeadlessClientToolRules(agent) {
|
|
|
482144
482490
|
debugWarn("headless startup", `Failed to clear persisted client tool rules for ${agent.id}: ${error5 instanceof Error ? error5.message : String(error5)}`);
|
|
482145
482491
|
});
|
|
482146
482492
|
}
|
|
482493
|
+
async function retrieveHeadlessConversation(backend3, conversationId) {
|
|
482494
|
+
const conversation = await backend3.retrieveConversation(conversationId);
|
|
482495
|
+
const detached = conversation.agent_id === null;
|
|
482496
|
+
const parentId = Reflect.get(conversation, "parent_agent_id");
|
|
482497
|
+
return {
|
|
482498
|
+
agent: detached ? projectConversationState(conversation) : await backend3.retrieveAgent(conversation.agent_id, {
|
|
482499
|
+
include: ["agent.tools", "agent.tags"]
|
|
482500
|
+
}),
|
|
482501
|
+
detached,
|
|
482502
|
+
parentAgentId: detached && typeof parentId === "string" ? parentId : null
|
|
482503
|
+
};
|
|
482504
|
+
}
|
|
482147
482505
|
var init_headless_ephemeral_startup = __esm(async () => {
|
|
482148
482506
|
init_ephemeral_conversation();
|
|
482149
482507
|
init_backend2();
|
|
@@ -482929,6 +483287,8 @@ In headless mode, use:
|
|
|
482929
483287
|
let specifiedAgentIdFromAmbient = false;
|
|
482930
483288
|
const forceNew = values4["new-agent"];
|
|
482931
483289
|
const ephemeralFlag = values4.ephemeral;
|
|
483290
|
+
let isDetached = Boolean(ephemeralFlag);
|
|
483291
|
+
let parentAgentId = null;
|
|
482932
483292
|
const systemPromptPreset = values4.system;
|
|
482933
483293
|
const systemCustom = values4["system-custom"];
|
|
482934
483294
|
const personalityInput = values4.personality;
|
|
@@ -483089,10 +483449,11 @@ In headless mode, use:
|
|
|
483089
483449
|
if (specifiedConversationId && specifiedConversationId !== "default") {
|
|
483090
483450
|
try {
|
|
483091
483451
|
debugLog("conversations", `retrieve(${specifiedConversationId}) [headless conv→agent lookup]`);
|
|
483092
|
-
|
|
483093
|
-
|
|
483094
|
-
|
|
483095
|
-
|
|
483452
|
+
({
|
|
483453
|
+
agent,
|
|
483454
|
+
detached: isDetached,
|
|
483455
|
+
parentAgentId
|
|
483456
|
+
} = await retrieveHeadlessConversation(startupBackend, specifiedConversationId));
|
|
483096
483457
|
} catch (error5) {
|
|
483097
483458
|
trackHeadlessBoundaryError("headless_conversation_lookup_failed", error5, "headless_startup_conversation_lookup");
|
|
483098
483459
|
console.error(`Conversation ${specifiedConversationId} not found`);
|
|
@@ -483215,9 +483576,9 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
|
|
|
483215
483576
|
process.exit(1);
|
|
483216
483577
|
}
|
|
483217
483578
|
markMilestone("HEADLESS_AGENT_RESOLVED");
|
|
483218
|
-
const publicAgentId =
|
|
483579
|
+
const publicAgentId = isDetached ? null : agent.id;
|
|
483219
483580
|
telemetry.setCurrentAgent(publicAgentId, agent.tags);
|
|
483220
|
-
const isResumingAgent = !
|
|
483581
|
+
const isResumingAgent = !isDetached && !!(specifiedAgentId || !forceNew);
|
|
483221
483582
|
let conversationModel;
|
|
483222
483583
|
if (isResumingAgent) {
|
|
483223
483584
|
const modelHandle = model ? resolveModel(model) : undefined;
|
|
@@ -483240,7 +483601,7 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
|
|
|
483240
483601
|
let effectiveReflectionSettings;
|
|
483241
483602
|
const isSubagent = process.env.LETTA_CODE_AGENT_ROLE === "subagent";
|
|
483242
483603
|
let startupMemfsFlag = autoEnableMemfsForFreshAgent ? true : memfsFlag;
|
|
483243
|
-
if (!isStatelessSession && backend3.capabilities.remoteMemfs && !autoEnableMemfsForFreshAgent) {
|
|
483604
|
+
if (!isStatelessSession && !isDetached && backend3.capabilities.remoteMemfs && !autoEnableMemfsForFreshAgent) {
|
|
483244
483605
|
const { hydrateMemfsSettingFromAgent: hydrateMemfsSettingFromAgent2, isLettaCloud: isLettaCloud2 } = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
|
|
483245
483606
|
const memfsEnabled = await hydrateMemfsSettingFromAgent2(agent);
|
|
483246
483607
|
if (!memfsEnabled && await isLettaCloud2()) {
|
|
@@ -483248,9 +483609,9 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
|
|
|
483248
483609
|
}
|
|
483249
483610
|
}
|
|
483250
483611
|
let memfsBgPromise;
|
|
483251
|
-
const secretsAgentId =
|
|
483612
|
+
const secretsAgentId = isDetached ? undefined : agent?.id;
|
|
483252
483613
|
const secretsInitPromise = secretsAgentId ? Promise.resolve().then(() => (init_secrets_store(), exports_secrets_store)).then(({ initSecretsFromServer: initSecretsFromServer2 }) => initSecretsFromServer2(secretsAgentId)) : Promise.resolve();
|
|
483253
|
-
if (isStatelessSession) {
|
|
483614
|
+
if (isStatelessSession || isDetached) {
|
|
483254
483615
|
settingsManager.setMemfsEnabled(agent.id, false);
|
|
483255
483616
|
} else if (!backend3.capabilities.remoteMemfs) {
|
|
483256
483617
|
if (backend3.capabilities.localMemfs) {
|
|
@@ -483332,11 +483693,11 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
|
|
|
483332
483693
|
memoryMode: getMemoryPromptModeForAgent2(taggedAgent.id)
|
|
483333
483694
|
});
|
|
483334
483695
|
}
|
|
483335
|
-
if (!
|
|
483696
|
+
if (!isDetached) {
|
|
483336
483697
|
clearHeadlessClientToolRules(agent);
|
|
483337
483698
|
}
|
|
483338
483699
|
try {
|
|
483339
|
-
if (
|
|
483700
|
+
if (isDetached) {
|
|
483340
483701
|
effectiveReflectionSettings = { trigger: "off", stepCount: 0 };
|
|
483341
483702
|
} else {
|
|
483342
483703
|
const resolvedReflectionSettings = await applyHeadlessReflectionOverrides(agent.id, reflectionOverrides);
|
|
@@ -483388,7 +483749,7 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
|
|
|
483388
483749
|
}
|
|
483389
483750
|
markMilestone("HEADLESS_CONVERSATION_READY");
|
|
483390
483751
|
setConversationId(conversationId);
|
|
483391
|
-
if (!
|
|
483752
|
+
if (!isDetached && shouldPersistSessionState()) {
|
|
483392
483753
|
await settingsManager.loadLocalProjectSettings();
|
|
483393
483754
|
settingsManager.persistSession(agent.id, conversationId);
|
|
483394
483755
|
}
|
|
@@ -483530,7 +483891,7 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
|
|
|
483530
483891
|
const resolveAllPendingApprovals = async (mode = "send_immediately") => {
|
|
483531
483892
|
const { getResumeDataFromBackend: getResumeDataFromBackend2 } = await Promise.resolve().then(() => (init_check_approval(), exports_check_approval));
|
|
483532
483893
|
while (true) {
|
|
483533
|
-
const freshAgent =
|
|
483894
|
+
const freshAgent = isDetached ? agent : await backend3.retrieveAgent(agent.id);
|
|
483534
483895
|
let resume;
|
|
483535
483896
|
try {
|
|
483536
483897
|
resume = await getResumeDataFromBackend2(freshAgent, conversationId);
|
|
@@ -483590,7 +483951,7 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
|
|
|
483590
483951
|
}
|
|
483591
483952
|
}
|
|
483592
483953
|
};
|
|
483593
|
-
if (isResumingAgent) {
|
|
483954
|
+
if (isResumingAgent || !usesRemoteEnvironment && isDetached && !ephemeralFlag) {
|
|
483594
483955
|
try {
|
|
483595
483956
|
await resolveAllPendingApprovals("queue_for_next_turn");
|
|
483596
483957
|
} catch (approvalError) {
|
|
@@ -483650,9 +484011,12 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
|
|
|
483650
484011
|
pushPart(prompt);
|
|
483651
484012
|
telemetry.trackUserInput(prompt, "user", reportModel ?? "unknown");
|
|
483652
484013
|
if (usesRemoteEnvironment) {
|
|
484014
|
+
const agentId = publicAgentId ?? parentAgentId;
|
|
484015
|
+
if (!agentId)
|
|
484016
|
+
throw new Error("Listener delivery requires a conversation with an agent or parent agent.");
|
|
483653
484017
|
const environmentSelector = explicitEnvironmentSelector ?? "";
|
|
483654
484018
|
const useCloudSandbox = isCloudEnvironmentSelector(environmentSelector);
|
|
483655
|
-
const environmentRouting = environmentSelector ? useCloudSandbox ? await resolveAgentSandboxConnectionId(
|
|
484019
|
+
const environmentRouting = environmentSelector ? useCloudSandbox ? await resolveAgentSandboxConnectionId(agentId, { conversationId }) : await resolveEnvironmentConnectionId(environmentSelector) : null;
|
|
483656
484020
|
const connectionId = environmentRouting?.connectionId ?? inheritedListenerConnectionId;
|
|
483657
484021
|
if (!connectionId)
|
|
483658
484022
|
throw new Error("No listener connection was resolved for this launch");
|
|
@@ -483666,8 +484030,9 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
|
|
|
483666
484030
|
noWait: isAgentLaunch || Boolean(values4["no-wait"]),
|
|
483667
484031
|
clientMessageId: values4["client-message-id"],
|
|
483668
484032
|
connectionId,
|
|
484033
|
+
parentAgentId: parentAgentId ?? undefined,
|
|
483669
484034
|
scope: {
|
|
483670
|
-
agent_id:
|
|
484035
|
+
agent_id: publicAgentId,
|
|
483671
484036
|
conversation_id: conversationId,
|
|
483672
484037
|
acting_user_id: resolveActingUserId()
|
|
483673
484038
|
},
|
|
@@ -484403,6 +484768,9 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
|
|
|
484403
484768
|
await exitHeadless(1, "headless_stop_reason_error");
|
|
484404
484769
|
}
|
|
484405
484770
|
} catch (error5) {
|
|
484771
|
+
if (sigintSignal.aborted) {
|
|
484772
|
+
await exitInterrupted();
|
|
484773
|
+
}
|
|
484406
484774
|
markIncompleteToolsAsCancelled(buffers, true, "stream_error");
|
|
484407
484775
|
const errorDetails = formatErrorDetails2(error5, agent.id);
|
|
484408
484776
|
trackHeadlessBoundaryError("headless_runtime_exception", error5, "headless_turn_execution");
|
|
@@ -484817,6 +485185,30 @@ async function runBidirectionalMode(agent, conversationId, effectiveModel, _outp
|
|
|
484817
485185
|
lineResolver = resolve42;
|
|
484818
485186
|
});
|
|
484819
485187
|
}
|
|
485188
|
+
const EXTERNAL_TOOL_WAIT_ABORTED = Symbol("externalToolWaitAborted");
|
|
485189
|
+
async function getNextLineOrAbort(signal) {
|
|
485190
|
+
if (signal?.aborted)
|
|
485191
|
+
return EXTERNAL_TOOL_WAIT_ABORTED;
|
|
485192
|
+
if (lineQueue.length > 0)
|
|
485193
|
+
return lineQueue.shift() ?? null;
|
|
485194
|
+
if (!signal)
|
|
485195
|
+
return getNextLine();
|
|
485196
|
+
return new Promise((resolve42) => {
|
|
485197
|
+
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
485198
|
+
const onAbort = () => {
|
|
485199
|
+
cleanup();
|
|
485200
|
+
if (lineResolver === settle3)
|
|
485201
|
+
lineResolver = null;
|
|
485202
|
+
resolve42(EXTERNAL_TOOL_WAIT_ABORTED);
|
|
485203
|
+
};
|
|
485204
|
+
const settle3 = (line) => {
|
|
485205
|
+
cleanup();
|
|
485206
|
+
resolve42(line);
|
|
485207
|
+
};
|
|
485208
|
+
signal.addEventListener("abort", onAbort);
|
|
485209
|
+
lineResolver = settle3;
|
|
485210
|
+
});
|
|
485211
|
+
}
|
|
484820
485212
|
async function requestPermission(toolCallId, toolName2, toolInput) {
|
|
484821
485213
|
const requestId = `perm-${toolCallId}`;
|
|
484822
485214
|
const diffs = await computeDiffPreviews(toolName2, toolInput);
|
|
@@ -484977,7 +485369,14 @@ async function runBidirectionalMode(agent, conversationId, effectiveModel, _outp
|
|
|
484977
485369
|
const toolsRequest = message2.request;
|
|
484978
485370
|
const tools = toolsRequest.tools ?? [];
|
|
484979
485371
|
registerExternalTools(tools);
|
|
484980
|
-
setExternalToolExecutor(async (toolCallId, toolName2, input) => {
|
|
485372
|
+
setExternalToolExecutor(async (toolCallId, toolName2, input, context3) => {
|
|
485373
|
+
const signal = context3?.signal;
|
|
485374
|
+
if (signal?.aborted) {
|
|
485375
|
+
return {
|
|
485376
|
+
content: [{ type: "text", text: INTERRUPTED_BY_USER }],
|
|
485377
|
+
isError: true
|
|
485378
|
+
};
|
|
485379
|
+
}
|
|
484981
485380
|
const execRequest = {
|
|
484982
485381
|
type: "control_request",
|
|
484983
485382
|
request_id: `ext-${toolCallId}`,
|
|
@@ -484989,25 +485388,48 @@ async function runBidirectionalMode(agent, conversationId, effectiveModel, _outp
|
|
|
484989
485388
|
}
|
|
484990
485389
|
};
|
|
484991
485390
|
writeWireMessage(execRequest);
|
|
484992
|
-
|
|
484993
|
-
|
|
484994
|
-
|
|
484995
|
-
|
|
484996
|
-
|
|
484997
|
-
isError: true
|
|
484998
|
-
};
|
|
484999
|
-
}
|
|
485000
|
-
if (!line2.trim())
|
|
485001
|
-
continue;
|
|
485002
|
-
try {
|
|
485003
|
-
const msg = JSON.parse(line2);
|
|
485004
|
-
if (msg.type === "control_response" && msg.response?.subtype === "external_tool_result" && msg.response?.tool_call_id === toolCallId) {
|
|
485391
|
+
const deferredLines = [];
|
|
485392
|
+
try {
|
|
485393
|
+
while (true) {
|
|
485394
|
+
const line2 = await getNextLineOrAbort(signal);
|
|
485395
|
+
if (line2 === EXTERNAL_TOOL_WAIT_ABORTED) {
|
|
485005
485396
|
return {
|
|
485006
|
-
content:
|
|
485007
|
-
isError:
|
|
485397
|
+
content: [{ type: "text", text: INTERRUPTED_BY_USER }],
|
|
485398
|
+
isError: true
|
|
485008
485399
|
};
|
|
485009
485400
|
}
|
|
485010
|
-
|
|
485401
|
+
if (line2 === null) {
|
|
485402
|
+
return {
|
|
485403
|
+
content: [
|
|
485404
|
+
{
|
|
485405
|
+
type: "text",
|
|
485406
|
+
text: currentAbortController?.signal.aborted ? INTERRUPTED_BY_USER : "stdin closed"
|
|
485407
|
+
}
|
|
485408
|
+
],
|
|
485409
|
+
isError: true
|
|
485410
|
+
};
|
|
485411
|
+
}
|
|
485412
|
+
if (!line2.trim())
|
|
485413
|
+
continue;
|
|
485414
|
+
try {
|
|
485415
|
+
const msg = JSON.parse(line2);
|
|
485416
|
+
if (msg.type === "control_response" && msg.response?.subtype === "external_tool_result") {
|
|
485417
|
+
if (msg.response.tool_call_id === toolCallId) {
|
|
485418
|
+
return {
|
|
485419
|
+
content: msg.response.content ?? [
|
|
485420
|
+
{ type: "text", text: "" }
|
|
485421
|
+
],
|
|
485422
|
+
isError: msg.response.is_error ?? false
|
|
485423
|
+
};
|
|
485424
|
+
}
|
|
485425
|
+
continue;
|
|
485426
|
+
}
|
|
485427
|
+
} catch {}
|
|
485428
|
+
deferredLines.push(line2);
|
|
485429
|
+
}
|
|
485430
|
+
} finally {
|
|
485431
|
+
if (deferredLines.length > 0)
|
|
485432
|
+
lineQueue.unshift(...deferredLines);
|
|
485011
485433
|
}
|
|
485012
485434
|
});
|
|
485013
485435
|
const registerResponse = {
|
|
@@ -485427,10 +485849,18 @@ async function runBidirectionalMode(agent, conversationId, effectiveModel, _outp
|
|
|
485427
485849
|
}
|
|
485428
485850
|
const { executeApprovalBatch: executeApprovalBatch2 } = await init_approval_execution().then(() => exports_approval_execution);
|
|
485429
485851
|
emitLocalToolCalls(decisions, sessionId);
|
|
485430
|
-
|
|
485431
|
-
|
|
485432
|
-
|
|
485433
|
-
|
|
485852
|
+
let executedResults;
|
|
485853
|
+
try {
|
|
485854
|
+
executedResults = await executeApprovalBatch2(decisions, undefined, {
|
|
485855
|
+
toolContextId: turnToolContextId ?? undefined,
|
|
485856
|
+
abortSignal: currentAbortController.signal
|
|
485857
|
+
});
|
|
485858
|
+
} catch (error5) {
|
|
485859
|
+
if (currentAbortController?.signal.aborted) {
|
|
485860
|
+
break;
|
|
485861
|
+
}
|
|
485862
|
+
throw error5;
|
|
485863
|
+
}
|
|
485434
485864
|
emitLocalToolReturns(executedResults, sessionId);
|
|
485435
485865
|
currentInput = responseState.prepare(executedResults, needsUserInput.length === 0);
|
|
485436
485866
|
continue;
|
|
@@ -485548,6 +485978,7 @@ var LLM_API_ERROR_MAX_RETRIES2 = 3, EMPTY_RESPONSE_MAX_RETRIES2 = 2, HEADLESS_ST
|
|
|
485548
485978
|
var init_headless = __esm(async () => {
|
|
485549
485979
|
init_error();
|
|
485550
485980
|
init_preloaded_skills();
|
|
485981
|
+
init_constants2();
|
|
485551
485982
|
init_headless_message_sender();
|
|
485552
485983
|
init_headless_response_state();
|
|
485553
485984
|
init_headless_startup_backend();
|
|
@@ -497505,7 +497936,6 @@ var init_SlashCommandAutocomplete = __esm(async () => {
|
|
|
497505
497936
|
"creating-skills",
|
|
497506
497937
|
"customizing-statusline",
|
|
497507
497938
|
"initializing-memory",
|
|
497508
|
-
"migrating-memory",
|
|
497509
497939
|
"syncing-memory-filesystem"
|
|
497510
497940
|
]);
|
|
497511
497941
|
_allCommands = Object.entries(commands).filter(([, { hidden }]) => !hidden).map(([cmd, { desc, order }]) => ({
|
|
@@ -498502,6 +498932,7 @@ function Input({
|
|
|
498502
498932
|
queueMode = "immediate",
|
|
498503
498933
|
deferModeSupported = false,
|
|
498504
498934
|
interruptRequested = false,
|
|
498935
|
+
hasStopFailedTasks = false,
|
|
498505
498936
|
agentId,
|
|
498506
498937
|
agentName,
|
|
498507
498938
|
currentModel,
|
|
@@ -498801,7 +499232,7 @@ function Input({
|
|
|
498801
499232
|
onBashInterrupt();
|
|
498802
499233
|
return;
|
|
498803
499234
|
}
|
|
498804
|
-
if ((streaming3 || interruptRequested) && onInterrupt) {
|
|
499235
|
+
if ((streaming3 || interruptRequested || hasStopFailedTasks) && onInterrupt) {
|
|
498805
499236
|
onInterrupt();
|
|
498806
499237
|
return;
|
|
498807
499238
|
}
|
|
@@ -514807,6 +515238,7 @@ function AppView(props) {
|
|
|
514807
515238
|
inputEnabled,
|
|
514808
515239
|
inputVisible,
|
|
514809
515240
|
interruptRequested,
|
|
515241
|
+
hasStopFailedTasks,
|
|
514810
515242
|
isAgentBusy,
|
|
514811
515243
|
liveItems,
|
|
514812
515244
|
liveTrajectoryElapsedBaseMs,
|
|
@@ -515035,6 +515467,7 @@ function AppView(props) {
|
|
|
515035
515467
|
queueMode,
|
|
515036
515468
|
deferModeSupported,
|
|
515037
515469
|
interruptRequested,
|
|
515470
|
+
hasStopFailedTasks,
|
|
515038
515471
|
agentId,
|
|
515039
515472
|
agentName,
|
|
515040
515473
|
currentModel: currentModelDisplay,
|
|
@@ -516193,6 +516626,12 @@ function useApprovalFlow(ctx) {
|
|
|
516193
516626
|
startupApprovals
|
|
516194
516627
|
]);
|
|
516195
516628
|
const sendAllResults = import_react113.useCallback(async (additionalDecision) => {
|
|
516629
|
+
const approvalAbortController = new AbortController;
|
|
516630
|
+
const approvalResultsSnapshot = [...approvalResults];
|
|
516631
|
+
const autoHandledSnapshot = [...autoHandledResults];
|
|
516632
|
+
const autoDeniedSnapshot = [...autoDeniedApprovals];
|
|
516633
|
+
const pendingSnapshot = [...pendingApprovals];
|
|
516634
|
+
const companionResults = buildCompanionResults(autoHandledSnapshot, autoDeniedSnapshot);
|
|
516196
516635
|
try {
|
|
516197
516636
|
if (userCancelledRef.current || abortControllerRef.current?.signal.aborted) {
|
|
516198
516637
|
setStreaming(false);
|
|
@@ -516202,12 +516641,13 @@ function useApprovalFlow(ctx) {
|
|
|
516202
516641
|
setApprovalResults([]);
|
|
516203
516642
|
setAutoHandledResults([]);
|
|
516204
516643
|
setAutoDeniedApprovals([]);
|
|
516644
|
+
clearApprovalToolContext();
|
|
516645
|
+
toolAbortControllerRef.current = null;
|
|
516646
|
+
executingToolCallIdsRef.current = [];
|
|
516647
|
+
interruptQueuedRef.current = false;
|
|
516648
|
+
toolResultsInFlightRef.current = false;
|
|
516205
516649
|
return;
|
|
516206
516650
|
}
|
|
516207
|
-
const approvalResultsSnapshot = [...approvalResults];
|
|
516208
|
-
const autoHandledSnapshot = [...autoHandledResults];
|
|
516209
|
-
const autoDeniedSnapshot = [...autoDeniedApprovals];
|
|
516210
|
-
const pendingSnapshot = [...pendingApprovals];
|
|
516211
516651
|
setPendingApprovals([]);
|
|
516212
516652
|
setApprovalContexts([]);
|
|
516213
516653
|
setApprovalResults([]);
|
|
@@ -516216,7 +516656,6 @@ function useApprovalFlow(ctx) {
|
|
|
516216
516656
|
setStreaming(true);
|
|
516217
516657
|
openTrajectorySegment();
|
|
516218
516658
|
buffersRef.current.interrupted = false;
|
|
516219
|
-
const approvalAbortController = new AbortController;
|
|
516220
516659
|
toolAbortControllerRef.current = approvalAbortController;
|
|
516221
516660
|
const allDecisions = [
|
|
516222
516661
|
...approvalResultsSnapshot,
|
|
@@ -516258,23 +516697,10 @@ function useApprovalFlow(ctx) {
|
|
|
516258
516697
|
localToolMs: toolRunMs
|
|
516259
516698
|
});
|
|
516260
516699
|
}
|
|
516261
|
-
|
|
516262
|
-
|
|
516263
|
-
|
|
516264
|
-
|
|
516265
|
-
tool_return: ar.result.toolReturn,
|
|
516266
|
-
status: ar.result.status,
|
|
516267
|
-
stdout: ar.result.stdout,
|
|
516268
|
-
stderr: ar.result.stderr
|
|
516269
|
-
})),
|
|
516270
|
-
...autoDeniedSnapshot.map((ad) => ({
|
|
516271
|
-
type: "approval",
|
|
516272
|
-
tool_call_id: ad.approval.toolCallId,
|
|
516273
|
-
approve: false,
|
|
516274
|
-
reason: ad.reason
|
|
516275
|
-
})),
|
|
516276
|
-
...executedResults
|
|
516277
|
-
];
|
|
516700
|
+
if (toolAbortControllerRef.current !== approvalAbortController) {
|
|
516701
|
+
return;
|
|
516702
|
+
}
|
|
516703
|
+
const allResults = [...companionResults, ...executedResults];
|
|
516278
516704
|
if (true) {
|
|
516279
516705
|
const expectedIds = new Set([
|
|
516280
516706
|
...autoHandledSnapshot.map((ar) => ar.toolCallId),
|
|
@@ -516293,9 +516719,7 @@ function useApprovalFlow(ctx) {
|
|
|
516293
516719
|
const wasAborted = approvalAbortController.signal.aborted;
|
|
516294
516720
|
const userCancelled = userCancelledRef.current;
|
|
516295
516721
|
if (wasAborted || userCancelled) {
|
|
516296
|
-
|
|
516297
|
-
queueApprovalResults(allResults);
|
|
516298
|
-
}
|
|
516722
|
+
queueApprovalResults(allResults);
|
|
516299
516723
|
setStreaming(false);
|
|
516300
516724
|
closeTrajectorySegment();
|
|
516301
516725
|
syncTrajectoryElapsedBase();
|
|
@@ -516316,6 +516740,24 @@ function useApprovalFlow(ctx) {
|
|
|
516316
516740
|
queueApprovalResults(null);
|
|
516317
516741
|
}
|
|
516318
516742
|
} catch (error5) {
|
|
516743
|
+
if (toolAbortControllerRef.current !== approvalAbortController) {
|
|
516744
|
+
return;
|
|
516745
|
+
}
|
|
516746
|
+
if (isUserAbortError(error5)) {
|
|
516747
|
+
markIncompleteToolsAsCancelled(buffersRef.current, true, "user_interrupt");
|
|
516748
|
+
const merged = overlayPartialResults(queuedApprovalResultsRef.current, [
|
|
516749
|
+
...error5.partialResults ?? [],
|
|
516750
|
+
...companionResults
|
|
516751
|
+
]);
|
|
516752
|
+
if (merged.length > 0) {
|
|
516753
|
+
queueApprovalResults(merged);
|
|
516754
|
+
}
|
|
516755
|
+
setStreaming(false);
|
|
516756
|
+
closeTrajectorySegment();
|
|
516757
|
+
syncTrajectoryElapsedBase();
|
|
516758
|
+
refreshDerived();
|
|
516759
|
+
return;
|
|
516760
|
+
}
|
|
516319
516761
|
markIncompleteToolsAsCancelled(buffersRef.current, true, "stream_error");
|
|
516320
516762
|
const errorDetails = formatErrorDetails2(error5, agentId);
|
|
516321
516763
|
appendError(errorDetails, {
|
|
@@ -516327,12 +516769,14 @@ function useApprovalFlow(ctx) {
|
|
|
516327
516769
|
syncTrajectoryElapsedBase();
|
|
516328
516770
|
refreshDerived();
|
|
516329
516771
|
} finally {
|
|
516330
|
-
|
|
516331
|
-
|
|
516332
|
-
|
|
516333
|
-
|
|
516334
|
-
|
|
516335
|
-
|
|
516772
|
+
if (toolAbortControllerRef.current === approvalAbortController) {
|
|
516773
|
+
clearApprovalToolContext();
|
|
516774
|
+
setIsExecutingTool(false);
|
|
516775
|
+
toolAbortControllerRef.current = null;
|
|
516776
|
+
executingToolCallIdsRef.current = [];
|
|
516777
|
+
interruptQueuedRef.current = false;
|
|
516778
|
+
toolResultsInFlightRef.current = false;
|
|
516779
|
+
}
|
|
516336
516780
|
}
|
|
516337
516781
|
}, [
|
|
516338
516782
|
agentId,
|
|
@@ -516660,7 +517104,10 @@ var init_use_approval_flow = __esm(async () => {
|
|
|
516660
517104
|
init_debug();
|
|
516661
517105
|
init_notifications();
|
|
516662
517106
|
init_turn_input();
|
|
516663
|
-
await
|
|
517107
|
+
await __promiseAll([
|
|
517108
|
+
init_approval_execution(),
|
|
517109
|
+
init_manager2()
|
|
517110
|
+
]);
|
|
516664
517111
|
import_react113 = __toESM(require_react(), 1);
|
|
516665
517112
|
});
|
|
516666
517113
|
|
|
@@ -517959,6 +518406,7 @@ function useConversationLoop(ctx) {
|
|
|
517959
518406
|
precomputedDiffsRef,
|
|
517960
518407
|
prepareScopedToolExecutionContext,
|
|
517961
518408
|
processingConversationRef,
|
|
518409
|
+
queuedApprovalResultsRef,
|
|
517962
518410
|
queueApprovalResults,
|
|
517963
518411
|
queueSnapshotRef,
|
|
517964
518412
|
quotaAutoSwapAttemptedRef,
|
|
@@ -518856,7 +519304,11 @@ ${feedback}
|
|
|
518856
519304
|
const autoAllowedAbortController = abortControllerRef.current ?? new AbortController;
|
|
518857
519305
|
const shouldTrackAutoAllowed = autoAllowedToolCallIds.length > 0;
|
|
518858
519306
|
let autoAllowedResults = [];
|
|
518859
|
-
|
|
519307
|
+
const autoDeniedResults = autoDenied.map((ac) => ({
|
|
519308
|
+
approval: ac.approval,
|
|
519309
|
+
reason: formatPermissionDenial(ac.permission)
|
|
519310
|
+
}));
|
|
519311
|
+
const prebuiltDeniedApprovalResults = buildDeniedResults(autoDeniedResults);
|
|
518860
519312
|
if (shouldTrackAutoAllowed) {
|
|
518861
519313
|
setIsExecutingTool(true);
|
|
518862
519314
|
executingToolCallIdsRef.current = autoAllowedToolCallIds;
|
|
@@ -518873,29 +519325,35 @@ ${feedback}
|
|
|
518873
519325
|
setToolCallsRunning(buffersRef.current, autoAllowedToolCallIds);
|
|
518874
519326
|
refreshDerived();
|
|
518875
519327
|
}
|
|
518876
|
-
|
|
518877
|
-
|
|
518878
|
-
|
|
518879
|
-
|
|
518880
|
-
|
|
518881
|
-
|
|
518882
|
-
|
|
518883
|
-
|
|
519328
|
+
try {
|
|
519329
|
+
const approvalToolContextId = approvalToolContextIdRef.current ?? (await prepareScopedToolExecutionContext(tempModelOverrideRef.current ?? undefined)).preparedToolContext.contextId;
|
|
519330
|
+
autoAllowedResults = autoAllowed.length > 0 ? await executeAutoAllowedTools(autoAllowed, (chunk2) => onChunk(buffersRef.current, chunk2), {
|
|
519331
|
+
abortSignal: autoAllowedAbortController.signal,
|
|
519332
|
+
onStreamingOutput: updateStreamingOutput,
|
|
519333
|
+
toolContextId: approvalToolContextId
|
|
519334
|
+
}) : [];
|
|
519335
|
+
} catch (error5) {
|
|
519336
|
+
if (shouldTrackAutoAllowed && toolAbortControllerRef.current !== autoAllowedAbortController) {
|
|
519337
|
+
return;
|
|
519338
|
+
}
|
|
519339
|
+
appendAbortPartials(error5, prebuiltDeniedApprovalResults);
|
|
519340
|
+
throw error5;
|
|
519341
|
+
}
|
|
519342
|
+
if (shouldTrackAutoAllowed && toolAbortControllerRef.current !== autoAllowedAbortController) {
|
|
519343
|
+
return;
|
|
519344
|
+
}
|
|
519345
|
+
for (const ad of autoDeniedResults) {
|
|
518884
519346
|
onChunk(buffersRef.current, {
|
|
518885
519347
|
message_type: "tool_return_message",
|
|
518886
519348
|
id: "dummy",
|
|
518887
519349
|
date: new Date().toISOString(),
|
|
518888
|
-
tool_call_id:
|
|
518889
|
-
tool_return: `Error: request to call tool denied. User reason: ${reason}`,
|
|
519350
|
+
tool_call_id: ad.approval.toolCallId,
|
|
519351
|
+
tool_return: `Error: request to call tool denied. User reason: ${ad.reason}`,
|
|
518890
519352
|
status: "error",
|
|
518891
519353
|
stdout: null,
|
|
518892
519354
|
stderr: null
|
|
518893
519355
|
});
|
|
518894
|
-
|
|
518895
|
-
approval: ac.approval,
|
|
518896
|
-
reason
|
|
518897
|
-
};
|
|
518898
|
-
});
|
|
519356
|
+
}
|
|
518899
519357
|
const allResults = [
|
|
518900
519358
|
...autoAllowedResults.map((ar) => ({
|
|
518901
519359
|
type: "tool",
|
|
@@ -518905,12 +519363,7 @@ ${feedback}
|
|
|
518905
519363
|
stdout: ar.result.stdout,
|
|
518906
519364
|
stderr: ar.result.stderr
|
|
518907
519365
|
})),
|
|
518908
|
-
...
|
|
518909
|
-
type: "approval",
|
|
518910
|
-
tool_call_id: ad.approval.toolCallId,
|
|
518911
|
-
approve: false,
|
|
518912
|
-
reason: ad.reason
|
|
518913
|
-
}))
|
|
519366
|
+
...prebuiltDeniedApprovalResults
|
|
518914
519367
|
];
|
|
518915
519368
|
if (autoAllowedExecutionRef.current) {
|
|
518916
519369
|
autoAllowedExecutionRef.current.results = allResults;
|
|
@@ -519008,7 +519461,7 @@ ${feedback}
|
|
|
519008
519461
|
return;
|
|
519009
519462
|
}
|
|
519010
519463
|
} finally {
|
|
519011
|
-
if (shouldTrackAutoAllowed) {
|
|
519464
|
+
if (shouldTrackAutoAllowed && toolAbortControllerRef.current === autoAllowedAbortController) {
|
|
519012
519465
|
setIsExecutingTool(false);
|
|
519013
519466
|
toolAbortControllerRef.current = null;
|
|
519014
519467
|
executingToolCallIdsRef.current = [];
|
|
@@ -519342,8 +519795,16 @@ ${feedback}
|
|
|
519342
519795
|
}
|
|
519343
519796
|
} catch (e2) {
|
|
519344
519797
|
debugWarn("message_stream", "Unhandled conversation error: %s", e2 instanceof Error ? e2.stack ?? e2.message : String(e2));
|
|
519345
|
-
|
|
519346
|
-
|
|
519798
|
+
if (abortControllerRef.current !== turnAbortController) {
|
|
519799
|
+
return;
|
|
519800
|
+
}
|
|
519801
|
+
markIncompleteToolsAsCancelled(buffersRef.current, true, isUserAbortError(e2) ? "user_interrupt" : "stream_error");
|
|
519802
|
+
if (EAGER_CANCEL && isUserAbortError(e2)) {
|
|
519803
|
+
const partials = e2.partialResults;
|
|
519804
|
+
const overlaid = partials ? overlayPartialResults(queuedApprovalResultsRef.current, partials) : [];
|
|
519805
|
+
if (overlaid.length > 0) {
|
|
519806
|
+
queueApprovalResults(overlaid);
|
|
519807
|
+
}
|
|
519347
519808
|
setStreaming(false);
|
|
519348
519809
|
refreshDerived();
|
|
519349
519810
|
return;
|
|
@@ -520102,18 +520563,23 @@ var init_use_feedback_handler = __esm(() => {
|
|
|
520102
520563
|
});
|
|
520103
520564
|
|
|
520104
520565
|
// src/cli/app/use-interrupt-handler.ts
|
|
520105
|
-
function hasActiveReflectionSubagentForAgent(agentId) {
|
|
520566
|
+
function hasActiveReflectionSubagentForAgent(agentId, conversationId) {
|
|
520106
520567
|
return getSubagents().some((agent) => {
|
|
520107
520568
|
if (agent.type.toLowerCase() !== "reflection")
|
|
520108
520569
|
return false;
|
|
520109
520570
|
if (agent.status !== "pending" && agent.status !== "running")
|
|
520110
520571
|
return false;
|
|
520111
|
-
|
|
520572
|
+
if (agent.parentAgentId !== agentId)
|
|
520573
|
+
return false;
|
|
520574
|
+
return conversationId === undefined || agent.parentConversationId === undefined || agent.parentConversationId === conversationId;
|
|
520112
520575
|
});
|
|
520113
520576
|
}
|
|
520114
|
-
function interruptSubagentsAndReleaseReflection(agentId) {
|
|
520115
|
-
const interruptedReflection = hasActiveReflectionSubagentForAgent(agentId);
|
|
520116
|
-
interruptActiveSubagents(INTERRUPTED_BY_USER
|
|
520577
|
+
function interruptSubagentsAndReleaseReflection(agentId, conversationId) {
|
|
520578
|
+
const interruptedReflection = hasActiveReflectionSubagentForAgent(agentId, conversationId);
|
|
520579
|
+
interruptActiveSubagents(INTERRUPTED_BY_USER, {
|
|
520580
|
+
agentId,
|
|
520581
|
+
conversationId
|
|
520582
|
+
});
|
|
520117
520583
|
if (interruptedReflection) {
|
|
520118
520584
|
releaseReflectionLaunch(agentId);
|
|
520119
520585
|
}
|
|
@@ -520215,7 +520681,7 @@ function useInterruptHandler(ctx) {
|
|
|
520215
520681
|
autoAllowedExecutionRef.current = null;
|
|
520216
520682
|
buffersRef.current.abortGeneration = (buffersRef.current.abortGeneration || 0) + 1;
|
|
520217
520683
|
const toolsCancelled = markIncompleteToolsAsCancelled(buffersRef.current, true, "user_interrupt");
|
|
520218
|
-
interruptSubagentsAndReleaseReflection(agentId);
|
|
520684
|
+
interruptSubagentsAndReleaseReflection(agentId, conversationIdRef.current);
|
|
520219
520685
|
if (!toolsCancelled) {
|
|
520220
520686
|
appendError(INTERRUPT_MESSAGE, true);
|
|
520221
520687
|
}
|
|
@@ -520245,6 +520711,16 @@ function useInterruptHandler(ctx) {
|
|
|
520245
520711
|
bumpDequeueEpoch: () => setDequeueEpoch((e2) => e2 + 1)
|
|
520246
520712
|
});
|
|
520247
520713
|
}
|
|
520714
|
+
const retried = interruptStopFailedSubagents(INTERRUPTED_BY_USER, {
|
|
520715
|
+
agentId,
|
|
520716
|
+
conversationId: conversationIdRef.current
|
|
520717
|
+
});
|
|
520718
|
+
if (retried.length > 0) {
|
|
520719
|
+
if (retried.some((id2) => getSubagents().find((agent) => agent.id === id2)?.type.toLowerCase() === "reflection")) {
|
|
520720
|
+
releaseReflectionLaunch(agentId);
|
|
520721
|
+
}
|
|
520722
|
+
appendError("Retrying stop of background task...", true);
|
|
520723
|
+
}
|
|
520248
520724
|
return;
|
|
520249
520725
|
}
|
|
520250
520726
|
if (waitingForQueueCancelRef.current) {
|
|
@@ -520255,7 +520731,7 @@ function useInterruptHandler(ctx) {
|
|
|
520255
520731
|
setInterruptRequested(true);
|
|
520256
520732
|
buffersRef.current.abortGeneration = (buffersRef.current.abortGeneration || 0) + 1;
|
|
520257
520733
|
const toolsCancelled = markIncompleteToolsAsCancelled(buffersRef.current, true, "user_interrupt");
|
|
520258
|
-
interruptSubagentsAndReleaseReflection(agentId);
|
|
520734
|
+
interruptSubagentsAndReleaseReflection(agentId, conversationIdRef.current);
|
|
520259
520735
|
abortControllerRef.current?.abort();
|
|
520260
520736
|
pendingInterruptRecoveryConversationIdRef.current = conversationIdRef.current;
|
|
520261
520737
|
userCancelledRef.current = true;
|
|
@@ -529520,6 +529996,7 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
|
|
|
529520
529996
|
precomputedDiffsRef,
|
|
529521
529997
|
prepareScopedToolExecutionContext,
|
|
529522
529998
|
processingConversationRef,
|
|
529999
|
+
queuedApprovalResultsRef,
|
|
529523
530000
|
queueApprovalResults,
|
|
529524
530001
|
queueSnapshotRef,
|
|
529525
530002
|
quotaAutoSwapAttemptedRef,
|
|
@@ -530276,6 +530753,18 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
|
|
|
530276
530753
|
deferredCommitAt
|
|
530277
530754
|
]);
|
|
530278
530755
|
const { agents: subagents } = import_react123.useSyncExternalStore(subscribe2, getSnapshot2);
|
|
530756
|
+
const hasStopFailedTasks = hasStopFailedSubagents({
|
|
530757
|
+
agentId,
|
|
530758
|
+
conversationId
|
|
530759
|
+
});
|
|
530760
|
+
const stopFailedNotifiedRef = import_react123.useRef(new Set);
|
|
530761
|
+
import_react123.useEffect(() => {
|
|
530762
|
+
const { failures, stops } = selectStopFailedNotifications(subagents, stopFailedNotifiedRef.current, { agentId, conversationId });
|
|
530763
|
+
const messages = [...failures, ...stops];
|
|
530764
|
+
if (messages.length > 0) {
|
|
530765
|
+
appendTaskNotificationEvents(messages);
|
|
530766
|
+
}
|
|
530767
|
+
}, [subagents, conversationId, appendTaskNotificationEvents, agentId]);
|
|
530279
530768
|
const estimatedLiveHeight = import_react123.useMemo(() => {
|
|
530280
530769
|
const countLines4 = (text3) => {
|
|
530281
530770
|
if (!text3)
|
|
@@ -530523,6 +531012,7 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
|
|
|
530523
531012
|
inputEnabled,
|
|
530524
531013
|
inputVisible,
|
|
530525
531014
|
interruptRequested: interruptRequested || !!abortControllerRef.current?.signal.aborted,
|
|
531015
|
+
hasStopFailedTasks,
|
|
530526
531016
|
isAgentBusy,
|
|
530527
531017
|
liveItems,
|
|
530528
531018
|
liveTrajectoryElapsedBaseMs,
|
|
@@ -534800,4 +535290,4 @@ function registerBunOAuthFlows() {
|
|
|
534800
535290
|
registerBunOAuthFlows();
|
|
534801
535291
|
await init_src5().then(() => exports_src2);
|
|
534802
535292
|
|
|
534803
|
-
//# debugId=
|
|
535293
|
+
//# debugId=9CD2133B459655FB64756E2164756E21
|