Dokümanlar menüsü
Uzak ajanlar (A2A)
Başka bir sunucuda koşan bir ajanı sıradan bir tool gibi çağırın — ağ üzerinden exactly-once, çünkü uzak taraf deterministik bir runId'yi tekrar oynatır.
Ne işe yarar#
createAgentTool yerel bir ajanı tool'a çevirir. createA2ATool aynısını başka bir sunucudaki ajan için yapar: o sunucunun REST ucuna POST atar ve cevabı tool sonucu olarak döner. Modelin açısından hiçbir fark yoktur.
Bunu bir HTTP çağrısından fazlası yapan şey runId'dir. Çağrıdan deterministik olarak türetilir, yani tekrarlanan bir POST'un ikinci bir yan etkisi olmaz — uzak runDurable aynı çalıştırmayı tekrar oynatır ve kayıtlı sonucu döner. Tool bir ebeveyn runDurable'ın içindeyse ebeveyn de onu journal'lar: ebeveyn resume edildiğinde uzak çağrı tümden atlanır.
Bu, zincirdeki son sınırdır. Bir tool çağrısı, bir alt-ajan, bir ağ router'ı, kuyruğa alınmış bir iş, bir cron tetiklemesi ve şimdi de başka bir makineye yapılan çağrı — garanti her birinde geçerlidir.
Adım adım#
Uzak sunucuyu ve ajanı gösterin. Sonuç; cevap metnini, varsa kesintileri, uzak ajan adını ve uzak tarafın hangi runId altında tekrar oynattığını taşır — o son alan exactly-once tutamağıdır ve loglanmaya değer.
import { createA2ATool } from '@gnldev/a2a';
const research = createA2ATool({
endpoint: 'https://research.internal',
agentName: 'researcher',
timeoutMs: 30_000,
secret: process.env.A2A_SECRET, // opt-in HMAC signing
});
const res = await runDurable({
runId: 'brief-9',
journal,
model,
tools: { research },
prompt: 'Summarise the competitor landscape',
});
// the tool result carries the remote handle:
// { text, interrupts, runId: 'a2a:brief-9:call-3', remoteAgent: 'researcher' }runId nereden geliyor#
runDurable içinde sarmalayıcı, zaten ebeveyn çalıştırmaya kapsanmış bir idempotencyKey verir — {parentRunId}:{toolCallId}, args modunda {parentRunId}:{toolName}:{hash} — ve uzak runId bundan türetilir. Mesele tam da bu kapsamlamadır: küresel olarak benzersizdir.
Dayanıklı bağlam dışında böyle bir anahtar yoktur, o yüzden ham toolCallId kullanılır ve o yalnız tek bir çalıştırma içinde benzersizdir. Bazı sağlayıcılar call_1 gibi kısa kimlikler üretir; ilgisiz iki çalıştırma aynısını üretebilir ve o zaman uzak taraf ikinci çağrı için birinci çalıştırmanın kayıtlı cevabını tekrar oynatır. Bu tool'a runDurable üzerinden ulaşmak bunu engeller; çıplak bir AI SDK döngüsünde kullanmak kimlik benzersizliğini sizin sorumluluğunuza bırakır.
İmzalama ve zaman aşımı#
İmzalama opt-in'dir. Bir secret verirseniz istek x-gnl-signature ile gider — timestamp + '.' + gövde üzerinden HMAC-SHA256 — ve yanında x-gnl-timestamp bulunur; böylece zaman damgası imzalananın parçası olur ve yakalanmış bir gövde süresiz tekrar edilemez. Alıcı sunucu bunu createRestApi({ a2aSecret }) ile doğrular. Secret yoksa istek imzasızdır; bu eski davranıştır ve değişmemiştir.
timeoutMs varsayılanı 30 saniyedir. Zaman aşımında hata bir adım zaman aşımı biçiminde şekillenir: saran durableTool bir failed kaydı yazar ve model sessiz bir askıda kalma yerine gerçek hatayı görür.
// on the receiving server — verifies x-gnl-signature over timestamp + '.' + body
app.route('/api', createRestApi(config, { title: 'Research', a2aSecret: process.env.A2A_SECRET }));API#
createA2AToolUzak bir ajana devreden bir AI SDK tool'u kurar. Seçenekler: endpoint, agentName, description?, headers?, fetchImpl?, timeoutMs? (varsayılan 30_000), secret?.
A2AResult{ text, interrupts, runId, remoteAgent } — runId, uzak tarafın tekrar oynattığı deterministik kimliktir.
a2aSecretAlıcı tarafta createRestApi({ a2aSecret }), x-gnl-signature / x-gnl-timestamp çiftini doğrular.
budgetGuardbudgetGuard — uzak fetch'ten ÖNCE çağrılan isteğe bağlı bir kanca; böylece bir kota kontrolü, aşımı sonradan fark etmek yerine çağrıyı reddedebilir. a2a kotayı kendi içinde taşımaz, host enjekte eder: ör. () => assertBudget(journal, { orgId, fallback }). Verilmezse hiç kota kontrolü yapılmaz.
StepTimeoutErrorZaman aşımında fırlatılan hata: { detail: { label, timeoutMs } }. Import edilmek yerine yerel tanımlanmıştır, çünkü @gnldev/durable burada yalnız devDependency'dir — şekli eşleştiği için durableTool sarmalayıcısı onu yine tanır ve failed kaydı yazar.
secret, alıcı sunucuda a2aSecret verin; aksi hâlde uca ulaşabilen her şey orada bir çalıştırma başlatabilir.