fix(event): address PR review gates
This commit is contained in:
@@ -62,7 +62,7 @@ func TestPersonalEventProjectorUsesRawEnvelopeForDebug(t *testing.T) {
|
||||
}
|
||||
ev := transport.Event{
|
||||
EventID: "raw-event",
|
||||
Data: `{"payload":{"uid":147867,"bizid":"internal-bizid"}}`,
|
||||
Data: `{"payload":{"uid":100001,"bizid":"internal-bizid"}}`,
|
||||
Headers: map[string]string{"TOPIC": "raw"},
|
||||
}
|
||||
projected, err := projector(ev)
|
||||
@@ -143,7 +143,7 @@ func TestEventConsumeRetiredPersonalFlagsAreUnknown(t *testing.T) {
|
||||
|
||||
func TestEventConsumeAsAppRejectedBeforePersonalParamSpecFlags(t *testing.T) {
|
||||
for _, args := range [][]string{
|
||||
{"--as", "app", "--user", "507971"},
|
||||
{"--as", "app", "--user", "test-user-001"},
|
||||
{"--as", "app", "--open-dingtalk-id", "open-user-1"},
|
||||
{"--as", "app", "--group", "cid"},
|
||||
{"--as", "app", "--query", "报警"},
|
||||
|
||||
@@ -405,7 +405,7 @@ func TestPersonalEventFromUserIsPubliclyAvailable(t *testing.T) {
|
||||
consumeCmd := newEventConsumeCommand()
|
||||
consumeCmd.SilenceUsage = true
|
||||
consumeCmd.SilenceErrors = true
|
||||
consumeCmd.SetArgs([]string{personal.EventFromUser, "--user", "507971", "--dry-run"})
|
||||
consumeCmd.SetArgs([]string{personal.EventFromUser, "--user", "test-user-001", "--dry-run"})
|
||||
if err := consumeCmd.Execute(); err != nil {
|
||||
t.Fatalf("consume dry-run Execute() error = %v", err)
|
||||
}
|
||||
@@ -420,7 +420,7 @@ func TestPersonalEventFromUserIsPubliclyAvailable(t *testing.T) {
|
||||
conflictingTargetCmd := newEventConsumeCommand()
|
||||
conflictingTargetCmd.SilenceUsage = true
|
||||
conflictingTargetCmd.SilenceErrors = true
|
||||
conflictingTargetCmd.SetArgs([]string{personal.EventFromUser, "--user", "507971", "--open-dingtalk-id", "open-user-1", "--dry-run"})
|
||||
conflictingTargetCmd.SetArgs([]string{personal.EventFromUser, "--user", "test-user-001", "--open-dingtalk-id", "open-user-1", "--dry-run"})
|
||||
err := conflictingTargetCmd.Execute()
|
||||
if err == nil || !strings.Contains(err.Error(), "--user and --open-dingtalk-id are mutually exclusive for "+personal.EventFromUser) {
|
||||
t.Fatalf("conflicting target identity error = %v", err)
|
||||
@@ -469,17 +469,13 @@ func TestEventConsumeCobraSchemaIncludesOpenDingTalkID(t *testing.T) {
|
||||
if _, ok := params["odid"]; ok {
|
||||
t.Fatalf("schema parameters unexpectedly include odid alias: %#v", params)
|
||||
}
|
||||
for name, want := range map[string]string{
|
||||
"user": "--subscribe-id is absent, event_key uses singleChat or sender, and --open-dingtalk-id is absent",
|
||||
"open-dingtalk-id": "--subscribe-id is absent, event_key uses singleChat or sender, and --user is absent",
|
||||
"group": "--subscribe-id is absent and event_key uses group",
|
||||
} {
|
||||
for _, name := range []string{"user", "open-dingtalk-id", "group"} {
|
||||
param, ok := params[name].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("schema parameter %s = %#v", name, params[name])
|
||||
}
|
||||
if got := param["required_when"]; got != want {
|
||||
t.Fatalf("schema parameter %s required_when = %#v, want %q", name, got, want)
|
||||
if got, exists := param["required_when"]; exists {
|
||||
t.Fatalf("schema parameter %s unexpectedly declares required_when = %#v", name, got)
|
||||
}
|
||||
}
|
||||
constraints, ok := doc["constraints"].(map[string]any)
|
||||
@@ -511,7 +507,6 @@ func TestEventConsumeCobraSchemaIncludesOpenDingTalkID(t *testing.T) {
|
||||
t.Fatalf("schema constraint %s = %#v, missing %#v", field, groups, want)
|
||||
}
|
||||
assertJSONConstraintGroup("require_one_of", []string{"event_key", "subscribe-id"})
|
||||
assertJSONConstraintGroup("mutually_exclusive", []string{"user", "open-dingtalk-id", "group"})
|
||||
}
|
||||
|
||||
func TestPersonalEventSchemaRejectsTableFormat(t *testing.T) {
|
||||
|
||||
@@ -74,13 +74,9 @@ func TestEventRegistryDeliversOneTypedSchemaPath(t *testing.T) {
|
||||
if _, exists := consumeParams["odid"]; exists {
|
||||
t.Error("event.consume exposes unsupported --odid alias")
|
||||
}
|
||||
for name, want := range map[string]string{
|
||||
"user": "--subscribe-id is absent, event_key uses singleChat or sender, and --open-dingtalk-id is absent",
|
||||
"open-dingtalk-id": "--subscribe-id is absent, event_key uses singleChat or sender, and --user is absent",
|
||||
"group": "--subscribe-id is absent and event_key uses group",
|
||||
} {
|
||||
if got := schemaContractString(consumeParams[name]["required_when"]); got != want {
|
||||
t.Errorf("event.consume --%s required_when = %q, want %q", name, got, want)
|
||||
for _, name := range []string{"user", "open-dingtalk-id", "group"} {
|
||||
if _, exists := consumeParams[name]["required_when"]; exists {
|
||||
t.Errorf("event.consume --%s unexpectedly declares required_when", name)
|
||||
}
|
||||
}
|
||||
if _, exists := consumeParams["duration"]["default"]; exists {
|
||||
@@ -91,7 +87,6 @@ func TestEventRegistryDeliversOneTypedSchemaPath(t *testing.T) {
|
||||
}
|
||||
assertSchemaContractPositional(t, consume, "event_key", false)
|
||||
assertSchemaContractConstraintGroup(t, consume, "require_one_of", []string{"event_key", "subscribe-id"})
|
||||
assertSchemaContractConstraintGroup(t, consume, "mutually_exclusive", []string{"user", "open-dingtalk-id", "group"})
|
||||
|
||||
eventSchema := payload.Tools["event.schema"]
|
||||
assertSchemaContractPositional(t, eventSchema, "event_key", true)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"version": 1,
|
||||
"source_hash": "sha256:2f24ccd75c2c02fe8c05f3f0b8ca774313232559bec7b8ab3d94f856b5712e07",
|
||||
"source_hash": "sha256:a65016dce21d32c609d5f422645c02bb28b00e719e459a548829fb513d6b3e5f",
|
||||
"surface_hash": "sha256:7ef588f38052f0104e027c8daff5fefd68698781f2c87715461183d4058288ed",
|
||||
"coverage": {
|
||||
"surface_products": 22,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"version": 1,
|
||||
"source_hash": "sha256:2f24ccd75c2c02fe8c05f3f0b8ca774313232559bec7b8ab3d94f856b5712e07",
|
||||
"source_hash": "sha256:a65016dce21d32c609d5f422645c02bb28b00e719e459a548829fb513d6b3e5f",
|
||||
"surface_hash": "sha256:7ef588f38052f0104e027c8daff5fefd68698781f2c87715461183d4058288ed",
|
||||
"source_files": 150,
|
||||
"hint_files": 46,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"version": 1,
|
||||
"source_hash": "sha256:baa16e40767270f9833ebccbdfc3732b03033b2cd4c8a95d96f87da5c73bcf1e",
|
||||
"source_hash": "sha256:5b8ce46a210299db7bb06a463155410f1a35c10becdcc2e8b23a6c804ee759b8",
|
||||
"surface_hash": "sha256:7ef588f38052f0104e027c8daff5fefd68698781f2c87715461183d4058288ed",
|
||||
"catalog": {
|
||||
"agent_metadata": {
|
||||
"products_with_metadata": 22,
|
||||
"source": "embedded-skill-metadata",
|
||||
"source_hash": "sha256:2f24ccd75c2c02fe8c05f3f0b8ca774313232559bec7b8ab3d94f856b5712e07",
|
||||
"source_hash": "sha256:a65016dce21d32c609d5f422645c02bb28b00e719e459a548829fb513d6b3e5f",
|
||||
"surface_hash": "sha256:7ef588f38052f0104e027c8daff5fefd68698781f2c87715461183d4058288ed",
|
||||
"surface_products": 22,
|
||||
"surface_tools": 572,
|
||||
@@ -290142,13 +290142,6 @@
|
||||
"cli_path": "event consume",
|
||||
"confirmation": "not_required",
|
||||
"constraints": {
|
||||
"mutually_exclusive": [
|
||||
[
|
||||
"user",
|
||||
"open-dingtalk-id",
|
||||
"group"
|
||||
]
|
||||
],
|
||||
"require_one_of": [
|
||||
[
|
||||
"event_key",
|
||||
@@ -291443,23 +291436,17 @@
|
||||
},
|
||||
"required_when": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "typed_metadata",
|
||||
"selected": true,
|
||||
"source": "typed_parameter_metadata",
|
||||
"value": "--subscribe-id is absent and event_key uses group"
|
||||
},
|
||||
{
|
||||
"precedence": "default",
|
||||
"selected": false,
|
||||
"selected": true,
|
||||
"source": "default",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"precedence": "typed_metadata",
|
||||
"precedence": "default",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "typed_parameter_metadata",
|
||||
"value": "--subscribe-id is absent and event_key uses group"
|
||||
"source": "default",
|
||||
"value": ""
|
||||
},
|
||||
"type": {
|
||||
"candidates": [
|
||||
@@ -291478,7 +291465,6 @@
|
||||
},
|
||||
"property": "group",
|
||||
"required": false,
|
||||
"required_when": "--subscribe-id is absent and event_key uses group",
|
||||
"type": "string"
|
||||
},
|
||||
"max-events": {
|
||||
@@ -291702,23 +291688,17 @@
|
||||
},
|
||||
"required_when": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "typed_metadata",
|
||||
"selected": true,
|
||||
"source": "typed_parameter_metadata",
|
||||
"value": "--subscribe-id is absent, event_key uses singleChat or sender, and --user is absent"
|
||||
},
|
||||
{
|
||||
"precedence": "default",
|
||||
"selected": false,
|
||||
"selected": true,
|
||||
"source": "default",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"precedence": "typed_metadata",
|
||||
"precedence": "default",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "typed_parameter_metadata",
|
||||
"value": "--subscribe-id is absent, event_key uses singleChat or sender, and --user is absent"
|
||||
"source": "default",
|
||||
"value": ""
|
||||
},
|
||||
"type": {
|
||||
"candidates": [
|
||||
@@ -291737,7 +291717,6 @@
|
||||
},
|
||||
"property": "openDingtalkId",
|
||||
"required": false,
|
||||
"required_when": "--subscribe-id is absent, event_key uses singleChat or sender, and --user is absent",
|
||||
"type": "string"
|
||||
},
|
||||
"output-dir": {
|
||||
@@ -292753,23 +292732,17 @@
|
||||
},
|
||||
"required_when": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "typed_metadata",
|
||||
"selected": true,
|
||||
"source": "typed_parameter_metadata",
|
||||
"value": "--subscribe-id is absent, event_key uses singleChat or sender, and --open-dingtalk-id is absent"
|
||||
},
|
||||
{
|
||||
"precedence": "default",
|
||||
"selected": false,
|
||||
"selected": true,
|
||||
"source": "default",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"precedence": "typed_metadata",
|
||||
"precedence": "default",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "typed_parameter_metadata",
|
||||
"value": "--subscribe-id is absent, event_key uses singleChat or sender, and --open-dingtalk-id is absent"
|
||||
"source": "default",
|
||||
"value": ""
|
||||
},
|
||||
"type": {
|
||||
"candidates": [
|
||||
@@ -292788,7 +292761,6 @@
|
||||
},
|
||||
"property": "user",
|
||||
"required": false,
|
||||
"required_when": "--subscribe-id is absent, event_key uses singleChat or sender, and --open-dingtalk-id is absent",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -57,10 +57,7 @@ func init() {
|
||||
registerRequireOneOf("dev.search_open_platform_docs_rag", "query", "keyword")
|
||||
registerRequireOneOf("devdoc.search_open_error_code_rag", "query", "request-id", "error-code", "error-message", "context")
|
||||
registerRequireOneOf("devdoc.search_open_platform_docs_rag", "query", "keyword")
|
||||
RegisterRuntimeSchemaConstraints("event.consume", RuntimeSchemaConstraints{
|
||||
MutuallyExclusive: [][]string{{"user", "open-dingtalk-id", "group"}},
|
||||
RequireOneOf: [][]string{{"event_key", "subscribe-id"}},
|
||||
})
|
||||
registerRequireOneOf("event.consume", "event_key", "subscribe-id")
|
||||
registerExclusiveOneOf("event.stop", "all", "subscribe_id")
|
||||
registerRequireOneOf("doc.insert_document_block", "text", "heading", "element")
|
||||
registerExclusiveOneOf("doc.update_document", "content", "content-file")
|
||||
|
||||
@@ -110,13 +110,6 @@ func cloneRuntimeSchemaStringMap(source map[string]string) map[string]string {
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterRuntimeSchemaParameterMetadata("event.consume", RuntimeSchemaParameterMetadata{
|
||||
RequiredWhen: map[string]string{
|
||||
"user": "--subscribe-id is absent, event_key uses singleChat or sender, and --open-dingtalk-id is absent",
|
||||
"open-dingtalk-id": "--subscribe-id is absent, event_key uses singleChat or sender, and --user is absent",
|
||||
"group": "--subscribe-id is absent and event_key uses group",
|
||||
},
|
||||
})
|
||||
RegisterRuntimeSchemaParameterMetadata("aisearch.enterprise_person_search", RuntimeSchemaParameterMetadata{
|
||||
Required: []string{"keyword"},
|
||||
})
|
||||
|
||||
@@ -151,7 +151,7 @@ func TestCompactFormatter_DispatchesPerEventType(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStructuredFormatsUseProjector(t *testing.T) {
|
||||
func TestCrossPlatformCoverageStructuredFormatsUseProjector(t *testing.T) {
|
||||
projector := Projector(func(ev transport.Event) (any, error) {
|
||||
return map[string]any{"type": ev.EventType, "content": "hello"}, nil
|
||||
})
|
||||
@@ -179,7 +179,7 @@ func TestStructuredFormatsUseProjector(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProjectionFailureWarnsAndEmitsFallback(t *testing.T) {
|
||||
func TestCrossPlatformCoverageProjectionFailureWarnsAndEmitsFallback(t *testing.T) {
|
||||
var warnings bytes.Buffer
|
||||
f, err := NewFormatter(
|
||||
FormatNDJSON,
|
||||
@@ -210,9 +210,9 @@ func TestProjectionFailureWarnsAndEmitsFallback(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRawFormatBypassesProjector(t *testing.T) {
|
||||
func TestCrossPlatformCoverageRawFormatBypassesProjector(t *testing.T) {
|
||||
called := false
|
||||
raw := `{"payload":{"uid":147867,"clientId":"internal-client","filterSubId":"internal-filter","bizid":"internal-bizid"}}`
|
||||
raw := `{"payload":{"uid":100001,"clientId":"internal-client","filterSubId":"internal-filter","bizid":"internal-bizid"}}`
|
||||
f, err := NewFormatter(FormatRaw, WithProjector(func(transport.Event) (any, error) {
|
||||
called = true
|
||||
return map[string]any{"projected": true}, nil
|
||||
|
||||
@@ -62,7 +62,7 @@ func TestPipeline_OutputDirFallback(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPipeline_StdoutAndOutputDirUseSameProjection(t *testing.T) {
|
||||
func TestCrossPlatformCoveragePipelineStdoutAndOutputDirUseSameProjection(t *testing.T) {
|
||||
ev := transport.Event{
|
||||
EventType: "personal.message",
|
||||
EventID: "ev1",
|
||||
|
||||
@@ -72,7 +72,7 @@ func TestClientCreateSubscriptionDWSRequestAndArrayResponse(t *testing.T) {
|
||||
RuleType: "singleChat",
|
||||
Name: "test-o2o",
|
||||
RuleParam: map[string]any{
|
||||
"targetUid": "507971",
|
||||
"targetUid": "test-user-001",
|
||||
"targetUidType": "staffId",
|
||||
},
|
||||
Filter: map[string]any{"field": "payload.body.content", "op": "contains", "value": "P0"},
|
||||
@@ -94,7 +94,7 @@ func TestClientCreateSubscriptionDWSRequestAndArrayResponse(t *testing.T) {
|
||||
if err := json.Unmarshal([]byte(gotReq.FilterRule), &filterRule); err != nil {
|
||||
t.Fatalf("filterRule is not JSON: %q: %v", gotReq.FilterRule, err)
|
||||
}
|
||||
if filterRule["targetUid"] != "507971" || filterRule["targetUidType"] != "staffId" {
|
||||
if filterRule["targetUid"] != "test-user-001" || filterRule["targetUidType"] != "staffId" {
|
||||
t.Fatalf("filterRule = %#v", filterRule)
|
||||
}
|
||||
if gotReq.Ext["ruleType"] != "singleChat" || gotReq.Ext["name"] != "test-o2o" || gotReq.Ext["idempotencyKey"] != "idem-1" {
|
||||
@@ -218,7 +218,7 @@ func TestClientDebugLogCreateSubscriptionRequestResponse(t *testing.T) {
|
||||
EventKey: EventSingleChat,
|
||||
RuleType: "singleChat",
|
||||
RuleParam: map[string]any{
|
||||
"targetUid": "507971",
|
||||
"targetUid": "test-user-001",
|
||||
"targetUidType": "staffId",
|
||||
},
|
||||
IdempotencyKey: "idem-1",
|
||||
@@ -234,7 +234,7 @@ func TestClientDebugLogCreateSubscriptionRequestResponse(t *testing.T) {
|
||||
EventSingleChat,
|
||||
"filterRule",
|
||||
"targetUid",
|
||||
"507971",
|
||||
"test-user-001",
|
||||
"sub-1",
|
||||
"req-ok",
|
||||
} {
|
||||
|
||||
@@ -201,10 +201,8 @@ func ProjectOutput(ev transport.Event) (any, error) {
|
||||
|
||||
if isMessageReceiveEvent(eventType) {
|
||||
var payload personalMessagePayload
|
||||
if len(bytes.TrimSpace(data.Payload)) > 0 && string(bytes.TrimSpace(data.Payload)) != "null" {
|
||||
if err := json.Unmarshal(data.Payload, &payload); err != nil {
|
||||
return ev, fmt.Errorf("decode personal message payload: %w", err)
|
||||
}
|
||||
if err := decodeRequiredPayload(data.Payload, &payload); err != nil {
|
||||
return ev, fmt.Errorf("decode personal message payload: %w", err)
|
||||
}
|
||||
return MessageEventOutput{
|
||||
Type: eventType,
|
||||
@@ -241,7 +239,7 @@ func ProjectOutput(ev transport.Event) (any, error) {
|
||||
|
||||
func projectReadEvent(ev transport.Event, base baseEventOutput, raw json.RawMessage) (any, error) {
|
||||
var payload personalReadPayload
|
||||
if err := decodeActionPayload(raw, &payload); err != nil {
|
||||
if err := decodeRequiredPayload(raw, &payload); err != nil {
|
||||
return ev, fmt.Errorf("decode personal read payload: %w", err)
|
||||
}
|
||||
return ReadEventOutput{
|
||||
@@ -262,7 +260,7 @@ func projectReadEvent(ev transport.Event, base baseEventOutput, raw json.RawMess
|
||||
|
||||
func projectRecallEvent(ev transport.Event, base baseEventOutput, raw json.RawMessage) (any, error) {
|
||||
var payload personalRecallPayload
|
||||
if err := decodeActionPayload(raw, &payload); err != nil {
|
||||
if err := decodeRequiredPayload(raw, &payload); err != nil {
|
||||
return ev, fmt.Errorf("decode personal recall payload: %w", err)
|
||||
}
|
||||
return RecallEventOutput{
|
||||
@@ -283,7 +281,7 @@ func projectRecallEvent(ev transport.Event, base baseEventOutput, raw json.RawMe
|
||||
|
||||
func projectReactionEvent(ev transport.Event, base baseEventOutput, raw json.RawMessage) (any, error) {
|
||||
var payload personalReactionPayload
|
||||
if err := decodeActionPayload(raw, &payload); err != nil {
|
||||
if err := decodeRequiredPayload(raw, &payload); err != nil {
|
||||
return ev, fmt.Errorf("decode personal reaction payload: %w", err)
|
||||
}
|
||||
return ReactionEventOutput{
|
||||
@@ -305,11 +303,36 @@ func projectReactionEvent(ev transport.Event, base baseEventOutput, raw json.Raw
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeActionPayload(raw json.RawMessage, target any) error {
|
||||
func decodeRequiredPayload(raw json.RawMessage, target any) error {
|
||||
trimmed := bytes.TrimSpace(raw)
|
||||
if len(trimmed) == 0 || string(trimmed) == "null" {
|
||||
return nil
|
||||
if len(trimmed) == 0 || bytes.Equal(trimmed, []byte("null")) {
|
||||
return fmt.Errorf("payload is missing")
|
||||
}
|
||||
|
||||
var payloadObject map[string]json.RawMessage
|
||||
if err := json.Unmarshal(trimmed, &payloadObject); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(payloadObject) == 0 {
|
||||
return fmt.Errorf("payload is empty")
|
||||
}
|
||||
|
||||
body, ok := payloadObject["body"]
|
||||
if !ok {
|
||||
return fmt.Errorf("payload body is missing")
|
||||
}
|
||||
body = bytes.TrimSpace(body)
|
||||
if len(body) == 0 || bytes.Equal(body, []byte("null")) {
|
||||
return fmt.Errorf("payload body is missing")
|
||||
}
|
||||
var bodyObject map[string]json.RawMessage
|
||||
if err := json.Unmarshal(body, &bodyObject); err != nil {
|
||||
return fmt.Errorf("decode payload body: %w", err)
|
||||
}
|
||||
if len(bodyObject) == 0 {
|
||||
return fmt.Errorf("payload body is empty")
|
||||
}
|
||||
|
||||
return json.Unmarshal(trimmed, target)
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ func personalMessageData(eventKey string) string {
|
||||
"payload":{
|
||||
"body":{
|
||||
"createTime":"2026-07-08 12:00:35",
|
||||
"sender":"昊小淼",
|
||||
"sender":"测试用户甲",
|
||||
"openMessageId":"msg-1",
|
||||
"senderOpenDingTalkId":"open-user-1",
|
||||
"openConversationId":"cid-1",
|
||||
@@ -55,16 +55,16 @@ func personalReadData(eventKey, messageID, conversationID string) string {
|
||||
"msgReadTime":"2026-07-14 13:53:31",
|
||||
"openConversationId":%q,
|
||||
"openMessageId":%q,
|
||||
"reader":"郑御白",
|
||||
"reader":"测试用户乙",
|
||||
"readerOpenDingTalkId":"reader-open-id",
|
||||
"sender":"昊淼",
|
||||
"sender":"测试用户甲",
|
||||
"senderOpenDingTalkId":"sender-open-id"
|
||||
},
|
||||
"clientId":"internal-client",
|
||||
"corpid":"internal-corp",
|
||||
"event_time":1784008411652,
|
||||
"filterSubId":"internal-filter",
|
||||
"uid":147867
|
||||
"uid":100001
|
||||
}
|
||||
}`, eventKey, conversationID, messageID)
|
||||
}
|
||||
@@ -81,16 +81,16 @@ func personalRecallData(eventKey, messageID, conversationID string) string {
|
||||
"msgRecallTime":"2026-07-14 13:56:32",
|
||||
"openConversationId":%q,
|
||||
"openMessageId":%q,
|
||||
"recaller":"郑御白",
|
||||
"recaller":"测试用户乙",
|
||||
"recallerOpenDingTalkId":"recaller-open-id",
|
||||
"sender":"郑御白",
|
||||
"sender":"测试用户乙",
|
||||
"senderOpenDingTalkId":"sender-open-id"
|
||||
},
|
||||
"clientId":"internal-client",
|
||||
"corpid":"internal-corp",
|
||||
"event_time":1784008592766,
|
||||
"filterSubId":"internal-filter",
|
||||
"uid":147867
|
||||
"uid":100001
|
||||
}
|
||||
}`, eventKey, conversationID, messageID)
|
||||
}
|
||||
@@ -108,23 +108,23 @@ func personalReactionData(eventKey, messageID, conversationID string) string {
|
||||
"emotionText":"微笑",
|
||||
"openConversationId":%q,
|
||||
"openSourceMessageId":%q,
|
||||
"oper":"郑御白",
|
||||
"oper":"测试用户乙",
|
||||
"operOpenDingtalkId":"operator-open-id",
|
||||
"operateTime":"2026-07-14 13:57:59",
|
||||
"operateType":"add",
|
||||
"sender":"昊淼",
|
||||
"sender":"测试用户甲",
|
||||
"senderOpenDingTalkId":"sender-open-id"
|
||||
},
|
||||
"clientId":"internal-client",
|
||||
"corpid":"internal-corp",
|
||||
"event_time":1784008679217,
|
||||
"filterSubId":"internal-filter",
|
||||
"uid":147867
|
||||
"uid":100001
|
||||
}
|
||||
}`, eventKey, conversationID, messageID)
|
||||
}
|
||||
|
||||
func TestProjectOutputMessageEvents(t *testing.T) {
|
||||
func TestCrossPlatformCoverageProjectOutputMessageEvents(t *testing.T) {
|
||||
for _, eventKey := range []string{EventMention, EventSingleChat, EventInChat, EventFromUser} {
|
||||
t.Run(eventKey, func(t *testing.T) {
|
||||
projected, err := ProjectOutput(transport.Event{
|
||||
@@ -149,7 +149,7 @@ func TestProjectOutputMessageEvents(t *testing.T) {
|
||||
SubscribeID: "outer-sub",
|
||||
MessageID: "msg-1",
|
||||
ConversationID: "cid-1",
|
||||
Sender: "昊小淼",
|
||||
Sender: "测试用户甲",
|
||||
SenderOpenDingTalkID: "open-user-1",
|
||||
Content: "在吗",
|
||||
CreateTime: "2026-07-08 12:00:35",
|
||||
@@ -162,7 +162,7 @@ func TestProjectOutputMessageEvents(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProjectOutputDecodesWrappedJSONString(t *testing.T) {
|
||||
func TestCrossPlatformCoverageProjectOutputDecodesWrappedJSONString(t *testing.T) {
|
||||
wrapped, err := json.Marshal(personalMessageData(EventSingleChat))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -177,7 +177,7 @@ func TestProjectOutputDecodesWrappedJSONString(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProjectOutputFallsBackToTransportFields(t *testing.T) {
|
||||
func TestCrossPlatformCoverageProjectOutputFallsBackToTransportFields(t *testing.T) {
|
||||
projected, err := ProjectOutput(transport.Event{
|
||||
EventID: "outer-event",
|
||||
EventBornTime: 123,
|
||||
@@ -194,7 +194,7 @@ func TestProjectOutputFallsBackToTransportFields(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProjectOutputReadEvents(t *testing.T) {
|
||||
func TestCrossPlatformCoverageProjectOutputReadEvents(t *testing.T) {
|
||||
for _, eventKey := range []string{EventReadO2O, EventReadGroup} {
|
||||
t.Run(eventKey, func(t *testing.T) {
|
||||
projected, err := ProjectOutput(transport.Event{
|
||||
@@ -211,9 +211,9 @@ func TestProjectOutputReadEvents(t *testing.T) {
|
||||
SubscribeID: "read-sub",
|
||||
MessageID: "read-message",
|
||||
ConversationID: "read-conversation",
|
||||
Reader: "郑御白",
|
||||
Reader: "测试用户乙",
|
||||
ReaderOpenDingTalkID: "reader-open-id",
|
||||
Sender: "昊淼",
|
||||
Sender: "测试用户甲",
|
||||
SenderOpenDingTalkID: "sender-open-id",
|
||||
ReadTime: "2026-07-14 13:53:31",
|
||||
EventTime: 1784008411652,
|
||||
@@ -226,7 +226,7 @@ func TestProjectOutputReadEvents(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProjectOutputRecallEvents(t *testing.T) {
|
||||
func TestCrossPlatformCoverageProjectOutputRecallEvents(t *testing.T) {
|
||||
for _, eventKey := range []string{EventRecallO2O, EventRecallGroup} {
|
||||
t.Run(eventKey, func(t *testing.T) {
|
||||
projected, err := ProjectOutput(transport.Event{
|
||||
@@ -243,9 +243,9 @@ func TestProjectOutputRecallEvents(t *testing.T) {
|
||||
SubscribeID: "recall-sub",
|
||||
MessageID: "recall-message",
|
||||
ConversationID: "recall-conversation",
|
||||
Recaller: "郑御白",
|
||||
Recaller: "测试用户乙",
|
||||
RecallerOpenDingTalkID: "recaller-open-id",
|
||||
Sender: "郑御白",
|
||||
Sender: "测试用户乙",
|
||||
SenderOpenDingTalkID: "sender-open-id",
|
||||
RecallTime: "2026-07-14 13:56:32",
|
||||
EventTime: 1784008592766,
|
||||
@@ -258,7 +258,7 @@ func TestProjectOutputRecallEvents(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProjectOutputReactionEvents(t *testing.T) {
|
||||
func TestCrossPlatformCoverageProjectOutputReactionEvents(t *testing.T) {
|
||||
for _, eventKey := range []string{EventReactionO2O, EventReactionGroup} {
|
||||
t.Run(eventKey, func(t *testing.T) {
|
||||
projected, err := ProjectOutput(transport.Event{
|
||||
@@ -275,13 +275,13 @@ func TestProjectOutputReactionEvents(t *testing.T) {
|
||||
SubscribeID: "reaction-sub",
|
||||
MessageID: "reaction-message",
|
||||
ConversationID: "reaction-conversation",
|
||||
Operator: "郑御白",
|
||||
Operator: "测试用户乙",
|
||||
OperatorOpenDingTalkID: "operator-open-id",
|
||||
ReactionName: "微笑",
|
||||
ReactionText: "微笑",
|
||||
OperationType: "add",
|
||||
OperationTime: "2026-07-14 13:57:59",
|
||||
Sender: "昊淼",
|
||||
Sender: "测试用户甲",
|
||||
SenderOpenDingTalkID: "sender-open-id",
|
||||
EventTime: 1784008679217,
|
||||
}
|
||||
@@ -293,7 +293,7 @@ func TestProjectOutputReactionEvents(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProjectOutputReactionRejectsLegacyOperatorOpenIDSpellings(t *testing.T) {
|
||||
func TestCrossPlatformCoverageProjectOutputReactionRejectsLegacyOperatorOpenIDSpellings(t *testing.T) {
|
||||
for _, legacyField := range []string{"operOpenDingtlkId", "operOpenDingTalkId"} {
|
||||
t.Run(legacyField, func(t *testing.T) {
|
||||
data := strings.Replace(
|
||||
@@ -327,7 +327,53 @@ func assertNoInternalActionFields(t *testing.T, projected any) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProjectOutputMalformedDataReturnsRawEnvelope(t *testing.T) {
|
||||
func TestCrossPlatformCoverageProjectOutputRejectsEmptyPayloads(t *testing.T) {
|
||||
eventKeys := []string{
|
||||
EventMention,
|
||||
EventSingleChat,
|
||||
EventInChat,
|
||||
EventFromUser,
|
||||
EventReadO2O,
|
||||
EventReadGroup,
|
||||
EventRecallO2O,
|
||||
EventRecallGroup,
|
||||
EventReactionO2O,
|
||||
EventReactionGroup,
|
||||
}
|
||||
payloads := []struct {
|
||||
name string
|
||||
json string
|
||||
}{
|
||||
{name: "missing", json: ""},
|
||||
{name: "null", json: `,"payload":null`},
|
||||
{name: "empty object", json: `,"payload":{}`},
|
||||
{name: "missing body", json: `,"payload":{"event_time":1}`},
|
||||
{name: "null body", json: `,"payload":{"body":null}`},
|
||||
{name: "empty body", json: `,"payload":{"body":{}}`},
|
||||
}
|
||||
|
||||
for _, eventKey := range eventKeys {
|
||||
for _, payload := range payloads {
|
||||
t.Run(eventKey+"/"+payload.name, func(t *testing.T) {
|
||||
ev := transport.Event{
|
||||
EventID: "outer-event",
|
||||
EventType: eventKey,
|
||||
Data: fmt.Sprintf(`{"eventKey":%q%s}`, eventKey, payload.json),
|
||||
}
|
||||
projected, err := ProjectOutput(ev)
|
||||
if err == nil {
|
||||
t.Fatal("ProjectOutput() error = nil, want payload validation error")
|
||||
}
|
||||
got, ok := projected.(transport.Event)
|
||||
if !ok || !reflect.DeepEqual(got, ev) {
|
||||
t.Fatalf("ProjectOutput() fallback = %#v, want %#v", projected, ev)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrossPlatformCoverageProjectOutputMalformedDataReturnsRawEnvelope(t *testing.T) {
|
||||
ev := transport.Event{EventID: "outer-event", Data: "not-json"}
|
||||
projected, err := ProjectOutput(ev)
|
||||
if err == nil {
|
||||
|
||||
@@ -495,7 +495,7 @@ func TestBuildFilterQueryAndJSON(t *testing.T) {
|
||||
func TestIdempotencyKeyUsesLocalIdentityKey(t *testing.T) {
|
||||
left := Identity{LocalSubject: "refresh:left", ClientID: "client-1", SourceID: "open"}
|
||||
right := Identity{LocalSubject: "refresh:right", ClientID: "client-1", SourceID: "open"}
|
||||
ruleParam := map[string]any{"targetUid": "507971", "targetUidType": "staffId"}
|
||||
ruleParam := map[string]any{"targetUid": "test-user-001", "targetUidType": "staffId"}
|
||||
leftKey := IdempotencyKey(left, EventSingleChat, "singleChat", ruleParam, "")
|
||||
rightKey := IdempotencyKey(right, EventSingleChat, "singleChat", ruleParam, "")
|
||||
if leftKey == rightKey {
|
||||
|
||||
@@ -43,16 +43,16 @@
|
||||
| 用户说 | 下一步 |
|
||||
|---|---|
|
||||
| "监听有人 @ 我的消息" | `event consume`,事件码 `user_im_message_receive_at`,参数 `-f ndjson` |
|
||||
| "监听我和 userId 507971 的单聊消息" | `event consume`,事件码 `user_im_message_receive_o2o`,参数 `--user 507971 -f ndjson` |
|
||||
| "监听我和 userId test-user-001 的单聊消息" | `event consume`,事件码 `user_im_message_receive_o2o`,参数 `--user test-user-001 -f ndjson` |
|
||||
| "监听我和 openDingtalkId abc 的单聊消息" | `event consume`,事件码 `user_im_message_receive_o2o`,参数 `--open-dingtalk-id abc -f ndjson` |
|
||||
| "监听 XX 群消息" | 先 `dws chat search --query "XX" --format json`,确认后 consume group |
|
||||
| "监听 userId 507971 发给我的消息" | `event consume`,事件码 `user_im_message_receive_user`,参数 `--user 507971 -f ndjson` |
|
||||
| "监听 userId test-user-001 发给我的消息" | `event consume`,事件码 `user_im_message_receive_user`,参数 `--user test-user-001 -f ndjson` |
|
||||
| "监听 openDingtalkId abc 发给我的消息" | `event consume`,事件码 `user_im_message_receive_user`,参数 `--open-dingtalk-id abc -f ndjson` |
|
||||
| "监听我发给 userId 507971 的消息是否已读" | `event consume`,事件码 `user_im_message_read_o2o`,参数 `--user 507971 -f ndjson` |
|
||||
| "监听我发给 userId test-user-001 的消息是否已读" | `event consume`,事件码 `user_im_message_read_o2o`,参数 `--user test-user-001 -f ndjson` |
|
||||
| "监听 XX 群消息已读" | 先解析群 ID,再 consume `user_im_message_read_group --group <id>` |
|
||||
| "监听我和 userId 507971 的消息撤回" | `event consume`,事件码 `user_im_message_recall_o2o`,参数 `--user 507971 -f ndjson` |
|
||||
| "监听我和 userId test-user-001 的消息撤回" | `event consume`,事件码 `user_im_message_recall_o2o`,参数 `--user test-user-001 -f ndjson` |
|
||||
| "监听 XX 群消息撤回" | 先解析群 ID,再 consume `user_im_message_recall_group --group <id>` |
|
||||
| "监听我和 userId 507971 的消息贴表情" | `event consume`,事件码 `user_im_message_reaction_o2o`,参数 `--user 507971 -f ndjson` |
|
||||
| "监听我和 userId test-user-001 的消息贴表情" | `event consume`,事件码 `user_im_message_reaction_o2o`,参数 `--user test-user-001 -f ndjson` |
|
||||
| "监听 XX 群消息表情回应" | 先解析群 ID,再 consume `user_im_message_reaction_group --group <id>` |
|
||||
| "监听并自动回复某人的单聊消息" | 先解析对端 userId,再启动 o2o consume;不要写轮询脚本 |
|
||||
| "查看个人消息事件 schema" | `dws event schema <event_key>` |
|
||||
@@ -89,16 +89,16 @@ dws event schema user_im_message_reaction_group
|
||||
|
||||
```bash
|
||||
dws event consume user_im_message_receive_at -f ndjson
|
||||
dws event consume user_im_message_receive_o2o --user 507971 -f ndjson
|
||||
dws event consume user_im_message_receive_o2o --user test-user-001 -f ndjson
|
||||
dws event consume user_im_message_receive_o2o --open-dingtalk-id abc -f ndjson
|
||||
dws event consume user_im_message_receive_group --group <openConversationId> -f ndjson
|
||||
dws event consume user_im_message_receive_user --user 507971 -f ndjson
|
||||
dws event consume user_im_message_receive_user --user test-user-001 -f ndjson
|
||||
dws event consume user_im_message_receive_user --open-dingtalk-id abc -f ndjson
|
||||
dws event consume user_im_message_read_o2o --user 507971 -f ndjson
|
||||
dws event consume user_im_message_read_o2o --user test-user-001 -f ndjson
|
||||
dws event consume user_im_message_read_group --group <openConversationId> -f ndjson
|
||||
dws event consume user_im_message_recall_o2o --user 507971 -f ndjson
|
||||
dws event consume user_im_message_recall_o2o --user test-user-001 -f ndjson
|
||||
dws event consume user_im_message_recall_group --group <openConversationId> -f ndjson
|
||||
dws event consume user_im_message_reaction_o2o --user 507971 -f ndjson
|
||||
dws event consume user_im_message_reaction_o2o --user test-user-001 -f ndjson
|
||||
dws event consume user_im_message_reaction_group --group <openConversationId> -f ndjson
|
||||
```
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ dws event consume user_im_message_receive_at -f ndjson
|
||||
|
||||
# 当前用户与指定用户的单聊消息
|
||||
dws event consume user_im_message_receive_o2o \
|
||||
--user 507971 \
|
||||
--user test-user-001 \
|
||||
-f ndjson
|
||||
|
||||
# 使用 openDingtalkId 监听外部联系人、机器人或跨组织身份的单聊消息
|
||||
@@ -107,7 +107,7 @@ dws event consume user_im_message_receive_group \
|
||||
|
||||
# 指定发送人的消息(单聊和群聊)
|
||||
dws event consume user_im_message_receive_user \
|
||||
--user 507971 \
|
||||
--user test-user-001 \
|
||||
-f ndjson
|
||||
|
||||
# 使用 openDingtalkId 监听指定发送人的消息
|
||||
@@ -117,7 +117,7 @@ dws event consume user_im_message_receive_user \
|
||||
|
||||
# 指定单聊消息已读
|
||||
dws event consume user_im_message_read_o2o \
|
||||
--user 507971 \
|
||||
--user test-user-001 \
|
||||
-f ndjson
|
||||
|
||||
# 指定群聊消息撤回
|
||||
@@ -127,7 +127,7 @@ dws event consume user_im_message_recall_group \
|
||||
|
||||
# 指定单聊消息收到表情回应
|
||||
dws event consume user_im_message_reaction_o2o \
|
||||
--user 507971 \
|
||||
--user test-user-001 \
|
||||
-f ndjson
|
||||
|
||||
# 有界自测
|
||||
@@ -137,7 +137,7 @@ dws event consume user_im_message_receive_at \
|
||||
|
||||
# 抓一条样本
|
||||
dws event consume user_im_message_receive_o2o \
|
||||
--user 507971 \
|
||||
--user test-user-001 \
|
||||
--max-events 1 \
|
||||
-f json
|
||||
```
|
||||
|
||||
@@ -66,7 +66,7 @@ dws event consume user_im_message_receive_at -f ndjson
|
||||
|
||||
# 指定单聊消息
|
||||
dws event consume user_im_message_receive_o2o \
|
||||
--user 507971 \
|
||||
--user test-user-001 \
|
||||
-f ndjson
|
||||
|
||||
# 通过 openDingtalkId 指定单聊对端
|
||||
@@ -81,7 +81,7 @@ dws event consume user_im_message_receive_group \
|
||||
|
||||
# 指定发送人的消息(单聊和群聊)
|
||||
dws event consume user_im_message_receive_user \
|
||||
--user 507971 \
|
||||
--user test-user-001 \
|
||||
-f ndjson
|
||||
|
||||
# 通过 openDingtalkId 指定发送人
|
||||
@@ -91,7 +91,7 @@ dws event consume user_im_message_receive_user \
|
||||
|
||||
# 指定单聊已读事件
|
||||
dws event consume user_im_message_read_o2o \
|
||||
--user 507971 \
|
||||
--user test-user-001 \
|
||||
-f ndjson
|
||||
|
||||
# 指定群聊已读事件
|
||||
@@ -101,7 +101,7 @@ dws event consume user_im_message_read_group \
|
||||
|
||||
# 指定单聊撤回事件
|
||||
dws event consume user_im_message_recall_o2o \
|
||||
--user 507971 \
|
||||
--user test-user-001 \
|
||||
-f ndjson
|
||||
|
||||
# 指定群聊撤回事件
|
||||
@@ -111,7 +111,7 @@ dws event consume user_im_message_recall_group \
|
||||
|
||||
# 指定单聊表情回应事件
|
||||
dws event consume user_im_message_reaction_o2o \
|
||||
--user 507971 \
|
||||
--user test-user-001 \
|
||||
-f ndjson
|
||||
|
||||
# 指定群聊表情回应事件
|
||||
|
||||
+18
-18
@@ -1005,9 +1005,9 @@ Agent 安装 dws skill 后,仅依据 skill 提供的参考文档,将自然
|
||||
#### `dws event consume user_im_message_receive_o2o`
|
||||
|
||||
**event_event_consume_o2o_001**
|
||||
- Prompt: 监听我和 userId 507971 的单聊消息
|
||||
- Expected: `dws event consume user_im_message_receive_o2o --user 507971 -f ndjson`
|
||||
- Flags: `--user` = `507971`
|
||||
- Prompt: 监听我和 userId test-user-001 的单聊消息
|
||||
- Expected: `dws event consume user_im_message_receive_o2o --user test-user-001 -f ndjson`
|
||||
- Flags: `--user` = `test-user-001`
|
||||
|
||||
**event_event_consume_o2o_open_id_001**
|
||||
- Prompt: 监听我和 openDingtalkId abc 的单聊消息
|
||||
@@ -1019,9 +1019,9 @@ Agent 安装 dws skill 后,仅依据 skill 提供的参考文档,将自然
|
||||
- Expected: `dws event consume user_im_message_receive_o2o -f ndjson`
|
||||
|
||||
**event_event_consume_o2o_auto_reply_001**
|
||||
- Prompt: 监听我和 userId 507971 的单聊消息,并对方发什么自动回复什么
|
||||
- Expected: `dws event consume user_im_message_receive_o2o --user 507971 -f ndjson`
|
||||
- Flags: `--user` = `507971`
|
||||
- Prompt: 监听我和 userId test-user-001 的单聊消息,并对方发什么自动回复什么
|
||||
- Expected: `dws event consume user_im_message_receive_o2o --user test-user-001 -f ndjson`
|
||||
- Flags: `--user` = `test-user-001`
|
||||
- Contract: 等待 stderr 的 `[event] ready`;从每行 NDJSON 顶层读取 `content` 和 `sender_open_dingtalk_id`,持续读取 stdout,不使用轮询或 output-dir watcher
|
||||
|
||||
#### `dws event consume user_im_message_receive_group`
|
||||
@@ -1035,9 +1035,9 @@ Agent 安装 dws skill 后,仅依据 skill 提供的参考文档,将自然
|
||||
#### `dws event consume user_im_message_receive_user`
|
||||
|
||||
**event_event_consume_user_001**
|
||||
- Prompt: 监听 userId 507971 发给我的消息,包括单聊和群聊
|
||||
- Expected: `dws event consume user_im_message_receive_user --user 507971 -f ndjson`
|
||||
- Flags: `--user` = `507971`
|
||||
- Prompt: 监听 userId test-user-001 发给我的消息,包括单聊和群聊
|
||||
- Expected: `dws event consume user_im_message_receive_user --user test-user-001 -f ndjson`
|
||||
- Flags: `--user` = `test-user-001`
|
||||
|
||||
**event_event_consume_user_open_id_001**
|
||||
- Prompt: 监听 openDingtalkId abc 发给我的消息,包括单聊和群聊
|
||||
@@ -1047,9 +1047,9 @@ Agent 安装 dws skill 后,仅依据 skill 提供的参考文档,将自然
|
||||
#### `dws event consume user_im_message_read_o2o`
|
||||
|
||||
**event_event_consume_read_o2o_001**
|
||||
- Prompt: 监听我发给 userId 507971 的单聊消息是否已读
|
||||
- Expected: `dws event consume user_im_message_read_o2o --user 507971 -f ndjson`
|
||||
- Flags: `--user` = `507971`
|
||||
- Prompt: 监听我发给 userId test-user-001 的单聊消息是否已读
|
||||
- Expected: `dws event consume user_im_message_read_o2o --user test-user-001 -f ndjson`
|
||||
- Flags: `--user` = `test-user-001`
|
||||
- Contract: 从每行 NDJSON 顶层读取 `message_id`、`reader`、`reader_open_dingtalk_id`、`read_time`
|
||||
|
||||
#### `dws event consume user_im_message_read_group`
|
||||
@@ -1063,9 +1063,9 @@ Agent 安装 dws skill 后,仅依据 skill 提供的参考文档,将自然
|
||||
#### `dws event consume user_im_message_recall_o2o`
|
||||
|
||||
**event_event_consume_recall_o2o_001**
|
||||
- Prompt: 监听我和 userId 507971 的单聊消息撤回事件
|
||||
- Expected: `dws event consume user_im_message_recall_o2o --user 507971 -f ndjson`
|
||||
- Flags: `--user` = `507971`
|
||||
- Prompt: 监听我和 userId test-user-001 的单聊消息撤回事件
|
||||
- Expected: `dws event consume user_im_message_recall_o2o --user test-user-001 -f ndjson`
|
||||
- Flags: `--user` = `test-user-001`
|
||||
- Contract: 从每行 NDJSON 顶层读取 `message_id`、`recaller`、`recaller_open_dingtalk_id`、`recall_time`
|
||||
|
||||
#### `dws event consume user_im_message_recall_group`
|
||||
@@ -1079,9 +1079,9 @@ Agent 安装 dws skill 后,仅依据 skill 提供的参考文档,将自然
|
||||
#### `dws event consume user_im_message_reaction_o2o`
|
||||
|
||||
**event_event_consume_reaction_o2o_001**
|
||||
- Prompt: 监听我和 userId 507971 的单聊消息贴表情事件
|
||||
- Expected: `dws event consume user_im_message_reaction_o2o --user 507971 -f ndjson`
|
||||
- Flags: `--user` = `507971`
|
||||
- Prompt: 监听我和 userId test-user-001 的单聊消息贴表情事件
|
||||
- Expected: `dws event consume user_im_message_reaction_o2o --user test-user-001 -f ndjson`
|
||||
- Flags: `--user` = `test-user-001`
|
||||
- Contract: 从每行 NDJSON 顶层读取 `operator`、`operator_open_dingtalk_id`、`reaction_name`、`operation_type`
|
||||
|
||||
**event_event_consume_reaction_o2o_open_id_001**
|
||||
|
||||
@@ -1424,8 +1424,8 @@
|
||||
|
||||
**event_event_consume_o2o_001** ✅ PASS
|
||||
|
||||
- Prompt: 监听我和 userId 507971 的单聊消息
|
||||
- Expected: `dws event consume user_im_message_receive_o2o --user 507971 -f ndjson`
|
||||
- Prompt: 监听我和 userId test-user-001 的单聊消息
|
||||
- Expected: `dws event consume user_im_message_receive_o2o --user test-user-001 -f ndjson`
|
||||
- Skill Reference: references/products/event.md
|
||||
- Command path: PASS (event consume user_im_message_receive_o2o)
|
||||
- Flags: PASS (1 flags validated)
|
||||
|
||||
Reference in New Issue
Block a user