Metadata-Version: 2.5
Name: diteko
Version: 0.4.0
Summary: Generate, export and run tests for Amazon Connect contact flows with Diteko (Grammatical Evolution).
Author: Lehlohonolo Sehako
License-Expression: MIT
License-File: LICENSE
Keywords: amazon-connect,contact-flow,cxblueprint,grammatical-evolution,ivr,mcp,testing
Classifier: Development Status :: 3 - Alpha
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 :: Communications :: Telephony
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Provides-Extra: cxblueprint
Requires-Dist: cxblueprint>=0.1.0.post15; extra == 'cxblueprint'
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: twine>=6; extra == 'dev'
Provides-Extra: mcp
Requires-Dist: mcp<3,>=1.26.0; extra == 'mcp'
Description-Content-Type: text/markdown

# diteko (Python)

Generate, export and run tests for Amazon Connect contact flows, from Python. It is the
testing counterpart to [cxblueprint](https://pypi.org/project/cxblueprint/): build or
export a flow, then let Diteko derive its grammar, evolve a test suite with Grammatical
Evolution, export it, and run it on Connect's native testing.

The SDK is a client: it talks to a running Diteko deployment over its REST API, so you need
one to point it at. If that deployment requires API keys, set `DITEKO_API_KEY` (or pass
`api_key=`); otherwise point the SDK only at a deployment inside your network or behind
your VPN.

```bash
pip install diteko               # SDK
pip install "diteko[mcp]"        # + MCP server for Claude Desktop / Cursor / VS Code
pip install "diteko[cxblueprint]"
```

## Getting started

1. **Find your Diteko.** Diteko is self-hosted: you need the address of a running deployment, such as `http://localhost:8888` when you run it yourself.
2. **Get a key, if it asks for one.** When a deployment requires API keys, whoever runs it creates one for you under Settings › API keys. `WRITE` is enough for everything here except live runs on Connect. Put it in the environment:

   ```bash
   export DITEKO_URL=https://diteko.example.internal
   export DITEKO_API_KEY=dk_...     # only if the deployment requires keys
   ```

3. **Check the connection:**

   ```python
   from diteko import Diteko

   dk = Diteko()            # DITEKO_URL and DITEKO_API_KEY from the environment
   print(dk.version())      # {'api': '1.1', 'server': '…', 'auth': 'keys'}
   print(dk.whoami())       # the key in use, or None when keys are off
   ```

4. **Run the example.** `examples/cxblueprint_to_excel.py`, also as a notebook, builds a flow with cxblueprint, evolves a suite and writes the Excel test script, in about a minute. Both ship in the source distribution: `pip download --no-binary :all: --no-deps diteko`, then unpack it.

## Watching a run, and typed results

```python
run = project.evolve(preset="standard").wait(progress=True)       # one line on stderr, kept up to date
run = project.evolve(preset="standard").wait(progress=print)      # or any callable, given a RunProgress
run.info.best_fitness, run.info.generation, run.info.generations

project.refresh().info            # ProjectInfo: grammar, latest run, suite, last execution, typed
execution = suite.publish_to_connect(dry_run=True)
execution.results                 # [Verdict(test_id, status, message), ...]
execution.passed, execution.failed, execution.inconclusive   # inconclusive: Connect could not start it, etc.
```

## The pipeline

```python
from diteko import Diteko

dk = Diteko("http://localhost:8888")

project = dk.projects.from_json("claims.json")          # Connect export or cxblueprint output
project.grammar.generate()                              # derive, store and validate the grammar
run = project.evolve(preset="standard", focus="balanced").wait()
suite = run.suite(top=30, selection="coverage")         # or selection="fitness"

for test in suite:
    print(test.test_id, test.keys, test.fitness)

suite.export_xlsx("claims-tests.xlsx")                  # manual test script (ISO/IEC/IEEE 29119-3)
suite.export_native("claims-native.json")               # Amazon Connect native test cases
result = suite.publish_to_connect(dry_run=True)         # dry run unless you say otherwise
print(result.passed, result.failed, result.verdicts)
```

### Straight from cxblueprint

```python
from cxblueprint import Flow
from diteko import Diteko

flow = Flow.build("Burger Order")
menu = flow.get_input("Press 1 for Classic or 2 for Veggie", timeout=10)
# ... build the flow as usual ...

project = Diteko().projects.from_cxblueprint(flow)      # compiles locally, uploads the JSON
```

### Other ways in

```python
dk.projects.import_from_connect("08e145dc-d959-4094-9021-6f10d8590be2")   # from the instance
dk.projects.list()                                      # every project and its next step
dk.projects.get(21601).suite(top=10).export_xlsx()
```

### Grammars as BNF or JSON

The two forms are exact reflections of each other. Both are validated by the same parser,
and both keep comments.

```python
g = project.grammar.latest()
spec = g.to_json()                    # {"format": "diteko-grammar/v1", "start": ..., "rules": [...]}
g.replace(spec, format="json").save() # edit as JSON, store as canonical BNF
dk.convert_grammar(bnf_text, "bnf", "json")
```

### Presets

| `preset`   | calls × generations |
| ---------- | ------------------- |
| `quick`    | 40 × 15             |
| `standard` | 100 × 50            |
| `thorough` | 200 × 120           |

| `focus`     | favours                                              |
| ----------- | ---------------------------------------------------- |
| `balanced`  | blocks and branches, plus happy paths and recoveries |
| `coverage`  | visiting as much of the flow as possible             |
| `errors`    | timeouts and wrong keys that still end properly      |
| `transfers` | calls that reach an agent queue                      |

Pass `population=`, `generations=`, `weights={"state_coverage": 1.0}` or `seed=` to go beyond them.

### API keys

```python
dk = Diteko("https://diteko.internal", api_key="dk_...")   # or set DITEKO_API_KEY
dk.whoami()   # {"name": "nightly CI", "prefix": "dk_...", "scope": "WRITE", ...}; None if keys are off
```

A key carries one scope: `READ` (see and export), `WRITE` (also create, run and dry-run),
`PUBLISH_LIVE` (also run on Connect for real, which is billed) or `ADMIN` (also manage keys).
Keys are created in the console under Settings, API keys.

## MCP server

```bash
DITEKO_URL=http://localhost:8888 DITEKO_API_KEY=dk_... diteko-mcp   # the key only if the server requires one
```

```json
{ "mcpServers": { "diteko": { "command": "diteko-mcp", "env": { "DITEKO_URL": "http://localhost:8888", "DITEKO_API_KEY": "dk_..." } } } }
```

| Tool               | Does                                                                                   |
| ------------------ | -------------------------------------------------------------------------------------- |
| `list_projects`    | every flow under test and its next step                                                |
| `import_flow`      | register a flow from JSON text, a file path, or a Connect flow id                      |
| `generate_grammar` | derive, store and validate a flow's grammar                                            |
| `convert_grammar`  | BNF ⇄ JSON                                                                             |
| `start_evolution`  | start a run (`size`, `focus`, `seed`)                                                  |
| `get_run`          | a run's progress                                                                       |
| `export_suite`     | `xlsx`, `json` or `native` to a file                                                   |
| `publish_suite`    | run on Connect; **`dry_run` defaults to true**, since a live run bills the AWS account |

Each tool carries MCP annotations: read-only tools say so, and `publish_suite` is marked as reaching an external system. Works with `mcp` 1.x and 2.x.

## Versioning

The package follows [Semantic Versioning](https://semver.org/). See the [changelog](#changelog) for what each release changed.

The server reports an **API version**, `MAJOR.MINOR`, at `GET /api/version`. A minor bump only adds endpoints or fields. A major bump changes something an existing client relies on. Each SDK release speaks one API major version, currently **1**. On its first call the SDK checks the server's version:

| Server                      | What happens                                                   |
| --------------------------- | -------------------------------------------------------------- |
| API 1.x                     | Works.                                                         |
| Another major               | `DitekoError`, saying whether to upgrade the SDK or the server |
| Too old to report a version | A warning, then it carries on                                  |

`Diteko(url, check_version=False)` skips the check, and `dk.version()` returns what the server reports.

## Development

```bash
cd clients/python
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev,mcp]"
pytest                                   # against an in-memory fake of the API
DITEKO_URL=http://localhost:8888 pytest  # also runs the live and contract tests against a local stack
```


# Changelog

All notable changes to the `diteko` Python package. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow
[Semantic Versioning](https://semver.org/) as described under “Versioning” in the README.

## [0.4.0] - 2026-10-11

### Added

- `Verdict.attempts` and `Verdict.passed_on_rerun`. A server on API 1.2 re-runs a test
  that failed, once, because Connect's prompt recognition sometimes misses a prompt the
  flow played; a pass on the re-run is reported as a pass with `attempts == 2`. Older
  servers leave `attempts` as `None`.

## [0.3.0] - 2026-10-11

### Added

- `Run.wait(progress=True)` keeps a line on stderr up to date while a run evolves; pass
  a callable instead to receive a `RunProgress` whenever the generation or status changes.
- Typed views alongside the raw responses: `Run.info` (`RunProgress`), `Project.info`
  (`ProjectInfo`: grammar, latest run, suite, last execution), `Execution.results`
  (`Verdict`s with Connect's message) and `Execution.inconclusive`.
- `Diteko()` reads `DITEKO_URL` when no address is given, as `diteko-mcp` already did.
- A getting-started guide in this README, and `examples/cxblueprint_to_excel.py` (and the
  same as a notebook): from a cxblueprint flow to an Excel test script.

### Fixed

- A project's last execution no longer reads as RUNNING for a moment after the execution
  reported COMPLETED (fixed server-side).

## [0.2.0] - 2026-10-11

### Added

- The first call checks that the server speaks this SDK's API major version
  (`GET /api/version`, API 1.x). A server on another major is refused with an
  error that says which side to upgrade; a server that predates version reporting
  gets a warning, not a failure. `Diteko(..., check_version=False)` skips the check.
- `Diteko.version()` returns the server's API version and build.
- API keys: the SDK and `diteko-mcp` send `DITEKO_API_KEY` (or `Diteko(api_key=...)`)
  to servers that require keys (API 1.1). A missing key, a refused key and a key
  without permission each raise a `DitekoError` that says which. `Diteko.whoami()`
  returns the key in use.

### Fixed

- Moving a record to another parent with a partial update (for example a grammar to
  another flow) no longer fails on the server (fixed server-side, Diteko API 1.0).

## [0.1.0] - 2026-10-10

### Added

- First release: projects from Connect exports, cxblueprint flows or a Connect
  instance; grammars as BNF or JSON; evolution with size and focus presets; suites
  exported as an Excel test script (ISO/IEC/IEEE 29119-3), JSON or Connect native
  tests; publishing to Connect, dry run by default.
- `diteko-mcp`, an MCP server exposing the same pipeline as eight tools, on `mcp`
  1.x or 2.x.

[0.4.0]: https://pypi.org/project/diteko/0.4.0/
[0.3.0]: https://pypi.org/project/diteko/0.3.0/
[0.2.0]: https://pypi.org/project/diteko/0.2.0/
[0.1.0]: https://pypi.org/project/diteko/0.1.0/
