← All tutorials

Track 6 · Foundation

deterministic

The flag that signals whether a primitive is a pure function. Put a pure primitive next to one that reads the clock to see the difference.

Beginner5 min
Video coming soon
Project codeBrowse this tutorial's folder in tutorials-pygithub.com/OpenSymbolicAI/tutorials-py/tree/main/06-deterministic

Before you start

Every primitive also carries a deterministic flag. It signals one thing: is this primitive a pure function (same inputs always giving the same output)? This track puts a pure primitive next to one that reads the clock.

1. Two primitives, one flag apart

The agent finds the next Monday. One primitive computes it from a given date; the other reads today's date off the system clock.

python
# dates.py
from datetime import date, timedelta

from opensymbolicai.blueprints import PlanExecute
from opensymbolicai.core import primitive


class Calendar(PlanExecute):
    @primitive(read_only=True, deterministic=False)  # depends on the clock
    def today(self) -> date:
        """Return today's date."""
        return date.today()

    @primitive(read_only=True)  # deterministic defaults to True: a pure function
    def next_monday(self, d: date) -> date:
        """Return the date of the first Monday after `d`."""
        days_ahead = (0 - d.weekday()) % 7
        if days_ahead == 0:
            days_ahead = 7
        return d + timedelta(days=days_ahead)

next_monday is pure: hand it 2026-06-02 and it always returns 2026-06-08, today or next year. today is not pure: its result depends on when it runs. That is what deterministic=False declares.

Both are also read_only=True. The two flags are independent.

2. Run it

python
# main.py
from dates import Calendar
from opensymbolicai.llm import LLMConfig

llm = LLMConfig(provider="ollama", model="qwen2.5-coder:7b")
agent = Calendar(llm=llm)

result = agent.run("calculate the date of the next Monday from the current date")
print(result.result)  # e.g. 2026-06-08
bash
uv run main.py

Run it next week and the answer changes, because today reads a new date. next_monday did not change at all. That split is exactly what the deterministic flag records.

Why the flag matters, and what it does not do

On its own, deterministic changes nothing about this run. Both primitives execute for real, and the flag is metadata.

The flag matters in tooling that leans on purity. A deterministic primitive's result can be cached: compute next_monday(2026-06-02) once and reuse 2026-06-08 on every later call with that date. today cannot be cached that way, so the flag also keeps it out of such a cache.