@moonshot-ai/kimi-code 0.23.1 → 0.23.3

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 (71) hide show
  1. package/dist/main.mjs +427 -206
  2. package/dist-web/assets/{CodeBlockNode-C3v9L5tu.js → CodeBlockNode-EM_kCY-N.js} +1 -1
  3. package/dist-web/assets/{CodeBlockShell.vue_vue_type_style_index_0_lang-OER_lgTH.js → CodeBlockShell.vue_vue_type_style_index_0_lang-CRgIOeOQ.js} +1 -1
  4. package/dist-web/assets/DesignSystemView-CHgJ_72D.css +1 -0
  5. package/dist-web/assets/DesignSystemView-CcrMrQZg.js +12 -0
  6. package/dist-web/assets/{Tooltip-C12yteht.js → Tooltip-CzU8Fz35.js} +1 -1
  7. package/dist-web/assets/{arc-06Rz4VQ-.js → arc-DJW0hKnH.js} +1 -1
  8. package/dist-web/assets/{architectureDiagram-3BPJPVTR-SukqShtR.js → architectureDiagram-3BPJPVTR-BugvyD1E.js} +1 -1
  9. package/dist-web/assets/{blockDiagram-GPEHLZMM-BNJEVQuc.js → blockDiagram-GPEHLZMM-CYo-sII1.js} +1 -1
  10. package/dist-web/assets/{c4Diagram-AAUBKEIU-C9SPPZVL.js → c4Diagram-AAUBKEIU-D5-N6MBf.js} +1 -1
  11. package/dist-web/assets/channel-CC7oTf8I.js +1 -0
  12. package/dist-web/assets/{chunk-2J33WTMH-BzX0gLZp.js → chunk-2J33WTMH-B3rIAyxG.js} +1 -1
  13. package/dist-web/assets/{chunk-4BX2VUAB-2tV0t7rP.js → chunk-4BX2VUAB-BqE5MO-d.js} +1 -1
  14. package/dist-web/assets/{chunk-55IACEB6-0TgNLC_z.js → chunk-55IACEB6-CLF660V6.js} +1 -1
  15. package/dist-web/assets/{chunk-727SXJPM-BSFCho5K.js → chunk-727SXJPM-B0BhWK0K.js} +1 -1
  16. package/dist-web/assets/{chunk-AQP2D5EJ-XiSvZi9j.js → chunk-AQP2D5EJ-DPjMnAJ0.js} +1 -1
  17. package/dist-web/assets/{chunk-FMBD7UC4-C_jrUP7r.js → chunk-FMBD7UC4-D5PTPUwg.js} +1 -1
  18. package/dist-web/assets/{chunk-ND2GUHAM-B6mTBYIB.js → chunk-ND2GUHAM-kAaY_4Vl.js} +1 -1
  19. package/dist-web/assets/{chunk-QZHKN3VN-DSY_ClX7.js → chunk-QZHKN3VN-C9evXZPa.js} +1 -1
  20. package/dist-web/assets/classDiagram-4FO5ZUOK-Khrb0akV.js +1 -0
  21. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-Khrb0akV.js +1 -0
  22. package/dist-web/assets/{cose-bilkent-S5V4N54A-BJEsiRfG.js → cose-bilkent-S5V4N54A-CLouiVVi.js} +1 -1
  23. package/dist-web/assets/{dagre-BM42HDAG-CBrTyMup.js → dagre-BM42HDAG-DzxOlw1n.js} +1 -1
  24. package/dist-web/assets/{diagram-2AECGRRQ-C5TmGHID.js → diagram-2AECGRRQ-BByJ2hb_.js} +1 -1
  25. package/dist-web/assets/{diagram-5GNKFQAL-DNiKwHCr.js → diagram-5GNKFQAL-IRsTcFso.js} +1 -1
  26. package/dist-web/assets/{diagram-KO2AKTUF-Dd35hxfq.js → diagram-KO2AKTUF-OnKw1-KB.js} +1 -1
  27. package/dist-web/assets/{diagram-LMA3HP47-WrOo32AA.js → diagram-LMA3HP47-BDxe5igX.js} +1 -1
  28. package/dist-web/assets/{diagram-OG6HWLK6-DR3kJpcY.js → diagram-OG6HWLK6-C8HfQ_tC.js} +1 -1
  29. package/dist-web/assets/{erDiagram-TEJ5UH35-BmSLh1fo.js → erDiagram-TEJ5UH35-9GqhMJHB.js} +1 -1
  30. package/dist-web/assets/{flowDiagram-I6XJVG4X-zQFT0Hxs.js → flowDiagram-I6XJVG4X-BxnUU20J.js} +1 -1
  31. package/dist-web/assets/{ganttDiagram-6RSMTGT7-CG2RzgSV.js → ganttDiagram-6RSMTGT7-BvvI2pVg.js} +1 -1
  32. package/dist-web/assets/{gitGraphDiagram-PVQCEYII-FepYh7HV.js → gitGraphDiagram-PVQCEYII-B7iu5op7.js} +1 -1
  33. package/dist-web/assets/{index-CMuCGyH1.js → index-BCLn8KKh.js} +2 -2
  34. package/dist-web/assets/{index-BUWl4lsr.js → index-Bi8oHSIr.js} +1 -1
  35. package/dist-web/assets/{index-_6Mhj8Rj.css → index-D-9xA0Nc.css} +1 -1
  36. package/dist-web/assets/index-e04Pgjfa.js +290 -0
  37. package/dist-web/assets/{index10-09ZlQIpo.js → index10-CCuAby3p.js} +1 -1
  38. package/dist-web/assets/{index11-C8YlETLm.js → index11-Dfvs1Rhd.js} +1 -1
  39. package/dist-web/assets/{index5-Dvc9jUB7.js → index5-iCBVHj23.js} +1 -1
  40. package/dist-web/assets/{index6-UocCE6Lj.js → index6-pl4U4MZe.js} +1 -1
  41. package/dist-web/assets/{index7-E3VgrKiQ.js → index7-DHIAb9rr.js} +1 -1
  42. package/dist-web/assets/{index8-Bxb-Xjem.js → index8-f7_g7Sdt.js} +2 -2
  43. package/dist-web/assets/{infoDiagram-5YYISTIA-BbI2KCTX.js → infoDiagram-5YYISTIA-CyYBC3kA.js} +1 -1
  44. package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-BzZLnVVK.js → ishikawaDiagram-YF4QCWOH-Jlcx9xTb.js} +1 -1
  45. package/dist-web/assets/{journeyDiagram-JHISSGLW-1f5fa5m5.js → journeyDiagram-JHISSGLW-CL5Yb_5k.js} +1 -1
  46. package/dist-web/assets/{kanban-definition-UN3LZRKU-BQhnYXtD.js → kanban-definition-UN3LZRKU-BqnauHAF.js} +1 -1
  47. package/dist-web/assets/{linear-CPygMVCd.js → linear-CMWGjNOi.js} +1 -1
  48. package/dist-web/assets/{mermaid.core-DzyMX8Ld.js → mermaid.core-KmcIQ1Ur.js} +66 -66
  49. package/dist-web/assets/{mindmap-definition-RKZ34NQL-B35GhhQo.js → mindmap-definition-RKZ34NQL-CVr19Hb0.js} +1 -1
  50. package/dist-web/assets/{pieDiagram-4H26LBE5-BxCyeEvP.js → pieDiagram-4H26LBE5-DJkmgpkl.js} +1 -1
  51. package/dist-web/assets/{quadrantDiagram-W4KKPZXB-C-sg-PQj.js → quadrantDiagram-W4KKPZXB-Q6FJUxUg.js} +1 -1
  52. package/dist-web/assets/{requirementDiagram-4Y6WPE33-RGkLcART.js → requirementDiagram-4Y6WPE33-CQTp7wfD.js} +1 -1
  53. package/dist-web/assets/{sankeyDiagram-5OEKKPKP-ZDy9_EXn.js → sankeyDiagram-5OEKKPKP-CyNSPnTi.js} +1 -1
  54. package/dist-web/assets/{sequenceDiagram-3UESZ5HK-9faAsd9D.js → sequenceDiagram-3UESZ5HK-DoC6yllg.js} +1 -1
  55. package/dist-web/assets/{stateDiagram-AJRCARHV-JM7V6DDb.js → stateDiagram-AJRCARHV-DJPyh7eE.js} +1 -1
  56. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-D6D0vb-i.js +1 -0
  57. package/dist-web/assets/{timeline-definition-PNZ67QCA-DBNxjfbt.js → timeline-definition-PNZ67QCA-C3cofncr.js} +1 -1
  58. package/dist-web/assets/{vennDiagram-CIIHVFJN-DHTh4JLY.js → vennDiagram-CIIHVFJN-D9J8WcHA.js} +1 -1
  59. package/dist-web/assets/{vue.runtime.esm-bundler-Cuefls6q.js → vue.runtime.esm-bundler-C14m1nnd.js} +1 -1
  60. package/dist-web/assets/{wardley-L42UT6IY-D70FWw9B.js → wardley-L42UT6IY-DkNDXFdt.js} +1 -1
  61. package/dist-web/assets/{wardleyDiagram-YWT4CUSO-BPHoDdFV.js → wardleyDiagram-YWT4CUSO-BHgVdx4X.js} +1 -1
  62. package/dist-web/assets/{xychartDiagram-2RQKCTM6-U3-Pc0An.js → xychartDiagram-2RQKCTM6-eziUIMuM.js} +1 -1
  63. package/dist-web/index.html +2 -2
  64. package/package.json +5 -5
  65. package/dist-web/assets/DesignSystemView-Bm5-sKT3.js +0 -12
  66. package/dist-web/assets/DesignSystemView-CxzrbiS1.css +0 -1
  67. package/dist-web/assets/channel-8SRtyypN.js +0 -1
  68. package/dist-web/assets/classDiagram-4FO5ZUOK-BICc9PAJ.js +0 -1
  69. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-BICc9PAJ.js +0 -1
  70. package/dist-web/assets/index-BCQoQ7Uo.js +0 -292
  71. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-B_V1QY7S.js +0 -1
package/dist/main.mjs CHANGED
@@ -9285,6 +9285,16 @@ function normalizeAnthropicStopReason(raw) {
9285
9285
  };
9286
9286
  }
9287
9287
  }
