From cffc48406cc79a5a15e927dfe1a9a4941265b1a7 Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 30 Jul 2026 10:29:39 +0800 Subject: [PATCH] fix(im): resolve direct recipients via contact search --- internal/cli/schema_agent_metadata/chat.json | 124 +++++++------- internal/cli/schema_agent_metadata/index.json | 2 +- internal/cli/schema_agent_metadata_audit.json | 2 +- internal/cli/schema_catalog/catalog.json | 16 +- internal/cli/schema_catalog/tools/chat.json | 158 +++++++++--------- internal/cli/schema_hints/metadata/chat.json | 8 +- internal/cli/schema_hints/selection/chat.json | 8 +- internal/shortcut/chat/chat_message.go | 4 +- .../shortcut/chat/coverage_completion_test.go | 6 +- internal/shortcut/chat/gap_fill_test.go | 25 ++- internal/shortcut/chat/lark_alignment.go | 13 +- internal/shortcut/chat/lark_alignment_test.go | 23 ++- internal/shortcut/chat/unified_send.go | 44 ++++- skills/mono/references/intent-guide.md | 8 +- skills/multi/dingtalk-chat/SKILL.md | 3 +- .../dws-shared/references/intent-guide.md | 8 +- 16 files changed, 250 insertions(+), 202 deletions(-) diff --git a/internal/cli/schema_agent_metadata/chat.json b/internal/cli/schema_agent_metadata/chat.json index a8767750..702ddd52 100644 --- a/internal/cli/schema_agent_metadata/chat.json +++ b/internal/cli/schema_agent_metadata/chat.json @@ -9836,14 +9836,14 @@ "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", "candidates": [ { "value": "统一发送文本、Markdown、当前用户文件或已有 mediaId 图片", "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media." + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media." } ] }, @@ -9852,14 +9852,14 @@ "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "candidates": [ { "value": "available", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." } ] }, @@ -9870,7 +9870,7 @@ "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", "candidates": [ { "value": [ @@ -9879,7 +9879,7 @@ "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media." + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media." } ] }, @@ -9888,14 +9888,14 @@ "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "candidates": [ { "value": "user_required", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." }, { "value": "not_required", @@ -9910,14 +9910,14 @@ "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "candidates": [ { "value": "write", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." }, { "value": "write", @@ -9935,7 +9935,7 @@ "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", "candidates": [ { "value": [ @@ -9945,7 +9945,7 @@ "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media." + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media." } ] }, @@ -9954,14 +9954,14 @@ "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "candidates": [ { "value": "unknown", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." }, { "value": "unknown", @@ -9976,30 +9976,30 @@ "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "candidates": [ { "value": "composite", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." } ] }, "interface_reason": { - "value": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports userId resolution, mediaId images, and the native init/upload/commit local-file flow.", + "value": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports live-compatible contact search with exact userId matching, mediaId images, and the native init/upload/commit local-file flow.", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "candidates": [ { - "value": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports userId resolution, mediaId images, and the native init/upload/commit local-file flow.", + "value": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports live-compatible contact search with exact userId matching, mediaId images, and the native init/upload/commit local-file flow.", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." } ] }, @@ -10024,21 +10024,21 @@ "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "candidates": [ { "value": true, "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." }, { "value": true, "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "selected": false, - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media." + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media." } ] }, @@ -10047,14 +10047,14 @@ "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "candidates": [ { "value": "medium", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists." }, { "value": "medium", @@ -10066,28 +10066,28 @@ }, "use_when": { "value": [ - "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先只读解析为 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" + "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" ], "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", "candidates": [ { "value": [ - "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先只读解析为 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" + "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" ], "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media." + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media." } ] } }, "idempotency": "unknown", "interface_mode": "composite", - "interface_reason": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports userId resolution, mediaId images, and the native init/upload/commit local-file flow.", + "interface_reason": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports live-compatible contact search with exact userId matching, mediaId images, and the native init/upload/commit local-file flow.", "reviewed": true, "risk": "medium", "source_refs": [ @@ -10099,7 +10099,7 @@ "skills/mono/references/intent-guide.md" ], "use_when": [ - "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先只读解析为 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" + "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" ] }, "chat +messages-send-by-webhook": { @@ -10380,14 +10380,14 @@ "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", "candidates": [ { "value": "创建流式卡片,可在同一次调用中写入内容并结束", "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting." + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting." } ] }, @@ -10396,14 +10396,14 @@ "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "candidates": [ { "value": "available", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." } ] }, @@ -10414,7 +10414,7 @@ "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", "candidates": [ { "value": [ @@ -10423,7 +10423,7 @@ "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting." + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting." } ] }, @@ -10432,14 +10432,14 @@ "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "candidates": [ { "value": "user_required", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." } ] }, @@ -10448,14 +10448,14 @@ "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "candidates": [ { "value": "write", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." } ] }, @@ -10467,7 +10467,7 @@ "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", "candidates": [ { "value": [ @@ -10477,7 +10477,7 @@ "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting." + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting." } ] }, @@ -10486,14 +10486,14 @@ "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "candidates": [ { "value": "unknown", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." } ] }, @@ -10502,30 +10502,30 @@ "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "candidates": [ { "value": "composite", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." } ] }, "interface_reason": { - "value": "Reviewed card lifecycle adapter: it can call create_and_send_card alone or compose it with update_streaming_card after extracting the returned bizId.", + "value": "Reviewed card lifecycle adapter: it can resolve a userId through contact search with exact matching, call create_and_send_card alone, or compose creation with update_streaming_card after extracting the returned bizId.", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "candidates": [ { - "value": "Reviewed card lifecycle adapter: it can call create_and_send_card alone or compose it with update_streaming_card after extracting the returned bizId.", + "value": "Reviewed card lifecycle adapter: it can resolve a userId through contact search with exact matching, call create_and_send_card alone, or compose creation with update_streaming_card after extracting the returned bizId.", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." } ] }, @@ -10550,21 +10550,21 @@ "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "candidates": [ { "value": true, "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." }, { "value": true, "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "selected": false, - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting." + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting." } ] }, @@ -10573,41 +10573,41 @@ "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "candidates": [ { "value": "medium", "source": "internal/cli/schema_hints/metadata/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property." } ] }, "use_when": { "value": [ - "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 做只读通讯录解析,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" + "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 通过通讯录关键词搜索做精确匹配,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" ], "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", "candidates": [ { "value": [ - "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 做只读通讯录解析,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" + "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 通过通讯录关键词搜索做精确匹配,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" ], "source": "internal/cli/schema_hints/selection/chat.json", "precedence": "reviewed_explicit", "selected": true, - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting." + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting." } ] } }, "idempotency": "unknown", "interface_mode": "composite", - "interface_reason": "Reviewed card lifecycle adapter: it can call create_and_send_card alone or compose it with update_streaming_card after extracting the returned bizId.", + "interface_reason": "Reviewed card lifecycle adapter: it can resolve a userId through contact search with exact matching, call create_and_send_card alone, or compose creation with update_streaming_card after extracting the returned bizId.", "reviewed": true, "risk": "medium", "source_refs": [ @@ -10618,7 +10618,7 @@ "internal/cli/schema_hints/selection/chat.json" ], "use_when": [ - "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 做只读通讯录解析,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" + "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 通过通讯录关键词搜索做精确匹配,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" ] }, "chat +messages-update-card": { diff --git a/internal/cli/schema_agent_metadata/index.json b/internal/cli/schema_agent_metadata/index.json index fca0f4cc..f80e1585 100644 --- a/internal/cli/schema_agent_metadata/index.json +++ b/internal/cli/schema_agent_metadata/index.json @@ -1,6 +1,6 @@ { "version": 1, - "source_hash": "sha256:f7afa1d0abaa0c3d4ead4c6262948b7565787abb0860bb724276d1d3fe52178b", + "source_hash": "sha256:f8cb29bdbeaceae6f04cbac8a93ea77f2a84f93f8304d25878c827b959bc0ba0", "surface_hash": "sha256:60eee8e2f37d6d9d60689efce85082798eb9ad38b7ba7c0b471c3de676a85a16", "coverage": { "surface_products": 26, diff --git a/internal/cli/schema_agent_metadata_audit.json b/internal/cli/schema_agent_metadata_audit.json index c0e5ff6e..01e0ac5f 100644 --- a/internal/cli/schema_agent_metadata_audit.json +++ b/internal/cli/schema_agent_metadata_audit.json @@ -1,6 +1,6 @@ { "version": 1, - "source_hash": "sha256:f7afa1d0abaa0c3d4ead4c6262948b7565787abb0860bb724276d1d3fe52178b", + "source_hash": "sha256:f8cb29bdbeaceae6f04cbac8a93ea77f2a84f93f8304d25878c827b959bc0ba0", "surface_hash": "sha256:60eee8e2f37d6d9d60689efce85082798eb9ad38b7ba7c0b471c3de676a85a16", "source_files": 160, "hint_files": 54, diff --git a/internal/cli/schema_catalog/catalog.json b/internal/cli/schema_catalog/catalog.json index 60f9e4aa..2a3ddf9a 100644 --- a/internal/cli/schema_catalog/catalog.json +++ b/internal/cli/schema_catalog/catalog.json @@ -1,12 +1,12 @@ { "version": 1, "surface_hash": "sha256:60eee8e2f37d6d9d60689efce85082798eb9ad38b7ba7c0b471c3de676a85a16", - "source_hash": "sha256:8fcebd5100f2727898290118b2b381cc3edc325bc1c8526e61036da5482e025b", + "source_hash": "sha256:735bbf8e04cfc44db741e9b14ffe1698f80aac5d2662d2c1c41b0aadcee9098d", "catalog": { "agent_metadata": { "products_with_metadata": 26, "source": "embedded-skill-metadata", - "source_hash": "sha256:f7afa1d0abaa0c3d4ead4c6262948b7565787abb0860bb724276d1d3fe52178b", + "source_hash": "sha256:f8cb29bdbeaceae6f04cbac8a93ea77f2a84f93f8304d25878c827b959bc0ba0", "surface_hash": "sha256:60eee8e2f37d6d9d60689efce85082798eb9ad38b7ba7c0b471c3de676a85a16", "surface_products": 26, "surface_tools": 845, @@ -10788,18 +10788,18 @@ "cli_name": "+messages-send", "cli_path": "chat +messages-send", "confirmation": "user_required", - "description": "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先只读解析为 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。\n\n参数约束:\n - --text、--markdown、--media-id、--file、--file-path 至少指定一个\n - --text、--markdown、--media-id、--file、--file-path 互斥,最多指定一个\n - --identity、--as 互斥,最多指定一个\n - --group、--chat-id 互斥,最多指定一个\n - --user、--open-dingtalk-id 互斥,最多指定一个\n - --uuid、--idempotency-key 互斥,最多指定一个\n - 目标、凭据和幂等参数受发送身份能力矩阵约束:user 必须指定一个群聊或单聊目标;bot 必须指定 robot-code 和一类目标;webhook 必须指定 webhook-token;幂等键仅 user 支持", + "description": "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。\n\n参数约束:\n - --text、--markdown、--media-id、--file、--file-path 至少指定一个\n - --text、--markdown、--media-id、--file、--file-path 互斥,最多指定一个\n - --identity、--as 互斥,最多指定一个\n - --group、--chat-id 互斥,最多指定一个\n - --user、--open-dingtalk-id 互斥,最多指定一个\n - --uuid、--idempotency-key 互斥,最多指定一个\n - 目标、凭据和幂等参数受发送身份能力矩阵约束:user 必须指定一个群聊或单聊目标;bot 必须指定 robot-code 和一类目标;webhook 必须指定 webhook-token;幂等键仅 user 支持", "effect": "write", "idempotency": "unknown", "interface_mode": "composite", - "interface_reason": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports userId resolution, mediaId images, and the native init/upload/commit local-file flow.", + "interface_reason": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports live-compatible contact search with exact userId matching, mediaId images, and the native init/upload/commit local-file flow.", "name": "shortcut_messages_send", "primary_cli_path": "chat +messages-send", "reviewed": true, "risk": "medium", "title": "统一发送文本、Markdown、当前用户文件或已有 mediaId 图片", "use_when": [ - "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先只读解析为 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" + "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" ] }, { @@ -10840,18 +10840,18 @@ "cli_name": "+messages-send-card", "cli_path": "chat +messages-send-card", "confirmation": "user_required", - "description": "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 做只读通讯录解析,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。\n\n参数约束:\n - --group、--receiver、--receiver-open-dingtalk-id 必须且只能指定一个\n - --flow-status 必须在 1-5 之间,且显式指定时必须同时提供 --content", + "description": "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 通过通讯录关键词搜索做精确匹配,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。\n\n参数约束:\n - --group、--receiver、--receiver-open-dingtalk-id 必须且只能指定一个\n - --flow-status 必须在 1-5 之间,且显式指定时必须同时提供 --content", "effect": "write", "idempotency": "unknown", "interface_mode": "composite", - "interface_reason": "Reviewed card lifecycle adapter: it can call create_and_send_card alone or compose it with update_streaming_card after extracting the returned bizId.", + "interface_reason": "Reviewed card lifecycle adapter: it can resolve a userId through contact search with exact matching, call create_and_send_card alone, or compose creation with update_streaming_card after extracting the returned bizId.", "name": "shortcut_messages_send_card", "primary_cli_path": "chat +messages-send-card", "reviewed": true, "risk": "medium", "title": "创建流式卡片,可在同一次调用中写入内容并结束", "use_when": [ - "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 做只读通讯录解析,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" + "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 通过通讯录关键词搜索做精确匹配,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" ] }, { diff --git a/internal/cli/schema_catalog/tools/chat.json b/internal/cli/schema_catalog/tools/chat.json index 40716f99..3b71ae25 100644 --- a/internal/cli/schema_catalog/tools/chat.json +++ b/internal/cli/schema_catalog/tools/chat.json @@ -73972,7 +73972,7 @@ ] ] }, - "description": "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先只读解析为 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。\n\n参数约束:\n - --text、--markdown、--media-id、--file、--file-path 至少指定一个\n - --text、--markdown、--media-id、--file、--file-path 互斥,最多指定一个\n - --identity、--as 互斥,最多指定一个\n - --group、--chat-id 互斥,最多指定一个\n - --user、--open-dingtalk-id 互斥,最多指定一个\n - --uuid、--idempotency-key 互斥,最多指定一个\n - 目标、凭据和幂等参数受发送身份能力矩阵约束:user 必须指定一个群聊或单聊目标;bot 必须指定 robot-code 和一类目标;webhook 必须指定 webhook-token;幂等键仅 user 支持", + "description": "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。\n\n参数约束:\n - --text、--markdown、--media-id、--file、--file-path 至少指定一个\n - --text、--markdown、--media-id、--file、--file-path 互斥,最多指定一个\n - --identity、--as 互斥,最多指定一个\n - --group、--chat-id 互斥,最多指定一个\n - --user、--open-dingtalk-id 互斥,最多指定一个\n - --uuid、--idempotency-key 互斥,最多指定一个\n - 目标、凭据和幂等参数受发送身份能力矩阵约束:user 必须指定一个群聊或单聊目标;bot 必须指定 robot-code 和一类目标;webhook 必须指定 webhook-token;幂等键仅 user 支持", "display": "群聊 / 消息 / 机器人", "effect": "write", "effect_source": "agent-hint", @@ -73985,7 +73985,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", "selected": true, "source": "internal/cli/schema_hints/selection/chat.json", "value": "统一发送文本、Markdown、当前用户文件或已有 mediaId 图片" @@ -73993,7 +73993,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", "source": "internal/cli/schema_hints/selection/chat.json", "value": "统一发送文本、Markdown、当前用户文件或已有 mediaId 图片" }, @@ -74001,7 +74001,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", "value": "available" @@ -74009,7 +74009,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "source": "internal/cli/schema_hints/metadata/chat.json", "value": "available" }, @@ -74017,7 +74017,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", "selected": true, "source": "internal/cli/schema_hints/selection/chat.json", "value": [ @@ -74027,7 +74027,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", "source": "internal/cli/schema_hints/selection/chat.json", "value": [ "需要 bot/webhook 发送媒体、卡片或 thread 回复时不要假设等价支持;改用真实存在的专用下层命令,缺少下层能力时停止" @@ -74053,7 +74053,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", "value": "user_required" @@ -74067,7 +74067,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "source": "internal/cli/schema_hints/metadata/chat.json", "value": "user_required" }, @@ -74077,19 +74077,19 @@ "precedence": "cobra_help", "selected": true, "source": "cobra_help", - "value": "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先只读解析为 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。\n\n参数约束:\n - --text、--markdown、--media-id、--file、--file-path 至少指定一个\n - --text、--markdown、--media-id、--file、--file-path 互斥,最多指定一个\n - --identity、--as 互斥,最多指定一个\n - --group、--chat-id 互斥,最多指定一个\n - --user、--open-dingtalk-id 互斥,最多指定一个\n - --uuid、--idempotency-key 互斥,最多指定一个\n - 目标、凭据和幂等参数受发送身份能力矩阵约束:user 必须指定一个群聊或单聊目标;bot 必须指定 robot-code 和一类目标;webhook 必须指定 webhook-token;幂等键仅 user 支持" + "value": "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。\n\n参数约束:\n - --text、--markdown、--media-id、--file、--file-path 至少指定一个\n - --text、--markdown、--media-id、--file、--file-path 互斥,最多指定一个\n - --identity、--as 互斥,最多指定一个\n - --group、--chat-id 互斥,最多指定一个\n - --user、--open-dingtalk-id 互斥,最多指定一个\n - --uuid、--idempotency-key 互斥,最多指定一个\n - 目标、凭据和幂等参数受发送身份能力矩阵约束:user 必须指定一个群聊或单聊目标;bot 必须指定 robot-code 和一类目标;webhook 必须指定 webhook-token;幂等键仅 user 支持" } ], "precedence": "cobra_help", "resolution": "highest_precedence", "source": "cobra_help", - "value": "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先只读解析为 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。\n\n参数约束:\n - --text、--markdown、--media-id、--file、--file-path 至少指定一个\n - --text、--markdown、--media-id、--file、--file-path 互斥,最多指定一个\n - --identity、--as 互斥,最多指定一个\n - --group、--chat-id 互斥,最多指定一个\n - --user、--open-dingtalk-id 互斥,最多指定一个\n - --uuid、--idempotency-key 互斥,最多指定一个\n - 目标、凭据和幂等参数受发送身份能力矩阵约束:user 必须指定一个群聊或单聊目标;bot 必须指定 robot-code 和一类目标;webhook 必须指定 webhook-token;幂等键仅 user 支持" + "value": "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。\n\n参数约束:\n - --text、--markdown、--media-id、--file、--file-path 至少指定一个\n - --text、--markdown、--media-id、--file、--file-path 互斥,最多指定一个\n - --identity、--as 互斥,最多指定一个\n - --group、--chat-id 互斥,最多指定一个\n - --user、--open-dingtalk-id 互斥,最多指定一个\n - --uuid、--idempotency-key 互斥,最多指定一个\n - 目标、凭据和幂等参数受发送身份能力矩阵约束:user 必须指定一个群聊或单聊目标;bot 必须指定 robot-code 和一类目标;webhook 必须指定 webhook-token;幂等键仅 user 支持" }, "effect": { "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", "value": "write" @@ -74103,7 +74103,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "source": "internal/cli/schema_hints/metadata/chat.json", "value": "write" }, @@ -74111,7 +74111,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", "selected": true, "source": "internal/cli/schema_hints/selection/chat.json", "value": [ @@ -74122,7 +74122,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", "source": "internal/cli/schema_hints/selection/chat.json", "value": [ "dws chat +messages-send --as user --chat-id \u003copenConversationId\u003e --markdown \"## 周报\" --idempotency-key \u003ckey\u003e", @@ -74133,7 +74133,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", "value": "unknown" @@ -74147,7 +74147,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "source": "internal/cli/schema_hints/metadata/chat.json", "value": "unknown" }, @@ -74155,7 +74155,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", "value": "composite" @@ -74163,7 +74163,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "source": "internal/cli/schema_hints/metadata/chat.json", "value": "composite" }, @@ -74171,17 +74171,17 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", - "value": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports userId resolution, mediaId images, and the native init/upload/commit local-file flow." + "value": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports live-compatible contact search with exact userId matching, mediaId images, and the native init/upload/commit local-file flow." } ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "source": "internal/cli/schema_hints/metadata/chat.json", - "value": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports userId resolution, mediaId images, and the native init/upload/commit local-file flow." + "value": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports live-compatible contact search with exact userId matching, mediaId images, and the native init/upload/commit local-file flow." }, "interface_ref": { "candidates": [ @@ -74203,14 +74203,14 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", "value": true }, { "precedence": "reviewed_explicit", - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", "selected": false, "source": "internal/cli/schema_hints/selection/chat.json", "value": true @@ -74218,7 +74218,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "source": "internal/cli/schema_hints/metadata/chat.json", "value": true }, @@ -74226,7 +74226,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", "value": "medium" @@ -74240,7 +74240,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "source": "internal/cli/schema_hints/metadata/chat.json", "value": "medium" }, @@ -74262,27 +74262,27 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", "selected": true, "source": "internal/cli/schema_hints/selection/chat.json", "value": [ - "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先只读解析为 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" + "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" ] } ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", "source": "internal/cli/schema_hints/selection/chat.json", "value": [ - "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先只读解析为 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" + "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" ] } }, "has_parameters": true, "idempotency": "unknown", "interface_mode": "composite", - "interface_reason": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports userId resolution, mediaId images, and the native init/upload/commit local-file flow.", + "interface_reason": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports live-compatible contact search with exact userId matching, mediaId images, and the native init/upload/commit local-file flow.", "is_alias": false, "name": "shortcut_messages_send", "parameter_count": 24, @@ -76120,7 +76120,7 @@ "type": "string" }, "user": { - "description": "单聊接收者 userId(user;包括 --dry-run 也会先只读解析 openDingTalkId);受发送身份能力矩阵约束", + "description": "单聊接收者 userId(user;包括 --dry-run 也会先通过通讯录搜索精确匹配 openDingTalkId);受发送身份能力矩阵约束", "field_provenance": { "description": { "candidates": [ @@ -76128,7 +76128,7 @@ "precedence": "cobra_contract", "selected": true, "source": "cobra_usage", - "value": "单聊接收者 userId(user;包括 --dry-run 也会先只读解析 openDingTalkId);受发送身份能力矩阵约束" + "value": "单聊接收者 userId(user;包括 --dry-run 也会先通过通讯录搜索精确匹配 openDingTalkId);受发送身份能力矩阵约束" }, { "precedence": "default", @@ -76140,7 +76140,7 @@ "precedence": "cobra_contract", "resolution": "highest_precedence", "source": "cobra_usage", - "value": "单聊接收者 userId(user;包括 --dry-run 也会先只读解析 openDingTalkId);受发送身份能力矩阵约束" + "value": "单聊接收者 userId(user;包括 --dry-run 也会先通过通讯录搜索精确匹配 openDingTalkId);受发送身份能力矩阵约束" }, "property": { "candidates": [ @@ -76464,7 +76464,7 @@ "source": "reviewed_command_registry", "title": "统一发送文本、Markdown、当前用户文件或已有 mediaId 图片", "use_when": [ - "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先只读解析为 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" + "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" ] }, "chat.shortcut_messages_send_by_webhook": { @@ -77361,7 +77361,7 @@ ] ] }, - "description": "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 做只读通讯录解析,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。\n\n参数约束:\n - --group、--receiver、--receiver-open-dingtalk-id 必须且只能指定一个\n - --flow-status 必须在 1-5 之间,且显式指定时必须同时提供 --content", + "description": "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 通过通讯录关键词搜索做精确匹配,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。\n\n参数约束:\n - --group、--receiver、--receiver-open-dingtalk-id 必须且只能指定一个\n - --flow-status 必须在 1-5 之间,且显式指定时必须同时提供 --content", "display": "群聊 / 消息 / 机器人", "effect": "write", "effect_source": "agent-hint", @@ -77374,7 +77374,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", "selected": true, "source": "internal/cli/schema_hints/selection/chat.json", "value": "创建流式卡片,可在同一次调用中写入内容并结束" @@ -77382,7 +77382,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", "source": "internal/cli/schema_hints/selection/chat.json", "value": "创建流式卡片,可在同一次调用中写入内容并结束" }, @@ -77390,7 +77390,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", "value": "available" @@ -77398,7 +77398,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "source": "internal/cli/schema_hints/metadata/chat.json", "value": "available" }, @@ -77406,7 +77406,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", "selected": true, "source": "internal/cli/schema_hints/selection/chat.json", "value": [ @@ -77416,7 +77416,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", "source": "internal/cli/schema_hints/selection/chat.json", "value": [ "已有 bizId、只需要追加或更新现有卡片内容时使用 +messages-update-card" @@ -77433,7 +77433,7 @@ }, { "precedence": "reviewed_manual", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "selected": false, "source": "reviewed_manual_hint", "source_ref": "chat +messages-send-card", @@ -77450,7 +77450,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", "value": "user_required" @@ -77458,7 +77458,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "source": "internal/cli/schema_hints/metadata/chat.json", "value": "user_required" }, @@ -77468,19 +77468,19 @@ "precedence": "cobra_help", "selected": true, "source": "cobra_help", - "value": "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 做只读通讯录解析,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。\n\n参数约束:\n - --group、--receiver、--receiver-open-dingtalk-id 必须且只能指定一个\n - --flow-status 必须在 1-5 之间,且显式指定时必须同时提供 --content" + "value": "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 通过通讯录关键词搜索做精确匹配,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。\n\n参数约束:\n - --group、--receiver、--receiver-open-dingtalk-id 必须且只能指定一个\n - --flow-status 必须在 1-5 之间,且显式指定时必须同时提供 --content" } ], "precedence": "cobra_help", "resolution": "highest_precedence", "source": "cobra_help", - "value": "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 做只读通讯录解析,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。\n\n参数约束:\n - --group、--receiver、--receiver-open-dingtalk-id 必须且只能指定一个\n - --flow-status 必须在 1-5 之间,且显式指定时必须同时提供 --content" + "value": "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 通过通讯录关键词搜索做精确匹配,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。\n\n参数约束:\n - --group、--receiver、--receiver-open-dingtalk-id 必须且只能指定一个\n - --flow-status 必须在 1-5 之间,且显式指定时必须同时提供 --content" }, "effect": { "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", "value": "write" @@ -77488,7 +77488,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "source": "internal/cli/schema_hints/metadata/chat.json", "value": "write" }, @@ -77496,7 +77496,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", "selected": true, "source": "internal/cli/schema_hints/selection/chat.json", "value": [ @@ -77507,7 +77507,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", "source": "internal/cli/schema_hints/selection/chat.json", "value": [ "dws chat +messages-send-card --group \u003copenConversationId\u003e --content \"任务已完成\"", @@ -77518,7 +77518,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", "value": "unknown" @@ -77526,7 +77526,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "source": "internal/cli/schema_hints/metadata/chat.json", "value": "unknown" }, @@ -77534,7 +77534,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", "value": "composite" @@ -77542,7 +77542,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "source": "internal/cli/schema_hints/metadata/chat.json", "value": "composite" }, @@ -77550,17 +77550,17 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", - "value": "Reviewed card lifecycle adapter: it can call create_and_send_card alone or compose it with update_streaming_card after extracting the returned bizId." + "value": "Reviewed card lifecycle adapter: it can resolve a userId through contact search with exact matching, call create_and_send_card alone, or compose creation with update_streaming_card after extracting the returned bizId." } ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "source": "internal/cli/schema_hints/metadata/chat.json", - "value": "Reviewed card lifecycle adapter: it can call create_and_send_card alone or compose it with update_streaming_card after extracting the returned bizId." + "value": "Reviewed card lifecycle adapter: it can resolve a userId through contact search with exact matching, call create_and_send_card alone, or compose creation with update_streaming_card after extracting the returned bizId." }, "interface_ref": { "candidates": [ @@ -77582,14 +77582,14 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", "value": true }, { "precedence": "reviewed_explicit", - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", "selected": false, "source": "internal/cli/schema_hints/selection/chat.json", "value": true @@ -77597,7 +77597,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "source": "internal/cli/schema_hints/metadata/chat.json", "value": true }, @@ -77605,7 +77605,7 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "selected": true, "source": "internal/cli/schema_hints/metadata/chat.json", "value": "medium" @@ -77613,7 +77613,7 @@ ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "source": "internal/cli/schema_hints/metadata/chat.json", "value": "medium" }, @@ -77635,27 +77635,27 @@ "candidates": [ { "precedence": "reviewed_explicit", - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", "selected": true, "source": "internal/cli/schema_hints/selection/chat.json", "value": [ - "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 做只读通讯录解析,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" + "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 通过通讯录关键词搜索做精确匹配,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" ] } ], "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", "source": "internal/cli/schema_hints/selection/chat.json", "value": [ - "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 做只读通讯录解析,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" + "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 通过通讯录关键词搜索做精确匹配,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" ] } }, "has_parameters": true, "idempotency": "unknown", "interface_mode": "composite", - "interface_reason": "Reviewed card lifecycle adapter: it can call create_and_send_card alone or compose it with update_streaming_card after extracting the returned bizId.", + "interface_reason": "Reviewed card lifecycle adapter: it can resolve a userId through contact search with exact matching, call create_and_send_card alone, or compose creation with update_streaming_card after extracting the returned bizId.", "is_alias": false, "name": "shortcut_messages_send_card", "parameter_count": 5, @@ -77926,7 +77926,7 @@ "type": "string" }, "receiver": { - "description": "单聊接收者 userId(与 --group/--receiver-open-dingtalk-id 互斥);始终只读解析为 openDingTalkId,包括 --dry-run 和 D/d 开头的 userId", + "description": "单聊接收者 userId(与 --group/--receiver-open-dingtalk-id 互斥);始终通过通讯录搜索精确匹配 openDingTalkId,包括 --dry-run 和 D/d 开头的 userId", "field_provenance": { "description": { "candidates": [ @@ -77934,7 +77934,7 @@ "precedence": "cobra_contract", "selected": true, "source": "cobra_usage", - "value": "单聊接收者 userId(与 --group/--receiver-open-dingtalk-id 互斥);始终只读解析为 openDingTalkId,包括 --dry-run 和 D/d 开头的 userId" + "value": "单聊接收者 userId(与 --group/--receiver-open-dingtalk-id 互斥);始终通过通讯录搜索精确匹配 openDingTalkId,包括 --dry-run 和 D/d 开头的 userId" }, { "precedence": "default", @@ -77946,7 +77946,7 @@ "precedence": "cobra_contract", "resolution": "highest_precedence", "source": "cobra_usage", - "value": "单聊接收者 userId(与 --group/--receiver-open-dingtalk-id 互斥);始终只读解析为 openDingTalkId,包括 --dry-run 和 D/d 开头的 userId" + "value": "单聊接收者 userId(与 --group/--receiver-open-dingtalk-id 互斥);始终通过通讯录搜索精确匹配 openDingTalkId,包括 --dry-run 和 D/d 开头的 userId" }, "property": { "candidates": [ @@ -78042,7 +78042,7 @@ "candidates": [ { "precedence": "reviewed_manual", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "selected": true, "source": "reviewed_manual_hint", "value": "receiverOpenDingTalkId" @@ -78056,7 +78056,7 @@ ], "precedence": "reviewed_manual", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "source": "reviewed_manual_hint", "value": "receiverOpenDingTalkId" }, @@ -78064,7 +78064,7 @@ "candidates": [ { "precedence": "reviewed_manual", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "selected": true, "source": "reviewed_manual_hint", "value": false @@ -78084,7 +78084,7 @@ ], "precedence": "reviewed_manual", "resolution": "highest_precedence", - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "source": "reviewed_manual_hint", "value": false }, @@ -78130,7 +78130,7 @@ "source": "reviewed_command_registry", "title": "创建流式卡片,可在同一次调用中写入内容并结束", "use_when": [ - "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 做只读通讯录解析,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" + "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 通过通讯录关键词搜索做精确匹配,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" ] }, "chat.shortcut_messages_update_card": { diff --git a/internal/cli/schema_hints/metadata/chat.json b/internal/cli/schema_hints/metadata/chat.json index 3aa3f546..21ee7b18 100644 --- a/internal/cli/schema_hints/metadata/chat.json +++ b/internal/cli/schema_hints/metadata/chat.json @@ -1172,9 +1172,9 @@ "idempotency": "unknown", "interface_mode": "composite", "availability": "available", - "interface_reason": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports userId resolution, mediaId images, and the native init/upload/commit local-file flow.", + "interface_reason": "Reviewed composite send adapter: it selects current-user, bot, or webhook transport; current-user additionally supports live-compatible contact search with exact userId matching, mediaId images, and the native init/upload/commit local-file flow.", "reviewed": true, - "review_reason": "Reviewed against every executable identity/content/target validation branch and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", + "review_reason": "Reviewed against every executable identity/content/target validation branch, authenticated contact-search response shape, and the real lower tool mappings; bot and webhook media are intentionally rejected because no equivalent lower capability exists.", "cli_path": "chat +messages-send", "runtime_gate": "typed_yes" }, @@ -1198,7 +1198,7 @@ "idempotency": "unknown", "interface_mode": "composite", "availability": "available", - "interface_reason": "Reviewed card lifecycle adapter: it can call create_and_send_card alone or compose it with update_streaming_card after extracting the returned bizId.", + "interface_reason": "Reviewed card lifecycle adapter: it can resolve a userId through contact search with exact matching, call create_and_send_card alone, or compose creation with update_streaming_card after extracting the returned bizId.", "parameters": { "receiver-open-dingtalk-id": { "property": "receiverOpenDingTalkId", @@ -1206,7 +1206,7 @@ } }, "reviewed": true, - "review_reason": "Reviewed against create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", + "review_reason": "Reviewed against authenticated contact-search resolution, create-only, two-action dry-run, create/update success, missing bizId, and partial-failure behavior that preserves the created bizId; the explicit openDingTalkId flag is bound to the lower interface's exact receiverOpenDingTalkId property.", "cli_path": "chat +messages-send-card", "runtime_gate": "typed_yes" }, diff --git a/internal/cli/schema_hints/selection/chat.json b/internal/cli/schema_hints/selection/chat.json index 789db46c..bd250c60 100644 --- a/internal/cli/schema_hints/selection/chat.json +++ b/internal/cli/schema_hints/selection/chat.json @@ -2133,7 +2133,7 @@ "chat.shortcut_messages_send": { "agent_summary": "统一发送文本、Markdown、当前用户文件或已有 mediaId 图片", "use_when": [ - "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先只读解析为 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" + "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。" ], "avoid_when": [ "需要 bot/webhook 发送媒体、卡片或 thread 回复时不要假设等价支持;改用真实存在的专用下层命令,缺少下层能力时停止" @@ -2143,7 +2143,7 @@ "dws chat +messages-send --as user --user --msg-type file --file ./report.pdf" ], "reviewed": true, - "review_reason": "Agent-authored from the verified identity/content capability matrix, userId resolution, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", + "review_reason": "Agent-authored from the verified identity/content capability matrix, live-compatible contact search with exact userId matching, native local-file upload flow, and fail-closed rejection of unsupported bot/webhook media.", "source_refs": [ "internal/cli/schema_command_registry.json#chat.shortcut_messages_send", "cobra-help:dws chat +messages-send", @@ -2172,7 +2172,7 @@ "chat.shortcut_messages_send_card": { "agent_summary": "创建流式卡片,可在同一次调用中写入内容并结束", "use_when": [ - "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 做只读通讯录解析,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" + "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 通过通讯录关键词搜索做精确匹配,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。" ], "avoid_when": [ "已有 bizId、只需要追加或更新现有卡片内容时使用 +messages-update-card" @@ -2182,7 +2182,7 @@ "dws chat +messages-send-card --receiver " ], "reviewed": true, - "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", + "review_reason": "Agent-authored from the verified create-only and create-then-update lifecycle, live-compatible contact search with exact userId matching, explicit userId/openDingTalkId routing, two-action dry-run, bizId extraction, and partial-failure reporting.", "source_refs": [ "internal/cli/schema_command_registry.json#chat.shortcut_messages_send_card", "cobra-help:dws chat +messages-send-card", diff --git a/internal/shortcut/chat/chat_message.go b/internal/shortcut/chat/chat_message.go index 50edbe40..4ec4aa8e 100644 --- a/internal/shortcut/chat/chat_message.go +++ b/internal/shortcut/chat/chat_message.go @@ -1015,11 +1015,11 @@ var MessagesSendCard = shortcut.Shortcut{ Command: "+messages-send-card", Product: "im", Description: "创建流式卡片,可在同一次调用中写入内容并结束", - Intent: "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 做只读通讯录解析,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。", + Intent: "当你要发送一张流式卡片消息时使用;群 openConversationId、单聊 userId、单聊 openDingTalkId 严格三选一,分别使用 --group、--receiver、--receiver-open-dingtalk-id。--receiver 始终按 userId 通过通讯录关键词搜索做精确匹配,即使值以 D/d 开头也不会猜成 openDingTalkId;已有 openDingTalkId 时必须用显式参数直传。userId 包括在 --dry-run 时也会先解析。只传目标时创建卡片并返回 bizId,供后续 messages-update-card 流式更新;同时传 --content 时会自动串联创建和更新,默认以 flowStatus=3 完成,避免卡片停留在加载中。", Risk: shortcut.RiskWrite, Flags: []shortcut.Flag{ {Name: "group", Type: shortcut.FlagString, Desc: "群 openConversationId(与两个单聊接收者参数互斥)"}, - {Name: "receiver", Type: shortcut.FlagString, Desc: "单聊接收者 userId(与 --group/--receiver-open-dingtalk-id 互斥);始终只读解析为 openDingTalkId,包括 --dry-run 和 D/d 开头的 userId"}, + {Name: "receiver", Type: shortcut.FlagString, Desc: "单聊接收者 userId(与 --group/--receiver-open-dingtalk-id 互斥);始终通过通讯录搜索精确匹配 openDingTalkId,包括 --dry-run 和 D/d 开头的 userId"}, {Name: "receiver-open-dingtalk-id", Type: shortcut.FlagString, Desc: "单聊接收者 openDingTalkId(与 --group/--receiver 互斥);显式直传且不做通讯录解析"}, {Name: "content", Type: shortcut.FlagString, Desc: "创建后立即写入的卡片内容;省略时仅创建并返回 bizId"}, {Name: "flow-status", Type: shortcut.FlagInt, Default: "3", Desc: "自动更新状态:1处理中/2输入中/3完成/4执行中/5错误;--flow-status 必须在 1-5 之间,且显式指定时必须同时提供 --content"}, diff --git a/internal/shortcut/chat/coverage_completion_test.go b/internal/shortcut/chat/coverage_completion_test.go index 6d3d34b2..8f8b47f1 100644 --- a/internal/shortcut/chat/coverage_completion_test.go +++ b/internal/shortcut/chat/coverage_completion_test.go @@ -120,17 +120,17 @@ func TestCrossPlatformCoverageChatCreateAndReplyFailures(t *testing.T) { }, { name: "explicit sender lookup", - caller: &larkAlignmentCaller{failProductTool: "contact/get_user_info_by_user_ids"}, + caller: &larkAlignmentCaller{failProductTool: "contact/search_contact_by_key_word"}, args: []string{"chat", "+messages-reply", "--conversation-id", "cid", "--message-id", "msg", "--ref-sender", "user-id", "--text", "收到", "--yes"}, wantError: "解析为 openDingTalkId", }, { name: "explicit sender unresolved", caller: &larkAlignmentCaller{responses: map[string]string{ - "contact/get_user_info_by_user_ids": `{"result":[]}`, + "contact/search_contact_by_key_word": `{"result":[]}`, }}, args: []string{"chat", "+messages-reply", "--conversation-id", "cid", "--message-id", "msg", "--ref-sender", "user-id", "--text", "收到", "--yes"}, - wantError: "无法把 --ref-sender", + wantError: "没有精确匹配", }, { name: "referenced message lookup", diff --git a/internal/shortcut/chat/gap_fill_test.go b/internal/shortcut/chat/gap_fill_test.go index b74df949..0af89941 100644 --- a/internal/shortcut/chat/gap_fill_test.go +++ b/internal/shortcut/chat/gap_fill_test.go @@ -80,9 +80,12 @@ func TestCrossPlatformCoverageMessagesSendCurrentUserImageAndUserResolution(t *t if len(fake.calls) != 2 { t.Fatalf("calls = %#v, want contact resolution + send", fake.calls) } - if fake.calls[0].product != "contact" || fake.calls[0].tool != "get_user_info_by_user_ids" { + if fake.calls[0].product != "contact" || fake.calls[0].tool != "search_contact_by_key_word" { t.Fatalf("resolution call = %#v", fake.calls[0]) } + if got := fake.calls[0].args["keyword"]; got != "user-id" { + t.Fatalf("resolution keyword = %#v, want user-id", got) + } send := fake.calls[1] if send.product != "chat" || send.tool != "send_personal_message" { t.Fatalf("send call = %#v", send) @@ -284,9 +287,15 @@ func TestCrossPlatformCoverageMessagesSendUserResolutionFailures(t *testing.T) { name string fake *larkAlignmentCaller }{ - {"lookup error", &larkAlignmentCaller{failProductTool: "contact/get_user_info_by_user_ids"}}, + {"lookup error", &larkAlignmentCaller{failProductTool: "contact/search_contact_by_key_word"}}, + {"no exact user id", &larkAlignmentCaller{responses: map[string]string{ + "contact/search_contact_by_key_word": `{"result":[{"userId":"other-user","openDingTalkId":"D-other"}]}`, + }}}, {"missing open id", &larkAlignmentCaller{responses: map[string]string{ - "contact/get_user_info_by_user_ids": `{"result":[]}`, + "contact/search_contact_by_key_word": `{"result":[{"userId":"user-id","name":"Resolved User"}]}`, + }}}, + {"ambiguous open id", &larkAlignmentCaller{responses: map[string]string{ + "contact/search_contact_by_key_word": `{"result":[{"userId":"user-id","openDingTalkId":"D-one"},{"userId":"user-id","openDingTalkId":"D-two"}]}`, }}}, } { t.Run(tc.name, func(t *testing.T) { @@ -394,7 +403,7 @@ func TestCrossPlatformCoverageMessagesSendCardResolvesReceiverForLowerTool(t *te } if len(fake.calls) != 2 || fake.calls[0].product != "contact" || - fake.calls[0].tool != "get_user_info_by_user_ids" || + fake.calls[0].tool != "search_contact_by_key_word" || fake.calls[1].product != "im" || fake.calls[1].tool != "create_and_send_card" { t.Fatalf("card receiver calls = %#v", fake.calls) @@ -402,7 +411,7 @@ func TestCrossPlatformCoverageMessagesSendCardResolvesReceiverForLowerTool(t *te if got := fake.calls[1].args["receiverOpenDingTalkId"]; got != "D-resolved" { t.Fatalf("receiverOpenDingTalkId = %#v, want D-resolved", got) } - if got := fake.calls[0].args["user_id_list"]; !reflect.DeepEqual(got, []string{"d-user-id"}) { + if got := fake.calls[0].args["keyword"]; got != "d-user-id" { t.Fatalf("D/d-prefixed userId resolution args = %#v", fake.calls[0].args) } if _, exists := fake.calls[1].args["receiverUid"]; exists { @@ -469,7 +478,7 @@ func TestCrossPlatformCoverageMessagesSendCardDryRunAndFailureBoundaries(t *test } if len(fake.calls) != 1 || fake.calls[0].product != "contact" || - fake.calls[0].tool != "get_user_info_by_user_ids" { + fake.calls[0].tool != "search_contact_by_key_word" { t.Fatalf("card dry-run receiver resolution calls = %#v", fake.calls) } var payload map[string]any @@ -486,7 +495,7 @@ func TestCrossPlatformCoverageMessagesSendCardDryRunAndFailureBoundaries(t *test }) t.Run("receiver resolution error", func(t *testing.T) { - fake := &larkAlignmentCaller{failProductTool: "contact/get_user_info_by_user_ids"} + fake := &larkAlignmentCaller{failProductTool: "contact/search_contact_by_key_word"} helpers.InitDeps(fake) root := newPlatformCoverageRoot() root.SetArgs([]string{ @@ -498,7 +507,7 @@ func TestCrossPlatformCoverageMessagesSendCardDryRunAndFailureBoundaries(t *test if err == nil || !strings.Contains(err.Error(), "解析为 openDingTalkId 失败") { t.Fatalf("receiver resolution error = %v", err) } - if len(fake.calls) != 1 || fake.calls[0].tool != "get_user_info_by_user_ids" { + if len(fake.calls) != 1 || fake.calls[0].tool != "search_contact_by_key_word" { t.Fatalf("receiver resolution calls = %#v", fake.calls) } }) diff --git a/internal/shortcut/chat/lark_alignment.go b/internal/shortcut/chat/lark_alignment.go index 9477a3ba..f7679d22 100644 --- a/internal/shortcut/chat/lark_alignment.go +++ b/internal/shortcut/chat/lark_alignment.go @@ -139,13 +139,13 @@ var MessagesReply = shortcut.Shortcut{ Command: "+messages-reply", Product: "chat", Description: "以当前用户身份引用回复消息(自动补全原发送者)", - Intent: "当你要以当前用户身份对已有消息发送纯文本引用回复时使用;提供会话和被引用消息即可,默认通过 mget 自动读取原发送者,也可显式传 openDingTalkId/userId。它不支持 bot 身份、富媒体、卡片或 thread 内回复。", + Intent: "当你要以当前用户身份对已有消息发送纯文本引用回复时使用;提供会话和被引用消息即可,默认通过 mget 自动读取原发送者,也可显式传 openDingTalkId/userId;userId 会通过通讯录搜索精确匹配 openDingTalkId。它不支持 bot 身份、富媒体、卡片或 thread 内回复。", Risk: shortcut.RiskWrite, Flags: []shortcut.Flag{ {Name: "conversation-id", Type: shortcut.FlagString, Desc: "会话 openConversationId", Required: true}, {Name: "ref-msg-id", Type: shortcut.FlagString, Desc: "被引用消息 openMessageId"}, {Name: "message-id", Type: shortcut.FlagString, Desc: "--ref-msg-id 的 lark-cli 对齐别名"}, - {Name: "ref-sender", Type: shortcut.FlagString, Desc: "原消息发送者 openDingTalkId/userId(不传则自动读取)"}, + {Name: "ref-sender", Type: shortcut.FlagString, Desc: "原消息发送者 openDingTalkId/userId(userId 通过通讯录搜索精确匹配;不传则自动读取)"}, {Name: "text", Type: shortcut.FlagString, Desc: "纯文本回复内容", Required: true}, {Name: "uuid", Type: shortcut.FlagString, Desc: "幂等键(可选)"}, {Name: "idempotency-key", Type: shortcut.FlagString, Desc: "--uuid 的 lark-cli 对齐别名"}, @@ -184,16 +184,11 @@ func resolveReplySender(rt *shortcut.RuntimeContext) (string, error) { if isOpenID(value) { return value, nil } - data, err := rt.CallMCPData("contact", "get_user_info_by_user_ids", map[string]any{ - "user_id_list": []string{value}, - }) + openID, err := resolveUserOpenDingTalkID(rt, value) if err != nil { return "", fmt.Errorf("把 --ref-sender userId 解析为 openDingTalkId 失败: %w", err) } - if openID := findOpenDingTalkID(data); openID != "" { - return openID, nil - } - return "", apperrors.NewValidation("无法把 --ref-sender 解析为 openDingTalkId") + return openID, nil } messageID := replyMessageID(rt) diff --git a/internal/shortcut/chat/lark_alignment_test.go b/internal/shortcut/chat/lark_alignment_test.go index fda0c22e..4331a82f 100644 --- a/internal/shortcut/chat/lark_alignment_test.go +++ b/internal/shortcut/chat/lark_alignment_test.go @@ -44,7 +44,24 @@ func (f *larkAlignmentCaller) CallTool(_ context.Context, product, tool string, case "contact/get_current_user_profile": text = `{"result":[{"orgEmployeeModel":{"userId":"self-user"}}]}` case "contact/get_user_info_by_user_ids": - text = `{"result":[{"userId":"user-id","openDingTalkId":"D-resolved"}]}` + text = `{"result":[{"orgEmployeeModel":{"orgUserId":"user-id","orgUserName":"Resolved User"}}]}` + case "contact/search_contact_by_key_word": + keyword, _ := args["keyword"].(string) + payload, _ := json.Marshal(map[string]any{ + "result": []map[string]any{ + { + "name": "Fuzzy Neighbor", + "userId": keyword + "-other", + "openDingTalkId": "D-other", + }, + { + "name": "Resolved User", + "userId": keyword, + "openDingTalkId": "D-resolved", + }, + }, + }) + text = string(payload) case "im/create_group_conversation": text = `{"result":{"cid":"internal-cid","openCid":"open-cid"}}` case "im/list_messages_by_ids": @@ -403,7 +420,7 @@ func TestMessagesMgetDryRunPublishesMultiResourceDownloadPlan(t *testing.T) { } } -func TestMessagesReplyResolvesUserIDBeforeExecution(t *testing.T) { +func TestCrossPlatformCoverageMessagesReplyResolvesUserIDBeforeExecution(t *testing.T) { fake := &larkAlignmentCaller{} helpers.InitDeps(fake) root := newPlatformCoverageRoot() @@ -420,7 +437,7 @@ func TestMessagesReplyResolvesUserIDBeforeExecution(t *testing.T) { } if len(fake.calls) != 2 || fake.calls[0].product != "contact" || - fake.calls[0].tool != "get_user_info_by_user_ids" || + fake.calls[0].tool != "search_contact_by_key_word" || fake.calls[1].tool != "send_personal_message" { t.Fatalf("calls = %#v", fake.calls) } diff --git a/internal/shortcut/chat/unified_send.go b/internal/shortcut/chat/unified_send.go index 72b91702..d0024bf6 100644 --- a/internal/shortcut/chat/unified_send.go +++ b/internal/shortcut/chat/unified_send.go @@ -28,14 +28,14 @@ var MessagesSend = shortcut.Shortcut{ Command: "+messages-send", Product: "chat", Description: "统一发送文本、Markdown、当前用户文件或已有 mediaId 图片", - Intent: "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先只读解析为 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。", + Intent: "当你希望用同一个入口选择 current-user、bot 或 webhook 身份发送消息时使用;命令会按身份校验目标、内容和凭据并路由到真实下层。current-user 支持文本/Markdown、已有 mediaId 图片、安全相对路径文件上传和幂等键;--user 传 userId 时包括在 --dry-run 中也会先通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId。bot 支持群聊或批量单聊文本/Markdown;webhook 的目标由 token 所在群决定。不会把 user 文件能力伪装成 bot/webhook 等价能力。", Risk: shortcut.RiskWrite, Flags: []shortcut.Flag{ {Name: "identity", Type: shortcut.FlagString, Default: "user", Enum: []string{"user", "bot", "webhook"}, Desc: "发送身份;目标、凭据和幂等参数受发送身份能力矩阵约束"}, {Name: "as", Type: shortcut.FlagString, Enum: []string{"user", "bot", "webhook"}, Desc: "--identity 的 lark-cli 对齐别名;受发送身份能力矩阵约束"}, {Name: "group", Type: shortcut.FlagString, Desc: "群 openConversationId(user/bot 群聊);受发送身份能力矩阵约束"}, {Name: "chat-id", Type: shortcut.FlagString, Desc: "--group 的 lark-cli 对齐别名;受发送身份能力矩阵约束"}, - {Name: "user", Type: shortcut.FlagString, Desc: "单聊接收者 userId(user;包括 --dry-run 也会先只读解析 openDingTalkId);受发送身份能力矩阵约束"}, + {Name: "user", Type: shortcut.FlagString, Desc: "单聊接收者 userId(user;包括 --dry-run 也会先通过通讯录搜索精确匹配 openDingTalkId);受发送身份能力矩阵约束"}, {Name: "open-dingtalk-id", Type: shortcut.FlagString, Desc: "单聊接收者 openDingTalkId(user);受发送身份能力矩阵约束"}, {Name: "users", Type: shortcut.FlagStringSlice, Desc: "批量单聊接收者 userId(bot);受发送身份能力矩阵约束"}, {Name: "open-dingtalk-ids", Type: shortcut.FlagStringSlice, Desc: "批量单聊接收者 openDingTalkId(bot);受发送身份能力矩阵约束"}, @@ -368,17 +368,43 @@ func messagesSendUserTarget(rt *shortcut.RuntimeContext) (group, openID string, func resolveUserOpenDingTalkID(rt *shortcut.RuntimeContext, userID string) (string, error) { userID = strings.TrimSpace(userID) - data, err := rt.CallMCPData("contact", "get_user_info_by_user_ids", map[string]any{ - "user_id_list": []string{userID}, + data, err := rt.CallMCPData("contact", "search_contact_by_key_word", map[string]any{ + "keyword": userID, }) if err != nil { - return "", fmt.Errorf("把 userId 解析为 openDingTalkId 失败: %w", err) + return "", fmt.Errorf("通过通讯录搜索把 userId %q 解析为 openDingTalkId 失败: %w", userID, err) } - openID := findOpenDingTalkID(data) - if openID == "" { - return "", apperrors.NewValidation("无法把 userId 解析为 openDingTalkId;请改用当前命令提供的显式 openDingTalkId 参数") + + exactRows := 0 + openIDs := make([]string, 0, 1) + for _, user := range shortcutMapSlice(data["result"]) { + if shortcutString(user, "userId", "userID") != userID { + continue + } + exactRows++ + if openID := shortcutString(user, "openDingTalkId", "openDingtalkId"); openID != "" { + openIDs = appendUniqueShortcutString(openIDs, openID) + } + } + switch { + case len(openIDs) == 1: + return openIDs[0], nil + case len(openIDs) > 1: + return "", apperrors.NewValidation(fmt.Sprintf( + "通讯录中 userId %q 精确匹配到多个不同的 openDingTalkId,无法安全选择", + userID, + )) + case exactRows > 0: + return "", apperrors.NewValidation(fmt.Sprintf( + "通讯录已精确匹配 userId %q,但结果未返回 openDingTalkId", + userID, + )) + default: + return "", apperrors.NewValidation(fmt.Sprintf( + "通讯录搜索结果中没有精确匹配的 userId %q", + userID, + )) } - return openID, nil } func executeMessagesSendUserFile( diff --git a/skills/mono/references/intent-guide.md b/skills/mono/references/intent-guide.md index e28c4fc7..69e34d65 100644 --- a/skills/mono/references/intent-guide.md +++ b/skills/mono/references/intent-guide.md @@ -273,8 +273,8 @@ alidocs 链接表面长得一样(`https://alidocs.dingtalk.com/i/nodes/{id}` - "帮我在群里发个消息提醒大家" — **个人身份**发群消息 - "发个单聊消息给某人" — 个人身份发单聊: - 已有 userId 时直接使用 `--user`;已有 openDingTalkId 时使用 `--open-dingtalk-id` - - 纯文本/Markdown 单聊传 `--user` 时直接走 userId 发送能力,不需要先手动查询 openDingTalkId - - 富媒体消息(image/file)单聊优先使用 `--open-dingtalk-id`;传 `--user` 时 CLI 会尝试解析为 openDingTalkId 后发送 + - `+messages-send --user` 对所有内容类型都会通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId;无需手动预查,`--dry-run` 也会执行这次只读解析 + - 已持有 openDingTalkId 时优先使用显式 `--open-dingtalk-id`,避免额外解析 - "发本地图片/文件/语音/视频到群里" — `dws chat message send ... --msg-type file --file-path <本地路径>`,CLI 内部自动上传并发送;png/jpg/pdf/mp4/zip 等任意扩展名都走这条,接收方看到的是可下载的文件附件。图片不会内联渲染,也不会生成 mediaId - "用已有 mediaId 发内联图片" — 仅当上游已经提供有效 mediaId 时,使用 `dws chat message send ... --msg-type image --media-id `;DWS CLI 不能把本地图片转换成 mediaId - "发图片+文字说明" — 不要硬塞进一条命令;先发图片/文件消息再补一条 `--text "..."` 即可 @@ -285,13 +285,13 @@ dws chat +messages-send --as user --open-dingtalk-id --msg-type ``` > ❌ 反模式:先把本地文件转换成 mediaId,或先经钉盘上传再拼装聊天消息。本地图片/文件一律用 `--msg-type file --file` 直发;`--msg-type image --media-id` 只接受上游已经提供的有效 mediaId。 -> 富媒体消息单聊优先使用 `--open-dingtalk-id`;传 `--user` 时 CLI 会尝试解析为 openDingTalkId 后发送。 +> 单聊已持有 openDingTalkId 时优先使用 `--open-dingtalk-id`;传 `--user` 时 CLI 会通过通讯录关键词搜索做 userId 精确匹配后发送。 `+messages-send` 的 @ 占位符按身份自动规范化并补齐:user 使用 `<@id>` / `<@all>`;bot/webhook 使用 `@id` / `@手机号` / `@all`。声明 `--at-*` / `--at-all` 即可,不要再手工拼 `@10`。 **用 `chat +messages-send-card` 的场景**: - 群聊流式卡片使用 `--group `。 -- 单聊已有 userId 时使用 `--receiver `,CLI 始终先只读解析为 openDingTalkId;即使 userId 以 D/d 开头也不会猜测类型,`--dry-run` 也会执行该解析。 +- 单聊已有 userId 时使用 `--receiver `,CLI 始终通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId;即使 userId 以 D/d 开头也不会猜测类型,`--dry-run` 也会执行该解析。 - 单聊已有 openDingTalkId 时必须显式使用 `--receiver-open-dingtalk-id `,避免与 userId 混淆。 - `--group`、`--receiver`、`--receiver-open-dingtalk-id` 严格三选一;传 `--content` 可在同一次调用中创建并结束卡片。 diff --git a/skills/multi/dingtalk-chat/SKILL.md b/skills/multi/dingtalk-chat/SKILL.md index 208c066e..7b0a4497 100644 --- a/skills/multi/dingtalk-chat/SKILL.md +++ b/skills/multi/dingtalk-chat/SKILL.md @@ -130,7 +130,8 @@ metadata: - 查询结果中的 `resourceRefs` 是可继续执行的资源上下文。引用、回复或合并转发中的子消息必须使用该子消息返回的 `messageId`;子消息缺会话 ID 时才继承父消息的 `openConversationId`。 - 上述五个查询 Shortcut 与 `+messages-resource-download` 都沿用安全本地下载的 `read/not_required` 契约,不应添加 `--yes` 或触发交互确认。下载只允许工作目录内相对路径、默认不覆盖并原子落盘;需要覆盖时必须由用户显式传 `--overwrite`。 - `+messages-send` 会按身份规范化 @ 占位符:user 使用 `<@id>` / `<@all>`,bot/webhook 使用 `@id` / `@手机号` / `@all`;只需声明 `--at-*` / `--at-all`,缺失占位符会自动补齐。 -- 流式卡片优先用 `+messages-send-card`:群聊传 `--group`,单聊 userId 传 `--receiver` 并由 CLI 只读解析,已有 openDingTalkId 则必须显式传 `--receiver-open-dingtalk-id`;三者严格三选一,禁止根据首字母猜身份类型。 +- `+messages-send --as user --user ` 会通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId,所有内容类型与 `--dry-run` 都使用同一只读解析链路;已有 openDingTalkId 时直接传 `--open-dingtalk-id`。 +- 流式卡片优先用 `+messages-send-card`:群聊传 `--group`,单聊 userId 传 `--receiver` 并由 CLI 通过通讯录关键词搜索做 userId 精确匹配,已有 openDingTalkId 则必须显式传 `--receiver-open-dingtalk-id`;三者严格三选一,禁止根据首字母猜身份类型。 ## 意图表 diff --git a/skills/multi/dws-shared/references/intent-guide.md b/skills/multi/dws-shared/references/intent-guide.md index 7ef3648e..5f3e07a0 100644 --- a/skills/multi/dws-shared/references/intent-guide.md +++ b/skills/multi/dws-shared/references/intent-guide.md @@ -288,8 +288,8 @@ alidocs 链接表面长得一样(`https://alidocs.dingtalk.com/i/nodes/{id}` - "帮我在群里发个消息提醒大家" — **个人身份**发群消息 - "发个单聊消息给某人" — 个人身份发单聊: - 已有 userId 时直接使用 `--user`;已有 openDingTalkId 时使用 `--open-dingtalk-id` - - 纯文本/Markdown 单聊传 `--user` 时直接走 userId 发送能力,不需要先手动查询 openDingTalkId - - 富媒体消息(image/file)单聊优先使用 `--open-dingtalk-id`;传 `--user` 时 CLI 会尝试解析为 openDingTalkId 后发送 + - `+messages-send --user` 对所有内容类型都会通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId;无需手动预查,`--dry-run` 也会执行这次只读解析 + - 已持有 openDingTalkId 时优先使用显式 `--open-dingtalk-id`,避免额外解析 - "发张图片/截图/语音/视频/文件到群里" / "发张图给某某" — **统一一条命令**:`dws chat message send ... --msg-type file --file-path <本地路径>`,CLI 内部自动上传并发送,**任意扩展名(png/jpg/pdf/mp4/zip…)都走这条** - "发图片+文字说明" — 不要硬塞进一条命令;先发文件消息再补一条 `--text "..."` 即可 @@ -299,11 +299,11 @@ dws chat message send --open-dingtalk-id --msg-type file --file ``` > ❌ 反模式:调 `dt_media_upload` / `extract_media_id.py` / `drive upload` / `drive download` 等前置工具再 `--msg-type image --media-id`。这是**旧链路**,仅当上游已持有 mediaId 才用;新场景一律 `--file-path` 直发,避免长链路与“空白图”现象。 -> 富媒体消息单聊优先使用 `--open-dingtalk-id`;传 `--user` 时 CLI 会尝试解析为 openDingTalkId 后发送。 +> 单聊已持有 openDingTalkId 时优先使用 `--open-dingtalk-id`;传 `--user` 时 CLI 会通过通讯录关键词搜索做 userId 精确匹配后发送。 **用 `chat +messages-send-card` 的场景**: - 群聊流式卡片使用 `--group `。 -- 单聊已有 userId 时使用 `--receiver `,CLI 始终先只读解析为 openDingTalkId;即使 userId 以 D/d 开头也不会猜测类型,`--dry-run` 也会执行该解析。 +- 单聊已有 userId 时使用 `--receiver `,CLI 始终通过通讯录关键词搜索并按 userId 精确匹配 openDingTalkId;即使 userId 以 D/d 开头也不会猜测类型,`--dry-run` 也会执行该解析。 - 单聊已有 openDingTalkId 时必须显式使用 `--receiver-open-dingtalk-id `,避免与 userId 混淆。 - `--group`、`--receiver`、`--receiver-open-dingtalk-id` 严格三选一;传 `--content` 可在同一次调用中创建并结束卡片。