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
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,28 @@
格式参考 [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
版本遵循 [Semantic Versioning](https://semver.org/spec/v2.0.0.html)。

## [0.6.3] - 2026-06-09

### 亮点

- **Hosted UI 联动收敛**:与最新 gateway / server 对齐 hosted `/hosted-ui/chat/`、share link、SSE 订阅和 native terminal 代理契约;`agentengine dashboard open` 继续优先打开托管入口,本地 `agentengine web` 保持调试用途。
- **Skill Space demo 可用性修复**:补齐 `ksadk.toolsets`、Tool Gateway、Skill Runtime 和 Skill Service 相关 package 文件,安装后的 LangGraph 样例可以直接绑定 AgentEngine 内置工具。
- **更新镜像不覆盖用户配置**:OpenClaw / Hermes 更新已有实例时默认只更新镜像和必要运行时字段,不再把本地 shell 或默认值生成的 env/storage/network/memory 配置覆盖到服务端。
- **开源样例门禁增强**:`ksadk-samples` 主推 LangGraph demo 增加 Skill Space、Skill Runtime、Workspace、Sandbox、知识库和长期记忆配置说明,并加入敏感信息扫描与结构校验。

### 修复

- 修复 LangGraph runner 在工具调用后没有文本流式 chunk 时不会输出最终 answer,导致本地 Web UI 存储空 assistant message 的问题。
- 修复 Skill Service KOP client 在 `KSADK_SKILL_SERVICE_REGION=pre-online` 下没有按 AgentEngine client 规则设置 `X-Ksc-Region: cn-beijing-6` 和 `X-KSC-CUSTOM-SOURCE: pre` 的问题。
- 修复内置工具 dispatcher 遇到未知 include/tool name 时可能抛异常的问题,现在返回结构化 `unknown_tool` 错误,便于 Agent 继续解释。
- 修复 OpenClaw / Hermes deploy update payload 默认携带 `env_vars`、`storage`、`network` 等配置组的问题,降低客户更新公共镜像时误改生产配置的风险。

### 兼容性说明

- 新建 OpenClaw / Hermes 实例仍会发送完整 env/storage/network/UI 配置;只有更新已有实例时默认改为最小 payload。
- 更新已有 OpenClaw / Hermes 时,如需覆盖模型或环境变量,请显式传入 `--model-base-url`、`--model-api-key`、`--default-model` 或 OpenClaw 的 `--env`;如需覆盖挂盘或网络,请显式传入对应 `--storage-*` / `--enable-vpc-access` 等参数。
- `--no-storage` 在已有实例更新场景下不会删除服务端既有挂盘配置;删除挂盘属于后续需要服务端明确 API 支持的危险操作。

## [0.6.2] - 2026-06-04

### 亮点
Expand Down
10 changes: 9 additions & 1 deletion README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

Kingsoft Cloud Agent Development Kit. `ksadk` provides the Python SDK and command line tools for building, running, packaging, and deploying AgentEngine agents. After installation, both `agentengine` and the equivalent `ksadk` command are available. KsADK covers local development, serverless runtime, ADK, LangChain/LangGraph, DeepAgents, Hermes, OpenClaw, MCP, and Skill Runtime scenarios.

Current version: `0.6.2`.
Current version: `0.6.3`.

## Install

Expand Down Expand Up @@ -60,6 +60,14 @@ agentengine dashboard open
- Built-in AgentEngine tools: skill discovery/loading, workspace file operations, component status, sandbox status, and sandbox direct code/command execution
- Sandbox Runtime: common sandbox abstraction with an E2B-compatible backend

## 0.6.3 Highlights

- Hosted UI links align with the latest gateway / server `/hosted-ui/chat/`, share link, SSE subscription, and native terminal proxy contracts; `agentengine dashboard open` keeps using hosted entrypoints while `agentengine web` stays focused on local debugging.
- LangGraph runner now emits the final answer after tool calls even when the model does not stream text chunks, avoiding empty assistant messages in the local Web UI.
- Skill Service supports `KSADK_SKILL_SERVICE_REGION=pre-online` KOP routing with the expected pre-online headers.
- OpenClaw and Hermes updates preserve existing server-side env, storage, network, and memory configuration by default, and only overwrite those groups when matching CLI options are supplied explicitly.
- `ksadk.toolsets`, Tool Gateway, Skill Runtime, and Skill Service files are included in the package so the recommended LangGraph demo works after a clean install.

## 0.6.2 Highlights

- Skill Runtime can discover Skill Space entries, download and verify skill packages, load `SKILL.md`, and execute workflow-style skills through `local_process` or E2B sandbox backends.
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
本地开发、Serverless 运行时、Google ADK、LangChain/LangGraph、
DeepAgents、Hermes、OpenClaw、MCP 和 Skill Runtime 等场景。

当前版本:`0.6.2`。
当前版本:`0.6.3`。

## 安装

Expand Down Expand Up @@ -64,6 +64,14 @@ agentengine launch . --target serverless
- AgentEngine 内置工具:skill 发现/加载、workspace 文件操作、component status、sandbox status 和 sandbox direct code/command execution
- Sandbox Runtime:通用沙箱抽象与 E2B 兼容后端

## 0.6.3 重点

- Hosted UI 与最新 gateway / server 对齐 `/hosted-ui/chat/`、share link、SSE 订阅和 native terminal 代理契约;`agentengine dashboard open` 继续优先打开托管入口,本地 `agentengine web` 保持调试用途。
- LangGraph runner 在工具调用后即使没有文本流式 chunk,也会输出最终 answer,避免本地 Web UI 出现空 assistant message。
- Skill Service 支持 `KSADK_SKILL_SERVICE_REGION=pre-online` 的 KOP 路由,自动设置预发所需 header。
- OpenClaw / Hermes 更新已有实例时默认保留服务端已有 env、storage、network、memory 配置,只在显式传入对应 CLI 参数时覆盖。
- `ksadk.toolsets`、Tool Gateway、Skill Runtime 与 Skill Service 相关文件纳入发布包,主推 LangGraph demo 可以在干净安装后直接绑定 AgentEngine 内置工具。

## 0.6.2 重点

- Skill Runtime 支持 Skill Space 远端发现、按需下载、`sha256` 校验、安全解压、`SKILL.md` instruction 加载,以及 `local_process` / E2B sandbox backend workflow 执行。
Expand All @@ -90,6 +98,7 @@ agentengine launch . --target serverless

- 文档:<https://kingsoftcloud.github.io/ksadk-python/>
- 仓库:<https://github.com/kingsoftcloud/ksadk-python>
- wiki:<https://zread.ai/kingsoftcloud/ksadk-python>
- 示例仓库:<https://github.com/kingsoftcloud/ksadk-samples>
- Web UI 仓库:<https://github.com/kingsoftcloud/ksadk-web>
- PyPI:<https://pypi.org/project/ksadk/>
Expand Down
99 changes: 94 additions & 5 deletions ksadk/cli/cmd_hermes.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from typing import Any, Callable, Optional

import click
from click.core import ParameterSource

from ksadk.api import AgentEngineClient
from ksadk.cli.agent_ref import merge_agent_inputs, resolve_agent_ref
Expand Down Expand Up @@ -56,7 +57,7 @@
)


DEFAULT_HERMES_IMAGE = "ghcr.io/kingsoftcloud/hermes-agent:2026.5.16-ksadk-v1"
DEFAULT_HERMES_IMAGE = "ghcr.io/kingsoftcloud/hermes-agent:2026.5.29.2-ksadk-v1"
DEFAULT_HERMES_CONTEXT_LENGTHS = (
("glm-5.1", "200000"),
)
Expand All @@ -65,11 +66,12 @@
)
DEFAULT_HERMES_MODEL_NAME = "glm-5.1"
DEFAULT_HERMES_PUBLIC_BASE_URL = "https://kspmas.ksyun.com/v1/"
DEFAULT_HERMES_RUNTIME_BASE_URL = "https://kspmas.ksyun.com/v1/"
DEFAULT_HERMES_RUNTIME_BASE_URL = DEFAULT_HERMES_PUBLIC_BASE_URL
KSPMAS_PUBLIC_BASES = (
"http://kspmas.ksyun.com",
"https://kspmas.ksyun.com",
)
KSPMAS_INTERNAL_BASE = DEFAULT_HERMES_PUBLIC_BASE_URL.rstrip("/")
_HERMES_GLOBAL_ENV_CACHE: dict[str, str] | None = None

