WikifitaGitHub live67e8de5
outro · sdk-test/sdk-test-protobuf

Protobuf Deep Analysis — Antigravity Wire Protocol

Complete protobuf message reference for the Antigravity localharness protocol: every message type, all fields, oneof patterns, serialization format, and wire protocol details

Baixar raw

Protobuf Deep Analysis — Antigravity Wire Protocol

Overview

The Antigravity SDK communicates with the localharness Go binary via Protocol Buffers serialized as JSON over a WebSocket connection. The localharness_pb2.py file (430 lines) is auto-generated from localharness.proto and defines the complete wire protocol.

This page documents every message type, every field, every oneof pattern, and the serialization rules.

Wire Format

stdin/stdout (Handshake Phase)

Length-prefixed binary protobuf:

[4 bytes uint32 little-endian: message_length][protobuf bytes: message_body]

This is standard binary protobuf, NOT JSON. The handshake is synchronous and blocking.

WebSocket (Runtime Phase)

JSON-serialized protobuf. The SDK uses google.protobuf.json_format.MessageToJson() and Parse() for serialization. Example wire message:

{
  "stepUpdate": {
    "cascadeId": "abc-123",
    "trajectoryId": "traj-0",
    "stepIndex": 3,
    "state": "ACTIVE",
    "source": "MODEL",
    "target": "USER",
    "textDelta": "Here are the files",
    "listDirectory": {
      "directoryPath": "/workspace",
      "results": [
        {"name": "src", "isDirectory": true},
        {"name": "README.md", "isDirectory": false, "fileSize": 1234}
      ]
    }
  },
  "seqNum": 42,
  "timestampMicros": 1721654400000000
}

Field naming: Protobuf field names use snake_case in the .proto definition but are serialized as camelCase in JSON (protobuf JSON mapping convention).

Message Category Map

graph TB
    subgraph "Handshake (stdin/stdout)"
        IC["InputConfig<br/>SDK → Harness"]
        OCI["OutputConfig<br/>Harness → SDK"]
        CI["ClientInfo<br/>part of InputConfig"]
    end

    subgraph "Initialization (WebSocket)"
        ICE["InitializeConversationEvent<br/>SDK → Harness"]
        HC["HarnessConfig<br/>central config message"]
    end

    subgraph "Model Configuration (oneof in HarnessConfig)"
        GC["GeminiConfig"]
        GMC["GemmaConfig"]
        CBC["CustomBackendConfig"]
    end

    subgraph "Runtime: Harness → SDK"
        OE["OutputEvent<br/>main envelope"]
        SU["StepUpdate<br/>workhorse message"]
        TSU["TrajectoryStateUpdate"]
        TC["ToolCall"]
        UM["UsageMetadata"]
    end

    subgraph "Runtime: SDK → Harness"
        IE["InputEvent<br/>main envelope"]
        UI["UserInput"]
        TCF["ToolConfirmation"]
        TR["ToolResponse"]
        UQR["UserQuestionsResponse"]
    end

    subgraph "Configuration Sub-messages"
        SI["SystemInstructions"]
        TL["Tool"]
        HST["HarnessSideTools"]
        WS["Workspace"]
        MCP["McpServerConfig"]
    end

    OE --> SU
    OE --> TSU
    OE --> TC
    OE --> UM
    ICE --> HC
    HC --> GC
    HC --> GMC
    HC --> CBC
    HC --> SI
    HC --> TL
    HC --> HST
    HC --> WS
    HC --> MCP

Handshake Messages

InputConfig (SDK to Harness, stdin)

Sent as the first message over stdin. The harness blocks until it receives this.

FieldProto #TypeDefaultDescription
storage_directory1string""Path for trajectory persistence on disk
port2uint320Requested WebSocket port. 0 = auto-assign
bind_address3string"localhost"WebSocket bind address
client_info4ClientInfoSDK metadata

Behavior: If port is 0, the harness selects an available port. The actual port is reported back in OutputConfig.port.

ClientInfo (sub-message of InputConfig)

FieldProto #TypeDescription
language1stringAlways "python" for the Python SDK
version2stringSDK version from package metadata (e.g., "0.1.2")
language_version3stringPython version string (e.g., "3.12.4")

OutputConfig (Harness to SDK, stdout)

Sent by the harness after it has started its WebSocket server.

FieldProto #TypeDescription
port1int32Actual WebSocket port the server is listening on
api_key2stringEphemeral API key for WebSocket authentication header

The api_key is a randomly generated string, valid only for this harness process lifetime. It is used in the x-goog-api-key header during the WebSocket handshake.

