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
28 changes: 28 additions & 0 deletions examples/sso_frontend_on_agentkit/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# AgentKit configuration
agentkit.yaml
agentkit*.yaml
.agentkit/

# Local secrets — never ship into the image (envs are injected by the runtime)
.env

# Python cache
__pycache__/
*.py[cod]
*$py.class

# Virtual environments
.venv/
venv/
ENV/
env/

# IDE / git
.vscode/
.idea/
.git/
.gitignore

# Docker
Dockerfile*
.dockerignore
14 changes: 14 additions & 0 deletions examples/sso_frontend_on_agentkit/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copy this file to `.env`, fill in your values, then:
# set -a && source .env && set +a

# --- Volcengine AK/SK ---
# Used by `veadk agentkit` to authenticate the build & deploy, and injected into
# the runtime so the app can call the VeIdentity API (the runtime has no usable
# role credentials). Create access keys at https://console.volcengine.com/iam/keymanage
VOLCENGINE_ACCESS_KEY=your-volcengine-access-key
VOLCENGINE_SECRET_KEY=your-volcengine-secret-key

# --- SSO: VeIdentity user pool (https://console.volcengine.com/veidentity) ---
# The UID of an existing user pool and one of its WEB_APPLICATION clients.
OAUTH2_USER_POOL_ID=your-user-pool-uid
OAUTH2_USER_POOL_CLIENT_ID=your-user-pool-client-uid
131 changes: 131 additions & 0 deletions examples/sso_frontend_on_agentkit/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# sso_frontend_on_agentkit · VeADK frontend with SSO on AgentKit

