Everything from zero to measured numbers on your own pipeline. You will need an API key: email us for one.
Your agents constantly look things up: "what's our refund policy?", "what did the last agent find?". Every lookup is a pause in your pipeline. forefetch is a memory service that learns your pipeline's rhythm and has the answer ready before the agent asks. You wire it in with a few calls, and it shows you, in numbers, on your own pipeline, how much waiting it removed.
Why bother: what we've measured so far
- In a 4-agent benchmark pipeline, the content an agent asked for was already waiting 61% of the time (random guessing: 4%): cutting ~60% of retrieval waiting.
- Over a real network with heavy payloads, only 4% of content had to be shipped at ask-time; 96% had already traveled earlier, while agents were busy thinking.
- On a months-old memory full of outdated facts, forefetch serves the current fact 75% of the time vs 33% for a memory that just piles everything up.
Plug it in
You get two things from us: the address https://api.forefetch.com and your own API key.
The key is your private space on the server: your own memory engine, your own database file;
no other tenant's data can touch yours.
pip install forefetch-client # one dependency (httpx)
If your team runs on Agno: one line
from forefetch_client.agno import remember_team
team = Team(members=[triage, resolver], ...) # your team, exactly as it is today
team = remember_team(team, "https://api.forefetch.com", api_key="yourkey",
knowledge={"Resolver": policy_docs}) # <- the whole integration
That's it. Every member gets its own isolated memory stream; relevant knowledge is retrieved
into each member's context before it runs; every answer feeds the prediction engine (never
quoted back as a fact); upstream members' conclusions arrive downstream as labeled hints;
sessions close themselves when a team run ends. Your prompts, models, and delegation logic
are untouched. The scorecard is one call away: team.forefetch["resolver"].report().
Any other framework: a ten-line wrapper
Below is the same integration written out by hand: LangGraph, CrewAI, or plain functions, the pattern is identical. A complete support pipeline: triage reads the ticket, resolver fixes it. Everything forefetch-related is marked: the agents are plain Agno.
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from forefetch_client import MemoryClient
BASE, KEY = "https://api.forefetch.com", "yourkey"
# ---- your agents, exactly as you'd build them without forefetch ------------------
triage = Agent(name="triage", model=OpenAIChat(id="gpt-4o-mini"),
instructions=["Read the ticket. State the problem type and root cause."])
resolver = Agent(name="resolver", model=OpenAIChat(id="gpt-4o-mini"),
instructions=["Resolve the ticket. Use the CONTEXT lines in the prompt."])
# ---- forefetch setup: one memory stream per agent --------------------------------
triage_mem = MemoryClient(BASE, api_key=KEY, stream="triage")
resolver_mem = MemoryClient(BASE, api_key=KEY, stream="resolver")
# load each agent's knowledge ONCE: docs, policies, past resolutions
resolver_mem.remember([
"refund policy: duplicate charges are refunded in full within 5 business days",
"ticket #1042 resolved: customer double-charged on invoice, refunded the duplicate",
])
# ---- the whole integration is this wrapper ---------------------------------------
def run_agent(agent, memory, task: str) -> str:
"""Memory in before the agent runs; memory out after it acts."""
ctx = memory.retrieve(task, k=4, full_suggestions=True)
# ctx["items"] -> this agent's own relevant rows (policy, past ticket...)
# ctx["wire_frac"] -> 1.0 means it was ALL already here before we asked
hints = memory.suggest(k=3)
# context the agent didn't ask for, each labeled with why it's offered, e.g.
# {"kind": "handoff", "from_stream": "triage", "text": "triage concluded: ..."}
context = [i["text"] for i in ctx["items"]] + \
[f"[{h['kind']} from {h.get('from_stream', 'memory')}] {h['text']}"
for h in hints]
prompt = task + "\n\nCONTEXT:\n" + "\n".join(f"- {c}" for c in context)
answer = agent.run(prompt, stream=False).content # your framework, unchanged
memory.observe(f"{memory.stream} concluded: {answer[:400]}", derived=True)
# ^ the important one: this is how forefetch learns your rhythm and gets the
# NEXT thing ready: it returns instantly, the work happens in the background.
# derived=True marks it as the agent's OWN answer: prediction fuel, never
# quoted back as a fact (facts you observe yourself leave it False)
return answer
# ---- run a ticket through the pipeline -------------------------------------------
ticket = "I was charged twice for invoice INV-2291."
finding = run_agent(triage, triage_mem, f"triage this ticket: {ticket}")
triage_mem.flush() # triage's observe ships in the background; flush before the
# next agent runs so the server has seen triage's conclusion
fix = run_agent(resolver, resolver_mem, f"resolve this ticket: {ticket}")
# by this point the resolver's suggest() already carried triage's finding, labeled
# "handoff from triage": forefetch noticed that resolver always runs after triage
# and primed it while triage was still talking to the LLM
triage_mem.end_session() # ticket done: close the episode and pre-warm
resolver_mem.end_session() # each agent's NEXT session with its usual first needs
That's the entire integration: your prompts, models, and pipeline logic stay untouched. The same wrapper connects forefetch to any framework (LangGraph, CrewAI, plain functions): retrieve + suggest before the agent runs, observe after it acts, end_session when the task truly ends.
Two rules of thumb:
- Observe real events: conclusions, decisions, tool results. A pipeline that only retrieves gives forefetch nothing to learn from.
end_session()means the task is really done: next-session predictions are built from what finished sessions did first.
Read your scorecard
resolver_mem.report()
{
"anticipation": true,
"streams": [
{"stream": "resolver", "rows": 214, "retrievals": 96, "scored": 92,
"mean_hit_frac": 0.71, "fully_ready": 61}
],
"wire": {"retrievals": 96, "full_serves": 58, "pushed_rows": 388, "wire_serve_rate": 0.60},
"handoffs": {"triage->resolver": {"count": 31, "p": 0.94}}
}
Three numbers matter:
mean_hit_frac(0.71): when the resolver asked, 71% of the answer was already ready. Scored by exact row identity, so a "hit" can never be a lucky similarity guess.wire_serve_rate(0.60): 60% of retrieves needed nothing shipped at all; the content had already traveled while agents were thinking.handoffs: the pipeline shape forefetch figured out by itself, from behavior alone. If this looks like your architecture diagram, the cross-agent prediction is working.
Expect low numbers for the first few tickets: forefetch needs ~3 repetitions to trust a handoff pattern and a few finished sessions to predict session starts. Then they climb.
Prove it to yourself (please do this)
Your key also works on a second address running the same server with all prediction turned off: a genuinely ordinary, reactive memory:
https://api.forefetch.com # prediction on
https://reactive.forefetch.com # same code, prediction off
Run the same tickets against both. On the reactive one, mean_hit_frac stays at 0 and every
retrieve ships everything. The difference between the two report()s is what forefetch
bought your pipeline: measured by you, not claimed by us.
What we'd love back
- The two
report()outputs (prediction on and off), plus a rough sketch of your pipeline: how many agents, typical session length. - One sentence on whether the labeled hints helped your agents: or ever got in the way.
- Whatever annoyed you. The missing API, the confusing step, the number you wanted to see.
If forefetch buys your pipeline nothing, that finding is exactly as valuable to us as a win : this project has cut its own features over honest measurements before.
Honest limits (design-partner build, not an SLA product)
- One server process per tenant: right for team-scale pilots, not thousands of concurrent users.
- After a server restart, learned rhythms re-learn within a few sessions (your stored memories are never lost).
- English-optimized embeddings.
- Rhythm learning assumes tasks flow through the pipeline one at a time (the normal agent setup today). Running many tasks concurrently through one tenant blurs what it learns: correct patterns still dominate at moderate concurrency in our tests, and it degrades to ordinary reactive behavior rather than misbehaving. Per-task tracking is on the roadmap.
- Known blind spot: an agent that runs only rarely AND needs case-specific context on its first question (say, a fraud reviewer asking about one particular claimant) still starts cold: none of the prediction signals cover that case yet.
Contact
Yashvardhan Goel: [email protected]