Append 20,000 turns
For the complete documentation index see: llms.txt
All documentation pages available in markdown.
The demo script is adapted from the infinite chat history example in the adk-aerospike repository. Open that source if you want to see how each turn is constructed before you run it yourself.
The script appends 20,000 alternating user and assistant turns with scoped state. Each append clears in-memory events so the session object stays small.
Save and run the demo script
-
Create
infinite-chat-history-demo.pywith the script in this section (or copy from the adk-aerospike example):import asyncioimport timeimport aerospikefrom aerospike_helpers.operations import map_operationsfrom google.adk.events import Event, EventActionsfrom google.adk.sessions.base_session_service import GetSessionConfigfrom google.genai import types as genai_typesfrom adk_aerospike import AerospikeSessionServiceAPP, USER, SID = "demo-app", "user-1", "session-1"TURNS = 20_000EVENTS_BIN = "events"def summarize_segments(client: aerospike.Client, cur: int) -> tuple[int, list[int]]:counts: list[int] = []for gidx in range(cur + 1):seg_pk = ("test", "adk_sessions", f"{APP}:{USER}:{SID}:g:{gidx:08d}")try:_, _, res = client.operate(seg_pk, [map_operations.map_size(EVENTS_BIN)])n = int(res.get(EVENTS_BIN, 0))except Exception:n = 0if n:counts.append(n)return len(counts), countsasync def main() -> None:client = aerospike.client({"hosts": [("127.0.0.1", 3000)],"max_error_rate": 100,"error_rate_window": 1,}).connect()session_service = AerospikeSessionService(client, "test")session = await session_service.create_session(app_name=APP, user_id=USER, session_id=SID)t0 = time.time()started = time.perf_counter()for i in range(TURNS):author = "user" if i % 2 == 0 else "assistant"await session_service.append_event(session,Event(invocation_id=f"turn-{i:05d}",author=author,timestamp=t0 + i * 0.001,content=genai_types.Content(role="user" if author == "user" else "model",parts=[genai_types.Part(text=(f"turn {i} from {author}: ""context line for a long-running agent session. "))],),actions=EventActions(state_delta={"step": i,"app:tenant": "acme","user:locale": "en-US",}),),)session.events.clear()if i and i % 5000 == 0:print(f" appended {i}...")print(f"append_event x{TURNS} in {time.perf_counter() - started:.1f}s")full = await session_service.get_session(app_name=APP, user_id=USER, session_id=SID)print(f"full history: {len(full.events)} events")print(f" first: {full.events[0].content.parts[0].text}") # type: ignore[union-attr]print(f" last: {full.events[-1].content.parts[0].text}") # type: ignore[union-attr]print(f" merged state keys: {list(full.state.keys())}")recent5 = await session_service.get_session(app_name=APP,user_id=USER,session_id=SID,config=GetSessionConfig(num_recent_events=5),)texts5 = [e.content.parts[0].text for e in recent5.events] # type: ignore[union-attr]print(f"num_recent_events=5: {texts5}")after = await session_service.get_session(app_name=APP,user_id=USER,session_id=SID,config=GetSessionConfig(after_timestamp=t0 + 19_990 * 0.001),)print(f"after_timestamp (last ~10 turns): {len(after.events)} events")pk = ("test", "adk_sessions", f"{APP}:{USER}:{SID}")_, _, sbins = client.select(pk, ["cur", "state"])cur = int(sbins.get("cur", 0))n_segs, sizes = summarize_segments(client, cur)print(f"session record — cur={cur}, segments={n_segs}, "f"events_in_segments={sum(sizes)}, "f"session_state_keys={len(sbins.get('state') or {})}")if sizes:print(f" segment sizes (first 3): {sizes[:3]} ... (last 3): {sizes[-3:]}")listed = await session_service.list_sessions(app_name=APP, user_id=USER)print(f"list_sessions: {[s.id for s in listed.sessions]}")await session_service.delete_session(app_name=APP, user_id=USER, session_id=SID)session_service.close()print("Connection closed.")if __name__ == "__main__":asyncio.run(main()) -
Run the script:
Terminal window python infinite-chat-history-demo.pyExpected result appended 5000...appended 10000...appended 15000...append_event x20000 in 13.9sThe append phase prints progress every 5,000 turns. On a typical laptop, allow about 15 seconds for the demo to complete 20,000 appends.
Match those four lines in your terminal. The last line (
append_event x20000 in …) is the summary.x20000confirms all appends finished. The seconds afterinvary by hardware.The script continues into read and inspection phases after these lines. Let it run to completion for the remaining pages.
Review the append phase output
-
Read the append loop:
Each turn alternates user and assistant authors. Every
append_eventcarries a multi-scopestate_delta, then clears in-memory events so the session object stays small across 20,000 turns:infinite-chat-history-demo.py for i in range(TURNS):author = "user" if i % 2 == 0 else "assistant"await session_service.append_event(session,Event(invocation_id=f"turn-{i:05d}",author=author,timestamp=t0 + i * 0.001,content=genai_types.Content(role="user" if author == "user" else "model",parts=[genai_types.Part(text=(f"turn {i} from {author}: ""context line for a long-running agent session. ")],],),actions=EventActions(state_delta={"step": i, # session-scoped"app:tenant": "acme", # app-scoped"user:locale": "en-US", # user-scoped}),),)session.events.clear()stepupdates on every turn and stays session-scoped.app:tenantanduser:localeroute to app-wide and user-wide Aerospike records.session.events.clear()drops cached events after each persist. Storage holds the full history. The in-memorysessiondoes not grow with every turn.
-
Read the progress lines:
Inside the loop, the script prints every 5,000 turns and summarizes when the loop finishes:
infinite-chat-history-demo.py if i and i % 5000 == 0:print(f" appended {i}...")# after the loop:print(f"append_event x{TURNS} in {time.perf_counter() - started:.1f}s")appended 5000...appended 10000...appended 15000...append_event x20000 in 13.9sEvents pack into map segments until Aerospike signals a segment is full, then rollover opens the next segment. Segment counts are not printed during the append phase. You verify them on Inspect segments after the read output.