1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! A typed Rust interface for the [Google Antigravity](https://antigravity.google)
//! agent runtime.
//!
//! <div class="warning">
//!
//! **Maturity warning**: this crate is new and should be considered **highly
//! untested**. The wire types are generated from the protobuf descriptor
//! embedded in the shipped `localharness` binary, and the handshake is locked
//! against captures from a live harness, but real-world mileage is minimal and
//! the API may change between releases while the surface settles. The upstream
//! SDK is itself alpha (`0.1.x`) and reserves extension ranges on its hottest
//! messages, so expect churn. Bug reports and wire captures that break the
//! types are very welcome at
//! <https://github.com/meawoppl/rust-code-agent-sdks/issues>.
//!
//! </div>
//!
//! # What this actually wraps
//!
//! `google-antigravity` on PyPI is a Python client for a compiled Go binary
//! called **`localharness`**, which is where the agent loop, the built-in tools,
//! and the model calls all live. This crate is a client for that same binary —
//! it is a sibling of the Python SDK, not a binding to it, and no Python is
//! involved at runtime.
//!
//! The binary ships **only** inside the platform-specific wheels published to
//! [PyPI](https://pypi.org/project/google-antigravity/). See
//! [`process::find_harness`] for how the crate locates it.
//!
//! # The protocol in one screen
//!
//! Unlike its sibling crates — [`claude-codes`](https://docs.rs/claude-codes) and
//! [`codex-codes`](https://docs.rs/codex-codes), which speak JSON-Lines over
//! stdio, and [`opencode-codes`](https://docs.rs/opencode-codes), which speaks
//! HTTP+SSE — Antigravity uses stdio *only* to bootstrap, then moves to a
//! loopback WebSocket:
//!
//! 1. **Handshake** (binary protobuf, `u32le`-length-prefixed, over stdio).
//! The client writes an [`protocol::InputConfig`]; the harness replies with
//! an [`protocol::OutputConfig`] carrying the port it bound and a
//! single-use API key. See [`handshake`].
//! 2. **Connect** to `ws://127.0.0.1:{port}/` with an `x-goog-api-key` header.
//! 3. **Initialize** by sending an [`protocol::InitializeConversationEvent`];
//! the harness replies with an
//! [`protocol::InitializeConversationResponse`] holding the conversation id
//! and any replayed history.
//! 4. **Converse** — send [`protocol::InputEvent`]s, receive
//! [`protocol::OutputEvent`]s. Every frame after the handshake is protobuf's
//! canonical **JSON** mapping, so the wire is text: `camelCase` members,
//! 64-bit integers as strings, `bytes` as base64, enums as value names.
//!
//! Note that a conversation **must** be configured with at least one model. A
//! harness initialised with no [`protocol::ModelConfig`] exits immediately and
//! closes the socket without an error frame.
//!
//! # Choosing a client
//!
//! | Type | What it gives you |
//! |------|-------------------|
//! | [`RawClient`] | The frames, unchanged. You drive the loop and answer the harness's requests yourself. |
//! | [`Client`] | Turn-oriented: [`Client::send`] returns a [`Turn`] that streams assembled [`Step`]s and answers tool calls, hooks, and policy checks from handlers you register. |
//!
//! A worked end-to-end example lives on [`Client`]. At the protocol tier, a
//! frame off the wire decodes like this:
//!
//! ```
//! use antigravity_codes::protocol::{OutputEvent, OutputEventEvent};
//!
//! // Exactly as a live harness emits it — note the stringified `seqNum`.
//! let frame = r#"{
//! "stepUpdate": {"cascadeId": "abc", "stepIndex": 0, "state": "STATE_DONE", "text": "hi"},
//! "seqNum": "3",
//! "timestampMicros": "1786220347646352"
//! }"#;
//!
//! let event: OutputEvent = serde_json::from_str(frame).unwrap();
//! assert_eq!(event.sequence(), Some(3));
//!
//! let Some(OutputEventEvent::StepUpdate(step)) = event.into_event() else {
//! panic!("expected a step update")
//! };
//! assert_eq!(step.text.as_deref(), Some("hi"));
//! assert!(step.is_terminal());
//! ```
//!
//! # Feature Flags
//!
//! | Feature | Description | WASM-compatible |
//! |---------|-------------|-----------------|
//! | `types` | Wire types and the handshake codec only (serde) | Yes |
//! | `async-client` | Async WebSocket client using tokio | No |
//! | `integration-tests` | Enables tests that need a real harness binary | No |
//!
//! All features are enabled by default. For WASM or type-sharing use cases:
//!
//! ```toml
//! [dependencies]
//! antigravity-codes = { version = "0.1", default-features = false, features = ["types"] }
//! ```
//!
//! # Versioning
//!
//! The crate version tracks the `google-antigravity` release whose harness it
//! was generated from and tested against — see [`TESTED_SDK_VERSION`].
pub use ;
/// The `google-antigravity` release this crate's types were generated from and
/// tested against.
///
/// The harness exposes no version of its own — it takes no arguments and its
/// handshake reply carries only a port and a key — so the wheel version is the
/// only handle there is. Mismatches are not detectable at runtime; unknown enum
/// values and unknown `oneof` arms are absorbed by design instead.
pub const TESTED_SDK_VERSION: &str = "0.1.10";
pub use ;
pub use RawClient;
pub use ;
pub use ;