Route active Feishu card text sends#500
Conversation
evandance
left a comment
There was a problem hiding this comment.
Thanks for picking this up — the bug is real (agent finishes with both a "running" streaming card and a separate final-text message). Worth fixing.
But I think this is the wrong layer. The agent calls feishu.send at turn-end because as far as it knows, that's how you send text. This PR addresses that by silently rerouting send at runtime — hiding the agent's intent rather than fixing it. Three cleaner places: tell the agent in the tool description not to double-send while a card is active; finalize the card in the dispatcher before letting send go through; or add an explicit feishu.finalizeStreamingCard() action. Runtime routing is the only option where callers have to look at a global lookup to predict what send will do — that's the smell.
Two concrete issues even if we accepted runtime routing as the design.
isCurrentTurnTarget returns true when to is empty, so any feishu.send({ text }) without an explicit target routes into whatever active card the session has. Empty to is a normal case (reply-in-thread, default chat), not an edge — so this silently changes destination on a common path.
activeCards is a module-scope Map, and cleanup depends on four hook paths in reply-dispatcher.ts all firing. There's no integration test for that. The next lifecycle refactor will silently leak the Map.
Before redesigning, could you share a trace or screenshot of the actual scenario, and why you went with runtime routing over the higher layers? That'd anchor the conversation in the real case.
|
Thanks, agreed. The bug is real, but the runtime reroute makes The observed scenario was: the agent finished a turn while a streaming card was still active, then sent final text separately, leaving both a running card and a separate final-text message. I will add that trace/screenshot to the PR description before redesigning. For the fix direction, I will step back from the module-scope |
|
Closing this in favor of #506. The replacement keeps |
Summary
Validation