agent_deply/pam_deploy_graph/checkpoint_store.py
dark 1e74ae3cd6 feat: 增加 PAM 部署 Agent 交互式 CLI 与真实 LLM 配置
- 新增 OpenAI-compatible LLM client,支持 base_url、api_key、model 配置
- 固化意图识别、参数抽取、部署计划生成的结构化 JSON 提示词
- 增加 MCP client 配置读取和真实 session 接入说明
- 实现 checkpoint 自动保存、resume 断点续跑和已完成步骤跳过
- 实现人工确认流程,支持失败 IP 回滚 approve/reject
- 新增 chat 常驻式 CLI 对话框,支持自然语言分析、参数设置、执行确认、状态查看、回滚确认和续跑
- 同步 README,补充 LLM、MCP、checkpoint、confirm/resume、chat 使用方式
- 增加相关单元测试,覆盖 LLM client、MCP 配置、确认/续跑和交互式 CLI
2026-06-01 10:26:40 +08:00

53 lines
1.6 KiB
Python

"""Business checkpoint JSON storage."""
from __future__ import annotations
import json
from dataclasses import asdict, fields, is_dataclass
from pathlib import Path
from typing import Any
from .constants import SENSITIVE_KEYS
from .models import AgentState
def redact_mapping(value: Any) -> Any:
if isinstance(value, dict):
result = {}
for key, item in value.items():
if str(key) in SENSITIVE_KEYS:
result[key] = "***"
else:
result[key] = redact_mapping(item)
return result
if isinstance(value, list):
return [redact_mapping(item) for item in value]
return value
def save_checkpoint(state: Any, path: str | Path, *, redact: bool = True) -> Path:
checkpoint_path = Path(path)
checkpoint_path.parent.mkdir(parents=True, exist_ok=True)
payload = asdict(state) if is_dataclass(state) else state
if redact:
payload = redact_mapping(payload)
checkpoint_path.write_text(
json.dumps(payload, ensure_ascii=False, indent=2),
encoding="utf-8",
)
return checkpoint_path
def load_checkpoint(path: str | Path) -> dict[str, Any]:
return json.loads(Path(path).read_text(encoding="utf-8"))
def agent_state_from_mapping(payload: dict[str, Any]) -> AgentState:
allowed_fields = {item.name for item in fields(AgentState)}
state_payload = {key: value for key, value in payload.items() if key in allowed_fields}
return AgentState(**state_payload)
def load_agent_state(path: str | Path) -> AgentState:
return agent_state_from_mapping(load_checkpoint(path))