feat(channels): LLM-generated summary for large responses (closes #64)#65
Merged
Merged
Conversation
Replace the head-truncation pseudo-summary used when channel responses
exceed 4096 chars with a real LLM-generated summary.
Runtime: when the final response body is > 4096 chars, run one extra
Chat() call asking the model to summarise its own output in 2-4
sentences, and attach the result as a2a.Message.Summary. Failure to
produce a summary is non-fatal — callers fall back to existing
SplitSummaryAndReport head-truncation.
Channel adapters (Slack, Telegram): prefer a2a.Message.Summary over
SplitSummaryAndReport(text) when set, in both the file-part path and
the text-over-4096 path. Pre-Summary behaviour is preserved when
Summary is empty, so non-LLMExecutor callers and offline tests are
unaffected.
Skip summarisation when the LLM body itself is short — even if a tool
attached a large file part, the LLM text already acts as the summary
of that file content.
- forge-core/a2a/types.go: add Summary string to Message
- forge-core/runtime/summary.go: new file — summary prompt + generator
- forge-core/runtime/loop.go: finalizeResponse() at both terminal
return paths
- forge-plugins/channels/slack: prefer response.Summary
- forge-plugins/channels/telegram: prefer response.Summary
- docs/core-concepts/channels.md: document the new contract
9 new runtime tests (TestNeedsSummary, TestGenerateSummary_*,
TestFinalizeResponse_*) and 4 new channel tests
(TestSendResponse_PrefersMessageSummary,
TestSendResponse_FallsBackWhenNoSummary on both adapters).
This was referenced May 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When a channel (Slack/Telegram) response exceeds 4096 chars, today's "summary" is a head-truncation — the first paragraph or 500 chars of the body. Users see the report's introduction but never its conclusion. They have to open the attachment to find the answer.
This PR replaces the head-truncation with a real LLM-generated summary, while keeping the head-truncation as a non-fatal fallback. Closes #64.
Changes
forge-core/a2a/types.go— addSummary stringtoa2a.Message(omitempty, backwards compatible).forge-core/runtime/summary.go(new) —generateSummary()does one extraChat()call with a focused system prompt ("2-4 sentences conveying the answer, not the introduction"). Returns empty on any error.forge-core/runtime/loop.go— both terminal return paths now callfinalizeResponse()which populatesSummarywhen the body is > 4096 chars. No summariser pass for short bodies, even when a tool attached a large file part (the LLM text is already the summary in that case).forge-plugins/channels/slack/slack.go— preferresponse.SummaryoverSplitSummaryAndReport(text)in both the file-part path and the text-over-4096 path.forge-plugins/channels/telegram/telegram.go— same.docs/core-concepts/channels.md— new "Summary Source" table describing the contract.Contract
Summary▸ falls back to head-truncationSummary▸ falls back to head-truncationTest plan
go test ./...inforge-core— 9 new tests insummary_test.go+ existingTestToolResultTruncationstill greengo test ./...inforge-plugins— 4 new tests (TestSendResponse_PrefersMessageSummary,TestSendResponse_FallsBackWhenNoSummary× Slack + Telegram)go test ./...inforge-cli— no regressionsgofmt -wandgolangci-lint runclean on all three modulesresearch-report.mdattachmentNon-goals (deferred)
forge.yaml(inline_max_chars,summary_target_chars,attach_full_report, per-channel overrides). Mentioned in [Feature]: Channel responses should produce an LLM-generated summary alongside the markdown attachment, not a head-truncation #64; can ship as a follow-up if there's demand.SplitSummaryAndReportto a "preview" name to make the fallback nature explicit.