




















@@ -1,6 +1,7 @@
11import type { AgentMessage } from "@mariozechner/pi-agent-core";
22import type { SessionManager } from "@mariozechner/pi-coding-agent";
33import type { OpenClawConfig } from "../config/types.openclaw.js";
4+import { redactSensitiveText } from "../logging/redact.js";
45import { getGlobalHookRunner } from "../plugins/hook-runner-global.js";
56import {
67applyInputProvenanceToUserMessage,
@@ -16,6 +17,71 @@ export type GuardedSessionManager = SessionManager & {
1617clearPendingToolResults?: () => void;
1718};
181920+function redactTranscriptText(value: string, cfg?: OpenClawConfig): string {
21+if (cfg?.logging?.redactSensitive === "off") {
22+return value;
23+}
24+return redactSensitiveText(value, {
25+mode: cfg?.logging?.redactSensitive,
26+patterns: cfg?.logging?.redactPatterns,
27+});
28+}
29+30+function redactTranscriptContentBlock(block: unknown, cfg?: OpenClawConfig): unknown {
31+if (!block || typeof block !== "object" || Array.isArray(block)) {
32+return block;
33+}
34+const source = block as Record<string, unknown>;
35+let next: Record<string, unknown> | null = null;
36+const assign = (key: string, value: string) => {
37+const redacted = redactTranscriptText(value, cfg);
38+if (redacted === value) {
39+return;
40+}
41+next ??= { ...source };
42+next[key] = redacted;
43+};
44+45+if (typeof source.text === "string") {
46+assign("text", source.text);
47+}
48+if (typeof source.thinking === "string") {
49+assign("thinking", source.thinking);
50+}
51+if (typeof source.partialJson === "string") {
52+assign("partialJson", source.partialJson);
53+}
54+return next ?? block;
55+}
56+57+function redactTranscriptContent(content: unknown, cfg?: OpenClawConfig): unknown {
58+if (typeof content === "string") {
59+return redactTranscriptText(content, cfg);
60+}
61+if (!Array.isArray(content)) {
62+return content;
63+}
64+let changed = false;
65+const redacted = content.map((block) => {
66+const next = redactTranscriptContentBlock(block, cfg);
67+changed ||= next !== block;
68+return next;
69+});
70+return changed ? redacted : content;
71+}
72+73+function redactTranscriptMessage(message: AgentMessage, cfg?: OpenClawConfig): AgentMessage {
74+const source = message as unknown as Record<string, unknown>;
75+const redactedContent = redactTranscriptContent(source.content, cfg);
76+if (redactedContent === source.content) {
77+return message;
78+}
79+return {
80+ ...source,
81+content: redactedContent,
82+} as unknown as AgentMessage;
83+}
84+1985/**
2086 * Apply the tool-result guard to a SessionManager exactly once and expose
2187 * a flush method on the instance for easy teardown handling.
@@ -38,14 +104,31 @@ export function guardSessionManager(
38104}
3910540106const hookRunner = getGlobalHookRunner();
41-const beforeMessageWrite = hookRunner?.hasHooks("before_message_write")
42- ? (event: { message: import("@mariozechner/pi-agent-core").AgentMessage }) => {
43-return hookRunner.runBeforeMessageWrite(event, {
44-agentId: opts?.agentId,
45-sessionKey: opts?.sessionKey,
46-});
107+const beforeMessageWrite = (event: {
108+message: import("@mariozechner/pi-agent-core").AgentMessage;
109+}) => {
110+let message = event.message;
111+let changed = false;
112+if (hookRunner?.hasHooks("before_message_write")) {
113+const result = hookRunner.runBeforeMessageWrite(event, {
114+agentId: opts?.agentId,
115+sessionKey: opts?.sessionKey,
116+});
117+if (result?.block) {
118+return result;
47119}
48- : undefined;
120+if (result?.message) {
121+message = result.message;
122+changed = true;
123+}
124+}
125+const redacted = redactTranscriptMessage(message, opts?.config);
126+if (redacted !== message) {
127+message = redacted;
128+changed = true;
129+}
130+return changed ? { message } : undefined;
131+};
4913250133const transform = hookRunner?.hasHooks("tool_result_persist")
51134 ? (
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。