@letta-ai/letta-code 0.34.3 → 0.34.4

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 (43) hide show
  1. package/dist/gateway-core.js +166 -621
  2. package/dist/gateway-core.js.map +8 -13
  3. package/dist/mcp-client.js +2 -2
  4. package/dist/mcp-client.js.map +1 -1
  5. package/dist/mcp-oauth.js +2 -2
  6. package/dist/mcp-oauth.js.map +1 -1
  7. package/dist/types/agent/subagents/manager.d.ts.map +1 -1
  8. package/dist/types/agent/subagents/sandbox.d.ts +6 -0
  9. package/dist/types/agent/subagents/sandbox.d.ts.map +1 -1
  10. package/dist/types/channels/gateway-core.d.ts +50 -8
  11. package/dist/types/channels/gateway-core.d.ts.map +1 -1
  12. package/dist/types/channels/gateway-sources.d.ts +0 -1
  13. package/dist/types/channels/gateway-sources.d.ts.map +1 -1
  14. package/dist/types/channels/message-channel-executor.d.ts +0 -1
  15. package/dist/types/channels/message-channel-executor.d.ts.map +1 -1
  16. package/dist/types/channels/message-channel-idempotency.d.ts +5 -14
  17. package/dist/types/channels/message-channel-idempotency.d.ts.map +1 -1
  18. package/dist/types/channels/message-channel-tool-definition.d.ts +1 -4
  19. package/dist/types/channels/message-channel-tool-definition.d.ts.map +1 -1
  20. package/dist/types/channels/plugin-types.d.ts +2 -3
  21. package/dist/types/channels/plugin-types.d.ts.map +1 -1
  22. package/dist/types/channels/types.d.ts +1 -3
  23. package/dist/types/channels/types.d.ts.map +1 -1
  24. package/dist/types/types/protocol_v2.d.ts +11 -5
  25. package/dist/types/types/protocol_v2.d.ts.map +1 -1
  26. package/dist/types/websocket/listener/queue.d.ts.map +1 -1
  27. package/letta.js +233 -804
  28. package/package.json +1 -1
  29. package/scripts/source-file-size-baseline.json +1 -1
  30. package/dist/types/channels/gateway-assistant-relay.d.ts +0 -37
  31. package/dist/types/channels/gateway-assistant-relay.d.ts.map +0 -1
  32. package/dist/types/channels/gateway-registration-policy.d.ts +0 -14
  33. package/dist/types/channels/gateway-registration-policy.d.ts.map +0 -1
  34. package/dist/types/channels/gateway-runtime-registration.d.ts +0 -12
  35. package/dist/types/channels/gateway-runtime-registration.d.ts.map +0 -1
  36. package/dist/types/channels/gateway-runtime-state.d.ts +0 -48
  37. package/dist/types/channels/gateway-runtime-state.d.ts.map +0 -1
  38. package/dist/types/channels/gateway-runtime-tool-scopes.d.ts +0 -26
  39. package/dist/types/channels/gateway-runtime-tool-scopes.d.ts.map +0 -1
  40. package/dist/types/channels/gateway-types.d.ts +0 -71
  41. package/dist/types/channels/gateway-types.d.ts.map +0 -1
  42. package/dist/types/types/channel-account-protocol.d.ts +0 -14
  43. package/dist/types/types/channel-account-protocol.d.ts.map +0 -1
