mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 09:10:45 +00:00
fix(channels): pass raw progress detail to drafts
This commit is contained in:
@@ -52,6 +52,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Channels/CLI: keep `openclaw channels list --json` usable when provider usage fetching fails, and report per-provider usage errors without aborting the channel list. Refs #67595.
|
||||
- Agents/messaging: deliver distinct final commentary after same-target `message` tool sends while still deduping text/media already sent by the tool, so short closing remarks are no longer silently dropped. Fixes #76915. Thanks @hclsys.
|
||||
- Agents/messaging: preserve string thread IDs when matching message-tool reply dedupe routes, avoiding precision loss on numeric-looking topic IDs before channel plugin comparison. Thanks @vincentkoc.
|
||||
- Channels/streaming: honor `agents.defaults.toolProgressDetail: "raw"` in Slack, Discord, Telegram, Matrix, and Microsoft Teams progress drafts, so tool-start lines include raw command/detail output when debugging. Thanks @vincentkoc.
|
||||
- OpenAI Codex: honor `auth.order.openai-codex` when starting app-server clients without an explicit auth profile, so status/model probes and implicit startup use the configured Codex account instead of falling back to the default profile. Thanks @vincentkoc.
|
||||
- OpenAI Codex: let SSRF-guarded provider requests inherit OpenClaw's undici IPv4/IPv6 fallback policy, so ChatGPT-backed Codex runs recover on IPv4-working hosts when DNS still returns unreachable IPv6 addresses. Fixes #76857. Thanks @jplavoiemtl and @SymbolStar.
|
||||
- Gateway/systemd: preserve operator-added secrets in the Gateway env file across re-stage while clearing OpenClaw-managed keys (such as `OPENCLAW_GATEWAY_TOKEN`) so a fresh staging value is never shadowed by a stale env-file copy; operator secrets are also retained when the state-dir `.env` is empty. Fixes #76860. Thanks @hclsys.
|
||||
|
||||
@@ -102,6 +102,7 @@ type DispatchInboundParams = {
|
||||
name?: string;
|
||||
phase?: string;
|
||||
args?: Record<string, unknown>;
|
||||
detailMode?: "explain" | "raw";
|
||||
}) => Promise<void> | void;
|
||||
onItemEvent?: (payload: {
|
||||
progressText?: string;
|
||||
@@ -1534,6 +1535,38 @@ describe("processDiscordMessage draft streaming", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("uses raw tool-progress detail in Discord progress drafts", async () => {
|
||||
const draftStream = createMockDraftStreamForTest();
|
||||
|
||||
dispatchInboundMessage.mockImplementationOnce(async (params?: DispatchInboundParams) => {
|
||||
await params?.replyOptions?.onToolStart?.({
|
||||
name: "exec",
|
||||
phase: "start",
|
||||
args: { command: "pnpm test -- --watch=false" },
|
||||
detailMode: "raw",
|
||||
});
|
||||
await params?.replyOptions?.onItemEvent?.({ progressText: "done" });
|
||||
return createNoQueuedDispatchResult();
|
||||
});
|
||||
|
||||
const ctx = await createAutomaticSourceDeliveryContext({
|
||||
discordConfig: {
|
||||
streaming: {
|
||||
mode: "progress",
|
||||
progress: {
|
||||
label: "Shelling",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await runProcessDiscordMessage(ctx);
|
||||
|
||||
expect(draftStream.update).toHaveBeenCalledWith(
|
||||
"Shelling\n🛠️ Exec: run tests, `pnpm test -- --watch=false`\n• done",
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps Discord progress lines across assistant boundaries", async () => {
|
||||
const draftStream = createMockDraftStreamForTest();
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ type ToolStartPayload = {
|
||||
name?: string;
|
||||
phase?: string;
|
||||
args?: Record<string, unknown>;
|
||||
detailMode?: "explain" | "raw";
|
||||
};
|
||||
|
||||
function readToolStringArg(args: Record<string, unknown>, key: string): string | undefined {
|
||||
@@ -668,12 +669,15 @@ export async function processDiscordMessage(
|
||||
await maybeBindStatusReactionsToToolReaction(payload);
|
||||
await statusReactions.setTool(payload.name);
|
||||
await draftPreview.pushToolProgress(
|
||||
formatChannelProgressDraftLine({
|
||||
event: "tool",
|
||||
name: payload.name,
|
||||
phase: payload.phase,
|
||||
args: payload.args,
|
||||
}),
|
||||
formatChannelProgressDraftLine(
|
||||
{
|
||||
event: "tool",
|
||||
name: payload.name,
|
||||
phase: payload.phase,
|
||||
args: payload.args,
|
||||
},
|
||||
payload.detailMode ? { detailMode: payload.detailMode } : undefined,
|
||||
),
|
||||
{ toolName: payload.name },
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1580,12 +1580,15 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
onToolStart: async (payload) => {
|
||||
const toolName = payload.name?.trim();
|
||||
await pushPreviewToolProgress(
|
||||
formatChannelProgressDraftLine({
|
||||
event: "tool",
|
||||
name: toolName,
|
||||
phase: payload.phase,
|
||||
args: payload.args,
|
||||
}),
|
||||
formatChannelProgressDraftLine(
|
||||
{
|
||||
event: "tool",
|
||||
name: toolName,
|
||||
phase: payload.phase,
|
||||
args: payload.args,
|
||||
},
|
||||
payload.detailMode ? { detailMode: payload.detailMode } : undefined,
|
||||
),
|
||||
{ toolName },
|
||||
);
|
||||
},
|
||||
|
||||
@@ -381,14 +381,18 @@ export function createMSTeamsReplyDispatcher(params: {
|
||||
name?: string;
|
||||
phase?: string;
|
||||
args?: Record<string, unknown>;
|
||||
detailMode?: "explain" | "raw";
|
||||
}) => {
|
||||
await streamController.pushProgressLine(
|
||||
formatChannelProgressDraftLine({
|
||||
event: "tool",
|
||||
name: payload.name,
|
||||
phase: payload.phase,
|
||||
args: payload.args,
|
||||
}),
|
||||
formatChannelProgressDraftLine(
|
||||
{
|
||||
event: "tool",
|
||||
name: payload.name,
|
||||
phase: payload.phase,
|
||||
args: payload.args,
|
||||
},
|
||||
payload.detailMode ? { detailMode: payload.detailMode } : undefined,
|
||||
),
|
||||
{ toolName: payload.name },
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1084,12 +1084,15 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
||||
await statusReactions.setTool(payload.name);
|
||||
}
|
||||
await pushPreviewToolProgress(
|
||||
formatChannelProgressDraftLine({
|
||||
event: "tool",
|
||||
name: payload.name,
|
||||
phase: payload.phase,
|
||||
args: payload.args,
|
||||
}),
|
||||
formatChannelProgressDraftLine(
|
||||
{
|
||||
event: "tool",
|
||||
name: payload.name,
|
||||
phase: payload.phase,
|
||||
args: payload.args,
|
||||
},
|
||||
payload.detailMode ? { detailMode: payload.detailMode } : undefined,
|
||||
),
|
||||
{ toolName: payload.name },
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1174,12 +1174,15 @@ export const dispatchTelegramMessage = async ({
|
||||
await statusReactionController.setTool(toolName);
|
||||
}
|
||||
await pushPreviewToolProgress(
|
||||
formatChannelProgressDraftLine({
|
||||
event: "tool",
|
||||
name: toolName,
|
||||
phase: payload.phase,
|
||||
args: payload.args,
|
||||
}),
|
||||
formatChannelProgressDraftLine(
|
||||
{
|
||||
event: "tool",
|
||||
name: toolName,
|
||||
phase: payload.phase,
|
||||
args: payload.args,
|
||||
},
|
||||
payload.detailMode ? { detailMode: payload.detailMode } : undefined,
|
||||
),
|
||||
{ toolName },
|
||||
);
|
||||
},
|
||||
|
||||
@@ -85,6 +85,7 @@ export type GetReplyOptions = {
|
||||
name?: string;
|
||||
phase?: string;
|
||||
args?: Record<string, unknown>;
|
||||
detailMode?: "explain" | "raw";
|
||||
}) => Promise<void> | void;
|
||||
/** Called when a concrete work item starts, updates, or completes. */
|
||||
onItemEvent?: (payload: {
|
||||
|
||||
@@ -1142,6 +1142,39 @@ describe("runAgentTurnWithFallback", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("forwards raw tool progress detail mode to tool-start reply options", async () => {
|
||||
const onToolStart = vi.fn();
|
||||
state.runEmbeddedPiAgentMock.mockImplementationOnce(async (params: EmbeddedAgentParams) => {
|
||||
await params.onAgentEvent?.({
|
||||
stream: "tool",
|
||||
data: {
|
||||
name: "exec",
|
||||
phase: "start",
|
||||
args: { command: "pnpm test -- --watch=false" },
|
||||
},
|
||||
});
|
||||
return { payloads: [{ text: "final" }], meta: {} };
|
||||
});
|
||||
|
||||
const runAgentTurnWithFallback = await getRunAgentTurnWithFallback();
|
||||
const result = await runAgentTurnWithFallback({
|
||||
...createMinimalRunAgentTurnParams({
|
||||
opts: {
|
||||
onToolStart,
|
||||
} satisfies GetReplyOptions,
|
||||
}),
|
||||
toolProgressDetail: "raw",
|
||||
});
|
||||
|
||||
expect(result.kind).toBe("success");
|
||||
expect(onToolStart).toHaveBeenCalledWith({
|
||||
name: "exec",
|
||||
phase: "start",
|
||||
args: { command: "pnpm test -- --watch=false" },
|
||||
detailMode: "raw",
|
||||
});
|
||||
});
|
||||
|
||||
it("publishes Codex app-server telemetry to agent event subscribers", async () => {
|
||||
const agentEvents = await import("../../infra/agent-events.js");
|
||||
const emitAgentEvent = vi.mocked(agentEvents.emitAgentEvent);
|
||||
|
||||
@@ -1537,6 +1537,7 @@ export async function runAgentTurnWithFallback(params: {
|
||||
evt.data.args && typeof evt.data.args === "object"
|
||||
? (evt.data.args as Record<string, unknown>)
|
||||
: undefined,
|
||||
detailMode: params.toolProgressDetail,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,6 +208,16 @@ describe("channel-streaming", () => {
|
||||
modified: ["/tmp/demo/index.html", "/tmp/demo/style.css"],
|
||||
}),
|
||||
).toBe("🩹 Apply Patch: /tmp/demo/{index.html, style.css}");
|
||||
expect(
|
||||
formatChannelProgressDraftLine(
|
||||
{
|
||||
event: "tool",
|
||||
name: "exec",
|
||||
args: { command: "pnpm test -- --watch=false" },
|
||||
},
|
||||
{ detailMode: "raw" },
|
||||
),
|
||||
).toBe("🛠️ Exec: run tests, `pnpm test -- --watch=false`");
|
||||
});
|
||||
|
||||
it("starts progress drafts after five seconds or a second work event", async () => {
|
||||
|
||||
Reference in New Issue
Block a user