Skip to content

fix: filter non-JSON log messages from ACP agent output#159

Closed
gandli wants to merge 4 commits intoopenclaw:mainfrom
gandli:fix/iflow-json-parse-error
Closed

fix: filter non-JSON log messages from ACP agent output#159
gandli wants to merge 4 commits intoopenclaw:mainfrom
gandli:fix/iflow-json-parse-error

Conversation

@gandli
Copy link
Contributor

@gandli gandli commented Mar 18, 2026

Problem

acpx fails to integrate with iflow CLI due to JSON parse errors when the agent outputs log messages like:

[iFlow ACP Agent] ACP adapter factory initialized
Failed to parse JSON message: [iFlow ACP Agent] ACP adapter factory initialized
SyntaxError: Unexpected token 'i', "[iFlow ACP "... is not valid JSON

Root Cause

iflow CLI outputs initialization log messages to stdout/stderr during startup. These non-JSON lines are passed to @agentclientprotocol/sdk's ndJsonStream parser, which attempts to parse them as JSON and fails.

Solution

Added two-layer filtering to prevent non-JSON log messages from breaking the ACP protocol stream:

  1. filterAcpOutputStream() - New method that filters the output stream before ndJsonStream parsing, silently skipping lines that cannot be parsed as JSON
  2. isValidAcpMessage() - Additional validation layer in createTappedStream() to ensure only valid ACP messages are processed

Testing

  • ✅ All 253 existing tests pass
  • acpx iflow sessions new now works without JSON parse errors
  • ✅ Compatible with other ACP agents that output log messages

Impact

Fixes integration with iflow CLI and other ACP agents that output initialization log messages to stdout/stderr during startup.

- Add filterAcpOutputStream() to filter out non-JSON lines from agent stdout before ndJsonStream parsing
- Add isValidAcpMessage() check in createTappedStream() as additional safety layer
- Prevents '[iFlow ACP Agent] ...' style log messages from causing JSON parse errors in @agentclientprotocol/sdk

Fixes integration with iflow CLI and other ACP agents that output log messages to stdout/stderr.
@gandli gandli force-pushed the fix/iflow-json-parse-error branch from f2e397a to 684d721 Compare March 18, 2026 14:10
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f2e397ac65

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1725 to +1727
} catch {
// If it fails to parse, it's likely a log message - skip it silently
// This prevents "[iFlow ACP Agent] ..." messages from causing parse errors

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail fast on stdout protocol violations

If an adapter prints banner/log text to stdout and then never completes the ACP handshake, this catch now drops that line and leaves connection.initialize() pending forever for every non-Gemini agent, because the only startup timeout here is the Gemini-specific path at src/client.ts:1020-1036. Before this change the same misconfiguration failed immediately with a parse error, so silently skipping stdout noise turns a debuggable protocol violation into a hang.

Useful? React with 👍 / 👎.

Comment on lines +1701 to +1703
const { value, done } = await reader.read();
if (done) {
break;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Flush the buffered final frame at EOF

When the child closes stdout without a trailing newline on the last JSON-RPC frame, hitting done breaks out of the loop and the remaining buffer is never parsed or enqueued. That drops the agent's final ACP message, so one-shot adapters can hang waiting for initialize() or the last prompt result even though the response was already written before exit.

Useful? React with 👍 / 👎.

gandli added 3 commits March 18, 2026 22:17
This hook automatically removes any Co-authored-by lines from commit messages,
preventing AI assistants from adding their signature to commits.
- Remove unused 'parsed' variable in filterAcpOutputStream()
- Keep JSON.parse() call for validation but don't assign to variable
- Add fail-fast mechanism: throw error after 10 consecutive non-JSON lines
  to detect adapters that don't support stdio ACP mode
- Flush buffered content at EOF to handle final JSON-RPC frame without trailing newline
- Reset non-JSON counter after successful JSON parse to allow occasional log lines

Addresses:
- P2: Fail fast on stdout protocol violations
- P2: Flush the buffered final frame at EOF
@gandli gandli closed this Mar 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant