Skip to content

Commit 4a860a8

Browse files
committed
Merge branch 'a2a/poc' into dev/1.5.0
2 parents ec8e85a + f855142 commit 4a860a8

27 files changed

Lines changed: 1414 additions & 24 deletions

‎.dockerignore‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
.git
2+
.venv
3+
.pytest_cache
4+
.ruff_cache
5+
__pycache__
6+
*.py[cod]
7+
*.egg-info
8+
.coverage
9+
htmlcov
10+
build
11+
dist
12+
docs
13+
tests
14+
samples
15+
.env
16+
.env.*
17+
wallet
18+
wallets
19+
*.pem
20+
*.key
21+
*.sso
22+
*.p12
23+
*.zip

‎.gcloudignore‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Keep the Cloud Build source upload small and exclude local credentials.
2+
#!include:.gitignore
3+
4+
.git
5+
.gcloudignore
6+
.venv
7+
.venv*/
8+
.env
9+
.env.*
10+
wallet/
11+
wallets/
12+
*.pem
13+
*.key
14+
*.sso
15+
*.p12
16+
*.zip
17+
__pycache__/
18+
.pytest_cache/
19+
.ruff_cache/
20+
build/
21+
dist/
22+
doc/
23+
docs/
24+
tests/
25+
samples/
26+
*.docx
27+
*.pdf
28+
*.png
29+
*.jpg
30+
*.jpeg

‎README.md‎

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Install the optional command line interface:
2020
python3 -m pip install 'select_ai[cli]'
2121
```
2222

23+
The CLI extra includes A2A server support.
24+
2325
## Documentation
2426

2527
See [Select AI for Python documentation][documentation]
@@ -30,16 +32,53 @@ Examples can be found in the [/samples][samples] directory
3032

3133
## Command Line Interface
3234

33-
The optional `select-ai` command provides an interactive chat REPL for Select AI
34-
profiles:
35+
The optional `select-ai` command provides interactive chat, SQL, profile
36+
management, and A2A server tools for Select AI:
3537

38+
### Chat
3639
```bash
3740
select-ai chat --profile OCI_AI_PROFILE
3841
```
39-
4042
![Select AI CLI demo](doc/source/image/select_ai_cli_demo.gif)
4143

42-
### Basic Example
44+
45+
### A2A Server
46+
47+
Expose one Oracle Database AI agent team as an A2A JSON-RPC HTTP server:
48+
49+
```bash
50+
select-ai a2a serve --team SALES_ANALYST --port 8000
51+
```
52+
53+
The command obtains database connection settings from its options or the
54+
`SELECT_AI_*` environment variables. Its Agent Card is available at
55+
`/.well-known/agent-card.json`, and its JSON-RPC endpoint is
56+
`/a2a/jsonrpc/`. Set `--public-url` when the server is behind a proxy or load
57+
balancer so that clients receive its externally reachable URL.
58+
59+
For Autonomous Database mTLS, also set `SELECT_AI_WALLET_LOCATION` to the
60+
directory containing the unzipped wallet and set `SELECT_AI_WALLET_PASSWORD`.
61+
The CLI passes both values to the Select AI SDK as `wallet_location` and
62+
`wallet_password`.
63+
64+
The server accepts both A2A 1.x and the A2A v0.3 JSON-RPC streaming protocol
65+
for compatibility with Gemini Enterprise.
66+
67+
Generate the A2A v0.3 Agent Card to paste into Gemini Enterprise after the
68+
service has a public URL:
69+
70+
```bash
71+
select-ai a2a agent-card \
72+
--team ORACLE_AI_DATABASE_AGENT \
73+
--public-url https://YOUR-SERVICE.run.app
74+
```
75+
76+
## Cloud Run
77+
78+
Deploy the A2A server to Cloud Run using the instructions in
79+
[gcloud/README.md](https://github.com/oracle/python-select-ai/blob/main/gcloud/README.md).
80+
81+
## Basic Example
4382

4483
```python
4584
import select_ai

‎doc/source/user_guide/cli.rst‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ workflows will be added in upcoming releases as the CLI evolves.
3232
:width: 100%
3333

