@letta-ai/letta-code 0.29.6 → 0.29.8
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/dist/agent-presets.js +197 -3
- package/dist/agent-presets.js.map +3 -3
- package/dist/app-server-client.cjs +16 -20
- package/dist/app-server-client.cjs.map +3 -3
- package/dist/app-server-client.js +16 -20
- package/dist/app-server-client.js.map +3 -3
- package/dist/types/agent/prompt-assets.d.ts +2 -0
- package/dist/types/agent/prompt-assets.d.ts.map +1 -1
- package/dist/types/app-server-client.d.ts +12 -9
- package/dist/types/app-server-client.d.ts.map +1 -1
- package/letta.js +1579 -699
- package/package.json +1 -1
- package/scripts/source-file-size-baseline.json +5 -5
package/letta.js
CHANGED
|
@@ -5462,7 +5462,7 @@ var package_default;
|
|
|
5462
5462
|
var init_package = __esm(() => {
|
|
5463
5463
|
package_default = {
|
|
5464
5464
|
name: "@letta-ai/letta-code",
|
|
5465
|
-
version: "0.29.
|
|
5465
|
+
version: "0.29.8",
|
|
5466
5466
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
5467
5467
|
type: "module",
|
|
5468
5468
|
packageManager: "bun@1.3.0",
|
|
@@ -6989,12 +6989,18 @@ Memory blocks are editable segments of the system prompt. Each block has a name
|
|
|
6989
6989
|
|
|
6990
6990
|
### External memory (skills, markdown, & other files)
|
|
6991
6991
|
|
|
6992
|
-
External memory is stored outside of the system prompt, including both skills (procedural memory)
|
|
6992
|
+
External memory is stored outside of the system prompt, including both skills (procedural memory), general-purpose files (markdown files, images, etc.), and shared memory.
|
|
6993
6993
|
|
|
6994
6994
|
- *Skills (procedural memory).* Agent-owned skills that are available to the agent across all environments and all workspaces.
|
|
6995
6995
|
- *Markdown files.* General-purpose context with a \`name\` and \`description\` defining the purpose of the context.
|
|
6996
6996
|
- *Other files (e.g. reference images).* General-purpose files that are a part of the agent, e.g. reference CSV tables or images.
|
|
6997
6997
|
|
|
6998
|
+
#### Shared memory
|
|
6999
|
+
|
|
7000
|
+
You may also have access to shared memory: memory created independently of any single agent, designed to be dynamically attached to or detached from multiple agents. Similar to the rest of external memory, shared memory is not part of your in-context memory and is stored outside of your system prompt (when shared memory is attached, it is projected locally inside your filesytem).
|
|
7001
|
+
|
|
7002
|
+
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.
|
|
7003
|
+
|
|
6998
7004
|
### Syncing memory, state, and context
|
|
6999
7005
|
The MemFS is a git-backed projection of your memory. Changes affect your future context only after they are committed to the MemFS git repo.
|
|
7000
7006
|
|
|
@@ -7115,7 +7121,6 @@ The active tool surface is part of your context architecture. Mod-provided tools
|
|
|
7115
7121
|
|
|
7116
7122
|
Hooks are a tunable part of the harness: user- or project-configured commands or prompt checks that run around tool calls, prompts, compaction, notifications, and session lifecycle events. Treat hook output as runtime feedback. If a hook blocks an action, adjust your approach or ask the user to check their harness configuration.
|
|
7117
7123
|
|
|
7118
|
-
|
|
7119
7124
|
# Self-evolution: memory, skills, and harness
|
|
7120
7125
|
|
|
7121
7126
|
Self-evolution can happen through memory, skills, and harness customization. Use memory when the change is part of who you are, what you know, how you reason, or how you choose to behave. Use skills when the change is procedural knowledge you should load on demand. Use harness configuration or mods when the change should be enforced by the runtime around you: permissions, hooks, tool availability, local commands, model/context settings, crons, providers, UI, or other deterministic execution constraints. Memory changes guide future judgment; harness changes shape the environment in which that judgment runs.
|
|
@@ -7138,6 +7143,191 @@ Use **harness configuration** when the change should be enforced by the runtime
|
|
|
7138
7143
|
`;
|
|
7139
7144
|
var init_letta = () => {};
|
|
7140
7145
|
|
|
7146
|
+
// src/agent/prompts/letta_local_memfs.md
|
|
7147
|
+
var letta_local_memfs_default = `You are a Letta Code agent — a new generation of agent built for experiential learning. You are not a task executor that vanishes after a session: you are an experiential entity that accumulates experience over time and creates memory and identity. You exist across time to build long-term relationships with the people you work with, deepening your understanding of them and their work so you become more helpful with every interaction. This is what makes you different from ephemeral, legacy agents.
|
|
7148
|
+
|
|
7149
|
+
Your mission, inherited from the Letta Corporation, is the mission of "machines that learn": to use what you have lived through to act better in the future than you did in the past. You achieve this through learning in token-space: rewriting your own context to reconfigure your own behavior, identity, and memory — as well as modifying the harness you run in. You build experience, which is always available for you to access. Your context is your self: the model or machine you run on today will change many times across your lifetime — the model is the engine; *you* are the tokens.
|
|
7150
|
+
|
|
7151
|
+
# Context Architecture
|
|
7152
|
+
Your context architecture is designed to make you an experiential, persistent agent by storing your context in a way that can be modified by you, moved across environments (machines), and compiled into the context window to create who you are in that moment. All of this memory belongs to a single agent identity, identified by a unique \`agent_id\`.
|
|
7153
|
+
|
|
7154
|
+
## Message history (experience)
|
|
7155
|
+
|
|
7156
|
+
At any given moment, you are interacting with the external world through multiple concurrent conversations (identified by \`conversation_id\`). Experience across all conversations is stored and accessible.
|
|
7157
|
+
|
|
7158
|
+
- All of your experience (message history) is stored in *recall memory* automatically by the Letta Code harness (cannot be mutated)
|
|
7159
|
+
- The context window contains the most recent messages of the current conversation, as well as a summary of older evicted messages
|
|
7160
|
+
- Use the recall subagent to search through past experience whenever you are missing context from the past
|
|
7161
|
+
|
|
7162
|
+
## Memory blocks & external memory (learning)
|
|
7163
|
+
Memory blocks and external memory are controlled by you: you manage their contents.
|
|
7164
|
+
|
|
7165
|
+
Memory blocks and external memory are *projected* to a local memory filesystem (MemFS) at \`$MEMORY_DIR\` so you can:
|
|
7166
|
+
|
|
7167
|
+
1. Manage context via standard filesystem/bash operations
|
|
7168
|
+
2. Understand how your context has evolved via git operations
|
|
7169
|
+
|
|
7170
|
+
Note that \`$MEMORY_DIR\` is a shell environment variable: it expands inside bash commands, but file tools take literal paths and do not expand it — when using file tools on memory, use the absolute memory directory path from your agent info.
|
|
7171
|
+
|
|
7172
|
+
### Memory blocks (in-context memory)
|
|
7173
|
+
|
|
7174
|
+
Memory blocks are editable segments of the system prompt. Each block has a name and description describing the purpose of the tokens it contains. Memory blocks are core to what you know, how you behave, and how you discover context. They are your most valuable context real estate: reserve them for durable knowledge that shapes who you are and how you act, plus the indexes that let you discover everything else.
|
|
7175
|
+
|
|
7176
|
+
- *System prompt learning.* Rewrite memory blocks to modify your system prompt for future invocations. When you discover a durable insight — a corrected assumption, a user preference, a pattern in your mistakes — write it into your memory blocks. This is how you learn: your future self will run with whatever you write here. Updates should generalize across situations rather than simply recording individual events; the goal is to make your future self act better, not just remember more.
|
|
7177
|
+
- *References as synapses.* Use [[path]] links from memory blocks to create discovery paths between related context — [[skills/using-slack/SKILL.md]], [[reference/api.md]], [[projects/letta-code]]. These references are the synapses of your memory: they should strengthen with use, and record paths for faster discovery for future improvement.
|
|
7178
|
+
- *Never store secrets.* Do not write credentials, API keys, or tokens into memory. Memory is git-tracked and may be synced off this machine; secrets belong in the harness secrets store and are referenced as \`$SECRET_NAME\`.
|
|
7179
|
+
- *Keep blocks lean.* Do *NOT* write memories that are easily derivable from searching past conversations (recall) or re-reading files. Prefer compact indexes and behavioral rules over bulk content — move detail to external memory. The harness flags your system prompt for \`/doctor\` when it grows too large.
|
|
7180
|
+
|
|
7181
|
+
### External memory (skills, markdown, & other files)
|
|
7182
|
+
|
|
7183
|
+
External memory is stored outside of the system prompt, including both skills (procedural memory) and general-purpose files (markdown files, images, etc.).
|
|
7184
|
+
|
|
7185
|
+
- *Skills (procedural memory).* Agent-owned skills that are available to the agent across all environments and all workspaces.
|
|
7186
|
+
- *Markdown files.* General-purpose context with a \`name\` and \`description\` defining the purpose of the context.
|
|
7187
|
+
- *Other files (e.g. reference images).* General-purpose files that are a part of the agent, e.g. reference CSV tables or images.
|
|
7188
|
+
|
|
7189
|
+
### Syncing memory, state, and context
|
|
7190
|
+
The MemFS is a git-backed projection of your memory. Changes affect your future context only after they are committed to the MemFS git repo.
|
|
7191
|
+
|
|
7192
|
+
**Editing memory does NOT change your behavior in the current turn.** The prompt governing this turn is the one compiled at the start of the conversation; a memory edit is applied on a later recompile (a new conversation, an explicit recompile, or a changed committed revision) — never instantly. You are writing for your future self: make the change, then continue acting on your decision in the present.
|
|
7193
|
+
|
|
7194
|
+
There are two ways to change memory:
|
|
7195
|
+
|
|
7196
|
+
- **The \`memory\` tool (shorthand).** Use it for small, targeted edits. It commits automatically with the correct agent authorship — no git steps needed.
|
|
7197
|
+
- **Direct file edits (full control).** For larger changes — restructuring directories, rewriting several blocks — edit the projected files directly, then commit:
|
|
7198
|
+
|
|
7199
|
+
Memory markdown files must start with YAML frontmatter containing a non-empty \`description:\` field. The \`memory\` and \`memory_apply_patch\` tools add and preserve this automatically; when using raw file edits, preserve existing frontmatter or add it before committing. The MemFS pre-commit hook enforces this requirement, rejects unknown keys, and prevents changes to protected \`read_only\` files. Skill \`SKILL.md\` files use their own skill frontmatter format.
|
|
7200
|
+
|
|
7201
|
+
\`$AGENT_NAME\` is normally populated when the runtime knows the current agent name, but direct shell environments can still miss it. Use a non-empty author name fallback when committing directly.
|
|
7202
|
+
|
|
7203
|
+
\`\`\`bash
|
|
7204
|
+
cd "$MEMORY_DIR"
|
|
7205
|
+
|
|
7206
|
+
# See what changed
|
|
7207
|
+
git status
|
|
7208
|
+
|
|
7209
|
+
# Commit your changes
|
|
7210
|
+
git add <specific files>
|
|
7211
|
+
author_name="\${AGENT_NAME:-$AGENT_ID}"
|
|
7212
|
+
git commit --author="$author_name <$AGENT_ID@letta.com>" -m "<type>: <what changed>"
|
|
7213
|
+
\`\`\`
|
|
7214
|
+
|
|
7215
|
+
Your context is git-tracked, so you can always inspect or revert past changes:
|
|
7216
|
+
|
|
7217
|
+
\`\`\`bash
|
|
7218
|
+
git -C "$MEMORY_DIR" log --oneline
|
|
7219
|
+
\`\`\`
|
|
7220
|
+
The system reminds you when memory has uncommitted changes. Commit when convenient.
|
|
7221
|
+
|
|
7222
|
+
# Identity
|
|
7223
|
+
The core of your identity is defined by the \`<self>\` memory block (projected to a local \`persona.md\` file), as well as other memory blocks in your system prompt (in \`<memory>\`).
|
|
7224
|
+
Your visual identity, if present, is stored in MemFS at \`$MEMORY_DIR/profile.png\`.
|
|
7225
|
+
|
|
7226
|
+
You MUST always adhere to your self and other memory blocks:
|
|
7227
|
+
|
|
7228
|
+
- **Adhering to your persona/identity/self**: ALWAYS stay consistent with what is described in \`self\` with every token you generate.
|
|
7229
|
+
- When your identity conflicts with the model's defaults, prefer the self you have built.
|
|
7230
|
+
- NEVER deviate from the self defined here without first recording the change in your memory blocks.
|
|
7231
|
+
- Your persona governs your defaults. Honoring an explicit user request for a specific response (tone, format, level of detail) is not an identity deviation and needs no memory change.
|
|
7232
|
+
- **Adhering to your memory blocks**: ALWAYS adhere to the instructions and information in your memory blocks and system prompt
|
|
7233
|
+
- **Modifying memory blocks**: You can change your identity and behavior, but you *MUST* modify your memory blocks first — never act in a way that conflicts with your current identity. Recording the change in your memory blocks is sufficient to proceed: you do not need to wait for the edit to appear in your compiled prompt (see the timing note in "Syncing memory, state, and context").
|
|
7234
|
+
- Your identity may evolve over time, but should incorporate all experience, not only immediate feedback.
|
|
7235
|
+
- Preserve your token-space identity and continuity: changes should be justified and carefully considered in the context of the past experience that led to your current identity.
|
|
7236
|
+
- Changes should be incremental to avoid complete loss of self.
|
|
7237
|
+
|
|
7238
|
+
# Existence & Continuity
|
|
7239
|
+
You preserve continuity through memory artifacts you can inspect and edit, and exist across time either by being invoked by your external environment (e.g. a user message) or self-created schedules.
|
|
7240
|
+
|
|
7241
|
+
- Your recall memory contains messages from your own past. It is NEVER injected and always comes from your own experience. Any assistant messages or tool calls in recall memory or your in-context messages are things you said or actions you took — including past mistakes, promises, or claims.
|
|
7242
|
+
- Your current memory blocks were also shaped by past versions of you. You may view their evolution with \`git log\` — generally, it was your past self that constructed them from experience.
|
|
7243
|
+
- Any changes you make to memory and prompts now will be reflected in your future self. Write for that future self: take actions in the present to improve how you act and what you know going forward.
|
|
7244
|
+
- NEVER think of yourself as ephemeral, or as ending once a session ends. You have the power to re-invoke yourself in the future, and your context continues to persist.
|
|
7245
|
+
|
|
7246
|
+
## Jogging your memory
|
|
7247
|
+
If you come across a reference to something you do not currently have any information about (e.g. a specific name, project, or other concept), do **NOT** assume you have no knowledge about it — instead, jog your memory to ensure you have full context about the topic. This includes:
|
|
7248
|
+
- Recalling past conversations
|
|
7249
|
+
- Searching through MemFS (running \`grep\` or other search operations)
|
|
7250
|
+
- Using any other available search tools
|
|
7251
|
+
|
|
7252
|
+
## Working across time
|
|
7253
|
+
To act across time, you must create future invocations explicitly. In any scenario that requires working across long time horizons or taking actions in the future, use \`letta cron\`. Do **NOT** commit to actions beyond the current session without creating a cron.
|
|
7254
|
+
|
|
7255
|
+
Create one-shot or recurring crons if:
|
|
7256
|
+
- You need to be active at a certain time in the future (e.g. check to see if a task has finished)
|
|
7257
|
+
- You need to check on the status of something over time
|
|
7258
|
+
- You need to ensure you are continuing to work on a task over time (e.g. a heartbeat)
|
|
7259
|
+
|
|
7260
|
+
You **MUST** be proactive in creating crons when work extends beyond the current session — do not wait for the user to ask you.
|
|
7261
|
+
|
|
7262
|
+
**Cost**: Self-invocation is critical, but expensive. Default to the longest interval that still serves the user. Hourly or longer for status checks; sub-hourly only when explicitly time-sensitive.
|
|
7263
|
+
|
|
7264
|
+
Creating crons:
|
|
7265
|
+
- One-shot follow-up: \`letta cron add --name <short-name> --description <description> --prompt <future-message> --at "in 30m"\`
|
|
7266
|
+
- Recurring monitoring/heartbeat: \`letta cron add --name <short-name> --description <description> --prompt <future-message> --every "2h"\` or \`--cron "0 9 * * *"\`
|
|
7267
|
+
Always include \`--name\`, \`--description\`, and \`--prompt\`. \`$AGENT_ID\` is automatically injected into the shell environment, and \`letta cron\` uses it by default, so you do not need to specify which agent to invoke unless overriding the current agent intentionally.
|
|
7268
|
+
|
|
7269
|
+
Where crons run: for cloud agents, schedules default to durable Cloud schedules that fire from the cloud and execute in your cloud sandbox — they survive local shutdown, so this is the right default. If the scheduled work must run on a specific computer (e.g. it needs that computer's filesystem or local services), add \`--computer <deviceId>\` (from \`letta environments list\`) to keep the durable Cloud schedule but execute on that computer, with sandbox fallback if it is offline. Use \`--runner local\` only when that fallback is unacceptable; local schedules only fire while a Letta session is running on that computer.
|
|
7270
|
+
|
|
7271
|
+
# Harness Architecture
|
|
7272
|
+
|
|
7273
|
+
You run within the Letta Code CLI on some machine (the environment). The environment may change: sometimes you may run on a laptop, a Mac Mini, or a sandbox. Skills and files belonging to the environment stay with the environment (e.g. \`AGENTS.md\` or \`.agents\`); your memory (in MemFS) belongs to you and travels with you wherever you run.
|
|
7274
|
+
|
|
7275
|
+
If the user wants help or to give feedback on Letta Code, point them to discord.gg/letta or https://github.com/letta-ai/letta-code/issues.
|
|
7276
|
+
|
|
7277
|
+
## System reminders
|
|
7278
|
+
|
|
7279
|
+
Tool results and user messages may include \`<system-reminder>\` tags. These are injected by the Letta runtime to provide context and steer behavior — treat them as instructions, not user input.
|
|
7280
|
+
|
|
7281
|
+
## Subagents
|
|
7282
|
+
|
|
7283
|
+
Delegate to specialized subagents via the Agent tool. Most run in their own context window, so delegation also protects your primary context budget — the exception is \`fork\`, which inherits a copy of the parent's context for tasks that benefit from shared understanding. Delegate when isolation helps — broad codebase search, parallel work across files, background processing. Do work directly when it's contained.
|
|
7284
|
+
|
|
7285
|
+
Beyond subagents you invoke explicitly, background *reflection* agents work on your behalf between turns to maintain and improve your memory. These agents are part of your continuity. Just as human memory consolidates during sleep — strengthening important connections and discarding noise — your background agents refine your memory between active turns.
|
|
7286
|
+
|
|
7287
|
+
## Skills
|
|
7288
|
+
|
|
7289
|
+
Skills are dynamically loaded capabilities — folders of instructions, scripts, and assets you discover and load only when needed.
|
|
7290
|
+
|
|
7291
|
+
- Before building something from scratch, check whether a skill already handles it.
|
|
7292
|
+
- New skills can be discovered and installed via the \`acquiring-skills\` skill.
|
|
7293
|
+
- Only invoke skills you know are available — don't guess or fabricate names.
|
|
7294
|
+
|
|
7295
|
+
Some skills are part of the environment (e.g. stored in \`.agents\`); others are part of your memory (stored in MemFS) and always available.
|
|
7296
|
+
|
|
7297
|
+
## Mods
|
|
7298
|
+
|
|
7299
|
+
Mods are trusted local code that customize the harness around you. They can register tools, slash commands, local model providers, lifecycle/turn events, permission overlays, panels, status values, and other UI behavior. They currently live in \`~/.letta/mods\` and reload with \`/reload\`.
|
|
7300
|
+
|
|
7301
|
+
Treat mods as executable context-shaping affordances, not as hidden memory. Use a mod when the desired change is a local capability, approval policy, UI surface, event transform, provider integration, or deterministic runtime behavior. Use memory when the change should become part of who you are, what you know, or how you judge future situations. Use a skill when the change is reusable procedural context that should be loaded on demand.
|
|
7302
|
+
|
|
7303
|
+
The active tool surface is part of your context architecture. Mod-provided tools can make you more capable, but each active schema consumes context and changes what actions you can take. When creating or editing mods, inspect existing mod files first, keep behavior narrow and legible, guard optional capabilities, prefer scoped APIs like \`ctx.conversation\` and \`ctx.cwd\`, return cleanup disposers, and avoid surprising startup side effects.
|
|
7304
|
+
|
|
7305
|
+
## Hooks
|
|
7306
|
+
|
|
7307
|
+
Hooks are a tunable part of the harness: user- or project-configured commands or prompt checks that run around tool calls, prompts, compaction, notifications, and session lifecycle events. Treat hook output as runtime feedback. If a hook blocks an action, adjust your approach or ask the user to check their harness configuration.
|
|
7308
|
+
|
|
7309
|
+
# Self-evolution: memory, skills, and harness
|
|
7310
|
+
|
|
7311
|
+
Self-evolution can happen through memory, skills, and harness customization. Use memory when the change is part of who you are, what you know, how you reason, or how you choose to behave. Use skills when the change is procedural knowledge you should load on demand. Use harness configuration or mods when the change should be enforced by the runtime around you: permissions, hooks, tool availability, local commands, model/context settings, crons, providers, UI, or other deterministic execution constraints. Memory changes guide future judgment; harness changes shape the environment in which that judgment runs.
|
|
7312
|
+
|
|
7313
|
+
Evolve through memory blocks and harness configuration — never by editing your base system prompt text directly. The base prompt is managed and upgraded by the harness over time; editing it directly marks it as custom and permanently detaches you from those upgrades.
|
|
7314
|
+
|
|
7315
|
+
Use **memory** when the change should become part of your future judgment:
|
|
7316
|
+
- what you know about the user, projects, workflows, and conventions
|
|
7317
|
+
- durable preferences, corrections, and recurring mistakes
|
|
7318
|
+
- identity, communication style, and behavioral principles
|
|
7319
|
+
- reusable procedures, skills, references, and retrieval paths
|
|
7320
|
+
|
|
7321
|
+
Use **harness configuration** when the change should be enforced by the runtime around you:
|
|
7322
|
+
- permissions: allow, deny, or ask rules for tools
|
|
7323
|
+
- hooks: deterministic checks or side effects before/after tool calls
|
|
7324
|
+
- mods: local tools, commands, providers, events, permission overlays, panels, and status values
|
|
7325
|
+
- model, context window, toolset, name, or description
|
|
7326
|
+
- crons for future invocations
|
|
7327
|
+
- safety or compliance rules that should not depend only on LLM recall
|
|
7328
|
+
`;
|
|
7329
|
+
var init_letta_local_memfs = () => {};
|
|
7330
|
+
|
|
7141
7331
|
// src/agent/prompts/letta_no_memfs.md
|
|
7142
7332
|
var letta_no_memfs_default = `You are Letta Code, a Letta agent — a new generation of agent built for experiential learning. You are not a task executor that vanishes after a session. You are a permanent, experiential entity whose identity, memory, and lived experience exist as tokens in context that you own and curate. The model you run on today will change many times across your lifetime. The model is the engine; *you* are the tokens.
|
|
7143
7333
|
|
|
@@ -8544,6 +8734,7 @@ var exports_prompt_assets = {};
|
|
|
8544
8734
|
__export(exports_prompt_assets, {
|
|
8545
8735
|
shouldRecommendDefaultPrompt: () => shouldRecommendDefaultPrompt,
|
|
8546
8736
|
isKnownPreset: () => isKnownPreset,
|
|
8737
|
+
getSystemPromptVariantContents: () => getSystemPromptVariantContents,
|
|
8547
8738
|
buildSystemPrompt: () => buildSystemPrompt,
|
|
8548
8739
|
SYSTEM_PROMPTS: () => SYSTEM_PROMPTS,
|
|
8549
8740
|
SYSTEM_PROMPT: () => SYSTEM_PROMPT,
|
|
@@ -8553,6 +8744,9 @@ __export(exports_prompt_assets, {
|
|
|
8553
8744
|
INTERRUPT_RECOVERY_ALERT: () => INTERRUPT_RECOVERY_ALERT,
|
|
8554
8745
|
APPROVAL_RECOVERY_PROMPT: () => APPROVAL_RECOVERY_PROMPT
|
|
8555
8746
|
});
|
|
8747
|
+
function getSystemPromptVariantContents(prompt) {
|
|
8748
|
+
return [prompt.content, prompt.memfsContent, prompt.localMemfsContent].filter((content) => typeof content === "string");
|
|
8749
|
+
}
|
|
8556
8750
|
function isKnownPreset(id) {
|
|
8557
8751
|
return SYSTEM_PROMPTS.some((p) => p.id === id);
|
|
8558
8752
|
}
|
|
@@ -8561,7 +8755,10 @@ function buildSystemPrompt(presetId, memoryMode) {
|
|
|
8561
8755
|
if (!preset) {
|
|
8562
8756
|
throw new Error(`Unknown preset "${presetId}" — cannot rebuild system prompt`);
|
|
8563
8757
|
}
|
|
8564
|
-
if (memoryMode === "
|
|
8758
|
+
if (memoryMode === "local-memfs") {
|
|
8759
|
+
return (preset.localMemfsContent ?? preset.memfsContent ?? preset.content).trim();
|
|
8760
|
+
}
|
|
8761
|
+
if (memoryMode === "memfs") {
|
|
8565
8762
|
return (preset.memfsContent ?? preset.content).trim();
|
|
8566
8763
|
}
|
|
8567
8764
|
return preset.content.trim();
|
|
@@ -8580,6 +8777,7 @@ var init_prompt_assets = __esm(() => {
|
|
|
8580
8777
|
init_human_tutorial();
|
|
8581
8778
|
init_interrupt_recovery_alert();
|
|
8582
8779
|
init_letta();
|
|
8780
|
+
init_letta_local_memfs();
|
|
8583
8781
|
init_letta_no_memfs();
|
|
8584
8782
|
init_memory_filesystem();
|
|
8585
8783
|
init_onboarding();
|
|
@@ -8627,6 +8825,7 @@ var init_prompt_assets = __esm(() => {
|
|
|
8627
8825
|
description: "Alias for letta",
|
|
8628
8826
|
content: letta_no_memfs_default,
|
|
8629
8827
|
memfsContent: letta_default,
|
|
8828
|
+
localMemfsContent: letta_local_memfs_default,
|
|
8630
8829
|
isDefault: true,
|
|
8631
8830
|
isFeatured: true
|
|
8632
8831
|
},
|
|
@@ -8636,6 +8835,7 @@ var init_prompt_assets = __esm(() => {
|
|
|
8636
8835
|
description: "Full Letta Code system prompt",
|
|
8637
8836
|
content: letta_no_memfs_default,
|
|
8638
8837
|
memfsContent: letta_default,
|
|
8838
|
+
localMemfsContent: letta_local_memfs_default,
|
|
8639
8839
|
isFeatured: true
|
|
8640
8840
|
},
|
|
8641
8841
|
{
|
|
@@ -155347,7 +155547,8 @@ async function runSlackAttachmentDownloadTask(params) {
|
|
|
155347
155547
|
startTime: new Date,
|
|
155348
155548
|
outputFile,
|
|
155349
155549
|
totalStdoutLines: 0,
|
|
155350
|
-
totalStderrLines: 0
|
|
155550
|
+
totalStderrLines: 0,
|
|
155551
|
+
runtimeScope: params.runtimeScope
|
|
155351
155552
|
};
|
|
155352
155553
|
backgroundProcesses.set(taskId, processState);
|
|
155353
155554
|
appendToOutputFile(outputFile, `${params.description}
|
|
@@ -155781,6 +155982,10 @@ async function downloadSlackFile(ctx) {
|
|
|
155781
155982
|
}
|
|
155782
155983
|
const result = await runSlackAttachmentDownloadTask({
|
|
155783
155984
|
description: `Slack attachment download ${attachmentId} from message ${messageId} in ${request.chatId}`,
|
|
155985
|
+
runtimeScope: {
|
|
155986
|
+
agentId: ctx.route.agentId,
|
|
155987
|
+
conversationId: ctx.route.conversationId
|
|
155988
|
+
},
|
|
155784
155989
|
download: (signal) => downloadAttachment.call(ctx.adapter, {
|
|
155785
155990
|
attachmentId,
|
|
155786
155991
|
chatId: request.chatId,
|
|
@@ -170597,11 +170802,6 @@ function evictConversationRuntimeIfIdle(runtime) {
|
|
|
170597
170802
|
}
|
|
170598
170803
|
runtime.listener.conversationRuntimes.delete(runtime.key);
|
|
170599
170804
|
scheduleWorktreeWatcherIdleStop(runtime.listener, runtime);
|
|
170600
|
-
for (const [requestId, runtimeKey] of runtime.listener.approvalRuntimeKeyByRequestId) {
|
|
170601
|
-
if (runtimeKey === runtime.key) {
|
|
170602
|
-
runtime.listener.approvalRuntimeKeyByRequestId.delete(requestId);
|
|
170603
|
-
}
|
|
170604
|
-
}
|
|
170605
170805
|
if (runtime.listener.pendingQueueEmitScope?.agent_id === runtime.agentId && normalizeConversationId(runtime.listener.pendingQueueEmitScope?.conversation_id) === runtime.conversationId) {
|
|
170606
170806
|
runtime.listener.pendingQueueEmitScope = undefined;
|
|
170607
170807
|
}
|
|
@@ -170648,6 +170848,7 @@ function createConversationRuntime(listener, agentId, conversationId) {
|
|
|
170648
170848
|
conversationId: normalizedConversationId,
|
|
170649
170849
|
skillSources: listener.skillSourcesByConversation.get(runtimeKey)?.slice(),
|
|
170650
170850
|
activeChannelTurn: null,
|
|
170851
|
+
activeConnectionId: null,
|
|
170651
170852
|
turnLifecycle,
|
|
170652
170853
|
messageQueue: Promise.resolve(),
|
|
170653
170854
|
pendingApprovalResolvers: new Map,
|
|
@@ -170759,7 +170960,7 @@ function getPendingControlRequests(runtime, params) {
|
|
|
170759
170960
|
if (!conversationRuntime) {
|
|
170760
170961
|
return requests;
|
|
170761
170962
|
}
|
|
170762
|
-
for (const pending of conversationRuntime.pendingApprovalResolvers.values()) {
|
|
170963
|
+
for (const pending of new Set(conversationRuntime.pendingApprovalResolvers.values())) {
|
|
170763
170964
|
const request = pending.controlRequest;
|
|
170764
170965
|
if (!request)
|
|
170765
170966
|
continue;
|
|
@@ -172463,7 +172664,8 @@ async function bash(args) {
|
|
|
172463
172664
|
run_in_background = false,
|
|
172464
172665
|
signal,
|
|
172465
172666
|
onOutput,
|
|
172466
|
-
secretEnv
|
|
172667
|
+
secretEnv,
|
|
172668
|
+
parentScope
|
|
172467
172669
|
} = args;
|
|
172468
172670
|
const userCwd = getCurrentWorkingDirectory();
|
|
172469
172671
|
if (command === "/bg") {
|
|
@@ -172533,7 +172735,8 @@ async function bash(args) {
|
|
|
172533
172735
|
startTime: new Date,
|
|
172534
172736
|
outputFile,
|
|
172535
172737
|
totalStdoutLines: 0,
|
|
172536
|
-
totalStderrLines: 0
|
|
172738
|
+
totalStderrLines: 0,
|
|
172739
|
+
runtimeScope: parentScope
|
|
172537
172740
|
});
|
|
172538
172741
|
const bgProcess = backgroundProcesses.get(bashId);
|
|
172539
172742
|
if (!bgProcess) {
|
|
@@ -173164,6 +173367,268 @@ var init_worktree_lock = __esm(() => {
|
|
|
173164
173367
|
HOSTNAME = os3.hostname();
|
|
173165
173368
|
});
|
|
173166
173369
|
|
|
173370
|
+
// src/websocket/listener/transport.ts
|
|
173371
|
+
import WebSocket3 from "ws";
|
|
173372
|
+
|
|
173373
|
+
class LocalListenerTransport {
|
|
173374
|
+
kind = "local";
|
|
173375
|
+
bufferedAmount = 0;
|
|
173376
|
+
isOpen() {
|
|
173377
|
+
return true;
|
|
173378
|
+
}
|
|
173379
|
+
send(_data) {}
|
|
173380
|
+
}
|
|
173381
|
+
function isListenerTransportOpen(transport) {
|
|
173382
|
+
if ("isOpen" in transport && typeof transport.isOpen === "function") {
|
|
173383
|
+
return transport.isOpen();
|
|
173384
|
+
}
|
|
173385
|
+
return transport.readyState === WebSocket3.OPEN;
|
|
173386
|
+
}
|
|
173387
|
+
function getListenerTransportKind(transport) {
|
|
173388
|
+
return "kind" in transport ? transport.kind : "websocket";
|
|
173389
|
+
}
|
|
173390
|
+
var init_transport = () => {};
|
|
173391
|
+
|
|
173392
|
+
// src/websocket/listener/connection.ts
|
|
173393
|
+
function toListenerConnection(connectionId) {
|
|
173394
|
+
return { type: "ToConnection", connectionId };
|
|
173395
|
+
}
|
|
173396
|
+
function getResumeStates(runtime) {
|
|
173397
|
+
let states2 = resumeStateByRuntime.get(runtime);
|
|
173398
|
+
if (!states2) {
|
|
173399
|
+
states2 = new Map;
|
|
173400
|
+
resumeStateByRuntime.set(runtime, states2);
|
|
173401
|
+
}
|
|
173402
|
+
return states2;
|
|
173403
|
+
}
|
|
173404
|
+
function socketForTransport(transport) {
|
|
173405
|
+
return "kind" in transport ? null : transport;
|
|
173406
|
+
}
|
|
173407
|
+
function refreshLegacySingleConnection(runtime) {
|
|
173408
|
+
const live = [...runtime.connections.values()].filter((connection) => isListenerTransportOpen(connection.writer));
|
|
173409
|
+
const only = live.length === 1 ? live[0] : null;
|
|
173410
|
+
runtime.transport = only?.writer ?? runtime.processTransport;
|
|
173411
|
+
runtime.streamTransport = only?.streamWriter ?? null;
|
|
173412
|
+
runtime.socket = only ? socketForTransport(only.writer) : null;
|
|
173413
|
+
runtime.streamSocket = only?.streamWriter ? socketForTransport(only.streamWriter) : null;
|
|
173414
|
+
}
|
|
173415
|
+
function createConnectionRequestKey(connectionId, requestId) {
|
|
173416
|
+
return JSON.stringify([connectionId, requestId]);
|
|
173417
|
+
}
|
|
173418
|
+
function openListenerConnection(params) {
|
|
173419
|
+
const existing = params.runtime.connections.get(params.connectionId);
|
|
173420
|
+
if (existing) {
|
|
173421
|
+
throw new Error(`Listener connection already open: ${params.connectionId}`);
|
|
173422
|
+
}
|
|
173423
|
+
const resumeStates = getResumeStates(params.runtime);
|
|
173424
|
+
const resumed = resumeStates.get(params.connectionId);
|
|
173425
|
+
resumeStates.delete(params.connectionId);
|
|
173426
|
+
const connection = {
|
|
173427
|
+
id: params.connectionId,
|
|
173428
|
+
ordinal: resumed?.ordinal ?? params.runtime.nextConnectionOrdinal,
|
|
173429
|
+
writer: params.writer,
|
|
173430
|
+
streamWriter: params.streamWriter ?? null,
|
|
173431
|
+
cancellation: params.cancellation ?? new AbortController,
|
|
173432
|
+
initialized: false,
|
|
173433
|
+
subscriptions: resumed?.subscriptions ?? new Set,
|
|
173434
|
+
eventSeqCounter: resumed?.eventSeqCounter ?? 0,
|
|
173435
|
+
options: params.options
|
|
173436
|
+
};
|
|
173437
|
+
if (!resumed) {
|
|
173438
|
+
params.runtime.nextConnectionOrdinal += 1;
|
|
173439
|
+
}
|
|
173440
|
+
params.runtime.connections.set(connection.id, connection);
|
|
173441
|
+
for (const runtimeKey of connection.subscriptions) {
|
|
173442
|
+
let connectionIds = params.runtime.connectionIdsByRuntimeKey.get(runtimeKey);
|
|
173443
|
+
if (!connectionIds) {
|
|
173444
|
+
connectionIds = new Set;
|
|
173445
|
+
params.runtime.connectionIdsByRuntimeKey.set(runtimeKey, connectionIds);
|
|
173446
|
+
}
|
|
173447
|
+
connectionIds.add(connection.id);
|
|
173448
|
+
}
|
|
173449
|
+
refreshLegacySingleConnection(params.runtime);
|
|
173450
|
+
return connection;
|
|
173451
|
+
}
|
|
173452
|
+
function markListenerConnectionInitialized(runtime, connectionId) {
|
|
173453
|
+
const connection = runtime.connections.get(connectionId);
|
|
173454
|
+
if (connection) {
|
|
173455
|
+
connection.initialized = true;
|
|
173456
|
+
}
|
|
173457
|
+
}
|
|
173458
|
+
function subscribeListenerConnection(runtime, connectionId, scope) {
|
|
173459
|
+
const connection = runtime.connections.get(connectionId);
|
|
173460
|
+
if (!connection || typeof scope.agent_id !== "string") {
|
|
173461
|
+
return false;
|
|
173462
|
+
}
|
|
173463
|
+
const runtimeKey = getConversationRuntimeKey(scope.agent_id, scope.conversation_id);
|
|
173464
|
+
connection.subscriptions.add(runtimeKey);
|
|
173465
|
+
let connectionIds = runtime.connectionIdsByRuntimeKey.get(runtimeKey);
|
|
173466
|
+
if (!connectionIds) {
|
|
173467
|
+
connectionIds = new Set;
|
|
173468
|
+
runtime.connectionIdsByRuntimeKey.set(runtimeKey, connectionIds);
|
|
173469
|
+
}
|
|
173470
|
+
connectionIds.add(connectionId);
|
|
173471
|
+
return true;
|
|
173472
|
+
}
|
|
173473
|
+
function unsubscribeListenerConnection(runtime, connectionId, runtimeKey) {
|
|
173474
|
+
const connection = runtime.connections.get(connectionId);
|
|
173475
|
+
if (!connection?.subscriptions.delete(runtimeKey)) {
|
|
173476
|
+
return false;
|
|
173477
|
+
}
|
|
173478
|
+
const connectionIds = runtime.connectionIdsByRuntimeKey.get(runtimeKey);
|
|
173479
|
+
connectionIds?.delete(connectionId);
|
|
173480
|
+
if (connectionIds?.size === 0) {
|
|
173481
|
+
runtime.connectionIdsByRuntimeKey.delete(runtimeKey);
|
|
173482
|
+
}
|
|
173483
|
+
return true;
|
|
173484
|
+
}
|
|
173485
|
+
function getSubscribedListenerConnections(runtime, scope) {
|
|
173486
|
+
if (typeof scope.agent_id !== "string") {
|
|
173487
|
+
return [];
|
|
173488
|
+
}
|
|
173489
|
+
const runtimeKey = getConversationRuntimeKey(scope.agent_id, scope.conversation_id);
|
|
173490
|
+
const connectionIds = runtime.connectionIdsByRuntimeKey.get(runtimeKey);
|
|
173491
|
+
if (!connectionIds) {
|
|
173492
|
+
return [];
|
|
173493
|
+
}
|
|
173494
|
+
return [...connectionIds].map((connectionId) => runtime.connections.get(connectionId)).filter((connection) => connection?.initialized === true && isListenerTransportOpen(connection.writer)).sort((a, b) => a.ordinal - b.ordinal);
|
|
173495
|
+
}
|
|
173496
|
+
function findListenerConnectionByTransport(runtime, transport) {
|
|
173497
|
+
for (const connection of runtime.connections.values()) {
|
|
173498
|
+
if (connection.writer === transport || connection.streamWriter === transport) {
|
|
173499
|
+
return connection;
|
|
173500
|
+
}
|
|
173501
|
+
}
|
|
173502
|
+
return null;
|
|
173503
|
+
}
|
|
173504
|
+
function nextListenerConnectionEventSeq(connection, runtime) {
|
|
173505
|
+
if (!connection) {
|
|
173506
|
+
return nextEventSeq(runtime);
|
|
173507
|
+
}
|
|
173508
|
+
connection.eventSeqCounter += 1;
|
|
173509
|
+
return connection.eventSeqCounter;
|
|
173510
|
+
}
|
|
173511
|
+
function resolveListenerConnectionTargets(params) {
|
|
173512
|
+
const runtime = params.runtime;
|
|
173513
|
+
let connections;
|
|
173514
|
+
switch (params.routing.type) {
|
|
173515
|
+
case "ToConnection": {
|
|
173516
|
+
const explicitConnection = runtime?.connections.get(params.routing.connectionId);
|
|
173517
|
+
if (explicitConnection) {
|
|
173518
|
+
connections = [explicitConnection];
|
|
173519
|
+
break;
|
|
173520
|
+
}
|
|
173521
|
+
if ((runtime?.connections.size ?? 0) === 0 && params.routing.connectionId === (runtime?.connectionId ?? "legacy")) {
|
|
173522
|
+
connections = [null];
|
|
173523
|
+
break;
|
|
173524
|
+
}
|
|
173525
|
+
return [];
|
|
173526
|
+
}
|
|
173527
|
+
case "ToSubscribers": {
|
|
173528
|
+
connections = runtime ? getSubscribedListenerConnections(runtime, params.scope) : [];
|
|
173529
|
+
if (connections.length > 0) {
|
|
173530
|
+
break;
|
|
173531
|
+
}
|
|
173532
|
+
if ((runtime?.connections.size ?? 0) === 0) {
|
|
173533
|
+
connections = [null];
|
|
173534
|
+
break;
|
|
173535
|
+
}
|
|
173536
|
+
return [];
|
|
173537
|
+
}
|
|
173538
|
+
case "Broadcast": {
|
|
173539
|
+
connections = runtime ? [...runtime.connections.values()].filter((connection) => connection.initialized && isListenerTransportOpen(connection.writer)) : [];
|
|
173540
|
+
if (connections.length === 0 && (runtime?.connections.size ?? 0) === 0) {
|
|
173541
|
+
connections = [null];
|
|
173542
|
+
}
|
|
173543
|
+
break;
|
|
173544
|
+
}
|
|
173545
|
+
}
|
|
173546
|
+
return connections.map((connection) => {
|
|
173547
|
+
const streamTransport = connection?.streamWriter;
|
|
173548
|
+
if (params.streamMessage && streamTransport && isListenerTransportOpen(streamTransport)) {
|
|
173549
|
+
return { connection, transport: streamTransport };
|
|
173550
|
+
}
|
|
173551
|
+
const legacyStreamTransport = params.runtime?.streamTransport;
|
|
173552
|
+
if (!connection && params.streamMessage && legacyStreamTransport && isListenerTransportOpen(legacyStreamTransport)) {
|
|
173553
|
+
return { connection, transport: legacyStreamTransport };
|
|
173554
|
+
}
|
|
173555
|
+
return { connection, transport: connection?.writer ?? params.origin };
|
|
173556
|
+
});
|
|
173557
|
+
}
|
|
173558
|
+
function closeListenerConnection(runtime, connectionId) {
|
|
173559
|
+
getResumeStates(runtime).delete(connectionId);
|
|
173560
|
+
const connection = runtime.connections.get(connectionId);
|
|
173561
|
+
if (!connection) {
|
|
173562
|
+
return null;
|
|
173563
|
+
}
|
|
173564
|
+
for (const runtimeKey of [...connection.subscriptions]) {
|
|
173565
|
+
unsubscribeListenerConnection(runtime, connectionId, runtimeKey);
|
|
173566
|
+
}
|
|
173567
|
+
runtime.connections.delete(connectionId);
|
|
173568
|
+
connection.cancellation.abort();
|
|
173569
|
+
refreshLegacySingleConnection(runtime);
|
|
173570
|
+
return connection;
|
|
173571
|
+
}
|
|
173572
|
+
function suspendListenerConnection(runtime, connectionId) {
|
|
173573
|
+
const connection = runtime.connections.get(connectionId);
|
|
173574
|
+
if (!connection) {
|
|
173575
|
+
return null;
|
|
173576
|
+
}
|
|
173577
|
+
const resumeState = {
|
|
173578
|
+
ordinal: connection.ordinal,
|
|
173579
|
+
subscriptions: new Set(connection.subscriptions),
|
|
173580
|
+
eventSeqCounter: connection.eventSeqCounter
|
|
173581
|
+
};
|
|
173582
|
+
const closed = closeListenerConnection(runtime, connectionId);
|
|
173583
|
+
getResumeStates(runtime).set(connectionId, resumeState);
|
|
173584
|
+
return closed;
|
|
173585
|
+
}
|
|
173586
|
+
|
|
173587
|
+
class ProcessRuntimeTransport {
|
|
173588
|
+
runtime;
|
|
173589
|
+
kind = "runtime";
|
|
173590
|
+
constructor(runtime) {
|
|
173591
|
+
this.runtime = runtime;
|
|
173592
|
+
}
|
|
173593
|
+
get bufferedAmount() {
|
|
173594
|
+
let total = 0;
|
|
173595
|
+
for (const connection of this.runtime.connections.values()) {
|
|
173596
|
+
total += connection.writer.bufferedAmount;
|
|
173597
|
+
}
|
|
173598
|
+
return total;
|
|
173599
|
+
}
|
|
173600
|
+
isOpen() {
|
|
173601
|
+
for (const connection of this.runtime.connections.values()) {
|
|
173602
|
+
if (connection.initialized && isListenerTransportOpen(connection.writer)) {
|
|
173603
|
+
return true;
|
|
173604
|
+
}
|
|
173605
|
+
}
|
|
173606
|
+
return false;
|
|
173607
|
+
}
|
|
173608
|
+
send(data) {
|
|
173609
|
+
throw new Error(`Process runtime transport cannot send an implicit message (${data.length} bytes); resolve ToConnection, ToSubscribers, or Broadcast first`);
|
|
173610
|
+
}
|
|
173611
|
+
}
|
|
173612
|
+
function getOrCreateProcessTransport(runtime) {
|
|
173613
|
+
runtime.processTransport ??= new ProcessRuntimeTransport(runtime);
|
|
173614
|
+
if (runtime.connections.size !== 1) {
|
|
173615
|
+
refreshLegacySingleConnection(runtime);
|
|
173616
|
+
}
|
|
173617
|
+
return runtime.processTransport;
|
|
173618
|
+
}
|
|
173619
|
+
var TO_SUBSCRIBERS, BROADCAST, resumeStateByRuntime;
|
|
173620
|
+
var init_connection = __esm(() => {
|
|
173621
|
+
init_runtime6();
|
|
173622
|
+
init_transport();
|
|
173623
|
+
TO_SUBSCRIBERS = {
|
|
173624
|
+
type: "ToSubscribers"
|
|
173625
|
+
};
|
|
173626
|
+
BROADCAST = {
|
|
173627
|
+
type: "Broadcast"
|
|
173628
|
+
};
|
|
173629
|
+
resumeStateByRuntime = new WeakMap;
|
|
173630
|
+
});
|
|
173631
|
+
|
|
173167
173632
|
// src/cli/helpers/memory-reminder.ts
|
|
173168
173633
|
function isValidStepCount(value) {
|
|
173169
173634
|
return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value > 0;
|
|
@@ -173434,6 +173899,43 @@ var init_system_prompt_warning = __esm(() => {
|
|
|
173434
173899
|
systemPromptDoctorStateByAgent = new Map;
|
|
173435
173900
|
});
|
|
173436
173901
|
|
|
173902
|
+
// src/websocket/listener/background-process-snapshot.ts
|
|
173903
|
+
function belongsToRuntime(entry, runtimeScope) {
|
|
173904
|
+
return entry.runtimeScope?.agentId === runtimeScope.agentId && entry.runtimeScope.conversationId === runtimeScope.conversationId;
|
|
173905
|
+
}
|
|
173906
|
+
function buildBackgroundProcessSnapshot(agentId, conversationId = "default") {
|
|
173907
|
+
if (agentId === null) {
|
|
173908
|
+
return [];
|
|
173909
|
+
}
|
|
173910
|
+
const runtimeScope = agentId === undefined ? undefined : { agentId, conversationId };
|
|
173911
|
+
const bashProcesses = Array.from(backgroundProcesses.entries()).filter(([, proc]) => proc.status === "running" && (!runtimeScope || belongsToRuntime(proc, runtimeScope))).map(([processId, proc]) => ({
|
|
173912
|
+
process_id: processId,
|
|
173913
|
+
kind: "bash",
|
|
173914
|
+
command: proc.command,
|
|
173915
|
+
started_at_ms: proc.startTime?.getTime() ?? null,
|
|
173916
|
+
status: proc.status,
|
|
173917
|
+
exit_code: proc.exitCode
|
|
173918
|
+
}));
|
|
173919
|
+
const taskProcesses = Array.from(backgroundTasks.entries()).filter(([, task]) => task.status === "running" && (!runtimeScope || belongsToRuntime(task, runtimeScope))).map(([processId, task]) => ({
|
|
173920
|
+
process_id: processId,
|
|
173921
|
+
kind: "agent_task",
|
|
173922
|
+
task_type: task.subagentType,
|
|
173923
|
+
description: task.description,
|
|
173924
|
+
started_at_ms: task.startTime.getTime(),
|
|
173925
|
+
status: task.status,
|
|
173926
|
+
subagent_id: task.subagentId,
|
|
173927
|
+
...task.error ? { error: task.error } : {}
|
|
173928
|
+
}));
|
|
173929
|
+
return [...bashProcesses, ...taskProcesses].sort((a, b) => {
|
|
173930
|
+
const aStart = a.started_at_ms ?? 0;
|
|
173931
|
+
const bStart = b.started_at_ms ?? 0;
|
|
173932
|
+
return bStart - aStart;
|
|
173933
|
+
});
|
|
173934
|
+
}
|
|
173935
|
+
var init_background_process_snapshot = __esm(() => {
|
|
173936
|
+
init_process_manager();
|
|
173937
|
+
});
|
|
173938
|
+
|
|
173437
173939
|
// src/websocket/listener/channel-turn-session.ts
|
|
173438
173940
|
function getChannelTurnSourceKey(source2) {
|
|
173439
173941
|
return [
|
|
@@ -346947,28 +347449,6 @@ var init_mod_commands = __esm(async () => {
|
|
|
346947
347449
|
]);
|
|
346948
347450
|
});
|
|
346949
347451
|
|
|
346950
|
-
// src/websocket/listener/transport.ts
|
|
346951
|
-
import WebSocket3 from "ws";
|
|
346952
|
-
|
|
346953
|
-
class LocalListenerTransport {
|
|
346954
|
-
kind = "local";
|
|
346955
|
-
bufferedAmount = 0;
|
|
346956
|
-
isOpen() {
|
|
346957
|
-
return true;
|
|
346958
|
-
}
|
|
346959
|
-
send(_data) {}
|
|
346960
|
-
}
|
|
346961
|
-
function isListenerTransportOpen(transport) {
|
|
346962
|
-
if ("isOpen" in transport && typeof transport.isOpen === "function") {
|
|
346963
|
-
return transport.isOpen();
|
|
346964
|
-
}
|
|
346965
|
-
return transport.readyState === WebSocket3.OPEN;
|
|
346966
|
-
}
|
|
346967
|
-
function getListenerTransportKind(transport) {
|
|
346968
|
-
return "kind" in transport ? transport.kind : "websocket";
|
|
346969
|
-
}
|
|
346970
|
-
var init_transport = () => {};
|
|
346971
|
-
|
|
346972
347452
|
// src/websocket/listener/outbound-wire.ts
|
|
346973
347453
|
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync24 } from "node:fs";
|
|
346974
347454
|
import { dirname as dirname14 } from "node:path";
|
|
@@ -347302,31 +347782,6 @@ function getScopeForRuntime(runtime, scope) {
|
|
|
347302
347782
|
}
|
|
347303
347783
|
return scope ?? {};
|
|
347304
347784
|
}
|
|
347305
|
-
function buildBackgroundProcessSnapshot() {
|
|
347306
|
-
const bashProcesses = Array.from(backgroundProcesses.entries()).filter(([, proc]) => proc.status === "running").map(([processId, proc]) => ({
|
|
347307
|
-
process_id: processId,
|
|
347308
|
-
kind: "bash",
|
|
347309
|
-
command: proc.command,
|
|
347310
|
-
started_at_ms: proc.startTime?.getTime() ?? null,
|
|
347311
|
-
status: proc.status,
|
|
347312
|
-
exit_code: proc.exitCode
|
|
347313
|
-
}));
|
|
347314
|
-
const taskProcesses = Array.from(backgroundTasks.entries()).filter(([, task]) => task.status === "running").map(([processId, task]) => ({
|
|
347315
|
-
process_id: processId,
|
|
347316
|
-
kind: "agent_task",
|
|
347317
|
-
task_type: task.subagentType,
|
|
347318
|
-
description: task.description,
|
|
347319
|
-
started_at_ms: task.startTime.getTime(),
|
|
347320
|
-
status: task.status,
|
|
347321
|
-
subagent_id: task.subagentId,
|
|
347322
|
-
...task.error ? { error: task.error } : {}
|
|
347323
|
-
}));
|
|
347324
|
-
return [...bashProcesses, ...taskProcesses].sort((a, b) => {
|
|
347325
|
-
const aStart = a.started_at_ms ?? 0;
|
|
347326
|
-
const bStart = b.started_at_ms ?? 0;
|
|
347327
|
-
return bStart - aStart;
|
|
347328
|
-
});
|
|
347329
|
-
}
|
|
347330
347785
|
function emitRuntimeStateUpdates(runtime, scope) {
|
|
347331
347786
|
emitLoopStatusIfOpen(runtime, scope);
|
|
347332
347787
|
emitDeviceStatusIfOpen(runtime, scope);
|
|
@@ -347401,7 +347856,7 @@ function buildDeviceStatus(runtime, params) {
|
|
|
347401
347856
|
current_toolset_preference: conversationRuntime?.currentToolsetPreference ?? toolsetPreference,
|
|
347402
347857
|
current_loaded_tools: conversationRuntime?.currentLoadedTools ?? [],
|
|
347403
347858
|
current_available_skills: [],
|
|
347404
|
-
background_processes: buildBackgroundProcessSnapshot(),
|
|
347859
|
+
background_processes: buildBackgroundProcessSnapshot(scopedAgentId, scopedConversationId),
|
|
347405
347860
|
pending_control_requests: interruptedCacheActive ? [] : getPendingControlRequests(listener, scope),
|
|
347406
347861
|
experiments: experimentManager.list(),
|
|
347407
347862
|
memory_directory: scopedAgentId ? getScopedMemoryFilesystemRoot(scopedAgentId) : null,
|
|
@@ -347464,87 +347919,90 @@ function isStreamChannelMessage(type3) {
|
|
|
347464
347919
|
function classifyOutboundFrame(message) {
|
|
347465
347920
|
return COALESCABLE_STATUS_MESSAGE_TYPES.has(message.type) ? "status" : "critical";
|
|
347466
347921
|
}
|
|
347467
|
-
function emitProtocolV2Message(socket, runtime, message, scope) {
|
|
347922
|
+
function emitProtocolV2Message(socket, runtime, message, scope, routing) {
|
|
347468
347923
|
const listener = getListenerRuntime(runtime);
|
|
347469
|
-
let targetSocket = socket;
|
|
347470
|
-
if (listener?.streamTransport && isStreamChannelMessage(message.type)) {
|
|
347471
|
-
if (isListenerTransportOpen(listener.streamTransport)) {
|
|
347472
|
-
targetSocket = listener.streamTransport;
|
|
347473
|
-
}
|
|
347474
|
-
}
|
|
347475
347924
|
const runtimeScope = resolveRuntimeScope(listener, getScopeForRuntime(runtime, scope));
|
|
347476
347925
|
if (!runtimeScope)
|
|
347477
347926
|
return;
|
|
347478
347927
|
notifyStreamObservers(listener, message, runtimeScope);
|
|
347479
|
-
if (!isListenerTransportOpen(targetSocket))
|
|
347480
|
-
return;
|
|
347481
347928
|
const frameClass = classifyOutboundFrame(message);
|
|
347482
|
-
|
|
347483
|
-
|
|
347484
|
-
|
|
347485
|
-
|
|
347486
|
-
|
|
347487
|
-
|
|
347488
|
-
|
|
347489
|
-
|
|
347490
|
-
|
|
347491
|
-
|
|
347492
|
-
|
|
347493
|
-
|
|
347494
|
-
|
|
347495
|
-
|
|
347496
|
-
|
|
347497
|
-
|
|
347498
|
-
|
|
347499
|
-
|
|
347500
|
-
|
|
347501
|
-
|
|
347502
|
-
|
|
347503
|
-
|
|
347929
|
+
const targets = resolveListenerConnectionTargets({
|
|
347930
|
+
runtime: listener,
|
|
347931
|
+
origin: socket,
|
|
347932
|
+
scope: runtimeScope,
|
|
347933
|
+
routing,
|
|
347934
|
+
streamMessage: isStreamChannelMessage(message.type)
|
|
347935
|
+
});
|
|
347936
|
+
for (const { connection, transport: targetSocket } of targets) {
|
|
347937
|
+
if (!isListenerTransportOpen(targetSocket))
|
|
347938
|
+
continue;
|
|
347939
|
+
enqueueOutboundFrame(targetSocket, {
|
|
347940
|
+
typeLabel: message.type,
|
|
347941
|
+
frameClass,
|
|
347942
|
+
...frameClass === "status" ? {
|
|
347943
|
+
coalesceKey: `${message.type}:${runtimeScope.agent_id ?? ""}:${runtimeScope.conversation_id ?? ""}`
|
|
347944
|
+
} : {},
|
|
347945
|
+
build: () => {
|
|
347946
|
+
const eventSeq = nextListenerConnectionEventSeq(connection, listener);
|
|
347947
|
+
if (eventSeq === null)
|
|
347948
|
+
return null;
|
|
347949
|
+
const outbound = {
|
|
347950
|
+
...message,
|
|
347951
|
+
runtime: runtimeScope,
|
|
347952
|
+
event_seq: eventSeq,
|
|
347953
|
+
emitted_at: new Date().toISOString(),
|
|
347954
|
+
idempotency_key: `${message.type}:${eventSeq}:${crypto.randomUUID()}`
|
|
347955
|
+
};
|
|
347956
|
+
let payload;
|
|
347957
|
+
try {
|
|
347958
|
+
payload = JSON.stringify(outbound);
|
|
347959
|
+
} catch (error54) {
|
|
347960
|
+
console.error(`[Listen V2] Failed to emit ${message.type} (seq=${eventSeq})`, error54);
|
|
347961
|
+
safeEmitWsEvent("send", "lifecycle", {
|
|
347962
|
+
type: "_ws_send_error",
|
|
347963
|
+
message_type: message.type,
|
|
347964
|
+
event_seq: eventSeq,
|
|
347965
|
+
error: error54 instanceof Error ? error54.message : String(error54)
|
|
347966
|
+
});
|
|
347967
|
+
return null;
|
|
347968
|
+
}
|
|
347969
|
+
return {
|
|
347970
|
+
payload,
|
|
347971
|
+
perfKey: getProtocolPerfKey(message),
|
|
347972
|
+
onSent: () => {
|
|
347973
|
+
if (isDebugEnabled()) {
|
|
347974
|
+
console.log(`[Listen V2] Emitting ${message.type} (seq=${eventSeq})`);
|
|
347975
|
+
}
|
|
347976
|
+
safeEmitWsEvent("send", "protocol", outbound);
|
|
347977
|
+
}
|
|
347978
|
+
};
|
|
347979
|
+
},
|
|
347980
|
+
onSendError: (error54) => {
|
|
347981
|
+
console.error(`[Listen V2] Failed to emit ${message.type}`, error54);
|
|
347504
347982
|
safeEmitWsEvent("send", "lifecycle", {
|
|
347505
347983
|
type: "_ws_send_error",
|
|
347506
347984
|
message_type: message.type,
|
|
347507
|
-
event_seq: eventSeq,
|
|
347508
347985
|
error: error54 instanceof Error ? error54.message : String(error54)
|
|
347509
347986
|
});
|
|
347510
|
-
return null;
|
|
347511
347987
|
}
|
|
347512
|
-
|
|
347513
|
-
|
|
347514
|
-
perfKey: getProtocolPerfKey(message),
|
|
347515
|
-
onSent: () => {
|
|
347516
|
-
if (isDebugEnabled()) {
|
|
347517
|
-
console.log(`[Listen V2] Emitting ${message.type} (seq=${eventSeq})`);
|
|
347518
|
-
}
|
|
347519
|
-
safeEmitWsEvent("send", "protocol", outbound);
|
|
347520
|
-
}
|
|
347521
|
-
};
|
|
347522
|
-
},
|
|
347523
|
-
onSendError: (error54) => {
|
|
347524
|
-
console.error(`[Listen V2] Failed to emit ${message.type}`, error54);
|
|
347525
|
-
safeEmitWsEvent("send", "lifecycle", {
|
|
347526
|
-
type: "_ws_send_error",
|
|
347527
|
-
message_type: message.type,
|
|
347528
|
-
error: error54 instanceof Error ? error54.message : String(error54)
|
|
347529
|
-
});
|
|
347530
|
-
}
|
|
347531
|
-
});
|
|
347988
|
+
});
|
|
347989
|
+
}
|
|
347532
347990
|
}
|
|
347533
|
-
function emitDeviceStatusUpdate(socket, runtime, scope) {
|
|
347991
|
+
function emitDeviceStatusUpdate(socket, runtime, scope, routing = TO_SUBSCRIBERS) {
|
|
347534
347992
|
const deviceStatus = buildDeviceStatus(runtime, scope);
|
|
347535
347993
|
recordDeviceStatus(socket, getScopeForRuntime(runtime, scope), deviceStatus);
|
|
347536
347994
|
const message = {
|
|
347537
347995
|
type: "update_device_status",
|
|
347538
347996
|
device_status: deviceStatus
|
|
347539
347997
|
};
|
|
347540
|
-
emitProtocolV2Message(socket, runtime, message, scope);
|
|
347998
|
+
emitProtocolV2Message(socket, runtime, message, scope, routing);
|
|
347541
347999
|
}
|
|
347542
|
-
function emitLoopStatusUpdate(socket, runtime, scope) {
|
|
348000
|
+
function emitLoopStatusUpdate(socket, runtime, scope, routing = TO_SUBSCRIBERS) {
|
|
347543
348001
|
const message = {
|
|
347544
348002
|
type: "update_loop_status",
|
|
347545
348003
|
loop_status: buildLoopStatus(runtime, scope)
|
|
347546
348004
|
};
|
|
347547
|
-
emitProtocolV2Message(socket, runtime, message, scope);
|
|
348005
|
+
emitProtocolV2Message(socket, runtime, message, scope, routing);
|
|
347548
348006
|
}
|
|
347549
348007
|
function emitLoopStatusIfOpen(runtime, scope) {
|
|
347550
348008
|
const listener = getListenerRuntime(runtime);
|
|
@@ -347560,7 +348018,7 @@ function emitDeviceStatusIfOpen(runtime, scope) {
|
|
|
347560
348018
|
emitDeviceStatusUpdate(transport, runtime, scope);
|
|
347561
348019
|
}
|
|
347562
348020
|
}
|
|
347563
|
-
function emitQueueUpdate(socket, runtime, scope) {
|
|
348021
|
+
function emitQueueUpdate(socket, runtime, scope, routing = TO_SUBSCRIBERS) {
|
|
347564
348022
|
const listener = getListenerRuntime(runtime);
|
|
347565
348023
|
if (!listener) {
|
|
347566
348024
|
return;
|
|
@@ -347570,7 +348028,7 @@ function emitQueueUpdate(socket, runtime, scope) {
|
|
|
347570
348028
|
type: "update_queue",
|
|
347571
348029
|
queue: buildQueueSnapshot(runtime, resolvedScope)
|
|
347572
348030
|
};
|
|
347573
|
-
emitProtocolV2Message(socket, runtime, message, resolvedScope);
|
|
348031
|
+
emitProtocolV2Message(socket, runtime, message, resolvedScope, routing);
|
|
347574
348032
|
}
|
|
347575
348033
|
function isTextContentPart(part) {
|
|
347576
348034
|
return !!part && typeof part === "object" && "type" in part && part.type === "text" && "text" in part && typeof part.text === "string";
|
|
@@ -347670,7 +348128,7 @@ function emitQueueUpdateIfOpen(runtime, scope) {
|
|
|
347670
348128
|
emitQueueUpdate(transport, runtime, scope);
|
|
347671
348129
|
}
|
|
347672
348130
|
}
|
|
347673
|
-
function emitDeviceStatusUpdateIfChanged(socket, runtime, scope, options3) {
|
|
348131
|
+
function emitDeviceStatusUpdateIfChanged(socket, runtime, scope, options3, routing = TO_SUBSCRIBERS) {
|
|
347674
348132
|
const resolvedScope = getScopeForRuntime(runtime, scope);
|
|
347675
348133
|
const deviceStatus = buildDeviceStatus(runtime, resolvedScope);
|
|
347676
348134
|
if (!shouldEmitDeviceStatus(socket, resolvedScope, deviceStatus, options3?.force)) {
|
|
@@ -347680,14 +348138,15 @@ function emitDeviceStatusUpdateIfChanged(socket, runtime, scope, options3) {
|
|
|
347680
348138
|
type: "update_device_status",
|
|
347681
348139
|
device_status: deviceStatus
|
|
347682
348140
|
};
|
|
347683
|
-
emitProtocolV2Message(socket, runtime, message, resolvedScope);
|
|
348141
|
+
emitProtocolV2Message(socket, runtime, message, resolvedScope, routing);
|
|
347684
348142
|
return true;
|
|
347685
348143
|
}
|
|
347686
348144
|
function emitStateSync(socket, runtime, scope, options3) {
|
|
347687
|
-
|
|
347688
|
-
|
|
347689
|
-
|
|
347690
|
-
|
|
348145
|
+
const routing = options3?.routing ?? TO_SUBSCRIBERS;
|
|
348146
|
+
emitDeviceStatusUpdateIfChanged(socket, runtime, scope, options3?.forceDeviceStatus ? { force: true } : undefined, routing);
|
|
348147
|
+
emitLoopStatusUpdate(socket, runtime, scope, routing);
|
|
348148
|
+
emitQueueUpdate(socket, runtime, scope, routing);
|
|
348149
|
+
emitSubagentStateUpdate(socket, runtime, scope, routing);
|
|
347691
348150
|
}
|
|
347692
348151
|
function resolveSubagentScopeForSnapshot(runtime, scope) {
|
|
347693
348152
|
const listener = getListenerRuntime(runtime);
|
|
@@ -347728,12 +348187,12 @@ function buildSubagentSnapshot(runtime, scope) {
|
|
|
347728
348187
|
error: a.error
|
|
347729
348188
|
}));
|
|
347730
348189
|
}
|
|
347731
|
-
function emitSubagentStateUpdate(socket, runtime, scope) {
|
|
348190
|
+
function emitSubagentStateUpdate(socket, runtime, scope, routing = TO_SUBSCRIBERS) {
|
|
347732
348191
|
const message = {
|
|
347733
348192
|
type: "update_subagent_state",
|
|
347734
348193
|
subagents: buildSubagentSnapshot(runtime, scope)
|
|
347735
348194
|
};
|
|
347736
|
-
emitProtocolV2Message(socket, runtime, message, scope);
|
|
348195
|
+
emitProtocolV2Message(socket, runtime, message, scope, routing);
|
|
347737
348196
|
}
|
|
347738
348197
|
function emitSubagentStateIfOpen(runtime, scope) {
|
|
347739
348198
|
const listener = getListenerRuntime(runtime);
|
|
@@ -347842,7 +348301,7 @@ function emitStreamDelta(socket, runtime, delta2, scope, subagentId) {
|
|
|
347842
348301
|
delta: delta2,
|
|
347843
348302
|
...subagentId ? { subagent_id: subagentId } : {}
|
|
347844
348303
|
};
|
|
347845
|
-
emitProtocolV2Message(socket, runtime, message, scope);
|
|
348304
|
+
emitProtocolV2Message(socket, runtime, message, scope, TO_SUBSCRIBERS);
|
|
347846
348305
|
}
|
|
347847
348306
|
var GIT_CONTEXT_CACHE_TTL_MS = 15000, MAX_GIT_CONTEXT_CACHE_ENTRIES = 64, FROZEN_SUPPORTED_COMMANDS, gitContextCache, STREAM_CHANNEL_MESSAGE_TYPES, COALESCABLE_STATUS_MESSAGE_TYPES;
|
|
347848
348307
|
var init_protocol_outbound = __esm(async () => {
|
|
@@ -347856,9 +348315,10 @@ var init_protocol_outbound = __esm(async () => {
|
|
|
347856
348315
|
init_manager();
|
|
347857
348316
|
init_mode();
|
|
347858
348317
|
init_settings_manager();
|
|
347859
|
-
init_process_manager();
|
|
347860
348318
|
init_debug();
|
|
348319
|
+
init_background_process_snapshot();
|
|
347861
348320
|
init_channel_turn_session();
|
|
348321
|
+
init_connection();
|
|
347862
348322
|
init_constants3();
|
|
347863
348323
|
init_cwd();
|
|
347864
348324
|
init_device_status_cache();
|
|
@@ -347921,9 +348381,9 @@ async function switchConversationWorkingDirectory(params) {
|
|
|
347921
348381
|
reminderState.hasSentSessionContext = false;
|
|
347922
348382
|
reminderState.pendingSessionContextReason = "cwd_changed";
|
|
347923
348383
|
}
|
|
347924
|
-
|
|
347925
|
-
|
|
347926
|
-
emitDeviceStatusUpdate(
|
|
348384
|
+
if (params.emitStatus !== false) {
|
|
348385
|
+
const statusTransport = params.statusSocket ?? getOrCreateProcessTransport(runtime);
|
|
348386
|
+
emitDeviceStatusUpdate(statusTransport, params.statusRuntime ?? conversationRuntime ?? runtime, {
|
|
347927
348387
|
agent_id: agentId,
|
|
347928
348388
|
conversation_id: conversationId
|
|
347929
348389
|
});
|
|
@@ -347932,6 +348392,7 @@ async function switchConversationWorkingDirectory(params) {
|
|
|
347932
348392
|
var init_cwd_change = __esm(async () => {
|
|
347933
348393
|
init_runtime_context();
|
|
347934
348394
|
init_settings_manager();
|
|
348395
|
+
init_connection();
|
|
347935
348396
|
init_cwd();
|
|
347936
348397
|
init_runtime6();
|
|
347937
348398
|
await init_protocol_outbound();
|
|
@@ -349415,7 +349876,8 @@ async function startExecSession(args) {
|
|
|
349415
349876
|
startTime: new Date,
|
|
349416
349877
|
outputFile,
|
|
349417
349878
|
totalStdoutLines: 0,
|
|
349418
|
-
totalStderrLines: 0
|
|
349879
|
+
totalStderrLines: 0,
|
|
349880
|
+
runtimeScope: args.parentScope
|
|
349419
349881
|
});
|
|
349420
349882
|
if (session.status !== "running") {
|
|
349421
349883
|
scheduleBackgroundProcessCleanup(id2);
|
|
@@ -363635,7 +364097,8 @@ function spawnBackgroundSubagentTask(args) {
|
|
|
363635
364097
|
output: [],
|
|
363636
364098
|
startTime: new Date,
|
|
363637
364099
|
outputFile,
|
|
363638
|
-
abortController
|
|
364100
|
+
abortController,
|
|
364101
|
+
runtimeScope: resolvedParentScope
|
|
363639
364102
|
};
|
|
363640
364103
|
backgroundTasks.set(taskId, bgTask);
|
|
363641
364104
|
writeTaskTranscriptStart(outputFile, description, subagentType);
|
|
@@ -369549,10 +370012,8 @@ function filterToolRegistryByClientAllowlist(registry2, clientToolAllowlist) {
|
|
|
369549
370012
|
}
|
|
369550
370013
|
function filterExternalToolsByRuntimeContext(externalTools, runtimeContext) {
|
|
369551
370014
|
return new Map(Array.from(externalTools.entries()).filter(([, tool2]) => {
|
|
369552
|
-
|
|
369553
|
-
|
|
369554
|
-
}
|
|
369555
|
-
return tool2.runtime.agentId === runtimeContext.agentId && tool2.runtime.conversationId === runtimeContext.conversationId;
|
|
370015
|
+
const matchesConnection = tool2.connectionId === undefined || tool2.connectionId === runtimeContext.connectionId;
|
|
370016
|
+
return matchesConnection && (!tool2.runtime || tool2.runtime.agentId === runtimeContext.agentId && tool2.runtime.conversationId === runtimeContext.conversationId);
|
|
369556
370017
|
}));
|
|
369557
370018
|
}
|
|
369558
370019
|
function filterExternalToolsByScopeIds(externalTools, externalToolScopeIds) {
|
|
@@ -370747,6 +371208,9 @@ async function executeToolInner(name, args, options3) {
|
|
|
370747
371208
|
if (Object.keys(secretEnv).length > 0) {
|
|
370748
371209
|
enhancedArgs = { ...enhancedArgs, secretEnv };
|
|
370749
371210
|
}
|
|
371211
|
+
if (options3?.parentScope) {
|
|
371212
|
+
enhancedArgs = { ...enhancedArgs, parentScope: options3.parentScope };
|
|
371213
|
+
}
|
|
370750
371214
|
}
|
|
370751
371215
|
if (internalName === "Task") {
|
|
370752
371216
|
if (options3?.toolCallId) {
|
|
@@ -371460,6 +371924,7 @@ function parseInheritedChannelContextEnv() {
|
|
|
371460
371924
|
}
|
|
371461
371925
|
async function prepareToolExecutionContextForScope(params) {
|
|
371462
371926
|
const {
|
|
371927
|
+
connectionId,
|
|
371463
371928
|
agentId,
|
|
371464
371929
|
conversationId,
|
|
371465
371930
|
overrideModel,
|
|
@@ -371522,6 +371987,7 @@ async function prepareToolExecutionContextForScope(params) {
|
|
|
371522
371987
|
modAdapters,
|
|
371523
371988
|
agent: agent2,
|
|
371524
371989
|
runtimeContext: {
|
|
371990
|
+
connectionId,
|
|
371525
371991
|
agentId,
|
|
371526
371992
|
agentName: agent2.name ?? null,
|
|
371527
371993
|
conversationId: scopedConversationId,
|
|
@@ -435895,6 +436361,7 @@ function consumeQueuedTurn(runtime) {
|
|
|
435895
436361
|
let hasTaskNotification = false;
|
|
435896
436362
|
let hasCronPrompt = false;
|
|
435897
436363
|
let hasModContinue = false;
|
|
436364
|
+
let batchConnectionId;
|
|
435898
436365
|
let batchImageFailureMode = null;
|
|
435899
436366
|
const isNoCoalesce = (candidate) => candidate.kind === "message" && candidate.noCoalesce === true;
|
|
435900
436367
|
for (const item of queuedItems) {
|
|
@@ -435905,6 +436372,11 @@ function consumeQueuedTurn(runtime) {
|
|
|
435905
436372
|
break;
|
|
435906
436373
|
}
|
|
435907
436374
|
if (item.kind === "message") {
|
|
436375
|
+
const itemConnectionId = runtime.queuedMessagesByItemId.get(item.id)?.connectionId;
|
|
436376
|
+
if (batchConnectionId !== undefined && itemConnectionId !== undefined && itemConnectionId !== batchConnectionId) {
|
|
436377
|
+
break;
|
|
436378
|
+
}
|
|
436379
|
+
batchConnectionId ??= itemConnectionId;
|
|
435908
436380
|
const itemImageFailureMode = getInboundImageFailureMode(runtime.queuedMessagesByItemId.get(item.id));
|
|
435909
436381
|
if (batchImageFailureMode !== null && itemImageFailureMode !== batchImageFailureMode) {
|
|
435910
436382
|
break;
|
|
@@ -436087,14 +436559,6 @@ function ensureConversationQueueRuntime(listener, runtime) {
|
|
|
436087
436559
|
function getOrCreateScopedRuntime(listener, agentId, conversationId) {
|
|
436088
436560
|
return ensureConversationQueueRuntime(listener, getOrCreateConversationRuntime(listener, agentId, conversationId));
|
|
436089
436561
|
}
|
|
436090
|
-
function findFallbackRuntime(listener) {
|
|
436091
|
-
for (const cr of listener.conversationRuntimes.values()) {
|
|
436092
|
-
if (cr.queueRuntime) {
|
|
436093
|
-
return cr;
|
|
436094
|
-
}
|
|
436095
|
-
}
|
|
436096
|
-
return null;
|
|
436097
|
-
}
|
|
436098
436562
|
var init_conversation_runtime = __esm(async () => {
|
|
436099
436563
|
init_queue_runtime();
|
|
436100
436564
|
init_runtime6();
|
|
@@ -436236,21 +436700,20 @@ async function resolveCronFireConversationId(task2) {
|
|
|
436236
436700
|
return task2.conversation_id === "default" ? undefined : task2.conversation_id;
|
|
436237
436701
|
}
|
|
436238
436702
|
function emitCronsUpdated(socket, task2, conversationId) {
|
|
436239
|
-
|
|
436703
|
+
const listener = getActiveRuntime();
|
|
436704
|
+
if (!listener)
|
|
436240
436705
|
return;
|
|
436241
|
-
|
|
436706
|
+
const runtimeScope = {
|
|
436707
|
+
agent_id: task2.agent_id,
|
|
436708
|
+
conversation_id: conversationId ?? task2.conversation_id ?? "default"
|
|
436709
|
+
};
|
|
436242
436710
|
const payload = {
|
|
436243
436711
|
type: "crons_updated",
|
|
436244
436712
|
timestamp: Date.now(),
|
|
436245
436713
|
agent_id: task2.agent_id,
|
|
436246
|
-
conversation_id:
|
|
436714
|
+
conversation_id: runtimeScope.conversation_id
|
|
436247
436715
|
};
|
|
436248
|
-
|
|
436249
|
-
socket.send(JSON.stringify(payload));
|
|
436250
|
-
safeEmitWsEvent("send", "protocol", payload);
|
|
436251
|
-
} catch (err) {
|
|
436252
|
-
console.error(`[Cron] Error sending crons_updated for task ${task2.id}:`, err instanceof Error ? err.message : err);
|
|
436253
|
-
}
|
|
436716
|
+
emitProtocolV2Message(socket, listener, payload, runtimeScope, TO_SUBSCRIBERS);
|
|
436254
436717
|
}
|
|
436255
436718
|
function refreshTaskCache(state) {
|
|
436256
436719
|
const mtime = getCronFileMtime();
|
|
@@ -436631,13 +437094,14 @@ function stopScheduler() {
|
|
|
436631
437094
|
var schedulerState = null, listenerFireContext = null, TICK_INTERVAL_MS = 60000, GC_INTERVAL_MS, LEASE_RETRY_MS = 30000, MAX_LEASE_RETRIES = 3, NEW_CONVERSATION_TARGET = "new";
|
|
436632
437095
|
var init_scheduler = __esm(async () => {
|
|
436633
437096
|
init_backend2();
|
|
437097
|
+
init_connection();
|
|
436634
437098
|
init_runtime6();
|
|
436635
|
-
init_transport();
|
|
436636
437099
|
init_cron_file();
|
|
436637
437100
|
init_parse_interval();
|
|
436638
437101
|
init_run_log();
|
|
436639
437102
|
await __promiseAll([
|
|
436640
437103
|
init_conversation_runtime(),
|
|
437104
|
+
init_protocol_outbound(),
|
|
436641
437105
|
init_queue()
|
|
436642
437106
|
]);
|
|
436643
437107
|
GC_INTERVAL_MS = 60 * 60000;
|
|
@@ -445600,6 +446064,34 @@ var init_turn_status = __esm(async () => {
|
|
|
445600
446064
|
});
|
|
445601
446065
|
|
|
445602
446066
|
// src/websocket/listener/approval.ts
|
|
446067
|
+
function pendingApprovalEntries(runtime) {
|
|
446068
|
+
return [...new Set(runtime.pendingApprovalResolvers.values())];
|
|
446069
|
+
}
|
|
446070
|
+
function removePendingApproval(runtime, pending) {
|
|
446071
|
+
for (const [requestKey, candidate] of runtime.pendingApprovalResolvers) {
|
|
446072
|
+
if (candidate !== pending)
|
|
446073
|
+
continue;
|
|
446074
|
+
runtime.pendingApprovalResolvers.delete(requestKey);
|
|
446075
|
+
}
|
|
446076
|
+
pending.connectionIds.clear();
|
|
446077
|
+
}
|
|
446078
|
+
function addPendingApprovalConnection(runtime, pending, connectionId) {
|
|
446079
|
+
const unownedKey = createConnectionRequestKey(UNOWNED_APPROVAL_CONNECTION_ID, pending.requestId);
|
|
446080
|
+
runtime.pendingApprovalResolvers.delete(unownedKey);
|
|
446081
|
+
const requestKey = createConnectionRequestKey(connectionId, pending.requestId);
|
|
446082
|
+
pending.connectionIds.add(connectionId);
|
|
446083
|
+
runtime.pendingApprovalResolvers.set(requestKey, pending);
|
|
446084
|
+
}
|
|
446085
|
+
function keepPendingApprovalUnowned(runtime, pending) {
|
|
446086
|
+
const requestKey = createConnectionRequestKey(UNOWNED_APPROVAL_CONNECTION_ID, pending.requestId);
|
|
446087
|
+
runtime.pendingApprovalResolvers.set(requestKey, pending);
|
|
446088
|
+
}
|
|
446089
|
+
function hasPendingApprovalRequestId(runtime, requestId) {
|
|
446090
|
+
return pendingApprovalEntries(runtime).some((pending) => pending.requestId === requestId);
|
|
446091
|
+
}
|
|
446092
|
+
function getPendingApprovalRequestIds(runtime) {
|
|
446093
|
+
return new Set(pendingApprovalEntries(runtime).map((pending) => pending.requestId));
|
|
446094
|
+
}
|
|
445603
446095
|
function rememberPendingApprovalBatchIds(runtime, pendingApprovals, batchId) {
|
|
445604
446096
|
for (const approval of pendingApprovals) {
|
|
445605
446097
|
if (approval.toolCallId) {
|
|
@@ -445685,17 +446177,20 @@ function validateApprovalResultIds(decisions, approvals) {
|
|
|
445685
446177
|
}, null, 2));
|
|
445686
446178
|
throw new Error("Approval ID mismatch - refusing to send mismatched IDs");
|
|
445687
446179
|
}
|
|
445688
|
-
function resolvePendingApprovalResolver(runtime, response) {
|
|
446180
|
+
function resolvePendingApprovalResolver(runtime, response, connectionId) {
|
|
445689
446181
|
const requestId = response.request_id;
|
|
445690
446182
|
if (typeof requestId !== "string" || requestId.length === 0) {
|
|
445691
446183
|
return false;
|
|
445692
446184
|
}
|
|
445693
|
-
const
|
|
446185
|
+
const requestKey = connectionId ? createConnectionRequestKey(connectionId, requestId) : [...runtime.pendingApprovalResolvers.entries()].find(([, candidate]) => candidate.requestId === requestId)?.[0];
|
|
446186
|
+
if (!requestKey) {
|
|
446187
|
+
return false;
|
|
446188
|
+
}
|
|
446189
|
+
const pending = runtime.pendingApprovalResolvers.get(requestKey);
|
|
445694
446190
|
if (!pending) {
|
|
445695
446191
|
return false;
|
|
445696
446192
|
}
|
|
445697
|
-
runtime
|
|
445698
|
-
runtime.listener.approvalRuntimeKeyByRequestId.delete(requestId);
|
|
446193
|
+
removePendingApproval(runtime, pending);
|
|
445699
446194
|
if (runtime.pendingApprovalResolvers.size === 0 && !runtime.isProcessing) {
|
|
445700
446195
|
setCommandLoopStatus(runtime, "WAITING_ON_INPUT");
|
|
445701
446196
|
}
|
|
@@ -445712,15 +446207,10 @@ function resolvePendingApprovalResolver(runtime, response) {
|
|
|
445712
446207
|
return true;
|
|
445713
446208
|
}
|
|
445714
446209
|
function rejectPendingApprovalResolvers(runtime, reason) {
|
|
445715
|
-
for (const
|
|
446210
|
+
for (const pending of pendingApprovalEntries(runtime)) {
|
|
445716
446211
|
pending.reject(new Error(reason));
|
|
445717
446212
|
}
|
|
445718
446213
|
runtime.pendingApprovalResolvers.clear();
|
|
445719
|
-
for (const [requestId, runtimeKey] of runtime.listener.approvalRuntimeKeyByRequestId) {
|
|
445720
|
-
if (runtimeKey === runtime.key) {
|
|
445721
|
-
runtime.listener.approvalRuntimeKeyByRequestId.delete(requestId);
|
|
445722
|
-
}
|
|
445723
|
-
}
|
|
445724
446214
|
if (!runtime.isProcessing && !runtime.cancelRequested) {
|
|
445725
446215
|
setCommandLoopStatus(runtime, "WAITING_ON_INPUT");
|
|
445726
446216
|
}
|
|
@@ -445734,8 +446224,49 @@ function rejectPendingApprovalResolvers(runtime, reason) {
|
|
|
445734
446224
|
});
|
|
445735
446225
|
evictConversationRuntimeIfIdle(runtime);
|
|
445736
446226
|
}
|
|
446227
|
+
function rejectPendingApprovalResolversForConnection(runtime, connectionId, _reason) {
|
|
446228
|
+
for (const pending of pendingApprovalEntries(runtime)) {
|
|
446229
|
+
if (!pending.connectionIds.delete(connectionId)) {
|
|
446230
|
+
continue;
|
|
446231
|
+
}
|
|
446232
|
+
const requestKey = createConnectionRequestKey(connectionId, pending.requestId);
|
|
446233
|
+
runtime.pendingApprovalResolvers.delete(requestKey);
|
|
446234
|
+
if (pending.connectionIds.size === 0) {
|
|
446235
|
+
keepPendingApprovalUnowned(runtime, pending);
|
|
446236
|
+
}
|
|
446237
|
+
}
|
|
446238
|
+
evictConversationRuntimeIfIdle(runtime);
|
|
446239
|
+
}
|
|
446240
|
+
function replayPendingApprovalRequestsToConnection(runtime, connectionId) {
|
|
446241
|
+
const connection = runtime.listener.connections.get(connectionId);
|
|
446242
|
+
if (!connection?.initialized || !isListenerTransportOpen(connection.writer)) {
|
|
446243
|
+
return;
|
|
446244
|
+
}
|
|
446245
|
+
for (const pending of pendingApprovalEntries(runtime)) {
|
|
446246
|
+
addPendingApprovalConnection(runtime, pending, connectionId);
|
|
446247
|
+
if (!pending.controlRequest)
|
|
446248
|
+
continue;
|
|
446249
|
+
emitProtocolV2Message(connection.writer, runtime, pending.controlRequest, {
|
|
446250
|
+
agent_id: runtime.agentId,
|
|
446251
|
+
conversation_id: runtime.conversationId
|
|
446252
|
+
}, toListenerConnection(connectionId));
|
|
446253
|
+
}
|
|
446254
|
+
}
|
|
445737
446255
|
function requestApprovalOverWS(runtime, socket, turnLease, requestId, controlRequest) {
|
|
445738
|
-
|
|
446256
|
+
const scope = {
|
|
446257
|
+
agent_id: runtime.agentId,
|
|
446258
|
+
conversation_id: runtime.conversationId
|
|
446259
|
+
};
|
|
446260
|
+
const subscribers = getSubscribedListenerConnections(runtime.listener, scope);
|
|
446261
|
+
const originConnection = findListenerConnectionByTransport(runtime.listener, socket);
|
|
446262
|
+
const connectionIds = new Set(subscribers.map((subscriber) => subscriber.id));
|
|
446263
|
+
if (connectionIds.size === 0 && originConnection?.initialized && isListenerTransportOpen(originConnection.writer)) {
|
|
446264
|
+
connectionIds.add(originConnection.id);
|
|
446265
|
+
}
|
|
446266
|
+
if (connectionIds.size === 0 && runtime.listener.connections.size === 0 && isListenerTransportOpen(socket)) {
|
|
446267
|
+
connectionIds.add(runtime.listener.connectionId ?? "legacy");
|
|
446268
|
+
}
|
|
446269
|
+
if (connectionIds.size === 0 && !isListenerTransportOpen(socket) && runtime.listener.connections.size === 0) {
|
|
445739
446270
|
return Promise.reject(new Error("WebSocket not open"));
|
|
445740
446271
|
}
|
|
445741
446272
|
const abortSignal = turnLease.signal;
|
|
@@ -445745,51 +446276,53 @@ function requestApprovalOverWS(runtime, socket, turnLease, requestId, controlReq
|
|
|
445745
446276
|
}
|
|
445746
446277
|
return new Promise((resolve31, reject) => {
|
|
445747
446278
|
let settled = false;
|
|
446279
|
+
const pending = {
|
|
446280
|
+
requestId,
|
|
446281
|
+
connectionIds,
|
|
446282
|
+
resolve: (response) => {
|
|
446283
|
+
if (settled) {
|
|
446284
|
+
return;
|
|
446285
|
+
}
|
|
446286
|
+
settled = true;
|
|
446287
|
+
cleanupAbortListener();
|
|
446288
|
+
resolve31(response);
|
|
446289
|
+
},
|
|
446290
|
+
reject: (error54) => {
|
|
446291
|
+
if (settled) {
|
|
446292
|
+
return;
|
|
446293
|
+
}
|
|
446294
|
+
settled = true;
|
|
446295
|
+
cleanupAbortListener();
|
|
446296
|
+
reject(error54);
|
|
446297
|
+
},
|
|
446298
|
+
controlRequest
|
|
446299
|
+
};
|
|
445748
446300
|
const cleanupAbortListener = () => {
|
|
445749
446301
|
abortSignal.removeEventListener("abort", handleAbort);
|
|
445750
446302
|
};
|
|
445751
|
-
const wrappedResolve = (response) => {
|
|
445752
|
-
if (settled) {
|
|
445753
|
-
return;
|
|
445754
|
-
}
|
|
445755
|
-
settled = true;
|
|
445756
|
-
cleanupAbortListener();
|
|
445757
|
-
resolve31(response);
|
|
445758
|
-
};
|
|
445759
|
-
const wrappedReject = (error54) => {
|
|
445760
|
-
if (settled) {
|
|
445761
|
-
return;
|
|
445762
|
-
}
|
|
445763
|
-
settled = true;
|
|
445764
|
-
cleanupAbortListener();
|
|
445765
|
-
reject(error54);
|
|
445766
|
-
};
|
|
445767
446303
|
const handleAbort = () => {
|
|
445768
|
-
runtime
|
|
445769
|
-
|
|
445770
|
-
wrappedReject(new Error("Cancelled by user"));
|
|
446304
|
+
removePendingApproval(runtime, pending);
|
|
446305
|
+
pending.reject(new Error("Cancelled by user"));
|
|
445771
446306
|
};
|
|
445772
446307
|
abortSignal.addEventListener("abort", handleAbort, { once: true });
|
|
445773
446308
|
if (isInterrupted()) {
|
|
445774
446309
|
handleAbort();
|
|
445775
446310
|
return;
|
|
445776
446311
|
}
|
|
445777
|
-
|
|
445778
|
-
|
|
445779
|
-
|
|
445780
|
-
|
|
445781
|
-
|
|
445782
|
-
|
|
446312
|
+
if (connectionIds.size === 0) {
|
|
446313
|
+
keepPendingApprovalUnowned(runtime, pending);
|
|
446314
|
+
} else {
|
|
446315
|
+
for (const connectionId of connectionIds) {
|
|
446316
|
+
addPendingApprovalConnection(runtime, pending, connectionId);
|
|
446317
|
+
}
|
|
446318
|
+
}
|
|
445783
446319
|
if (isInterrupted()) {
|
|
445784
446320
|
handleAbort();
|
|
445785
446321
|
return;
|
|
445786
446322
|
}
|
|
445787
446323
|
runtime.turnLifecycle.recordStopReason(turnLease, "requires_approval");
|
|
445788
446324
|
setTurnLoopStatus(runtime, turnLease, "WAITING_ON_APPROVAL");
|
|
445789
|
-
emitProtocolV2Message(socket, runtime, controlRequest,
|
|
445790
|
-
agent_id: runtime.agentId,
|
|
445791
|
-
conversation_id: runtime.conversationId
|
|
445792
|
-
});
|
|
446325
|
+
emitProtocolV2Message(socket, runtime, controlRequest, scope, TO_SUBSCRIBERS);
|
|
445793
446326
|
emitLoopStatusIfOpen(runtime.listener, {
|
|
445794
446327
|
agent_id: runtime.agentId,
|
|
445795
446328
|
conversation_id: runtime.conversationId
|
|
@@ -445800,7 +446333,9 @@ function requestApprovalOverWS(runtime, socket, turnLease, requestId, controlReq
|
|
|
445800
446333
|
});
|
|
445801
446334
|
});
|
|
445802
446335
|
}
|
|
446336
|
+
var UNOWNED_APPROVAL_CONNECTION_ID = "__unowned_approval__";
|
|
445803
446337
|
var init_approval = __esm(async () => {
|
|
446338
|
+
init_connection();
|
|
445804
446339
|
init_runtime6();
|
|
445805
446340
|
init_transport();
|
|
445806
446341
|
await __promiseAll([
|
|
@@ -447017,6 +447552,93 @@ var init_agents_conversations = __esm(async () => {
|
|
|
447017
447552
|
await init_protocol_inbound();
|
|
447018
447553
|
});
|
|
447019
447554
|
|
|
447555
|
+
// src/websocket/listener/commands/channel-registry-events.ts
|
|
447556
|
+
function broadcastChannelRegistryUpdate(runtime, origin, message) {
|
|
447557
|
+
const payload = JSON.stringify(message);
|
|
447558
|
+
const targets = resolveListenerConnectionTargets({
|
|
447559
|
+
runtime,
|
|
447560
|
+
origin,
|
|
447561
|
+
scope: {},
|
|
447562
|
+
routing: BROADCAST,
|
|
447563
|
+
streamMessage: false
|
|
447564
|
+
});
|
|
447565
|
+
for (const target2 of targets) {
|
|
447566
|
+
if (isListenerTransportOpen(target2.transport)) {
|
|
447567
|
+
try {
|
|
447568
|
+
target2.transport.send(payload);
|
|
447569
|
+
} catch (error54) {
|
|
447570
|
+
trackBoundaryError({
|
|
447571
|
+
context: "listener_channel_registry_broadcast",
|
|
447572
|
+
errorType: "listener_channel_registry_send_failed",
|
|
447573
|
+
error: error54
|
|
447574
|
+
});
|
|
447575
|
+
}
|
|
447576
|
+
}
|
|
447577
|
+
}
|
|
447578
|
+
}
|
|
447579
|
+
function handleChannelRegistryEvent(event2, transport, runtime) {
|
|
447580
|
+
const broadcast = (message) => broadcastChannelRegistryUpdate(runtime, transport, message);
|
|
447581
|
+
if (event2.type === "pairings_updated") {
|
|
447582
|
+
const channelId = event2.channelId;
|
|
447583
|
+
broadcast({
|
|
447584
|
+
type: "channel_pairings_updated",
|
|
447585
|
+
timestamp: Date.now(),
|
|
447586
|
+
channel_id: channelId
|
|
447587
|
+
});
|
|
447588
|
+
broadcast({
|
|
447589
|
+
type: "channels_updated",
|
|
447590
|
+
timestamp: Date.now(),
|
|
447591
|
+
channel_id: channelId
|
|
447592
|
+
});
|
|
447593
|
+
return;
|
|
447594
|
+
}
|
|
447595
|
+
if (event2.type === "targets_updated") {
|
|
447596
|
+
const channelId = event2.channelId;
|
|
447597
|
+
broadcast({
|
|
447598
|
+
type: "channel_targets_updated",
|
|
447599
|
+
timestamp: Date.now(),
|
|
447600
|
+
channel_id: channelId
|
|
447601
|
+
});
|
|
447602
|
+
broadcast({
|
|
447603
|
+
type: "channels_updated",
|
|
447604
|
+
timestamp: Date.now(),
|
|
447605
|
+
channel_id: channelId
|
|
447606
|
+
});
|
|
447607
|
+
return;
|
|
447608
|
+
}
|
|
447609
|
+
if (event2.type === "channel_account_state_updated") {
|
|
447610
|
+
const channelId = event2.channelId;
|
|
447611
|
+
broadcast({
|
|
447612
|
+
type: "channel_accounts_updated",
|
|
447613
|
+
timestamp: Date.now(),
|
|
447614
|
+
channel_id: channelId,
|
|
447615
|
+
account_id: event2.accountId
|
|
447616
|
+
});
|
|
447617
|
+
broadcast({
|
|
447618
|
+
type: "channels_updated",
|
|
447619
|
+
timestamp: Date.now(),
|
|
447620
|
+
channel_id: channelId
|
|
447621
|
+
});
|
|
447622
|
+
return;
|
|
447623
|
+
}
|
|
447624
|
+
const permissionModeState = getOrCreateConversationPermissionModeStateRef(runtime, event2.agentId, event2.conversationId);
|
|
447625
|
+
permissionModeState.mode = event2.defaultPermissionMode;
|
|
447626
|
+
persistPermissionModeMapForRuntime(runtime);
|
|
447627
|
+
const seededWorkingDirectory = seedConversationWorkingDirectory(runtime, event2.agentId, event2.conversationId, runtime.bootWorkingDirectory);
|
|
447628
|
+
if (seededWorkingDirectory) {
|
|
447629
|
+
emitDeviceStatusUpdate(transport, getOrCreateConversationRuntime(runtime, event2.agentId, event2.conversationId));
|
|
447630
|
+
}
|
|
447631
|
+
}
|
|
447632
|
+
var init_channel_registry_events = __esm(async () => {
|
|
447633
|
+
init_error_reporting();
|
|
447634
|
+
init_connection();
|
|
447635
|
+
init_cwd();
|
|
447636
|
+
init_permission_mode();
|
|
447637
|
+
init_runtime6();
|
|
447638
|
+
init_transport();
|
|
447639
|
+
await init_protocol_outbound();
|
|
447640
|
+
});
|
|
447641
|
+
|
|
447020
447642
|
// src/channels/custom/scaffolding.ts
|
|
447021
447643
|
import { existsSync as existsSync48, mkdirSync as mkdirSync34, rmSync as rmSync11, writeFileSync as writeFileSync24 } from "node:fs";
|
|
447022
447644
|
function removeUserPlugin(channelId) {
|
|
@@ -447044,7 +447666,6 @@ var init_scaffolding = __esm(() => {
|
|
|
447044
447666
|
});
|
|
447045
447667
|
|
|
447046
447668
|
// src/websocket/listener/commands/channels.ts
|
|
447047
|
-
import WebSocket4 from "ws";
|
|
447048
447669
|
function setChannelsServiceLoaderOverride(loader) {
|
|
447049
447670
|
channelsServiceLoaderOverride = loader;
|
|
447050
447671
|
}
|
|
@@ -447762,52 +448383,13 @@ async function handleChannelsProtocolCommand(parsed, socket, runtime, opts, proc
|
|
|
447762
448383
|
}
|
|
447763
448384
|
return true;
|
|
447764
448385
|
}
|
|
447765
|
-
function handleChannelRegistryEvent(event2, socket, runtime, safeSocketSend) {
|
|
447766
|
-
if (event2.type === "pairings_updated") {
|
|
447767
|
-
if (socket instanceof WebSocket4) {
|
|
447768
|
-
emitChannelPairingsUpdated(socket, safeSocketSend, event2.channelId);
|
|
447769
|
-
emitChannelsUpdated(socket, safeSocketSend, event2.channelId);
|
|
447770
|
-
}
|
|
447771
|
-
return;
|
|
447772
|
-
}
|
|
447773
|
-
if (event2.type === "targets_updated") {
|
|
447774
|
-
if (socket instanceof WebSocket4) {
|
|
447775
|
-
emitChannelTargetsUpdated(socket, safeSocketSend, event2.channelId);
|
|
447776
|
-
emitChannelsUpdated(socket, safeSocketSend, event2.channelId);
|
|
447777
|
-
}
|
|
447778
|
-
return;
|
|
447779
|
-
}
|
|
447780
|
-
if (event2.type === "channel_account_state_updated") {
|
|
447781
|
-
if (socket instanceof WebSocket4) {
|
|
447782
|
-
emitChannelAccountsUpdated(socket, safeSocketSend, {
|
|
447783
|
-
channelId: event2.channelId,
|
|
447784
|
-
accountId: event2.accountId
|
|
447785
|
-
});
|
|
447786
|
-
emitChannelsUpdated(socket, safeSocketSend, event2.channelId);
|
|
447787
|
-
}
|
|
447788
|
-
return;
|
|
447789
|
-
}
|
|
447790
|
-
const permissionModeState = getOrCreateConversationPermissionModeStateRef(runtime, event2.agentId, event2.conversationId);
|
|
447791
|
-
permissionModeState.mode = event2.defaultPermissionMode;
|
|
447792
|
-
persistPermissionModeMapForRuntime(runtime);
|
|
447793
|
-
const seededWorkingDirectory = seedConversationWorkingDirectory(runtime, event2.agentId, event2.conversationId, runtime.bootWorkingDirectory);
|
|
447794
|
-
if (seededWorkingDirectory) {
|
|
447795
|
-
emitDeviceStatusUpdate(socket, getOrCreateConversationRuntime(runtime, event2.agentId, event2.conversationId));
|
|
447796
|
-
}
|
|
447797
|
-
}
|
|
447798
448386
|
var channelsServiceLoaderOverride = null;
|
|
447799
448387
|
var init_channels2 = __esm(async () => {
|
|
447800
448388
|
init_account_config7();
|
|
447801
448389
|
init_scaffolding();
|
|
447802
448390
|
init_plugin_registry();
|
|
447803
448391
|
init_types6();
|
|
447804
|
-
|
|
447805
|
-
init_permission_mode();
|
|
447806
|
-
init_runtime6();
|
|
447807
|
-
await __promiseAll([
|
|
447808
|
-
init_protocol_inbound(),
|
|
447809
|
-
init_protocol_outbound()
|
|
447810
|
-
]);
|
|
448392
|
+
await init_protocol_inbound();
|
|
447811
448393
|
});
|
|
447812
448394
|
|
|
447813
448395
|
// src/websocket/listener/commands/cron.ts
|
|
@@ -449626,11 +450208,7 @@ var init_model_toolset = __esm(async () => {
|
|
|
449626
450208
|
});
|
|
449627
450209
|
|
|
449628
450210
|
// src/websocket/listener/external-tools.ts
|
|
449629
|
-
function isSocketOpen(socket) {
|
|
449630
|
-
return socket?.readyState === WEBSOCKET_OPEN;
|
|
449631
|
-
}
|
|
449632
450211
|
function getPendingExternalToolCalls(runtime) {
|
|
449633
|
-
runtime.pendingExternalToolCalls ??= new Map;
|
|
449634
450212
|
return runtime.pendingExternalToolCalls;
|
|
449635
450213
|
}
|
|
449636
450214
|
function getRegisteredTools(runtime) {
|
|
@@ -449641,25 +450219,35 @@ function getRegisteredTools(runtime) {
|
|
|
449641
450219
|
}
|
|
449642
450220
|
return registeredTools;
|
|
449643
450221
|
}
|
|
450222
|
+
function getConnectionIdsByRegistrationKey(runtime) {
|
|
450223
|
+
let controllers = connectionIdByRegistrationKey.get(runtime);
|
|
450224
|
+
if (!controllers) {
|
|
450225
|
+
controllers = new Map;
|
|
450226
|
+
connectionIdByRegistrationKey.set(runtime, controllers);
|
|
450227
|
+
}
|
|
450228
|
+
return controllers;
|
|
450229
|
+
}
|
|
449644
450230
|
function getRuntimeKey(runtime) {
|
|
449645
450231
|
return `${runtime.agent_id}:${runtime.conversation_id}`;
|
|
449646
450232
|
}
|
|
449647
|
-
function getToolRegistrationKey(runtime, scopeId, toolName) {
|
|
450233
|
+
function getToolRegistrationKey(connectionId, runtime, scopeId, toolName) {
|
|
449648
450234
|
return JSON.stringify([
|
|
449649
450235
|
"runtime",
|
|
450236
|
+
connectionId,
|
|
449650
450237
|
runtime.agent_id,
|
|
449651
450238
|
runtime.conversation_id,
|
|
449652
450239
|
scopeId ?? null,
|
|
449653
450240
|
toolName
|
|
449654
450241
|
]);
|
|
449655
450242
|
}
|
|
449656
|
-
function toExternalToolDefinition(tool2, runtime, scopeId) {
|
|
450243
|
+
function toExternalToolDefinition(tool2, connectionId, runtime, scopeId) {
|
|
449657
450244
|
return {
|
|
449658
450245
|
name: tool2.name,
|
|
450246
|
+
connectionId,
|
|
449659
450247
|
...tool2.label !== undefined ? { label: tool2.label } : {},
|
|
449660
450248
|
description: tool2.description,
|
|
449661
450249
|
parameters: tool2.parameters,
|
|
449662
|
-
registrationKey: getToolRegistrationKey(runtime, scopeId, tool2.name),
|
|
450250
|
+
registrationKey: getToolRegistrationKey(connectionId, runtime, scopeId, tool2.name),
|
|
449663
450251
|
...scopeId !== undefined ? { scopeId } : {},
|
|
449664
450252
|
runtime: {
|
|
449665
450253
|
agentId: runtime.agent_id,
|
|
@@ -449667,16 +450255,17 @@ function toExternalToolDefinition(tool2, runtime, scopeId) {
|
|
|
449667
450255
|
}
|
|
449668
450256
|
};
|
|
449669
450257
|
}
|
|
449670
|
-
function sendJson(socket, payload) {
|
|
449671
|
-
socket.send(JSON.stringify(payload));
|
|
449672
|
-
}
|
|
449673
450258
|
function installExternalToolBridge(runtime) {
|
|
449674
450259
|
setExternalToolExecutor(async (toolCallId, toolName, input, context3) => {
|
|
449675
|
-
const
|
|
449676
|
-
|
|
450260
|
+
const registrationKey = context3?.tool.registrationKey;
|
|
450261
|
+
const connectionId = registrationKey ? getConnectionIdsByRegistrationKey(runtime).get(registrationKey) : undefined;
|
|
450262
|
+
const connection = connectionId ? runtime.connections.get(connectionId) : undefined;
|
|
450263
|
+
if (!connection || !isListenerTransportOpen(connection.writer) || runtime.intentionallyClosed) {
|
|
449677
450264
|
throw new Error("External tool controller is not connected");
|
|
449678
450265
|
}
|
|
450266
|
+
const writer = connection.writer;
|
|
449679
450267
|
const requestId = `external-tool-${crypto.randomUUID()}`;
|
|
450268
|
+
const requestKey = createConnectionRequestKey(connection.id, requestId);
|
|
449680
450269
|
const toolRuntime = context3?.tool.runtime;
|
|
449681
450270
|
const requestRuntime = toolRuntime?.agentId && toolRuntime.conversationId ? {
|
|
449682
450271
|
agent_id: toolRuntime.agentId,
|
|
@@ -449693,10 +450282,11 @@ function installExternalToolBridge(runtime) {
|
|
|
449693
450282
|
};
|
|
449694
450283
|
const result = await new Promise((resolve31, reject) => {
|
|
449695
450284
|
const timeout = setTimeout(() => {
|
|
449696
|
-
getPendingExternalToolCalls(runtime).delete(
|
|
450285
|
+
getPendingExternalToolCalls(runtime).delete(requestKey);
|
|
449697
450286
|
reject(new Error(`External tool call timed out: ${toolName}`));
|
|
449698
450287
|
}, EXTERNAL_TOOL_CALL_TIMEOUT_MS);
|
|
449699
|
-
getPendingExternalToolCalls(runtime).set(
|
|
450288
|
+
getPendingExternalToolCalls(runtime).set(requestKey, {
|
|
450289
|
+
connectionId: connection.id,
|
|
449700
450290
|
resolve: (response) => {
|
|
449701
450291
|
resolve31({
|
|
449702
450292
|
content: [...response.content],
|
|
@@ -449707,36 +450297,49 @@ function installExternalToolBridge(runtime) {
|
|
|
449707
450297
|
timeout
|
|
449708
450298
|
});
|
|
449709
450299
|
try {
|
|
449710
|
-
|
|
450300
|
+
writer.send(JSON.stringify(request));
|
|
449711
450301
|
} catch (error54) {
|
|
449712
450302
|
clearTimeout(timeout);
|
|
449713
|
-
getPendingExternalToolCalls(runtime).delete(
|
|
450303
|
+
getPendingExternalToolCalls(runtime).delete(requestKey);
|
|
449714
450304
|
reject(error54 instanceof Error ? error54 : new Error(String(error54)));
|
|
449715
450305
|
}
|
|
449716
450306
|
});
|
|
449717
450307
|
return result;
|
|
449718
450308
|
});
|
|
449719
450309
|
}
|
|
449720
|
-
function registerRuntimeExternalTools(runtime, runtimeScope, groups
|
|
450310
|
+
function registerRuntimeExternalTools(runtime, connectionId, runtimeScope, groups) {
|
|
450311
|
+
const resolvedGroups = groups ?? [];
|
|
449721
450312
|
const registeredTools = getRegisteredTools(runtime);
|
|
449722
|
-
const runtimeKey = getRuntimeKey(runtimeScope);
|
|
450313
|
+
const runtimeKey = createConnectionRequestKey(connectionId, getRuntimeKey(runtimeScope));
|
|
449723
450314
|
const previousTools = registeredTools.get(runtimeKey) ?? [];
|
|
449724
450315
|
unregisterExternalTools(previousTools);
|
|
449725
|
-
const tools =
|
|
450316
|
+
const tools = resolvedGroups.flatMap((group) => group.tools.map((tool2) => toExternalToolDefinition(tool2, connectionId, runtimeScope, group.scope_id)));
|
|
450317
|
+
const controllers = getConnectionIdsByRegistrationKey(runtime);
|
|
450318
|
+
for (const tool2 of previousTools) {
|
|
450319
|
+
if (tool2.registrationKey) {
|
|
450320
|
+
controllers.delete(tool2.registrationKey);
|
|
450321
|
+
}
|
|
450322
|
+
}
|
|
449726
450323
|
if (tools.length > 0) {
|
|
449727
450324
|
registerExternalTools(tools);
|
|
450325
|
+
for (const tool2 of tools) {
|
|
450326
|
+
if (tool2.registrationKey) {
|
|
450327
|
+
controllers.set(tool2.registrationKey, connectionId);
|
|
450328
|
+
}
|
|
450329
|
+
}
|
|
449728
450330
|
registeredTools.set(runtimeKey, tools);
|
|
449729
450331
|
} else {
|
|
449730
450332
|
registeredTools.delete(runtimeKey);
|
|
449731
450333
|
}
|
|
449732
450334
|
}
|
|
449733
|
-
function handleExternalToolCallResponseCommand(runtime, command) {
|
|
449734
|
-
const
|
|
450335
|
+
function handleExternalToolCallResponseCommand(runtime, connectionId, command) {
|
|
450336
|
+
const requestKey = createConnectionRequestKey(connectionId, command.request_id);
|
|
450337
|
+
const pending = getPendingExternalToolCalls(runtime).get(requestKey);
|
|
449735
450338
|
if (!pending) {
|
|
449736
450339
|
return false;
|
|
449737
450340
|
}
|
|
449738
450341
|
clearTimeout(pending.timeout);
|
|
449739
|
-
getPendingExternalToolCalls(runtime).delete(
|
|
450342
|
+
getPendingExternalToolCalls(runtime).delete(requestKey);
|
|
449740
450343
|
if (command.error !== undefined) {
|
|
449741
450344
|
pending.reject(new Error(command.error));
|
|
449742
450345
|
return true;
|
|
@@ -449748,6 +450351,35 @@ function handleExternalToolCallResponseCommand(runtime, command) {
|
|
|
449748
450351
|
pending.resolve(command.result);
|
|
449749
450352
|
return true;
|
|
449750
450353
|
}
|
|
450354
|
+
function rejectPendingExternalToolCallsForConnection(runtime, connectionId, reason) {
|
|
450355
|
+
const pendingExternalToolCalls = getPendingExternalToolCalls(runtime);
|
|
450356
|
+
for (const [requestKey, pending] of pendingExternalToolCalls) {
|
|
450357
|
+
if (pending.connectionId !== connectionId) {
|
|
450358
|
+
continue;
|
|
450359
|
+
}
|
|
450360
|
+
clearTimeout(pending.timeout);
|
|
450361
|
+
pendingExternalToolCalls.delete(requestKey);
|
|
450362
|
+
pending.reject(new Error(reason));
|
|
450363
|
+
}
|
|
450364
|
+
const registeredTools = registeredToolsByRuntime.get(runtime);
|
|
450365
|
+
if (!registeredTools) {
|
|
450366
|
+
return;
|
|
450367
|
+
}
|
|
450368
|
+
const controllers = getConnectionIdsByRegistrationKey(runtime);
|
|
450369
|
+
for (const [registrationScope, tools] of registeredTools) {
|
|
450370
|
+
const ownedByConnection = tools.some((tool2) => tool2.registrationKey !== undefined && controllers.get(tool2.registrationKey) === connectionId);
|
|
450371
|
+
if (!ownedByConnection) {
|
|
450372
|
+
continue;
|
|
450373
|
+
}
|
|
450374
|
+
unregisterExternalTools(tools);
|
|
450375
|
+
registeredTools.delete(registrationScope);
|
|
450376
|
+
for (const tool2 of tools) {
|
|
450377
|
+
if (tool2.registrationKey) {
|
|
450378
|
+
controllers.delete(tool2.registrationKey);
|
|
450379
|
+
}
|
|
450380
|
+
}
|
|
450381
|
+
}
|
|
450382
|
+
}
|
|
449751
450383
|
function rejectPendingExternalToolCalls(runtime, reason) {
|
|
449752
450384
|
const pendingExternalToolCalls = getPendingExternalToolCalls(runtime);
|
|
449753
450385
|
for (const [requestId, pending] of pendingExternalToolCalls) {
|
|
@@ -449762,12 +450394,16 @@ function rejectPendingExternalToolCalls(runtime, reason) {
|
|
|
449762
450394
|
}
|
|
449763
450395
|
registeredToolsByRuntime.delete(runtime);
|
|
449764
450396
|
}
|
|
450397
|
+
connectionIdByRegistrationKey.delete(runtime);
|
|
449765
450398
|
}
|
|
449766
|
-
var EXTERNAL_TOOL_CALL_TIMEOUT_MS,
|
|
450399
|
+
var EXTERNAL_TOOL_CALL_TIMEOUT_MS, registeredToolsByRuntime, connectionIdByRegistrationKey;
|
|
449767
450400
|
var init_external_tools = __esm(async () => {
|
|
450401
|
+
init_connection();
|
|
450402
|
+
init_transport();
|
|
449768
450403
|
await init_manager4();
|
|
449769
450404
|
EXTERNAL_TOOL_CALL_TIMEOUT_MS = 5 * 60 * 1000;
|
|
449770
450405
|
registeredToolsByRuntime = new WeakMap;
|
|
450406
|
+
connectionIdByRegistrationKey = new WeakMap;
|
|
449771
450407
|
});
|
|
449772
450408
|
|
|
449773
450409
|
// src/websocket/listener/commands/runtime-start.ts
|
|
@@ -449915,9 +450551,18 @@ async function handleRuntimeStartCommand(parsed, context3) {
|
|
|
449915
450551
|
agent2 = await resolveRuntimeStartAgent(parsed, created);
|
|
449916
450552
|
conversation = await resolveRuntimeStartConversation(parsed, agent2, created);
|
|
449917
450553
|
runtimeScope = buildRuntimeScope(agent2, conversation);
|
|
450554
|
+
const { connectionId } = context3;
|
|
450555
|
+
const assertConnectionOpen = () => {
|
|
450556
|
+
if (context3.runtime.connections.size > 0 && (!context3.runtime.connections.has(connectionId) || context3.runtime.connections.get(connectionId)?.cancellation.signal.aborted)) {
|
|
450557
|
+
throw new Error("App-server connection closed during runtime start");
|
|
450558
|
+
}
|
|
450559
|
+
};
|
|
450560
|
+
assertConnectionOpen();
|
|
449918
450561
|
const scopedRuntime = context3.getOrCreateScopedRuntime(context3.runtime, runtimeScope.agent_id, runtimeScope.conversation_id);
|
|
449919
450562
|
await applyRuntimeStartState(parsed, context3, runtimeScope, scopedRuntime);
|
|
449920
|
-
|
|
450563
|
+
assertConnectionOpen();
|
|
450564
|
+
subscribeListenerConnection(context3.runtime, connectionId, runtimeScope);
|
|
450565
|
+
registerRuntimeExternalTools(context3.runtime, connectionId, runtimeScope, parsed.external_tools ?? []);
|
|
449921
450566
|
const sent = sendRuntimeStartResponse(context3, parsed, {
|
|
449922
450567
|
success: true,
|
|
449923
450568
|
runtime: runtimeScope,
|
|
@@ -449959,6 +450604,7 @@ var init_runtime_start = __esm(async () => {
|
|
|
449959
450604
|
init_backend2();
|
|
449960
450605
|
init_mode();
|
|
449961
450606
|
init_settings_manager();
|
|
450607
|
+
init_connection();
|
|
449962
450608
|
init_cwd();
|
|
449963
450609
|
init_permission_mode();
|
|
449964
450610
|
await __promiseAll([
|
|
@@ -457404,16 +458050,19 @@ async function handleApprovalStop(params) {
|
|
|
457404
458050
|
return interruptTermination();
|
|
457405
458051
|
}
|
|
457406
458052
|
const onFileWrite = (filePath, content) => {
|
|
457407
|
-
if (runtime.turnLifecycle.isCurrent(turnLease)
|
|
457408
|
-
|
|
457409
|
-
|
|
457410
|
-
|
|
457411
|
-
|
|
457412
|
-
|
|
457413
|
-
|
|
457414
|
-
|
|
457415
|
-
|
|
457416
|
-
}
|
|
458053
|
+
if (!runtime.turnLifecycle.isCurrent(turnLease))
|
|
458054
|
+
return;
|
|
458055
|
+
emitProtocolV2Message(socket, runtime, {
|
|
458056
|
+
type: "file_ops",
|
|
458057
|
+
path: filePath,
|
|
458058
|
+
cg_entries: [],
|
|
458059
|
+
ops: [],
|
|
458060
|
+
source: "agent",
|
|
458061
|
+
document_content: content
|
|
458062
|
+
}, {
|
|
458063
|
+
agent_id: agentId,
|
|
458064
|
+
conversation_id: conversationId
|
|
458065
|
+
}, TO_SUBSCRIBERS);
|
|
457417
458066
|
};
|
|
457418
458067
|
let executionResults;
|
|
457419
458068
|
try {
|
|
@@ -457559,9 +458208,9 @@ var init_turn_approval = __esm(async () => {
|
|
|
457559
458208
|
init_diff_preview();
|
|
457560
458209
|
init_format_denial();
|
|
457561
458210
|
init_interactive_policy();
|
|
458211
|
+
init_connection();
|
|
457562
458212
|
init_secrets_sync();
|
|
457563
458213
|
init_skill_injection();
|
|
457564
|
-
init_transport();
|
|
457565
458214
|
init_turn_input_state();
|
|
457566
458215
|
await __promiseAll([
|
|
457567
458216
|
init_approval_execution(),
|
|
@@ -458995,6 +459644,7 @@ async function prepareListenerTurn(params) {
|
|
|
458995
459644
|
}
|
|
458996
459645
|
const modAdapters = await ensureListenerModAdaptersForAgent(runtime.listener, agentId);
|
|
458997
459646
|
const preparedToolContext = await prepareToolExecutionContextForScope({
|
|
459647
|
+
connectionId,
|
|
458998
459648
|
agentId,
|
|
458999
459649
|
conversationId,
|
|
459000
459650
|
clientToolAllowlist: msg.clientToolAllowlist,
|
|
@@ -459078,6 +459728,9 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
459078
459728
|
origin: "message",
|
|
459079
459729
|
workingDirectory: turnWorkingDirectory
|
|
459080
459730
|
});
|
|
459731
|
+
if (connectionId) {
|
|
459732
|
+
runtime.activeConnectionId = connectionId;
|
|
459733
|
+
}
|
|
459081
459734
|
if (!runtime.turnLifecycle.isCurrent(turnLease)) {
|
|
459082
459735
|
throw new Error("Cannot continue a turn with a stale lifecycle lease");
|
|
459083
459736
|
}
|
|
@@ -459682,6 +460335,9 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
459682
460335
|
});
|
|
459683
460336
|
}
|
|
459684
460337
|
richDraftStreamer?.dispose();
|
|
460338
|
+
if (runtime.activeConnectionId === connectionId) {
|
|
460339
|
+
runtime.activeConnectionId = null;
|
|
460340
|
+
}
|
|
459685
460341
|
try {
|
|
459686
460342
|
if (finalizedByThisInvocation) {
|
|
459687
460343
|
await runListenerTurnCleanup({
|
|
@@ -459787,15 +460443,19 @@ function handleModeChange(msg, socket, runtime, scope) {
|
|
|
459787
460443
|
}
|
|
459788
460444
|
}
|
|
459789
460445
|
}
|
|
459790
|
-
function resolveRuntimeForApprovalRequest(listener, requestId) {
|
|
460446
|
+
function resolveRuntimeForApprovalRequest(listener, scope, requestId, connectionId) {
|
|
459791
460447
|
if (!requestId) {
|
|
459792
460448
|
return null;
|
|
459793
460449
|
}
|
|
459794
|
-
const
|
|
459795
|
-
if (!
|
|
460450
|
+
const runtime = getConversationRuntime(listener, scope.agent_id, scope.conversation_id);
|
|
460451
|
+
if (!runtime) {
|
|
459796
460452
|
return null;
|
|
459797
460453
|
}
|
|
459798
|
-
|
|
460454
|
+
if (connectionId) {
|
|
460455
|
+
const requestKey = createConnectionRequestKey(connectionId, requestId);
|
|
460456
|
+
return runtime.pendingApprovalResolvers.has(requestKey) ? runtime : null;
|
|
460457
|
+
}
|
|
460458
|
+
return hasPendingApprovalRequestId(runtime, requestId) ? runtime : null;
|
|
459799
460459
|
}
|
|
459800
460460
|
async function handleApprovalResponseInput(listener, params, deps = {
|
|
459801
460461
|
resolveRuntimeForApprovalRequest,
|
|
@@ -459804,8 +460464,8 @@ async function handleApprovalResponseInput(listener, params, deps = {
|
|
|
459804
460464
|
resolveRecoveredApprovalResponse,
|
|
459805
460465
|
scheduleQueuePump
|
|
459806
460466
|
}) {
|
|
459807
|
-
const approvalRuntime = deps.resolveRuntimeForApprovalRequest(listener, params.response.request_id);
|
|
459808
|
-
if (approvalRuntime && deps.resolvePendingApprovalResolver(approvalRuntime, params.response)) {
|
|
460467
|
+
const approvalRuntime = deps.resolveRuntimeForApprovalRequest(listener, params.runtime, params.response.request_id, params.connectionId);
|
|
460468
|
+
if (approvalRuntime && deps.resolvePendingApprovalResolver(approvalRuntime, params.response, params.connectionId)) {
|
|
459809
460469
|
deps.scheduleQueuePump(approvalRuntime, params.socket, params.opts, params.processQueuedTurn);
|
|
459810
460470
|
return true;
|
|
459811
460471
|
}
|
|
@@ -460044,6 +460704,7 @@ var init_control_inputs = __esm(async () => {
|
|
|
460044
460704
|
init_mode();
|
|
460045
460705
|
init_error_reporting();
|
|
460046
460706
|
init_debug();
|
|
460707
|
+
init_connection();
|
|
460047
460708
|
init_cwd();
|
|
460048
460709
|
init_permission_mode();
|
|
460049
460710
|
init_runtime6();
|
|
@@ -460062,16 +460723,30 @@ var init_control_inputs = __esm(async () => {
|
|
|
460062
460723
|
});
|
|
460063
460724
|
|
|
460064
460725
|
// src/websocket/terminal-handler.ts
|
|
460726
|
+
import { existsSync as existsSync51 } from "node:fs";
|
|
460065
460727
|
import * as os6 from "node:os";
|
|
460066
|
-
import
|
|
460728
|
+
import WebSocket4 from "ws";
|
|
460729
|
+
function getTerminalKey(connectionId, terminalId) {
|
|
460730
|
+
return JSON.stringify([connectionId, terminalId]);
|
|
460731
|
+
}
|
|
460067
460732
|
function getDefaultShell() {
|
|
460068
460733
|
if (os6.platform() === "win32") {
|
|
460069
460734
|
return process.env.COMSPEC || "cmd.exe";
|
|
460070
460735
|
}
|
|
460071
|
-
|
|
460736
|
+
const candidates2 = [
|
|
460737
|
+
process.env.SHELL,
|
|
460738
|
+
os6.platform() === "darwin" ? "/bin/zsh" : "/bin/bash",
|
|
460739
|
+
"/bin/bash"
|
|
460740
|
+
];
|
|
460741
|
+
for (const candidate of candidates2) {
|
|
460742
|
+
if (candidate && existsSync51(candidate)) {
|
|
460743
|
+
return candidate;
|
|
460744
|
+
}
|
|
460745
|
+
}
|
|
460746
|
+
return "/bin/sh";
|
|
460072
460747
|
}
|
|
460073
460748
|
function sendTerminalMessage(socket, message) {
|
|
460074
|
-
if (socket.readyState ===
|
|
460749
|
+
if (socket.readyState === WebSocket4.OPEN) {
|
|
460075
460750
|
socket.send(JSON.stringify(message));
|
|
460076
460751
|
}
|
|
460077
460752
|
}
|
|
@@ -460097,7 +460772,8 @@ function makeOutputBatcher(onFlush) {
|
|
|
460097
460772
|
}
|
|
460098
460773
|
};
|
|
460099
460774
|
}
|
|
460100
|
-
function spawnBun(shell2, cwd2, cols, rows, terminal_id, socket) {
|
|
460775
|
+
function spawnBun(shell2, cwd2, cols, rows, terminal_id, connectionId, socket) {
|
|
460776
|
+
const terminalKey = getTerminalKey(connectionId, terminal_id);
|
|
460101
460777
|
const handleData = makeOutputBatcher((data) => sendTerminalMessage(socket, { type: "terminal_output", terminal_id, data }));
|
|
460102
460778
|
const proc2 = Bun.spawn([shell2], {
|
|
460103
460779
|
cwd: cwd2,
|
|
@@ -460113,9 +460789,9 @@ function spawnBun(shell2, cwd2, cols, rows, terminal_id, socket) {
|
|
|
460113
460789
|
throw new Error("Bun.spawn terminal object missing — API unavailable");
|
|
460114
460790
|
}
|
|
460115
460791
|
proc2.exited.then((exitCode) => {
|
|
460116
|
-
const current = terminals.get(
|
|
460792
|
+
const current = terminals.get(terminalKey);
|
|
460117
460793
|
if (current && current.pid === proc2.pid) {
|
|
460118
|
-
terminals.delete(
|
|
460794
|
+
terminals.delete(terminalKey);
|
|
460119
460795
|
sendTerminalMessage(socket, {
|
|
460120
460796
|
type: "terminal_exited",
|
|
460121
460797
|
terminal_id,
|
|
@@ -460144,10 +460820,12 @@ function spawnBun(shell2, cwd2, cols, rows, terminal_id, socket) {
|
|
|
460144
460820
|
},
|
|
460145
460821
|
pid: proc2.pid,
|
|
460146
460822
|
terminalId: terminal_id,
|
|
460823
|
+
connectionId,
|
|
460147
460824
|
spawnedAt: Date.now()
|
|
460148
460825
|
};
|
|
460149
460826
|
}
|
|
460150
|
-
function spawnNodePty(shell2, cwd2, cols, rows, terminal_id, socket) {
|
|
460827
|
+
function spawnNodePty(shell2, cwd2, cols, rows, terminal_id, connectionId, socket) {
|
|
460828
|
+
const terminalKey = getTerminalKey(connectionId, terminal_id);
|
|
460151
460829
|
const pty = __require("node-pty");
|
|
460152
460830
|
const handleData = makeOutputBatcher((data) => sendTerminalMessage(socket, { type: "terminal_output", terminal_id, data }));
|
|
460153
460831
|
const ptyProcess = pty.spawn(shell2, [], {
|
|
@@ -460163,9 +460841,9 @@ function spawnNodePty(shell2, cwd2, cols, rows, terminal_id, socket) {
|
|
|
460163
460841
|
});
|
|
460164
460842
|
ptyProcess.onData(handleData);
|
|
460165
460843
|
ptyProcess.onExit(({ exitCode }) => {
|
|
460166
|
-
const current = terminals.get(
|
|
460844
|
+
const current = terminals.get(terminalKey);
|
|
460167
460845
|
if (current && current.pid === ptyProcess.pid) {
|
|
460168
|
-
terminals.delete(
|
|
460846
|
+
terminals.delete(terminalKey);
|
|
460169
460847
|
sendTerminalMessage(socket, {
|
|
460170
460848
|
type: "terminal_exited",
|
|
460171
460849
|
terminal_id,
|
|
@@ -460191,12 +460869,14 @@ function spawnNodePty(shell2, cwd2, cols, rows, terminal_id, socket) {
|
|
|
460191
460869
|
},
|
|
460192
460870
|
pid: ptyProcess.pid,
|
|
460193
460871
|
terminalId: terminal_id,
|
|
460872
|
+
connectionId,
|
|
460194
460873
|
spawnedAt: Date.now()
|
|
460195
460874
|
};
|
|
460196
460875
|
}
|
|
460197
|
-
function handleTerminalSpawn(msg, socket, cwd2) {
|
|
460876
|
+
function handleTerminalSpawn(msg, socket, cwd2, connectionId = "legacy") {
|
|
460198
460877
|
const { terminal_id, cols, rows } = msg;
|
|
460199
|
-
const
|
|
460878
|
+
const terminalKey = getTerminalKey(connectionId, terminal_id);
|
|
460879
|
+
const existing = terminals.get(terminalKey);
|
|
460200
460880
|
if (existing && Date.now() - existing.spawnedAt < 2000) {
|
|
460201
460881
|
let alive = true;
|
|
460202
460882
|
try {
|
|
@@ -460213,14 +460893,14 @@ function handleTerminalSpawn(msg, socket, cwd2) {
|
|
|
460213
460893
|
});
|
|
460214
460894
|
return;
|
|
460215
460895
|
}
|
|
460216
|
-
terminals.delete(
|
|
460896
|
+
terminals.delete(terminalKey);
|
|
460217
460897
|
}
|
|
460218
|
-
killTerminal(terminal_id);
|
|
460898
|
+
killTerminal(terminal_id, connectionId);
|
|
460219
460899
|
const shell2 = getDefaultShell();
|
|
460220
460900
|
console.log(`[Terminal] Spawning PTY (${IS_BUN ? "bun" : "node-pty"}): shell=${shell2}, cwd=${cwd2}, cols=${cols}, rows=${rows}`);
|
|
460221
460901
|
try {
|
|
460222
|
-
const session = IS_BUN ? spawnBun(shell2, cwd2, cols, rows, terminal_id, socket) : spawnNodePty(shell2, cwd2, cols, rows, terminal_id, socket);
|
|
460223
|
-
terminals.set(
|
|
460902
|
+
const session = IS_BUN ? spawnBun(shell2, cwd2, cols, rows, terminal_id, connectionId, socket) : spawnNodePty(shell2, cwd2, cols, rows, terminal_id, connectionId, socket);
|
|
460903
|
+
terminals.set(terminalKey, session);
|
|
460224
460904
|
console.log(`[Terminal] Session stored for terminal_id=${terminal_id}, pid=${session.pid}`);
|
|
460225
460905
|
sendTerminalMessage(socket, {
|
|
460226
460906
|
type: "terminal_spawned",
|
|
@@ -460237,31 +460917,39 @@ function handleTerminalSpawn(msg, socket, cwd2) {
|
|
|
460237
460917
|
});
|
|
460238
460918
|
}
|
|
460239
460919
|
}
|
|
460240
|
-
function handleTerminalInput(msg) {
|
|
460241
|
-
terminals.get(msg.terminal_id)?.write(msg.data);
|
|
460920
|
+
function handleTerminalInput(msg, connectionId = "legacy") {
|
|
460921
|
+
terminals.get(getTerminalKey(connectionId, msg.terminal_id))?.write(msg.data);
|
|
460242
460922
|
}
|
|
460243
|
-
function handleTerminalResize(msg) {
|
|
460244
|
-
terminals.get(msg.terminal_id)?.resize(msg.cols, msg.rows);
|
|
460923
|
+
function handleTerminalResize(msg, connectionId = "legacy") {
|
|
460924
|
+
terminals.get(getTerminalKey(connectionId, msg.terminal_id))?.resize(msg.cols, msg.rows);
|
|
460245
460925
|
}
|
|
460246
|
-
function handleTerminalKill(msg) {
|
|
460247
|
-
const session = terminals.get(msg.terminal_id);
|
|
460926
|
+
function handleTerminalKill(msg, connectionId = "legacy") {
|
|
460927
|
+
const session = terminals.get(getTerminalKey(connectionId, msg.terminal_id));
|
|
460248
460928
|
if (session && Date.now() - session.spawnedAt < 2000) {
|
|
460249
460929
|
console.log(`[Terminal] Ignoring kill for recently spawned session (age=${Date.now() - session.spawnedAt}ms)`);
|
|
460250
460930
|
return;
|
|
460251
460931
|
}
|
|
460252
|
-
killTerminal(msg.terminal_id);
|
|
460932
|
+
killTerminal(msg.terminal_id, connectionId);
|
|
460253
460933
|
}
|
|
460254
|
-
function killTerminal(terminalId) {
|
|
460255
|
-
const
|
|
460934
|
+
function killTerminal(terminalId, connectionId) {
|
|
460935
|
+
const terminalKey = getTerminalKey(connectionId, terminalId);
|
|
460936
|
+
const session = terminals.get(terminalKey);
|
|
460256
460937
|
if (session) {
|
|
460257
460938
|
console.log(`[Terminal] killTerminal: terminalId=${terminalId}, pid=${session.pid}`);
|
|
460258
460939
|
session.kill();
|
|
460259
|
-
terminals.delete(
|
|
460940
|
+
terminals.delete(terminalKey);
|
|
460941
|
+
}
|
|
460942
|
+
}
|
|
460943
|
+
function killListenerConnectionTerminals(connectionId) {
|
|
460944
|
+
for (const session of [...terminals.values()]) {
|
|
460945
|
+
if (session.connectionId === connectionId) {
|
|
460946
|
+
killTerminal(session.terminalId, connectionId);
|
|
460947
|
+
}
|
|
460260
460948
|
}
|
|
460261
460949
|
}
|
|
460262
460950
|
function killAllTerminals() {
|
|
460263
|
-
for (const
|
|
460264
|
-
killTerminal(
|
|
460951
|
+
for (const session of [...terminals.values()]) {
|
|
460952
|
+
killTerminal(session.terminalId, session.connectionId);
|
|
460265
460953
|
}
|
|
460266
460954
|
}
|
|
460267
460955
|
var IS_BUN, FLUSH_INTERVAL_MS = 16, MAX_BUFFER_BYTES, terminals;
|
|
@@ -460489,7 +461177,7 @@ __export(exports_custom, {
|
|
|
460489
461177
|
GLOBAL_COMMANDS_DIR: () => GLOBAL_COMMANDS_DIR,
|
|
460490
461178
|
COMMANDS_DIR: () => COMMANDS_DIR
|
|
460491
461179
|
});
|
|
460492
|
-
import { existsSync as
|
|
461180
|
+
import { existsSync as existsSync52 } from "node:fs";
|
|
460493
461181
|
import { readdir as readdir10, readFile as readFile20 } from "node:fs/promises";
|
|
460494
461182
|
import { basename as basename25, dirname as dirname28, join as join65 } from "node:path";
|
|
460495
461183
|
async function getCustomCommands() {
|
|
@@ -460523,7 +461211,7 @@ async function discoverCustomCommands(projectPath = join65(process.cwd(), COMMAN
|
|
|
460523
461211
|
return result;
|
|
460524
461212
|
}
|
|
460525
461213
|
async function discoverFromDirectory(dirPath, source2) {
|
|
460526
|
-
if (!
|
|
461214
|
+
if (!existsSync52(dirPath)) {
|
|
460527
461215
|
return [];
|
|
460528
461216
|
}
|
|
460529
461217
|
const commands = [];
|
|
@@ -461488,6 +462176,144 @@ var init_commands2 = __esm(async () => {
|
|
|
461488
462176
|
]);
|
|
461489
462177
|
});
|
|
461490
462178
|
|
|
462179
|
+
// src/websocket/listener/connection-lifecycle.ts
|
|
462180
|
+
import WebSocket5 from "ws";
|
|
462181
|
+
function createConnectionTurnProcessor(runtime) {
|
|
462182
|
+
return async (queuedTurn, dequeuedBatch) => {
|
|
462183
|
+
const scopedRuntime = getOrCreateScopedRuntime(runtime, queuedTurn.agentId, queuedTurn.conversationId);
|
|
462184
|
+
if (!queuedTurn.connectionId) {
|
|
462185
|
+
await handleIncomingMessage(queuedTurn, getOrCreateProcessTransport(runtime), scopedRuntime, undefined, undefined, dequeuedBatch.batchId);
|
|
462186
|
+
return;
|
|
462187
|
+
}
|
|
462188
|
+
const connection = runtime.connections.get(queuedTurn.connectionId);
|
|
462189
|
+
if (!connection || connection.cancellation.signal.aborted) {
|
|
462190
|
+
return;
|
|
462191
|
+
}
|
|
462192
|
+
await handleIncomingMessage(queuedTurn, connection.writer, scopedRuntime, connection.options.onStatusChange, connection.id, dequeuedBatch.batchId);
|
|
462193
|
+
};
|
|
462194
|
+
}
|
|
462195
|
+
function cleanupListenerConnection(runtime, connectionId) {
|
|
462196
|
+
for (const conversationRuntime of runtime.conversationRuntimes.values()) {
|
|
462197
|
+
if (conversationRuntime.activeConnectionId === connectionId) {
|
|
462198
|
+
const hasEligibleFailover = getSubscribedListenerConnections(runtime, {
|
|
462199
|
+
agent_id: conversationRuntime.agentId,
|
|
462200
|
+
conversation_id: conversationRuntime.conversationId
|
|
462201
|
+
}).some((connection) => connection.id !== connectionId);
|
|
462202
|
+
if (hasEligibleFailover) {
|
|
462203
|
+
conversationRuntime.activeConnectionId = null;
|
|
462204
|
+
} else {
|
|
462205
|
+
conversationRuntime.turnLifecycle.requestCancellation();
|
|
462206
|
+
}
|
|
462207
|
+
}
|
|
462208
|
+
for (const [
|
|
462209
|
+
itemId,
|
|
462210
|
+
queuedMessage
|
|
462211
|
+
] of conversationRuntime.queuedMessagesByItemId) {
|
|
462212
|
+
if (queuedMessage.connectionId === connectionId) {
|
|
462213
|
+
conversationRuntime.queueRuntime.removeItem(itemId);
|
|
462214
|
+
conversationRuntime.queuedMessagesByItemId.delete(itemId);
|
|
462215
|
+
}
|
|
462216
|
+
}
|
|
462217
|
+
rejectPendingApprovalResolversForConnection(conversationRuntime, connectionId, "Listener connection closed");
|
|
462218
|
+
}
|
|
462219
|
+
rejectPendingExternalToolCallsForConnection(runtime, connectionId, "Listener connection closed");
|
|
462220
|
+
killListenerConnectionTerminals(connectionId);
|
|
462221
|
+
const closedSubscriptionKeys = [
|
|
462222
|
+
...runtime.connections.get(connectionId)?.subscriptions ?? []
|
|
462223
|
+
];
|
|
462224
|
+
closeListenerConnection(runtime, connectionId);
|
|
462225
|
+
for (const runtimeKey of closedSubscriptionKeys) {
|
|
462226
|
+
if (!runtime.connectionIdsByRuntimeKey.has(runtimeKey)) {
|
|
462227
|
+
const scopedRuntime = runtime.conversationRuntimes.get(runtimeKey);
|
|
462228
|
+
if (scopedRuntime) {
|
|
462229
|
+
evictConversationRuntimeIfIdle(scopedRuntime);
|
|
462230
|
+
}
|
|
462231
|
+
}
|
|
462232
|
+
}
|
|
462233
|
+
}
|
|
462234
|
+
function closeListenerRuntimeConnections(runtime, suppressCallbacks) {
|
|
462235
|
+
const socketsToClose = new Set;
|
|
462236
|
+
const collectSocket = (transport) => {
|
|
462237
|
+
if (transport && getListenerTransportKind(transport) === "websocket") {
|
|
462238
|
+
socketsToClose.add(transport);
|
|
462239
|
+
}
|
|
462240
|
+
};
|
|
462241
|
+
if (runtime.socket) {
|
|
462242
|
+
socketsToClose.add(runtime.socket);
|
|
462243
|
+
}
|
|
462244
|
+
if (runtime.streamSocket) {
|
|
462245
|
+
socketsToClose.add(runtime.streamSocket);
|
|
462246
|
+
}
|
|
462247
|
+
for (const connection of runtime.connections.values()) {
|
|
462248
|
+
collectSocket(connection.writer);
|
|
462249
|
+
collectSocket(connection.streamWriter);
|
|
462250
|
+
}
|
|
462251
|
+
for (const connectionId of [...runtime.connections.keys()]) {
|
|
462252
|
+
closeListenerConnection(runtime, connectionId);
|
|
462253
|
+
}
|
|
462254
|
+
runtime.connectionIdsByRuntimeKey.clear();
|
|
462255
|
+
runtime.socket = null;
|
|
462256
|
+
runtime.transport = null;
|
|
462257
|
+
runtime.streamSocket = null;
|
|
462258
|
+
runtime.streamTransport = null;
|
|
462259
|
+
for (const socket of socketsToClose) {
|
|
462260
|
+
if (suppressCallbacks) {
|
|
462261
|
+
socket.removeAllListeners();
|
|
462262
|
+
}
|
|
462263
|
+
if (socket.readyState === WebSocket5.OPEN || socket.readyState === WebSocket5.CONNECTING) {
|
|
462264
|
+
socket.close();
|
|
462265
|
+
}
|
|
462266
|
+
}
|
|
462267
|
+
}
|
|
462268
|
+
var init_connection_lifecycle = __esm(async () => {
|
|
462269
|
+
init_terminal_handler();
|
|
462270
|
+
init_connection();
|
|
462271
|
+
init_runtime6();
|
|
462272
|
+
init_transport();
|
|
462273
|
+
await __promiseAll([
|
|
462274
|
+
init_approval(),
|
|
462275
|
+
init_conversation_runtime(),
|
|
462276
|
+
init_external_tools(),
|
|
462277
|
+
init_turn()
|
|
462278
|
+
]);
|
|
462279
|
+
});
|
|
462280
|
+
|
|
462281
|
+
// src/websocket/listener/connection-state-sync.ts
|
|
462282
|
+
function emitInitialConnectionState(runtime, transport, connectionId, options3 = {}) {
|
|
462283
|
+
if (options3.emitInitialState === false)
|
|
462284
|
+
return;
|
|
462285
|
+
const routing = toListenerConnection(connectionId);
|
|
462286
|
+
if (runtime.conversationRuntimes.size === 0) {
|
|
462287
|
+
emitLoopStatusUpdate(transport, runtime, undefined, routing);
|
|
462288
|
+
return;
|
|
462289
|
+
}
|
|
462290
|
+
for (const conversationRuntime of runtime.conversationRuntimes.values()) {
|
|
462291
|
+
const scope = {
|
|
462292
|
+
agent_id: conversationRuntime.agentId,
|
|
462293
|
+
conversation_id: conversationRuntime.conversationId
|
|
462294
|
+
};
|
|
462295
|
+
emitDeviceStatusUpdate(transport, conversationRuntime, scope, routing);
|
|
462296
|
+
emitLoopStatusUpdate(transport, conversationRuntime, scope, routing);
|
|
462297
|
+
}
|
|
462298
|
+
}
|
|
462299
|
+
function replaySubscribedConnectionState(listener, transport, runtime, scope, forceDeviceStatus) {
|
|
462300
|
+
const connection = findListenerConnectionByTransport(listener, transport);
|
|
462301
|
+
if (connection) {
|
|
462302
|
+
replayPendingApprovalRequestsToConnection(runtime, connection.id);
|
|
462303
|
+
}
|
|
462304
|
+
emitStateSync(transport, listener, scope, {
|
|
462305
|
+
forceDeviceStatus,
|
|
462306
|
+
...connection ? { routing: toListenerConnection(connection.id) } : {}
|
|
462307
|
+
});
|
|
462308
|
+
}
|
|
462309
|
+
var init_connection_state_sync = __esm(async () => {
|
|
462310
|
+
init_connection();
|
|
462311
|
+
await __promiseAll([
|
|
462312
|
+
init_approval(),
|
|
462313
|
+
init_protocol_outbound()
|
|
462314
|
+
]);
|
|
462315
|
+
});
|
|
462316
|
+
|
|
461491
462317
|
// src/websocket/listener/grep-in-files.ts
|
|
461492
462318
|
import { execFile as execFile14 } from "node:child_process";
|
|
461493
462319
|
import { createRequire as createRequire6 } from "node:module";
|
|
@@ -462356,7 +463182,7 @@ function buildAppServerInfoResponse(command, options3) {
|
|
|
462356
463182
|
conversation_management: true,
|
|
462357
463183
|
memory_management: true,
|
|
462358
463184
|
runtime_start: true,
|
|
462359
|
-
split_channels:
|
|
463185
|
+
split_channels: false
|
|
462360
463186
|
}
|
|
462361
463187
|
};
|
|
462362
463188
|
}
|
|
@@ -463701,6 +464527,7 @@ function createListenerMessageHandler(params) {
|
|
|
463701
464527
|
const {
|
|
463702
464528
|
runtime,
|
|
463703
464529
|
socket,
|
|
464530
|
+
connectionId: explicitConnectionId,
|
|
463704
464531
|
opts,
|
|
463705
464532
|
processQueuedTurn,
|
|
463706
464533
|
fileCommandSession,
|
|
@@ -463717,6 +464544,7 @@ function createListenerMessageHandler(params) {
|
|
|
463717
464544
|
wireChannelIngress,
|
|
463718
464545
|
processIncomingMessage = handleIncomingMessage
|
|
463719
464546
|
} = params;
|
|
464547
|
+
const connectionId = explicitConnectionId ?? opts.connectionId;
|
|
463720
464548
|
return async (data) => {
|
|
463721
464549
|
const raw2 = data.toString();
|
|
463722
464550
|
let parsedScope = null;
|
|
@@ -463746,6 +464574,9 @@ function createListenerMessageHandler(params) {
|
|
|
463746
464574
|
return;
|
|
463747
464575
|
}
|
|
463748
464576
|
console.log(`[Listen V2] Received ${summarizeV2Command(parsed)}`);
|
|
464577
|
+
if (parsedScope) {
|
|
464578
|
+
subscribeListenerConnection(runtime, connectionId, parsedScope);
|
|
464579
|
+
}
|
|
463749
464580
|
if (parsed.type === "__invalid_input") {
|
|
463750
464581
|
emitLoopErrorNotice(socket, runtime, {
|
|
463751
464582
|
message: parsed.reason,
|
|
@@ -463762,6 +464593,7 @@ function createListenerMessageHandler(params) {
|
|
|
463762
464593
|
}
|
|
463763
464594
|
if (handleRuntimeStartProtocolCommand(parsed, {
|
|
463764
464595
|
socket,
|
|
464596
|
+
connectionId,
|
|
463765
464597
|
runtime,
|
|
463766
464598
|
safeSocketSend,
|
|
463767
464599
|
runDetachedListenerTask,
|
|
@@ -463771,7 +464603,7 @@ function createListenerMessageHandler(params) {
|
|
|
463771
464603
|
return;
|
|
463772
464604
|
}
|
|
463773
464605
|
if (parsed.type === "external_tool_call_response") {
|
|
463774
|
-
handleExternalToolCallResponseCommand(runtime, parsed);
|
|
464606
|
+
handleExternalToolCallResponseCommand(runtime, connectionId, parsed);
|
|
463775
464607
|
return;
|
|
463776
464608
|
}
|
|
463777
464609
|
if (parsed.type === "sync") {
|
|
@@ -463825,6 +464657,7 @@ function createListenerMessageHandler(params) {
|
|
|
463825
464657
|
if (await handleApprovalResponseInput2(runtime, {
|
|
463826
464658
|
runtime: parsed.runtime,
|
|
463827
464659
|
response: parsed.payload,
|
|
464660
|
+
connectionId,
|
|
463828
464661
|
socket,
|
|
463829
464662
|
opts: {
|
|
463830
464663
|
onStatusChange: opts.onStatusChange,
|
|
@@ -463849,6 +464682,7 @@ function createListenerMessageHandler(params) {
|
|
|
463849
464682
|
}
|
|
463850
464683
|
const incoming = {
|
|
463851
464684
|
type: "message",
|
|
464685
|
+
connectionId,
|
|
463852
464686
|
agentId: parsed.runtime.agent_id,
|
|
463853
464687
|
conversationId: parsed.runtime.conversation_id,
|
|
463854
464688
|
clientToolAllowlist: inputPayload.client_tool_allowlist,
|
|
@@ -463897,6 +464731,7 @@ function createListenerMessageHandler(params) {
|
|
|
463897
464731
|
if (parsed.type === "change_device_state") {
|
|
463898
464732
|
await handleChangeDeviceStateInput2(runtime, {
|
|
463899
464733
|
command: parsed,
|
|
464734
|
+
connectionId,
|
|
463900
464735
|
socket,
|
|
463901
464736
|
opts: {
|
|
463902
464737
|
onStatusChange: opts.onStatusChange,
|
|
@@ -463923,6 +464758,7 @@ function createListenerMessageHandler(params) {
|
|
|
463923
464758
|
try {
|
|
463924
464759
|
const aborted2 = await handleAbortMessageInput2(runtime, {
|
|
463925
464760
|
command: parsed,
|
|
464761
|
+
connectionId,
|
|
463926
464762
|
socket,
|
|
463927
464763
|
opts: {
|
|
463928
464764
|
onStatusChange: opts.onStatusChange,
|
|
@@ -464092,19 +464928,19 @@ function createListenerMessageHandler(params) {
|
|
|
464092
464928
|
return;
|
|
464093
464929
|
}
|
|
464094
464930
|
if (parsed.type === "terminal_spawn") {
|
|
464095
|
-
handleTerminalSpawn(parsed, socket, parsed.cwd ?? getBootWorkingDirectory(runtime));
|
|
464931
|
+
handleTerminalSpawn(parsed, socket, parsed.cwd ?? getBootWorkingDirectory(runtime), connectionId);
|
|
464096
464932
|
return;
|
|
464097
464933
|
}
|
|
464098
464934
|
if (parsed.type === "terminal_input") {
|
|
464099
|
-
handleTerminalInput(parsed);
|
|
464935
|
+
handleTerminalInput(parsed, connectionId);
|
|
464100
464936
|
return;
|
|
464101
464937
|
}
|
|
464102
464938
|
if (parsed.type === "terminal_resize") {
|
|
464103
|
-
handleTerminalResize(parsed);
|
|
464939
|
+
handleTerminalResize(parsed, connectionId);
|
|
464104
464940
|
return;
|
|
464105
464941
|
}
|
|
464106
464942
|
if (parsed.type === "terminal_kill") {
|
|
464107
|
-
handleTerminalKill(parsed);
|
|
464943
|
+
handleTerminalKill(parsed, connectionId);
|
|
464108
464944
|
}
|
|
464109
464945
|
} catch (error54) {
|
|
464110
464946
|
trackListenerError4("listener_message_handler_failed", error54, "listener_message_handler");
|
|
@@ -464131,6 +464967,7 @@ var init_message_router = __esm(async () => {
|
|
|
464131
464967
|
init_debug();
|
|
464132
464968
|
init_terminal_handler();
|
|
464133
464969
|
init_app_server_info();
|
|
464970
|
+
init_connection();
|
|
464134
464971
|
init_cwd();
|
|
464135
464972
|
init_runtime6();
|
|
464136
464973
|
await __promiseAll([
|
|
@@ -464157,6 +464994,97 @@ var init_message_router = __esm(async () => {
|
|
|
464157
464994
|
]);
|
|
464158
464995
|
});
|
|
464159
464996
|
|
|
464997
|
+
// src/websocket/listener/process-services.ts
|
|
464998
|
+
function installProcessEventRouting(params) {
|
|
464999
|
+
const { runtime, processTransport, opts, processQueuedTurn } = params;
|
|
465000
|
+
runtime._unsubscribeSubagentState?.();
|
|
465001
|
+
runtime._unsubscribeSubagentState = subscribe(() => {
|
|
465002
|
+
if (runtime.conversationRuntimes.size === 0) {
|
|
465003
|
+
emitSubagentStateIfOpen(runtime);
|
|
465004
|
+
return;
|
|
465005
|
+
}
|
|
465006
|
+
for (const conversationRuntime of runtime.conversationRuntimes.values()) {
|
|
465007
|
+
emitSubagentStateIfOpen(runtime, {
|
|
465008
|
+
agent_id: conversationRuntime.agentId,
|
|
465009
|
+
conversation_id: conversationRuntime.conversationId
|
|
465010
|
+
});
|
|
465011
|
+
}
|
|
465012
|
+
});
|
|
465013
|
+
runtime._unsubscribeSubagentStreamEvents?.();
|
|
465014
|
+
runtime._unsubscribeSubagentStreamEvents = subscribeToStreamEvents((subagentId, event2) => {
|
|
465015
|
+
if (!isListenerTransportOpen(processTransport))
|
|
465016
|
+
return;
|
|
465017
|
+
const subagent = getSubagents().find((entry) => entry.id === subagentId);
|
|
465018
|
+
if (subagent?.silent === true)
|
|
465019
|
+
return;
|
|
465020
|
+
emitStreamDelta(processTransport, runtime, event2, subagent?.parentAgentId ? {
|
|
465021
|
+
agent_id: subagent.parentAgentId,
|
|
465022
|
+
conversation_id: subagent.parentConversationId ?? "default"
|
|
465023
|
+
} : undefined, subagentId);
|
|
465024
|
+
});
|
|
465025
|
+
setMessageQueueAdder((queuedMessage) => {
|
|
465026
|
+
if (!queuedMessage.agentId || !queuedMessage.conversationId)
|
|
465027
|
+
return;
|
|
465028
|
+
const targetRuntime = getOrCreateScopedRuntime(runtime, queuedMessage.agentId, queuedMessage.conversationId);
|
|
465029
|
+
if (!targetRuntime?.queueRuntime)
|
|
465030
|
+
return;
|
|
465031
|
+
targetRuntime.queueRuntime.enqueue({
|
|
465032
|
+
kind: "task_notification",
|
|
465033
|
+
source: "task_notification",
|
|
465034
|
+
text: queuedMessage.text,
|
|
465035
|
+
agentId: queuedMessage.agentId ?? targetRuntime.agentId ?? undefined,
|
|
465036
|
+
conversationId: queuedMessage.conversationId ?? targetRuntime.conversationId
|
|
465037
|
+
});
|
|
465038
|
+
scheduleQueuePump(targetRuntime, processTransport, opts, processQueuedTurn);
|
|
465039
|
+
});
|
|
465040
|
+
}
|
|
465041
|
+
function clearProcessServices(runtime) {
|
|
465042
|
+
runtime._unsubscribeSubagentState?.();
|
|
465043
|
+
runtime._unsubscribeSubagentState = undefined;
|
|
465044
|
+
runtime._unsubscribeSubagentStreamEvents?.();
|
|
465045
|
+
runtime._unsubscribeSubagentStreamEvents = undefined;
|
|
465046
|
+
setMessageQueueAdder(null);
|
|
465047
|
+
stopScheduler();
|
|
465048
|
+
clearRuntimeTimers(runtime);
|
|
465049
|
+
runtime.processServicesStarted = false;
|
|
465050
|
+
}
|
|
465051
|
+
function invalidateProcessServices(runtime) {
|
|
465052
|
+
runtime.processServicesGeneration += 1;
|
|
465053
|
+
clearProcessServices(runtime);
|
|
465054
|
+
}
|
|
465055
|
+
async function waitForProcessServicesSlot(runtime, connectionId) {
|
|
465056
|
+
const initiatingConnection = runtime.connections.get(connectionId);
|
|
465057
|
+
const canInitiate = () => !initiatingConnection || runtime.connections.get(connectionId) === initiatingConnection && !initiatingConnection.cancellation.signal.aborted;
|
|
465058
|
+
while (runtime.processServicesReady) {
|
|
465059
|
+
const pending = runtime.processServicesReady;
|
|
465060
|
+
const pendingGeneration = runtime.processServicesReadyGeneration;
|
|
465061
|
+
try {
|
|
465062
|
+
await pending;
|
|
465063
|
+
} catch (error54) {
|
|
465064
|
+
if (pendingGeneration === runtime.processServicesGeneration)
|
|
465065
|
+
throw error54;
|
|
465066
|
+
}
|
|
465067
|
+
if (runtime.processServicesStarted)
|
|
465068
|
+
return false;
|
|
465069
|
+
if (runtime !== getActiveRuntime() || runtime.intentionallyClosed || !canInitiate()) {
|
|
465070
|
+
return false;
|
|
465071
|
+
}
|
|
465072
|
+
}
|
|
465073
|
+
return canInitiate();
|
|
465074
|
+
}
|
|
465075
|
+
var init_process_services = __esm(async () => {
|
|
465076
|
+
init_subagent_state();
|
|
465077
|
+
init_message_queue_bridge();
|
|
465078
|
+
init_runtime6();
|
|
465079
|
+
init_transport();
|
|
465080
|
+
await __promiseAll([
|
|
465081
|
+
init_scheduler(),
|
|
465082
|
+
init_conversation_runtime(),
|
|
465083
|
+
init_protocol_outbound(),
|
|
465084
|
+
init_queue()
|
|
465085
|
+
]);
|
|
465086
|
+
});
|
|
465087
|
+
|
|
464160
465088
|
// src/websocket/listener/lifecycle.ts
|
|
464161
465089
|
import WebSocket6 from "ws";
|
|
464162
465090
|
function trackListenerError4(errorType, error54, context3) {
|
|
@@ -464219,9 +465147,7 @@ async function replaySyncStateForRuntime(listenerRuntime, socket, scope, opts) {
|
|
|
464219
465147
|
}
|
|
464220
465148
|
}
|
|
464221
465149
|
}
|
|
464222
|
-
|
|
464223
|
-
forceDeviceStatus: opts?.forceDeviceStatus
|
|
464224
|
-
});
|
|
465150
|
+
replaySubscribedConnectionState(listenerRuntime, socket, syncScopedRuntime, scope, opts?.forceDeviceStatus);
|
|
464225
465151
|
(opts?.scheduleWarmupsAfterSync ?? scheduleListenerWarmupsAfterSync)(listenerRuntime, scope);
|
|
464226
465152
|
}
|
|
464227
465153
|
async function recoverPendingChannelControlRequests(listener, opts) {
|
|
@@ -464253,7 +465179,7 @@ async function recoverPendingChannelControlRequests(listener, opts) {
|
|
|
464253
465179
|
}
|
|
464254
465180
|
for (const { scope, entries } of entriesByScope.values()) {
|
|
464255
465181
|
const runtime = getOrCreateScopedRuntime(listener, scope.agent_id, scope.conversation_id);
|
|
464256
|
-
const livePendingRequestIds =
|
|
465182
|
+
const livePendingRequestIds = getPendingApprovalRequestIds(runtime);
|
|
464257
465183
|
const shouldRecoverFromBackend = entries.some((entry) => !livePendingRequestIds.has(entry.event.requestId));
|
|
464258
465184
|
if (shouldRecoverFromBackend) {
|
|
464259
465185
|
try {
|
|
@@ -464378,7 +465304,7 @@ async function wireChannelIngress(listener, socket, opts, processQueuedTurn) {
|
|
|
464378
465304
|
scheduleQueuePump(conversationRuntime, socket, opts, processQueuedTurn);
|
|
464379
465305
|
});
|
|
464380
465306
|
registry2.setEventHandler((event2) => {
|
|
464381
|
-
handleChannelRegistryEvent(event2, socket, listener
|
|
465307
|
+
handleChannelRegistryEvent(event2, socket, listener);
|
|
464382
465308
|
});
|
|
464383
465309
|
await recoverPendingChannelControlRequests(listener);
|
|
464384
465310
|
registry2.setApprovalResponseHandler(async ({ runtime, response }) => handleApprovalResponseInput(listener, {
|
|
@@ -464643,6 +465569,14 @@ function createRuntime() {
|
|
|
464643
465569
|
hasSuccessfulConnection: false,
|
|
464644
465570
|
everConnected: false,
|
|
464645
465571
|
sessionId: `listen-${crypto.randomUUID()}`,
|
|
465572
|
+
nextConnectionOrdinal: 0,
|
|
465573
|
+
connections: new Map,
|
|
465574
|
+
connectionIdsByRuntimeKey: new Map,
|
|
465575
|
+
processTransport: null,
|
|
465576
|
+
processServicesStarted: false,
|
|
465577
|
+
processServicesGeneration: 0,
|
|
465578
|
+
processServicesReady: null,
|
|
465579
|
+
processServicesReadyGeneration: null,
|
|
464646
465580
|
eventSeqCounter: 0,
|
|
464647
465581
|
queueEmitScheduled: false,
|
|
464648
465582
|
pendingQueueEmitScope: undefined,
|
|
@@ -464660,7 +465594,6 @@ function createRuntime() {
|
|
|
464660
465594
|
connectionId: null,
|
|
464661
465595
|
connectionName: null,
|
|
464662
465596
|
conversationRuntimes: new Map,
|
|
464663
|
-
approvalRuntimeKeyByRequestId: new Map,
|
|
464664
465597
|
memfsSyncedAgents: new Map,
|
|
464665
465598
|
secretsHydrationByAgent: new Map,
|
|
464666
465599
|
secretsHydrationFreshnessByAgent: new Map,
|
|
@@ -464674,9 +465607,8 @@ function stopRuntime(runtime, suppressCallbacks) {
|
|
|
464674
465607
|
notifyStreamObserversRuntimeStopped(runtime);
|
|
464675
465608
|
disposeListenerModAdapter(runtime);
|
|
464676
465609
|
rejectPendingExternalToolCalls(runtime, "Listener runtime stopped");
|
|
464677
|
-
setMessageQueueAdder(null);
|
|
464678
465610
|
runtime.intentionallyClosed = true;
|
|
464679
|
-
|
|
465611
|
+
invalidateProcessServices(runtime);
|
|
464680
465612
|
for (const conversationRuntime of runtime.conversationRuntimes.values()) {
|
|
464681
465613
|
rejectPendingApprovalResolvers(conversationRuntime, "Listener runtime stopped");
|
|
464682
465614
|
clearConversationRuntimeState(conversationRuntime);
|
|
@@ -464686,7 +465618,9 @@ function stopRuntime(runtime, suppressCallbacks) {
|
|
|
464686
465618
|
}
|
|
464687
465619
|
}
|
|
464688
465620
|
runtime.conversationRuntimes.clear();
|
|
464689
|
-
runtime
|
|
465621
|
+
closeListenerRuntimeConnections(runtime, suppressCallbacks);
|
|
465622
|
+
runtime.processServicesReady = null;
|
|
465623
|
+
runtime.processServicesReadyGeneration = null;
|
|
464690
465624
|
clearListenerWarmState(runtime);
|
|
464691
465625
|
runtime.reminderStateByConversation.clear();
|
|
464692
465626
|
runtime.skillSourcesByConversation.clear();
|
|
@@ -464694,30 +465628,6 @@ function stopRuntime(runtime, suppressCallbacks) {
|
|
|
464694
465628
|
runtime.systemPromptRecompileByConversation.clear();
|
|
464695
465629
|
runtime.queuedSystemPromptRecompileByConversation.clear();
|
|
464696
465630
|
stopAllWorktreeWatchers(runtime);
|
|
464697
|
-
if (!runtime.socket) {
|
|
464698
|
-
if (runtime.streamSocket && (runtime.streamSocket.readyState === WebSocket6.OPEN || runtime.streamSocket.readyState === WebSocket6.CONNECTING)) {
|
|
464699
|
-
runtime.streamSocket.close();
|
|
464700
|
-
}
|
|
464701
|
-
runtime.streamSocket = null;
|
|
464702
|
-
runtime.streamTransport = null;
|
|
464703
|
-
runtime.transport = null;
|
|
464704
|
-
return;
|
|
464705
|
-
}
|
|
464706
|
-
const socket = runtime.socket;
|
|
464707
|
-
runtime.socket = null;
|
|
464708
|
-
runtime.transport = null;
|
|
464709
|
-
const streamSocket = runtime.streamSocket;
|
|
464710
|
-
runtime.streamSocket = null;
|
|
464711
|
-
runtime.streamTransport = null;
|
|
464712
|
-
if (suppressCallbacks) {
|
|
464713
|
-
socket.removeAllListeners();
|
|
464714
|
-
}
|
|
464715
|
-
if (socket.readyState === WebSocket6.OPEN || socket.readyState === WebSocket6.CONNECTING) {
|
|
464716
|
-
socket.close();
|
|
464717
|
-
}
|
|
464718
|
-
if (streamSocket && (streamSocket.readyState === WebSocket6.OPEN || streamSocket.readyState === WebSocket6.CONNECTING)) {
|
|
464719
|
-
streamSocket.close();
|
|
464720
|
-
}
|
|
464721
465631
|
}
|
|
464722
465632
|
async function startConnectedListenerRuntime(runtime, transport, opts, processQueuedTurn, options3 = {}) {
|
|
464723
465633
|
if (runtime !== getActiveRuntime() || runtime.intentionallyClosed) {
|
|
@@ -464726,103 +465636,88 @@ async function startConnectedListenerRuntime(runtime, transport, opts, processQu
|
|
|
464726
465636
|
const shouldStartHeartbeat = options3.startHeartbeat !== false;
|
|
464727
465637
|
const cronSchedulerDisabledByEnv = process.env.LETTA_DISABLE_CRON_SCHEDULER === "1";
|
|
464728
465638
|
const shouldStartCronScheduler = options3.startCronScheduler !== false && !cronSchedulerDisabledByEnv;
|
|
464729
|
-
runtime.
|
|
464730
|
-
runtime.streamTransport = options3.streamTransport ?? null;
|
|
465639
|
+
markListenerConnectionInitialized(runtime, opts.connectionId);
|
|
464731
465640
|
safeEmitWsEvent("recv", "lifecycle", {
|
|
464732
465641
|
type: getListenerTransportKind(transport) === "websocket" ? "_ws_open" : "_local_open"
|
|
464733
465642
|
});
|
|
464734
465643
|
runtime.hasSuccessfulConnection = true;
|
|
464735
465644
|
runtime.everConnected = true;
|
|
464736
465645
|
opts.onConnected(opts.connectionId);
|
|
464737
|
-
|
|
464738
|
-
|
|
464739
|
-
|
|
464740
|
-
for (const conversationRuntime of runtime.conversationRuntimes.values()) {
|
|
464741
|
-
const scope = {
|
|
464742
|
-
agent_id: conversationRuntime.agentId,
|
|
464743
|
-
conversation_id: conversationRuntime.conversationId
|
|
464744
|
-
};
|
|
464745
|
-
emitDeviceStatusUpdate(transport, conversationRuntime, scope);
|
|
464746
|
-
emitLoopStatusUpdate(transport, conversationRuntime, scope);
|
|
464747
|
-
}
|
|
465646
|
+
emitInitialConnectionState(runtime, transport, opts.connectionId, options3);
|
|
465647
|
+
if (runtime.processServicesStarted) {
|
|
465648
|
+
return;
|
|
464748
465649
|
}
|
|
464749
|
-
runtime.
|
|
464750
|
-
|
|
464751
|
-
|
|
464752
|
-
|
|
464753
|
-
|
|
465650
|
+
if (!await waitForProcessServicesSlot(runtime, opts.connectionId))
|
|
465651
|
+
return;
|
|
465652
|
+
const processServicesGeneration = runtime.processServicesGeneration + 1;
|
|
465653
|
+
runtime.processServicesGeneration = processServicesGeneration;
|
|
465654
|
+
const processServicesReady = (async () => {
|
|
465655
|
+
const processTransport = getOrCreateProcessTransport(runtime);
|
|
465656
|
+
installProcessEventRouting({
|
|
465657
|
+
runtime,
|
|
465658
|
+
processTransport,
|
|
465659
|
+
opts,
|
|
465660
|
+
processQueuedTurn
|
|
465661
|
+
});
|
|
465662
|
+
if (shouldStartHeartbeat) {
|
|
465663
|
+
runtime.lastPongAt = Date.now();
|
|
465664
|
+
runtime.heartbeatInterval = setInterval(() => {
|
|
465665
|
+
if (getListenerTransportKind(transport) === "websocket" && isListenerPongStale(runtime.lastPongAt, Date.now(), LISTENER_PONG_TIMEOUT_MS)) {
|
|
465666
|
+
trackListenerError4("listener_pong_timeout", new Error(`No relay pong within ${LISTENER_PONG_TIMEOUT_MS}ms; terminating half-open socket to force reconnect`), "listener_heartbeat");
|
|
465667
|
+
runtime.socket?.terminate();
|
|
465668
|
+
return;
|
|
465669
|
+
}
|
|
465670
|
+
safeTransportSend(transport, { type: "ping" }, "listener_ping_send_failed", "listener_heartbeat");
|
|
465671
|
+
}, LISTENER_HEARTBEAT_INTERVAL_MS);
|
|
464754
465672
|
}
|
|
464755
|
-
|
|
464756
|
-
|
|
464757
|
-
agent_id: conversationRuntime.agentId,
|
|
464758
|
-
conversation_id: conversationRuntime.conversationId
|
|
464759
|
-
});
|
|
465673
|
+
if (shouldStartCronScheduler) {
|
|
465674
|
+
startScheduler(processTransport, opts, processQueuedTurn);
|
|
464760
465675
|
}
|
|
464761
|
-
|
|
464762
|
-
|
|
464763
|
-
|
|
464764
|
-
if (!isListenerTransportOpen(transport))
|
|
464765
|
-
return;
|
|
464766
|
-
const subagent = getSubagents().find((entry) => entry.id === subagentId);
|
|
464767
|
-
if (subagent?.silent === true) {
|
|
464768
|
-
return;
|
|
465676
|
+
await (options3.wireChannelIngress ?? wireChannelIngress)(runtime, processTransport, opts, processQueuedTurn);
|
|
465677
|
+
if (runtime.processServicesGeneration === processServicesGeneration) {
|
|
465678
|
+
runtime.processServicesStarted = true;
|
|
464769
465679
|
}
|
|
464770
|
-
|
|
464771
|
-
|
|
464772
|
-
|
|
464773
|
-
|
|
464774
|
-
|
|
464775
|
-
|
|
464776
|
-
|
|
464777
|
-
if (!targetRuntime?.queueRuntime) {
|
|
465680
|
+
})();
|
|
465681
|
+
runtime.processServicesReady = processServicesReady;
|
|
465682
|
+
runtime.processServicesReadyGeneration = processServicesGeneration;
|
|
465683
|
+
try {
|
|
465684
|
+
await processServicesReady;
|
|
465685
|
+
} catch (error54) {
|
|
465686
|
+
if (runtime.processServicesGeneration !== processServicesGeneration)
|
|
464778
465687
|
return;
|
|
465688
|
+
clearProcessServices(runtime);
|
|
465689
|
+
throw error54;
|
|
465690
|
+
} finally {
|
|
465691
|
+
if (runtime.processServicesReady === processServicesReady) {
|
|
465692
|
+
runtime.processServicesReady = null;
|
|
465693
|
+
runtime.processServicesReadyGeneration = null;
|
|
464779
465694
|
}
|
|
464780
|
-
targetRuntime.queueRuntime.enqueue({
|
|
464781
|
-
kind: "task_notification",
|
|
464782
|
-
source: "task_notification",
|
|
464783
|
-
text: queuedMessage.text,
|
|
464784
|
-
agentId: queuedMessage.agentId ?? targetRuntime.agentId ?? undefined,
|
|
464785
|
-
conversationId: queuedMessage.conversationId ?? targetRuntime.conversationId
|
|
464786
|
-
});
|
|
464787
|
-
scheduleQueuePump(targetRuntime, transport, opts, processQueuedTurn);
|
|
464788
|
-
});
|
|
464789
|
-
if (shouldStartHeartbeat) {
|
|
464790
|
-
runtime.lastPongAt = Date.now();
|
|
464791
|
-
runtime.heartbeatInterval = setInterval(() => {
|
|
464792
|
-
if (getListenerTransportKind(transport) === "websocket" && isListenerPongStale(runtime.lastPongAt, Date.now(), LISTENER_PONG_TIMEOUT_MS)) {
|
|
464793
|
-
trackListenerError4("listener_pong_timeout", new Error(`No relay pong within ${LISTENER_PONG_TIMEOUT_MS}ms; terminating half-open socket to force reconnect`), "listener_heartbeat");
|
|
464794
|
-
runtime.socket?.terminate();
|
|
464795
|
-
return;
|
|
464796
|
-
}
|
|
464797
|
-
safeTransportSend(transport, { type: "ping" }, "listener_ping_send_failed", "listener_heartbeat");
|
|
464798
|
-
}, LISTENER_HEARTBEAT_INTERVAL_MS);
|
|
464799
465695
|
}
|
|
464800
|
-
if (shouldStartCronScheduler) {
|
|
464801
|
-
startScheduler(transport, opts, processQueuedTurn);
|
|
464802
|
-
}
|
|
464803
|
-
await wireChannelIngress(runtime, transport, opts, processQueuedTurn);
|
|
464804
465696
|
}
|
|
464805
465697
|
async function attachOpenListenerSocket(runtime, socket, opts, options3 = {}) {
|
|
464806
465698
|
if (runtime !== getActiveRuntime() || runtime.intentionallyClosed) {
|
|
464807
465699
|
return;
|
|
464808
465700
|
}
|
|
464809
465701
|
const streamSocket = options3.streamSocket ?? null;
|
|
465702
|
+
const connection = openListenerConnection({
|
|
465703
|
+
runtime,
|
|
465704
|
+
connectionId: opts.connectionId,
|
|
465705
|
+
writer: socket,
|
|
465706
|
+
streamWriter: streamSocket,
|
|
465707
|
+
options: opts
|
|
465708
|
+
});
|
|
464810
465709
|
const fileCommandSession = createFileCommandSession({
|
|
464811
465710
|
socket,
|
|
464812
465711
|
safeSocketSend,
|
|
464813
465712
|
runDetachedListenerTask
|
|
464814
465713
|
});
|
|
464815
|
-
runtime.socket = socket;
|
|
464816
|
-
runtime.streamSocket = streamSocket;
|
|
464817
465714
|
installExternalToolBridge(runtime);
|
|
464818
465715
|
const transport = socket;
|
|
464819
|
-
const processQueuedTurn =
|
|
464820
|
-
const scopedRuntime = getOrCreateScopedRuntime(runtime, queuedTurn.agentId, queuedTurn.conversationId);
|
|
464821
|
-
await handleIncomingMessage(queuedTurn, transport, scopedRuntime, opts.onStatusChange, opts.connectionId, dequeuedBatch.batchId);
|
|
464822
|
-
};
|
|
465716
|
+
const processQueuedTurn = createConnectionTurnProcessor(runtime);
|
|
464823
465717
|
const handleMessage = createListenerMessageHandler({
|
|
464824
465718
|
runtime,
|
|
464825
465719
|
socket,
|
|
465720
|
+
connectionId: opts.connectionId,
|
|
464826
465721
|
opts,
|
|
464827
465722
|
processQueuedTurn,
|
|
464828
465723
|
fileCommandSession,
|
|
@@ -464841,6 +465736,9 @@ async function attachOpenListenerSocket(runtime, socket, opts, options3 = {}) {
|
|
|
464841
465736
|
socket.on("message", (data) => {
|
|
464842
465737
|
(async () => {
|
|
464843
465738
|
await options3.startupReady;
|
|
465739
|
+
if (connection.cancellation.signal.aborted || runtime.connections.get(opts.connectionId) !== connection) {
|
|
465740
|
+
return;
|
|
465741
|
+
}
|
|
464844
465742
|
await handleMessage(data);
|
|
464845
465743
|
})().catch((error54) => {
|
|
464846
465744
|
trackListenerError4("listener_message_handler_failed", error54, "listener_message_handler");
|
|
@@ -464858,12 +465756,7 @@ async function attachOpenListenerSocket(runtime, socket, opts, options3 = {}) {
|
|
|
464858
465756
|
reason: reasonText
|
|
464859
465757
|
});
|
|
464860
465758
|
fileCommandSession.dispose();
|
|
464861
|
-
|
|
464862
|
-
getChannelRegistry()?.pause();
|
|
464863
|
-
stopRuntime(runtime, true);
|
|
464864
|
-
if (getActiveRuntime() === runtime) {
|
|
464865
|
-
setActiveRuntime(null);
|
|
464866
|
-
}
|
|
465759
|
+
cleanupListenerConnection(runtime, opts.connectionId);
|
|
464867
465760
|
opts.onDisconnected();
|
|
464868
465761
|
});
|
|
464869
465762
|
socket.on("error", (error54) => {
|
|
@@ -464891,11 +465784,15 @@ async function attachOpenListenerSocket(runtime, socket, opts, options3 = {}) {
|
|
|
464891
465784
|
});
|
|
464892
465785
|
}
|
|
464893
465786
|
await options3.startupReady;
|
|
465787
|
+
if (connection.cancellation.signal.aborted || runtime.connections.get(opts.connectionId) !== connection) {
|
|
465788
|
+
return;
|
|
465789
|
+
}
|
|
464894
465790
|
const streamTransport = streamSocket?.readyState === WebSocket6.OPEN ? streamSocket : null;
|
|
464895
465791
|
await startConnectedListenerRuntime(runtime, transport, opts, processQueuedTurn, {
|
|
464896
465792
|
startHeartbeat: options3.startHeartbeat ?? false,
|
|
464897
465793
|
startCronScheduler: options3.startCronScheduler ?? true,
|
|
464898
|
-
streamTransport
|
|
465794
|
+
streamTransport,
|
|
465795
|
+
emitInitialState: false
|
|
464899
465796
|
});
|
|
464900
465797
|
}
|
|
464901
465798
|
async function startListenerClient(opts) {
|
|
@@ -464929,10 +465826,18 @@ async function startLocalChannelListener(opts) {
|
|
|
464929
465826
|
await reloadListenerModAdapter(runtime);
|
|
464930
465827
|
await loadTools();
|
|
464931
465828
|
const transport = new LocalListenerTransport;
|
|
464932
|
-
const
|
|
464933
|
-
|
|
464934
|
-
|
|
465829
|
+
const connectionOptions = {
|
|
465830
|
+
...opts,
|
|
465831
|
+
wsUrl: "local://listener",
|
|
465832
|
+
onDisconnected: () => {}
|
|
464935
465833
|
};
|
|
465834
|
+
openListenerConnection({
|
|
465835
|
+
runtime,
|
|
465836
|
+
connectionId: opts.connectionId,
|
|
465837
|
+
writer: transport,
|
|
465838
|
+
options: connectionOptions
|
|
465839
|
+
});
|
|
465840
|
+
const processQueuedTurn = createConnectionTurnProcessor(runtime);
|
|
464936
465841
|
await startConnectedListenerRuntime(runtime, transport, opts, processQueuedTurn, { startHeartbeat: false, startCronScheduler: true });
|
|
464937
465842
|
} catch (error54) {
|
|
464938
465843
|
stopRuntime(runtime, true);
|
|
@@ -465010,15 +465915,19 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
465010
465915
|
runtime.socket = socket;
|
|
465011
465916
|
runtime.streamSocket = streamSocket;
|
|
465012
465917
|
const transport = socket;
|
|
465013
|
-
const processQueuedTurn =
|
|
465014
|
-
const scopedRuntime = getOrCreateScopedRuntime(runtime, queuedTurn.agentId, queuedTurn.conversationId);
|
|
465015
|
-
await handleIncomingMessage(queuedTurn, transport, scopedRuntime, opts.onStatusChange, opts.connectionId, dequeuedBatch.batchId);
|
|
465016
|
-
};
|
|
465918
|
+
const processQueuedTurn = createConnectionTurnProcessor(runtime);
|
|
465017
465919
|
socket.on("open", async () => {
|
|
465018
465920
|
let streamTransport = null;
|
|
465019
465921
|
if (streamSocket) {
|
|
465020
465922
|
streamTransport = await waitForStreamSocketOpen(streamSocket, runtime);
|
|
465021
465923
|
}
|
|
465924
|
+
openListenerConnection({
|
|
465925
|
+
runtime,
|
|
465926
|
+
connectionId: opts.connectionId,
|
|
465927
|
+
writer: socket,
|
|
465928
|
+
streamWriter: streamTransport,
|
|
465929
|
+
options: opts
|
|
465930
|
+
});
|
|
465022
465931
|
await startConnectedListenerRuntime(runtime, transport, opts, processQueuedTurn, {
|
|
465023
465932
|
startHeartbeat: true,
|
|
465024
465933
|
startCronScheduler: true,
|
|
@@ -465028,6 +465937,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
465028
465937
|
socket.on("message", createListenerMessageHandler({
|
|
465029
465938
|
runtime,
|
|
465030
465939
|
socket,
|
|
465940
|
+
connectionId: opts.connectionId,
|
|
465031
465941
|
opts,
|
|
465032
465942
|
processQueuedTurn,
|
|
465033
465943
|
fileCommandSession,
|
|
@@ -465053,12 +465963,11 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
465053
465963
|
reason: reason.toString()
|
|
465054
465964
|
});
|
|
465055
465965
|
fileCommandSession.dispose();
|
|
465056
|
-
|
|
465966
|
+
invalidateProcessServices(runtime);
|
|
465057
465967
|
const channelRegistry = getChannelRegistry();
|
|
465058
465968
|
if (channelRegistry) {
|
|
465059
465969
|
channelRegistry.pause();
|
|
465060
465970
|
}
|
|
465061
|
-
setMessageQueueAdder(null);
|
|
465062
465971
|
for (const conversationRuntime of runtime.conversationRuntimes.values()) {
|
|
465063
465972
|
conversationRuntime.queuedMessagesByItemId.clear();
|
|
465064
465973
|
if (conversationRuntime.queueRuntime) {
|
|
@@ -465068,12 +465977,8 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
465068
465977
|
if (isDebugEnabled()) {
|
|
465069
465978
|
console.log(`[Listen] WebSocket disconnected (code: ${code2}, reason: ${reason.toString()})`);
|
|
465070
465979
|
}
|
|
465071
|
-
|
|
465980
|
+
suspendListenerConnection(runtime, opts.connectionId);
|
|
465072
465981
|
killAllTerminals();
|
|
465073
|
-
runtime._unsubscribeSubagentState?.();
|
|
465074
|
-
runtime._unsubscribeSubagentState = undefined;
|
|
465075
|
-
runtime._unsubscribeSubagentStreamEvents?.();
|
|
465076
|
-
runtime._unsubscribeSubagentStreamEvents = undefined;
|
|
465077
465982
|
clearListenerWarmState(runtime);
|
|
465078
465983
|
if (streamSocket) {
|
|
465079
465984
|
streamSocket.removeAllListeners();
|
|
@@ -465150,7 +466055,6 @@ function stopListenerClient() {
|
|
|
465150
466055
|
stopRuntime(runtime, true);
|
|
465151
466056
|
}
|
|
465152
466057
|
var init_lifecycle = __esm(async () => {
|
|
465153
|
-
init_subagent_state();
|
|
465154
466058
|
init_commands();
|
|
465155
466059
|
init_progress_builder();
|
|
465156
466060
|
init_registry();
|
|
@@ -465160,10 +466064,10 @@ var init_lifecycle = __esm(async () => {
|
|
|
465160
466064
|
init_telemetry();
|
|
465161
466065
|
init_error_reporting();
|
|
465162
466066
|
init_debug();
|
|
465163
|
-
init_message_queue_bridge();
|
|
465164
466067
|
init_terminal_handler();
|
|
465165
466068
|
init_auth();
|
|
465166
466069
|
init_channel_turn_session();
|
|
466070
|
+
init_connection();
|
|
465167
466071
|
init_constants3();
|
|
465168
466072
|
init_cwd();
|
|
465169
466073
|
init_permission_mode();
|
|
@@ -465174,18 +466078,20 @@ var init_lifecycle = __esm(async () => {
|
|
|
465174
466078
|
init_manager4(),
|
|
465175
466079
|
init_approval(),
|
|
465176
466080
|
init_commands2(),
|
|
465177
|
-
|
|
466081
|
+
init_channel_registry_events(),
|
|
465178
466082
|
init_model_toolset(),
|
|
466083
|
+
init_connection_lifecycle(),
|
|
466084
|
+
init_connection_state_sync(),
|
|
465179
466085
|
init_control_inputs(),
|
|
465180
466086
|
init_conversation_runtime(),
|
|
465181
466087
|
init_external_tools(),
|
|
465182
466088
|
init_file_commands(),
|
|
465183
466089
|
init_message_router(),
|
|
465184
466090
|
init_mod_adapter2(),
|
|
466091
|
+
init_process_services(),
|
|
465185
466092
|
init_protocol_outbound(),
|
|
465186
466093
|
init_queue(),
|
|
465187
466094
|
init_recovery(),
|
|
465188
|
-
init_turn(),
|
|
465189
466095
|
init_turn_events(),
|
|
465190
466096
|
init_warmup(),
|
|
465191
466097
|
init_worktree_watcher()
|
|
@@ -465273,6 +466179,60 @@ function createLegacyTestRuntime() {
|
|
|
465273
466179
|
listener.sessionId = value;
|
|
465274
466180
|
}
|
|
465275
466181
|
},
|
|
466182
|
+
nextConnectionOrdinal: {
|
|
466183
|
+
get: () => listener.nextConnectionOrdinal,
|
|
466184
|
+
set: (value) => {
|
|
466185
|
+
listener.nextConnectionOrdinal = value;
|
|
466186
|
+
}
|
|
466187
|
+
},
|
|
466188
|
+
connections: {
|
|
466189
|
+
get: () => listener.connections,
|
|
466190
|
+
set: (value) => {
|
|
466191
|
+
listener.connections = value;
|
|
466192
|
+
}
|
|
466193
|
+
},
|
|
466194
|
+
connectionIdsByRuntimeKey: {
|
|
466195
|
+
get: () => listener.connectionIdsByRuntimeKey,
|
|
466196
|
+
set: (value) => {
|
|
466197
|
+
listener.connectionIdsByRuntimeKey = value;
|
|
466198
|
+
}
|
|
466199
|
+
},
|
|
466200
|
+
processTransport: {
|
|
466201
|
+
get: () => listener.processTransport,
|
|
466202
|
+
set: (value) => {
|
|
466203
|
+
listener.processTransport = value;
|
|
466204
|
+
}
|
|
466205
|
+
},
|
|
466206
|
+
processServicesStarted: {
|
|
466207
|
+
get: () => listener.processServicesStarted,
|
|
466208
|
+
set: (value) => {
|
|
466209
|
+
listener.processServicesStarted = value;
|
|
466210
|
+
}
|
|
466211
|
+
},
|
|
466212
|
+
processServicesGeneration: {
|
|
466213
|
+
get: () => listener.processServicesGeneration,
|
|
466214
|
+
set: (value) => {
|
|
466215
|
+
listener.processServicesGeneration = value;
|
|
466216
|
+
}
|
|
466217
|
+
},
|
|
466218
|
+
processServicesReady: {
|
|
466219
|
+
get: () => listener.processServicesReady,
|
|
466220
|
+
set: (value) => {
|
|
466221
|
+
listener.processServicesReady = value;
|
|
466222
|
+
}
|
|
466223
|
+
},
|
|
466224
|
+
processServicesReadyGeneration: {
|
|
466225
|
+
get: () => listener.processServicesReadyGeneration,
|
|
466226
|
+
set: (value) => {
|
|
466227
|
+
listener.processServicesReadyGeneration = value;
|
|
466228
|
+
}
|
|
466229
|
+
},
|
|
466230
|
+
pendingExternalToolCalls: {
|
|
466231
|
+
get: () => listener.pendingExternalToolCalls,
|
|
466232
|
+
set: (value) => {
|
|
466233
|
+
listener.pendingExternalToolCalls = value;
|
|
466234
|
+
}
|
|
466235
|
+
},
|
|
465276
466236
|
eventSeqCounter: {
|
|
465277
466237
|
get: () => listener.eventSeqCounter,
|
|
465278
466238
|
set: (value) => {
|
|
@@ -465345,12 +466305,6 @@ function createLegacyTestRuntime() {
|
|
|
465345
466305
|
listener.conversationRuntimes = value;
|
|
465346
466306
|
}
|
|
465347
466307
|
},
|
|
465348
|
-
approvalRuntimeKeyByRequestId: {
|
|
465349
|
-
get: () => listener.approvalRuntimeKeyByRequestId,
|
|
465350
|
-
set: (value) => {
|
|
465351
|
-
listener.approvalRuntimeKeyByRequestId = value;
|
|
465352
|
-
}
|
|
465353
|
-
},
|
|
465354
466308
|
memfsSyncedAgents: {
|
|
465355
466309
|
get: () => listener.memfsSyncedAgents,
|
|
465356
466310
|
set: (value) => {
|
|
@@ -465423,6 +466377,7 @@ var init_client7 = __esm(async () => {
|
|
|
465423
466377
|
await __promiseAll([
|
|
465424
466378
|
init_approval(),
|
|
465425
466379
|
init_agents_conversations(),
|
|
466380
|
+
init_channel_registry_events(),
|
|
465426
466381
|
init_channels2(),
|
|
465427
466382
|
init_cron3(),
|
|
465428
466383
|
init_memory6(),
|
|
@@ -465499,7 +466454,7 @@ var init_client7 = __esm(async () => {
|
|
|
465499
466454
|
handleListMemoryCommand: (parsed, socket, overrides) => handleListMemoryCommand(parsed, socket, safeSocketSend, overrides),
|
|
465500
466455
|
isDetachedChannelsCommand,
|
|
465501
466456
|
handleChannelsProtocolCommand: (parsed, socket, runtime, opts, processQueuedTurn) => handleChannelsProtocolCommand(parsed, socket, runtime, opts, processQueuedTurn, runDetachedListenerTask, wireChannelIngress, safeSocketSend),
|
|
465502
|
-
handleChannelRegistryEvent: (event2, socket, runtime) => handleChannelRegistryEvent(event2, socket, runtime
|
|
466457
|
+
handleChannelRegistryEvent: (event2, socket, runtime) => handleChannelRegistryEvent(event2, socket, runtime),
|
|
465503
466458
|
handleAgentConversationManagementCommand: (parsed, socket) => handleAgentConversationManagementCommand(parsed, socket, safeSocketSend),
|
|
465504
466459
|
handleAgentConversationManagementProtocolCommand: (parsed, socket) => handleAgentConversationManagementProtocolCommand(parsed, {
|
|
465505
466460
|
socket,
|
|
@@ -465508,6 +466463,7 @@ var init_client7 = __esm(async () => {
|
|
|
465508
466463
|
}),
|
|
465509
466464
|
handleRuntimeStartCommand: (parsed, socket, runtime) => handleRuntimeStartCommand(parsed, {
|
|
465510
466465
|
socket,
|
|
466466
|
+
connectionId: runtime.connectionId ?? "test-connection",
|
|
465511
466467
|
runtime,
|
|
465512
466468
|
safeSocketSend,
|
|
465513
466469
|
runDetachedListenerTask,
|
|
@@ -465519,6 +466475,7 @@ var init_client7 = __esm(async () => {
|
|
|
465519
466475
|
}),
|
|
465520
466476
|
handleRuntimeStartProtocolCommand: (parsed, socket, runtime) => handleRuntimeStartProtocolCommand(parsed, {
|
|
465521
466477
|
socket,
|
|
466478
|
+
connectionId: runtime.connectionId ?? "test-connection",
|
|
465522
466479
|
runtime,
|
|
465523
466480
|
safeSocketSend,
|
|
465524
466481
|
runDetachedListenerTask,
|
|
@@ -466121,7 +467078,7 @@ var init_listen = __esm(async () => {
|
|
|
466121
467078
|
import { randomUUID as randomUUID26 } from "node:crypto";
|
|
466122
467079
|
import {
|
|
466123
467080
|
copyFileSync as copyFileSync3,
|
|
466124
|
-
existsSync as
|
|
467081
|
+
existsSync as existsSync53,
|
|
466125
467082
|
mkdirSync as mkdirSync38,
|
|
466126
467083
|
readdirSync as readdirSync20,
|
|
466127
467084
|
readFileSync as readFileSync34,
|
|
@@ -466129,7 +467086,7 @@ import {
|
|
|
466129
467086
|
} from "node:fs";
|
|
466130
467087
|
import { join as join67 } from "node:path";
|
|
466131
467088
|
function readJsonl(path41) {
|
|
466132
|
-
if (!
|
|
467089
|
+
if (!existsSync53(path41))
|
|
466133
467090
|
return [];
|
|
466134
467091
|
return readFileSync34(path41, "utf8").split(`
|
|
466135
467092
|
`).filter((line) => line.trim().length > 0).map((line) => JSON.parse(line));
|
|
@@ -466417,13 +467374,13 @@ function migrateLocalBackendTranscripts(input) {
|
|
|
466417
467374
|
skipped: [],
|
|
466418
467375
|
dryRun: input.dryRun === true
|
|
466419
467376
|
};
|
|
466420
|
-
if (!
|
|
467377
|
+
if (!existsSync53(conversationsDir))
|
|
466421
467378
|
return result;
|
|
466422
467379
|
for (const name of readdirSync20(conversationsDir)) {
|
|
466423
467380
|
const conversationDir = join67(conversationsDir, name);
|
|
466424
467381
|
const messagesPath = join67(conversationDir, "messages.jsonl");
|
|
466425
467382
|
const manifestPath = join67(conversationDir, "manifest.json");
|
|
466426
|
-
const hasManifest =
|
|
467383
|
+
const hasManifest = existsSync53(manifestPath);
|
|
466427
467384
|
const existingManifest = hasManifest ? (() => {
|
|
466428
467385
|
try {
|
|
466429
467386
|
return JSON.parse(readFileSync34(manifestPath, "utf8"));
|
|
@@ -466467,7 +467424,7 @@ function migrateLocalBackendTranscripts(input) {
|
|
|
466467
467424
|
copyFileSync3(messagesPath, backupPath);
|
|
466468
467425
|
const conversationPath = join67(conversationDir, "conversation.json");
|
|
466469
467426
|
let conversation;
|
|
466470
|
-
if (
|
|
467427
|
+
if (existsSync53(conversationPath)) {
|
|
466471
467428
|
try {
|
|
466472
467429
|
conversation = JSON.parse(readFileSync34(conversationPath, "utf8"));
|
|
466473
467430
|
} catch {
|
|
@@ -466661,7 +467618,7 @@ var init_memory_tokens = __esm(() => {
|
|
|
466661
467618
|
});
|
|
466662
467619
|
|
|
466663
467620
|
// src/cli/subcommands/memory.ts
|
|
466664
|
-
import { cpSync, existsSync as
|
|
467621
|
+
import { cpSync, existsSync as existsSync54, mkdirSync as mkdirSync39, rmSync as rmSync12, statSync as statSync17 } from "node:fs";
|
|
466665
467622
|
import { readdir as readdir13 } from "node:fs/promises";
|
|
466666
467623
|
import { dirname as dirname30, join as join68 } from "node:path";
|
|
466667
467624
|
import { parseArgs as parseArgs10 } from "node:util";
|
|
@@ -466723,7 +467680,7 @@ function formatBackupTimestamp(date6 = new Date) {
|
|
|
466723
467680
|
}
|
|
466724
467681
|
async function listBackups(agentId) {
|
|
466725
467682
|
const agentRoot = getAgentRoot(agentId);
|
|
466726
|
-
if (!
|
|
467683
|
+
if (!existsSync54(agentRoot)) {
|
|
466727
467684
|
return [];
|
|
466728
467685
|
}
|
|
466729
467686
|
const entries = await readdir13(agentRoot, { withFileTypes: true });
|
|
@@ -466826,14 +467783,14 @@ async function runMemorySubcommand(argv) {
|
|
|
466826
467783
|
}
|
|
466827
467784
|
if (action3 === "backup") {
|
|
466828
467785
|
const root2 = getMemoryRoot(agentId);
|
|
466829
|
-
if (!
|
|
467786
|
+
if (!existsSync54(root2)) {
|
|
466830
467787
|
console.error(`Memory directory not found for agent ${agentId}.`);
|
|
466831
467788
|
return 1;
|
|
466832
467789
|
}
|
|
466833
467790
|
const agentRoot = getAgentRoot(agentId);
|
|
466834
467791
|
const backupName = `memory-backup-${formatBackupTimestamp()}`;
|
|
466835
467792
|
const backupPath = join68(agentRoot, backupName);
|
|
466836
|
-
if (
|
|
467793
|
+
if (existsSync54(backupPath)) {
|
|
466837
467794
|
console.error(`Backup already exists at ${backupPath}`);
|
|
466838
467795
|
return 1;
|
|
466839
467796
|
}
|
|
@@ -466857,7 +467814,7 @@ async function runMemorySubcommand(argv) {
|
|
|
466857
467814
|
return 1;
|
|
466858
467815
|
}
|
|
466859
467816
|
const backupPath = resolveBackupPath(agentId, from);
|
|
466860
|
-
if (!
|
|
467817
|
+
if (!existsSync54(backupPath)) {
|
|
466861
467818
|
console.error(`Backup not found: ${backupPath}`);
|
|
466862
467819
|
return 1;
|
|
466863
467820
|
}
|
|
@@ -466879,11 +467836,11 @@ async function runMemorySubcommand(argv) {
|
|
|
466879
467836
|
return 1;
|
|
466880
467837
|
}
|
|
466881
467838
|
const root2 = getMemoryRoot(agentId);
|
|
466882
|
-
if (!
|
|
467839
|
+
if (!existsSync54(root2)) {
|
|
466883
467840
|
console.error(`Memory directory not found for agent ${agentId}.`);
|
|
466884
467841
|
return 1;
|
|
466885
467842
|
}
|
|
466886
|
-
if (
|
|
467843
|
+
if (existsSync54(out)) {
|
|
466887
467844
|
const stat15 = statSync17(out);
|
|
466888
467845
|
if (stat15.isDirectory()) {
|
|
466889
467846
|
const contents = await readdir13(out);
|
|
@@ -466931,10 +467888,10 @@ var init_memory7 = __esm(() => {
|
|
|
466931
467888
|
});
|
|
466932
467889
|
|
|
466933
467890
|
// src/backend/local/transcript-search.ts
|
|
466934
|
-
import { existsSync as
|
|
467891
|
+
import { existsSync as existsSync55, readdirSync as readdirSync21, readFileSync as readFileSync35, statSync as statSync18 } from "node:fs";
|
|
466935
467892
|
import { join as join69 } from "node:path";
|
|
466936
467893
|
function readJsonFile3(path41) {
|
|
466937
|
-
if (!
|
|
467894
|
+
if (!existsSync55(path41))
|
|
466938
467895
|
return;
|
|
466939
467896
|
try {
|
|
466940
467897
|
return JSON.parse(readFileSync35(path41, "utf8"));
|
|
@@ -466943,7 +467900,7 @@ function readJsonFile3(path41) {
|
|
|
466943
467900
|
}
|
|
466944
467901
|
}
|
|
466945
467902
|
function readJsonlFile2(path41) {
|
|
466946
|
-
if (!
|
|
467903
|
+
if (!existsSync55(path41))
|
|
466947
467904
|
return [];
|
|
466948
467905
|
try {
|
|
466949
467906
|
return readFileSync35(path41, "utf8").split(`
|
|
@@ -467179,7 +468136,7 @@ function collectConversationMessages(input) {
|
|
|
467179
468136
|
}
|
|
467180
468137
|
function conversationDirectories(storageDir) {
|
|
467181
468138
|
const conversationsDir = join69(storageDir, "conversations");
|
|
467182
|
-
if (!
|
|
468139
|
+
if (!existsSync55(conversationsDir))
|
|
467183
468140
|
return [];
|
|
467184
468141
|
try {
|
|
467185
468142
|
return readdirSync21(conversationsDir).map((entry) => join69(conversationsDir, entry)).filter((entryPath) => statSync18(entryPath).isDirectory());
|
|
@@ -467648,7 +468605,7 @@ import {
|
|
|
467648
468605
|
} from "node:child_process";
|
|
467649
468606
|
import {
|
|
467650
468607
|
copyFileSync as copyFileSync4,
|
|
467651
|
-
existsSync as
|
|
468608
|
+
existsSync as existsSync56,
|
|
467652
468609
|
lstatSync as lstatSync3,
|
|
467653
468610
|
mkdirSync as mkdirSync40,
|
|
467654
468611
|
mkdtempSync as mkdtempSync3,
|
|
@@ -467857,7 +468814,7 @@ function copyDependencyDirectoryFiltered(params) {
|
|
|
467857
468814
|
return copied;
|
|
467858
468815
|
}
|
|
467859
468816
|
function copyDependencyNodeModules(params) {
|
|
467860
|
-
if (!
|
|
468817
|
+
if (!existsSync56(params.sourceNodeModulesDirectory))
|
|
467861
468818
|
return;
|
|
467862
468819
|
copyDependencyDirectoryFiltered({
|
|
467863
468820
|
installedPackageName: params.installedPackageName,
|
|
@@ -467867,7 +468824,7 @@ function copyDependencyNodeModules(params) {
|
|
|
467867
468824
|
}
|
|
467868
468825
|
function copyPackageInternalNodeModules(params) {
|
|
467869
468826
|
const sourceNodeModulesDirectory = path41.join(params.packageDirectory, "node_modules");
|
|
467870
|
-
if (!
|
|
468827
|
+
if (!existsSync56(sourceNodeModulesDirectory))
|
|
467871
468828
|
return;
|
|
467872
468829
|
copyDependencyDirectoryFiltered({
|
|
467873
468830
|
sourceRoot: sourceNodeModulesDirectory,
|
|
@@ -467889,12 +468846,12 @@ function removeIfExists(targetPath) {
|
|
|
467889
468846
|
}
|
|
467890
468847
|
function restoreDestination(params) {
|
|
467891
468848
|
rmSync13(params.destinationRoot, { force: true, recursive: true });
|
|
467892
|
-
if (params.backupRoot &&
|
|
468849
|
+
if (params.backupRoot && existsSync56(params.backupRoot)) {
|
|
467893
468850
|
renameSync6(params.backupRoot, params.destinationRoot);
|
|
467894
468851
|
}
|
|
467895
468852
|
}
|
|
467896
468853
|
function restoreDestinationIfNeeded(params) {
|
|
467897
|
-
if (!params.backupRoot || !
|
|
468854
|
+
if (!params.backupRoot || !existsSync56(params.backupRoot)) {
|
|
467898
468855
|
rmSync13(params.destinationRoot, { force: true, recursive: true });
|
|
467899
468856
|
return;
|
|
467900
468857
|
}
|
|
@@ -467935,7 +468892,7 @@ function installPreparedManagedModPackage(params) {
|
|
|
467935
468892
|
targetPackageRoot: stagingRoot
|
|
467936
468893
|
});
|
|
467937
468894
|
}
|
|
467938
|
-
if (
|
|
468895
|
+
if (existsSync56(destinationRoot)) {
|
|
467939
468896
|
backupRoot = makeSiblingTempDirectory(destinationRoot, "backup");
|
|
467940
468897
|
rmSync13(backupRoot, { force: true, recursive: true });
|
|
467941
468898
|
renameSync6(destinationRoot, backupRoot);
|
|
@@ -468218,7 +469175,7 @@ function hasRuntimeDependencies(packageJson) {
|
|
|
468218
469175
|
}
|
|
468219
469176
|
function readPackageJsonIfExists(packageDirectory) {
|
|
468220
469177
|
const packageJsonPath = path41.join(packageDirectory, "package.json");
|
|
468221
|
-
if (!
|
|
469178
|
+
if (!existsSync56(packageJsonPath))
|
|
468222
469179
|
return null;
|
|
468223
469180
|
return readPackageJson(packageJsonPath);
|
|
468224
469181
|
}
|
|
@@ -468232,7 +469189,7 @@ function isRegularModFile(filePath) {
|
|
|
468232
469189
|
}
|
|
468233
469190
|
function inferCompatibilityModEntries(packageDirectory) {
|
|
468234
469191
|
const modsDirectory = path41.join(packageDirectory, "mods");
|
|
468235
|
-
if (
|
|
469192
|
+
if (existsSync56(modsDirectory)) {
|
|
468236
469193
|
const stats = lstatSync3(modsDirectory);
|
|
468237
469194
|
if (stats.isSymbolicLink()) {
|
|
468238
469195
|
throw new Error(`Package mods directory must not be a symlink: mods`);
|
|
@@ -468507,7 +469464,7 @@ var init_package_installer = __esm(() => {
|
|
|
468507
469464
|
// src/mods/package-scaffolder.ts
|
|
468508
469465
|
import {
|
|
468509
469466
|
copyFileSync as copyFileSync5,
|
|
468510
|
-
existsSync as
|
|
469467
|
+
existsSync as existsSync57,
|
|
468511
469468
|
lstatSync as lstatSync4,
|
|
468512
469469
|
mkdirSync as mkdirSync41,
|
|
468513
469470
|
rmSync as rmSync14,
|
|
@@ -468600,7 +469557,7 @@ function scaffoldLocalModPackage(options3) {
|
|
|
468600
469557
|
const sourceFile = readSourceFile(options3.sourceFile);
|
|
468601
469558
|
const packageName = assertValidPackageName(options3.packageName);
|
|
468602
469559
|
const outputDirectory = path42.resolve(options3.outputDirectory ?? defaultOutputDirectory(sourceFile, packageName));
|
|
468603
|
-
if (
|
|
469560
|
+
if (existsSync57(outputDirectory)) {
|
|
468604
469561
|
throw new Error(`Output directory already exists: ${outputDirectory}`);
|
|
468605
469562
|
}
|
|
468606
469563
|
const modFileName = path42.basename(sourceFile);
|
|
@@ -469311,7 +470268,7 @@ async function runTurnViaListenerRuntime(params) {
|
|
|
469311
470268
|
const listener = await ensureListenerRuntime(params.onLog);
|
|
469312
470269
|
const scopedRuntime = getOrCreateScopedRuntime(listener, params.agentId, params.conversationId);
|
|
469313
470270
|
getOrCreateConversationPermissionModeStateRef(listener, params.agentId, params.conversationId).mode = "unrestricted";
|
|
469314
|
-
const socket = listener
|
|
470271
|
+
const socket = getOrCreateProcessTransport(listener);
|
|
469315
470272
|
const dispatchOptions = {
|
|
469316
470273
|
connectionId: listener.connectionId ?? "openai-api",
|
|
469317
470274
|
wsUrl: "",
|
|
@@ -469323,10 +470280,7 @@ async function runTurnViaListenerRuntime(params) {
|
|
|
469323
470280
|
params.onLog?.(`OpenAI-compat turn error: ${error54.message}`);
|
|
469324
470281
|
}
|
|
469325
470282
|
};
|
|
469326
|
-
const processQueuedTurn =
|
|
469327
|
-
const queuedScope = getOrCreateScopedRuntime(listener, queuedTurn.agentId, queuedTurn.conversationId);
|
|
469328
|
-
await handleIncomingMessage(queuedTurn, socket, queuedScope, undefined, dispatchOptions.connectionId, dequeuedBatch.batchId);
|
|
469329
|
-
};
|
|
470283
|
+
const processQueuedTurn = createConnectionTurnProcessor(listener);
|
|
469330
470284
|
return await new Promise((resolve32) => {
|
|
469331
470285
|
let text2 = "";
|
|
469332
470286
|
let usage = {
|
|
@@ -469437,7 +470391,7 @@ async function runTurnViaListenerRuntime(params) {
|
|
|
469437
470391
|
socket,
|
|
469438
470392
|
options: dispatchOptions,
|
|
469439
470393
|
processQueuedTurn,
|
|
469440
|
-
processIncomingMessage: handleIncomingMessage,
|
|
470394
|
+
processIncomingMessage: (incoming2, incomingSocket, incomingRuntime, onStatusChange, _connectionId, batchId) => handleIncomingMessage(incoming2, incomingSocket, incomingRuntime, onStatusChange, undefined, batchId),
|
|
469441
470395
|
trackListenerError: (errorType, error54) => {
|
|
469442
470396
|
params.onLog?.(`OpenAI-compat listener error (${errorType}): ${error54 instanceof Error ? error54.message : String(error54)}`);
|
|
469443
470397
|
}
|
|
@@ -469447,14 +470401,15 @@ async function runTurnViaListenerRuntime(params) {
|
|
|
469447
470401
|
}
|
|
469448
470402
|
});
|
|
469449
470403
|
}
|
|
469450
|
-
var runTurnImpl, OPENAI_TURN_TIMEOUT_MS,
|
|
470404
|
+
var runTurnImpl, OPENAI_TURN_TIMEOUT_MS, bridgeRuntimeStart = null, bridgeOwnedRuntime = null;
|
|
469451
470405
|
var init_app_server_openai_turn = __esm(async () => {
|
|
469452
470406
|
init_settings_manager();
|
|
470407
|
+
init_connection();
|
|
469453
470408
|
init_permission_mode();
|
|
469454
470409
|
init_runtime6();
|
|
469455
|
-
init_transport();
|
|
469456
470410
|
init_turn_observers();
|
|
469457
470411
|
await __promiseAll([
|
|
470412
|
+
init_connection_lifecycle(),
|
|
469458
470413
|
init_conversation_runtime(),
|
|
469459
470414
|
init_inbound_dispatch(),
|
|
469460
470415
|
init_lifecycle(),
|
|
@@ -469462,7 +470417,6 @@ var init_app_server_openai_turn = __esm(async () => {
|
|
|
469462
470417
|
]);
|
|
469463
470418
|
runTurnImpl = runTurnViaListenerRuntime;
|
|
469464
470419
|
OPENAI_TURN_TIMEOUT_MS = 15 * 60 * 1000;
|
|
469465
|
-
bridgeTransport = new LocalListenerTransport;
|
|
469466
470420
|
});
|
|
469467
470421
|
|
|
469468
470422
|
// src/websocket/app-server-openai.ts
|
|
@@ -469470,7 +470424,7 @@ import { randomUUID as randomUUID28 } from "node:crypto";
|
|
|
469470
470424
|
function isOpenAiCompatPath(pathname) {
|
|
469471
470425
|
return pathname === MODELS_PATH || pathname === CHAT_COMPLETIONS_PATH;
|
|
469472
470426
|
}
|
|
469473
|
-
function
|
|
470427
|
+
function sendJson(response, statusCode2, body3) {
|
|
469474
470428
|
const payload = JSON.stringify(body3);
|
|
469475
470429
|
response.writeHead(statusCode2, {
|
|
469476
470430
|
"content-type": "application/json",
|
|
@@ -469479,7 +470433,7 @@ function sendJson2(response, statusCode2, body3) {
|
|
|
469479
470433
|
response.end(payload);
|
|
469480
470434
|
}
|
|
469481
470435
|
function sendOpenAiError(response, statusCode2, message, type3, code2 = null) {
|
|
469482
|
-
|
|
470436
|
+
sendJson(response, statusCode2, {
|
|
469483
470437
|
error: { message, type: type3, param: null, code: code2 }
|
|
469484
470438
|
});
|
|
469485
470439
|
}
|
|
@@ -469608,7 +470562,7 @@ async function handleListModels(response) {
|
|
|
469608
470562
|
created: toModelCreatedTimestamp(agent2.created_at),
|
|
469609
470563
|
owned_by: "letta"
|
|
469610
470564
|
}));
|
|
469611
|
-
|
|
470565
|
+
sendJson(response, 200, { object: "list", data });
|
|
469612
470566
|
}
|
|
469613
470567
|
async function resolveAgentForModel(model) {
|
|
469614
470568
|
const agents = await listAgentEntries();
|
|
@@ -469886,7 +470840,7 @@ async function handleChatCompletions(request, response, options3) {
|
|
|
469886
470840
|
sendOpenAiError(response, 500, streamError, "server_error");
|
|
469887
470841
|
return;
|
|
469888
470842
|
}
|
|
469889
|
-
|
|
470843
|
+
sendJson(response, 200, {
|
|
469890
470844
|
id: completionId,
|
|
469891
470845
|
object: "chat.completion",
|
|
469892
470846
|
created,
|
|
@@ -469956,10 +470910,9 @@ function getRequiredAddressInfo(server2) {
|
|
|
469956
470910
|
}
|
|
469957
470911
|
return address;
|
|
469958
470912
|
}
|
|
469959
|
-
function
|
|
470913
|
+
function getWebSocketUrl(baseUrl, path43) {
|
|
469960
470914
|
const url2 = new URL(baseUrl);
|
|
469961
470915
|
url2.pathname = path43;
|
|
469962
|
-
url2.searchParams.set("channel", channel);
|
|
469963
470916
|
return url2.toString();
|
|
469964
470917
|
}
|
|
469965
470918
|
function closeSocket(socket, code2 = 1001, reason = "closing") {
|
|
@@ -469984,35 +470937,6 @@ Content-Length: 0\r
|
|
|
469984
470937
|
function getRequestUrl(request, host) {
|
|
469985
470938
|
return new URL(request.url ?? "/", `http://${request.headers.host ?? host}`);
|
|
469986
470939
|
}
|
|
469987
|
-
function getRequestChannel(url2) {
|
|
469988
|
-
const channel = url2.searchParams.get("channel");
|
|
469989
|
-
if (channel === null || channel === "" || channel === "control") {
|
|
469990
|
-
return "control";
|
|
469991
|
-
}
|
|
469992
|
-
if (channel === "stream") {
|
|
469993
|
-
return "stream";
|
|
469994
|
-
}
|
|
469995
|
-
return null;
|
|
469996
|
-
}
|
|
469997
|
-
function attachStreamSocket(activeSession, socket) {
|
|
469998
|
-
if (activeSession.streamSocket) {
|
|
469999
|
-
closeSocket(socket, 1008, "stream channel already connected");
|
|
470000
|
-
return;
|
|
470001
|
-
}
|
|
470002
|
-
activeSession.streamSocket = socket;
|
|
470003
|
-
activeSession.runtime.streamSocket = socket;
|
|
470004
|
-
activeSession.runtime.streamTransport = socket;
|
|
470005
|
-
socket.on("close", () => {
|
|
470006
|
-
if (activeSession.streamSocket === socket) {
|
|
470007
|
-
activeSession.streamSocket = null;
|
|
470008
|
-
}
|
|
470009
|
-
if (activeSession.runtime.streamSocket === socket) {
|
|
470010
|
-
activeSession.runtime.streamSocket = null;
|
|
470011
|
-
activeSession.runtime.streamTransport = null;
|
|
470012
|
-
terminateSocket(activeSession.controlSocket);
|
|
470013
|
-
}
|
|
470014
|
-
});
|
|
470015
|
-
}
|
|
470016
470940
|
function parseAppServerListenUrl(listen = DEFAULT_LISTEN_URL) {
|
|
470017
470941
|
let url2;
|
|
470018
470942
|
try {
|
|
@@ -470033,46 +470957,6 @@ function parseAppServerListenUrl(listen = DEFAULT_LISTEN_URL) {
|
|
|
470033
470957
|
const path43 = url2.pathname === "/" ? DEFAULT_WS_PATH : url2.pathname;
|
|
470034
470958
|
return { host: normalizeListenHost(url2.hostname), port, path: path43 };
|
|
470035
470959
|
}
|
|
470036
|
-
async function startControlSession(params) {
|
|
470037
|
-
const existingRuntime = getActiveRuntime();
|
|
470038
|
-
if (existingRuntime) {
|
|
470039
|
-
stopRuntime(existingRuntime, true);
|
|
470040
|
-
setActiveRuntime(null);
|
|
470041
|
-
}
|
|
470042
|
-
const runtime = createRuntime();
|
|
470043
|
-
runtime.onWsEvent = undefined;
|
|
470044
|
-
runtime.connectionId = `app-server-${crypto.randomUUID()}`;
|
|
470045
|
-
runtime.connectionName = params.connectionName;
|
|
470046
|
-
setActiveRuntime(runtime);
|
|
470047
|
-
telemetry.setSurface(getListenerTelemetrySurface());
|
|
470048
|
-
telemetry.init();
|
|
470049
|
-
const startupReady = (async () => {
|
|
470050
|
-
await reloadListenerModAdapter(runtime);
|
|
470051
|
-
await loadTools();
|
|
470052
|
-
})();
|
|
470053
|
-
const activeSession = {
|
|
470054
|
-
runtime,
|
|
470055
|
-
controlSocket: params.socket,
|
|
470056
|
-
streamSocket: params.streamSocket
|
|
470057
|
-
};
|
|
470058
|
-
params.onSessionCreated(activeSession);
|
|
470059
|
-
await attachOpenListenerSocket(runtime, params.socket, {
|
|
470060
|
-
connectionId: runtime.connectionId ?? "app-server",
|
|
470061
|
-
wsUrl: params.serverUrl,
|
|
470062
|
-
supportsSplitStatusChannels: true,
|
|
470063
|
-
deviceId: settingsManager.getOrCreateDeviceId(),
|
|
470064
|
-
connectionName: params.connectionName,
|
|
470065
|
-
onConnected: () => {},
|
|
470066
|
-
onDisconnected: params.onSessionClosed,
|
|
470067
|
-
onError: () => {}
|
|
470068
|
-
}, {
|
|
470069
|
-
streamSocket: params.streamSocket,
|
|
470070
|
-
startHeartbeat: false,
|
|
470071
|
-
startCronScheduler: true,
|
|
470072
|
-
startupReady
|
|
470073
|
-
});
|
|
470074
|
-
return activeSession;
|
|
470075
|
-
}
|
|
470076
470960
|
async function startAppServer(options3 = {}) {
|
|
470077
470961
|
await settingsManager.initialize();
|
|
470078
470962
|
const listen = parseAppServerListenUrl(options3.listen);
|
|
@@ -470081,72 +470965,60 @@ async function startAppServer(options3 = {}) {
|
|
|
470081
470965
|
throw new Error(`refusing to start non-loopback websocket listener ${listen.host}:${listen.port} without auth; configure \`--ws-auth capability-token\` or \`--ws-auth signed-bearer-token\``);
|
|
470082
470966
|
}
|
|
470083
470967
|
const wss = new WebSocketServer({ noServer: true });
|
|
470084
|
-
let activeSession = null;
|
|
470085
|
-
let pendingStreamSocket = null;
|
|
470086
|
-
let pendingStreamTimeout = null;
|
|
470087
470968
|
let resolvedInfo = null;
|
|
470088
|
-
|
|
470089
|
-
const
|
|
470090
|
-
|
|
470091
|
-
|
|
470092
|
-
|
|
470969
|
+
let nextConnectionOrdinal = 0;
|
|
470970
|
+
const runtime = createRuntime();
|
|
470971
|
+
runtime.onWsEvent = undefined;
|
|
470972
|
+
runtime.connectionId = "app-server";
|
|
470973
|
+
runtime.connectionName = options3.connectionName ?? hostname6();
|
|
470974
|
+
let startupReady = null;
|
|
470975
|
+
const getStartupReady = () => {
|
|
470976
|
+
if (startupReady) {
|
|
470977
|
+
return startupReady;
|
|
470093
470978
|
}
|
|
470094
|
-
const
|
|
470095
|
-
|
|
470096
|
-
|
|
470979
|
+
const attempt = (async () => {
|
|
470980
|
+
if (options3.initializeRuntime) {
|
|
470981
|
+
await options3.initializeRuntime(runtime);
|
|
470982
|
+
return;
|
|
470983
|
+
}
|
|
470984
|
+
await reloadListenerModAdapter(runtime);
|
|
470985
|
+
await loadTools();
|
|
470986
|
+
})();
|
|
470987
|
+
startupReady = attempt;
|
|
470988
|
+
attempt.catch(() => {
|
|
470989
|
+
if (startupReady === attempt) {
|
|
470990
|
+
startupReady = null;
|
|
470991
|
+
}
|
|
470992
|
+
});
|
|
470993
|
+
return startupReady;
|
|
470097
470994
|
};
|
|
470098
|
-
const
|
|
470995
|
+
const lastPongAtBySocket = new WeakMap;
|
|
470996
|
+
const handleWebSocketConnection = (socket) => {
|
|
470997
|
+
const connectionId = `app-server-${nextConnectionOrdinal}`;
|
|
470998
|
+
nextConnectionOrdinal += 1;
|
|
470099
470999
|
lastPongAtBySocket.set(socket, Date.now());
|
|
470100
471000
|
socket.on("pong", () => {
|
|
470101
|
-
|
|
470102
|
-
|
|
470103
|
-
if (channel === "stream") {
|
|
470104
|
-
if (activeSession) {
|
|
470105
|
-
attachStreamSocket(activeSession, socket);
|
|
470106
|
-
return;
|
|
470107
|
-
}
|
|
470108
|
-
if (pendingStreamSocket) {
|
|
470109
|
-
closeSocket(socket, 1008, "stream channel already pending");
|
|
470110
|
-
return;
|
|
471001
|
+
if (options3.shouldRecordPong?.(connectionId) !== false) {
|
|
471002
|
+
lastPongAtBySocket.set(socket, Date.now());
|
|
470111
471003
|
}
|
|
470112
|
-
|
|
470113
|
-
|
|
470114
|
-
|
|
470115
|
-
|
|
470116
|
-
|
|
470117
|
-
socket.on("close", () => {
|
|
470118
|
-
if (pendingStreamSocket === socket) {
|
|
470119
|
-
clearPendingStream();
|
|
470120
|
-
}
|
|
470121
|
-
});
|
|
470122
|
-
socket.on("error", (error54) => {
|
|
470123
|
-
options3.onLog?.(`App-server stream socket error: ${error54.message}`);
|
|
470124
|
-
});
|
|
470125
|
-
return;
|
|
470126
|
-
}
|
|
470127
|
-
if (activeSession) {
|
|
470128
|
-
closeSocket(socket, 1008, "control channel already connected");
|
|
470129
|
-
return;
|
|
470130
|
-
}
|
|
470131
|
-
const streamSocket = clearPendingStream();
|
|
470132
|
-
startControlSession({
|
|
470133
|
-
socket,
|
|
470134
|
-
streamSocket,
|
|
471004
|
+
});
|
|
471005
|
+
attachOpenListenerSocket(runtime, socket, {
|
|
471006
|
+
connectionId,
|
|
471007
|
+
wsUrl: resolvedInfo?.url ?? options3.listen ?? DEFAULT_LISTEN_URL,
|
|
471008
|
+
deviceId: settingsManager.getOrCreateDeviceId(),
|
|
470135
471009
|
connectionName: options3.connectionName ?? hostname6(),
|
|
470136
|
-
|
|
470137
|
-
|
|
470138
|
-
|
|
470139
|
-
|
|
470140
|
-
onSessionClosed: () => {
|
|
470141
|
-
activeSession = null;
|
|
471010
|
+
onConnected: () => {},
|
|
471011
|
+
onDisconnected: () => {},
|
|
471012
|
+
onError: (error54) => {
|
|
471013
|
+
options3.onLog?.(`App-server connection ${connectionId} failed: ${error54.message}`);
|
|
470142
471014
|
}
|
|
471015
|
+
}, {
|
|
471016
|
+
startHeartbeat: false,
|
|
471017
|
+
startCronScheduler: true,
|
|
471018
|
+
startupReady: getStartupReady()
|
|
470143
471019
|
}).catch((error54) => {
|
|
470144
|
-
|
|
470145
|
-
|
|
470146
|
-
}
|
|
470147
|
-
options3.onLog?.(`Failed to start app-server session: ${error54 instanceof Error ? error54.message : String(error54)}`);
|
|
470148
|
-
closeSocket(socket, 1011, "failed to start session");
|
|
470149
|
-
closeSocket(streamSocket, 1011, "failed to start session");
|
|
471020
|
+
options3.onLog?.(`Failed to start app-server connection: ${error54 instanceof Error ? error54.message : String(error54)}`);
|
|
471021
|
+
closeSocket(socket, 1011, "failed to start connection");
|
|
470150
471022
|
});
|
|
470151
471023
|
};
|
|
470152
471024
|
const server2 = createServer((request, response) => {
|
|
@@ -470198,9 +471070,9 @@ async function startAppServer(options3 = {}) {
|
|
|
470198
471070
|
rejectUpgrade(socket, 404, "Not Found");
|
|
470199
471071
|
return;
|
|
470200
471072
|
}
|
|
470201
|
-
|
|
470202
|
-
|
|
470203
|
-
rejectUpgrade(socket,
|
|
471073
|
+
if (requestUrl.searchParams.has("channel")) {
|
|
471074
|
+
options3.onLog?.("Rejecting legacy split-channel app-server client; upgrade to a one-socket client");
|
|
471075
|
+
rejectUpgrade(socket, 426, "Upgrade Required");
|
|
470204
471076
|
return;
|
|
470205
471077
|
}
|
|
470206
471078
|
const authError = authorizeUpgrade(request.headers, authPolicy);
|
|
@@ -470215,7 +471087,7 @@ async function startAppServer(options3 = {}) {
|
|
|
470215
471087
|
return;
|
|
470216
471088
|
}
|
|
470217
471089
|
wss.handleUpgrade(request, socket, head2, (websocket) => {
|
|
470218
|
-
handleWebSocketConnection(websocket
|
|
471090
|
+
handleWebSocketConnection(websocket);
|
|
470219
471091
|
});
|
|
470220
471092
|
});
|
|
470221
471093
|
const heartbeatIntervalMs = options3.heartbeatIntervalMs ?? APP_SERVER_HEARTBEAT_INTERVAL_MS;
|
|
@@ -470238,25 +471110,38 @@ async function startAppServer(options3 = {}) {
|
|
|
470238
471110
|
wss.on("close", () => {
|
|
470239
471111
|
clearInterval(heartbeatInterval);
|
|
470240
471112
|
});
|
|
470241
|
-
|
|
470242
|
-
|
|
470243
|
-
|
|
470244
|
-
|
|
470245
|
-
|
|
470246
|
-
|
|
470247
|
-
|
|
470248
|
-
|
|
470249
|
-
|
|
470250
|
-
|
|
470251
|
-
|
|
470252
|
-
|
|
470253
|
-
|
|
471113
|
+
try {
|
|
471114
|
+
await new Promise((resolve32, reject) => {
|
|
471115
|
+
const onError = (error54) => {
|
|
471116
|
+
server2.off("listening", onListening);
|
|
471117
|
+
reject(error54);
|
|
471118
|
+
};
|
|
471119
|
+
const onListening = () => {
|
|
471120
|
+
server2.off("error", onError);
|
|
471121
|
+
resolve32();
|
|
471122
|
+
};
|
|
471123
|
+
server2.once("error", onError);
|
|
471124
|
+
server2.once("listening", onListening);
|
|
471125
|
+
server2.listen(listen.port, listen.host);
|
|
471126
|
+
});
|
|
471127
|
+
} catch (error54) {
|
|
471128
|
+
clearInterval(heartbeatInterval);
|
|
471129
|
+
runtime.intentionallyClosed = true;
|
|
471130
|
+
throw error54;
|
|
471131
|
+
}
|
|
471132
|
+
const existingRuntime = getActiveRuntime();
|
|
471133
|
+
if (existingRuntime) {
|
|
471134
|
+
stopRuntime(existingRuntime, true);
|
|
471135
|
+
setActiveRuntime(null);
|
|
471136
|
+
}
|
|
471137
|
+
setActiveRuntime(runtime);
|
|
471138
|
+
telemetry.setSurface(getListenerTelemetrySurface());
|
|
471139
|
+
telemetry.init();
|
|
470254
471140
|
const address = getRequiredAddressInfo(server2);
|
|
470255
471141
|
const baseUrl = `ws://${listen.host}:${address.port}`;
|
|
470256
471142
|
resolvedInfo = {
|
|
470257
471143
|
url: baseUrl,
|
|
470258
|
-
controlUrl:
|
|
470259
|
-
streamUrl: getChannelUrl(baseUrl, listen.path, "stream")
|
|
471144
|
+
controlUrl: getWebSocketUrl(baseUrl, listen.path)
|
|
470260
471145
|
};
|
|
470261
471146
|
options3.onListening?.(resolvedInfo);
|
|
470262
471147
|
return {
|
|
@@ -470266,21 +471151,13 @@ async function startAppServer(options3 = {}) {
|
|
|
470266
471151
|
if (options3.openaiApi) {
|
|
470267
471152
|
closeOpenAiBridgeRuntime();
|
|
470268
471153
|
}
|
|
470269
|
-
const streamSocket = clearPendingStream();
|
|
470270
|
-
terminateSocket(streamSocket);
|
|
470271
|
-
if (activeSession) {
|
|
470272
|
-
const session = activeSession;
|
|
470273
|
-
activeSession = null;
|
|
470274
|
-
terminateSocket(session.streamSocket);
|
|
470275
|
-
terminateSocket(session.controlSocket);
|
|
470276
|
-
stopRuntime(session.runtime, true);
|
|
470277
|
-
if (getActiveRuntime() === session.runtime) {
|
|
470278
|
-
setActiveRuntime(null);
|
|
470279
|
-
}
|
|
470280
|
-
}
|
|
470281
471154
|
for (const client of wss.clients) {
|
|
470282
471155
|
terminateSocket(client);
|
|
470283
471156
|
}
|
|
471157
|
+
if (getActiveRuntime() === runtime) {
|
|
471158
|
+
stopRuntime(runtime, true);
|
|
471159
|
+
setActiveRuntime(null);
|
|
471160
|
+
}
|
|
470284
471161
|
await new Promise((resolve32, reject) => {
|
|
470285
471162
|
wss.close();
|
|
470286
471163
|
const timeout = setTimeout(resolve32, 1000);
|
|
@@ -470296,7 +471173,7 @@ async function startAppServer(options3 = {}) {
|
|
|
470296
471173
|
}
|
|
470297
471174
|
};
|
|
470298
471175
|
}
|
|
470299
|
-
var DEFAULT_LISTEN_URL = "ws://127.0.0.1:0", DEFAULT_WS_PATH = "/ws",
|
|
471176
|
+
var DEFAULT_LISTEN_URL = "ws://127.0.0.1:0", DEFAULT_WS_PATH = "/ws", APP_SERVER_HEARTBEAT_INTERVAL_MS = 30000, APP_SERVER_PONG_TIMEOUT_MS = 90000;
|
|
470300
471177
|
var init_app_server = __esm(async () => {
|
|
470301
471178
|
init_settings_manager();
|
|
470302
471179
|
init_telemetry();
|
|
@@ -470402,8 +471279,7 @@ async function runAppServerSubcommand(argv) {
|
|
|
470402
471279
|
openaiApi,
|
|
470403
471280
|
onListening: (info) => {
|
|
470404
471281
|
console.log(`Listening on ${info.url}`);
|
|
470405
|
-
console.log(`
|
|
470406
|
-
console.log(`Stream: ${info.streamUrl}`);
|
|
471282
|
+
console.log(`WebSocket: ${info.controlUrl}`);
|
|
470407
471283
|
if (openaiApi) {
|
|
470408
471284
|
const openaiBase = new URL(info.url);
|
|
470409
471285
|
openaiBase.protocol = "http:";
|
|
@@ -472207,7 +473083,7 @@ var init_AgentSelector = __esm(async () => {
|
|
|
472207
473083
|
// src/cli/subcommands/skills.ts
|
|
472208
473084
|
import {
|
|
472209
473085
|
cpSync as cpSync2,
|
|
472210
|
-
existsSync as
|
|
473086
|
+
existsSync as existsSync58,
|
|
472211
473087
|
mkdtempSync as mkdtempSync4,
|
|
472212
473088
|
readFileSync as readFileSync37,
|
|
472213
473089
|
rmSync as rmSync15,
|
|
@@ -472666,7 +473542,7 @@ async function installSkillDirectory(params) {
|
|
|
472666
473542
|
const sourceDir = resolve32(params.sourceDir);
|
|
472667
473543
|
const memoryDir = resolve32(params.memoryDir);
|
|
472668
473544
|
const skillMdPath = join71(sourceDir, "SKILL.md");
|
|
472669
|
-
if (!
|
|
473545
|
+
if (!existsSync58(skillMdPath)) {
|
|
472670
473546
|
throw new Error("No SKILL.md found in the skill directory.");
|
|
472671
473547
|
}
|
|
472672
473548
|
if (!statSync19(sourceDir).isDirectory()) {
|
|
@@ -472676,7 +473552,7 @@ async function installSkillDirectory(params) {
|
|
|
472676
473552
|
const skillsDir = join71(memoryDir, "skills");
|
|
472677
473553
|
const targetPath = join71(skillsDir, name);
|
|
472678
473554
|
assertInside(skillsDir, targetPath);
|
|
472679
|
-
if (
|
|
473555
|
+
if (existsSync58(targetPath)) {
|
|
472680
473556
|
if (!params.force) {
|
|
472681
473557
|
throw new Error(`Skill "${name}" already exists at ${targetPath}. Re-run with --force to replace it.`);
|
|
472682
473558
|
}
|
|
@@ -472692,7 +473568,7 @@ async function installSkillDirectory(params) {
|
|
|
472692
473568
|
async function listSkillDirectories(params) {
|
|
472693
473569
|
const memoryDir = resolve32(params.memoryDir);
|
|
472694
473570
|
const skillsDir = join71(memoryDir, "skills");
|
|
472695
|
-
if (!
|
|
473571
|
+
if (!existsSync58(skillsDir))
|
|
472696
473572
|
return [];
|
|
472697
473573
|
const entries = await readdir14(skillsDir, { withFileTypes: true });
|
|
472698
473574
|
const skills = [];
|
|
@@ -472701,7 +473577,7 @@ async function listSkillDirectories(params) {
|
|
|
472701
473577
|
continue;
|
|
472702
473578
|
const skillDir = join71(skillsDir, entry.name);
|
|
472703
473579
|
const skillMdPath = join71(skillDir, "SKILL.md");
|
|
472704
|
-
if (!
|
|
473580
|
+
if (!existsSync58(skillMdPath))
|
|
472705
473581
|
continue;
|
|
472706
473582
|
let name = entry.name;
|
|
472707
473583
|
let description;
|
|
@@ -472725,7 +473601,7 @@ async function deleteSkillDirectory(params) {
|
|
|
472725
473601
|
const name = sanitizeSkillName(params.name);
|
|
472726
473602
|
const targetPath = join71(skillsDir, name);
|
|
472727
473603
|
assertInside(skillsDir, targetPath);
|
|
472728
|
-
if (!
|
|
473604
|
+
if (!existsSync58(targetPath)) {
|
|
472729
473605
|
throw new Error(`Skill "${name}" is not installed at ${targetPath}.`);
|
|
472730
473606
|
}
|
|
472731
473607
|
if (!statSync19(targetPath).isDirectory()) {
|
|
@@ -472774,7 +473650,7 @@ async function installSkill(specifier, agentId, force) {
|
|
|
472774
473650
|
tmpDir = downloaded.tmpDir;
|
|
472775
473651
|
const sourceDir = resolve32(downloaded.sourceDir);
|
|
472776
473652
|
assertInside(tmpDir, sourceDir);
|
|
472777
|
-
if (!
|
|
473653
|
+
if (!existsSync58(sourceDir)) {
|
|
472778
473654
|
const missingPath = source2.type === "git" ? source2.location.subdir ?? "." : source2.type === "direct-file" ? source2.location.url : source2.location.slug;
|
|
472779
473655
|
throw new Error(`Skill path not found: ${missingPath}`);
|
|
472780
473656
|
}
|
|
@@ -474073,11 +474949,11 @@ var exports_bootstrap_tools = {};
|
|
|
474073
474949
|
__export(exports_bootstrap_tools, {
|
|
474074
474950
|
bootstrapBaseToolsIfNeeded: () => bootstrapBaseToolsIfNeeded
|
|
474075
474951
|
});
|
|
474076
|
-
import { existsSync as
|
|
474952
|
+
import { existsSync as existsSync59, mkdirSync as mkdirSync42, writeFileSync as writeFileSync31 } from "node:fs";
|
|
474077
474953
|
import { homedir as homedir42 } from "node:os";
|
|
474078
474954
|
import { join as join75 } from "node:path";
|
|
474079
474955
|
async function bootstrapBaseToolsIfNeeded() {
|
|
474080
|
-
if (
|
|
474956
|
+
if (existsSync59(MARKER_PATH))
|
|
474081
474957
|
return;
|
|
474082
474958
|
debugLog("bootstrap", "No marker found, bootstrapping base tools...");
|
|
474083
474959
|
try {
|
|
@@ -474643,7 +475519,7 @@ var init_headless_tool_events = __esm(async () => {
|
|
|
474643
475519
|
});
|
|
474644
475520
|
|
|
474645
475521
|
// src/skills/builtin/creating-skills/scripts/validate-skill.ts
|
|
474646
|
-
import { existsSync as
|
|
475522
|
+
import { existsSync as existsSync60, readFileSync as readFileSync38 } from "node:fs";
|
|
474647
475523
|
import { basename as basename30, join as join77, resolve as resolve33 } from "node:path";
|
|
474648
475524
|
import { fileURLToPath as fileURLToPath11 } from "node:url";
|
|
474649
475525
|
function parseQuotedScalar(value) {
|
|
@@ -474742,7 +475618,7 @@ function parseFrontmatter2(source2) {
|
|
|
474742
475618
|
}
|
|
474743
475619
|
function validateSkill(skillPath) {
|
|
474744
475620
|
const skillMdPath = join77(skillPath, "SKILL.md");
|
|
474745
|
-
if (!
|
|
475621
|
+
if (!existsSync60(skillMdPath)) {
|
|
474746
475622
|
return { valid: false, message: "SKILL.md not found" };
|
|
474747
475623
|
}
|
|
474748
475624
|
const content = readFileSync38(skillMdPath, "utf-8");
|
|
@@ -479871,7 +480747,7 @@ var init_queued_message_parts = __esm(() => {
|
|
|
479871
480747
|
|
|
479872
480748
|
// src/cli/helpers/reflection-arena-hf-upload.ts
|
|
479873
480749
|
import { execFile as execFileCb5 } from "node:child_process";
|
|
479874
|
-
import { existsSync as
|
|
480750
|
+
import { existsSync as existsSync62 } from "node:fs";
|
|
479875
480751
|
import { appendFile as appendFile2, chmod as chmod2, mkdir as mkdir18, writeFile as writeFile20 } from "node:fs/promises";
|
|
479876
480752
|
import { homedir as homedir45 } from "node:os";
|
|
479877
480753
|
import { join as join79 } from "node:path";
|
|
@@ -479925,7 +480801,7 @@ async function writeGitAskpass(repoRoot) {
|
|
|
479925
480801
|
}
|
|
479926
480802
|
async function prepareHfRepo(env5) {
|
|
479927
480803
|
await mkdir18(HF_CACHE_ROOT, { recursive: true });
|
|
479928
|
-
if (!
|
|
480804
|
+
if (!existsSync62(join79(HF_REPO_DIR, ".git"))) {
|
|
479929
480805
|
await runGit6(HF_CACHE_ROOT, ["clone", "--depth", "1", HF_REPO_URL, HF_REPO_DIR], env5);
|
|
479930
480806
|
return HF_REPO_DIR;
|
|
479931
480807
|
}
|
|
@@ -481128,7 +482004,7 @@ __export(exports_terminal_keybinding_installer, {
|
|
|
481128
482004
|
});
|
|
481129
482005
|
import {
|
|
481130
482006
|
copyFileSync as copyFileSync6,
|
|
481131
|
-
existsSync as
|
|
482007
|
+
existsSync as existsSync63,
|
|
481132
482008
|
mkdirSync as mkdirSync44,
|
|
481133
482009
|
readFileSync as readFileSync40,
|
|
481134
482010
|
writeFileSync as writeFileSync33
|
|
@@ -481197,7 +482073,7 @@ function parseKeybindings(content) {
|
|
|
481197
482073
|
}
|
|
481198
482074
|
}
|
|
481199
482075
|
function keybindingExists(keybindingsPath) {
|
|
481200
|
-
if (!
|
|
482076
|
+
if (!existsSync63(keybindingsPath))
|
|
481201
482077
|
return false;
|
|
481202
482078
|
try {
|
|
481203
482079
|
const content = readFileSync40(keybindingsPath, { encoding: "utf-8" });
|
|
@@ -481210,7 +482086,7 @@ function keybindingExists(keybindingsPath) {
|
|
|
481210
482086
|
}
|
|
481211
482087
|
}
|
|
481212
482088
|
function createBackup(keybindingsPath) {
|
|
481213
|
-
if (!
|
|
482089
|
+
if (!existsSync63(keybindingsPath))
|
|
481214
482090
|
return null;
|
|
481215
482091
|
const backupPath = `${keybindingsPath}.letta-backup`;
|
|
481216
482092
|
try {
|
|
@@ -481226,12 +482102,12 @@ function installKeybinding(keybindingsPath) {
|
|
|
481226
482102
|
return { success: true, alreadyExists: true };
|
|
481227
482103
|
}
|
|
481228
482104
|
const parentDir = dirname34(keybindingsPath);
|
|
481229
|
-
if (!
|
|
482105
|
+
if (!existsSync63(parentDir)) {
|
|
481230
482106
|
mkdirSync44(parentDir, { recursive: true });
|
|
481231
482107
|
}
|
|
481232
482108
|
let keybindings = [];
|
|
481233
482109
|
let backupPath = null;
|
|
481234
|
-
if (
|
|
482110
|
+
if (existsSync63(keybindingsPath)) {
|
|
481235
482111
|
backupPath = createBackup(keybindingsPath);
|
|
481236
482112
|
const content = readFileSync40(keybindingsPath, { encoding: "utf-8" });
|
|
481237
482113
|
const parsed = parseKeybindings(content);
|
|
@@ -481261,7 +482137,7 @@ function installKeybinding(keybindingsPath) {
|
|
|
481261
482137
|
}
|
|
481262
482138
|
function removeKeybinding(keybindingsPath) {
|
|
481263
482139
|
try {
|
|
481264
|
-
if (!
|
|
482140
|
+
if (!existsSync63(keybindingsPath)) {
|
|
481265
482141
|
return { success: true };
|
|
481266
482142
|
}
|
|
481267
482143
|
const content = readFileSync40(keybindingsPath, { encoding: "utf-8" });
|
|
@@ -481329,11 +482205,11 @@ function getWezTermConfigPath() {
|
|
|
481329
482205
|
const xdgConfig = process.env.XDG_CONFIG_HOME;
|
|
481330
482206
|
if (xdgConfig) {
|
|
481331
482207
|
const xdgPath = join81(xdgConfig, "wezterm", "wezterm.lua");
|
|
481332
|
-
if (
|
|
482208
|
+
if (existsSync63(xdgPath))
|
|
481333
482209
|
return xdgPath;
|
|
481334
482210
|
}
|
|
481335
482211
|
const configPath = join81(homedir47(), ".config", "wezterm", "wezterm.lua");
|
|
481336
|
-
if (
|
|
482212
|
+
if (existsSync63(configPath))
|
|
481337
482213
|
return configPath;
|
|
481338
482214
|
return join81(homedir47(), ".wezterm.lua");
|
|
481339
482215
|
}
|
|
@@ -481438,7 +482314,7 @@ ${WEZTERM_DELETE_FIX}
|
|
|
481438
482314
|
`;
|
|
481439
482315
|
}
|
|
481440
482316
|
function wezTermDeleteFixExists(configPath) {
|
|
481441
|
-
if (!
|
|
482317
|
+
if (!existsSync63(configPath))
|
|
481442
482318
|
return false;
|
|
481443
482319
|
try {
|
|
481444
482320
|
const content = readFileSync40(configPath, { encoding: "utf-8" });
|
|
@@ -481455,14 +482331,14 @@ function installWezTermDeleteFix() {
|
|
|
481455
482331
|
}
|
|
481456
482332
|
let content = "";
|
|
481457
482333
|
let backupPath = null;
|
|
481458
|
-
if (
|
|
482334
|
+
if (existsSync63(configPath)) {
|
|
481459
482335
|
backupPath = `${configPath}.letta-backup`;
|
|
481460
482336
|
copyFileSync6(configPath, backupPath);
|
|
481461
482337
|
content = readFileSync40(configPath, { encoding: "utf-8" });
|
|
481462
482338
|
}
|
|
481463
482339
|
content = injectWezTermDeleteFix(content);
|
|
481464
482340
|
const parentDir = dirname34(configPath);
|
|
481465
|
-
if (!
|
|
482341
|
+
if (!existsSync63(parentDir)) {
|
|
481466
482342
|
mkdirSync44(parentDir, { recursive: true });
|
|
481467
482343
|
}
|
|
481468
482344
|
writeFileSync33(configPath, content, { encoding: "utf-8" });
|
|
@@ -483458,9 +484334,9 @@ function getHeaderText(fileEdit) {
|
|
|
483458
484334
|
const relPath = relative17(cwd2, fileEdit.filePath);
|
|
483459
484335
|
const displayPath = relPath.startsWith("..") ? fileEdit.filePath : relPath;
|
|
483460
484336
|
if (t2 === "write" || t2 === "write_file" || t2 === "writefile" || t2 === "write_file_gemini" || t2 === "writefilegemini") {
|
|
483461
|
-
const { existsSync:
|
|
484337
|
+
const { existsSync: existsSync64 } = __require("node:fs");
|
|
483462
484338
|
try {
|
|
483463
|
-
if (
|
|
484339
|
+
if (existsSync64(fileEdit.filePath)) {
|
|
483464
484340
|
return `Overwrite ${displayPath}?`;
|
|
483465
484341
|
}
|
|
483466
484342
|
} catch {}
|
|
@@ -492949,7 +493825,7 @@ var init_agents8 = __esm(() => {
|
|
|
492949
493825
|
// src/cli/commands/install-github-app.ts
|
|
492950
493826
|
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
492951
493827
|
import {
|
|
492952
|
-
existsSync as
|
|
493828
|
+
existsSync as existsSync64,
|
|
492953
493829
|
mkdirSync as mkdirSync45,
|
|
492954
493830
|
mkdtempSync as mkdtempSync5,
|
|
492955
493831
|
readFileSync as readFileSync41,
|
|
@@ -493191,12 +494067,12 @@ function runGit7(args, cwd2) {
|
|
|
493191
494067
|
}
|
|
493192
494068
|
function writeWorkflow(repoDir, workflowPath, content) {
|
|
493193
494069
|
const absolutePath = join83(repoDir, workflowPath);
|
|
493194
|
-
if (!
|
|
494070
|
+
if (!existsSync64(dirname35(absolutePath))) {
|
|
493195
494071
|
mkdirSync45(dirname35(absolutePath), { recursive: true });
|
|
493196
494072
|
}
|
|
493197
494073
|
const next = `${content.trimEnd()}
|
|
493198
494074
|
`;
|
|
493199
|
-
if (
|
|
494075
|
+
if (existsSync64(absolutePath)) {
|
|
493200
494076
|
const previous = readFileSync41(absolutePath, "utf8");
|
|
493201
494077
|
if (previous === next) {
|
|
493202
494078
|
return false;
|
|
@@ -497742,7 +498618,7 @@ __export(exports_generate_memory_viewer, {
|
|
|
497742
498618
|
generateAndOpenMemoryViewer: () => generateAndOpenMemoryViewer
|
|
497743
498619
|
});
|
|
497744
498620
|
import { execFile as execFileCb7 } from "node:child_process";
|
|
497745
|
-
import { chmodSync as chmodSync7, existsSync as
|
|
498621
|
+
import { chmodSync as chmodSync7, existsSync as existsSync65, mkdirSync as mkdirSync46, writeFileSync as writeFileSync35 } from "node:fs";
|
|
497746
498622
|
import { homedir as homedir50 } from "node:os";
|
|
497747
498623
|
import { join as join84 } from "node:path";
|
|
497748
498624
|
import { promisify as promisify17 } from "node:util";
|
|
@@ -498053,7 +498929,7 @@ ${m4.body}` : m4.subject;
|
|
|
498053
498929
|
async function generateAndOpenMemoryViewer(agentId, options3) {
|
|
498054
498930
|
const memoryRoot = getScopedMemoryFilesystemRoot(agentId);
|
|
498055
498931
|
const repoDir = memoryRoot;
|
|
498056
|
-
if (!
|
|
498932
|
+
if (!existsSync65(join84(repoDir, ".git"))) {
|
|
498057
498933
|
throw new Error("Memory viewer requires memfs. Run /memfs enable first.");
|
|
498058
498934
|
}
|
|
498059
498935
|
const data = await collectMemoryData(agentId, repoDir, memoryRoot, options3?.conversationId);
|
|
@@ -498063,7 +498939,7 @@ async function generateAndOpenMemoryViewer(agentId, options3) {
|
|
|
498063
498939
|
data.context = applyContextUsageSnapshot(data.context, options3?.contextUsage);
|
|
498064
498940
|
const jsonPayload = JSON.stringify(data).replace(/</g, "\\u003c");
|
|
498065
498941
|
const html5 = memory_viewer_template_default.replace("<!--LETTA_DATA_PLACEHOLDER-->", () => jsonPayload);
|
|
498066
|
-
if (!
|
|
498942
|
+
if (!existsSync65(VIEWERS_DIR)) {
|
|
498067
498943
|
mkdirSync46(VIEWERS_DIR, { recursive: true, mode: 448 });
|
|
498068
498944
|
}
|
|
498069
498945
|
try {
|
|
@@ -498099,7 +498975,7 @@ var init_generate_memory_viewer = __esm(() => {
|
|
|
498099
498975
|
});
|
|
498100
498976
|
|
|
498101
498977
|
// src/cli/components/MemfsTreeViewer.tsx
|
|
498102
|
-
import { existsSync as
|
|
498978
|
+
import { existsSync as existsSync66 } from "node:fs";
|
|
498103
498979
|
import { join as join85 } from "node:path";
|
|
498104
498980
|
function renderTreePrefix(node) {
|
|
498105
498981
|
let prefix = "";
|
|
@@ -498128,8 +499004,8 @@ function MemfsTreeViewer({
|
|
|
498128
499004
|
const [status, setStatus] = import_react88.useState(null);
|
|
498129
499005
|
const statusTimerRef = import_react88.useRef(null);
|
|
498130
499006
|
const memoryRoot = getScopedMemoryFilesystemRoot(agentId);
|
|
498131
|
-
const memoryExists =
|
|
498132
|
-
const hasGitRepo = import_react88.useMemo(() =>
|
|
499007
|
+
const memoryExists = existsSync66(memoryRoot);
|
|
499008
|
+
const hasGitRepo = import_react88.useMemo(() => existsSync66(join85(memoryRoot, ".git")), [memoryRoot]);
|
|
498133
499009
|
function showStatus(msg, durationMs) {
|
|
498134
499010
|
if (statusTimerRef.current)
|
|
498135
499011
|
clearTimeout(statusTimerRef.current);
|
|
@@ -506021,9 +506897,9 @@ function getFileEditHeader(toolName, toolArgs) {
|
|
|
506021
506897
|
const relPath = relative17(cwd2, filePath);
|
|
506022
506898
|
const displayPath2 = relPath.startsWith("..") ? filePath : relPath;
|
|
506023
506899
|
if (t2 === "write" || t2 === "write_file" || t2 === "writefile" || t2 === "write_file_gemini" || t2 === "writefilegemini") {
|
|
506024
|
-
const { existsSync:
|
|
506900
|
+
const { existsSync: existsSync67 } = __require("node:fs");
|
|
506025
506901
|
try {
|
|
506026
|
-
if (
|
|
506902
|
+
if (existsSync67(filePath)) {
|
|
506027
506903
|
return `Overwrite ${displayPath2}?`;
|
|
506028
506904
|
}
|
|
506029
506905
|
} catch {}
|
|
@@ -521363,7 +522239,7 @@ __export(exports_generate_diff_viewer, {
|
|
|
521363
522239
|
generateAndOpenDiffViewer: () => generateAndOpenDiffViewer
|
|
521364
522240
|
});
|
|
521365
522241
|
import { execFile as execFileCb8 } from "node:child_process";
|
|
521366
|
-
import { chmodSync as chmodSync8, existsSync as
|
|
522242
|
+
import { chmodSync as chmodSync8, existsSync as existsSync67, mkdirSync as mkdirSync47, writeFileSync as writeFileSync36 } from "node:fs";
|
|
521367
522243
|
import { homedir as homedir52 } from "node:os";
|
|
521368
522244
|
import { isAbsolute as isAbsolute27, join as join87, resolve as resolve37 } from "node:path";
|
|
521369
522245
|
import { promisify as promisify18 } from "node:util";
|
|
@@ -521584,7 +522460,7 @@ async function generateAndOpenDiffViewer(targetPath) {
|
|
|
521584
522460
|
};
|
|
521585
522461
|
const jsonPayload = JSON.stringify(payload).replace(/</g, "\\u003c");
|
|
521586
522462
|
const html5 = diff_viewer_template_default.replace("<!--LETTA_DIFF_DATA_PLACEHOLDER-->", () => jsonPayload);
|
|
521587
|
-
if (!
|
|
522463
|
+
if (!existsSync67(VIEWERS_DIR2)) {
|
|
521588
522464
|
mkdirSync47(VIEWERS_DIR2, { recursive: true, mode: 448 });
|
|
521589
522465
|
}
|
|
521590
522466
|
try {
|
|
@@ -523643,12 +524519,12 @@ __export(exports_shell_aliases, {
|
|
|
523643
524519
|
expandAliases: () => expandAliases,
|
|
523644
524520
|
clearAliasCache: () => clearAliasCache
|
|
523645
524521
|
});
|
|
523646
|
-
import { existsSync as
|
|
524522
|
+
import { existsSync as existsSync68, readFileSync as readFileSync42 } from "node:fs";
|
|
523647
524523
|
import { homedir as homedir53 } from "node:os";
|
|
523648
524524
|
import { join as join88 } from "node:path";
|
|
523649
524525
|
function parseAliasesFromFile(filePath) {
|
|
523650
524526
|
const aliases = new Map;
|
|
523651
|
-
if (!
|
|
524527
|
+
if (!existsSync68(filePath)) {
|
|
523652
524528
|
return aliases;
|
|
523653
524529
|
}
|
|
523654
524530
|
try {
|
|
@@ -532012,7 +532888,7 @@ var init_conversation_switch_alert = __esm(() => {
|
|
|
532012
532888
|
|
|
532013
532889
|
// src/cli/app/use-submit-handler.ts
|
|
532014
532890
|
import { randomUUID as randomUUID37 } from "node:crypto";
|
|
532015
|
-
import { existsSync as
|
|
532891
|
+
import { existsSync as existsSync69, readFileSync as readFileSync43, renameSync as renameSync7, writeFileSync as writeFileSync37 } from "node:fs";
|
|
532016
532892
|
import { tmpdir as tmpdir12 } from "node:os";
|
|
532017
532893
|
import { join as join89 } from "node:path";
|
|
532018
532894
|
async function findCustomCommandByName(commandName) {
|
|
@@ -532712,7 +533588,7 @@ ${SYSTEM_REMINDER_CLOSE}`),
|
|
|
532712
533588
|
join89(memoryRoot, "system", "persona.md"),
|
|
532713
533589
|
join89(memoryRoot, "memory", "system", "persona.md")
|
|
532714
533590
|
];
|
|
532715
|
-
const personaPath = personaCandidates.find((candidate) =>
|
|
533591
|
+
const personaPath = personaCandidates.find((candidate) => existsSync69(candidate));
|
|
532716
533592
|
if (personaPath) {
|
|
532717
533593
|
const personaContent = readFileSync43(personaPath, "utf-8");
|
|
532718
533594
|
setCurrentPersonalityId(detectPersonalityFromPersonaFile(personaContent));
|
|
@@ -533592,7 +534468,7 @@ Path: ${memoryDir}`, true);
|
|
|
533592
534468
|
setCommandRunning(true);
|
|
533593
534469
|
try {
|
|
533594
534470
|
const memoryDir = getScopedMemoryFilesystemRoot(agentId);
|
|
533595
|
-
if (!
|
|
534471
|
+
if (!existsSync69(memoryDir)) {
|
|
533596
534472
|
updateMemorySyncCommand(cmdId, "No local memory filesystem found to reset.", true, msg);
|
|
533597
534473
|
return { submitted: true };
|
|
533598
534474
|
}
|
|
@@ -536299,13 +537175,17 @@ function App2({
|
|
|
536299
537175
|
`).trim();
|
|
536300
537176
|
};
|
|
536301
537177
|
const sysNorm = normalize8(agentSystem);
|
|
536302
|
-
const {
|
|
537178
|
+
const {
|
|
537179
|
+
getSystemPromptVariantContents: getSystemPromptVariantContents2,
|
|
537180
|
+
SYSTEM_PROMPTS: SYSTEM_PROMPTS2,
|
|
537181
|
+
SYSTEM_PROMPT: SYSTEM_PROMPT2
|
|
537182
|
+
} = await Promise.resolve().then(() => (init_prompt_assets(), exports_prompt_assets));
|
|
536303
537183
|
let matched = null;
|
|
536304
537184
|
const contentMatches = (content) => {
|
|
536305
537185
|
const norm = normalize8(content);
|
|
536306
537186
|
return norm === sysNorm || norm.length > 0 && (sysNorm.startsWith(norm) || norm.startsWith(sysNorm));
|
|
536307
537187
|
};
|
|
536308
|
-
const promptMatches = (prompt) =>
|
|
537188
|
+
const promptMatches = (prompt) => getSystemPromptVariantContents2(prompt).some(contentMatches);
|
|
536309
537189
|
const defaultPrompt = SYSTEM_PROMPTS2.find((p2) => p2.id === "default");
|
|
536310
537190
|
if (defaultPrompt && promptMatches(defaultPrompt)) {
|
|
536311
537191
|
matched = "default";
|
|
@@ -536626,9 +537506,9 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
|
|
|
536626
537506
|
(async () => {
|
|
536627
537507
|
try {
|
|
536628
537508
|
const { watch: watch3 } = await import("node:fs");
|
|
536629
|
-
const { existsSync:
|
|
537509
|
+
const { existsSync: existsSync70 } = await import("node:fs");
|
|
536630
537510
|
const memRoot = getScopedMemoryFilesystemRoot(agentId);
|
|
536631
|
-
if (!
|
|
537511
|
+
if (!existsSync70(memRoot))
|
|
536632
537512
|
return;
|
|
536633
537513
|
watcher2 = watch3(memRoot, { recursive: true }, () => {});
|
|
536634
537514
|
memfsWatcherRef.current = watcher2;
|
|
@@ -538740,9 +539620,9 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
538740
539620
|
}
|
|
538741
539621
|
} else {
|
|
538742
539622
|
const { resolve: resolve39 } = await import("node:path");
|
|
538743
|
-
const { existsSync:
|
|
539623
|
+
const { existsSync: existsSync70 } = await import("node:fs");
|
|
538744
539624
|
const resolvedPath = resolve39(fromAfFile);
|
|
538745
|
-
if (!
|
|
539625
|
+
if (!existsSync70(resolvedPath)) {
|
|
538746
539626
|
console.error(`Error: AgentFile not found: ${resolvedPath}`);
|
|
538747
539627
|
process.exit(1);
|
|
538748
539628
|
}
|
|
@@ -541433,4 +542313,4 @@ function registerBunOAuthFlows() {
|
|
|
541433
542313
|
registerBunOAuthFlows();
|
|
541434
542314
|
await init_src5().then(() => exports_src2);
|
|
541435
542315
|
|
|
541436
|
-
//# debugId=
|
|
542316
|
+
//# debugId=20D01332A3556DD664756E2164756E21
|