Claude Architect WorkshopPDFEPUBlearnwithparam.comkaas.team

Foundations, lesson 6

Long conversations

A summary drops the facts unless code keeps them

After 30 turns your agent summarises the case, and the refund amount and the approval date fall out of the summary. Full order and shipment results fill the rest of the window. The customer asks how much was refunded and the agent has no answer. This is the agent at Lumen Supply, an online electronics shop. You will watch it lose the facts, then fix it with two small functions.

I doWatch the failure and its fix.

Facts sit outside the summary

Three parts share the work. Code keeps the facts. Code also trims each tool result before Claude reads it. Claude answers the question.

The case is Dana's refund: 30 turns over two days. A long case reaches Claude as a summary of the story, a few recent messages, and a facts block of values that must not be lost.

Facts and trimmed output go in. The summary is the story.Turns30 of themFacts and trimkept in codeClaudereads the facts firstthe facts are code, so a summary cannot drop themFacts and trimmed output go in. The summary is the story.Turns30 of themFacts and trimkept in codeClaudereads the facts firstthe facts are code, so a summary cannot drop them

The facts block answers the question

Dana asks for the refund amount and the approval date on turn 31. The facts block holds both, so Claude answers in one sentence.

Open the harness card. The recorded request is 460 input tokens, and the facts block sits first, under a heading. Without the trim and the facts it is 2,138 tokens, and the answer is missing.

  1. CustomerRemind me of my refund amount and the date it was approved.
    Show the result
    Remind me of my refund amount and the date it was approved.
  2. HarnessClaude is given 1147 characters (460 tokens), with case facts: order_id 1042, customer Dana Cho, amount 89.0, refund_approved_on 2026-02-14
    Show the result
    {
      "order_id": "1042",
      "customer": "Dana Cho",
      "amount": 89.0,
      "refund_approved_on": "2026-02-14"
    }
  3. ClaudeDana's refund for order 1042 is $89.00, and it was approved on February 14, 2026. I don't have any other details about…
    Show the result
    Dana's refund for order 1042 is $89.00, and it was approved on February 14, 2026. I don't have any other details about the refund's processing or when the money will reach her account.

1147 characters, 460 tokens given: the reply holds what was asked.

Two functions as written

update returns the facts after one more turn. The starting code returns them unchanged, so no fact is ever kept. trim cuts a tool result to the fields that matter. The starting code returns the whole result.

Each request carries a rolling window: a summary plus the last eight turns. A shipment result of 1,776 characters is paid for on every request while it stays in that window, and the case holds four of them.

starter/facts.py
1"""EDIT THIS FILE. It keeps the case facts and cuts tool output down.2Run `./workshop check long-conversations` until it is green, then3`./workshop watch long-conversations`.4"""56from kit.api import Json789def update(facts: Json, turn: Json) -> Json:10 """Return the case facts after one more turn."""11 # TODO(workshop): keep customer, order_id, amount and refund_approved_on,12 # the key names the order lookup returns.13 return facts141516def trim(tool: str, result: Json) -> Json:17 """Return only the fields the next step needs from a tool result."""18 # TODO(workshop): keep the fields each tool is used for, drop the rest.19 return result

What happens when the facts are not kept?

Take the question "How much was my refund?" on turn 31. The order lookup that held the amount was on turn 3. The summary says the agent approved a refund, and nothing more.

Predict: What does the agent reply?

  1. AIt gives the amount, because the summary keeps the story.
  2. BIt says it does not have the amount, because the summary dropped it.
Show the answer

B. The amount sat in a tool result on turn 3. The summary kept the story and dropped the number.

The agent has no amount to give

This is the same question with the starting code. The context is over four thousand characters, most of it full shipment results, and none of it holds the amount or the date. The result card is red.

This is a real Claude Haiku 5.5 run, recorded once and replayed here. Claude was told to say when a detail is missing, so it says so and asks Dana again.

  1. CustomerRemind me of my refund amount and the date it was approved.
    Show the result
    Remind me of my refund amount and the date it was approved.
  2. HarnessClaude is given 4426 characters (2138 tokens), with no case facts, only a summary
    Show the result
    {}
  3. ClaudeI'm sorry, but the case notes confirm that a refund was approved for order 1042 without listing the amount or the…
    Show the result
    I'm sorry, but the case notes confirm that a refund was approved for order 1042 without listing the amount or the approval date, so I can't give you those details. I can check the order again or help you start the return for the loose keys.

