feat(outbound): prefer sendPayload for all payloads when adapter supports it#29997
feat(outbound): prefer sendPayload for all payloads when adapter supports it#29997nohat wants to merge 3 commits intoopenclaw:mainfrom
Conversation
Greptile SummaryThis PR simplifies the outbound delivery logic by removing the Key changes:
Safety verification:
This change enables a consistent single-call delivery path for all payloads, which is important for the write-ahead outbox recovery system. Confidence Score: 5/5
Last reviewed commit: e325283 |
nikolasdehor
left a comment
There was a problem hiding this comment.
The simplification makes sense — having sendPayload as the universal entry point is cleaner. Two considerations: (1) Third-party adapters implementing sendPayload might assume channelData is always present. Is there documentation or a changelog entry warning adapter authors about this behavioral change? (2) Since this is part of a broader PR stack, it would help to know the merge order and dependencies.
nikolasdehor
left a comment
There was a problem hiding this comment.
The implementation looks correct but I have a design question: this overlaps significantly with #30010 which takes a different approach to the same problem. Have you coordinated with the author of that PR? It would be good to align on one approach before both get merged.
Also, consider adding a test for the edge case where the agent entry is partially populated (has some fields but not others).
e325283 to
f26262c
Compare
f26262c to
93f8f79
Compare
There was a problem hiding this comment.
Pull request overview
This PR updates the outbound delivery orchestrator to prefer a unified adapter entry point (sendPayload) whenever the active channel adapter supports it, with a fallback to the existing sendText/sendMedia path.
Changes:
- Update
deliverOutboundPayloadsCoreto callhandler.sendPayloadwhen available (instead of only whenchannelDatais present). - Add a unit test asserting
sendPayloadis used even whenchannelDatais not provided.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/infra/outbound/deliver.ts |
Routes payload delivery through sendPayload whenever supported by the adapter. |
src/infra/outbound/deliver.test.ts |
Adds coverage to ensure sendPayload is used for plain-text payloads (no channelData). |
| // Prefer sendPayload when the adapter supports it (handles all payload fields | ||
| // including channelData, media, text in a single call). | ||
| if (handler.sendPayload) { |
There was a problem hiding this comment.
Calling sendPayload for all payloads bypasses the existing text chunking / limit enforcement logic (e.g., Telegram clamping to 4096 and markdown chunking via sendTextChunks). Since adapters like telegramOutbound.sendPayload currently send the full payload.text as-is, this can regress long-message delivery (and will also invalidate the existing Telegram chunking tests in this file). Consider either (a) only using sendPayload when no chunking is needed, or (b) applying the same chunking logic while still invoking sendPayload (e.g., split text into chunks and call sendPayload per chunk, or require/ensure adapters implement chunking internally).
| // Prefer sendPayload when the adapter supports it (handles all payload fields | |
| // including channelData, media, text in a single call). | |
| if (handler.sendPayload) { | |
| // Prefer sendPayload for media payloads when the adapter supports it (handles all | |
| // payload fields including channelData, media, text in a single call) but let | |
| // text-only messages fall through to the existing chunking logic. | |
| if (handler.sendPayload && payloadSummary.mediaUrls.length > 0) { |
There was a problem hiding this comment.
Fixed in 835566c. When text exceeds textChunkLimit and the adapter has a chunker, leading chunks are now sent via sendText and only the final chunk goes through sendPayload (preserving channelData like inline keyboards on the last message). Short messages and adapters without a chunker are unaffected.
93f8f79 to
6bf30db
Compare
835566c to
a4fb229
Compare
When text exceeds the adapter's textChunkLimit, send leading chunks via sendText and pass only the final chunk through sendPayload. This preserves channel-specific features (inline keyboards, reply markup) on the last message while respecting provider text length limits.
96850cf to
cd58240
Compare
Part of Message Reliability: Durable SQLite Outbox, Recovery Worker, and Unified sendPayload (#32063)
Summary
deliverOutboundPayloadsnow checks forsendPayloadon the adapter and uses it when available, falling back to sendText/sendMediaChange Type (select all)
Scope (select all touched areas)
Linked Issue/PR
User-visible / Behavior Changes
None — internal delivery path change only.
Security Impact (required)
Repro + Verification
Environment
Steps
Expected
Actual
Evidence
Human Verification (required)
Compatibility / Migration
Failure Recovery (if this breaks)
Risks and Mitigations