Skip to content

fix(agent): stop fabricating empty message content - #2678

Open
1688mengdie wants to merge 1 commit into
GCWing:mainfrom
BitFun-SIG:fix/empty-text-placeholder
Open

fix(agent): stop fabricating empty message content#2678
1688mengdie wants to merge 1 commit into
GCWing:mainfrom
BitFun-SIG:fix/empty-text-placeholder

Conversation

@1688mengdie

Copy link
Copy Markdown

Problem

The Text arm of impl From<Message> for AIMessage injected a synthetic placeholder
for empty text to avoid sending empty content to the provider: empty user text became
"(empty message)", empty system text became "You are a helpful assistant.", and
any other empty text became a single space. The model then treated these fabricated
strings as a real user utterance or a system directive.

Root cause

The "avoid empty content" defensive intent was implemented by injecting a non-empty
synthetic token, which defeats the downstream converters' existing empty-content
handling (openai/gemini filter out empty content, anthropic skips an empty system
message) because a non-empty fabricated string bypasses those filters. The Mixed arm
already returns None for empty text and is the correct in-file precedent to reuse;
the Text arm did not.

Fix

Return None for empty text in the Text arm instead of fabricating a placeholder,
keeping the existing warn! diagnostic. Nothing synthetic reaches the provider, the
converters' empty-content semantics apply, and the normal non-empty path is unchanged.
No new helper or configuration is introduced.

Testing

  • Test degree: tested (focused behavioral tests).
  • Added 4 behavioral cases in message.rs: empty user/system/assistant text becomes
    None; non-empty text is preserved.
  • cargo test -p bitfun-core --features agent-runtime --jobs 4 - message::tests green
    (9 passed); one unrelated pre-existing coordinator test still fails on the clean
    baseline.
  • AI-assisted: yes (generated with review; commands above recorded).

Closes #2675

Commit list:

  • cc7e90846 fix(agent): stop fabricating empty message content - message.rs Text arm
    placeholder -> None; adds 4 behavioral tests.

The Text arm of `impl From<Message> for AIMessage` injected a synthetic
placeholder for empty text to avoid sending empty content to the provider:
empty user text became "(empty message)", empty system became "You are a
helpful assistant.", and any other empty text became a single space. The
model then treated these fabricated strings as a real user utterance or a
system directive.

The fabricated value also defeats the downstream converters' existing
empty-content handling (openai/gemini filter out empty content, anthropic
skips an empty system message), because a non-empty fabricated string
bypasses the filter. The Mixed arm already produces None for empty text and
is the correct in-file precedent to reuse.

Return None for empty text in the Text arm instead, keeping the existing
warn! diagnostic. Nothing synthetic reaches the provider, the empty-content
semantics of the converters apply, and the normal non-empty path is
unchanged.

Test: added 4 behavioral cases (empty user/system/assistant to None, and
non-empty text preserved) in message.rs; agentic::core::message::tests pass.
AI: generated with review; verified with `cargo test -p bitfun-core
--features agent-runtime --jobs 4` (message.rs tests green; one unrelated
pre-existing coordinator test still fails on the clean baseline).
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.

[Bug]: empty text messages are fabricated into placeholder tokens before reaching the model

1 participant