DEV Community

Gnana Joshna Gunda
Gnana Joshna Gunda

Posted on

Hindsight Reminded Me What I Promised a Customer.

Hindsight Reminded Me What I Promised a Customer

The most damaging meeting mistake is often a small one: I forget what I said I would send, or I carry one customer’s concern into another customer’s conversation. I built Meeting Prep Agent around a simple rule: a useful briefing must come from dated notes I can inspect, not from a model’s confidence.

The gap between two meetings

Calendars remember that a meeting happened. Chat histories remember what was typed into one session. Neither reliably brings the right promise back when I sit down with the same customer again. A language model cannot know that I promised a rollout plan unless I give it that history.

Meeting Prep Agent gives that history a small, explicit workflow. I can save a dated note, prepare for a meeting with a natural-language question, research a company, or review human ratings of earlier briefings. The persistent record lives in Hindsight. Streamlit handles the forms and conversation; Hindsight handles memory retention and retrieval; the app turns returned facts into a compact, reviewable briefing.

Meeting Prep Agent screenshot

The screenshot shows the uploaded Meeting Prep Agent interface.

Architecture diagram showing the user, Streamlit app, Hindsight memory bank, research, and feedback loop

The app retains dated, contact-scoped notes, retrieves relevant evidence from Hindsight, and returns a briefing for the user to review.

The important boundary is between the note and the interpretation. I write down what was said; Hindsight stores it with a date and contact tag; Reflect uses matching memories to prepare an answer. The app does not send a follow-up, update a CRM, or infer that I completed a task because time passed.

I also learned that motion is not automatically polish. On slower machines, a continuously drifting background and entrance animation on every Streamlit rerun made the workflow feel sluggish. I removed those effects, kept the pale yellow and olive palette, and left only small hover transitions. Moving between sections should feel immediate; animation should not compete with the work.

Save a dated event, not a vague profile

I keep meeting capture deliberately plain. The user enters a person or organization, a meeting date, and free-text notes. The app builds a record that includes the contact name, a normalized matching key, and the date before retaining it. That gives Hindsight both the original statement and useful anchors for later retrieval.

content = (
    "MEETING NOTES\n"
    f"Contact: {save_contact.strip()}\n"
    f"Contact matching key: {' '.join(save_contact.casefold().split())}\n"
    f"Meeting date: {meeting_date.isoformat()}\n"
    "Notes as entered by the user:\n"
    f"{notes.strip()}"
)
hindsight_request(
    "retain", base_url, api_key,
    bank_id=bank_id.strip(),
    content=content,
    tags=[contact_tag(save_contact)],
)
Enter fullscreen mode Exit fullscreen mode

The note is not silently rewritten into a different version of events. That choice matters when the important difference is a commitment’s status. “I will send the rollout plan by Friday” is not the same fact as “They confirmed receiving the plan.” The first records an open commitment; a later note can provide evidence that it was completed.

I use Hindsight’s retain operation for notes, written feedback, and explicitly saved company research. Each kind of record says what it is and when it was captured. This lets later retrieval distinguish a customer statement from a public web result or a user’s correction about an earlier briefing.

Scope retrieval before asking the model to reason

A shared memory bank can contain many people and companies. Including a name in a prompt is useful, but it is a weak boundary by itself: the model still sees whatever the search returns. I normalize each contact name and derive a stable tag from it, then use strict tag matching when asking Hindsight for a briefing.

def contact_tag(contact: str) -> str:
    normalized = " ".join(contact.casefold().split())
    digest = hashlib.sha256(normalized.encode("utf-8")).hexdigest()[:24]
    return f"meeting-contact-{digest}"

answer = hindsight_request(
    "reflect", base_url, api_key,
    bank_id=bank_id.strip(),
    query=query,
    tags=[contact_tag(prep_contact)],
    tags_match="all_strict",
    include_facts=True,
    max_tokens=512,
    budget="low",
)
Enter fullscreen mode Exit fullscreen mode

The tag makes “Northstar Foods” resolve consistently if someone changes capitalization or adds an extra space. all_strict excludes records that do not carry the contact tag, including older notes saved before tagging was introduced. For those records, I ask the user to save them again rather than weakening the filter and risking a briefing assembled from multiple customers. This is retrieval scoping, not authorization: a real multi-user deployment still needs server-side access control.

