Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ The CLI passes both values to the Select AI SDK as `wallet_location` and
The server accepts both A2A 1.x and the A2A v0.3 JSON-RPC streaming protocol
for compatibility with Gemini Enterprise.

See the [A2A user guide](doc/source/user_guide/a2a.rst) for the dynamic
gateway, A2UI connection flow, persistent task state, task polling and
See the [A2A user guide](doc/source/user_guide/a2a.rst) for dynamic sessions,
the A2UI connection flow, persistent task state, task polling and
cancellation, wallet configuration, and Google Cloud deployment modes.

Generate the A2A v0.3 Agent Card to paste into Gemini Enterprise after the
Expand Down
6 changes: 3 additions & 3 deletions doc/source/image/a2a_architecture.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
248 changes: 163 additions & 85 deletions doc/source/user_guide/a2a.rst

Large diffs are not rendered by default.

60 changes: 35 additions & 25 deletions doc/source/user_guide/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,6 @@ current defaults:

select-ai a2a --help
select-ai a2a serve --help
select-ai a2a gateway --help
select-ai a2a worker --help
select-ai a2a agent-card --help

Expand All @@ -218,11 +217,9 @@ current defaults:
* - Command
- Purpose
* - ``select-ai a2a serve``
- Start a standalone A2A HTTP server for one configured database AI Agent
Team. It accepts the database connection and optional wallet options.
* - ``select-ai a2a gateway``
- Start the public dynamic A2A/A2UI gateway. It uses Consul to discover
workers and does not connect to Oracle directly.
- Start the public A2A HTTP server in standalone or clustered deployment
mode. Standalone accepts database connection and wallet options;
clustered uses Consul to discover workers.
* - ``select-ai a2a worker``
- Start the internal worker that registers with Consul and creates an
isolated database-bearing child process for each submitted connection.
Expand Down Expand Up @@ -260,6 +257,12 @@ Important options are ``--team`` (required), ``--host``, ``--port``,
wallet for this standalone path. If no password is provided, the command
prompts for it.

By default, ``a2a serve`` does not require an application OAuth token and
separates database sessions by A2A conversation. Add ``--require-oauth`` to
require ``Authorization: Bearer ...`` and scope sessions by authenticated
owner as well as conversation. The Agent Card advertises bearer security only
in that mode.

Dynamic gateway and worker
--------------------------

Expand All @@ -270,29 +273,38 @@ passing the A2UI form values to the worker.

.. code-block:: bash

CONSUL_HTTP_URL=http://127.0.0.1:8500 \
WORKER_ID=local-worker \
WORKER_ADDRESS=127.0.0.1 \
WORKER_PORT=8081 \
select-ai a2a worker --host 127.0.0.1 --port 8081
select-ai a2a worker \
--host 127.0.0.1 \
--port 8081 \
--consul-url http://127.0.0.1:8500 \
--worker-id local-worker \
--worker-endpoint http://127.0.0.1:8081

select-ai a2a gateway \
select-ai a2a serve \
--deployment clustered \
--host 127.0.0.1 \
--port 8000 \
--agent-url http://127.0.0.1:8000 \
--public-url http://127.0.0.1:8000 \
--consul-url http://127.0.0.1:8500

The worker options are ``--host``, ``--port``, ``--session-ttl-seconds``, and
``--session-start-timeout-seconds``. Its registration can be configured with
the ``CONSUL_HTTP_URL``, ``WORKER_ID``, ``WORKER_ADDRESS``, ``WORKER_PORT``,
and optional ``WORKER_ENDPOINT`` environment variables. The worker's
``--tls-cert-file``, ``--tls-key-file``, and ``--tls-ca-file`` options enable
gateway-to-worker mTLS; provide all three together.

