Metadata-Version: 2.5
Name: determine
Version: 0.4.3
Summary: Simple context-aware AI inference for Python.
Author: Jack
License-Expression: MIT
License-File: LICENSE
Keywords: ai,decision,generation,inference,llm,procedural,reasoning
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# Determine

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

The main API has only two operations:

~~~python
determine.answer(...)
determine.choose(...)
~~~

## Install

~~~bash
pip install determine
~~~

## Quick start

~~~python
import determine

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

name = "Jack"
favourite_food = "Chinese"

answer = determine.answer(
    "Suggest something I might like for dinner."
)

print(answer)
~~~

Determine automatically sees relevant variables and surrounding source code.

## answer()

Use `answer()` when the AI can produce any answer.

~~~python
player_health = 24
ammo = 0

response = determine.answer(
    "Explain what situation the player is in."
)

print(response)
~~~

You can set a generation limit:

~~~python
response = determine.answer(
    "Explain this carefully.",
    max_tokens=2048
)
~~~

## choose()

Use `choose()` when the AI must select from available options.

~~~python
health = 12
ammo = 0
enemy_distance = 3

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

print(action)
~~~

Options can also be other Python values:

~~~python
difficulty = determine.choose(
    "Choose the best difficulty.",
    [1, 2, 3, 4, 5]
)
~~~

## max_tokens

Thinking models may need extra generation space before producing their final
answer.

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

If `max_tokens` is not supplied, Determine lets the backend use its normal
default.

## Multi-turn conversations

Multi-turn only needs a normal Python list:

~~~python
import determine

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

history = []

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

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

The same history works with `choose()`:

~~~python
history = []

determine.answer(
    "I prefer quiet places.",
    history=history
)

place = determine.choose(
    "Where should I go?",
    [
        "busy shopping centre",
        "quiet park",
        "concert"
    ],
    history=history
)

print(place)
~~~

Start a fresh conversation with:

~~~python
history = []
~~~

## Functions as choices

Functions can also be options.

~~~python
import determine

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


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


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


def device_info():
    """Show information about the connected device."""
    print("Getting device information...")


request = input("> ")

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

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

## OpenAI-compatible APIs

~~~python
import determine

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

You can specify the model manually:

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

## Ollama

~~~python
import determine

determine.configure(
    "ollama:qwen3"
)

print(
    determine.answer(
        "Say hello."
    )
)
~~~

Or let Determine use an installed model:

~~~python
determine.configure("ollama")
~~~

## llama.cpp

Use a local GGUF directly:

~~~python
import determine

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

print(
    determine.answer(
        "What should I do?"
    )
)
~~~

Extra llama.cpp arguments can be supplied:

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

A custom llama.cpp binary can also be supplied:

~~~python
determine.configure(
    "llama.cpp:/home/me/models/model.gguf",
    binary="/home/me/llama.cpp/build/bin/llama-cli"
)
~~~

## API keys

~~~bash
export DETERMINE_API_KEY="your-key"
~~~

Determine also checks `OPENAI_API_KEY`.

## Advanced configuration

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

Individual calls can override settings:

~~~python
answer = determine.answer(
    "Think carefully.",
    temperature=0.1,
    max_tokens=2048,
    reasoning_effort="high"
)
~~~

## Why Determine?

Simple decisions are easy to hard-code:

~~~python
if health <= 0:
    game_over()
~~~

But decisions involving many interacting variables can become difficult to
maintain.

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

Determine is useful for things such as:

- game AI
- procedural generation
- natural-language tools
- hardware-aware configuration
- recommendation systems
- adaptive software
- 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 actions, security boundaries, or other
safety-critical systems.

When functions are passed to `choose()`, only provide functions that you
actually want the AI to be allowed to execute.

## License

MIT
