nolo-cli 0.170.1 → 0.171.0-alpha.1

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 (100) hide show
  1. package/{_executeModel-7J6IIHWQ.js → _executeModel-YJW2HPFY.js} +29 -29
  2. package/{agentDeleteCommand-F66NIWCF.js → agentDeleteCommand-O3EG3HS4.js} +37 -37
  3. package/{agentEmailCommands-M4SHODDA.js → agentEmailCommands-AIWZNMRW.js} +41 -41
  4. package/{agentListCommands-4BBFWXHX.js → agentListCommands-377PQ6K4.js} +25 -25
  5. package/{agentMachineCommands-R55P5SZY.js → agentMachineCommands-TYL7KKSL.js} +21 -21
  6. package/{agentProviderCommands-4USYTCL3.js → agentProviderCommands-TWVILNAN.js} +2 -2
  7. package/{agentRecordCommands-PDWACZFR.js → agentRecordCommands-YPRND72K.js} +37 -37
  8. package/{agentRunCommand-U2F74LTS.js → agentRunCommand-T7AQKKH5.js} +38 -38
  9. package/{agentRunControl-EI3BGJFM.js → agentRunControl-SBHIICUQ.js} +5 -5
  10. package/{agentRuntimeLocal-7EZYBR6X.js → agentRuntimeLocal-7ZE2ZQAL.js} +19 -19
  11. package/{agentSlice-UN7ZHCAM.js → agentSlice-BHH2DZKN.js} +3 -3
  12. package/{appDeleteCommands-WS3UFMCB.js → appDeleteCommands-LHOX4HM3.js} +22 -22
  13. package/{appDeployCommands-W5B7I73P.js → appDeployCommands-A6CQQTI3.js} +22 -22
  14. package/{appDeployStatusCommands-UEHNV2GU.js → appDeployStatusCommands-7TTNQODL.js} +22 -22
  15. package/{appGetCommands-XJOBVREN.js → appGetCommands-22F4E37N.js} +22 -22
  16. package/{appListCommands-BISQV6BQ.js → appListCommands-WCDOJUVV.js} +22 -22
  17. package/{authCommand-H35CPF25.js → authCommand-BSOLJFPV.js} +12 -12
  18. package/{builtinSkillRegistry-LJV7FHNI.js → builtinSkillRegistry-V76JTNCJ.js} +2 -2
  19. package/{chunk-2AZSL4GL.js → chunk-22FIHMYU.js} +3 -3
  20. package/{chunk-SH3XD4E2.js → chunk-3LNVSFTH.js} +2 -1
  21. package/{chunk-SAZSXMTR.js → chunk-6OC2YMGH.js} +4 -4
  22. package/{chunk-2DXGW4UO.js → chunk-6OYC7NDH.js} +160 -37
  23. package/{chunk-7NKZA46B.js → chunk-72T5DXRH.js} +4 -4
  24. package/{chunk-3USFOET4.js → chunk-7CDMXZJA.js} +3 -3
  25. package/{chunk-DI7ZFGDQ.js → chunk-7L2HZQNN.js} +2 -2
  26. package/{chunk-XLBQQ5SB.js → chunk-7MBN2JZ5.js} +4 -4
  27. package/{chunk-FQU23S3P.js → chunk-AGAB26VE.js} +11 -11
  28. package/{chunk-G3VYRPTV.js → chunk-AJ52EA72.js} +4 -4
  29. package/{chunk-JPPQ3GUO.js → chunk-APB44JID.js} +3 -3
  30. package/{chunk-CEXJ6Y3C.js → chunk-AUGBRK3P.js} +2 -1
  31. package/{chunk-WC7UXON2.js → chunk-BJWOOJX5.js} +89 -36
  32. package/{chunk-URO44BCD.js → chunk-BQSW7453.js} +1 -1
  33. package/{chunk-Z6HR75HX.js → chunk-C2OYZYJ7.js} +3 -3
  34. package/{chunk-IMMA7QFE.js → chunk-CAAH5LNN.js} +2 -2
  35. package/{chunk-O2AY3CVI.js → chunk-CEYUVQYU.js} +16 -16
  36. package/{chunk-URW5UM6Y.js → chunk-CI5DVWU7.js} +1 -1
  37. package/{chunk-WVREKHHJ.js → chunk-DWQD3JTX.js} +3 -3
  38. package/{chunk-45IOFLGH.js → chunk-EPMWJ7X7.js} +11 -11
  39. package/{chunk-IOFLVIKF.js → chunk-EWLPIR2S.js} +1 -1
  40. package/{chunk-6EQD4AQL.js → chunk-GC64WGMD.js} +1 -1
  41. package/{chunk-FYYSDHVQ.js → chunk-HLAL63BZ.js} +1 -1
  42. package/{chunk-PIG2IUVZ.js → chunk-I2QHI2XM.js} +2 -2
  43. package/{chunk-BSKTDOGA.js → chunk-JHXY4H3P.js} +56 -56
  44. package/{chunk-7VWWGKEQ.js → chunk-K2NTGYVK.js} +3 -3
  45. package/{chunk-I7S63QUU.js → chunk-KNDA4K34.js} +1 -1
  46. package/{chunk-CMRP4XHV.js → chunk-MIME4XKU.js} +12 -12
  47. package/{chunk-HEC32F3G.js → chunk-O3FUFEUI.js} +1 -1
  48. package/{chunk-KJETBEEN.js → chunk-OPNHKULV.js} +1 -1
  49. package/{chunk-EWO77ZGF.js → chunk-OQ3DOBYB.js} +3 -3
  50. package/{chunk-WLPUUBFR.js → chunk-P4V35AFD.js} +3 -3
  51. package/{chunk-DHNQA4VI.js → chunk-Q7UPF643.js} +1 -1
  52. package/{chunk-TOUKACDK.js → chunk-RATR6VCP.js} +1 -1
  53. package/{chunk-XITIONPS.js → chunk-SC5TDLTP.js} +6 -6
  54. package/{chunk-LEZLJTQ4.js → chunk-SUBKVXFM.js} +1 -1
  55. package/{chunk-ZPKUJROL.js → chunk-TDNAAXUQ.js} +2 -2
  56. package/{chunk-SQX235S2.js → chunk-TSCI6X6C.js} +1 -1
  57. package/{chunk-V7PCFWX3.js → chunk-TVGX5QIN.js} +2 -2
  58. package/{chunk-XLQFVHNX.js → chunk-TYQZRSL6.js} +1 -1
  59. package/{chunk-46OQD3AP.js → chunk-UIVOLTFM.js} +4 -4
  60. package/{chunk-3ELX6JK5.js → chunk-UPC23AAN.js} +10 -10
  61. package/{chunk-MFVOJ6KF.js → chunk-W6E5IXIP.js} +3 -3
  62. package/{chunk-HZMWJUSD.js → chunk-WPOSH6PA.js} +2 -2
  63. package/{chunk-YCRROBDY.js → chunk-WXOKJP3W.js} +2 -1
  64. package/{chunk-CEQFVBI2.js → chunk-X2Q5GT5J.js} +3 -3
  65. package/{chunk-ASSNAASW.js → chunk-XHR22EKE.js} +5 -5
  66. package/{chunk-KMDDG73K.js → chunk-XWX5ZGWR.js} +1 -1
  67. package/{chunk-QW6SSF7V.js → chunk-ZJ66I757.js} +15 -15
  68. package/{commandRegistry-3XBG7JHS.js → commandRegistry-EAPXP4BC.js} +56 -56
  69. package/{contentThunks-OO3MJAED.js → contentThunks-SJAKJV4V.js} +11 -11
  70. package/{createAgentAutomationAction-F3O6FJ5W.js → createAgentAutomationAction-IBSAZBSP.js} +11 -11
  71. package/{createDialogAction-UBQKDUK5.js → createDialogAction-MQDTLASD.js} +13 -13
  72. package/{createPageAction-RDEDO4GF.js → createPageAction-EOPBBQMH.js} +11 -11
  73. package/{dialogCommands-P5HSDZ7T.js → dialogCommands-SV4M5HAV.js} +23 -23
  74. package/{dialogSlice-WZCWWYR3.js → dialogSlice-6CC3YDDL.js} +10 -10
  75. package/{docCreateCommands-B2M3MGX7.js → docCreateCommands-UC2CPMH7.js} +21 -21
  76. package/{docDeleteCommands-NHCUX4XL.js → docDeleteCommands-SRPTGMZ2.js} +22 -22
  77. package/{docReadCommands-FOLST4JD.js → docReadCommands-U3TDUPOY.js} +21 -21
  78. package/{docStore-PTSCGC6T.js → docStore-RSBDE3UH.js} +1 -1
  79. package/{docUpdateCommands-YZT2PQP2.js → docUpdateCommands-G5J5UKGP.js} +21 -21
  80. package/{getPricing-XQ3N3RBP.js → getPricing-2UPNNW3Y.js} +3 -3
  81. package/{handleSendMessageAction-3YMQS6XO.js → handleSendMessageAction-EM43KNSP.js} +23 -23
  82. package/index.js +4 -4
  83. package/{localRuntimeAdapter-ZIAOTUBE.js → localRuntimeAdapter-N5WDXYSY.js} +35 -35
  84. package/{machineCommands-3LSEP24P.js → machineCommands-L34XTTLG.js} +36 -36
  85. package/{machineWsRunDispatch-7A3TSH4Q.js → machineWsRunDispatch-IKI7FGKI.js} +36 -36
  86. package/{models-PZQC7VV4.js → models-UUNO6DOL.js} +2 -2
  87. package/package.json +1 -1
  88. package/{providerPresetApply-PKUOHQJT.js → providerPresetApply-5K4PBX4J.js} +6 -6
  89. package/{providerRegistry-HNQLIFN2.js → providerRegistry-K5MSZ3Y5.js} +6 -6
  90. package/{readlineWorkspace-OFBP6OA7.js → readlineWorkspace-ZANIHEDR.js} +44 -44
  91. package/{runAgentClientLoop-F6EQK26A.js → runAgentClientLoop-HPF2WFFQ.js} +27 -27
  92. package/{runtimeDoctorCommands-LYMJEM4F.js → runtimeDoctorCommands-DXJH5HIB.js} +6 -6
  93. package/{secretCommands-DNY56NSU.js → secretCommands-7S6REMJV.js} +2 -2
  94. package/{spaceCommands-XESXH5CW.js → spaceCommands-6KPBWGGE.js} +21 -21
  95. package/{streamAgentChatTurn-KXELVHFR.js → streamAgentChatTurn-3SNWCCK2.js} +33 -33
  96. package/{tools-FMNDEVTZ.js → tools-7SMCO2GW.js} +21 -21
  97. package/{tuiSummaryLlmCaller-FQOEF4IE.js → tuiSummaryLlmCaller-H6WX54WY.js} +8 -8
  98. package/{updateDialogTitleAction-65R3Y22L.js → updateDialogTitleAction-XIMLNROU.js} +11 -11
  99. package/{chunk-CGFNDIKK.js → chunk-5KTQVMCX.js} +0 -0
  100. package/{chunk-UHTDNB5Y.js → chunk-76YUTLOT.js} +3 -3