The gateway options are ``--agent-url`` (required, or ``AGENT_URL``),
The worker options are ``--host``, ``--port``, ``--worker-id``,
``--consul-url``, ``--worker-endpoint``, ``--session-ttl-seconds``, and
``--session-start-timeout-seconds``. ``WORKER_ID``, ``CONSUL_HTTP_URL``, and
``WORKER_ENDPOINT`` are environment fallbacks; explicit command-line values
take precedence. ``--port`` is also the port registered with Consul. Cluster
manifests can set ``WORKER_ADDRESS`` to the pod IP when no endpoint is
supplied. The worker's ``--tls-cert-file``, ``--tls-key-file``, and
``--tls-ca-file`` options enable gateway-to-worker mTLS; provide all three
together.

The clustered serve options are ``--public-url`` (or ``PUBLIC_URL``),
``--consul-url`` (or ``CONSUL_HTTP_URL``), ``--worker-service`` (or
``WORKER_SERVICE``), and ``--session-ttl-seconds`` (or
``SESSION_TTL_SECONDS``). The optional
``SESSION_TTL_SECONDS``). ``--dsn``, ``--user``, ``--password``, and ``--team``
fix any supplied connection values; the generated A2UI form contains only the
missing values. ``--a2ui-form`` loads a custom A2UI JSON form that must submit
exactly those missing values. ``--require-oauth`` has the same ownership
behavior in standalone and clustered deployments. The optional
``--worker-tls-ca-file``, ``--worker-tls-cert-file``, and
``--worker-tls-key-file`` options configure the gateway's client side of
gateway-to-worker mTLS. These TLS settings protect the internal HTTP hop and
Expand Down Expand Up @@ -341,9 +353,7 @@ Command summary
* - ``select-ai profile translate``
- Translate text with a saved profile.
* - ``select-ai a2a serve``
- Start the standalone A2A server.
* - ``select-ai a2a gateway``
- Start the public dynamic A2A gateway.
- Start the public A2A server in standalone or clustered mode.
* - ``select-ai a2a worker``
- Start the internal dynamic-session worker.
* - ``select-ai a2a agent-card``
Expand Down
20 changes: 14 additions & 6 deletions docker/a2a-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,21 @@ if [ -f "$wallet_archive" ]; then
export SELECT_AI_WALLET_LOCATION="$(dirname "$wallet_file")"
fi

: "${SELECT_AI_A2A_TEAM:?SELECT_AI_A2A_TEAM is required}"
: "${PUBLIC_URL:?PUBLIC_URL is required}"
: "${SELECT_AI_POOL_MAX_SIZE:=10}"

exec select-ai a2a serve \
--team "$SELECT_AI_A2A_TEAM" \
--host 0.0.0.0 \
--port "${PORT:-8080}" \
--pool-max-size "$SELECT_AI_POOL_MAX_SIZE" \
serve_args=(
--deployment standalone
--host 0.0.0.0
--port "${PORT:-8080}"
--pool-max-size "$SELECT_AI_POOL_MAX_SIZE"
--public-url "$PUBLIC_URL"
)
if [ -n "${SELECT_AI_A2A_TEAM:-}" ]; then
serve_args+=(--team "$SELECT_AI_A2A_TEAM")
fi
if [ "${SELECT_AI_A2A_REQUIRE_OAUTH:-false}" = "true" ]; then
serve_args+=(--require-oauth)
fi

exec select-ai a2a serve "${serve_args[@]}"
156 changes: 74 additions & 82 deletions gcloud/README.md
Original file line number Diff line number Diff line change
@@ -1,115 +1,107 @@
# Google Cloud deployment modes

Select AI for Python supports two A2A deployment architectures. The key
decisions are where the database connection and Select AI team are selected,
which components carry the session, and how capacity is added:

- Standalone fixes the database and team at deployment time. One Cloud Run A2A
service owns the configured connection pool and serves that team.
- The gateway selects the database and team per user session. A Cloud Run A2A
gateway routes sessions through Consul to a clustered GKE worker pool, with
one isolated child runtime and database connection pool per active session.

The gateway architecture is designed for horizontal session capacity. Gateway
instances, Consul, and worker replicas are separate components; adding worker
replicas increases the number of concurrent database sessions that can be
hosted behind the same A2A endpoint. Consul preserves session and task affinity
when requests reach different gateway instances. Oracle Database capacity and
the configured session TTL remain the limiting factors.
Select AI for Python supports three Google Cloud A2A deployment profiles. The
profiles keep deployment topology separate from connection provisioning:

