@letta-ai/letta-code 0.34.15 → 0.34.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/app-server-client.cjs +22 -2
  2. package/dist/app-server-client.cjs.map +4 -4
  3. package/dist/app-server-client.js +22 -2
  4. package/dist/app-server-client.js.map +4 -4
  5. package/dist/mcp-client.js +2 -2
  6. package/dist/mcp-client.js.map +1 -1
  7. package/dist/mcp-oauth.js +2 -2
  8. package/dist/mcp-oauth.js.map +1 -1
  9. package/dist/types/agent/turn-recovery-policy.d.ts +1 -0
  10. package/dist/types/agent/turn-recovery-policy.d.ts.map +1 -1
  11. package/dist/types/app-server-client.d.ts +14 -8
  12. package/dist/types/app-server-client.d.ts.map +1 -1
  13. package/dist/types/backend/api/environments.d.ts +2 -0
  14. package/dist/types/backend/api/environments.d.ts.map +1 -1
  15. package/dist/types/backend/dev/local-provider-errors.d.ts.map +1 -1
  16. package/dist/types/reminders/engine.d.ts +7 -0
  17. package/dist/types/reminders/engine.d.ts.map +1 -1
  18. package/dist/types/tools/impl/external-coding-agent-task.d.ts +2 -0
  19. package/dist/types/tools/impl/external-coding-agent-task.d.ts.map +1 -1
  20. package/dist/types/tools/impl/external-coding-agent.d.ts +13 -1
  21. package/dist/types/tools/impl/external-coding-agent.d.ts.map +1 -1
  22. package/dist/types/tools/impl/remote-external-coding-agent.d.ts +37 -1
  23. package/dist/types/tools/impl/remote-external-coding-agent.d.ts.map +1 -1
  24. package/dist/types/tools/impl/send-agent-message.d.ts +2 -0
  25. package/dist/types/tools/impl/send-agent-message.d.ts.map +1 -1
  26. package/dist/types/tools/impl/task-stop.d.ts +4 -1
  27. package/dist/types/tools/impl/task-stop.d.ts.map +1 -1
  28. package/dist/types/types/app-server-info.d.ts +2 -0
  29. package/dist/types/types/app-server-info.d.ts.map +1 -1
  30. package/dist/types/types/app-server-protocol.d.ts +4 -0
  31. package/dist/types/types/app-server-protocol.d.ts.map +1 -1
  32. package/dist/types/types/protocol_v2.d.ts +1 -0
  33. package/dist/types/types/protocol_v2.d.ts.map +1 -1
  34. package/dist/types/types/subagent-protocol.d.ts +34 -0
  35. package/dist/types/types/subagent-protocol.d.ts.map +1 -1
  36. package/dist/types/websocket/listener/protocol-outbound.d.ts.map +1 -1
  37. package/dist/types/websocket/listener/queue.d.ts.map +1 -1
  38. package/dist/types/websocket/listener/types.d.ts +4 -3
  39. package/dist/types/websocket/listener/types.d.ts.map +1 -1
  40. package/letta.js +530 -47
  41. package/npm-shrinkwrap.json +2 -2
  42. package/package.json +1 -1
  43. package/scripts/source-file-size-baseline.json +5 -3
  44. package/skills/working-across-computers/SKILL.md +4 -0
