chore: format + regenerate protocol
This commit is contained in:
@@ -357,7 +357,7 @@ public struct SendParams: Codable, Sendable {
|
|||||||
gifplayback: Bool?,
|
gifplayback: Bool?,
|
||||||
channel: String?,
|
channel: String?,
|
||||||
accountid: String?,
|
accountid: String?,
|
||||||
sessionkey: String? = nil,
|
sessionkey: String?,
|
||||||
idempotencykey: String
|
idempotencykey: String
|
||||||
) {
|
) {
|
||||||
self.to = to
|
self.to = to
|
||||||
@@ -431,6 +431,7 @@ public struct AgentParams: Codable, Sendable {
|
|||||||
public let deliver: Bool?
|
public let deliver: Bool?
|
||||||
public let attachments: [AnyCodable]?
|
public let attachments: [AnyCodable]?
|
||||||
public let channel: String?
|
public let channel: String?
|
||||||
|
public let accountid: String?
|
||||||
public let timeout: Int?
|
public let timeout: Int?
|
||||||
public let lane: String?
|
public let lane: String?
|
||||||
public let extrasystemprompt: String?
|
public let extrasystemprompt: String?
|
||||||
@@ -447,6 +448,7 @@ public struct AgentParams: Codable, Sendable {
|
|||||||
deliver: Bool?,
|
deliver: Bool?,
|
||||||
attachments: [AnyCodable]?,
|
attachments: [AnyCodable]?,
|
||||||
channel: String?,
|
channel: String?,
|
||||||
|
accountid: String?,
|
||||||
timeout: Int?,
|
timeout: Int?,
|
||||||
lane: String?,
|
lane: String?,
|
||||||
extrasystemprompt: String?,
|
extrasystemprompt: String?,
|
||||||
@@ -462,6 +464,7 @@ public struct AgentParams: Codable, Sendable {
|
|||||||
self.deliver = deliver
|
self.deliver = deliver
|
||||||
self.attachments = attachments
|
self.attachments = attachments
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
|
self.accountid = accountid
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
self.lane = lane
|
self.lane = lane
|
||||||
self.extrasystemprompt = extrasystemprompt
|
self.extrasystemprompt = extrasystemprompt
|
||||||
@@ -478,6 +481,7 @@ public struct AgentParams: Codable, Sendable {
|
|||||||
case deliver
|
case deliver
|
||||||
case attachments
|
case attachments
|
||||||
case channel
|
case channel
|
||||||
|
case accountid = "accountId"
|
||||||
case timeout
|
case timeout
|
||||||
case lane
|
case lane
|
||||||
case extrasystemprompt = "extraSystemPrompt"
|
case extrasystemprompt = "extraSystemPrompt"
|
||||||
|
|||||||
@@ -37,5 +37,7 @@ export function channelTargetSchema(options?: { description?: string }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function channelTargetsSchema(options?: { description?: string }) {
|
export function channelTargetsSchema(options?: { description?: string }) {
|
||||||
return Type.Array(channelTargetSchema({ description: options?.description ?? CHANNEL_TARGETS_DESCRIPTION }));
|
return Type.Array(
|
||||||
|
channelTargetSchema({ description: options?.description ?? CHANNEL_TARGETS_DESCRIPTION }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,7 @@ import {
|
|||||||
} from "../auto-reply/reply/queue.js";
|
} from "../auto-reply/reply/queue.js";
|
||||||
import { callGateway } from "../gateway/call.js";
|
import { callGateway } from "../gateway/call.js";
|
||||||
import { defaultRuntime } from "../runtime.js";
|
import { defaultRuntime } from "../runtime.js";
|
||||||
import {
|
import { type DeliveryContext, normalizeDeliveryContext } from "../utils/delivery-context.js";
|
||||||
type DeliveryContext,
|
|
||||||
normalizeDeliveryContext,
|
|
||||||
} from "../utils/delivery-context.js";
|
|
||||||
import { isEmbeddedPiRunActive, queueEmbeddedPiMessage } from "./pi-embedded.js";
|
import { isEmbeddedPiRunActive, queueEmbeddedPiMessage } from "./pi-embedded.js";
|
||||||
import { readLatestAssistantReply } from "./tools/agent-step.js";
|
import { readLatestAssistantReply } from "./tools/agent-step.js";
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ describe("formatInboundBodyWithSenderMeta", () => {
|
|||||||
|
|
||||||
it("appends a sender meta line for non-direct messages", () => {
|
it("appends a sender meta line for non-direct messages", () => {
|
||||||
const ctx: MsgContext = { ChatType: "group", SenderName: "Alice", SenderId: "A1" };
|
const ctx: MsgContext = { ChatType: "group", SenderName: "Alice", SenderId: "A1" };
|
||||||
expect(formatInboundBodyWithSenderMeta({ ctx, body: "[X] hi" })).toBe("[X] hi\n[from: Alice (A1)]");
|
expect(formatInboundBodyWithSenderMeta({ ctx, body: "[X] hi" })).toBe(
|
||||||
|
"[X] hi\n[from: Alice (A1)]",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("prefers SenderE164 in the label when present", () => {
|
it("prefers SenderE164 in the label when present", () => {
|
||||||
@@ -21,7 +23,9 @@ describe("formatInboundBodyWithSenderMeta", () => {
|
|||||||
SenderId: "bob@s.whatsapp.net",
|
SenderId: "bob@s.whatsapp.net",
|
||||||
SenderE164: "+222",
|
SenderE164: "+222",
|
||||||
};
|
};
|
||||||
expect(formatInboundBodyWithSenderMeta({ ctx, body: "[X] hi" })).toBe("[X] hi\n[from: Bob (+222)]");
|
expect(formatInboundBodyWithSenderMeta({ ctx, body: "[X] hi" })).toBe(
|
||||||
|
"[X] hi\n[from: Bob (+222)]",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("preserves escaped newline style when body uses literal \\\\n", () => {
|
it("preserves escaped newline style when body uses literal \\\\n", () => {
|
||||||
@@ -38,4 +42,3 @@ describe("formatInboundBodyWithSenderMeta", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
import type { MsgContext } from "../templating.js";
|
import type { MsgContext } from "../templating.js";
|
||||||
|
|
||||||
export function formatInboundBodyWithSenderMeta(params: {
|
export function formatInboundBodyWithSenderMeta(params: { body: string; ctx: MsgContext }): string {
|
||||||
body: string;
|
|
||||||
ctx: MsgContext;
|
|
||||||
}): string {
|
|
||||||
const body = params.body;
|
const body = params.body;
|
||||||
if (!body.trim()) return body;
|
if (!body.trim()) return body;
|
||||||
const chatType = params.ctx.ChatType?.trim().toLowerCase();
|
const chatType = params.ctx.ChatType?.trim().toLowerCase();
|
||||||
|
|||||||
@@ -49,4 +49,3 @@ describe("initSessionState sender meta", () => {
|
|||||||
expect(result.sessionCtx.BodyStripped).toBe("[WhatsApp +1] ping");
|
expect(result.sessionCtx.BodyStripped).toBe("[WhatsApp +1] ping");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -234,8 +234,7 @@ export const discordPlugin: ChannelPlugin<ResolvedDiscordAccount> = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const filtered = q ? rows.filter((row) => row.name?.toLowerCase().includes(q)) : rows;
|
const filtered = q ? rows.filter((row) => row.name?.toLowerCase().includes(q)) : rows;
|
||||||
const limited =
|
const limited = typeof limit === "number" && limit > 0 ? filtered.slice(0, limit) : filtered;
|
||||||
typeof limit === "number" && limit > 0 ? filtered.slice(0, limit) : filtered;
|
|
||||||
return limited;
|
return limited;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,15 +25,9 @@ export function createMessageCliHelpers(
|
|||||||
.option("--verbose", "Verbose logging", false);
|
.option("--verbose", "Verbose logging", false);
|
||||||
|
|
||||||
const withMessageTarget = (command: Command) =>
|
const withMessageTarget = (command: Command) =>
|
||||||
command.option(
|
command.option("-t, --to <dest>", CHANNEL_TARGET_DESCRIPTION);
|
||||||
"-t, --to <dest>",
|
|
||||||
CHANNEL_TARGET_DESCRIPTION,
|
|
||||||
);
|
|
||||||
const withRequiredMessageTarget = (command: Command) =>
|
const withRequiredMessageTarget = (command: Command) =>
|
||||||
command.requiredOption(
|
command.requiredOption("-t, --to <dest>", CHANNEL_TARGET_DESCRIPTION);
|
||||||
"-t, --to <dest>",
|
|
||||||
CHANNEL_TARGET_DESCRIPTION,
|
|
||||||
);
|
|
||||||
|
|
||||||
const runMessageAction = async (action: string, opts: Record<string, unknown>) => {
|
const runMessageAction = async (action: string, opts: Record<string, unknown>) => {
|
||||||
setVerbose(Boolean(opts.verbose));
|
setVerbose(Boolean(opts.verbose));
|
||||||
|
|||||||
@@ -7,10 +7,7 @@ export function registerMessageBroadcastCommand(message: Command, helpers: Messa
|
|||||||
.withMessageBase(
|
.withMessageBase(
|
||||||
message.command("broadcast").description("Broadcast a message to multiple targets"),
|
message.command("broadcast").description("Broadcast a message to multiple targets"),
|
||||||
)
|
)
|
||||||
.requiredOption(
|
.requiredOption("--targets <target...>", CHANNEL_TARGETS_DESCRIPTION)
|
||||||
"--targets <target...>",
|
|
||||||
CHANNEL_TARGETS_DESCRIPTION,
|
|
||||||
)
|
|
||||||
.option("--message <text>", "Message to send")
|
.option("--message <text>", "Message to send")
|
||||||
.option("--media <url>", "Media URL")
|
.option("--media <url>", "Media URL")
|
||||||
.action(async (options: Record<string, unknown>) => {
|
.action(async (options: Record<string, unknown>) => {
|
||||||
|
|||||||
@@ -275,8 +275,7 @@ const FIELD_HELP: Record<string, string> = {
|
|||||||
'Text prefix for cross-context markers (supports "{channel}").',
|
'Text prefix for cross-context markers (supports "{channel}").',
|
||||||
"tools.message.crossContext.marker.suffix":
|
"tools.message.crossContext.marker.suffix":
|
||||||
'Text suffix for cross-context markers (supports "{channel}").',
|
'Text suffix for cross-context markers (supports "{channel}").',
|
||||||
"tools.message.broadcast.enabled":
|
"tools.message.broadcast.enabled": "Enable broadcast action (default: true).",
|
||||||
"Enable broadcast action (default: true).",
|
|
||||||
"tools.web.search.enabled": "Enable the web_search tool (requires Brave API key).",
|
"tools.web.search.enabled": "Enable the web_search tool (requires Brave API key).",
|
||||||
"tools.web.search.provider": 'Search provider (only "brave" supported today).',
|
"tools.web.search.provider": 'Search provider (only "brave" supported today).',
|
||||||
"tools.web.search.apiKey": "Brave Search API key (fallback: BRAVE_API_KEY env var).",
|
"tools.web.search.apiKey": "Brave Search API key (fallback: BRAVE_API_KEY env var).",
|
||||||
|
|||||||
@@ -202,8 +202,7 @@ export const agentHandlers: GatewayRequestHandlers = {
|
|||||||
const lastChannel = sessionEntry?.lastChannel;
|
const lastChannel = sessionEntry?.lastChannel;
|
||||||
const lastTo = typeof sessionEntry?.lastTo === "string" ? sessionEntry.lastTo.trim() : "";
|
const lastTo = typeof sessionEntry?.lastTo === "string" ? sessionEntry.lastTo.trim() : "";
|
||||||
const resolvedAccountId =
|
const resolvedAccountId =
|
||||||
normalizeAccountId(request.accountId) ??
|
normalizeAccountId(request.accountId) ?? normalizeAccountId(sessionEntry?.lastAccountId);
|
||||||
normalizeAccountId(sessionEntry?.lastAccountId);
|
|
||||||
|
|
||||||
const wantsDelivery = request.deliver === true;
|
const wantsDelivery = request.deliver === true;
|
||||||
|
|
||||||
|
|||||||
@@ -157,7 +157,10 @@ describe("runMessageAction context isolation", () => {
|
|||||||
to: "imessage:+15551230000",
|
to: "imessage:+15551230000",
|
||||||
message: "hi",
|
message: "hi",
|
||||||
},
|
},
|
||||||
toolContext: { currentChannelId: "imessage:+15551234567", currentChannelProvider: "imessage" },
|
toolContext: {
|
||||||
|
currentChannelId: "imessage:+15551234567",
|
||||||
|
currentChannelProvider: "imessage",
|
||||||
|
},
|
||||||
dryRun: true,
|
dryRun: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ import type {
|
|||||||
} from "../../channels/plugins/types.js";
|
} from "../../channels/plugins/types.js";
|
||||||
import type { ClawdbotConfig } from "../../config/config.js";
|
import type { ClawdbotConfig } from "../../config/config.js";
|
||||||
import type { GatewayClientMode, GatewayClientName } from "../../utils/message-channel.js";
|
import type { GatewayClientMode, GatewayClientName } from "../../utils/message-channel.js";
|
||||||
import { listConfiguredMessageChannels, resolveMessageChannelSelection } from "./channel-selection.js";
|
import {
|
||||||
|
listConfiguredMessageChannels,
|
||||||
|
resolveMessageChannelSelection,
|
||||||
|
} from "./channel-selection.js";
|
||||||
import type { OutboundSendDeps } from "./deliver.js";
|
import type { OutboundSendDeps } from "./deliver.js";
|
||||||
import type { MessagePollResult, MessageSendResult } from "./message.js";
|
import type { MessagePollResult, MessageSendResult } from "./message.js";
|
||||||
import { sendMessage, sendPoll } from "./message.js";
|
import { sendMessage, sendPoll } from "./message.js";
|
||||||
|
|||||||
@@ -77,7 +77,8 @@ export function enforceCrossContextPolicy(params: {
|
|||||||
if (params.cfg.tools?.message?.allowCrossContextSend) return;
|
if (params.cfg.tools?.message?.allowCrossContextSend) return;
|
||||||
|
|
||||||
const currentProvider = params.toolContext?.currentChannelProvider;
|
const currentProvider = params.toolContext?.currentChannelProvider;
|
||||||
const allowWithinProvider = params.cfg.tools?.message?.crossContext?.allowWithinProvider !== false;
|
const allowWithinProvider =
|
||||||
|
params.cfg.tools?.message?.crossContext?.allowWithinProvider !== false;
|
||||||
const allowAcrossProviders =
|
const allowAcrossProviders =
|
||||||
params.cfg.tools?.message?.crossContext?.allowAcrossProviders === true;
|
params.cfg.tools?.message?.crossContext?.allowAcrossProviders === true;
|
||||||
|
|
||||||
@@ -132,7 +133,7 @@ export async function buildCrossContextDecoration(params: {
|
|||||||
|
|
||||||
const adapter = getChannelMessageAdapter(params.channel);
|
const adapter = getChannelMessageAdapter(params.channel);
|
||||||
const embeds = adapter.supportsEmbeds
|
const embeds = adapter.supportsEmbeds
|
||||||
? adapter.buildCrossContextEmbeds?.(originLabel) ?? undefined
|
? (adapter.buildCrossContextEmbeds?.(originLabel) ?? undefined)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
return { prefix, suffix, embeds };
|
return { prefix, suffix, embeds };
|
||||||
|
|||||||
@@ -31,7 +31,10 @@ function normalizeQuery(value: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function stripTargetPrefixes(value: string): string {
|
function stripTargetPrefixes(value: string): string {
|
||||||
return value.replace(/^(channel|group|user):/i, "").replace(/^[@#]/, "").trim();
|
return value
|
||||||
|
.replace(/^(channel|group|user):/i, "")
|
||||||
|
.replace(/^[@#]/, "")
|
||||||
|
.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
function preserveTargetCase(channel: ChannelId, raw: string, normalized: string): string {
|
function preserveTargetCase(channel: ChannelId, raw: string, normalized: string): string {
|
||||||
@@ -132,7 +135,7 @@ async function listDirectoryEntries(params: {
|
|||||||
const runtime = params.runtime ?? defaultRuntime;
|
const runtime = params.runtime ?? defaultRuntime;
|
||||||
const useLive = params.source === "live";
|
const useLive = params.source === "live";
|
||||||
if (params.kind === "user") {
|
if (params.kind === "user") {
|
||||||
const fn = useLive ? directory.listPeersLive ?? directory.listPeers : directory.listPeers;
|
const fn = useLive ? (directory.listPeersLive ?? directory.listPeers) : directory.listPeers;
|
||||||
if (!fn) return [];
|
if (!fn) return [];
|
||||||
return await fn({
|
return await fn({
|
||||||
cfg: params.cfg,
|
cfg: params.cfg,
|
||||||
@@ -142,7 +145,7 @@ async function listDirectoryEntries(params: {
|
|||||||
runtime,
|
runtime,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const fn = useLive ? directory.listGroupsLive ?? directory.listGroups : directory.listGroups;
|
const fn = useLive ? (directory.listGroupsLive ?? directory.listGroups) : directory.listGroups;
|
||||||
if (!fn) return [];
|
if (!fn) return [];
|
||||||
return await fn({
|
return await fn({
|
||||||
cfg: params.cfg,
|
cfg: params.cfg,
|
||||||
@@ -254,9 +257,7 @@ export async function resolveMessagingTarget(params: {
|
|||||||
if (match.kind === "ambiguous") {
|
if (match.kind === "ambiguous") {
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
error: new Error(
|
error: new Error(`Ambiguous target "${raw}". Provide a unique name or an explicit id.`),
|
||||||
`Ambiguous target "${raw}". Provide a unique name or an explicit id.`,
|
|
||||||
),
|
|
||||||
candidates: match.entries,
|
candidates: match.entries,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -323,15 +323,13 @@ export const buildTelegramMessageContext = async ({
|
|||||||
replyTarget.id ? ` id:${replyTarget.id}` : ""
|
replyTarget.id ? ` id:${replyTarget.id}` : ""
|
||||||
}]\n${replyTarget.body}\n[/Replying]`
|
}]\n${replyTarget.body}\n[/Replying]`
|
||||||
: "";
|
: "";
|
||||||
const groupLabel = isGroup ? buildGroupLabel(msg, chatId, resolvedThreadId) : undefined;
|
const groupLabel = isGroup ? buildGroupLabel(msg, chatId, resolvedThreadId) : undefined;
|
||||||
const body = formatAgentEnvelope({
|
const body = formatAgentEnvelope({
|
||||||
channel: "Telegram",
|
channel: "Telegram",
|
||||||
from: isGroup
|
from: isGroup ? (groupLabel ?? `group:${chatId}`) : buildSenderLabel(msg, senderId || chatId),
|
||||||
? (groupLabel ?? `group:${chatId}`)
|
timestamp: msg.date ? msg.date * 1000 : undefined,
|
||||||
: buildSenderLabel(msg, senderId || chatId),
|
body: `${bodyText}${replySuffix}`,
|
||||||
timestamp: msg.date ? msg.date * 1000 : undefined,
|
});
|
||||||
body: `${bodyText}${replySuffix}`,
|
|
||||||
});
|
|
||||||
let combinedBody = body;
|
let combinedBody = body;
|
||||||
if (isGroup && historyKey && historyLimit > 0) {
|
if (isGroup && historyKey && historyLimit > 0) {
|
||||||
combinedBody = buildPendingHistoryContextFromMap({
|
combinedBody = buildPendingHistoryContextFromMap({
|
||||||
|
|||||||
@@ -171,17 +171,17 @@ describe("createTelegramBot", () => {
|
|||||||
getFile: async () => ({ download: async () => new Uint8Array() }),
|
getFile: async () => ({ download: async () => new Uint8Array() }),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(replySpy).toHaveBeenCalledTimes(1);
|
expect(replySpy).toHaveBeenCalledTimes(1);
|
||||||
const payload = replySpy.mock.calls[0][0];
|
const payload = replySpy.mock.calls[0][0];
|
||||||
expect(payload.WasMentioned).toBe(true);
|
expect(payload.WasMentioned).toBe(true);
|
||||||
expect(payload.SenderName).toBe("Ada");
|
expect(payload.SenderName).toBe("Ada");
|
||||||
expect(payload.SenderId).toBe("9");
|
expect(payload.SenderId).toBe("9");
|
||||||
expect(payload.Body).toMatch(/^\[Telegram Test Group id:7 2025-01-09T00:00Z\]/);
|
expect(payload.Body).toMatch(/^\[Telegram Test Group id:7 2025-01-09T00:00Z\]/);
|
||||||
});
|
});
|
||||||
it("keeps group envelope headers stable (sender identity is separate)", async () => {
|
it("keeps group envelope headers stable (sender identity is separate)", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
channels: {
|
channels: {
|
||||||
@@ -212,13 +212,13 @@ describe("createTelegramBot", () => {
|
|||||||
getFile: async () => ({ download: async () => new Uint8Array() }),
|
getFile: async () => ({ download: async () => new Uint8Array() }),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(replySpy).toHaveBeenCalledTimes(1);
|
expect(replySpy).toHaveBeenCalledTimes(1);
|
||||||
const payload = replySpy.mock.calls[0][0];
|
const payload = replySpy.mock.calls[0][0];
|
||||||
expect(payload.SenderName).toBe("Ada Lovelace");
|
expect(payload.SenderName).toBe("Ada Lovelace");
|
||||||
expect(payload.SenderId).toBe("99");
|
expect(payload.SenderId).toBe("99");
|
||||||
expect(payload.SenderUsername).toBe("ada");
|
expect(payload.SenderUsername).toBe("ada");
|
||||||
expect(payload.Body).toMatch(/^\[Telegram Ops id:42 2025-01-09T00:00Z\]/);
|
expect(payload.Body).toMatch(/^\[Telegram Ops id:42 2025-01-09T00:00Z\]/);
|
||||||
});
|
});
|
||||||
it("reacts to mention-gated group messages when ackReaction is enabled", async () => {
|
it("reacts to mention-gated group messages when ackReaction is enabled", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
setMessageReactionSpy.mockReset();
|
setMessageReactionSpy.mockReset();
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ export type DeliveryContext = {
|
|||||||
|
|
||||||
export function normalizeDeliveryContext(context?: DeliveryContext): DeliveryContext | undefined {
|
export function normalizeDeliveryContext(context?: DeliveryContext): DeliveryContext | undefined {
|
||||||
if (!context) return undefined;
|
if (!context) return undefined;
|
||||||
const channel =
|
const channel = typeof context.channel === "string" ? context.channel.trim() : undefined;
|
||||||
typeof context.channel === "string" ? context.channel.trim() : undefined;
|
|
||||||
const to = typeof context.to === "string" ? context.to.trim() : undefined;
|
const to = typeof context.to === "string" ? context.to.trim() : undefined;
|
||||||
const accountId = normalizeAccountId(context.accountId);
|
const accountId = normalizeAccountId(context.accountId);
|
||||||
if (!channel && !to && !accountId) return undefined;
|
if (!channel && !to && !accountId) return undefined;
|
||||||
|
|||||||
@@ -216,7 +216,12 @@ describe("broadcast groups", () => {
|
|||||||
|
|
||||||
expect(resolver).toHaveBeenCalledTimes(2);
|
expect(resolver).toHaveBeenCalledTimes(2);
|
||||||
for (const call of resolver.mock.calls.slice(0, 2)) {
|
for (const call of resolver.mock.calls.slice(0, 2)) {
|
||||||
const payload = call[0] as { Body: string; SenderName?: string; SenderE164?: string; SenderId?: string };
|
const payload = call[0] as {
|
||||||
|
Body: string;
|
||||||
|
SenderName?: string;
|
||||||
|
SenderE164?: string;
|
||||||
|
SenderId?: string;
|
||||||
|
};
|
||||||
expect(payload.Body).toContain("Chat messages since your last reply");
|
expect(payload.Body).toContain("Chat messages since your last reply");
|
||||||
expect(payload.Body).toContain("Alice (+111): hello group");
|
expect(payload.Body).toContain("Alice (+111): hello group");
|
||||||
expect(payload.Body).toContain("[message_id: g1]");
|
expect(payload.Body).toContain("[message_id: g1]");
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ import {
|
|||||||
} from "../../../auto-reply/reply/response-prefix-template.js";
|
} from "../../../auto-reply/reply/response-prefix-template.js";
|
||||||
import { resolveTextChunkLimit } from "../../../auto-reply/chunk.js";
|
import { resolveTextChunkLimit } from "../../../auto-reply/chunk.js";
|
||||||
import { formatAgentEnvelope } from "../../../auto-reply/envelope.js";
|
import { formatAgentEnvelope } from "../../../auto-reply/envelope.js";
|
||||||
import { buildHistoryContextFromEntries, type HistoryEntry } from "../../../auto-reply/reply/history.js";
|
import {
|
||||||
|
buildHistoryContextFromEntries,
|
||||||
|
type HistoryEntry,
|
||||||
|
} from "../../../auto-reply/reply/history.js";
|
||||||
import { dispatchReplyWithBufferedBlockDispatcher } from "../../../auto-reply/reply/provider-dispatcher.js";
|
import { dispatchReplyWithBufferedBlockDispatcher } from "../../../auto-reply/reply/provider-dispatcher.js";
|
||||||
import type { getReplyFromConfig } from "../../../auto-reply/reply.js";
|
import type { getReplyFromConfig } from "../../../auto-reply/reply.js";
|
||||||
import type { ReplyPayload } from "../../../auto-reply/types.js";
|
import type { ReplyPayload } from "../../../auto-reply/types.js";
|
||||||
@@ -88,7 +91,9 @@ export async function processMessage(params: {
|
|||||||
currentMessage: combinedBody,
|
currentMessage: combinedBody,
|
||||||
excludeLast: false,
|
excludeLast: false,
|
||||||
formatEntry: (entry) => {
|
formatEntry: (entry) => {
|
||||||
const bodyWithId = entry.messageId ? `${entry.body}\n[message_id: ${entry.messageId}]` : entry.body;
|
const bodyWithId = entry.messageId
|
||||||
|
? `${entry.body}\n[message_id: ${entry.messageId}]`
|
||||||
|
: entry.body;
|
||||||
return formatAgentEnvelope({
|
return formatAgentEnvelope({
|
||||||
channel: "WhatsApp",
|
channel: "WhatsApp",
|
||||||
from: conversationId,
|
from: conversationId,
|
||||||
|
|||||||
Reference in New Issue
Block a user