v0.7.9 RELEASED – Vertex AI via OpenAI-compatible endpoint + Google ADK agent witnessing. Available on PyPI and npm.

Who this is for: GCP developers using Vertex AI or Gemini API, platform engineers managing AI workloads on Google Cloud, compliance teams building evidence pipelines for regulated AI, and auditors evaluating Google Cloud AI deployments.

The evidence gap in every Vertex AI deployment. Google provides Vertex AI audit logs, Model Garden cards, and Responsible AI practices. These cover platform-level operations. When your application calls gemini-2.0-flash for a customer-facing decision, what evidence proves that specific inference was governed at the application layer?

Contents

1. Two Paths to Witnessing 2. Vertex AI Inference Witnessing 3. Gemini API Direct 4. Google ADK Agent Witnessing 5. Vertex AI Audit Log Complementarity 6. Regulatory Evidence Mapping 7. Quick Start 8. References

1. Two Paths to Witnessing

There are two integration paths for witnessing Google AI inference. Which one you choose depends on how your application calls the model.

Path SDK Method Adapter What It Captures Best For
Vertex AI / Gemini API
OpenAI-compatible endpoint
witness.wrap(client) OpenAI adapter Per-inference evidence: prompt hash, response hash, model ID, token usage, latency Direct model inference via Vertex AI or the Gemini API
Google ADK Agent
Agent Development Kit wrapper
wrap_google_adk(agent, witness) Google ADK adapter Agent-level evidence: input, output, model used, total execution time ADK agent workflows with multi-step reasoning and tool use

These paths are independent. Use one or both depending on your architecture. If you call Gemini directly for inference, use Path 1. If you run ADK agents, use Path 2. If your ADK agents call Gemini internally, Path 2 witnesses the agent boundary -- you do not need to also wrap the internal model calls.

2. Vertex AI Inference Witnessing

Vertex AI now exposes an OpenAI-compatible endpoint. This means the standard OpenAI adapter works out of the box. Point the OpenAI client at the Vertex AI endpoint, wrap it with the witness, and every inference is captured.

Python

from openai import OpenAI
from swt3_ai import Witness

witness = Witness(
    endpoint="https://your-instance.example.com/api/v1/witness",
    api_key="axm_live_...",
    tenant_id="YOUR_TENANT",
)

client = witness.wrap(OpenAI(
    base_url="https://REGION-aiplatform.googleapis.com/v1/projects/PROJECT/locations/REGION/endpoints/openapi",
    api_key="YOUR_GCP_TOKEN",
))

response = client.chat.completions.create(
    model="google/gemini-2.0-flash",
    messages=[{"role": "user", "content": "Classify this support ticket."}],
)

witness.flush()

TypeScript

import OpenAI from 'openai';
import { Witness } from '@tenova/swt3-ai';

const witness = new Witness({
  endpoint: 'https://your-instance.example.com/api/v1/witness',
  apiKey: 'axm_live_...',
  tenantId: 'YOUR_TENANT',
});

const client = witness.wrap(new OpenAI({
  baseURL: 'https://REGION-aiplatform.googleapis.com/v1/projects/PROJECT/locations/REGION/endpoints/openapi',
  apiKey: 'YOUR_GCP_TOKEN',
}));

const response = await client.chat.completions.create({
  model: 'google/gemini-2.0-flash',
  messages: [{ role: 'user', content: 'Classify this support ticket.' }],
});

await witness.flush();

Why this works: Vertex AI's OpenAI-compatible endpoint accepts the same request format as OpenAI's API. The SWT3 OpenAI adapter intercepts the call transparently. The provider tag in the witness record will read openai (since the client is an OpenAI SDK instance), but the model_id field captures the actual model name -- google/gemini-2.0-flash -- which is the value that matters for audit purposes.

AI-INF.1 -- Inference Witnessing

What the anchor captures

model_id: google/gemini-2.0-flash -- the Gemini model name exactly as passed to the API.

prompt_hash: SHA-256 of the prompt content. Proves what was sent without storing the content.

response_hash: SHA-256 of the model response. Proves what was received without storing the content.

latency_ms: Wall-clock time for the inference call.

Assessor tip

The anchor captures the Gemini model version even though the underlying client is the OpenAI SDK. Verify the model_id field contains the expected Gemini model identifier (e.g., google/gemini-2.0-flash). If it shows a generic name like gpt-4, the application is not correctly specifying the Vertex AI model -- this is a configuration finding, not a witness protocol issue.

3. Gemini API Direct

For developers using the Gemini API directly (not through Vertex AI), Google also provides an OpenAI-compatible endpoint at generativelanguage.googleapis.com. The same pattern applies -- point the OpenAI client at the Gemini endpoint and wrap it.

Python

from openai import OpenAI
from swt3_ai import Witness

