gRPC Protocol — Wire Format and Service Methods
Complete gRPC protocol reference for the Antigravity Language Server Service: endpoints, service methods, authentication headers, message types, and streaming behavior
gRPC Protocol — Wire Format and Service Methods
Overview
The localharness Go binary communicates with Google's backend via gRPC through the Cloud Code proxy endpoint. This is the protocol used for all model API calls, code completions, and project validation. The SDK itself never speaks gRPC directly -- it delegates to the harness over WebSocket, and the harness handles gRPC communication.
graph LR
subgraph "SDK Process"
SDK["Python SDK"]
end
subgraph "Harness Process"
LH["localharness<br/>(Go binary)"]
Gen["generator.<br/>requestBuilder"]
end
subgraph "Google Backend"
Proxy["cloudcode-pa.googleapis.com<br/>(Cloud Code Proxy)"]
Gemini["Gemini API"]
end
SDK -->|"WebSocket<br/>JSON-serialized protobuf"| LH
LH --> Gen
Gen -->|"gRPC<br/>binary protobuf + Bearer token"| Proxy
Proxy --> Gemini
Primary Endpoint
| Property | Value |
|---|---|
| Proxy URL | https://cloudcode-pa.googleapis.com |
| Service | exa.language_server_pb.LanguageServerService |
| Protocol | gRPC (HTTP/2, binary protobuf) |
| Transport | TLS 1.3 |
The endpoint is a proxy -- it routes requests to the appropriate backend (Gemini API, Vertex AI, etc.) based on the authentication context and request parameters.
Service Definition
syntax = "proto3";
package exa.language_server_pb;
service LanguageServerService {
// Project validation
rpc ValidateProject (ValidateProjectRequest) returns (ValidateProjectResponse);
// Code completion
rpc GetCompletions (GetCompletionsRequest) returns (GetCompletionsResponse);
// Streaming chat (the primary method for agent conversations)
rpc Chat (ChatRequest) returns (stream ChatResponse);
}
Method Details
ValidateProject
| Property | Value |
|---|---|
| Type | Unary |
| Purpose | Validates project configuration and permissions |
| Called | At session startup, before first Chat call |
| Returns | Project status, permissions, quotas |
This method is called to verify that the authenticated user has access to the requested project and that the project is properly configured. It also returns quota and billing information.
GetCompletions
| Property | Value |
|---|---|
| Type | Unary |
| Purpose | Code completion requests |
| Called | On-demand for tab completions in IDE context |
| Returns | Ranked completion candidates |
Used primarily by the IDE integration for inline code completions. The harness uses this for the "tab completion" feature, not for conversational agent interactions.
Chat
| Property | Value |
|---|---|
| Type | Server-side streaming |
| Purpose | Conversational agent interactions |
| Called | For every user message in the agent loop |
| Returns | Stream of ChatResponse messages |
This is the primary method used by the agent loop. The harness sends a ChatRequest containing the conversation history, system instructions, and available tools, then receives a stream of response chunks.
Service Descriptors (from Decompilation)
The decompiled binary reveals the full service descriptor generation:
// Decompiled: language_server_go_grpc.generateLanguageServerServiceServiceDesc
func generateLanguageServerServiceServiceDesc() grpc.ServiceDesc {
return grpc.ServiceDesc{
ServiceName: "exa.language_server_pb.LanguageServerService",
Methods: []grpc.MethodDesc{
{MethodName: "ValidateProject", Handler: validateProjectHandler},
{MethodName: "GetCompletions", Handler: getCompletionsHandler},
},
Streams: []grpc.StreamDesc{
{StreamName: "Chat", Handler: chatStreamHandler, ServerStreams: true},
},
}
}
The LanguageServerServiceHandlerHook pattern shows hook points where method handlers can be intercepted -- enabling middleware-style processing of all gRPC calls.
Authentication Headers
All gRPC calls include the following metadata headers:
Required Headers
// Set on every gRPC call
metadata.Set("authorization", "Bearer " + accessToken)
metadata.Set("x-goog-api-client", clientIdentificationString)
metadata.Set("x-goog-user-project", projectId)
metadata.Set("x-codeium-csrf-token", csrfToken)
metadata.Set("X-Http-Session-Id", sessionId)
| Header | Purpose | Value Source |
|---|---|---|
authorization | OAuth2 Bearer token | Auth chain (keychain/file/cache) |
x-goog-api-client | Client identification | Compiled into binary |
x-goog-user-project | Billing project | GCP project ID |
x-codeium-csrf-token | CSRF protection | Generated per session |
X-Http-Session-Id | Session tracking | Generated per connection |
Google-Specific Headers
These headers provide additional routing, logging, and tracing information:
| Header | Purpose | When Used |
|---|---|---|
x-goog-sherlog-Link | Internal logging/tracing correlation | All calls |
x-goog-cloud-target-resource | Target resource routing | Vertex AI calls |
X-Goog-Ext-525006001-bin | Binary extension data (protobuf-encoded) | Feature negotiation |
X-Goog-Drive-Resource-Keys | Drive resource keys | Drive-integrated features |
X-Goog-Request-Reason | Audit trail | All calls |
API Key Header (Non-OAuth)
For non-OAuth flows (direct API key authentication):
metadata.Set("x-api-key", apiKey)
This is used when the SDK is configured with a Gemini API key instead of OAuth2 credentials. The harness detects this and uses x-api-key instead of authorization: Bearer.
Authentication Flow in gRPC Context
sequenceDiagram
participant SDK as Python SDK
participant Harness as localharness
participant Auth as Auth Provider
participant Proxy as cloudcode-pa.googleapis.com
participant Gemini as Gemini API
Note over SDK,Gemini: Chat Request Flow
SDK->>Harness: InputEvent{user_input: "prompt"}
Harness->>Auth: TrySilentAuth()
alt Token valid
Auth-->>Harness: access_token
else Token expired
Auth->>Auth: refreshAndSaveToken()
Auth-->>Harness: fresh access_token
end
Harness->>Harness: Build ChatRequest protobuf
Harness->>Harness: Set gRPC metadata headers
Harness->>Proxy: gRPC Chat(ChatRequest)
Note right of Harness: Headers:<br/>authorization: Bearer [token]<br/>x-goog-api-client: [id]<br/>x-goog-user-project: [project]<br/>x-codeium-csrf-token: [csrf]<br/>X-Http-Session-Id: [session]
Proxy->>Gemini: Forward request
Gemini-->>Proxy: Streaming response
loop Each response chunk
Proxy-->>Harness: ChatResponse (stream)
Harness-->>SDK: OutputEvent{step_update}
end
Proxy-->>Harness: Stream complete
Harness-->>SDK: OutputEvent{step_update: DONE}
Token Expiry During Streaming
gRPC metadata headers are set once per connection. If the access token expires during a long-running streaming response, the connection may be terminated:
sequenceDiagram
participant H as Harness
participant P as Proxy
H->>P: gRPC Chat (token valid, TTL=300s)
P-->>H: ChatResponse chunk 1
P-->>H: ChatResponse chunk 2
Note over H: Token expires (TTL=0)
P-->>H: UNAUTHENTICATED error
Note right of H: gRPC status code: 16<br/>"Request had invalid authentication credentials"
H->>H: TrySilentAuth() → refresh token
H->>P: New gRPC Chat (fresh token)
P-->>H: ChatResponse (resumed)
The harness handles this by catching UNAUTHENTICATED status errors and retrying with a fresh token. This is transparent to the SDK.
Additional gRPC Services
Beyond LanguageServerService, the decompiled binary reveals several additional gRPC services:
ApiServerService
service ApiServerService {
rpc ApplyTrajectoryHeuristics (...) returns (...);
rpc CreateTrajectoryShareStream (...) returns (...);
rpc GetCascadeModelConfigs (...) returns (...);
rpc GetCommandModelConfigs (...) returns (...);
rpc GetCompletionExamples (...) returns (...);
rpc GetDeploymentConfig (...) returns (...);
rpc GetEmbeddings (...) returns (...);
rpc GetImageGeneration (...) returns (...);
rpc GetMQuery (...) returns (...);
rpc GetMcpServerTemplates (...) returns (...);
rpc GetModelInfos (...) returns (...);
rpc GetModelStatuses (...) returns (...);
rpc GetTeamOrganizationalControls (...) returns (...);
rpc GetTranscription (...) returns (...);
rpc GetUnleashContextFields (...) returns (...);
rpc GetWebDocsOptions (...) returns (...);
rpc GetWebSearchRedirect (...) returns (...);
rpc GetWebSearchResults (...) returns (...);
rpc ProvideFeedback (...) returns (...);
rpc RecordAsyncTelemetry (...) returns (...);
}
This service handles configuration, metadata, and management operations. It is used for:
- Model discovery and status checks
- MCP server template retrieval
- Feature flag context (
UnleashContextFields) - Telemetry submission
- Embedding generation
CloudCode Service (v1internal)
service CloudCode {
rpc CompleteCode (...) returns (...);
rpc FetchAdminControls (...) returns (...);
rpc FetchCodeCustomizationState (...) returns (...);
rpc GenerateChat (...) returns (...);
rpc GetCodeAssistGlobalUserSetting (...) returns (...);
rpc InternalAtomicAgenticChat (...) returns (...);
rpc ListAgents (...) returns (...);
rpc ListCloudAICompanionProjects (...) returns (...);
rpc ListExperiments (...) returns (...);
rpc ListModelConfigs (...) returns (...);
rpc ListRemoteRepositories (...) returns (...);
rpc LoadCodeAssist (...) returns (...);
rpc MigrateDatabaseCode (...) returns (...);
rpc OnboardUser (...) returns (...);
rpc RecordClientEvent (...) returns (...);
rpc RecordCodeAssistMetrics (...) returns (...);
rpc RecordSmartchoicesFeedback (...) returns (...);
rpc SearchSnippets (...) returns (...);
rpc SetCodeAssistGlobalUserSetting (...) returns (...);
rpc TransformCode (...) returns (...);
}
This is the internal Cloud Code service used for:
- Code completion and transformation
- Agent listing and management
- User onboarding
- Admin controls
- A/B experiment management
AnalyticsService
service AnalyticsService {
rpc RecordEvent (...) returns (...);
// Additional telemetry methods
}
Handles telemetry event recording. Events use the ProductEvent protobuf format.
gRPC Error Codes
The harness handles the following gRPC status codes:
| Code | Name | Meaning | Handling |
|---|---|---|---|
| 0 | OK | Success | Normal processing |
| 1 | CANCELLED | Call cancelled | By SDK cancel request |
| 3 | INVALID_ARGUMENT | Bad request | Log and surface to SDK |
| 7 | PERMISSION_DENIED | Auth insufficient | Trigger re-auth |
| 8 | RESOURCE_EXHAUSTED | Quota exceeded | Surface to SDK as error |
| 10 | ABORTED | Operation aborted | Retry if idempotent |
| 13 | INTERNAL | Server error | Retry with backoff |
| 14 | UNAVAILABLE | Service down | Retry with backoff |
| 16 | UNAUTHENTICATED | Token expired | Refresh token, retry |
Error Recovery Pattern
flowchart TD
Req["gRPC Request"] --> Check{"Response status?"}
Check -->|OK| Success["Process response"]
Check -->|UNAUTHENTICATED| Refresh["TrySilentAuth() → refresh"]
Refresh --> Retry["Retry request with fresh token"]
Retry --> Check
Check -->|UNAVAILABLE| Backoff["Exponential backoff"]
Backoff --> Retry
Check -->|RESOURCE_EXHAUSTED| Quota["Surface quota error to SDK"]
Check -->|Other| Error["Log error, surface to SDK"]
Wire Format Details
gRPC Message Framing
gRPC uses HTTP/2 with a 5-byte header prefix:
[1 byte: compressed flag][4 bytes uint32: message length][protobuf bytes]
Protobuf Serialization
All gRPC messages use standard binary protobuf serialization (NOT JSON, unlike the WebSocket protocol between SDK and harness).
Streaming
The Chat method uses server-side streaming:
- Client sends ONE
ChatRequest - Server sends MULTIPLE
ChatResponsemessages - Stream ends when server sends trailing metadata
Each ChatResponse may contain:
- Text deltas (incremental response tokens)
- Thinking deltas (reasoning tokens)
- Tool call requests
- Usage metadata
- State transitions
Relationship to WebSocket Protocol
The gRPC protocol is internal to the harness. The SDK never interacts with it directly. The translation layer:
graph TB
subgraph "SDK Side"
IE["InputEvent<br/>(JSON over WebSocket)"]
end
subgraph "Harness Side"
WS["WebSocket Handler"]
AL["Agent Loop"]
Gen["generator.requestBuilder"]
GRPC["gRPC Client"]
end
subgraph "Backend"
Proxy["cloudcode-pa.googleapis.com"]
end
IE -->|"JSON protobuf"| WS
WS -->|"Parsed InputEvent"| AL
AL -->|"Build ChatRequest"| Gen
Gen -->|"Binary protobuf"| GRPC
GRPC -->|"HTTP/2 + TLS"| Proxy
Proxy -->|"Stream ChatResponse"| GRPC
GRPC -->|"Parsed responses"| AL
AL -->|"Build OutputEvent"| WS
WS -->|"JSON protobuf"| IE
CelEnforcer (Request Authorization)
The decompiled binary includes a CEL (Common Expression Language) enforcement layer:
// Decompiled: celEnforcer.IsRequestAllowed
func (e *CelEnforcer) IsRequestAllowed(request *Request) bool {
// Evaluates CEL expressions against the request
// Used for fine-grained authorization in sandbox proxy
}
This provides expression-based access control for gRPC requests. CEL expressions can evaluate arbitrary conditions on the request context, enabling:
- Per-user rate limiting
- Feature gating
- Geographic restrictions
- Custom authorization rules
Sandbox Proxy
The sandboxproxy package implements a proxy layer for sandboxed execution environments:
// Decompiled: sandboxproxy.NewServer
func NewServer(config *Config) *Server {
// Creates a proxy server that intercepts gRPC calls
// Applies CEL enforcement
// Routes to appropriate backend
}
The sandbox proxy:
- Intercepts incoming gRPC requests
- Applies CEL enforcement rules
- Routes to the appropriate backend
- Handles authentication forwarding
Cross-References
- sdk-test-auth-chain — How auth tokens are obtained and refreshed for gRPC calls
- sdk-test-protobuf — Protobuf message definitions used in gRPC messages
- sdk-test-localharness — How the harness manages the gRPC connection lifecycle
- sdk-test-decompiled-patterns — Decompiled gRPC service descriptors and handlers
- sdk-test-architecture — JETSKY ecosystem architecture
Source: Decompiled from agy binary via Ghidra MCP. Functions: language_server_go_grpc.*, language_server_go_proto.*, api_server_go_proto.*, v1internal_go_proto.*, codeassistclient.*. Service descriptors extracted from generateLanguageServerServiceServiceDesc.