Compare commits

..

2 Commits

Author SHA1 Message Date
yuzhe
4569724cec docs: 同步 Agent 上传与优化接口说明 2026-07-23 13:55:00 +08:00
yuzhe
557e24883d feat(skill): 固定服务地址并强化目标确认 2026-07-23 13:50:24 +08:00
8 changed files with 36 additions and 9 deletions

View File

@@ -12,6 +12,7 @@ Use a two-phase plan/apply workflow. Optimize for correct placement, not speed.
- Treat the product hierarchy as `operation group -> project -> work -> review round`.
- Never use a collection/delivery-set identifier. `collections`, `notes`, and `versions` are legacy compatibility names.
- Never infer a project or work from a partial name, page position, recent activity, or a remembered ID.
- At the start of every invocation, discover and explicitly ask the operator to confirm the exact operation group and project. A target confirmation from an earlier invocation cannot be reused.
- Never create a work until the operator confirms the resolved group, project, content, image order, and confirmation code.
- Never create a new round until the operator confirms the resolved work and current round.
- Never retry a timed-out create request. First inspect current server state; otherwise a retry can create a duplicate round.
@@ -38,7 +39,7 @@ Do not create groups, projects, API keys, feedback, or review decisions with thi
For both operations, require:
- Delivery Desk base URL. Default to `DELIVERY_DESK_BASE_URL` or `http://127.0.0.1:3010` only for local development.
- Use the fixed Delivery Desk API address `http://192.168.30.90:3010`. Do not ask the operator to configure it. Use `--base-url` only when the operator explicitly instructs you to migrate or test another environment.
- A valid API key in `DELIVERY_DESK_API_KEY`.
- Exact target project, resolved to group ID/name and project ID/name/slug.
- Ordered public image URLs or ordered local image paths.
@@ -57,7 +58,7 @@ For `create_round`, also require:
When information is missing, ask one concise question listing only the missing fields. Do not proceed to mutation.
## 3. Discover authoritative IDs
## 3. Discover and confirm the authoritative target
Use the bundled script from the skill directory:
@@ -73,8 +74,9 @@ Resolution rules:
1. Match IDs first.
2. Validate the project ID against its returned group ID, group name, project name, and slug.
3. If the operator supplied only names, list exact matches with IDs and ask the operator to choose when zero or multiple matches exist.
4. Even with one match, show the resolved identity before creating the plan.
5. For a new round, verify the work belongs to the confirmed project.
4. Even when the request already names a target or only one project is accessible, show the resolved group name/ID and project name/ID/slug and ask: `本次操作目标是否为:运营组「<group_name>」(ID <group_id>) / 项目「<project_name>」(ID <project_id>, slug <slug>)?请回复“确认目标”。`
5. Accept only an explicit target confirmation given during the current invocation. Do not generate `plan-work` or `plan-round` before it.
6. For a new round, verify the work belongs to the confirmed project.
Do not silently choose the only project merely because an API key currently exposes one.

View File

@@ -1,4 +1,4 @@
interface:
display_name: "上传 Delivery Desk 作品"
short_description: "精确定位运营组与项目,安全创建作品或提交新的验收轮次"
default_prompt: "Use $upload-delivery-desk-work to safely locate the exact project and upload a work or a new review round."
default_prompt: "Use $upload-delivery-desk-work to discover and ask me to confirm the exact operation group and project before uploading a work or a new review round."

View File

