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
Browse 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.