wagent 1.0.0 → 1.0.2

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.
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import "./quiet-console.js";
2
3
  import { InstanceManager } from "./services/instance-manager.js";
3
4
  import { createChildLogger } from "./utils/logger.js";
4
5
  import { generateText, tool } from "ai";
@@ -15,6 +16,12 @@ const typingUntil = new Map();
15
16
  function getOwnJid(adapter) {
16
17
  return adapter.getMyJid();
17
18
  }
19
+ function toUserJid(jid) {
20
+ if (!jid || !jid.includes("@"))
21
+ return jid;
22
+ const [user, domain] = jid.split("@");
23
+ return `${user.split(":")[0]}@${domain}`;
24
+ }
18
25
  function getContactName(adapter, jid) {
19
26
  return adapter.getContacts(jid).then((c) => {
20
27
  const match = c.find((x) => x.jid === jid);
@@ -146,7 +153,7 @@ function buildTools(adapter) {
146
153
  execute: async ({ to, text, quotedMessageId }, { experimental_context }) => {
147
154
  const ctx = experimental_context;
148
155
  const target = await resolveTarget(adapter, to, ctx);
149
- const content = { type: "text", text };
156
+ const content = { type: "text", text: withAgentPrefix(text) };
150
157
  if (quotedMessageId)
151
158
  content.quotedMessageId = quotedMessageId;
152
159
  await delayBeforeReply(ctx.config);
@@ -677,15 +684,34 @@ function messageCanReachAgent(config, event, isSelf, text) {
677
684
  function isConfirmation(text) {
678
685
  return /\b(confirm|confirmed|approve|approved|yes|ship it|looks good)\b/i.test(text);
679
686
  }
687
+ function isPromptDraftRequest(text) {
688
+ return /\b(enough|draft|write.*prompt|make.*prompt|system prompt|ready|done|that's it|that is it)\b/i.test(text);
689
+ }
690
+ function maybeExtractSayCommand(text) {
691
+ const match = text.match(/^\s*say\s+["']?(.+?)["']?\s*$/i);
692
+ return match?.[1]?.trim() ?? null;
693
+ }
694
+ function withAgentPrefix(text) {
695
+ return text.trim().toLowerCase().startsWith("wagent:") ? text : `wagent: ${text}`;
696
+ }
697
+ function nextBootstrapQuestion(notes) {
698
+ const questions = [
699
+ "Got it. Who are you to me, and what should I call you?",
700
+ "What should my purpose be?",
701
+ "Who am I allowed to read or reply to?",
702
+ "What vibe should I use when I talk?",
703
+ ];
704
+ return questions[Math.min(Math.max(notes.length - 1, 0), questions.length - 1)];
705
+ }
680
706
  async function sendTracked(adapter, to, text) {
681
- const res = await adapter.sendMessage(to, { type: "text", text });
707
+ const res = await adapter.sendMessage(to, { type: "text", text: withAgentPrefix(text) });
682
708
  rememberAgentMessage(res.messageId);
683
709
  }
684
710
  async function startBootstrap(adapter, config, myJid) {
685
711
  if (config.agent.bootstrapStarted || config.agent.mode !== "bootstrap")
686
712
  return config;
687
713
  await sendTracked(adapter, myJid, "I'm online. I don't know who I am yet.");
688
- await sendTracked(adapter, myJid, "Tell me my purpose, your relationship to me, my vibe, and who I can read or reply to.");
714
+ await sendTracked(adapter, myJid, "Tell me my purpose, what to call you, my vibe, and who I can read/reply to. Say 'draft prompt' when ready.");
689
715
  await sendTracked(adapter, myJid, "I can message contacts, manage WhatsApp tools, remember context, compact memory, and enforce read/reply permissions.");
690
716
  config.agent.bootstrapStarted = true;
691
717
  saveConfig(config);
@@ -701,7 +727,24 @@ async function handleBootstrapMessage(adapter, config, chatId, text) {
701
727
  await sendTracked(adapter, chatId, "Confirmed. I compacted setup context and will follow this system prompt from now on.");
702
728
  return config;
703
729
  }
730
+ if (config.agent.pendingSystemPrompt && !isConfirmation(text)) {
731
+ config.agent.pendingSystemPrompt = undefined;
732
+ config.agent.bootstrapNotes.push(`Feedback on rejected draft: ${text}`);
733
+ saveConfig(config);
734
+ await sendTracked(adapter, chatId, "Okay, I won't use that draft. Tell me what to change, or say 'draft prompt' when ready.");
735
+ return config;
736
+ }
737
+ const say = maybeExtractSayCommand(text);
738
+ if (say) {
739
+ await sendTracked(adapter, chatId, say);
740
+ return config;
741
+ }
704
742
  config.agent.bootstrapNotes.push(text);
743
+ if (!isPromptDraftRequest(text)) {
744
+ saveConfig(config);
745
+ await sendTracked(adapter, chatId, nextBootstrapQuestion(config.agent.bootstrapNotes));
746
+ return config;
747
+ }
705
748
  const draft = await generateWithFallback(config, {
706
749
  system: "Draft a concise first-person system prompt for a WhatsApp agent from the user's setup notes. Include identity, purpose, vibe, read/reply boundaries, and tool behavior. Return only the prompt.",
707
750
  messages: [{ role: "user", content: config.agent.bootstrapNotes.join("\n\n") }],
@@ -743,7 +786,7 @@ async function processMessage(adapter, config, instId, event, text, isSelf, send
743
786
  if (responseText) {
744
787
  await adapter.sendPresence(chatId, "composing");
745
788
  await delayBeforeReply(config);
746
- const content = { type: "text", text: responseText };
789
+ const content = { type: "text", text: withAgentPrefix(responseText) };
747
790
  const res = await adapter.sendMessage(chatId, content);
748
791
  rememberAgentMessage(res.messageId);
749
792
  await adapter.sendPresence(chatId, "paused");
@@ -751,7 +794,7 @@ async function processMessage(adapter, config, instId, event, text, isSelf, send
751
794
  }
752
795
  else if (allToolCalls.length > 0) {
753
796
  logger.info({ chatId, toolCount: allToolCalls.length }, "Tools executed silently");
754
- const res = await adapter.sendMessage(chatId, { type: "text", text: "Done." });
797
+ const res = await adapter.sendMessage(chatId, { type: "text", text: withAgentPrefix("Done.") });
755
798
  rememberAgentMessage(res.messageId);
756
799
  }
757
800
  }
@@ -759,7 +802,7 @@ async function processMessage(adapter, config, instId, event, text, isSelf, send
759
802
  const msg = err instanceof Error ? err.message : String(err);
760
803
  logger.error({ err, chatId }, "Agent error");
761
804
  try {
762
- const fallback = "Sorry, I hit an error processing that. Please try again.";
805
+ const fallback = withAgentPrefix("Sorry, I hit an error processing that. Please try again.");
763
806
  const res = await adapter.sendMessage(chatId, { type: "text", text: fallback });
764
807
  rememberAgentMessage(res.messageId);
765
808
  }
@@ -794,6 +837,7 @@ async function main() {
794
837
  instanceId = instances[0].id;
795
838
  }
796
839
  let myJid = null;
840
+ let myUserJid = null;
797
841
  instanceManager.onAnyEvent((event, instId, payload) => {
798
842
  if (event === "connection.changed" && instId === instanceId) {
799
843
  const conn = payload;
@@ -804,6 +848,7 @@ async function main() {
804
848
  if (conn.status === "open") {
805
849
  const adapter = instanceManager.getAdapter(instId);
806
850
  myJid = getOwnJid(adapter);
851
+ myUserJid = toUserJid(myJid);
807
852
  console.log(`\nWhatsApp connected as ${myJid}`);
808
853
  }
809
854
  }
@@ -812,7 +857,8 @@ async function main() {
812
857
  const adapter = instanceManager.getAdapter(instanceId);
813
858
  for (let i = 0; i < 60; i++) {
814
859
  myJid = getOwnJid(adapter);
815
- if (myJid)
860
+ myUserJid = toUserJid(myJid);
861
+ if (myJid && myUserJid)
816
862
  break;
817
863
  await new Promise((r) => setTimeout(r, 1000));
818
864
  }
@@ -822,7 +868,7 @@ async function main() {
822
868
  }
823
869
  config = await ensureAiConfig(config);
824
870
  const tools = buildTools(adapter);
825
- config = await startBootstrap(adapter, config, myJid);
871
+ config = await startBootstrap(adapter, config, myUserJid ?? myJid);
826
872
  console.log("Agent ready. Message yourself to configure or command it.");
827
873
  instanceManager.onAnyEvent(async (event, instId, payload) => {
828
874
  if (event === "presence.updated" && instId === instanceId) {
@@ -850,11 +896,11 @@ async function main() {
850
896
  for (const k of toDelete)
851
897
  processedMessages.delete(k);
852
898
  }
853
- const isSelf = msg.message.sender === myJid || msg.message.isFromMe;
854
- if (!messageCanReachAgent(config, msg, isSelf, text))
899
+ const isOwnerSelfChat = Boolean(msg.message.isFromMe && myUserJid && msg.chatId === myUserJid);
900
+ if (!messageCanReachAgent(config, msg, isOwnerSelfChat, text))
855
901
  return;
856
902
  await waitForTypingToStop(msg.chatId);
857
- if (config.agent.mode === "bootstrap" && isSelf) {
903
+ if (config.agent.mode === "bootstrap" && isOwnerSelfChat) {
858
904
  config = await handleBootstrapMessage(adapter, config, msg.chatId, text);
859
905
  return;
860
906
  }
@@ -862,7 +908,7 @@ async function main() {
862
908
  const chatName = msg.chatId.endsWith("@g.us")
863
909
  ? await getGroupName(adapter, msg.chatId)
864
910
  : senderName;
865
- processMessage(adapter, config, instanceId, msg, text, isSelf, senderName, chatName, tools)
911
+ processMessage(adapter, config, instanceId, msg, text, isOwnerSelfChat, senderName, chatName, tools)
866
912
  .catch((err) => logger.error({ err }, "processMessage error"));
867
913
  }
868
914
  });
@@ -0,0 +1,31 @@
1
+ const originalConsole = {
2
+ log: console.log.bind(console),
3
+ warn: console.warn.bind(console),
4
+ error: console.error.bind(console),
5
+ };
6
+ function shouldSuppressConsole(args) {
7
+ if (process.argv.includes("--debug"))
8
+ return false;
9
+ const text = args.map((arg) => (typeof arg === "string" ? arg : "")).join(" ");
10
+ return (text.startsWith("Closing session:") ||
11
+ text.includes("Decrypted message with closed session") ||
12
+ text.includes("stream errored out") ||
13
+ text.includes("no name present") ||
14
+ text.includes("blocked on missing key") ||
15
+ text.includes("failed to find key") ||
16
+ text.includes("transaction failed") ||
17
+ text.includes("failed to decrypt message"));
18
+ }
19
+ console.log = (...args) => {
20
+ if (!shouldSuppressConsole(args))
21
+ originalConsole.log(...args);
22
+ };
23
+ console.warn = (...args) => {
24
+ if (!shouldSuppressConsole(args))
25
+ originalConsole.warn(...args);
26
+ };
27
+ console.error = (...args) => {
28
+ if (!shouldSuppressConsole(args))
29
+ originalConsole.error(...args);
30
+ };
31
+ export {};
@@ -2,12 +2,12 @@
2
2
  // WA MCP — Structured Logger with Request Tracing
3
3
  // ============================================================
4
4
  import pino from "pino";
5
- import { SERVER_NAME, DEFAULT_LOG_LEVEL } from "../constants.js";
5
+ import { SERVER_NAME } from "../constants.js";
6
6
  const logLevel = process.argv.includes("--debug")
7
7
  ? "debug"
8
8
  : process.argv.includes("--verbose")
9
9
  ? "info"
10
- : DEFAULT_LOG_LEVEL;
10
+ : "silent";
11
11
  const isStdio = process.env.WA_TRANSPORT === "stdio";
12
12
  export const logger = pino({
13
13
  name: SERVER_NAME,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wagent",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "WhatsApp Agent — AI-powered WhatsApp assistant using WAMCP + Groq",
5
5
  "type": "module",
6
6
  "bin": {