Initialization Messages

InitializeConversationEvent (SDK to Harness, first WebSocket message)

FieldProto #TypeDescription
config1HarnessConfigComplete agent configuration

This is the ONLY message the SDK sends before the runtime loop begins. The harness uses it to set up the entire agent session.

HarnessConfig (the central configuration message)

This is the most important message in the protocol. It defines the entire agent session.

FieldProto #TypeOneof GroupDescription
cascade_id1stringConversation/session identifier. Used to correlate trajectories
gemini_config2GeminiConfigmodel_configCloud Gemini API configuration
gemma_config3GemmaConfigmodel_configLocal Gemma model configuration
custom_backend13CustomBackendConfigmodel_configExternal backend (DeepSeek, etc.)
system_instructions4SystemInstructionsAgent persona and instructions
tools5repeated ToolCustom Python tool definitions (schemas only)
harness_side_tools6HarnessSideToolsBuilt-in tool enable/disable toggles
compaction_threshold7uint32Token count that triggers context compaction
workspaces8repeated WorkspaceAllowed filesystem directories
skills_paths9repeated stringDirectories to scan for skill files
finish_tool_schema_json10stringJSON schema for structured output via FINISH tool
initial_trajectory11bytesSerialized trajectory for session resumption
app_data_dir12stringOverride for harness app data directory
mcp_servers14repeated McpServerConfigMCP server configurations

model_config Oneof Pattern

The model_config field is a oneof that selects the backend. Exactly one must be set:

oneof model_config {
  GeminiConfig gemini_config = 2;
  GemmaConfig gemma_config = 3;
  CustomBackendConfig custom_backend = 13;
}
VariantUse CaseProto Field
GeminiConfigCloud Gemini API2
GemmaConfigLocal Gemma via OpenAI-compatible endpoint3
CustomBackendConfigAny external backend (DeepSeek, etc.)13

If none is set, the harness falls back to environment variable GEMINI_API_KEY and default Gemini config.

Model Configuration Messages

GeminiConfig

FieldProto #TypeDefaultDescription
api_key1stringGemini API key. Falls back to $GEMINI_API_KEY env var
base_url2stringCustom API endpoint (overrides default Gemini endpoint)
model_name3string"gemini-3.5-flash"Model identifier
thinking_level4stringExtended thinking level (minimal/low/medium/high)
enable_url_context5boolfalseEnable URL context grounding
enable_google_search6boolfalseEnable Google Search grounding
use_vertex7boolfalseRoute through Vertex AI
project8stringGCP project ID (required if use_vertex=true)
location9stringGCP region (required if use_vertex=true)

GemmaConfig

FieldProto #TypeDescription
base_url1stringOpenAI-compatible endpoint (e.g., "http://localhost:8080/v1")
model_name2stringModel identifier (e.g., "gemma-4-12B-it-qat-4bit")

This is the dedicated config for local Gemma models. The harness sends requests using the OpenAI Chat Completions format to the specified endpoint. See sdk-test-integrations for Gemma 4 MTP pipeline details.

CustomBackendConfig

FieldProto #TypeDescription
backend_type1stringBackend identifier (e.g., "deepseek", "ollama")
config_json2stringJSON-encoded backend-specific configuration

This is the escape hatch for any backend not natively supported. The config_json field carries arbitrary configuration that the harness forwards to the backend adapter.

System Instructions Messages

SystemInstructions (oneof)

oneof system_instructions {
  CustomSystemInstructions custom = 1;
  AppendedSystemInstructions appended = 2;
}

CustomSystemInstructions

Full replacement of the system prompt. Use with caution -- this replaces ALL default instructions.

FieldProto #TypeDescription
parts1repeated PartContent parts (text only for system instructions)

AppendedSystemInstructions

Appends to the default system prompt. This is the recommended approach.

FieldProto #TypeDescription
custom_identity1stringCustom identity statement (e.g., "You are a security analyst")
sections2repeated SectionAdditional instruction sections

Section

FieldProto #TypeDescription
title1stringSection heading
content2stringSection body

Tool Definition Messages

Tool (custom Python tool schema)

FieldProto #TypeDescription
name1stringFunction name (e.g., "get_weather")
description2stringFunction docstring
parameters_json_schema3stringJSON Schema for input parameters
response_json_schema4stringJSON Schema for response format

These are schema-only definitions. The harness calls back to the SDK via ToolCall when it needs to execute a Python tool.

HarnessSideTools (11 toggle configs)

