Dokümantasyon / Geliştirici modu
Python worker'ı
Her ajanın bir Python ortamı var ve orada çalışan kodu bir model yazıyor. Bu sayfada o kodu çalıştıran worker süreci, sınırları, kodun neleri göremediği, nereye yazamadığı ve ulaşmak istediği host'ların nasıl değerlendirildiği anlatılıyor.
Her uzmana bir worker
Skill'ler ekrana çıktı basan kod olarak yazılır, run_python da basılan çıktıyı geri döndürür. Kod bir worker'da çalışır. Worker, aynı yorumlayıcıyı ve paketleri kullanan ayrı bir Python sürecidir. ivralo onu ilk çağrıda başlatır ve uzman yaşadığı sürece açık tutar. Değişkenler çağrılar arasında korunur; bir kez yüklediğiniz DataFrame yüklü kalır. Çalışma klasörü, çalışma alanının kendisidir.
| Ayar | Varsayılan | Etkisi |
|---|---|---|
IVRALO_PYTHON_TIMEOUT | 300 | Bir çağrının kaç saniye çalışabileceği; süre dolunca worker öldürülür |
IVRALO_PYTHON_MAX_MB | 4096 | Worker'ın kullanabileceği bellek; 0 sınırı kaldırır |
IVRALO_PYTHON_ISOLATION | process | inline kodu ivralo'nun kendi sürecinde çalıştırır; sınır da ağ koruması da kalmaz |
Süreyi aşan bir çağrı, başlattığı bütün süreçlerle birlikte öldürülür ve modele eski değişkenlerinin silindiği bildirilir. Oturumda Esc'ye basmak aynı işi anında yapar. Sonraki çağrı yeni bir worker ile başlar. Bir uzmanın çağrıları sırayla çalışır, iki çağrı hiçbir zaman aynı worker'ı paylaşmaz.
Bellek sınırı süreci öldürmez, yalnızca sınırlar: sınır aşılınca kodun içindeki bellek ayırma işlemi MemoryError ile başarısız olur. Bu hata traceback olarak geri gelir, oturum açık kalır. Linux'ta sınırı RLIMIT_DATA, Windows'ta bir Job Object koyar; makinenizde hangisinin devrede olduğunu ivralo doctor gösterir.
ivralo kapanınca geride hiçbir şey kalmaz: ivralo girdiyi kapattığında worker çıkar, Linux worker'a parent-death sinyali gönderir, Windows'ta da Job Object bütün süreç ağacını sonlandırır. Worker başlayamazsa hataları .ivralo/python-worker.log dosyasında bulursunuz.
Oturumda her run_python çağrısı, çalışmadan önce kodunu onay diyaloğunda gösterir (Düzenleme ve onaylar). Başında kimsenin olmadığı bir çalıştırmada ise diyalog açılmaz; kod bu sınırların içinde doğrudan çalışır.
Kodun göremedikleri
Worker'ın ortamında hiçbir kimlik bilgisi bulunmaz. ivralo worker'ı başlatmadan önce şu değişkenleri siler: adı _KEY, _TOKEN ya da _SECRET ile biten veya içinde PASSWORD, SECRET ya da WEBHOOK geçen her değişken, ivralo'nun kendi veritabanı URL'si, IVRALO_SQL_URL ve databases.json içinde bir veritabanı için adı geçen her değişken. Worker .env'i yükledikten sonra bunları bir kez daha siler. print(os.environ) çalıştırsanız hiçbiri görünmez.
Kimlik bilgisi gerektiren çağrıyı, o bilgiye sahip tek taraf olan ivralo yapar. Buna credential broker diyoruz: kod isteğini worker'ın pipe'ından iletir, ivralo cevabı verir. Bu yolla iki tür çağrı yapılabilir:
| Tür | Worker'ın içinde | ivralo ne yapar |
|---|---|---|
| Veritabanlarınız | query_database, list_tables, describe_table, list_databases | Sorguyu kendi salt okunur bağlantısında çalıştırır, satırları DataFrame olarak döndürür; tek cevapta en fazla 10.000 satır ve 8 MB |
| Stok fotoğraflar | search_photos, save_photo, photos_status | Unsplash'e IVRALO_UNSPLASH_ACCESS_KEY ile istek atar, görseli yazma korumasının kurallarına göre kaydeder |
Yetkileri bu türlerden birini kapsamayan uzmanın isteği, eksik yetkinin adı verilerek reddedilir. ivralo üzerinden yapılan her çağrı kayda geçer. Kayıtta kimlik bilgisinin değeri değil, yalnızca adı yer alır. Bu satır kodun çıktısından sonra gelir ve saklanan çalıştırmada durur:
[ivralo answered this code's calls: photos.search with IVRALO_UNSPLASH_ACCESS_KEY (1 call, 0.4s)]
.env dosyası nerede olursa olsun okunamaz. .ivralo/ ya da .git/ klasörünü açmak veya listelemek de, büyük-küçük harf nasıl yazılırsa yazılsın, reddedilir. Bunların dışındaki her okuma serbesttir.
Yazma koruması
Yazma koruması open'ı ve onunla birlikte kullanılan dosya çağrılarını (os.replace, os.rename, os.remove, shutil.copy, shutil.move, shutil.rmtree, Path.unlink ve diğerleri) sarar. Çalışma alanının dışına yazılmaya izin verilmez. Üzerine yazılacak bir dosya ise önce ivralo'nun geçmişine kopyalanır.
Bazı yollara çalışma alanının içinde bile yazılamaz:
.ivralo/(geçmiş, planlar, değişiklik kayıtları, repo'nunpermissions.json'ı); yalnızca geçmişin kendi snapshot'ları istisnadır;.git/, çünkü bir hook ya daconfigdeğişikliği daha sonra hiçbir diyalog açılmadan çalışır;- ana dizin çalışma alanının kendisiyse ivralo'nun kendi ayarları:
permissions.json,databases.json,mcp.json,schedules.json, Google token'ı, ivralo'nun okuduğu.envdosyaları ve yerel skill rafıskills.local/'un tamamı.
İzin dosyası da skill'in frontmatter'ı da birer yetkidir. Bunlara yazabilen bir kod, kendisine sonradan sorulacak soruları ortadan kaldırabilir. Ret mesajı kapalı olan yolu söyler ve koddan başka bir yol aramak yerine durumu kullanıcıya bildirmesini ister.
Ana ajanın ve Code Engineer'ın Python'u yalnızca okuma yapar. Onlar için her türlü yazma, çalışma alanının içinde bile reddedilir ve ret mesajı onları edit_file ile write_file'a yönlendirir. Böylece "her düzenleme gösterilir ve onaylanır" kuralı bir söz olmaktan çıkıp programın kendisine yerleşir: diyaloğu atlayan bir yol yoktur. Okuma, import ve hesaplama bundan etkilenmez.
Güvenmediğiniz bir klasör
Güvenmediğiniz bir klasörde worker, o klasörün kendi kodunu import etmez. Çalışma alanı ve çalışma klasörü sys.path'ten çıkarılır. Çalışma alanındaki bir modül için import app yazılırsa hata mesajı güven kapısını ve ivralo trust komutunu anar; model de etrafından dolaşmaya çalışmak yerine durur. Standart kütüphane, kurulu paketler ve ivralo'nun kendi modülleri import edilmeye devam eder; çalışma alanındaki bir dosyayı open() ile açmak da çalışır. Güvendiğiniz bir klasörde hiçbir şey değişmez.
Worker hiçbir zaman bytecode yazmaz. Bu yüzden run_python repo'nuzda __pycache__ bırakmaz.
Ağ koruması
Kodun ulaşmak istediği her host'u önce ivralo değerlendirir. Kullanılan egress politikası, shell'i ve web araçlarını yöneten politikanın aynısıdır (Shell komutları). Worker'ın içinde socket modülünün yaptığı ad sorguları ve bağlantılar ivralo'nun sürecine sorulur. Listelerinizde olmayan bir host için soru, daha hiçbir sorgu yapılmadan sorulur. Böylece reddedilen bir ad hiçbir yere, DNS'e bile gitmez.
| Host | Karar |
|---|---|
| Link-local, bulut metadata, multicast ya da ayrılmış adresler, çözümlenemeyen bir ad | Listeleriniz ne derse desin hiçbir zaman ulaşılmaz |
hosts.deny içinde | Reddedilir |
İki izin dosyasından birinde hosts.allow içinde | İzin verilir |
| Loopback, özel bir adres, yerel bir ad ya da hiçbir listede olmayan bir host | Sorulur |
Worker sorduğunda oturumda "Code in run_python wants to reach api.example.com" mesajı üç seçenekle çıkar: bu seferlik evet (o worker kapanana kadar geçerli), her zaman (repo'nun .ivralo/permissions.json'ına hosts.allow altında yazılır; yalnızca güvendiğiniz bir klasörde sunulur) ya da hayır. ivralo ask ya da bir zamanlama gibi başında kimsenin olmadığı durumlarda istek reddedilir. Cevap vermek için harcadığınız süre, çağrının zaman aşımına sayılmaz.
Ret, koda başarısız bir ad sorgusunun fırlattığı hata (socket.gaierror) olarak, ivralo'nun gerekçesiyle birlikte ulaşır. Böylece HTTP kütüphaneleri zaten bildikleri şekilde hata verir. Kodun denediği bütün host'lar sonucun altındaki satırda listelenir.