feat(FN-3175): document global tool output persistence setting in settings

Added documentation for the global tool output persistence setting to the settings reference guide.

Fusion-Task-Id: FN-3175
This commit is contained in:
Fusion
2026-05-02 02:05:15 -07:00
committed by gsxdsm
parent 3cdd77cd55
commit b4401d5911
16 changed files with 128 additions and 2 deletions

View File

@@ -155,6 +155,24 @@ describe("AgentLogger", () => {
expect(store.appendAgentLog).toHaveBeenCalledWith("FN-004", "Read", "tool", "src/index.ts", undefined);
});
it("omits tool detail when persistAgentToolOutput is disabled", async () => {
const store = createMockStore();
const logger = new AgentLogger({
store,
taskId: "FN-004B",
persistAgentToolOutput: false,
});
logger.onToolStart("Read", { path: "src/index.ts" });
logger.onToolEnd("Read", false, "ok");
logger.onToolEnd("Read", true, "err");
await vi.advanceTimersByTimeAsync(0);
expect(store.appendAgentLog).toHaveBeenNthCalledWith(1, "FN-004B", "Read", "tool", undefined, undefined);
expect(store.appendAgentLog).toHaveBeenNthCalledWith(2, "FN-004B", "Read", "tool_result", undefined, undefined);
expect(store.appendAgentLog).toHaveBeenNthCalledWith(3, "FN-004B", "Read", "tool_error", undefined, undefined);
});
it("logs tool with undefined detail for unknown args", async () => {
const store = createMockStore();
const logger = new AgentLogger({ store, taskId: "FN-005" });

View File

@@ -1417,6 +1417,7 @@ export class HeartbeatMonitor {
agentLogger = new AgentLogger({
appendLog: (entry) => this.store.appendRunLog(agentId, run.id, entry),
agent: agent.role as AgentRole,
persistAgentToolOutput: memorySettings?.persistAgentToolOutput,
});
} else if (taskId) {
agentLogger = new AgentLogger({
@@ -1424,6 +1425,7 @@ export class HeartbeatMonitor {
taskId,
agent: agent.role as AgentRole,
appendLog: (entry) => this.store.appendRunLog(agentId, run.id, entry),
persistAgentToolOutput: memorySettings?.persistAgentToolOutput,
});
}

View File

@@ -44,6 +44,8 @@ export function summarizeToolArgs(name: string, args?: Record<string, unknown>):
* When both are provided, both sinks receive every entry.
*/
export interface AgentLoggerOptions {
/** When false, omit `detail` payloads for tool entries while preserving the rows. */
persistAgentToolOutput?: boolean;
/** The task store used to persist agent log entries (task-store mode). */
store?: TaskStore;
/** The task ID this logger is associated with (task-store mode). */
@@ -107,6 +109,7 @@ export class AgentLogger {
private readonly externalTextCb?: (taskId: string, delta: string) => void;
private readonly externalToolCb?: (taskId: string, toolName: string) => void;
private readonly log = createLogger("agent-logger");
private readonly persistAgentToolOutput: boolean;
constructor(options: AgentLoggerOptions) {
this.store = options.store;
@@ -117,6 +120,7 @@ export class AgentLogger {
this.externalToolCb = options.onAgentTool;
this.flushSizeBytes = options.flushSizeBytes ?? FLUSH_SIZE_BYTES;
this.flushIntervalMs = options.flushIntervalMs ?? FLUSH_INTERVAL_MS;
this.persistAgentToolOutput = options.persistAgentToolOutput !== false;
// Bind callbacks so they can be passed directly as function references
this.onText = this.onText.bind(this);
@@ -208,12 +212,14 @@ export class AgentLogger {
* @param storeWarnMsg - Warning message prefix used when the task-store write fails.
*/
private writeEntry(text: string, type: AgentLogEntry["type"], detail: string | undefined, _storeWarnMsg: string, immediate = false): void {
const isToolEntry = type === "tool" || type === "tool_result" || type === "tool_error";
const includeDetail = !isToolEntry || this.persistAgentToolOutput;
const entry: AgentLogEntry = {
timestamp: new Date().toISOString(),
taskId: this.taskId,
text,
type,
...(detail !== undefined && { detail }),
...(detail !== undefined && includeDetail && { detail }),
...(this.agent !== undefined && { agent: this.agent }),
};

View File

@@ -2679,6 +2679,7 @@ export class TaskExecutor {
store: this.store,
taskId: task.id,
agent: "executor",
persistAgentToolOutput: settings.persistAgentToolOutput,
onAgentText: (taskId, delta) => {
lastAssistantText += delta;
stuckDetector?.recordActivity(taskId);
@@ -4762,6 +4763,7 @@ and show an appropriate message to the user.\`
store: this.store,
taskId: task.id,
agent: "reviewer",
persistAgentToolOutput: settings.persistAgentToolOutput,
onAgentText: (taskId, delta) => {
this.options.onAgentText?.(taskId, delta);
},

View File

@@ -896,6 +896,7 @@ async function attemptInMergeVerificationFix(
store,
taskId,
agent: "merger",
persistAgentToolOutput: settings.persistAgentToolOutput,
onAgentText: options.onAgentText,
onAgentTool: options.onAgentTool,
});
@@ -2275,6 +2276,7 @@ You are assisting with a paused \`git pull --rebase\`.
store,
taskId,
agent: "merger",
persistAgentToolOutput: settings.persistAgentToolOutput,
onAgentText: options?.onAgentText
? (_id, delta) => options.onAgentText?.(delta)
: undefined,
@@ -4707,6 +4709,7 @@ async function runAiAgentForCommit(params: AiAgentParams): Promise<{ success: bo
store,
taskId,
agent: "merger",
persistAgentToolOutput: settings.persistAgentToolOutput,
onAgentText: options.onAgentText
? (_id, delta) => options.onAgentText!(delta)
: undefined,
@@ -5298,6 +5301,7 @@ If issues are found that need attention, describe them clearly and include concr
store,
taskId,
agent: "merger",
persistAgentToolOutput: settings.persistAgentToolOutput,
});
try {

View File

@@ -343,6 +343,7 @@ export async function reviewStep(
onAgentText: options.onText
? (_id, delta) => options.onText!(delta)
: undefined,
persistAgentToolOutput: liveSettings?.persistAgentToolOutput,
})
: null;

View File

@@ -911,6 +911,7 @@ export class StepSessionExecutor {
store: this.store,
taskId: taskDetail.id,
agent: "executor",
persistAgentToolOutput: settings.persistAgentToolOutput,
});
let session: AgentSession | null = null;

View File

@@ -888,6 +888,7 @@ export class TriageProcessor {
store: this.store,
taskId: task.id,
agent: "triage",
persistAgentToolOutput: settings.persistAgentToolOutput,
onAgentText: (id, delta) => {
stuckDetector?.recordActivity(task.id);
this.options.onAgentText?.(id, delta);