9288
+ function applyResponseFormat$1(kwargs, format) {
9289
+ if (format === void 0) return;
9290
+ if (format.type === "json_object") throw new ChatProviderError("Anthropic provider requires a JSON schema for structured response output.");
9291
+ const outputConfig = kwargs["output_config"] !== void 0 && kwargs["output_config"] !== null ? { ...kwargs["output_config"] } : {};
9292
+ outputConfig["format"] = {
9293
+ type: "json_schema",
9294
+ schema: format.jsonSchema.schema
9295
+ };
9296
+ kwargs["output_config"] = outputConfig;
9297
+ }
9288
9298
  /**
9289
9299
  * Extract Claude family + version from a model id.
9290
9300
  *
@@ -9927,6 +9937,7 @@ var init_anthropic = __esmMin((() => {
9927
9937
  const thinking = this._generationKwargs.thinking;
9928
9938
  if (thinking !== void 0 && !(thinking.type === "disabled" && isFableModel(this._model))) kwargs["thinking"] = thinking;
9929
9939
  if (this._generationKwargs.output_config !== void 0) kwargs["output_config"] = this._generationKwargs.output_config;
9940
+ applyResponseFormat$1(kwargs, options?.responseFormat);
9930
9941
  if (this._generationKwargs.contextManagement !== void 0) kwargs["context_management"] = this._generationKwargs.contextManagement;
9931
9942
  const betas = this._generationKwargs.betaFeatures ?? [];
9932
9943
  const extraHeaders = {};
@@ -44858,6 +44869,13 @@ function toolToGoogleGenAI(tool) {
44858
44869
  parametersJsonSchema: tool.parameters
44859
44870
  }] };
44860
44871
  }
44872
+ function applyResponseFormat(config, format) {
44873
+ if (format === void 0) return;
44874
+ config["responseMimeType"] = "application/json";
44875
+ delete config["responseSchema"];
44876
+ delete config["responseJsonSchema"];
44877
+ if (format.type === "json_schema") config["responseJsonSchema"] = format.jsonSchema.schema;
44878
+ }
44861
44879
  function toolCallIdToName(toolCallId, toolNameById) {
44862
44880
  const name = toolNameById.get(toolCallId);
44863
44881
  if (name !== void 0) return name;
@@ -45299,6 +45317,7 @@ var init_google_genai = __esmMin((() => {
45299
45317
  systemInstruction: systemPrompt,
45300
45318
  ...tools.length > 0 ? { tools: tools.map((t) => toolToGoogleGenAI(t)) } : {}
45301
45319
  };
45320
+ applyResponseFormat(config, options?.responseFormat);
45302
45321
  try {
45303
45322
  const models = this._createClient(options?.auth).models;
45304
45323
  const params = {
@@ -53516,6 +53535,18 @@ function convertTool$1(tool) {
53516
53535
  }
53517
53536
  };
53518
53537
  }
53538
+ function responseFormatToOpenAI$1(format) {
53539
+ if (format.type === "json_object") return { type: "json_object" };
53540
+ return {
53541
+ type: "json_schema",
53542
+ json_schema: {
53543
+ name: format.jsonSchema.name,
53544
+ schema: format.jsonSchema.schema,
53545
+ strict: format.jsonSchema.strict,
53546
+ description: format.jsonSchema.description
53547
+ }
53548
+ };
53549
+ }
53519
53550
  /**
53520
53551
  * Extract usage from a streaming chunk. Moonshot may place usage in
53521
53552
  * `choices[0].usage` in addition to the top-level `usage` field.
@@ -53717,6 +53748,7 @@ var init_kimi = __esmMin((() => {
53717
53748
  ...requestKwargs,
53718
53749
  ...extraBody
53719
53750
  };
53751
+ if (options?.responseFormat !== void 0) createParams["response_format"] = responseFormatToOpenAI$1(options.responseFormat);
53720
53752
  if (tools.length > 0) createParams["tools"] = tools.map((t) => convertTool$1(t));
53721
53753
  if (this._stream) createParams["stream_options"] = { include_usage: true };
53722
53754
  try {
@@ -53798,6 +53830,18 @@ var init_kimi = __esmMin((() => {
53798
53830
  }));
53799
53831
  //#endregion
53800
53832
  //#region ../../packages/kosong/src/providers/openai-legacy.ts
53833
+ function responseFormatToOpenAI(format) {
53834
+ if (format.type === "json_object") return { type: "json_object" };
53835
+ return {
53836
+ type: "json_schema",
53837
+ json_schema: {
53838
+ name: format.jsonSchema.name,
53839
+ schema: format.jsonSchema.schema,
53840
+ strict: format.jsonSchema.strict,
53841
+ description: format.jsonSchema.description
53842
+ }
53843
+ };
53844
+ }
53801
53845
  function extractReasoningContent(source, explicitKey) {
53802
53846
  if (typeof source !== "object" || source === null) return void 0;
53803
53847
  const record = source;
@@ -54070,6 +54114,7 @@ var init_openai_legacy = __esmMin((() => {
54070
54114
  stream: this._stream,
54071
54115
  ...kwargs
54072
54116
  };
54117
+ if (options?.responseFormat !== void 0) createParams["response_format"] = responseFormatToOpenAI(options.responseFormat);
54073
54118
  if (tools.length > 0) createParams["tools"] = tools.map((t) => toolToOpenAI(t));
54074
54119
  if (this._stream) createParams["stream_options"] = { include_usage: true };
54075
54120
  if (reasoningEffort !== void 0) createParams["reasoning_effort"] = reasoningEffort;
@@ -54295,6 +54340,16 @@ function formatResponsesFailedResponse(response) {
54295
54340
  const reason = incompleteDetails === void 0 ? void 0 : readStringField$1(incompleteDetails, "reason");
54296
54341
  return reason === void 0 ? "Unknown error (no error details in response)" : `incomplete: ${reason}`;
54297
54342
  }
54343
+ function responseFormatToResponsesText(format) {
54344
+ if (format.type === "json_object") return { format: { type: "json_object" } };
54345
+ return { format: {
54346
+ type: "json_schema",
54347
+ name: format.jsonSchema.name,
54348
+ schema: format.jsonSchema.schema,
54349
+ strict: format.jsonSchema.strict,
54350
+ description: format.jsonSchema.description
54351
+ } };
54352
+ }
54298
54353
  function contentPartsToInputItems(parts) {
54299
54354
  const items = [];
54300
54355
  for (const part of parts) switch (part.type) {
@@ -54814,6 +54869,10 @@ var init_openai_responses = __esmMin((() => {
54814
54869
  ...kwargs
54815
54870
  };
54816
54871
  if (systemPrompt) createParams["instructions"] = systemPrompt;
54872
+ if (options?.responseFormat !== void 0) createParams["text"] = {
54873
+ ...asRawObject(createParams["text"]),
54874
+ ...responseFormatToResponsesText(options.responseFormat)
54875
+ };
54817
54876
  if (!("responses" in client) || typeof client.responses?.create !== "function") throw new Error("OpenAI SDK version does not support Responses API. Upgrade to >=4.x with responses support.");
54818
54877
  options?.onRequestSent?.();
54819
54878
  return new OpenAIResponsesStreamedMessage(await client.responses.create(createParams, options?.signal ? { signal: options.signal } : void 0), this._stream);
@@ -77871,57 +77930,6 @@ var init_full = __esmMin((() => {
77871
77930
  buildInstruction(customInstruction) {
77872
77931
  return renderPrompt(compaction_instruction_default, { customInstruction: customInstruction?.trim() ?? "" }).trimEnd();
77873
77932
  }
77874
- /**
77875
- * Keep-all rebuild (Phase 1): after compaction folded the history — and the
77876
- * dynamic tool schema messages with it — append ONE merged schema message so
77877
- * the model keeps calling its loaded tools without re-selecting. Schemas are
77878
- * read from the live registry, never copied from the old history, so a
77879
- * schema that changed since load self-heals here. Names whose server is
77880
- * currently disconnected have no registry schema and are not rebuilt (the
77881
- * model re-selects after reconnect); names that survived into the
77882
- * post-compaction history (none under today's users+summary rebuild, but
77883
- * guarded) are not duplicated. The message goes through the normal
77884
- * injection-origin append, so estimation and records pick it up as usual.
77885
- *
77886
- * Budget guard: the rebuilt floor (users + summary + schemas) is the one
77887
- * part of the post-compaction context that compaction itself can never
77888
- * shrink — if it lands inside the auto-compaction trigger band, every
77889
- * following step re-compacts and rebuilds in a loop. Admit schemas (in name
77890
- * order) only while the projected context stays within HALF the compaction
77891
- * trigger, so normal turn content still fits before the next compaction;
77892
- * anything dropped is simply re-selectable on demand, the same degradation
77893
- * as a disconnected server.
77894
- */
77895
- rebuildDynamicToolSchemas(activeBefore) {
77896
- if (!this.agent.toolSelectEnabled) return;
77897
- if (activeBefore.size === 0) return;
77898
- const surviving = collectLoadedDynamicToolNames(this.agent.context.history);
77899
- const candidates = [...activeBefore].filter((name) => !surviving.has(name)).toSorted((a, b) => a.localeCompare(b)).map((name) => this.agent.tools.getMcpToolSchema(name)).filter((tool) => tool !== void 0);
77900
- if (candidates.length === 0) return;
77901
- const tools = [];
77902
- let projected = this.tokenCountWithPending;
77903
- for (const tool of candidates) {
77904
- const toolTokens = estimateTokensForTools([tool]);
77905
- if (this.strategy.shouldCompact((projected + toolTokens) * 2)) break;
77906
- tools.push(tool);
77907
- projected += toolTokens;
77908
- }
77909
- if (tools.length < candidates.length) this.agent.log.info("trimmed dynamic tool schema rebuild to stay clear of the compaction trigger", {
77910
- kept: tools.length,
77911
- dropped: candidates.slice(tools.length).map((tool) => tool.name)
77912
- });
77913
- if (tools.length === 0) return;
77914
- this.agent.context.appendMessage({
77915
- role: "system",
77916
- content: [],
77917
- toolCalls: [],
77918
- tools,
77919
- origin: {
77920
- kind: "injection",
77921
- variant: DYNAMIC_TOOL_SCHEMA_VARIANT
77922
- }
77923
- });
77924
- }
77925
77933
  postProcessSummary(summary) {
77926
77934
  const todos = this.agent.tools.storeData()["todo"] ?? [];
77927
77935
  if (todos.length === 0) return summary;
@@ -77932,7 +77940,6 @@ var init_full = __esmMin((() => {
77932
77940
  const startedAt = Date.now();
77933
77941
  const originalHistory = [...this.agent.context.history];
77934
77942
  const tokensBefore = estimateTokensForMessages(originalHistory);
77935
- const activeDynamicToolsBefore = new Set(this.agent.tools.loadedDynamicToolNames());
77936
77943
  let retryCount = 0;
77937
77944
  try {
77938
77945
  await this.triggerPreCompactHook(data, tokensBefore, signal);
@@ -78021,7 +78028,6 @@ var init_full = __esmMin((() => {
78021
78028
  tokensBefore,
78022
78029
  droppedCount: droppedCount === 0 ? void 0 : droppedCount
78023
78030
  });
78024
- this.rebuildDynamicToolSchemas(activeDynamicToolsBefore);
78025
78031
  this.agent.telemetry.track("compaction_finished", {
78026
78032
  source: data.source,
78027
78033
  tokens_before: result.tokensBefore,
@@ -78050,7 +78056,7 @@ var init_full = __esmMin((() => {
78050
78056
  thinking_effort: this.agent.config.thinkingEffort,
78051
78057
  error_type: error instanceof Error ? error.name : "Unknown"
78052
78058
  });
78053
- if (isKimiError(error) && error.code === ErrorCodes.AUTH_LOGIN_REQUIRED) throw error;
78059
+ if (isKimiError(error) && (error.code === ErrorCodes.AUTH_LOGIN_REQUIRED || error.code === ErrorCodes.PROVIDER_AUTH_ERROR)) throw error;
78054
78060
  throw new KimiError(ErrorCodes.COMPACTION_FAILED, String(error), { cause: error });
78055
78061
  }
78056
78062
  }
@@ -79838,6 +79844,11 @@ function sniffMediaFromMagic(data) {
79838
79844
  * after the `WEBP` tag, or the first JPEG SOFn segment). Returns `null`
79839
79845
  * for formats whose dimensions are not locatable from that region, or
79840
79846
  * when the supplied buffer is too short to cover it.
79847
+ *
79848
+ * JPEG dimensions are reported in DISPLAY space: an EXIF Orientation of
79849
+ * 5-8 transposes the image at decode time, so the SOF width/height are
79850
+ * swapped to match what decoders (and this codebase's crop regions and
79851
+ * compression captions) actually operate in.
79841
79852
  */
79842
79853
  function sniffImageDimensions(data) {
79843
79854
  const buf = toBuffer$2(data);
@@ -79881,6 +79892,7 @@ function sniffImageDimensions(data) {
79881
79892
  };
79882
79893
  }
79883
79894
  if (startsWith(buf, [255, 216])) {
79895
+ let orientation = null;
79884
79896
  let offset = 2;
79885
79897
  while (offset + 9 < buf.length) {
79886
79898
  if (buf[offset] !== 255) {
@@ -79888,21 +79900,60 @@ function sniffImageDimensions(data) {
79888
79900
  continue;
79889
79901
  }
79890
79902
  const marker = buf[offset + 1];
79891
- if (marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204) return {
79892
- height: buf.readUInt16BE(offset + 5),
79893
- width: buf.readUInt16BE(offset + 7)
79894
- };
79903
+ if (marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204) {
79904
+ const height = buf.readUInt16BE(offset + 5);
79905
+ const width = buf.readUInt16BE(offset + 7);
79906
+ return orientation !== null && orientation >= 5 ? {
79907
+ width: height,
79908
+ height: width,
79909
+ transposed: true
79910
+ } : {
79911
+ width,
79912
+ height
79913
+ };
79914
+ }
79895
79915
  if (marker === 216 || marker === 217 || marker >= 208 && marker <= 215) {
79896
79916
  offset += 2;
79897
79917
  continue;
79898
79918
  }
79899
79919
  const segmentLength = buf.readUInt16BE(offset + 2);
79900
79920
  if (segmentLength < 2) break;
79921
+ if (marker === 225 && orientation === null) orientation = readExifOrientation(buf, offset + 4, offset + 2 + segmentLength);
79901
79922
  offset += 2 + segmentLength;
79902
79923
  }
79903
79924
  }
79904
79925
  return null;
79905
79926
  }
79927
+ /**
79928
+ * Read the Orientation tag (0x0112) out of a JPEG APP1 payload spanning
79929
+ * [`start`, `end`). Returns 1-8, or `null` when the payload is not EXIF,
79930
+ * is truncated, or carries no valid orientation. Only IFD0 is examined —
79931
+ * that is where the tag lives; nothing here follows nested IFDs.
79932
+ */
79933
+ function readExifOrientation(buf, start, end) {
79934
+ const boundedEnd = Math.min(end, buf.length);
79935
+ if (start + 6 > boundedEnd || buf.toString("latin1", start, start + 6) !== "Exif\0\0") return null;
79936
+ const tiff = start + 6;
79937
+ if (tiff + 8 > boundedEnd) return null;
79938
+ const byteOrder = buf.toString("latin1", tiff, tiff + 2);
79939
+ const le = byteOrder === "II";
79940
+ if (!le && byteOrder !== "MM") return null;
79941
+ const u16 = (offset) => le ? buf.readUInt16LE(offset) : buf.readUInt16BE(offset);
79942
+ const u32 = (offset) => le ? buf.readUInt32LE(offset) : buf.readUInt32BE(offset);
79943
+ if (u16(tiff + 2) !== 42) return null;
79944
+ const ifd = tiff + u32(tiff + 4);
79945
+ if (ifd + 2 > boundedEnd) return null;
79946
+ const entryCount = u16(ifd);
79947
+ for (let i = 0; i < entryCount; i += 1) {
79948
+ const entry = ifd + 2 + i * 12;
79949
+ if (entry + 12 > boundedEnd) return null;
79950
+ if (u16(entry) === 274) {
79951
+ const value = u16(entry + 8);
79952
+ return value >= 1 && value <= 8 ? value : null;
79953
+ }
79954
+ }
79955
+ return null;
79956
+ }
79906
79957
  function getSuffix(path) {
79907
79958
  const idx = path.lastIndexOf(".");
79908
79959
  if (idx === -1) return "";
@@ -121696,7 +121747,8 @@ var init_esm$13 = __esmMin((() => {
121696
121747
  * `changed: false`.
121697
121748
  */
121698
121749
  async function compressImageForModel(bytes, mimeType, options = {}) {
121699
- const maxEdge = options.maxEdge ?? 2e3;
121750
+ const startedAt = Date.now();
121751
+ const maxEdge = options.maxEdge ?? 3e3;
121700
121752
  const byteBudget = options.byteBudget ?? 3932160;
121701
121753
  const maxDecodeBytes = options.maxDecodeBytes ?? MAX_DECODE_BYTES;
121702
121754
  const normalizedMime = normalizeMime(mimeType);
@@ -121712,38 +121764,50 @@ async function compressImageForModel(bytes, mimeType, options = {}) {
121712
121764
  originalByteLength: bytes.length,
121713
121765
  finalByteLength: bytes.length
121714
121766
  });
121715
- if (bytes.length === 0) return passthrough();
121716
- if (!RECODABLE_MIME.has(normalizedMime)) return passthrough();
121767
+ const finish = (outcome, result) => {
121768
+ reportCompressEvent(options.telemetry, {
121769
+ outcome,
121770
+ startedAt,
121771
+ inputMime: normalizedMime,
121772
+ exifTransposed: dims?.transposed === true,
121773
+ result
121774
+ });
121775
+ return result;
121776
+ };
121777
+ if (bytes.length === 0) return finish("passthrough_unsupported", passthrough());
121778
+ if (!RECODABLE_MIME.has(normalizedMime)) return finish("passthrough_unsupported", passthrough());
121717
121779
  const longestEdge = dims ? Math.max(dims.width, dims.height) : 0;
121718
- if (bytes.length <= byteBudget && (longestEdge > 0 && longestEdge <= maxEdge || longestEdge === 0)) return passthrough();
121719
- if (dims && dims.width * dims.height > MAX_DECODE_PIXELS) return passthrough();
121720
- if (bytes.length > maxDecodeBytes) return passthrough();
121780
+ if (bytes.length <= byteBudget && (longestEdge > 0 && longestEdge <= maxEdge || longestEdge === 0)) return finish("passthrough_fast", passthrough());
121781
+ if (dims && dims.width * dims.height > MAX_DECODE_PIXELS) return finish("passthrough_guard", passthrough());
121782
+ if (bytes.length > maxDecodeBytes) return finish("passthrough_guard", passthrough());
121721
121783
  try {
121722
121784
  const { Jimp } = await Promise.resolve().then(() => (init_esm$13(), esm_exports$3));
121723
121785
  const image = await Jimp.fromBuffer(Buffer.from(bytes));
121724
121786
  const sourceIsPng = normalizedMime === "image/png";
121787
+ const decodedWidth = image.width;
121788
+ const decodedHeight = image.height;
121725
121789
  fitWithinEdge(image, maxEdge);
121726
121790
  const encoded = await encodeWithinBudget(image, {
121727
121791
  sourceIsPng,
121728
121792
  byteBudget,
121729
- fallbackEdge: FALLBACK_EDGE_PX
121793
+ fallbackEdges: FALLBACK_EDGES_PX
121730
121794
  });
121731
- const originalPixels = (dims?.width ?? 0) * (dims?.height ?? 0);
121795
+ const originalPixels = decodedWidth * decodedHeight;
121732
121796
  const finalPixels = encoded.width * encoded.height;
121733
- if (!(encoded.data.length < bytes.length) && !(originalPixels > 0 && finalPixels < originalPixels)) return passthrough();
121734
- return {
121797
+ if (!(encoded.data.length < bytes.length) && !(finalPixels < originalPixels)) return finish("passthrough_unhelpful", passthrough());
121798
+ return finish("compressed", {
121735
121799
  data: encoded.data,
121736
121800
  mimeType: encoded.mimeType,
121737
121801
  width: encoded.width,
121738
121802
  height: encoded.height,
121739
- originalWidth: dims?.width ?? 0,
121740
- originalHeight: dims?.height ?? 0,
121803
+ originalWidth: decodedWidth,
121804
+ originalHeight: decodedHeight,
121741
121805
  changed: true,
121742
121806
  originalByteLength: bytes.length,
121743
121807
  finalByteLength: encoded.data.length
121744
- };
121808
+ });
121745
121809
  } catch {
121746
- return passthrough();
121810
+ return finish("passthrough_error", passthrough());
121747
121811
  }
121748
121812
  }
121749
121813
  /**
@@ -121752,24 +121816,35 @@ async function compressImageForModel(bytes, mimeType, options = {}) {
121752
121816
  * returns the original base64 unchanged on any failure.
121753
121817
  */
121754
121818
  async function compressBase64ForModel(base64, mimeType, options = {}) {
121819
+ const startedAt = Date.now();
121755
121820
  const maxDecodeBytes = options.maxDecodeBytes ?? MAX_DECODE_BYTES;
121756
121821
  const approxBytes = Math.floor(base64.length * 3 / 4);
121757
- if (approxBytes > maxDecodeBytes) return {
121758
- base64,
121759
- mimeType,
121760
- width: 0,
121761
- height: 0,
121762
- originalWidth: 0,
121763
- originalHeight: 0,
121764
- changed: false,
121765
- originalByteLength: approxBytes,
121766
- finalByteLength: approxBytes
121767
- };
121822
+ if (approxBytes > maxDecodeBytes) {
121823
+ const result = {
121824
+ base64,
121825
+ mimeType,
121826
+ width: 0,
121827
+ height: 0,
121828
+ originalWidth: 0,
121829
+ originalHeight: 0,
121830
+ changed: false,
121831
+ originalByteLength: approxBytes,
121832
+ finalByteLength: approxBytes
121833
+ };
121834
+ reportCompressEvent(options.telemetry, {
121835
+ outcome: "passthrough_guard",
121836
+ startedAt,
121837
+ inputMime: normalizeMime(mimeType),
121838
+ exifTransposed: false,
121839
+ result
121840
+ });
121841
+ return result;
121842
+ }
121768
121843
  let bytes;
121769
121844
  try {
121770
121845
  bytes = Buffer.from(base64, "base64");
121771
121846
  } catch {
121772
- return {
121847
+ const result = {
121773
121848
  base64,
121774
121849
  mimeType,
121775
121850
  width: 0,
@@ -121780,6 +121855,14 @@ async function compressBase64ForModel(base64, mimeType, options = {}) {
121780
121855
  originalByteLength: 0,
121781
121856
  finalByteLength: 0
121782
121857
  };
121858
+ reportCompressEvent(options.telemetry, {
121859
+ outcome: "passthrough_error",
121860
+ startedAt,
121861
+ inputMime: normalizeMime(mimeType),
121862
+ exifTransposed: false,
121863
+ result
121864
+ });
121865
+ return result;
121783
121866
  }
121784
121867
  const result = await compressImageForModel(bytes, mimeType, options);
121785
121868
  if (!result.changed) return {
@@ -121884,36 +121967,41 @@ async function compressImageContentParts(parts, options = {}) {
121884
121967
  * larger than the edge cap is therefore delivered at native resolution.
121885
121968
  */
121886
121969
  async function cropImageForModel(bytes, mimeType, region, options = {}) {
121887
- const maxEdge = options.maxEdge ?? 2e3;
121970
+ const startedAt = Date.now();
121971
+ const maxEdge = options.maxEdge ?? 3e3;
121888
121972
  const byteBudget = options.byteBudget ?? 3932160;
121889
121973
  const maxDecodeBytes = options.maxDecodeBytes ?? MAX_DECODE_BYTES;
121890
121974
  const normalizedMime = normalizeMime(mimeType);
121891
- if (bytes.length === 0) return {
121892
- ok: false,
121893
- error: "The image is empty."
121975
+ const fail = (errorKind, error) => {
121976
+ reportCropEvent(options.telemetry, {
121977
+ startedAt,
121978
+ ok: false,
121979
+ errorKind
121980
+ });
121981
+ return {
121982
+ ok: false,
121983
+ error
121984
+ };
121894
121985
  };
121895
- if (!RECODABLE_MIME.has(normalizedMime)) return {
121896
- ok: false,
121897
- error: `Cropping is only supported for PNG and JPEG images; got ${mimeType}.`
121986
+ const succeed = (result) => {
121987
+ reportCropEvent(options.telemetry, {
121988
+ startedAt,
121989
+ ok: true,
121990
+ result
121991
+ });
121992
+ return result;
121898
121993
  };
121994
+ if (bytes.length === 0) return fail("empty", "The image is empty.");
121995
+ if (!RECODABLE_MIME.has(normalizedMime)) return fail("unsupported_format", `Cropping is only supported for PNG and JPEG images; got ${mimeType}.`);
121899
121996
  if (![
121900
121997
  region.x,
121901
121998
  region.y,
121902
121999
  region.width,
121903
122000
  region.height
121904
- ].every((value) => Number.isFinite(value))) return {
121905
- ok: false,
121906
- error: `Region coordinates must be finite numbers; got x=${String(region.x)}, y=${String(region.y)}, width=${String(region.width)}, height=${String(region.height)}.`
121907
- };
122001
+ ].every((value) => Number.isFinite(value))) return fail("region_invalid", `Region coordinates must be finite numbers; got x=${String(region.x)}, y=${String(region.y)}, width=${String(region.width)}, height=${String(region.height)}.`);
121908
122002
  const dims = sniffImageDimensions(bytes);
121909
- if (dims && dims.width * dims.height > MAX_DECODE_PIXELS) return {
121910
- ok: false,
121911
- error: `The image (${String(dims.width)}x${String(dims.height)} pixels) is too large to decode for cropping.`
121912
- };
121913
- if (bytes.length > maxDecodeBytes) return {
121914
- ok: false,
121915
- error: "The image is too large to decode for cropping."
121916
- };
122003
+ if (dims && dims.width * dims.height > MAX_DECODE_PIXELS) return fail("too_large", `The image (${String(dims.width)}x${String(dims.height)} pixels) is too large to decode for cropping.`);
122004
+ if (bytes.length > maxDecodeBytes) return fail("too_large", "The image is too large to decode for cropping.");
121917
122005
  try {
121918
122006
  const { Jimp } = await Promise.resolve().then(() => (init_esm$13(), esm_exports$3));
121919
122007
  const image = await Jimp.fromBuffer(Buffer.from(bytes));
@@ -121921,10 +122009,7 @@ async function cropImageForModel(bytes, mimeType, region, options = {}) {
121921
122009
  const originalHeight = image.height;
121922
122010
  const x = Math.floor(region.x);
121923
122011
  const y = Math.floor(region.y);
121924
- if (x < 0 || y < 0 || x >= originalWidth || y >= originalHeight || region.width < 1 || region.height < 1) return {
121925
- ok: false,
121926
- error: `Region (x=${String(region.x)}, y=${String(region.y)}, width=${String(region.width)}, height=${String(region.height)}) lies outside the ${String(originalWidth)}x${String(originalHeight)} image.`
121927
- };
122012
+ if (x < 0 || y < 0 || x >= originalWidth || y >= originalHeight || region.width < 1 || region.height < 1) return fail("out_of_bounds", `Region (x=${String(region.x)}, y=${String(region.y)}, width=${String(region.width)}, height=${String(region.height)}) lies outside the ${String(originalWidth)}x${String(originalHeight)} image.`);
121928
122013
  const w = Math.min(Math.floor(region.width), originalWidth - x);
121929
122014
  const h = Math.min(Math.floor(region.height), originalHeight - y);
121930
122015
  const applied = {
@@ -121942,11 +122027,8 @@ async function cropImageForModel(bytes, mimeType, region, options = {}) {
121942
122027
  const sourceIsPng = normalizedMime === "image/png";
121943
122028
  if (options.skipResize === true) {
121944
122029
  const buffer = sourceIsPng ? await image.getBuffer("image/png", { deflateLevel: 9 }) : await image.getBuffer("image/jpeg", { quality: 90 });
121945
- if (buffer.length > byteBudget) return {
121946
- ok: false,
121947
- error: `The cropped region encodes to ${String(buffer.length)} bytes (${formatByteSize$2(buffer.length)}), over the ${String(byteBudget)}-byte (${formatByteSize$2(byteBudget)}) per-image limit. Choose a smaller region, or allow downscaling.`
121948
- };
121949
- return {
122030
+ if (buffer.length > byteBudget) return fail("budget", `The cropped region encodes to ${String(buffer.length)} bytes (${formatByteSize$2(buffer.length)}), over the ${String(byteBudget)}-byte (${formatByteSize$2(byteBudget)}) per-image limit. Choose a smaller region, or allow downscaling.`);
122031
+ return succeed({
121950
122032
  ok: true,
121951
122033
  data: new Uint8Array(buffer),
121952
122034
  mimeType: sourceIsPng ? "image/png" : "image/jpeg",
@@ -121958,15 +122040,15 @@ async function cropImageForModel(bytes, mimeType, region, options = {}) {
121958
122040
  resized: false,
121959
122041
  originalByteLength: bytes.length,
121960
122042
  finalByteLength: buffer.length
121961
- };
122043
+ });
121962
122044
  }
121963
122045
  fitWithinEdge(image, maxEdge);
121964
122046
  const encoded = await encodeWithinBudget(image, {
121965
122047
  sourceIsPng,
121966
122048
  byteBudget,
121967
- fallbackEdge: FALLBACK_EDGE_PX
122049
+ fallbackEdges: FALLBACK_EDGES_PX
121968
122050
  });
121969
- return {
122051
+ return succeed({
121970
122052
  ok: true,
121971
122053
  data: new Uint8Array(encoded.data),
121972
122054
  mimeType: encoded.mimeType,
@@ -121978,12 +122060,9 @@ async function cropImageForModel(bytes, mimeType, region, options = {}) {
121978
122060
  resized: encoded.width !== w || encoded.height !== h,
121979
122061
  originalByteLength: bytes.length,
121980
122062
  finalByteLength: encoded.data.length
121981
- };
122063
+ });
121982
122064
  } catch (error) {
121983
- return {
121984
- ok: false,
121985
- error: `Failed to decode the image for cropping: ${error instanceof Error ? error.message : String(error)}`
121986
- };
122065
+ return fail("decode_failed", `Failed to decode the image for cropping: ${error instanceof Error ? error.message : String(error)}`);
121987
122066
  }
121988
122067
  }
121989
122068
  /**
@@ -122056,14 +122135,17 @@ function parseImageDataUrl$1(url) {
122056
122135
  * Strategy — prefer the source format so a downscaled screenshot stays lossless
122057
122136
  * PNG (preserving text and transparency), and only fall back to lossy JPEG when
122058
122137
  * PNG cannot meet the byte budget:
122059
- * - PNG source: PNG at the fitted size → a smaller PNG rescale → JPEG ladder.
122060
- * - JPEG source: JPEG quality ladder → a smaller JPEG rescale.
122138
+ * - PNG source: PNG at the fitted size → smaller PNG rescales, stepping down
122139
+ * the fallback edges → JPEG ladder.
122140
+ * - JPEG source: the full quality ladder at the fitted size, then again at
122141
+ * each fallback edge — a smaller rescale must not skip the high-quality
122142
+ * rungs its extra pixels just paid for.
122061
122143
  *
122062
122144
  * Always returns the smallest buffer it produced, even if no attempt met the
122063
122145
  * budget — the caller still gates on whether it actually helped.
122064
122146
  */
122065
122147
  async function encodeWithinBudget(image, opts) {
122066
- const { sourceIsPng, byteBudget, fallbackEdge } = opts;
122148
+ const { sourceIsPng, byteBudget, fallbackEdges } = opts;
122067
122149
  let smallest = null;
122068
122150
  const consider = (data, mimeType) => {
122069
122151
  const candidate = {
@@ -122079,7 +122161,8 @@ async function encodeWithinBudget(image, opts) {
122079
122161
  const png = await image.getBuffer("image/png", { deflateLevel: 9 });
122080
122162
  if (png.length <= byteBudget) return consider(png, "image/png");
122081
122163
  consider(png, "image/png");
122082
- if (fitWithinEdge(image, fallbackEdge)) {
122164
+ for (const edge of fallbackEdges) {
122165
+ if (!fitWithinEdge(image, edge)) continue;
122083
122166
  const smallerPng = await image.getBuffer("image/png", { deflateLevel: 9 });
122084
122167
  if (smallerPng.length <= byteBudget) return consider(smallerPng, "image/png");
122085
122168
  consider(smallerPng, "image/png");
@@ -122096,12 +122179,26 @@ async function encodeWithinBudget(image, opts) {
122096
122179
  if (jpeg.length <= byteBudget) return consider(jpeg, "image/jpeg");
122097
122180
  consider(jpeg, "image/jpeg");
122098
122181
  }
122099
- if (fitWithinEdge(image, fallbackEdge)) consider(await image.getBuffer("image/jpeg", { quality: JPEG_QUALITY_STEPS.at(-1) }), "image/jpeg");
122182
+ for (const edge of fallbackEdges) {
122183
+ if (!fitWithinEdge(image, edge)) continue;
122184
+ for (const quality of JPEG_QUALITY_STEPS) {
122185
+ const jpeg = await image.getBuffer("image/jpeg", { quality });
122186
+ if (jpeg.length <= byteBudget) return consider(jpeg, "image/jpeg");
122187
+ consider(jpeg, "image/jpeg");
122188
+ }
122189
+ }
122100
122190
  return smallest;
122101
122191
  }
122102
122192
  /**
122103
122193
  * Scale `image` so its longest edge is at most `edge`, preserving aspect
122104
122194
  * ratio. No-op (returns false) when the image already fits.
122195
+ *
122196
+ * Deliberately passes no `mode`: without one, jimp's default resizer
122197
+ * downscales with a full-coverage area average (every source pixel
122198
+ * contributes to the output), which does not alias. The named
122199
+ * ResizeStrategy modes (BILINEAR, BICUBIC, …) switch to point-sampled
122200
+ * interpolation that skips source pixels beyond ~2x reduction and produces
122201
+ * moiré on text and fine patterns — do not "upgrade" this call to one.
122105
122202
  */
122106
122203
  function fitWithinEdge(image, edge) {
122107
122204
  const longest = Math.max(image.width, image.height);
@@ -122117,7 +122214,53 @@ function normalizeMime(mimeType) {
122117
122214
  const lower = mimeType.trim().toLowerCase();
122118
122215
  return lower === "image/jpg" ? "image/jpeg" : lower;
122119
122216
  }
122120
- var IMAGE_BYTE_BUDGET, JPEG_QUALITY_STEPS, FALLBACK_EDGE_PX, MAX_DECODE_PIXELS, MAX_DECODE_BYTES, RECODABLE_MIME, CAPTION_OPENING, CAPTION_PATTERN;
122217
+ /**
122218
+ * Emit the `image_compress` event. Properties are all numeric/enum — never
122219
+ * paths or content — and a throwing client is swallowed so telemetry can
122220
+ * never affect the compression result.
122221
+ */
122222
+ function reportCompressEvent(telemetry, input) {
122223
+ if (telemetry === void 0) return;
122224
+ try {
122225
+ telemetry.client.track("image_compress", {
122226
+ source: telemetry.source,
122227
+ outcome: input.outcome,
122228
+ input_mime: input.inputMime,
122229
+ output_mime: normalizeMime(input.result.mimeType),
122230
+ original_bytes: input.result.originalByteLength,
122231
+ final_bytes: input.result.finalByteLength,
122232
+ original_width: input.result.originalWidth,
122233
+ original_height: input.result.originalHeight,
122234
+ final_width: input.result.width,
122235
+ final_height: input.result.height,
122236
+ exif_transposed: input.exifTransposed,
122237
+ duration_ms: Date.now() - input.startedAt
122238
+ });
122239
+ } catch {}
122240
+ }
122241
+ /**
122242
+ * Emit the `image_crop` event. Reports the region as a share of the original
122243
+ * pixel area rather than raw coordinates.
122244
+ */
122245
+ function reportCropEvent(telemetry, input) {
122246
+ if (telemetry === void 0) return;
122247
+ try {
122248
+ const { result } = input;
122249
+ const originalPixels = result === void 0 ? 0 : result.originalWidth * result.originalHeight;
122250
+ telemetry.client.track("image_crop", {
122251
+ source: telemetry.source,
122252
+ ok: input.ok,
122253
+ error_kind: input.errorKind,
122254
+ resized: result?.resized,
122255
+ original_width: result?.originalWidth,
122256
+ original_height: result?.originalHeight,
122257
+ region_area_ratio: result === void 0 || originalPixels === 0 ? void 0 : result.region.width * result.region.height / originalPixels,
122258
+ final_bytes: result?.finalByteLength,
122259
+ duration_ms: Date.now() - input.startedAt
122260
+ });
122261
+ } catch {}
122262
+ }
122263
+ var IMAGE_BYTE_BUDGET, JPEG_QUALITY_STEPS, FALLBACK_EDGES_PX, MAX_DECODE_PIXELS, MAX_DECODE_BYTES, RECODABLE_MIME, CAPTION_OPENING, CAPTION_PATTERN;
122121
122264
  var init_image_compress = __esmMin((() => {
122122
122265
  init_file_type$1();
122123
122266
  IMAGE_BYTE_BUDGET = 3.75 * 1024 * 1024;
@@ -122127,7 +122270,7 @@ var init_image_compress = __esmMin((() => {
122127
122270
  40,
122128
122271
  20
122129
122272
  ];
122130
- FALLBACK_EDGE_PX = 1e3;
122273
+ FALLBACK_EDGES_PX = [2e3, 1e3];
122131
122274
  MAX_DECODE_PIXELS = 1e8;
122132
122275
  MAX_DECODE_BYTES = 64 * 1024 * 1024;
122133
122276
  RECODABLE_MIME = new Set(["image/png", "image/jpeg"]);
@@ -123396,19 +123539,26 @@ var init_goal$1 = __esmMin((() => {
123396
123539
  }));
123397
123540
  //#endregion
123398
123541
  //#region ../../packages/agent-core/src/session/hooks/runner.ts
123542
+ function buildHookSpawnOptions(options) {
123543
+ return {
123544
+ shell: true,
123545
+ cwd: options.cwd,
123546
+ stdio: "pipe",
123547
+ detached: process.platform !== "win32",
123548
+ windowsHide: true,
123549
+ env: options.env ? {
123550
+ ...process.env,
123551
+ ...options.env
123552
+ } : void 0
123553
+ };
123554
+ }
123399
123555
  async function runHook(command, input, options) {
123400
123556
  let child;
123401
123557
  try {
123402
- child = spawn$1(command, {
123403
- shell: true,
123558
+ child = spawn$1(command, buildHookSpawnOptions({
123404
123559
  cwd: options.cwd,
123405
- stdio: "pipe",
123406
- detached: process.platform !== "win32",
123407
- env: options.env ? {
123408
- ...process.env,
123409
- ...options.env
123410
- } : void 0
123411
- });
123560
+ env: options.env
123561
+ }));
123412
123562
  } catch (error) {
123413
123563
  return allowResult({ stderr: errorMessage$4(error) });
123414
123564
  }
@@ -124229,7 +124379,7 @@ function buildGoalReminder(goal) {
124229
124379
  lines.push("");
124230
124380
  lines.push("Before doing any goal work, check the objective and latest request for a clear hard budget limit. If one is present and the current goal does not already record that limit, call SetGoalBudget first. Do not invent budgets. If a requested budget is not reasonable, do not set it; tell the user it is not reasonable.");
124231
124381
  lines.push("");
124232
- lines.push("Goal mode is iterative. Keep the self-audit brief each turn. Do not explore unrelated interpretations once the goal can be decided. If the objective is simple, already answered, impossible, unsafe, or contradictory, do not run another goal turn. Explain briefly if useful, then call UpdateGoal with `complete` or `blocked` in the same turn. Otherwise, choose one bounded, useful slice of work toward the objective. Do not try to finish a broad goal in one turn unless the whole goal is genuinely small. Most goal turns should not call UpdateGoal: after completing a useful slice, if material work remains, end the turn normally without calling UpdateGoal so the runtime can continue the goal in the next turn. Call UpdateGoal with `complete` only when all required work is done, any stated validation has passed, and there is no useful next action. Do not mark complete after only producing a plan, summary, first pass, or partial result. Before calling `complete`, check that every required part of the objective is done, completion criteria are satisfied, requested or expected validation passed or has been reported as impossible, and no known material task remains. Call UpdateGoal with `blocked` only for a genuine impasse: an external condition, required user input, missing credentials or permissions, a persistent technical failure, or an impossible, unsafe, or contradictory objective. Do not use `blocked` because the work is large, hard, slow, uncertain, partial, still needs validation, or needs more goal turns.");
124382
+ lines.push("Goal mode is iterative. Keep the self-audit brief each turn. Do not explore unrelated interpretations once the goal can be decided. If the objective is simple, already answered, impossible, unsafe, or contradictory, do not run another goal turn. Explain briefly if useful, then call UpdateGoal with `complete` or `blocked` in the same turn. Otherwise, choose one bounded, useful slice of work toward the objective. Do not try to finish a broad goal in one turn unless the whole goal is genuinely small. Most goal turns should not call UpdateGoal: after completing a useful slice, if material work remains, end the turn normally without calling UpdateGoal so the runtime can continue the goal in the next turn. Call UpdateGoal with `complete` only when all required work is done, any stated validation has passed, and there is no useful next action. Completion audit: before calling `complete`, verify the current state against the actual objective and every explicit requirement. Treat weak or indirect evidence as not complete. Do not mark complete after only producing a plan, summary, first pass, or partial result. Do not mark complete merely because a budget is nearly exhausted or you want to stop. Blocked audit: do not call UpdateGoal with `blocked` the first time you hit a blocker. Use `blocked` only for a genuine impasse: an external condition, required user input, missing credentials or permissions, or a persistent technical failure. For those non-terminal blockers, the same blocking condition must repeat for at least 3 consecutive goal turns before you call `blocked`, counting the original/user-triggered turn and automatic continuations. If a previously blocked goal is resumed, treat the resumed run as a fresh blocked audit. Exception: if the objective itself is impossible, unsafe, or contradictory, call UpdateGoal with `blocked` in the same turn; do not run more goal turns just to satisfy the audit. Do not use `blocked` because the work is large, hard, slow, uncertain, incomplete, still needs validation, would benefit from clarification, or needs more goal turns. Once the 3-turn threshold is met and you cannot make meaningful progress without user input or an external-state change, call UpdateGoal with `blocked`; do not keep reporting the blocker while leaving the goal active.");
124233
124383
  return lines.join("\n");
124234
124384
  }
124235
124385
  /** Highest budget-usage fraction across the set hard budgets (turns/tokens/time). */
@@ -142142,7 +142292,13 @@ async function mcpResultToExecutableOutput(result, qualifiedToolName, options =
142142
142292
  if (part !== null) converted.push(part);
142143
142293
  }
142144
142294
  const budgeted = applyTextBudget(wrapMediaOnly(converted, qualifiedToolName));
142145
- const compressed = await compressImageContentParts(budgeted.parts, { annotate: { persistOriginal: (bytes, mimeType) => persistOriginalImage(bytes, mimeType, options.originalsDir === void 0 ? {} : { dir: options.originalsDir }) } });
142295
+ const compressed = await compressImageContentParts(budgeted.parts, {
142296
+ telemetry: options.telemetry === void 0 ? void 0 : {
142297
+ client: options.telemetry,
142298
+ source: "mcp_tool_result"
142299
+ },
142300
+ annotate: { persistOriginal: (bytes, mimeType) => persistOriginalImage(bytes, mimeType, options.originalsDir === void 0 ? {} : { dir: options.originalsDir }) }
142301
+ });
142146
142302
  const capped = applyBinaryPartCap(compressed.parts);
142147
142303
  const truncated = budgeted.truncated || capped.truncated;
142148
142304
  return {
@@ -150452,7 +150608,8 @@ var init_read_media = __esmMin((() => {
150452
150608
  name = "ReadMediaFile";
150453
150609
  description;
150454
150610
  parameters = toInputJsonSchema(ReadMediaFileInputSchema);
150455
- constructor(kaos, workspace, capabilities, videoUploader) {
150611
+ compressTelemetry;
150612
+ constructor(kaos, workspace, capabilities, videoUploader, telemetry) {
150456
150613
  this.kaos = kaos;
150457
150614
  this.workspace = workspace;
150458
150615
  this.capabilities = capabilities;
@@ -150463,6 +150620,10 @@ var init_read_media = __esmMin((() => {
150463
150620
  throw skip;
150464
150621
  }
150465
150622
  this.description = buildDescription(capabilities);
150623
+ this.compressTelemetry = telemetry === void 0 ? void 0 : {
150624
+ client: telemetry,
150625
+ source: "read_media"
150626
+ };
150466
150627
  }
150467
150628
  resolveExecution(args) {
150468
150629
  const path = resolvePathAccessPath(args.path, {
@@ -150528,7 +150689,10 @@ var init_read_media = __esmMin((() => {
150528
150689
  let mediaPart;
150529
150690
  let delivery;
150530
150691
  if (fileType.kind === "image") if (args.region !== void 0) {
150531
- const outcome = await cropImageForModel(data, fileType.mimeType, args.region, { skipResize: args.full_resolution === true });
150692
+ const outcome = await cropImageForModel(data, fileType.mimeType, args.region, {
150693
+ skipResize: args.full_resolution === true,
150694
+ telemetry: this.compressTelemetry
150695
+ });
150532
150696
  if (!outcome.ok) return {
150533
150697
  isError: true,
150534
150698
  output: `Cannot read region from "${args.path}": ${outcome.error}`
@@ -150547,7 +150711,7 @@ var init_read_media = __esmMin((() => {
150547
150711
  region: outcome.region,
150548
150712
  resized: outcome.resized
150549
150713
  };
150550
- dimensions ??= {
150714
+ dimensions = {
150551
150715
  width: outcome.originalWidth,
150552
150716
  height: outcome.originalHeight
150553
150717
  };
@@ -150569,7 +150733,7 @@ var init_read_media = __esmMin((() => {
150569
150733
  mimeType: fileType.mimeType
150570
150734
  };
150571
150735
  } else {
150572
- const compressed = await compressImageForModel(data, fileType.mimeType);
150736
+ const compressed = await compressImageForModel(data, fileType.mimeType, { telemetry: this.compressTelemetry });
150573
150737
  const base64 = Buffer.from(compressed.data).toString("base64");
150574
150738
  mediaPart = {
150575
150739
  type: "image_url",
@@ -150582,6 +150746,10 @@ var init_read_media = __esmMin((() => {
150582
150746
  byteLength: compressed.finalByteLength,
150583
150747
  mimeType: compressed.mimeType
150584
150748
  };
150749
+ if (compressed.changed) dimensions = {
150750
+ width: compressed.originalWidth,
150751
+ height: compressed.originalHeight
150752
+ };
150585
150753
  }
150586
150754
  else if (this.videoUploader !== void 0) mediaPart = await this.videoUploader({
150587
150755
  data,
@@ -151012,10 +151180,13 @@ var init_outcome_prompts = __esmMin((() => {}));
151012
151180
  //#region ../../packages/agent-core/src/tools/builtin/goal/update-goal.md?raw
151013
151181
  var update_goal_default;
151014
151182
  var init_update_goal$1 = __esmMin((() => {
151015
- update_goal_default = "Set the status of the current goal. This is how you resume, end, or yield an autonomous goal.\n\n- `active` — resume a paused or blocked goal when the user explicitly asks you to work on that goal.\n- `complete` — the objective is satisfied and any stated validation has passed. The goal ends and a completion summary is recorded.\n- `blocked` — a genuine impasse prevents useful progress: an external condition, required user input, missing credentials or permissions, a persistent technical failure, or an impossible, unsafe, or contradictory objective. The goal stops but can be resumed later. Do not use `blocked` because the work is large, hard, slow, uncertain, partial, still needs validation, or needs more goal turns.\n- `paused` — set the goal aside for now (e.g. to hand control back to the user). It can be resumed later.\n\nMost active goal turns should not call this tool. If you complete one useful slice of work and material work remains, end the turn normally without calling UpdateGoal; the runtime will prompt you to continue in the next goal turn. Call `complete` only when all required work is done, any stated validation has passed, and there is no useful next action. Before calling `complete`, check that every required part of the objective is done, completion criteria are satisfied, requested or expected validation passed or has been reported as impossible, and no known material task remains. Do not call `complete` after only producing a plan, summary, first pass, or partial result. If you call `blocked`, you will be prompted to explain the blocker in your next message. Setting the status is the machine-readable signal; the completion summary or blocker explanation is yours to write in the following message.\n";
151183
+ update_goal_default = "Set the status of the current goal. This is how you resume, complete, or block an autonomous goal.\n\n- `active` — resume a paused or blocked goal when the user explicitly asks you to work on that goal.\n- `complete` — the objective is satisfied and any stated validation has passed. The goal ends and a completion summary is recorded. Before using this, verify the current state against the actual objective and every explicit requirement. Treat weak or indirect evidence as not complete. Do not use `complete` merely because a budget is nearly exhausted or you want to stop.\n- `blocked` — a genuine impasse prevents useful progress: an external condition, required user input, missing credentials or permissions, a persistent technical failure, or an impossible, unsafe, or contradictory objective. For non-terminal blockers, do not use `blocked` the first time you hit the blocker. The same blocking condition must repeat for at least 3 consecutive goal turns before you call `blocked`, counting the original/user-triggered turn and automatic continuations. If a previously blocked goal is resumed, treat the resumed run as a fresh blocked audit. If the objective itself is impossible, unsafe, or contradictory, call `blocked` in the same turn instead of running more goal turns. Do not use `blocked` because the work is large, hard, slow, uncertain, incomplete, still needs validation, would benefit from clarification, or needs more goal turns. Once the 3-turn threshold is met and you cannot make meaningful progress without user input or an external-state change, call `blocked` instead of leaving the goal active.\n\nMost active goal turns should not call this tool. If you complete one useful slice of work and material work remains, end the turn normally without calling UpdateGoal; the runtime will prompt you to continue in the next goal turn. Call `complete` only when all required work is done, any stated validation has passed, and there is no useful next action. Do not call `complete` after only producing a plan, summary, first pass, or partial result. Call `blocked` only after the blocked audit threshold is met. If you call `blocked`, you will be prompted to explain the blocker in your next message. Setting the status is the machine-readable signal; the completion summary or blocker explanation is yours to write in the following message.\n";
151016
151184
  }));
151017
151185
  //#endregion
151018
151186
  //#region ../../packages/agent-core/src/tools/builtin/goal/update-goal.ts
151187
+ function isUpdateGoalStatus(status) {
151188
+ return status === "active" || status === "complete" || status === "blocked";
151189
+ }
151019
151190
  var UpdateGoalToolInputSchema, UpdateGoalTool;
151020
151191
  var init_update_goal = __esmMin((() => {
151021
151192
  init_zod$1();
@@ -151025,9 +151196,8 @@ var init_update_goal = __esmMin((() => {
151025
151196
  UpdateGoalToolInputSchema = object({ status: _enum([
151026
151197
  "active",
151027
151198
  "complete",
151028
- "paused",
151029
151199
  "blocked"
151030
- ]).describe("The lifecycle status to set for the current goal.") }).strict();
151200
+ ]).describe("The lifecycle status to set for the current goal. Use `blocked` for impossible, unsafe, or contradictory objectives, or after the same non-terminal blocking condition repeats for at least 3 consecutive goal turns.") }).strict();
151031
151201
  UpdateGoalTool = class {
151032
151202
  agent;
151033
151203
  name = "UpdateGoal";
@@ -151037,20 +151207,25 @@ var init_update_goal = __esmMin((() => {
151037
151207
  this.agent = agent;
151038
151208
  }
151039
151209
  resolveExecution(args) {
151210
+ if (!isUpdateGoalStatus(args.status)) return {
151211
+ isError: true,
151212
+ output: "Invalid goal status. Use `active`, `complete`, or `blocked`."
151213
+ };
151214
+ const status = args.status;
151040
151215
  const goal = this.agent.goal;
151041
151216
  const currentGoal = goal.getGoal().goal;
151042
151217
  const goalIsActive = currentGoal?.status === "active";
151043
151218
  return {
151044
- description: `Setting goal status: ${args.status}`,
151045
- stopBatchAfterThis: args.status !== "active" && goalIsActive,
151219
+ description: `Setting goal status: ${status}`,
151220
+ stopBatchAfterThis: status !== "active" && goalIsActive,
151046
151221
  approvalRule: this.name,
151047
151222
  execute: async () => {
151048
- if (args.status === "active") {
151223
+ if (status === "active") {
151049
151224
  if (currentGoal === null) return { output: "Goal not resumed: no current goal." };
151050
151225
  await goal.resumeGoal({}, "model");
151051
151226
  return { output: "Goal resumed." };
151052
151227
  }
151053
- if (args.status === "complete") {
151228
+ if (status === "complete") {
151054
151229
  const completed = await goal.markComplete({}, "model");
151055
151230
  if (completed === null) return { output: "Goal not completed: no active goal." };
151056
151231
  return {
@@ -151058,7 +151233,7 @@ var init_update_goal = __esmMin((() => {
151058
151233
  stopTurn: true
151059
151234
  };
151060
151235
  }
151061
- if (args.status === "blocked") {
151236
+ if (status === "blocked") {
151062
151237
  const blocked = await goal.markBlocked({}, "model");
151063
151238
  if (blocked === null) return { output: "Goal not blocked: no active goal." };
151064
151239
  return {
@@ -151066,11 +151241,9 @@ var init_update_goal = __esmMin((() => {
151066
151241
  stopTurn: true
151067
151242
  };
151068
151243
  }
151069
- if (currentGoal === null) return { output: "Goal not paused: no current goal." };
151070
- await goal.pauseGoal({}, "model");
151071
151244
  return {
151072
- output: "Goal paused.",
151073
- stopTurn: true
151245
+ isError: true,
151246
+ output: "Invalid goal status. Use `active`, `complete`, or `blocked`."
151074
151247
  };
151075
151248
  }
151076
151249
  };
@@ -152107,7 +152280,10 @@ var init_tool$1 = __esmMin((() => {
152107
152280
  return {
152108
152281
  approvalRule: qualified,
152109
152282
  execute: async (context) => {
152110
- return mcpResultToExecutableOutput(await client.callTool(tool.name, args ?? {}, context.signal), qualified, { originalsDir: this.agent.mediaOriginalsDir });
152283
+ return mcpResultToExecutableOutput(await client.callTool(tool.name, args ?? {}, context.signal), qualified, {
152284
+ originalsDir: this.agent.mediaOriginalsDir,
152285
+ telemetry: this.agent.telemetry
152286
+ });
152111
152287
  }
152112
152288
  };
152113
152289
  }
@@ -152292,8 +152468,8 @@ var init_tool$1 = __esmMin((() => {
152292
152468
  * defer-window pending set. History is the single source of truth, so the
152293
152469
  * ledger survives resume (records replay rebuilds the history), keeps its
152294
152470
  * state across undo (schema messages have `injection` origin and are not
152295
- * undone), and self-heals after compaction (the rebuild message re-carries
152296
- * the schemas).
152471
+ * undone), and empties at compaction (schema messages are discarded with
152472
+ * the folded history — the model re-selects what it still needs).
152297
152473
  */
152298
152474
  loadedDynamicToolNames() {
152299
152475
  const names = collectLoadedDynamicToolNames(this.agent.context.history);
@@ -152314,12 +152490,11 @@ var init_tool$1 = __esmMin((() => {
152314
152490
  this.pendingLoadedDynamicTools.clear();
152315
152491
  }
152316
152492
  /**
152317
- * Compaction rebuilt the history: from here on the keep-all rebuild message
152318
- * (which may have trimmed or skipped schemas — budget guard, disconnected
152319
- * servers) is the sole truth about what is still loaded. A pending entry
152320
- * surviving past this boundary would report a schema the context no longer
152321
- * carries as loaded, and re-selecting it would wrongly answer
152322
- * "Already available" instead of injecting.
152493
+ * Compaction rebuilt the history and discarded every loaded schema with it
152494
+ * — the loaded set is empty from here on. A pending entry surviving past
152495
+ * this boundary would report a schema the context no longer carries as
152496
+ * loaded, and re-selecting it would wrongly answer "Already available"
152497
+ * instead of injecting.
152323
152498
  */
152324
152499
  onContextCompacted() {
152325
152500
  this.pendingLoadedDynamicTools.clear();
@@ -152393,7 +152568,7 @@ var init_tool$1 = __esmMin((() => {
152393
152568
  new GrepTool(kaos, workspace, this.agent.telemetry),
152394
152569
  new GlobTool(kaos, workspace, this.agent.telemetry),
152395
152570
  new BashTool(kaos, cwd, background, { allowBackground }),
152396
- (modelCapabilities.image_in || modelCapabilities.video_in) && new ReadMediaFileTool(kaos, workspace, modelCapabilities, videoUploader),
152571
+ (modelCapabilities.image_in || modelCapabilities.video_in) && new ReadMediaFileTool(kaos, workspace, modelCapabilities, videoUploader, this.agent.telemetry),
152397
152572
  new EnterPlanModeTool(this.agent),
152398
152573
  new ExitPlanModeTool(this.agent),
152399
152574
  new SelectToolsTool(this.agent),
@@ -153011,15 +153186,23 @@ var init_turn = __esmMin((() => {
153011
153186
  "useful slice, if material work remains, end the turn normally without calling UpdateGoal so",
153012
153187
  "the runtime can continue the goal in the next turn. Call UpdateGoal with `complete` only when",
153013
153188
  "all required work is done, any stated validation has passed, and there is no useful next",
153014
- "action. Do not mark complete after only producing a plan, summary, first pass, or partial",
153015
- "result. Before calling `complete`, check that every required part of the objective is done,",
153016
- "completion criteria are satisfied, requested or expected validation passed or has been",
153017
- "reported as impossible, and no known material task remains. Call UpdateGoal with `blocked`",
153018
- "only for a genuine impasse: an external condition, required user input, missing credentials",
153019
- "or permissions, a persistent technical failure, or an impossible, unsafe, or contradictory",
153020
- "objective. Do not use `blocked` because the work is large, hard, slow, uncertain, partial,",
153021
- "still needs validation, or needs more goal turns. Do not ask the user for input unless a real",
153022
- "blocker prevents progress."
153189
+ "action. Completion audit: before calling `complete`, verify the current state against the",
153190
+ "actual objective and every explicit requirement. Treat weak or indirect evidence as not",
153191
+ "complete. Do not mark complete after only producing a plan, summary, first pass, or partial",
153192
+ "result. Do not mark complete merely because a budget is nearly exhausted or you want to stop.",
153193
+ "Blocked audit: do not call UpdateGoal with `blocked` the first time you hit a blocker. Use",
153194
+ "`blocked` only for a genuine impasse: an external condition, required user input, missing",
153195
+ "credentials or permissions, or a persistent technical failure. For those non-terminal",
153196
+ "blockers, the same blocking condition must repeat for at least 3 consecutive goal turns before",
153197
+ "you call `blocked`, counting the original/user-triggered turn and automatic continuations.",
153198
+ "If a previously blocked goal is resumed, treat the resumed run as a fresh blocked audit.",
153199
+ "Exception: if the objective itself is impossible, unsafe, or contradictory, call UpdateGoal",
153200
+ "with `blocked` in the same turn; do not run more goal turns just to satisfy the audit. Do not",
153201
+ "use `blocked` because the work is large, hard, slow, uncertain, incomplete, still needs",
153202
+ "validation, would benefit from clarification, or needs more goal turns. Once the 3-turn",
153203
+ "threshold is met and you cannot make meaningful progress without user input or an",
153204
+ "external-state change, call UpdateGoal with `blocked`; do not keep reporting the blocker while",
153205
+ "leaving the goal active. Do not ask the user for input unless a real blocker prevents progress."
153023
153206
  ].join(" ");
153024
153207
  TurnFlow = class {
153025
153208
  agent;
@@ -153212,10 +153395,16 @@ var init_turn = __esmMin((() => {
153212
153395
  try {
153213
153396
  if (this.agent.goal.getGoal().goal?.status === "active") return await this.driveGoal(firstTurnId, input, origin, signal);
153214
153397
  const end = await this.runOneTurn(firstTurnId, input, origin, signal, true);
153215
- if (this.agent.goal.getGoal().goal?.status === "active" && end.event.reason !== "cancelled" && end.event.reason !== "failed" && end.event.reason !== "filtered") return await this.driveGoal(this.allocateTurnId(), [{
153216
- type: "text",
153217
- text: GOAL_CONTINUATION_PROMPT
153218
- }], GOAL_CONTINUATION_ORIGIN, signal);
153398
+ if (this.agent.goal.getGoal().goal?.status === "active" && end.event.reason !== "cancelled" && end.event.reason !== "failed" && end.event.reason !== "filtered") {
153399
+ if ((await this.agent.goal.incrementTurn())?.budget.overBudget === true) {
153400
+ await this.agent.goal.markBlocked({ reason: "A configured budget was reached" });
153401
+ return end;
153402
+ }
153403
+ return await this.driveGoal(this.allocateTurnId(), [{
153404
+ type: "text",
153405
+ text: GOAL_CONTINUATION_PROMPT
153406
+ }], GOAL_CONTINUATION_ORIGIN, signal);
153407
+ }
153219
153408
  return end;
153220
153409
  } finally {
153221
153410
  if (ownsActiveTurn()) this.activeTurn = null;
@@ -153225,8 +153414,8 @@ var init_turn = __esmMin((() => {
153225
153414
  * Drives an active goal as a sequence of ordinary turns — the autonomous
153226
153415
  * equivalent of the user repeatedly typing "continue". Each iteration runs one
153227
153416
  * full turn, then reads the goal status the model set via `UpdateGoal`:
153228
- * `complete` (the record is cleared) / `blocked` / `paused` stop the loop;
153229
- * `active` (the model didn't decide) re-injects the goal reminder and runs the
153417
+ * `complete` (the record is cleared) / `blocked` stop the loop; `active`
153418
+ * (the model didn't decide) re-injects the goal reminder and runs the
153230
153419
  * next continuation turn. Aborted or failed turns pause the goal. Goal-state
153231
153420
  * blockers, such as explicit `UpdateGoal('blocked')`, prompt-hook blocks, and
153232
153421
  * budget limits, block it (all resumable). Returns the final turn's result.
@@ -205862,13 +206051,16 @@ var init_provider_manager = __esmMin((() => {
205862
206051
  return await request(auth);
205863
206052
  } catch (error) {
205864
206053
  if (!(error instanceof APIStatusError) || error.statusCode !== 401) throw error;
205865
- if (refreshed) throw new KimiError(ErrorCodes.AUTH_LOGIN_REQUIRED, "OAuth provider credentials were rejected. Send /login to login.", {
205866
- cause: error,
205867
- details: {
205868
- statusCode: error.statusCode,
205869
- requestId: error.requestId
205870
- }
205871
- });
206054
+ if (refreshed) {
206055
+ const reason = error.message.replaceAll("\r", "");
206056
+ throw new KimiError(ErrorCodes.PROVIDER_AUTH_ERROR, reason.length > 0 ? reason : "OAuth provider credentials were rejected.", {
206057
+ cause: error,
206058
+ details: {
206059
+ statusCode: error.statusCode,
206060
+ requestId: error.requestId
206061
+ }
206062
+ });
206063
+ }
205872
206064
  auth = await fetchAuth(true);
205873
206065
  }
205874
206066
  };
@@ -209492,6 +209684,7 @@ var _CoreProcessService, CoreProcessService;
209492
209684
  var init_coreProcessService = __esmMin((() => {
209493
209685
  init_rpc();
209494
209686
  init_di();
209687
+ init_telemetry();
209495
209688
  init_src$2();
209496
209689
  init_managedAuth();
209497
209690
  init_coreProcessClient();
@@ -209513,6 +209706,7 @@ var init_coreProcessService = __esmMin((() => {
209513
209706
  */
209514
209707
  rpc;
209515
209708
  kimiRequestHeaders;
209709
+ telemetry;
209516
209710
  /**
209517
209711
  * The in-process `KimiCore` instance. Kept private so daemon-side code can't
209518
209712
  * grab it and bypass the peer-service indirection.
@@ -209535,6 +209729,7 @@ var init_coreProcessService = __esmMin((() => {
209535
209729
  const [coreRpc, sdkRpc] = createRPC();
209536
209730
  const resolveOAuthTokenProvider = options.resolveOAuthTokenProvider ?? _CoreProcessService._defaultOAuthTokenResolver(env.homeDir, env.configPath);
209537
209731
  this.kimiRequestHeaders = options.kimiRequestHeaders ?? _CoreProcessService._defaultKimiRequestHeaders(env.homeDir, options.identity);
209732
+ this.telemetry = options.telemetry ?? noopTelemetryClient;
209538
209733
  const appVersion = options.appVersion ?? options.identity?.version;
209539
209734
  this._core = new KimiCore(coreRpc, {
209540
209735
  ...options,
@@ -218643,8 +218838,12 @@ function applyCatalogProvider(config, options) {
218643
218838
  init_src();
218644
218839
  //#endregion
218645
218840
  //#region ../../packages/telemetry/src/types.ts
218841
+ const MAX_TELEMETRY_NUMBER_MAGNITUDE = Number.MAX_SAFE_INTEGER;
218646
218842
  function isTelemetryPrimitive(value) {
218647
- return value === null || value === void 0 || typeof value === "boolean" || typeof value === "string" || typeof value === "number" && Number.isFinite(value);
218843
+ return value === null || value === void 0 || typeof value === "boolean" || typeof value === "string" || typeof value === "number" && isTelemetryNumber(value);
218844
+ }
218845
+ function isTelemetryNumber(value) {
218846
+ return Number.isFinite(value) && Math.abs(value) <= MAX_TELEMETRY_NUMBER_MAGNITUDE;
218648
218847
  }
218649
218848
  //#endregion
218650
218849
  //#region ../../packages/telemetry/src/client.ts
@@ -218928,7 +219127,7 @@ function setPrimitive(target, key, value) {
218928
219127
  }
218929
219128
  //#endregion
218930
219129
  //#region ../../packages/telemetry/src/systemMetrics.ts
218931
- const DEFAULT_INTERVAL_MS = 3e4;
219130
+ const DEFAULT_INTERVAL_MS = 3e5;
218932
219131
  const DEFAULT_WARMUP_SAMPLE_MS = 1500;
218933
219132
  const SYSTEM_METRICS_EVENT = "system_metrics";
218934
219133
  var SystemMetricsCollector = class {
@@ -218984,7 +219183,7 @@ var SystemMetricsCollector = class {
218984
219183
  this.previousHrtime = now;
218985
219184
  const mem = process.memoryUsage();
218986
219185
  const constrainedMemory = getConstrainedMemoryBytes();
218987
- this.client.track(SYSTEM_METRICS_EVENT, {
219186
+ const properties = {
218988
219187
  process_started_at: this.processStartedAtSeconds,
218989
219188
  process_uptime_ms: Math.round(process.uptime() * 1e3),
218990
219189
  rss_bytes: mem.rss,
@@ -218992,7 +219191,6 @@ var SystemMetricsCollector = class {
218992
219191
  heap_total_bytes: mem.heapTotal,
218993
219192
  external_bytes: mem.external,
218994
219193
  array_buffers_bytes: mem.arrayBuffers,
218995
- constrained_memory_bytes: constrainedMemory,
218996
219194
  cpu_user_us: cpu.user,
218997
219195
  cpu_system_us: cpu.system,
218998
219196
  cpu_elapsed_us: Math.round(elapsedUs),
@@ -219000,13 +219198,15 @@ var SystemMetricsCollector = class {
219000
219198
  free_mem_bytes: freemem(),
219001
219199
  total_mem_bytes: totalmem(),
219002
219200
  cpu_count: cpus().length
219003
- });
219201
+ };
219202
+ if (constrainedMemory !== void 0) properties["constrained_memory_bytes"] = constrainedMemory;
219203
+ this.client.track(SYSTEM_METRICS_EVENT, properties);
219004
219204
  }
219005
219205
  };
219006
219206
  function getConstrainedMemoryBytes() {
219007
219207
  if (typeof process.constrainedMemory !== "function") return void 0;
219008
219208
  const value = process.constrainedMemory();
219009
- return Number.isFinite(value) ? value : void 0;
219209
+ return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
219010
219210
  }
219011
219211
  const SERVER_EVENT_PREFIX = "kfc_";
219012
219212
  const USER_ID_PREFIX = "kfc_device_id_";
@@ -238571,7 +238771,10 @@ async function compressPromptImageParts(parts, options = {}) {
238571
238771
  if (part.type === "image_url") {
238572
238772
  const parsed = parseImageDataUrl(part.imageUrl.url);
238573
238773
  if (parsed !== null) {
238574
- const result = await compressBase64ForModel(parsed.base64, parsed.mimeType);
238774
+ const result = await compressBase64ForModel(parsed.base64, parsed.mimeType, { telemetry: options.telemetry === void 0 ? void 0 : {
238775
+ client: options.telemetry,
238776
+ source: "acp_prompt"
238777
+ } });
238575
238778
  if (result.changed) {
238576
238779
  const originalPath = await persistOriginalImage(Buffer.from(parsed.base64, "base64"), parsed.mimeType, options.originalsDir === void 0 ? {} : { dir: options.originalsDir });
238577
238780
  out.push({
@@ -240372,7 +240575,11 @@ var AcpSession = class {
240372
240575
  let parts;
240373
240576
  try {
240374
240577
  const sessionDir = this.session.summary?.sessionDir;
240375
- parts = await compressPromptImageParts(acpBlocksToPromptParts(blocks), { originalsDir: sessionDir === void 0 ? void 0 : sessionMediaOriginalsDir(sessionDir) });
240578
+ const track = this.track;
240579
+ parts = await compressPromptImageParts(acpBlocksToPromptParts(blocks), {
240580
+ originalsDir: sessionDir === void 0 ? void 0 : sessionMediaOriginalsDir(sessionDir),
240581
+ telemetry: track === void 0 ? void 0 : { track: (event, properties) => track(event, properties === void 0 ? void 0 : { ...properties }) }
240582
+ });
240376
240583
  } finally {
240377
240584
  this.pendingPromptAborts.delete(pending);
240378
240585
  }
@@ -276137,10 +276344,13 @@ function registerPromptsRoutes(app, ix) {
276137
276344
  const promptService = a.get(IPromptService);
276138
276345
  const fileStore = a.get(IFileStore);
276139
276346
  const core = a.get(ICoreProcessService);
276140
- const resolved = await resolvePromptMediaFiles(body, fileStore, join(a.get(IEnvironmentService).homeDir, "cache"), { resolveOriginalsDir: async () => {
276141
- const sessionDir = (await core.rpc.listSessions({ sessionId: session_id }))[0]?.sessionDir;
276142
- return sessionDir === void 0 ? void 0 : sessionMediaOriginalsDir(sessionDir);
276143
- } });
276347
+ const resolved = await resolvePromptMediaFiles(body, fileStore, join(a.get(IEnvironmentService).homeDir, "cache"), {
276348
+ telemetry: core.telemetry === void 0 ? void 0 : withTelemetryContext$1(core.telemetry, { sessionId: session_id }),
276349
+ resolveOriginalsDir: async () => {
276350
+ const sessionDir = (await core.rpc.listSessions({ sessionId: session_id }))[0]?.sessionDir;
276351
+ return sessionDir === void 0 ? void 0 : sessionMediaOriginalsDir(sessionDir);
276352
+ }
276353
+ });
276144
276354
  return promptService.submit(session_id, resolved);
276145
276355
  });
276146
276356
  reply.send(okEnvelope(result, req.id));
@@ -276229,10 +276439,14 @@ async function resolvePromptMediaFiles(body, store, cacheDir, options = {}) {
276229
276439
  }
276230
276440
  return originalsDir;
276231
276441
  };
276442
+ const telemetryFor = (source) => options.telemetry === void 0 ? void 0 : {
276443
+ client: options.telemetry,
276444
+ source
276445
+ };
276232
276446
  const content = [];
276233
276447
  for (const part of body.content) {
276234
276448
  if (part.type === "image" && part.source.kind === "base64") {
276235
- const compressed = await compressBase64ForModel(part.source.data, part.source.media_type);
276449
+ const compressed = await compressBase64ForModel(part.source.data, part.source.media_type, { telemetry: telemetryFor("prompt_inline") });
276236
276450
  if (compressed.changed) {
276237
276451
  const dir = await resolveOriginalsDir();
276238
276452
  const originalPath = await persistOriginalImage(Buffer.from(part.source.data, "base64"), part.source.media_type, dir === void 0 ? {} : { dir });
@@ -276285,7 +276499,7 @@ async function resolvePromptMediaFiles(body, store, cacheDir, options = {}) {
276285
276499
  let mediaType = file.meta.media_type;
276286
276500
  let bytes = data;
276287
276501
  if (part.type === "image") {
276288
- const compressed = await compressImageForModel(data, mediaType);
276502
+ const compressed = await compressImageForModel(data, mediaType, { telemetry: telemetryFor("prompt_file") });
276289
276503
  if (compressed.changed) content.push({
276290
276504
  type: "text",
276291
276505
  text: buildImageCompressionCaption({
@@ -368352,7 +368566,11 @@ init_dist$7();
368352
368566
  *
368353
368567
  * Used to bound shutdown so a wedged cleanup step can't keep a completed
368354
368568
  * headless run alive, without silently swallowing a cleanup that fails fast. The
368355
- * timer is unref'd so it never keeps the loop alive on its own.
368569
+ * timer stays ref'd so a cleanup step that suspends on an unref'd handle (e.g.
368570
+ * telemetry's retry backoff when the network is blocked) can't drain the event
368571
+ * loop and exit 0 before the rejection propagates — the timer keeps the loop
368572
+ * alive until it fires, then gives the rejection a chance to surface. A wedged
368573
+ * cleanup is still bounded by `timeoutMs`, so this can't hang the run forever.
368356
368574
  */
368357
368575
  async function raceWithTimeout(promise, timeoutMs) {
368358
368576
  let timedOut = false;
@@ -368366,7 +368584,6 @@ async function raceWithTimeout(promise, timeoutMs) {
368366
368584
  timedOut = true;
368367
368585
  resolve();
368368
368586
  }, timeoutMs);
368369
- timer.unref?.();
368370
368587
  });
368371
368588
  try {
368372
368589
  await Promise.race([guarded, timedOutSignal]);
@@ -374112,15 +374329,18 @@ var EditorKeyboardController = class {
374112
374329
  }
374113
374330
  const meta = parseImageMeta(media.bytes);
374114
374331
  if (meta === null) return false;
374115
- const compressed = await compressImageForModel(media.bytes, meta.mime);
374332
+ const compressed = await compressImageForModel(media.bytes, meta.mime, { telemetry: {
374333
+ client: { track: (event, properties) => this.host.track(event, properties === void 0 ? void 0 : { ...properties }) },
374334
+ source: "tui_paste"
374335
+ } });
374116
374336
  const sessionDir = this.host.session?.summary?.sessionDir;
374117
374337
  const attachment = compressed.changed ? this.imageStore.addImage(compressed.data, compressed.mimeType, compressed.width, compressed.height, {
374118
374338
  path: await persistOriginalImage(media.bytes, meta.mime, sessionDir === void 0 ? {} : { dir: sessionMediaOriginalsDir(sessionDir) }),
374119
- width: meta.width,
374120
- height: meta.height,
374339
+ width: compressed.originalWidth,
374340
+ height: compressed.originalHeight,
374121
374341
  byteLength: media.bytes.length,
374122
374342
  mime: meta.mime
374123
- }) : this.imageStore.addImage(media.bytes, meta.mime, meta.width, meta.height);
374343
+ }) : this.imageStore.addImage(media.bytes, meta.mime, compressed.width || meta.width, compressed.height || meta.height);
374124
374344
  this.host.state.editor.insertTextAtCursor?.(`${attachment.placeholder} `);
374125
374345
  this.host.state.ui.requestRender();
374126
374346
  this.host.track("shortcut_paste", { kind: "image" });
@@ -383290,6 +383510,7 @@ function main() {
383290
383510
  handleMainCommand(opts, version).then(async (outcome) => {
383291
383511
  if (outcome.headlessCompleted) await finalizeHeadlessRun(process, [process.stdout, process.stderr], () => Number(process.exitCode) || 0);
383292
383512
  }).catch(async (error) => {
383513
+ process.exitCode = 1;
383293
383514
  const operation = opts.prompt !== void 0 ? "run prompt" : "start shell";
383294
383515
  await logStartupFailure(operation, error);
383295
383516
  process.stderr.write(formatStartupError(error, { operation }));