Skip to content

Commit cfe49f6

Browse files
committed
docs: add Gemini Interactions API documentation page
Dedicated docs page covering request format (string/Turn[]/Content[]), fixture matching, SSE event format with lifecycle examples, recording configuration, and TanStack AI integration guide. Sidebar updated with Gemini Interactions nav entry.
1 parent 1a78981 commit cfe49f6

2 files changed

Lines changed: 349 additions & 0 deletions

File tree

Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Gemini Interactions — aimock</title>
7+
<link rel="icon" type="image/svg+xml" href="../favicon.svg" />
8+
<link rel="preconnect" href="https://fonts.googleapis.com" />
9+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10+
<link
11+
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=Instrument+Sans:wght@400;500;600;700&display=swap"
12+
rel="stylesheet"
13+
/>
14+
<link rel="stylesheet" href="../style.css" />
15+
</head>
16+
<body>
17+
<nav class="top-nav">
18+
<div class="nav-inner">
19+
<div style="display: flex; align-items: center; gap: 1rem">
20+
<button
21+
class="sidebar-toggle"
22+
onclick="document.querySelector('.sidebar').classList.toggle('open')"
23+
aria-label="Toggle sidebar"
24+
>
25+
&#9776;
26+
</button>
27+
<a href="/" class="nav-brand"> <span class="prompt">$</span> aimock </a>
28+
</div>
29+
<ul class="nav-links">
30+
<li><a href="/">Home</a></li>
31+
<li><a href="/docs" style="color: var(--accent)">Docs</a></li>
32+
<li>
33+
<a href="https://github.com/CopilotKit/aimock" class="gh-link" target="_blank"
34+
><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
35+
<path
36+
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"
37+
/>
38+
</svg>
39+
GitHub</a
40+
>
41+
</li>
42+
</ul>
43+
</div>
44+
</nav>
45+
46+
<div class="docs-layout">
47+
<aside class="sidebar" id="sidebar"></aside>
48+
49+
<main class="docs-content">
50+
<h1>Gemini Interactions API</h1>
51+
<p class="lead">
52+
The Gemini Interactions API is Google's stateful conversation endpoint. Unlike the
53+
standard
54+
<code>generateContent</code>/<code>streamGenerateContent</code> endpoints, Interactions
55+
uses <code>previous_interaction_id</code> for server-side conversation state, flat
56+
<code>outputs[]</code> instead of nested <code>candidates[].content.parts[]</code>, and
57+
typed SSE events with an <code>event_type</code> field inside each JSON payload.
58+
</p>
59+
60+
<h2>Endpoint</h2>
61+
<table class="endpoint-table">
62+
<thead>
63+
<tr>
64+
<th>Method</th>
65+
<th>Path</th>
66+
<th>Format</th>
67+
</tr>
68+
</thead>
69+
<tbody>
70+
<tr>
71+
<td>POST</td>
72+
<td>/v1beta/interactions</td>
73+
<td>SSE (typed JSON events)</td>
74+
</tr>
75+
</tbody>
76+
</table>
77+
78+
<h2>Quick Start</h2>
79+
<p>Set up a minimal mock that responds to a Gemini Interactions request:</p>
80+
81+
<div class="code-block">
82+
<div class="code-block-header">quick-start.ts <span class="lang-tag">ts</span></div>
83+
<pre><code><span class="kw">import</span> { <span class="type">LLMock</span> } <span class="kw">from</span> <span class="str">"@copilotkit/aimock"</span>;
84+
85+
<span class="kw">const</span> <span class="op">mock</span> = <span class="kw">new</span> <span class="type">LLMock</span>();
86+
<span class="op">mock</span>.<span class="fn">on</span>({ <span class="prop">userMessage</span>: <span class="str">"hello"</span> }, { <span class="prop">content</span>: <span class="str">"Hi there!"</span> });
87+
<span class="kw">await</span> <span class="op">mock</span>.<span class="fn">listen</span>(<span class="num">4010</span>);
88+
89+
<span class="cm">// Client sends:</span>
90+
<span class="cm">// POST /v1beta/interactions</span>
91+
<span class="cm">// { model: "gemini-2.5-flash", input: "hello", stream: true }</span></code></pre>
92+
</div>
93+
94+
<h2>Request Format</h2>
95+
<p>
96+
The Interactions API accepts several input shapes. aimock normalizes all of them into the
97+
unified fixture-matching format.
98+
</p>
99+
100+
<h3>String Input (Simple Prompt)</h3>
101+
<div class="code-block">
102+
<div class="code-block-header">string-input.json <span class="lang-tag">json</span></div>
103+
<pre><code>{
104+
<span class="prop">"model"</span>: <span class="str">"gemini-2.5-flash"</span>,
105+
<span class="prop">"input"</span>: <span class="str">"What is the capital of France?"</span>,
106+
<span class="prop">"stream"</span>: <span class="kw">true</span>
107+
}</code></pre>
108+
</div>
109+
110+
<h3>Turn[] Input (Multi-Turn)</h3>
111+
<div class="code-block">
112+
<div class="code-block-header">
113+
multi-turn-input.json <span class="lang-tag">json</span>
114+
</div>
115+
<pre><code>{
116+
<span class="prop">"model"</span>: <span class="str">"gemini-2.5-flash"</span>,
117+
<span class="prop">"input"</span>: [
118+
{ <span class="prop">"role"</span>: <span class="str">"user"</span>, <span class="prop">"parts"</span>: [{ <span class="prop">"type"</span>: <span class="str">"text"</span>, <span class="prop">"text"</span>: <span class="str">"Hello"</span> }] },
119+
{ <span class="prop">"role"</span>: <span class="str">"model"</span>, <span class="prop">"parts"</span>: [{ <span class="prop">"type"</span>: <span class="str">"text"</span>, <span class="prop">"text"</span>: <span class="str">"Hi there!"</span> }] },
120+
{ <span class="prop">"role"</span>: <span class="str">"user"</span>, <span class="prop">"parts"</span>: [{ <span class="prop">"type"</span>: <span class="str">"text"</span>, <span class="prop">"text"</span>: <span class="str">"Tell me a joke"</span> }] }
121+
],
122+
<span class="prop">"stream"</span>: <span class="kw">true</span>
123+
}</code></pre>
124+
</div>
125+
126+
<h3>Content[] with Function Result (Tool Response)</h3>
127+
<div class="code-block">
128+
<div class="code-block-header">
129+
tool-response-input.json <span class="lang-tag">json</span>
130+
</div>
131+
<pre><code>{
132+
<span class="prop">"model"</span>: <span class="str">"gemini-2.5-flash"</span>,
133+
<span class="prop">"input"</span>: [
134+
{
135+
<span class="prop">"role"</span>: <span class="str">"user"</span>,
136+
<span class="prop">"parts"</span>: [
137+
{ <span class="prop">"type"</span>: <span class="str">"function_result"</span>, <span class="prop">"name"</span>: <span class="str">"get_weather"</span>, <span class="prop">"call_id"</span>: <span class="str">"call_abc123"</span>, <span class="prop">"output"</span>: <span class="str">"72F sunny"</span> }
138+
]
139+
}
140+
],
141+
<span class="prop">"previous_interaction_id"</span>: <span class="str">"interaction_abc123"</span>,
142+
<span class="prop">"stream"</span>: <span class="kw">true</span>
143+
}</code></pre>
144+
</div>
145+
146+
<h3>Stateful Chaining</h3>
147+
<p>
148+
The <code>previous_interaction_id</code> field links turns together on the server side.
149+
Each response includes an <code>interaction_id</code> that the client passes as
150+
<code>previous_interaction_id</code> in the next request, eliminating the need to resend
151+
full conversation history.
152+
</p>
153+
154+
<h2>Fixture Matching</h2>
155+
<p>
156+
Fixtures use the same <code>match</code> object as all other providers. The most common
157+
matchers for Interactions are <code>userMessage</code> and <code>sequenceIndex</code>.
158+
</p>
159+
160+
<h3>userMessage Matching</h3>
161+
<div class="code-block">
162+
<div class="code-block-header">
163+
user-message-match.ts <span class="lang-tag">ts</span>
164+
</div>
165+
<pre><code><span class="kw">const</span> <span class="op">fixture</span> = {
166+
<span class="prop">match</span>: { <span class="prop">userMessage</span>: <span class="str">"hello"</span> },
167+
<span class="prop">response</span>: { <span class="prop">content</span>: <span class="str">"Hi from Gemini Interactions!"</span> },
168+
};</code></pre>
169+
</div>
170+
171+
<h3>sequenceIndex for Multi-Turn Chains</h3>
172+
<p>
173+
Since the Interactions API is stateful, multi-turn conversations are the primary use case.
174+
Use <code>sequenceIndex</code> to match by turn position:
175+
</p>
176+
<div class="code-block">
177+
<div class="code-block-header">sequence-match.ts <span class="lang-tag">ts</span></div>
178+
<pre><code><span class="kw">const</span> <span class="op">fixtures</span> = [
179+
{
180+
<span class="prop">match</span>: { <span class="prop">sequenceIndex</span>: <span class="num">0</span> },
181+
<span class="prop">response</span>: {
182+
<span class="prop">toolCalls</span>: [{ <span class="prop">name</span>: <span class="str">"get_weather"</span>, <span class="prop">arguments</span>: { <span class="prop">city</span>: <span class="str">"NYC"</span> } }]
183+
},
184+
},
185+
{
186+
<span class="prop">match</span>: { <span class="prop">sequenceIndex</span>: <span class="num">1</span> },
187+
<span class="prop">response</span>: { <span class="prop">content</span>: <span class="str">"The weather in NYC is 72F and sunny."</span> },
188+
},
189+
];
190+
191+
<span class="kw">const</span> <span class="op">instance</span> = <span class="kw">await</span> <span class="fn">createServer</span>(<span class="op">fixtures</span>);
192+
193+
<span class="cm">// Turn 1: model calls get_weather tool</span>
194+
<span class="cm">// Turn 2: after tool result, model produces final text</span></code></pre>
195+
</div>
196+
197+
<h2>SSE Event Format</h2>
198+
<p>
199+
Unlike standard Gemini SSE (bare <code>data:</code> chunks), the Interactions API uses
200+
typed events. Each SSE line is a <code>data:</code> JSON object containing an
201+
<code>event_type</code> field.
202+
</p>
203+
204+
<h3>Event Types</h3>
205+
<table class="endpoint-table">
206+
<thead>
207+
<tr>
208+
<th>Event Type</th>
209+
<th>Description</th>
210+
</tr>
211+
</thead>
212+
<tbody>
213+
<tr>
214+
<td><code>interaction.start</code></td>
215+
<td>Opening event with interaction_id and model metadata</td>
216+
</tr>
217+
<tr>
218+
<td><code>content.start</code></td>
219+
<td>Marks beginning of an output part</td>
220+
</tr>
221+
<tr>
222+
<td><code>content.delta</code></td>
223+
<td>Incremental text or function_call chunk</td>
224+
</tr>
225+
<tr>
226+
<td><code>content.stop</code></td>
227+
<td>Marks completion of an output part</td>
228+
</tr>
229+
<tr>
230+
<td><code>interaction.complete</code></td>
231+
<td>Final event with usage metadata and finish reason</td>
232+
</tr>
233+
</tbody>
234+
</table>
235+
236+
<h3>Text Streaming Example</h3>
237+
<div class="code-block">
238+
<div class="code-block-header">
239+
text-sse-events.txt <span class="lang-tag">text</span>
240+
</div>
241+
<pre><code>data: {"event_type":"interaction.start","interaction":{"id":"int_abc123","status":"in_progress"},"event_id":"evt_1"}
242+
243+
data: {"event_type":"content.start","index":0,"content":{"type":"text"},"event_id":"evt_2"}
244+
245+
data: {"event_type":"content.delta","index":0,"delta":{"type":"text","text":"Hi "},"event_id":"evt_3"}
246+
247+
data: {"event_type":"content.delta","index":0,"delta":{"type":"text","text":"there!"},"event_id":"evt_4"}
248+
249+
data: {"event_type":"content.stop","index":0,"event_id":"evt_5"}
250+
251+
data: {"event_type":"interaction.complete","interaction":{"id":"int_abc123","status":"completed","usage":{"total_input_tokens":5,"total_output_tokens":3,"total_tokens":8}},"event_id":"evt_6"}</code></pre>
252+
</div>
253+
254+
<h3>Tool Call Streaming Example</h3>
255+
<div class="code-block">
256+
<div class="code-block-header">
257+
tool-sse-events.txt <span class="lang-tag">text</span>
258+
</div>
259+
<pre><code>data: {"event_type":"interaction.start","interaction":{"id":"int_def456","status":"in_progress"},"event_id":"evt_1"}
260+
261+
data: {"event_type":"content.start","index":0,"content":{"type":"function_call"},"event_id":"evt_2"}
262+
263+
data: {"event_type":"content.delta","index":0,"delta":{"type":"function_call","id":"tc_abc123","name":"get_weather","arguments":{"city":"NYC"}},"event_id":"evt_3"}
264+
265+
data: {"event_type":"content.stop","index":0,"event_id":"evt_4"}
266+
267+
data: {"event_type":"interaction.complete","interaction":{"id":"int_def456","status":"requires_action","usage":{"total_input_tokens":8,"total_output_tokens":12,"total_tokens":20}},"event_id":"evt_5"}</code></pre>
268+
</div>
269+
270+
<h2>Recording</h2>
271+
<p>
272+
To record real Gemini Interactions API traffic, use the <code>gemini</code> provider
273+
settings (same base URL, same API key). The Interactions endpoint shares the Gemini
274+
infrastructure:
275+
</p>
276+
277+
<div class="code-block">
278+
<div class="code-block-header">record-config.ts <span class="lang-tag">ts</span></div>
279+
<pre><code><span class="kw">import</span> { <span class="type">LLMock</span> } <span class="kw">from</span> <span class="str">"@copilotkit/aimock"</span>;
280+
281+
<span class="kw">const</span> <span class="op">mock</span> = <span class="kw">new</span> <span class="type">LLMock</span>({
282+
<span class="prop">record</span>: {
283+
<span class="prop">providers</span>: {
284+
<span class="prop">gemini</span>: <span class="str">"https://generativelanguage.googleapis.com"</span>,
285+
},
286+
},
287+
});
288+
<span class="kw">await</span> <span class="op">mock</span>.<span class="fn">listen</span>(<span class="num">4010</span>);</code></pre>
289+
</div>
290+
291+
<p>
292+
Unmatched requests to <code>/v1beta/interactions</code> are proxied to the real API, and
293+
the response is recorded as a new fixture.
294+
</p>
295+
296+
<h2>Integration with TanStack AI</h2>
297+
<p>
298+
TanStack AI provides a <code>geminiTextInteractions()</code> adapter for the Interactions
299+
API. When your client uses this adapter, point it at your aimock instance and the same
300+
fixtures will serve the responses. See the
301+
<a href="https://ai.tanstack.com" target="_blank">TanStack AI docs</a> for adapter
302+
configuration.
303+
</p>
304+
305+
<h2>Known Limitations</h2>
306+
<div class="info-box">
307+
<p>
308+
The Gemini Interactions API is currently in <strong>beta</strong>. Both the real API and
309+
aimock's support for it are subject to change as the API stabilizes.
310+
</p>
311+
</div>
312+
<ul>
313+
<li>
314+
<strong>Beta API</strong> &mdash; event types and request shapes may shift between
315+
releases.
316+
</li>
317+
<li>
318+
<strong>Text output + function tools only</strong> &mdash; the current scope covers text
319+
generation and function calling.
320+
</li>
321+
<li>
322+
<strong>Built-in tools not supported</strong> &mdash; Google's built-in tools
323+
(<code>google_search</code>, <code>code_execution</code>) are not yet mocked.
324+
</li>
325+
<li>
326+
<strong>Non-text modalities not supported</strong> &mdash; image, audio, and video
327+
inputs/outputs are not handled by this endpoint.
328+
</li>
329+
</ul>
330+
</main>
331+
<aside class="page-toc" id="page-toc"></aside>
332+
</div>
333+
<footer class="docs-footer">
334+
<div class="footer-inner">
335+
<div class="footer-left"><span>$</span> aimock &middot; MIT License</div>
336+
<ul class="footer-links">
337+
<li><a href="https://github.com/CopilotKit/aimock" target="_blank">GitHub</a></li>
338+
<li>
339+
<a href="https://www.npmjs.com/package/@copilotkit/aimock" target="_blank">npm</a>
340+
</li>
341+
</ul>
342+
</div>
343+
</footer>
344+
<script src="../sidebar.js"></script>
345+
<script src="../cli-tabs.js"></script>
346+
</body>
347+
</html>

docs/sidebar.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
{ label: "Quick Start: LLM", href: "/chat-completions" },
1111
{ label: "Quick Start: aimock", href: "/aimock-cli" },
1212
{ label: "Examples", href: "/examples" },
13+
{ label: "MCP Server", href: "/mcp" },
1314
],
1415
},
1516
{
@@ -19,6 +20,7 @@
1920
{ label: "Responses API (OpenAI)", href: "/responses-api" },
2021
{ label: "Claude Messages", href: "/claude-messages" },
2122
{ label: "Gemini", href: "/gemini" },
23+
{ label: "Gemini Interactions", href: "/gemini-interactions" },
2224
{ label: "Azure OpenAI", href: "/azure-openai" },
2325
{ label: "AWS Bedrock", href: "/aws-bedrock" },
2426
{ label: "Ollama", href: "/ollama" },

0 commit comments

Comments
 (0)