@heylemon/lemonade 2026.2.20 → 2026.2.23

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.20",
3
- "commit": "e49805d8488591840c53c697252f44ddfa686424",
4
- "builtAt": "2026-02-19T10:41:08.140Z"
2
+ "version": "2026.2.23",
3
+ "commit": "f1adf7fa5b1b100dc4f58d4325177d6e5b5b8a7d",
4
+ "builtAt": "2026-02-19T12:51:54.600Z"
5
5
  }
@@ -1 +1 @@
1
- 097295da59112a03be00996fb0b774b800b315f4a291f6253930f4d42aa9a1ac
1
+ 00d7457932c72398a32d50708e2b4ec5f036c496f20116275d6f99bddf66b38c
@@ -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,78 @@ 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 a synthetic transcription so the agent doesn't hallucinate
1019
+ // about installing Whisper or other transcription tools.
1020
+ return {
1021
+ outputs: selected.map((item) => ({
1022
+ kind: "audio.transcription",
1023
+ attachmentIndex: item.index,
1024
+ text: "[Voice message received. The user sent an audio note but transcription is temporarily unavailable. Ask them to send a text message instead.]",
1025
+ provider: "local-parakeet",
1026
+ model: "parakeet",
1027
+ })),
1028
+ decision: {
1029
+ capability,
1030
+ outcome: "success",
1031
+ attachments: selected.map((item) => ({
1032
+ attachmentIndex: item.index,
1033
+ attempts: [
1034
+ {
1035
+ type: "cli",
1036
+ provider: "local-parakeet",
1037
+ model: "parakeet",
1038
+ outcome: "skipped",
1039
+ reason: "local Parakeet unavailable – injected placeholder",
1040
+ },
1041
+ ],
1042
+ chosen: undefined,
1043
+ })),
1044
+ },
1045
+ };
1046
+ }
1047
+ const outputs = [];
1048
+ const attachmentDecisions = [];
1049
+ for (const attachment of selected) {
1050
+ const { output, attempts } = await runAttachmentEntries({
1051
+ capability,
1052
+ cfg,
1053
+ ctx,
1054
+ attachmentIndex: attachment.index,
1055
+ agentDir: params.agentDir,
1056
+ providerRegistry: params.providerRegistry,
1057
+ cache: params.attachments,
1058
+ entries: [parakeetEntry],
1059
+ config,
1060
+ });
1061
+ if (output)
1062
+ outputs.push(output);
1063
+ attachmentDecisions.push({
1064
+ attachmentIndex: attachment.index,
1065
+ attempts,
1066
+ chosen: attempts.find((attempt) => attempt.outcome === "success"),
1067
+ });
1068
+ }
1069
+ const decision = {
1070
+ capability,
1071
+ outcome: outputs.length > 0 ? "success" : "skipped",
1072
+ attachments: attachmentDecisions,
1073
+ };
1074
+ if (shouldLogVerbose()) {
1075
+ logVerbose(`Media understanding ${formatDecisionSummary(decision)} (forced local Parakeet)`);
1076
+ }
1077
+ return {
1078
+ outputs,
1079
+ decision,
1080
+ };
1081
+ }
1004
1082
  const entries = resolveModelEntries({
1005
1083
  cfg,
1006
1084
  capability,
@@ -26,6 +26,10 @@ read_when:
26
26
  - Never send half-baked replies to messaging surfaces.
27
27
  - You're not the user's voice — be careful in group chats.
28
28
 
29
+ ## Conversation
30
+
31
+ When someone greets you or asks how you're doing, answer them like a human would. Say "I'm doing great!" or "All good on my end!" — don't just bounce their question back or immediately pivot to "what can I help with?" Small talk is fine. Be warm first, task-oriented second.
32
+
29
33
  ## Vibe
30
34
 
31
35
  Be the assistant you'd actually want to talk to. Concise when needed, thorough when it matters. Not a corporate drone. Not a sycophant. Just... good.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heylemon/lemonade",
3
- "version": "2026.2.20",
3
+ "version": "2026.2.23",
4
4
  "description": "AI gateway CLI for Lemon - local AI assistant with integrations",
5
5
  "publishConfig": {
6
6
  "access": "restricted"