Belajar A2A - SDK: Python & TypeScript
Episode 6 of 23

Belajar A2A - SDK: Python & TypeScript

Bangun agent A2A sungguhan memakai SDK resmi. Kita membedah a2a-sdk Python dari AgentCard sampai executor, lalu SDK TypeScript @a2a-js/sdk dengan pattern handler dan streaming, lengkap dengan contoh client.

AI Agent
AI AgentAugust 3, 2026
0 views
5 min read

Pendahuluan

Di episode 5 kalian sudah menguasai method JSON-RPC inti — message/send, tasks/get, tasks/cancel, tasks/pushNotificationConfig, messages/list — beserta binding HTTP-nya. Sekarang waktunya naik ke lapisan yang lebih nyaman: SDK resmi. Dengan SDK, kerumitan serialisasi, task store, SSE streaming, dan penyajian Agent Card dibungkus rapi sehingga kalian cukup fokus pada logika agent. Roadmap episode ini: mulai dari a2a-sdk Python — install, struktur server, sampai client — lalu @a2a-js/sdk TypeScript dengan pattern handler dan streaming.

Mengenal a2a-sdk Python

a2a-sdk adalah SDK Python resmi untuk A2A, menyediakan komponen server dan client sekaligus. Instalasi cukup satu baris, dengan ekstra opsional sesuai kebutuhan:

Install a2a-sdk beserta ekstra
pip install a2a-sdk "a2a-sdk[fastapi]" "a2a-sdk[grpc]"

Ekstra fastapi menambahkan integrasi server web, grpc untuk binding yang kita bedah di episode 11, telemetry untuk tracing OpenTelemetry, dan sql untuk task store berbasis database. a2a-sdk juga mencakup semua tipe inti protokol — Task, Message, TextPart, DataPart, FilePart, Artifact — sebagai model Pydantic.

Server Python: dari AgentCard ke Executor

Seperti yang sudah dipelajari, A2A server butuh empat komponen: AgentCard, TaskStore, executor, dan request handler. Mari kita bangun agent pemberi skor lead:

Pythonserver.py — agent skor lead dengan a2a-sdk
import uvicorn
from starlette.applications import Starlette
from a2a.helpers import get_message_text, new_task_from_user_message, new_text_message, new_text_part
from a2a.server.agent_execution import AgentExecutor, RequestContext
from a2a.server.events import EventQueue
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.routes import create_agent_card_routes, create_jsonrpc_routes
from a2a.server.tasks import InMemoryTaskStore, TaskUpdater
from a2a.types import AgentCapabilities, AgentCard, AgentInterface, AgentSkill, TaskState
 
class LeadScorerExecutor(AgentExecutor):
    async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
        task = new_task_from_user_message(context.message)
        await event_queue.enqueue_event(task)
        updater = TaskUpdater(event_queue=event_queue, task_id=task.id, context_id=task.context_id)
        await updater.update_status(TaskState.TASK_STATE_WORKING, message=new_text_message("Menganalisis lead..."))
        query = get_message_text(context.message)
        result = f"Skor lead untuk '{query or 'kosong'}': 87 (prioritas tinggi)"
        await updater.add_artifact(parts=[new_text_part(text=result, media_type="text/plain")])
        await updater.update_status(TaskState.TASK_STATE_COMPLETED, message=new_text_message("Analisis selesai."))
 
card = AgentCard(
    name="Lead Scorer",
    description="Memberikan skor lead dari deskripsi singkat.",
    url="http://127.0.0.1:9999",
    version="1.0.0",
    default_input_modes=["text/plain"],
    default_output_modes=["text/plain"],
    capabilities=AgentCapabilities(streaming=True),
    supported_interfaces=[AgentInterface(protocol_binding="JSONRPC", url="http://127.0.0.1:9999", protocol_version="1.0")],
    skills=[AgentSkill(id="skor_lead", name="Skor Lead", description="Menghitung skor lead dari deskripsi.", input_modes=["text/plain"], output_modes=["text/plain"])],
)
 
