Skip to content

Commit 9d31389

Browse files
authored
refactor!: Remove obsolete polling suspension fields from request protocol (#759)
* Remove polling suspension fields Assisted-by: Codex:GPT-5.4 * Tighten polling validation tests Assisted-by: Codex:GPT-5.4 * Add polling payload shape regression test Assisted-by: Codex:GPT-5.4
1 parent 064f67d commit 9d31389

2 files changed

Lines changed: 138 additions & 18 deletions

File tree

pkg/entities/requests/model.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,17 +186,12 @@ type RequestGetAIModelSchema struct {
186186

187187
type RequestStartPolling struct {
188188
RequestInvokeLLM
189-
190-
WorkflowRunID string `json:"workflow_run_id" validate:"required"`
191-
NodeID string `json:"node_id" validate:"required"`
192189
}
193190

194191
type RequestCheckPolling struct {
195192
BaseRequestInvokeModel
196193
Credentials
197194

198-
ModelType model_entities.ModelType `json:"model_type" validate:"required,model_type,eq=llm"`
199-
WorkflowRunID string `json:"workflow_run_id" validate:"required"`
200-
NodeID string `json:"node_id" validate:"required"`
201-
PluginState map[string]any `json:"plugin_state" validate:"required,min=1"`
195+
ModelType model_entities.ModelType `json:"model_type" validate:"required,model_type,eq=llm"`
196+
PluginState map[string]any `json:"plugin_state" validate:"required,min=1"`
202197
}

pkg/entities/requests/model_polling_test.go

Lines changed: 136 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,61 @@ import (
44
"encoding/json"
55
"testing"
66

7+
"github.com/go-playground/validator/v10"
78
"github.com/langgenius/dify-plugin-daemon/pkg/entities/model_entities"
9+
"github.com/langgenius/dify-plugin-daemon/pkg/utils/parser"
810
"github.com/langgenius/dify-plugin-daemon/pkg/validators"
911
)
1012

13+
func TestRequestStartPollingDoesNotRequireSuspensionFields(t *testing.T) {
14+
payload := []byte(`{
15+
"provider": "volcengine",
16+
"model": "doubao-seedance-2-0-260128",
17+
"model_type": "llm",
18+
"credentials": {"ark_api_key": "test"}
19+
}`)
20+
21+
var request RequestStartPolling
22+
if err := json.Unmarshal(payload, &request); err != nil {
23+
t.Fatalf("unmarshal request: %v", err)
24+
}
25+
26+
if err := validators.GlobalEntitiesValidator.Struct(request); err != nil {
27+
t.Fatalf("validate request: %v", err)
28+
}
29+
}
30+
1131
func TestRequestCheckPollingRequiresPluginState(t *testing.T) {
1232
payload := []byte(`{
1333
"provider": "volcengine",
1434
"model": "doubao-seedance-2-0-260128",
1535
"model_type": "llm",
16-
"credentials": {"ark_api_key": "test"},
17-
"workflow_run_id": "wr-1",
18-
"node_id": "llm-1"
36+
"credentials": {"ark_api_key": "test"}
1937
}`)
2038

2139
var request RequestCheckPolling
2240
if err := json.Unmarshal(payload, &request); err != nil {
2341
t.Fatalf("unmarshal request: %v", err)
2442
}
2543

26-
if err := validators.GlobalEntitiesValidator.Struct(request); err == nil {
27-
t.Fatal("expected missing plugin_state validation error")
44+
if err := validators.GlobalEntitiesValidator.Struct(request); err != nil {
45+
validationErrors, ok := err.(validator.ValidationErrors)
46+
if !ok {
47+
t.Fatalf("unexpected validation error type: %T: %v", err, err)
48+
}
49+
if len(validationErrors) != 1 {
50+
t.Fatalf("expected 1 validation error, got %d: %v", len(validationErrors), validationErrors)
51+
}
52+
validationError := validationErrors[0]
53+
if validationError.Field() != "PluginState" {
54+
t.Fatalf("unexpected field: %s", validationError.Field())
55+
}
56+
if validationError.Tag() != "required" {
57+
t.Fatalf("unexpected tag: %s", validationError.Tag())
58+
}
59+
return
2860
}
61+
t.Fatal("expected missing plugin_state validation error")
2962
}
3063

3164
func TestRequestCheckPollingRejectsEmptyPluginState(t *testing.T) {
@@ -34,8 +67,6 @@ func TestRequestCheckPollingRejectsEmptyPluginState(t *testing.T) {
3467
"model": "doubao-seedance-2-0-260128",
3568
"model_type": "llm",
3669
"credentials": {"ark_api_key": "test"},
37-
"workflow_run_id": "wr-1",
38-
"node_id": "llm-1",
3970
"plugin_state": {}
4071
}`)
4172

@@ -44,9 +75,24 @@ func TestRequestCheckPollingRejectsEmptyPluginState(t *testing.T) {
4475
t.Fatalf("unmarshal request: %v", err)
4576
}
4677

47-
if err := validators.GlobalEntitiesValidator.Struct(request); err == nil {
48-
t.Fatal("expected empty plugin_state validation error")
78+
if err := validators.GlobalEntitiesValidator.Struct(request); err != nil {
79+
validationErrors, ok := err.(validator.ValidationErrors)
80+
if !ok {
81+
t.Fatalf("unexpected validation error type: %T: %v", err, err)
82+
}
83+
if len(validationErrors) != 1 {
84+
t.Fatalf("expected 1 validation error, got %d: %v", len(validationErrors), validationErrors)
85+
}
86+
validationError := validationErrors[0]
87+
if validationError.Field() != "PluginState" {
88+
t.Fatalf("unexpected field: %s", validationError.Field())
89+
}
90+
if validationError.Tag() != "min" {
91+
t.Fatalf("unexpected tag: %s", validationError.Tag())
92+
}
93+
return
4994
}
95+
t.Fatal("expected empty plugin_state validation error")
5096
}
5197

5298
func TestRequestCheckPollingAcceptsPluginState(t *testing.T) {
@@ -55,8 +101,6 @@ func TestRequestCheckPollingAcceptsPluginState(t *testing.T) {
55101
"model": "doubao-seedance-2-0-260128",
56102
"model_type": "llm",
57103
"credentials": {"ark_api_key": "test"},
58-
"workflow_run_id": "wr-1",
59-
"node_id": "llm-1",
60104
"plugin_state": {"task_id": "task-1"}
61105
}`)
62106

@@ -75,3 +119,84 @@ func TestRequestCheckPollingAcceptsPluginState(t *testing.T) {
75119
t.Fatalf("unexpected plugin_state: %#v", request.PluginState)
76120
}
77121
}
122+
123+
func TestPollingRequestMapExcludesSuspensionFields(t *testing.T) {
124+
startPolling := RequestStartPolling{
125+
RequestInvokeLLM: RequestInvokeLLM{
126+
BaseRequestInvokeModel: BaseRequestInvokeModel{
127+
Provider: "volcengine",
128+
Model: "doubao-seedance-2-0-260128",
129+
},
130+
Credentials: Credentials{
131+
Credentials: map[string]any{"ark_api_key": "test"},
132+
},
133+
InvokeLLMSchema: InvokeLLMSchema{
134+
Stream: true,
135+
},
136+
ModelType: model_entities.MODEL_TYPE_LLM,
137+
},
138+
}
139+
140+
assertPollingRequestMapShape(t, parser.StructToMap(startPolling), false)
141+
142+
checkPolling := RequestCheckPolling{
143+
BaseRequestInvokeModel: BaseRequestInvokeModel{
144+
Provider: "volcengine",
145+
Model: "doubao-seedance-2-0-260128",
146+
},
147+
Credentials: Credentials{
148+
Credentials: map[string]any{"ark_api_key": "test"},
149+
},
150+
ModelType: model_entities.MODEL_TYPE_LLM,
151+
PluginState: map[string]any{"task_id": "task-1"},
152+
}
153+
154+
assertPollingRequestMapShape(t, parser.StructToMap(checkPolling), true)
155+
}
156+
157+
func assertPollingRequestMapShape(t *testing.T, result map[string]any, expectPluginState bool) {
158+
t.Helper()
159+
160+
if _, ok := result["workflow_run_id"]; ok {
161+
t.Fatal("workflow_run_id should not be present in polling request map")
162+
}
163+
if _, ok := result["node_id"]; ok {
164+
t.Fatal("node_id should not be present in polling request map")
165+
}
166+
167+
if result["provider"] != "volcengine" {
168+
t.Fatalf("provider should be volcengine, got %#v", result["provider"])
169+
}
170+
if result["model"] != "doubao-seedance-2-0-260128" {
171+
t.Fatalf("model should be present, got %#v", result["model"])
172+
}
173+
if result["model_type"] != model_entities.MODEL_TYPE_LLM {
174+
t.Fatalf("model_type should be llm, got %#v", result["model_type"])
175+
}
176+
177+
credentials, ok := result["credentials"].(map[string]any)
178+
if !ok {
179+
t.Fatalf("credentials should be a map, got %T", result["credentials"])
180+
}
181+
if credentials["ark_api_key"] != "test" {
182+
t.Fatalf("credentials should contain ark_api_key, got %#v", credentials)
183+
}
184+
185+
if expectPluginState {
186+
pluginState, ok := result["plugin_state"].(map[string]any)
187+
if !ok {
188+
t.Fatalf("plugin_state should be a map, got %T", result["plugin_state"])
189+
}
190+
if pluginState["task_id"] != "task-1" {
191+
t.Fatalf("plugin_state should contain task_id, got %#v", pluginState)
192+
}
193+
return
194+
}
195+
196+
if _, ok := result["plugin_state"]; ok {
197+
t.Fatal("plugin_state should not be present in start polling request map")
198+
}
199+
if stream, ok := result["stream"].(bool); !ok || !stream {
200+
t.Fatalf("stream should be true, got %#v", result["stream"])
201+
}
202+
}

0 commit comments

Comments
 (0)