very-happy-cli 0.2.128 → 0.2.129

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 (45) hide show
  1. package/dist/{AcpBackend-D7987ody.mjs → AcpBackend-MAU4POiE.mjs} +16 -4
  2. package/dist/{AcpBackend-BYU6J2n0.cjs → AcpBackend-kU2VqiYx.cjs} +16 -4
  3. package/dist/{AcpSessionManager-artXJgqb.cjs → AcpSessionManager-BWasT5jq.cjs} +1 -1
  4. package/dist/{AcpSessionManager-BwrjVZyn.mjs → AcpSessionManager-uSGDDRqF.mjs} +1 -1
  5. package/dist/{agentGuidance-B1xYgHx6.cjs → agentGuidance-B1PsijGg.cjs} +1 -1
  6. package/dist/{agentGuidance-BPGPaNlo.mjs → agentGuidance-DlZ5s0Om.mjs} +1 -1
  7. package/dist/codex/happyMcpStdioBridge.cjs +2 -2
  8. package/dist/codex/happyMcpStdioBridge.mjs +2 -2
  9. package/dist/{config-Dmkzs3o4.cjs → config-DswZvA8V.cjs} +4 -4
  10. package/dist/{config-DSBE0Az0.mjs → config-_DKtp9qs.mjs} +4 -4
  11. package/dist/{index-35FahgEU.mjs → index-1QwKRLYG.mjs} +4 -4
  12. package/dist/{index-D_YVlpsW.cjs → index-BdZ7Dlg0.cjs} +184 -86
  13. package/dist/{index-m0Dnccc_.mjs → index-FMMrmSa2.mjs} +115 -32
  14. package/dist/{index-vyTJsT_R.cjs → index-dqKLs4dZ.cjs} +114 -31
  15. package/dist/{index-CJmXLSQc.cjs → index-lwOIU7K9.cjs} +4 -4
  16. package/dist/{index-CfM6ewd8.mjs → index-tr2Fqhby.mjs} +177 -83
  17. package/dist/index.cjs +4 -4
  18. package/dist/index.mjs +4 -4
  19. package/dist/{installTerminalHooks-ClrFe2fA.mjs → installTerminalHooks-B3a0ugvz.mjs} +4 -4
  20. package/dist/{installTerminalHooks-C1zwiJJ2.cjs → installTerminalHooks-CV2LAKXO.cjs} +4 -4
  21. package/dist/lib.cjs +2 -2
  22. package/dist/lib.d.cts +5 -0
  23. package/dist/lib.d.mts +5 -0
  24. package/dist/lib.mjs +2 -2
  25. package/dist/{limits-CrwtFbi8.cjs → limits-B5wJ5Slz.cjs} +7 -7
  26. package/dist/{limits-BNTLh2lw.mjs → limits-C41sn_OJ.mjs} +7 -7
  27. package/dist/{mcp-Bc_mmJt8.cjs → mcp-B7lwVQT8.cjs} +4 -4
  28. package/dist/{mcp-BsohER5A.mjs → mcp-BHNVwrwS.mjs} +4 -4
  29. package/dist/{runGemini-B9S85Vms.mjs → runGemini-FNZrH8yX.mjs} +6 -6
  30. package/dist/{runGemini-B2GesRWm.cjs → runGemini-gbflWQ3_.cjs} +6 -6
  31. package/dist/{runOpenClaw-Byhq-B1y.mjs → runOpenClaw-3EF_Rqv_.mjs} +5 -5
  32. package/dist/{runOpenClaw-DCK-R8qe.cjs → runOpenClaw-CmhYI7OB.cjs} +5 -5
  33. package/dist/{send-DQS1zNWp.mjs → send-DV7IeBAv.mjs} +4 -4
  34. package/dist/{send-CPdT1nOg.cjs → send-DqedYZtc.cjs} +4 -4
  35. package/dist/{sessions-DC0IKaD9.cjs → sessions-Bz243hZ9.cjs} +4 -4
  36. package/dist/{sessions-DIOdWnPe.mjs → sessions-ieB0bLb5.mjs} +4 -4
  37. package/dist/{spawn-DrnCW2QK.cjs → spawn-BXwwueEs.cjs} +4 -4
  38. package/dist/{spawn-DV4pIAHZ.mjs → spawn-CcqzmjhT.mjs} +4 -4
  39. package/dist/{teams-CwXEJs9I.cjs → teams-BtI6h4Dw.cjs} +4 -4
  40. package/dist/{teams-DlTHOiCk.mjs → teams-Bx79Wr9-.mjs} +4 -4
  41. package/dist/{todo-DrME15xq.cjs → todo-B-Kj9lXl.cjs} +3 -3
  42. package/dist/{todo-BwXURAbQ.mjs → todo-CGRuBaiH.mjs} +3 -3
  43. package/dist/{types-DfatCoQL.cjs → types-Ba9u0uZL.cjs} +19 -5
  44. package/dist/{types-CFs8FmiY.mjs → types-BvYEAHds.mjs} +19 -5
  45. package/package.json +7 -7
