Merge pull request 'fix/gateway-keywords-no-empty' (#19) from fix/gateway-keywords-no-empty into main
Reviewed-on: #19
This commit was merged in pull request #19.
This commit is contained in:
@@ -115,14 +115,12 @@ export function registerBeforeMessageWriteHook(deps: BeforeMessageWriteDeps): vo
|
|||||||
const policy = resolvePolicy(live, channelId, policyState.channelPolicies as Record<string, any>);
|
const policy = resolvePolicy(live, channelId, policyState.channelPolicies as Record<string, any>);
|
||||||
|
|
||||||
const trimmed = content.trim();
|
const trimmed = content.trim();
|
||||||
const isNoReply = /^NO_REPLY$/i.test(trimmed) || /^HEARTBEAT_OK$/i.test(trimmed);
|
const isNoReply = /^NO$/i.test(trimmed) || /^NO_REPLY$/i.test(trimmed);
|
||||||
const lastChar = trimmed.length > 0 ? Array.from(trimmed).pop() || "" : "";
|
const lastChar = trimmed.length > 0 ? Array.from(trimmed).pop() || "" : "";
|
||||||
const hasEndSymbol = !!lastChar && policy.endSymbols.includes(lastChar);
|
const hasEndSymbol = !!lastChar && policy.endSymbols.includes(lastChar);
|
||||||
const waitId = live.waitIdentifier || "👤";
|
const waitId = live.waitIdentifier || "👤";
|
||||||
const hasWaitIdentifier = !!lastChar && lastChar === waitId;
|
const hasWaitIdentifier = !!lastChar && lastChar === waitId;
|
||||||
// Only treat explicit NO_REPLY/HEARTBEAT_OK keywords as no-reply.
|
// Treat explicit NO/NO_REPLY keywords as no-reply.
|
||||||
// Empty content is NOT treated as no-reply — it may come from intermediate
|
|
||||||
// model responses (e.g. thinking-only blocks) that are not final answers.
|
|
||||||
const wasNoReply = isNoReply;
|
const wasNoReply = isNoReply;
|
||||||
|
|
||||||
const turnDebug = getTurnDebugInfo(channelId);
|
const turnDebug = getTurnDebugInfo(channelId);
|
||||||
@@ -143,7 +141,10 @@ export function registerBeforeMessageWriteHook(deps: BeforeMessageWriteDeps): vo
|
|||||||
const wasAllowed = sessionAllowed.get(key);
|
const wasAllowed = sessionAllowed.get(key);
|
||||||
|
|
||||||
if (wasNoReply) {
|
if (wasNoReply) {
|
||||||
api.logger.info(`dirigent: DEBUG NO_REPLY detected session=${key} wasAllowed=${wasAllowed}`);
|
const noReplyKeyword = /^NO$/i.test(trimmed) ? "NO" : "NO_REPLY";
|
||||||
|
api.logger.info(
|
||||||
|
`dirigent: DEBUG NO_REPLY detected session=${key} wasAllowed=${wasAllowed} keyword=${noReplyKeyword}`,
|
||||||
|
);
|
||||||
|
|
||||||
if (wasAllowed === undefined) return;
|
if (wasAllowed === undefined) return;
|
||||||
|
|
||||||
|
|||||||
@@ -74,12 +74,12 @@ export function registerMessageSentHook(deps: MessageSentDeps): void {
|
|||||||
const policy = resolvePolicy(live, channelId, policyState.channelPolicies as Record<string, any>);
|
const policy = resolvePolicy(live, channelId, policyState.channelPolicies as Record<string, any>);
|
||||||
|
|
||||||
const trimmed = content.trim();
|
const trimmed = content.trim();
|
||||||
const isNoReply = /^NO_REPLY$/i.test(trimmed) || /^HEARTBEAT_OK$/i.test(trimmed);
|
const isNoReply = /^NO$/i.test(trimmed) || /^NO_REPLY$/i.test(trimmed);
|
||||||
const lastChar = trimmed.length > 0 ? Array.from(trimmed).pop() || "" : "";
|
const lastChar = trimmed.length > 0 ? Array.from(trimmed).pop() || "" : "";
|
||||||
const hasEndSymbol = !!lastChar && policy.endSymbols.includes(lastChar);
|
const hasEndSymbol = !!lastChar && policy.endSymbols.includes(lastChar);
|
||||||
const waitId = live.waitIdentifier || "👤";
|
const waitId = live.waitIdentifier || "👤";
|
||||||
const hasWaitIdentifier = !!lastChar && lastChar === waitId;
|
const hasWaitIdentifier = !!lastChar && lastChar === waitId;
|
||||||
// Only treat explicit NO_REPLY/HEARTBEAT_OK keywords as no-reply.
|
// Treat explicit NO/NO_REPLY keywords as no-reply.
|
||||||
const wasNoReply = isNoReply;
|
const wasNoReply = isNoReply;
|
||||||
|
|
||||||
if (key && sessionTurnHandled.has(key)) {
|
if (key && sessionTurnHandled.has(key)) {
|
||||||
@@ -101,8 +101,10 @@ export function registerMessageSentHook(deps: MessageSentDeps): void {
|
|||||||
if (wasNoReply || hasEndSymbol) {
|
if (wasNoReply || hasEndSymbol) {
|
||||||
const nextSpeaker = onSpeakerDone(channelId, accountId, wasNoReply);
|
const nextSpeaker = onSpeakerDone(channelId, accountId, wasNoReply);
|
||||||
const trigger = wasNoReply ? "no_reply_keyword" : "end_symbol";
|
const trigger = wasNoReply ? "no_reply_keyword" : "end_symbol";
|
||||||
|
const noReplyKeyword = wasNoReply ? (/^NO$/i.test(trimmed) ? "NO" : "NO_REPLY") : "";
|
||||||
|
const keywordNote = wasNoReply ? ` keyword=${noReplyKeyword}` : "";
|
||||||
api.logger.info(
|
api.logger.info(
|
||||||
`dirigent: turn onSpeakerDone channel=${channelId} from=${accountId} next=${nextSpeaker ?? "dormant"} trigger=${trigger}`,
|
`dirigent: turn onSpeakerDone channel=${channelId} from=${accountId} next=${nextSpeaker ?? "dormant"} trigger=${trigger}${keywordNote}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (wasNoReply && nextSpeaker && live.moderatorBotToken) {
|
if (wasNoReply && nextSpeaker && live.moderatorBotToken) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ type DebugConfig = {
|
|||||||
|
|
||||||
function buildEndMarkerInstruction(endSymbols: string[], isGroupChat: boolean, schedulingIdentifier: string, waitIdentifier: string): string {
|
function buildEndMarkerInstruction(endSymbols: string[], isGroupChat: boolean, schedulingIdentifier: string, waitIdentifier: string): string {
|
||||||
const symbols = endSymbols.length > 0 ? endSymbols.join("") : "🔚";
|
const symbols = endSymbols.length > 0 ? endSymbols.join("") : "🔚";
|
||||||
let instruction = `Your response MUST end with ${symbols}. Exception: gateway keywords (e.g. NO_REPLY, HEARTBEAT_OK) must NOT include ${symbols}.`;
|
let instruction = `Your response MUST end with ${symbols}. Exception: gateway keywords (e.g. NO_REPLY, HEARTBEAT_OK, NO, or an empty response) must NOT include ${symbols}.`;
|
||||||
if (isGroupChat) {
|
if (isGroupChat) {
|
||||||
instruction += `\n\nGroup chat rules: If this message is not relevant to you, does not need your response, or you have nothing valuable to add, reply with NO_REPLY. Do not speak just for the sake of speaking.`;
|
instruction += `\n\nGroup chat rules: If this message is not relevant to you, does not need your response, or you have nothing valuable to add, reply with NO_REPLY. Do not speak just for the sake of speaking.`;
|
||||||
instruction += `\n\nWait for human reply: If you need a human to respond to your message, end with ${waitIdentifier} instead of ${symbols}. This pauses all agents until a human speaks. Use this sparingly — only when you are confident the human is actively participating in the discussion (has sent a message recently). Do NOT use it speculatively.`;
|
instruction += `\n\nWait for human reply: If you need a human to respond to your message, end with ${waitIdentifier} instead of ${symbols}. This pauses all agents until a human speaks. Use this sparingly — only when you are confident the human is actively participating in the discussion (has sent a message recently). Do NOT use it speculatively.`;
|
||||||
|
|||||||
Reference in New Issue
Block a user