Each sub-message has a single enabled bool field:

Sub-messageProto #Tool ControlledExtra Fields
FindToolConfig1find_file
RunCommandToolConfig2run_command
SubagentsConfig3start_subagent
UserQuestionsConfig4ask_question
FileEditToolConfig5edit_file
ViewFileToolConfig6view_file
WriteToFileToolConfig7create_file
GrepSearchToolConfig8search_directory
ListDirToolConfig9list_directory
GenerateImageToolConfig10generate_imagemodel_name (string, default: "gemini-3.1-flash-image-preview")
PermissionsConfig11workspace validationenforce_workspace_validation (bool)

Workspace

FieldProto #TypeDescription
filesystem_workspace1oneofCurrently only FilesystemWorkspace variant
directory1 (inner)stringAbsolute path to allowed directory

Runtime Messages: Harness to SDK

OutputEvent (the main event envelope)

Every message from the harness to the SDK is wrapped in an OutputEvent.

FieldProto #TypeOneof GroupDescription
seq_num1int64Monotonically increasing sequence number
timestamp_micros2int64Timestamp in microseconds since epoch
step_update10StepUpdateeventAgent step update
trajectory_state_update11TrajectoryStateUpdateeventTrajectory lifecycle state change
tool_call12ToolCalleventHost-side tool invocation request
usage_metadata20UsageMetadataToken usage (may accompany any event)

The event oneof ensures each OutputEvent carries exactly one type of event.

StepUpdate (the workhorse message)

The most complex message in the protocol. At ~1.7KB in the proto definition, it covers every possible agent action.

FieldProto #TypeDescription
cascade_id1stringParent trajectory (conversation) ID
trajectory_id2stringThis trajectory's ID (differs for subagents)
step_index3uint32Step number within the trajectory
state4State enumUNSPECIFIED/ACTIVE/DONE/WAITING_FOR_USER/ERROR
source5Source enumUNSPECIFIED/SYSTEM/USER/MODEL
target6Target enumUNSPECIFIED/USER/MODEL/ENVIRONMENT
error_message7stringError details (when state=ERROR)
thinking8stringFull thinking text (non-streaming)
text_delta9stringIncremental text token (streaming)
thinking_delta10stringIncremental thinking token (streaming)
text11stringFull accumulated text (non-streaming)
request_text12stringUser-facing request text
tool_confirmation_request13ToolConfirmationRequestApproval needed for tool execution
questions_request14UserQuestionsRequestQuestions for the user

State Enum

ValueNameMeaning
0UNSPECIFIEDDefault/unset
1ACTIVEStep is currently executing
2DONEStep completed successfully
3WAITING_FOR_USERWaiting for user input (confirmation or question)
4ERRORStep failed

Source Enum

ValueNameMeaning
0UNSPECIFIEDDefault
1SYSTEMSystem-generated step
2USERUser-initiated step
3MODELModel-generated step

Target Enum

ValueNameMeaning
0UNSPECIFIEDDefault
1USERDirected at the user
2MODELDirected at the model
3ENVIRONMENTDirected at the environment (tools)

Action Sub-messages (oneof)

Each StepUpdate carries exactly ONE action sub-message:

ActionProto FieldMessage TypeKey Fields
list_directory20ActionListDirectorydirectory_path, results[] (name, is_directory, file_size)
find_file21ActionFindFiledirectory_path, query, output
search_directory22ActionSearchDirectorydirectory_path, query, num_results
view_file23ActionViewFilefile_path, start_line, end_line
create_file24ActionCreateFilefile_path, contents
edit_file25ActionEditFilefile_path, diff_blocks[]
run_command26ActionRunCommandcommand_line, working_dir, exit_code, combined_output
compaction27ActionCompaction(empty)
invoke_subagent28ActionInvokeSubagent(empty)
generate_image29ActionGenerateImageprompt, image_paths[], image_name
finish30ActionFinishoutput_string (contains structured output JSON if schema set)
error31ActionErrorerror_message, http_code
mcp_tool32ActionMcpToolserver_name, tool_name, arguments_json

ActionEditFile Detail

The edit_file action carries a diff structure:

message ActionEditFile {
  string file_path = 1;
  repeated DiffBlock diff_blocks = 2;
}

message DiffBlock {
  uint32 start_line = 1;
  uint32 end_line = 2;
  repeated DiffLine lines = 3;
}

message DiffLine {
  string text = 1;
  LineAction action = 2;  // KEEP, INSERT, DELETE
}

ActionRunCommand Detail