@@ -1,12 +1,12 @@
1
- import { D as DefaultTransport, A as AcpBackend } from './AcpBackend-D7987ody.mjs';
2
- export { a as DEFAULT_IDLE_TIMEOUT_MS, b as DEFAULT_TOOL_CALL_TIMEOUT_MS, e as extractErrorDetail, f as formatDuration, c as formatDurationMinutes, h as handleAgentMessageChunk, d as handleAgentThoughtChunk, g as handleLegacyMessageChunk, i as handlePlanUpdate, j as handleThinkingUpdate, k as handleToolCall, l as handleToolCallUpdate, p as parseArgsFromContent } from './AcpBackend-D7987ody.mjs';
3
- import { c as configuration, g as readSettings, i as encodeBase64, l as logger } from './limits-BNTLh2lw.mjs';
4
- import { A as AcpSessionManager } from './AcpSessionManager-BwrjVZyn.mjs';
5
- import { g as connectionState, A as ApiClient, p as projectPath, h as BUILTIN_TODO_DISCOVERY } from './types-CFs8FmiY.mjs';
1
+ import { D as DefaultTransport, A as AcpBackend } from './AcpBackend-MAU4POiE.mjs';
2
+ export { a as DEFAULT_IDLE_TIMEOUT_MS, b as DEFAULT_TOOL_CALL_TIMEOUT_MS, e as extractErrorDetail, f as formatDuration, c as formatDurationMinutes, h as handleAgentMessageChunk, d as handleAgentThoughtChunk, g as handleLegacyMessageChunk, i as handlePlanUpdate, j as handleThinkingUpdate, k as handleToolCall, l as handleToolCallUpdate, p as parseArgsFromContent } from './AcpBackend-MAU4POiE.mjs';
3
+ import { c as configuration, g as readSettings, i as encodeBase64, l as logger } from './limits-C41sn_OJ.mjs';
4
+ import { A as AcpSessionManager } from './AcpSessionManager-uSGDDRqF.mjs';
5
+ import { f as connectionState, A as ApiClient, p as projectPath, g as BUILTIN_TODO_DISCOVERY } from './types-BvYEAHds.mjs';
6
+ import { P as PI_TEAMS_EXTENSION, n as initialMachineMetadata, o as createSessionMetadata, u as setupOfflineReconnection, v as notifyDaemonSessionStarted, z as StreamRelay, x as MessageQueue2, B as hashObject, C as startHappyServer, E as registerAgentAttachmentDownloads, F as TitleGenerator, y as registerKillSessionHandler, H as CLAUDE_ATTACHMENT_KINDS, I as stageClaudeAttachments, J as appendStagedAttachmentsToPrompt, K as BasePermissionHandler, L as writeSessionModeFile, N as normalizeAcpPermissionMode, O as removeSessionModeFile } from './index-tr2Fqhby.mjs';
6
7
  import { mkdir, chmod, writeFile, rename } from 'node:fs/promises';
7
8
  import { randomUUID } from 'node:crypto';
8
9
  import { join } from 'node:path';
9
- import { P as PI_TEAMS_EXTENSION, n as initialMachineMetadata, o as createSessionMetadata, u as setupOfflineReconnection, v as notifyDaemonSessionStarted, z as StreamRelay, x as MessageQueue2, B as hashObject, C as startHappyServer, E as TitleGenerator, y as registerKillSessionHandler, F as BasePermissionHandler, H as writeSessionModeFile, I as normalizeAcpPermissionMode, J as removeSessionModeFile } from './index-CfM6ewd8.mjs';
10
10
  import 'node:child_process';
11
11
  import '@agentclientprotocol/sdk';
12
12
  import 'node:fs';
@@ -32,7 +32,7 @@ import 'fs';
32
32
  import 'node:readline';
33
33
  import '@anthropic-ai/sandbox-runtime';
34
34
  import 'expo-server-sdk';
35
- import './agentGuidance-BPGPaNlo.mjs';
35
+ import './agentGuidance-DlZ5s0Om.mjs';
36
36
  import 'ink';
