Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
78eaec8
Feat: Add previousInteractionId to LlmRequest and interactionId to Ll…
May 20, 2026
b7ff160
Feat: Implement and register InteractionsRequestProcessor
May 20, 2026
18494c0
Feat: Implement interactions_utils for mapping and running Interactio…
May 20, 2026
81285df
Feat: Integrate Interactions API into Gemini model class
May 20, 2026
ab2cf0b
Test: Add unit tests for Interactions API and verify script
May 20, 2026
3c044e8
Test: Add unit test edge cases for 100% statement and branch coverage
May 20, 2026
8aa7b81
Fix: Remove MIME type checking code duplication and delete verificati…
May 21, 2026
a7fe707
Chore: Upgrade @google/genai SDK to version 2.0.0
May 21, 2026
b181159
Fix: Update copyright year to 2026 and reuse base64Encode utility
May 21, 2026
c219001
Fix: Point @google/genai package resolution to public registry to res…
May 21, 2026
205a906
Fix: Make structural interfaces independent to resolve strict GenAI S…
May 21, 2026
c4561d4
Refactor interactions API integration to use native SDK types and res…
Jun 1, 2026
7a2cb68
Merge branch 'main' into feat/interactions-api-2
AmaadMartin Jun 1, 2026
f9d74a6
refactor(test): optimize interactions utils and fix agent loader test…
Jun 1, 2026
50e0152
refactor(types): remove explicit any and eslint-disable from interact…
Jun 1, 2026
b96ee03
Merge branch 'main' into feat/interactions-api-2
AmaadMartin Jun 2, 2026
4ed4f03
Merge branch 'main' into feat/interactions-api-2
AmaadMartin Jun 2, 2026
2d303eb
Merge branch 'main' into feat/interactions-api-2
AmaadMartin Jun 3, 2026
1ff040d
Merge branch 'main' into feat/interactions-api-2
AmaadMartin Jun 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"@google-cloud/opentelemetry-cloud-trace-exporter": "^3.0.0",
"@google-cloud/storage": "^7.17.1",
"@google-cloud/vertexai": "^1.12.0",
"@google/genai": "^1.37.0",
"@google/genai": "^2.0.0",
"@mikro-orm/core": "^6.6.10",
"@mikro-orm/reflection": "^6.6.6",
"@modelcontextprotocol/sdk": "^1.26.0",
Expand Down
2 changes: 2 additions & 0 deletions core/src/agents/llm_agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import {CONTENT_REQUEST_PROCESSOR} from './processors/content_request_processor.
import {ContextCompactorRequestProcessor} from './processors/context_compactor_request_processor.js';
import {IDENTITY_LLM_REQUEST_PROCESSOR} from './processors/identity_llm_request_processor.js';
import {INSTRUCTIONS_LLM_REQUEST_PROCESSOR} from './processors/instructions_llm_request_processor.js';
import {INTERACTIONS_REQUEST_PROCESSOR} from './processors/interactions_request_processor.js';
import {REQUEST_CONFIRMATION_LLM_REQUEST_PROCESSOR} from './processors/request_confirmation_llm_request_processor.js';
import {TOOL_FILTER_REQUEST_PROCESSOR} from './processors/tool_filter_request_processor.js';
import {ReadonlyContext} from './readonly_context.js';
Expand Down Expand Up @@ -396,6 +397,7 @@ export class LlmAgent extends BaseAgent {
INSTRUCTIONS_LLM_REQUEST_PROCESSOR,
REQUEST_CONFIRMATION_LLM_REQUEST_PROCESSOR,
CONTENT_REQUEST_PROCESSOR,
INTERACTIONS_REQUEST_PROCESSOR,
CODE_EXECUTION_REQUEST_PROCESSOR,
TOOL_FILTER_REQUEST_PROCESSOR,
];
Expand Down
49 changes: 49 additions & 0 deletions core/src/agents/processors/interactions_request_processor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {Event} from '../../events/event.js';
import {Gemini} from '../../models/google_llm.js';
import {LlmRequest} from '../../models/llm_request.js';
import {InvocationContext} from '../invocation_context.js';
import {isLlmAgent} from '../llm_agent.js';
import {BaseLlmRequestProcessor} from './base_llm_processor.js';