4426 characters, 2138 tokens given: the reply lacks it.

Facts are kept in code, output is trimmed

update copies the customer, order, amount and approval date from the order lookup into the facts. Later turns do not erase them. trim keeps only the fields each tool is used for, and the tests need the result under a quarter of its size.

Put the key facts at the start or the end of the context, under a heading. The middle of a long input is where detail is missed. None of this needs a model.

What reaches Claude on the last turn, in order.CustomerClaudeHarnessToolquestionfacts and recent turnsreply
facts.pygreen lines are what the fix adds
1"""Case facts live outside the summary, and tool output is cut to size."""23from kit.api import Json45NEEDED = {6 "lookup_order": ["order_id", "customer", "amount", "refund_approved_on"],7 "track_shipment": ["order_id", "status", "eta"],8}9FACTS = ("customer", "order_id", "amount", "refund_approved_on")101112def trim(tool: str, result: Json) -> Json:13 """Return only the fields the next step needs from a tool result."""14 return {k: result[k] for k in NEEDED.get(tool, []) if k in result}151617def update(facts: Json, turn: Json) -> Json:18 """Return the case facts after one more turn."""19 if turn["tool"] != "lookup_order":20 return facts2122 kept = trim(turn["tool"], turn["result"])2324 return {**facts, **{k: v for k, v in kept.items() if k in FACTS}}
We doChange one setting at a time and predict.

The same question now has an answer

Use the switch to run the question with the starting code, then the facts block. On the second button, the card marked "This is where the runs split" shows what Claude was given.

Try the approval date too. The starting code gives no date, and the fixed code gives it in one line.

This part is interactive in the lab: run ./workshop watch long-conversations.

Try it: facts and trimming

Change the rules and the question. Two halves are on offer: the facts block without the trim, and the trim without the facts.

The trim alone shrinks the context and still cannot answer. The facts block alone answers with the window still full. The fix needs both.

Every combination is a recorded run, so this works with no internet.

This part is interactive in the lab: run ./workshop watch long-conversations.

The same rules run in the Agent SDK

In the Claude Agent SDK, trim runs as a PostToolUse hook, code the SDK runs right after a tool returns. In this real Claude Haiku 5.5 run, the shipment result reaches Claude at 74 of 1,776 characters. With the starting code, Claude cannot give the amount or the date.

Because a hook is plain code, it is deterministic. A rule that must hold before every refund goes in a PreToolUse hook on the refund tool, for example HookMatcher(matcher=REFUND, hooks=[check]).

A session is one saved conversation, and session_extras picks how the next one starts: {"resume": id} replays the saved history, adding "fork_session": True copies it first, and {} starts fresh. Resume suits a session whose context is still true. Start fresh with a summary and the facts when it is stale, and tell a resumed agent which files changed.