1. **Fixed standalone** runs one Cloud Run service with DSN, username,
password, and team fixed by deployment. It uses the shared connection pool
and supports streaming.
2. **Dynamic standalone** runs one Cloud Run service. Connection URL and AI
Agent may be fixed independently by deployment; each user supplies all
remaining connection values through A2UI and receives an isolated
child-process session. Its in-memory routing requires exactly one Cloud Run
instance and streaming is disabled.
3. **Clustered dynamic** runs the same public A2A contract on Cloud Run, with
Consul and workers on GKE. DSN and team are fixed; each user supplies
username and password through A2UI. Consul provides distributed routing and
workers own the isolated session processes.

![Select AI A2A deployment architecture](../doc/source/image/a2a_architecture.svg)

The A2A commands are cloud-neutral: `select-ai a2a serve`,
`select-ai a2a gateway`, and `select-ai a2a worker` can run as processes or
containers on any cloud platform, a Kubernetes cluster, or self-managed
infrastructure with the required Oracle and Consul connectivity. The scripts
in this directory are optional Google Cloud automation for the Cloud Run/GKE
topologies shown below.
The A2A commands are cloud-neutral. These scripts are optional Google Cloud
automation for the Cloud Run and GKE profiles.

## What the A2A client connects to
## Standalone deployments

### Standalone server
Use the same script with an explicit connection mode.

The standalone deployment is one Cloud Run A2A service for one configured
Oracle database and one Select AI team.

The service receives its database credentials from Secret Manager. The A2A
client can discover the Agent Card and immediately send a database prompt.
The server supports blocking tasks, task polling, and streaming responses.

Deploy it with:
Dynamic standalone:

```bash
gcloud/standalone/deploy.sh --build
gcloud/standalone/deploy.sh \
--project PROJECT_ID \
--connection-mode dynamic \
--build
```

Use [standalone deployment](standalone/README.md) for the deployment details.
Fixed standalone:

### Dynamic gateway
```bash
gcloud/standalone/deploy.sh \
--project PROJECT_ID \
--connection-mode fixed \
--a2a-team ORACLE_AI_DATABASE_AGENT \
--build
```

The gateway deployment provides one public A2A endpoint for users who choose
the database and Select AI team at runtime.
The modes use distinct default services:

The client first sends a message and receives an A2UI connection form. After
the client submits the DSN, username, password, and team name, the gateway
opens a temporary worker session. Subsequent A2A messages use that session and
execute against the selected database and team.
- `select-ai-a2a-standalone-dynamic`
- `select-ai-a2a-standalone-fixed`

The gateway supports blocking tasks and asynchronous task polling. Its Agent
Card advertises `streaming: false`; clients use `message/send` followed by
`tasks/get` for long-running work. The gateway-to-worker path uses internal
protobuf messages, while the public client-facing path remains A2A JSON-RPC.
See the [standalone deployment guide](standalone/README.md).

The gateway database session currently accepts a DSN, username, and password.
Wallet-based Oracle Database mTLS is not yet supported by this session path.
The optional mTLS deployment mode described in the gateway documentation
secures the gateway-to-worker connection; it is separate from database mTLS.
The standalone guide also shows how to select the newest existing image
directly from Artifact Registry by immutable digest. Use that workflow when
creating another Cloud Run service without rebuilding an identical image or
depending on an existing service as the image source.

Deploy it with:
## Clustered dynamic deployment

```bash
gcloud/gateway/deploy.sh --project PROJECT_ID
gcloud/cluster/deploy.sh --project PROJECT_ID
```

Use [gateway deployment](gateway/README.md) for the deployment details.
Pass `--image-uri IMAGE@sha256:DIGEST` to reuse an existing immutable image
for both the Cloud Run server and GKE workers instead of building another one.

