Skip to main content

Determine

Determine makes AI inference feel like a normal part of Python.

The main API has only two operations:

determine.answer(...)
determine.choose(...)

Install

pip install determine

Quick start

import determine

determine.configure(
    "http://127.0.0.1:8080"
)

preference = "Chinese"
budget = "cheap"

answer = determine.answer(
    "What should I eat?"
)

print(answer)

Determine can automatically see relevant runtime variables and surrounding source code.

answer()

Use answer() when the result can be open-ended.

response = determine.answer(
    "Explain what is happening."
)

choose()

Use choose() when the result must be one of several possibilities.

health = 12
ammo = 0
enemy_distance = 3

action = determine.choose(
    "What should the player do?",
    [
        "fight",
        "run",
        "hide"
    ]
)

print(action)

Explicit context

Automatic context is convenient for small programs:

determine.answer(
    "What should happen?"
)

For larger programs, you can specify exactly what Determine should see.

By variable name:

health = 12
ammo = 0
score = 400

action = determine.choose(
    "What should the player do?",
    [
        "fight",
        "run",
        "hide"
    ],
    context=[
        "health",
        "ammo"
    ]
)

Only health and ammo are sent as runtime context.

You can also provide an explicit dictionary:

answer = determine.answer(
    "What should the player do?",
    context={
        "health": health,
        "ammo": ammo
    }
)

Or disable automatic context entirely:

answer = determine.answer(
    "Say hello.",
    context=False
)

This makes it possible to start with Determine's automatic context while still having precise control when an application becomes larger.

Typed structured answers

answer() can return multiple typed values at once by using schema=.

result = determine.answer(
    "Choose an action and estimate your confidence.",
    schema={
        "action": str,
        "confidence": float
    }
)

print(result)

The result is a normal Python dictionary:

{
    "action": "run",
    "confidence": 0.93
}

Supported types include:

str
int
float
bool
list
dict

Nested structures also work:

result = determine.answer(
    "Evaluate the current situation.",
    schema={
        "action": str,
        "confidence": float,
        "details": {
            "danger": int,
            "safe": bool
        }
    }
)

Determine validates and converts the returned values to the requested types.

max_tokens

Both operations support a generation limit:

answer = determine.answer(
    "Think carefully about this.",
    max_tokens=2048
)
choice = determine.choose(
    "What should happen?",
    [
        "continue",
        "stop",
        "retry"
    ],
    max_tokens=1024
)

This can be useful with reasoning models that need generation space before producing their final answer.

Multi-turn conversations

Use a normal Python list:

history = []

Then reuse it:

print(
    determine.answer(
        "My spaceship is called Juniper.",
        history=history
    )
)

print(
    determine.answer(
        "What is my spaceship called?",
        history=history
    )
)

The same history can be shared between answer() and choose().

Functions as choices

Functions can also be options.

def backup():
    """Back up the connected device."""
    print("Backing up...")


def update(version="latest"):
    """Update the connected device."""
    print("Updating to", version)


request = input("> ")

determine.choose(
    request,
    [
        backup,
        update
    ]
)

Determine can choose the function that genuinely matches the request and extract its arguments.

If none of the functions can perform the request, it returns None.

OpenAI-compatible APIs

determine.configure(
    "http://127.0.0.1:8080"
)

Determine attempts to discover the model automatically.

You can also specify it:

determine.configure(
    "http://127.0.0.1:8080",
    model="my-model"
)

Ollama

determine.configure(
    "ollama:qwen3"
)

Or:

determine.configure(
    "ollama"
)

llama.cpp

determine.configure(
    "llama.cpp:/home/me/model.gguf"
)

Extra arguments can be supplied:

determine.configure(
    "llama.cpp:/home/me/model.gguf",
    args=[
        "-ngl", "all",
        "-c", "32768"
    ]
)

API keys

export DETERMINE_API_KEY="your-key"

Determine also checks OPENAI_API_KEY.

Advanced configuration

determine.configure(
    endpoint="http://localhost:8080",
    model="my-model",
    temperature=0.2,
    timeout=120,
    reasoning_effort="high"
)