@@ -19,6 +19,7 @@ from urllib.parse import quote, urlsplit
from urllib.request import Request, urlopen
MAX_LOCAL_IMAGE_BYTES = 20 * 1024 * 1024
DEFAULT_BASE_URL = "http://192.168.30.90:3010"
LOCAL_IMAGE_TYPES = {
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
@@ -75,7 +76,7 @@ def api_key() -> str:
def base_url(value: str | None = None) -> str:
return (value or os.getenv("DELIVERY_DESK_BASE_URL") or "http://127.0.0.1:3010").rstrip("/")
return (value or DEFAULT_BASE_URL).rstrip("/")
def request_json(base: str, path: str, *, method: str = "GET", body: dict[str, Any] | None = None) -> tuple[int, Any]:
@@ -461,7 +462,7 @@ def cmd_apply(args: argparse.Namespace) -> None:
def add_common(command: argparse.ArgumentParser) -> None:
command.add_argument("--base-url", default=None)
command.add_argument("--base-url", default=None, help=f"Delivery Desk API 地址(默认:{DEFAULT_BASE_URL}")
def add_content(command: argparse.ArgumentParser, *, title_required: bool) -> None:

View File

@@ -67,10 +67,11 @@ flowchart LR
- 点击图片打开悬浮图片窗格;只有该窗格可以新增坐标批注,并支持原图查看、缩放和前后切换。点击窗格外会同时关闭图片窗格和验收协作面板。
- 标题、正文和 Tag 批注保存 `start_offset``end_offset``selected_text` 及前后文,提交时校验选区仍与轮次快照一致。
- `GET /api/works/:workId/annotations` 按轮次返回图片批注、文字批注、总体反馈和验收事件。
- `GET /api/works/:workId/optimization-context?round=N` 聚合指定轮次的内容、图片和可执行反馈,默认排除已关闭或撤回记录,供外部内容优化流程只读使用。
## Agent 安全上传
内置 Agent Skill 采用“发现目标 → 生成计划 → 人工确认 → 单次写入 → 读取核验”的两阶段流程。计划文件只保存目标 ID、待写内容和确认摘要不保存 API Key并写入已被 Git 忽略的 `tmp/` 目录。
内置 Agent Skill 固定连接 `http://192.168.30.90:3010`,采用“发现目标 → 操作者确认运营组和项目 → 生成计划 → 操作者确认内容与确认 → 单次写入 → 读取核验”的两阶段确认流程。计划文件只保存目标 ID、待写内容和确认摘要不保存 API Key并写入已被 Git 忽略的 `tmp/` 目录。
新建作品以 `externalId` 保证幂等;新增验收轮次没有幂等键。轮次写入超时或响应不明确时,必须先重新读取作品状态,不能直接重试,以免重复创建轮次。

View File

@@ -12,7 +12,7 @@ Authorization: Bearer dd_live_xxx
## Agent 安全上传 Skill
项目内置 `.agents/skills/upload-delivery-desk-work`,用于引导 Agent 精确定位运营组、项目和作品后创建作品或提交新验收轮次。它强制执行“发现 → 生成计划 → 操作者确认 → 单次提交 → 回读验证”,不允许根据名称猜测目标。
项目内置 `.agents/skills/upload-delivery-desk-work`,用于引导 Agent 精确定位运营组、项目和作品后创建作品或提交新验收轮次。它固定连接 `http://192.168.30.90:3010`,并强制执行“发现 → 操作者确认运营组与项目 → 生成计划 → 操作者确认内容 → 单次提交 → 回读验证”,不允许根据名称猜测目标。
更新 Skill 后重新生成分发包:
@@ -113,8 +113,14 @@ curl "http://localhost:3010/api/works/12?round=2" \
# 按轮返回该作品全部反馈和验收事件
curl http://localhost:3010/api/works/12/annotations \
-H "Authorization: Bearer $DELIVERY_DESK_API_KEY"
# 返回用于优化指定轮次内容与图片的精简上下文;默认只含未撤回的开放反馈
curl "http://localhost:3010/api/works/12/optimization-context?round=2" \
-H "Authorization: Bearer $DELIVERY_DESK_API_KEY"
```
`optimization-context` 返回项目、作品、轮次、标题、正文、Tag、图片元信息以及图片批注、文字批注、总体反馈和回复。需要审计已关闭或已撤回的历史反馈时增加 `include_history=true`;该接口只读,不会修改作品。
标题、正文和 Tag 选区批注使用:
```json

View File

@@ -57,6 +57,8 @@ JSON URL 导入依赖活动 COS 配置。同一 COS/CDN 域名的图片直接使
Agent 通过 API 新建作品或提交验收轮次时,使用 `.agents/skills/upload-delivery-desk-work`。API Key 只通过 `DELIVERY_DESK_API_KEY` 环境变量注入,不写入计划文件、文档或 Git。
Skill 默认固定连接 `http://192.168.30.90:3010`,不读取环境变量覆盖服务地址。只有操作者明确要求迁移或测试其他环境时,才使用 `--base-url` 指定另一地址。
Agent 可用 `--image-url` 提交公网图片,也可用 `--image-file` 将生成在运营电脑上的本地图片直接 multipart 上传;两种模式不混用,不把图片转换为 Base64。
```powershell

View File

@@ -70,6 +70,21 @@ def apply_silently(path: Path, code: str) -> dict:
def main() -> None:
previous_base_url = os.environ.get("DELIVERY_DESK_BASE_URL")
os.environ["DELIVERY_DESK_BASE_URL"] = "http://should-not-override.invalid"
try:
assert MODULE.base_url() == "http://192.168.30.90:3010"
assert MODULE.base_url("https://delivery.example.com/") == "https://delivery.example.com"
finally:
if previous_base_url is None:
os.environ.pop("DELIVERY_DESK_BASE_URL", None)
else:
os.environ["DELIVERY_DESK_BASE_URL"] = previous_base_url
skill_text = (SCRIPT.parents[1] / "SKILL.md").read_text(encoding="utf-8")
assert "请回复“确认目标”" in skill_text
assert "Do not generate `plan-work` or `plan-round` before it." in skill_text
original_exact_project = MODULE.exact_project
original_request_json = MODULE.request_json
original_request_multipart = MODULE.request_multipart