Metadata-Version: 2.5
Name: davirix
Version: 0.2.3
Summary: Davirix Agent Platform uchun rasmiy Python SDK — 'completed' hech qachon 'bajarildi' degani emas
Project-URL: Homepage, https://davirix.com
Project-URL: Source, https://github.com/davirixai/python-sdk
Author: Davirix
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: agent,davirix,idempotency,operations,sdk
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
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: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: jsonschema>=4.20
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# davirix — Python SDK

Davirix agent platformasi uchun rasmiy Python mijozi (`/v1/executions`).

> ## ⚠ `completed` — «bajarildi» degani EMAS
>
> `status: completed` — **model javob berdi** degani. Amal (SMS ketdimi,
> karta yangilandimi) bajarildimi — bu **faqat `operations[]`** da ko'rinadi.
> Konnektor timeout bersa amal `UNKNOWN` bo'lib qoladi, model esa baribir
> chiroyli javob yozishi mumkin.
>
> Shuning uchun bu SDK'da `execution.success` yo'q va `bool(execution)`
> **TypeError** beradi. Yagona «bajarildimi» javobi — `execution.verified`.

## O'rnatish

```bash
pip install davirix          # PyPI (hali nashr qilinmagan — pastga qarang)
pip install -e .             # monorepodan
```

Yagona runtime bog'liqlik — `httpx`.

## 10 qatorlik misol

```python
from davirix import Davirix

dx = Davirix(tenant_id="acme", actor="service:billing")   # kalit: DAVIRIX_API_KEY
n = dx.run(agent_id="acme-support", input={"text": "Mijozga SMS yubor"})

print(n.status)      # "completed"          ← MODEL javob berdi
print(n.verified)    # False                ← AMAL tasdiqlanmagan
print(n.verdict)     # Verdict.UNKNOWN      ← nega: natija noma'lum

if not n.verified:
    for op in n.unknown_operations:
        print(op.capability_id, op.status)  # notification.send_sms UNKNOWN
        # ⛔ QAYTA YUBORMANG — reconciliation aniqlaydi
```

`n.text` — model javobi. U **matn**, amal isboti emas.

## To'rtta qoida

**1. `completed` ≠ «bajarildi».** `verified` — fail-closed: `operations[]`
kelmasa ham, holat tanish bo'lmasa ham **False**. «Bilmadim» hech qachon
«ha» ga aylanmaydi.

```python
n.status        # ijro holati (xom satr)
n.verified      # BARCHA yozuv amallari manbadan tasdiqlanganmi
n.verdict       # nega: verified · no_actions · unknown · failed_action ·
                #       pending_action · unreported · not_completed
n.operations    # typed amallar ro'yxati
n.coverage      # `operations[]` ga ishonish mumkinmi (degraded_reasons bilan)
n.require_verified()   # tasdiq SHART bo'lgan joyda — UnverifiedError
```

Amal holatining **uch** holati aralashtirilmaydi:

| Javob | Ma'no | `verified` |
|---|---|---|
| `operations: [...]` | bilamiz | amallarga qarab |
| `operations: []` | yozuv amali bo'lmagan | `True` |
| `operations` yo'q / `coverage.complete: false` | **bilmaymiz** | `False` |

Tasdiqlanmagan amal bilan tugagan ijroni kod umuman o'qimasa, SDK
`davirix` logger'iga WARNING yozadi (asyncio'ning «Task exception was never
retrieved» naqshi). O'chirish: `set_unverified_warning(False)`.

**2. `UNKNOWN` — istisno EMAS.** SDK u uchun hech qachon istisno
ko'tarmaydi. Sabab amaliy: istisno ko'rgan joyda mijoz `except: retry`
yozadi va **dublikat effekt** yaratadi. `UNKNOWN` dan yagona chiqish yo'li —
reconciliation.

**3. `idempotency_key` avtomatik va barqaror.**

```python
dx.run(agent_id="x", input={"text": "..."})                    # kalit argumentlardan
dx.run(agent_id="x", input={"text": "..."}, key="buyurtma-42") # yoki mijoz beradi
```

Kalit so'rov tanasining **kanonik** shaklidan chiqariladi — platformaning
`semantic_key`/`action_hash` bilan **ayni** qoidalar
(`contracts/execution/v1/CANONICALIZATION.md`). Ayni argumentlar → ayni kalit
→ server ikkinchi ijro yaratmaydi. Shu bois tarmoq uzilganda **qo'lda qayta
chaqirish xavfsiz**.

**4. Retry faqat `retryable: true` da.**