HERMES_RESOURCE = ResourceDescriptor(
Expand Down Expand Up @@ -115,13 +117,52 @@
"agentengine hermes open ar-xxxx --chat",
"agentengine hermes exec ar-xxxx -- status",
"agentengine hermes pairing ar-xxxx -- list",
"agentengine hermes pairing ar-xxxx -- approve wpsxiezuo <code>",
"agentengine hermes delete ar-xxxx",
),
missing_ref_message="未找到 Hermes Agent,请指定 Agent(--agent 或位置参数)",
resolution_commands=("agentengine hermes list",),
)


def _option_was_explicit(ctx: click.Context | None, name: str) -> bool:
if ctx is None:
return False
try:
return ctx.get_parameter_source(name) != ParameterSource.DEFAULT
except Exception:
return False


def _build_hermes_update_payload(
*,
payload: dict[str, Any],
storage_config: dict[str, Any] | None,
network_payload: dict[str, Any] | None,
include_env: bool,
include_storage: bool,
) -> dict[str, Any]:
"""构建已有 Hermes 的最小更新请求,避免镜像更新覆盖用户配置。"""
update_payload: dict[str, Any] = {
"name": payload["name"],
"description": payload["description"],
"framework": payload["framework"],
"artifact_type": payload["artifact_type"],
"artifact_path": payload["artifact_path"],
"region": payload["region"],
"resources": payload["resources"],
"scaling": payload["scaling"],
"ui_config": payload["ui_config"],
}
if include_env:
update_payload["env_vars"] = payload["env_vars"]
if include_storage and storage_config:
update_payload["storage"] = storage_config
if network_payload:
update_payload["network"] = network_payload
return update_payload