/**
* Request processor for Gemini Interactions API.
* Resolves the previous interaction ID from the session history.
*/
export class InteractionsRequestProcessor implements BaseLlmRequestProcessor {
// eslint-disable-next-line require-yield
async *runAsync(
invocationContext: InvocationContext,
llmRequest: LlmRequest,
): AsyncGenerator<Event, void, void> {
const agent = invocationContext.agent;
if (!agent || !isLlmAgent(agent)) {
return;
}

const model = agent.canonicalModel;
if (model instanceof Gemini && model.useInteractionsApi) {
const events = invocationContext.session.events;
for (let i = events.length - 1; i >= 0; i--) {
const event = events[i];
// Skip events not belonging to the current branch or author
if (
event.branch === invocationContext.branch &&
event.author === agent.name &&
event.interactionId
) {
llmRequest.previousInteractionId = event.interactionId;
break;
}
}
}
}
}

export const INTERACTIONS_REQUEST_PROCESSOR =
new InteractionsRequestProcessor();
4 changes: 4 additions & 0 deletions core/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ export {
ContentRequestProcessor,
} from './agents/processors/content_request_processor.js';
export {ContextCompactorRequestProcessor} from './agents/processors/context_compactor_request_processor.js';
export {
INTERACTIONS_REQUEST_PROCESSOR,
InteractionsRequestProcessor,
} from './agents/processors/interactions_request_processor.js';
export {ReadonlyContext} from './agents/readonly_context.js';
export {RoutedAgent, isRoutedAgent} from './agents/routed_agent.js';
export type {AgentRouter, RoutedAgentConfig} from './agents/routed_agent.js';
Expand Down
12 changes: 12 additions & 0 deletions core/src/models/google_llm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {StreamingResponseAggregator} from '../utils/streaming_utils.js';
import {BaseLlm} from './base_llm.js';
import {BaseLlmConnection} from './base_llm_connection.js';
import {GeminiLlmConnection} from './gemini_llm_connection.js';
import {generateContentViaInteractions} from './interactions_utils.js';
import {LlmRequest} from './llm_request.js';
import {createLlmResponse, LlmResponse} from './llm_response.js';

Expand Down Expand Up @@ -53,6 +54,10 @@ export interface GeminiParams {
* Headers to merge with internally crafted headers.
*/
headers?: Record<string, string>;
/**
* Whether to use the Interactions API for stateful conversations.
*/
useInteractionsApi?: boolean;
}

/**
Expand All @@ -64,6 +69,7 @@ export class Gemini extends BaseLlm {
private readonly project?: string;
private readonly location?: string;
private readonly headers?: Record<string, string>;
readonly useInteractionsApi: boolean;

/**
* @param params The parameters for creating a Gemini instance.
Expand All @@ -75,6 +81,7 @@ export class Gemini extends BaseLlm {
project,
location,
headers,
useInteractionsApi,
}: GeminiParams) {
if (!model) {
model = 'gemini-2.5-flash';
Expand All @@ -99,6 +106,7 @@ export class Gemini extends BaseLlm {
this.apiKey = params.apiKey;
this.headers = headers;
this.vertexai = !!params.vertexai;
this.useInteractionsApi = !!useInteractionsApi;
}

/**
Expand Down Expand Up @@ -132,6 +140,10 @@ export class Gemini extends BaseLlm {
stream = false,
abortSignal?: AbortSignal,
): AsyncGenerator<LlmResponse, void> {
if (this.useInteractionsApi) {
yield* generateContentViaInteractions(this.apiClient, llmRequest, stream);
return;
}
this.preprocessRequest(llmRequest);
this.maybeAppendUserContent(llmRequest);
logger.info(
Expand Down
Loading
Loading