| Holat | SDK qiladi |
|---|---|
| `429` (+ `Retry-After`) | qayta urinadi, serverning kutish vaqtini hurmat qiladi |
| `502/503` + `retryable: true` | qayta urinadi |
| `502/503` `retryable`siz | **urinmaydi** — «vaqtinchalikdir» deb taxmin qilinmaydi |
| `409 / 422 / 403 / 404` | urinmaydi (holat qayta urinishdan o'zgarmaydi) |
| ulanish uzildi (javob yo'q) | **urinmaydi** — POST bajarilgan bo'lishi mumkin |
| ijro `failed`, `error.retryable: true` | **avtomatik qayta yurgizilmaydi** — yangi ijro = yangi effekt; qaror mijozniki |

## `davirix app check` — Domen shartnomasi

Ilova AI uchun **tayyormi** — buni taxmin qilmang, o'lchang:

```bash
davirix app check app-manifest.json
```

```
Daraja: A2 — Command'lar idempotentlik bilan, agent YOZADI

  A3 ga chiqish uchun:
    - [command.verification.missing.r3] `billing.charge`: `verification`
      yo'q — va bu R3 amal: qaytarilmaydigan yoki moliyaviy ta'sirli.
```

### Darajalar

| | Nima ochiladi |
|---|---|
| **A0** | ⛔ hech narsa |
| **A1** | 👁 agent **o'qiydi** |
| **A2** | ✍️ agent **yozadi** |
| **A3** | ✅ agent «**bajarildi**» deya oladi |
| **A4** | 🚀 **avtonom** ishlaydi |

### CI darvozasi

```bash
davirix app check app-manifest.json --min-level A3
```

Standart `--min-level` — **A1**. Endi boshlagan ilova birinchi kunidan
qizil CI ko'rsa, tekshiruvchini o'chirib qo'yardi.

### Kutubxona sifatida

```python
from davirix import check_manifest

res = check_manifest(manifest)          # daraja HISOBLANADI
print(res.level)                        # "A2"
for f in res.blocking("A3"):
    print(f.code, f.message)
```

### ⛔ Daraja e'lon qilinmaydi

Manifestda `level` maydoni yo'q va sxema uni rad etadi. Ilova o'zini
A4 deb **atay olmaydi**.

### Ikki xil qoida

| Qatlam | Nima |
|---|---|
| **Sxema** | SHAKL — turlar, enum, naqsh, noma'lum maydon |
| **Tekshiruvchi** | TAYYORLIK — nima yetishmaydi va qaysi darajani to'sadi |

⚠ Tayyorlik qoidasini sxemaga qo'yish A0 ni **erishib bo'lmaydigan**
qiladi: ilova o'z holatini bilish o'rniga sxema xatosini olardi.

---

## API

```python
dx.run(...)      # yaratadi va yakunlanguncha kutadi (yoki approval kutishigacha)
dx.start(...)    # yaratadi va darhol qaytadi
dx.get(id)       # holat
dx.wait(x)       # kuzatish
dx.cancel(id)    # kooperativ bekor qilish
```

`run()` istisno ko'tarmaydi ijro **holati** uchun: `failed` ham, `cancelled`
ham, `waiting_for_approval` ham — bu **ma'lumot**, xato emas. Istisnolar
faqat transport/protokol uchun (`errors.py`).

Kutish budjeti tugasa — `ExecutionTimeout`: ijro **serverda davom etmoqda**,
`dx.get(execution_id)` bilan kuzatishda davom eting.

## Manzil (`base_url`)

Default — `https://api.davirix.com`. **Uch darajada** o'zgartiriladi,
ustunlik tartibi bilan:

```python
Davirix(api_key="…", base_url="http://localhost:8001")   # 1. konstruktor — eng kuchli
```
```bash
export DAVIRIX_BASE_URL=https://api.eu.davirix.com        # 2. muhit
```
```
                                                          # 3. default
```

⚡ **Nega uch daraja:** manzil kelajakda o'zgarishi mumkin (mintaqaviy
endpoint, on-prem o'rnatma, lokal stend). Konstruktor argumenti test
uchun, env — deployment uchun, default — hech narsa sozlanmaganda.
Mijoz kodini o'zgartirmasdan manzilni almashtira olishi kerak.

## Sir

`api_key` — konstruktor argumenti yoki `DAVIRIX_API_KEY`. Kodga yozilmaydi,
`repr()` ga tushmaydi, xato matniga tushmaydi. Kalit umuman berilmasa mijoz
**qurilmaydi** (jim autentifikatsiyasiz so'rov yo'q).

## Testlar — kontrakt fixture'laridan

Testlar `contracts/platform/execution/v1/fixtures/` dan **to'g'ridan-to'g'ri**
oziqlanadi; ro'yxat qo'lda emas, katalogdan o'qiladi. Kontrakt o'zgarsa SDK
darhol qizil bo'ladi.

```bash
pip install -e ".[dev]"
pytest -q
python scripts/mutation_check.py     # qoidalarni buzuvchi o'zgarish qizil bo'lishini isbotlaydi
```

Kontraktlar boshqa joyda bo'lsa: `DAVIRIX_CONTRACTS_DIR=/yo'l/contracts pytest -q`.

## Holat (0.2.1)

### 0.2.x da nima yangi

* ⚡ **`davirix app check`** — Domen shartnomasi tekshiruvchisi va
  A0–A4 daraja hisobi. Sxema paket ichida yuboriladi.
* `check_manifest` · `check_file` · `CheckResult` · `Finding` —
  paket darajasida eksport.
* `__version__` paket metadatasidan — ilgari u qo'lda yozilardi
  va nashr versiyasidan ajralib ketgandi (0.2.1 da tuzatildi).
* Misol identifikatorlari **neytral** (`acme-*`): SDK ochiq bo'ladi va
  unda haqiqiy mijoz nomi turmasligi kerak. CI qo'riqchisi bor.

### Cheklovlar

* Sinxron mijoz. `async` mijoz — keyingi versiya.
* `POST/GET/cancel` qamrab olingan; `events`/`stream`/`resume`/`feedback`/
  `handoff` — keyingi versiya.
* **PyPI'ga hali nashr qilinmagan.** Nashr — alohida qadam.