package/letta.js CHANGED
@@ -5710,7 +5710,7 @@ var package_default;
5710
5710
  var init_package = __esm(() => {
5711
5711
  package_default = {
5712
5712
  name: "@letta-ai/letta-code",
5713
- version: "0.34.3",
5713
+ version: "0.34.4",
5714
5714
  lettaStartupLogProtocol: 1,
5715
5715
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5716
5716
  type: "module",
@@ -161807,7 +161807,6 @@ function normalizeLoadedAccount(account) {
161807
161807
  next[camelKey] = raw2[snakeKey];
161808
161808
  }
161809
161809
  }
161810
- next.replyMode = next.replyMode === "relay" ? "relay" : "tool";
161811
161810
  if (isCustomChannelAccount(next) || !isFirstPartyChannelId(next.channel)) {
161812
161811
  next.config = isRecord2(next.config) ? { ...next.config } : {};
161813
161812
  }
@@ -161880,7 +161879,6 @@ function makeDefaultLegacyAccount(channelId) {
161880
161879
  enabled: config.enabled,
161881
161880
  token: config.token,
161882
161881
  dmPolicy: config.dmPolicy,
161883
- replyMode: "tool",
161884
161882
  allowedUsers: [...config.allowedUsers],
161885
161883
  transcribeVoice: config.transcribeVoice === true,
161886
161884
  richPrivateChatDefault: config.richPrivateChatDefault !== false,
@@ -161900,7 +161898,6 @@ function makeDefaultLegacyAccount(channelId) {
161900
161898
  enabled: config.enabled,
161901
161899
  token: config.token,
161902
161900
  dmPolicy: config.dmPolicy,
161903
- replyMode: "tool",
161904
161901
  allowedUsers: [...config.allowedUsers],
161905
161902
  allowedChannels: config.allowedChannels ? Array.isArray(config.allowedChannels) ? [...config.allowedChannels] : { ...config.allowedChannels } : undefined,
161906
161903
  autoThreadOnMention: config.autoThreadOnMention ?? true,
@@ -161918,7 +161915,6 @@ function makeDefaultLegacyAccount(channelId) {
161918
161915
  accountId: LEGACY_CHANNEL_ACCOUNT_ID,
161919
161916
  enabled: config.enabled,
161920
161917
  dmPolicy: config.dmPolicy,
161921
- replyMode: "tool",
161922
161918
  allowedUsers: [...config.allowedUsers],
161923
161919
  agentId: config.agentId,
161924
161920
  selfChatMode: config.selfChatMode !== false,
@@ -161951,7 +161947,6 @@ function makeDefaultLegacyAccount(channelId) {
161951
161947
  account: config.account,
161952
161948
  accountUuid: config.accountUuid,
161953
161949
  dmPolicy: config.dmPolicy,
161954
- replyMode: "tool",
161955
161950
  allowedUsers: [...config.allowedUsers],
161956
161951
  agentId: config.agentId,
161957
161952
  selfChatMode: config.selfChatMode === true,
@@ -162191,7 +162186,6 @@ var init_accounts = __esm(() => {
162191
162186
  remove_stale_routes: "removeStaleRoutes",
162192
162187
  rich_draft_streaming: "richDraftStreaming",
162193
162188
  rich_private_chat_default: "richPrivateChatDefault",
162194
- reply_mode: "replyMode",
162195
162189
  thread_policy_by_channel: "threadPolicyByChannel",
162196
162190
  transcribe_voice: "transcribeVoice",
162197
162191
  download_media: "downloadMedia",
@@ -169688,11 +169682,7 @@ function buildUnboundRouteInstructions(channelId, chatId) {
169688
169682
 
169689
169683
  ` + `Open Channels > ${displayName} in Letta Code and connect this chat there.
169690
169684
 
169691
- ` + `CLI on the listener machine:
169692
-
169693
- ` + `letta channels route add --channel ${channelId} --chat-id ${chatId} --agent <agent-id>
169694
-
169695
- ` + `Find your agent id with letta agents list.`;
169685
+ ` + `Chat ID: ${chatId}`;
169696
169686
  }
169697
169687
  function buildSlackAppSetupInstructions() {
169698
169688
  return `This Slack app isn't connected to a Letta agent yet.
@@ -182569,7 +182559,6 @@ function createAccountFromPatch(channelId, accountId, patch2) {
182569
182559
  enabled: normalizedPatch.enabled ?? false,
182570
182560
  token: normalizedPatch.token ?? "",
182571
182561
  dmPolicy: normalizedPatch.dmPolicy ?? "pairing",
182572
- replyMode: normalizedPatch.replyMode ?? "tool",
182573
182562
  allowedUsers: normalizedPatch.allowedUsers ?? [],
182574
182563
  groupMode: normalizeTelegramGroupMode(normalizedPatch.groupMode) ?? "open",
182575
182564
  transcribeVoice: normalizedPatch.transcribeVoice === true,
@@ -182594,7 +182583,6 @@ function createAccountFromPatch(channelId, accountId, patch2) {
182594
182583
  agentId: normalizedPatch.agentId ?? null,
182595
182584
  defaultPermissionMode: normalizedPatch.defaultPermissionMode ?? "standard",
182596
182585
  dmPolicy: normalizedPatch.dmPolicy ?? "pairing",
182597
- replyMode: normalizedPatch.replyMode ?? "tool",
182598
182586
  allowedUsers: normalizedPatch.allowedUsers ?? [],
182599
182587
  allowedChannels: normalizedPatch.allowedChannels ?? [],
182600
182588
  autoThreadOnMention: normalizedPatch.autoThreadOnMention ?? false,
@@ -182615,7 +182603,6 @@ function createAccountFromPatch(channelId, accountId, patch2) {
182615
182603
  enabled: normalizedPatch.enabled ?? false,
182616
182604
  agentId: normalizedPatch.agentId ?? null,
182617
182605
  dmPolicy: normalizedPatch.dmPolicy ?? "pairing",
182618
- replyMode: normalizedPatch.replyMode ?? "tool",
182619
182606
  allowedUsers: normalizedPatch.allowedUsers ?? [],
182620
182607
  selfChatMode: normalizedPatch.selfChatMode ?? true,
182621
182608
  groupMode: normalizeWhatsAppGroupMode(normalizedPatch.groupMode) ?? "disabled",
@@ -182648,7 +182635,6 @@ function createAccountFromPatch(channelId, accountId, patch2) {
182648
182635
  agentId: normalizedPatch.agentId ?? null,
182649
182636
  selfChatMode: normalizedPatch.selfChatMode === true,
182650
182637
  dmPolicy: normalizedPatch.dmPolicy ?? "pairing",
182651
- replyMode: normalizedPatch.replyMode ?? "tool",
182652
182638
  allowedUsers: normalizedPatch.allowedUsers ?? [],
182653
182639
  groupMode: normalizeSignalGroupMode(normalizedPatch.groupMode) ?? "disabled",
182654
182640
  allowedGroups: normalizedPatch.allowedGroups ?? [],
@@ -182668,7 +182654,6 @@ function createAccountFromPatch(channelId, accountId, patch2) {
182668
182654
  displayName: normalizeDisplayName(normalizedPatch.displayName),
182669
182655
  enabled: normalizedPatch.enabled ?? false,
182670
182656
  dmPolicy: normalizedPatch.dmPolicy ?? "pairing",
182671
- replyMode: normalizedPatch.replyMode ?? "tool",
182672
182657
  allowedUsers: normalizedPatch.allowedUsers ?? [],
182673
182658
  config: { ...normalizedPatch.config ?? {} },
182674
182659
  createdAt: now2,
@@ -182690,7 +182675,6 @@ function createAccountFromPatch(channelId, accountId, patch2) {
182690
182675
  mentionOnlyChannels: [...normalizedPatch.mentionOnlyChannels ?? []],
182691
182676
  allowBots: normalizedPatch.allowBots ?? false,
182692
182677
  dmPolicy: normalizedPatch.dmPolicy ?? "open",
182693
- replyMode: normalizedPatch.replyMode ?? "tool",
182694
182678
  allowedUsers: normalizedPatch.allowedUsers ?? [],
182695
182679
  createdAt: now2,
182696
182680
  updatedAt: now2
@@ -182706,7 +182690,6 @@ function mergeAccountPatch(existing, patch2) {
182706
182690
  enabled: normalizedPatch.enabled ?? existing.enabled,
182707
182691
  token: normalizedPatch.token ?? existing.token,
182708
182692
  dmPolicy: normalizedPatch.dmPolicy ?? existing.dmPolicy,
182709
- replyMode: normalizedPatch.replyMode ?? existing.replyMode ?? "tool",
182710
182693
  allowedUsers: normalizedPatch.allowedUsers ?? existing.allowedUsers,
182711
182694
  groupMode: normalizeTelegramGroupMode(normalizedPatch.groupMode) ?? existing.groupMode ?? "open",
182712
182695
  transcribeVoice: normalizedPatch.transcribeVoice ?? existing.transcribeVoice ?? false,
@@ -182725,7 +182708,6 @@ function mergeAccountPatch(existing, patch2) {
182725
182708
  agentId: normalizedPatch.agentId ?? existing.agentId,
182726
182709
  defaultPermissionMode: normalizedPatch.defaultPermissionMode ?? existing.defaultPermissionMode ?? "standard",
182727
182710
  dmPolicy: normalizedPatch.dmPolicy ?? existing.dmPolicy,
182728
- replyMode: normalizedPatch.replyMode ?? existing.replyMode ?? "tool",
182729
182711
  allowedUsers: normalizedPatch.allowedUsers ?? existing.allowedUsers,
182730
182712
  allowedChannels: normalizedPatch.allowedChannels ?? existing.allowedChannels,
182731
182713
  autoThreadOnMention: normalizedPatch.autoThreadOnMention ?? existing.autoThreadOnMention,
@@ -182744,7 +182726,6 @@ function mergeAccountPatch(existing, patch2) {
182744
182726
  enabled: normalizedPatch.enabled ?? existing.enabled,
182745
182727
  agentId: normalizedPatch.agentId ?? existing.agentId,
182746
182728
  dmPolicy: normalizedPatch.dmPolicy ?? existing.dmPolicy,
182747
- replyMode: normalizedPatch.replyMode ?? existing.replyMode ?? "tool",
182748
182729
  allowedUsers: normalizedPatch.allowedUsers ?? existing.allowedUsers,
182749
182730
  selfChatMode: normalizedPatch.selfChatMode ?? existing.selfChatMode,
182750
182731
  groupMode: normalizeWhatsAppGroupMode(normalizedPatch.groupMode) ?? existing.groupMode,
@@ -182775,7 +182756,6 @@ function mergeAccountPatch(existing, patch2) {
182775
182756
  agentId: normalizedPatch.agentId ?? existing.agentId,
182776
182757
  selfChatMode: normalizedPatch.selfChatMode ?? existing.selfChatMode,
182777
182758
  dmPolicy: normalizedPatch.dmPolicy ?? existing.dmPolicy,
182778
- replyMode: normalizedPatch.replyMode ?? existing.replyMode ?? "tool",
182779
182759
  allowedUsers: normalizedPatch.allowedUsers ?? existing.allowedUsers,
182780
182760
  groupMode: normalizeSignalGroupMode(normalizedPatch.groupMode) ?? existing.groupMode,
182781
182761
  allowedGroups: normalizedPatch.allowedGroups ?? existing.allowedGroups,
@@ -182793,7 +182773,6 @@ function mergeAccountPatch(existing, patch2) {
182793
182773
  displayName: normalizedPatch.displayName !== undefined ? normalizeDisplayName(normalizedPatch.displayName) : existing.displayName,
182794
182774
  enabled: normalizedPatch.enabled ?? existing.enabled,
182795
182775
  dmPolicy: normalizedPatch.dmPolicy ?? existing.dmPolicy,
182796
- replyMode: normalizedPatch.replyMode ?? existing.replyMode ?? "tool",
182797
182776
  allowedUsers: normalizedPatch.allowedUsers ?? existing.allowedUsers,
182798
182777
  config: normalizedPatch.config !== undefined ? { ...existing.config, ...normalizedPatch.config } : { ...existing.config },
182799
182778
  updatedAt: nextUpdatedAt
@@ -182815,7 +182794,6 @@ function mergeAccountPatch(existing, patch2) {
182815
182794
  ],
182816
182795
  allowBots: normalizedPatch.allowBots ?? existing.allowBots ?? false,
182817
182796
  dmPolicy: normalizedPatch.dmPolicy ?? existing.dmPolicy,
182818
- replyMode: normalizedPatch.replyMode ?? existing.replyMode ?? "tool",
182819
182797
  allowedUsers: normalizedPatch.allowedUsers ?? existing.allowedUsers,
182820
182798
  updatedAt: nextUpdatedAt
182821
182799
  };
@@ -182880,7 +182858,6 @@ function toAccountSnapshot(account) {
182880
182858
  configured: isAccountConfigured(account),
182881
182859
  running,
182882
182860
  dmPolicy: account.dmPolicy,
182883
- replyMode: account.replyMode ?? "tool",
182884
182861
  allowedUsers: [...account.allowedUsers],
182885
182862
  config,
182886
182863
  hasToken: account.token.trim().length > 0,
@@ -182903,7 +182880,6 @@ function toAccountSnapshot(account) {
182903
182880
  configured: isAccountConfigured(account),
182904
182881
  running,
182905
182882
  dmPolicy: account.dmPolicy,
182906
- replyMode: account.replyMode ?? "tool",
182907
182883
  allowedUsers: [...account.allowedUsers],
182908
182884
  config: toChannelAccountProtocolConfig(account),
182909
182885
  allowedChannels: account.allowedChannels ? Array.isArray(account.allowedChannels) ? [...account.allowedChannels] : { ...account.allowedChannels } : [],
@@ -182929,7 +182905,6 @@ function toAccountSnapshot(account) {
182929
182905
  configured: isAccountConfigured(account),
182930
182906
  running,
182931
182907
  dmPolicy: account.dmPolicy,
182932
- replyMode: account.replyMode ?? "tool",
182933
182908
  allowedUsers: [...account.allowedUsers],
182934
182909
  config: toChannelAccountProtocolConfig(account),
182935
182910
  agentId: account.agentId,
@@ -182963,7 +182938,6 @@ function toAccountSnapshot(account) {
182963
182938
  configured: isAccountConfigured(account),
182964
182939
  running,
182965
182940
  dmPolicy: account.dmPolicy,
182966
- replyMode: account.replyMode ?? "tool",
182967
182941
  allowedUsers: [...account.allowedUsers],
182968
182942
  config: toChannelAccountProtocolConfig(account),
182969
182943
  agentId: account.agentId,
@@ -182988,7 +182962,6 @@ function toAccountSnapshot(account) {
182988
182962
  configured: isAccountConfigured(account),
182989
182963
  running,
182990
182964
  dmPolicy: account.dmPolicy,
182991
- replyMode: account.replyMode ?? "tool",
182992
182965
  allowedUsers: [...account.allowedUsers],
182993
182966
  config: toChannelAccountProtocolConfig(account),
182994
182967
  createdAt: account.createdAt,
@@ -183004,7 +182977,6 @@ function toAccountSnapshot(account) {
183004
182977
  running,
183005
182978
  mode: account.mode,
183006
182979
  dmPolicy: account.dmPolicy,
183007
- replyMode: account.replyMode ?? "tool",
183008
182980
  allowedUsers: [...account.allowedUsers],
183009
182981
  config: toChannelAccountProtocolConfig(account),
183010
182982
  hasBotToken: account.botToken.trim().length > 0,
@@ -183068,7 +183040,6 @@ function getChannelConfigSnapshot(channelId, accountId) {
183068
183040
  displayName: account.displayName,
183069
183041
  enabled: account.enabled,
183070
183042
  dmPolicy: account.dmPolicy,
183071
- replyMode: account.replyMode ?? "tool",
183072
183043
  allowedUsers: [...account.allowedUsers],
183073
183044
  config: toChannelConfigSnapshotProtocolConfig(account),
183074
183045
  hasToken: account.token.trim().length > 0,
@@ -183086,7 +183057,6 @@ function getChannelConfigSnapshot(channelId, accountId) {
183086
183057
  displayName: account.displayName,
183087
183058
  enabled: account.enabled,
183088
183059
  dmPolicy: account.dmPolicy,
183089
- replyMode: account.replyMode ?? "tool",
183090
183060
  allowedUsers: [...account.allowedUsers],
183091
183061
  config: toChannelConfigSnapshotProtocolConfig(account),
183092
183062
  allowedChannels: account.allowedChannels ? Array.isArray(account.allowedChannels) ? [...account.allowedChannels] : { ...account.allowedChannels } : [],
@@ -183108,7 +183078,6 @@ function getChannelConfigSnapshot(channelId, accountId) {
183108
183078
  displayName: account.displayName,
183109
183079
  enabled: account.enabled,
183110
183080
  dmPolicy: account.dmPolicy,
183111
- replyMode: account.replyMode ?? "tool",
183112
183081
  allowedUsers: [...account.allowedUsers],
183113
183082
  config: toChannelConfigSnapshotProtocolConfig(account),
183114
183083
  agentId: account.agentId,
@@ -183138,7 +183107,6 @@ function getChannelConfigSnapshot(channelId, accountId) {
183138
183107
  displayName: account.displayName,
183139
183108
  enabled: account.enabled,
183140
183109
  dmPolicy: account.dmPolicy,
183141
- replyMode: account.replyMode ?? "tool",
183142
183110
  allowedUsers: [...account.allowedUsers],
183143
183111
  config: toChannelConfigSnapshotProtocolConfig(account),
183144
183112
  agentId: account.agentId,
@@ -183159,7 +183127,6 @@ function getChannelConfigSnapshot(channelId, accountId) {
183159
183127
  displayName: account.displayName,
183160
183128
  enabled: account.enabled,
183161
183129
  dmPolicy: account.dmPolicy,
183162
- replyMode: account.replyMode ?? "tool",
183163
183130
  allowedUsers: [...account.allowedUsers],
183164
183131
  config: toChannelConfigSnapshotProtocolConfig(account)
183165
183132
  };
@@ -183171,7 +183138,6 @@ function getChannelConfigSnapshot(channelId, accountId) {
183171
183138
  enabled: account.enabled,
183172
183139
  mode: account.mode,
183173
183140
  dmPolicy: account.dmPolicy,
183174
- replyMode: account.replyMode ?? "tool",
183175
183141
  allowedUsers: [...account.allowedUsers],
183176
183142
  config: toChannelConfigSnapshotProtocolConfig(account),
183177
183143
  hasBotToken: account.botToken.trim().length > 0,
@@ -183694,7 +183660,6 @@ async function setChannelConfigLive(channelId, patch2, accountId) {
183694
183660
  mode: normalizedPatch.mode,
183695
183661
  defaultPermissionMode: normalizedPatch.defaultPermissionMode,
183696
183662
  dmPolicy: normalizedPatch.dmPolicy,
183697
- replyMode: normalizedPatch.replyMode,
183698
183663
  allowedUsers: normalizedPatch.allowedUsers,
183699
183664
  allowedChannels: normalizedPatch.allowedChannels,
183700
183665
  agentId: normalizedPatch.agentId,
@@ -183733,7 +183698,6 @@ async function setChannelConfigLive(channelId, patch2, accountId) {
183733
183698
  mode: normalizedPatch.mode,
183734
183699
  defaultPermissionMode: normalizedPatch.defaultPermissionMode,
183735
183700
  dmPolicy: normalizedPatch.dmPolicy,
183736
- replyMode: normalizedPatch.replyMode,
183737
183701
  allowedUsers: normalizedPatch.allowedUsers,
183738
183702
  allowedChannels: normalizedPatch.allowedChannels,
183739
183703
  agentId: normalizedPatch.agentId,
@@ -220056,7 +220020,7 @@ class CodexAppServerClient {
220056
220020
  await this.request("initialize", {
220057
220021
  clientInfo: {
220058
220022
  name: "letta-code",
220059
- version: "0.34.3"
220023
+ version: "0.34.4"
220060
220024
  },
220061
220025
  capabilities: null
220062
220026
  });
@@ -222478,9 +222442,14 @@ function wrapSubagentLauncher(input) {
222478
222442
  }
222479
222443
  const isLocal = input.backendMode === "local";
222480
222444
  const storageDir = input.localBackendStorageDir ?? undefined;
222445
+ const scratchpadDir = input.scratchpadDir || undefined;
222446
+ if (scratchpadDir) {
222447
+ mkdirSync29(scratchpadDir, { recursive: true });
222448
+ }
222481
222449
  const harnessWritableRoots = [
222482
222450
  getTranscriptRoot(),
222483
- ...isLocal && storageDir ? [storageDir] : []
222451
+ ...isLocal && storageDir ? [storageDir] : [],
222452
+ ...scratchpadDir ? [scratchpadDir] : []
222484
222453
  ];
222485
222454
  const policy = buildMemorySubagentSandboxPolicy({
222486
222455
  memoryRoots: writableMemoryRoots,
@@ -224113,7 +224082,8 @@ async function executeSubagent(type3, config, model, userPrompt, subagentId, isR
224113
224082
  memoryRoots: inheritedMemoryRoots.roots,
224114
224083
  inheritedPrimaryRoot,
224115
224084
  memoryScope,
224116
- localBackendStorageDir
224085
+ localBackendStorageDir,
224086
+ scratchpadDir: childEnv.LETTA_SCRATCHPAD
224117
224087
  });
224118
224088
  const spawnLauncher = sandbox ? { command: sandbox.command, args: sandbox.args } : launcher;
224119
224089
  const spawnEnv = sandbox ? { ...childEnv, ...sandbox.sandboxEnv } : childEnv;
@@ -231245,9 +231215,6 @@ function getQueueItemsScope(items3) {
231245
231215
  function hasSameQueueScope(a2, b3) {
231246
231216
  return (a2.agentId ?? null) === (b3.agentId ?? null) && (a2.conversationId ?? null) === (b3.conversationId ?? null);
231247
231217
  }
231248
- function externalToolScopeSelection(message) {
231249
- return JSON.stringify(message?.externalToolScopeIds ?? []);
231250
- }
231251
231218
  function getBatchActingUserId(items3) {
231252
231219
  const actingUserId = items3[0]?.actingUserId;
231253
231220
  if (!actingUserId || items3.some((item) => item.actingUserId !== actingUserId)) {
@@ -231331,20 +231298,12 @@ function consumeQueuedTurn(runtime) {
231331
231298
  let batchConnectionId;
231332
231299
  let batchImageFailureMode = null;
231333
231300
  let batchPreferences = JSON.stringify(getStoredClientPreferences(runtime.agentId, runtime.conversationId));
231334
- let batchExternalToolScopes = null;
231335
231301
  const isNoCoalesce = (candidate) => candidate.kind === "message" && candidate.noCoalesce === true;
231336
231302
  for (const item of queuedItems) {
231337
231303
  if (!isCoalescable(item.kind) || !hasSameQueueScope(firstQueuedItem, item)) {
231338
231304
  break;
231339
231305
  }
231340
231306
  const incoming = runtime.queuedMessagesByItemId.get(item.id);
231341
- if (item.kind === "message") {
231342
- const externalToolScopes = externalToolScopeSelection(incoming);
231343
- if (batchExternalToolScopes !== null && externalToolScopes !== batchExternalToolScopes) {
231344
- break;
231345
- }
231346
- batchExternalToolScopes = externalToolScopes;
231347
- }
231348
231307
  if (incoming?.clientPreferences !== undefined) {
231349
231308
  const preferences = JSON.stringify(normalizeClientPreferences(incoming.clientPreferences));
231350
231309
  if (preferences !== batchPreferences && (queueLen > 0 || runtime.turnLifecycle.kind !== "idle"))
@@ -235971,11 +235930,10 @@ function isChannelId(value) {
235971
235930
  }
235972
235931
  function hasValidChannelPolicyFields(config) {
235973
235932
  const hasValidDmPolicy = config.dm_policy === undefined || config.dm_policy === "pairing" || config.dm_policy === "allowlist" || config.dm_policy === "open";
235974
- const hasValidReplyMode = config.reply_mode === undefined || config.reply_mode === "tool" || config.reply_mode === "relay";
235975
235933
  const hasValidAllowedUsers = config.allowed_users === undefined || Array.isArray(config.allowed_users) && config.allowed_users.every((entry) => typeof entry === "string");
235976
235934
  const hasValidDisplayName = config.display_name === undefined || typeof config.display_name === "string";
235977
235935
  const hasValidEnabled = config.enabled === undefined || typeof config.enabled === "boolean";
235978
- return hasValidDmPolicy && hasValidReplyMode && hasValidAllowedUsers && hasValidDisplayName && hasValidEnabled;
235936
+ return hasValidDmPolicy && hasValidAllowedUsers && hasValidDisplayName && hasValidEnabled;
235979
235937
  }
235980
235938
  function hasOnlyFields(value, allowedFields) {
235981
235939
  return Object.keys(value).every((field) => allowedFields.has(field));
@@ -235987,7 +235945,6 @@ var init_channel_service_validation = __esm(() => {
235987
235945
  "display_name",
235988
235946
  "enabled",
235989
235947
  "dm_policy",
235990
- "reply_mode",
235991
235948
  "allowed_users",
235992
235949
  "config"
235993
235950
  ]);
@@ -235995,13 +235952,11 @@ var init_channel_service_validation = __esm(() => {
235995
235952
  "display_name",
235996
235953
  "enabled",
235997
235954
  "dm_policy",
235998
- "reply_mode",
235999
235955
  "allowed_users",
236000
235956
  "config"
236001
235957
  ]);
236002
235958
  CHANNEL_SET_CONFIG_FIELDS = new Set([
236003
235959
  "dm_policy",
236004
- "reply_mode",
236005
235960
  "allowed_users",
236006
235961
  "plugin_config"
236007
235962
  ]);
@@ -453786,7 +453741,7 @@ var init_mcp_client = __esm(() => {
453786
453741
  init_streamableHttp();
453787
453742
  DEFAULT_CLIENT_INFO = {
453788
453743
  name: "letta-code",
453789
- version: "0.34.3"
453744
+ version: "0.34.4"
453790
453745
  };
453791
453746
  });
453792
453747
 
@@ -463670,108 +463625,38 @@ var init_message_channel_formatting = __esm(() => {
463670
463625
  function isErrorResult(result3) {
463671
463626
  return result3.startsWith("Error:");
463672
463627
  }
463673
- function createMessageChannelIdempotencyScope(state2) {
463674
- const inFlightActionKeys = new Map;
463675
- const inFlightTextDeliveryKeys = new Map;
463676
- const inFlightRelayTextDeliveryKeys = new Set;
463677
- const successfulActionKeys = new Set(state2?.successfulActionKeys ?? []);
463678
- const successfulTextDeliveryKeys = new Set(state2?.successfulTextDeliveryKeys ?? []);
463679
- const successfulRelayTextDeliveryKeys = new Set(state2?.successfulRelayTextDeliveryKeys ?? []);
463680
- let lastSuccessfulActionKey = state2?.lastSuccessfulActionKey ?? null;
463628
+ function createMessageChannelIdempotencyScope() {
463629
+ const inFlight = new Map;
463630
+ let lastSuccessful = null;
463681
463631
  let latestInvocation = 0;
463682
- const addInFlightTextDelivery = (key3) => {
463683
- if (key3) {
463684
- inFlightTextDeliveryKeys.set(key3, (inFlightTextDeliveryKeys.get(key3) ?? 0) + 1);
463685
- }
463686
- };
463687
- const removeInFlightTextDelivery = (key3) => {
463688
- if (!key3)
463689
- return;
463690
- const remaining = (inFlightTextDeliveryKeys.get(key3) ?? 1) - 1;
463691
- if (remaining > 0)
463692
- inFlightTextDeliveryKeys.set(key3, remaining);
463693
- else
463694
- inFlightTextDeliveryKeys.delete(key3);
463695
- };
463696
463632
  return {
463697
- async execute(actionKey, textDeliveryKey, effect) {
463698
- if (!actionKey) {
463633
+ async execute(key3, effect) {
463634
+ if (!key3) {
463699
463635
  latestInvocation += 1;
463700
- lastSuccessfulActionKey = null;
463636
+ lastSuccessful = null;
463701
463637
  return await effect();
463702
463638
  }
463703
- if (inFlightActionKeys.has(actionKey) || textDeliveryKey && inFlightRelayTextDeliveryKeys.has(textDeliveryKey)) {
463639
+ const pendingDuplicate = inFlight.get(key3);
463640
+ if (pendingDuplicate) {
463704
463641
  throw new MessageChannelDuplicateActionError("in-flight");
463705
463642
  }
463706
- if (lastSuccessfulActionKey === actionKey || textDeliveryKey && successfulRelayTextDeliveryKeys.has(textDeliveryKey)) {
463643
+ if (lastSuccessful?.key === key3) {
463707
463644
  throw new MessageChannelDuplicateActionError("completed");
463708
463645
  }
463709
463646
  const invocation = ++latestInvocation;
463710
- lastSuccessfulActionKey = null;
463711
- const pending = Promise.resolve().then(effect);
463712
- inFlightActionKeys.set(actionKey, pending);
463713
- addInFlightTextDelivery(textDeliveryKey);
463714
- try {
463715
- const result3 = await pending;
463716
- if (!isErrorResult(result3)) {
463717
- successfulActionKeys.add(actionKey);
463718
- if (textDeliveryKey)
463719
- successfulTextDeliveryKeys.add(textDeliveryKey);
463720
- if (invocation === latestInvocation) {
463721
- lastSuccessfulActionKey = actionKey;
463722
- }
463723
- }
463724
- return result3;
463725
- } finally {
463726
- if (inFlightActionKeys.get(actionKey) === pending) {
463727
- inFlightActionKeys.delete(actionKey);
463728
- }
463729
- removeInFlightTextDelivery(textDeliveryKey);
463730
- }
463731
- },
463732
- async executeRelay(actionKey, textDeliveryKey, effect) {
463733
- if (!actionKey)
463734
- return await effect();
463735
- if (inFlightActionKeys.has(actionKey) || textDeliveryKey && inFlightTextDeliveryKeys.has(textDeliveryKey)) {
463736
- throw new MessageChannelDuplicateActionError("in-flight");
463737
- }
463738
- if (successfulActionKeys.has(actionKey) || textDeliveryKey && successfulTextDeliveryKeys.has(textDeliveryKey)) {
463739
- throw new MessageChannelDuplicateActionError("completed");
463740
- }
463647
+ lastSuccessful = null;
463741
463648
  const pending = Promise.resolve().then(effect);
463742
- inFlightActionKeys.set(actionKey, pending);
463743
- addInFlightTextDelivery(textDeliveryKey);
463744
- if (textDeliveryKey)
463745
- inFlightRelayTextDeliveryKeys.add(textDeliveryKey);
463649
+ inFlight.set(key3, pending);
463746
463650
  try {
463747
463651
  const result3 = await pending;
463748
- if (!isErrorResult(result3)) {
463749
- successfulActionKeys.add(actionKey);
463750
- if (textDeliveryKey) {
463751
- successfulTextDeliveryKeys.add(textDeliveryKey);
463752
- successfulRelayTextDeliveryKeys.add(textDeliveryKey);
463753
- }
463652
+ if (invocation === latestInvocation && !isErrorResult(result3)) {
463653
+ lastSuccessful = { key: key3 };
463754
463654
  }
463755
463655
  return result3;
463756
463656
  } finally {
463757
- if (inFlightActionKeys.get(actionKey) === pending) {
463758
- inFlightActionKeys.delete(actionKey);
463759
- }
463760
- removeInFlightTextDelivery(textDeliveryKey);
463761
- if (textDeliveryKey)
463762
- inFlightRelayTextDeliveryKeys.delete(textDeliveryKey);
463657
+ if (inFlight.get(key3) === pending)
463658
+ inFlight.delete(key3);
463763
463659
  }
463764
- },
463765
- snapshot() {
463766
- if (inFlightActionKeys.size > 0 || inFlightTextDeliveryKeys.size > 0) {
463767
- return null;
463768
- }
463769
- return {
463770
- successfulActionKeys: [...successfulActionKeys],
463771
- successfulTextDeliveryKeys: [...successfulTextDeliveryKeys],
463772
- successfulRelayTextDeliveryKeys: [...successfulRelayTextDeliveryKeys],
463773
- lastSuccessfulActionKey
463774
- };
463775
463660
  }
463776
463661
  };
463777
463662
  }
@@ -463985,20 +463870,6 @@ function messageIdempotencyKey(request2, route) {
463985
463870
  replyToMessageId: effectiveTextReplyId(request2, route)
463986
463871
  });
463987
463872
  }
463988
- function textDeliveryFingerprint(request2, route) {
463989
- if (request2.action !== "send" && request2.action !== "send-rich" || request2.mediaPath) {
463990
- return null;
463991
- }
463992
- return JSON.stringify({
463993
- channel: request2.channel,
463994
- chatId: route.chatId,
463995
- accountId: route.accountId ?? null,
463996
- chatType: route.chatType ?? null,
463997
- threadId: effectiveTextThreadId(request2, route),
463998
- message: request2.message?.trim() ?? null,
463999
- replyToMessageId: effectiveTextReplyId(request2, route)
464000
- });
464001
- }
464002
463873
  async function executeMessageChannel(input, options) {
464003
463874
  const normalized = normalizeMessageChannelInput(input, options.resolver);
464004
463875
  if (typeof normalized === "string")
@@ -464067,7 +463938,7 @@ async function executeMessageChannel(input, options) {
464067
463938
  });
464068
463939
  const requestThreadId = normalized.action === "download-file" ? normalized.threadId : inferredThreadId ?? (normalized.channel === "telegram" && context4.route.chatType === "direct" ? normalized.threadId : context4.route.threadId ?? normalized.threadId);
464069
463940
  const request3 = buildMessageChannelRequest(normalized, normalized.chatId, requestThreadId);
464070
- return await dispatchWithIdempotency(request3, context4, options.idempotencyScope, options.idempotencyMode);
463941
+ return await dispatchWithIdempotency(request3, context4, options.idempotencyScope);
464071
463942
  }
464072
463943
  if (normalized.channel !== "slack") {
464073
463944
  return `Error: Explicit MessageChannel targets are not supported on ${normalized.channel}.`;
@@ -464100,13 +463971,10 @@ async function executeMessageChannel(input, options) {
464100
463971
  async function executeMessageChannelExternalTool(input, options) {
464101
463972
  return createMessageChannelExternalToolResult(await executeMessageChannel(input, options));
464102
463973
  }
464103
- function dispatchWithIdempotency(request2, context3, scope, mode = "explicit") {
463974
+ function dispatchWithIdempotency(request2, context3, scope) {
464104
463975
  const dispatch = () => dispatchMessageChannelAction({ request: request2, context: context3 });
464105
- const actionKey = messageIdempotencyKey(request2, context3.route);
464106
- const deliveryKey = textDeliveryFingerprint(request2, context3.route);
464107
- if (!scope)
464108
- return dispatch();
464109
- return mode === "relay" ? scope.executeRelay(actionKey, deliveryKey, dispatch) : scope.execute(actionKey, deliveryKey, dispatch);
463976
+ const key3 = messageIdempotencyKey(request2, context3.route);
463977
+ return scope ? scope.execute(key3, dispatch) : dispatch();
464110
463978
  }
464111
463979
  var init_message_channel_executor = __esm(() => {
464112
463980
  init_message_channel_formatting();
@@ -464282,7 +464150,7 @@ function createLocalMessageChannelResolver() {
464282
464150
  }
464283
464151
  };
464284
464152
  }
464285
- function resolveLocalMessageChannelExecution(args, idempotencyScope, idempotencyMode = "explicit") {
464153
+ function resolveLocalMessageChannelExecution(args, idempotencyScope) {
464286
464154
  if (!getChannelRegistry()) {
464287
464155
  return "Error: Channel system is not initialized. Start with --channels flag.";
464288
464156
  }
@@ -464293,14 +464161,9 @@ function resolveLocalMessageChannelExecution(args, idempotencyScope, idempotency
464293
464161
  scope: args.parentScope,
464294
464162
  resolver: createLocalMessageChannelResolver(),
464295
464163
  channelTurnSources: args.channelTurnSources,
464296
- idempotencyScope,
464297
- idempotencyMode
464164
+ idempotencyScope
464298
464165
  };
464299
464166
  }
464300
- async function relayLocalMessageChannel(args, idempotencyScope) {
464301
- const execution = resolveLocalMessageChannelExecution(args, idempotencyScope, "relay");
464302
- return typeof execution === "string" ? execution : await executeMessageChannel(args, execution);
464303
- }
464304
464167
  async function executeLocalMessageChannelExternalTool(args, idempotencyScope) {
464305
464168
  const execution = resolveLocalMessageChannelExecution(args, idempotencyScope);
464306
464169
  return typeof execution === "string" ? createMessageChannelExternalToolResult(execution) : await executeMessageChannelExternalTool(args, execution);
@@ -464819,117 +464682,6 @@ var init_channel_rich_draft_streamer = __esm(() => {
464819
464682
  ]);
464820
464683
  });
464821
464684
 
464822
- // src/channels/gateway-assistant-relay.ts
464823
- class GatewayAssistantTextAccumulator {
464824
- currentMessageId;
464825
- currentText;
464826
- deltaKeys;
464827
- finalizedMessageIds;
464828
- constructor(state2) {
464829
- this.currentMessageId = state2?.currentMessageId ?? null;
464830
- this.currentText = state2?.currentText ?? "";
464831
- this.deltaKeys = new Set(state2?.deltaKeys ?? []);
464832
- this.finalizedMessageIds = new Set(state2?.finalizedMessageIds ?? []);
464833
- }
464834
- snapshot() {
464835
- return {
464836
- currentMessageId: this.currentMessageId,
464837
- currentText: this.currentText,
464838
- deltaKeys: [...this.deltaKeys],
464839
- finalizedMessageIds: [...this.finalizedMessageIds]
464840
- };
464841
- }
464842
- handleDelta(message) {
464843
- const delta2 = message.delta;
464844
- if (delta2.message_type === "assistant_message") {
464845
- const messageId2 = delta2.otid || delta2.id;
464846
- if (!messageId2 || this.finalizedMessageIds.has(messageId2))
464847
- return [];
464848
- const finalized = this.currentMessageId && this.currentMessageId !== messageId2 ? this.finalizeCurrent() : null;
464849
- if (!this.currentMessageId)
464850
- this.currentMessageId = messageId2;
464851
- if (!this.deltaKeys.has(message.idempotency_key)) {
464852
- const text2 = typeof delta2.content === "string" ? delta2.content : delta2.content.map((part) => part.text ?? "").join("");
464853
- this.deltaKeys.add(message.idempotency_key);
464854
- this.currentText += text2;
464855
- }
464856
- return finalized ? [finalized] : [];
464857
- }
464858
- if (delta2.message_type === "tool_call_message" || delta2.message_type === "approval_request_message") {
464859
- const finalized = this.finalizeCurrent();
464860
- return finalized ? [finalized] : [];
464861
- }
464862
- if (delta2.message_type === "reasoning_message") {
464863
- const boundaryId = delta2.otid || delta2.id;
464864
- if (this.currentMessageId && (!boundaryId || boundaryId !== this.currentMessageId)) {
464865
- const finalized = this.finalizeCurrent();
464866
- return finalized ? [finalized] : [];
464867
- }
464868
- }
464869
- return [];
464870
- }
464871
- finalizeCurrent() {
464872
- const messageId2 = this.currentMessageId;
464873
- if (!messageId2)
464874
- return null;
464875
- const text2 = this.currentText.trim();
464876
- this.currentMessageId = null;
464877
- this.currentText = "";
464878
- this.finalizedMessageIds.add(messageId2);
464879
- return text2 ? { messageId: messageId2, text: text2 } : null;
464880
- }
464881
- }
464882
- function relayFinalizedAssistantMessage(options) {
464883
- if (options.sources.length !== 1 || !options.relay)
464884
- return;
464885
- const warn = (error5) => {
464886
- const detail = error5 instanceof Error ? error5.message : String(error5);
464887
- console.warn(`[channels] Automatic relay failed: ${detail}`);
464888
- };
464889
- try {
464890
- const pending = options.relay({
464891
- text: options.message.text,
464892
- sources: options.sources,
464893
- idempotencyScope: options.idempotencyScope
464894
- });
464895
- if (pending)
464896
- return pending.catch(warn);
464897
- } catch (error5) {
464898
- warn(error5);
464899
- }
464900
- }
464901
- function stopReasonFromDelta(message) {
464902
- const delta2 = message.delta;
464903
- return delta2.message_type === "stop_reason" && "stop_reason" in delta2 && typeof delta2.stop_reason === "string" ? delta2.stop_reason : null;
464904
- }
464905
- function runIdFromDelta(message) {
464906
- const runId = "run_id" in message.delta ? message.delta.run_id : undefined;
464907
- return typeof runId === "string" && runId.length > 0 ? runId : undefined;
464908
- }
464909
- function channelTurnOutcome(stopReason) {
464910
- if (stopReason === "cancelled")
464911
- return "cancelled";
464912
- return stopReason === "end_turn" || stopReason === "tool_rule" ? "completed" : "error";
464913
- }
464914
-
464915
- // src/channels/gateway-registration-policy.ts
464916
- async function prepareGatewayRegistrationPolicy(options) {
464917
- const automaticRelay = options.override ?? (options.hooks.resolveAssistantRelayPolicy ? await options.hooks.resolveAssistantRelayPolicy(options.runtime, options.sources) : Boolean(options.hooks.relayAssistantText));
464918
- const tool = await options.hooks.buildExternalTool(options.runtime, options.sources, { automaticRelay });
464919
- return { automaticRelay, tool };
464920
- }
464921
- function modelStatusFromRuntimeStart(response, runtime) {
464922
- const agent = response.agent;
464923
- const conversation = response.conversation;
464924
- const agentModel = typeof agent?.model === "string" ? agent.model : response.agent?.llm_config?.model ?? null;
464925
- const conversationModel = typeof conversation?.model === "string" ? conversation.model : null;
464926
- const isAgentScope = runtime.conversation_id === "default";
464927
- return {
464928
- modelHandle: isAgentScope ? agentModel : conversationModel ?? agentModel,
464929
- scope: isAgentScope ? "agent" : "conversation"
464930
- };
464931
- }
464932
-
464933
464685
  // src/channels/gateway-sources.ts
464934
464686
  function sourceRouteKey(source) {
464935
464687
  return [
@@ -464959,231 +464711,6 @@ function uniqueRoutedSources(sources) {
464959
464711
  function uniqueLifecycleSources(sources) {
464960
464712
  return uniqueSourcesBy(sources, sourceLifecycleKey);
464961
464713
  }
464962
- function channelTagsForSources(sources) {
464963
- return [...new Set(sources.map((source) => `channel:${source.channel}`))];
464964
- }
464965
-
464966
- // src/channels/gateway-runtime-registration.ts
464967
- async function performGatewayRuntimeRegistration(options) {
464968
- const {
464969
- client,
464970
- hooks,
464971
- state: state2,
464972
- delivery,
464973
- policyOverride,
464974
- externalToolsOverride
464975
- } = options;
464976
- const prepared = externalToolsOverride ? { automaticRelay: policyOverride ?? false, tool: null } : await prepareGatewayRegistrationPolicy({
464977
- hooks,
464978
- runtime: delivery.runtime,
464979
- sources: delivery.sources,
464980
- ...policyOverride === undefined ? {} : { override: policyOverride }
464981
- });
464982
- const { automaticRelay, tool } = prepared;
464983
- const externalTools = externalToolsOverride ?? (tool ? [{ tools: [tool] }] : []);
464984
- const conversationTags2 = channelTagsForSources(delivery.sources);
464985
- const signature = JSON.stringify({
464986
- mode: delivery.defaultPermissionMode ?? null,
464987
- automaticRelay,
464988
- externalTools,
464989
- conversationTags: conversationTags2
464990
- });
464991
- if (state2.registrationSignature === signature && state2.registration) {
464992
- await state2.registration;
464993
- return automaticRelay;
464994
- }
464995
- const registration = client.runtimeStart({
464996
- agent_id: delivery.runtime.agent_id,
464997
- conversation_id: delivery.runtime.conversation_id,
464998
- ...conversationTags2.length > 0 ? { conversation_source_tags: conversationTags2 } : {},
464999
- ...delivery.defaultPermissionMode ? { mode: delivery.defaultPermissionMode } : {},
465000
- recover_approvals: true,
465001
- force_device_status: false,
465002
- wait_for_replay: true,
465003
- preserve_skill_sources: true,
465004
- client_info: { name: "channel-gateway", title: "Channel Gateway" },
465005
- external_tools: externalTools
465006
- }).then((response) => {
465007
- if (!response.success) {
465008
- throw new Error(response.error ?? "Failed to register channel runtime");
465009
- }
465010
- state2.modelStatus = modelStatusFromRuntimeStart(response, delivery.runtime);
465011
- });
465012
- state2.registrationSignature = signature;
465013
- state2.registration = registration;
465014
- try {
465015
- await registration;
465016
- } catch (error5) {
465017
- if (state2.registration === registration) {
465018
- state2.registration = null;
465019
- state2.registrationSignature = null;
465020
- }
465021
- throw error5;
465022
- }
465023
- return automaticRelay;
465024
- }
465025
- var init_gateway_runtime_registration = () => {};
465026
-
465027
- // src/channels/gateway-runtime-state.ts
465028
- function gatewayRuntimeKey(runtime) {
465029
- return `${runtime.agent_id}:${runtime.conversation_id}`;
465030
- }
465031
- function hasAgentRuntime(value) {
465032
- return !!value.runtime?.agent_id;
465033
- }
465034
- function hasGatewayRuntimeWork(state2) {
465035
- return Boolean(state2 && (state2.active || state2.pendingSourcesByClientMessageId.size > 0));
465036
- }
465037
- function rememberAcceptedClientMessageId(state2, clientMessageId) {
465038
- state2.acceptedClientMessageIds.delete(clientMessageId);
465039
- state2.acceptedClientMessageIds.add(clientMessageId);
465040
- if (state2.acceptedClientMessageIds.size <= MAX_ACCEPTED_CLIENT_MESSAGE_IDS)
465041
- return;
465042
- const oldest = state2.acceptedClientMessageIds.values().next().value;
465043
- if (oldest)
465044
- state2.acceptedClientMessageIds.delete(oldest);
465045
- }
465046
- function remainingGatewaySources(state2) {
465047
- return uniqueLifecycleSources([
465048
- ...state2.active?.lifecycleSources ?? [],
465049
- ...Array.from(state2.pendingSourcesByClientMessageId.values()).flatMap((pending) => pending.sources)
465050
- ]);
465051
- }
465052
- var MAX_ACCEPTED_CLIENT_MESSAGE_IDS = 2048;
465053
- var init_gateway_runtime_state = () => {};
465054
-
465055
- // src/channels/gateway-runtime-tool-scopes.ts
465056
- function runtimeKey(runtime) {
465057
- return `${runtime.agent_id}:${runtime.conversation_id}`;
465058
- }
465059
-
465060
- class GatewayRuntimeToolScopes {
465061
- client;
465062
- states = new Map;
465063
- retryTimers = new Set;
465064
- closed = false;
465065
- constructor(client) {
465066
- this.client = client;
465067
- }
465068
- create(runtime, sources, automaticRelay, tool) {
465069
- const id2 = `channel-turn-${crypto.randomUUID()}`;
465070
- const scope = {
465071
- id: id2,
465072
- runtime,
465073
- sources: structuredClone(sources),
465074
- automaticRelay,
465075
- ...tool ? { group: { scope_id: id2, tools: [structuredClone(tool)] } } : {}
465076
- };
465077
- this.retain(scope);
465078
- return scope;
465079
- }
465080
- retain(scope) {
465081
- this.getState(scope.runtime).scopes.set(scope.id, scope);
465082
- }
465083
- detach(scope) {
465084
- this.states.get(runtimeKey(scope.runtime))?.scopes.delete(scope.id);
465085
- return scope;
465086
- }
465087
- release(scope) {
465088
- this.states.get(runtimeKey(scope.runtime))?.scopes.delete(scope.id);
465089
- }
465090
- resolve(runtime, scopeId) {
465091
- return this.states.get(runtimeKey(runtime))?.scopes.get(scopeId) ?? null;
465092
- }
465093
- selection(scope) {
465094
- return [scope.id];
465095
- }
465096
- hasRetainedScopes(runtime) {
465097
- return (this.states.get(runtimeKey(runtime))?.scopes.size ?? 0) > 0;
465098
- }
465099
- registrationGroups(runtime, includeUnscoped) {
465100
- const state2 = this.states.get(runtimeKey(runtime));
465101
- if (!state2)
465102
- return [];
465103
- const scoped = [...state2.scopes.values()].flatMap((scope) => scope.group ? [scope.group] : []);
465104
- return includeUnscoped ? [...scoped, ...state2.desiredUnscoped] : scoped;
465105
- }
465106
- setDesiredUnscoped(runtime, groups) {
465107
- this.getState(runtime).desiredUnscoped = groups;
465108
- }
465109
- async updateDesiredUnscoped(updates, isBusy) {
465110
- const immediateByTools = new Map;
465111
- for (const update3 of updates) {
465112
- for (const runtime of update3.runtimes) {
465113
- this.getState(runtime).desiredUnscoped = update3.external_tools;
465114
- if (!isBusy(runtime)) {
465115
- const externalTools = this.registrationGroups(runtime, true);
465116
- const signature = JSON.stringify(externalTools);
465117
- const existing = immediateByTools.get(signature);
465118
- if (existing)
465119
- existing.runtimes.push(runtime);
465120
- else
465121
- immediateByTools.set(signature, {
465122
- runtimes: [runtime],
465123
- external_tools: externalTools
465124
- });
465125
- }
465126
- }
465127
- }
465128
- const immediate = [...immediateByTools.values()];
465129
- if (immediate.length === 0)
465130
- return;
465131
- const response = await this.client.runtimeExternalToolsUpdate({
465132
- updates: immediate
465133
- });
465134
- if (!response.success) {
465135
- throw new Error(response.error ?? "Failed to update routed runtime tools");
465136
- }
465137
- }
465138
- flushWhenIdle(runtime, isBusy, schedule) {
465139
- if (isBusy() || this.closed)
465140
- return;
465141
- schedule(async () => {
465142
- if (isBusy())
465143
- return;
465144
- const response = await this.client.runtimeExternalToolsUpdate({
465145
- updates: [
465146
- {
465147
- runtimes: [runtime],
465148
- external_tools: this.registrationGroups(runtime, true)
465149
- }
465150
- ]
465151
- });
465152
- if (!response.success) {
465153
- throw new Error(response.error ?? "Failed to update routed runtime tools");
465154
- }
465155
- }).catch(() => {
465156
- if (this.closed)
465157
- return;
465158
- const timer = setTimeout(() => {
465159
- this.retryTimers.delete(timer);
465160
- this.flushWhenIdle(runtime, isBusy, schedule);
465161
- }, RETRY_DELAY_MS);
465162
- timer.unref?.();
465163
- this.retryTimers.add(timer);
465164
- });
465165
- }
465166
- forgetRuntime(runtime) {
465167
- this.states.delete(runtimeKey(runtime));
465168
- }
465169
- close() {
465170
- this.closed = true;
465171
- for (const timer of this.retryTimers)
465172
- clearTimeout(timer);
465173
- this.retryTimers.clear();
465174
- this.states.clear();
465175
- }
465176
- getState(runtime) {
465177
- const key3 = runtimeKey(runtime);
465178
- let state2 = this.states.get(key3);
465179
- if (!state2) {
465180
- state2 = { runtime, scopes: new Map, desiredUnscoped: [] };
465181
- this.states.set(key3, state2);
465182
- }
465183
- return state2;
465184
- }
465185
- }
465186
- var RETRY_DELAY_MS = 1000;
465187
464714
 
465188
464715
  // src/channels/progress-builder.ts
465189
464716
  function getMessageType(delta2) {
@@ -465590,40 +465117,49 @@ var init_progress_builder = __esm(() => {
465590
465117
  });
465591
465118
 
465592
465119
  // src/channels/gateway-core.ts
465120
+ function runtimeKey(runtime) {
465121
+ return `${runtime.agent_id}:${runtime.conversation_id}`;
465122
+ }
465123
+ function hasAgentRuntime(value) {
465124
+ return !!value.runtime?.agent_id;
465125
+ }
465126
+ function channelTagsForSources(sources) {
465127
+ return [...new Set(sources.map((source) => `channel:${source.channel}`))];
465128
+ }
465129
+ function stopReasonFromDelta(message) {
465130
+ const delta2 = message.delta;
465131
+ return delta2.message_type === "stop_reason" && "stop_reason" in delta2 && typeof delta2.stop_reason === "string" ? delta2.stop_reason : null;
465132
+ }
465133
+ function runIdFromDelta(message) {
465134
+ const runId = "run_id" in message.delta ? message.delta.run_id : undefined;
465135
+ return typeof runId === "string" && runId.length > 0 ? runId : undefined;
465136
+ }
465137
+ function lifecycleOutcome(stopReason) {
465138
+ if (stopReason === "cancelled")
465139
+ return "cancelled";
465140
+ if (stopReason === "end_turn" || stopReason === "tool_rule") {
465141
+ return "completed";
465142
+ }
465143
+ return "error";
465144
+ }
465145
+
465593
465146
  class ChannelGateway {
465594
465147
  client;
465595
465148
  hooks;
465596
465149
  states = new Map;
465597
465150
  disposers = [];
465598
- runtimeToolScopes;
465599
465151
  registrationQueue = Promise.resolve();
465600
465152
  constructor(client, hooks) {
465601
465153
  this.client = client;
465602
465154
  this.hooks = hooks;
465603
- this.runtimeToolScopes = new GatewayRuntimeToolScopes(client);
465604
- this.disposers.push(client.onMessage((message) => this.handleMessage(message)), client.onExternalToolCall(async (request2) => {
465605
- const state2 = hasAgentRuntime(request2) ? this.states.get(gatewayRuntimeKey(request2.runtime)) : undefined;
465155
+ this.disposers.push(client.onMessage((message) => this.handleMessage(message)), client.onExternalToolCall((request2) => {
465156
+ const state2 = hasAgentRuntime(request2) ? this.states.get(runtimeKey(request2.runtime)) : undefined;
465606
465157
  const active = state2?.active;
465607
- const scoped = hasAgentRuntime(request2) && request2.scope_id ? this.runtimeToolScopes.resolve(request2.runtime, request2.scope_id) : null;
465608
- if (request2.scope_id && !scoped) {
465609
- throw new Error(`Unknown or stale external tool scope: ${request2.scope_id}`);
465610
- }
465611
- const sources = scoped?.sources ?? active?.routingSources ?? state2?.routedSources ?? [];
465612
- const activeOwnsScope = Boolean(scoped && active?.toolScopes.some((scope) => scope.id === scoped.id));
465613
- try {
465614
- return await hooks.executeExternalTool(request2, sources, activeOwnsScope || !request2.scope_id && active ? active?.idempotencyScope : null);
465615
- } catch (error5) {
465616
- if (!(error5 instanceof MessageChannelDuplicateActionError))
465617
- throw error5;
465618
- return {
465619
- content: [{ type: "text", text: error5.message }],
465620
- is_error: true
465621
- };
465622
- }
465158
+ const sources = active?.routingSources ?? state2?.routedSources ?? [];
465159
+ return hooks.executeExternalTool(request2, sources, active?.idempotencyScope ?? null);
465623
465160
  }));
465624
465161
  }
465625
465162
  close() {
465626
- this.runtimeToolScopes.close();
465627
465163
  for (const dispose of this.disposers.splice(0))
465628
465164
  dispose();
465629
465165
  this.client.close();
@@ -465648,34 +465184,16 @@ class ChannelGateway {
465648
465184
  const workAtSubmit = state2.active || state2.pendingSourcesByClientMessageId.size > 0;
465649
465185
  state2.pendingSourcesByClientMessageId.set(delivery.clientMessageId, {
465650
465186
  sources: uniqueLifecycleSources(delivery.sources),
465651
- disposition: "submitting",
465652
- automaticRelay: false
465187
+ disposition: "submitting"
465653
465188
  });
465654
465189
  try {
465655
- const toolScope = await this.enqueueRegistration(async () => {
465190
+ await this.enqueueRegistration(async () => {
465656
465191
  state2.routedSources = uniqueRoutedSources([
465657
465192
  ...state2.routedSources,
465658
465193
  ...delivery.sources
465659
465194
  ]);
465660
- const { automaticRelay, tool } = await prepareGatewayRegistrationPolicy({
465661
- hooks: this.hooks,
465662
- runtime: delivery.runtime,
465663
- sources: delivery.sources
465664
- });
465665
- const scope = this.runtimeToolScopes.create(delivery.runtime, delivery.sources, automaticRelay, tool);
465666
- try {
465667
- await this.performRuntimeRegistration(state2, delivery, automaticRelay, this.runtimeToolScopes.registrationGroups(delivery.runtime, false));
465668
- return scope;
465669
- } catch (error5) {
465670
- this.runtimeToolScopes.release(scope);
465671
- throw error5;
465672
- }
465195
+ await this.performRuntimeRegistration(state2, delivery);
465673
465196
  });
465674
- const submitted = state2.pendingSourcesByClientMessageId.get(delivery.clientMessageId);
465675
- if (submitted) {
465676
- submitted.automaticRelay = toolScope.automaticRelay;
465677
- submitted.toolScope = toolScope;
465678
- }
465679
465197
  const response = await this.client.submitInput({
465680
465198
  runtime: delivery.runtime,
465681
465199
  payload: {
@@ -465688,24 +465206,21 @@ class ChannelGateway {
465688
465206
  }
465689
465207
  ],
465690
465208
  image_failure_mode: "drop",
465691
- client_preferences: {},
465692
- external_tool_scope_ids: this.runtimeToolScopes.selection(toolScope)
465209
+ client_preferences: {}
465693
465210
  }
465694
465211
  });
465695
465212
  if (!response.accepted) {
465696
465213
  state2.pendingSourcesByClientMessageId.delete(delivery.clientMessageId);
465697
- this.runtimeToolScopes.release(toolScope);
465698
- this.finishToolScopesIfIdle(state2);
465699
465214
  if (workAtSubmit && !state2.active)
465700
465215
  this.finishRejectedDelivery(state2, delivery);
465701
465216
  return false;
465702
465217
  }
465703
- rememberAcceptedClientMessageId(state2, delivery.clientMessageId);
465218
+ this.rememberAcceptedClientMessageId(state2, delivery.clientMessageId);
465704
465219
  for (const source of delivery.sources) {
465705
465220
  this.enqueueHook(state2, () => this.hooks.onLifecycle({ type: "queued", source }));
465706
465221
  }
465707
465222
  if (response.disposition === "started") {
465708
- this.activateSources(state2, delivery.clientMessageId, delivery.sources, toolScope.automaticRelay, toolScope);
465223
+ this.activateSources(state2, delivery.clientMessageId, delivery.sources);
465709
465224
  state2.pendingSourcesByClientMessageId.delete(delivery.clientMessageId);
465710
465225
  } else if (response.disposition === "queued") {
465711
465226
  const pending = state2.pendingSourcesByClientMessageId.get(delivery.clientMessageId);
@@ -465716,19 +465231,20 @@ class ChannelGateway {
465716
465231
  }
465717
465232
  return true;
465718
465233
  } catch (error5) {
465719
- const failed2 = state2.pendingSourcesByClientMessageId.get(delivery.clientMessageId);
465720
465234
  state2.pendingSourcesByClientMessageId.delete(delivery.clientMessageId);
465721
- if (failed2?.toolScope) {
465722
- this.runtimeToolScopes.release(failed2.toolScope);
465723
- }
465724
- this.finishToolScopesIfIdle(state2);
465725
465235
  if (workAtSubmit && !state2.active)
465726
465236
  this.finishRejectedDelivery(state2, delivery);
465727
465237
  throw error5;
465728
465238
  }
465729
465239
  }
465240
+ remainingSources(state2) {
465241
+ return uniqueLifecycleSources([
465242
+ ...state2.active?.lifecycleSources ?? [],
465243
+ ...Array.from(state2.pendingSourcesByClientMessageId.values()).flatMap((pending) => pending.sources)
465244
+ ]);
465245
+ }
465730
465246
  finishRejectedDelivery(state2, delivery) {
465731
- const remainingSources = remainingGatewaySources(state2);
465247
+ const remainingSources = this.remainingSources(state2);
465732
465248
  this.enqueueHook(state2, () => this.hooks.onLifecycle({
465733
465249
  type: "finished",
465734
465250
  batchId: `channel-${delivery.clientMessageId}`,
@@ -465753,14 +465269,13 @@ class ChannelGateway {
465753
465269
  }
465754
465270
  state2.pendingSourcesByClientMessageId.set(delivery.clientMessageId, {
465755
465271
  sources,
465756
- disposition: "queued",
465757
- automaticRelay: false
465272
+ disposition: "queued"
465758
465273
  });
465759
465274
  state2.routedSources = uniqueRoutedSources([
465760
465275
  ...state2.routedSources,
465761
465276
  ...delivery.sources
465762
465277
  ]);
465763
- rememberAcceptedClientMessageId(state2, delivery.clientMessageId);
465278
+ this.rememberAcceptedClientMessageId(state2, delivery.clientMessageId);
465764
465279
  }
465765
465280
  async restoreRuntime(runtime, sources) {
465766
465281
  const state2 = this.getState(runtime);
@@ -465773,10 +465288,7 @@ class ChannelGateway {
465773
465288
  lifecycleSources: uniqueLifecycleSources(sources),
465774
465289
  progress: createChannelTurnProgressBuilder(),
465775
465290
  richDraft: null,
465776
- assistantText: new GatewayAssistantTextAccumulator,
465777
- idempotencyScope: createMessageChannelIdempotencyScope(),
465778
- relayEligible: false,
465779
- toolScopes: []
465291
+ idempotencyScope: createMessageChannelIdempotencyScope()
465780
465292
  };
465781
465293
  state2.active = recoveredTurn;
465782
465294
  }
@@ -465794,7 +465306,7 @@ class ChannelGateway {
465794
465306
  return replayedRequestIds;
465795
465307
  }
465796
465308
  async adoptActiveDelivery(delivery) {
465797
- const key3 = gatewayRuntimeKey(delivery.runtime);
465309
+ const key3 = runtimeKey(delivery.runtime);
465798
465310
  const stateExisted = this.states.has(key3);
465799
465311
  const state2 = this.getState(delivery.runtime);
465800
465312
  const batchId = `channel-${delivery.clientMessageId}`;
@@ -465803,8 +465315,8 @@ class ChannelGateway {
465803
465315
  if (state2.active.batchId !== batchId) {
465804
465316
  throw new Error(`Cannot adopt ${batchId}; ${state2.active.batchId} is already active`);
465805
465317
  }
465806
- this.activateSources(state2, delivery.clientMessageId, delivery.sources, state2.active.relayEligible);
465807
- rememberAcceptedClientMessageId(state2, delivery.clientMessageId);
465318
+ this.activateSources(state2, delivery.clientMessageId, delivery.sources);
465319
+ this.rememberAcceptedClientMessageId(state2, delivery.clientMessageId);
465808
465320
  return;
465809
465321
  }
465810
465322
  const previousRoutedSources = state2.routedSources;
@@ -465816,21 +465328,19 @@ class ChannelGateway {
465816
465328
  lifecycleSources: uniqueLifecycleSources(delivery.sources),
465817
465329
  progress: createChannelTurnProgressBuilder(),
465818
465330
  richDraft: null,
465819
- assistantText: new GatewayAssistantTextAccumulator(delivery.activeTurnState?.assistantText),
465820
- idempotencyScope: createMessageChannelIdempotencyScope(delivery.activeTurnState?.idempotency),
465821
- relayEligible: delivery.activeTurnState?.automaticRelay ?? Boolean(delivery.activeTurnState),
465822
- toolScopes: delivery.activeTurnState?.toolScopes ?? []
465331
+ idempotencyScope: createMessageChannelIdempotencyScope()
465823
465332
  };
465824
465333
  state2.active = active;
465825
- for (const scope of active.toolScopes)
465826
- this.runtimeToolScopes.retain(scope);
465827
465334
  state2.routedSources = uniqueRoutedSources([
465828
465335
  ...state2.routedSources,
465829
465336
  ...delivery.sources
465830
465337
  ]);
465831
- rememberAcceptedClientMessageId(state2, delivery.clientMessageId);
465338
+ this.rememberAcceptedClientMessageId(state2, delivery.clientMessageId);
465832
465339
  try {
465833
- await this.performRuntimeRegistration(state2, { ...delivery, content: "" }, active.relayEligible, this.runtimeToolScopes.registrationGroups(delivery.runtime, false));
465340
+ await this.performRuntimeRegistration(state2, {
465341
+ ...delivery,
465342
+ content: ""
465343
+ });
465834
465344
  if (state2.active !== active)
465835
465345
  return;
465836
465346
  active.richDraft = this.hooks.createRichDraft?.({
@@ -465844,9 +465354,6 @@ class ChannelGateway {
465844
465354
  }));
465845
465355
  } catch (error5) {
465846
465356
  active.richDraft?.dispose();
465847
- for (const scope of active.toolScopes) {
465848
- this.runtimeToolScopes.release(scope);
465849
- }
465850
465357
  if (state2.active === active)
465851
465358
  state2.active = null;
465852
465359
  state2.routedSources = previousRoutedSources;
@@ -465860,67 +465367,51 @@ class ChannelGateway {
465860
465367
  });
465861
465368
  }
465862
465369
  releaseActiveDelivery(runtime, clientMessageId) {
465863
- const key3 = gatewayRuntimeKey(runtime);
465370
+ const key3 = runtimeKey(runtime);
465864
465371
  const state2 = this.states.get(key3);
465865
465372
  const active = state2?.active;
465866
465373
  if (!state2 || active?.batchId !== `channel-${clientMessageId}`) {
465867
- return null;
465374
+ return false;
465868
465375
  }
465869
- if (state2.hookQueue)
465870
- return null;
465871
- const idempotency = active.idempotencyScope.snapshot();
465872
- if (!idempotency)
465873
- return null;
465874
- const toolScopes = active.toolScopes.map((scope) => this.runtimeToolScopes.detach(scope));
465875
- const handoffState = {
465876
- assistantText: active.assistantText.snapshot(),
465877
- idempotency,
465878
- automaticRelay: active.relayEligible,
465879
- ...toolScopes.length > 0 ? { toolScopes } : {}
465880
- };
465881
465376
  active.richDraft?.dispose();
465882
465377
  this.states.delete(key3);
465883
- return handoffState;
465378
+ return true;
465884
465379
  }
465885
465380
  async registerRuntime(runtime, sources = [], defaultPermissionMode) {
465886
465381
  const state2 = this.getState(runtime);
465887
465382
  await this.enqueueRegistration(async () => {
465888
465383
  this.setRoutedSources(runtime, sources);
465889
- const prepared = await prepareGatewayRegistrationPolicy({
465890
- hooks: this.hooks,
465891
- runtime,
465892
- sources
465893
- });
465894
- const externalTools = prepared.tool ? [{ tools: [prepared.tool] }] : [];
465895
- this.runtimeToolScopes.setDesiredUnscoped(runtime, externalTools);
465896
- if (this.runtimeToolScopes.hasRetainedScopes(runtime))
465897
- return;
465898
465384
  await this.performRuntimeRegistration(state2, {
465899
465385
  runtime,
465900
465386
  content: "",
465901
465387
  sources,
465902
465388
  clientMessageId: "recovered",
465903
465389
  ...defaultPermissionMode ? { defaultPermissionMode } : {}
465904
- }, prepared.automaticRelay, externalTools);
465390
+ });
465905
465391
  });
465906
465392
  }
465907
465393
  async publishRuntimeTools(runtime, sources = []) {
465908
465394
  return await this.enqueueRegistration(async () => {
465909
- if (this.states.has(gatewayRuntimeKey(runtime)))
465395
+ if (this.states.has(runtimeKey(runtime)))
465910
465396
  return false;
465911
465397
  const tool = await this.hooks.buildExternalTool(runtime, sources);
465912
- await this.runtimeToolScopes.updateDesiredUnscoped([
465913
- {
465914
- runtimes: [runtime],
465915
- external_tools: tool ? [{ tools: [tool] }] : []
465916
- }
465917
- ], () => false);
465398
+ const response = await this.client.runtimeExternalToolsUpdate({
465399
+ updates: [
465400
+ {
465401
+ runtimes: [runtime],
465402
+ external_tools: tool ? [{ tools: [tool] }] : []
465403
+ }
465404
+ ]
465405
+ });
465406
+ if (!response.success) {
465407
+ throw new Error(response.error ?? "Failed to publish channel runtime tools");
465408
+ }
465918
465409
  return tool !== null;
465919
465410
  });
465920
465411
  }
465921
465412
  async releaseRuntimeTools(runtime, routedSources = [], options = {}) {
465922
465413
  await this.enqueueRegistration(async () => {
465923
- const key3 = gatewayRuntimeKey(runtime);
465414
+ const key3 = runtimeKey(runtime);
465924
465415
  const state2 = this.states.get(key3);
465925
465416
  if (options.cleanupIdleRuntime) {
465926
465417
  if (routedSources.length > 0 || (state2?.routedSources.length ?? 0) > 0) {
@@ -465942,7 +465433,6 @@ class ChannelGateway {
465942
465433
  if (!response.success) {
465943
465434
  throw new Error(response.error ?? "Failed to release channel runtime tools");
465944
465435
  }
465945
- this.runtimeToolScopes.forgetRuntime(runtime);
465946
465436
  });
465947
465437
  }
465948
465438
  async submitApprovalResponse(runtime, response) {
@@ -465960,14 +465450,21 @@ class ChannelGateway {
465960
465450
  }
465961
465451
  updateRoutedRuntimeTools(updates, routedSources) {
465962
465452
  return this.enqueueRegistration(async () => {
465963
- await this.runtimeToolScopes.updateDesiredUnscoped(updates, (runtime) => hasGatewayRuntimeWork(this.states.get(gatewayRuntimeKey(runtime))));
465453
+ if (updates.length > 0) {
465454
+ const response = await this.client.runtimeExternalToolsUpdate({
465455
+ updates
465456
+ });
465457
+ if (!response.success) {
465458
+ throw new Error(response.error ?? "Failed to update routed runtime tools");
465459
+ }
465460
+ }
465964
465461
  for (const update3 of routedSources) {
465965
465462
  this.setRoutedSources(update3.runtime, update3.sources);
465966
465463
  }
465967
465464
  });
465968
465465
  }
465969
465466
  getModelStatus(runtime) {
465970
- return this.states.get(gatewayRuntimeKey(runtime))?.modelStatus ?? null;
465467
+ return this.states.get(runtimeKey(runtime))?.modelStatus ?? null;
465971
465468
  }
465972
465469
  updateModelStatus(runtime, modelHandle) {
465973
465470
  const state2 = this.getState(runtime);
@@ -465977,7 +465474,7 @@ class ChannelGateway {
465977
465474
  };
465978
465475
  }
465979
465476
  getState(runtime) {
465980
- const key3 = gatewayRuntimeKey(runtime);
465477
+ const key3 = runtimeKey(runtime);
465981
465478
  let state2 = this.states.get(key3);
465982
465479
  if (!state2) {
465983
465480
  state2 = {
@@ -465997,10 +465494,14 @@ class ChannelGateway {
465997
465494
  }
465998
465495
  return state2;
465999
465496
  }
466000
- finishToolScopesIfIdle(state2) {
466001
- if (state2.active || state2.pendingSourcesByClientMessageId.size > 0)
465497
+ rememberAcceptedClientMessageId(state2, clientMessageId) {
465498
+ state2.acceptedClientMessageIds.delete(clientMessageId);
465499
+ state2.acceptedClientMessageIds.add(clientMessageId);
465500
+ if (state2.acceptedClientMessageIds.size <= MAX_ACCEPTED_CLIENT_MESSAGE_IDS)
466002
465501
  return;
466003
- this.runtimeToolScopes.flushWhenIdle(state2.runtime, () => hasGatewayRuntimeWork(this.states.get(gatewayRuntimeKey(state2.runtime))), (task2) => this.enqueueRegistration(task2));
465502
+ const oldest = state2.acceptedClientMessageIds.values().next().value;
465503
+ if (oldest)
465504
+ state2.acceptedClientMessageIds.delete(oldest);
466004
465505
  }
466005
465506
  enqueueHook(state2, hook) {
466006
465507
  let pending;
@@ -466034,15 +465535,52 @@ class ChannelGateway {
466034
465535
  });
466035
465536
  return result3;
466036
465537
  }
466037
- async performRuntimeRegistration(state2, delivery, policyOverride, externalToolsOverride) {
466038
- return await performGatewayRuntimeRegistration({
466039
- client: this.client,
466040
- hooks: this.hooks,
466041
- state: state2,
466042
- delivery,
466043
- ...policyOverride === undefined ? {} : { policyOverride },
466044
- ...externalToolsOverride === undefined ? {} : { externalToolsOverride }
465538
+ async performRuntimeRegistration(state2, delivery) {
465539
+ const tool = await this.hooks.buildExternalTool(delivery.runtime, delivery.sources);
465540
+ const conversationTags2 = channelTagsForSources(delivery.sources);
465541
+ const signature = JSON.stringify({
465542
+ mode: delivery.defaultPermissionMode ?? null,
465543
+ tool,
465544
+ conversationTags: conversationTags2
465545
+ });
465546
+ if (state2.registrationSignature === signature && state2.registration) {
465547
+ return state2.registration;
465548
+ }
465549
+ const registration = this.client.runtimeStart({
465550
+ agent_id: delivery.runtime.agent_id,
465551
+ conversation_id: delivery.runtime.conversation_id,
465552
+ ...conversationTags2.length > 0 ? { conversation_source_tags: conversationTags2 } : {},
465553
+ ...delivery.defaultPermissionMode ? { mode: delivery.defaultPermissionMode } : {},
465554
+ recover_approvals: true,
465555
+ force_device_status: false,
465556
+ wait_for_replay: true,
465557
+ preserve_skill_sources: true,
465558
+ client_info: { name: "channel-gateway", title: "Channel Gateway" },
465559
+ external_tools: tool ? [{ tools: [tool] }] : []
465560
+ }).then((response) => {
465561
+ if (!response.success) {
465562
+ throw new Error(response.error ?? "Failed to register channel runtime");
465563
+ }
465564
+ const agentRecord = response.agent;
465565
+ const conversationRecord = response.conversation;
465566
+ const agentModel = typeof agentRecord?.model === "string" ? agentRecord.model : response.agent?.llm_config?.model ?? null;
465567
+ const conversationModel = typeof conversationRecord?.model === "string" ? conversationRecord.model : null;
465568
+ state2.modelStatus = {
465569
+ modelHandle: delivery.runtime.conversation_id === "default" ? agentModel : conversationModel ?? agentModel,
465570
+ scope: delivery.runtime.conversation_id === "default" ? "agent" : "conversation"
465571
+ };
466045
465572
  });
465573
+ state2.registrationSignature = signature;
465574
+ state2.registration = registration;
465575
+ try {
465576
+ await registration;
465577
+ } catch (error5) {
465578
+ if (state2.registration === registration) {
465579
+ state2.registration = null;
465580
+ state2.registrationSignature = null;
465581
+ }
465582
+ throw error5;
465583
+ }
466046
465584
  }
466047
465585
  handleMessage(message) {
466048
465586
  if (message.type === "update_queue") {
@@ -466090,25 +465628,15 @@ class ChannelGateway {
466090
465628
  continue;
466091
465629
  }
466092
465630
  const target2 = pending.removalDisposition === "dequeued" ? dequeued : cancelled;
466093
- target2.push({
466094
- clientMessageId,
466095
- sources: pending.sources,
466096
- automaticRelay: pending.automaticRelay,
466097
- ...pending.toolScope ? { toolScope: pending.toolScope } : {}
466098
- });
465631
+ target2.push({ clientMessageId, sources: pending.sources });
466099
465632
  state2.pendingSourcesByClientMessageId.delete(clientMessageId);
466100
465633
  }
466101
465634
  const firstDequeued = dequeued[0];
466102
465635
  if (firstDequeued) {
466103
- const dequeuedScopes = dequeued.flatMap((entry) => entry.toolScope ? [entry.toolScope] : []);
466104
- this.activateSources(state2, firstDequeued.clientMessageId, dequeued.flatMap((entry) => entry.sources), dequeued.every((entry) => entry.automaticRelay), dequeuedScopes[0]);
466105
- if (state2.active)
466106
- state2.active.toolScopes.push(...dequeuedScopes.slice(1));
465636
+ this.activateSources(state2, firstDequeued.clientMessageId, dequeued.flatMap((entry) => entry.sources));
466107
465637
  }
466108
465638
  for (const entry of cancelled) {
466109
- if (entry.toolScope)
466110
- this.runtimeToolScopes.release(entry.toolScope);
466111
- const remainingSources = remainingGatewaySources(state2);
465639
+ const remainingSources = this.remainingSources(state2);
466112
465640
  this.enqueueHook(state2, () => this.hooks.onLifecycle({
466113
465641
  type: "finished",
466114
465642
  batchId: `channel-${entry.clientMessageId}`,
@@ -466118,12 +465646,9 @@ class ChannelGateway {
466118
465646
  ...remainingSources.length ? { remainingSources } : {}
466119
465647
  }));
466120
465648
  }
466121
- this.finishToolScopesIfIdle(state2);
466122
465649
  }
466123
- activateSources(state2, clientMessageId, sources, automaticRelay, toolScope) {
465650
+ activateSources(state2, clientMessageId, sources) {
466124
465651
  if (state2.active) {
466125
- if (toolScope)
466126
- state2.active.toolScopes.push(toolScope);
466127
465652
  const knownLifecycleKeys = new Set(state2.active.lifecycleSources.map(sourceLifecycleKey));
466128
465653
  const addedLifecycleSources = uniqueLifecycleSources(sources).filter((source) => !knownLifecycleKeys.has(sourceLifecycleKey(source)));
466129
465654
  if (addedLifecycleSources.length === 0)
@@ -466136,7 +465661,6 @@ class ChannelGateway {
466136
465661
  ...state2.active.routingSources,
466137
465662
  ...sources
466138
465663
  ]);
466139
- state2.active.relayEligible &&= automaticRelay;
466140
465664
  const processingEvent2 = {
466141
465665
  type: "processing",
466142
465666
  batchId: state2.active.batchId,
@@ -466156,10 +465680,7 @@ class ChannelGateway {
466156
465680
  batchId: `channel-${clientMessageId}`,
466157
465681
  sources: routingSources
466158
465682
  }) ?? null,
466159
- assistantText: new GatewayAssistantTextAccumulator,
466160
- idempotencyScope: createMessageChannelIdempotencyScope(),
466161
- relayEligible: automaticRelay,
466162
- toolScopes: toolScope ? [toolScope] : []
465683
+ idempotencyScope: createMessageChannelIdempotencyScope()
466163
465684
  };
466164
465685
  const processingEvent = {
466165
465686
  type: "processing",
@@ -466178,7 +465699,6 @@ class ChannelGateway {
466178
465699
  const runId = runIdFromDelta(message);
466179
465700
  if (runId)
466180
465701
  active.runId = runId;
466181
- this.enqueueFinalizedAssistantMessages(state2, active, active.assistantText.handleDelta(message));
466182
465702
  for (const update3 of active.progress.buildUpdates(message.delta)) {
466183
465703
  this.enqueueHook(state2, () => this.hooks.onProgress({
466184
465704
  type: "progress",
@@ -466189,46 +465709,23 @@ class ChannelGateway {
466189
465709
  }
466190
465710
  active.richDraft?.handleDelta(message.delta);
466191
465711
  const stopReason = stopReasonFromDelta(message);
466192
- if (stopReason === "requires_approval" || stopReason === "end_turn" || stopReason === "tool_rule") {
465712
+ if (stopReason === "requires_approval" || stopReason === "end_turn") {
466193
465713
  active.richDraft?.flushPending();
466194
- const finalized = active.assistantText.finalizeCurrent();
466195
- if (finalized) {
466196
- this.enqueueFinalizedAssistantMessages(state2, active, [finalized]);
466197
- }
466198
465714
  }
466199
465715
  }
466200
- enqueueFinalizedAssistantMessages(state2, active, messages) {
466201
- const relay = active.relayEligible ? this.hooks.relayAssistantText : undefined;
466202
- for (const message of messages)
466203
- this.enqueueHook(state2, () => relayFinalizedAssistantMessage({
466204
- message,
466205
- sources: active.routingSources,
466206
- idempotencyScope: active.idempotencyScope,
466207
- relay
466208
- }));
466209
- }
466210
465716
  handleTurnFinished(runtime, terminal) {
466211
465717
  const state2 = this.getState(runtime);
466212
465718
  const active = state2.active;
466213
465719
  if (!active)
466214
465720
  return;
466215
- if (terminal.stopReason === "end_turn" || terminal.stopReason === "tool_rule") {
466216
- const finalized = active.assistantText.finalizeCurrent();
466217
- if (finalized) {
466218
- this.enqueueFinalizedAssistantMessages(state2, active, [finalized]);
466219
- }
466220
- }
466221
465721
  state2.active = null;
466222
465722
  active.richDraft?.dispose();
466223
- for (const scope of active.toolScopes)
466224
- this.runtimeToolScopes.release(scope);
466225
- this.finishToolScopesIfIdle(state2);
466226
- const remainingSources = channelTurnOutcome(terminal.stopReason) === "completed" ? remainingGatewaySources(state2) : [];
465723
+ const remainingSources = lifecycleOutcome(terminal.stopReason) === "completed" ? this.remainingSources(state2) : [];
466227
465724
  this.enqueueHook(state2, () => this.hooks.onLifecycle({
466228
465725
  type: "finished",
466229
465726
  batchId: active.batchId,
466230
465727
  sources: active.lifecycleSources,
466231
- outcome: channelTurnOutcome(terminal.stopReason),
465728
+ outcome: lifecycleOutcome(terminal.stopReason),
466232
465729
  stopReason: terminal.stopReason,
466233
465730
  ...remainingSources.length ? { remainingSources } : {},
466234
465731
  ...terminal.runId ?? active.runId ? { runId: terminal.runId ?? active.runId } : {},
@@ -466238,7 +465735,7 @@ class ChannelGateway {
466238
465735
  handleControlRequest(message) {
466239
465736
  if (!message.agent_id || !message.conversation_id)
466240
465737
  return;
466241
- const state2 = this.states.get(gatewayRuntimeKey({
465738
+ const state2 = this.states.get(runtimeKey({
466242
465739
  agent_id: message.agent_id,
466243
465740
  conversation_id: message.conversation_id
466244
465741
  }));
@@ -466261,9 +465758,8 @@ class ChannelGateway {
466261
465758
  }));
466262
465759
  }
466263
465760
  }
465761
+ var MAX_ACCEPTED_CLIENT_MESSAGE_IDS = 2048;
466264
465762
  var init_gateway_core = __esm(() => {
466265
- init_gateway_runtime_registration();
466266
- init_gateway_runtime_state();
466267
465763
  init_message_channel_idempotency();
466268
465764
  init_progress_builder();
466269
465765
  });
@@ -466368,15 +465864,12 @@ function resolveMessageChannelToolChannels(channels) {
466368
465864
  actions.add(action3);
466369
465865
  schemaContributions.push(...asSchemaContributionArray(discovery?.schema));
466370
465866
  }
466371
- const routedDestinationKeys = new Set(channels.map((channel) => channel.routedDestinationKey).filter(Boolean));
466372
- const hasCompleteDestinationKeys = channels.every((channel) => channel.routedDestinationKey);
466373
465867
  return {
466374
465868
  activeChannels: [...uniqueChannels.keys()],
466375
465869
  displayNames: [...uniqueChannels.values()].map((channel) => channel.displayName),
466376
465870
  accountIds: [...accountIds],
466377
465871
  actions: [...actions],
466378
- schemaContributions,
466379
- automaticRelay: channels.length > 0 && channels.every((channel) => channel.replyMode === "relay") && (hasCompleteDestinationKeys ? routedDestinationKeys.size === 1 : channels.length === 1)
465872
+ schemaContributions
466380
465873
  };
466381
465874
  }
466382
465875
  function mergeSchemaContributions(schema5, contributions) {
@@ -466454,9 +465947,7 @@ No external channel adapters are currently running.`;
466454
465947
  const channelList = discovery.displayNames.join(", ");
466455
465948
  const actionList = discovery.actions.join(", ");
466456
465949
  const hasAction = (action3) => discovery.actions.includes(action3);
466457
- const scopedReplyContract = scoped ? discovery.automaticRelay ? `
466458
-
466459
- This routed external channel turn uses automatic relay. Plain assistant text is delivered to the external user as each assistant message is finalized, so write the user-visible reply normally and do not make a duplicate MessageChannel send. When a host exposes MessageChannel alongside relay, use it only for explicit actions such as reactions and files; exact duplicate final text is suppressed.` : '\n\nThis tool is currently scoped to a routed external channel turn. Plain assistant text is not delivered to that external user. If a user-visible reply is appropriate, your final action for the turn must be one MessageChannel call with action="send", channel from the notification, chat_id from the notification, and message containing the reply. After that final send succeeds, do not repeat or paraphrase the sent message in assistant text; finish with only `Sent.` as the internal confirmation. This does not apply to a short acknowledgement sent before continuing substantive work. If no user-visible response is appropriate, do not call MessageChannel and do not send an empty acknowledgement. For lightweight acknowledgement, prefer action="react" when supported. If the useful response belongs later, schedule the follow-up instead of sending a placeholder.' : "";
465950
+ const scopedReplyContract = scoped ? '\n\nThis tool is currently scoped to a routed external channel turn. Plain assistant text is not delivered to that external user. If a user-visible reply is appropriate, your final action for the turn must be one MessageChannel call with action="send", channel from the notification, chat_id from the notification, and message containing the reply. After that final send succeeds, do not repeat or paraphrase the sent message in assistant text; finish with only `Sent.` as the internal confirmation. This does not apply to a short acknowledgement sent before continuing substantive work. If no user-visible response is appropriate, do not call MessageChannel and do not send an empty acknowledgement. For lightweight acknowledgement, prefer action="react" when supported. If the useful response belongs later, schedule the follow-up instead of sending a placeholder.' : "";
466460
465951
  const slackWorkAcknowledgement = discovery.activeChannels.includes("slack") ? `
466461
465952
 
466462
465953
  For Slack requests that require nontrivial work or several tool calls, send one short MessageChannel call with action="send" before starting other tools. This gives the Slack user verbal acknowledgement and a View in web link. Do not do this for no-ops, reaction-only responses, or simple no-tool answers.` : "";
@@ -466542,13 +466033,11 @@ async function resolveLocalMessageChannelToolChannels(scope) {
466542
466033
  accountId: null
466543
466034
  }));
466544
466035
  const channels = [];
466545
- for (const { channelId, accountId, routedDestinationKey } of targets) {
466036
+ for (const { channelId, accountId } of targets) {
466546
466037
  const channel = {
466547
466038
  channelId,
466548
466039
  displayName: getChannelDisplayName(channelId),
466549
- accountId,
466550
- routedDestinationKey,
466551
- replyMode: accountId ? getChannelAccount(channelId, accountId)?.replyMode ?? "tool" : "tool"
466040
+ accountId
466552
466041
  };
466553
466042
  try {
466554
466043
  const plugin = await loadChannelPlugin(channelId);
@@ -466565,7 +466054,6 @@ async function resolveLocalMessageChannelToolChannels(scope) {
466565
466054
  }
466566
466055
  var loggedDiscoveryErrors;
466567
466056
  var init_message_tool = __esm(() => {
466568
- init_accounts();
466569
466057
  init_message_channel_tool_definition();
466570
466058
  init_plugin_registry();
466571
466059
  init_registry();
@@ -466573,46 +466061,34 @@ var init_message_tool = __esm(() => {
466573
466061
  });
466574
466062
 
466575
466063
  // src/channels/message-channel-gateway-tool.ts
466576
- async function buildGatewayMessageChannelTool(sources, runtime, policy) {
466577
- const routed = sources.length > 0;
466578
- const channelScopes = routed ? sources.map((source) => ({
466064
+ async function buildGatewayMessageChannelTool(sources, runtime) {
466065
+ const seen = new Set;
466066
+ const channelScopes = (sources.length > 0 ? sources.map((source) => ({
466579
466067
  channelId: source.channel,
466580
- accountId: source.accountId ?? null,
466581
- routedDestinationKey: sourceRouteKey(source)
466068
+ accountId: source.accountId ?? null
466582
466069
  })) : runtime ? listEligibleProactiveSlackAccounts({
466583
466070
  agentId: runtime.agent_id
466584
466071
  }).map(({ account }) => ({
466585
466072
  channelId: "slack",
466586
466073
  accountId: account.accountId
466587
- })) : [];
466588
- const toolScopes = routed && policy?.automaticRelay === true ? [] : routed && policy?.automaticRelay === false ? channelScopes : channelScopes.filter(({ channelId, accountId }) => !accountId || getChannelAccount(channelId, accountId)?.replyMode !== "relay");
466589
- const routedDestinations = new Set(sources.map(sourceRouteKey));
466590
- const exposedScopes = routed && routedDestinations.size > 1 ? channelScopes : toolScopes;
466591
- if (exposedScopes.length === 0)
466074
+ })) : []).filter(({ channelId, accountId }) => {
466075
+ const key3 = `${channelId}:${accountId ?? ""}`;
466076
+ if (seen.has(key3))
466077
+ return false;
466078
+ seen.add(key3);
466079
+ return true;
466080
+ });
466081
+ if (channelScopes.length === 0)
466592
466082
  return null;
466593
- const resolvedChannels = await resolveLocalMessageChannelToolChannels({
466594
- channels: exposedScopes
466595
- });
466596
- const tool = await buildMessageChannelExternalToolDefinition({
466597
- channels: routed && policy?.automaticRelay === false ? resolvedChannels.map((channel) => ({
466598
- ...channel,
466599
- replyMode: "tool"
466600
- })) : resolvedChannels,
466601
- scoped: routed,
466083
+ return buildMessageChannelExternalToolDefinition({
466084
+ channels: await resolveLocalMessageChannelToolChannels({
466085
+ channels: channelScopes
466086
+ }),
466087
+ scoped: sources.length > 0,
466602
466088
  allowProactiveTargets: true
466603
466089
  });
466604
- const accountIds = [
466605
- ...new Set(exposedScopes.map(({ accountId }) => accountId?.trim()).filter((accountId) => Boolean(accountId)))
466606
- ];
466607
- if (routed && accountIds.length > 1) {
466608
- tool.description += `
466609
-
466610
- Currently routed accounts: ${accountIds.join(", ")}.`;
466611
- }
466612
- return tool;
466613
466090
  }
466614
466091
  var init_message_channel_gateway_tool = __esm(() => {
466615
- init_accounts();
466616
466092
  init_message_channel_tool_definition();
466617
466093
  init_message_tool();
466618
466094
  init_proactive_accounts();
@@ -466717,7 +466193,6 @@ function mapChannelConfig(snapshot2) {
466717
466193
  display_name: snapshot2.displayName,
466718
466194
  enabled: snapshot2.enabled,
466719
466195
  dm_policy: snapshot2.dmPolicy,
466720
- reply_mode: snapshot2.replyMode ?? "tool",
466721
466196
  allowed_users: snapshot2.allowedUsers,
466722
466197
  config: snapshot2.config ?? {}
466723
466198
  };
@@ -466731,7 +466206,6 @@ function mapChannelAccount(snapshot2) {
466731
466206
  configured: snapshot2.configured,
466732
466207
  running: snapshot2.running,
466733
466208
  dm_policy: snapshot2.dmPolicy,
466734
- reply_mode: snapshot2.replyMode ?? "tool",
466735
466209
  allowed_users: snapshot2.allowedUsers,
466736
466210
  config: snapshot2.config ?? {},
466737
466211
  created_at: snapshot2.createdAt,
@@ -466856,7 +466330,6 @@ async function handleAccountConfigLifecycleCommand(parsed, socket, runDetachedLi
466856
466330
  displayName: "display_name" in parsed.account ? parsed.account.display_name : undefined,
466857
466331
  enabled: "enabled" in parsed.account ? parsed.account.enabled : undefined,
466858
466332
  dmPolicy: parsed.account.dm_policy,
466859
- replyMode: parsed.account.reply_mode,
466860
466333
  allowedUsers: parsed.account.allowed_users,
466861
466334
  config: pluginConfig
466862
466335
  }, {
@@ -466897,7 +466370,6 @@ async function handleAccountConfigLifecycleCommand(parsed, socket, runDetachedLi
466897
466370
  displayName: "display_name" in parsed.patch ? parsed.patch.display_name : undefined,
466898
466371
  enabled: "enabled" in parsed.patch ? parsed.patch.enabled : undefined,
466899
466372
  dmPolicy: parsed.patch.dm_policy,
466900
- replyMode: parsed.patch.reply_mode,
466901
466373
  allowedUsers: parsed.patch.allowed_users,
466902
466374
  config: pluginConfig
466903
466375
  };
@@ -467098,7 +466570,6 @@ async function handleAccountConfigLifecycleCommand(parsed, socket, runDetachedLi
467098
466570
  const pluginConfig = getChannelPluginConfig(parsed.config, "plugin_config") ?? {};
467099
466571
  const snapshot2 = await setChannelConfigLive2(parsed.channel_id, {
467100
466572
  dmPolicy: parsed.config.dm_policy,
467101
- replyMode: parsed.config.reply_mode,
467102
466573
  allowedUsers: parsed.config.allowed_users,
467103
466574
  config: pluginConfig
467104
466575
  }, parsed.account_id);
@@ -467435,9 +466906,7 @@ function groupSourcesByRuntime(sources) {
467435
466906
  function toolScopeKey(sources, runtime) {
467436
466907
  if (sources.length === 0)
467437
466908
  return `proactive:${runtime.agent_id}`;
467438
- const destinationClass = new Set(sources.map(sourceRouteKey)).size > 1 ? "multiple" : "single";
467439
466909
  return JSON.stringify([
467440
- destinationClass,
467441
466910
  ...new Set(sources.map((source) => `${source.channel}:${source.accountId ?? ""}`))
467442
466911
  ].sort());
467443
466912
  }
@@ -467748,76 +467217,6 @@ function isUpdateModelResponse(message) {
467748
467217
  function isExecuteCommandResponse(message) {
467749
467218
  return !!message && typeof message === "object" && message.type === "execute_command_response";
467750
467219
  }
467751
- async function deliverLocalAssistantText(options) {
467752
- const source = options.sources.length === 1 ? options.sources[0] : undefined;
467753
- if (!source?.accountId)
467754
- return;
467755
- try {
467756
- const result3 = await relayLocalMessageChannel({
467757
- channel: source.channel,
467758
- action: "send",
467759
- chat_id: source.chatId,
467760
- accountId: source.accountId,
467761
- message: options.text,
467762
- parentScope: {
467763
- agentId: source.agentId,
467764
- conversationId: source.conversationId
467765
- },
467766
- channelTurnSources: options.sources
467767
- }, options.idempotencyScope);
467768
- if (result3.startsWith("Error:"))
467769
- throw new Error(result3);
467770
- } catch (error5) {
467771
- if (error5 instanceof MessageChannelDuplicateActionError)
467772
- return;
467773
- throw error5;
467774
- }
467775
- }
467776
- function createLocalChannelGatewayHooks(registry4) {
467777
- return {
467778
- createRichDraft: ({ batchId, sources }) => {
467779
- const streamer = createChannelRichDraftStreamer({ batchId, sources });
467780
- return streamer ? {
467781
- handleDelta: (delta2) => {
467782
- streamer.handleChunk(delta2);
467783
- },
467784
- flushPending: () => streamer.flushPending(),
467785
- dispose: () => streamer.dispose()
467786
- } : null;
467787
- },
467788
- resolveAssistantRelayPolicy: (_runtime, sources) => {
467789
- const routedSources = uniqueRoutedSources(sources);
467790
- if (routedSources.length !== 1)
467791
- return false;
467792
- const source = routedSources[0];
467793
- if (!source?.accountId)
467794
- return false;
467795
- return getChannelAccount(source.channel, source.accountId)?.replyMode === "relay";
467796
- },
467797
- buildExternalTool: async (runtime, sources, policy) => {
467798
- return buildGatewayMessageChannelTool(sources, runtime, policy);
467799
- },
467800
- executeExternalTool: async (request2, sources, idempotencyScope) => {
467801
- if (request2.tool_name !== "MessageChannel" || !request2.runtime?.agent_id) {
467802
- throw new Error(`Unsupported gateway tool: ${request2.tool_name}`);
467803
- }
467804
- return await executeLocalMessageChannelExternalTool({
467805
- ...request2.input,
467806
- channel: String(request2.input.channel ?? ""),
467807
- action: String(request2.input.action ?? ""),
467808
- parentScope: {
467809
- agentId: request2.runtime.agent_id,
467810
- conversationId: request2.runtime.conversation_id
467811
- },
467812
- channelTurnSources: sources
467813
- }, idempotencyScope);
467814
- },
467815
- relayAssistantText: deliverLocalAssistantText,
467816
- onLifecycle: (event) => registry4.dispatchTurnLifecycleEvent(event),
467817
- onProgress: (event) => registry4.dispatchTurnProgressEvent(event),
467818
- onControlRequest: (event) => registry4.registerPendingControlRequest(event)
467819
- };
467820
- }
467821
467220
  async function startLocalChannelGateway(options) {
467822
467221
  await settingsManager.initialize();
467823
467222
  const client = createAppServerClient({
@@ -467855,7 +467254,39 @@ async function startLocalChannelGateway(options) {
467855
467254
  throw new Error("Channel registry did not initialize");
467856
467255
  }
467857
467256
  let gateway;
467858
- gateway = new ChannelGateway(client, createLocalChannelGatewayHooks(registry4));
467257
+ gateway = new ChannelGateway(client, {
467258
+ createRichDraft: ({ batchId, sources }) => {
467259
+ const streamer = createChannelRichDraftStreamer({ batchId, sources });
467260
+ return streamer ? {
467261
+ handleDelta: (delta2) => {
467262
+ streamer.handleChunk(delta2);
467263
+ },
467264
+ flushPending: () => streamer.flushPending(),
467265
+ dispose: () => streamer.dispose()
467266
+ } : null;
467267
+ },
467268
+ buildExternalTool: async (runtime, sources) => {
467269
+ return buildGatewayMessageChannelTool(sources, runtime);
467270
+ },
467271
+ executeExternalTool: async (request2, sources, idempotencyScope) => {
467272
+ if (request2.tool_name !== "MessageChannel" || !request2.runtime?.agent_id) {
467273
+ throw new Error(`Unsupported gateway tool: ${request2.tool_name}`);
467274
+ }
467275
+ return await executeLocalMessageChannelExternalTool({
467276
+ ...request2.input,
467277
+ channel: String(request2.input.channel ?? ""),
467278
+ action: String(request2.input.action ?? ""),
467279
+ parentScope: {
467280
+ agentId: request2.runtime.agent_id,
467281
+ conversationId: request2.runtime.conversation_id
467282
+ },
467283
+ channelTurnSources: sources
467284
+ }, idempotencyScope);
467285
+ },
467286
+ onLifecycle: (event) => registry4.dispatchTurnLifecycleEvent(event),
467287
+ onProgress: (event) => registry4.dispatchTurnProgressEvent(event),
467288
+ onControlRequest: (event) => registry4.registerPendingControlRequest(event)
467289
+ });
467859
467290
  const routedRuntimeRegistrationRefresher = createRoutedRuntimeRegistrationRefresher({
467860
467291
  registry: registry4,
467861
467292
  channelNames: options.channelNames,
@@ -468149,13 +467580,11 @@ var init_gateway_local = __esm(() => {
468149
467580
  init_app_server_client();
468150
467581
  init_settings_manager();
468151
467582
  init_message_channel();
468152
- init_accounts();
468153
467583
  init_channel_rich_draft_streamer();
468154
467584
  init_command_runtime_executor();
468155
467585
  init_commands();
468156
467586
  init_gateway_core();
468157
467587
  init_message_channel_gateway_tool();
468158
- init_message_channel_idempotency();
468159
467588
  init_plugin_registry();
468160
467589
  init_protocol_command_handler();
468161
467590
  init_registry();
@@ -522161,4 +521590,4 @@ function registerBunOAuthFlows() {
522161
521590
  registerBunOAuthFlows();
522162
521591
  await init_src5().then(() => exports_src2);
522163
521592
 
522164
- //# debugId=8ABF0F41F824320764756E2164756E21
521593
+ //# debugId=C2333FD748A08D4B64756E2164756E21