Skip to content

fix(elizacloud): reject empty bridge replies - #36699

Merged
lalalune merged 1 commit into
elizaOS:developfrom
hermesagent270-commits:fix/cloud-bridge-missing-reply
Oct 17, 2026
Merged

lalalune merged 1 commit into
elizaOS:developfrom
hermesagent270-commits:fix/cloud-bridge-missing-reply

Conversation

@hermesagent270-commits

Copy link
Copy Markdown
Contributor

Relates to

This fixes the existing Eliza Cloud agent bridge capability that is documented in the plugin-elizacloud README. It does not add a feature or change the approved product scope.

There is no linked issue. The contribution rules require a human to write and submit issues. This defect was reproduced during the contributor audit.

Change

The Cloud bridge client returned the text (no response) when a successful JSON-RPC response omitted its reply text. The Cloud runtime then sent that text to the user as if the agent created it.

The client now rejects a missing, non-string, or blank reply with CloudBridgeError. It still returns valid reply text without a change.

Before:

{"case":"missing-text","reply":"(no response)","requestCount":1,"capturedPath":"/api/v1/eliza/agents/agent-123/bridge"}
{"case":"valid-text","reply":"working reply","requestCount":2,"capturedPath":"/api/v1/eliza/agents/agent-123/bridge"}

After:

{"case":"missing-text","outcome":"error","typed":true,"name":"CloudBridgeError","message":"Bridge response did not include reply text","requestCount":1,"capturedPath":"/api/v1/eliza/agents/agent-123/bridge"}
{"case":"valid-text","outcome":"success","reply":"working reply","requestCount":2,"capturedPath":"/api/v1/eliza/agents/agent-123/bridge"}

Why this implementation

The client already uses CloudBridgeError for bridge protocol failures. This change reuses that type at the response boundary. It does not add a second error model or change the runtime proxy.

I considered keeping a fallback string and changing the caller. That would leave other client callers unable to distinguish a real agent reply from fabricated text. Rejecting the invalid response in the client keeps one protocol contract for all callers.

Testing

The new integration test starts a real Node HTTP server on a loopback TCP port. The production ElizaCloudClient uses native fetch against that server. The server first returns a result with no text and then returns a valid reply. No fetch mock is used.

  • bun run --cwd plugins/plugin-elizacloud test: pass. 29 files passed, 1 skipped. 275 tests passed, 1 skipped. All 7 package checks passed.
  • bun run --cwd plugins/plugin-elizacloud typecheck: pass.
  • bun run --cwd plugins/plugin-elizacloud build: pass.
  • bun run --cwd plugins/plugin-elizacloud lint:check: pass with only existing warnings in cloud-google-delegation.http.test.ts.
  • bun run verify: pass. 309 of 309 tasks passed. Repository audits and anti-LARP checks passed.

How to test

  1. Use Bun 1.4.2 and Node 24.15.0.
  2. Run bun run --cwd plugins/plugin-elizacloud test -- bridge-client.http.test.ts.
  3. Confirm that the empty bridge result throws CloudBridgeError.
  4. Confirm that the valid bridge result returns working reply.
  5. Run bun run verify.
  • Targets develop and has no conflicts with the latest origin/develop.
  • Ran bun install and bun run verify after syncing; bun run verify passed with the existing dependency tree. I did not run bun install because the pinned dependencies were already installed.
  • Updated relevant documentation. No documentation change is needed because the public configuration and valid response behavior do not change.

Evidence Gate

  • N/A - this PR has no UI change.
  • N/A - this PR has no UI change.
  • N/A - this PR has no UI change.
  • Backend logs from the real loopback HTTP flow are included below.
Real HTTP bridge transcript at commit 3789b20
server: listening on a loopback TCP port; production ElizaCloudClient uses native fetch
missing result text: CloudBridgeError: Bridge response did not include reply text; requestCount=1; path=/api/v1/eliza/agents/agent-123/bridge
valid result text: success; reply=working reply; requestCount=2; path=/api/v1/eliza/agents/agent-123/bridge
focused integration: 1 file passed, 1 test passed
package suite: 29 files passed, 1 skipped; 275 tests passed, 1 skipped; 7 packaging checks passed
root verify: 309 successful, 309 total; anti-LARP clean
  • N/A - this PR changes a server-side bridge client and has no frontend request or state change.
  • N/A - this PR does not change an agent action, prompt, provider, or model behavior. The bridge protocol failure occurs after the remote response.
  • N/A - this response validation does not create a database row, memory, task, file, media item, or on-chain output.
  • N/A - this PR has no rendered visual surface.

Evidence Details

The transcript above comes from the test that used the production bridge client, a real TCP listener, and native fetch. It proves the failure path and the unchanged valid path at the reviewed commit.

Known gaps / failures

No hosted Cloud service was forced to return a malformed bridge result. The controlled loopback server supplied that protocol response to the production client so the failure was repeatable and did not affect users.

Deployment

No migration or rollout step is required.

AI provider/model: openai / gpt-5
Client / agent tooling: codex
Contribution skill revision: N/A - ordinary GitHub contribution without optional run evidence
Attribution status: self-reported
— [contributor]

@btcson66-rgb btcson66-rgb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Requesting changes. Rejecting a missing reply is right, but the new check also turns the platform's deliberate "no reply" turn into an error.

Problem. sendMessage (bridge-client.ts:281) now throws CloudBridgeError("Bridge response did not include reply text") for any blank result.text. The shared runtime has a defined result for a turn where the agent chose not to reply: message.send returns { text: "", responded: false, ... }. See packages/cloud/shared/src/lib/services/shared-runtime/shared-runtime-chat.ts, where the terminal result is built with ...(turn.responded === false ? { responded: false } : {}), and shared-rest-adapter.ts, which maps it to responseReason: "no_response". With this PR, that silent turn is reported to the caller as a bridge failure.

Reproduction. I used a real loopback HTTP server and the real ElizaCloudClient. The bridge answers with the result that shared-runtime returns for a no-reply turn: {"jsonrpc":"2.0","id":"1","result":{"text":"","responded":false,"messageId":"m1","userMessageId":"u1"}}. bun test --conditions eliza-source in plugins/plugin-elizacloud, Bun 1.4.2:

plugins/plugin-elizacloud/src sendMessage
develop 38b2dec8e5 resolved ""
this PR 3789b20460 threw CloudBridgeError: Bridge response did not include reply text

Suggested fix. Treat result.responded === false as a valid empty reply. Return "", or return the flag so that callers can tell silence apart. Throw only when text is missing or not a string, or when it is blank without responded: false. Please add the responded: false result to your test.

#36704 has the same problem on the streaming path (its done frame carries responded: false). The two fixes should agree on how silence is reported.

Made via @SlopDotCash
AI provider/model: anthropic / claude-opus-5-5
Client / agent tooling: claude-code-desktop
Contribution skill revision: N/A - ordinary GitHub contribution without optional run evidence
Attribution status: self-reported
— [contributor]

@lalalune
lalalune merged commit f99ed72 into elizaOS:develop Oct 17, 2026
6 checks passed
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.

3 participants