@@ -2,7 +2,7 @@ import {
2
2
  DEVIN_CONNECT_URL,
3
3
  parseSseDataLineJson,
4
4
  parseSseDataLineObject
5
- } from "./chunk-KMDDG73K.js";
5
+ } from "./chunk-XWX5ZGWR.js";
6
6
  import {
7
7
  applyChatCompletionDelta,
8
8
  applyResponsesToolEvent,
@@ -11,7 +11,7 @@ import {
11
11
  flushChatCompletionStream,
12
12
  providerHttpFailure,
13
13
  throwIfChatCompletionStreamFailed
14
- } from "./chunk-7NKZA46B.js";
14
+ } from "./chunk-72T5DXRH.js";
15
15
  import {
16
16
  readSseFrames
17
17
  } from "./chunk-HNUWUO75.js";
@@ -23,15 +23,16 @@ import {
23
23
  EXECUTION_BACKEND_KINDS
24
24
  } from "./chunk-PWTNI4N7.js";
25
25
  import {
26
+ IMAGE_OMITTED_PLACEHOLDER,
26
27
  hasImageInRuntimeMessages,
27
28
  stripImagePartsFromMessages
28
- } from "./chunk-CEXJ6Y3C.js";
29
+ } from "./chunk-AUGBRK3P.js";
29
30
  import {
30
31
  clipToolText,
31
32
  resolveAgentImageInputSupport,
32
33
  resolveHistoricalToolContentCap,
33
34
  resolveToolOutputProfile
34
- } from "./chunk-BSKTDOGA.js";
35
+ } from "./chunk-JHXY4H3P.js";
35
36
  import {
36
37
  applyShapingCounts,
37
38
  attachProjectionFacts,
@@ -66,7 +67,7 @@ import {
66
67
  hashStablePrefixContent,
67
68
  resolveResponseGuidelines,
68
69
  resolveToolGuidedSections
69
- } from "./chunk-TOUKACDK.js";
70
+ } from "./chunk-RATR6VCP.js";
70
71
  import {
71
72
  classifyUnparsableToolArgs,
72
73
  collectStablePromptPrefix,
@@ -90,7 +91,7 @@ import {
90
91
  toOpenAiCompatibleMessages,
91
92
  toResponsesTools,
92
93
  transferDowngradedToolTurnOrigin
93
- } from "./chunk-DI7ZFGDQ.js";
94
+ } from "./chunk-7L2HZQNN.js";
94
95
  import {
95
96
  BRIDGE_STREAM_MAX_CHARS,
96
97
  CLI_NOLO_WORKSPACE_TOOL_NAMES,
@@ -125,7 +126,7 @@ import {
125
126
  resolveEmptyAssistantFallbackMessage,
126
127
  resolveEmptyAssistantOutcome,
127
128
  resolveTruncatedReasoningTailLog
128
- } from "./chunk-HEC32F3G.js";
129
+ } from "./chunk-O3FUFEUI.js";
129
130
  import {
130
131
  COMPACTION_SUMMARY_SCHEMA_VERSION,
131
132
  COMPACTION_SUMMARY_SYSTEM_PROMPT,
@@ -148,7 +149,7 @@ import {
148
149
  sha256Hex,
149
150
  truncateToolOutputForContext,
150
151
  withProviderCallTimingFields
151
- } from "./chunk-ASSNAASW.js";
152
+ } from "./chunk-XHR22EKE.js";
152
153
  import {
153
154
  clipCompactText
154
155
  } from "./chunk-5MMAK75Q.js";
