@heylemon/lemonade 2026.2.19 → 2026.2.21

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2026.2.19",
3
- "commit": "c777f36571f501d0553aacf38e22f45e00f135b2",
4
- "builtAt": "2026-02-19T10:34:34.300Z"
2
+ "version": "2026.2.21",
3
+ "commit": "f1adf7fa5b1b100dc4f58d4325177d6e5b5b8a7d",
4
+ "builtAt": "2026-02-19T11:32:30.329Z"
5
5
  }
@@ -1 +1 @@
1
- 65a14b12e4ff701a566b2ab1dd533ba4b4789395611a1e7af703c28197f10d78
1
+ 61cedf672a2f645b8bc0c25ed3098af955cc9ee4c0a98935bd816883b972f478
@@ -426,6 +426,12 @@ async function resolveAutoEntries(params) {
426
426
  return [keys];
427
427
  return [];
428
428
  }
429
+ function isWhatsAppContext(ctx) {
430
+ const candidates = [ctx.Surface, ctx.Provider, ctx.OriginatingChannel]
431
+ .map((value) => value?.trim().toLowerCase())
432
+ .filter((value) => Boolean(value));
433
+ return candidates.some((value) => value === "whatsapp");
434
+ }
429
435
  export async function resolveAutoImageModel(params) {
430
436
  const providerRegistry = buildProviderRegistry();
431
437
  const toActive = (entry) => {
@@ -1001,6 +1007,70 @@ export async function runCapability(params) {
1001
1007
  };
1002
1008
  }
1003
1009
  }
1010
+ // For WhatsApp audio, force local Parakeet transcription only.
1011
+ // Do not fall back to whisper/provider-based transcription paths.
1012
+ if (capability === "audio" && isWhatsAppContext(ctx)) {
1013
+ const parakeetEntry = await resolveLocalParakeetEntry();
1014
+ if (!parakeetEntry) {
1015
+ if (shouldLogVerbose()) {
1016
+ logVerbose("audio understanding skipped for WhatsApp: local Parakeet is unavailable");
1017
+ }
1018
+ return {
1019
+ outputs: [],
1020
+ decision: {
1021
+ capability,
1022
+ outcome: "skipped",
1023
+ attachments: selected.map((item) => ({
1024
+ attachmentIndex: item.index,
1025
+ attempts: [
1026
+ {
1027
+ type: "cli",
1028
+ provider: "local-parakeet",
1029
+ model: "parakeet",
1030
+ outcome: "skipped",
1031
+ reason: "local Parakeet unavailable",
1032
+ },
1033
+ ],
1034
+ chosen: undefined,
1035
+ })),
1036
+ },
1037
+ };
1038
+ }
1039
+ const outputs = [];
1040
+ const attachmentDecisions = [];
1041
+ for (const attachment of selected) {
1042
+ const { output, attempts } = await runAttachmentEntries({
1043
+ capability,
1044
+ cfg,
1045
+ ctx,
1046
+ attachmentIndex: attachment.index,
1047
+ agentDir: params.agentDir,
1048
+ providerRegistry: params.providerRegistry,
1049
+ cache: params.attachments,
1050
+ entries: [parakeetEntry],
1051
+ config,
1052
+ });
1053
+ if (output)
1054
+ outputs.push(output);
1055
+ attachmentDecisions.push({
1056
+ attachmentIndex: attachment.index,
1057
+ attempts,
1058
+ chosen: attempts.find((attempt) => attempt.outcome === "success"),
1059
+ });
1060
+ }
1061
+ const decision = {
1062
+ capability,
1063
+ outcome: outputs.length > 0 ? "success" : "skipped",
1064
+ attachments: attachmentDecisions,
1065
+ };
1066
+ if (shouldLogVerbose()) {
1067
+ logVerbose(`Media understanding ${formatDecisionSummary(decision)} (forced local Parakeet)`);
1068
+ }
1069
+ return {
1070
+ outputs,
1071
+ decision,
1072
+ };
1073
+ }
1004
1074
  const entries = resolveModelEntries({
1005
1075
  cfg,
1006
1076
  capability,
@@ -333,7 +333,9 @@ export async function monitorWebInbox(options) {
333
333
  const maxBytes = maxMb * 1024 * 1024;
334
334
  const saved = await saveMediaBuffer(inboundMedia.buffer, inboundMedia.mimetype, "inbound", maxBytes);
335
335
  mediaPath = saved.path;
336
- mediaType = inboundMedia.mimetype;
336
+ // Prefer detected mime from saved media (sniffed from bytes), then
337
+ // fall back to transport-provided mimetype.
338
+ mediaType = saved.contentType ?? inboundMedia.mimetype;
337
339
  // Extract text from document attachments (PDF, DOCX, etc.)
338
340
  if (mediaPath && isExtractableDocument(mediaType)) {
339
341
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heylemon/lemonade",
3
- "version": "2026.2.19",
3
+ "version": "2026.2.21",
4
4
  "description": "AI gateway CLI for Lemon - local AI assistant with integrations",
5
5
  "publishConfig": {
6
6
  "access": "restricted"