3434
The package provides an optional ``select-ai`` command line tool. Install the
35-
CLI extra to use it:
35+
CLI extra to use it, including the A2A server commands:
3636

3737
.. code-block:: bash
3838

‎doc/source/user_guide/installation.rst‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ are isolated from your system Python installation.
7272
7373
python -m pip install --upgrade "select_ai[cli]"
7474
75-
This installs the ``select-ai`` command. See :ref:`Command Line Interface
76-
<cli>`.
75+
This installs the ``select-ai`` command and its A2A server support. See
76+
:ref:`Command Line Interface <cli>`.
7777

7878
6. If you are behind a proxy, use the ``--proxy`` option. For example:
7979

‎docker/Dockerfile‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
FROM oraclelinux:10-slim
2+
3+
ENV PATH=/opt/venv/bin:$PATH
4+
5+
RUN microdnf update -y \
6+
&& microdnf install -y python3 python3-pip ca-certificates unzip \
7+
&& microdnf clean all
8+
9+
WORKDIR /app
10+
11+
COPY pyproject.toml README.md LICENSE.txt ./
12+
COPY src ./src
13+
14+
RUN python3 -m venv /opt/venv \
15+
&& python -m pip install --no-cache-dir --upgrade pip setuptools wheel \
16+
&& python -m pip install --no-cache-dir '.[a2a]'
17+
18+
COPY docker/a2a-entrypoint.sh /app/docker/a2a-entrypoint.sh
19+
20+
RUN chmod 0555 /app/docker/a2a-entrypoint.sh
21+
22+
ENTRYPOINT ["select-ai"]

‎docker/a2a-entrypoint.sh‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/usr/bin/env sh
2+
3+
# Cloud Run-only A2A launcher. It expands the optional wallet archive mounted
4+
# by deploy.sh, then starts the generic select-ai CLI in A2A server mode.
5+
6+
set -eu
7+
8+
wallet_archive=/var/run/secrets/select-ai-wallet/wallet.zip
9+
wallet_root=/tmp/select-ai-wallet
10+
11+
if [ -f "$wallet_archive" ]; then
12+
mkdir -p "$wallet_root"
13+
chmod 700 "$wallet_root"
14+
unzip -q "$wallet_archive" -d "$wallet_root"
15+
16+
wallet_file="$(find "$wallet_root" -type f -name ewallet.pem -print -quit)"
17+
if [ -z "$wallet_file" ]; then
18+
echo "Wallet ZIP does not contain ewallet.pem" >&2
19+
exit 1
20+
fi
21+
export SELECT_AI_WALLET_LOCATION="$(dirname "$wallet_file")"
22+
fi
23+
24+
: "${SELECT_AI_A2A_TEAM:?SELECT_AI_A2A_TEAM is required}"
25+
: "${PUBLIC_URL:?PUBLIC_URL is required}"
26+
: "${SELECT_AI_POOL_MAX_SIZE:=10}"
27+
28+
exec select-ai a2a serve \
29+
--team "$SELECT_AI_A2A_TEAM" \
30+
--host 0.0.0.0 \
31+
--port "${PORT:-8080}" \
32+
--pool-max-size "$SELECT_AI_POOL_MAX_SIZE" \
33+
--public-url "$PUBLIC_URL"