witness = Witness(
    endpoint="https://your-instance.example.com/api/v1/witness",
    api_key="axm_live_...",
    tenant_id="YOUR_TENANT",
)

client = witness.wrap(OpenAI(
    base_url="https://generativelanguage.googleapis.com/v1beta/openai/",
    api_key="YOUR_GEMINI_KEY",
))

response = client.chat.completions.create(
    model="gemini-2.0-flash",
    messages=[{"role": "user", "content": "Summarize this contract clause."}],
)

witness.flush()

TypeScript

import OpenAI from 'openai';
import { Witness } from '@tenova/swt3-ai';

const witness = new Witness({
  endpoint: 'https://your-instance.example.com/api/v1/witness',
  apiKey: 'axm_live_...',
  tenantId: 'YOUR_TENANT',
});

const client = witness.wrap(new OpenAI({
  baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai/',
  apiKey: 'YOUR_GEMINI_KEY',
}));

const response = await client.chat.completions.create({
  model: 'gemini-2.0-flash',
  messages: [{ role: 'user', content: 'Summarize this contract clause.' }],
});

await witness.flush();

Vertex AI vs. Gemini API: The Vertex AI endpoint routes through your GCP project and inherits its IAM, VPC, and audit log configuration. The Gemini API endpoint is a standalone API with its own key. Both produce identical witness anchors. Choose based on your organization's infrastructure requirements -- Vertex AI for enterprise GCP environments, Gemini API for simpler deployments.

System Prompt Witnessing

Both the Vertex AI and Gemini API paths use the OpenAI-compatible message format, which means system prompts are role: "system" messages in the messages array. The adapter extracts and hashes them independently as system_prompt_hash -- the same behavior as direct OpenAI usage.

response = client.chat.completions.create(
    model="google/gemini-2.0-flash",
    messages=[
        {"role": "system", "content": "You are a document classifier for regulated industries."},
        {"role": "user", "content": "Classify this filing."},
    ],
)
# system_prompt_hash captures the classifier instructions for this call

If your system prompt changes between deployments, the hash changes automatically. This creates drift evidence for Gemini deployments without any additional configuration.

AI-INF.2 -- System Prompt Governance

Configuration integrity for Gemini deployments

Assessor tip

Query the ledger for system_prompt_hash values on Gemini inference anchors. A stable hash across the assessment period proves the system prompt was consistent. A hash change proves it was modified -- cross-reference with the organization's change management records. This works identically for both Vertex AI and Gemini API paths.

4. Google ADK Agent Witnessing

The Agent Development Kit (ADK) is Google's framework for building multi-step AI agents. ADK agents may chain multiple model calls, use tools, and maintain state across turns. The ADK adapter witnesses the agent-level execution -- input in, result out -- rather than individual LLM calls within the agent loop.

Python

from swt3_ai import Witness
from swt3_ai.adapters.google_adk import wrap_google_adk

witness = Witness(
    endpoint="https://your-instance.example.com/api/v1/witness",
    api_key="axm_live_...",
    tenant_id="YOUR_TENANT",
    agent_id="claims-processor",
)

agent = wrap_google_adk(your_adk_agent, witness, model_id="gemini-2.0-flash")
result = agent.run("Process this customer request")

witness.flush()

TypeScript

import { Witness, wrapGoogleADK } from '@tenova/swt3-ai';

const witness = new Witness({
  endpoint: 'https://your-instance.example.com/api/v1/witness',
  apiKey: 'axm_live_...',
  tenantId: 'YOUR_TENANT',
  agentId: 'claims-processor',
});

const agent = wrapGoogleADK(yourAdkAgent, witness, { modelId: 'gemini-2.0-flash' });
const result = await agent.run('Process this customer request');

await witness.flush();

Why agent-level witnessing matters: ADK agents may invoke Gemini multiple times internally -- once to reason about the task, again to select a tool, again to interpret the tool's output. Witnessing each internal call would produce noise without compliance value. The ADK adapter witnesses the outer boundary: what went in, what came out, which model powered it, and how long the full execution took. This is the evidence surface that auditors need.

AI-INF.1 -- Agent-Level Witnessing

What the assessor verifies

Each ADK agent invocation produces a single anchor covering the full agent execution: prompt in, result out, model used, total wall-clock latency.

The agent_id field (e.g., claims-processor) links the anchor to the specific agent in your deployment. This allows auditors to trace a decision back to the responsible agent without parsing internal reasoning traces.

Assessor tip

The distinction between model-level and agent-level evidence matters. Model-level evidence (from witness.wrap()) proves a single LLM call happened. Agent-level evidence (from wrap_google_adk()) proves an autonomous workflow completed. For regulatory purposes, agent-level evidence is often more relevant because it maps to a business decision, not an infrastructure call. If the organization uses both paths, verify that agent anchors have agent_id set and model-only anchors do not -- this prevents double-counting in compliance reporting.