Deploy the VeADK web UI (A2UI) together with **VeIdentity single sign-on** to
a [Volcengine AgentKit](https://www.volcengine.com/) runtime. Unauthenticated
browsers see a login page; after sign-in the UI and backend agent run as the
logged-in user. Fully non-interactive — copy the commands to deploy.

> 中文版:[README.zh.md](./README.zh.md)

## Layout

```text
sso_frontend_on_agentkit/
├── app.py # entry: web UI + agent API + SSO
├── agents/
│ └── sso_demo_agent/ # a minimal agent
├── requirements.txt # veadk-python>=0.5.39
├── .env.example
└── .dockerignore
```

## How it works

The UI, agent API, VeIdentity OAuth2 middleware and bundled web UI all come
from `veadk-python` on PyPI. SSO is configured entirely through runtime
environment variables — no code changes.

`app.py` adds two adaptations for the AgentKit gateway, which authenticates
every request with the runtime key in the `Authorization: Bearer <key>` header
and forwards that header to the container:

- **Strip the gateway key**: the SSO middleware treats any `Authorization`
header as the user's access token and tries to decode it as a JWT — the
opaque gateway key fails with `Invalid JWT format`. `app.py` removes that
non-JWT header before the middleware runs, so SSO falls back to its session
cookie. A real user JWT is kept.
- **Forward the querystring onto assets**: if the gateway is configured to take
the key from the query string, the served `index.html` appends the page's
querystring to its `/assets/*` URLs so subresource requests carry it too.

> Both adaptations are built into `veadk frontend` from the next release; this
> example self-contains them so it runs on the current release.

## 1. Prerequisites

- A VeIdentity user pool and one of its `WEB_APPLICATION` clients
(<https://console.volcengine.com/veidentity>) — note both **UIDs**.
- Your account AK/SK — used both by the local `veadk agentkit` build & deploy
and by the runtime to call the VeIdentity API (the runtime has no usable role
credentials, so they must be injected). The model is provided by the runtime.

```bash
cd examples/sso_frontend_on_agentkit
cp .env.example .env
# Edit .env:
# VOLCENGINE_ACCESS_KEY / VOLCENGINE_SECRET_KEY (local deploy auth)
# OAUTH2_USER_POOL_ID / OAUTH2_USER_POOL_CLIENT_ID (pool & client UIDs)
set -a && source .env && set +a
```

## 2. Configure (non-interactive)

Account-specific fields (container registry, runtime role, …) are auto-created
when omitted. The runtime needs the two UIDs and AK/SK — it has no usable role
credentials, so AK/SK must be injected to call the VeIdentity API. The model is
provided by the runtime, so it is not in `--runtime_envs`:

```bash
veadk agentkit config \
--agent_name sso-frontend-demo \
--entry_point app.py \
--language Python --language_version 3.12 \
--launch_type cloud --region cn-beijing \
--runtime_name sso-frontend-demo \
--runtime_auth_type key_auth \
--runtime_envs OAUTH2_USER_POOL_ID="$OAUTH2_USER_POOL_ID" \
--runtime_envs OAUTH2_USER_POOL_CLIENT_ID="$OAUTH2_USER_POOL_CLIENT_ID" \
--runtime_envs VOLCENGINE_ACCESS_KEY="$VOLCENGINE_ACCESS_KEY" \
--runtime_envs VOLCENGINE_SECRET_KEY="$VOLCENGINE_SECRET_KEY" \
--runtime_envs OTEL_SDK_DISABLED=true \
--runtime_envs VEADK_DISABLE_EXPIRE_AT=true
```

## 3. Deploy

```bash
# Build the image and create the runtime; prints the endpoint and API key.
veadk agentkit launch
```

Set the callback to the printed endpoint (merged into the existing
`runtime_envs`) and update the runtime once more:

```bash
veadk agentkit config \
--runtime_envs OAUTH2_REDIRECT_URI=https://<your-endpoint>/oauth2/callback
veadk agentkit deploy
```

Locally the callback defaults to `http://127.0.0.1:8000/oauth2/callback`, so no
env var is needed; once deployed the browser hits the public endpoint, which is
only known after the runtime is created — hence this separate step. The callback
is registered with the user pool client automatically.

## 4. Access

The AgentKit gateway requires the runtime key on every request, and the runtime
key currently only supports the header location (`CreateRuntime`'s
`ApiKeyLocation` accepts only `header`). A browser's top-level navigation cannot
set a header, so use a browser extension (e.g. ModHeader) to add, for this
domain, globally:

```text
Authorization: Bearer <your-runtime-key>
```

Then open the endpoint: the UI loads → redirects to VeIdentity login → callback
(the extension adds the header to pass the gateway) → the session lives in a
cookie and the UI and agent API work.

## Notes

- **Model**: provided by the AgentKit runtime; to pin one, add
`--runtime_envs MODEL_AGENT_NAME=... --runtime_envs MODEL_AGENT_API_KEY=...`.
- **AK/SK**: used by the local `veadk agentkit` build & deploy **and** on the
runtime for the VeIdentity API calls (resolve the pool, register the callback).
The runtime has no usable role credentials (IMDS times out), so AK/SK must be
injected or the container crashes on startup.
- **Redeploy**: after changing an env var, merge it with
`veadk agentkit config --runtime_envs K=V` and re-run `veadk agentkit deploy`
(image layers are reused). Tear down with `veadk agentkit destroy`.
115 changes: 115 additions & 0 deletions examples/sso_frontend_on_agentkit/README.zh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# sso_frontend_on_agentkit · 把带 SSO 的 VeADK 前端部署到 AgentKit

将 VeADK 的 Web 界面(A2UI)连同 **VeIdentity 单点登录** 一起部署到
[火山引擎 AgentKit](https://www.volcengine.com/) 运行时。未登录的浏览器看到登录页,
登录后以登录用户的身份使用界面与后端 Agent。全程非交互,复制命令即可部署。

> English version: [README.md](./README.md)

## 目录结构

```text
sso_frontend_on_agentkit/
├── app.py # 部署入口:Web 界面 + Agent API + SSO
├── agents/
│ └── sso_demo_agent/ # 一个最简 Agent
├── requirements.txt # veadk-python>=0.5.39
├── .env.example
└── .dockerignore
```

## 工作原理

界面、Agent API、VeIdentity OAuth2 中间件、内置 Web 界面都来自 PyPI 上的
`veadk-python`。SSO 全部通过运行时环境变量配置,无需改代码。

`app.py` 针对 AgentKit 网关做了两处适配。网关对每个请求都用运行时 key 鉴权,
key 放在 `Authorization: Bearer <key>` 请求头里,并把该头透传给容器:

- **剥离网关 key**:SSO 中间件会把 `Authorization` 头当成用户的访问令牌去解析 JWT,
而网关 key 不是 JWT,会报 `Invalid JWT format`。`app.py` 在中间件之前移除这个非 JWT
的头,使 SSO 回退到会话 cookie;合法的用户 JWT 保持不变。
- **静态资源透传 querystring**:若网关改为从查询串取 key,浏览器加载 `/assets/*`
也需带上 key。返回的 `index.html` 会把页面的查询串拼到各静态资源 URL 上。

> 这两处适配自下一个版本起已内置进 `veadk frontend`,本示例自带它们以便在当前
> 发布版上直接运行。

## 1. 前置准备

- 一个 VeIdentity 用户池及其下的一个 `WEB_APPLICATION` 客户端
(控制台:<https://console.volcengine.com/veidentity>),记下两者的 **UID**。
- 账号的 AK/SK:本地 `veadk agentkit` 构建部署,以及运行时调用 VeIdentity API
都要用(运行时取不到角色凭证,必须注入)。模型由 AgentKit 运行时提供。

```bash
cd examples/sso_frontend_on_agentkit
cp .env.example .env
# 编辑 .env:
# VOLCENGINE_ACCESS_KEY / VOLCENGINE_SECRET_KEY (本地部署鉴权用)
# OAUTH2_USER_POOL_ID / OAUTH2_USER_POOL_CLIENT_ID (用户池、客户端的 UID)
set -a && source .env && set +a
```

## 2. 生成配置(非交互)

账号相关字段(镜像仓库、运行时角色等)省略即自动创建。运行时需要两个 UID 和
AK/SK——运行时取不到角色凭证,调用 VeIdentity API 必须注入 AK/SK;模型由运行时
提供,无需写进 `--runtime_envs`:

```bash
veadk agentkit config \
--agent_name sso-frontend-demo \
--entry_point app.py \
--language Python --language_version 3.12 \
--launch_type cloud --region cn-beijing \
--runtime_name sso-frontend-demo \
--runtime_auth_type key_auth \
--runtime_envs OAUTH2_USER_POOL_ID="$OAUTH2_USER_POOL_ID" \
--runtime_envs OAUTH2_USER_POOL_CLIENT_ID="$OAUTH2_USER_POOL_CLIENT_ID" \
--runtime_envs VOLCENGINE_ACCESS_KEY="$VOLCENGINE_ACCESS_KEY" \
--runtime_envs VOLCENGINE_SECRET_KEY="$VOLCENGINE_SECRET_KEY" \
--runtime_envs OTEL_SDK_DISABLED=true \
--runtime_envs VEADK_DISABLE_EXPIRE_AT=true
```

## 3. 部署

```bash
# 构建镜像并创建运行时,输出 endpoint 与 API key
veadk agentkit launch
```

把上一步输出的 endpoint 填入回调地址(会合并进现有 `runtime_envs`),再更新运行时:

```bash
veadk agentkit config \
--runtime_envs OAUTH2_REDIRECT_URI=https://<your-endpoint>/oauth2/callback
veadk agentkit deploy
```

本地启动时默认回调即 `http://127.0.0.1:8000/oauth2/callback`,无需设置;部署后浏览器
访问的是公网 endpoint,而它只在运行时创建后才知道,因此这一步单独设置——回调会自动
注册到用户池客户端,云端无需手动添加。

## 4. 访问

AgentKit 网关要求每个请求都带运行时 key。当前运行时 key 只支持放在请求头里
(`CreateRuntime` 的 `ApiKeyLocation` 仅接受 `header`),而浏览器的顶层导航无法自带请求头,
因此用浏览器扩展(如 ModHeader)对该域名**全局**添加请求头:

```text
Authorization: Bearer <your-runtime-key>
```

随后访问 endpoint 即可:界面加载 → 跳转 VeIdentity 登录 → 回调(扩展会带上请求头过网关)
→ 登录态走会话 cookie,界面与 Agent API 正常工作。

## 注意

- **模型**:由 AgentKit 运行时提供;如需指定,可自行加
`--runtime_envs MODEL_AGENT_NAME=... --runtime_envs MODEL_AGENT_API_KEY=...`。
- **AK/SK**:本地构建部署要用;运行时调用 VeIdentity API(解析用户池、注册回调)
也要用——运行时取不到角色凭证(IMDS 超时),必须注入 `runtime_envs`,否则容器启动即崩。
- **重新部署**:改动环境变量后,`veadk agentkit config --runtime_envs K=V` 合并后重跑
`veadk agentkit deploy` 即可,镜像层会复用。用 `veadk agentkit destroy` 拆除。
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from . import agent

__all__ = ["agent"]
30 changes: 30 additions & 0 deletions examples/sso_frontend_on_agentkit/agents/sso_demo_agent/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Minimal backend agent for the SSO-frontend-on-AgentKit demo.

A plain VeADK ``Agent`` (no callbacks). The model comes from the MODEL_AGENT_*
runtime environment variables. The Google ADK agent loader picks up ``root_agent``.
"""

from veadk import Agent

agent = Agent(
name="sso_demo_agent",
description="Demo agent served behind an SSO login page.",
instruction="You are a helpful assistant. Answer concisely.",
)

# Required by the Google ADK agent loader.
root_agent = agent
Loading
Loading