mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 13:26:04 -06:00
fix(agents): preserve trusted tool media provenance
This commit is contained in:
@@ -28,6 +28,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Telegram/Gateway: route targeted Telegram `/stop@bot` messages onto the control lane without cached bot metadata and match gateway stop requests across raw/canonical session aliases. (#82298) Thanks @VACInc.
|
||||
- MS Teams/media: sniff inline `data:image/*` attachment bytes before staging them, skipping payloads that are not actually images.
|
||||
- WebChat/media: require trusted local-media provenance before preserving local audio reply paths for display, so untrusted audio-looking paths go through normal staging and read-policy checks.
|
||||
- Agents/tool media: preserve trusted local-media provenance when merging generated tool attachments into final reply payloads, so trusted audio/media survives outbound display normalization.
|
||||
- Update: let package-swap `doctor --fix` persist core config repairs while plugin schemas are still converging, preventing update failures on externalized channel configs.
|
||||
- Update: carry plugin-validation bypasses into config mutation pre-write reads, so package update doctor repairs can finish while externalized plugin schemas are converging.
|
||||
- Update/doctor: keep plugin-validation bypasses on the top-level `$include` config write path, so package repair can update included plugin config files without flattening them into the root config.
|
||||
|
||||
@@ -2516,6 +2516,7 @@ export async function runEmbeddedPiAgent(
|
||||
payloads,
|
||||
toolMediaUrls: attempt.toolMediaUrls,
|
||||
toolAudioAsVoice: attempt.toolAudioAsVoice,
|
||||
toolTrustedLocalMedia: attempt.toolTrustedLocalMedia,
|
||||
});
|
||||
const timedOutDuringPrompt =
|
||||
timedOut && !timedOutDuringCompaction && !timedOutDuringToolExecution;
|
||||
|
||||
@@ -4277,6 +4277,7 @@ export async function runEmbeddedAttempt(
|
||||
heartbeatToolResponse: getHeartbeatToolResponse(),
|
||||
toolMediaUrls: pendingToolMediaReply?.mediaUrls,
|
||||
toolAudioAsVoice: pendingToolMediaReply?.audioAsVoice,
|
||||
toolTrustedLocalMedia: pendingToolMediaReply?.trustedLocalMedia,
|
||||
successfulCronAdds: getSuccessfulCronAdds(),
|
||||
cloudCodeAssistFormatError: Boolean(
|
||||
lastAssistant?.errorMessage && isCloudCodeAssistFormatError(lastAssistant.errorMessage),
|
||||
|
||||
@@ -70,4 +70,23 @@ describe("mergeAttemptToolMediaPayloads", () => {
|
||||
deliverDespiteSourceReplySuppression: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves trusted local media provenance when merging tool media", () => {
|
||||
expect(
|
||||
mergeAttemptToolMediaPayloads({
|
||||
payloads: [{ text: "done" }],
|
||||
toolMediaUrls: ["/tmp/reply.opus"],
|
||||
toolAudioAsVoice: true,
|
||||
toolTrustedLocalMedia: true,
|
||||
}),
|
||||
).toEqual([
|
||||
{
|
||||
text: "done",
|
||||
mediaUrls: ["/tmp/reply.opus"],
|
||||
mediaUrl: "/tmp/reply.opus",
|
||||
audioAsVoice: true,
|
||||
trustedLocalMedia: true,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,11 +7,12 @@ export function mergeAttemptToolMediaPayloads(params: {
|
||||
payloads?: EmbeddedRunPayload[];
|
||||
toolMediaUrls?: string[];
|
||||
toolAudioAsVoice?: boolean;
|
||||
toolTrustedLocalMedia?: boolean;
|
||||
}): EmbeddedRunPayload[] | undefined {
|
||||
const mediaUrls = Array.from(
|
||||
new Set(params.toolMediaUrls?.map((url) => url.trim()).filter(Boolean) ?? []),
|
||||
);
|
||||
if (mediaUrls.length === 0 && !params.toolAudioAsVoice) {
|
||||
if (mediaUrls.length === 0 && !params.toolAudioAsVoice && !params.toolTrustedLocalMedia) {
|
||||
return params.payloads;
|
||||
}
|
||||
|
||||
@@ -25,6 +26,7 @@ export function mergeAttemptToolMediaPayloads(params: {
|
||||
mediaUrls: mergedMediaUrls.length ? mergedMediaUrls : undefined,
|
||||
mediaUrl: payload.mediaUrl ?? mergedMediaUrls[0],
|
||||
audioAsVoice: payload.audioAsVoice || params.toolAudioAsVoice || undefined,
|
||||
trustedLocalMedia: payload.trustedLocalMedia || params.toolTrustedLocalMedia || undefined,
|
||||
});
|
||||
return payloads;
|
||||
}
|
||||
@@ -35,6 +37,7 @@ export function mergeAttemptToolMediaPayloads(params: {
|
||||
mediaUrls: mediaUrls.length ? mediaUrls : undefined,
|
||||
mediaUrl: mediaUrls[0],
|
||||
audioAsVoice: params.toolAudioAsVoice || undefined,
|
||||
trustedLocalMedia: params.toolTrustedLocalMedia || undefined,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -122,6 +122,7 @@ export type EmbeddedRunAttemptResult = {
|
||||
heartbeatToolResponse?: HeartbeatToolResponse;
|
||||
toolMediaUrls?: string[];
|
||||
toolAudioAsVoice?: boolean;
|
||||
toolTrustedLocalMedia?: boolean;
|
||||
successfulCronAdds?: number;
|
||||
cloudCodeAssistFormatError: boolean;
|
||||
attemptUsage?: NormalizedUsage;
|
||||
|
||||
@@ -173,6 +173,7 @@ export type EmbeddedPiRunResult = {
|
||||
isError?: boolean;
|
||||
isReasoning?: boolean;
|
||||
audioAsVoice?: boolean;
|
||||
trustedLocalMedia?: boolean;
|
||||
channelData?: Record<string, unknown>;
|
||||
}>;
|
||||
meta: EmbeddedPiRunMeta;
|
||||
|
||||
Reference in New Issue
Block a user