Full ADK integration details: For tool witnessing within ADK agents, multi-turn session handling, and advanced configuration, see the dedicated Google ADK Witnessing Guide.

5. Vertex AI Audit Log Complementarity

Vertex AI Cloud Audit Logs and SWT3 witness anchors serve different purposes. Neither replaces the other. Together, they form a complete evidence chain from infrastructure to application.

Evidence Dimension Vertex AI Audit Logs SWT3 Witness Anchors
Who called the model IAM principal, service account Not captured (infrastructure concern)
Which API was called Method, endpoint, parameters Not captured (infrastructure concern)
What was sent to the model Not logged (data residency) SHA-256 hash of prompt content
What the model returned Not logged (data residency) SHA-256 hash of response content
Which model version Model resource name model_id in anchor
Latency and token usage Partial (request latency only) Wall-clock latency + token counts
Tamper-evident record Mutable log sink Cryptographic fingerprint, independently verifiable
Cross-provider portability GCP-only Same anchor format across all providers
Complementary evidence layers

Combining Vertex audit logs with SWT3 anchors

Vertex AI audit logs answer "who called what API and when." SWT3 anchors answer "what did the AI decide and can you prove it." An auditor evaluating an AI deployment needs both layers. The audit log proves the infrastructure was used correctly. The witness anchor proves the AI decision was governed.

Assessor tip

Request the Vertex AI Cloud Audit Log export for the assessment period alongside the SWT3 ledger export. Cross-reference timestamps: every PredictRequest or GenerateContent entry in the audit log should have a corresponding SWT3 anchor within a 5-second window. If audit log entries exist without matching anchors, the application has an unwitnessed inference path -- a gap in the evidence chain. If anchors exist without matching audit log entries, the witness is recording calls from a non-GCP endpoint (e.g., Gemini API direct), which is valid but should match the organization's stated architecture.

6. Regulatory Evidence Mapping

Every witness anchor minted on Vertex AI or Gemini maps to specific regulatory obligations. This table shows which SWT3 procedure satisfies each requirement and what evidence the anchor provides.

Obligation Regulation SWT3 Evidence Procedure
Automatic logging of AI system operation EU AI Act Art. 12 Per-decision fingerprint with timestamp, model ID, and content hashes AI-INF.1
Transparency of AI output EU AI Act Art. 13 Response hash proves what the model returned at decision time AI-INF.1
Deployer obligation to monitor EU AI Act Art. 26 Continuous anchor stream proves ongoing monitoring is operational AI-INF.1
Document AI interfaces and dependencies NIST AI RMF MAP 1.5 Model ID, provider, agent_id, and latency in every anchor AI-INF.1
Track deployed AI behavior NIST AI RMF MN 2.2 Continuous decision-level tracking via anchor stream AI-INF.1
AI management system monitoring ISO 42001 Clause 9.1 Witness anchors as monitoring evidence for AI management system performance AI-INF.1
AI risk treatment evidence ISO 42001 Clause 8.3 Anchor density and refusal rates demonstrate risk controls are active AI-GRD.1
Agent identity and accountability NIST AI RMF GV 1.3 agent_id field on ADK anchors links decisions to specific agents AI-ID.1

Framework-specific crosswalks: For detailed mappings beyond this summary table, see the Google Gemini Agent Platform Crosswalk, the EU AI Act Compliance Crosswalk, and the NIST AI RMF Crosswalk.

7. Quick Start

Three lines to compliance evidence. Create the witness, wrap the client, flush when done. Every Gemini inference is now witnessed.

Install

# Python
pip install swt3-ai openai

# TypeScript
npm install @tenova/swt3-ai openai

Minimal Example (Vertex AI OpenAI-Compatible Endpoint)

from openai import OpenAI
from swt3_ai import Witness

witness = Witness(
    endpoint="https://your-instance.example.com/api/v1/witness",
    api_key="axm_live_...",
    tenant_id="YOUR_TENANT",
)

client = witness.wrap(OpenAI(
    base_url="https://REGION-aiplatform.googleapis.com/v1/projects/PROJECT/locations/REGION/endpoints/openapi",
    api_key="YOUR_GCP_TOKEN",
))

response = client.chat.completions.create(
    model="google/gemini-2.0-flash",
    messages=[{"role": "user", "content": "Classify this document."}],
)

witness.flush()

Four lines added to your existing code. Zero changes to application logic. Every Gemini inference now has a cryptographic witness anchor that survives independently of Google Cloud infrastructure.

Choose Your Path

If You Have Start With Lines of Code
Vertex AI with OpenAI-compat endpoint witness.wrap(OpenAI(base_url=vertex_url)) 1
Gemini API direct witness.wrap(OpenAI(base_url=gemini_url)) 1
Google ADK agents wrap_google_adk(agent, witness) 1

8. References

Other Witnessing Guides