The Reflect prompt asks for dated facts and suggestions separately. It tells the model to mark a promise complete only when a later dated note confirms it, to call an unconfirmed status “not recorded,” and not to treat silence as completion. I request source facts and display them with the answer so I can check the evidence instead of treating generated prose as a source of truth.

There is also a fallback path. If Reflect does not include readable source memories, the app calls Hindsight Recall with the same strict contact tag and requests source chunks and facts. If neither operation returns evidence, the app withholds the briefing and explains that no matching notes were found. Hindsight’s open-source memory framework and API documentation describe the retain, reflect, and recall operations behind this flow.

A dated briefing for Flipkart with separate remembered facts and next-step suggestions

The briefing puts dates before advice. The source notes remain available to inspect, and the suggestions are framed as actions to take—not as events that already happened.

Keep a slow memory call from freezing the page

One integration detail affected the experience as much as retrieval quality. Streamlit reruns the app when a widget changes, and a synchronous network call in that path can make the entire page appear stuck while Hindsight responds. I run each client’s async operation on its own event loop and close the client on that same loop. Meeting preparation runs in a worker thread; a small Streamlit fragment polls for completion and updates the waiting message while the rest of the page remains usable.

@st.fragment(run_every="1s")
def render_pending_briefing():
    pending = st.session_state.get("pending_meeting_briefing")
    if not pending:
        return
    future = pending["future"]
    if not future.done():
        with st.chat_message("assistant", avatar="🧠"):
            st.markdown("I’m checking the saved meeting notes now…")
            st.caption("You can keep using the page while Hindsight prepares the briefing.")
        return
    # Collect the result, save it to the contact's chat, then rerun the page.
Enter fullscreen mode Exit fullscreen mode

This does not make a remote model call instantaneous. It makes waiting visible and keeps a slow call from owning the page’s main execution path. The app also uses a fresh Hindsight client for each operation, avoiding reuse of an async transport after Streamlit or Python has closed its event loop.

For a concrete example, consider two meetings with Northstar Foods. In the first note, I record that setup could interrupt the customer’s busy season and that I promised to send a rollout plan by October 2. If I ask whether the plan was completed, the available evidence supports “status not recorded.” After a second note says the customer received the plan and adds a new promise to send a deployment checklist, the next briefing has grounds to mark the plan complete while keeping the checklist open. The dates and source notes let me audit that transition.

That example is intentionally mundane. The useful behavior is not that the model produces a polished paragraph. It is that a new event changes what the system can responsibly say about an older commitment.

Research and feedback need separate labels

Before a meeting, I can search for current hiring posts and company facts. The app displays result titles, snippets, and source links, and lets me choose whether to retain the results as dated public research. Search output is background, not a customer statement. A snippet can be stale or incomplete; the UI tells me to open the source before relying on it.

After a briefing, I can record whether it was useful, what happened in the meeting, and corrections to the answer. The written review goes to Hindsight as future guidance. Numeric ratings, dates, and a hashed contact tag are stored locally for the chart. I can view them as a line or bars, alongside a rolling average of the last three ratings.

Human-rated meeting preparation performance chart with line and bar options

The graph summarizes user ratings. It is not a model accuracy score, and one or two reviews do not establish a reliable trend.

That distinction keeps the feedback loop honest. A user rating tells me whether a briefing helped that user. It does not prove that every fact was correct. Corrections can guide later briefings, while the original meeting notes remain the evidence for what was said.

What I would carry into another agent

  1. Attach identity and time when writing. It is much harder to recover the correct person and event date from an unstructured bank later.
  2. Treat “not recorded” as a valid answer. If no later note confirms a promise, the system should expose the gap rather than fill it with a likely story.
  3. Show the evidence beside the summary. Provenance gives the user a practical way to challenge a retrieval or interpretation error.
  4. Keep feedback separate from facts. A correction can improve future emphasis without becoming proof of what happened in a meeting.
  5. Make the interface responsive around slow services. A spinner is not a substitute for letting the rest of the application keep working.

A reminder, not a source of truth

Meeting Prep Agent is useful when it helps me walk into the next conversation remembering the right promise, concern, and open question. Hindsight supplies continuity across meetings; the language model turns retrieved history into a plan for the next conversation. I keep the final check with the person who attended: inspect the dated notes, verify the source, and correct the record when reality changes.

That is the part I trust most. The agent can remind me what I wrote down. It should never pretend to remember what I did not.

Top comments (0)