feat(cli): add agent_message type for precise --final output filtering

Introduce dedicated agent_message IR type to distinguish final AI responses
from generic stdout. This enables --final flag to show only agent messages,
filtering out all intermediate content (JSONL events, reasoning, tool calls).

Changes:
- Add agent_message type to CliOutputUnitType
- Update JsonLinesParser to map final responses from all tools (codex,
  gemini, claude, opencode) to agent_message type
- Add final_output field to database schema with migration
- Update getCachedOutput and getConversation to return finalOutput
- Prefer finalOutput in outputAction for --final flag

Fixes issue where --final showed raw JSONL instead of filtered content.
This commit is contained in:
catlog22
2026-01-18 19:49:33 +08:00
parent 40b003be68
commit 16c96229f9
5 changed files with 69 additions and 25 deletions

View File

@@ -982,12 +982,18 @@ async function executeCliTool(
// Create new turn - cache full output when not streaming (default)
const shouldCache = !parsed.data.stream;
// Compute parsed output (filtered, intermediate content removed) for final display
// Compute parsed output (filtered, intermediate content removed) for general display
const computedParsedOutput = flattenOutputUnits(allOutputUnits, {
excludeTypes: ['stderr', 'progress', 'metadata', 'system', 'tool_call', 'thought', 'code', 'file_diff', 'streaming_content'],
stripCommandJsonBlocks: true // Strip embedded command execution JSON from agent_message
});
// Compute final output (only agent_message) for --final flag
const computedFinalOutput = flattenOutputUnits(allOutputUnits, {
includeTypes: ['agent_message'],
stripCommandJsonBlocks: true // Strip embedded command execution JSON from agent_message
});
const newTurnOutput = {
stdout: stdout.substring(0, 10240), // Truncate preview to 10KB
stderr: stderr.substring(0, 2048), // Truncate preview to 2KB
@@ -995,7 +1001,8 @@ async function executeCliTool(
cached: shouldCache,
stdout_full: shouldCache ? stdout : undefined,
stderr_full: shouldCache ? stderr : undefined,
parsed_output: computedParsedOutput || undefined, // Filtered output for final display
parsed_output: computedParsedOutput || undefined, // Filtered output for general display
final_output: computedFinalOutput || undefined, // Agent message only for --final flag
structured: allOutputUnits // Save structured IR units
};
@@ -1156,7 +1163,8 @@ async function executeCliTool(
exit_code: code,
duration_ms: duration,
output: newTurnOutput,
parsedOutput: computedParsedOutput // Use already-computed filtered output
parsedOutput: computedParsedOutput, // Use already-computed filtered output
finalOutput: computedFinalOutput // Use already-computed agent_message only output
};
resolve({
@@ -1165,7 +1173,8 @@ async function executeCliTool(
conversation,
stdout,
stderr,
parsedOutput: execution.parsedOutput
parsedOutput: execution.parsedOutput,
finalOutput: execution.finalOutput
});
});