@syengup/friday-channel-next 1.0.1 → 1.0.3
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.
|
@@ -343,6 +343,17 @@ export function forwardAgentEventRaw(evt) {
|
|
|
343
343
|
});
|
|
344
344
|
}
|
|
345
345
|
}
|
|
346
|
+
// Codex app-server projects every tool/command call onto BOTH the standard `tool` stream
|
|
347
|
+
// (carrying args + the real result) AND a redundant `item` event (kind:"tool"/"command"),
|
|
348
|
+
// and core flags that item `suppressChannelProgress: true` ("do not surface in channel
|
|
349
|
+
// progress"). Forwarding the suppressed item anyway double-renders every non-exec tool in
|
|
350
|
+
// the app — the `tool`-stream row plus a second `item kind:tool` row, with the result landing
|
|
351
|
+
// only on the first. Honor the flag and drop suppressed items; the `tool` stream (and, for
|
|
352
|
+
// exec, the synthesized `command_output`) already carries everything the app renders. Codex
|
|
353
|
+
// reasoning items (preamble/analysis) are NOT suppressed, so this never touches thinking.
|
|
354
|
+
if (evt.stream === "item" && evt.data.suppressChannelProgress === true) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
346
357
|
// Register sessionKey → runId so we can resolve parentRunId
|
|
347
358
|
if (sk && evt.stream === "lifecycle" && evt.data.phase === "start") {
|
|
348
359
|
registerSessionKeyForRun(sk, evt.runId);
|
|
@@ -467,6 +467,16 @@ export async function handleMessages(req, res) {
|
|
|
467
467
|
runId,
|
|
468
468
|
suppressTyping: true,
|
|
469
469
|
disableBlockStreaming: true,
|
|
470
|
+
// friday-next is a direct device channel: the final assistant reply auto-delivers
|
|
471
|
+
// to the app live over SSE (sendText), and the channel already declares ChatType
|
|
472
|
+
// "direct" + outbound.deliveryMode "direct". But OpenClaw core's source-reply policy
|
|
473
|
+
// (resolveSourceReplyDeliveryMode) can still resolve `message_tool_only` for this
|
|
474
|
+
// channel from its own defaults — when it does, the agent prompt tells the model
|
|
475
|
+
// "visible replies are NOT auto-delivered; use message(action=send) for everything",
|
|
476
|
+
// which makes Codex route its whole answer through the `message` tool (and that tool
|
|
477
|
+
// crashes on friday-next). Pin `automatic` so core honors the channel's own direct
|
|
478
|
+
// delivery and never instructs the model to deliver via the message tool.
|
|
479
|
+
sourceReplyDeliveryMode: "automatic",
|
|
470
480
|
// A1: feed the chosen thinking level into the run as a one-shot override so the model
|
|
471
481
|
// request asks for a reasoning summary. The session-stored `thinkingLevel` alone is NOT
|
|
472
482
|
// honored by the reply dispatch; `thinkingLevelOverride` has top priority in OpenClaw's
|
package/package.json
CHANGED
|
@@ -175,6 +175,37 @@ describe("forwardAgentEventRaw (thinking delta rewrite)", () => {
|
|
|
175
175
|
expect(thinking[1].data.reasoningPrefixChars).toBe(2);
|
|
176
176
|
});
|
|
177
177
|
|
|
178
|
+
it("drops item events flagged suppressChannelProgress (Codex tool/command duplicates)", () => {
|
|
179
|
+
// Codex app-server projects every tool/command onto both the `tool` stream and a redundant
|
|
180
|
+
// `item` event flagged suppressChannelProgress:true. Forwarding the item double-renders the
|
|
181
|
+
// tool in the app. We honor the flag and drop it.
|
|
182
|
+
forwardAgentEventRaw({
|
|
183
|
+
runId,
|
|
184
|
+
seq: 1,
|
|
185
|
+
stream: "item",
|
|
186
|
+
sessionKey,
|
|
187
|
+
data: {
|
|
188
|
+
itemId: "call_abc",
|
|
189
|
+
kind: "tool",
|
|
190
|
+
phase: "start",
|
|
191
|
+
name: "web_search",
|
|
192
|
+
suppressChannelProgress: true,
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
expect(sseEmitter.broadcastToRun).not.toHaveBeenCalled();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("forwards item events that are not suppressed (e.g. reasoning analysis markers)", () => {
|
|
199
|
+
forwardAgentEventRaw({
|
|
200
|
+
runId,
|
|
201
|
+
seq: 1,
|
|
202
|
+
stream: "item",
|
|
203
|
+
sessionKey,
|
|
204
|
+
data: { itemId: "rs_1", kind: "analysis", phase: "start", title: "Reasoning" },
|
|
205
|
+
});
|
|
206
|
+
expect(sseEmitter.broadcastToRun).toHaveBeenCalledTimes(1);
|
|
207
|
+
});
|
|
208
|
+
|
|
178
209
|
it("does not translate preamble items from a non-Codex source", () => {
|
|
179
210
|
forwardAgentEventRaw({
|
|
180
211
|
runId,
|
package/src/friday-session.ts
CHANGED
|
@@ -398,6 +398,18 @@ export function forwardAgentEventRaw(evt: ForwardAgentEventArgs): void {
|
|
|
398
398
|
}
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
+
// Codex app-server projects every tool/command call onto BOTH the standard `tool` stream
|
|
402
|
+
// (carrying args + the real result) AND a redundant `item` event (kind:"tool"/"command"),
|
|
403
|
+
// and core flags that item `suppressChannelProgress: true` ("do not surface in channel
|
|
404
|
+
// progress"). Forwarding the suppressed item anyway double-renders every non-exec tool in
|
|
405
|
+
// the app — the `tool`-stream row plus a second `item kind:tool` row, with the result landing
|
|
406
|
+
// only on the first. Honor the flag and drop suppressed items; the `tool` stream (and, for
|
|
407
|
+
// exec, the synthesized `command_output`) already carries everything the app renders. Codex
|
|
408
|
+
// reasoning items (preamble/analysis) are NOT suppressed, so this never touches thinking.
|
|
409
|
+
if (evt.stream === "item" && evt.data.suppressChannelProgress === true) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
|
|
401
413
|
// Register sessionKey → runId so we can resolve parentRunId
|
|
402
414
|
if (sk && evt.stream === "lifecycle" && evt.data.phase === "start") {
|
|
403
415
|
registerSessionKeyForRun(sk, evt.runId);
|
|
@@ -635,6 +635,16 @@ export async function handleMessages(req: IncomingMessage, res: ServerResponse):
|
|
|
635
635
|
runId,
|
|
636
636
|
suppressTyping: true,
|
|
637
637
|
disableBlockStreaming: true,
|
|
638
|
+
// friday-next is a direct device channel: the final assistant reply auto-delivers
|
|
639
|
+
// to the app live over SSE (sendText), and the channel already declares ChatType
|
|
640
|
+
// "direct" + outbound.deliveryMode "direct". But OpenClaw core's source-reply policy
|
|
641
|
+
// (resolveSourceReplyDeliveryMode) can still resolve `message_tool_only` for this
|
|
642
|
+
// channel from its own defaults — when it does, the agent prompt tells the model
|
|
643
|
+
// "visible replies are NOT auto-delivered; use message(action=send) for everything",
|
|
644
|
+
// which makes Codex route its whole answer through the `message` tool (and that tool
|
|
645
|
+
// crashes on friday-next). Pin `automatic` so core honors the channel's own direct
|
|
646
|
+
// delivery and never instructs the model to deliver via the message tool.
|
|
647
|
+
sourceReplyDeliveryMode: "automatic",
|
|
638
648
|
// A1: feed the chosen thinking level into the run as a one-shot override so the model
|
|
639
649
|
// request asks for a reasoning summary. The session-stored `thinkingLevel` alone is NOT
|
|
640
650
|
// honored by the reply dispatch; `thinkingLevelOverride` has top priority in OpenClaw's
|