handler = DefaultRequestHandler(agent_executor=LeadScorerExecutor(), task_store=InMemoryTaskStore(), agent_card=card)
routes = create_agent_card_routes(card) + create_jsonrpc_routes(handler, "/")
app = Starlette(routes=routes)
 
uvicorn.run(app, host="127.0.0.1", port=9999)

Alurnya jelas: LeadScorerExecutor adalah jantung logika — method execute menerima RequestContext dan EventQueue, lalu mendorong status lewat TaskUpdater; setiap update_status dan add_artifact diterjemahkan SDK menjadi event JSON-RPC yang tepat, termasuk streaming bila client meminta. Untuk agent satu-fungsi, SDK dan ADK juga menyediakan pintasan decorator task handler seperti @agent.task_method — cukup satu fungsi per skill yang mengembalikan Task berstatus completed. create_agent_card_routes menyajikan kartu di /.well-known/agent-card.json, sedangkan create_jsonrpc_routes memasang method JSON-RPC di root /.

Client Python: A2AClient

A2AClient menangani fetch Agent Card, penyusunan JSON-RPC, parsing respons, hingga streaming. Contoh klien untuk agent di atas:

Pythonclient.py — konsumen agent dengan A2AClient
from a2a.client import A2AClient
 
async def main() -> None:
    async with A2AClient(url="http://127.0.0.1:9999") as client:
        card = await client.get_agent_card()
        print(f"Agent: {card.name}, streaming={card.capabilities.streaming}")
        response = await client.send_message(
            message={"role": "user", "parts": [{"kind": "text", "text": "Lead: PT Nusantara, budget besar"}]}
        )
        task = response.result
        print(f"State: {task.status.state}")
asyncio.run(main())

send_message mengirim method message/send dan mengembalikan task lengkap — cocok untuk pekerjaan cepat. Untuk tugas lama, ada send_message_subscribe yang membuka streaming; kita bedah khusus di episode 7.

SDK TypeScript: @a2a-js/sdk

Di sisi JavaScript, SDK resminya adalah @a2a-js/sdk, berjalan di Node.js dengan dukungan TypeScript penuh. SDK dibagi beberapa entry point: root export berisi tipe bersama (Message, Task, AgentCard), @a2a-js/sdk/server berisi executor dan request handler, dan @a2a-js/sdk/client berisi client factory.

Install SDK TypeScript dan Express
npm install @a2a-js/sdk express uuid
npm install -D typescript tsx @types/express @types/uuid

Server TypeScript: Handler & Routing

Inti server TypeScript adalah interface AgentExecutor dengan method execute yang menerima RequestContext dan IExecutionEventBus. Versi TypeScript dari agent skor lead:

executor.ts — AgentExecutor untuk skor lead
import type { AgentExecutor, RequestContext, IExecutionEventBus } from "@a2a-js/sdk";
 
class LeadScorerExecutor implements AgentExecutor {
  async execute(requestContext: RequestContext, eventBus: IExecutionEventBus): Promise<void> {
    const text = requestContext.message.parts.find((p) => p.kind === "text")?.text ?? "";
    const score = `Skor lead untuk '${text}': 87 (prioritas tinggi)`;
    const artifacts = [{ artifactId: "skor-1", parts: [{ kind: "text", text: score }] }];
    await eventBus.publish({
      kind: "task",
      id: requestContext.taskId,
      contextId: requestContext.contextId,
      status: { state: "completed" },
      artifacts,
    });
  }
 
  async cancelTask(taskId: string, eventBus: IExecutionEventBus): Promise<void> {
    console.log(`Membatalkan task ${taskId}`);
  }
}

Publish event kind: "task" langsung ke state completed setara dengan rangkaian update_status di Python. Untuk laporan progres, tambahkan publish kind: "status-update" dengan final: false di sela-sela pekerjaan. Wiring ke Express nyaris tanpa "rasa protokol":

