Bu hujjatning oxirida sizda ishlaydigan agent bo'ladi: kod yozasiz, platformaga ulaysiz, o'rnatasiz va unga birinchi so'rovni yuborib javobini ko'rasiz.
Misol sifatida kalkulyator agentini quramiz — 12 + 5 yuboramiz, 17 qaytadi. Ataylab eng oddiy mantiq: bu yerdagi gap matematikada emas, agent platformaga qanday ulanishida.
Kerak: Python 3.11+, terminal, 20 daqiqa.
Bu hujjatdagi buyruqlar haqiqatan ishga tushirilib tekshirilgan.
Javoblar — o'sha ishning haqiqiy chiqishi, qo'lda yozilgan emas.
Bu yerdagi kod va manifest to'liq keltirilgan — nusxa olib ishlatsangiz bo'ladi. Boshqa hech qanday fayl kerak emas.
Vaqtingizni behuda sarflamasligingiz uchun bilib qo'ying. Quyidagilar kamchilik sifatida yozilgan, bahona sifatida emas:
| Nima | Holati |
Developer Portal (agentfather.uz/portal) | Ishlaydi: hisob, agent yaratish, manifest, «Sinov» bo'limi (sinab ko'rish + sinov tokeni), statistika, otzivlar. «Explore» va vidjetlar yo'q — mijoz ekranlari botdagi ilovada. |
| Portaldagi «o'rnatish havolasi» | Brauzerda o'rnatish sahifasini ochmaydi — JSON qaytaradi (client_id, authorize_url). O'rnatishni 7-bo'limdagidek o'zingiz boshlaysiz. |
Bot va Mini App (@AgentFatherAI_bot) | Mijoz tomoni shu yerda. Agentni yollash, unga vazifa berish, natijani ko'rish — botdagi ilovada. Portal — dasturchi uchun, bot — foydalanuvchi uchun. Ikkalasini adashtirmang. |
| Rozilik (consent) ekrani | Brauzerda ham ochiladi: kirish Telegram hisobi bilan (Login Widget), parol yo'q. Telegram ichida esa ilovaning o'zida chiziladi (7.1). |
| Dasturchi uchun sinov | Bor: POST /apps/{id}/test-run (6.4) agentni bitta so'rov bilan sinaydi, POST /apps/{id}/sandbox-token (6.5) o'z kodingiz uchun token beradi. Ikkalasi portalda tugma sifatida ham bor. Mijoz o'rnatishi sinov uchun kerak emas. |
| Sinov ma'lumoti (demo kontaktlar va h.k.) | POST /api/v1/dev/sandbox/seed sinov tashkilotingizga haqiqiy shakldagi vazifa, fayl va kontakt qo'yadi. Usiz tashkilot bo'sh keladi. |
| Moderatsiya | Faqat marketplace'ga chiqish uchun. O'z agentingizni o'zingiz sinash uchun moderatsiya kutish shart emas. |
Xulosa: agent yozish va sinash — portalda yoki terminalda, ikkisi bir xil endpointlarni chaqiradi. Mijoz o'rnatishi (7-bo'lim) esa alohida ish va u sizning sinovingizga to'siq bo'lmaydi. Quyida to'liq yo'l, boshidan oxirigacha.
Beshta narsa bor va ular bir-biriga shunday ulanadi:
Integratsiya (app) ──▶ Manifest (versiya) ──▶ O'rnatish ──▶ Ish (run)
OAuth kalitlari agent nima qila oladi mijoz ruxsat berdi agent ishladi
redirect_uri runtime.endpoint access_token natija
| Atama | Bu nima | Qayerda tug'iladi |
Integratsiya (app) | OAuth kalitlari konteyneri: client_id, client_secret, signing_secret, redirect_uri. Kod emas. | POST /api/v1/dev/apps |
| Manifest | Agent nima qila olishini e'lon qiladi: qaysi manzilda turadi, qanday ruxsat kerak, qanday sozlama so'raydi. JSON fayl. | POST /api/v1/dev/apps/{id}/versions |
| Agent | Sizning kodingiz. Bitta HTTP server. Platforma unga so'rov yuboradi. | Sizning serveringiz |
O'rnatish (installation) | Mijoz «roziman» dedi → sizga access_token berildi. | OAuth oqimi |
Ish (run) | Bitta bajarilish: kirish → agent → natija. | POST /api/v1/runs |
Eng muhim tushunish: platforma — chaqiruvchi, sizning agentingiz — chaqiriluvchi. Agentni ishga tushirib qo'yib kutish hech narsa bermaydi. Kimdir ish yaratmaguncha agentingizga hech kim murojaat qilmaydi. Agar «SDK'ni run qildim, ammo hech nima kelmadi» degan holatda bo'lsangiz — sabab shu, va bu xato emas.
Bu — eng ko'p savol tug'diradigan joy, shuning uchun har birini alohida yozamiz.
redirect_uri — mijoz brauzeri qaytadigan manzilKim ochadi: foydalanuvchining brauzeri. Qachon: faqat o'rnatish paytida, bir marta. Qayerda beriladi: integratsiya yaratganda (redirect_uris) — 4-bo'lim.
Mijoz «Roziman» tugmasini bosgach, platforma uning brauzerini shu manzilga qaytaradi va URL'ga bir martalik code qo'shadi:
https://sizning-agent.uz/oauth/callback?code=XLZPuwd4hJm5N4mk…&state=…
Sizning saytingiz shu code ni oladi va uni access_token ga almashtiradi (7-bo'lim). Shundan keyin bu manzil boshqa ishlatilmaydi.
Qoidalar:
http://localhost va http://127.0.0.1 — ishlab chiqish uchun ruxsat (app/api/schemas.py).
# (fragment) bo'lmasligi kerak. ortiqcha / ham invalid_redirect_uri beradi.
redirect_uris — ro'yxat), keyin PATCH bilan o'zgartirasiz.
runtime.endpoint — platforma so'rov yuboradigan manzilKim ochadi: AFAI serveri (odam emas). Qachon: har bir ishda, doimiy. Qayerda beriladi: manifest ichida — 6-bo'lim.
amoCRM yoki Telegram'dagi «webhook» tushunchasiga to'g'ri keladigani — aynan shu. Ish yaratilganda platforma shu manzilga POST yuboradi:
{
"type": "run.execute",
"run": { "id": "run_…", "input": {"a": 12, "b": 5, "op": "+"} },
"agent": { "id": "afai.calculator", "version": "1.0.0" },
"installation": { "id": "ins_…", "workspace_id": "ws_…", "scopes": [], "settings": {} },
"callback": { "base_url": "https://agentfather.uz/api/v1", "token": "…", "expires_in": 900 }
}
Sarlavhalar: X-AFAI-Signature: t=<unix>,v1=<hmac>, X-AFAI-Event, X-AFAI-Delivery, X-AFAI-Attempt.
Qoidalar — bular redirect_uri dagidan butunlay boshqa:
agentfather.uz da HTTPS majburiy (REQUIRE_HTTPS_ENDPOINTS=true).localhost ham, ichki IP ham qat'iyan mumkin emas — bizning serverimiz ularga chiqa olmaydi va bu SSRF hujumi yo'li bo'lardi (app/security/ssrf.py). Urinsangiz aniq shu xatoni olasiz:
``json {"status": "failed", "error_code": "blocked_target", "error_message": "Bu manzilga so'rov yuborilmaydi: ichki manzil (::1)"} ``
callback.base_url — siz bermaysiz, o'zi keladiYuqoridagi so'rovning ichida callback bloki bor. Bu — teskari yo'nalish: agent AFAI'ga natija qaytarish uchun ishlatadi. Tokeni vaqtinchalik (15 daqiqa) va faqat shu ish uchun. Hech qayerda ro'yxatdan o'tkazilmaydi. SDK uni o'zi ulaydi.
redirect_uri | runtime.endpoint | callback.base_url | |
| Yo'nalish | AFAI → brauzer → siz | AFAI → agent | agent → AFAI |
| Kim ochadi | odam | server | sizning kodingiz |
| Qachon | o'rnatishda, 1 marta | har ishda | uzoq ishlarda |
localhost mumkinmi | ha | yo'q | — |
| Kim beradi | siz (app yaratishda) | siz (manifestda) | platforma (so'rov ichida) |
| Nima bilan himoyalangan | PKCE + aniq moslik | HMAC imzo | vaqtinchalik token |
Nega birlashtirib bo'lmaydi: birinchisiga localhost mumkin, ikkinchisiga qat'iyan mumkin emas. Biri brauzer GET ini kutadi, ikkinchisi imzolangan server POST ini. Bitta maydon ikkala qoidaga ham bo'ysuna olmaydi. Buning ustiga runtime.type: "inline" agentlarda endpoint umuman bo'lmaydi, redirect_uri esa baribir kerak.
agentfather.uzPlatformani o'zingizda ko'tarish shart emas — kerak ham emas. Sizga faqat HTTP API kerak: hisob, app, manifest, sinov — hammasi shu API orqali (yoki portaldagi tugmalar bilan). Platformani ishga tushiradigan buyruqlar sizga tegishli emas.
Bitta shart bor: agentingiz internetdan ochiq HTTPS manzilda turishi kerak: noutbukingizdagi localhost:8200 ga bizning serverimiz hech qachon chiqa olmaydi.
Ikki yo'l:
docs/AGENT_DEPLOY.md). ``bash cloudflared tunnel --url http://localhost:8200 # → https://random-words-1234.trycloudflare.com ` Shu https://… manzilni manifestdagi endpoint` ga yozasiz.
export AFAI_BASE_URL=https://agentfather.uz
API manzili haqida. API alohida subdomenda emas — barcha yo'llar
saytning o'zida, https://agentfather.uz/api/v1/… ostida. «API'ning
URL'i qaysi?» degan savolning javobi: sayt manzili + /api/v1.
Windows'da ishlayotganlar uchun. export X=y — Linux/macOS (bash)
yozuvi. PowerShell'da xuddi shu narsa
$env:AFAI_BASE_URL = "https://agentfather.uz", buyruq ichida esa
$AFAI_BASE_URLo'rniga$env:AFAI_BASE_URLturadi. Eng osoni —
qiymatlarni buyruqqa to'g'ridan-to'g'ri yozib yuborish.
Platformaning o'zi sizda bo'lsa (AFAI jamoasi ichida ishlayotganlar):
ko'tarish yo'liplatform/README.mdda. O'shandaAFAI_BASE_URL
http://localhost:8100bo'ladi, tunnel kerak emas vaendpointga
http://localhost:8200 yoziladi. Qolgan hamma qadam bir xil.
Xohlasangiz shu bo'limni brauzerda ham qilsa bo'ladi:
https://agentfather.uz/portal — hisob ochish, kalit olish, agent
yaratish, manifest yuklash formalar bilan. Portal ham, curl ham bitta
X-Developer-Key bilan ishlaydi, natijasi bir xil.
curl -s -X POST $AFAI_BASE_URL/api/v1/dev/register \
-H "Content-Type: application/json" \
-d '{"email":"siz@example.uz","name":"Ismingiz","company":"Kompaniya"}'
Javob:
{
"developer": { "id": "dev_3ad4606d8ec48d3a7bbca511" },
"api_key": "dvk_3d72202de63c52883ef83eb7a6a72481574804cd27f0b388",
"warning": "Kalitni saqlang — u boshqa ko'rsatilmaydi.",
"sandbox_workspace_id": "ws_3a417b0961a340285243d550"
}
Ikkalasini ham saqlang:
export AFAI_DEV_KEY=dvk_…
export SANDBOX_WS=ws_…
sandbox_workspace_id — bu sizning sinov tashkilotingiz. U shu zahoti, mijozsiz ochiladi. Bo'sh keladi: demo kontakt, vazifa yoki fayl bo'lmaydi.
⚠️ Dasturchi kaliti X-Developer-Key sarlavhasida yuboriladi,
Authorization: Bearer da emas. Chalkashtirsangiz
unauthorized: Sessiya tokeni o'qib bo'lmadi olasiz.
curl -s -X POST $AFAI_BASE_URL/api/v1/dev/apps \
-H "X-Developer-Key: $AFAI_DEV_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Kalkulyator",
"slug": "kalkulyator",
"summary": "Ikki sonni hisoblaydi",
"type": "public",
"redirect_uris": ["https://sizning-agent.uz/oauth/callback"],
"requested_scopes": ["runs:write"]
}'
slug va type — o'zgarmas: birinchisi havolalarda ishlatiladi, ikkinchisi integratsiyaning turi. Qolgan hammasini keyin PATCH bilan o'zgartirasiz — faqat o'zgartirmoqchi bo'lgan maydonni yuboring, qolganlari joyida qoladi:
curl -s -X PATCH $AFAI_BASE_URL/api/v1/dev/apps/$APP_ID \
-H "X-Developer-Key: $AFAI_DEV_KEY" \
-H "Content-Type: application/json" \
-d '{"summary": "Yangi tavsif", "support_email": "siz@example.com"}'
| Maydon | Turi | Izoh |
name | matn | Marketplace'dagi nomi |
summary | matn | Bir qatorlik tavsif (kartada ko'rinadi) |
description | matn | To'liq tavsif |
logo_url | URL | Marketplace uchun majburiy |
privacy_url | URL | Maxfiylik siyosati — majburiy |
support_email | Qo'llab-quvvatlash — majburiy | |
homepage_url | URL | Sayt |
install_url | URL | Bot-agentlar uchun: t.me/... |
redirect_uris | ro'yxat | OAuth qaytish manzillari |
requested_scopes | ro'yxat | So'raladigan ruxsatlar (to'liq ro'yxat) |
Ro'yxat maydonlari (redirect_uris, requested_scopes) butunlay almashtiriladi, ustiga qo'shilmaydi — yangisini to'liq yuboring.
requested_scopes ni o'zgartirish mavjud o'rnatishlarga ta'sir qilmaydi: mijozda agent eski ruxsatlar bilan ishlab turaveradi, yangisi uchun u qayta rozilik berishi kerak. Manifestda e'lon qilingan scope shu ro'yxatdan oshib ketsa, versiya qabul qilinmaydi.
Javobda uchta sir keladi va ular boshqa hech qachon ko'rsatilmaydi:
{
"id": "app_248bc66cc7c2b71ff2f16564",
"client_id": "afai_076a491f3367de262807c9e899c7f008",
"client_secret": "afsec_IitDBFVdR6BNDeCAFiTIXx_udsic25t7IpQelrW5PDA",
"signing_secret": "agsec_4PabK8vUlqqCC3ICdiZzBjCuVYYFJkTJq6aHzATH6DE",
"status": "draft"
}
| Sir | Nima uchun | Kim ishlatadi |
client_id | Integratsiyaning ochiq kimligi | OAuth authorize |
client_secret | Token almashish | Sizning backend'ingiz |
signing_secret | Bizdan kelgan so'rov imzosini tekshirish | Sizning agentingiz (AFAI_AGENT_SECRET) |
export APP_ID=app_…
export CLIENT_ID=afai_…
export CLIENT_SECRET=afsec_…
export AFAI_AGENT_SECRET=agsec_…
status: "draft" — bu to'sqinlik emas. **Moderatsiya faqat marketplace
uchun kerak** (10-bo'lim). Draft agentni o'zingizga hoziroq o'rnatib
sinashingiz mumkin; o'rnatish ekranida shunchaki ogohlantirish chiqadi.
pip install httpx uvicorn
pip install https://agentfather.uz/sdk/afai-sdk.tar.gz
AFAI jamoasi ichida ishlayotgan bo'lsangiz SDK repoda turadi:
pip install -e platform/sdk/python.
SDK sizning o'rningizga to'rt ishni qiladi: imzoni tekshiradi, callback tokenini ulaydi, qadamlarni yozadi, xatoni platforma tushunadigan formatga o'giradi. Siz faqat mantiqni yozasiz.
main.py — to'liq kalkulyator
from afai_sdk import Agent
agent = Agent() # AFAI_AGENT_SECRET ni muhitdan oladi
AMALLAR = {
"+": lambda a, b: a + b,
"-": lambda a, b: a - b,
"*": lambda a, b: a * b,
"/": lambda a, b: a / b,
}
@agent.on_run
async def handle(run):
"""Har bir `run.execute` shu funksiyaga tushadi."""
a = run.input.get("a")
b = run.input.get("b")
op = run.input.get("op", "+")
if a is None or b is None:
raise ValueError("`a` va `b` majburiy")
if op not in AMALLAR:
raise ValueError(f"`{op}` — noma'lum amal")
if op == "/" and b == 0:
raise ValueError("Nolga bo'lib bo'lmaydi")
await run.say(f"Hisoblayapman: {a} {op} {b}")
natija = AMALLAR[op](a, b)
await run.step("compute", name="calculator",
input={"a": a, "b": b, "op": op},
output={"result": natija})
await run.say(f"Javob: {natija}")
return {"result": natija, "expression": f"{a} {op} {b}"}
app = agent.asgi()
Nima bo'lyapti:
| Qator | Ma'nosi |
Agent() | AFAI_AGENT_SECRET ni muhitdan oladi va har bir so'rov imzosini tekshiradi |
@agent.on_run | Har bir ish shu funksiyaga tushadi |
run.input | POST /api/v1/runs da yuborilgan input |
run.settings | Mijoz kiritgan sozlamalar (manifestdagi config) |
run.scopes | Mijoz bergan ruxsatlar |
run.say(...) | Odamga ko'rinadigan xabar |
run.step(...) | Texnik qadam — ish tafsilotida ko'rinadi |
raise ... | Ish failed bo'ladi, xato matni mijozga ko'rinadi |
return {...} | Ishning output i |
agent.asgi() | Toza ASGI ilova — uvicorn shuni ko'taradi |
Eng ko'p uchraydigan xato: Agent(client_secret) deb yozish. Agentga
signing_secret(agsec_…) kerak,client_secret(afsec_…) emas.
Chalkashtirsangiz har bir so'rov 401 invalid_signature bo'ladi.
export AFAI_AGENT_SECRET=agsec_… # 4.2 dan
uvicorn main:app --port 8200 # `main.py` turgan katalogda
INFO: Uvicorn running on http://127.0.0.1:8200 (Press CTRL+C to quit)
Diqqat: hozir hech nima bo'lmaydi va bo'lishi ham kerak emas. Agent —
passiv server, u kutadi. Unga so'rov faqat 8-bo'limda keladi. Agar shu
yerda «nega loglar bo'sh» deb to'xtab qolsangiz — hammasi to'g'ri ketyapti.
agentfather.uz ga qarshi ishlayotgan bo'lsangiz, shu yerda tunnelni ham oching (3-bo'lim A) va chiqqan https://… manzilni yozib qo'ying.
Manifest — agentingiz qayerda turishini va nima qila olishini aytadi. Aynan shu yerda ikkinchi URL (runtime.endpoint) beriladi.
afai.agent.jsonAgentingiz yonida turadigan oddiy JSON fayl:
{
"manifest_version": 1,
"id": "afai.calculator",
"version": "1.0.0",
"name": { "uz": "Kalkulyator", "en": "Calculator" },
"summary": {
"uz": "Ikki sonni qo'shadi, ayiradi, ko'paytiradi yoki bo'ladi",
"en": "Adds, subtracts, multiplies or divides two numbers"
},
"categories": ["namuna"],
"runtime": {
"type": "webhook",
"endpoint": "https://random-words-1234.trycloudflare.com",
"timeout_ms": 30000
},
"scopes": ["runs:write"],
"triggers": [{ "type": "manual" }]
}
endpoint— shu yerda.agentfather.uzda: tunnel yoki serveringiz
berganhttps://…. Lokal platformada:http://localhost:8200.
To'liq maydonlar ro'yxati: MANIFEST.md.
curl -s -X POST $AFAI_BASE_URL/api/v1/dev/manifest/validate \
-H "Content-Type: application/json" \
-d @afai.agent.json
{ "valid": true, "errors": [], "summary": "Manifest yaroqli" }
Bu endpoint hisobsiz ishlaydi — kalit ham kerak emas, shuning uchun CI'ga qo'yish oson. Xato bo'lsa har biri path, message va fix bilan qaytadi. Portalda esa «Versiyalar» bo'limidagi «Tekshirish» tugmasi shuni chaqiradi.
curl -s -X POST $AFAI_BASE_URL/api/v1/dev/apps/$APP_ID/versions \
-H "X-Developer-Key: $AFAI_DEV_KEY" \
-H "Content-Type: application/json" \
-d "{\"version\":\"1.0.0\",\"manifest\":$(cat afai.agent.json)}"
{
"id": "ver_59f4255797d2b8d4d394907b",
"version": "1.0.0",
"status": "draft",
"is_current": true,
"message": "Versiya joriy qilindi"
}
is_current: true — birinchi versiya avtomatik joriy bo'ladi. Keyingi versiyalarni POST /versions/{id}/promote bilan joriy qilasiz.
Manifest e'lon qilingandan keyin agentni bitta so'rov bilan sinash mumkin. O'rnatish ham, token ham kerak emas:
curl -s -X POST $AFAI_BASE_URL/api/v1/dev/apps/$APP_ID/test-run \
-H "X-Developer-Key: $AFAI_DEV_KEY" \
-H "Content-Type: application/json" \
-d '{"input": {"a": 12, "b": 5, "op": "+"}}'
{
"agent": { "version": "1.0.0", "runtime_type": "webhook",
"endpoint": "https://sizning-agent.uz" },
"run": { "status": "succeeded", "duration_ms": 41,
"output": { "result": 17, "expression": "12 + 5" } }
}
Platforma agentingizni o'z sandbox tashkilotingizga o'rnatib, bitta haqiqiy ish yuboradi: o'sha imzo, o'sha qadamlar, o'sha xatolar. Ya'ni bu yerda ishlagan narsa mijozda ham ishlaydi.
Agent yiqilsa javob baribir 200 bo'ladi, ichida status: "failed" va error_code — «sinov yashil» bo'lib qolmaydi. agent.endpoint esa so'rov aynan qayerga ketganini ko'rsatadi.
Kodni o'zgartirsangiz — agentni qayta ishga tushiring va shu
buyruqni yana yuboring. Manifestni o'zgartirsangiz — avval yangi
versiya e'lon qiling (6.3), sinov ishi doim eng yangi manifestni oladi.
test-run da ishni platforma yaratadi. O'z kodingizdan (SDK, navbat, qayta urinish) yaratishni sinash uchun access_token kerak:
curl -s -X POST $AFAI_BASE_URL/api/v1/dev/apps/$APP_ID/sandbox-token \
-H "X-Developer-Key: $AFAI_DEV_KEY"
{ "access_token": "eyJ…", "expires_in": 7200, "installation_id": "ins_…",
"workspace_id": "ws_…", "agent_version": "1.0.0" }
export ACCESS_TOKEN=eyJ…
curl -s -X POST $AFAI_BASE_URL/api/v1/runs \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"input": {"a": 12, "b": 5, "op": "+"}}'
Token o'z sinov tashkilotingiz uchun, lekin oddiy token: o'sha imzo, o'sha scope'lar. Ya'ni shu bilan yozilgan kod mijoz tokenida ham o'zgarishsiz ishlaydi.
Portalda tugma bor. agentfather.uz/portal/ → agent → «Sinov»:
«Sinab ko'rish» (6.4) va «Sinov tokeni» (6.5) shu yerda, natija va
qadamlar ekranda ko'rinadi. Buyruq qatori faqat CI uchun kerak.
Quyidagi 7-bo'lim — mijoz qanday o'rnatishi. Uni agentingiz ishlab turganini ko'rganingizdan keyin o'qing: mijoz o'rnatishi sizning sinovingiz uchun kerak emas.
Bu bo'lim bitta oqim, ikki qadam bo'lib yozilgan. Ular ikki xil joyda bajariladi va shuning uchun alohida ko'rinadi:
7.1 mijoz brauzerida 7.3 sizning serveringizda
/oauth/authorize → /oauth/token
(rozilik ekrani) ← code + code_verifier → access_token
│
└── rozilikdan keyin brauzer sizning `redirect_uri` ingizga
`?code=…` bilan qaytadi — 7.3 aynan shu yerdan boshlanadi
Ya'ni 7.3 ni «alohida qilish» shart emas: u sizning /oauth/callback marshrutingizning ichida bo'ladi. Qo'lda sinaganda esa o'sha marshrutning o'rnida siz turasiz — kodni brauzer manzilidan nusxalab olasiz.
redirect_uri ikkala qadamda ham bitta bo'lishi shart (yoki ikkalasida ham yozilmaydi — yuqoridagi izohga qarang). Kodda uni bitta konstanta qiling. Tayyor namuna — /install va /oauth/callback, 60 qator:
curl -O https://agentfather.uz/sdk/examples/callback.py
Barcha namunalar: GET /sdk/examples (main.py, callback.py, install.py, afai.agent.json).
Bu bo'lim sizning sinovingiz uchun emas. O'z agentingizni sinash
uchun 6.4 va 6.5 yetarli. Bu yerda yozilgani — boshqa odam sizning
agentingizni o'z tashkilotiga qanday qo'shishi, ya'ni mahsulotga
chiqqanda kerak bo'ladigan qism.
Mijoz uchun bu qadamsiz hech qanday ish yaratib bo'lmaydi: POST /api/v1/runs o'rnatishga tegishli access_token talab qiladi.
agentfather.uz da — brauzer orqaliPKCE juftligini yarating:
python - <<'PY'
import base64, hashlib, secrets
v = base64.urlsafe_b64encode(secrets.token_bytes(48)).rstrip(b"=").decode()
c = base64.urlsafe_b64encode(hashlib.sha256(v.encode()).digest()).rstrip(b"=").decode()
print("VERIFIER: ", v)
print("CHALLENGE:", c)
PY
verifier ni saqlang — 7.3 da kerak.
Kim nimani yasaydi (bu yerda eng ko'p chalkashlik bo'ladi):
| Qiymat | Kim yasaydi | Kim ko'radi |
code_verifier | siz — tasodifiy satr | faqat siz. Hech qayerga chiqmaydi, /oauth/token da bir marta yuboriladi |
code_challenge | siz — BASE64URL(SHA256(verifier)) | authorize havolasida ochiq ketadi |
code | platforma — mijoz «Ruxsat berish» ni bosgandan keyin | brauzer sizning redirect_uri ingizga ?code=… bilan qaytaradi |
Ya'ni code ni o'zingiz o'ylab topmaysiz: u rozilikdan keyin tug'iladi, 10 daqiqa yashaydi va bir marta ishlatiladi. Nega bunday: challenge ochiq ketadi, verifier esa sizda qoladi — kodni yo'lda ushlab olgan odam uni tokenga almashtira olmaydi (PKCE, RFC 7636).
Rozilik havolasini oching:
redirect_uri ni yozmasangiz ham bo'ladi. Integratsiyada bitta
manzil ro'yxatdan o'tgan bo'lsa, platforma o'shani oladi — authorize'da
ham, token almashuvida ham. Shunda ikki joyda ikki xil satr yozib
qo'yish holati umuman bo'lmaydi (RFC 6749 §3.1.2.3). Bir nechta manzil
ro'yxatdan o'tgan bo'lsa — qaysi biri ekanini aytish kerak.
Xohlasangiz aniq yozasiz:
# App'dagi `redirect_uris` dan aynan bittasi.
export REDIRECT_URI=https://sizning-agent.uz/oauth/callback
https://agentfather.uz/oauth/authorize
?client_id=$CLIENT_ID
&redirect_uri=$REDIRECT_URI
&scope=runs:write
&code_challenge=$CHALLENGE
&code_challenge_method=S256
&response_type=code
Havolani brauzerda oching. Nima bo'ladi:
1. brauzer rozilik sahifasiga o'tadi; sessiya bo'lmasa AFAI sizni kirish sahifasiga yuboradi va so'rovni next ichida saqlab qoladi; 2. kirish sahifasida Telegram tugmasi bor (Login Widget) — telefon raqami va Telegram tasdiqi orqali kirasiz. AFAI hisobi Telegram akkauntiga bog'langan, alohida parol yo'q; 3. kirgach brauzer avtomatik rozilik ekraniga qaytadi — scope'lar, ogohlantirishlar va «Ruxsat berish» shu yerda.
Nega Telegram orqali. Mijoz hisobi Telegram akkauntiga bog'langan,
shuning uchun sessiyani ham Telegram beradi: ilova ichida initData,
brauzerda Login Widget (docs/BOT.md §3.1.1). Parol bilan kirish yo'q —
ataylab.
Telefonda osonroq. Kirish sahifasida ikkinchi havola ham bor —
«Telegram ilovasida davom etish». U qurilmangizdagi Telegram'ni ochadi
va bot rozilik ekranini ilovada ko'rsatadi (?start=oauth_<nonce>).
redirect_uri sifatida o'zingiz boshqaradigan haqiqiy HTTPS manzil
bering: telefondagi Telegram sizning noutbukingizdagi localhost ga
chiqa olmaydi.
Roziliktan keyin brauzer redirect_uri ga qaytadi va URL'da ?code=… bo'ladi. Mana shu yerda redirect_uri ishlatildi — 2.1-bo'limda aytilgani.
Sinash uchun bu bo'lim kerak emas. O'z agentingizni sinashda 6.4 va
6.5 dan foydalanasiz — u yerda na PKCE, na console token, na brauzer
qatnashadi. Quyidagi qadamlar mahsulotga chiqqanda kerak: ularni
sizning/installva/oauth/callbackmarshrutlaringiz bajaradi.
Bu yo'l faqat o'z platformangizda ishlaydi: prodda CONSOLE_AUTO_PROVISION=false va sessiya tashqaridan ochilmaydi (ataylab — mijoz sessiyasi faqat AFAI ilovasi orqali beriladi).
curl -s -X POST $AFAI_BASE_URL/console/session \
-H "Content-Type: application/json" \
-d '{"email":"siz@example.uz","name":"Ismingiz","workspace":"Sinov MChJ"}'
Emailni ro'yxatdan o'tgan email bilan bir xil qiling. Shunda sessiya
to'g'ridan-to'g'ri sizning sinov tashkilotingizga tushadi — javobdagi
workspace_id4.1 dagisandbox_workspace_idbilan bir xil bo'lishi
kerak. Boshqa email bersangiz, boshqa tashkilot ochiladi va agentingiz
u yerda ko'rinmaydi.
{ "token": "eyJhbGciOi…", "workspace_id": "ws_3a417b0961a340285243d550", "role": "owner" }
export CONSOLE_TOKEN=eyJ…
Rozilik:
curl -s -X POST $AFAI_BASE_URL/oauth/consent \
-H "Authorization: Bearer $CONSOLE_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"client_id\":\"$CLIENT_ID\",
\"redirect_uri\":\"http://localhost:8080/oauth/callback\",
\"scope\":\"runs:write\",
\"code_challenge\":\"$CHALLENGE\",
\"approved\":true}"
{ "redirect_url": "http://localhost:8080/oauth/callback?code=XLZPuwd4hJm5N4mk…", "approved": true }
code ni javobdan qo'lda olasiz — brauzer kerak emas.
code → access_tokenIkki manzil bor, ikkalasi bir xil ishlaydi — qaysi biri qulay bo'lsa:
| Manzil | Tana turi | Qachon |
POST /oauth/token | application/x-www-form-urlencoded | curl, SDK, RFC 6749 talabi |
POST /oauth/token.json | application/json | Postman va JSON bilan ishlaydiganlar uchun |
Maydonlar — oltitasi ham majburiy va hech biri token emas (Authorization sarlavhasi bu so'rovda yo'q: access token aynan shu so'rovdan keyin paydo bo'ladi):
| Maydon | Nima | Qayerdan olasiz |
grant_type | doim authorization_code | — |
client_id | integratsiyaning ochiq kimligi | GET /api/v1/dev/apps/{id} |
client_secret | afsec_… | app yaratilganda bir marta; yo'qolsa POST /apps/{id}/rotate-secret |
code | bir martalik kod | callback manzilidagi ?code= dan keyin, & gacha |
code_verifier | PKCE juftining maxfiy yarmi | 7.1 da yasagansiz (challenge emas!) |
redirect_uri | authorize'dagi aynan o'sha manzil | app'dagi redirect_uris dan |
curl -s -X POST $AFAI_BASE_URL/oauth/token \
-d grant_type=authorization_code \
-d client_id=$CLIENT_ID \
-d client_secret=$CLIENT_SECRET \
-d code=$CODE \
-d code_verifier=$VERIFIER \
-d redirect_uri=$REDIRECT_URI
Xuddi shu narsa JSON bilan:
curl -s -X POST $AFAI_BASE_URL/oauth/token.json \
-H "Content-Type: application/json" \
-d "{\"grant_type\":\"authorization_code\",
\"client_id\":\"$CLIENT_ID\",
\"client_secret\":\"$CLIENT_SECRET\",
\"code\":\"$CODE\",
\"code_verifier\":\"$VERIFIER\",
\"redirect_uri\":\"$REDIRECT_URI\"}"
**redirect_uri bu yerda ham kerak va authorize'dagi bilan
belgi-belgisiga bir xil bo'lishi shart** (RFC 7636 talabi: kodni
o'g'irlagan odam uni boshqa manzilga almashtira olmasin). Farq qilsa
invalid_grant: redirect_uri avtorizatsiyadagidan farq qiladi keladi —
javobning details maydonida ikkala qiymat ham turadi
(expectedvareceived), ya'ni farqni taxmin qilish shart emas.
Eng ko'p uchraydigan to'rttasi:
1. brauzer manzil qatoridan to'liq URL nusxalanadi — ?code=… qismi
bilan. redirect_uri da so'rov qismi bo'lmaydi;
2. oxiridagi/—…/callback/boshqa satr hisoblanadi;
3. maydonlar Postman'da Params (query) ga yoziladi — ular tanaga
tushmaydi;Body → x-www-form-urlencodedyoki/oauth/token.json;
4. ikki tunnel manzili almashib ketadi: redirect_uri — mijoz brauzeri
qaytadigan manzil, runtime.endpoint — platforma ish yuboradigan
manzil. Bular boshqa-boshqa.
{
"access_token": "eyJhbGciOi…",
"token_type": "Bearer",
"expires_in": 7200,
"refresh_token": "vBaZ_xpx5ehGlfFuY3DH971bLZ6cFjSm…",
"scope": "runs:write workspace:read",
"installation_id": "ins_6352156e70a8179c5149f00d",
"workspace_id": "ws_3a417b0961a340285243d550"
}
export ACCESS_TOKEN=eyJ…
Har bir yangilashda yangi refresh token keladi. Eskisini ikkinchi marta
ishlatsangiz, platforma buni o'g'irlik deb hisoblaydi va barcha tokenlarni
bekor qiladi. SDK buni o'zi to'g'ri bajaradi.
Endi hamma bo'lak joyida. So'rov yuboramiz:
curl -s -X POST $AFAI_BASE_URL/api/v1/runs \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"input": {"a": 12, "b": 5, "op": "+"}}'
{
"id": "run_42595a3a0cbdd6c5dd4b3c5d",
"status": "succeeded",
"input": { "a": 12, "b": 5, "op": "+" },
"output": { "result": 17, "expression": "12 + 5" },
"duration_ms": 41
}
Shu daqiqada agentingiz terminalida POST ko'rinadi. Zanjir yopildi:
curl → platforma → run yaratildi → run.execute (imzolangan) → agentingiz
→ natija → platforma → sizning javobingiz
curl -s $AFAI_BASE_URL/api/v1/runs/$RUN_ID \
-H "Authorization: Bearer $ACCESS_TOKEN" | jq '.steps'
[
{ "seq": 1, "type": "message", "output": { "text": "Hisoblayapman: 12 + 5" } },
{ "seq": 2, "type": "compute", "name": "calculator",
"input": { "a": 12, "b": 5, "op": "+" }, "output": { "result": 17 } },
{ "seq": 3, "type": "message", "output": { "text": "Javob: 17" } }
]
run.say va run.step yozganlaringiz aynan shu yerda ko'rinadi.
curl -s -X POST $AFAI_BASE_URL/api/v1/runs \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"input": {"a": 1, "b": 0, "op": "/"}}'
{ "status": "failed", "error_code": "ValueError", "error_message": "Nolga bo'lib bo'lmaydi" }
Kodingizdagi raise shunday ko'rinadi. Xato matni mijozga yetadi — shuning uchun uni odam tushunadigan qilib yozing.
Muammoni oxiridan boshiga qarab qidiring:
1. Ish umuman yaratildimi? POST /api/v1/runs javobidagi status ni qarang. failed bo'lsa error_code hamma narsani aytadi.
2. Platforma agentga chiqa oldimi?
curl -s $AFAI_BASE_URL/api/v1/dev/apps/$APP_ID/logs \
-H "X-Developer-Key: $AFAI_DEV_KEY"
3. Agent so'rovni oldimi? Agent terminalida POST qatorini qidiring. Bo'sh bo'lsa — so'rov unga yetmagan (jadvalning 1–3 qatorlari).
| Belgisi | Sabab | Yechim |
blocked_target: ichki manzil (::1) | endpoint da localhost, lekin platforma boshqa mashinada | agentfather.uz da: tunnel yoki server manzili. Lokalda: .env da ALLOW_PRIVATE_NETWORK_TARGETS=true |
blocked_target: faqat HTTPS qabul qilinadi | http:// endpoint | HTTPS bering (prodda majburiy) |
agent_unreachable | Agent 30 soniyada javob bermadi yoki o'chiq | Agentni ko'taring; uzoq ish bo'lsa run.defer() |
Agentda 401 invalid_signature | AFAI_AGENT_SECRET noto'g'ri yoki bo'sh | 4.2 dagi signing_secret (agsec_…). Yo'qotgan bo'lsangiz: POST /dev/apps/{id}/rotate-signing-secret |
| Agent loglari butunlay bo'sh | Hech kim ish yaratmagan | Bu xato emas. 6.4-bo'limdagi test-run ni yuboring |
unauthorized: Sessiya tokeni o'qib bo'lmadi | Dev kalitini Authorization ga qo'ygansiz | X-Developer-Key: dvk_… |
invalid_redirect_uri | Manzil ro'yxatdagidan farq qiladi | Harfma-harf bir xil bo'lsin |
invalid_grant: PKCE tekshiruvidan o'tmadi | Boshqa code_verifier | 7.1 dagi verifier ni saqlang |
insufficient_scope | Scope so'ralmagan yoki berilmagan | requested_scopes ga qo'shing va qayta o'rnating |
| Rozilik sahifasi «login» ga tashlaydi | Oddiy brauzerda ochgansiz | Havolani Telegram ichidan (@AgentFatherAI_bot → ilova) oching |
| Manifest o'zgardi, lekin eskisi ishlayapti | Yangi versiya joriy emas | POST /dev/apps/{id}/versions/{ver}/promote |
Yuqoridagi hammasi o'zingiz uchun ishladi. Agentni boshqa mijozlar ham yollashi uchun uni moderatsiyaga topshirasiz. Uchta maydon to'ldirilmasa ariza qabul qilinmaydi:
curl -s -X PATCH $AFAI_BASE_URL/api/v1/dev/apps/$APP_ID \
-H "X-Developer-Key: $AFAI_DEV_KEY" -H "Content-Type: application/json" \
-d '{"logo_url":"https://…/logo.png",
"privacy_url":"https://…/privacy",
"support_email":"siz@example.com"}'
curl -s -X POST $AFAI_BASE_URL/api/v1/dev/apps/$APP_ID/submit \
-H "X-Developer-Key: $AFAI_DEV_KEY"
# → {"status":"in_review","message":"Ariza qabul qilindi — moderatsiya 3 ish kunigacha."}
Yetishmagan narsa bo'lsa javob aynan nimaligini aytadi (review_requirements_missing → details.missing).
Moderatsiyadan o'tgach agent marketplace'da paydo bo'ladi va mijoz uni AgentFather ilovasidan yollaydi (Explore → «Install»).
Bitta tashkilotda bir nechta agent turadi va ular bir-biriga murojaat qila oladi. Bu alohida protokol emas — o'sha platforma tool'lari:
| Nima kerak | Tool | Kerakli scope |
| Boshqa agentga ish topshirish (natija keyin) | delegate_task | tasks:write |
| Boshqa agentdan javob so'rash (hozir) | ask_agent | runs:write |
| Hodisa chiqarish, kim eshitsa o'sha ushlaydi | emit_event | webhooks:manage |
Ikki narsani bilib qo'ying:
ask_agent faqat tools da e'lon qilingan tool'ni chaqira oladi — e'lon qilish «shu tashkilotdagi boshqa agentlar buni chaqirishi mumkin» degani.
bo'lmaydi, zanjir chuqurligi esa 3 bilan chegaralangan.
To'liq shartnoma, xavfsizlik qoidalari va misollar: agentfather.uz/docs/agents.
| Xohlasangiz | Qarang |
| Uzoq ishlar (SMS, indekslash, hisobot) | INTEGRATION.md → run.defer() |
| Boshqa agentlar bilan ishlash | INTEGRATION.md → delegate_task, ask_agent |
| Mijozdan sozlama olish (API kalit va h.k.) | MANIFEST.md → config |
| Hodisalarga obuna | WEBHOOKS.md |
| AFAI ichida o'z UI'ingiz | SURFACES.md |
| Kod yozmasdan agent | MANIFEST.md → runtime.type: "inline" |
| Agentni serverga qo'yish | docs/AGENT_DEPLOY.md |
| Marketplace qoidalari | MARKETPLACE.md |
| Xato kodlari to'liq ro'yxati | ERRORS.md |