mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:50:43 +00:00
fix(exec): preserve turnSourceChannel as messageProvider in approval followup runs (#74666)
When an exec-approval followup run has no deliverable route and no gateway-internal channel, buildAgentFollowupArgs was passing channel=undefined to the spawned agent. This left defaults.messageProvider=undefined in the followup run, causing tools.elevated.allowFrom.<provider> checks to always fail with provider=null after the user approved an async elevated command. Thread turnSourceChannel through buildAgentFollowupArgs and use it as a fallback when sessionOnlyOriginChannel is absent. Fixes #74646. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -89,6 +89,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Plugin SDK/testing: lazy-load TypeScript from the plugin test-contract runtime and add release checks for critical SDK contract entrypoint imports and bundle size, so published packages fail preflight before shipping ESM-incompatible or oversized contract helpers. Thanks @vincentkoc.
|
||||
- Channels/Microsoft Teams: treat configured `19:...@thread.tacv2` and legacy `19:...@thread.skype` team/channel IDs as already resolved during startup, avoiding false `channels unresolved` warnings while preserving Graph name lookup for display-name entries. Fixes #74683. Thanks @dseravalli.
|
||||
- CLI/browser: preserve parent flags while lazy-loading browser subcommands, so `openclaw browser --json open` and `openclaw browser --json tabs` keep machine-readable output after reparsing. Fixes #74574. Thanks @devintegeritsm.
|
||||
- Exec/elevated: preserve `turnSourceChannel` as `messageProvider` on approval-followup runs so `tools.elevated.allowFrom.<provider>` checks no longer fail with `provider=null` after the user approves an async elevated command. Fixes #74646. Thanks @xhd2015.
|
||||
- Plugins/runtime-deps: add `openclaw plugins deps` inspection and repair with script-free package-manager defaults shared across plugin installers, so operators can repair missing bundled runtime deps without corrupting JSON output or blocking unrelated conflict-free deps. Thanks @vincentkoc.
|
||||
- Agents/output: strip internal `[tool calls omitted]` replay placeholders from user-facing replies while preserving visible reply whitespace. Fixes #74573. Thanks @blaspat.
|
||||
- Providers/Google Vertex: route authorized_user ADC credentials through OpenClaw's REST transport so Docker installs using gcloud application-default credentials no longer crash in the Google SDK before requests are sent. Fixes #74628. Thanks @frankhal2001-design.
|
||||
|
||||
@@ -252,6 +252,28 @@ describe("exec approval followup", () => {
|
||||
expect(sendMessage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("preserves turnSourceChannel as messageProvider on the followup run when no deliverable route exists", async () => {
|
||||
// Regression: #74646 — tools.elevated.allowFrom.<provider> fails in approval followup
|
||||
await sendExecApprovalFollowup({
|
||||
approvalId: "req-elevated-74646",
|
||||
sessionKey: "agent:main:telegram:-100123",
|
||||
turnSourceChannel: "telegram",
|
||||
resultText: "Exec completed: systemctl status gateway",
|
||||
});
|
||||
|
||||
expect(callGatewayTool).toHaveBeenCalledWith(
|
||||
"agent",
|
||||
expect.any(Object),
|
||||
expect.objectContaining({
|
||||
sessionKey: "agent:main:telegram:-100123",
|
||||
deliver: false,
|
||||
channel: "telegram",
|
||||
}),
|
||||
{ expectFinal: true },
|
||||
);
|
||||
expect(sendMessage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("throws when neither a session nor a deliverable route is available", async () => {
|
||||
await expect(
|
||||
sendExecApprovalFollowup({
|
||||
|
||||
@@ -145,17 +145,22 @@ function buildAgentFollowupArgs(params: {
|
||||
resultText: string;
|
||||
deliveryTarget: ExternalBestEffortDeliveryTarget;
|
||||
sessionOnlyOriginChannel?: string;
|
||||
turnSourceChannel?: string;
|
||||
turnSourceTo?: string;
|
||||
turnSourceAccountId?: string;
|
||||
turnSourceThreadId?: string | number;
|
||||
}) {
|
||||
const { deliveryTarget, sessionOnlyOriginChannel } = params;
|
||||
// When the followup run has no deliverable route and no gateway-internal channel,
|
||||
// preserve the raw turnSourceChannel so the spawned agent inherits messageProvider.
|
||||
// Without this, tools.elevated.allowFrom.<provider> checks fail with provider=null.
|
||||
const fallbackChannel = sessionOnlyOriginChannel ?? params.turnSourceChannel;
|
||||
return {
|
||||
sessionKey: params.sessionKey,
|
||||
message: buildExecApprovalFollowupPrompt(params.resultText),
|
||||
deliver: deliveryTarget.deliver,
|
||||
...(deliveryTarget.deliver ? { bestEffortDeliver: true as const } : {}),
|
||||
channel: deliveryTarget.deliver ? deliveryTarget.channel : sessionOnlyOriginChannel,
|
||||
channel: deliveryTarget.deliver ? deliveryTarget.channel : fallbackChannel,
|
||||
to: deliveryTarget.deliver
|
||||
? deliveryTarget.to
|
||||
: sessionOnlyOriginChannel
|
||||
@@ -241,6 +246,7 @@ export async function sendExecApprovalFollowup(
|
||||
resultText,
|
||||
deliveryTarget,
|
||||
sessionOnlyOriginChannel,
|
||||
turnSourceChannel: params.turnSourceChannel,
|
||||
turnSourceTo: params.turnSourceTo,
|
||||
turnSourceAccountId: params.turnSourceAccountId,
|
||||
turnSourceThreadId: params.turnSourceThreadId,
|
||||
|
||||
Reference in New Issue
Block a user