message ActionRunCommand {
  string command_line = 1;
  string working_dir = 2;
  int32 exit_code = 3;
  string combined_output = 4;  // stdout + stderr merged
}

TrajectoryStateUpdate

FieldProto #TypeDescription
trajectory_id1stringTrajectory identifier
state2TrajectoryState enumUNSPECIFIED/RUNNING/IDLE
error3stringError message if trajectory failed

The SDK uses these to determine idle state. A connection is idle only when ALL trajectories (parent + subagents) are in IDLE state.

ToolCall (host-side tool invocation)

Sent when the harness needs the SDK to execute a Python tool.

FieldProto #TypeDescription
id1stringUnique call identifier (correlates with ToolResponse)
name2stringTool function name
args3map<string, string>Serialized arguments
server_name4stringMCP server name (if MCP tool)

UsageMetadata

FieldProto #TypeDescription
prompt_token_count1uint64Input tokens consumed
cached_content_token_count2uint64Cached subset of input tokens
candidates_token_count3uint64Output tokens (excluding thinking)
thoughts_token_count4uint64Thinking/reasoning tokens
total_token_count5uint64Sum of all token categories

Runtime Messages: SDK to Harness

InputEvent (the main input envelope)

Every message from the SDK to the harness is an InputEvent with a oneof payload:

VariantProto #TypeDescription
user_input1stringSimple text prompt
complex_user_input2UserInputMultimodal input (text + media)
tool_confirmation3ToolConfirmationApprove/deny a tool call
tool_response4ToolResponseResult of a Python tool execution
question_response5UserQuestionsResponseAnswer to agent questions
halt_request6boolCancel current model turn
automated_trigger7stringTrigger notification message

UserInput (multimodal input)

FieldProto #TypeDescription
parts1repeated PartContent parts

Part (oneof content type)

message Part {
  oneof content {
    string text = 1;
    Media media = 2;
    SlashCommand slash_command = 3;
  }
}

Media

FieldProto #TypeDescription
mime_type1stringMIME type (e.g., "image/png")
description2stringOptional description
data3bytesRaw media data

SlashCommand

FieldProto #TypeDescription
name1stringSlash command name (without leading /)

ToolConfirmation

FieldProto #TypeDescription
trajectory_id1stringTarget trajectory
step_index2uint32Target step
accepted3booltrue = approve, false = deny

ToolResponse

FieldProto #TypeDescription
id1stringCorrelates with ToolCall.id
response_json2stringJSON-serialized result
supplemental_media3repeated MediaAttachments
response4StructStructured result (protobuf Struct)

UserQuestionsResponse

FieldProto #TypeDescription
trajectory_id1stringTarget trajectory
step_index2uint32Target step
cancelled3boolUser cancelled (oneof)
response4QuestionsResponseUser's answers (oneof)

MCP Configuration Messages

McpServerConfig

FieldProto #TypeOneof GroupDescription
name1stringServer identifier
stdio2McpStdioTransporttransportstdio-based transport
http3McpHttpTransporttransportHTTP-based transport
enabled_tools4repeated stringTool allowlist
disabled_tools5repeated stringTool denylist
auth_provider_type6AuthProviderType enumUNSPECIFIED/GOOGLE_CREDENTIALS

McpStdioTransport

FieldProto #TypeDescription
command1stringExecutable path
args2repeated stringCommand arguments
env3map<string, string>Environment variables

McpHttpTransport

FieldProto #TypeDescription
url1stringHTTP endpoint URL
headers2map<string, string>Request headers

AuthProviderType Enum

ValueNameDescription
0UNSPECIFIEDNo auth
1GOOGLE_CREDENTIALSUse Google OAuth2 credentials

Serialization Rules

JSON Mapping

Protobuf JSON mapping rules apply:

  • Field names: snake_case in proto → camelCase in JSON
  • Enum values: Sent as string names (e.g., "ACTIVE" not 1)
  • Bytes fields: Base64-encoded
  • Default values: Omitted from wire format
  • oneof: Only the set variant appears

Content Type

All WebSocket messages use the default WebSocket text frame with JSON content. Binary frames are not used.

Message Size

No explicit size limit is enforced by the protocol. Practical limits:

  • Individual messages: Typically < 1MB
  • initial_trajectory: Can be several MB (serialized conversation history)
  • ActionCreateFile.contents: Can be large for file creation
  • combined_output in ActionRunCommand: Can be large for command output

Cross-References


Source: localharness_pb2.py (430 lines), auto-generated from localharness.proto. Python SDK: local_connection.py (1792 lines).