fix: resolve small triage issues

This commit is contained in:
Peter Steinberger
2026-05-04 07:38:34 +01:00
parent deffd11a43
commit fa689295c6
40 changed files with 739 additions and 61 deletions

View File

@@ -117,6 +117,10 @@ export const slackChannelConfigUiHints = {
label: "Slack Draft Tool Progress",
help: "Show tool/progress activity in the live draft preview message (default: true). Set false to hide interim tool updates while the draft preview stays active.",
},
"streaming.preview.commandText": {
label: "Slack Draft Command Text",
help: 'Command/exec detail in preview tool-progress lines: "raw" preserves released behavior; "status" shows only the tool label.',
},
"streaming.progress.label": {
label: "Slack Progress Label",
help: 'Initial progress draft title. Use "auto" for built-in single-word labels, a custom string, or false to hide the title.',
@@ -137,6 +141,10 @@ export const slackChannelConfigUiHints = {
label: "Slack Progress Tool Lines",
help: "Show compact tool/progress lines in progress draft mode (default: true). Set false to keep only the label until final delivery.",
},
"streaming.progress.commandText": {
label: "Slack Progress Command Text",
help: 'Command/exec detail in progress draft lines: "raw" preserves released behavior; "status" shows only the tool label.',
},
"thread.historyScope": {
label: "Slack Thread History Scope",
help: 'Scope for Slack thread history context ("thread" isolates per thread; "channel" reuses channel history).',

View File

@@ -37,7 +37,16 @@ let capturedReplyOptions:
| {
disableBlockStreaming?: boolean;
suppressDefaultToolProgressMessages?: boolean;
onItemEvent?: (payload: { progressText: string }) => Promise<void> | void;
onItemEvent?: (payload: {
kind?: string;
progressText?: string;
summary?: string;
title?: string;
name?: string;
phase?: string;
status?: string;
meta?: string;
}) => Promise<void> | void;
onPartialReply?: (payload: { text: string }) => Promise<void> | void;
}
| undefined;
@@ -73,7 +82,18 @@ let mockedDispatchSequence: Array<{
}> = [];
let mockedProgressEvents: string[] = [];
let mockedReplyOptionEvents: Array<
{ kind: "item"; progressText: string } | { kind: "partial"; text: string }
| {
kind: "item";
itemKind?: string;
progressText?: string;
summary?: string;
title?: string;
name?: string;
phase?: string;
status?: string;
meta?: string;
}
| { kind: "partial"; text: string }
> = [];
const noop = () => {};
@@ -246,6 +266,41 @@ vi.mock("openclaw/plugin-sdk/channel-streaming", () => ({
}
: undefined;
},
buildChannelProgressDraftLineForEntry: (
entry: {
streaming?: {
progress?: { commandText?: "raw" | "status" };
preview?: { commandText?: "raw" | "status" };
};
},
params: {
itemKind?: string;
progressText?: string;
summary?: string;
title?: string;
name?: string;
},
) => {
if (
(entry.streaming?.progress?.commandText ?? entry.streaming?.preview?.commandText) ===
"status" &&
(params.itemKind === "command" || params.name === "exec")
) {
return {
kind: "item",
text: "🛠️ Exec",
label: "Exec",
};
}
const text = params.progressText ?? params.summary ?? params.title ?? params.name;
return text
? {
kind: "item",
text,
label: params.title ?? params.name ?? "Update",
}
: undefined;
},
createChannelProgressDraftGate: (params: { onStart: () => void | Promise<void> }) => {
let started = false;
let workEvents = 0;
@@ -290,6 +345,15 @@ vi.mock("openclaw/plugin-sdk/channel-streaming", () => ({
title?: string;
name?: string;
}) => params.progressText ?? params.summary ?? params.title ?? params.name,
formatChannelProgressDraftLineForEntry: (
_entry: unknown,
params: {
progressText?: string;
summary?: string;
title?: string;
name?: string;
},
) => params.progressText ?? params.summary ?? params.title ?? params.name,
resolveChannelProgressDraftMaxLines: (entry?: {
streaming?: { progress?: { maxLines?: number } };
}) => entry?.streaming?.progress?.maxLines ?? 8,
@@ -472,7 +536,16 @@ vi.mock("../reply.runtime.js", () => ({
replyOptions?: {
disableBlockStreaming?: boolean;
suppressDefaultToolProgressMessages?: boolean;
onItemEvent?: (payload: { progressText: string }) => Promise<void> | void;
onItemEvent?: (payload: {
kind?: string;
progressText?: string;
summary?: string;
title?: string;
name?: string;
phase?: string;
status?: string;
meta?: string;
}) => Promise<void> | void;
onPartialReply?: (payload: { text: string }) => Promise<void> | void;
};
dispatcher: {
@@ -492,7 +565,16 @@ vi.mock("../reply.runtime.js", () => ({
if (mockedReplyOptionEvents.length > 0) {
for (const entry of mockedReplyOptionEvents) {
if (entry.kind === "item") {
await params.replyOptions?.onItemEvent?.({ progressText: entry.progressText });
await params.replyOptions?.onItemEvent?.({
kind: entry.itemKind,
progressText: entry.progressText,
summary: entry.summary,
title: entry.title,
name: entry.name,
phase: entry.phase,
status: entry.status,
meta: entry.meta,
});
} else {
await params.replyOptions?.onPartialReply?.({ text: entry.text });
}
@@ -749,6 +831,34 @@ describe("dispatchPreparedSlackMessage preview fallback", () => {
);
});
it("can hide raw Slack command progress text by config", async () => {
const draftStream = createDraftStreamStub();
createSlackDraftStreamMock.mockReturnValueOnce(draftStream);
mockedSlackStreamingMode = "progress";
mockedSlackDraftMode = "status_final";
mockedDispatchSequence = [];
mockedReplyOptionEvents = [
{
kind: "item",
itemKind: "command",
name: "exec",
progressText: "exec pnpm test -- --watch=false",
},
{ kind: "item", progressText: "done" },
];
await dispatchPreparedSlackMessage(
createPreparedSlackMessage({
accountConfig: {
streaming: { mode: "progress", progress: { label: "Shelling", commandText: "status" } },
},
}),
);
expect(draftStream.update).toHaveBeenCalledWith("Shelling\n• 🛠️ Exec\n• done");
expect(draftStream.update.mock.calls.flat().join("\n")).not.toContain("pnpm test");
});
it("suppresses standalone Slack tool progress when progress lines are disabled", async () => {
mockedSlackStreamingMode = "progress";
mockedSlackDraftMode = "status_final";

View File

@@ -14,6 +14,7 @@ import {
} from "openclaw/plugin-sdk/channel-reply-pipeline";
import {
buildChannelProgressDraftLine,
buildChannelProgressDraftLineForEntry,
createChannelProgressDraftGate,
formatChannelProgressDraftText,
isChannelProgressDraftWorkToolName,
@@ -1108,7 +1109,8 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
await statusReactions.setTool(payload.name);
}
await pushPreviewToolProgress(
buildChannelProgressDraftLine(
buildChannelProgressDraftLineForEntry(
account.config,
{
event: "tool",
name: payload.name,
@@ -1122,7 +1124,7 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
},
onItemEvent: async (payload) => {
await pushPreviewToolProgress(
buildChannelProgressDraftLine({
buildChannelProgressDraftLineForEntry(account.config, {
event: "item",
itemKind: payload.kind,
title: payload.title,