app/sdk_agent.pyfile: 148 lines
···51 lines not shown52 input_data: HookInput, tool_use_id: str | None, context: HookContext53 ) -> HookJSONOutput:54 assert input_data["hook_event_name"] == "PostToolUse"55 blocks = input_data["tool_response"]56 full = json.loads(57 blocks[0]["text"] if isinstance(blocks, list) else "{}"58 )59 kept = facts.trim(TRACK, full)6061 return {62 "hookSpecificOutput": {63 "hookEventName": "PostToolUse",64 "updatedToolOutput": [65 {"type": "text", "text": json.dumps(kept)}66 ],67 }68 }6970 return {"PostToolUse": [HookMatcher(matcher=PREFIX + TRACK, hooks=[cut])]}717273def session_extras(mode: str, session_id: str | None = None) -> Json:74 """The options that continue a saved session: resume, fork or start fresh.7576 `resume` replays the saved history, `fork_session` copies it into a new···72 lines not shown
  1. Customeramount, date and parcel
  2. Tool result74 of 1776 characters
    Show the result
    {"order_id": "1042", "status": "delivered", "eta": "delivered 2026-02-06"}
  3. ClaudeYour refund for order 1042 is $89.00, and it was approved on 2026-02-14. Tracking shows the parcel was delivered on…

amount, date and parcel status all present

You doFix the starting code, then test yourself.

You do: keep the facts

Copy the starting code and open work/long-conversations/facts.py. update() keeps no case facts, and trim() passes every tool result through whole. By the last turn the amount and date are buried, and the agent asks again.

Terminal
./workshop start long-conversations
./workshop check long-conversations
./workshop watch long-conversations

The checks keep the customer, order, amount and approval date as facts across later turns, and cut a shipment result to a quarter of its size. Then the recorded long ticket must answer from the facts block.

Check your understanding

Answer each question, then read why every option is right or wrong. The wrong options are the mistakes engineers make on the job.

1. A 30-turn refund case is summarised three times. On turn 31 the customer asks for the refund amount and the agent asks them again. What is the best fix?

  1. AKeep the amount and date in a facts block that code rebuilds and puts first.
  2. BSwitch to a model with a larger context window so the whole history fits.
  3. CWrite a longer summary prompt and ask the model to keep every number.
  4. DAsk the customer to repeat the amount at the start of each session.
Show the answer

Answer: A

  • A Correct. Code keeps the facts exactly, so no summary can rewrite them.
  • B A larger window holds more text but does not stop a summary from dropping the amount.
  • C A longer prompt still asks a summary to rewrite itself, and each rewrite blurs numbers again.
  • D This moves the work to the customer and leaves the agent unchanged.

2. Each order lookup returns 40 fields and the agent uses 5. After four lookups, 85 percent of the context is tool output. What should change?

  1. ARaise the output token limit so the model can read the longer results.
  2. BTell the model in the prompt to ignore the extra fields.
  3. CSummarise the tool results once the window is nearly full.
  4. DCut each result to the five fields needed before the model reads it.
Show the answer

Answer: D

  • A The output limit controls the reply, and the results still fill the input.
  • B The ignored fields still cost tokens on every request.
  • C A late summary can blur the values the answer needs.
  • D Correct. Trimming keeps the needed fields and drops the rest, so every later turn is cheaper.

3. A 60,000 token input holds two key findings in the middle. The model misses both and finds a third one at the top. What is the best change?

  1. APut the key findings first, under a clear heading.
  2. BShorten the sentences around the findings.
  3. CLeave them in the middle, because the model reads the whole input evenly.
  4. DRepeat the question twice at the end of the prompt.
Show the answer

Answer: A

  • A Correct. The start and the end of a long input are read most reliably, and a heading names what matters.
  • B Shorter sentences do not change where the findings sit.
  • C Attention is uneven across a long input, and the middle is where detail is most easily missed.
  • D The question is not the problem. The findings are hard to find.

4. Select two effects of a history that grows to 30 turns of full tool output.

  1. AOld detail is buried, so a value from turn 3 is easy to miss.
  2. BThe model reads the old lines more carefully than the new ones.
  3. CEvery request carries the whole history, so cost rises each turn.
  4. DThe model reads the history once, so later turns cost nothing extra.
Show the answer

Answer: A, C

  • A Correct. The value is still there, but the model has more to search.
  • B Attention does not favour the old lines. Detail in the middle is easily missed.
  • C Correct. Each turn resends the history, so it is paid for again.
  • D Every request sends the history again, so the cost recurs on each turn.

5. An investigation was left for two weeks, and most of the files it read have changed since. The agent resumes the named session and quotes the old results. What is the best handling?

  1. AResume and raise the turn limit so the agent has time to notice.
  2. BStart fresh with a summary and the facts, because the old context is stale.
  3. CResume again and trust the old results, since the session remembers the work.
  4. DFork the session so the stale results are copied into a safe branch.
Show the answer

Answer: B

  • A More turns do not tell the agent that the files changed.
  • B Correct. A fresh start with the facts drops the stale output.
  • C A resumed session carries the old results, which are now wrong.
  • D A fork copies the same stale history into the branch.

6. A team wants to compare a refactor and a rewrite, both starting from the same 40-turn investigation. Which approach fits?

  1. AResume the same session twice and run both approaches in it.
  2. BStart two fresh sessions and paste a summary into each.
  3. CRun the refactor first, then the rewrite, in one session.
  4. DFork once per approach, so each branch starts from the same history.
Show the answer

Answer: D

  • A Both approaches would write into one history and mix their results.
  • B A fresh summary loses detail that the forks would keep.
  • C The rewrite would start from the refactor's results, not the original state.
  • D Correct. A fork copies the history into a new session, so each branch starts equal.

7. A named session continues after two files changed. The agent still quotes the old file contents. What do you add when you resume?

  1. AA longer system prompt that says to trust the session.
  2. BNothing, because a resumed session refreshes its own files.
  3. CA line that tells the agent which files changed, so it reads them again.
  4. DA second fork of the same session.
Show the answer

Answer: C

  • A Trusting the session is what keeps the old results in use.
  • B A session holds what was read then. It does not watch files.
  • C Correct. The agent cannot see the change unless it is told, and it can read the two files again.
  • D A fork copies the same old results.

8. Select two valid uses of resuming a named session.

  1. AContinue work after a large refactor changed most of the files.
  2. BContinue a task in the same session, where the context is current.
  3. CStart a follow-up on the same task the next morning, when no files changed.
  4. DBranch into two experiments from one saved point.
Show the answer

Answer: B, C

  • A After a large change the old results are stale, and a fresh start with a summary is safer.
  • B Correct. The context is still true, so resuming saves the work.
  • C Correct. Nothing changed, so the history is still accurate.
  • D Branching is a fork, which copies the history into a new session.

9. A shipment tool returns dates in three formats. Downstream code parses 1 in 6 of them wrongly. What is the most reliable fix?

  1. ANormalise the dates in a PostToolUse hook, before the model reads the result.
  2. BTell the customer which format to expect.
  3. CRetry the tool until it returns a format the parser knows.
  4. DAsk the model in the prompt to rewrite each date before it uses it.
Show the answer

Answer: A

  • A Correct. A hook runs every time and reshapes the result before the model sees it.
  • B The customer did not choose the format.
  • C A retry returns the same mixed formats.
  • D A prompt is probable, not certain, and 1 in 6 misses would persist.

10. A business rule must hold before any refund, with no exception. Which control fits?

  1. AA longer tool description that explains the rule.
  2. BA hook that checks the rule in code before the refund tool runs.
  3. CA sentence in the system prompt that states the rule.
  4. DA reviewer who reads the transcripts each week.
Show the answer

Answer: B

  • A A description guides the choice of tool and does not block a call.
  • B Correct. A hook is deterministic, so the rule holds on every call.
  • C A prompt rule is followed most of the time, and this rule needs every time.
  • D A weekly review finds a breach after the refund is paid.

11. A prompt asks the model to trim its own tool output. In a test of 12 replies, 1 skips the trim. What is the best change?

  1. AReword the prompt to say trim in capital letters.
  2. BMove the trim into a PostToolUse hook that runs on each result.
  3. CAdd two examples of a trimmed result to the prompt.
  4. DLower the temperature and run the test again.
Show the answer

Answer: B

  • A Emphasis improves the odds but leaves a chance of a miss.
  • B Correct. A hook runs in code, so the trim does not depend on the model.
  • C Examples help, and the model can still skip the step.
  • D A lower temperature reduces variety and does not make a step certain.

12. Select two things a PostToolUse hook can do.

  1. AChange what the model decided before it called the tool.
  2. BLog each result for later review.
  3. CReshape a tool result before the model reads it.
  4. DUndo a tool call that already finished.
Show the answer

Answer: B, C

  • A The call was already made. A PreToolUse hook acts before it.
  • B Correct. The hook sees the result, so it can record it.
  • C Correct. The hook can replace the output the model reads.
  • D The tool already ran. A hook cannot take that back.

Play: predict the output

This version keeps facts, but it takes them from every tool.

python
def update(facts: Json, turn: Json) -> Json:
    kept = trim(turn["tool"], turn["result"])
    return {**facts, **kept}

Predict: Turn 3 looks up order 1042. Turn 9 tracks a shipment for order 1077. What does facts["order_id"] hold after turn 9?

  1. A1042, the order the case is about.
  2. B1077, from the shipment lookup.
Show the answer

B. Every result merges into the facts, so a later lookup overwrites a case fact. Take each fact from the tool that owns it, and keep only the keys you named.

References

Conclusions

  • Case facts are kept in code, outside the summary, and placed first.
  • Each tool result is cut to the fields the next step needs.
  • Resume, fork or start fresh depends on whether the history is still worth its size.

You can now keep the facts of a long case exact and keep the window small.

Facts block

Values kept in code and placed first, so a summary cannot drop them

Summary

A rewrite of the story that loses specific values

Trim

Cutting a tool result to the fields the next step needs

Fork

A new session that starts from a copy of an old one