Why Determine?

Some decisions have many interacting variables, thresholds, and possible combinations.

Instead of maintaining a large decision tree:

action = determine.choose(
    "What should the enemy do?",
    [
        "attack",
        "defend",
        "run",
        "heal"
    ]
)

Determine can reason over the current program state.

Useful examples include:

  • game AI
  • procedural generation
  • adaptive software
  • natural-language tools
  • hardware-aware settings
  • recommendation systems
  • fuzzy classification
  • decisions involving many variables and thresholds

Security

AI output is nondeterministic.

Do not use Determine as the only protection for authentication, permissions, financial actions, destructive operations, security boundaries, or other safety-critical systems.

Only expose functions to choose() that the AI should actually be allowed to execute.

License

MIT

License

Determine 0.6.0 and later are licensed under the:

Redistribution and Modification License (RAML) 1.0

RAML allows you to:

  • use Determine in personal or commercial projects;
  • use Determine as a dependency;
  • study and modify the source code;
  • create private modified versions;
  • redistribute genuinely modified versions.

If you redistribute a modified version of Determine itself, it must contain material functional changes and must clearly credit the original project and author.

Superficial changes such as renaming, formatting changes, metadata changes, version changes, comment changes, or minor cosmetic modifications do not by themselves qualify as a material modification.

A simple acceptable attribution is:

Based on Determine by Jack.

Modified versions must not represent themselves as the official Determine project.

See the LICENSE file for the complete RAML 1.0 terms.

Earlier Determine releases remain available under the licenses that accompanied those releases.

Live token streaming

Streaming is optional and does not change normal Determine usage.

For a normal non-streaming call:

answer = determine.answer(
    "Explain this."
)

Advanced users can receive generated text live with on_token=:

import determine

determine.configure(
    "http://127.0.0.1:8080"
)


def show_token(token):
    print(
        token,
        end="",
        flush=True
    )


answer = determine.answer(
    "Tell me a short story.",
    on_token=show_token
)

print()
print()
print("Final answer:")
print(answer)

A short version is:

answer = determine.answer(
    "Explain quantum computing.",
    on_token=lambda token: print(
        token,
        end="",
        flush=True
    )
)

The callback receives text as soon as the backend provides it.

answer() still returns the complete final response after generation finishes.

Streaming works with:

  • OpenAI-compatible streaming APIs;
  • Ollama;
  • llama.cpp.

choose() also accepts on_token= for advanced debugging:

choice = determine.choose(
    "What should the player do?",
    [
        "fight",
        "run",
        "hide"
    ],
    on_token=lambda token: print(
        token,
        end="",
        flush=True
    )
)

Because choose() uses constrained internal output, its streamed text may be an option index or JSON rather than the final Python value.

When schema= is used with answer(), the stream contains the raw JSON as it is generated, while the final returned value is still the validated Python dictionary.

Metadata

Release files for determine 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for determine 0.7.0
File Size Uploaded
determine-0.7.0.tar.gz 41.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for determine 0.7.0
File Interpreter ABI Platform
determine-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 61.2 kB

Release files / determine-0.7.0.tar.gz

Download URL determine-0.7.0.tar.gz
Size 41.4 kB
Tags Source
SHA-256 checksum
How to use checksums
3f1960f40054ae5b4d51f1d0665d0aaca351fed0286936d328b28ae3e6ee895b
BLAKE2b-256 checksum
How to use checksums
9905fbce01b8e91c756f2c854a340a649eb09905e51ff00acda87df07fb16874
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release files / determine-0.7.0-py3-none-any.whl

Download URL determine-0.7.0-py3-none-any.whl
Size 19.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b8ae5c007be4814f06da9fcb2868aff3e24c6f21d537d1827a3356c72f20160e
BLAKE2b-256 checksum
How to use checksums
d398aeaa26c7ed98366d77e279c59fbb13cdb62bc08fe7b5a5779c13d5bf6950
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release history Release notifications | RSS feed

0.8.0

2 release files

This release

0.7.0 This release

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.0

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page