From 662e6a48151c0f4b5d1ac680221232840440d536 Mon Sep 17 00:00:00 2001 From: RockChinQ Date: Thu, 12 Mar 2026 09:52:59 -0400 Subject: [PATCH] fix(longtext): avoid split interfering with multi-chain agent responses Use query variable '_longtext_split_extra_chains' to pass extra split segments instead of appending to resp_message_chain directly. This prevents agent tool-call multi-round responses from being misidentified as split results and sent repeatedly. respback.py reverts to original single-chain logic and appends split extra chains after the main response. --- src/langbot/pkg/pipeline/longtext/longtext.py | 13 ++-- src/langbot/pkg/pipeline/respback/respback.py | 64 ++++++++----------- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/src/langbot/pkg/pipeline/longtext/longtext.py b/src/langbot/pkg/pipeline/longtext/longtext.py index 3920ec41..73094db3 100644 --- a/src/langbot/pkg/pipeline/longtext/longtext.py +++ b/src/langbot/pkg/pipeline/longtext/longtext.py @@ -97,10 +97,15 @@ class LongTextProcessStage(stage.PipelineStage): original_text = str(query.resp_message_chain[-1]) threshold = query.pipeline_config['output']['long-text-processing']['threshold'] segments = self.strategy_impl.split_text(original_text, threshold) - query.resp_message_chain.pop() - for segment in segments: - query.resp_message_chain.append( - platform_message.MessageChain([platform_message.Plain(text=segment)]) + # Replace the last chain with the first segment, store extra segments separately + # to avoid interfering with existing multi-chain scenarios (e.g. agent tool calls) + query.resp_message_chain[-1] = platform_message.MessageChain( + [platform_message.Plain(text=segments[0])] + ) + if len(segments) > 1: + query.set_variable( + '_longtext_split_extra_chains', + [platform_message.MessageChain([platform_message.Plain(text=seg)]) for seg in segments[1:]], ) else: query.resp_message_chain[-1] = platform_message.MessageChain( diff --git a/src/langbot/pkg/pipeline/respback/respback.py b/src/langbot/pkg/pipeline/respback/respback.py index cd397857..87120f78 100644 --- a/src/langbot/pkg/pipeline/respback/respback.py +++ b/src/langbot/pkg/pipeline/respback/respback.py @@ -30,48 +30,40 @@ class SendResponseBackStage(stage.PipelineStage): await asyncio.sleep(random_delay) + if query.pipeline_config['output']['misc']['at-sender'] and isinstance( + query.message_event, platform_events.GroupMessage + ): + query.resp_message_chain[-1].insert(0, platform_message.At(target=query.message_event.sender.id)) + quote_origin = query.pipeline_config['output']['misc']['quote-origin'] - if len(query.resp_message_chain) > 1: - # Multiple chains (split strategy): send each sequentially - for i, chain in enumerate(query.resp_message_chain): - is_first = i == 0 - - if ( - is_first - and query.pipeline_config['output']['misc']['at-sender'] - and isinstance(query.message_event, platform_events.GroupMessage) - ): - chain.insert(0, platform_message.At(target=query.message_event.sender.id)) + has_chunks = any(isinstance(msg, provider_message.MessageChunk) for msg in query.resp_messages) + # TODO 命令与流式的兼容性问题 + if await query.adapter.is_stream_output_supported() and has_chunks: + is_final = [msg.is_final for msg in query.resp_messages][0] + await query.adapter.reply_message_chunk( + message_source=query.message_event, + bot_message=query.resp_messages[-1], + message=query.resp_message_chain[-1], + quote_origin=quote_origin, + is_final=is_final, + ) + else: + await query.adapter.reply_message( + message_source=query.message_event, + message=query.resp_message_chain[-1], + quote_origin=quote_origin, + ) + # Send extra chains produced by long text split strategy + extra_chains = query.get_variable('_longtext_split_extra_chains') + if extra_chains: + for chain in extra_chains: await query.adapter.reply_message( message_source=query.message_event, message=chain, - quote_origin=quote_origin if is_first else False, - ) - - else: - if query.pipeline_config['output']['misc']['at-sender'] and isinstance( - query.message_event, platform_events.GroupMessage - ): - query.resp_message_chain[-1].insert(0, platform_message.At(target=query.message_event.sender.id)) - - has_chunks = any(isinstance(msg, provider_message.MessageChunk) for msg in query.resp_messages) - # TODO 命令与流式的兼容性问题 - if await query.adapter.is_stream_output_supported() and has_chunks: - is_final = [msg.is_final for msg in query.resp_messages][0] - await query.adapter.reply_message_chunk( - message_source=query.message_event, - bot_message=query.resp_messages[-1], - message=query.resp_message_chain[-1], - quote_origin=quote_origin, - is_final=is_final, - ) - else: - await query.adapter.reply_message( - message_source=query.message_event, - message=query.resp_message_chain[-1], - quote_origin=quote_origin, + quote_origin=False, ) + query.set_variable('_longtext_split_extra_chains', None) return entities.StageProcessResult(result_type=entities.ResultType.CONTINUE, new_query=query)