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
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ install-webui:

STATIC_DIR = ksadk/server/static
OPEN_SOURCE_SMOKE_VENV ?= /tmp/ksadk-open-source-smoke
OPEN_SOURCE_SMOKE_WHEEL := dist/ksadk-0.6.2-py3-none-any.whl
OPEN_SOURCE_SMOKE_WHEEL ?= dist/ksadk-$(VERSION)-py3-none-any.whl

build-webui:
@echo "ℹ️ ksadk-python 不包含可编辑 Web UI 源码。"
Expand Down Expand Up @@ -224,6 +224,7 @@ PUBLIC_DOCS_URL ?= https://kingsoftcloud.github.io/ksadk-python/
PUBLIC_PYPI_PROJECT ?= ksadk
PUBLIC_ALIAS_PYPI_PROJECT ?= agentengine-sdk-python
PUBLIC_RELEASE_TAG ?= v$(V)
PUBLIC_PUBLISH_PHASE ?= pre-publish

public-status:
@echo "==> public candidate"
Expand Down Expand Up @@ -296,15 +297,15 @@ public-preflight: public-audit public-test public-docs-build public-build-check
public-publish-check:
@echo "==> publication state check"
@if [ -f "scripts/check_publication_state.py" ]; then \
uv run python scripts/check_publication_state.py --phase pre-publish; \
uv run python scripts/check_publication_state.py --phase "$(PUBLIC_PUBLISH_PHASE)" --version "$(VERSION)"; \
else \
echo "⚠️ scripts/check_publication_state.py 不存在,执行基础 HTTP 检查"; \
python3 -c 'import json, urllib.request; targets={"repo":"$(PUBLIC_REPO)","docs":"$(PUBLIC_DOCS_URL)","pypi":"https://pypi.org/pypi/$(PUBLIC_PYPI_PROJECT)/json","alias_pypi":"https://pypi.org/pypi/$(PUBLIC_ALIAS_PYPI_PROJECT)/json"}; [print("%s: HTTP %s%s" % (name, resp.status, ("\n version=%s" % json.load(resp)["info"].get("version")) if name.endswith("pypi") else "")) for name, url in targets.items() for resp in [urllib.request.urlopen(url, timeout=20)]]'; \
fi

public-release-tag:
ifndef V
$(error ❌ 请指定版本号,例如: make public-release-tag V=0.6.2)
$(error ❌ 请指定版本号,例如: make public-release-tag V=$(VERSION))
endif
@branch=$$(git branch --show-current); \
if [ "$$branch" != "$(PUBLIC_BRANCH)" ]; then \
Expand Down
11 changes: 10 additions & 1 deletion README.zh-CN.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
98 changes: 98 additions & 0 deletions scripts/check_publication_state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""检查公开发布状态。

发布前使用 `--phase pre-publish`,确保 GitHub Pages 可访问且 PyPI 上还没有
当前版本;发布后使用 `--phase post-publish`,确保 PyPI 已能查询到当前版本。
"""

from __future__ import annotations

import argparse
import json
import sys
import urllib.error
import urllib.request
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]
PYPROJECT = ROOT / "pyproject.toml"


def _current_version() -> str:
for line in PYPROJECT.read_text(encoding="utf-8").splitlines():
if line.startswith("version = "):
return line.split("=", 1)[1].strip().strip('"')
raise RuntimeError("pyproject.toml 中未找到 version")


def _open(url: str) -> tuple[int, bytes]:
request = urllib.request.Request(url, headers={"User-Agent": "ksadk-publication-check"})
with urllib.request.urlopen(request, timeout=20) as response:
return response.status, response.read()


def _expect_http_ok(name: str, url: str) -> None:
status, _ = _open(url)
if status != 200:
raise RuntimeError(f"{name}: 期望 HTTP 200,实际 {status}: {url}")
print(f"{name}: HTTP {status}")


def _pypi_project_version(project: str) -> str | None:
url = f"https://pypi.org/pypi/{project}/json"
try:
status, body = _open(url)
except urllib.error.HTTPError as exc:
if exc.code == 404:
return None
raise
if status != 200:
raise RuntimeError(f"{project}: 期望 HTTP 200,实际 {status}: {url}")
data = json.loads(body)
return data.get("info", {}).get("version")


def _pypi_version_exists(project: str, version: str) -> bool:
url = f"https://pypi.org/pypi/{project}/{version}/json"
try:
status, _ = _open(url)
except urllib.error.HTTPError as exc:
if exc.code == 404:
return False
raise
if status != 200:
raise RuntimeError(f"{project}=={version}: 期望 HTTP 200 或 404,实际 {status}")
return True


def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--phase", choices=("pre-publish", "post-publish"), required=True)
parser.add_argument("--version", default=_current_version())
parser.add_argument("--project", default="ksadk")
parser.add_argument("--alias-project", default="agentengine-sdk-python")
parser.add_argument("--docs-url", default="https://kingsoftcloud.github.io/ksadk-python/")
args = parser.parse_args()

_expect_http_ok("docs", args.docs_url)

latest = _pypi_project_version(args.project)
print(f"pypi:{args.project}: latest={latest}")

exists = _pypi_version_exists(args.project, args.version)
print(f"pypi:{args.project}=={args.version}: exists={exists}")

alias_latest = _pypi_project_version(args.alias_project)
print(f"pypi:{args.alias_project}: latest={alias_latest}")

if args.phase == "pre-publish" and exists:
raise RuntimeError(f"发布前检查失败:PyPI 已存在 {args.project}=={args.version}")
if args.phase == "post-publish" and not exists:
raise RuntimeError(f"发布后检查失败:PyPI 尚未存在 {args.project}=={args.version}")

print(f"✅ publication {args.phase} check passed for {args.project}=={args.version}")
return 0


if __name__ == "__main__":
sys.exit(main())
Loading