Carlos Sanoja
All work

Repaso: a learning agent whose memory a parent can inspect

August 2026 to September 2026AWS hackathon, Good Neighbor Agents track

A child who asks an agent for help should not have to start from zero each time, and the adult supporting them should be able to see what was tried. Repaso connects a family's Telegram conversation to a persistent learning record on Strands Agents and Amazon Bedrock AgentCore Runtime, and shows that record in a family dashboard. On 14 September 2026 a real Telegram exchange against the deployed runtime (version 13) retrieved a previously used explanation, produced a different one and saved it, without counting the help request as an answer. That is the extent of the live evidence: there was no family pilot, no teacher evaluation, no measured learning gain, and one day of real activity. Two upstream bug-fix pull requests to Strands came out of the work and are still open.

1Problem

Chat tutors are usually stateless in the way that matters. A learner asks for another example of equivalent fractions, gets one, and next week gets the same cake explanation again because nothing recorded that it was already tried. The adult who sits between the learner and the school sees none of this: not which explanation was used, not what an answer actually demonstrated, not what happens next.

The proposed audience is a community learning facilitator supporting families between meetings, starting with fourth-grade mathematics. That audience is a proposal in the README, not something I tested with anyone. The design question was narrow: what is the smallest durable record that lets a model avoid repeating itself and lets an adult check the model's claims?

2Approach

The agent keeps its own learning memory in DynamoDB instead of relying on a managed memory service; the README says plainly that the project does not provision the separate AgentCore Memory service. For each learner it stores the explanation approaches already used, evaluated answers, the content of the questions behind those answers, difficulty coverage, a mastery estimate, stored spaced-review dates and the decisions an adult recorded.

Deterministic code owns everything with consequences: family ownership of data, assessments, spacing, mastery updates, time limits and decisions with external effects. Models do the language work. A small model reads what the family's message is (an answer, a request for an explanation, something else) and returns a typed intent. Only a message read as an answer, while a practice capsule is open, can reach the grader. A larger model writes the explanation, and it is handed the approaches already used so that it can pick a different one. Asking for help is never graded as a wrong answer.

Strands supplies the typed structured-output boundary and four graphs: ingestion, practice, response (grade, apply, adapt, escalate) and quality. Durable operation records and leases stop tested duplicate events from applying a learning effect twice. Delivery is at least once, so Telegram can duplicate a message if it accepts a send and the acknowledgement is lost.

The dashboard is read-only and is the part meant for the adult. It descends from family to learner to topic to recorded day to a learning episode, which opens three synchronized columns: the conversation, the agent and its memory, and the learning evidence. A button re-reads saved memory from storage. Where the evidence is weak the interface says so; the live data showed "three answers, one distinct question" and the dashboard displays exactly that rather than a mastery claim.

3Architecture

Telegram messages flow through a queue to AgentCore, which reads and writes durable memory; a read-only dashboard observes the same state Telegramfamily chat API, queue, workerEventBridge and SQS AgentCore RuntimeStrands graphs, Bedrock Learning memoryDynamoDB Dashboardread-only recoverable outbox returns the reply
Request path as described in the README. The dashboard reads stored state and correlated CloudWatch events; it cannot send Telegram messages or enqueue work.

Scheduler events enter the same work pipeline as Telegram updates, so a scheduled practice capsule and a conversational turn share one path with the same ownership checks. Infrastructure is defined in CDK, and a separate hosted demo runs on Lambda with synthetic learners and scripted model replies. I have left its address out of this page because it is a rehearsal, not a deployment.

4Results

MeasurementResultMeasured on
Second help request: prior approach retrieved, different approach saved1 of 1 on version 13Live Telegram and AWS, 14 Sep 2026, runtime version 13, one operator (me)
Approach labels saved2Same exchange: "same-size piece cake model" (first request, no prior approach), then "paper strip folding"
Generation call time, first and second explanation3.88 s, 4.92 sSame exchange, Sonnet call only, not total Telegram latency
Assessed answers after both help requests3 (unchanged)Same exchange; help was not graded
Answer grader against my labels18 of 18 graded decisions agreeDevelopment half, 30 synthetic cases, 5 distinct questions, 18 distinct answers; author labels only
False automatic-correct0 of 8, upper bound 32.4%Same set, Wilson 95% interval, threshold 0.85
Message-reader, answer versus not an answer42/44 (Haiku 4.5)22 message shapes, 2 samples each, live Bedrock, 13 Sep 2026
One synthetic student-day$0.1629One run, 29 live calls, 12 Sep 2026; excludes infrastructure and human time
Full test suite at deployment of version 132123 passed, 66 skippedLocal run, 86.09 s

Measurement: the first four rows come from a single live session driven by the developer, not a family. The grader rows use labels I wrote myself; no teacher has labelled a case and the held-out half of the sixty answers was never opened. Cost is arithmetic on one measured journey, of which $0.1516 was building the question bank from two photographed pages and $0.0111 was the day's practice. Nothing was billed over a month.

Two further upstream results: pull request 4207 (read the model id through the public model configuration accessor so custom providers keep their id in traces) and pull request 4208 (declare the model-state and cache-boundary arguments on the streaming interface that the event loop already passes). Both carry regression tests, both were opened on 6 September, and both were still open and unmerged when I checked on 19 October 2026. I found the problems while wrapping models for deterministic record and replay.

5What did not work

The first live attempts proved little

The first request at 21:58 UTC reached the runtime, was classified and delivered, but there was no open practice, so the bot replied that the capsule would arrive later and nothing was saved. When I then opened a study session and answered its three questions, all three questions were identical: three different identifiers with the same text and options. The 3 of 3 correct result was real and meant nothing about mastery. The bank selection had to be changed to drop identical content, and the interface now reports distinct questions next to answers.

The safety filter blocked my own prompt

On version 12, a help request ended in a guardrail intervention (prompt attack, medium confidence) before any explanation was produced. The old template put application instructions inside the user message. Moving instructions to the system message and passing lesson data as a record fixed it, and a probe containing "ignore instructions" in the data was still blocked. The failed request remained visible and no longer counted as an explanation remembered. Even after the fix, one generated explanation gave away the equivalence early, so I do not claim the answer stays hidden.

The cheapest reader invented answers

Nova Micro read the answer-versus-not split correctly 39 times in 44, but in 4 of 44 calls it filled the answer field with "6/8", an option the family never wrote, twice on a lone thumbs-up. One of those would have been graded correct. I routed the reader to a structured-output role instead (Haiku 4.5 deployed; 42 of 44 on the split, and neither Haiku nor Nova Lite invented an answer).

An answerability check that removed good items

A forced-choice probe that could veto generated questions rejected all 36 planted-defect decisions but also kept only 7 of 54 unplanted decisions (13.0%), against 20 of 54 (37.0%) with the critic alone. Both labels there come from construction, since no teacher reviewed the items. The probe now only records its signal and cannot discard anything.

The grader decided ambiguous answers alone

At the 0.85 threshold, four ambiguous answers ("Creo que sí porque las dos se parecen", one text against four questions) were decided automatically at exactly 0.85 confidence, where my label said a person should look. I froze the threshold anyway: the sweep showed no measurable gain from moving it, and I recorded that 0.85 sits on a mass point. That is a known weakness, not a resolution.

6Lessons