Skip to content

Commit 2272f50

Browse files
committed
fix(delivery): treat internal artifacts as silent skips
1 parent 45046fc commit 2272f50

5 files changed

Lines changed: 25 additions & 22 deletions

File tree

extensions/telegram/src/bot-message-dispatch.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4660,6 +4660,22 @@ describe("dispatchTelegramMessage draft streaming", () => {
46604660
expect(deliverReplies).not.toHaveBeenCalled();
46614661
});
46624662

4663+
it("does not emit an empty-response fallback for internal artifact skips", async () => {
4664+
dispatchReplyWithBufferedBlockDispatcher.mockImplementation(async ({ dispatcherOptions }) => {
4665+
dispatcherOptions.onSkip?.({ text: "<channel|>" }, { kind: "final", reason: "silent" });
4666+
return { queuedFinal: false, counts: { block: 0, final: 0, tool: 0 } };
4667+
});
4668+
4669+
await dispatchWithContext({
4670+
context: createContext({
4671+
ctxPayload: createDirectSessionPayload(),
4672+
}),
4673+
streamMode: "off",
4674+
});
4675+
4676+
expect(deliverReplies).not.toHaveBeenCalled();
4677+
});
4678+
46634679
it("does not emit a silent-reply fallback for no-response group turns", async () => {
46644680
dispatchReplyWithBufferedBlockDispatcher.mockResolvedValue({
46654681
queuedFinal: false,

src/auto-reply/reply/normalize-reply.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
type ResponsePrefixContext,
2121
} from "./response-prefix-template.js";
2222

23-
export type NormalizeReplySkipReason = "empty" | "silent" | "heartbeat" | "internalArtifact";
23+
export type NormalizeReplySkipReason = "empty" | "silent" | "heartbeat";
2424

2525
export type NormalizeReplyOptions = {
2626
responsePrefix?: string;
@@ -98,10 +98,8 @@ export function normalizeReplyPayload(
9898
text = stripped.text;
9999
}
100100

101-
// Suppress standalone internal protocol artifacts (Codex/Harmony channel
102-
// markers, reasoning directives) before they reach messaging channels. #88128
103101
if (text && isInternalFormattingArtifact(text) && !hasContent("")) {
104-
opts.onSkip?.("internalArtifact");
102+
opts.onSkip?.("silent");
105103
return null;
106104
}
107105

src/auto-reply/reply/reply-utils.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ describe("normalizeReplyPayload", () => {
150150
expect(reply.channelData).toEqual(payload.channelData);
151151
});
152152

153-
it("records skip reasons for silent/empty/internal-artifact payloads", () => {
153+
it("records skip reasons for silent, empty, and internal artifact payloads", () => {
154154
const cases = [
155155
{ name: "silent", payload: { text: SILENT_REPLY_TOKEN }, reason: "silent" },
156156
{
@@ -162,17 +162,17 @@ describe("normalizeReplyPayload", () => {
162162
{
163163
name: "internalArtifact <channel|>",
164164
payload: { text: "<channel|>" },
165-
reason: "internalArtifact",
165+
reason: "silent",
166166
},
167167
{
168168
name: "internalArtifact set-thought",
169169
payload: { text: "set-thought <channel|>" },
170-
reason: "internalArtifact",
170+
reason: "silent",
171171
},
172172
{
173173
name: "internalArtifact box-drawing separator",
174174
payload: { text: "───" },
175-
reason: "internalArtifact",
175+
reason: "silent",
176176
},
177177
] as const;
178178
for (const testCase of cases) {

src/auto-reply/tokens.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ describe("isInternalFormattingArtifact", () => {
1818
expect(isInternalFormattingArtifact("<channel|answer>")).toBe(true);
1919
expect(isInternalFormattingArtifact("<lane|reasoning>")).toBe(true);
2020
expect(isInternalFormattingArtifact("<|>")).toBe(true);
21+
expect(isInternalFormattingArtifact("<|channel|>")).toBe(true);
22+
expect(isInternalFormattingArtifact("<|message|>")).toBe(true);
23+
expect(isInternalFormattingArtifact("<|call|>")).toBe(true);
2124
});
2225

2326
it("matches set-thought directives (#88128)", () => {

src/auto-reply/tokens.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,9 @@ export const HEARTBEAT_TOKEN = "HEARTBEAT_OK";
66
/** Token that marks an auto-reply response as intentionally silent. */
77
export const SILENT_REPLY_TOKEN = "NO_REPLY";
88

9-
// Narrow protocol-only matcher for internal streaming artifacts that LLM
10-
// providers (Codex/Harmony) emit as standalone fragments during response
11-
// generation. Only matches patterns that are never valid user-facing content.
12-
// Intentionally excludes generic markdown separators (---, ***, ___) and
13-
// XML-like tags (<tag>, </tag>) which could appear in legitimate replies.
149
const HARMONY_CHANNEL_MARKER_RE = /^\s*(?:set-thought\s+)?<[\w]*\|[^>]*>\s*$/;
1510
const BOX_DRAWING_HR_ONLY_RE = /^\s*{3,}\s*$/;
1611

17-
/**
18-
* Returns true when text consists entirely of an internal runtime/protocol
19-
* artifact that must never be delivered to user-facing messaging channels.
20-
*
21-
* Scoped to observed Codex/Harmony markers only:
22-
* - `<channel|>`, `<word|value>` — provider channel routing markers
23-
* - `set-thought <channel|>` — reasoning lane transition directives
24-
* - `───` (box-drawing HR) — internal markdown renderer separator
25-
*/
2612
export function isInternalFormattingArtifact(text: string | undefined): boolean {
2713
if (!text) {
2814
return false;

0 commit comments

Comments
 (0)