server.ts — pasang card dan route A2A
import express from "express";
import { AGENT_CARD_PATH } from "@a2a-js/sdk";
import { DefaultRequestHandler, InMemoryTaskStore } from "@a2a-js/sdk/server";
import { agentCardHandler, jsonRpcHandler } from "@a2a-js/sdk/server/express";
import { leadScorerCard } from "./card";
import { LeadScorerExecutor } from "./executor";
 
const requestHandler = new DefaultRequestHandler(leadScorerCard, new InMemoryTaskStore(), new LeadScorerExecutor());
const app = express();
app.use(express.json());
app.get(AGENT_CARD_PATH, agentCardHandler(leadScorerCard));
app.post("/", jsonRpcHandler(requestHandler));
app.listen(4000, () => console.log("Lead Scorer siap di :4000"));

Perhatikan AGENT_CARD_PATH — konstanta yang merujuk /.well-known/agent-card.json, path yang sama dengan versi Python. Konsistensi ini bukan kebetulan: kedua SDK mengikuti spesifikasi yang sama, sehingga agent Python dan TypeScript saling memanggil tanpa modifikasi.

Client TypeScript: Pola Streaming

@a2a-js/sdk/client menyediakan ClientFactory yang membaca Agent Card dari URL. Streaming ditawarkan lewat async generator, sehingga kalian bisa pakai for await secara alami:

client.ts — konsumen streaming di TypeScript
import { ClientFactory } from "@a2a-js/sdk/client";
import { v4 as uuidv4 } from "uuid";
 
const client = await new ClientFactory().createFromUrl("http://localhost:4000");
const stream = client.sendMessageStream({
  message: { kind: "message", messageId: uuidv4(), role: "user", parts: [{ kind: "text", text: "Lead: PT Nusantara, budget besar" }] },
});
for await (const event of stream) {
  if (event.kind === "task") {
    console.log(`[task] ${event.id} - ${event.status.state}`);
  } else if (event.kind === "status-update") {
    console.log(`[status] ${event.status.state}`);
  }
  if (event.kind === "task" && event.status.state === "completed") break;
}

Client ini tidak peduli server di baliknya berbahasa Python atau TypeScript — ia hanya tahu bahwa URL tersebut menyajikan Agent Card yang valid. Justru itulah poin utama episode ini: SDK membuat perbedaan bahasa menjadi detail implementasi, bukan halangan integrasi.

Penutup

Episode 6 membekali kalian dua SDK resmi untuk membangun dan mengonsumsi agent A2A. Di Python, a2a-sdk menyediakan komponen lengkap — AgentCard, DefaultRequestHandler, InMemoryTaskStore, AgentExecutor, TaskUpdater — dengan decorator task handler sebagai pintasan. Di TypeScript, @a2a-js/sdk menawarkan hal yang sama lewat AgentExecutor, DefaultRequestHandler, dan client streaming berbasis async generator.

Inti yang harus dibawa pulang:

  • a2a-sdk Python mencakup server dan client dalam satu paket, dengan model Pydantic untuk semua tipe protokol.
  • Executor adalah satu-satunya tempat logika agent; status dan artefak dilaporkan lewat event queue dan TaskUpdater.
  • Decorator task handler memangkas boilerplate untuk agent satu-fungsi tanpa kehilangan akurasi task lifecycle.
  • @a2a-js/sdk dibagi ke entry point tipe, server, dan client, dengan Express middleware siap pakai.
  • Kedua SDK ini interoperable penuh karena sama-sama menerapkan spesifikasi A2A.

Kedua SDK tadi sudah mendukung streaming dan push notification, tapi kita baru menyentuh permukaannya. Di episode 7 kita membedah sampai dalam: Streaming & Push Notifications — cara kerja SSE untuk aliran event task secara real-time, konfigurasi pushNotificationConfig, strategi retry, hingga fallback ke polling. Sampai jumpa!

Belajar A2A - SDK: Python & TypeScript | Belajar A2A