Metadata-Version: 2.5
Name: pydeltacode
Version: 0.2.0
Summary: Optimise your code for runtime performance, loc or peak memory on demand inside your script and compare LLM suggestions against your code. Solutions are tested end-to-end against the function calls executed and results are stored locally for manual verification. This package is designed to retain benefits of AI refactoring but keep an engineer friendly workflow.
Project-URL: Homepage, https://www.deltacode.org
Project-URL: Documentation, https://www.deltacode.org
Author-email: Kyle Winkler <kylewinkler@deltacode.com.au>
License-Expression: LicenseRef-Proprietary
License-File: LICENSE
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: anthropic>=0.80
Requires-Dist: fpdf2>=2.8
Requires-Dist: mcp>=1.2
Requires-Dist: openai>=1.0
Requires-Dist: pyyaml>=6.0
Description-Content-Type: text/markdown

# pydeltacode

Optimise your code for runtime performance, loc or peak memory on demand inside
your script and compare LLM suggestions against your code. Solutions are tested
end-to-end against the function calls executed and results are stored locally
for manual verification.

**📖 Full documentation: [www.deltacode.org](https://www.deltacode.org)**


## Install

```
pip install pydeltacode
```

For development (editable install from a checkout of this repo):

```
pip install -e .
```

## Usage

```python
from pydeltacode import refactor, llm

# One of eight providers: openai, anthropic, gemini, xai, deepseek,
# mistral, kimi, openrouter. ${VAR} is resolved from the environment
# at runtime, so the key never lives in your source.
llm.set_credentials("openai", "${PROVIDER_API_KEY}")

optimise = refactor(objective="speed")


@optimise.track
def sum_of_squares(values):
    squares = []
    for v in values:
        squares.append(v * v)
    total = 0
    for s in squares:
        total = total + s
    return total


if __name__ == "__main__":
    sum_of_squares(list(range(5_000)))     # record a real call
    result = optimise.optimise(            # refactor, verify, keep the best
        sum_of_squares, tries=5, use_captured_inputs=True
    )
    print(result["winner_version"], result["report_path"])
```

`optimise()` sends the tracked function to your provider, runs each suggestion
against the calls you actually recorded, and only keeps a candidate whose
outputs match the original *and* which improves the objective. The winner is
written back into your source file; every attempt, the code sent and received,
and a PDF report are saved locally.

## Agent mode — you write the code, deltacode judges it

If you already have a model (an IDE agent like Claude Code, Cursor or Copilot),
you don't need deltacode to call a second one. Agent mode asks *you* for each
candidate, then does what it's actually for: swap it in, execute it, compare
the outputs against the real recorded calls, measure it, and accept or reject
it.

Agent mode is reached through the MCP server:

```
pip install pydeltacode
claude mcp add deltacode -- python -m pydeltacode.mcp_server
```

The user then just asks — *"use deltacode to make `calculate_average` faster"* —
and the agent runs the whole workflow itself:

| tool | what it does |
|---|---|
| `analyse_function` | which recording strategies apply to this function |
| `optimise_function` | measure the agent's candidates, write the report |
| `list_runs` / `get_run` | read back earlier measurements |
| `swap_version` | restore a different measured version |

`optimise_function`'s `recording` argument chooses what the calls are recorded
from — `entry` runs the user's own script (strongest evidence), `test` runs a
named pytest node, and `inputs` takes calls the agent supplies. The agent is
instructed to **ask the user** which one to use, since that choice determines
what the report is evidence of.

See [AGENTS.md](AGENTS.md) for the full contract.

Underneath it is the `propose=` callback, which `optimise()` accepts directly
if you'd rather drive it from Python yourself:

```python
def my_agent(code, feedback, context):
    # `code`     - the lines to improve (baseline, or the running best)
    # `feedback` - what the last attempt measured and why it was rejected
    # `context`  - objective, constraints, baseline metrics, try number
    return ["def sum_of_squares(values):",
            "    return sum(v * v for v in values)"]

result = optimise.optimise(sum_of_squares, tries=5, propose=my_agent)
```

Your candidate is registered as an ordinary version and goes through exactly
the same verification as an LLM-generated one — the agent supplies code, it
does not get to decide whether the code is good.

In this mode:

- **No API key is needed.** deltacode makes zero LLM calls, and the run records
  its provider as `agent` so a report never names a model that was never asked.
- **`privacy_mode` is a no-op**, since nothing leaves your machine. Your
  callback receives real identifiers, not pseudonyms.
- **Job YAML can't express it** — a YAML file can't carry a Python callable,
  so agent mode is Python/MCP only.

Every attempt records `source` (`"agent"` or `"llm"`) and `code_sha256`, the
hash of the exact code that was executed to produce its numbers, in both
`optimise.json` and `report.pdf`. That's so a reviewer can check a claimed
improvement against the bytes it was really measured on. Note this is
tamper-*evident*, not tamper-proof: deltacode runs locally with full write
access, so it raises the cost of faking a result and leaves a trail, but it
is not a security boundary.

Tracked/refactored data is written to `.pydeltacode/<hash>/` (gitignored) in
the current working directory. Save location can also be changed.  

## License

Proprietary — see [LICENSE](LICENSE).