@click.group("hermes", context_settings=CONTEXT_SETTINGS)
def hermes():
"""Hermes Agent 资源管理。"""
Expand Down Expand Up @@ -302,6 +343,19 @@ def _build_hermes_env_vars(
value = _env_value(*source_keys)
if value:
raw[target_key] = value
for key in (
"WPSXIEZUO_APP_ID",
"WPSXIEZUO_APP_KEY",
"WPSXIEZUO_API_BASE",
"WPSXIEZUO_WS_ENDPOINT",
"WPSXIEZUO_GROUP_AT_ONLY",
"WPSXIEZUO_ALLOWED_USERS",
"WPSXIEZUO_ALLOW_ALL_USERS",
"WPSXIEZUO_HOME_CHANNEL",
):
value = _env_value(key)
if value:
raw[key] = value
return [
{"Key": key, "Value": str(value), "IsSensitive": any(token in key for token in ("KEY", "TOKEN", "SECRET"))}
for key, value in raw.items()
Expand All @@ -327,7 +381,8 @@ def _validate_hermes_model_config(


def _normalize_hermes_runtime_base_url(base_url: str | None) -> str:
return str(base_url or "").strip()
normalized = str(base_url or "").strip()
return normalized


def _flatten_agent_detail(agent: dict[str, Any]) -> dict[str, Any]:
Expand Down Expand Up @@ -481,6 +536,21 @@ def deploy(
"""部署 Hermes runtime 到云端。"""
_ = output_mode
dry_run = effective_dry_run(dry_run)
ctx = click.get_current_context(silent=True)
include_env_on_update = any(
(
_option_was_explicit(ctx, "model_base_url"),
_option_was_explicit(ctx, "model_api_key"),
_option_was_explicit(ctx, "default_model"),
)
)
include_storage_on_update = any(
(
_option_was_explicit(ctx, "storage_size_gi"),
_option_was_explicit(ctx, "storage_mount_path"),
_option_was_explicit(ctx, "no_storage"),
)
)
run_async_with_dry_run(
_deploy_hermes(
name=name,
Expand All @@ -494,6 +564,8 @@ def deploy(
storage_size_gi=storage_size_gi,
storage_mount_path=storage_mount_path,
no_storage=no_storage,
include_env_on_update=include_env_on_update,
include_storage_on_update=include_storage_on_update,
**network_cli_kwargs(
enable_public_access=enable_public_access,
enable_vpc_access=enable_vpc_access,
Expand Down Expand Up @@ -523,6 +595,8 @@ async def _deploy_hermes(
storage_size_gi: int,
storage_mount_path: str | None,
no_storage: bool,
include_env_on_update: bool,
include_storage_on_update: bool,
enable_public_access: bool | None,
enable_vpc_access: bool,
vpc_id: str | None,
Expand Down Expand Up @@ -582,13 +656,17 @@ async def _deploy_hermes(
)
if storage_config:
payload["storage"] = storage_config
if existing_agent_id and include_storage_on_update and no_storage:
print_warn("更新已有 Hermes 时 `--no-storage` 不会删除服务端既有挂盘配置;默认保留已有配置。")
network_payload = build_network_payload(
enable_public_access=enable_public_access,
enable_vpc_access=enable_vpc_access,
vpc_id=vpc_id,
subnet_id=subnet_id,
security_group_id=security_group_id,
availability_zone=availability_zone,
region=region,
dry_run=dry_run,
)
if network_payload:
payload["network"] = network_payload
Expand All @@ -599,7 +677,14 @@ async def _deploy_hermes(

async with AgentEngineClient(region=region, dry_run=dry_run) as client:
if existing_agent_id:
res = await client.update_agent(existing_agent_id, payload)
update_payload = _build_hermes_update_payload(
payload=payload,
storage_config=storage_config,
network_payload=network_payload,
include_env=include_env_on_update,
include_storage=include_storage_on_update,
)
res = await client.update_agent(existing_agent_id, update_payload)
if res is None:
res = {}
res.setdefault("agent_id", existing_agent_id)
Expand Down Expand Up @@ -958,7 +1043,11 @@ def pairing_hermes(
dry_run: bool,
output_mode: str | None,
):
"""透传 Hermes pairing 审批子命令。"""
"""透传 Hermes pairing 审批子命令。

WPS 协作配对码来自未授权用户私聊机器人时 Hermes 返回的 pairing code,
审批示例:agentengine hermes pairing <agent> -- approve wpsxiezuo <code>
"""
_ = output_mode
try:
agent_ref, validated_argv = _split_terminal_agent_ref_and_argv(
Expand Down
Loading
Loading