fix(chat): complete catalog leaf contracts

This commit is contained in:
长真 committed 2026-08-11 14:16:23 +08:00
1 parent eb3f7328bb
commit 156d95e6d1
3 files changed
+97 -13

No files matched your search

@@ -137,6 +137,7 @@ func TestDeliveryShortcutProgressiveQueriesReturnCompleteContracts(t *testing.T)
assertSchemaSummarySafety(t, summaryByCLIPath, "chat clear-messages", "destructive", "high", "user_required")
assertSchemaSummarySafety(t, summaryByCLIPath, "chat data-auth cross-org", "write", "high", "user_required")
assertSchemaSummarySafety(t, summaryByCLIPath, "chat group share-invite", "write", "medium", "user_required")
assertChatCatalogCompleteLeafContracts(t)
}
func assertSchemaSummarySafety(
@@ -163,6 +164,83 @@ func assertSchemaSummarySafety(
}
}
func assertChatCatalogCompleteLeafContracts(t testing.TB) {
t.Helper()
for _, cliPath := range []string{
"chat clear-messages",
"chat clear-red-point",
"chat hide",
"chat mark-read",
"chat mark-unread",
"chat mute-at-all",
"chat mute-red-envelope",
} {
leaf := executeShortcutSchemaQuery(t, "--cli-path", cliPath)
assertSchemaLeafParameterRequired(t, leaf, cliPath, "conversation-id", true)
}
markRead := executeShortcutSchemaQuery(t, "--cli-path", "chat mark-read")
assertSchemaLeafParameterRequired(t, markRead, "chat mark-read", "message-id", true)
chmod := executeShortcutSchemaQuery(t, "--cli-path", "chat chmod")
assertSchemaLeafConstraints(t, chmod, "chat chmod", map[string]any{
"require_one_of": [][]string{{"conversation-id", "open-dingtalk-id", "user", "permParam"}},
"mutually_exclusive": [][]string{{"conversation-id", "open-dingtalk-id", "user"}},
})
assertChatGrantParameterFacts(t, chmod, "chat chmod")
crossOrg := executeShortcutSchemaQuery(t, "--cli-path", "chat data-auth cross-org")
assertSchemaLeafConstraints(t, crossOrg, "chat data-auth cross-org", map[string]any{
"require_one_of": [][]string{{"target-org-id", "all"}},
"mutually_exclusive": [][]string{{"target-org-id", "all"}},
})
assertChatGrantParameterFacts(t, crossOrg, "chat data-auth cross-org")
shareInvite := executeShortcutSchemaQuery(t, "--cli-path", "chat group share-invite")
assertSchemaLeafConstraints(t, shareInvite, "chat group share-invite", map[string]any{
"require_one_of": [][]string{{"target", "receiver"}},
"mutually_exclusive": [][]string{{"target", "receiver"}},
})
}
func assertSchemaLeafParameterRequired(t testing.TB, leaf map[string]any, cliPath, name string, want bool) {
t.Helper()
parameters := schemaContractMap(leaf["parameters"])
parameter := parameters[name]
if parameter == nil {
t.Fatalf("%s missing --%s parameter: %#v", cliPath, name, parameters)
}
if got, _ := parameter["required"].(bool); got != want {
t.Fatalf("%s --%s required = %#v, want %v", cliPath, name, parameter["required"], want)
}
}
func assertSchemaLeafConstraints(t testing.TB, leaf map[string]any, cliPath string, want map[string]any) {
t.Helper()
if got := leaf["constraints"]; !schemaContractJSONEqual(got, want) {
t.Fatalf("%s constraints = %#v, want %#v", cliPath, got, want)
}
}
func assertChatGrantParameterFacts(t testing.TB, leaf map[string]any, cliPath string) {
t.Helper()
parameters := schemaContractMap(leaf["parameters"])
grantType := parameters["grant-type"]
if grantType == nil {
t.Fatalf("%s missing --grant-type parameter: %#v", cliPath, parameters)
}
wantEnum := []string{"once", "session", "timed", "permanent"}
if got := schemaContractStringSlice(grantType["enum"]); !schemaContractJSONEqual(got, wantEnum) {
t.Fatalf("%s --grant-type enum = %#v, want %#v", cliPath, got, wantEnum)
}
if got := schemaContractString(parameters["session-id"]["required_when"]); got != "grant-type is session" {
t.Fatalf("%s --session-id required_when = %q, want grant-type is session", cliPath, got)
}
if got := schemaContractString(parameters["ttl"]["required_when"]); got != "grant-type is timed" {
t.Fatalf("%s --ttl required_when = %q, want grant-type is timed", cliPath, got)
}
}
func TestDeliveryDocUpdateShortcutPublishesCompleteConditionalContract(t *testing.T) {
leaf := executeShortcutSchemaQuery(t, "--cli-path", "doc +update")
if got, want := schemaContractString(leaf["confirmation"]), "user_required"; got != want {
@@ -38,6 +38,11 @@ func init() {
registerRequireTogether("calendar.update_calendar_event", "recurrence-type", "recurrence-interval", "recurrence-range-type")
registerExclusiveOneOf("chat.search_messages_by_sender", "sender-user-id", "sender-open-dingtalk-id")
registerExclusiveOneOf("chat.create_and_send_card", "group", "receiver")
RegisterRuntimeSchemaConstraints("chat.chat_permission_grant", RuntimeSchemaConstraints{
MutuallyExclusive: [][]string{{"conversation-id", "open-dingtalk-id", "user"}},
RequireOneOf: [][]string{{"conversation-id", "open-dingtalk-id", "user", "permParam"}},
})
registerExclusiveOneOf("chat.chat_permission_grant_cross_org_data", "target-org-id", "all")
registerRequireOneOf("chat.add_emoji_reaction", "conversation-id", "group", "id", "chat")
registerRequireOneOf("chat.add_text_emotion", "conversation-id", "group", "id", "chat")
registerRequireOneOf("chat.update_text_emotion", "conversation-id", "group", "id", "chat")
@@ -49,6 +54,7 @@ func init() {
registerRequireOneOf("chat.send_personal_message", "text", "content", "msg-type")
registerExclusiveOneOf("chat.send_robot_message", "group", "users")
registerRequireOneOf("chat.set_group_member_mute_list", "users", "user")
registerExclusiveOneOf("chat.share_group_invite_url", "target", "receiver")
registerExclusiveOneOf("chat.transfer_group_owner", "new-owner", "user")
registerRequireOneOf("chat.update_conv_member_roles", "users", "user")
registerRequireOneOf("chat.update_notification_off", "conversation-id", "id", "chat")
+13 -13
View File
@@ -1361,11 +1361,11 @@ func newChatCommand() *cobra.Command {
Parameters: []contract.ParamDecl{
{Name: "agentCode", Property: "agentCode", Required: boolPtr(false)},
{Name: "conversation-id", Property: "grantParams.openCid", Required: boolPtr(false)},
{Name: "grant-type", Property: "grantType", Required: boolPtr(false)},
{Name: "grant-type", Property: "grantType", Required: boolPtr(false), Enum: []string{"once", "session", "timed", "permanent"}},
{Name: "open-dingtalk-id", Property: "grantParams.openDingTalkId", Required: boolPtr(false)},
{Name: "permParam", Property: "grantParams", Required: boolPtr(false)},
{Name: "session-id", Property: "sessionId", Required: boolPtr(false)},
{Name: "ttl", Property: "ttl", Required: boolPtr(false)},
{Name: "session-id", Property: "sessionId", Required: boolPtr(false), RequiredWhen: "grant-type is session"},
{Name: "ttl", Property: "ttl", Required: boolPtr(false), RequiredWhen: "grant-type is timed"},
{Name: "user", Property: "grantParams.userId", Required: boolPtr(false)},
},
},
@@ -1432,10 +1432,10 @@ func newChatCommand() *cobra.Command {
Parameters: []contract.ParamDecl{
{Name: "agentCode", Property: "agentCode", Required: boolPtr(false)},
{Name: "all", Property: "grantParams.targetOrgId", Required: boolPtr(false)},
{Name: "grant-type", Property: "grantType", Required: boolPtr(false)},
{Name: "session-id", Property: "sessionId", Required: boolPtr(false)},
{Name: "grant-type", Property: "grantType", Required: boolPtr(false), Enum: []string{"once", "session", "timed", "permanent"}},
{Name: "session-id", Property: "sessionId", Required: boolPtr(false), RequiredWhen: "grant-type is session"},
{Name: "target-org-id", Property: "grantParams.targetOrgId", Required: boolPtr(false)},
{Name: "ttl", Property: "ttl", Required: boolPtr(false)},
{Name: "ttl", Property: "ttl", Required: boolPtr(false), RequiredWhen: "grant-type is timed"},
},
},
})
@@ -7846,7 +7846,7 @@ status 可选值:
},
Parameters: []contract.ParamDecl{
{Name: "chat", Property: "openConversationId", Required: boolPtr(false)},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(false)},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(true)},
{Name: "id", Property: "openConversationId", Required: boolPtr(false)},
},
},
@@ -7906,7 +7906,7 @@ status 可选值:
},
Parameters: []contract.ParamDecl{
{Name: "chat", Property: "openConversationId", Required: boolPtr(false)},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(false)},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(true)},
{Name: "id", Property: "openConversationId", Required: boolPtr(false)},
},
},
@@ -8078,7 +8078,7 @@ status 可选值:
},
Parameters: []contract.ParamDecl{
{Name: "chat", Property: "openConversationId", Required: boolPtr(false)},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(false)},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(true)},
{Name: "id", Property: "openConversationId", Required: boolPtr(false)},
},
},
@@ -8146,7 +8146,7 @@ status 可选值:
},
Parameters: []contract.ParamDecl{
{Name: "chat", Property: "openConversationId", Required: boolPtr(false)},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(false)},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(true)},
{Name: "id", Property: "openConversationId", Required: boolPtr(false)},
{Name: "message-id", Property: "openMessageId", Required: boolPtr(true)},
},
@@ -8434,7 +8434,7 @@ status 可选值:
},
Parameters: []contract.ParamDecl{
{Name: "chat", Property: "openConversationId", Required: boolPtr(false)},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(false)},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(true)},
{Name: "id", Property: "openConversationId", Required: boolPtr(false)},
},
},
@@ -8494,7 +8494,7 @@ status 可选值:
},
Parameters: []contract.ParamDecl{
{Name: "chat", Property: "openConversationId", Required: boolPtr(false)},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(false)},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(true)},
{Name: "id", Property: "openConversationId", Required: boolPtr(false)},
{Name: "off", Property: "mute", Required: boolPtr(false), InterfaceType: "boolean"},
},
@@ -8555,7 +8555,7 @@ status 可选值:
},
Parameters: []contract.ParamDecl{
{Name: "chat", Property: "openConversationId", Required: boolPtr(false)},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(false)},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(true)},
{Name: "id", Property: "openConversationId", Required: boolPtr(false)},
{Name: "off", Property: "mute", Required: boolPtr(false), InterfaceType: "boolean"},
},