Long-Doc Chat - AG2

07 · Long-Doc Chat

A "remember the last words" chat exercise that stress-tests the assembly chain. Three policies compose to control exactly what the LLM sees on each call — drop non-conversation events, hard-cap to the last 6 events, then enforce a token budget. A separate TailWindowCompact strategy keeps the underlying stream history small too. Watch the compaction events fire as the conversation grows.

What it covers

Primitives covered

Source

<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br>50<br>51<br>52<br>53<br>54<br>55<br>56<br>57<br>58<br>59<br>60<br>61<br>62<br>63<br>64<br>65<br>66<br>67<br>68<br>69<br>70<br>71<br>72<br>73<br>74<br>75<br>76<br>77<br>78<br>79<br>80<br>81<br>82<br>83<br>84<br>85<br>86<br>87<br>88<br>89<br>90<br> <br>"""07 · Long-doc chat — composing assembly policies<br>Shows the assembly chain in action. Three policies compose in order:<br>1. ``ConversationPolicy`` — drops every event that isn't conversation or<br> tool traffic (no lifecycle noise reaches the LLM).<br>2. ``SlidingWindowPolicy(max_events=6)`` — hard-caps the number of events<br> forwarded to the LLM, so history can't grow unbounded.<br>3. ``TokenBudgetPolicy(max_tokens=2000)`` — character-based secondary cap,<br> belt-and-braces against one huge event blowing the budget.<br>Also pairs the assembly chain with ``TailWindowCompact`` so the agent's<br>stream history itself (not just the view into it) is kept small.<br>Run::<br> .venv/bin/python 07_long_doc_chat.py<br>"""<br>import asyncio<br>from ag2 import Agent, KnowledgeConfig<br>from ag2.compact import CompactTrigger, TailWindowCompact<br>from ag2.config import GeminiConfig<br>from ag2.events import CompactionCompleted<br>from ag2.knowledge import MemoryKnowledgeStore<br>from ag2.policies import (<br> ConversationPolicy,<br> SlidingWindowPolicy,<br> TokenBudgetPolicy,<br>)<br>from ag2.stream import MemoryStream<br>def section(title: str) -> None:<br> print(f"\n── {title} ───")<br>QUESTIONS = [<br> "Remember the word 'oak'.",<br> "Remember the word 'river'.",<br> "Remember the word 'lantern'.",<br> "Remember the word 'sable'.",<br> "Remember the word 'quartz'.",<br> "Name the three most recent words I asked you to remember.",<br>]<br>async def main() -> None:<br> config = GeminiConfig(model="gemini-3-flash-preview", temperature=0)<br> store = MemoryKnowledgeStore()<br> compactions: list[CompactionCompleted] = []<br> stream = MemoryStream()<br> stream.where(CompactionCompleted).subscribe(lambda e: compactions.append(e))<br> agent = Agent(<br> "lexicon",<br> prompt=(<br> "Be very terse — one short sentence per reply. "<br> "Answer directly without calling any tools."<br> ),<br> config=config,<br> assembly=[<br> ConversationPolicy(),<br> SlidingWindowPolicy(max_events=6, transparent=True),<br> TokenBudgetPolicy(max_tokens=2000),<br> ],<br> knowledge=KnowledgeConfig(<br> store=store,<br> compact=TailWindowCompact(target=4),<br> compact_trigger=CompactTrigger(max_events=8),<br> ),<br> )<br> section("Long-doc chat — assembly policies trim what the LLM actually sees")<br> reply = await agent.ask(QUESTIONS[0], stream=stream)<br> print(f"Q1> {QUESTIONS[0]}")<br> print(f"A1> {reply.body}")<br> for i, q in enumerate(QUESTIONS[1:], start=2):<br> reply = await reply.ask(q)<br> print(f"Q{i}> {q}")<br> print(f"A{i}> {reply.body}")<br> print()<br> print(f"Compactions fired during run: {len(compactions)}")<br> for c in compactions:<br> print(f" - {c.strategy}: {c.events_before} → {c.events_after} events")<br>if __name__ == "__main__":<br> asyncio.run(main())<br>