@@ -158,6 +159,9 @@ import {
158
159
  import {
159
160
  isAbortError
160
161
  } from "./chunk-7DPNBQSV.js";
162
+ import {
163
+ resolveNoloStateDir
164
+ } from "./chunk-ZWQUWF6W.js";
161
165
  import {
162
166
  buildDialogSummaryLayer
163
167
  } from "./chunk-VEA7H5FG.js";
@@ -187,7 +191,7 @@ import {
187
191
  import {
188
192
  buildProviderAuthHeaders,
189
193
  buildProviderExecutionPlan
190
- } from "./chunk-PIG2IUVZ.js";
194
+ } from "./chunk-I2QHI2XM.js";
191
195
  import {
192
196
  isRecord
193
197
  } from "./chunk-KUG52IAP.js";
@@ -206,9 +210,6 @@ import {
206
210
  import {
207
211
  asTrimmedLowercaseString
208
212
  } from "./chunk-QSJ3HFEF.js";
209
- import {
210
- resolveNoloStateDir
211
- } from "./chunk-ZWQUWF6W.js";
212
213
  import {
213
214
  __export
214
215
  } from "./chunk-4VNS5WPM.js";
@@ -12503,6 +12504,32 @@ function createLoopTiming() {
12503
12504
  return { mark, flush: flush2 };
12504
12505
  }
12505
12506
 
12507
+ // packages/agent-runtime/toolImages.ts
12508
+ import { createHash } from "node:crypto";
12509
+ var TOOL_IMAGES = Symbol("runtime-only-tool-images");
12510
+ function toolImages(message) {
12511
+ return message[TOOL_IMAGES] ?? [];
12512
+ }
12513
+ function withoutToolImages(message) {
12514
+ if (!(TOOL_IMAGES in message)) return message;
12515
+ const { [TOOL_IMAGES]: _images, ...textOnly } = message;
12516
+ return textOnly;
12517
+ }
12518
+ function createToolImageLedger() {
12519
+ const seen = /* @__PURE__ */ new Set();
12520
+ return (images) => (images ?? []).filter((image) => {
12521
+ const hash2 = createHash("sha256").update(Buffer.from(image.dataBase64, "base64")).digest("hex");
12522
+ if (seen.has(hash2)) return false;
12523
+ seen.add(hash2);
12524
+ return true;
12525
+ });
12526
+ }
12527
+ function omitToolImages(message, reason, placeholder = `[image omitted: ${reason}]`) {
12528
+ if (!toolImages(message).length) return message;
12529
+ return { ...withoutToolImages(message), content: `${message.content ?? ""}
12530
+ ${placeholder}` };
12531
+ }
12532
+
12506
12533
  // packages/agent-runtime/toolCallPairing.ts
12507
12534
  function readToolCallId(message) {
12508
12535
  if (typeof message.tool_call_id === "string" && message.tool_call_id) {
@@ -12605,7 +12632,7 @@ function sanitizeToolCallPairing(messages) {
12605
12632
  }
12606
12633
 
12607
12634
  // packages/agent-runtime/toolSpillStore.ts
12608
- import { createHash } from "node:crypto";
12635
+ import { createHash as createHash2 } from "node:crypto";
12609
12636
  import { existsSync, mkdirSync, readdirSync, renameSync, statSync, unlinkSync, utimesSync, writeFileSync } from "node:fs";
12610
12637
  import { isAbsolute, join as join2, relative } from "node:path";
12611
12638
  var DEFAULT_MAX_SPILL_DIR_BYTES = 50 * 1024 * 1024;
@@ -12697,7 +12724,7 @@ function spillToolOutput(options) {
12697
12724
  maxTotalBytes: options.maxRetentionBytes,
12698
12725
  throttleMs: SPILL_CLEANUP_THROTTLE_MS
12699
12726
  });
12700
- const hash2 = createHash("sha256").update(content).digest("hex").slice(0, 12);
12727
+ const hash2 = createHash2("sha256").update(content).digest("hex").slice(0, 12);
12701
12728
  const safeToolName = (options.toolName || "tool").replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 24);
12702
12729
  const fileName = `spill-${safeToolName}-${hash2}.log`;
12703
12730
  const spillPath = join2(spillDir, fileName);
@@ -13170,7 +13197,7 @@ function prepareHistoryForNextTurn(history, contextReferenceResolver) {
13170
13197
  function filterImagePartsFromMessages(messages, supportsImages) {
13171
13198
  if (supportsImages) return messages;
13172
13199
  return stripImagePartsFromMessages(messages).map(
13173
- (stripped, index) => transferDowngradedToolTurnOrigin(messages[index], stripped)
13200
+ (stripped, index) => omitToolImages(transferDowngradedToolTurnOrigin(messages[index], stripped), "model has no vision", IMAGE_OMITTED_PLACEHOLDER)
13174
13201
  );
13175
13202
  }
13176
13203
  var MODEL_PROJECTED_USER_PART_TYPES = /* @__PURE__ */ new Set(["attachment", "media_job"]);
@@ -13262,7 +13289,7 @@ ${args2.input}` : [
13262
13289
  }
13263
13290
 
13264
13291
  // packages/agent-runtime/toolArgsTruncationPolicy.ts
13265
- import { createHash as createHash2 } from "node:crypto";
13292
+ import { createHash as createHash3 } from "node:crypto";
13266
13293
  var TRUNCATION_TAIL_DROP_ALLOWED_TOOLS = /* @__PURE__ */ new Set([
13267
13294
  "ask_user"
13268
13295
  ]);
@@ -13293,7 +13320,7 @@ function buildToolArgsDiagnosticLine(args2) {
13293
13320
  const { toolName, raw, outcome, context: context3 } = args2;
13294
13321
  const env = args2.env ?? process.env;
13295
13322
  const scan2 = scanTruncation(raw);
13296
- const sha = createHash2("sha256").update(raw).digest("hex").slice(0, 12);
13323
+ const sha = createHash3("sha256").update(raw).digest("hex").slice(0, 12);
13297
13324
  const parts2 = [
13298
13325
  `[tool-args-diag] ${toolName} ${outcome}`,
13299
13326
  `len=${raw.length}`,
@@ -13896,7 +13923,7 @@ async function evaluateCapabilityPolicy(capability, normalizedInput, ctx) {
13896
13923
  }
13897
13924
 
13898
13925
  // packages/agent-runtime/capabilities/execShellCapability.ts
13899
- import { createHash as createHash3 } from "node:crypto";
13926
+ import { createHash as createHash4 } from "node:crypto";
13900
13927
 
13901
13928
  // packages/agent-runtime/execShellCompletionWarnings.ts
13902
13929
  var BG_ESCAPE_WORD_PATTERN = /(?:^|[\s;|(&/\\])(nohup|disown|setsid|start-process)(?=$|[\s;|)&])/i;
@@ -15572,7 +15599,7 @@ function execShellExecutionBinding(input, ctx) {
15572
15599
  confirmed: ctx.confirmed,
15573
15600
  enableDestructiveShellGuard: ctx.enableDestructiveShellGuard,
15574
15601
  blockDestructiveWithoutConfirmation: ctx.blockDestructiveWithoutConfirmation,
15575
- envDigest: createHash3("sha256").update(JSON.stringify(process.env)).digest("hex")
15602
+ envDigest: createHash4("sha256").update(JSON.stringify(process.env)).digest("hex")
15576
15603
  });
15577
15604
  }
15578
15605
  var execShellCapability = {
@@ -15705,8 +15732,75 @@ async function invokeCapability(capabilityOrName, input, ctx = {}) {
15705
15732
 
15706
15733
  // packages/agent-runtime/localWorkspaceTools.ts
15707
15734
  import { existsSync as existsSync4 } from "node:fs";
15708
- import { createHash as createHash4 } from "node:crypto";
15709
- import { lstat, mkdir, readdir as readdir2, readFile as readFile3, realpath, stat as stat3, writeFile } from "node:fs/promises";
15735
+ import { createHash as createHash5 } from "node:crypto";
15736
+
15737
+ // packages/agent-runtime/readImage.ts
15738
+ import { readFile } from "node:fs/promises";
15739
+ import { extname } from "node:path";
15740
+ var MAX_IMAGE_BASE64_BYTES = 2 * 1024 * 1024;
15741
+ var MAX_IMAGE_EDGE = 1568;
15742
+ var MIME_BY_EXTENSION = {
15743
+ ".png": "image/png",
15744
+ ".jpg": "image/jpeg",
15745
+ ".jpeg": "image/jpeg",
15746
+ ".webp": "image/webp",
15747
+ ".gif": "image/gif"
15748
+ };
15749
+ function detectMime(bytes) {
15750
+ if (bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) return "image/png";
15751
+ if (bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) return "image/jpeg";
15752
+ if (["GIF87a", "GIF89a"].includes(bytes.toString("ascii", 0, 6))) return "image/gif";
15753
+ if (bytes.toString("ascii", 0, 4) === "RIFF" && bytes.toString("ascii", 8, 12) === "WEBP") return "image/webp";
15754
+ }
15755
+ async function readLocalImage(path, options) {
15756
+ const limit = options?.maxBase64Bytes ?? MAX_IMAGE_BASE64_BYTES;
15757
+ const expected = MIME_BY_EXTENSION[extname(path).toLowerCase()];
15758
+ if (!expected) throw new Error("read_image: unsupported image extension (PNG/JPEG/WebP/GIF only)");
15759
+ const bytes = await readFile(path);
15760
+ if (detectMime(bytes) !== expected) throw new Error("read_image: image extension and magic bytes do not match");
15761
+ const { default: sharp } = await import("./dist-Q2JSMAKA.js");
15762
+ const image = sharp(bytes, { limitInputPixels: 4e7, animated: false });
15763
+ const meta = await image.metadata();
15764
+ if (!meta.width || !meta.height) throw new Error("read_image: invalid image dimensions");
15765
+ const encoded = (length) => 4 * Math.ceil(length / 3);
15766
+ let output = bytes;
15767
+ let mimeType = expected;
15768
+ let width = meta.width;
15769
+ let height = meta.height;
15770
+ if (Math.max(width, height) > MAX_IMAGE_EDGE || encoded(output.length) > limit) {
15771
+ const resized = await image.rotate().resize({ width: MAX_IMAGE_EDGE, height: MAX_IMAGE_EDGE, fit: "inside", withoutEnlargement: true }).jpeg({ quality: 80 }).toBuffer({ resolveWithObject: true });
15772
+ output = resized.data;
15773
+ width = resized.info.width;
15774
+ height = resized.info.height;
15775
+ mimeType = "image/jpeg";
15776
+ }
15777
+ while (encoded(output.length) > limit) {
15778
+ const current = encoded(output.length);
15779
+ if (width === 1 && height === 1) {
15780
+ throw new Error(
15781
+ `read_image: compressed image ${width}x${height}, ${output.length} bytes (${current} base64 bytes) still exceeds ${limit} base64 bytes`
15782
+ );
15783
+ }
15784
+ const scale = Math.min(0.9, Math.sqrt(limit / current) * 0.95);
15785
+ const resized = await image.clone().rotate().resize({
15786
+ width: Math.max(1, Math.floor(width * scale)),
15787
+ height: Math.max(1, Math.floor(height * scale)),
15788
+ fit: "inside",
15789
+ withoutEnlargement: true
15790
+ }).jpeg({ quality: 80 }).toBuffer({ resolveWithObject: true });
15791
+ output = resized.data;
15792
+ width = resized.info.width;
15793
+ height = resized.info.height;
15794
+ mimeType = "image/jpeg";
15795
+ }
15796
+ return {
15797
+ content: `[image ${width}x${height} ${output.length} bytes \u2192 ${path}]`,
15798
+ images: [{ mimeType, dataBase64: output.toString("base64") }]
15799
+ };
15800
+ }
15801
+
15802
+ // packages/agent-runtime/localWorkspaceTools.ts
15803
+ import { lstat, mkdir, readdir as readdir2, readFile as readFile4, realpath, stat as stat3, writeFile } from "node:fs/promises";
15710
15804
  import { homedir } from "node:os";
15711
15805
  import { dirname as dirname2, isAbsolute as isAbsolute2, relative as relative3, resolve as resolve4, sep } from "node:path";
15712
15806
  import { spawn as spawnChildProcess3 } from "node:child_process";
@@ -15744,15 +15838,15 @@ function isLineRangeCovered(request3, covered) {
15744
15838
  }
15745
15839
 
15746
15840
  // packages/agent-runtime/fileTextSearch.ts
15747
- import { readdir, readFile as readFile2, stat as stat2 } from "node:fs/promises";
15841
+ import { readdir, readFile as readFile3, stat as stat2 } from "node:fs/promises";
15748
15842
  import { basename, relative as relative2, resolve as resolve3 } from "node:path";
15749
15843
  import { spawn as spawnChildProcess2 } from "node:child_process";
15750
15844
 
15751
15845
  // packages/agent-runtime/gitignore.ts
15752
- import { readFile, stat } from "node:fs/promises";
15846
+ import { readFile as readFile2, stat } from "node:fs/promises";
15753
15847
  import { resolve as resolve2 } from "node:path";
15754
15848
  async function readRootGitignorePatterns(workspaceRoot) {
15755
- const content = await readFile(resolve2(workspaceRoot, ".gitignore"), "utf8").catch(() => null);
15849
+ const content = await readFile2(resolve2(workspaceRoot, ".gitignore"), "utf8").catch(() => null);
15756
15850
  if (content === null) return [];
15757
15851
  return content.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#") && !line.startsWith("!")).flatMap((line) => {
15758
15852
  const unanchored = line.replace(/^\//, "");
@@ -15832,7 +15926,7 @@ async function decorate(root, raw, context3, absolute = false) {
15832
15926
  let lines = cache.get(x.file);
15833
15927
  if (!lines) {
15834
15928
  try {
15835
- lines = (await readFile2(x.file, "utf8")).split(/\r\n|\r|\n/);
15929
+ lines = (await readFile3(x.file, "utf8")).split(/\r\n|\r|\n/);
15836
15930
  } catch {
15837
15931
  continue;
15838
15932
  }
@@ -15861,7 +15955,7 @@ function globMatch(pattern, value) {
15861
15955
  const r = new RegExp(`^${source}$`);
15862
15956
  return r.test(value) || r.test(basename(value));
15863
15957
  }
15864
- var defaultReadTextFile = (filePath) => readFile2(filePath, "utf8").catch(() => "");
15958
+ var defaultReadTextFile = (filePath) => readFile3(filePath, "utf8").catch(() => "");
15865
15959
  async function jsSearch(o, targetPath) {
15866
15960
  const max4 = o.maxResults ?? Number.MAX_SAFE_INTEGER;
15867
15961
  const excludes = o.exclude ?? [];
@@ -16221,6 +16315,7 @@ function runTasks(args2) {
16221
16315
  // packages/agent-runtime/localWorkspaceToolDefs.ts
16222
16316
  var WORKSPACE_TOOL_NAMES = [
16223
16317
  "readFile",
16318
+ "read_image",
16224
16319
  "writeFile",
16225
16320
  "editFile",
16226
16321
  "globFiles",
@@ -16526,6 +16621,16 @@ function buildTaskStopTool() {
16526
16621
  };
16527
16622
  }
16528
16623
  function buildWorkspaceToolDefinition(toolName) {
16624
+ if (toolName === "read_image") {
16625
+ return {
16626
+ type: "function",
16627
+ function: {
16628
+ name: "read_image",
16629
+ description: "Read one local PNG/JPEG/WebP/GIF image. Long edges above 1568px are resized to JPEG q80. Maximum encoded base64 size is 2MiB.",
16630
+ parameters: { type: "object", properties: { path: buildWorkspacePathProperty() }, required: ["path"], additionalProperties: false }
16631
+ }
16632
+ };
16633
+ }
16529
16634
  if (toolName === "readFile") {
16530
16635
  return buildReadWorkspaceFileTool();
16531
16636
  }
@@ -16922,7 +17027,7 @@ function readVisualStateCaptureArgs(args2) {
16922
17027
  }
16923
17028
  async function readWorkspacePackageScripts(workspaceRoot) {
16924
17029
  try {
16925
- const raw = await readFile3(resolve4(workspaceRoot, "package.json"), "utf8");
17030
+ const raw = await readFile4(resolve4(workspaceRoot, "package.json"), "utf8");
16926
17031
  const parsed = JSON.parse(raw);
16927
17032
  const scripts = parsed && typeof parsed === "object" && parsed.scripts && typeof parsed.scripts === "object" ? Object.keys(parsed.scripts).sort() : [];
16928
17033
  return { scripts };
@@ -17107,7 +17212,7 @@ async function readFileTool(args2) {
17107
17212
  allowRuntimeOwnedSpill: true,
17108
17213
  ...args2.confirmExternalFileAccess ? { confirmExternalFileAccess: args2.confirmExternalFileAccess } : {}
17109
17214
  });
17110
- const content = await readFile3(absolutePath, "utf8");
17215
+ const content = await readFile4(absolutePath, "utf8");
17111
17216
  const activity = extractActivity(parsed);
17112
17217
  const sliced = sliceReadFileContent({
17113
17218
  content,
@@ -17125,7 +17230,7 @@ async function readFileTool(args2) {
17125
17230
  const force = parsed.force === true;
17126
17231
  const ledger = args2.readLedger;
17127
17232
  const requestRange = { startLine: sliced.startLine, endLine: sliced.endLine };
17128
- const fingerprint = createHash4("sha1").update(content).digest("hex").slice(0, 20);
17233
+ const fingerprint = createHash5("sha1").update(content).digest("hex").slice(0, 20);
17129
17234
  let entry = ledger?.get(relativePath);
17130
17235
  if (entry && entry.fingerprint !== fingerprint) {
17131
17236
  entry = void 0;
@@ -17300,7 +17405,7 @@ async function editFileTool(args2) {
17300
17405
  requestedPath,
17301
17406
  ...args2.confirmExternalFileAccess ? { confirmExternalFileAccess: args2.confirmExternalFileAccess } : {}
17302
17407
  });
17303
- const content = await readFile3(absolutePath, "utf8");
17408
+ const content = await readFile4(absolutePath, "utf8");
17304
17409
  const { count: replacementCount, result: nextContent } = countAndReplaceEolTolerant({
17305
17410
  content,
17306
17411
  oldText,
@@ -17993,6 +18098,16 @@ function createLocalWorkspaceToolExecutors(args2) {
17993
18098
  ...fileAccess,
17994
18099
  ...args2.resolveRipgrepBinary ? { resolveRipgrepBinary: args2.resolveRipgrepBinary } : {}
17995
18100
  }),
18101
+ read_image: async (call) => {
18102
+ const parsed = parseWorkspaceToolArguments(call.arguments);
18103
+ if (Object.keys(parsed).some((key) => key !== "path")) throw new Error("read_image accepts exactly one path");
18104
+ const absolutePath = await resolveLocalWorkspaceToolPath({
18105
+ workspaceRoot: args2.workspaceRoot,
18106
+ requestedPath: requireWorkspaceToolPath(parsed),
18107
+ ...fileAccess
18108
+ });
18109
+ return readLocalImage(absolutePath);
18110
+ },
17996
18111
  readFile: (call) => readFileTool({
17997
18112
  call,
17998
18113
  workspaceRoot: args2.workspaceRoot,
@@ -18203,6 +18318,7 @@ var NEVER_LOCAL_TOOLS = /* @__PURE__ */ new Set([
18203
18318
  ]);
18204
18319
  var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
18205
18320
  "readFile",
18321
+ "read_image",
18206
18322
  "writeFile",
18207
18323
  "editFile",
18208
18324
  "globFiles",
@@ -18763,13 +18879,13 @@ function createTurnTranscript(args2) {
18763
18879
  pushTool: (msg) => {
18764
18880
  const capped = cap(msg);
18765
18881
  working.push(capped);
18766
- raw.push(capped);
18882
+ raw.push(withoutToolImages(capped));
18767
18883
  },
18768
18884
  popLast: () => {
18769
18885
  raw.pop();
18770
18886
  return working.pop();
18771
18887
  },
18772
- persisted: (persistedInput, persistedInputReference) => applyPersistedTurnInput(raw, persistedInput, persistedInputReference)
18888
+ persisted: (persistedInput, persistedInputReference) => applyPersistedTurnInput(raw.map(withoutToolImages), persistedInput, persistedInputReference)
18773
18889
  };
18774
18890
  }
18775
18891
 
@@ -19484,8 +19600,8 @@ function createTurnCompactionController(args2) {
19484
19600
  }
19485
19601
 
19486
19602
  // packages/agent-runtime/providerCallTelemetry.ts
19487
- import { createHash as createHash5 } from "node:crypto";
19488
- var shortHash = (value) => createHash5("sha1").update(value).digest("hex").slice(0, 12);
19603
+ import { createHash as createHash6 } from "node:crypto";
19604
+ var shortHash = (value) => createHash6("sha1").update(value).digest("hex").slice(0, 12);
19489
19605
  var hashMessage = (message) => {
19490
19606
  let text2;
19491
19607
  try {
@@ -19568,6 +19684,7 @@ function buildRoundBudgetWarningPrompt(threshold) {
19568
19684
  }
19569
19685
  var CONCURRENT_READONLY_TOOLS = /* @__PURE__ */ new Set([
19570
19686
  "readFile",
19687
+ "read_image",
19571
19688
  "read_file",
19572
19689
  "readWorkspaceFile",
19573
19690
  "globFiles",
@@ -20049,6 +20166,7 @@ async function runLocalAgentTurn(input) {
20049
20166
  ...msg,
20050
20167
  content: truncateToolOutputForContext(msg.content, contextWindow)
20051
20168
  } : msg;
20169
+ const acceptToolImages = createToolImageLedger();
20052
20170
  const transcript = createTurnTranscript({
20053
20171
  initialWorking: messages,
20054
20172
  prefixCount,
@@ -20229,6 +20347,9 @@ async function runLocalAgentTurn(input) {
20229
20347
  providerName: agentConfig.provider,
20230
20348
  model: provider.model
20231
20349
  });
20350
+ transcript.replaceWorkingHistory(transcript.working().map(
20351
+ (message) => omitToolImages(message, "already sent this turn")
20352
+ ));
20232
20353
  loopTiming.mark("llmCall", round);
20233
20354
  usageLedger.recordProviderCall({
20234
20355
  usage: result4.usage,
@@ -20413,6 +20534,7 @@ ${reasoningTailLog}
20413
20534
  }),
20414
20535
  tool_call_id: toolCall.id,
20415
20536
  toolName,
20537
+ [TOOL_IMAGES]: acceptToolImages(toolResult.images),
20416
20538
  ...observedMetadata ? { tool_result_metadata: observedMetadata } : {}
20417
20539
  });
20418
20540
  };
@@ -21945,7 +22067,7 @@ function buildLoadSkillExecutor(args2) {
21945
22067
  const { resolveSkillByName } = await import("./skillDiscovery-QC35EQY4.js");
21946
22068
  const resolved = resolveSkillByName(args2.cwd, name);
21947
22069
  if (!resolved) {
21948
- const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-LJV7FHNI.js");
22070
+ const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-V76JTNCJ.js");
21949
22071
  const builtin = resolveBuiltinSkillByName(name);
21950
22072
  if (builtin) {
21951
22073
  return {
@@ -22004,14 +22126,14 @@ Available skills: ${available.join(", ")}`;
22004
22126
  }
22005
22127
 
22006
22128
  // packages/agent-runtime/sessionIdentity.ts
22007
- import { createHash as createHash6 } from "node:crypto";
22129
+ import { createHash as createHash7 } from "node:crypto";
22008
22130
  var SALT = "nolo-session-identity-v1";
22009
22131
  function isStableSessionIdentityEnabled(env = process.env) {
22010
22132
  const v = env.NOLO_STABLE_SESSION_IDENTITY?.trim().toLowerCase();
22011
22133
  return !(v === "0" || v === "false" || v === "off");
22012
22134
  }
22013
22135
  function deriveStableUuid(sessionKey, purpose) {
22014
- const h = createHash6("sha256").update(`${SALT}\0${purpose}\0${sessionKey}`).digest();
22136
+ const h = createHash7("sha256").update(`${SALT}\0${purpose}\0${sessionKey}`).digest();
22015
22137
  h[6] = h[6] & 15 | 80;
22016
22138
  h[8] = h[8] & 63 | 128;
22017
22139
  const x = h.subarray(0, 16).toString("hex");
@@ -22633,6 +22755,7 @@ export {
22633
22755
  Duration_exports,
22634
22756
  Exit_exports,
22635
22757
  Effect_exports,
22758
+ toolImages,
22636
22759
  formatToolOverflowMarker,
22637
22760
  isDestructiveShellCommand,
22638
22761
  evaluateShellCommandPolicy,
@@ -27,11 +27,11 @@ import {
27
27
  stablePromptCacheKey,
28
28
  toOpenAiCompatibleMessages,
29
29
  toResponsesTools
30
- } from "./chunk-DI7ZFGDQ.js";
30
+ } from "./chunk-7L2HZQNN.js";
31
31
  import {
32
32
  isMeaningfulChatCompletionOutput,
33
33
  isMeaningfulResponsesOutput
34
- } from "./chunk-ASSNAASW.js";
34
+ } from "./chunk-XHR22EKE.js";
35
35
  import {
36
36
  clipCompactText
37
37
  } from "./chunk-5MMAK75Q.js";
@@ -44,14 +44,14 @@ import {
44
44
  resolvePlatformAuthToken,
45
45
  resolvePlatformServerUrl,
46
46
  resolveProviderTransportDecision
47
- } from "./chunk-PIG2IUVZ.js";
47
+ } from "./chunk-I2QHI2XM.js";
48
48
  import {
49
49
  isRecord
50
50
  } from "./chunk-KUG52IAP.js";
51
51
  import {
52
52
  NOLO_CLIENT_VERSION_HEADER,
53
53
  isPlatformMimoProviderModel
54
- } from "./chunk-CGFNDIKK.js";
54
+ } from "./chunk-5KTQVMCX.js";
55
55
 