37
37
  import 'react';
38
38
  import '@anthropic-ai/claude-agent-sdk';
@@ -518,6 +518,7 @@ function extractConfigSelector(configOptions, category) {
518
518
  }
519
519
  const id = normalizeComparable(option.id);
520
520
  const name = normalizeComparable(option.name);
521
+ if (category === "thought_level") return id.includes("thinking") || id.includes("thought") || name.includes("thinking");
521
522
  if (category === "model") {
522
523
  return id.includes("model") || name.includes("model");
523
524
  }
@@ -632,6 +633,7 @@ async function runAcp(opts) {
632
633
  startedBy: opts.startedBy,
633
634
  sandbox: settings.sandboxConfig
634
635
  });
636
+ metadata.attachmentKinds = [];
635
637
  const response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
636
638
  if (response) {
637
639
  logAcp("muted", `Happy Session ID: ${response.id}`);
@@ -677,6 +679,8 @@ async function runAcp(opts) {
677
679
  let currentModel;
678
680
  let modeSelector = null;
679
681
  let modelSelector = null;
682
+ let thoughtSelector = null;
683
+ let currentEffort;
680
684
  let legacyModes = null;
681
685
  let legacyModels = null;
682
686
  let sawSlashCommands = false;
@@ -824,35 +828,78 @@ async function runAcp(opts) {
824
828
  };
825
829
  }
826
830
  };
831
+ const switchEffortIfRequested = async (requested, modelChanged) => {
832
+ const discardStaleEffort = () => {
833
+ if (currentEffort === requested) currentEffort = null;
834
+ session.sendSessionEvent({ type: "message", message: `The new model does not support thinking level "${requested}"; using its current thinking level.` });
835
+ };
836
+ if (thoughtSelector) {
837
+ const resolved = thoughtSelector.options.find((option) => option.code === requested)?.code;
838
+ if (!resolved) {
839
+ if (modelChanged) {
840
+ discardStaleEffort();
841
+ return;
842
+ }
843
+ throw new Error(`Unsupported thinking level: ${requested}`);
844
+ }
845
+ if (resolved === thoughtSelector.currentCode) return;
846
+ if (!await backend.setSessionConfigOption(thoughtSelector.configId, resolved)) {
847
+ throw new Error(`Failed to switch thinking level to ${resolved}`);
848
+ }
849
+ thoughtSelector.currentCode = resolved;
850
+ session.updateMetadata((metadata2) => ({ ...metadata2, currentThoughtLevelCode: resolved }));
851
+ return;
852
+ }
853
+ if (permissionModeIsFileBacked() && legacyModes) {
854
+ const resolved = legacyModes.availableModes.find((mode) => mode.id === requested)?.id;
855
+ if (!resolved) {
856
+ if (modelChanged) {
857
+ discardStaleEffort();
858
+ return;
859
+ }
860
+ throw new Error(`Unsupported thinking level: ${requested}`);
861
+ }
862
+ if (resolved === legacyModes.currentModeId) return;
863
+ if (!await backend.setSessionMode(resolved)) throw new Error(`Failed to switch thinking level to ${resolved}`);
864
+ legacyModes = { ...legacyModes, currentModeId: resolved };
865
+ session.updateMetadata((metadata2) => ({ ...metadata2, currentOperatingModeCode: resolved, currentThoughtLevelCode: resolved }));
866
+ return;
867
+ }
868
+ if (modelChanged) {
869
+ discardStaleEffort();
870
+ return;
871
+ }
872
+ throw new Error(`This agent does not advertise thinking levels`);
873
+ };
827
874
  const switchModelIfRequested = async (requestedModel) => {
828
875
  if (!requestedModel) {
829
- return;
876
+ return false;
830
877
  }
831
878
  if (modelSelector) {
832
879
  const resolved = resolveRequestedCode(modelSelector.options, requestedModel);
833
880
  if (!resolved) {
834
881
  logger.debug(`[${opts.agentName}] Ignoring unknown ACP model request: ${requestedModel}`);
835
- return;
882
+ return false;
836
883
  }
837
884
  if (resolved === modelSelector.currentCode) {
838
- return;
885
+ return false;
839
886
  }
840
887
  const switched2 = await backend.setSessionConfigOption(modelSelector.configId, resolved);
841
888
  if (switched2) {
842
889
  modelSelector.currentCode = resolved;
843
- return;
890
+ return true;
844
891
  }
845
892
  }
846
893
  if (!legacyModels) {
847
- return;
894
+ return false;
848
895
  }
849
896
  const resolvedLegacyModel = resolveRequestedLegacyModelCode(legacyModels, requestedModel);
850
897
  if (!resolvedLegacyModel) {
851
898
  logger.debug(`[${opts.agentName}] Ignoring unknown ACP legacy model request: ${requestedModel}`);
852
- return;
899
+ return false;
853
900
  }
854
901
  if (resolvedLegacyModel === legacyModels.currentModelId) {
855
- return;
902
+ return false;
856
903
  }
857
904
  const switched = await backend.setSessionModel(resolvedLegacyModel);
858
905
  if (switched) {
@@ -860,7 +907,13 @@ async function runAcp(opts) {
860
907
  ...legacyModels,
861
908
  currentModelId: resolvedLegacyModel
862
909
  };
910
+ return true;
863
911
  }
912
+ return false;
913
+ };
914
+ const isCurrentRequestedModel = (requested) => {
915
+ if (modelSelector) return resolveRequestedCode(modelSelector.options, requested) === modelSelector.currentCode;
916
+ return !!legacyModels && resolveRequestedLegacyModelCode(legacyModels, requested) === legacyModels.currentModelId;
864
917
  };