The default GKE cluster and public Cloud Run service are both named
`select-ai-a2a-cluster` in their respective resource namespaces. The server uses direct VPC egress to
reach Consul and the GKE workers. The worker transport is private HTTP by
default; optional mTLS protects the server-to-worker hop. Wallet-based Oracle
Database mTLS is not yet supported for dynamic sessions.

See the [cluster deployment guide](cluster/README.md).

## Client-visible differences

| Client concern | Standalone server | Dynamic gateway |
| --- | --- | --- |
| Database/team selection | Configured by the deployment | Submitted by each user session through A2UI |
| First client operation | Send the database prompt | Send a prompt, submit the connection form, then send the database prompt |
| Credentials | Stored in Secret Manager for the service | Supplied for the temporary session and held by its worker |
| Database mTLS | Supported through the standalone wallet configuration | Not yet supported for gateway database sessions |
| Public service | One Cloud Run A2A service | Cloud Run gateway backed by GKE workers and Consul |
| Agent Card input | `text/plain` | `text/plain` and `application/json+a2ui` |
| Agent Card streaming | `true` | `false` |
| Blocking request | `message/send` waits for the final task result | `message/send` waits for the final task result after the session is connected |
| Streaming response | Supported through A2A streaming methods and SSE | Not available; clients use task polling |
| Asynchronous task | `message/send` with `configuration.blocking: false` | `message/send` with `configuration.blocking: false` |
| Task polling | `tasks/get` until the task reaches a terminal state | `tasks/get` until the task reaches a terminal state |
| Session ownership | Cloud Run service database pool | One child process and async pool per active user session |
| Task/context storage | Oracle Database | Oracle Database, with Consul routing metadata |
| Capacity control | Cloud Run instances and per-instance pool size | Gateway instances, Consul routing, worker replicas, per-session pools, and session TTL |
| Best fit | One known database/team and predictable operations | Multiple databases/teams selected dynamically from one endpoint |

Both deployments expose the public A2A endpoint at:
| Concern | Fixed standalone | Dynamic standalone | Clustered dynamic |
| --- | --- | --- | --- |
| Topology | Cloud Run | One Cloud Run instance | Cloud Run + Consul + GKE workers |
| Deployment-fixed values | Connection URL, username, password, AI Agent | Any subset of Connection URL and AI Agent | Connection URL and AI Agent |
| A2UI form | None | All connection values not fixed by deployment | Username and password |
| Database runtime | Shared configured pool | Isolated local child process | Isolated worker child process |
| Streaming | Supported | Not currently supported | Not currently supported |
| Task/context storage | Oracle Database | Oracle Database | Oracle Database with Consul routing metadata |
| Scaling | Cloud Run instances and pool size | One Cloud Run instance | Cloud Run instances and worker replicas |

All three expose:

```text
/.well-known/agent-card.json
/a2a/jsonrpc/
```

Both accept A2A 1.0 method names and the A2A v0.3 compatibility method names.
The gateway client flow is documented in the
[gateway samples](../samples/a2a/gateway/README.md).

## Which deployment should you choose?
They accept A2A 1.0 method names and the A2A v0.3 compatibility method names.
The connection-form client flow is documented in the
[dynamic-session samples](../samples/a2a/dynamic/README.md).

Choose the standalone server when the service owner controls the database
identity and team, wants clients to send prompts immediately, and benefits
from streaming responses.
By default, the private Cloud Run deployments rely on Cloud Run IAM and keep
database sessions separate by A2A conversation. Add `--require-oauth` to
either deployment script when verified human-user ownership is required. In
that mode Gemini Enterprise must be configured with end-user OAuth and sends
its user token in `Authorization`; missing tokens receive HTTP 401.

Choose the gateway when one A2A endpoint must serve users selecting different
Oracle databases or teams, with isolated temporary sessions and worker-based
capacity.
`X-Serverless-Authorization` is separate and automatic: Gemini Enterprise uses
it to invoke the private Cloud Run service, and Cloud Run consumes it before
the request reaches `a2a serve`.
Loading