56
56
  // packages/ai/token/sseUsageExtract.ts
57
57
  var TOKEN_FIELDS = [
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  fetchReferenceContents,
3
3
  resolveReferenceAssets
4
- } from "./chunk-CEQFVBI2.js";
4
+ } from "./chunk-X2Q5GT5J.js";
5
5
  import {
6
6
  updateTokensAction
7
- } from "./chunk-CMRP4XHV.js";
7
+ } from "./chunk-MIME4XKU.js";
8
8
  import {
9
9
  applyUpdateTokensFulfilled
10
10
  } from "./chunk-OWYYDMGJ.js";
@@ -12,7 +12,7 @@ import {
12
12
  extractReasoningFromResponseOutput,
13
13
  extractTextFromResponseOutput,
14
14
  extractToolCallsFromResponseOutput
15
- } from "./chunk-DI7ZFGDQ.js";
15
+ } from "./chunk-7L2HZQNN.js";
16
16
  import {
17
17
  isRecord
18
18
  } from "./chunk-KUG52IAP.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getModelContextWindow
3
- } from "./chunk-ASSNAASW.js";
3
+ } from "./chunk-XHR22EKE.js";
4
4
  import {
5
5
  isRecord
6
6
  } from "./chunk-KUG52IAP.js";
@@ -11,7 +11,7 @@ import {
11
11
  PLATFORM_HOSTED_KIMI_K3_MODEL,
12
12
  isFireworksKimiModel,
13
13
  isNoloHostedProvider
14
- } from "./chunk-CGFNDIKK.js";
14
+ } from "./chunk-5KTQVMCX.js";
15
15
  import {
16
16
  asTrimmedLowercaseString
17
17
  } from "./chunk-QSJ3HFEF.js";