865
918
  const onBackendMessage = (msg) => {
866
919
  if (verbose) {
@@ -897,6 +950,7 @@ async function runAcp(opts) {
897
950
  }
898
951
  modeSelector = extractConfigSelector(configOptions, "mode");
899
952
  modelSelector = extractConfigSelector(configOptions, "model");
953
+ thoughtSelector = extractConfigSelector(configOptions, "thought_level");
900
954
  if (verbose) {
901
955
  if (modeSelector) {
902
956
  sawModes = true;
@@ -997,22 +1051,35 @@ async function runAcp(opts) {
997
1051
  };
998
1052
  backend.onMessage(onBackendMessage);
999
1053
  const titleGenerator = new TitleGenerator(session);
1054
+ registerAgentAttachmentDownloads(session);
1055
+ let userMessageDelivery = Promise.resolve();
1000
1056
  session.onUserMessage((message) => {
1001
- if (!message.content.text) {
1002
- return;
1003
- }
1004
- titleGenerator.maybeGenerate(message.content.text);
1005
- if (typeof message.meta?.permissionMode === "string") {
1006
- currentPermissionMode = message.meta.permissionMode;
1007
- logger.debug(`[${opts.agentName}] Requested ACP permission mode: ${currentPermissionMode}`);
1008
- }
1009
- if (message.meta && Object.prototype.hasOwnProperty.call(message.meta, "model")) {
1010
- currentModel = message.meta.model ?? null;
1011
- logger.debug(`[${opts.agentName}] Requested ACP model: ${currentModel ?? "null"}`);
1012
- }
1013
- messageQueue.push(message.content.text, {
1014
- permissionMode: currentPermissionMode,
1015
- model: currentModel
1057
+ const downloads = session.drainAttachmentsForUserMessage();
1058
+ userMessageDelivery = userMessageDelivery.then(async () => {
1059
+ const attachments = await downloads;
1060
+ if (!message.content.text && !attachments?.length) {
1061
+ return;
1062
+ }
1063
+ titleGenerator.maybeGenerate(message.content.text);
1064
+ if (typeof message.meta?.permissionMode === "string") {
1065
+ currentPermissionMode = message.meta.permissionMode;
1066
+ logger.debug(`[${opts.agentName}] Requested ACP permission mode: ${currentPermissionMode}`);
1067
+ }
1068
+ if (message.meta && Object.prototype.hasOwnProperty.call(message.meta, "model")) {
1069
+ currentModel = message.meta.model ?? null;
1070
+ logger.debug(`[${opts.agentName}] Requested ACP model: ${currentModel ?? "null"}`);
1071
+ }
1072
+ if (message.meta && Object.prototype.hasOwnProperty.call(message.meta, "effort")) {
1073
+ currentEffort = message.meta.effort ?? null;
1074
+ }
1075
+ messageQueue.push(message.content.text, {
1076
+ permissionMode: currentPermissionMode,
1077
+ model: currentModel,
1078
+ effort: currentEffort
1079
+ }, attachments, message.localKey);
1080
+ }).catch(() => {
1081
+ logger.warn("[ACP] Failed to prepare user attachments");
1082
+ session.sendSessionEvent({ type: "message", message: "Could not prepare this message. Please send it again." });
1016
1083
  });
1017
1084
  });
1018
1085
  session.keepAlive(thinking, "remote");
@@ -1058,6 +1125,15 @@ async function runAcp(opts) {
1058
1125
  try {
1059
1126
  const started = await backend.startSession();
1060
1127
  acpSessionId = started.sessionId;
1128
+ if (opts.model) {
1129
+ await switchModelIfRequested(opts.model);
1130
+ const applied = isCurrentRequestedModel(opts.model);
1131
+ if (!applied) session.sendSessionEvent({ type: "message", message: "The saved model is unavailable for this agent; using its current model." });
1132
+ }
1133
+ session.updateMetadata((current) => ({
1134
+ ...current,
1135
+ attachmentKinds: opts.agentName === "pi" && backend.supportsImageAttachments ? [...CLAUDE_ATTACHMENT_KINDS] : []
1136
+ }));
1061
1137
  if (permissionModeIsFileBacked()) {
1062
1138
  fileBackedModeActive = true;
1063
1139
  publishFileBackedPermissionMode(initialPermissionMode);
@@ -1097,13 +1173,19 @@ async function runAcp(opts) {
1097
1173
  if (typeof batch.mode.permissionMode === "string" && batch.mode.permissionMode.length > 0) {
1098
1174
  await switchPermissionModeIfRequested(batch.mode.permissionMode);
1099
1175
  }
1100
- if (typeof batch.mode.model === "string" && batch.mode.model.length > 0) {
1101
- await switchModelIfRequested(batch.mode.model);
1176
+ const modelChanged = typeof batch.mode.model === "string" && batch.mode.model.length > 0 ? await switchModelIfRequested(batch.mode.model) : false;
1177
+ if (typeof batch.mode.effort === "string") {
1178
+ await switchEffortIfRequested(batch.mode.effort, modelChanged);
1102
1179
  }
1103
1180
  const prompt = todoDiscoverySent ? batch.message : `${batch.message}
1104
1181
 
1105
1182
  ${BUILTIN_TODO_DISCOVERY}`;
1106
- await backend.sendPrompt(acpSessionId, prompt);
1183
+ const attachments = batch.attachments ?? [];
1184
+ const staged = attachments.length ? await stageClaudeAttachments(attachments, {
1185
+ happyHomeDir: configuration.happyHomeDir,
1186
+ sessionId: session.sessionId
1187
+ }) : [];
1188
+ await backend.sendPrompt(acpSessionId, appendStagedAttachmentsToPrompt(prompt, staged), attachments);
1107
1189
  todoDiscoverySent = true;
1108
1190
  await turnEnded;
1109
1191
  sendEnvelopes(sessionManager.endTurn("completed"));
@@ -1114,6 +1196,7 @@ ${BUILTIN_TODO_DISCOVERY}`;
1114
1196
  logAcp("muted", `Outgoing prompt completion from ${opts.agentName}`);
1115
1197
  }
1116
1198
  } catch (error) {
1199
+ session.sendSessionEvent({ type: "message", message: "The agent could not process this message or its attachments. Please check the agent and try again." });
1117
1200
  sendEnvelopes(sessionManager.endTurn("failed"));
1118
1201
  streamRelay.endTurn();
1119
1202
  setThinking(false);
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var AcpBackend = require('./AcpBackend-BYU6J2n0.cjs');
4
- var persistence = require('./limits-CrwtFbi8.cjs');
5
- var AcpSessionManager = require('./AcpSessionManager-artXJgqb.cjs');
6
- var api = require('./types-DfatCoQL.cjs');
3
+ var AcpBackend = require('./AcpBackend-kU2VqiYx.cjs');
4
+ var persistence = require('./limits-B5wJ5Slz.cjs');
5
+ var AcpSessionManager = require('./AcpSessionManager-BWasT5jq.cjs');
6
+ var api = require('./types-Ba9u0uZL.cjs');
7
+ var index = require('./index-BdZ7Dlg0.cjs');
7
8
  var promises = require('node:fs/promises');
8
9
  var node_crypto = require('node:crypto');
9
10
  var path = require('node:path');
10
- var index = require('./index-D_YVlpsW.cjs');
11
11
  require('node:child_process');
12
12
  require('@agentclientprotocol/sdk');
13
13
  require('node:fs');
@@ -33,7 +33,7 @@ require('fs');
33
33
  require('node:readline');
34
34
  require('@anthropic-ai/sandbox-runtime');
35
35
  require('expo-server-sdk');
36
- require('./agentGuidance-B1xYgHx6.cjs');
36
+ require('./agentGuidance-B1PsijGg.cjs');
37
37
  require('ink');
38
38
  require('react');
39
39
  require('@anthropic-ai/claude-agent-sdk');
@@ -519,6 +519,7 @@ function extractConfigSelector(configOptions, category) {
519
519
  }
520
520
  const id = normalizeComparable(option.id);
521
521
  const name = normalizeComparable(option.name);
522
+ if (category === "thought_level") return id.includes("thinking") || id.includes("thought") || name.includes("thinking");
522
523
  if (category === "model") {
523
524
  return id.includes("model") || name.includes("model");
524
525
  }
@@ -633,6 +634,7 @@ async function runAcp(opts) {
633
634
  startedBy: opts.startedBy,
634
635
  sandbox: settings.sandboxConfig
635
636
  });
637
+ metadata.attachmentKinds = [];
636
638
  const response = await api$1.getOrCreateSession({ tag: sessionTag, metadata, state });
637
639
  if (response) {
638
640
  logAcp("muted", `Happy Session ID: ${response.id}`);
@@ -678,6 +680,8 @@ async function runAcp(opts) {
678
680
  let currentModel;
679
681
  let modeSelector = null;
680
682
  let modelSelector = null;
683
+ let thoughtSelector = null;
684
+ let currentEffort;
681
685
  let legacyModes = null;
682
686
  let legacyModels = null;
683
687
  let sawSlashCommands = false;
@@ -825,35 +829,78 @@ async function runAcp(opts) {
825
829
  };
826
830
  }
827
831
  };
832
+ const switchEffortIfRequested = async (requested, modelChanged) => {
833
+ const discardStaleEffort = () => {
834
+ if (currentEffort === requested) currentEffort = null;
835
+ session.sendSessionEvent({ type: "message", message: `The new model does not support thinking level "${requested}"; using its current thinking level.` });
836
+ };
837
+ if (thoughtSelector) {
838
+ const resolved = thoughtSelector.options.find((option) => option.code === requested)?.code;
839
+ if (!resolved) {
840
+ if (modelChanged) {
841
+ discardStaleEffort();
842
+ return;
843
+ }
844
+ throw new Error(`Unsupported thinking level: ${requested}`);
845
+ }
846
+ if (resolved === thoughtSelector.currentCode) return;
847
+ if (!await backend.setSessionConfigOption(thoughtSelector.configId, resolved)) {
848
+ throw new Error(`Failed to switch thinking level to ${resolved}`);
849
+ }
850
+ thoughtSelector.currentCode = resolved;
851
+ session.updateMetadata((metadata2) => ({ ...metadata2, currentThoughtLevelCode: resolved }));
852
+ return;
853
+ }
854
+ if (permissionModeIsFileBacked() && legacyModes) {
855
+ const resolved = legacyModes.availableModes.find((mode) => mode.id === requested)?.id;
856
+ if (!resolved) {
857
+ if (modelChanged) {
858
+ discardStaleEffort();
859
+ return;
860
+ }
861
+ throw new Error(`Unsupported thinking level: ${requested}`);
862
+ }
863
+ if (resolved === legacyModes.currentModeId) return;
864
+ if (!await backend.setSessionMode(resolved)) throw new Error(`Failed to switch thinking level to ${resolved}`);
865
+ legacyModes = { ...legacyModes, currentModeId: resolved };
866
+ session.updateMetadata((metadata2) => ({ ...metadata2, currentOperatingModeCode: resolved, currentThoughtLevelCode: resolved }));
867
+ return;
868
+ }
869
+ if (modelChanged) {
870
+ discardStaleEffort();
871
+ return;
872
+ }
873
+ throw new Error(`This agent does not advertise thinking levels`);
874
+ };
828
875
  const switchModelIfRequested = async (requestedModel) => {
829
876
  if (!requestedModel) {
830
- return;
877
+ return false;
831
878
  }
832
879
  if (modelSelector) {
833
880
  const resolved = resolveRequestedCode(modelSelector.options, requestedModel);
834
881
  if (!resolved) {
835
882
  persistence.logger.debug(`[${opts.agentName}] Ignoring unknown ACP model request: ${requestedModel}`);
836
- return;
883
+ return false;
837
884
  }
838
885
  if (resolved === modelSelector.currentCode) {
839
- return;
886
+ return false;
840
887
  }
841
888
  const switched2 = await backend.setSessionConfigOption(modelSelector.configId, resolved);
842
889
  if (switched2) {
843
890
  modelSelector.currentCode = resolved;
844
- return;
891
+ return true;
845
892
  }
846
893
  }
847
894
  if (!legacyModels) {
848
- return;
895
+ return false;
849
896
  }
850
897
  const resolvedLegacyModel = resolveRequestedLegacyModelCode(legacyModels, requestedModel);
851
898
  if (!resolvedLegacyModel) {
852
899
  persistence.logger.debug(`[${opts.agentName}] Ignoring unknown ACP legacy model request: ${requestedModel}`);
853
- return;
900
+ return false;
854
901
  }
855
902
  if (resolvedLegacyModel === legacyModels.currentModelId) {
856
- return;
903
+ return false;
857
904
  }
858
905
  const switched = await backend.setSessionModel(resolvedLegacyModel);
859
906
  if (switched) {
@@ -861,7 +908,13 @@ async function runAcp(opts) {
861
908
  ...legacyModels,
862
909
  currentModelId: resolvedLegacyModel
863
910
  };
911
+ return true;
864
912
  }
913
+ return false;
914
+ };
915
+ const isCurrentRequestedModel = (requested) => {
916
+ if (modelSelector) return resolveRequestedCode(modelSelector.options, requested) === modelSelector.currentCode;
917
+ return !!legacyModels && resolveRequestedLegacyModelCode(legacyModels, requested) === legacyModels.currentModelId;
865
918
  };
866
919
  const onBackendMessage = (msg) => {
867
920
  if (verbose) {
@@ -898,6 +951,7 @@ async function runAcp(opts) {
898
951
  }
899
952
  modeSelector = extractConfigSelector(configOptions, "mode");
900
953
  modelSelector = extractConfigSelector(configOptions, "model");
954
+ thoughtSelector = extractConfigSelector(configOptions, "thought_level");
901
955
  if (verbose) {
902
956
  if (modeSelector) {
903
957
  sawModes = true;
@@ -998,22 +1052,35 @@ async function runAcp(opts) {
998
1052
  };
999
1053
  backend.onMessage(onBackendMessage);
1000
1054
  const titleGenerator = new index.TitleGenerator(session);
1055
+ index.registerAgentAttachmentDownloads(session);
1056
+ let userMessageDelivery = Promise.resolve();
1001
1057
  session.onUserMessage((message) => {
1002
- if (!message.content.text) {
1003
- return;
1004
- }
1005
- titleGenerator.maybeGenerate(message.content.text);
1006
- if (typeof message.meta?.permissionMode === "string") {
1007
- currentPermissionMode = message.meta.permissionMode;
1008
- persistence.logger.debug(`[${opts.agentName}] Requested ACP permission mode: ${currentPermissionMode}`);
1009
- }
1010
- if (message.meta && Object.prototype.hasOwnProperty.call(message.meta, "model")) {
1011
- currentModel = message.meta.model ?? null;
1012
- persistence.logger.debug(`[${opts.agentName}] Requested ACP model: ${currentModel ?? "null"}`);
1013
- }
1014
- messageQueue.push(message.content.text, {
1015
- permissionMode: currentPermissionMode,
1016
- model: currentModel
1058
+ const downloads = session.drainAttachmentsForUserMessage();
1059
+ userMessageDelivery = userMessageDelivery.then(async () => {
1060
+ const attachments = await downloads;
1061
+ if (!message.content.text && !attachments?.length) {
1062
+ return;
1063
+ }
1064
+ titleGenerator.maybeGenerate(message.content.text);
1065
+ if (typeof message.meta?.permissionMode === "string") {
1066
+ currentPermissionMode = message.meta.permissionMode;
1067
+ persistence.logger.debug(`[${opts.agentName}] Requested ACP permission mode: ${currentPermissionMode}`);
1068
+ }
1069
+ if (message.meta && Object.prototype.hasOwnProperty.call(message.meta, "model")) {
1070
+ currentModel = message.meta.model ?? null;
1071
+ persistence.logger.debug(`[${opts.agentName}] Requested ACP model: ${currentModel ?? "null"}`);
1072
+ }
1073
+ if (message.meta && Object.prototype.hasOwnProperty.call(message.meta, "effort")) {
1074
+ currentEffort = message.meta.effort ?? null;
1075
+ }
1076
+ messageQueue.push(message.content.text, {
1077
+ permissionMode: currentPermissionMode,
1078
+ model: currentModel,
1079
+ effort: currentEffort
1080
+ }, attachments, message.localKey);
1081
+ }).catch(() => {
1082
+ persistence.logger.warn("[ACP] Failed to prepare user attachments");
1083
+ session.sendSessionEvent({ type: "message", message: "Could not prepare this message. Please send it again." });
1017
1084
  });
1018
1085
  });
1019
1086
  session.keepAlive(thinking, "remote");
@@ -1059,6 +1126,15 @@ async function runAcp(opts) {
1059
1126
  try {
1060
1127
  const started = await backend.startSession();
1061
1128
  acpSessionId = started.sessionId;
1129
+ if (opts.model) {
1130
+ await switchModelIfRequested(opts.model);
1131
+ const applied = isCurrentRequestedModel(opts.model);
1132
+ if (!applied) session.sendSessionEvent({ type: "message", message: "The saved model is unavailable for this agent; using its current model." });
1133
+ }
1134
+ session.updateMetadata((current) => ({
1135
+ ...current,
1136
+ attachmentKinds: opts.agentName === "pi" && backend.supportsImageAttachments ? [...index.CLAUDE_ATTACHMENT_KINDS] : []
1137
+ }));
1062
1138
  if (permissionModeIsFileBacked()) {
1063
1139
  fileBackedModeActive = true;
1064
1140
  publishFileBackedPermissionMode(initialPermissionMode);
@@ -1098,13 +1174,19 @@ async function runAcp(opts) {
1098
1174
  if (typeof batch.mode.permissionMode === "string" && batch.mode.permissionMode.length > 0) {
1099
1175
  await switchPermissionModeIfRequested(batch.mode.permissionMode);
1100
1176
  }
1101
- if (typeof batch.mode.model === "string" && batch.mode.model.length > 0) {
1102
- await switchModelIfRequested(batch.mode.model);
1177
+ const modelChanged = typeof batch.mode.model === "string" && batch.mode.model.length > 0 ? await switchModelIfRequested(batch.mode.model) : false;
1178
+ if (typeof batch.mode.effort === "string") {
1179
+ await switchEffortIfRequested(batch.mode.effort, modelChanged);
1103
1180
  }
1104
1181
  const prompt = todoDiscoverySent ? batch.message : `${batch.message}
1105
1182
 
1106
1183
  ${api.BUILTIN_TODO_DISCOVERY}`;
1107
- await backend.sendPrompt(acpSessionId, prompt);
1184
+ const attachments = batch.attachments ?? [];
1185
+ const staged = attachments.length ? await index.stageClaudeAttachments(attachments, {
1186
+ happyHomeDir: persistence.configuration.happyHomeDir,
1187
+ sessionId: session.sessionId
1188
+ }) : [];
1189
+ await backend.sendPrompt(acpSessionId, index.appendStagedAttachmentsToPrompt(prompt, staged), attachments);
1108
1190
  todoDiscoverySent = true;
1109
1191
  await turnEnded;
1110
1192
  sendEnvelopes(sessionManager.endTurn("completed"));
@@ -1115,6 +1197,7 @@ ${api.BUILTIN_TODO_DISCOVERY}`;
1115
1197
  logAcp("muted", `Outgoing prompt completion from ${opts.agentName}`);
1116
1198
  }
1117
1199
  } catch (error) {
1200
+ session.sendSessionEvent({ type: "message", message: "The agent could not process this message or its attachments. Please check the agent and try again." });
1118
1201
  sendEnvelopes(sessionManager.endTurn("failed"));
1119
1202
  streamRelay.endTurn();
1120
1203
  setThinking(false);
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-D_YVlpsW.cjs');
3
+ var index = require('./index-BdZ7Dlg0.cjs');
4
4
  var claudeAgentSdk = require('@anthropic-ai/claude-agent-sdk');
5
5
  require('chalk');
6
6
  require('node:os');
7
7
  require('node:crypto');
8
- require('./types-DfatCoQL.cjs');
8
+ require('./types-Ba9u0uZL.cjs');
9
9
  require('axios');
10
- require('./limits-CrwtFbi8.cjs');
10
+ require('./limits-B5wJ5Slz.cjs');
11
11
  require('node:fs/promises');
12
12
  require('node:fs');
13
13
  require('node:path');
@@ -31,7 +31,7 @@ require('fs');
31
31
  require('node:readline');
32
32
  require('@anthropic-ai/sandbox-runtime');
33
33
  require('expo-server-sdk');
34
- require('./agentGuidance-B1xYgHx6.cjs');
34
+ require('./agentGuidance-B1PsijGg.cjs');
35
35
  require('ink');
36
36
  require('react');
37
37
  require('ps-list');