package/letta.js CHANGED
@@ -5913,7 +5913,7 @@ var package_default;
5913
5913
  var init_package = __esm(() => {
5914
5914
  package_default = {
5915
5915
  name: "@letta-ai/letta-code",
5916
- version: "0.34.15",
5916
+ version: "0.34.16",
5917
5917
  lettaStartupLogProtocol: 1,
5918
5918
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5919
5919
  type: "module",
@@ -113780,7 +113780,7 @@ function selectChatGPTQuotaFailoverHandle(params) {
113780
113780
  const index = Math.min(Math.floor(random() * candidates2.length), candidates2.length - 1);
113781
113781
  return candidates2[index]?.handle ?? null;
113782
113782
  }
113783
- var INVALID_TOOL_CALL_IDS_FRAGMENT = "invalid tool call ids", APPROVAL_PENDING_DETAIL_FRAGMENT = "waiting for approval", CONVERSATION_BUSY_DETAIL_FRAGMENTS, CONVERSATION_BUSY_RUN_ID_PATTERN, EMPTY_RESPONSE_DETAIL_FRAGMENT = "empty content in", RETRYABLE_PROVIDER_DETAIL_PATTERNS, NON_RETRYABLE_PROVIDER_DETAIL_PATTERNS, NON_RETRYABLE_RUN_ERROR_TYPES, NON_RETRYABLE_429_REASONS, NON_RETRYABLE_QUOTA_DETAIL_PATTERNS, NON_RETRYABLE_4XX_PATTERN, RETRYABLE_429_PATTERN, DEFAULT_TRANSIENT_RETRY_BASE_DELAY_MS = 1000, CLOUDFLARE_EDGE_52X_RETRY_BASE_DELAY_MS = 5000, CONVERSATION_BUSY_RETRY_BASE_DELAY_MS = 1e4, EMPTY_RESPONSE_RETRY_BASE_DELAY_MS = 500, STALE_APPROVAL_RECOVERY_DENIAL_REASON = "The agent harness automatically closed this stale pending tool call to recover from a client/server state desync: the server was still waiting on a result for it, but the harness had no matching tool execution in flight and no result was ever recorded. It was not denied by the user or a permissions policy. Re-issue the tool call if you still need it.", CHATGPT_USAGE_LIMIT_FRAGMENT = "usage_limit_reached", CHATGPT_OAUTH_PROVIDER_TYPE2 = "chatgpt_oauth", BYOK_PROVIDER_CATEGORY = "byok";
113783
+ var INVALID_TOOL_CALL_IDS_FRAGMENT = "invalid tool call ids", APPROVAL_PENDING_DETAIL_FRAGMENT = "waiting for approval", CONVERSATION_BUSY_DETAIL_FRAGMENTS, CONVERSATION_BUSY_RUN_ID_PATTERN, EMPTY_RESPONSE_DETAIL_FRAGMENT = "empty content in", RETRYABLE_PROVIDER_DETAIL_PATTERNS, NON_RETRYABLE_PROVIDER_DETAIL_PATTERNS, NON_RETRYABLE_RUN_ERROR_TYPES, NON_RETRYABLE_429_REASONS, NON_RETRYABLE_QUOTA_DETAIL_PATTERNS, NON_RETRYABLE_4XX_PATTERN, RETRYABLE_429_PATTERN, DEFAULT_TRANSIENT_RETRY_BASE_DELAY_MS = 1000, CLOUDFLARE_EDGE_52X_RETRY_BASE_DELAY_MS = 5000, CONVERSATION_BUSY_RETRY_BASE_DELAY_MS = 1e4, EMPTY_RESPONSE_RETRY_BASE_DELAY_MS = 500, STALE_APPROVAL_RECOVERY_DENIAL_REASON = "The agent harness automatically closed this stale pending tool call to recover from a client/server state desync: the server was still waiting on a result for it, but the harness had no matching tool execution in flight and no result was ever recorded. It was not denied by the user or a permissions policy. Re-issue the tool call if you still need it.", STARTED_TOOL_CALL_RECOVERY_DENIAL_REASON = "The agent harness closed this pending tool call while recovering from an interrupted turn. The call had started, but its result was not recorded, so it may or may not have run. Check whether its effect already happened before running it again.", CHATGPT_USAGE_LIMIT_FRAGMENT = "usage_limit_reached", CHATGPT_OAUTH_PROVIDER_TYPE2 = "chatgpt_oauth", BYOK_PROVIDER_CATEGORY = "byok";
113784
113784
  var init_turn_recovery_policy = __esm(() => {
113785
113785
  init_error_formatter();
113786
113786
  init_zai_errors();
@@ -114121,7 +114121,9 @@ var init_local_provider_errors = __esm(() => {
114121
114121
  "timed out",
114122
114122
  "terminated",
114123
114123
  "retry delay",
114124
- "unable to verify"
114124
+ "unable to verify",
114125
+ "websocket connection limit reached",
114126
+ "exceeded request buffer limit"
114125
114127
  ];
114126
114128
  });
114127
114129
 
@@ -210859,7 +210861,7 @@ var init_mcp_client = __esm(() => {
210859
210861
  init_streamableHttp();
210860
210862
  DEFAULT_CLIENT_INFO = {
210861
210863
  name: "letta-code",
210862
- version: "0.34.15"
210864
+ version: "0.34.16"
210863
210865
  };
210864
210866
  });
210865
210867
 
@@ -215074,6 +215076,7 @@ agent IDs backed by their native sessions. A message to active work steers its
215074
215076
  in-flight turn (Claude interrupts through stream-json and sends the replacement
215075
215077
  instruction; Codex uses app-server turn/steer). An idle follow-up starts one tracked local background
215076
215078
  turn. Neither path uses the Cloud messaging backend.
215079
+ Computer-qualified IDs returned by remote launches can be steered too.
215077
215080
 
215078
215081
  An agent has a persistent identity and shared memory. It can have multiple
215079
215082
  conversations, each with its own message history.
@@ -223299,6 +223302,7 @@ function buildSubagentSnapshot(runtime, scope) {
223299
223302
  prompt: a2.prompt,
223300
223303
  status: a2.status,
223301
223304
  agent_url: a2.agentURL,
223305
+ agent_id: a2.agentId ?? null,
223302
223306
  conversation_id: a2.conversationId ?? null,
223303
223307
  super_run_id: a2.superRunId,
223304
223308
  model: a2.model,
@@ -240089,7 +240093,7 @@ class CodexAppServerClient {
240089
240093
  await this.request("initialize", {
240090
240094
  clientInfo: {
240091
240095
  name: "letta-code",
240092
- version: "0.34.15"
240096
+ version: "0.34.16"
240093
240097
  },
240094
240098
  capabilities: null
240095
240099
  });
@@ -241207,10 +241211,22 @@ async function buildAgentInfoReminder(context3) {
241207
241211
  context3.state.hasSentAgentInfo = true;
241208
241212
  return reminder || null;
241209
241213
  }
241214
+ async function listAvailableSecretNames(agentId, lookupParent) {
241215
+ const { ensureSecretsLoaded: ensureSecretsLoaded2, listSecretNames: listSecretNames2 } = await Promise.resolve().then(() => (init_secrets_store(), exports_secrets_store));
241216
+ const names2 = new Set(listSecretNames2(agentId));
241217
+ try {
241218
+ const scopeAgentId = await getMcpScopeAgentId(agentId, undefined, lookupParent);
241219
+ if (scopeAgentId !== agentId) {
241220
+ await ensureSecretsLoaded2(scopeAgentId);
241221
+ for (const name of listSecretNames2(scopeAgentId))
241222
+ names2.add(name);
241223
+ }
241224
+ } catch {}
241225
+ return [...names2].sort();
241226
+ }
241210
241227
  async function buildSecretsInfoReminder(context3) {
241211
241228
  try {
241212
- const { listSecretNames: listSecretNames2 } = await Promise.resolve().then(() => (init_secrets_store(), exports_secrets_store));
241213
- const names2 = listSecretNames2(context3.agent.id);
241229
+ const names2 = await listAvailableSecretNames(context3.agent.id);
241214
241230
  const namesKey = names2.join("\x00");
241215
241231
  const isRefresh = context3.state.pendingSecretsInfoRefresh;
241216
241232
  const namesChanged = context3.state.lastSentSecretNamesKey !== null && context3.state.lastSentSecretNamesKey !== namesKey;
@@ -242574,18 +242590,24 @@ function createExternalCodingAgentConfig(type3) {
242574
242590
  function isExternalCodingAgentType(value) {
242575
242591
  return EXTERNAL_CODING_AGENT_TYPES.includes(value);
242576
242592
  }
242577
- function formatExternalCodingAgentId(type3, sessionId) {
242578
- return `${EXTERNAL_AGENT_ID_PREFIXES[type3]}${sessionId}`;
242593
+ function formatExternalCodingAgentId(type3, sessionId, computer) {
242594
+ const id2 = `${EXTERNAL_AGENT_ID_PREFIXES[type3]}${sessionId}`;
242595
+ return computer ? `${id2}@${computer}` : id2;
242579
242596
  }
242580
242597
  function parseExternalCodingAgentId(agentId) {
242581
242598
  if (!agentId)
242582
242599
  return null;
242600
+ const separator = agentId.lastIndexOf("@");
242601
+ const nativeId = separator === -1 ? agentId : agentId.slice(0, separator);
242602
+ const computer = separator === -1 ? undefined : agentId.slice(separator + 1);
242603
+ if (computer !== undefined && !computer.trim())
242604
+ return null;
242583
242605
  for (const type3 of EXTERNAL_CODING_AGENT_TYPES) {
242584
242606
  const prefix = EXTERNAL_AGENT_ID_PREFIXES[type3];
242585
- if (agentId.startsWith(prefix)) {
242586
- const sessionId = agentId.slice(prefix.length);
242607
+ if (nativeId.startsWith(prefix)) {
242608
+ const sessionId = nativeId.slice(prefix.length);
242587
242609
  if ((type3 === "opencode" ? /^ses_[a-zA-Z0-9]+$/ : NATIVE_SESSION_ID_PATTERN).test(sessionId)) {
242588
- return { type: type3, sessionId };
242610
+ return { type: type3, sessionId, ...computer ? { computer } : {} };
242589
242611
  }
242590
242612
  }
242591
242613
  }
@@ -242768,10 +242790,27 @@ function parseExternalCodingAgentOutput(type3, stdout) {
242768
242790
  ...sessionId ? { sessionId } : {}
242769
242791
  };
242770
242792
  }
242793
+ async function resolveExternalCodingAgentSecretEnv(parentAgentId, lookupParent) {
242794
+ const { ensureSecretsLoaded: ensureSecretsLoaded2, loadSecrets: loadSecrets2 } = await Promise.resolve().then(() => (init_secrets_store(), exports_secrets_store));
242795
+ let inherited = {};
242796
+ try {
242797
+ const scopeAgentId = await getMcpScopeAgentId(parentAgentId, undefined, lookupParent);
242798
+ if (scopeAgentId !== parentAgentId) {
242799
+ await ensureSecretsLoaded2(scopeAgentId);
242800
+ inherited = loadSecrets2(scopeAgentId);
242801
+ }
242802
+ } catch {}
242803
+ try {
242804
+ await ensureSecretsLoaded2(parentAgentId);
242805
+ } catch {}
242806
+ return { ...inherited, ...loadSecrets2(parentAgentId) };
242807
+ }
242771
242808
  async function runExternalCodingAgent(options, deps = {}) {
242772
242809
  const startedAt = Date.now();
242810
+ const secretEnv = await (deps.resolveSecretEnv ?? resolveExternalCodingAgentSecretEnv)(options.parentAgentId);
242773
242811
  const env6 = {
242774
242812
  ...deps.env ?? process.env,
242813
+ ...secretEnv,
242775
242814
  AGENT_ID: options.parentAgentId,
242776
242815
  LETTA_AGENT_ID: options.parentAgentId,
242777
242816
  LETTA_PARENT_AGENT_ID: options.parentAgentId,
@@ -242798,7 +242837,14 @@ async function runExternalCodingAgent(options, deps = {}) {
242798
242837
  captureReservation ??= reserveNativeSessionCapture(source, sessionId, scope, env6);
242799
242838
  return captureReservation;
242800
242839
  };
242801
- const capture = async (result3) => {
242840
+ const capture = async (rawResult) => {
242841
+ const result3 = {
242842
+ ...rawResult,
242843
+ report: scrubSecretsFromString(rawResult.report, secretEnv),
242844
+ ...rawResult.error !== undefined && {
242845
+ error: scrubSecretsFromString(rawResult.error, secretEnv)
242846
+ }
242847
+ };
242802
242848
  const sessionId = result3.runtimeSessionId ?? captureSessionId;
242803
242849
  if (scope && sessionId) {
242804
242850
  try {
@@ -242931,6 +242977,7 @@ var init_external_coding_agent = __esm(() => {
242931
242977
  init_mcp_scope();
242932
242978
  init_engine3();
242933
242979
  init_runtime_context();
242980
+ init_secret_substitution();
242934
242981
  init_claude_stream_session();
242935
242982
  init_codex_app_server();
242936
242983
  init_native_session_capture();
@@ -243628,7 +243675,7 @@ function isAppServerInfoResponseMessage(message2) {
243628
243675
  return false;
243629
243676
  }
243630
243677
  const capabilityRecord = capabilities;
243631
- return candidate.type === "app_server_info_response" && typeof candidate.request_id === "string" && candidate.request_id.length > 0 && candidate.success === true && (candidate.backend === "local" || candidate.backend === "api") && typeof candidate.letta_code_version === "string" && typeof candidate.protocol_version === "number" && Number.isInteger(candidate.protocol_version) && typeof capabilityRecord.agent_management === "boolean" && typeof capabilityRecord.conversation_management === "boolean" && typeof capabilityRecord.memory_management === "boolean" && typeof capabilityRecord.runtime_start === "boolean" && (capabilityRecord.agent_free_conversations === undefined || typeof capabilityRecord.agent_free_conversations === "boolean") && (capabilityRecord.launch_subagent === undefined || typeof capabilityRecord.launch_subagent === "boolean") && (capabilityRecord.launch_subagent_notify_caller === undefined || typeof capabilityRecord.launch_subagent_notify_caller === "boolean") && (capabilityRecord.runtime_workspace_sandbox === undefined || typeof capabilityRecord.runtime_workspace_sandbox === "boolean") && (capabilityRecord.runtime_external_tools_update === undefined || typeof capabilityRecord.runtime_external_tools_update === "boolean") && (capabilityRecord.structured_outputs === undefined || typeof capabilityRecord.structured_outputs === "boolean") && (capabilityRecord.write_file_base64 === undefined || typeof capabilityRecord.write_file_base64 === "boolean") && typeof capabilityRecord.split_channels === "boolean";
243678
+ return candidate.type === "app_server_info_response" && typeof candidate.request_id === "string" && candidate.request_id.length > 0 && candidate.success === true && (candidate.backend === "local" || candidate.backend === "api") && typeof candidate.letta_code_version === "string" && typeof candidate.protocol_version === "number" && Number.isInteger(candidate.protocol_version) && typeof capabilityRecord.agent_management === "boolean" && typeof capabilityRecord.conversation_management === "boolean" && typeof capabilityRecord.memory_management === "boolean" && typeof capabilityRecord.runtime_start === "boolean" && (capabilityRecord.agent_free_conversations === undefined || typeof capabilityRecord.agent_free_conversations === "boolean") && (capabilityRecord.launch_subagent === undefined || typeof capabilityRecord.launch_subagent === "boolean") && (capabilityRecord.launch_subagent_notify_caller === undefined || typeof capabilityRecord.launch_subagent_notify_caller === "boolean") && (capabilityRecord.subagent_message === undefined || typeof capabilityRecord.subagent_message === "boolean") && (capabilityRecord.runtime_workspace_sandbox === undefined || typeof capabilityRecord.runtime_workspace_sandbox === "boolean") && (capabilityRecord.runtime_external_tools_update === undefined || typeof capabilityRecord.runtime_external_tools_update === "boolean") && (capabilityRecord.structured_outputs === undefined || typeof capabilityRecord.structured_outputs === "boolean") && (capabilityRecord.write_file_base64 === undefined || typeof capabilityRecord.write_file_base64 === "boolean") && typeof capabilityRecord.split_channels === "boolean";
243632
243679
  }
243633
243680
  var APP_SERVER_PROTOCOL_VERSION = 1;
243634
243681
 
@@ -243882,6 +243929,26 @@ class AppServerClient {
243882
243929
  predicate: (message2) => message2.type === "launch_subagent_response"
243883
243930
  });
243884
243931
  }
243932
+ sendSubagentMessage(command, options = {}) {
243933
+ return this.request({
243934
+ ...command,
243935
+ type: "subagent_message",
243936
+ request_id: command.request_id ?? this.nextRequestId("subagent-message")
243937
+ }, {
243938
+ ...options,
243939
+ predicate: (message2) => message2.type === "subagent_message_response"
243940
+ });
243941
+ }
243942
+ stopSubagent(command, options = {}) {
243943
+ return this.request({
243944
+ ...command,
243945
+ type: "subagent_stop",
243946
+ request_id: command.request_id ?? this.nextRequestId("subagent-stop")
243947
+ }, {
243948
+ ...options,
243949
+ predicate: (message2) => message2.type === "subagent_stop_response" && message2.agent_id === command.agent_id
243950
+ });
243951
+ }
243885
243952
  runtimeStart(command, options = {}) {
243886
243953
  return this.request({
243887
243954
  type: "runtime_start",
@@ -246262,6 +246329,9 @@ function formatRemoteStartupError(type3, computer, code2) {
246262
246329
  function formatOutdatedComputerError(type3, computer) {
246263
246330
  return `${computer} is running an older Letta Code that can't run ${DISPLAY_NAMES[type3]} subagents remotely. Update Letta Code on ${computer}.`;
246264
246331
  }
246332
+ function formatOutdatedSteeringError(computer) {
246333
+ return `${computer} is running an older Letta Code that can't steer Claude Code subagents remotely. Update Letta Code on ${computer}.`;
246334
+ }
246265
246335
  async function defaultResolveComputer(computer, scope) {
246266
246336
  if (!isCloudEnvironmentSelector(computer))
246267
246337
  return resolveEnvironmentConnectionId(computer);
@@ -246290,6 +246360,18 @@ async function defaultConnect(connectionId, scope) {
246290
246360
  throw error5;
246291
246361
  }
246292
246362
  }
246363
+ async function resolveQualifiedComputer(deviceId) {
246364
+ try {
246365
+ const environment2 = await getEnvironmentConnection(deviceId);
246366
+ if (!isEnvironmentOnline(environment2) || !environment2.connectionId)
246367
+ throw new Error(`Computer "${deviceId}" is offline`);
246368
+ return { connectionId: environment2.connectionId, environment: environment2 };
246369
+ } catch (error5) {
246370
+ if (errorMessage3(error5).includes("offline"))
246371
+ throw error5;
246372
+ return resolveEnvironmentConnectionId(deviceId);
246373
+ }
246374
+ }
246293
246375
  function errorMessage3(error5) {
246294
246376
  return error5 instanceof Error ? error5.message : String(error5);
246295
246377
  }
@@ -246342,6 +246424,22 @@ class RemoteSubagentFollower {
246342
246424
  markLaunched() {
246343
246425
  this.launched = true;
246344
246426
  }
246427
+ async waitForAgentId(timeoutMs) {
246428
+ const deadline = Date.now() + timeoutMs;
246429
+ while (Date.now() < deadline) {
246430
+ if (this.latest?.agent_id)
246431
+ return this.latest.agent_id;
246432
+ const remaining = deadline - Date.now();
246433
+ if (remaining <= 0 || this.closed || this.lost)
246434
+ break;
246435
+ await Promise.race([
246436
+ this.wake.promise,
246437
+ new Promise((resolve37) => setTimeout(resolve37, remaining))
246438
+ ]);
246439
+ this.wake = Promise.withResolvers();
246440
+ }
246441
+ return this.latest?.agent_id ?? null;
246442
+ }
246345
246443
  close() {
246346
246444
  this.closed = true;
246347
246445
  this.detach?.();
@@ -246395,6 +246493,8 @@ class RemoteSubagentFollower {
246395
246493
  async function launchRemoteExternalCodingAgent(params, deps) {
246396
246494
  const { type: type3, computer, parentScope } = params;
246397
246495
  let connectionId;
246496
+ let deviceId;
246497
+ let supportsSteering;
246398
246498
  try {
246399
246499
  const resolved2 = await (deps.resolveComputer ?? defaultResolveComputer)(computer, parentScope);
246400
246500
  if (resolved2.environment.metadata?.launch_subagent_notify_caller !== true)
@@ -246403,6 +246503,8 @@ async function launchRemoteExternalCodingAgent(params, deps) {
246403
246503
  error: formatOutdatedComputerError(type3, computer)
246404
246504
  };
246405
246505
  connectionId = resolved2.connectionId;
246506
+ deviceId = resolved2.environment.deviceId;
246507
+ supportsSteering = resolved2.environment.metadata?.subagent_message === true;
246406
246508
  } catch (error5) {
246407
246509
  return { success: false, error: errorMessage3(error5) };
246408
246510
  }
@@ -246454,7 +246556,10 @@ async function launchRemoteExternalCodingAgent(params, deps) {
246454
246556
  };
246455
246557
  }
246456
246558
  follower.markLaunched();
246457
- const { taskId, outputFile } = deps.spawn({
246559
+ const nativeAgentId = supportsSteering ? await follower.waitForAgentId(deps.agentIdWaitMs ?? 2000) : null;
246560
+ const parsedNativeAgentId = nativeAgentId ? parseExternalCodingAgentId(nativeAgentId) : null;
246561
+ const qualifiedAgentId = parsedNativeAgentId && !parsedNativeAgentId.computer ? formatExternalCodingAgentId(parsedNativeAgentId.type, parsedNativeAgentId.sessionId, deviceId) : null;
246562
+ const { taskId, outputFile, subagentId } = deps.spawn({
246458
246563
  subagentType: type3,
246459
246564
  config: createExternalCodingAgentConfig(type3),
246460
246565
  prompt: params.prompt,
@@ -246463,16 +246568,16 @@ async function launchRemoteExternalCodingAgent(params, deps) {
246463
246568
  toolCallId: params.toolCallId,
246464
246569
  parentScope,
246465
246570
  deps: {
246466
- spawnSubagentImpl: async (_type, _prompt, model, subagentId, signal) => {
246571
+ spawnSubagentImpl: async (_type, _prompt, model, subagentId2, signal) => {
246467
246572
  const startedAt = Date.now();
246468
- updateSubagent(subagentId, { status: "running" });
246573
+ updateSubagent(subagentId2, { status: "running" });
246469
246574
  try {
246470
- const final = await follower.waitForTerminal(signal, (snapshot2) => updateSubagent(subagentId, {
246575
+ const final = await follower.waitForTerminal(signal, (snapshot2) => updateSubagent(subagentId2, {
246471
246576
  toolCalls: snapshot2.tool_calls,
246472
246577
  totalTokens: snapshot2.total_tokens
246473
246578
  }));
246474
246579
  return {
246475
- agentId: parentScope.agentId,
246580
+ agentId: qualifiedAgentId ?? parentScope.agentId,
246476
246581
  model: final.model ?? model,
246477
246582
  report: final.result ?? "",
246478
246583
  success: final.status === "completed",
@@ -246495,14 +246600,142 @@ async function launchRemoteExternalCodingAgent(params, deps) {
246495
246600
  }
246496
246601
  }
246497
246602
  });
246603
+ if (qualifiedAgentId)
246604
+ updateSubagent(subagentId, { agentId: qualifiedAgentId });
246498
246605
  return {
246499
246606
  success: true,
246500
246607
  task_id: taskId,
246501
246608
  output_file: outputFile,
246502
- agent_id: null,
246609
+ agent_id: qualifiedAgentId,
246503
246610
  conversation_id: null
246504
246611
  };
246505
246612
  }
246613
+ async function connectQualifiedTarget(agentId, parentScope, deps) {
246614
+ const target2 = parseExternalCodingAgentId(agentId);
246615
+ if (!target2?.computer || target2.type === "opencode")
246616
+ throw new Error(`Invalid remote external coding agent ID: ${agentId}`);
246617
+ const resolved2 = await (deps.resolveComputer ?? resolveQualifiedComputer)(target2.computer);
246618
+ if (resolved2.environment.metadata?.subagent_message !== true)
246619
+ throw new Error(formatOutdatedSteeringError(target2.computer));
246620
+ return {
246621
+ target: target2,
246622
+ client: await (deps.connect ?? defaultConnect)(resolved2.connectionId, parentScope)
246623
+ };
246624
+ }
246625
+ async function stopRemoteExternalCodingAgent(params, deps = {}) {
246626
+ const requestId = `subagent-stop-${randomUUID41()}`;
246627
+ const { target: target2, client } = await connectQualifiedTarget(params.agentId, params.parentScope, deps);
246628
+ try {
246629
+ const response = await client.stopSubagent({
246630
+ request_id: requestId,
246631
+ runtime: {
246632
+ agent_id: params.parentScope.agentId,
246633
+ conversation_id: params.parentScope.conversationId,
246634
+ ...params.parentScope.actingUserId ? { acting_user_id: params.parentScope.actingUserId } : {}
246635
+ },
246636
+ agent_id: formatExternalCodingAgentId(target2.type, target2.sessionId)
246637
+ });
246638
+ if (!response.success)
246639
+ throw new Error(response.error ?? "Stop failed");
246640
+ return { stopped: response.stopped };
246641
+ } finally {
246642
+ client.close();
246643
+ }
246644
+ }
246645
+ async function sendRemoteExternalCodingAgentMessage(params, deps = {}) {
246646
+ const requestId = `subagent-message-${randomUUID41()}`;
246647
+ const { target: target2, client } = await connectQualifiedTarget(params.agentId, params.parentScope, deps);
246648
+ const toolCallId = params.toolCallId ?? `remote-followup-${randomUUID41()}`;
246649
+ const connect = async () => {
246650
+ const resolved2 = await (deps.resolveComputer ?? resolveQualifiedComputer)(target2.computer);
246651
+ return (deps.connect ?? defaultConnect)(resolved2.connectionId, params.parentScope);
246652
+ };
246653
+ const follower = new RemoteSubagentFollower(params.parentScope, toolCallId, connect, 2000);
246654
+ follower.attach(client);
246655
+ const bareAgentId = formatExternalCodingAgentId(target2.type, target2.sessionId);
246656
+ let response;
246657
+ try {
246658
+ response = await client.sendSubagentMessage({
246659
+ request_id: requestId,
246660
+ runtime: {
246661
+ agent_id: params.parentScope.agentId,
246662
+ conversation_id: params.parentScope.conversationId,
246663
+ ...params.parentScope.actingUserId ? { acting_user_id: params.parentScope.actingUserId } : {}
246664
+ },
246665
+ agent_id: bareAgentId,
246666
+ message: params.message,
246667
+ tool_call_id: toolCallId
246668
+ });
246669
+ } catch (error5) {
246670
+ follower.close();
246671
+ throw error5;
246672
+ }
246673
+ if (!response.success) {
246674
+ follower.close();
246675
+ throw new Error(response.error);
246676
+ }
246677
+ if (response.delivery === "steered") {
246678
+ follower.close();
246679
+ return { delivery: "steered" };
246680
+ }
246681
+ follower.markLaunched();
246682
+ const completion = follower.waitForTerminal(undefined, () => {
246683
+ return;
246684
+ }).then((final) => ({
246685
+ agentId: bareAgentId,
246686
+ model: final.model,
246687
+ report: final.result ?? "",
246688
+ success: final.status === "completed",
246689
+ ...final.status === "error" ? { error: final.error ?? "Remote follow-up failed" } : {},
246690
+ totalTokens: final.total_tokens,
246691
+ durationMs: final.duration_ms
246692
+ })).finally(() => follower.close());
246693
+ const interrupt = async () => {
246694
+ const resolved2 = await (deps.resolveComputer ?? resolveQualifiedComputer)(target2.computer);
246695
+ const stopClient = await (deps.connect ?? defaultConnect)(resolved2.connectionId, params.parentScope);
246696
+ try {
246697
+ await stopClient.stopSubagent({
246698
+ runtime: {
246699
+ agent_id: params.parentScope.agentId,
246700
+ conversation_id: params.parentScope.conversationId
246701
+ },
246702
+ agent_id: bareAgentId
246703
+ });
246704
+ } finally {
246705
+ stopClient.close();
246706
+ }
246707
+ };
246708
+ const track = deps.track;
246709
+ if (!track) {
246710
+ follower.close();
246711
+ throw new Error("Remote follow-up tracking is unavailable");
246712
+ }
246713
+ let tracked;
246714
+ try {
246715
+ tracked = track({
246716
+ type: target2.type,
246717
+ agentId: params.agentId,
246718
+ message: params.message,
246719
+ parentScope: params.parentScope,
246720
+ completion,
246721
+ interrupt
246722
+ });
246723
+ } catch (error5) {
246724
+ try {
246725
+ await interrupt();
246726
+ } catch {}
246727
+ follower.close();
246728
+ completion.catch(() => {
246729
+ return;
246730
+ });
246731
+ throw error5;
246732
+ }
246733
+ return {
246734
+ delivery: "resumed",
246735
+ taskId: tracked.taskId,
246736
+ outputFile: tracked.outputFile
246737
+ };
246738
+ }
246506
246739
  var DISPLAY_NAMES, RemoteWorkerLostError;
246507
246740
  var init_remote_external_coding_agent = __esm(() => {
246508
246741
  init_subagent_state();
@@ -247160,6 +247393,8 @@ function trackExternalFollowupCompletion(args) {
247160
247393
  prompt: args.message,
247161
247394
  description: `Continue ${args.type} session`,
247162
247395
  existingAgentId: args.agentId,
247396
+ toolCallId: args.toolCallId,
247397
+ publishResult: args.publishResult,
247163
247398
  parentScope: args.parentScope,
247164
247399
  actingUserId: args.parentScope.actingUserId,
247165
247400
  deps: {
@@ -247273,6 +247508,28 @@ async function send_agent_message(args, deps = {}) {
247273
247508
  }
247274
247509
  args.signal?.throwIfAborted();
247275
247510
  const parentScope = sender;
247511
+ if (externalTarget.computer) {
247512
+ const receipt3 = await (deps.sendRemoteExternalMessage ?? sendRemoteExternalCodingAgentMessage)({
247513
+ agentId: args.agent_id,
247514
+ message: args.message,
247515
+ parentScope: {
247516
+ ...parentScope,
247517
+ actingUserId: getRuntimeActingUserAttribution()
247518
+ }
247519
+ }, {
247520
+ track: deps.trackExternalFollowup ?? trackExternalFollowupCompletion
247521
+ });
247522
+ return {
247523
+ content: JSON.stringify({
247524
+ status: "accepted",
247525
+ agent_id: args.agent_id,
247526
+ delivery: receipt3.delivery === "steered" ? "remote/steer" : "remote/resume",
247527
+ ...receipt3.taskId ? { task_id: receipt3.taskId } : {},
247528
+ ...receipt3.outputFile ? { output_file: receipt3.outputFile } : {}
247529
+ }),
247530
+ status: "success"
247531
+ };
247532
+ }
247276
247533
  if (externalTarget.type === "opencode") {
247277
247534
  const receipt3 = await sendOpenCodeMessage({
247278
247535
  sessionId: externalTarget.sessionId,
@@ -247546,6 +247803,7 @@ var init_send_agent_message = __esm(async () => {
247546
247803
  init_external_coding_agent();
247547
247804
  init_native_session_capture();
247548
247805
  init_opencode_session();
247806
+ init_remote_external_coding_agent();
247549
247807
  await init_external_coding_agent_task();
247550
247808
  FULL_CONVERSATION_ID = /^conv-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
247551
247809
  });
@@ -248068,13 +248326,40 @@ async function cancelRemoteRun(subagentId) {
248068
248326
  };
248069
248327
  }
248070
248328
  }
248071
- async function task_stop(args) {
248329
+ async function task_stop(args, deps = {}) {
248072
248330
  validateRequiredParams(args, ["task_id"], "TaskStop");
248073
248331
  const { task_id } = args;
248074
248332
  const task2 = backgroundTasks.get(task_id);
248075
248333
  if (task2) {
248076
248334
  if (task2.status === "running" && task2.abortController) {
248077
- const remote = task2.remote ? await cancelRemoteRun(task2.subagentId) : undefined;
248335
+ const child = getSubagents().find((agent) => agent.id === task2.subagentId);
248336
+ const external3 = parseExternalCodingAgentId(child?.agentId ?? undefined);
248337
+ let remote;
248338
+ if (external3?.computer) {
248339
+ try {
248340
+ if (!task2.runtimeScope)
248341
+ throw new Error("its parent conversation is not known");
248342
+ const result3 = await (deps.stopRemoteExternal ?? stopRemoteExternalCodingAgent)({
248343
+ agentId: child?.agentId,
248344
+ parentScope: {
248345
+ agentId: task2.runtimeScope.agentId,
248346
+ conversationId: task2.runtimeScope.conversationId,
248347
+ actingUserId: task2.actingUserId
248348
+ }
248349
+ });
248350
+ remote = {
248351
+ killed: result3.stopped,
248352
+ output: result3.stopped ? "Stopped the remote external subagent" : "The remote external subagent was not running"
248353
+ };
248354
+ } catch (error5) {
248355
+ remote = {
248356
+ killed: false,
248357
+ output: `Couldn't stop the remote external subagent: ${getErrorMessage2(error5)}`
248358
+ };
248359
+ }
248360
+ } else if (task2.remote) {
248361
+ remote = await cancelRemoteRun(task2.subagentId);
248362
+ }
248078
248363
  if (remote && !remote.killed)
248079
248364
  return remote;
248080
248365
  task2.abortController.abort();
@@ -248091,7 +248376,9 @@ async function task_stop(args) {
248091
248376
  var init_task_stop = __esm(async () => {
248092
248377
  init_subagent_state();
248093
248378
  init_backend2();
248379
+ init_external_coding_agent();
248094
248380
  init_process_manager();
248381
+ init_remote_external_coding_agent();
248095
248382
  await init_kill_bash();
248096
248383
  });
248097
248384
 
@@ -258274,11 +258561,13 @@ function buildQueuedTurnMessage(runtime, batch) {
258274
258561
  return null;
258275
258562
  const scopeItem = batch.items[0];
258276
258563
  const batchActingUserId = batch.items.some((item) => item.kind === "message") ? getBatchActingUserId(batch.items) : template3?.actingUserId ?? getBatchActingUserId(batch.items);
258564
+ const processOwnedTurn = !batch.items.some((item) => item.kind === "message");
258277
258565
  return {
258278
258566
  type: "message",
258279
258567
  agentId: scopeItem?.agentId ?? runtime.agentId ?? undefined,
258280
258568
  conversationId: scopeItem?.conversationId ?? runtime.conversationId,
258281
258569
  ...template3,
258570
+ ...processOwnedTurn ? { processOwnedTurn: true } : {},
258282
258571
  actingUserId: batchActingUserId ?? undefined,
258283
258572
  suppressActingUserFallback: batchActingUserId === null || batchActingUserId === undefined && template3?.suppressActingUserFallback === true,
258284
258573
  ...durableInputIdentities.length > 0 ? { durableInputIdentities: [...new Set(durableInputIdentities)] } : {},
@@ -262377,17 +262666,11 @@ function ListenerStatusUI(props) {
262377
262666
  }, undefined, false, undefined, this)
262378
262667
  ]
262379
262668
  }, undefined, true, undefined, this),
262380
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
262381
- children: isFirstRun ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
262669
+ isFirstRun && /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
262670
+ children: /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
262382
262671
  dimColor: true,
262383
262672
  children: "Connected. Head back to Letta in your browser — it will detect this computer automatically. Keep this window open."
262384
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
262385
- dimColor: true,
262386
- children: [
262387
- 'Connect to this computer by visiting any agent and clicking the "cloud" button at the bottom left of the messenger input and swapping your computer to ',
262388
- envName
262389
- ]
262390
- }, undefined, true, undefined, this)
262673
+ }, undefined, false, undefined, this)
262391
262674
  }, undefined, false, undefined, this)
262392
262675
  ]
262393
262676
  }, undefined, true, undefined, this);
@@ -263018,6 +263301,7 @@ async function registerWithCloud(opts, fetchImpl = fetch) {
263018
263301
  supportsPairedListenerGenerations: true,
263019
263302
  supported_commands: SUPPORTED_REMOTE_COMMANDS,
263020
263303
  launch_subagent_notify_caller: true,
263304
+ subagent_message: true,
263021
263305
  self_update: getSelfUpdateStatus()
263022
263306
  }
263023
263307
  })
@@ -264207,6 +264491,20 @@ function isLaunchSubagentCommand(value) {
264207
264491
  return false;
264208
264492
  return args.max_turns === undefined || typeof args.max_turns === "number" && Number.isSafeInteger(args.max_turns) && args.max_turns > 0;
264209
264493
  }
264494
+ function hasValidControlBase(value) {
264495
+ if (!value || typeof value !== "object")
264496
+ return false;
264497
+ const c = value;
264498
+ return typeof c.request_id === "string" && c.request_id.trim().length > 0 && isAgentRuntimeScope(c.runtime) && c.runtime.agent_id.trim().length > 0 && c.runtime.conversation_id.trim().length > 0 && typeof c.agent_id === "string" && c.agent_id.trim().length > 0;
264499
+ }
264500
+ function isSubagentMessageCommand(value) {
264501
+ if (!hasValidControlBase(value) || value.type !== "subagent_message")
264502
+ return false;
264503
+ return typeof value.message === "string" && value.message.trim().length > 0 && (value.tool_call_id === undefined || typeof value.tool_call_id === "string" && value.tool_call_id.trim().length > 0);
264504
+ }
264505
+ function isSubagentStopCommand(value) {
264506
+ return hasValidControlBase(value) && value.type === "subagent_stop";
264507
+ }
264210
264508
  var ARGUMENTS;
264211
264509
  var init_subagent_protocol_inbound = __esm(() => {
264212
264510
  ARGUMENTS = new Set([
@@ -264250,7 +264548,7 @@ var init_browser_device_mcp_oauth_protocol_inbound = __esm(() => {
264250
264548
 
264251
264549
  // src/websocket/listener/task-control-protocol-inbound.ts
264252
264550
  function isTaskControlProtocolCommand(value) {
264253
- return isBrowserDeviceMcpOAuthProtocolCommand(value) || isExecuteCommandCommand(value) || isRemoveQueueItemCommand(value) || isMonitorStopCommand(value);
264551
+ return isBrowserDeviceMcpOAuthProtocolCommand(value) || isExecuteCommandCommand(value) || isRemoveQueueItemCommand(value) || isMonitorStopCommand(value) || isSubagentMessageCommand(value) || isSubagentStopCommand(value);
264254
264552
  }
264255
264553
  function isExecuteCommandCommand(value) {
264256
264554
  if (!value || typeof value !== "object")
@@ -264272,6 +264570,7 @@ function isMonitorStopCommand(value) {
264272
264570
  }
264273
264571
  var init_task_control_protocol_inbound = __esm(() => {
264274
264572
  init_browser_device_mcp_oauth_protocol_inbound();
264573
+ init_subagent_protocol_inbound();
264275
264574
  });
264276
264575
 
264277
264576
  // src/websocket/listener/protocol-inbound.ts
@@ -459752,6 +460051,7 @@ function buildAppServerInfoResponse(command, options) {
459752
460051
  agent_free_conversations: true,
459753
460052
  launch_subagent: true,
459754
460053
  launch_subagent_notify_caller: true,
460054
+ subagent_message: true,
459755
460055
  runtime_workspace_sandbox: true,
459756
460056
  runtime_external_tools_update: true,
459757
460057
  structured_outputs: options.backend === "api",
@@ -461248,6 +461548,174 @@ var init_monitors = __esm(async () => {
461248
461548
  ]);
461249
461549
  });
461250
461550
 
461551
+ // src/websocket/listener/commands/subagent-control.ts
461552
+ function dedupeKey(command) {
461553
+ return JSON.stringify([
461554
+ command.runtime.agent_id,
461555
+ command.runtime.conversation_id,
461556
+ command.agent_id,
461557
+ command.request_id
461558
+ ]);
461559
+ }
461560
+ function finishUntrackedNativeCapture2(completion, reservation, source, sessionId) {
461561
+ if (!reservation)
461562
+ return;
461563
+ completion.then(() => reservation.capture(), () => reservation.capture()).catch((error5) => reportNativeSessionCaptureFailure(source, sessionId, error5));
461564
+ }
461565
+ function findOwnedTask(runtime, agentId) {
461566
+ const subagent = getSubagents().find((entry) => entry.agentId === agentId && entry.parentAgentId === runtime.agentId && entry.parentConversationId === runtime.conversationId);
461567
+ if (!subagent)
461568
+ return;
461569
+ return [...backgroundTasks.entries()].find(([, task2]) => task2.subagentId === subagent.id);
461570
+ }
461571
+ function runtimeContext(parent, command) {
461572
+ return {
461573
+ agentId: parent.agentId,
461574
+ conversationId: parent.conversationId,
461575
+ actingUserId: command.runtime.acting_user_id,
461576
+ workingDirectory: getConversationWorkingDirectory(parent.listener, parent.agentId, parent.conversationId),
461577
+ skillSources: parent.skillSources,
461578
+ workspaceSandbox: parent.workspaceSandbox,
461579
+ executionSettings: parent.executionSettings
461580
+ };
461581
+ }
461582
+ async function handleSubagentMessageCommand(command, parent, deps = {}) {
461583
+ const now2 = (deps.now ?? Date.now)();
461584
+ const key3 = dedupeKey(command);
461585
+ for (const [id2, cached4] of responses) {
461586
+ if (cached4.expiresAt <= now2)
461587
+ responses.delete(id2);
461588
+ }
461589
+ const cached3 = responses.get(key3);
461590
+ if (cached3)
461591
+ return cached3.response;
461592
+ const response = (async () => {
461593
+ const base2 = {
461594
+ type: "subagent_message_response",
461595
+ request_id: command.request_id,
461596
+ runtime: command.runtime
461597
+ };
461598
+ try {
461599
+ if (parent.agentId !== command.runtime.agent_id || parent.conversationId !== command.runtime.conversation_id)
461600
+ throw new Error("Parent runtime does not match the message request");
461601
+ if (!findOwnedTask(parent, command.agent_id))
461602
+ throw new Error("Subagent does not belong to this conversation");
461603
+ const target2 = parseExternalCodingAgentId(command.agent_id);
461604
+ if (!target2 || target2.computer || !isExternalCodingAgentType(target2.type))
461605
+ throw new Error("Invalid external coding agent ID");
461606
+ if (!target2.sessionId)
461607
+ throw new Error("External coding agent ID has no session ID");
461608
+ const sessionId = target2.sessionId;
461609
+ if (target2.type === "opencode")
461610
+ throw new Error("Remote OpenCode steering is not supported");
461611
+ let captureReservation;
461612
+ const source = target2.type === "claude-code" ? "claude_code" : "codex";
461613
+ const receipt = await runOutsideRuntimeContext(() => runWithRuntimeContext(runtimeContext(parent, command), () => target2.type === "claude-code" ? (deps.sendClaude ?? sendClaudeMessage)({
461614
+ sessionId: target2.sessionId,
461615
+ prompt: command.message,
461616
+ parentAgentId: command.runtime.agent_id,
461617
+ cwd: getCurrentWorkingDirectory(),
461618
+ beforeStart: async () => {
461619
+ captureReservation = await (deps.reserveCapture ?? reserveNativeSessionCapture)(source, sessionId, {
461620
+ agentId: command.runtime.agent_id,
461621
+ conversationId: command.runtime.conversation_id,
461622
+ actingUserId: command.runtime.acting_user_id
461623
+ });
461624
+ }
461625
+ }) : (deps.sendCodex ?? sendCodexMessage)({
461626
+ threadId: target2.sessionId,
461627
+ prompt: command.message,
461628
+ parentAgentId: command.runtime.agent_id,
461629
+ cwd: getCurrentWorkingDirectory(),
461630
+ beforeStart: async () => {
461631
+ captureReservation = await (deps.reserveCapture ?? reserveNativeSessionCapture)(source, sessionId, {
461632
+ agentId: command.runtime.agent_id,
461633
+ conversationId: command.runtime.conversation_id,
461634
+ actingUserId: command.runtime.acting_user_id
461635
+ });
461636
+ }
461637
+ })));
461638
+ if (receipt.mode === "steered")
461639
+ return { ...base2, success: true, delivery: "steered" };
461640
+ if (!receipt.completion || !receipt.interrupt)
461641
+ throw new Error("External coding agent returned an incomplete receipt");
461642
+ try {
461643
+ (deps.track ?? trackExternalFollowupCompletion)({
461644
+ type: target2.type,
461645
+ agentId: command.agent_id,
461646
+ message: command.message,
461647
+ parentScope: {
461648
+ agentId: parent.agentId,
461649
+ conversationId: parent.conversationId,
461650
+ actingUserId: command.runtime.acting_user_id
461651
+ },
461652
+ completion: receipt.completion,
461653
+ interrupt: receipt.interrupt,
461654
+ captureReservation,
461655
+ toolCallId: command.tool_call_id,
461656
+ publishResult: true
461657
+ });
461658
+ } catch (error5) {
461659
+ await receipt.interrupt().catch(() => {
461660
+ return;
461661
+ });
461662
+ finishUntrackedNativeCapture2(receipt.completion, captureReservation, source, sessionId);
461663
+ throw error5;
461664
+ }
461665
+ return { ...base2, success: true, delivery: "resumed" };
461666
+ } catch (error5) {
461667
+ return {
461668
+ ...base2,
461669
+ success: false,
461670
+ error: error5 instanceof Error ? error5.message : String(error5)
461671
+ };
461672
+ }
461673
+ })();
461674
+ responses.set(key3, {
461675
+ expiresAt: now2 + DEDUPE_TTL_MS,
461676
+ response
461677
+ });
461678
+ const result3 = await response;
461679
+ if (!result3.success && responses.get(key3)?.response === response)
461680
+ responses.delete(key3);
461681
+ return result3;
461682
+ }
461683
+ async function handleSubagentStopCommand(command, parent) {
461684
+ const base2 = {
461685
+ type: "subagent_stop_response",
461686
+ request_id: command.request_id,
461687
+ runtime: command.runtime,
461688
+ agent_id: command.agent_id,
461689
+ success: false,
461690
+ stopped: false
461691
+ };
461692
+ if (parent.agentId !== command.runtime.agent_id || parent.conversationId !== command.runtime.conversation_id)
461693
+ return { ...base2, error: "Parent runtime does not match the stop request" };
461694
+ const owned = findOwnedTask(parent, command.agent_id);
461695
+ if (!owned)
461696
+ return { ...base2, error: "Subagent does not belong to this conversation" };
461697
+ const [, task2] = owned;
461698
+ if (task2.status !== "running")
461699
+ return { ...base2, success: true };
461700
+ if (!task2.abortController)
461701
+ return { ...base2, error: "Subagent could not be stopped" };
461702
+ task2.abortController.abort(new Error("Stopped by remote parent"));
461703
+ return { ...base2, success: true, stopped: true };
461704
+ }
461705
+ var DEDUPE_TTL_MS = 30000, responses;
461706
+ var init_subagent_control = __esm(async () => {
461707
+ init_subagent_state();
461708
+ init_runtime_context();
461709
+ init_claude_stream_session();
461710
+ init_codex_app_server();
461711
+ init_external_coding_agent();
461712
+ init_native_session_capture();
461713
+ init_process_manager();
461714
+ init_cwd();
461715
+ await init_external_coding_agent_task();
461716
+ responses = new Map;
461717
+ });
461718
+
461251
461719
  // src/websocket/listener/commands/subagents.ts
461252
461720
  async function handleLaunchSubagentCommand(command, parent, connectionId, launch = launchSubagent, startupTimeoutMs2 = 25000) {
461253
461721
  const response = {
@@ -461330,10 +461798,16 @@ async function handleTaskControlCommand(command, context3) {
461330
461798
  safeSocketSend
461331
461799
  } = context3;
461332
461800
  const execute = async () => {
461333
- const response = command.type === "monitor_stop" ? await handleMonitorStopCommand(command, runtime) : await handleLaunchSubagentCommand(command, getOrCreateScopedRuntime2(runtime, command.runtime.agent_id, command.runtime.conversation_id), connectionId);
461801
+ if (command.type === "monitor_stop") {
461802
+ const response2 = await handleMonitorStopCommand(command, runtime);
461803
+ safeSocketSend(socket, response2, response2.type, command.type);
461804
+ return;
461805
+ }
461806
+ const parent = getOrCreateScopedRuntime2(runtime, command.runtime.agent_id, command.runtime.conversation_id);
461807
+ const response = command.type === "launch_subagent" ? await handleLaunchSubagentCommand(command, parent, connectionId) : command.type === "subagent_message" ? await handleSubagentMessageCommand(command, parent) : await handleSubagentStopCommand(command, parent);
461334
461808
  safeSocketSend(socket, response, response.type, command.type);
461335
461809
  };
461336
- if (command.type === "launch_subagent") {
461810
+ if (command.type === "launch_subagent" || command.type === "subagent_message") {
461337
461811
  runDetachedListenerTask2(command.type, execute);
461338
461812
  } else {
461339
461813
  await execute();
@@ -461342,6 +461816,7 @@ async function handleTaskControlCommand(command, context3) {
461342
461816
  var init_task_control = __esm(async () => {
461343
461817
  await __promiseAll([
461344
461818
  init_monitors(),
461819
+ init_subagent_control(),
461345
461820
  init_subagents3()
461346
461821
  ]);
461347
461822
  });
@@ -461415,7 +461890,7 @@ function createListenerMessageHandler(params) {
461415
461890
  handleTurnFinishedAck(runtime, socket, connectionId, parsed);
461416
461891
  return;
461417
461892
  }
461418
- if (parsed.type === "launch_subagent" || parsed.type === "monitor_stop") {
461893
+ if (parsed.type === "launch_subagent" || parsed.type === "monitor_stop" || parsed.type === "subagent_message" || parsed.type === "subagent_stop") {
461419
461894
  const { handleTaskControlCommand: handleTaskControlCommand2 } = await init_task_control().then(() => exports_task_control);
461420
461895
  await handleTaskControlCommand2(parsed, {
461421
461896
  runtime,
@@ -462959,7 +463434,7 @@ async function recoverApprovalStateForSync(runtime, scope, deps = {}, opts = {})
462959
463434
  return {
462960
463435
  type: "deny",
462961
463436
  approval,
462962
- reason: STALE_APPROVAL_RECOVERY_DENIAL_REASON
463437
+ reason: STARTED_TOOL_CALL_RECOVERY_DENIAL_REASON
462963
463438
  };
462964
463439
  }
462965
463440
  if (!("tool_return" in saved)) {
@@ -479495,14 +479970,14 @@ async function executeChannelServiceCommand(command) {
479495
479970
  if (!isDetachedChannelsCommand(command)) {
479496
479971
  throw new Error(`Unsupported ChannelGateway command: ${command.type}`);
479497
479972
  }
479498
- const responses = [];
479973
+ const responses2 = [];
479499
479974
  const detachedTasks = [];
479500
479975
  const socket = {};
479501
479976
  const safeSocketSend2 = (_socket, payload) => {
479502
479977
  if (!payload || typeof payload !== "object" || !("type" in payload)) {
479503
479978
  throw new Error("ChannelGateway service emitted an invalid response");
479504
479979
  }
479505
- responses.push(payload);
479980
+ responses2.push(payload);
479506
479981
  return true;
479507
479982
  };
479508
479983
  const runDetachedListenerTask2 = (_commandName, task2) => {
@@ -479510,7 +479985,7 @@ async function executeChannelServiceCommand(command) {
479510
479985
  };
479511
479986
  await handleChannelsProtocolCommand(command, socket, runDetachedListenerTask2, safeSocketSend2);
479512
479987
  await Promise.all(detachedTasks);
479513
- return responses;
479988
+ return responses2;
479514
479989
  }
479515
479990
  async function executeGatewayServiceCommand(request3) {
479516
479991
  if (request3.kind === "protocol") {
@@ -522281,6 +522756,18 @@ var init_reasoning_tab_toggle = __esm(() => {
522281
522756
  DISABLE_ARGS = new Set(["off", "disable", "disabled", "false", "0"]);
522282
522757
  });
522283
522758
 
522759
+ // src/cli/helpers/rename-conversation-target.ts
522760
+ async function renameConvo(conversationId, summary) {
522761
+ if (conversationId === "default") {
522762
+ throw new Error(DEFAULT_CONVERSATION_RENAME_ERROR);
522763
+ }
522764
+ await getBackend().updateConversation(conversationId, { summary });
522765
+ }
522766
+ var DEFAULT_CONVERSATION_RENAME_ERROR = "The default conversation can't be renamed. Start a named one with /new <name>, or switch to another conversation first.";
522767
+ var init_rename_conversation_target = __esm(() => {
522768
+ init_backend2();
522769
+ });
522770
+
522284
522771
  // src/cli/app/command-routing.ts
522285
522772
  function aliasBareExitCommand(input) {
522286
522773
  if (input === "exit" || input === "quit")
@@ -525328,23 +525815,18 @@ Tip: Use /clear instead to clear the current message buffer.`;
525328
525815
  });
525329
525816
  setCommandRunning(true);
525330
525817
  try {
525331
- const backend3 = getBackend();
525332
525818
  if (shouldAutoGenerate) {
525333
525819
  const conversationTitle = await generateConversationTitle();
525334
525820
  if (!conversationTitle) {
525335
525821
  cmd.fail("No conversation content available to generate a title");
525336
525822
  return { submitted: true };
525337
525823
  }
525338
- await backend3.updateConversation(conversationId, {
525339
- summary: conversationTitle
525340
- });
525824
+ await renameConvo(conversationIdRef.current, conversationTitle);
525341
525825
  setConversationSummary(conversationTitle);
525342
525826
  setConversationAutoTitleEligibility(false);
525343
525827
  cmd.finish(`Conversation title set to "${conversationTitle}"`, true);
525344
525828
  } else {
525345
- await backend3.updateConversation(conversationId, {
525346
- summary: newValue
525347
- });
525829
+ await renameConvo(conversationIdRef.current, newValue);
525348
525830
  setConversationSummary(newValue);
525349
525831
  setConversationAutoTitleEligibility(false);
525350
525832
  cmd.finish(`Conversation renamed to "${newValue}"`, true);
@@ -526458,6 +526940,7 @@ var init_use_submit_handler = __esm(async () => {
526458
526940
  init_reflection_completion();
526459
526941
  init_reflection_launcher();
526460
526942
  init_reflection_transcript();
526943
+ init_rename_conversation_target();
526461
526944
  init_system_prompt_warning();
526462
526945
  init_thinking_messages();
526463
526946
  init_command_runtime();
@@ -533937,4 +534420,4 @@ function registerBunOAuthFlows() {
533937
534420
  registerBunOAuthFlows();
533938
534421
  await init_src5().then(() => exports_src2);
533939
534422
 
533940
- //# debugId=7FE5874CEEAF628D64756E2164756E21
534423
+ //# debugId=B487A0F42461099B64756E2164756E21