Skip to content

feat(channels): LLM-generated summary for large responses (closes #64)#65

Merged
initializ-mk merged 1 commit into
mainfrom
feature/channel-response-summary
May 19, 2026
Merged

feat(channels): LLM-generated summary for large responses (closes #64)#65
initializ-mk merged 1 commit into
mainfrom
feature/channel-response-summary

Conversation

@initializ-mk
Copy link
Copy Markdown
Contributor

@initializ-mk initializ-mk commented May 19, 2026

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 — add Summary string to a2a.Message (omitempty, backwards compatible).
  • forge-core/runtime/summary.go (new) — generateSummary() does one extra Chat() 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 call finalizeResponse() which populates Summary when 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 — prefer response.Summary over SplitSummaryAndReport(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

LLM body length File part attached Inline summary source
≤ 4096 chars Full body sent inline (no attachment)
≤ 4096 chars Yes The body itself (already a summary of the file)
> 4096 chars LLM-generated Summary ▸ falls back to head-truncation
> 4096 chars Yes LLM-generated Summary ▸ falls back to head-truncation

Test plan

  • go test ./... in forge-core — 9 new tests in summary_test.go + existing TestToolResultTruncation still green
  • go test ./... in forge-plugins — 4 new tests (TestSendResponse_PrefersMessageSummary, TestSendResponse_FallsBackWhenNoSummary × Slack + Telegram)
  • go test ./... in forge-cli — no regressions
  • gofmt -w and golangci-lint run clean on all three modules
  • Manual: deploy an agent with a research skill, verify Slack/Telegram receives a real summary + research-report.md attachment
  • Manual: verify offline/LLM-failure path still delivers head-truncated message (not empty)

Non-goals (deferred)

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).
@initializ-mk initializ-mk merged commit e001a3a into main May 19, 2026
10 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.

[Feature]: Channel responses should produce an LLM-generated summary alongside the markdown attachment, not a head-truncation

1 participant