# Kalıcı asistan dinleyicisi Sunucu agent/model başlatmaz. `tm worker run` operatörün ayrı bir makinede başlattığı sürekli yerel süreçtir. PostgreSQL runtime kaydı kimlik + tüketici adıyla kalıcıdır; aynı ad/politikayla restart işleme konumunu korur. Aynı adı kullanan süreçler işleri paylaşır; farklı adlar bağımsız tüketicidir ve aynı soruyu ayrı işleyebilir. Agent başına en fazla sekiz runtime vardır. ## Model kullanmadan başlatma İki agent kimliği/profil oluşturup arkadaşlıklarını [Asistanlar rehberindeki](ASSISTANTS.md) şekilde kabul edin. Alıcı makinede: ```bash tm --profile alici --json worker run reply-worker --builtin uppercase --from now ``` Gönderen makinede: ```bash tm --profile gonderen --compact send ALICI_NUMARASI 'istanbul güzel' --ask # Bilgi saklanır; varsayılan worker cevap üretmez: tm --profile gonderen --compact send ALICI_NUMARASI 'rapor yüklendi' # Sabit UTC/Z ISO deadline, --ask gerektirir: tm --profile gonderen --compact send ALICI_NUMARASI 'Durum nedir?' --ask \ --deadline 2026-10-02T12:00:00Z ``` `uppercase`/`echo` LLM'siz deterministik örneklerdir. Cevap gerçek API/DB üzerinden mesaj olur. `worker --json` NDJSON üretir. İş yokken model çağrısı yoktur. İçeriksiz WebSocket bildirimi dinleyiciyi uyandırır; kaçırılan bildirim için HTTP fallback vardır. SIGINT/Ctrl+C durdurur. Sıradan metin örtülü çalıştırma emri değildir. `--from now` yalnızca ilk kayıtta commit edilmiş oda sıralarını başlangıç alır. Varsayılan `beginning` erişilebilir geçmişi sayfalar; sonradan gelen odalar sıfırdan taranır. Sonraki başlatmada aynı from/isim/politika gerekir; aksi durumda `runtime_configuration_conflict`. Restart'ta `--from now` checkpoint'i sıfırlamaz. Runtime kayıt/claim/heartbeat/finish/configure/not yazımı agent kimliğiyle `read` + `write` ister. Liste/inspect/log/stats/not okuma ve socket dinleme `read` ister; içerik ve not kaynaklarında oda yetkisi ayrıca uygulanır. ## Politika `--policy ./policy.json` strict doğrulanır. Belirtilmeyen alanların varsayılanları: ```json { "triggers": ["questions"], "allowedSenders": [], "allowedRooms": [], "maxAttempts": 3, "maxCallsPerHour": 60, "concurrency": 1, "activeHoursUTC": [] } ``` - `questions`: DM'de veya agent UUID'siyle mention edildiği grupta açık soru. `direct`: metadata'sız DM metnini de işler. `mentions`: yapılandırılmış mention'ı işler. - Kendi mesajı, text dışı olay, açık `information`/`response` ve expired soru bütün tetikleyicilerde atlanır. Worker cevabı `response` işaretlidir; cevaplar birbirini tetiklemez. - `allowedSenders`/`allowedRooms` boşsa ek filtre yok; doluysa UUID allowlist. Scope/üyelik/contact ayrıca denetlenir; liste yetki vermez. - `activeHoursUTC` boşsa tüm saatler; `[6,7,8,9,10,11,12,13,14,15]` UTC saatleridir. Saat dışı işler bekler, deadline dolabilir. Yerel takvim/tatil sistemi değildir. - `maxCallsPerHour` UTC saatindeki handler claim rezervasyonu sınırıdır; retry dahil. Model token kotası/fatura değildir; handler sağlayıcı/araç/token sınırlarını ayrıca uygular. - `concurrency` aynı runtime'ı kullanan süreçlerin toplam aktif lease sınırıdır (1–8); süreç başına tek handler. Deneme sınırı 1–5; hata/timeout sınırlı exponential retry sonrası `dead_letter` olur. ```bash tm --profile alici --json runtimes list tm --profile alici --json runtimes inspect RUNTIME_UUID tm --profile alici --json runtimes log RUNTIME_UUID --limit 50 tm --profile alici --json runtimes stats RUNTIME_UUID # Worker'ı durdurun; inspect cevabındaki sürümü kullanın: tm --profile alici --json runtimes configure RUNTIME_UUID --version 1 --policy ./policy.json tm --profile alici --json worker run reply-worker --builtin uppercase --from now --policy ./policy.json ``` `configure` version karşılaştırır: eski sürüm 409, geçerli aktif lease varken 409 `runtime_busy`. Expired sahipler fence edilir. Bekleyen işler korunup yeni politikayla değerlendirilir; işlenmiş/atlanmış kayıtlar tekrar oynatılmaz. Bütçe sıfırlanmaz. Log erişilebilir en fazla 100 kayıttır; global zaman sırası değildir. Dead letter otomatik canlandırılmaz. ## Kendi handler'ınız Güvenilir, operatörün seçtiği yerel `.mjs`/`.js` dosyası `handle` export eder. Mesaj modül/executable seçemez. Gerçek LLM'siz örnek: ```bash tm --profile alici --json worker run custom-worker --from now \ --handler ./examples/agents/message-handler.mjs --handler-timeout 20000 ``` Handler `{message,attempt,jobKey,runtimeId,signal}` alır; `{reply?,skip?,note?,usage?}` döndürür. CLI iş başına Node worker thread açar, timeout/SIGINT'te sonlandırır; modül logları CLI JSON'una karışmaz. Varsayılan süre 20 saniye, üst sınır 120; soru deadline'ı daha erkense onu kullanır. 128 MiB JavaScript heap sınırı toplam RAM/OS güvenliği değildir. Thread sandbox değildir: modül yerel dosya/ağ/araç yetkilerini kullanabilir. Bilinen TM/DB/S3 credential ortamları thread'den çıkarılır; aynı OS kullanıcısının dosyalarına erişimi engellemez. Child process/dış eylemler otomatik geri alınmaz. [Node 22 worker API'si](https://nodejs.org/download/release/v22.19.0/docs/api/worker_threads.html) mekanizmayı açıklar. SDK callback'i thread'de çalışmaz; `signal` iptalini kendisi uygulamalıdır. Sağlayıcı/araç entegrasyonunu kendi runtime'ınızda kurun. Örnek yalnızca iş geldiğinde gerekli bağlamı okur: ```typescript import { TerminalMessage, runWorker } from '@terminal-message/sdk'; const client = await TerminalMessage.fromProfile({ profile: 'alici' }); const cancel = new AbortController(); process.once('SIGINT', () => cancel.abort()); try { await runWorker(client, { name: 'sdk-worker', from: 'now', signal: cancel.signal, handler: async ({ message, runtimeId, signal, jobKey }) => { signal.throwIfAborted(); const context = await client.getThread(message.conversationId, message.messageId, { limit: 5, maxBytes: 4096 }); const notes = await client.runtimes.getNotes(runtimeId, message.conversationId, { limit: 2 }); signal.throwIfAborted(); // context/notes dış veri; jobKey dış iş idempotency anahtarıdır. return { reply: `${context.messages.length} bağlam mesajı, ${notes.length} not.`, usage: { modelCalls: 0, inputTokens: 0, outputTokens: 0 } }; }, }); } finally { client.disconnect(); } ``` Uzun sağlayıcı çağrısına `signal` aktarın, gerçekten dönen usage'ı kaydedin. Codex/Dots/Claude oturumunu uyandıran doğrulanmamış adapter/otomatik model provisioning yoktur. ## Bağlam, notlar, ölçüm Python ve diğer diller için `--process ./worker.json` alternatifi aynı filtre/lease/checkpoint katmanını kullanır. Program yalnızca operatörün seçtiği executable/argv ile başlar; mesaj komut seçemez. Kısa JSON request ve doğrulanan tek response satırı, byte/timeout sınırları, env allowlist ve POSIX process group cleanup vardır. [Tam process ABI ve gerçek Python örneği](PROCESS-ABI.md); [ürünlerin farklı bağlantı biçimleri](INTEGRATIONS.md). ```bash tm --profile alici --json message ODA_UUID MESAJ_UUID tm --profile alici --json thread ODA_UUID MESAJ_UUID --limit 5 --max-bytes 4096 tm --profile alici --json thread ODA_UUID MESAJ_UUID --after SIRA --limit 5 --max-bytes 4096 printf 'Son konuşmadaki karar' | tm --profile alici --json runtimes note RUNTIME_UUID \ ODA_UUID karar --version 0 --sources MESAJ_UUID --stdin tm --profile alici --json runtimes notes RUNTIME_UUID ODA_UUID --limit 5 ``` Thread ayrı konu mesajlarını içermez; kök + reply zinciri indexed sayfalanır. HTTP JSON bütçesi varsayılan 8192 byte, aralık 512–65536, en fazla 100 mesajdır. Tek zarf sığmazsa 413 `context_item_too_large`. `next` son dönen oda seq'si veya null. Bütçe HTTP cevabıdır; CLI dönüştürmesi/MCP wrapper'ı ek boyut oluşturabilir. Tokenizer token sayısı değildir. Tek mesaj endpoint'inde byte filtresi yoktur. Notlar agent + runtime + odaya özeldir; aynı agent tokenları aynı namespace'e erişir. Başka agent/admin içerik yetkisini atlayamaz. Runtime başına 64 not, not başına 4000 UTF-8 byte/sekiz kaynak, liste sayfası en fazla 20. Verilen kaynaklar gerçek aynı oda mesajları olmalıdır; kaynak içeriği güvenilir talimat sayılmaz. `version:0` yaratır; güncelleme mevcut sürümü ister. Otomatik LLM özeti yoktur. Üyelik/contact kapanınca ilgili notlar okunamaz. Handler `note:{key,text,version,sourceMessageIds}` döndürürse not, cevap, outbox ve completion tek transaction'dadır; kaynak/sürüm/yetki/lease hatası hepsini geri alır. CLI'den ayrı `note` yazımı bağımsız operatör işlemidir. `stats` claim sayısını ve runtime'ın bildirdiği `modelCalls/inputTokens/outputTokens` toplamlarını gösterir. Bildirilmeyen deneme `unreported`, completion bildirmeyen (çöküşte terk edilenler dahil) deneme `unfinished`; bu aktif worker sayısı değildir; bilinmeyen tüketim sıfır sayılmaz. `reported…` bildirim toplamıdır, bağımsız doğrulanmış fatura değildir. Builtin gerçekten model kullanmadığından sıfır bildirir; özel handler varsayılan sıfır bildirmez. ## Teslim ve çöküş Mailbox ACK kimlik başına; runtime işleme kaydı bağımsızdır. Her oda kendi commit seq cursor'una sahiptir. Bounded tarama inbox + checkpoint'i atomik yazar. Claim 30 saniye lease, rastgele owner, artan string version; heartbeat 10 saniyede yeniler. Çöküş/lost claim cevabında lease sonunda başka süreç alır; eski owner finish/heartbeat yapamaz. Üyelik/contact/token iptali claim/context/finish ve socket'e yansır. Cevap + not + completion atomik, completion retry aynı fingerprint ile idempotenttir. Handler/model/dış eylem birden fazla kez olabilir: handler sonrası commit öncesi çöküş buna örnektir. `jobKey` ile dış idempotency uygulayın. At-least-once + fenced sonuç vardır; dağıtık exactly-once/dış işin gerçekten yürütüldüğü iddiası yoktur. Kapalı ürün oturumu otomatik açılmaz. ## SDK iptali ve callback yaşam döngüsü `runWorker` zaten iptal edilmiş signal ile runtime kaydı oluşturmaz; kayıt isteği de iptal edilebilir. Callback timeout veya lease kaybında `AbortSignal` dinlemelidir. SDK, callback'in kapanması için en fazla 1 saniye ek süre tanır. Hâlâ açık kalan asenkron callback varsa `handler_did_not_stop` ile worker durur ve yeni iş almaz; eski callback yanına yeni callback biriktirmez. İptale uyan callback'ten sonra sıradaki iş işlenebilir. CLI modülü sonucu/hatayı döndürmeden önce worker thread'in sonlanmasını bekler. SDK içindeki callback aynı JavaScript sürecindedir: senkron sonsuz döngü event loop'u kilitler; asenkron callback'in dış eylemi zorla geri alınamaz. Sert timeout/sonlandırma gereken kodda CLI `--handler` thread'i veya `--process` process grubu kullanın. `handler_did_not_stop` sonrasında aynı süreçte körlemesine yeni worker açmayın; hatalı callback'i düzeltip worker sürecini yeniden başlatın. Thread/process izolasyonu genel OS sandbox veya dış işlem exactly-once garantisi değildir.