Keep per-call state server-side, keyed by call id
Store full per-call state on your server, keyed by call ID, and expose only the fields the voice AI agent needs.
The claim
global_data travels with every tool call and the model can see it. That makes it the right place for a short, AI-facing summary and the wrong place for a growing record. You keep the record in a store keyed by call_id, which the platform posts with every tool call. You write only a count and the distinct areas to global_data. A second tool reads the whole record back from the store when the mechanic asks for it.
How it works
def record_finding(self, args, raw_data):
call_id = raw_data.get("call_id")
findings = STORE.setdefault(call_id, [])
findings.append({"area": area, "detail": detail}) # the full text
seen = list(dict.fromkeys(f["area"] for f in findings)) # distinct areas
r = FunctionResult(f"Recorded {area}. {len(findings)} findings so far.")
r.add_action("set_global_data", { # the summary
"findings": len(findings), "areas": ", ".join(seen)})
return rAfter the third finding, what the platform receives:
{"response": "Recorded wheels. 3 findings so far.",
"action": [{"set_global_data": {"findings": 3, "areas": "brakes, gears, wheels"}}]}The three findings in the store run to several hundred bytes; the whole action stays under 120. Because areas holds distinct values, twenty more findings on one area leave it the same size. read_back_report reads STORE[call_id], not global_data. global_data never carries the full text between turns; the model receives it in the read-back response.
call_id is the key because it is the one identifier the platform attaches to every tool call for the life of the call. Two distinct call ids get two records.
Limitations
The store is a dictionary in the process. A restart loses it, and two replicas would not share it; your version is a table keyed by call_id.
Nothing here removes a call’s record when the call ends. Where you do that is your design choice; the store only grows in this recipe.
What to change first
Put detail into the set_global_data action and run the verifier. It fails on the first finding, at the size check. That is the point: the record was about to ride along with every tool call for the rest of the conversation.
Where this sits
Before this
Seen in a build
One of 8 recipes composed by AI phone ordering: a voice agent working with a live backend in real time.
Seen in a build
One of 10 recipes composed by Embed a state-aware voice agent in your web page.