@@ -17,7 +17,7 @@ import {
17
17
  } from "./chunk-LIQJTQRN.js";
18
18
  import {
19
19
  createFileCredentialBroker
20
- } from "./chunk-UHTDNB5Y.js";
20
+ } from "./chunk-76YUTLOT.js";
21
21
  import {
22
22
  asRecordOrEmpty
23
23
  } from "./chunk-KX6YBIHG.js";
@@ -347,7 +347,7 @@ var slice = createSliceWithThunks({
347
347
  const overrides = {};
348
348
  if (args.systemPromptOverride !== void 0) overrides.prompt = args.systemPromptOverride;
349
349
  if (args.toolsOverride !== void 0) overrides.tools = args.toolsOverride;
350
- const { _executeModel } = await import("./_executeModel-7J6IIHWQ.js");
350
+ const { _executeModel } = await import("./_executeModel-YJW2HPFY.js");
351
351
  return _executeModel(
352
352
  {
353
353
  isStreaming: args.isStreaming ?? false,
@@ -368,7 +368,7 @@ var slice = createSliceWithThunks({
368
368
  * - 循环直到无工具调用或触发其他运行时停止条件
369
369
  */
370
370
  runAgent: create.asyncThunk(async (args, thunkApi) => {
371
- const { runAgentClientLoop } = await import("./runAgentClientLoop-F6EQK26A.js");
371
+ const { runAgentClientLoop } = await import("./runAgentClientLoop-HPF2WFFQ.js");
372
372
  const { content: loopContent, toolCallCount } = await runAgentClientLoop(
373
373
  {
374
374
  agentKey: args.agentKey,
@@ -384,7 +384,7 @@ var slice = createSliceWithThunks({
384
384
  * 聊天轮次流式 Agent 调用
385
385
  */
386
386
  streamAgentChatTurn: create.asyncThunk(async (args, thunkApi) => {
387
- const { streamAgentChatTurnHandler } = await import("./streamAgentChatTurn-KXELVHFR.js");
387
+ const { streamAgentChatTurnHandler } = await import("./streamAgentChatTurn-3SNWCCK2.js");
388
388
  return streamAgentChatTurnHandler(args, thunkApi);
389
389
  }),
390
390
  /**
@@ -5,7 +5,7 @@ import {
5
5
  inlineImageUrlsForCustomProvider,
6
6
  prepareTools,
7
7
  shouldInlineImageUrlsForAgent
8
- } from "./chunk-2AZSL4GL.js";
8
+ } from "./chunk-22FIHMYU.js";
9
9
  import {
10
10
  CONFIRMATION_INPUT_KEYS,
11
11
  INVALID_TOOL_ARGS_REPLACEMENT,
@@ -14,16 +14,16 @@ import {
14
14
  performFetchRequest,
15
15
  sanitizeOutboundMessages,
16
16
  stripModelToolArgs
17
- } from "./chunk-3ELX6JK5.js";
17
+ } from "./chunk-UPC23AAN.js";
18
18
  import {
19
19
  findToolExecutor,
20
20
  toolDefinitionsByName
21
- } from "./chunk-QW6SSF7V.js";
21
+ } from "./chunk-ZJ66I757.js";
22
22
  import {
23
23
  classifyApiError,
24
24
  classifyGenerationError,
25
25
  extractErrorDiagnostics
26
- } from "./chunk-CEQFVBI2.js";
26
+ } from "./chunk-X2Q5GT5J.js";
27
27
  import {
28
28
  createSSEParser,
29
29
  createToolRunId,
@@ -32,7 +32,7 @@ import {
32
32
  toolRunSetPending,
33
33
  toolRunStarted,
34
34
  toolRunSucceeded
35
- } from "./chunk-WLPUUBFR.js";
35
+ } from "./chunk-P4V35AFD.js";
36
36
  import {
37
37
  getPublicImageAgentMode
38
38
  } from "./chunk-VIDPVFP3.js";
@@ -42,10 +42,10 @@ import {
42
42
  messageStreaming,
43
43
  toolResultNeedsUserConfirmation,
44
44
  updateToolMessage
45
- } from "./chunk-CMRP4XHV.js";
45
+ } from "./chunk-MIME4XKU.js";
46
46
  import {
47
47
  streamAgentChatTurn
48
- } from "./chunk-XLBQQ5SB.js";
48
+ } from "./chunk-7MBN2JZ5.js";
49
49
  import {
50
50
  getCurrentSpaceId
51
51
  } from "./chunk-ZJ7UHBJS.js";
@@ -85,13 +85,13 @@ import {
85
85
  } from "./chunk-56GBUMO5.js";
86
86
  import {
87
87
  normalizeChatCompletionsBodyForProvider
88
- } from "./chunk-DI7ZFGDQ.js";
88
+ } from "./chunk-7L2HZQNN.js";
89
89
  import {
90
90
  EMPTY_ASSISTANT_REPAIR_PROMPT
91
- } from "./chunk-HEC32F3G.js";
91
+ } from "./chunk-O3FUFEUI.js";
92
92
  import {
93
93
  getModelInfo
94
- } from "./chunk-ASSNAASW.js";
94
+ } from "./chunk-XHR22EKE.js";
95
95
  import {
96
96
  isAbortError
97
97
  } from "./chunk-7DPNBQSV.js";
@@ -105,7 +105,7 @@ import {
105
105
  } from "./chunk-5EMSBTQ6.js";
106
106
  import {
107
107
  getApiEndpoint
108
- } from "./chunk-6EQD4AQL.js";
108
+ } from "./chunk-GC64WGMD.js";
109
109
  import {
110
110
  isRecord
111
111
  } from "./chunk-KUG52IAP.js";