What It Is
GrpcAgentClient is a Python class that looks like a function. You call it with messages, it returns a string or dict. Internally, it makes a gRPC call to a remote process in another language. But the caller doesn’t know that.
This is the trick that makes the entire language-agnostic system work without changing a single line in ManifestWorker.
The Problem It Solves
ManifestWorker has this line:manifest.run is a wrapper around the developer’s handler function. It takes a list of message dicts, returns a string or dict.
For TypeScript/Kotlin agents, we need that same call to go over the network. But we can’t change ManifestWorker — it handles task state transitions, error handling, tracing, payment settlement. Touching it risks breaking everything.
Solution: make GrpcAgentClient a callable that quacks like a handler function.
How It Works
The Response Contract
ManifestWorker doesn’t care how the response was produced. It only cares about the type:| Handler returns | ManifestWorker does | Task state |
|---|---|---|
"The capital of France is Paris." | Creates message + artifact | completed |
{"state": "input-required", "prompt": "Can you clarify?"} | Creates message, keeps task open | input-required |
{"state": "auth-required"} | Creates message, keeps task open | auth-required |
ResultProcessor, ResponseDetector, ArtifactBuilder — processes them identically to a local Python handler’s output.
Real Example: What Happens When a User Asks a Question
A user sends “What is quantum computing?” to a TypeScript agent:When It’s Created
DuringRegisterAgent, the gRPC service creates a GrpcAgentClient and attaches it to the manifest:
Connection Lifecycle
The client connects lazily — the gRPC channel is created on the first call, not during initialization. This avoids connection errors during registration if the SDK’s server isn’t fully ready yet. When the SDK disconnects (Ctrl+C, crash), the nextHandleMessages call fails with grpc.StatusCode.UNAVAILABLE. ManifestWorker’s existing error handling catches this and marks the task as failed. No special handling needed.