mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 20:31:22 +00:00
Heartbeat: allow suppressing tool warnings (#18497)
* Heartbeat: allow suppressing tool warnings * Changelog: note heartbeat tool-warning suppression
This commit is contained in:
@@ -922,6 +922,7 @@ export async function runEmbeddedPiAgent(
|
||||
verboseLevel: params.verboseLevel,
|
||||
reasoningLevel: params.reasoningLevel,
|
||||
toolResultFormat: resolvedToolResultFormat,
|
||||
suppressToolErrorWarnings: params.suppressToolErrorWarnings,
|
||||
inlineToolResultsAllowed: false,
|
||||
});
|
||||
|
||||
|
||||
@@ -74,6 +74,8 @@ export type RunEmbeddedPiAgentParams = {
|
||||
verboseLevel?: VerboseLevel;
|
||||
reasoningLevel?: ReasoningLevel;
|
||||
toolResultFormat?: ToolResultFormat;
|
||||
/** If true, suppress tool error warning payloads for this run (including mutating tools). */
|
||||
suppressToolErrorWarnings?: boolean;
|
||||
execOverrides?: Pick<ExecToolDefaults, "host" | "security" | "ask" | "node">;
|
||||
bashElevated?: ExecElevatedDefaults;
|
||||
timeoutMs: number;
|
||||
|
||||
@@ -252,6 +252,15 @@ describe("buildEmbeddedRunPayloads", () => {
|
||||
expect(payloads[0]?.text).toContain("connection timeout");
|
||||
});
|
||||
|
||||
it("suppresses mutating tool errors when suppressToolErrorWarnings is enabled", () => {
|
||||
const payloads = buildPayloads({
|
||||
lastToolError: { toolName: "exec", error: "command not found" },
|
||||
suppressToolErrorWarnings: true,
|
||||
});
|
||||
|
||||
expect(payloads).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("shows recoverable tool errors for mutating tools", () => {
|
||||
const payloads = buildPayloads({
|
||||
lastToolError: { toolName: "message", meta: "reply", error: "text required" },
|
||||
|
||||
@@ -48,7 +48,11 @@ function shouldShowToolErrorWarning(params: {
|
||||
lastToolError: LastToolError;
|
||||
hasUserFacingReply: boolean;
|
||||
suppressToolErrors: boolean;
|
||||
suppressToolErrorWarnings?: boolean;
|
||||
}): boolean {
|
||||
if (params.suppressToolErrorWarnings) {
|
||||
return false;
|
||||
}
|
||||
const isMutatingToolError =
|
||||
params.lastToolError.mutatingAction ?? isLikelyMutatingToolName(params.lastToolError.toolName);
|
||||
if (isMutatingToolError) {
|
||||
@@ -71,6 +75,7 @@ export function buildEmbeddedRunPayloads(params: {
|
||||
verboseLevel?: VerboseLevel;
|
||||
reasoningLevel?: ReasoningLevel;
|
||||
toolResultFormat?: ToolResultFormat;
|
||||
suppressToolErrorWarnings?: boolean;
|
||||
inlineToolResultsAllowed: boolean;
|
||||
}): Array<{
|
||||
text?: string;
|
||||
@@ -247,6 +252,7 @@ export function buildEmbeddedRunPayloads(params: {
|
||||
lastToolError: params.lastToolError,
|
||||
hasUserFacingReply: hasUserFacingAssistantReply,
|
||||
suppressToolErrors: Boolean(params.config?.messages?.suppressToolErrors),
|
||||
suppressToolErrorWarnings: params.suppressToolErrorWarnings,
|
||||
});
|
||||
|
||||
// Always surface mutating tool failures so we do not silently confirm actions that did not happen.
|
||||
|
||||
@@ -312,6 +312,7 @@ export async function runAgentTurnWithFallback(params: {
|
||||
}
|
||||
return isMarkdownCapableMessageChannel(channel) ? "markdown" : "plain";
|
||||
})(),
|
||||
suppressToolErrorWarnings: params.opts?.suppressToolErrorWarnings,
|
||||
bashElevated: params.followupRun.run.bashElevated,
|
||||
timeoutMs: params.followupRun.run.timeoutMs,
|
||||
runId,
|
||||
|
||||
@@ -166,6 +166,7 @@ export function createFollowupRunner(params: {
|
||||
thinkLevel: queued.run.thinkLevel,
|
||||
verboseLevel: queued.run.verboseLevel,
|
||||
reasoningLevel: queued.run.reasoningLevel,
|
||||
suppressToolErrorWarnings: opts?.suppressToolErrorWarnings,
|
||||
execOverrides: queued.run.execOverrides,
|
||||
bashElevated: queued.run.bashElevated,
|
||||
timeoutMs: queued.run.timeoutMs,
|
||||
|
||||
@@ -29,6 +29,8 @@ export type GetReplyOptions = {
|
||||
isHeartbeat?: boolean;
|
||||
/** Resolved heartbeat model override (provider/model string from merged per-agent config). */
|
||||
heartbeatModelOverride?: string;
|
||||
/** If true, suppress tool error warning payloads for this run. */
|
||||
suppressToolErrorWarnings?: boolean;
|
||||
onPartialReply?: (payload: ReplyPayload) => Promise<void> | void;
|
||||
onReasoningStream?: (payload: ReplyPayload) => Promise<void> | void;
|
||||
/** Called when a thinking/reasoning block ends. */
|
||||
|
||||
@@ -17,6 +17,10 @@ export const FIELD_HELP: Record<string, string> = {
|
||||
"Optional allowlist of skills for this agent (omit = all skills; empty = no skills).",
|
||||
"agents.list[].identity.avatar":
|
||||
"Avatar image path (relative to the agent workspace only) or a remote URL/data URL.",
|
||||
"agents.defaults.heartbeat.suppressToolErrorWarnings":
|
||||
"Suppress tool error warning payloads during heartbeat runs.",
|
||||
"agents.list[].heartbeat.suppressToolErrorWarnings":
|
||||
"Suppress tool error warning payloads during heartbeat runs.",
|
||||
"discovery.mdns.mode":
|
||||
'mDNS broadcast mode ("minimal" default, "full" includes cliPath/sshPort, "off" disables mDNS).',
|
||||
"gateway.auth.token":
|
||||
|
||||
@@ -220,6 +220,8 @@ export type AgentDefaultsConfig = {
|
||||
prompt?: string;
|
||||
/** Max chars allowed after HEARTBEAT_OK before delivery (default: 30). */
|
||||
ackMaxChars?: number;
|
||||
/** Suppress tool error warning payloads during heartbeat runs. */
|
||||
suppressToolErrorWarnings?: boolean;
|
||||
/**
|
||||
* When enabled, deliver the model's reasoning payload for heartbeat runs (when available)
|
||||
* as a separate message prefixed with `Reasoning:` (same as `/reasoning on`).
|
||||
|
||||
@@ -29,6 +29,7 @@ export const HeartbeatSchema = z
|
||||
accountId: z.string().optional(),
|
||||
prompt: z.string().optional(),
|
||||
ackMaxChars: z.number().int().nonnegative().optional(),
|
||||
suppressToolErrorWarnings: z.boolean().optional(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((val, ctx) => {
|
||||
|
||||
@@ -540,9 +540,10 @@ export async function runHeartbeatOnce(opts: {
|
||||
|
||||
try {
|
||||
const heartbeatModelOverride = heartbeat?.model?.trim() || undefined;
|
||||
const suppressToolErrorWarnings = heartbeat?.suppressToolErrorWarnings === true;
|
||||
const replyOpts = heartbeatModelOverride
|
||||
? { isHeartbeat: true, heartbeatModelOverride }
|
||||
: { isHeartbeat: true };
|
||||
? { isHeartbeat: true, heartbeatModelOverride, suppressToolErrorWarnings }
|
||||
: { isHeartbeat: true, suppressToolErrorWarnings };
|
||||
const replyResult = await getReplyFromConfig(ctx, replyOpts, cfg);
|
||||
const replyPayload = resolveHeartbeatReplyPayload(replyResult);
|
||||
const includeReasoning = heartbeat?.includeReasoning === true;
|
||||
|
||||
Reference in New Issue
Block a user