WikifitaGitHub live67e8de5
outro · sdk-test/sdk-test-grpc-protocol

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

Baixar raw

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

PropertyValue
Proxy URLhttps://cloudcode-pa.googleapis.com
Serviceexa.language_server_pb.LanguageServerService
ProtocolgRPC (HTTP/2, binary protobuf)
TransportTLS 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

PropertyValue
TypeUnary
PurposeValidates project configuration and permissions
CalledAt session startup, before first Chat call
ReturnsProject 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

PropertyValue
TypeUnary
PurposeCode completion requests
CalledOn-demand for tab completions in IDE context
ReturnsRanked 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

PropertyValue
TypeServer-side streaming
PurposeConversational agent interactions
CalledFor every user message in the agent loop
ReturnsStream 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)
HeaderPurposeValue Source
authorizationOAuth2 Bearer tokenAuth chain (keychain/file/cache)
x-goog-api-clientClient identificationCompiled into binary
x-goog-user-projectBilling projectGCP project ID
x-codeium-csrf-tokenCSRF protectionGenerated per session
X-Http-Session-IdSession trackingGenerated per connection

Google-Specific Headers

These headers provide additional routing, logging, and tracing information:

HeaderPurposeWhen Used
x-goog-sherlog-LinkInternal logging/tracing correlationAll calls
x-goog-cloud-target-resourceTarget resource routingVertex AI calls
X-Goog-Ext-525006001-binBinary extension data (protobuf-encoded)Feature negotiation
X-Goog-Drive-Resource-KeysDrive resource keysDrive-integrated features
X-Goog-Request-ReasonAudit trailAll 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:

CodeNameMeaningHandling
0OKSuccessNormal processing
1CANCELLEDCall cancelledBy SDK cancel request
3INVALID_ARGUMENTBad requestLog and surface to SDK
7PERMISSION_DENIEDAuth insufficientTrigger re-auth
8RESOURCE_EXHAUSTEDQuota exceededSurface to SDK as error
10ABORTEDOperation abortedRetry if idempotent
13INTERNALServer errorRetry with backoff
14UNAVAILABLEService downRetry with backoff
16UNAUTHENTICATEDToken expiredRefresh 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 ChatResponse messages
  • 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:

  1. Intercepts incoming gRPC requests
  2. Applies CEL enforcement rules
  3. Routes to the appropriate backend
  4. Handles authentication forwarding

Cross-References


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.