From 644616c642583205be13561b40ff1cb9b5cc531f Mon Sep 17 00:00:00 2001 From: jesse-engineer <784909593@qq.com> Date: Tue, 28 Apr 2026 23:08:43 +0800 Subject: [PATCH 1/2] feat(ark): add WithExtraFields for Responses API JSON merge - arkOptions.extraFields and WithExtraFields option - mergeResponsesRequestExtraJSON: shallow merge into wire JSON after preprocess - Generate/Stream/CreatePrefixCache use invokeCreateResponses* when extra set - go.mod replace volcengine-go-sdk to fork commit until upstream merges PR Depends-on: https://github.com/volcengine/volcengine-go-sdk/pull/151 Made-with: Cursor --- components/model/ark/go.mod | 2 + components/model/ark/go.sum | 4 +- components/model/ark/option.go | 12 +++++ components/model/ark/responses_api.go | 38 +++++++++++++-- components/model/ark/responses_merge.go | 46 ++++++++++++++++++ components/model/ark/responses_merge_test.go | 50 ++++++++++++++++++++ 6 files changed, 147 insertions(+), 5 deletions(-) create mode 100644 components/model/ark/responses_merge.go create mode 100644 components/model/ark/responses_merge_test.go diff --git a/components/model/ark/go.mod b/components/model/ark/go.mod index 3e136ee9c..29743063a 100644 --- a/components/model/ark/go.mod +++ b/components/model/ark/go.mod @@ -49,3 +49,5 @@ require ( gopkg.in/yaml.v2 v2.2.8 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +replace github.com/volcengine/volcengine-go-sdk => github.com/jesse-engineer/volcengine-go-sdk v1.2.26-0.20260428150644-cf9db789ee32 diff --git a/components/model/ark/go.sum b/components/model/ark/go.sum index 96f141149..567b92573 100644 --- a/components/model/ark/go.sum +++ b/components/model/ark/go.sum @@ -66,6 +66,8 @@ github.com/goph/emperror v0.17.2/go.mod h1:+ZbQ+fUNO/6FNiUo0ujtMjhgad9Xa6fQL9KhH github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jesse-engineer/volcengine-go-sdk v1.2.26-0.20260428150644-cf9db789ee32 h1:MmTysoe+4IMf8JpHkDZg2UF3sN5nt976sNLKXMoI6eg= +github.com/jesse-engineer/volcengine-go-sdk v1.2.26-0.20260428150644-cf9db789ee32/go.mod h1:oxoVo+A17kvkwPkIeIHPVLjSw7EQAm+l/Vau1YGHN+A= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -137,8 +139,6 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/volcengine/volc-sdk-golang v1.0.23 h1:anOslb2Qp6ywnsbyq9jqR0ljuO63kg9PY+4OehIk5R8= github.com/volcengine/volc-sdk-golang v1.0.23/go.mod h1:AfG/PZRUkHJ9inETvbjNifTDgut25Wbkm2QoYBTbvyU= -github.com/volcengine/volcengine-go-sdk v1.2.9 h1:du2gnImtyWXKkQFnJW/GXCs+UBibGGOXIbP1Ams2pB8= -github.com/volcengine/volcengine-go-sdk v1.2.9/go.mod h1:oxoVo+A17kvkwPkIeIHPVLjSw7EQAm+l/Vau1YGHN+A= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= diff --git a/components/model/ark/option.go b/components/model/ark/option.go index d112effb4..eb9a81850 100644 --- a/components/model/ark/option.go +++ b/components/model/ark/option.go @@ -35,6 +35,9 @@ type arkOptions struct { maxToolCalls *int64 enableReasoningContentPassback bool + + // extraFields are shallow-merged into serialized Responses API JSON after multimodal preprocessing. + extraFields map[string]any } // WithCustomHeader sets custom headers for a single request @@ -153,3 +156,12 @@ func WithEnableReasoningContentPassback(enable bool) model.Option { o.enableReasoningContentPassback = enable }) } + +// WithExtraFields sets extra top-level JSON fields on the Responses API request body. +// Merged after inputs are built and after multimodal preprocessing; extra keys override existing keys. +// Requires volcengine-go-sdk with PreprocessResponsesRequest, CreateResponsesFromJSON, CreateResponsesStreamFromJSON. +func WithExtraFields(extraFields map[string]any) model.Option { + return model.WrapImplSpecificOptFn(func(o *arkOptions) { + o.extraFields = extraFields + }) +} diff --git a/components/model/ark/responses_api.go b/components/model/ark/responses_api.go index 2b9caf156..d2b4ea302 100644 --- a/components/model/ark/responses_api.go +++ b/components/model/ark/responses_api.go @@ -35,6 +35,7 @@ import ( arkModel "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model" "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model/responses" "github.com/volcengine/volcengine-go-sdk/service/arkruntime/utils" + "github.com/volcengine/volcengine-go-sdk/volcengine" ) type Thinking = arkModel.Thinking @@ -283,7 +284,7 @@ func (cm *ResponsesAPIChatModel) Generate(ctx context.Context, input []*schema.M } }() - responseObject, err := cm.client.CreateResponses(ctx, responseReq, arkruntime.WithCustomHeaders(specOptions.customHeaders)) + responseObject, err := cm.invokeCreateResponses(ctx, responseReq, specOptions) if err != nil { return nil, fmt.Errorf("failed to create responses: %w", err) } @@ -350,7 +351,7 @@ func (cm *ResponsesAPIChatModel) Stream(ctx context.Context, input []*schema.Mes } }() - responseStreamReader, err := cm.client.CreateResponsesStream(ctx, responseReq, arkruntime.WithCustomHeaders(specOptions.customHeaders)) + responseStreamReader, err := cm.invokeCreateResponsesStream(ctx, responseReq, specOptions) if err != nil { return nil, fmt.Errorf("failed to create responses: %w", err) } @@ -948,6 +949,37 @@ func (cm *ResponsesAPIChatModel) getOptions(opts []model.Option) (*model.Options return options, arkOpts, nil } +func (cm *ResponsesAPIChatModel) invokeCreateResponses(ctx context.Context, responseReq *responses.ResponsesRequest, spec *arkOptions) (*responses.ResponseObject, error) { + h := arkruntime.WithCustomHeaders(spec.customHeaders) + if len(spec.extraFields) == 0 { + return cm.client.CreateResponses(ctx, responseReq, h) + } + if err := cm.client.PreprocessResponsesRequest(ctx, responseReq); err != nil { + return nil, err + } + raw, err := mergeResponsesRequestExtraJSON(responseReq, spec.extraFields) + if err != nil { + return nil, err + } + return cm.client.CreateResponsesFromJSON(ctx, responseReq.Model, raw, h) +} + +func (cm *ResponsesAPIChatModel) invokeCreateResponsesStream(ctx context.Context, responseReq *responses.ResponsesRequest, spec *arkOptions) (*utils.ResponsesStreamReader, error) { + h := arkruntime.WithCustomHeaders(spec.customHeaders) + if len(spec.extraFields) == 0 { + return cm.client.CreateResponsesStream(ctx, responseReq, h) + } + responseReq.Stream = volcengine.Bool(true) + if err := cm.client.PreprocessResponsesRequest(ctx, responseReq); err != nil { + return nil, err + } + raw, err := mergeResponsesRequestExtraJSON(responseReq, spec.extraFields) + if err != nil { + return nil, err + } + return cm.client.CreateResponsesStreamFromJSON(ctx, responseReq.Model, raw, h) +} + func (cm *ResponsesAPIChatModel) toTools(tis []*schema.ToolInfo) ([]*responses.ResponsesTool, error) { tools := make([]*responses.ResponsesTool, len(tis)) for i := range tis { @@ -1712,7 +1744,7 @@ func (cm *ResponsesAPIChatModel) CreatePrefixCache(ctx context.Context, prefix [ return nil, err } - responseObject, err := cm.client.CreateResponses(ctx, responseReq) + responseObject, err := cm.invokeCreateResponses(ctx, responseReq, specOptions) if err != nil { return nil, err } diff --git a/components/model/ark/responses_merge.go b/components/model/ark/responses_merge.go new file mode 100644 index 000000000..74714b6ad --- /dev/null +++ b/components/model/ark/responses_merge.go @@ -0,0 +1,46 @@ +/* + * Copyright 2025 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ark + +import ( + "fmt" + + "github.com/bytedance/sonic" + "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model/responses" +) + +func mergeResponsesRequestExtraJSON(req *responses.ResponsesRequest, extra map[string]any) ([]byte, error) { + if len(extra) == 0 { + return sonic.Marshal(req) + } + baseBytes, err := sonic.Marshal(req) + if err != nil { + return nil, fmt.Errorf("marshal responses request: %w", err) + } + var base map[string]any + if err := sonic.Unmarshal(baseBytes, &base); err != nil { + return nil, fmt.Errorf("unmarshal responses request json: %w", err) + } + for k, v := range extra { + base[k] = v + } + out, err := sonic.Marshal(base) + if err != nil { + return nil, fmt.Errorf("marshal merged request: %w", err) + } + return out, nil +} diff --git a/components/model/ark/responses_merge_test.go b/components/model/ark/responses_merge_test.go new file mode 100644 index 000000000..78027a773 --- /dev/null +++ b/components/model/ark/responses_merge_test.go @@ -0,0 +1,50 @@ +/* + * Copyright 2025 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ark + +import ( + "testing" + + "github.com/bytedance/sonic" + "github.com/stretchr/testify/assert" + "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model/responses" + + "github.com/cloudwego/eino/components/model" +) + +func TestWithExtraFieldsOption(t *testing.T) { + fields := map[string]any{"custom_param": "x", "nested": map[string]any{"k": 1}} + opt := model.GetImplSpecificOptions(&arkOptions{}, WithExtraFields(fields)) + assert.Equal(t, fields, opt.extraFields) +} + +func TestMergeResponsesRequestExtraJSON(t *testing.T) { + req := &responses.ResponsesRequest{ + Model: "ep-test", + } + extra := map[string]any{"thinking": map[string]any{"type": "disabled"}} + + raw, err := mergeResponsesRequestExtraJSON(req, extra) + assert.NoError(t, err) + + var out map[string]any + assert.NoError(t, sonic.Unmarshal(raw, &out)) + assert.Equal(t, "ep-test", out["model"]) + th, ok := out["thinking"].(map[string]any) + assert.True(t, ok) + assert.Equal(t, "disabled", th["type"]) +} From 13ba969cb96f29dc14880e80b529c2feafb89cc9 Mon Sep 17 00:00:00 2001 From: jesse-engineer <784909593@qq.com> Date: Tue, 28 Apr 2026 23:20:01 +0800 Subject: [PATCH 2/2] refactor(ark): use arkruntime.WithResponsesExtraFields Remove local JSON merge; map WithExtraFields to SDK requestOption. Update replace pseudo-version for volcengine PR. Made-with: Cursor --- components/model/ark/go.mod | 2 +- components/model/ark/go.sum | 4 +- components/model/ark/option.go | 4 +- components/model/ark/option_test.go | 6 +++ components/model/ark/responses_api.go | 31 +++++------- components/model/ark/responses_merge.go | 46 ------------------ components/model/ark/responses_merge_test.go | 50 -------------------- 7 files changed, 24 insertions(+), 119 deletions(-) delete mode 100644 components/model/ark/responses_merge.go delete mode 100644 components/model/ark/responses_merge_test.go diff --git a/components/model/ark/go.mod b/components/model/ark/go.mod index 29743063a..a9f195ce0 100644 --- a/components/model/ark/go.mod +++ b/components/model/ark/go.mod @@ -50,4 +50,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/volcengine/volcengine-go-sdk => github.com/jesse-engineer/volcengine-go-sdk v1.2.26-0.20260428150644-cf9db789ee32 +replace github.com/volcengine/volcengine-go-sdk => github.com/jesse-engineer/volcengine-go-sdk v1.2.26-0.20260428152021-d3ac2bef0584 diff --git a/components/model/ark/go.sum b/components/model/ark/go.sum index 567b92573..7560c9f6f 100644 --- a/components/model/ark/go.sum +++ b/components/model/ark/go.sum @@ -66,8 +66,8 @@ github.com/goph/emperror v0.17.2/go.mod h1:+ZbQ+fUNO/6FNiUo0ujtMjhgad9Xa6fQL9KhH github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/jesse-engineer/volcengine-go-sdk v1.2.26-0.20260428150644-cf9db789ee32 h1:MmTysoe+4IMf8JpHkDZg2UF3sN5nt976sNLKXMoI6eg= -github.com/jesse-engineer/volcengine-go-sdk v1.2.26-0.20260428150644-cf9db789ee32/go.mod h1:oxoVo+A17kvkwPkIeIHPVLjSw7EQAm+l/Vau1YGHN+A= +github.com/jesse-engineer/volcengine-go-sdk v1.2.26-0.20260428152021-d3ac2bef0584 h1:hdi/IU3ATB4ZSmG1r15rJignySbT2c14PLQ9I2Adddc= +github.com/jesse-engineer/volcengine-go-sdk v1.2.26-0.20260428152021-d3ac2bef0584/go.mod h1:oxoVo+A17kvkwPkIeIHPVLjSw7EQAm+l/Vau1YGHN+A= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= diff --git a/components/model/ark/option.go b/components/model/ark/option.go index eb9a81850..3a725eee6 100644 --- a/components/model/ark/option.go +++ b/components/model/ark/option.go @@ -158,8 +158,8 @@ func WithEnableReasoningContentPassback(enable bool) model.Option { } // WithExtraFields sets extra top-level JSON fields on the Responses API request body. -// Merged after inputs are built and after multimodal preprocessing; extra keys override existing keys. -// Requires volcengine-go-sdk with PreprocessResponsesRequest, CreateResponsesFromJSON, CreateResponsesStreamFromJSON. +// Merged inside volcengine-go-sdk after the request is built and multimodal inputs are preprocessed; +// keys in extraFields override existing keys. See arkruntime.WithResponsesExtraFields. func WithExtraFields(extraFields map[string]any) model.Option { return model.WrapImplSpecificOptFn(func(o *arkOptions) { o.extraFields = extraFields diff --git a/components/model/ark/option_test.go b/components/model/ark/option_test.go index 0b11df7b7..7d5d0d168 100644 --- a/components/model/ark/option_test.go +++ b/components/model/ark/option_test.go @@ -46,3 +46,9 @@ func TestOptions(t *testing.T) { assert.Equal(t, cacheOpt, *opt.cache) assert.Equal(t, arkModel.ThinkingTypeEnabled, opt.thinking.Type) } + +func TestWithExtraFieldsOption(t *testing.T) { + fields := map[string]any{"k": "v"} + opt := model.GetImplSpecificOptions(&arkOptions{}, WithExtraFields(fields)) + assert.Equal(t, fields, opt.extraFields) +} diff --git a/components/model/ark/responses_api.go b/components/model/ark/responses_api.go index d2b4ea302..e5a0a0aa1 100644 --- a/components/model/ark/responses_api.go +++ b/components/model/ark/responses_api.go @@ -35,7 +35,6 @@ import ( arkModel "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model" "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model/responses" "github.com/volcengine/volcengine-go-sdk/service/arkruntime/utils" - "github.com/volcengine/volcengine-go-sdk/volcengine" ) type Thinking = arkModel.Thinking @@ -949,19 +948,23 @@ func (cm *ResponsesAPIChatModel) getOptions(opts []model.Option) (*model.Options return options, arkOpts, nil } +func extraFieldsToIface(m map[string]any) map[string]interface{} { + if len(m) == 0 { + return nil + } + out := make(map[string]interface{}, len(m)) + for k, v := range m { + out[k] = v + } + return out +} + func (cm *ResponsesAPIChatModel) invokeCreateResponses(ctx context.Context, responseReq *responses.ResponsesRequest, spec *arkOptions) (*responses.ResponseObject, error) { h := arkruntime.WithCustomHeaders(spec.customHeaders) if len(spec.extraFields) == 0 { return cm.client.CreateResponses(ctx, responseReq, h) } - if err := cm.client.PreprocessResponsesRequest(ctx, responseReq); err != nil { - return nil, err - } - raw, err := mergeResponsesRequestExtraJSON(responseReq, spec.extraFields) - if err != nil { - return nil, err - } - return cm.client.CreateResponsesFromJSON(ctx, responseReq.Model, raw, h) + return cm.client.CreateResponses(ctx, responseReq, h, arkruntime.WithResponsesExtraFields(extraFieldsToIface(spec.extraFields))) } func (cm *ResponsesAPIChatModel) invokeCreateResponsesStream(ctx context.Context, responseReq *responses.ResponsesRequest, spec *arkOptions) (*utils.ResponsesStreamReader, error) { @@ -969,15 +972,7 @@ func (cm *ResponsesAPIChatModel) invokeCreateResponsesStream(ctx context.Context if len(spec.extraFields) == 0 { return cm.client.CreateResponsesStream(ctx, responseReq, h) } - responseReq.Stream = volcengine.Bool(true) - if err := cm.client.PreprocessResponsesRequest(ctx, responseReq); err != nil { - return nil, err - } - raw, err := mergeResponsesRequestExtraJSON(responseReq, spec.extraFields) - if err != nil { - return nil, err - } - return cm.client.CreateResponsesStreamFromJSON(ctx, responseReq.Model, raw, h) + return cm.client.CreateResponsesStream(ctx, responseReq, h, arkruntime.WithResponsesExtraFields(extraFieldsToIface(spec.extraFields))) } func (cm *ResponsesAPIChatModel) toTools(tis []*schema.ToolInfo) ([]*responses.ResponsesTool, error) { diff --git a/components/model/ark/responses_merge.go b/components/model/ark/responses_merge.go deleted file mode 100644 index 74714b6ad..000000000 --- a/components/model/ark/responses_merge.go +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2025 CloudWeGo Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ark - -import ( - "fmt" - - "github.com/bytedance/sonic" - "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model/responses" -) - -func mergeResponsesRequestExtraJSON(req *responses.ResponsesRequest, extra map[string]any) ([]byte, error) { - if len(extra) == 0 { - return sonic.Marshal(req) - } - baseBytes, err := sonic.Marshal(req) - if err != nil { - return nil, fmt.Errorf("marshal responses request: %w", err) - } - var base map[string]any - if err := sonic.Unmarshal(baseBytes, &base); err != nil { - return nil, fmt.Errorf("unmarshal responses request json: %w", err) - } - for k, v := range extra { - base[k] = v - } - out, err := sonic.Marshal(base) - if err != nil { - return nil, fmt.Errorf("marshal merged request: %w", err) - } - return out, nil -} diff --git a/components/model/ark/responses_merge_test.go b/components/model/ark/responses_merge_test.go deleted file mode 100644 index 78027a773..000000000 --- a/components/model/ark/responses_merge_test.go +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2025 CloudWeGo Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ark - -import ( - "testing" - - "github.com/bytedance/sonic" - "github.com/stretchr/testify/assert" - "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model/responses" - - "github.com/cloudwego/eino/components/model" -) - -func TestWithExtraFieldsOption(t *testing.T) { - fields := map[string]any{"custom_param": "x", "nested": map[string]any{"k": 1}} - opt := model.GetImplSpecificOptions(&arkOptions{}, WithExtraFields(fields)) - assert.Equal(t, fields, opt.extraFields) -} - -func TestMergeResponsesRequestExtraJSON(t *testing.T) { - req := &responses.ResponsesRequest{ - Model: "ep-test", - } - extra := map[string]any{"thinking": map[string]any{"type": "disabled"}} - - raw, err := mergeResponsesRequestExtraJSON(req, extra) - assert.NoError(t, err) - - var out map[string]any - assert.NoError(t, sonic.Unmarshal(raw, &out)) - assert.Equal(t, "ep-test", out["model"]) - th, ok := out["thinking"].(map[string]any) - assert.True(t, ok) - assert.Equal(t, "disabled", th["type"]) -}