‎gcloud/README.md‎

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# Deploy the Select AI A2A server to Google Cloud
2+
3+
`gcloud/deploy.sh` builds or selects a Select AI container image, creates or
4+
updates a private Cloud Run service, and configures its database secrets. Run
5+
it on a machine with the [Google Cloud CLI](https://cloud.google.com/sdk/docs/install)
6+
installed and authenticated to the target project.
7+
8+
## IAM permissions
9+
10+
The scripts use the active `gcloud` identity. They do not elevate its access.
11+
12+
### Deployer (the active gcloud identity)
13+
14+
| Operation | Required permissions |
15+
| --- | --- |
16+
| Inspect and create the Artifact Registry repository | `artifactregistry.repositories.get`, `artifactregistry.repositories.create` |
17+
| Inspect and create the default runtime service account | `iam.serviceAccounts.get`, `iam.serviceAccounts.create` |
18+
| Deploy or update Cloud Run | `run.services.create`, `run.services.update`, `run.services.get`, `run.operations.get`; `iam.serviceAccounts.actAs` on the runtime service account; `artifactregistry.repositories.downloadArtifacts` on the image repository |
19+
| With `--build`, upload local source, submit, and wait for a build | `storage.buckets.get`, `storage.objects.create` on the configured source-staging bucket; `cloudbuild.builds.create`, `cloudbuild.builds.get`, `serviceusage.services.use` |
20+
| Inspect, create, and add versions to database or wallet secrets | `secretmanager.secrets.get`, `secretmanager.secrets.create`, `secretmanager.versions.add` |
21+
| Grant the runtime account access to those secrets | `secretmanager.secrets.getIamPolicy`, `secretmanager.secrets.setIamPolicy` |
22+
| Grant Gemini Enterprise and the active gcloud identity access to the service | `run.services.getIamPolicy`, `run.services.setIamPolicy` |
23+
| Obtain the project number | `resourcemanager.projects.get` |
24+
25+
### Runtime service account
26+
27+
| Operation | Required permissions |
28+
| --- | --- |
29+
| Read database and wallet secrets while serving requests | `secretmanager.versions.access` |
30+
31+
### Other service identities
32+
33+
| Principal | Operation | Required permissions |
34+
| --- | --- | --- |
35+
| Cloud Build execution service account | With `--build`, push the built image | `artifactregistry.repositories.uploadArtifacts` |
36+
| Gemini Enterprise service agent | Invoke the private Cloud Run service | `run.routes.invoke` |
37+
| Active gcloud identity | Fetch the Agent Card after deployment | `run.routes.invoke` |
38+
39+
The source-staging bucket is Cloud Build's default unless a custom bucket is
40+
configured. Cloud Build also needs access to its build-log destination; the
41+
default same-project build account has that access. If your organization uses
42+
a custom build service account, source bucket, or log bucket, its administrator
43+
must grant the equivalent Cloud Storage permissions on those resources.
44+
45+
Google Cloud references: [Service Usage access control](https://cloud.google.com/service-usage/docs/access-control), [Cloud Run deployment permissions](https://cloud.google.com/run/docs/reference/iam/roles), [Secret Manager access control](https://cloud.google.com/secret-manager/docs/access-control), [Artifact Registry roles](https://cloud.google.com/artifact-registry/docs/access-control), and [Cloud Build roles](https://cloud.google.com/build/docs/iam-roles-permissions).
46+
47+
The rows that set IAM policy are administrative mutations. They are present
48+
because `deploy.sh` creates and rotates secrets and configures private-service
49+
invocation. If your customer deployment identity must not change IAM, provision
50+
the secrets and the `secretmanager.versions.access`/`run.routes.invoke`
51+
permissions beforehand, then
52+
remove those policy-setting commands from the deployment workflow.
53+
54+
## Prerequisite: enable project APIs once
55+
56+
An administrator must enable these APIs once for the project:
57+
58+
```bash
59+
gcloud services enable \
60+
run.googleapis.com \
61+
cloudbuild.googleapis.com \
62+
artifactregistry.googleapis.com \
63+
secretmanager.googleapis.com \
64+
discoveryengine.googleapis.com \
65+
--project PROJECT_ID
66+
```
67+
68+
## Deploy (and update) the A2A server
69+
70+
```bash
71+
gcloud/deploy.sh --build
72+
```
73+
74+
On the first deployment, the script prompts for the ADB user, password, and
75+
connect descriptor. It stores them in Secret Manager under names based on the
76+
Cloud Run service, and grants only the runtime service account access. The
77+
container receives the values as `SELECT_AI_USER`, `SELECT_AI_PASSWORD`, and
78+
`SELECT_AI_DB_CONNECT_STRING`; they are never placed in the image or source
79+
tree.
80+
81+
### Optional: Autonomous Database mTLS wallet
82+
83+
The Select AI SDK already supports `wallet_location` and `wallet_password`.
84+
For Cloud Run, pass the path to the downloaded Autonomous Database wallet ZIP
85+
on the first deployment (or when replacing it):
86+
87+
```bash
88+
gcloud/deploy.sh --wallet-archive /path/to/Wallet_database.zip
89+
```
90+
91+
The script prompts for the wallet password, stores the ZIP and password as
92+
service-specific Secret Manager secrets, and grants access only to the runtime
93+
service account. Cloud Run mounts the ZIP read-only; its A2A launcher expands it
94+
into ephemeral `/tmp` storage before starting the SDK, verifies it contains
95+
`ewallet.pem`, and sets `SELECT_AI_WALLET_LOCATION` to that file's directory.
96+
Do not commit the wallet ZIP or put its contents in the image.
97+
98+
Later deploys reuse the wallet. To replace it, pass `--wallet-archive` again.
99+
100+
The first deployment needs `--build` (or an explicit `--image-uri`). Later
101+
deployments reuse the image already deployed to the service, so changing Cloud
102+
Run configuration or secrets does not create another image. The command
103+
deploys private Cloud Run, sets the final public URL in the Agent Card, grants your active
104+
gcloud identity and Gemini Enterprise Discovery Engine service agent the
105+
`run.routes.invoke` permission for this Cloud Run service.
106+
107+
The default Cloud Run service is `oracle-a2a-agent`. Its default Agent Team,
108+
installed in Oracle Database, is `ORACLE_AI_DATABASE_AGENT`. Override either
109+
with explicit options:
110+
111+
```bash
112+
gcloud/deploy.sh --service sales-analyst-a2a --a2a-team SALES_ANALYST
113+
```
114+
115+
Use a distinct `--service` value for each A2A team. Each service gets distinct Secret
116+
Manager secret names by default, so credentials remain attached to that A2A
117+
server.
118+
119+
`--max-instances` controls the number of Cloud Run containers. Each container
120+
can use up to 10 Oracle connections by default; change that limit with
121+
`--pool-max-size`, for example `gcloud/deploy.sh --pool-max-size 20`.
122+
123+
### Update the Select AI SDK or this repository
124+
125+
Update the checkout (or modify its dependency version), then explicitly build
126+
and deploy the new image:
127+
128+
```bash
129+
git pull
130+
gcloud/deploy.sh --build
131+
```
132+
133+
`--build` creates a freshly tagged image from the current source; without it,
134+
the existing image is reused. Existing database secrets are reused without
135+
prompting. To rotate the ADB credentials, explicitly request it:
136+
137+
```bash
138+
gcloud/deploy.sh --rotate-db-credentials
139+
```
140+
141+
### What `cloudbuild.yaml` does
142+
143+
`gcloud/deploy.sh --build` uses `gcloud/cloudbuild.yaml` to tell Cloud Build to build
144+
`docker/Dockerfile` and push it to Artifact Registry. It is build configuration,
145+
not a command you run. The build context is the repository root, so the image
146+
can install the Select AI source from `pyproject.toml` and `src/`.
147+
148+
### Cloud Build upload contents
149+
150+
Before the build starts, `gcloud builds submit` archives and uploads the
151+
repository root. The root `.gcloudignore` excludes local virtual environments,
152+
generated documentation, test data, caches, credentials, and Git metadata.
153+
Keep `src/`, `pyproject.toml`, `docker/`, and `gcloud/` in the upload; they are
154+
required to build the image. If the upload is unexpectedly large, check local
155+
directories against `.gcloudignore` before running `--build` again.
156+
157+
After a successful deployment, the script prints the A2A Agent Card JSON.
158+
Paste that JSON into Gemini Enterprise to register the private service. The
159+
required Gemini Enterprise invocation permission has already been added.

‎gcloud/cloudbuild.yaml‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Build one reusable A2A server image. Database team selection is Cloud Run
2+
# configuration, not an image-build input.
3+
steps:
4+
- name: gcr.io/cloud-builders/docker
5+
args:
6+
- build
7+
- --file
8+
- docker/Dockerfile
9+
- --tag
10+
- ${_REGION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/select-ai:${_IMAGE_TAG}
11+
- .
12+
13+
images:
14+
- ${_REGION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/select-ai:${_IMAGE_TAG}
15+
16+
substitutions:
17+
_REGION: us-central1
18+
_REPOSITORY: select-ai
19+
_IMAGE_TAG: latest

0 commit comments

Comments
 (0)