Summary of Today’s Gen AI Agents Session: Five Apples and a Calculator – Tools and Memory in the OpenAI Agents SDK (7 Nov 2026)

Thursday we set up the OpenAI project and its helpers. Today we gave the agent the two things that make it useful: tools to act with, and memory to remember with.

1. Check the Pipe First

Before adding anything, confirm the key and the connection work with the smallest possible agent and a question with a known answer, such as the capital of France.

One change at a time. If the basic agent fails, it’s your key or your environment. If it works and the next step fails, you know exactly where to look.

2. The Exercise

I have 5 apples and buy 2 more. How many do I have?

The agent must recognise this needs addition, call the add tool, and answer 7.

We’ve built a calculator before, as an MCP server. This time the tools live directly inside the agent.

3. Custom Tools: calci_tools.py

from agents import function_tool

@function_tool
def add(a: float, b: float) -> float:
    """Add two numbers.

    Args:
        a: The first number.
        b: The second number.
    """
    print(f"[tool] add({a}, {b})")
    return a + b

@function_tool
def divide(a: float, b: float) -> float | str:
    """Divide a by b.

    Args:
        a: The number to divide.
        b: The number to divide by.
    """
    print(f"[tool] divide({a}, {b})")
    if b == 0:
        return "Cannot divide by zero. Ask the user for a different divisor."
    return a / b

# subtract, multiply and modulus follow the same pattern

What to notice:

  • @function_tool turns an ordinary function into a tool the agent can call.
  • The docstring is the contract. The SDK reads Google-style docstrings, including the Args: section, to tell the model what each parameter means. A vague docstring gets a confused model.
  • The print statements show you exactly when a tool is called and with what values. This is the fastest way to confirm the model really used the tool rather than guessing.
  • The zero check in divide returns a plain message instead of crashing. The agent reads that message and can recover, which a stack trace wouldn’t allow.

All five tools: add, subtract, multiply, divide and modulus.

4. The Calculator Agent

from agents import Agent, Runner
from calci_tools import add, subtract, multiply, divide, modulus

agent = Agent(
    name="Smart Calculator",
    instructions=(
        "You understand maths questions written in plain language. "
        "Always use the calculator tools for every calculation. "
        "Never work out a number yourself. "
        "Explain the final answer simply."
    ),
    tools=[add, subtract, multiply, divide, modulus],
    model=MODEL_NAME,
)

result = Runner.run_sync(agent, "I have 5 apples and buy 2 more. How many do I have?")
print(result.final_output)

Why insist on the tools? An LLM predicts tokens; it doesn’t calculate. It will often get simple sums right and then get a larger one confidently wrong. Forcing every calculation through a tool makes the arithmetic correct and makes the agent’s behaviour visible in your logs.

5. Short-Term Memory: SQLiteSession

from agents import SQLiteSession

session = SQLiteSession("session_101", "calculator_memory.db")

Runner.run_sync(agent, "I have 5 apples.", session=session)
result = Runner.run_sync(agent, "I bought 2 more. How many now?", session=session)
print(result.final_output)   # 7: it remembered the 5
  • SQLiteSession is the SDK’s built-in session, an implementation of its session base class (SessionABC). It stores the conversation in a local SQLite file.
  • Same session ID → the agent remembers, even across separate runs of the program, because the history is on disk.
  • New session ID → a clean slate.
  • The session goes to the Runner, not the Agent. The agent is the configuration; the session is the conversation.

Compare with Claude: there, the SDK gave you a session ID and you had to map it to the user yourself. Here, you choose the ID, so a customer ID or a student name can be the session ID. Same concept, less plumbing.

6. Same Concepts, Every Framework

The names change; the ideas don’t.

ConceptOpenAI Agents SDKGoogle Gemini ADK
The agentAgentLlmAgent
Runs itRunnerRunner
Conversation memoryA session such as SQLiteSession, passed to the runnerA session service such as InMemorySessionService
Custom tools@function_toolPlain Python functions

LangChain and CrewAI follow the same patterns again. Once you can name the concept, finding it in a new framework is a quick documentation search. That’s the memory-map approach in practice.

7. What’s Next

  1. A downloads agent, combining built-in and custom tools.
  2. The tutor agent in OpenAI, with the same three tones as the Claude version, detailed, revision and beginner, plus memory.

✅ Action Items

  1. Build calci_tools.py with all five tools, including the divide-by-zero guard.
  2. Run the apple question and use your print output to confirm add was actually called.
  3. Add a SQLiteSession, ask a question that depends on the previous one, then change the session ID and watch the memory disappear.
  4. Research OpenAI’s built-in tools. The SDK calls them hosted tools. Pick one and build a small agent around it.
  5. Try the tutor agent in the OpenAI SDK with the three tones and a session.

⏭️ Next up: the downloads agent, with built-in and custom tools together.

By continuous learner

enthusiastic technology learner

Leave a comment